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
222 s << "Will resample audio from " << _fs->audio_sample_rate << " to " << _fs->target_sample_rate();
223 _log->log (s.str ());
225 _swr_context = swr_alloc_set_opts (
227 audio_channel_layout,
229 _fs->target_sample_rate(),
230 audio_channel_layout,
232 _fs->audio_sample_rate,
236 swr_init (_swr_context);
238 throw EncodeError ("Cannot resample audio as libswresample is not present");
241 #ifdef HAVE_SWRESAMPLE
246 for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) {
247 _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, (ServerDescription *) 0)));
250 vector<ServerDescription*> servers = Config::instance()->servers ();
252 for (vector<ServerDescription*>::iterator i = servers.begin(); i != servers.end(); ++i) {
253 for (int j = 0; j < (*i)->threads (); ++j) {
254 _worker_threads.push_back (new boost::thread (boost::bind (&J2KWAVEncoder::encoder_thread, this, *i)));
260 J2KWAVEncoder::process_end ()
262 boost::mutex::scoped_lock lock (_worker_mutex);
264 _log->log ("Clearing queue of " + lexical_cast<string> (_queue.size ()));
266 /* Keep waking workers until the queue is empty */
267 while (!_queue.empty ()) {
268 _log->log ("Waking with " + lexical_cast<string> (_queue.size ()));
269 _worker_condition.notify_all ();
270 _worker_condition.wait (lock);
275 terminate_worker_threads ();
277 _log->log ("Mopping up " + lexical_cast<string> (_queue.size()));
279 /* The following sequence of events can occur in the above code:
280 1. a remote worker takes the last image off the queue
281 2. the loop above terminates
282 3. the remote worker fails to encode the image and puts it back on the queue
283 4. the remote worker is then terminated by terminate_worker_threads
285 So just mop up anything left in the queue here.
288 for (list<shared_ptr<DCPVideoFrame> >::iterator i = _queue.begin(); i != _queue.end(); ++i) {
290 s << "Encode left-over frame " << (*i)->frame();
291 _log->log (s.str ());
293 shared_ptr<EncodedData> e = (*i)->encode_locally ();
294 e->write (_opt, (*i)->frame ());
295 frame_done ((*i)->frame ());
296 } catch (std::exception& e) {
298 s << "Local encode failed " << e.what() << ".";
299 _log->log (s.str ());
307 uint8_t buffer[256 * _fs->bytes_per_sample() * _fs->audio_channels];
313 int const frames = swr_convert (_swr_context, out, 256, 0, 0);
316 throw EncodeError ("could not run sample-rate converter");
323 write_audio (buffer, frames * _fs->bytes_per_sample() * _fs->audio_channels);
326 swr_free (&_swr_context);
330 close_sound_files ();
332 /* Rename .wav.tmp files to .wav */
333 for (int i = 0; i < _fs->audio_channels; ++i) {
334 if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) {
335 boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false));
337 boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false));
342 J2KWAVEncoder::process_audio (uint8_t* data, int size)
344 /* This is a buffer we might use if we are sample-rate converting;
345 it will need freeing if so.
347 uint8_t* out_buffer = 0;
349 /* Maybe sample-rate convert */
353 uint8_t const * in[2] = {
358 /* Here's samples per channel */
359 int const samples = size / _fs->bytes_per_sample();
361 /* And here's frames (where 1 frame is a collection of samples, 1 for each channel,
362 so for 5.1 a frame would be 6 samples)
364 int const frames = samples / _fs->audio_channels;
366 /* Compute the resampled frame count and add 32 for luck */
367 int const out_buffer_size_frames = ceil (frames * _fs->target_sample_rate() / _fs->audio_sample_rate) + 32;
368 int const out_buffer_size_bytes = out_buffer_size_frames * _fs->audio_channels * _fs->bytes_per_sample();
369 out_buffer = new uint8_t[out_buffer_size_bytes];
377 int out_frames = swr_convert (_swr_context, out, out_buffer_size_frames, in, frames);
378 if (out_frames < 0) {
379 throw EncodeError ("could not run sample-rate converter");
382 /* And point our variables at the resampled audio */
384 size = out_frames * _fs->audio_channels * _fs->bytes_per_sample();
388 write_audio (data, size);
390 /* Delete the sample-rate conversion buffer, if it exists */
395 J2KWAVEncoder::write_audio (uint8_t* data, int size)
397 /* XXX: we are assuming that the _deinterleave_buffer_size is a multiple
398 of the sample size and that size is a multiple of _fs->audio_channels * sample_size.
401 assert ((size % (_fs->audio_channels * _fs->bytes_per_sample())) == 0);
402 assert ((_deinterleave_buffer_size % _fs->bytes_per_sample()) == 0);
404 /* XXX: this code is very tricksy and it must be possible to make it simpler ... */
406 /* Number of bytes left to read this time */
407 int remaining = size;
408 /* Our position in the output buffers, in bytes */
410 while (remaining > 0) {
411 /* How many bytes of the deinterleaved data to do this time */
412 int this_time = min (remaining / _fs->audio_channels, _deinterleave_buffer_size);
413 for (int i = 0; i < _fs->audio_channels; ++i) {
414 for (int j = 0; j < this_time; j += _fs->bytes_per_sample()) {
415 for (int k = 0; k < _fs->bytes_per_sample(); ++k) {
416 int const to = j + k;
417 int const from = position + (i * _fs->bytes_per_sample()) + (j * _fs->audio_channels) + k;
418 _deinterleave_buffer[to] = data[from];
422 switch (_fs->audio_sample_format) {
423 case AV_SAMPLE_FMT_S16:
424 sf_write_short (_sound_files[i], (const short *) _deinterleave_buffer, this_time / _fs->bytes_per_sample());
427 throw EncodeError ("unknown audio sample format");
431 position += this_time;
432 remaining -= this_time * _fs->audio_channels;