summaryrefslogtreecommitdiff
path: root/src/lib/writer.h
blob: d922cfce01a4685ed1b5941dc1bf0998f999c3ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

*/

#include <list>
#include <boost/shared_ptr.hpp>
#include <boost/thread.hpp>
#include <boost/thread/condition.hpp>
#include "exceptions.h"
#include "types.h"

class Film;
class EncodedData;
class AudioBuffers;
class Job;

namespace libdcp {
	class MonoPictureAsset;
	class MonoPictureAssetWriter;
	class StereoPictureAsset;
	class StereoPictureAssetWriter;
	class PictureAsset;
	class PictureAssetWriter;
	class SoundAsset;
	class SoundAssetWriter;
}

struct QueueItem
{
public:
	enum Type {
		/** a normal frame with some JPEG200 data */
		FULL,
		/** a frame whose data already exists in the MXF,
		    and we fake-write it; i.e. we update the writer's
		    state but we use the data that is already on disk.
		*/
		FAKE,
		/** this is a repeat of the last frame to be written */
		REPEAT
	} type;

	/** encoded data for FULL */
	boost::shared_ptr<const EncodedData> encoded;
	/** size of data for FAKE */
	int size;
	/** frame index */
	int frame;
	Eyes eyes;
};

bool operator< (QueueItem const & a, QueueItem const & b);
bool operator== (QueueItem const & a, QueueItem const & b);

class Writer : public ExceptionStore, public boost::noncopyable
{
public:
	Writer (boost::shared_ptr<const Film>, boost::shared_ptr<Job>);

	bool can_fake_write (int) const;
	
	void write (boost::shared_ptr<const EncodedData>, int, Eyes);
	void fake_write (int, Eyes);
	void write (boost::shared_ptr<const AudioBuffers>);
	void repeat (int f, Eyes);
	void finish ();

private:

	void thread ();
	void check_existing_picture_mxf ();
	bool check_existing_picture_mxf_frame (FILE *, int, Eyes);
	bool have_sequenced_image_at_queue_head () const;

	/** our Film */
	boost::shared_ptr<const Film> _film;
	boost::shared_ptr<Job> _job;
	/** the first frame index that does not already exist in our MXF */
	int _first_nonexistant_frame;

	/** our thread, or 0 */
	boost::thread* _thread;
	/** true if our thread should finish */
	bool _finish;
	/** queue of things to write to disk */
	std::list<QueueItem> _queue;
	/** number of FULL frames whose JPEG200 data is currently held in RAM */
	int _queued_full_in_memory;
	/** mutex for thread state */
	mutable boost::mutex _mutex;
	/** condition to manage thread wakeups */
	boost::condition _condition;
	/** the data of the last written frame, or 0 if there isn't one */
	boost::shared_ptr<const EncodedData> _last_written[EYES_COUNT];
	/** the index of the last written frame */
	int _last_written_frame;
	Eyes _last_written_eyes;
	/** maximum number of frames to hold in memory, for when we are managing
	    ordering
	*/
	static const int _maximum_frames_in_memory;

	/** number of FULL written frames */
	int _full_written;
	/** number of FAKE written frames */
	int _fake_written;
	/** number of REPEAT written frames */
	int _repeat_written;
	/** number of frames pushed to disk and then recovered
	    due to the limit of frames to be held in memory.
	*/
	int _pushed_to_disk;
	
	boost::shared_ptr<libdcp::PictureAsset> _picture_asset;
	boost::shared_ptr<libdcp::PictureAssetWriter> _picture_asset_writer;
	boost::shared_ptr<libdcp::SoundAsset> _sound_asset;
	boost::shared_ptr<libdcp::SoundAssetWriter> _sound_asset_writer;
};