summaryrefslogtreecommitdiff
path: root/src/lib/encoder.h
blob: e5916ad3a022bc8f2f9c8c117e182f339d7f3def (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
134
135
136
137
/*
    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.

*/

#ifndef DVDOMATIC_ENCODER_H
#define DVDOMATIC_ENCODER_H

/** @file src/encoder.h
 *  @brief Parent class for classes which can encode video and audio frames.
 */

#include <boost/shared_ptr.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/thread.hpp>
#include <boost/optional.hpp>
#include <list>
#include <stdint.h>
extern "C" {
#include <libavutil/samplefmt.h>
}
#ifdef HAVE_SWRESAMPLE
extern "C" {
#include <libswresample/swresample.h>
}
#endif
#include <sndfile.h>
#include "util.h"
#include "video_sink.h"
#include "audio_sink.h"

class EncodeOptions;
class Image;
class Subtitle;
class AudioBuffers;
class Film;
class ServerDescription;
class DCPVideoFrame;

/** @class Encoder
 *  @brief Encoder to J2K and WAV for DCP.
 *
 *  Video is supplied to process_video as YUV frames, and audio
 *  is supplied as uncompressed PCM in blocks of various sizes.
 */

class Encoder : public VideoSink, public AudioSink
{
public:
	Encoder (boost::shared_ptr<const Film> f, boost::shared_ptr<const EncodeOptions> o);
	virtual ~Encoder ();

	/** Called to indicate that a processing run is about to begin */
	virtual void process_begin ();

	/** Call with a frame of video.
	 *  @param i Video frame image.
	 *  @param same true if i is the same as the last time we were called.
	 *  @param s A subtitle that should be on this frame, or 0.
	 */
	void process_video (boost::shared_ptr<Image> i, bool same, boost::shared_ptr<Subtitle> s);

	/** Call with some audio data */
	void process_audio (boost::shared_ptr<AudioBuffers>);

	/** Called when a processing run has finished */
	virtual void process_end ();

	float current_frames_per_second () const;
	bool skipping () const;
	SourceFrame video_frame () const;

protected:
	
	void frame_done ();
	void frame_skipped ();
	
	/** Film that we are encoding */
	boost::shared_ptr<const Film> _film;
	/** Options */
	boost::shared_ptr<const EncodeOptions> _opt;

	/** Mutex for _time_history, _just_skipped and _last_frame */
	mutable boost::mutex _history_mutex;
	/** List of the times of completion of the last _history_size frames;
	    first is the most recently completed.
	*/
	std::list<struct timeval> _time_history;
	/** Number of frames that we should keep history for */
	static int const _history_size;
	/** true if the last frame we processed was skipped (because it was already done) */
	bool _just_skipped;

	/** Number of video frames received so far */
	SourceFrame _video_frame;
	/** Number of audio frames received so far */
	int64_t _audio_frame;

private:
	void close_sound_files ();
	void write_audio (boost::shared_ptr<const AudioBuffers> audio);

	void encoder_thread (ServerDescription *);
	void terminate_worker_threads ();
	void link (std::string, std::string) const;

#if HAVE_SWRESAMPLE	
	SwrContext* _swr_context;
#endif	

	std::vector<SNDFILE*> _sound_files;
	int64_t _audio_frames_written;

	boost::optional<int> _last_real_frame;
	bool _process_end;
	std::list<boost::shared_ptr<DCPVideoFrame> > _queue;
	std::list<boost::thread *> _worker_threads;
	mutable boost::mutex _worker_mutex;
	boost::condition _worker_condition;
};

#endif