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/j2k_wav_encoder.cc
21 * @brief An encoder which writes JPEG2000 and WAV files.
28 #include <boost/thread.hpp>
29 #include <boost/filesystem.hpp>
30 #include <boost/lexical_cast.hpp>
33 #include "j2k_wav_encoder.h"
35 #include "film_state.h"
37 #include "exceptions.h"
38 #include "dcp_video_frame.h"
45 using namespace boost;
47 J2KWAVEncoder::J2KWAVEncoder (shared_ptr<const FilmState> s, shared_ptr<const Options> o, Log* l)
49 #ifdef HAVE_SWRESAMPLE
52 , _deinterleave_buffer_size (8192)
53 , _deinterleave_buffer (0)
54 , _process_end (false)
56 /* Create sound output files with .tmp suffixes; we will rename
57 them if and when we complete.
59 for (int i = 0; i < _fs->audio_channels; ++i) {
61 sf_info.samplerate = dcp_audio_sample_rate (_fs->audio_sample_rate);
62 /* We write mono files */
64 sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24;
65 SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info);
67 throw CreateFileError (_opt->multichannel_audio_out_path (i, true));
69 _sound_files.push_back (f);
72 /* Create buffer for deinterleaving audio */
73 _deinterleave_buffer = new uint8_t[_deinterleave_buffer_size];
76 J2KWAVEncoder::~J2KWAVEncoder ()
78 terminate_worker_threads ();
79 delete[] _deinterleave_buffer;
84 J2KWAVEncoder::terminate_worker_threads ()
86 boost::mutex::scoped_lock lock (_worker_mutex);
88 _worker_condition.notify_all ();
91 for (list<boost::thread *>::iterator i = _worker_threads.begin(); i != _worker_threads.end(); ++i) {
98 J2KWAVEncoder::close_sound_files ()
100 for (vector<SNDFILE*>::iterator i = _sound_files.begin(); i != _sound_files.end(); ++i) {
104 _sound_files.clear ();
108 J2KWAVEncoder::process_video (shared_ptr<Image> yuv, int frame)
110 boost::mutex::scoped_lock lock (_worker_mutex);
112 /* Wait until the queue has gone down a bit */
113 while (_queue.size() >= _worker_threads.size() * 2 && !_process_end) {
114 _worker_condition.wait (lock);
121 /* Only do the processing if we don't already have a file for this frame */
122 if (!boost::filesystem::exists (_opt->frame_out_path (frame, false))) {
123 pair<string, string> const s = Filter::ffmpeg_strings (_fs->filters);
124 _queue.push_back (boost::shared_ptr<DCPVideoFrame> (
126 yuv, _opt->out_size, _opt->padding, _fs->scaler, frame, _fs->frames_per_second, s.second,
127 Config::instance()->colour_lut_index (), Config::instance()->j2k_bandwidth (),
132 _worker_condition.notify_all ();
139 J2KWAVEncoder::encoder_thread (ServerDescription* server)
141 /* Number of seconds that we currently wait between attempts
142 to connect to the server; not relevant for localhost
145 int remote_backoff = 0;
148 boost::mutex::scoped_lock lock (_worker_mutex);
149 while (_queue.empty () && !_process_end) {
150 _worker_condition.wait (lock);
157 boost::shared_ptr<DCPVideoFrame> vf = _queue.front ();
162 shared_ptr<EncodedData> encoded;
166 encoded = vf->encode_remotely (server);
168 if (remote_backoff > 0) {
170 s << server->host_name() << " was lost, but now she is found; removing backoff";
171 _log->log (s.str ());
174 /* This job succeeded, so remove any backoff */
177 } catch (std::exception& e) {
178 if (remote_backoff < 60) {
180 remote_backoff += 10;
183 s << "Remote encode of " << vf->frame() << " on " << server->host_name() << " failed (" << e.what() << "); thread sleeping for " << remote_backoff << "s.";
184 _log->log (s.str ());
189 encoded = vf->encode_locally ();
190 } catch (std::exception& e) {
192 s << "Local encode failed " << e.what() << ".";
193 _log->log (s.str ());
198 encoded->write (_opt, vf->frame ());
199 frame_done (vf->frame ());
202 _queue.push_front (vf);
206 if (remote_backoff > 0) {
207 dvdomatic_sleep (remote_backoff);
211 _worker_condition.notify_all ();
216 J2KWAVEncoder::process_begin (int64_t audio_channel_layout, AVSampleFormat audio_sample_format)
218 if ((_fs->audio_sample_rate != dcp_audio_sample_rate (_fs->audio_sample_rate)) || (rint (_fs->frames_per_second) != _fs->frames_per_second)) {
219 #ifdef HAVE_SWRESAMPLE
220 _swr_context = swr_alloc_set_opts (
222 audio_channel_layout,
224 target_sample_rate(),
225 audio_channel_layout,
227 _fs->audio_sample_rate,
231 swr_init (_swr_context);
233 throw EncodeError ("Cannot resample audio as libswresample is not present");
236 #ifdef HAVE_SWRESAMPLE
241 for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) {
242 _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (ServerDescription *) 0)));
245 vector<ServerDescription*> servers = Config::instance()->servers ();
247 for (vector<ServerDescription*>::iterator i = servers.begin(); i != servers.end(); ++i) {
248 for (int j = 0; j < (*i)->threads (); ++j) {
249 _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, *i)));
255 J2KWAVEncoder::process_end ()
257 boost::mutex::scoped_lock lock (_worker_mutex);
259 _log->log ("Clearing queue of " + lexical_cast<string> (_queue.size ()));
261 /* Keep waking workers until the queue is empty */
262 while (!_queue.empty ()) {
263 _log->log ("Waking with " + lexical_cast<string> (_queue.size ()));
264 _worker_condition.notify_all ();
265 _worker_condition.wait (lock);
270 terminate_worker_threads ();
272 _log->log ("Mopping up " + lexical_cast<string> (_queue.size()));
274 /* The following sequence of events can occur in the above code:
275 1. a remote worker takes the last image off the queue
276 2. the loop above terminates
277 3. the remote worker fails to encode the image and puts it back on the queue
278 4. the remote worker is then terminated by terminate_worker_threads
280 So just mop up anything left in the queue here.
283 for (list<shared_ptr<DCPVideoFrame> >::iterator i = _queue.begin(); i != _queue.end(); ++i) {
285 s << "Encode left-over frame " << (*i)->frame();
286 _log->log (s.str ());
288 shared_ptr<EncodedData> e = (*i)->encode_locally ();
289 e->write (_opt, (*i)->frame ());
290 frame_done ((*i)->frame ());
291 } catch (std::exception& e) {
293 s << "Local encode failed " << e.what() << ".";
294 _log->log (s.str ());
303 uint8_t buffer[256 * _fs->bytes_per_sample() * _fs->audio_channels];
308 int const frames = swr_convert (_swr_context, out, 256, 0, 0);
311 throw EncodeError ("could not run sample-rate converter");
319 write_audio (buffer, frames);
322 swr_free (&_swr_context);
326 close_sound_files ();
328 /* Rename .wav.tmp files to .wav */
329 for (int i = 0; i < _fs->audio_channels; ++i) {
330 if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
331 boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
333 boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false));
338 J2KWAVEncoder::process_audio (uint8_t* data, int size)
340 /* This is a buffer we might use if we are sample-rate converting;
341 it will need freeing if so.
343 uint8_t* out_buffer = 0;
345 /* Maybe sample-rate convert */
349 uint8_t const * in[2] = {
354 /* Here's samples per channel */
355 int const samples = size / _fs->bytes_per_sample();
357 /* And here's frames (where 1 frame is a collection of samples, 1 for each channel,
358 so for 5.1 a frame would be 6 samples)
360 int const frames = samples / _fs->audio_channels;
362 /* Compute the resampled frame count and add 32 for luck */
363 int const out_buffer_size_frames = ceil (frames * target_sample_rate() / _fs->audio_sample_rate) + 32;
364 int const out_buffer_size_bytes = out_buffer_size_frames * _fs->audio_channels * _fs->bytes_per_sample();
365 out_buffer = new uint8_t[out_buffer_size_bytes];
373 int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, size);
374 if (out_frames < 0) {
375 throw EncodeError ("could not run sample-rate converter");
378 /* And point our variables at the resampled audio */
380 size = out_frames * _fs->audio_channels * _fs->bytes_per_sample();
384 write_audio (data, size);
386 /* Delete the sample-rate conversion buffer, if it exists */
391 J2KWAVEncoder::write_audio (uint8_t* data, int size)
393 /* Size of a sample in bytes */
394 int const sample_size = 2;
396 /* XXX: we are assuming that sample_size is right, the _deinterleave_buffer_size is a multiple
397 of the sample size and that data_size is a multiple of _fs->audio_channels * sample_size.
400 /* XXX: this code is very tricksy and it must be possible to make it simpler ... */
402 /* Number of bytes left to read this time */
403 int remaining = size;
404 /* Our position in the output buffers, in bytes */
406 while (remaining > 0) {
407 /* How many bytes of the deinterleaved data to do this time */
408 int this_time = min (remaining / _fs->audio_channels, _deinterleave_buffer_size);
409 for (int i = 0; i < _fs->audio_channels; ++i) {
410 for (int j = 0; j < this_time; j += sample_size) {
411 for (int k = 0; k < sample_size; ++k) {
412 int const to = j + k;
413 int const from = position + (i * sample_size) + (j * _fs->audio_channels) + k;
414 _deinterleave_buffer[to] = data[from];
418 switch (_fs->audio_sample_format) {
419 case AV_SAMPLE_FMT_S16:
420 sf_write_short (_sound_files[i], (const short *) _deinterleave_buffer, this_time / sample_size);
423 throw EncodeError ("unknown audio sample format");
427 position += this_time;
428 remaining -= this_time * _fs->audio_channels;
433 J2KWAVEncoder::target_sample_rate () const
435 double t = dcp_audio_sample_rate (_fs->audio_sample_rate);
436 if (rint (_fs->frames_per_second) != _fs->frames_per_second) {
437 if (_fs->frames_per_second == 23.976) {
438 /* 24fps drop-frame ie 24 * 1000 / 1001 frames per second;
439 hence we need to resample the audio to dcp_audio_sample_rate * 1000 / 1001
440 so that when we play it back at dcp_audio_sample_rate it is sped up
441 by the same amount that the video is
443 t *= double(1000) / 1001;
445 throw EncodeError ("unknown fractional frame rate");