2 Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 /** @file src/encoder.h
21 * @brief Parent class for classes which can encode video and audio frames.
24 #include <boost/filesystem.hpp>
30 #include "exceptions.h"
33 using std::stringstream;
35 using namespace boost;
37 int const Encoder::_history_size = 25;
39 /** @param f Film that we are encoding.
42 Encoder::Encoder (shared_ptr<const Film> f, shared_ptr<const EncodeOptions> o)
45 , _just_skipped (false)
48 #ifdef HAVE_SWRESAMPLE
51 , _audio_frames_written (0)
53 if (_film->audio_stream()) {
54 /* Create sound output files with .tmp suffixes; we will rename
55 them if and when we complete.
57 for (int i = 0; i < _film->audio_channels(); ++i) {
59 sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate());
60 /* We write mono files */
62 sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
63 SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
65 throw CreateFileError (_opt->multichannel_audio_out_path (i, true));
67 _sound_files.push_back (f);
78 Encoder::process_begin ()
80 if (_film->audio_stream() && _film->audio_stream()->sample_rate() != _film->target_audio_sample_rate()) {
81 #ifdef HAVE_SWRESAMPLE
84 s << "Will resample audio from " << _film->audio_stream()->sample_rate() << " to " << _film->target_audio_sample_rate();
85 _film->log()->log (s.str ());
87 /* We will be using planar float data when we call the resampler */
88 _swr_context = swr_alloc_set_opts (
90 _film->audio_stream()->channel_layout(),
92 _film->target_audio_sample_rate(),
93 _film->audio_stream()->channel_layout(),
95 _film->audio_stream()->sample_rate(),
99 swr_init (_swr_context);
101 throw EncodeError ("Cannot resample audio as libswresample is not present");
104 #ifdef HAVE_SWRESAMPLE
112 Encoder::process_end ()
115 if (_film->audio_stream() && _swr_context) {
117 shared_ptr<AudioBuffers> out (new AudioBuffers (_film->audio_stream()->channels(), 256));
120 int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0);
123 throw EncodeError ("could not run sample-rate converter");
130 out->set_frames (frames);
134 swr_free (&_swr_context);
138 if (_film->audio_stream()) {
139 close_sound_files ();
141 /* Rename .wav.tmp files to .wav */
142 for (int i = 0; i < _film->audio_channels(); ++i) {
143 if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
144 boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
146 boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false));
151 /** @return an estimate of the current number of frames we are encoding per second,
155 Encoder::current_frames_per_second () const
157 boost::mutex::scoped_lock lock (_history_mutex);
158 if (int (_time_history.size()) < _history_size) {
163 gettimeofday (&now, 0);
165 return _history_size / (seconds (now) - seconds (_time_history.back ()));
168 /** @return true if the last frame to be processed was skipped as it already existed */
170 Encoder::skipping () const
172 boost::mutex::scoped_lock (_history_mutex);
173 return _just_skipped;
176 /** @return Number of video frames that have been received */
178 Encoder::video_frame () const
180 boost::mutex::scoped_lock (_history_mutex);
184 /** Should be called when a frame has been encoded successfully.
185 * @param n Source frame index.
188 Encoder::frame_done ()
190 boost::mutex::scoped_lock lock (_history_mutex);
191 _just_skipped = false;
194 gettimeofday (&tv, 0);
195 _time_history.push_front (tv);
196 if (int (_time_history.size()) > _history_size) {
197 _time_history.pop_back ();
201 /** Called by a subclass when it has just skipped the processing
202 of a frame because it has already been done.
205 Encoder::frame_skipped ()
207 boost::mutex::scoped_lock lock (_history_mutex);
208 _just_skipped = true;
212 Encoder::process_video (shared_ptr<Image> i, boost::shared_ptr<Subtitle> s)
214 if (_opt->video_skip != 0 && (_video_frame % _opt->video_skip) != 0) {
219 if (_opt->video_range) {
220 pair<SourceFrame, SourceFrame> const r = _opt->video_range.get();
221 if (_video_frame < r.first || _video_frame >= r.second) {
227 do_process_video (i, s);
232 Encoder::process_audio (shared_ptr<AudioBuffers> data)
234 if (_opt->audio_range) {
236 shared_ptr<AudioBuffers> trimmed (new AudioBuffers (*data.get ()));
238 /* Range that we are encoding */
239 pair<int64_t, int64_t> required_range = _opt->audio_range.get();
240 /* Range of this block of data */
241 pair<int64_t, int64_t> this_range (_audio_frame, _audio_frame + trimmed->frames());
243 if (this_range.second < required_range.first || required_range.second < this_range.first) {
244 /* No part of this audio is within the required range */
246 } else if (required_range.first >= this_range.first && required_range.first < this_range.second) {
248 int64_t const shift = required_range.first - this_range.first;
249 trimmed->move (shift, 0, trimmed->frames() - shift);
250 trimmed->set_frames (trimmed->frames() - shift);
251 } else if (required_range.second >= this_range.first && required_range.second < this_range.second) {
253 trimmed->set_frames (required_range.second - this_range.first);
260 /* Maybe sample-rate convert */
263 /* Compute the resampled frames count and add 32 for luck */
264 int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_stream()->sample_rate()) + 32;
266 shared_ptr<AudioBuffers> resampled (new AudioBuffers (_film->audio_stream()->channels(), max_resampled_frames));
269 int const resampled_frames = swr_convert (
270 _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) data->data(), data->frames()
273 if (resampled_frames < 0) {
274 throw EncodeError ("could not run sample-rate converter");
277 resampled->set_frames (resampled_frames);
279 /* And point our variables at the resampled audio */
286 _audio_frame += data->frames ();
290 Encoder::write_audio (shared_ptr<const AudioBuffers> audio)
292 for (int i = 0; i < _film->audio_channels(); ++i) {
293 sf_write_float (_sound_files[i], audio->data(i), audio->frames());
296 _audio_frames_written += audio->frames ();
300 Encoder::close_sound_files ()
302 for (vector<SNDFILE*>::iterator i = _sound_files.begin(); i != _sound_files.end(); ++i) {
306 _sound_files.clear ();