From d0babb26ab341026fe227de810ed30c6c9f65cf2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 11 Jan 2013 18:50:50 +0000 Subject: Try a separate writer thread. --- src/lib/encoder.cc | 94 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 73 insertions(+), 21 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 693bd5bc8..93a364fed 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -60,7 +60,9 @@ Encoder::Encoder (shared_ptr f, shared_ptr o) , _swr_context (0) #endif , _audio_frames_written (0) - , _process_end (false) + , _terminate_encoder (false) + , _writer_thread (0) + , _terminate_writer (false) { if (_film->audio_stream()) { /* Create sound output files with .tmp suffixes; we will rename @@ -85,6 +87,7 @@ Encoder::~Encoder () { close_sound_files (); terminate_worker_threads (); + terminate_writer_thread (); } void @@ -130,6 +133,8 @@ Encoder::process_begin () _worker_threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, *i))); } } + + _writer_thread = new boost::thread (boost::bind (&Encoder::writer_thread, this)); } @@ -174,11 +179,11 @@ Encoder::process_end () boost::mutex::scoped_lock lock (_worker_mutex); - _film->log()->log ("Clearing queue of " + lexical_cast (_queue.size ())); + _film->log()->log ("Clearing queue of " + lexical_cast (_encode_queue.size ())); /* Keep waking workers until the queue is empty */ - while (!_queue.empty ()) { - _film->log()->log ("Waking with " + lexical_cast (_queue.size ()), Log::VERBOSE); + while (!_encode_queue.empty ()) { + _film->log()->log ("Waking with " + lexical_cast (_encode_queue.size ()), Log::VERBOSE); _worker_condition.notify_all (); _worker_condition.wait (lock); } @@ -186,8 +191,9 @@ Encoder::process_end () lock.unlock (); terminate_worker_threads (); + terminate_writer_thread (); - _film->log()->log ("Mopping up " + lexical_cast (_queue.size())); + _film->log()->log ("Mopping up " + lexical_cast (_encode_queue.size())); /* The following sequence of events can occur in the above code: 1. a remote worker takes the last image off the queue @@ -198,7 +204,7 @@ Encoder::process_end () So just mop up anything left in the queue here. */ - for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { + for (list >::iterator i = _encode_queue.begin(); i != _encode_queue.end(); ++i) { _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); try { shared_ptr e = (*i)->encode_locally (); @@ -209,6 +215,11 @@ Encoder::process_end () } } + /* Mop up any unwritten things in the writer's queue */ + for (list, int> >::iterator i = _write_queue.begin(); i != _write_queue.end(); ++i) { + i->first->write (_opt, i->second); + } + /* Now do links (or copies on windows) to duplicate frames */ for (list >::iterator i = _links_required.begin(); i != _links_required.end(); ++i) { link (_opt->frame_out_path (i->first, false), _opt->frame_out_path (i->second, false)); @@ -295,13 +306,13 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr= _worker_threads.size() * 2 && !_process_end) { - TIMING ("decoder sleeps with queue of %1", _queue.size()); + while (_encode_queue.size() >= _worker_threads.size() * 2 && !_terminate_encoder) { + TIMING ("decoder sleeps with queue of %1", _encode_queue.size()); _worker_condition.wait (lock); - TIMING ("decoder wakes with queue of %1", _queue.size()); + TIMING ("decoder wakes with queue of %1", _encode_queue.size()); } - if (_process_end) { + if (_terminate_encoder) { return; } @@ -320,8 +331,8 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); - TIMING ("adding to queue of %1", _queue.size ()); - _queue.push_back (boost::shared_ptr ( + TIMING ("adding to queue of %1", _encode_queue.size ()); + _encode_queue.push_back (boost::shared_ptr ( new DCPVideoFrame ( image, sub, _opt->out_size, _opt->padding, _film->subtitle_offset(), _film->subtitle_scale(), _film->scaler(), _video_frame, _film->frames_per_second(), s.second, @@ -434,7 +445,7 @@ void Encoder::terminate_worker_threads () { boost::mutex::scoped_lock lock (_worker_mutex); - _process_end = true; + _terminate_encoder = true; _worker_condition.notify_all (); lock.unlock (); @@ -444,6 +455,23 @@ Encoder::terminate_worker_threads () } } +void +Encoder::terminate_writer_thread () +{ + if (!_writer_thread) { + return; + } + + boost::mutex::scoped_lock lock (_writer_mutex); + _terminate_writer = true; + _writer_condition.notify_all (); + lock.unlock (); + + _writer_thread->join (); + delete _writer_thread; + _writer_thread = 0; +} + void Encoder::encoder_thread (ServerDescription* server) { @@ -457,18 +485,18 @@ Encoder::encoder_thread (ServerDescription* server) TIMING ("encoder thread %1 sleeps", boost::this_thread::get_id()); boost::mutex::scoped_lock lock (_worker_mutex); - while (_queue.empty () && !_process_end) { + while (_encode_queue.empty () && !_terminate_encoder) { _worker_condition.wait (lock); } - if (_process_end) { + if (_terminate_encoder) { return; } - TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); - boost::shared_ptr vf = _queue.front (); + TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _encode_queue.size()); + boost::shared_ptr vf = _encode_queue.front (); _film->log()->log (String::compose ("Encoder thread %1 pops frame %2 from queue", boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); - _queue.pop_front (); + _encode_queue.pop_front (); lock.unlock (); @@ -508,14 +536,15 @@ Encoder::encoder_thread (ServerDescription* server) } if (encoded) { - encoded->write (_opt, vf->frame ()); - frame_done (); + boost::mutex::scoped_lock lock (_writer_mutex); + _write_queue.push_back (make_pair (encoded, vf->frame ())); + _writer_condition.notify_all (); } else { lock.lock (); _film->log()->log ( String::compose ("Encoder thread %1 pushes frame %2 back onto queue after failure", boost::this_thread::get_id(), vf->frame()) ); - _queue.push_front (vf); + _encode_queue.push_front (vf); lock.unlock (); } @@ -542,3 +571,26 @@ Encoder::link (string a, string b) const boost::filesystem::copy_file (a, b); #endif } + +void +Encoder::writer_thread () +{ + while (1) + { + boost::mutex::scoped_lock lock (_writer_mutex); + while (_write_queue.empty() && !_terminate_writer) { + _writer_condition.wait (lock); + } + + if (_terminate_writer) { + return; + } + + pair, int> encoded = _write_queue.front (); + _write_queue.pop_front (); + + lock.unlock (); + encoded.first->write (_opt, encoded.second); + lock.lock (); + } +} -- cgit v1.2.3 From ef0aa27c671f9c34b9aad79015bcc50cb10c0fc5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 11 Jan 2013 19:20:51 +0000 Subject: Encoded data must be copied; disambiguate second lock in encoder_thread. --- src/lib/dcp_video_frame.cc | 26 ++++++++++++++++++++------ src/lib/dcp_video_frame.h | 21 +++++++++------------ src/lib/encoder.cc | 2 +- 3 files changed, 30 insertions(+), 19 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 8b70b0aa4..f84fa8a3f 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -59,6 +59,7 @@ using std::string; using std::stringstream; using std::ofstream; +using std::cout; using boost::shared_ptr; /** Construct a DCP video frame. @@ -371,6 +372,18 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) return e; } +EncodedData::EncodedData (int s) + : _data (new uint8_t[s]) + , _size (s) +{ + +} + +EncodedData::~EncodedData () +{ + delete[] _data; +} + /** Write this data to a J2K file. * @param opt Options. * @param frame Frame index. @@ -413,14 +426,15 @@ EncodedData::send (shared_ptr socket) socket->write (_data, _size, 30); } -/** @param s Size of data in bytes */ -RemotelyEncodedData::RemotelyEncodedData (int s) - : EncodedData (new uint8_t[s], s) +LocallyEncodedData::LocallyEncodedData (uint8_t* d, int s) + : EncodedData (s) { - + memcpy (_data, d, s); } -RemotelyEncodedData::~RemotelyEncodedData () +/** @param s Size of data in bytes */ +RemotelyEncodedData::RemotelyEncodedData (int s) + : EncodedData (s) { - delete[] _data; + } diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 57e7e6203..f5ffa467e 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -39,15 +39,11 @@ class Subtitle; class EncodedData { public: - /** @param d Data (will not be freed by this class, but may be by subclasses) - * @param s Size of data, in bytes. + /** @param s Size of data, in bytes. */ - EncodedData (uint8_t* d, int s) - : _data (d) - , _size (s) - {} + EncodedData (int s); - virtual ~EncodedData () {} + virtual ~EncodedData (); void send (boost::shared_ptr socket); void write (boost::shared_ptr, SourceFrame); @@ -65,6 +61,10 @@ public: protected: uint8_t* _data; ///< data int _size; ///< data size in bytes + +private: + /* No copy construction */ + EncodedData (EncodedData const &); }; /** @class LocallyEncodedData @@ -75,12 +75,10 @@ protected: class LocallyEncodedData : public EncodedData { public: - /** @param d Data (which will not be freed by this class) + /** @param d Data (which will be copied by this class) * @param s Size of data, in bytes. */ - LocallyEncodedData (uint8_t* d, int s) - : EncodedData (d, s) - {} + LocallyEncodedData (uint8_t* d, int s); }; /** @class RemotelyEncodedData @@ -91,7 +89,6 @@ class RemotelyEncodedData : public EncodedData { public: RemotelyEncodedData (int s); - ~RemotelyEncodedData (); }; /** @class DCPVideoFrame diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 93a364fed..f6d0cc40e 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -536,7 +536,7 @@ Encoder::encoder_thread (ServerDescription* server) } if (encoded) { - boost::mutex::scoped_lock lock (_writer_mutex); + boost::mutex::scoped_lock lock2 (_writer_mutex); _write_queue.push_back (make_pair (encoded, vf->frame ())); _writer_condition.notify_all (); } else { -- cgit v1.2.3 From 7b81eb3b0b4e173404c30d754796c7339034c3c5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 11 Jan 2013 19:29:03 +0000 Subject: Add writer thread timing. --- src/lib/encoder.cc | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index f6d0cc40e..ef8866897 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -577,10 +577,12 @@ Encoder::writer_thread () { while (1) { + TIMING ("writer sleeps"); boost::mutex::scoped_lock lock (_writer_mutex); while (_write_queue.empty() && !_terminate_writer) { _writer_condition.wait (lock); } + TIMING ("writer wakes with a queue of %1", _write_queue.size()); if (_terminate_writer) { return; -- cgit v1.2.3 From 72494dd766159e9bdac5d80479b43eb1b3ca15b2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 11 Jan 2013 19:30:44 +0000 Subject: Make the previous compile. --- src/lib/encoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index ef8866897..731a39042 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -577,8 +577,8 @@ Encoder::writer_thread () { while (1) { - TIMING ("writer sleeps"); boost::mutex::scoped_lock lock (_writer_mutex); + TIMING ("writer sleeps with a queue of %1", _write_queue.size()); while (_write_queue.empty() && !_terminate_writer) { _writer_condition.wait (lock); } -- cgit v1.2.3 From c7292767fe4935da750423461a41224b3e0a8e37 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 16 Jan 2013 21:45:41 +0000 Subject: Give DCPFrameRate a constructor. Add repeat member and cleverer dcp frame rate calculations. --- src/lib/check_hashes_job.cc | 6 +++-- src/lib/dcp_video_frame.cc | 6 ++--- src/lib/encoder.cc | 2 +- src/lib/film.cc | 13 +++++---- src/lib/make_dcp_job.cc | 11 +++++--- src/lib/options.h | 8 +++--- src/lib/util.cc | 66 ++++++++++++++++++++++++++++++++------------- src/lib/util.h | 19 ++++++++----- 8 files changed, 88 insertions(+), 43 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc index 701584c74..6f6591396 100644 --- a/src/lib/check_hashes_job.cc +++ b/src/lib/check_hashes_job.cc @@ -59,9 +59,11 @@ CheckHashesJob::run () } SourceFrame const N = _film->dcp_trim_start() + _film->dcp_length().get(); - DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ()); + DCPFrameRate const dfr (_film->frames_per_second ()); + + int const inc = dfr.skip ? 2 : 1; - for (SourceFrame i = _film->dcp_trim_start(); i < N; i += dfr.skip) { + for (SourceFrame i = _film->dcp_trim_start(); i < N; i += inc) { string const j2k_file = _encode_opt->frame_out_path (i, false); string const hash_file = _encode_opt->hash_out_path (i, false); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index c6b29ba41..f6fb8fe2e 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -66,8 +66,8 @@ using boost::shared_ptr; * @param out Required size of output, in pixels (including any padding). * @param s Scaler to use. * @param p Number of pixels of padding either side of the image. - * @param f Index of the frame within the Film. - * @param fps Frames per second of the Film. + * @param f Index of the frame within the Film's source. + * @param fps Frames per second of the Film's source. * @param pp FFmpeg post-processing string to use. * @param clut Colour look-up table to use (see Config::colour_lut_index ()) * @param bw J2K bandwidth to use (see Config::j2k_bandwidth ()) @@ -86,7 +86,7 @@ DCPVideoFrame::DCPVideoFrame ( , _subtitle_scale (subtitle_scale) , _scaler (s) , _frame (f) - , _frames_per_second (dcp_frame_rate(fps).frames_per_second) + , _frames_per_second (DCPFrameRate(fps).frames_per_second) , _post_process (pp) , _colour_lut (clut) , _j2k_bandwidth (bw) diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index efedfcfef..afa636150 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -279,7 +279,7 @@ Encoder::frame_skipped () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - if (_opt->video_skip != 0 && (_video_frame % _opt->video_skip) != 0) { + if (_opt->video_skip && (_video_frame % 2)) { ++_video_frame; return; } diff --git a/src/lib/film.cc b/src/lib/film.cc index f0441c9e0..17e14e544 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -294,25 +294,26 @@ Film::make_dcp (bool transcode) if (dcp_length ()) { oe->video_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get()); if (audio_stream()) { + DCPFrameRate dfr (frames_per_second ()); oe->audio_range = make_pair ( video_frames_to_audio_frames ( oe->video_range.get().first, dcp_audio_sample_rate (audio_stream()->sample_rate()), - dcp_frame_rate (frames_per_second()).frames_per_second + dfr.frames_per_second ), video_frames_to_audio_frames ( oe->video_range.get().second, dcp_audio_sample_rate (audio_stream()->sample_rate()), - dcp_frame_rate (frames_per_second()).frames_per_second + dfr.frames_per_second ) ); } } - oe->video_skip = dcp_frame_rate (frames_per_second()).skip; + oe->video_skip = DCPFrameRate (frames_per_second()).skip; shared_ptr od (new DecodeOptions); od->decode_subtitles = with_subtitles (); @@ -704,13 +705,15 @@ Film::target_audio_sample_rate () const /* Resample to a DCI-approved sample rate */ double t = dcp_audio_sample_rate (audio_stream()->sample_rate()); - DCPFrameRate dfr = dcp_frame_rate (frames_per_second ()); + DCPFrameRate dfr (frames_per_second ()); /* Compensate for the fact that video will be rounded to the nearest integer number of frames per second. */ + + int const mult = dfr.skip ? 2 : 1; if (dfr.run_fast) { - t *= _frames_per_second * dfr.skip / dfr.frames_per_second; + t *= _frames_per_second * mult / dfr.frames_per_second; } return rint (t); diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index b9f0cacf3..67a2d8b13 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -61,7 +61,9 @@ MakeDCPJob::name () const string MakeDCPJob::j2c_path (int f, int offset) const { - SourceFrame const s = ((f + offset) * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start(); + DCPFrameRate dfr (_film->frames_per_second()); + int const mult = dfr.skip ? 2 : 1; + SourceFrame const s = ((f + offset) * mult) + _film->dcp_trim_start(); return _opt->frame_out_path (s, false); } @@ -85,13 +87,16 @@ MakeDCPJob::run () /* Remove any old DCP */ boost::filesystem::remove_all (dcp_path); - DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ()); + DCPFrameRate const dfr (_film->frames_per_second ()); int frames = 0; switch (_film->content_type ()) { case VIDEO: /* Source frames -> DCP frames */ - frames = _film->dcp_length().get() / dfr.skip; + frames = _film->dcp_length().get(); + if (dfr.skip) { + frames /= 2; + } break; case STILL: frames = _film->still_duration() * 24; diff --git a/src/lib/options.h b/src/lib/options.h index 55b066a2d..d1fc1d54e 100644 --- a/src/lib/options.h +++ b/src/lib/options.h @@ -39,7 +39,7 @@ public: EncodeOptions (std::string f, std::string e, std::string m) : padding (0) - , video_skip (0) + , video_skip (false) , _frame_out_path (f) , _frame_out_extension (e) , _multichannel_audio_out_path (m) @@ -98,10 +98,8 @@ public: /** Range of audio frames to decode (in the DCP's sampling rate) */ boost::optional > audio_range; - /** Skip frames such that we don't decode any frame where (index % decode_video_skip) != 0; e.g. - * 1 for every frame, 2 for every other frame, etc. - */ - SourceFrame video_skip; + /** true to skip every other frame */ + SourceFrame video_skip; private: /** Path of the directory to write video frames to */ diff --git a/src/lib/util.cc b/src/lib/util.cc index 0fced638c..4228ce6cf 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -330,25 +330,55 @@ md5_digest (string file) return s.str (); } -/** @param fps Arbitrary frames-per-second value. - * @return DCPFrameRate for this frames-per-second. - */ -DCPFrameRate -dcp_frame_rate (float fps) -{ - DCPFrameRate dfr; - - dfr.run_fast = (fps != rint (fps)); - dfr.frames_per_second = rint (fps); - dfr.skip = 1; - - /* XXX: somewhat arbitrary */ - if (fps == 50) { - dfr.frames_per_second = 25; - dfr.skip = 2; +static bool about_equal (float a, float b) +{ + /* A film of F seconds at f FPS will be Ff frames; + Consider some delta FPS d, so if we run the same + film at (f + d) FPS it will last F(f + d) seconds. + + Hence the difference in length over the length of the film will + be F(f + d) - Ff frames + = Ff + Fd - Ff frames + = Fd frames + = Fd/f seconds + + So if we accept a difference of 1 frame, ie 1/f seconds, we can + say that + + 1/f = Fd/f + ie 1 = Fd + ie d = 1/F + + So for a 3hr film, ie F = 3 * 60 * 60 = 10800, the acceptable + FPS error is 1/F ~= 0.0001 ~= 10-e4 + */ + + return (fabs (a - b) < 1e-4); +} + +/** @param fps Arbitrary source frames-per-second value */ +DCPFrameRate::DCPFrameRate (float fps) + : frames_per_second (rint (fps)) + , skip (false) + , repeat (false) + , run_fast (false) +{ + if (about_equal (fps, 50)) { + /* XXX: not sure about this; just run at 50? + Ring Peter Jackson. + */ + frames_per_second = 25; + skip = true; + } else if (fps >= (27.5 / 2) && fps <= (32.5 / 2)) { + frames_per_second = 30; + repeat = true; + } else if (fps >= (24.5 / 2) && fps <= (27.5 / 2)) { + frames_per_second = 25; + repeat = true; + } else if (fps >= (20 / 2) && fps <= (24.5 / 2)) { + frames_per_second = 24; + repeat = true; } - - return dfr; } /** @param An arbitrary sampling rate. diff --git a/src/lib/util.h b/src/lib/util.h index 024c40fb5..50e7410d6 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -61,14 +61,22 @@ typedef int SourceFrame; struct DCPFrameRate { + DCPFrameRate (float); + /** frames per second for the DCP */ int frames_per_second; - /** Skip every `skip' frames. e.g. if this is 1, we skip nothing; - * if it's 2, we skip every other frame. - */ - int skip; + /** true to skip every other frame */ + bool skip; + /** true to repeat every frame once */ + bool repeat; /** true if this DCP will run its video faster than the source - * (e.g. if the source is 29.97fps and we will run the DCP at 30fps) + * without taking into account `skip' and `repeat'. + * (i.e. run_fast will be true if + * source is 29.97fps, DCP is 30fps + * source is 14.50fps, DCP is 30fps + * but not if + * source is 15.00fps, DCP is 30fps + * source is 12.50fps, DCP is 25fps) */ bool run_fast; }; @@ -183,7 +191,6 @@ struct Rect extern std::string crop_string (Position, Size); extern int dcp_audio_sample_rate (int); -extern DCPFrameRate dcp_frame_rate (float); extern int dcp_audio_channels (int); extern std::string colour_lut_index_to_name (int index); extern int stride_round_up (int, int const *, int); -- cgit v1.2.3 From f35b2a637ba82e39eb81e030c2e112185349cac5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 00:10:12 +0000 Subject: EncodeOptions can go. --- src/lib/ab_transcode_job.cc | 5 +- src/lib/ab_transcode_job.h | 3 -- src/lib/check_hashes_job.cc | 13 +++--- src/lib/check_hashes_job.h | 3 -- src/lib/dcp_video_frame.cc | 8 ++-- src/lib/dcp_video_frame.h | 4 +- src/lib/encoder.cc | 39 +++++++++------- src/lib/encoder.h | 5 +- src/lib/film.cc | 111 +++++++++++++++++++++++++++++++------------- src/lib/film.h | 6 +++ src/lib/make_dcp_job.cc | 12 ++--- src/lib/make_dcp_job.h | 6 +-- src/lib/options.h | 84 --------------------------------- src/lib/transcode_job.cc | 5 +- src/lib/transcode_job.h | 4 +- src/lib/transcoder.h | 1 - 16 files changed, 132 insertions(+), 177 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index a6233c185..2dd8f95ad 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -32,10 +32,9 @@ using boost::shared_ptr; /** @param f Film to compare. * @param o Options. */ -ABTranscodeJob::ABTranscodeJob (shared_ptr f, shared_ptr od, shared_ptr oe, shared_ptr req) +ABTranscodeJob::ABTranscodeJob (shared_ptr f, shared_ptr od, shared_ptr req) : Job (f, req) , _decode_opt (od) - , _encode_opt (oe) { _film_b.reset (new Film (*_film)); _film_b->set_scaler (Config::instance()->reference_scaler ()); @@ -53,7 +52,7 @@ ABTranscodeJob::run () { try { /* _film_b is the one with reference filters */ - ABTranscoder w (_film_b, _film, _decode_opt, this, shared_ptr (new Encoder (_film, _encode_opt))); + ABTranscoder w (_film_b, _film, _decode_opt, this, shared_ptr (new Encoder (_film))); w.go (); set_progress (1); set_state (FINISHED_OK); diff --git a/src/lib/ab_transcode_job.h b/src/lib/ab_transcode_job.h index 86a2a81b8..69c157651 100644 --- a/src/lib/ab_transcode_job.h +++ b/src/lib/ab_transcode_job.h @@ -26,7 +26,6 @@ class Film; class DecodeOptions; -class EncodeOptions; /** @class ABTranscodeJob * @brief Job to run a transcoder which produces output for A/B comparison of various settings. @@ -41,7 +40,6 @@ public: ABTranscodeJob ( boost::shared_ptr f, boost::shared_ptr od, - boost::shared_ptr oe, boost::shared_ptr req ); @@ -50,7 +48,6 @@ public: private: boost::shared_ptr _decode_opt; - boost::shared_ptr _encode_opt; /** Copy of our Film using the reference filters and scaler */ boost::shared_ptr _film_b; diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc index 6f6591396..099845d8c 100644 --- a/src/lib/check_hashes_job.cc +++ b/src/lib/check_hashes_job.cc @@ -34,10 +34,9 @@ using std::stringstream; using std::ifstream; using boost::shared_ptr; -CheckHashesJob::CheckHashesJob (shared_ptr f, shared_ptr od, shared_ptr oe, shared_ptr req) +CheckHashesJob::CheckHashesJob (shared_ptr f, shared_ptr od, shared_ptr req) : Job (f, req) , _decode_opt (od) - , _encode_opt (oe) , _bad (0) { @@ -64,8 +63,8 @@ CheckHashesJob::run () int const inc = dfr.skip ? 2 : 1; for (SourceFrame i = _film->dcp_trim_start(); i < N; i += inc) { - string const j2k_file = _encode_opt->frame_out_path (i, false); - string const hash_file = _encode_opt->hash_out_path (i, false); + string const j2k_file = _film->frame_out_path (i, false); + string const hash_file = _film->hash_out_path (i, false); if (!boost::filesystem::exists (j2k_file)) { _film->log()->log (String::compose ("Frame %1 has a missing J2K file.", i)); @@ -94,13 +93,13 @@ CheckHashesJob::run () shared_ptr tc; if (_film->dcp_ab()) { - tc.reset (new ABTranscodeJob (_film, _decode_opt, _encode_opt, shared_from_this())); + tc.reset (new ABTranscodeJob (_film, _decode_opt, shared_from_this())); } else { - tc.reset (new TranscodeJob (_film, _decode_opt, _encode_opt, shared_from_this())); + tc.reset (new TranscodeJob (_film, _decode_opt, shared_from_this())); } JobManager::instance()->add_after (shared_from_this(), tc); - JobManager::instance()->add_after (tc, shared_ptr (new CheckHashesJob (_film, _decode_opt, _encode_opt, tc))); + JobManager::instance()->add_after (tc, shared_ptr (new CheckHashesJob (_film, _decode_opt, tc))); } set_progress (1); diff --git a/src/lib/check_hashes_job.h b/src/lib/check_hashes_job.h index c41af9d3f..7e62b0e7a 100644 --- a/src/lib/check_hashes_job.h +++ b/src/lib/check_hashes_job.h @@ -20,7 +20,6 @@ #include "job.h" class DecodeOptions; -class EncodeOptions; class CheckHashesJob : public Job { @@ -28,7 +27,6 @@ public: CheckHashesJob ( boost::shared_ptr f, boost::shared_ptr od, - boost::shared_ptr oe, boost::shared_ptr req ); @@ -38,6 +36,5 @@ public: private: boost::shared_ptr _decode_opt; - boost::shared_ptr _encode_opt; int _bad; }; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index f6fb8fe2e..c00ed9b88 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -376,9 +376,9 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) * @param frame Frame index. */ void -EncodedData::write (shared_ptr opt, SourceFrame frame) +EncodedData::write (shared_ptr film, SourceFrame frame) { - string const tmp_j2k = opt->frame_out_path (frame, true); + string const tmp_j2k = film->frame_out_path (frame, true); FILE* f = fopen (tmp_j2k.c_str (), "wb"); @@ -389,13 +389,13 @@ EncodedData::write (shared_ptr opt, SourceFrame frame) fwrite (_data, 1, _size, f); fclose (f); - string const real_j2k = opt->frame_out_path (frame, false); + string const real_j2k = film->frame_out_path (frame, false); /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */ boost::filesystem::rename (tmp_j2k, real_j2k); /* Write a file containing the hash */ - string const hash = opt->hash_out_path (frame, false); + string const hash = film->hash_out_path (frame, false); ofstream h (hash.c_str()); h << md5_digest (_data, _size) << "\n"; h.close (); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 134720da8..1b75cb207 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -26,7 +26,7 @@ */ class FilmState; -class EncodeOptions; +class Film; class ServerDescription; class Scaler; class Image; @@ -50,7 +50,7 @@ public: virtual ~EncodedData () {} void send (boost::shared_ptr socket); - void write (boost::shared_ptr, SourceFrame); + void write (boost::shared_ptr, SourceFrame); /** @return data */ uint8_t* data () const { diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index afa636150..35b43e334 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -34,6 +34,7 @@ #include "config.h" #include "dcp_video_frame.h" #include "server.h" +#include "format.h" #include "cross.h" using std::pair; @@ -50,9 +51,8 @@ int const Encoder::_history_size = 25; /** @param f Film that we are encoding. * @param o Options. */ -Encoder::Encoder (shared_ptr f, shared_ptr o) +Encoder::Encoder (shared_ptr f) : _film (f) - , _opt (o) , _just_skipped (false) , _video_frame (0) , _audio_frame (0) @@ -72,9 +72,9 @@ Encoder::Encoder (shared_ptr f, shared_ptr o) /* We write mono files */ sf_info.channels = 1; sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24; - SNDFILE* f = sf_open (_opt->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info); + SNDFILE* f = sf_open (_film->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info); if (f == 0) { - throw CreateFileError (_opt->multichannel_audio_out_path (i, true)); + throw CreateFileError (_film->multichannel_audio_out_path (i, true)); } _sound_files.push_back (f); } @@ -165,10 +165,10 @@ Encoder::process_end () /* Rename .wav.tmp files to .wav */ for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) { - if (boost::filesystem::exists (_opt->multichannel_audio_out_path (i, false))) { - boost::filesystem::remove (_opt->multichannel_audio_out_path (i, false)); + if (boost::filesystem::exists (_film->multichannel_audio_out_path (i, false))) { + boost::filesystem::remove (_film->multichannel_audio_out_path (i, false)); } - boost::filesystem::rename (_opt->multichannel_audio_out_path (i, true), _opt->multichannel_audio_out_path (i, false)); + boost::filesystem::rename (_film->multichannel_audio_out_path (i, true), _film->multichannel_audio_out_path (i, false)); } } @@ -202,7 +202,7 @@ Encoder::process_end () _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); try { shared_ptr e = (*i)->encode_locally (); - e->write (_opt, (*i)->frame ()); + e->write (_film, (*i)->frame ()); frame_done (); } catch (std::exception& e) { _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); @@ -211,8 +211,8 @@ Encoder::process_end () /* Now do links (or copies on windows) to duplicate frames */ for (list >::iterator i = _links_required.begin(); i != _links_required.end(); ++i) { - link (_opt->frame_out_path (i->first, false), _opt->frame_out_path (i->second, false)); - link (_opt->hash_out_path (i->first, false), _opt->hash_out_path (i->second, false)); + link (_film->frame_out_path (i->first, false), _film->frame_out_path (i->second, false)); + link (_film->hash_out_path (i->first, false), _film->hash_out_path (i->second, false)); } } @@ -279,13 +279,15 @@ Encoder::frame_skipped () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - if (_opt->video_skip && (_video_frame % 2)) { + DCPFrameRate dfr (_film->frames_per_second ()); + + if (dfr.skip && (_video_frame % 2)) { ++_video_frame; return; } - if (_opt->video_range) { - pair const r = _opt->video_range.get(); + if (_film->video_range ()) { + pair const r = _film->video_range().get(); if (_video_frame < r.first || _video_frame >= r.second) { ++_video_frame; return; @@ -306,7 +308,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrframe_out_path (_video_frame, false))) { + if (boost::filesystem::exists (_film->frame_out_path (_video_frame, false))) { frame_skipped (); return; } @@ -323,7 +325,8 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr ( new DCPVideoFrame ( - image, sub, _opt->out_size, _opt->padding, _film->subtitle_offset(), _film->subtitle_scale(), + image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), + _film->subtitle_offset(), _film->subtitle_scale(), _film->scaler(), _video_frame, _film->frames_per_second(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), _film->log() @@ -340,11 +343,11 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr data) { - if (_opt->audio_range) { + if (_film->audio_range ()) { shared_ptr trimmed (new AudioBuffers (*data.get ())); /* Range that we are encoding */ - pair required_range = _opt->audio_range.get(); + pair required_range = _film->audio_range().get(); /* Range of this block of data */ pair this_range (_audio_frame, _audio_frame + trimmed->frames()); @@ -508,7 +511,7 @@ Encoder::encoder_thread (ServerDescription* server) } if (encoded) { - encoded->write (_opt, vf->frame ()); + encoded->write (_film, vf->frame ()); frame_done (); } else { lock.lock (); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index bd38dc6bd..d8edf9b26 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -44,7 +44,6 @@ extern "C" { #include "video_sink.h" #include "audio_sink.h" -class EncodeOptions; class Image; class Subtitle; class AudioBuffers; @@ -62,7 +61,7 @@ class DCPVideoFrame; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f, boost::shared_ptr o); + Encoder (boost::shared_ptr f); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ @@ -99,8 +98,6 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; - /** Options */ - boost::shared_ptr _opt; /** Mutex for _time_history, _just_skipped and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/film.cc b/src/lib/film.cc index 83c60a5f5..4bf6606a9 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -290,33 +290,6 @@ Film::make_dcp (bool transcode) throw MissingSettingError ("name"); } - shared_ptr oe (new EncodeOptions (j2k_dir(), ".j2c", dir ("wavs"))); - oe->out_size = format()->dcp_size (); - oe->padding = format()->dcp_padding (shared_from_this ()); - if (dcp_length ()) { - oe->video_range = make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get()); - if (audio_stream()) { - DCPFrameRate dfr (frames_per_second ()); - oe->audio_range = make_pair ( - - video_frames_to_audio_frames ( - oe->video_range.get().first, - dcp_audio_sample_rate (audio_stream()->sample_rate()), - dfr.frames_per_second - ), - - video_frames_to_audio_frames ( - oe->video_range.get().second, - dcp_audio_sample_rate (audio_stream()->sample_rate()), - dfr.frames_per_second - ) - ); - } - - } - - oe->video_skip = DCPFrameRate (frames_per_second()).skip; - shared_ptr od (new DecodeOptions); od->decode_subtitles = with_subtitles (); @@ -324,14 +297,14 @@ Film::make_dcp (bool transcode) if (transcode) { if (dcp_ab()) { - r = JobManager::instance()->add (shared_ptr (new ABTranscodeJob (shared_from_this(), od, oe, shared_ptr ()))); + r = JobManager::instance()->add (shared_ptr (new ABTranscodeJob (shared_from_this(), od, shared_ptr ()))); } else { - r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this(), od, oe, shared_ptr ()))); + r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this(), od, shared_ptr ()))); } } - r = JobManager::instance()->add (shared_ptr (new CheckHashesJob (shared_from_this(), od, oe, r))); - JobManager::instance()->add (shared_ptr (new MakeDCPJob (shared_from_this(), oe, r))); + r = JobManager::instance()->add (shared_ptr (new CheckHashesJob (shared_from_this(), od, r))); + JobManager::instance()->add (shared_ptr (new MakeDCPJob (shared_from_this(), r))); } /** Start a job to examine our content file */ @@ -1437,3 +1410,79 @@ Film::audio_stream () const return _external_audio_stream; } + +/** @param f Source frame index. + * @param t true to return a temporary file path, otherwise a permanent one. + * @return The path to write this video frame to. + */ +string +Film::frame_out_path (SourceFrame f, bool t) const +{ + stringstream s; + s << j2k_dir() << "/"; + s.width (8); + s << std::setfill('0') << f << ".j2c"; + + if (t) { + s << ".tmp"; + } + + return s.str (); +} + +string +Film::hash_out_path (SourceFrame f, bool t) const +{ + return frame_out_path (f, t) + ".md5"; +} + +/** @param c Audio channel index. + * @param t true to return a temporary file path, otherwise a permanent one. + * @return The path to write this audio file to. + */ +string +Film::multichannel_audio_out_path (int c, bool t) const +{ + stringstream s; + s << dir ("wavs") << "/" << (c + 1) << ".wav"; + if (t) { + s << ".tmp"; + } + + return s.str (); +} + +boost::optional > +Film::video_range () const +{ + if (!dcp_length()) { + return boost::optional > (); + } + + return make_pair (dcp_trim_start(), dcp_trim_start() + dcp_length().get()); +} + +boost::optional > +Film::audio_range () const +{ + boost::optional > vr = video_range (); + if (!vr || !audio_stream()) { + return boost::optional > (); + } + + DCPFrameRate dfr (frames_per_second ()); + return make_pair ( + + video_frames_to_audio_frames ( + vr.get().first, + dcp_audio_sample_rate (audio_stream()->sample_rate()), + dfr.frames_per_second + ), + + video_frames_to_audio_frames ( + vr.get().second, + dcp_audio_sample_rate (audio_stream()->sample_rate()), + dfr.frames_per_second + ) + ); +} diff --git a/src/lib/film.h b/src/lib/film.h index 3485dfaae..6c27af3ab 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -78,6 +78,10 @@ public: std::string file (std::string f) const; std::string dir (std::string d) const; + std::string frame_out_path (SourceFrame f, bool t) const; + std::string hash_out_path (SourceFrame f, bool t) const; + std::string multichannel_audio_out_path (int c, bool t) const; + std::string content_path () const; ContentType content_type () const; @@ -97,6 +101,8 @@ public: } int audio_channels () const; + boost::optional > video_range () const; + boost::optional > audio_range () const; void set_dci_date_today (); diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index 67a2d8b13..efc2f05d5 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -36,6 +36,7 @@ extern "C" { #include "options.h" #include "imagemagick_decoder.h" #include "film.h" +#include "format.h" using std::string; using std::cout; @@ -44,9 +45,8 @@ using boost::shared_ptr; /** @param f Film we are making the DCP for. * @param o Options. */ -MakeDCPJob::MakeDCPJob (shared_ptr f, shared_ptr o, shared_ptr req) +MakeDCPJob::MakeDCPJob (shared_ptr f, shared_ptr req) : Job (f, req) - , _opt (o) { } @@ -64,13 +64,13 @@ MakeDCPJob::j2c_path (int f, int offset) const DCPFrameRate dfr (_film->frames_per_second()); int const mult = dfr.skip ? 2 : 1; SourceFrame const s = ((f + offset) * mult) + _film->dcp_trim_start(); - return _opt->frame_out_path (s, false); + return _film->frame_out_path (s, false); } string MakeDCPJob::wav_path (libdcp::Channel c) const { - return _opt->multichannel_audio_out_path (int (c), false); + return _film->multichannel_audio_out_path (int (c), false); } void @@ -138,8 +138,8 @@ MakeDCPJob::run () &dcp.Progress, dfr.frames_per_second, this_time, - _opt->out_size.width, - _opt->out_size.height + _film->format()->dcp_size().width, + _film->format()->dcp_size().height ) ); diff --git a/src/lib/make_dcp_job.h b/src/lib/make_dcp_job.h index 5e4f78a25..481382248 100644 --- a/src/lib/make_dcp_job.h +++ b/src/lib/make_dcp_job.h @@ -23,15 +23,13 @@ #include "job.h" -class EncodeOptions; - /** @class MakeDCPJob * @brief A job to create DCPs */ class MakeDCPJob : public Job { public: - MakeDCPJob (boost::shared_ptr, boost::shared_ptr, boost::shared_ptr req); + MakeDCPJob (boost::shared_ptr, boost::shared_ptr req); std::string name () const; void run (); @@ -40,7 +38,5 @@ private: void dcp_progress (float); std::string j2c_path (int, int) const; std::string wav_path (libdcp::Channel) const; - - boost::shared_ptr _opt; }; diff --git a/src/lib/options.h b/src/lib/options.h index d1fc1d54e..2f8733507 100644 --- a/src/lib/options.h +++ b/src/lib/options.h @@ -27,90 +27,6 @@ #include #include "util.h" -/** @class EncodeOptions - * @brief EncodeOptions for an encoding operation. - * - * These are settings which may be different, in different circumstances, for - * the same film; ie they are options for a particular operation. - */ -class EncodeOptions -{ -public: - - EncodeOptions (std::string f, std::string e, std::string m) - : padding (0) - , video_skip (false) - , _frame_out_path (f) - , _frame_out_extension (e) - , _multichannel_audio_out_path (m) - {} - - /** @return The path to write video frames to */ - std::string frame_out_path () const { - return _frame_out_path; - } - - /** @param f Source frame index. - * @param t true to return a temporary file path, otherwise a permanent one. - * @return The path to write this video frame to. - */ - std::string frame_out_path (SourceFrame f, bool t) const { - std::stringstream s; - s << _frame_out_path << "/"; - s.width (8); - s << std::setfill('0') << f << _frame_out_extension; - - if (t) { - s << ".tmp"; - } - - return s.str (); - } - - std::string hash_out_path (SourceFrame f, bool t) const { - return frame_out_path (f, t) + ".md5"; - } - - /** @return Path to write multichannel audio data to */ - std::string multichannel_audio_out_path () const { - return _multichannel_audio_out_path; - } - - /** @param c Audio channel index. - * @param t true to return a temporary file path, otherwise a permanent one. - * @return The path to write this audio file to. - */ - std::string multichannel_audio_out_path (int c, bool t) const { - std::stringstream s; - s << _multichannel_audio_out_path << "/" << (c + 1) << ".wav"; - if (t) { - s << ".tmp"; - } - - return s.str (); - } - - Size out_size; ///< size of output images - int padding; ///< number of pixels of padding (in terms of the output size) each side of the image - - /** Range of video frames to encode (in DCP frames) */ - boost::optional > video_range; - /** Range of audio frames to decode (in the DCP's sampling rate) */ - boost::optional > audio_range; - - /** true to skip every other frame */ - SourceFrame video_skip; - -private: - /** Path of the directory to write video frames to */ - std::string _frame_out_path; - /** Extension to use for video frame files (including the leading .) */ - std::string _frame_out_extension; - /** Path of the directory to write audio files to */ - std::string _multichannel_audio_out_path; -}; - - class DecodeOptions { public: diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index dfb9b1071..db5c33641 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -40,10 +40,9 @@ using boost::shared_ptr; * @param o Options. * @param req Job that must be completed before this job is run. */ -TranscodeJob::TranscodeJob (shared_ptr f, shared_ptr od, shared_ptr oe, shared_ptr req) +TranscodeJob::TranscodeJob (shared_ptr f, shared_ptr od, shared_ptr req) : Job (f, req) , _decode_opt (od) - , _encode_opt (oe) { } @@ -62,7 +61,7 @@ TranscodeJob::run () _film->log()->log ("Transcode job starting"); _film->log()->log (String::compose ("Audio delay is %1ms", _film->audio_delay())); - _encoder.reset (new Encoder (_film, _encode_opt)); + _encoder.reset (new Encoder (_film)); Transcoder w (_film, _decode_opt, this, _encoder); w.go (); set_progress (1); diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index 97f655e15..aef190a64 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -26,7 +26,6 @@ class Encoder; class DecodeOptions; -class EncodeOptions; /** @class TranscodeJob * @brief A job which transcodes from one format to another. @@ -34,7 +33,7 @@ class EncodeOptions; class TranscodeJob : public Job { public: - TranscodeJob (boost::shared_ptr f, boost::shared_ptr od, boost::shared_ptr oe, boost::shared_ptr req); + TranscodeJob (boost::shared_ptr f, boost::shared_ptr od, boost::shared_ptr req); std::string name () const; void run (); @@ -45,6 +44,5 @@ protected: private: boost::shared_ptr _decode_opt; - boost::shared_ptr _encode_opt; boost::shared_ptr _encoder; }; diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index b50113742..ef6a438c8 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -36,7 +36,6 @@ class Gain; class VideoDecoder; class AudioDecoder; class DelayLine; -class EncodeOptions; class DecodeOptions; /** @class Transcoder -- cgit v1.2.3 From 3882d34aed9dee417ceed93bf0bf5372b3970ff6 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 20:49:09 +0000 Subject: Basics of doing trim using asset entry point / duration. --- src/lib/encoder.cc | 32 -------------------------------- src/lib/film.cc | 34 ---------------------------------- src/lib/film.h | 2 -- src/lib/make_dcp_job.cc | 7 +++++++ 4 files changed, 7 insertions(+), 68 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 35b43e334..c32d68834 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -286,14 +286,6 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrvideo_range ()) { - pair const r = _film->video_range().get(); - if (_video_frame < r.first || _video_frame >= r.second) { - ++_video_frame; - return; - } - } - boost::mutex::scoped_lock lock (_worker_mutex); /* Wait until the queue has gone down a bit */ @@ -343,30 +335,6 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr data) { - if (_film->audio_range ()) { - shared_ptr trimmed (new AudioBuffers (*data.get ())); - - /* Range that we are encoding */ - pair required_range = _film->audio_range().get(); - /* Range of this block of data */ - pair this_range (_audio_frame, _audio_frame + trimmed->frames()); - - if (this_range.second < required_range.first || required_range.second < this_range.first) { - /* No part of this audio is within the required range */ - return; - } else if (required_range.first >= this_range.first && required_range.first < this_range.second) { - /* Trim start */ - int64_t const shift = required_range.first - this_range.first; - trimmed->move (shift, 0, trimmed->frames() - shift); - trimmed->set_frames (trimmed->frames() - shift); - } else if (required_range.second >= this_range.first && required_range.second < this_range.second) { - /* Trim end */ - trimmed->set_frames (required_range.second - this_range.first); - } - - data = trimmed; - } - #if HAVE_SWRESAMPLE /* Maybe sample-rate convert */ if (_swr_context) { diff --git a/src/lib/film.cc b/src/lib/film.cc index 8fe03184d..2af8d3c14 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -1450,37 +1450,3 @@ Film::multichannel_audio_out_path (int c, bool t) const return s.str (); } -boost::optional > -Film::video_range () const -{ - if (!dcp_length()) { - return boost::optional > (); - } - - return make_pair (trim_start(), trim_start() + dcp_length().get()); -} - -boost::optional > -Film::audio_range () const -{ - boost::optional > vr = video_range (); - if (!vr || !audio_stream()) { - return boost::optional > (); - } - - DCPFrameRate dfr (frames_per_second ()); - return make_pair ( - - video_frames_to_audio_frames ( - vr.get().first, - dcp_audio_sample_rate (audio_stream()->sample_rate()), - dfr.frames_per_second - ), - - video_frames_to_audio_frames ( - vr.get().second, - dcp_audio_sample_rate (audio_stream()->sample_rate()), - dfr.frames_per_second - ) - ); -} diff --git a/src/lib/film.h b/src/lib/film.h index 4cecf663c..b03d84920 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -101,8 +101,6 @@ public: } int audio_channels () const; - boost::optional > video_range () const; - boost::optional > audio_range () const; void set_dci_date_today (); diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index fcb10069d..3603298d9 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -142,6 +142,9 @@ MakeDCPJob::run () _film->format()->dcp_size().height ) ); + + pa->set_entry_point (_film->trim_start ()); + pa->set_duration (_film->duration ()); ascend (); @@ -161,6 +164,10 @@ MakeDCPJob::run () dcp_audio_channels (_film->audio_channels()) ) ); + + sa->set_entry_point (_film->trim_start ()); + sa->set_duration (_film->duration ()); + ascend (); } -- cgit v1.2.3 From 39c65e47432c76a4e34aaea5317bd7362409aed0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 21:30:16 +0000 Subject: Try to tidy up frame indexing; use DCP length obtained from the transcode to make the DCP. --- src/lib/check_hashes_job.cc | 12 ++++-------- src/lib/dcp_video_frame.cc | 9 +++++---- src/lib/dcp_video_frame.h | 12 ++++++------ src/lib/encoder.cc | 39 +++++++++++++++++++++++---------------- src/lib/encoder.h | 12 ++++++++---- src/lib/ffmpeg_decoder.cc | 1 + src/lib/ffmpeg_decoder.h | 2 +- src/lib/film.cc | 40 +++++++++++++++++++++++++--------------- src/lib/film.h | 26 +++++++++++++++++--------- src/lib/filter_graph.cc | 1 + src/lib/filter_graph.h | 6 +++--- src/lib/format.cc | 1 + src/lib/format.h | 10 +++++----- src/lib/image.cc | 1 + src/lib/image.h | 14 +++++++------- src/lib/imagemagick_decoder.cc | 3 ++- src/lib/imagemagick_decoder.h | 2 +- src/lib/make_dcp_job.cc | 32 ++++++++------------------------ src/lib/matcher.h | 2 +- src/lib/server.cc | 1 + src/lib/subtitle.cc | 1 + src/lib/transcode_job.cc | 15 +++++++++++++-- src/lib/util.cc | 11 +---------- src/lib/util.h | 34 ++++------------------------------ src/lib/video_decoder.h | 2 +- src/wx/film_editor.cc | 2 ++ src/wx/film_viewer.cc | 1 + src/wx/properties_dialog.cc | 4 ++-- test/metadata.ref | 1 + test/test.cc | 14 +++++++------- 30 files changed, 154 insertions(+), 157 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc index cf4e86b79..55a744552 100644 --- a/src/lib/check_hashes_job.cc +++ b/src/lib/check_hashes_job.cc @@ -53,16 +53,12 @@ CheckHashesJob::run () { _bad = 0; - if (!_film->dcp_length()) { - throw EncodeError ("cannot check hashes of a DCP with unknown length"); + if (!_film->dcp_intrinsic_duration()) { + throw EncodeError ("cannot check hashes of a DCP with unknown intrinsic duration"); } - SourceFrame const N = _film->trim_start() + _film->dcp_length().get(); - DCPFrameRate const dfr (_film->frames_per_second ()); - - int const inc = dfr.skip ? 2 : 1; - - for (SourceFrame i = _film->trim_start(); i < N; i += inc) { + int const N = _film->dcp_intrinsic_duration().get(); + for (int i = 0; i < N; ++i) { string const j2k_file = _film->frame_out_path (i, false); string const hash_file = _film->hash_out_path (i, false); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index c00ed9b88..427d447ef 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -60,13 +60,14 @@ using std::string; using std::stringstream; using std::ofstream; using boost::shared_ptr; +using libdcp::Size; /** Construct a DCP video frame. * @param input Input image. * @param out Required size of output, in pixels (including any padding). * @param s Scaler to use. * @param p Number of pixels of padding either side of the image. - * @param f Index of the frame within the Film's source. + * @param f Index of the frame within the DCP's intrinsic duration. * @param fps Frames per second of the Film's source. * @param pp FFmpeg post-processing string to use. * @param clut Colour look-up table to use (see Config::colour_lut_index ()) @@ -76,7 +77,7 @@ using boost::shared_ptr; DCPVideoFrame::DCPVideoFrame ( shared_ptr yuv, shared_ptr sub, Size out, int p, int subtitle_offset, float subtitle_scale, - Scaler const * s, SourceFrame f, float fps, string pp, int clut, int bw, Log* l + Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l ) : _input (yuv) , _subtitle (sub) @@ -373,10 +374,10 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) /** Write this data to a J2K file. * @param opt Options. - * @param frame Frame index. + * @param frame DCP Frame index. */ void -EncodedData::write (shared_ptr film, SourceFrame frame) +EncodedData::write (shared_ptr film, int frame) { string const tmp_j2k = film->frame_out_path (frame, true); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 1b75cb207..4271ebb28 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -50,7 +50,7 @@ public: virtual ~EncodedData () {} void send (boost::shared_ptr socket); - void write (boost::shared_ptr, SourceFrame); + void write (boost::shared_ptr, int); /** @return data */ uint8_t* data () const { @@ -107,8 +107,8 @@ class DCPVideoFrame { public: DCPVideoFrame ( - boost::shared_ptr, boost::shared_ptr, Size, - int, int, float, Scaler const *, SourceFrame, float, std::string, int, int, Log * + boost::shared_ptr, boost::shared_ptr, libdcp::Size, + int, int, float, Scaler const *, int, float, std::string, int, int, Log * ); virtual ~DCPVideoFrame (); @@ -116,7 +116,7 @@ public: boost::shared_ptr encode_locally (); boost::shared_ptr encode_remotely (ServerDescription const *); - SourceFrame frame () const { + int frame () const { return _frame; } @@ -125,12 +125,12 @@ private: boost::shared_ptr _input; ///< the input image boost::shared_ptr _subtitle; ///< any subtitle that should be on the image - Size _out_size; ///< the required size of the output, in pixels + libdcp::Size _out_size; ///< the required size of the output, in pixels int _padding; int _subtitle_offset; float _subtitle_scale; Scaler const * _scaler; ///< scaler to use - SourceFrame _frame; ///< frame index within the Film's source + int _frame; ///< frame index within the DCP's intrinsic duration int _frames_per_second; ///< Frames per second that we will use for the DCP (rounded) std::string _post_process; ///< FFmpeg post-processing string to use int _colour_lut; ///< Colour look-up table to use diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c32d68834..6df7c85a1 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -54,12 +54,13 @@ int const Encoder::_history_size = 25; Encoder::Encoder (shared_ptr f) : _film (f) , _just_skipped (false) - , _video_frame (0) - , _audio_frame (0) + , _video_frames_in (0) + , _audio_frames_in (0) + , _video_frames_out (0) + , _audio_frames_out (0) #ifdef HAVE_SWRESAMPLE , _swr_context (0) #endif - , _audio_frames_written (0) , _process_end (false) { if (_film->audio_stream()) { @@ -241,12 +242,12 @@ Encoder::skipping () const return _just_skipped; } -/** @return Number of video frames that have been received */ -SourceFrame -Encoder::video_frame () const +/** @return Number of video frames that have been sent out */ +int +Encoder::video_frames_out () const { boost::mutex::scoped_lock (_history_mutex); - return _video_frame; + return _video_frames_out; } /** Should be called when a frame has been encoded successfully. @@ -281,8 +282,8 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrframes_per_second ()); - if (dfr.skip && (_video_frame % 2)) { - ++_video_frame; + if (dfr.skip && (_video_frames_in % 2)) { + ++_video_frames_in; return; } @@ -300,7 +301,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrframe_out_path (_video_frame, false))) { + if (boost::filesystem::exists (_film->frame_out_path (_video_frames_out, false))) { frame_skipped (); return; } @@ -310,7 +311,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); @@ -319,17 +320,23 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrformat()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), - _film->scaler(), _video_frame, _film->frames_per_second(), s.second, + _film->scaler(), _video_frames_out, _film->frames_per_second(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), _film->log() ) )); _worker_condition.notify_all (); - _last_real_frame = _video_frame; + _last_real_frame = _video_frames_out; } - ++_video_frame; + ++_video_frames_in; + ++_video_frames_out; + + if (dfr.repeat) { + _links_required.push_back (make_pair (_video_frames_out, _video_frames_out - 1)); + ++_video_frames_out; + } } void @@ -378,7 +385,7 @@ Encoder::process_audio (shared_ptr data) write_audio (data); - _audio_frame += data->frames (); + _audio_frames_in += data->frames (); } void @@ -388,7 +395,7 @@ Encoder::write_audio (shared_ptr audio) sf_write_float (_sound_files[i], audio->data(i), audio->frames()); } - _audio_frames_written += audio->frames (); + _audio_frames_out += audio->frames (); } void diff --git a/src/lib/encoder.h b/src/lib/encoder.h index d8edf9b26..20255cca9 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -82,7 +82,7 @@ public: float current_frames_per_second () const; bool skipping () const; - SourceFrame video_frame () const; + int video_frames_out () const; private: @@ -111,9 +111,13 @@ private: bool _just_skipped; /** Number of video frames received so far */ - SourceFrame _video_frame; + SourceFrame _video_frames_in; /** Number of audio frames received so far */ - int64_t _audio_frame; + int64_t _audio_frames_in; + /** Number of video frames written for the DCP so far */ + int _video_frames_out; + /** Number of audio frames written for the DCP so far */ + int64_t _audio_frames_out; #if HAVE_SWRESAMPLE SwrContext* _swr_context; @@ -122,11 +126,11 @@ private: /** List of links that we need to create when all frames have been processed; * such that we need to call link (first, second) for each member of this list. * In other words, `first' is a `real' frame and `second' should be a link to `first'. + * Frames are DCP frames. */ std::list > _links_required; std::vector _sound_files; - int64_t _audio_frames_written; boost::optional _last_real_frame; bool _process_end; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 9e5cda889..e7dfc206b 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -58,6 +58,7 @@ using std::list; using boost::shared_ptr; using boost::optional; using boost::dynamic_pointer_cast; +using libdcp::Size; FFmpegDecoder::FFmpegDecoder (shared_ptr f, DecodeOptions o, Job* j) : Decoder (f, o, j) diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 51b88a24a..9a4e65ebc 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -90,7 +90,7 @@ public: ~FFmpegDecoder (); float frames_per_second () const; - Size native_size () const; + libdcp::Size native_size () const; SourceFrame length () const; int time_base_numerator () const; int time_base_denominator () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index 2af8d3c14..1741d49e6 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -72,6 +72,7 @@ using boost::to_upper_copy; using boost::ends_with; using boost::starts_with; using boost::optional; +using libdcp::Size; int const Film::state_version = 2; @@ -180,6 +181,7 @@ Film::Film (Film const & o) , _package_type (o._package_type) , _size (o._size) , _length (o._length) + , _dcp_intrinsic_duration (o._dcp_intrinsic_duration) , _content_digest (o._content_digest) , _content_audio_streams (o._content_audio_streams) , _external_audio_stream (o._external_audio_stream) @@ -423,6 +425,7 @@ Film::write_metadata () const f << "width " << _size.width << "\n"; f << "height " << _size.height << "\n"; f << "length " << _length.get_value_or(0) << "\n"; + f << "dcp_intrinsic_duration " << _dcp_intrinsic_duration.get_value_or(0) << "\n"; f << "content_digest " << _content_digest << "\n"; for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { @@ -569,6 +572,11 @@ Film::read_metadata () if (vv) { _length = vv; } + } else if (k == "dcp_intrinsic_duration") { + int const vv = atoi (v.c_str ()); + if (vv) { + _dcp_intrinsic_duration = vv; + } } else if (k == "content_digest") { _content_digest = v; } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { @@ -695,18 +703,10 @@ Film::target_audio_sample_rate () const return rint (t); } -boost::optional -Film::dcp_length () const +int +Film::still_duration_in_frames () const { - if (content_type() == STILL) { - return _still_duration * frames_per_second(); - } - - if (!length()) { - return boost::optional (); - } - - return length().get() - trim_start() - trim_end(); + return still_duration() * frames_per_second(); } /** @return a DCI-compliant name for a DCP of this film */ @@ -1327,7 +1327,17 @@ Film::unset_length () _length = boost::none; } signal_changed (LENGTH); -} +} + +void +Film::set_dcp_intrinsic_duration (int d) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _dcp_intrinsic_duration = d; + } + signal_changed (DCP_INTRINSIC_DURATION); +} void Film::set_content_digest (string d) @@ -1409,12 +1419,12 @@ Film::audio_stream () const return _external_audio_stream; } -/** @param f Source frame index. +/** @param f DCP frame index. * @param t true to return a temporary file path, otherwise a permanent one. * @return The path to write this video frame to. */ string -Film::frame_out_path (SourceFrame f, bool t) const +Film::frame_out_path (int f, bool t) const { stringstream s; s << j2k_dir() << "/"; @@ -1429,7 +1439,7 @@ Film::frame_out_path (SourceFrame f, bool t) const } string -Film::hash_out_path (SourceFrame f, bool t) const +Film::hash_out_path (int f, bool t) const { return frame_out_path (f, t) + ".md5"; } diff --git a/src/lib/film.h b/src/lib/film.h index b03d84920..e10abfa4b 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -78,8 +78,8 @@ public: std::string file (std::string f) const; std::string dir (std::string d) const; - std::string frame_out_path (SourceFrame f, bool t) const; - std::string hash_out_path (SourceFrame f, bool t) const; + std::string frame_out_path (int f, bool t) const; + std::string hash_out_path (int f, bool t) const; std::string multichannel_audio_out_path (int c, bool t) const; std::string content_path () const; @@ -90,11 +90,14 @@ public: void write_metadata () const; void read_metadata (); - Size cropped_size (Size) const; - boost::optional dcp_length () const; + libdcp::Size cropped_size (libdcp::Size) const; std::string dci_name () const; std::string dcp_name () const; + boost::optional dcp_intrinsic_duration () const { + return _dcp_intrinsic_duration; + } + /** @return true if our state has changed since we last saved it */ bool dirty () const { return _dirty; @@ -137,6 +140,7 @@ public: DCI_METADATA, SIZE, LENGTH, + DCP_INTRINSIC_DURATION, CONTENT_AUDIO_STREAMS, SUBTITLE_STREAMS, FRAMES_PER_SECOND, @@ -195,12 +199,12 @@ public: return _scaler; } - SourceFrame trim_start () const { + int trim_start () const { boost::mutex::scoped_lock lm (_state_mutex); return _trim_start; } - SourceFrame trim_end () const { + int trim_end () const { boost::mutex::scoped_lock lm (_state_mutex); return _trim_end; } @@ -245,6 +249,8 @@ public: return _still_duration; } + int still_duration_in_frames () const; + boost::shared_ptr subtitle_stream () const { boost::mutex::scoped_lock lm (_state_mutex); return _subtitle_stream; @@ -310,7 +316,7 @@ public: return _package_type; } - Size size () const { + libdcp::Size size () const { boost::mutex::scoped_lock lm (_state_mutex); return _size; } @@ -387,9 +393,10 @@ public: void set_studio (std::string); void set_facility (std::string); void set_package_type (std::string); - void set_size (Size); + void set_size (libdcp::Size); void set_length (SourceFrame); void unset_length (); + void set_dcp_intrinsic_duration (int); void set_content_digest (std::string); void set_content_audio_streams (std::vector >); void set_subtitle_streams (std::vector >); @@ -499,9 +506,10 @@ private: /* Data which are cached to speed things up */ /** Size, in pixels, of the source (ignoring cropping) */ - Size _size; + libdcp::Size _size; /** The length of the source, in video frames (as far as we know) */ boost::optional _length; + boost::optional _dcp_intrinsic_duration; /** MD5 digest of our content file */ std::string _content_digest; /** The audio streams in our content */ diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index 376ab404f..86864a762 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -47,6 +47,7 @@ using std::stringstream; using std::string; using std::list; using boost::shared_ptr; +using libdcp::Size; /** Construct a FilterGraph for the settings in a film. * @param film Film. diff --git a/src/lib/filter_graph.h b/src/lib/filter_graph.h index 9e6ac6252..7e4e8422b 100644 --- a/src/lib/filter_graph.h +++ b/src/lib/filter_graph.h @@ -37,15 +37,15 @@ class FFmpegDecoder; class FilterGraph { public: - FilterGraph (boost::shared_ptr film, FFmpegDecoder* decoder, Size s, AVPixelFormat p); + FilterGraph (boost::shared_ptr film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p); - bool can_process (Size s, AVPixelFormat p) const; + bool can_process (libdcp::Size s, AVPixelFormat p) const; std::list > process (AVFrame const * frame); private: AVFilterContext* _buffer_src_context; AVFilterContext* _buffer_sink_context; - Size _size; ///< size of the images that this chain can process + libdcp::Size _size; ///< size of the images that this chain can process AVPixelFormat _pixel_format; ///< pixel format of the images that this chain can process }; diff --git a/src/lib/format.cc b/src/lib/format.cc index 975862411..a80fab619 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -35,6 +35,7 @@ using std::setprecision; using std::stringstream; using std::vector; using boost::shared_ptr; +using libdcp::Size; vector Format::_formats; diff --git a/src/lib/format.h b/src/lib/format.h index 2118237a4..48a000480 100644 --- a/src/lib/format.h +++ b/src/lib/format.h @@ -31,7 +31,7 @@ class Film; class Format { public: - Format (Size dcp, std::string id, std::string n, std::string d) + Format (libdcp::Size dcp, std::string id, std::string n, std::string d) : _dcp_size (dcp) , _id (id) , _nickname (n) @@ -52,7 +52,7 @@ public: * put in a DCP for this ratio. This size will not correspond * to the ratio when we are doing things like 16:9 in a Flat frame. */ - Size dcp_size () const { + libdcp::Size dcp_size () const { return _dcp_size; } @@ -85,7 +85,7 @@ protected: * put in a DCP for this ratio. This size will not correspond * to the ratio when we are doing things like 16:9 in a Flat frame. */ - Size _dcp_size; + libdcp::Size _dcp_size; /** id for use in metadata */ std::string _id; /** nickname (e.g. Flat, Scope) */ @@ -104,7 +104,7 @@ private: class FixedFormat : public Format { public: - FixedFormat (int, Size, std::string, std::string, std::string); + FixedFormat (int, libdcp::Size, std::string, std::string, std::string); int ratio_as_integer (boost::shared_ptr) const { return _ratio; @@ -125,7 +125,7 @@ private: class VariableFormat : public Format { public: - VariableFormat (Size, std::string, std::string, std::string); + VariableFormat (libdcp::Size, std::string, std::string, std::string); int ratio_as_integer (boost::shared_ptr f) const; float ratio_as_float (boost::shared_ptr f) const; diff --git a/src/lib/image.cc b/src/lib/image.cc index f774f476f..c41558f02 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -42,6 +42,7 @@ extern "C" { using namespace std; using namespace boost; +using libdcp::Size; void Image::swap (Image& other) diff --git a/src/lib/image.h b/src/lib/image.h index e19c6f54b..5ca3f337c 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -66,13 +66,13 @@ public: virtual int * stride () const = 0; /** @return Size of the image, in pixels */ - virtual Size size () const = 0; + virtual libdcp::Size size () const = 0; int components () const; int lines (int) const; - boost::shared_ptr scale_and_convert_to_rgb (Size out_size, int padding, Scaler const * scaler, bool aligned) const; - boost::shared_ptr scale (Size, Scaler const *, bool aligned) const; + boost::shared_ptr scale_and_convert_to_rgb (libdcp::Size out_size, int padding, Scaler const * scaler, bool aligned) const; + boost::shared_ptr scale (libdcp::Size, Scaler const *, bool aligned) const; boost::shared_ptr post_process (std::string, bool aligned) const; void alpha_blend (boost::shared_ptr image, Position pos); boost::shared_ptr crop (Crop c, bool aligned) const; @@ -106,7 +106,7 @@ public: uint8_t ** data () const; int * line_size () const; int * stride () const; - Size size () const; + libdcp::Size size () const; private: /* Not allowed */ @@ -122,7 +122,7 @@ private: class SimpleImage : public Image { public: - SimpleImage (AVPixelFormat, Size, bool); + SimpleImage (AVPixelFormat, libdcp::Size, bool); SimpleImage (SimpleImage const &); SimpleImage& operator= (SimpleImage const &); ~SimpleImage (); @@ -130,14 +130,14 @@ public: uint8_t ** data () const; int * line_size () const; int * stride () const; - Size size () const; + libdcp::Size size () const; protected: void allocate (); void swap (SimpleImage &); private: - Size _size; ///< size in pixels + libdcp::Size _size; ///< size in pixels uint8_t** _data; ///< array of pointers to components int* _line_size; ///< array of sizes of the data in each line, in pixels (without any alignment padding bytes) int* _stride; ///< array of strides for each line (including any alignment padding bytes) diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 063730540..bab4f2f07 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -27,6 +27,7 @@ using std::cout; using boost::shared_ptr; +using libdcp::Size; ImageMagickDecoder::ImageMagickDecoder ( boost::shared_ptr f, DecodeOptions o, Job* j) @@ -70,7 +71,7 @@ bool ImageMagickDecoder::pass () { if (_iter == _files.end()) { - if (!_film->dcp_length() || video_frame() >= _film->dcp_length().get()) { + if (video_frame() >= _film->still_duration_in_frames()) { return true; } diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 5dfcab6f0..84a6f15f9 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -33,7 +33,7 @@ public: return 0; } - Size native_size () const; + libdcp::Size native_size () const; SourceFrame length () const { /* We don't know */ diff --git a/src/lib/make_dcp_job.cc b/src/lib/make_dcp_job.cc index 3603298d9..6877e5e88 100644 --- a/src/lib/make_dcp_job.cc +++ b/src/lib/make_dcp_job.cc @@ -61,10 +61,7 @@ MakeDCPJob::name () const string MakeDCPJob::j2c_path (int f, int offset) const { - DCPFrameRate dfr (_film->frames_per_second()); - int const mult = dfr.skip ? 2 : 1; - SourceFrame const s = ((f + offset) * mult) + _film->trim_start(); - return _film->frame_out_path (s, false); + return _film->frame_out_path (f, false); } string @@ -76,8 +73,8 @@ MakeDCPJob::wav_path (libdcp::Channel c) const void MakeDCPJob::run () { - if (!_film->dcp_length()) { - throw EncodeError ("cannot make a DCP when the source length is not known"); + if (!_film->dcp_intrinsic_duration()) { + throw EncodeError ("cannot make a DCP when its intrinsic duration is not known"); } descend (0.9); @@ -87,22 +84,10 @@ MakeDCPJob::run () /* Remove any old DCP */ boost::filesystem::remove_all (dcp_path); + int const frames = _film->dcp_intrinsic_duration().get(); + int const duration = frames - _film->trim_start() - _film->trim_end(); DCPFrameRate const dfr (_film->frames_per_second ()); - int frames = 0; - switch (_film->content_type ()) { - case VIDEO: - /* Source frames -> DCP frames */ - frames = _film->dcp_length().get(); - if (dfr.skip) { - frames /= 2; - } - break; - case STILL: - frames = _film->still_duration() * 24; - break; - } - libdcp::DCP dcp (_film->dir (_film->dcp_name())); dcp.Progress.connect (boost::bind (&MakeDCPJob::dcp_progress, this, _1)); @@ -138,13 +123,12 @@ MakeDCPJob::run () &dcp.Progress, dfr.frames_per_second, this_time, - _film->format()->dcp_size().width, - _film->format()->dcp_size().height + _film->format()->dcp_size() ) ); pa->set_entry_point (_film->trim_start ()); - pa->set_duration (_film->duration ()); + pa->set_duration (duration); ascend (); @@ -166,7 +150,7 @@ MakeDCPJob::run () ); sa->set_entry_point (_film->trim_start ()); - sa->set_duration (_film->duration ()); + sa->set_duration (duration); ascend (); } diff --git a/src/lib/matcher.h b/src/lib/matcher.h index b94c28446..60bb87432 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -35,6 +35,6 @@ private: int _video_frames; int64_t _audio_frames; boost::optional _pixel_format; - boost::optional _size; + boost::optional _size; boost::optional _channels; }; diff --git a/src/lib/server.cc b/src/lib/server.cc index bea75cff8..134cb65a0 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -45,6 +45,7 @@ using boost::algorithm::is_any_of; using boost::algorithm::split; using boost::thread; using boost::bind; +using libdcp::Size; /** Create a server description from a string of metadata returned from as_metadata(). * @param v Metadata. diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index c52d3ac66..a7aa7cd21 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -27,6 +27,7 @@ using namespace std; using namespace boost; +using libdcp::Size; /** Construct a TimedSubtitle. This is a subtitle image, position, * and a range of time over which it should be shown. diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index c9792ed2e..6dd74c36c 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -67,7 +67,10 @@ TranscodeJob::run () set_progress (1); set_state (FINISHED_OK); + _film->set_dcp_intrinsic_duration (_encoder->video_frames_out ()); + _film->log()->log ("Transcode job completed successfully"); + _film->log()->log (String::compose ("DCP intrinsic duration is %1", _encoder->video_frames_out())); } catch (std::exception& e) { @@ -115,11 +118,19 @@ TranscodeJob::remaining_time () const return 0; } - if (!_film->dcp_length()) { + if (!_film->length()) { return 0; } + /* Compute approximate proposed length here, as it's only here that we need it */ + int length = _film->length().get(); + DCPFrameRate const dfr (_film->frames_per_second ()); + if (dfr.skip) { + length /= 2; + } + /* If we are repeating it shouldn't affect transcode time, so don't take it into account */ + /* We assume that dcp_length() is valid, if it is set */ - SourceFrame const left = _film->trim_start() + _film->dcp_length().get() - _encoder->video_frame(); + int const left = length - _encoder->video_frames_out(); return left / fps; } diff --git a/src/lib/util.cc b/src/lib/util.cc index b500ddc2f..0e250bb08 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -63,6 +63,7 @@ extern "C" { using namespace std; using namespace boost; +using libdcp::Size; thread::id ui_thread; @@ -455,16 +456,6 @@ dcp_audio_channels (int f) } -bool operator== (Size const & a, Size const & b) -{ - return (a.width == b.width && a.height == b.height); -} - -bool operator!= (Size const & a, Size const & b) -{ - return !(a == b); -} - bool operator== (Crop const & a, Crop const & b) { return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); diff --git a/src/lib/util.h b/src/lib/util.h index 1fd2c0150..c4940a5d7 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -29,6 +29,7 @@ #include #include #include +#include extern "C" { #include #include @@ -99,33 +100,6 @@ enum ContentType { VIDEO ///< content is a video }; -/** @class Size - * @brief Representation of the size of something */ -struct Size -{ - /** Construct a zero Size */ - Size () - : width (0) - , height (0) - {} - - /** @param w Width. - * @param h Height. - */ - Size (int w, int h) - : width (w) - , height (h) - {} - - /** width */ - int width; - /** height */ - int height; -}; - -extern bool operator== (Size const & a, Size const & b); -extern bool operator!= (Size const & a, Size const & b); - /** @struct Crop * @brief A description of the crop of an image or video. */ @@ -195,14 +169,14 @@ struct Rect return Position (x, y); } - Size size () const { - return Size (width, height); + libdcp::Size size () const { + return libdcp::Size (width, height); } Rect intersection (Rect const & other) const; }; -extern std::string crop_string (Position, Size); +extern std::string crop_string (Position, libdcp::Size); extern int dcp_audio_sample_rate (int); extern int dcp_audio_channels (int); extern std::string colour_lut_index_to_name (int index); diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index c0eab2140..ef1ab041a 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -32,7 +32,7 @@ public: /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; /** @return native size in pixels */ - virtual Size native_size () const = 0; + virtual libdcp::Size native_size () const = 0; /** @return length (in source video frames), according to our content's header */ virtual SourceFrame length () const = 0; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index f83518b88..bbaeb17c4 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -665,6 +665,8 @@ FilmEditor::film_changed (Film::Property p) _trim_end->SetRange (0, _film->length().get()); } break; + case Film::DCP_INTRINSIC_DURATION: + break; case Film::DCP_CONTENT_TYPE: checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ())); _dcp_name->SetLabel (std_to_wx (_film->dcp_name ())); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 347531cc2..e5da41d5e 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -44,6 +44,7 @@ using std::max; using std::cout; using std::list; using boost::shared_ptr; +using libdcp::Size; FilmViewer::FilmViewer (shared_ptr f, wxWindow* p) : wxPanel (p) diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index c34922ec4..0cf75cf51 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -91,9 +91,9 @@ PropertiesDialog::frames_already_encoded () const return ""; } - if (_film->dcp_length()) { + if (_film->length()) { /* XXX: encoded_frames() should check which frames have been encoded */ - u << " (" << ((_film->encoded_frames() - _film->trim_start()) * 100 / _film->dcp_length().get()) << "%)"; + u << " (" << (_film->encoded_frames() * 100 / _film->length().get()) << "%)"; } return u.str (); } diff --git a/test/metadata.ref b/test/metadata.ref index 90255e916..ff0c25118 100644 --- a/test/metadata.ref +++ b/test/metadata.ref @@ -34,6 +34,7 @@ package_type width 0 height 0 length 0 +dcp_intrinsic_duration 0 content_digest external_audio_stream external 0 0 frames_per_second 0 diff --git a/test/test.cc b/test/test.cc index 9143b87d5..7e1d92e06 100644 --- a/test/test.cc +++ b/test/test.cc @@ -325,7 +325,7 @@ do_remote_encode (shared_ptr frame, ServerDescription* descriptio BOOST_AUTO_TEST_CASE (client_server_test) { - shared_ptr image (new SimpleImage (PIX_FMT_RGB24, Size (1998, 1080), false)); + shared_ptr image (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (1998, 1080), false)); uint8_t* p = image->data()[0]; for (int y = 0; y < 1080; ++y) { @@ -336,7 +336,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) } } - shared_ptr sub_image (new SimpleImage (PIX_FMT_RGBA, Size (100, 200), false)); + shared_ptr sub_image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (100, 200), false)); p = sub_image->data()[0]; for (int y = 0; y < 200; ++y) { for (int x = 0; x < 100; ++x) { @@ -355,7 +355,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) new DCPVideoFrame ( image, subtitle, - Size (1998, 1080), + libdcp::Size (1998, 1080), 0, 0, 1, @@ -636,7 +636,7 @@ BOOST_AUTO_TEST_CASE (job_manager_test) BOOST_AUTO_TEST_CASE (compact_image_test) { - SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, Size (50, 50), false); + SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, libdcp::Size (50, 50), false); BOOST_CHECK_EQUAL (s->components(), 1); BOOST_CHECK_EQUAL (s->stride()[0], 50 * 3); BOOST_CHECK_EQUAL (s->line_size()[0], 50 * 3); @@ -662,7 +662,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_CHECK (t->stride()[0] == s->stride()[0]); /* assignment operator */ - SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, Size (150, 150), true); + SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, libdcp::Size (150, 150), true); *u = *s; BOOST_CHECK_EQUAL (u->components(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 50 * 3); @@ -685,7 +685,7 @@ BOOST_AUTO_TEST_CASE (compact_image_test) BOOST_AUTO_TEST_CASE (aligned_image_test) { - SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, Size (50, 50), true); + SimpleImage* s = new SimpleImage (PIX_FMT_RGB24, libdcp::Size (50, 50), true); BOOST_CHECK_EQUAL (s->components(), 1); /* 160 is 150 aligned to the nearest 32 bytes */ BOOST_CHECK_EQUAL (s->stride()[0], 160); @@ -712,7 +712,7 @@ BOOST_AUTO_TEST_CASE (aligned_image_test) BOOST_CHECK (t->stride()[0] == s->stride()[0]); /* assignment operator */ - SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, Size (150, 150), false); + SimpleImage* u = new SimpleImage (PIX_FMT_YUV422P, libdcp::Size (150, 150), false); *u = *s; BOOST_CHECK_EQUAL (u->components(), 1); BOOST_CHECK_EQUAL (u->stride()[0], 160); -- cgit v1.2.3 From cadd50fe2609a1ad9963389d65d8e91f85226752 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 23:42:59 +0000 Subject: Sort of works to a first-order approximation. --- src/lib/dcp_video_frame.cc | 15 +++++ src/lib/dcp_video_frame.h | 2 + src/lib/encoder.cc | 148 ++++++++++++++++++++++++++++++++++----------- src/lib/encoder.h | 25 +++++--- 4 files changed, 146 insertions(+), 44 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 1c408270e..da864ad9f 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -380,6 +380,21 @@ EncodedData::EncodedData (int s) } +EncodedData::EncodedData (string file) +{ + _size = boost::filesystem::file_size (file); + _data = new uint8_t[_size]; + + FILE* f = fopen (file.c_str(), "rb"); + if (!f) { + throw FileError ("could not open file for reading", file); + } + + fread (_data, 1, _size, f); + fclose (f); +} + + EncodedData::~EncodedData () { delete[] _data; diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index e311724d8..b446352c7 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -43,6 +43,8 @@ public: */ EncodedData (int s); + EncodedData (std::string f); + virtual ~EncodedData (); void send (boost::shared_ptr socket); diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0f48310ef..c6960d0d1 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -24,6 +24,7 @@ #include #include #include +#include #include "encoder.h" #include "util.h" #include "options.h" @@ -47,6 +48,7 @@ using std::make_pair; using namespace boost; int const Encoder::_history_size = 25; +unsigned int const Encoder::_maximum_frames_in_memory = 8; /** @param f Film that we are encoding. * @param o Options. @@ -60,10 +62,12 @@ Encoder::Encoder (shared_ptr f) , _audio_frames_out (0) #ifdef HAVE_SWRESAMPLE , _swr_context (0) -#endif +#endif + , _have_a_real_frame (false) , _terminate_encoder (false) , _writer_thread (0) - , _terminate_writer (false) + , _finish_writer (false) + , _last_written_frame (-1) { if (_film->audio_stream()) { /* Create sound output files with .tmp suffixes; we will rename @@ -88,7 +92,7 @@ Encoder::~Encoder () { close_sound_files (); terminate_worker_threads (); - terminate_writer_thread (); + finish_writer_thread (); } void @@ -135,6 +139,17 @@ Encoder::process_begin () } } + /* XXX! */ + _picture_asset.reset ( + new libdcp::MonoPictureAsset ( + _film->dir (_film->dcp_name()), + String::compose ("video_%1.mxf", 0), + DCPFrameRate (_film->frames_per_second()).frames_per_second, + _film->format()->dcp_size() + ) + ); + + _picture_asset_writer = _picture_asset->start_write (); _writer_thread = new boost::thread (boost::bind (&Encoder::writer_thread, this)); } @@ -192,7 +207,6 @@ Encoder::process_end () lock.unlock (); terminate_worker_threads (); - terminate_writer_thread (); _film->log()->log ("Mopping up " + lexical_cast (_encode_queue.size())); @@ -209,23 +223,19 @@ Encoder::process_end () _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); try { shared_ptr e = (*i)->encode_locally (); - e->write (_film, (*i)->frame ()); + { + boost::mutex::scoped_lock lock2 (_writer_mutex); + _write_queue.push_back (make_pair (e, (*i)->frame ())); + _writer_condition.notify_all (); + } frame_done (); } catch (std::exception& e) { _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); } } - /* Mop up any unwritten things in the writer's queue */ - for (list, int> >::iterator i = _write_queue.begin(); i != _write_queue.end(); ++i) { - i->first->write (_opt, i->second); - } - - /* Now do links (or copies on windows) to duplicate frames */ - for (list >::iterator i = _links_required.begin(); i != _links_required.end(); ++i) { - link (_film->frame_out_path (i->first, false), _film->frame_out_path (i->second, false)); - link (_film->hash_out_path (i->first, false), _film->hash_out_path (i->second, false)); - } + finish_writer_thread (); + _picture_asset_writer->finalize (); } /** @return an estimate of the current number of frames we are encoding per second, @@ -317,12 +327,13 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr (), _video_frames_out)); } else { /* Queue this new frame for encoding */ pair const s = Filter::ffmpeg_strings (_film->filters()); @@ -338,14 +349,15 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr (), _video_frames_out)); ++_video_frames_out; } } @@ -434,14 +446,14 @@ Encoder::terminate_worker_threads () } void -Encoder::terminate_writer_thread () +Encoder::finish_writer_thread () { if (!_writer_thread) { return; } boost::mutex::scoped_lock lock (_writer_mutex); - _terminate_writer = true; + _finish_writer = true; _writer_condition.notify_all (); lock.unlock (); @@ -550,27 +562,95 @@ Encoder::link (string a, string b) const #endif } +struct WriteQueueSorter +{ + bool operator() (pair, int> const & a, pair, int> const & b) { + return a.second < b.second; + } +}; + void Encoder::writer_thread () { while (1) { boost::mutex::scoped_lock lock (_writer_mutex); - TIMING ("writer sleeps with a queue of %1", _write_queue.size()); - while (_write_queue.empty() && !_terminate_writer) { - _writer_condition.wait (lock); + + while (1) { + if (_finish_writer || + _write_queue.size() > _maximum_frames_in_memory || + (!_write_queue.empty() && _write_queue.front().second == (_last_written_frame + 1))) { + + break; + } + + TIMING ("writer sleeps with a queue of %1; %2 pending", _write_queue.size(), _pending.size()); + _writer_condition.wait (lock); + TIMING ("writer wakes with a queue of %1", _write_queue.size()); + + _write_queue.sort (WriteQueueSorter ()); } - TIMING ("writer wakes with a queue of %1", _write_queue.size()); - if (_terminate_writer) { + if (_finish_writer && _write_queue.empty() && _pending.empty()) { return; } - pair, int> encoded = _write_queue.front (); - _write_queue.pop_front (); + /* Write any frames that we can write; i.e. those that are in sequence */ + while (!_write_queue.empty() && _write_queue.front().second == (_last_written_frame + 1)) { + pair, int> encoded = _write_queue.front (); + _write_queue.pop_front (); - lock.unlock (); - encoded.first->write (_opt, encoded.second); - lock.lock (); + lock.unlock (); + /* XXX: write to mxf */ + _film->log()->log (String::compose ("Writer writes %1 to MXF", encoded.second)); + if (encoded.first) { + _picture_asset_writer->write (encoded.first->data(), encoded.first->size()); + _last_written = encoded.first; + } else { + _picture_asset_writer->write (_last_written->data(), _last_written->size()); + } + lock.lock (); + + ++_last_written_frame; + } + + while (_write_queue.size() > _maximum_frames_in_memory) { + /* Too many frames in memory which can't yet be written to the stream. + Put some to disk. + */ + + pair, int> encoded = _write_queue.front (); + _write_queue.pop_back (); + if (!encoded.first) { + /* This is a `repeat-last' frame, so no need to write it to disk */ + continue; + } + + lock.unlock (); + _film->log()->log (String::compose ("Writer full; pushes %1 to disk", encoded.second)); + encoded.first->write (_film, encoded.second); + lock.lock (); + + _pending.push_back (encoded.second); + } + + while (_write_queue.size() < _maximum_frames_in_memory && !_pending.empty()) { + /* We have some space in memory. Fetch some frames back off disk. */ + + _pending.sort (); + int const fetch = _pending.front (); + + lock.unlock (); + _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch)); + shared_ptr encoded; + if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) { + /* It's an actual frame (not a repeat-last); load it in */ + encoded.reset (new EncodedData (_film->frame_out_path (fetch, false))); + } + lock.lock (); + + _write_queue.push_back (make_pair (encoded, fetch)); + _pending.remove (fetch); + } } } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 96e7a1d25..3e2b5d957 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -52,6 +52,11 @@ class ServerDescription; class DCPVideoFrame; class EncodedData; +namespace libdcp { + class MonoPictureAsset; + class MonoPictureAssetWriter; +} + /** @class Encoder * @brief Encoder to J2K and WAV for DCP. * @@ -121,22 +126,15 @@ private: int64_t _audio_frames_out; void writer_thread (); - void terminate_writer_thread (); + void finish_writer_thread (); #if HAVE_SWRESAMPLE SwrContext* _swr_context; #endif - /** List of links that we need to create when all frames have been processed; - * such that we need to call link (first, second) for each member of this list. - * In other words, `first' is a `real' frame and `second' should be a link to `first'. - * Frames are DCP frames. - */ - std::list > _links_required; - std::vector _sound_files; - boost::optional _last_real_frame; + bool _have_a_real_frame; bool _terminate_encoder; std::list > _encode_queue; std::list _worker_threads; @@ -144,10 +142,17 @@ private: boost::condition _worker_condition; boost::thread* _writer_thread; - bool _terminate_writer; + bool _finish_writer; std::list, int> > _write_queue; mutable boost::mutex _writer_mutex; boost::condition _writer_condition; + boost::shared_ptr _last_written; + std::list _pending; + int _last_written_frame; + static const unsigned int _maximum_frames_in_memory; + + boost::shared_ptr _picture_asset; + boost::shared_ptr _picture_asset_writer; }; #endif -- cgit v1.2.3 From a93bbd88eaa67a1e24471789335a2790b6cfbc78 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 23:56:49 +0000 Subject: Some fixes and logs. --- src/lib/encoder.cc | 5 ++--- src/lib/log.cc | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c6960d0d1..0d5fc1c6e 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -601,7 +601,6 @@ Encoder::writer_thread () _write_queue.pop_front (); lock.unlock (); - /* XXX: write to mxf */ _film->log()->log (String::compose ("Writer writes %1 to MXF", encoded.second)); if (encoded.first) { _picture_asset_writer->write (encoded.first->data(), encoded.first->size()); @@ -619,7 +618,7 @@ Encoder::writer_thread () Put some to disk. */ - pair, int> encoded = _write_queue.front (); + pair, int> encoded = _write_queue.back (); _write_queue.pop_back (); if (!encoded.first) { /* This is a `repeat-last' frame, so no need to write it to disk */ @@ -627,7 +626,7 @@ Encoder::writer_thread () } lock.unlock (); - _film->log()->log (String::compose ("Writer full; pushes %1 to disk", encoded.second)); + _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, encoded.second)); encoded.first->write (_film, encoded.second); lock.lock (); diff --git a/src/lib/log.cc b/src/lib/log.cc index 06cff0495..7459700ea 100644 --- a/src/lib/log.cc +++ b/src/lib/log.cc @@ -28,7 +28,7 @@ using namespace std; Log::Log () - : _level (VERBOSE) + : _level (STANDARD) { } -- cgit v1.2.3 From d4024b9f794823a2808724ae9fae74195f1a0824 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 18 Jan 2013 00:19:21 +0000 Subject: Some missing frame_done()s. --- src/lib/encoder.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0d5fc1c6e..b37a3c098 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -334,6 +334,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr (), _video_frames_out)); + frame_done (); } else { /* Queue this new frame for encoding */ pair const s = Filter::ffmpeg_strings (_film->filters()); @@ -359,6 +360,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr (), _video_frames_out)); ++_video_frames_out; + frame_done (); } } @@ -529,6 +531,7 @@ Encoder::encoder_thread (ServerDescription* server) boost::mutex::scoped_lock lock2 (_writer_mutex); _write_queue.push_back (make_pair (encoded, vf->frame ())); _writer_condition.notify_all (); + frame_done (); } else { lock.lock (); _film->log()->log ( -- cgit v1.2.3 From 479b67ec506289a4763b2dd4f07e72d1dd676483 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 18 Jan 2013 00:40:49 +0000 Subject: Add writer class to pull some stuff out of Encoder. --- NOTES | 6 ++ src/lib/encoder.cc | 172 ++++---------------------------------------------- src/lib/encoder.h | 23 +------ src/lib/writer.cc | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lib/writer.h | 60 ++++++++++++++++++ src/lib/wscript | 1 + 6 files changed, 261 insertions(+), 181 deletions(-) create mode 100644 NOTES create mode 100644 src/lib/writer.cc create mode 100644 src/lib/writer.h (limited to 'src/lib/encoder.cc') diff --git a/NOTES b/NOTES new file mode 100644 index 000000000..5be074c90 --- /dev/null +++ b/NOTES @@ -0,0 +1,6 @@ + +Encoder to write audio mxf; and sort out creation of those mxfs +DCP job still to write XML; presumably. +Write hashes of frames after successful write. +Make check of hashes optional + diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index b37a3c098..bad420f35 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -37,6 +37,7 @@ #include "server.h" #include "format.h" #include "cross.h" +#include "writer.h" using std::pair; using std::string; @@ -48,7 +49,6 @@ using std::make_pair; using namespace boost; int const Encoder::_history_size = 25; -unsigned int const Encoder::_maximum_frames_in_memory = 8; /** @param f Film that we are encoding. * @param o Options. @@ -65,9 +65,6 @@ Encoder::Encoder (shared_ptr f) #endif , _have_a_real_frame (false) , _terminate_encoder (false) - , _writer_thread (0) - , _finish_writer (false) - , _last_written_frame (-1) { if (_film->audio_stream()) { /* Create sound output files with .tmp suffixes; we will rename @@ -92,7 +89,9 @@ Encoder::~Encoder () { close_sound_files (); terminate_worker_threads (); - finish_writer_thread (); + if (_writer) { + _writer->finish (); + } } void @@ -139,18 +138,7 @@ Encoder::process_begin () } } - /* XXX! */ - _picture_asset.reset ( - new libdcp::MonoPictureAsset ( - _film->dir (_film->dcp_name()), - String::compose ("video_%1.mxf", 0), - DCPFrameRate (_film->frames_per_second()).frames_per_second, - _film->format()->dcp_size() - ) - ); - - _picture_asset_writer = _picture_asset->start_write (); - _writer_thread = new boost::thread (boost::bind (&Encoder::writer_thread, this)); + _writer.reset (new Writer (_film)); } @@ -222,20 +210,15 @@ Encoder::process_end () for (list >::iterator i = _encode_queue.begin(); i != _encode_queue.end(); ++i) { _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); try { - shared_ptr e = (*i)->encode_locally (); - { - boost::mutex::scoped_lock lock2 (_writer_mutex); - _write_queue.push_back (make_pair (e, (*i)->frame ())); - _writer_condition.notify_all (); - } + _writer->write ((*i)->encode_locally(), (*i)->frame ()); frame_done (); } catch (std::exception& e) { _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); } } - finish_writer_thread (); - _picture_asset_writer->finalize (); + _writer->finish (); + _writer.reset (); } /** @return an estimate of the current number of frames we are encoding per second, @@ -328,12 +311,8 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr (), _video_frames_out)); + /* Use the last frame that we encoded. */ + _writer->repeat (_video_frames_out); frame_done (); } else { /* Queue this new frame for encoding */ @@ -357,8 +336,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr (), _video_frames_out)); + _writer->repeat (_video_frames_out); ++_video_frames_out; frame_done (); } @@ -447,23 +425,6 @@ Encoder::terminate_worker_threads () } } -void -Encoder::finish_writer_thread () -{ - if (!_writer_thread) { - return; - } - - boost::mutex::scoped_lock lock (_writer_mutex); - _finish_writer = true; - _writer_condition.notify_all (); - lock.unlock (); - - _writer_thread->join (); - delete _writer_thread; - _writer_thread = 0; -} - void Encoder::encoder_thread (ServerDescription* server) { @@ -528,9 +489,7 @@ Encoder::encoder_thread (ServerDescription* server) } if (encoded) { - boost::mutex::scoped_lock lock2 (_writer_mutex); - _write_queue.push_back (make_pair (encoded, vf->frame ())); - _writer_condition.notify_all (); + _writer->write (encoded, vf->frame ()); frame_done (); } else { lock.lock (); @@ -549,110 +508,3 @@ Encoder::encoder_thread (ServerDescription* server) _worker_condition.notify_all (); } } - -void -Encoder::link (string a, string b) const -{ -#ifdef DVDOMATIC_POSIX - int const r = symlink (a.c_str(), b.c_str()); - if (r) { - throw EncodeError (String::compose ("could not create symlink from %1 to %2", a, b)); - } -#endif - -#ifdef DVDOMATIC_WINDOWS - boost::filesystem::copy_file (a, b); -#endif -} - -struct WriteQueueSorter -{ - bool operator() (pair, int> const & a, pair, int> const & b) { - return a.second < b.second; - } -}; - -void -Encoder::writer_thread () -{ - while (1) - { - boost::mutex::scoped_lock lock (_writer_mutex); - - while (1) { - if (_finish_writer || - _write_queue.size() > _maximum_frames_in_memory || - (!_write_queue.empty() && _write_queue.front().second == (_last_written_frame + 1))) { - - break; - } - - TIMING ("writer sleeps with a queue of %1; %2 pending", _write_queue.size(), _pending.size()); - _writer_condition.wait (lock); - TIMING ("writer wakes with a queue of %1", _write_queue.size()); - - _write_queue.sort (WriteQueueSorter ()); - } - - if (_finish_writer && _write_queue.empty() && _pending.empty()) { - return; - } - - /* Write any frames that we can write; i.e. those that are in sequence */ - while (!_write_queue.empty() && _write_queue.front().second == (_last_written_frame + 1)) { - pair, int> encoded = _write_queue.front (); - _write_queue.pop_front (); - - lock.unlock (); - _film->log()->log (String::compose ("Writer writes %1 to MXF", encoded.second)); - if (encoded.first) { - _picture_asset_writer->write (encoded.first->data(), encoded.first->size()); - _last_written = encoded.first; - } else { - _picture_asset_writer->write (_last_written->data(), _last_written->size()); - } - lock.lock (); - - ++_last_written_frame; - } - - while (_write_queue.size() > _maximum_frames_in_memory) { - /* Too many frames in memory which can't yet be written to the stream. - Put some to disk. - */ - - pair, int> encoded = _write_queue.back (); - _write_queue.pop_back (); - if (!encoded.first) { - /* This is a `repeat-last' frame, so no need to write it to disk */ - continue; - } - - lock.unlock (); - _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, encoded.second)); - encoded.first->write (_film, encoded.second); - lock.lock (); - - _pending.push_back (encoded.second); - } - - while (_write_queue.size() < _maximum_frames_in_memory && !_pending.empty()) { - /* We have some space in memory. Fetch some frames back off disk. */ - - _pending.sort (); - int const fetch = _pending.front (); - - lock.unlock (); - _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch)); - shared_ptr encoded; - if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) { - /* It's an actual frame (not a repeat-last); load it in */ - encoded.reset (new EncodedData (_film->frame_out_path (fetch, false))); - } - lock.lock (); - - _write_queue.push_back (make_pair (encoded, fetch)); - _pending.remove (fetch); - } - } -} diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 3e2b5d957..a277aca51 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -51,11 +51,7 @@ class Film; class ServerDescription; class DCPVideoFrame; class EncodedData; - -namespace libdcp { - class MonoPictureAsset; - class MonoPictureAssetWriter; -} +class Writer; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -100,7 +96,6 @@ private: void encoder_thread (ServerDescription *); void terminate_worker_threads (); - void link (std::string, std::string) const; /** Film that we are encoding */ boost::shared_ptr _film; @@ -125,9 +120,6 @@ private: /** Number of audio frames written for the DCP so far */ int64_t _audio_frames_out; - void writer_thread (); - void finish_writer_thread (); - #if HAVE_SWRESAMPLE SwrContext* _swr_context; #endif @@ -141,18 +133,7 @@ private: mutable boost::mutex _worker_mutex; boost::condition _worker_condition; - boost::thread* _writer_thread; - bool _finish_writer; - std::list, int> > _write_queue; - mutable boost::mutex _writer_mutex; - boost::condition _writer_condition; - boost::shared_ptr _last_written; - std::list _pending; - int _last_written_frame; - static const unsigned int _maximum_frames_in_memory; - - boost::shared_ptr _picture_asset; - boost::shared_ptr _picture_asset_writer; + boost::shared_ptr _writer; }; #endif diff --git a/src/lib/writer.cc b/src/lib/writer.cc new file mode 100644 index 000000000..0381ee378 --- /dev/null +++ b/src/lib/writer.cc @@ -0,0 +1,180 @@ +/* + Copyright (C) 2012 Carl Hetherington + + 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 +#include "writer.h" +#include "compose.hpp" +#include "film.h" +#include "format.h" +#include "log.h" +#include "dcp_video_frame.h" + +using std::make_pair; +using std::pair; +using boost::shared_ptr; + +unsigned int const Writer::_maximum_frames_in_memory = 8; + +Writer::Writer (shared_ptr f) + : _film (f) + , _thread (0) + , _finish (false) + , _last_written_frame (-1) +{ + _picture_asset.reset ( + new libdcp::MonoPictureAsset ( + _film->dir (_film->dcp_name()), + String::compose ("video_%1.mxf", 0), + DCPFrameRate (_film->frames_per_second()).frames_per_second, + _film->format()->dcp_size() + ) + ); + + _picture_asset_writer = _picture_asset->start_write (); + + _thread = new boost::thread (boost::bind (&Writer::thread, this)); +} + +void +Writer::write (shared_ptr encoded, int frame) +{ + boost::mutex::scoped_lock lock (_mutex); + _queue.push_back (make_pair (encoded, frame)); + _condition.notify_all (); +} + +struct QueueSorter +{ + bool operator() (pair, int> const & a, pair, int> const & b) { + return a.second < b.second; + } +}; + +void +Writer::thread () +{ + while (1) + { + boost::mutex::scoped_lock lock (_mutex); + + while (1) { + if (_finish || + _queue.size() > _maximum_frames_in_memory || + (!_queue.empty() && _queue.front().second == (_last_written_frame + 1))) { + + break; + } + + TIMING ("writer sleeps with a queue of %1; %2 pending", _queue.size(), _pending.size()); + _condition.wait (lock); + TIMING ("writer wakes with a queue of %1", _queue.size()); + + _queue.sort (QueueSorter ()); + } + + if (_finish && _queue.empty() && _pending.empty()) { + return; + } + + /* Write any frames that we can write; i.e. those that are in sequence */ + while (!_queue.empty() && _queue.front().second == (_last_written_frame + 1)) { + pair, int> encoded = _queue.front (); + _queue.pop_front (); + + lock.unlock (); + _film->log()->log (String::compose ("Writer writes %1 to MXF", encoded.second)); + if (encoded.first) { + _picture_asset_writer->write (encoded.first->data(), encoded.first->size()); + _last_written = encoded.first; + } else { + _picture_asset_writer->write (_last_written->data(), _last_written->size()); + } + lock.lock (); + + ++_last_written_frame; + } + + while (_queue.size() > _maximum_frames_in_memory) { + /* Too many frames in memory which can't yet be written to the stream. + Put some to disk. + */ + + pair, int> encoded = _queue.back (); + _queue.pop_back (); + if (!encoded.first) { + /* This is a `repeat-last' frame, so no need to write it to disk */ + continue; + } + + lock.unlock (); + _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, encoded.second)); + encoded.first->write (_film, encoded.second); + lock.lock (); + + _pending.push_back (encoded.second); + } + + while (_queue.size() < _maximum_frames_in_memory && !_pending.empty()) { + /* We have some space in memory. Fetch some frames back off disk. */ + + _pending.sort (); + int const fetch = _pending.front (); + + lock.unlock (); + _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch)); + shared_ptr encoded; + if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) { + /* It's an actual frame (not a repeat-last); load it in */ + encoded.reset (new EncodedData (_film->frame_out_path (fetch, false))); + } + lock.lock (); + + _queue.push_back (make_pair (encoded, fetch)); + _pending.remove (fetch); + } + } + +} + +void +Writer::finish () +{ + if (!_thread) { + return; + } + + boost::mutex::scoped_lock lock (_mutex); + _finish = true; + _condition.notify_all (); + lock.unlock (); + + _thread->join (); + delete _thread; + _thread = 0; + + _picture_asset_writer->finalize (); +} + +/** Tell the writer that frame `f' should be a repeat of the frame before it */ +void +Writer::repeat (int f) +{ + boost::mutex::scoped_lock lock (_mutex); + _queue.push_back (make_pair (shared_ptr (), f)); +} diff --git a/src/lib/writer.h b/src/lib/writer.h new file mode 100644 index 000000000..8156308a6 --- /dev/null +++ b/src/lib/writer.h @@ -0,0 +1,60 @@ +/* + Copyright (C) 2012 Carl Hetherington + + 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 +#include +#include +#include + +class Film; +class EncodedData; + +namespace libdcp { + class MonoPictureAsset; + class MonoPictureAssetWriter; +} + +class Writer +{ +public: + Writer (boost::shared_ptr); + + void write (boost::shared_ptr, int); + void repeat (int f); + void finish (); + +private: + + void thread (); + + boost::shared_ptr _film; + + boost::thread* _thread; + bool _finish; + std::list, int> > _queue; + mutable boost::mutex _mutex; + boost::condition _condition; + boost::shared_ptr _last_written; + std::list _pending; + int _last_written_frame; + static const unsigned int _maximum_frames_in_memory; + + boost::shared_ptr _picture_asset; + boost::shared_ptr _picture_asset_writer; +}; diff --git a/src/lib/wscript b/src/lib/wscript index b2b639f06..6d72f6480 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -56,6 +56,7 @@ def build(bld): version.cc video_decoder.cc video_source.cc + writer.cc """ obj.target = 'dvdomatic' -- cgit v1.2.3 From 5e4ab7ebd9a6b62b64fbaf91d7aa1a2a9d4bdec4 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 18 Jan 2013 21:49:49 +0000 Subject: Untested direct write of audio to MXF. --- NOTES | 2 +- src/lib/dcp_video_frame.cc | 2 +- src/lib/dcp_video_frame.h | 2 +- src/lib/encoder.cc | 59 +++------------------------------------------- src/lib/encoder.h | 8 ------- src/lib/writer.cc | 35 ++++++++++++++++++++++----- src/lib/writer.h | 12 +++++++--- 7 files changed, 44 insertions(+), 76 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/NOTES b/NOTES index a771e9bfd..b384cb6c0 100644 --- a/NOTES +++ b/NOTES @@ -4,4 +4,4 @@ Get rid of DCP job entirely and make encoder write XML (since it has the *Asset ... perhaps generate the CPL hash on the fly Write hashes of frames after successful write. Make check of hashes optional; recovery in general - +Fix multi-reel or remove it \ No newline at end of file diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index da864ad9f..89db5761a 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -405,7 +405,7 @@ EncodedData::~EncodedData () * @param frame DCP Frame index. */ void -EncodedData::write (shared_ptr film, int frame) +EncodedData::write (shared_ptr film, int frame) const { string const tmp_j2k = film->frame_out_path (frame, true); diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index b446352c7..2ad2b0d44 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -48,7 +48,7 @@ public: virtual ~EncodedData (); void send (boost::shared_ptr socket); - void write (boost::shared_ptr, int); + void write (boost::shared_ptr, int) const; /** @return data */ uint8_t* data () const { diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index bad420f35..c2416b87e 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -57,37 +57,18 @@ Encoder::Encoder (shared_ptr f) : _film (f) , _just_skipped (false) , _video_frames_in (0) - , _audio_frames_in (0) , _video_frames_out (0) - , _audio_frames_out (0) #ifdef HAVE_SWRESAMPLE , _swr_context (0) #endif , _have_a_real_frame (false) , _terminate_encoder (false) { - if (_film->audio_stream()) { - /* Create sound output files with .tmp suffixes; we will rename - them if and when we complete. - */ - for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) { - SF_INFO sf_info; - sf_info.samplerate = dcp_audio_sample_rate (_film->audio_stream()->sample_rate()); - /* We write mono files */ - sf_info.channels = 1; - sf_info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_24; - SNDFILE* f = sf_open (_film->multichannel_audio_out_path (i, true).c_str (), SFM_WRITE, &sf_info); - if (f == 0) { - throw CreateFileError (_film->multichannel_audio_out_path (i, true)); - } - _sound_files.push_back (f); - } - } + } Encoder::~Encoder () { - close_sound_files (); terminate_worker_threads (); if (_writer) { _writer->finish (); @@ -162,25 +143,13 @@ Encoder::process_end () } out->set_frames (frames); - write_audio (out); + _writer->write (out); } swr_free (&_swr_context); } #endif - if (_film->audio_stream()) { - close_sound_files (); - - /* Rename .wav.tmp files to .wav */ - for (int i = 0; i < dcp_audio_channels (_film->audio_channels()); ++i) { - if (boost::filesystem::exists (_film->multichannel_audio_out_path (i, false))) { - boost::filesystem::remove (_film->multichannel_audio_out_path (i, false)); - } - boost::filesystem::rename (_film->multichannel_audio_out_path (i, true), _film->multichannel_audio_out_path (i, false)); - } - } - boost::mutex::scoped_lock lock (_worker_mutex); _film->log()->log ("Clearing queue of " + lexical_cast (_encode_queue.size ())); @@ -386,31 +355,9 @@ Encoder::process_audio (shared_ptr data) data = b; } - write_audio (data); - - _audio_frames_in += data->frames (); + _writer->write (data); } -void -Encoder::write_audio (shared_ptr audio) -{ - for (int i = 0; i < audio->channels(); ++i) { - sf_write_float (_sound_files[i], audio->data(i), audio->frames()); - } - - _audio_frames_out += audio->frames (); -} - -void -Encoder::close_sound_files () -{ - for (vector::iterator i = _sound_files.begin(); i != _sound_files.end(); ++i) { - sf_close (*i); - } - - _sound_files.clear (); -} - void Encoder::terminate_worker_threads () { diff --git a/src/lib/encoder.h b/src/lib/encoder.h index a277aca51..fc89d674a 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -39,7 +39,6 @@ extern "C" { #include } #endif -#include #include "util.h" #include "video_sink.h" #include "audio_sink.h" @@ -91,7 +90,6 @@ private: void frame_done (); void frame_skipped (); - void close_sound_files (); void write_audio (boost::shared_ptr audio); void encoder_thread (ServerDescription *); @@ -113,19 +111,13 @@ private: /** Number of video frames received so far */ SourceFrame _video_frames_in; - /** Number of audio frames received so far */ - int64_t _audio_frames_in; /** Number of video frames written for the DCP so far */ int _video_frames_out; - /** Number of audio frames written for the DCP so far */ - int64_t _audio_frames_out; #if HAVE_SWRESAMPLE SwrContext* _swr_context; #endif - std::vector _sound_files; - bool _have_a_real_frame; bool _terminate_encoder; std::list > _encode_queue; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 0381ee378..fbd371550 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -18,6 +18,7 @@ */ #include +#include #include "writer.h" #include "compose.hpp" #include "film.h" @@ -48,20 +49,41 @@ Writer::Writer (shared_ptr f) _picture_asset_writer = _picture_asset->start_write (); + if (_film->audio_channels() > 0) { + _sound_asset.reset ( + new libdcp::SoundAsset ( + _film->dir (_film->dcp_name()), + String::compose ("audio_%1.mxf", 0), + DCPFrameRate (_film->frames_per_second()).frames_per_second, + _film->audio_channels(), + _film->audio_stream()->sample_rate() + ) + ); + + _sound_asset_writer = _sound_asset->start_write (); + } + _thread = new boost::thread (boost::bind (&Writer::thread, this)); } void -Writer::write (shared_ptr encoded, int frame) +Writer::write (shared_ptr encoded, int frame) { boost::mutex::scoped_lock lock (_mutex); _queue.push_back (make_pair (encoded, frame)); _condition.notify_all (); } +/** This method is not thread safe */ +void +Writer::write (shared_ptr audio) +{ + _sound_asset_writer->write (audio->data(), audio->frames()); +} + struct QueueSorter { - bool operator() (pair, int> const & a, pair, int> const & b) { + bool operator() (pair, int> const & a, pair, int> const & b) { return a.second < b.second; } }; @@ -94,7 +116,7 @@ Writer::thread () /* Write any frames that we can write; i.e. those that are in sequence */ while (!_queue.empty() && _queue.front().second == (_last_written_frame + 1)) { - pair, int> encoded = _queue.front (); + pair, int> encoded = _queue.front (); _queue.pop_front (); lock.unlock (); @@ -115,7 +137,7 @@ Writer::thread () Put some to disk. */ - pair, int> encoded = _queue.back (); + pair, int> encoded = _queue.back (); _queue.pop_back (); if (!encoded.first) { /* This is a `repeat-last' frame, so no need to write it to disk */ @@ -138,7 +160,7 @@ Writer::thread () lock.unlock (); _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch)); - shared_ptr encoded; + shared_ptr encoded; if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) { /* It's an actual frame (not a repeat-last); load it in */ encoded.reset (new EncodedData (_film->frame_out_path (fetch, false))); @@ -169,6 +191,7 @@ Writer::finish () _thread = 0; _picture_asset_writer->finalize (); + _sound_asset_writer->finalize (); } /** Tell the writer that frame `f' should be a repeat of the frame before it */ @@ -176,5 +199,5 @@ void Writer::repeat (int f) { boost::mutex::scoped_lock lock (_mutex); - _queue.push_back (make_pair (shared_ptr (), f)); + _queue.push_back (make_pair (shared_ptr (), f)); } diff --git a/src/lib/writer.h b/src/lib/writer.h index 8156308a6..77f98f160 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -24,10 +24,13 @@ class Film; class EncodedData; +class AudioBuffers; namespace libdcp { class MonoPictureAsset; class MonoPictureAssetWriter; + class SoundAsset; + class SoundAssetWriter; } class Writer @@ -35,7 +38,8 @@ class Writer public: Writer (boost::shared_ptr); - void write (boost::shared_ptr, int); + void write (boost::shared_ptr, int); + void write (boost::shared_ptr); void repeat (int f); void finish (); @@ -47,14 +51,16 @@ private: boost::thread* _thread; bool _finish; - std::list, int> > _queue; + std::list, int> > _queue; mutable boost::mutex _mutex; boost::condition _condition; - boost::shared_ptr _last_written; + boost::shared_ptr _last_written; std::list _pending; int _last_written_frame; static const unsigned int _maximum_frames_in_memory; boost::shared_ptr _picture_asset; boost::shared_ptr _picture_asset_writer; + boost::shared_ptr _sound_asset; + boost::shared_ptr _sound_asset_writer; }; -- cgit v1.2.3 From 657f735160fd8b0abc67d6e5f519da5786ed26f0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 21 Jan 2013 20:35:00 +0000 Subject: Fix a couple of things; go back to un-numbered MXF file names for a bit. --- src/lib/encoder.cc | 2 +- src/lib/encoder.h | 4 ++-- src/lib/writer.cc | 8 ++++---- src/lib/writer.h | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c2416b87e..6b14b2698 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -53,7 +53,7 @@ int const Encoder::_history_size = 25; /** @param f Film that we are encoding. * @param o Options. */ -Encoder::Encoder (shared_ptr f) +Encoder::Encoder (shared_ptr f) : _film (f) , _just_skipped (false) , _video_frames_in (0) diff --git a/src/lib/encoder.h b/src/lib/encoder.h index fc89d674a..429b46a18 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -62,7 +62,7 @@ class Writer; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f); + Encoder (boost::shared_ptr f); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ @@ -96,7 +96,7 @@ private: void terminate_worker_threads (); /** Film that we are encoding */ - boost::shared_ptr _film; + boost::shared_ptr _film; /** Mutex for _time_history, _just_skipped and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index df6f20791..56cfa43a7 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -33,7 +33,7 @@ using boost::shared_ptr; unsigned int const Writer::_maximum_frames_in_memory = 8; -Writer::Writer (shared_ptr f) +Writer::Writer (shared_ptr f) : _film (f) , _thread (0) , _finish (false) @@ -42,7 +42,7 @@ Writer::Writer (shared_ptr f) _picture_asset.reset ( new libdcp::MonoPictureAsset ( _film->dir (_film->dcp_name()), - String::compose ("video_%1.mxf", 0), + "video.mxf", DCPFrameRate (_film->frames_per_second()).frames_per_second, _film->format()->dcp_size() ) @@ -54,7 +54,7 @@ Writer::Writer (shared_ptr f) _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), - String::compose ("audio_%1.mxf", 0), + "audio.mxf", DCPFrameRate (_film->frames_per_second()).frames_per_second, _film->audio_channels(), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) @@ -199,7 +199,7 @@ Writer::finish () int const frames = _last_written_frame + 1; int const duration = frames - _film->trim_start() - _film->trim_end(); - _film->set_intrinsic_duration (frames); + _film->set_dcp_intrinsic_duration (frames); _picture_asset->set_entry_point (_film->trim_start ()); _picture_asset->set_duration (duration); diff --git a/src/lib/writer.h b/src/lib/writer.h index 77f98f160..1aaea4d9d 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -36,7 +36,7 @@ namespace libdcp { class Writer { public: - Writer (boost::shared_ptr); + Writer (boost::shared_ptr); void write (boost::shared_ptr, int); void write (boost::shared_ptr); @@ -47,7 +47,7 @@ private: void thread (); - boost::shared_ptr _film; + boost::shared_ptr _film; boost::thread* _thread; bool _finish; -- cgit v1.2.3 From 0b760c0526b0b9d13def519ab8afba1e511d8111 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 23 Jan 2013 20:49:26 +0000 Subject: Try to fix up paths for video MXFs, hashes and temporarily-stored frames. --- .gitignore | 5 +- src/lib/check_hashes_job.cc | 120 -------------------------------------------- src/lib/check_hashes_job.h | 39 -------------- src/lib/dcp_video_frame.cc | 12 ++--- src/lib/encoder.cc | 26 ---------- src/lib/encoder.h | 6 +-- src/lib/film.cc | 90 ++++++++++++++++----------------- src/lib/film.h | 10 ++-- src/lib/transcode_job.cc | 5 -- src/lib/writer.cc | 6 +-- src/lib/wscript | 1 - 11 files changed, 61 insertions(+), 259 deletions(-) delete mode 100644 src/lib/check_hashes_job.cc delete mode 100644 src/lib/check_hashes_job.h (limited to 'src/lib/encoder.cc') diff --git a/.gitignore b/.gitignore index 4c0c1926d..cc3351558 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,7 @@ doc/manual/pdf doc/manual/extensions.ent .be/id-cache *.pyc - +GPATH +GRTAGS +GSYMS +GTAGS diff --git a/src/lib/check_hashes_job.cc b/src/lib/check_hashes_job.cc deleted file mode 100644 index 55a744552..000000000 --- a/src/lib/check_hashes_job.cc +++ /dev/null @@ -1,120 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - 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 -#include -#include -#include "check_hashes_job.h" -#include "options.h" -#include "log.h" -#include "job_manager.h" -#include "ab_transcode_job.h" -#include "transcode_job.h" -#include "film.h" -#include "exceptions.h" - -using std::string; -using std::stringstream; -using std::ifstream; -using boost::shared_ptr; - -CheckHashesJob::CheckHashesJob (shared_ptr f, DecodeOptions o, shared_ptr req) - : Job (f, req) - , _decode_opt (o) - , _bad (0) -{ - -} - -string -CheckHashesJob::name () const -{ - return String::compose ("Check hashes of %1", _film->name()); -} - -void -CheckHashesJob::run () -{ - _bad = 0; - - if (!_film->dcp_intrinsic_duration()) { - throw EncodeError ("cannot check hashes of a DCP with unknown intrinsic duration"); - } - - int const N = _film->dcp_intrinsic_duration().get(); - for (int i = 0; i < N; ++i) { - string const j2k_file = _film->frame_out_path (i, false); - string const hash_file = _film->hash_out_path (i, false); - - if (!boost::filesystem::exists (j2k_file)) { - _film->log()->log (String::compose ("Frame %1 has a missing J2K file.", i)); - boost::filesystem::remove (hash_file); - ++_bad; - } else if (!boost::filesystem::exists (hash_file)) { - _film->log()->log (String::compose ("Frame %1 has a missing hash file.", i)); - boost::filesystem::remove (j2k_file); - ++_bad; - } else { - ifstream ref (hash_file.c_str ()); - string hash; - ref >> hash; - if (hash != md5_digest (j2k_file)) { - _film->log()->log (String::compose ("Frame %1 has wrong hash; deleting.", i)); - boost::filesystem::remove (j2k_file); - boost::filesystem::remove (hash_file); - ++_bad; - } - } - - set_progress (float (i) / N); - } - - if (_bad) { - shared_ptr tc; - - if (_film->dcp_ab()) { - tc.reset (new ABTranscodeJob (_film, _decode_opt, shared_from_this())); - } else { - tc.reset (new TranscodeJob (_film, _decode_opt, shared_from_this())); - } - - JobManager::instance()->add_after (shared_from_this(), tc); - JobManager::instance()->add_after (tc, shared_ptr (new CheckHashesJob (_film, _decode_opt, tc))); - } - - set_progress (1); - set_state (FINISHED_OK); -} - -string -CheckHashesJob::status () const -{ - stringstream s; - s << Job::status (); - if (overall_progress() > 0) { - if (_bad == 0) { - s << "; no bad frames found"; - } else if (_bad == 1) { - s << "; 1 bad frame found"; - } else { - s << "; " << _bad << " bad frames found"; - } - } - return s.str (); -} diff --git a/src/lib/check_hashes_job.h b/src/lib/check_hashes_job.h deleted file mode 100644 index 5fa17382d..000000000 --- a/src/lib/check_hashes_job.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - 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 "job.h" -#include "options.h" - -class CheckHashesJob : public Job -{ -public: - CheckHashesJob ( - boost::shared_ptr f, - DecodeOptions od, - boost::shared_ptr req - ); - - std::string name () const; - void run (); - std::string status () const; - -private: - DecodeOptions _decode_opt; - int _bad; -}; diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index c3f0fed03..5df2d7a46 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -407,27 +407,27 @@ EncodedData::~EncodedData () void EncodedData::write (shared_ptr film, int frame) const { - string const tmp_j2k = film->frame_out_path (frame, true); + string const tmp_j2c = film->j2c_path (frame, true); - FILE* f = fopen (tmp_j2k.c_str (), "wb"); + FILE* f = fopen (tmp_j2c.c_str (), "wb"); if (!f) { - throw WriteFileError (tmp_j2k, errno); + throw WriteFileError (tmp_j2c, errno); } fwrite (_data, 1, _size, f); fclose (f); - string const real_j2k = film->frame_out_path (frame, false); + string const real_j2c = film->j2c_path (frame, false); /* Rename the file from foo.j2c.tmp to foo.j2c now that it is complete */ - boost::filesystem::rename (tmp_j2k, real_j2k); + boost::filesystem::rename (tmp_j2c, real_j2c); } void EncodedData::write_hash (shared_ptr film, int frame) const { - string const hash = film->hash_out_path (frame, false); + string const hash = film->hash_path (frame); ofstream h (hash.c_str()); h << md5_digest (_data, _size) << "\n"; } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 6b14b2698..978d787e8 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -55,7 +55,6 @@ int const Encoder::_history_size = 25; */ Encoder::Encoder (shared_ptr f) : _film (f) - , _just_skipped (false) , _video_frames_in (0) , _video_frames_out (0) #ifdef HAVE_SWRESAMPLE @@ -207,14 +206,6 @@ Encoder::current_frames_per_second () const return _history_size / (seconds (now) - seconds (_time_history.back ())); } -/** @return true if the last frame to be processed was skipped as it already existed */ -bool -Encoder::skipping () const -{ - boost::mutex::scoped_lock (_history_mutex); - return _just_skipped; -} - /** @return Number of video frames that have been sent out */ int Encoder::video_frames_out () const @@ -230,7 +221,6 @@ void Encoder::frame_done () { boost::mutex::scoped_lock lock (_history_mutex); - _just_skipped = false; struct timeval tv; gettimeofday (&tv, 0); @@ -240,16 +230,6 @@ Encoder::frame_done () } } -/** Called by a subclass when it has just skipped the processing - of a frame because it has already been done. -*/ -void -Encoder::frame_skipped () -{ - boost::mutex::scoped_lock lock (_history_mutex); - _just_skipped = true; -} - void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { @@ -273,12 +253,6 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrframe_out_path (_video_frames_out, false))) { - frame_skipped (); - return; - } - if (same && _have_a_real_frame) { /* Use the last frame that we encoded. */ _writer->repeat (_video_frames_out); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 429b46a18..8b02f7004 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -82,13 +82,11 @@ public: virtual void process_end (); float current_frames_per_second () const; - bool skipping () const; int video_frames_out () const; private: void frame_done (); - void frame_skipped (); void write_audio (boost::shared_ptr audio); @@ -98,7 +96,7 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; - /** Mutex for _time_history, _just_skipped and _last_frame */ + /** Mutex for _time_history 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. @@ -106,8 +104,6 @@ private: std::list _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_frames_in; diff --git a/src/lib/film.cc b/src/lib/film.cc index ae9edbfdb..dc308078c 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -46,7 +46,6 @@ #include "scaler.h" #include "decoder_factory.h" #include "config.h" -#include "check_hashes_job.h" #include "version.h" #include "ui_signaller.h" #include "video_decoder.h" @@ -194,24 +193,14 @@ Film::~Film () { delete _log; } - -/** @return The path to the directory to write JPEG2000 files to */ + string -Film::j2k_dir () const +Film::video_state_identifier () const { - assert (format()); - - boost::filesystem::path p; - - /* Start with j2c */ - p /= "j2c"; + assert (format ()); pair f = Filter::ffmpeg_strings (filters()); - /* Write stuff to specify the filter / post-processing settings that are in use, - so that we don't get confused about J2K files generated using different - settings. - */ stringstream s; s << format()->id() << "_" << content_digest() @@ -221,19 +210,33 @@ Film::j2k_dir () const << "_" << j2k_bandwidth() << "_" << boost::lexical_cast (colour_lut()); - p /= s.str (); - - /* Similarly for the A/B case */ if (dcp_ab()) { - stringstream s; pair fa = Filter::ffmpeg_strings (Config::instance()->reference_filters()); s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second; - p /= s.str (); } - + + return s.str (); +} + +/** @return The path to the directory to write video frame hash files to */ +string +Film::hash_dir () const +{ + boost::filesystem::path p; + p /= "hash"; + p /= video_state_identifier (); return dir (p.string()); } +string +Film::video_mxf_path () const +{ + boost::filesystem::path p; + p /= "video"; + p /= video_state_identifier (); + return file (p.string()); +} + /** Add suitable Jobs to the JobManager to create a DCP for this Film. * @param true to transcode, false to use the WAV and J2K files that are already there. */ @@ -302,8 +305,6 @@ Film::make_dcp (bool transcode) r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this(), od, shared_ptr ()))); } } - - // r = JobManager::instance()->add (shared_ptr (new CheckHashesJob (shared_from_this(), od, r))); } /** Start a job to examine our content file */ @@ -344,7 +345,7 @@ Film::encoded_frames () const } int N = 0; - for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (j2k_dir ()); i != boost::filesystem::directory_iterator(); ++i) { + for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (hash_dir ()); i != boost::filesystem::directory_iterator(); ++i) { ++N; boost::this_thread::interruption_point (); } @@ -1391,44 +1392,37 @@ Film::audio_stream () const return _external_audio_stream; } -/** @param f DCP frame index. - * @param t true to return a temporary file path, otherwise a permanent one. - * @return The path to write this video frame to. - */ string -Film::frame_out_path (int f, bool t) const +Film::hash_path (int f) const { + boost::filesystem::path p; + p /= hash_dir (); + stringstream s; - s << j2k_dir() << "/"; s.width (8); - s << std::setfill('0') << f << ".j2c"; + s << setfill('0') << f << ".md5"; - if (t) { - s << ".tmp"; - } - - return s.str (); + p /= s.str(); + return p.string (); } string -Film::hash_out_path (int f, bool t) const +Film::j2c_path (int f, bool t) const { - return frame_out_path (f, t) + ".md5"; -} + boost::filesystem::path p; + p /= "j2c"; + p /= video_state_identifier (); -/** @param c Audio channel index. - * @param t true to return a temporary file path, otherwise a permanent one. - * @return The path to write this audio file to. - */ -string -Film::multichannel_audio_out_path (int c, bool t) const -{ stringstream s; - s << dir ("wavs") << "/" << (c + 1) << ".wav"; + s.width (8); + s << setfill('0') << f << ".j2c"; + if (t) { s << ".tmp"; } - - return s.str (); + + p /= s.str(); + return p.string (); } + diff --git a/src/lib/film.h b/src/lib/film.h index 60646b0c8..4d2819be3 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -59,7 +59,10 @@ public: Film (Film const &); ~Film (); - std::string j2k_dir () const; + std::string hash_dir () const; + std::string j2c_path (int f, bool t) const; + std::string hash_path (int f) const; + std::string video_mxf_path () const; void examine_content (); void send_dcp_to_tms (); @@ -78,10 +81,6 @@ public: std::string file (std::string f) const; std::string dir (std::string d) const; - std::string frame_out_path (int f, bool t) const; - std::string hash_out_path (int f, bool t) const; - std::string multichannel_audio_out_path (int c, bool t) const; - std::string content_path () const; ContentType content_type () const; @@ -413,6 +412,7 @@ private: void signal_changed (Property); void examine_content_finished (); + std::string video_state_identifier () const; /** Complete path to directory containing the film metadata; * must not be relative. diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 6dd74c36c..e9a59c743 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -89,11 +89,6 @@ TranscodeJob::status () const return "0%"; } - if (_encoder->skipping () && !finished ()) { - return "skipping already-encoded frames"; - } - - float const fps = _encoder->current_frames_per_second (); if (fps == 0) { return Job::status (); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index a434db0ec..16ed5c349 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -42,7 +42,7 @@ Writer::Writer (shared_ptr f) _picture_asset.reset ( new libdcp::MonoPictureAsset ( _film->dir (_film->dcp_name()), - "video.mxf", + _film->video_mxf_path(), DCPFrameRate (_film->frames_per_second()).frames_per_second, _film->format()->dcp_size() ) @@ -164,9 +164,9 @@ Writer::thread () lock.unlock (); _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch)); shared_ptr encoded; - if (boost::filesystem::exists (_film->frame_out_path (fetch, false))) { + if (boost::filesystem::exists (_film->j2c_path (fetch, false))) { /* It's an actual frame (not a repeat-last); load it in */ - encoded.reset (new EncodedData (_film->frame_out_path (fetch, false))); + encoded.reset (new EncodedData (_film->j2c_path (fetch, false))); } lock.lock (); diff --git a/src/lib/wscript b/src/lib/wscript index 02c426373..5d676f249 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -14,7 +14,6 @@ def build(bld): ab_transcoder.cc audio_decoder.cc audio_source.cc - check_hashes_job.cc config.cc combiner.cc cross.cc -- cgit v1.2.3 From aeb20874df252fd8d36f5d3742ed8e34f2215367 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 2 Feb 2013 13:46:20 +0000 Subject: First try at doing fake writes. --- src/lib/encoder.cc | 5 +- src/lib/writer.cc | 161 ++++++++++++++++++++++++++++++++++------------------- src/lib/writer.h | 27 ++++++++- 3 files changed, 134 insertions(+), 59 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 978d787e8..b92be84a8 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -253,7 +253,10 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrcan_fake_write (_video_frames_out)) { + _writer->fake_write (_video_frames_out); + _have_a_real_frame = false; + } else if (same && _have_a_real_frame) { /* Use the last frame that we encoded. */ _writer->repeat (_video_frames_out); frame_done (); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 7f338e238..a444efad8 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -47,7 +47,7 @@ Writer::Writer (shared_ptr f) { check_existing_picture_mxf (); - /* Create our picture asset in a subdirectory, named according to the + /* Create our picture asset in a subdirectory, named according to those film's parameters which affect the video output. We will hard-link it into the DCP later. */ @@ -60,8 +60,8 @@ Writer::Writer (shared_ptr f) _film->format()->dcp_size() ) ); - - _picture_asset_writer = _picture_asset->start_write (); + + _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); if (_film->audio_channels() > 0) { _sound_asset.reset ( @@ -84,7 +84,30 @@ void Writer::write (shared_ptr encoded, int frame) { boost::mutex::scoped_lock lock (_mutex); - _queue.push_back (make_pair (encoded, frame)); + + QueueItem qi; + qi.type = QueueItem::FULL; + qi.encoded = encoded; + qi.frame = frame; + _queue.push_back (qi); + + _condition.notify_all (); +} + +void +Writer::fake_write (int frame) +{ + boost::mutex::scoped_lock lock (_mutex); + + ifstream ifi (_film->info_path (frame).c_str()); + libdcp::FrameInfo info (ifi); + + QueueItem qi; + qi.type = QueueItem::FAKE; + qi.size = info.size; + qi.frame = frame; + _queue.push_back (qi); + _condition.notify_all (); } @@ -95,13 +118,6 @@ Writer::write (shared_ptr audio) _sound_asset_writer->write (audio->data(), audio->frames()); } -struct QueueSorter -{ - bool operator() (pair, int> const & a, pair, int> const & b) { - return a.second < b.second; - } -}; - void Writer::thread () { @@ -112,7 +128,7 @@ Writer::thread () while (1) { if (_finish || _queue.size() > _maximum_frames_in_memory || - (!_queue.empty() && _queue.front().second == (_last_written_frame + 1))) { + (!_queue.empty() && _queue.front().frame == (_last_written_frame + 1))) { break; } @@ -121,7 +137,7 @@ Writer::thread () _condition.wait (lock); TIMING ("writer wakes with a queue of %1", _queue.size()); - _queue.sort (QueueSorter ()); + _queue.sort (); } if (_finish && _queue.empty() && _pending.empty()) { @@ -129,19 +145,32 @@ Writer::thread () } /* Write any frames that we can write; i.e. those that are in sequence */ - while (!_queue.empty() && _queue.front().second == (_last_written_frame + 1)) { - pair, int> encoded = _queue.front (); + while (!_queue.empty() && _queue.front().frame == (_last_written_frame + 1)) { + QueueItem qi = _queue.front (); _queue.pop_front (); lock.unlock (); - _film->log()->log (String::compose ("Writer writes %1 to MXF", encoded.second)); - if (encoded.first) { - libdcp::FrameInfo const fin = _picture_asset_writer->write (encoded.first->data(), encoded.first->size()); - encoded.first->write_info (_film, encoded.second, fin); - _last_written = encoded.first; - } else { + switch (qi.type) { + case QueueItem::FULL: + { + _film->log()->log (String::compose ("Writer FULL-writes %1 to MXF", qi.frame)); + libdcp::FrameInfo const fin = _picture_asset_writer->write (qi.encoded->data(), qi.encoded->size()); + qi.encoded->write_info (_film, qi.frame, fin); + _last_written = qi.encoded; + break; + } + case QueueItem::FAKE: + _film->log()->log (String::compose ("Writer FAKE-writes %1 to MXF", qi.frame)); + _picture_asset_writer->fake_write (qi.size); + _last_written.reset (); + break; + case QueueItem::REPEAT: + { + _film->log()->log (String::compose ("Writer REPEAT-writes %1 to MXF", qi.frame)); libdcp::FrameInfo const fin = _picture_asset_writer->write (_last_written->data(), _last_written->size()); - _last_written->write_info (_film, encoded.second, fin); + _last_written->write_info (_film, qi.frame, fin); + break; + } } lock.lock (); @@ -150,41 +179,39 @@ Writer::thread () while (_queue.size() > _maximum_frames_in_memory) { /* Too many frames in memory which can't yet be written to the stream. - Put some to disk. + Put some in our pending list (and write FULL queue items' data to disk) */ - pair, int> encoded = _queue.back (); + QueueItem qi = _queue.back (); _queue.pop_back (); - if (!encoded.first) { - /* This is a `repeat-last' frame, so no need to write it to disk */ - continue; - } - lock.unlock (); - _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, encoded.second)); - encoded.first->write (_film, encoded.second); - lock.lock (); + if (qi.type == QueueItem::FULL) { + lock.unlock (); + _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, qi.frame)); + qi.encoded->write (_film, qi.frame); + lock.lock (); + qi.encoded.reset (); + } - _pending.push_back (encoded.second); + _pending.push_back (qi); } while (_queue.size() < _maximum_frames_in_memory && !_pending.empty()) { /* We have some space in memory. Fetch some frames back off disk. */ _pending.sort (); - int const fetch = _pending.front (); - - lock.unlock (); - _film->log()->log (String::compose ("Writer pulls %1 back from disk", fetch)); - shared_ptr encoded; - if (boost::filesystem::exists (_film->j2c_path (fetch, false))) { - /* It's an actual frame (not a repeat-last); load it in */ - encoded.reset (new EncodedData (_film->j2c_path (fetch, false))); + QueueItem qi = _pending.front (); + + if (qi.type == QueueItem::FULL) { + lock.unlock (); + _film->log()->log (String::compose ("Writer pulls %1 back from disk", qi.frame)); + shared_ptr encoded; + qi.encoded.reset (new EncodedData (_film->j2c_path (qi.frame, false))); + lock.lock (); } - lock.lock (); - _queue.push_back (make_pair (encoded, fetch)); - _pending.remove (fetch); + _queue.push_back (qi); + _pending.remove (qi); } } @@ -266,20 +293,24 @@ void Writer::repeat (int f) { boost::mutex::scoped_lock lock (_mutex); - _queue.push_back (make_pair (shared_ptr (), f)); + + QueueItem qi; + qi.type = QueueItem::REPEAT; + qi.frame = f; + + _queue.push_back (qi); + + _condition.notify_all (); } + void Writer::check_existing_picture_mxf () { + /* Try to open the existing MXF */ boost::filesystem::path p; p /= _film->video_mxf_dir (); p /= _film->video_mxf_filename (); - if (!boost::filesystem::exists (p)) { - return; - } - - /* Try to open the picture MXF */ FILE* mxf = fopen (p.string().c_str(), "rb"); if (!mxf) { return; @@ -293,20 +324,38 @@ Writer::check_existing_picture_mxf () /* Read the data from the MXF and hash it */ fseek (mxf, info.offset, SEEK_SET); - uint8_t* data = new uint8_t[info.length]; - fread (data, 1, info.length, mxf); - string const existing_hash = md5_digest (data, info.length); - delete[] data; + EncodedData data (info.size); + fread (data.data(), 1, data.size(), mxf); + string const existing_hash = md5_digest (data.data(), data.size()); if (existing_hash != info.hash) { - cout << "frame " << _first_nonexistant_frame << " failed hash check.\n"; + _film->log()->log (String::compose ("Existing frame %1 failed hash check", _first_nonexistant_frame)); break; } - cout << "frame " << _first_nonexistant_frame << " ok.\n"; + _film->log()->log (String::compose ("Have existing frame %1", _first_nonexistant_frame)); ++_first_nonexistant_frame; } fclose (mxf); } +/** @return true if the fake write succeeded, otherwise false */ +bool +Writer::can_fake_write (int frame) const +{ + return (frame != 0 && frame < _first_nonexistant_frame); +} + + +bool +operator< (QueueItem const & a, QueueItem const & b) +{ + return a.frame < b.frame; +} + +bool +operator== (QueueItem const & a, QueueItem const & b) +{ + return a.frame == b.frame; +} diff --git a/src/lib/writer.h b/src/lib/writer.h index 768d63448..57609825d 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -33,12 +33,35 @@ namespace libdcp { class SoundAssetWriter; } +struct QueueItem +{ +public: + enum Type { + FULL, + FAKE, + REPEAT + } type; + + /** encoded data for FULL */ + boost::shared_ptr encoded; + /** size of data for FAKE */ + int size; + /** frame index */ + int frame; +}; + +bool operator< (QueueItem const & a, QueueItem const & b); +bool operator== (QueueItem const & a, QueueItem const & b); + class Writer { public: Writer (boost::shared_ptr); + + bool can_fake_write (int) const; void write (boost::shared_ptr, int); + void fake_write (int); void write (boost::shared_ptr); void repeat (int f); void finish (); @@ -53,11 +76,11 @@ private: boost::thread* _thread; bool _finish; - std::list, int> > _queue; + std::list _queue; mutable boost::mutex _mutex; boost::condition _condition; boost::shared_ptr _last_written; - std::list _pending; + std::list _pending; int _last_written_frame; static const unsigned int _maximum_frames_in_memory; -- cgit v1.2.3 From 9298f5a03786be14cfe3c37871e76f749617e6ca Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 7 Feb 2013 14:53:14 +0000 Subject: Add believed missing frame done. --- src/lib/encoder.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index b92be84a8..ccca719a3 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -256,6 +256,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrcan_fake_write (_video_frames_out)) { _writer->fake_write (_video_frames_out); _have_a_real_frame = false; + frame_done (); } else if (same && _have_a_real_frame) { /* Use the last frame that we encoded. */ _writer->repeat (_video_frames_out); -- cgit v1.2.3 From 748995a13c2a6758ef867b2b78b945342768bae7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 8 Feb 2013 12:47:51 +0000 Subject: Rename some things. --- src/lib/encoder.cc | 74 +++++++++++++++++++++++++++--------------------------- src/lib/encoder.h | 14 +++++------ 2 files changed, 44 insertions(+), 44 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index ccca719a3..8d8e8c0e4 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -61,14 +61,14 @@ Encoder::Encoder (shared_ptr f) , _swr_context (0) #endif , _have_a_real_frame (false) - , _terminate_encoder (false) + , _terminate (false) { } Encoder::~Encoder () { - terminate_worker_threads (); + terminate_threads (); if (_writer) { _writer->finish (); } @@ -107,14 +107,14 @@ Encoder::process_begin () } for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { - _worker_threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, (ServerDescription *) 0))); + _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, (ServerDescription *) 0))); } vector servers = Config::instance()->servers (); for (vector::iterator i = servers.begin(); i != servers.end(); ++i) { for (int j = 0; j < (*i)->threads (); ++j) { - _worker_threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, *i))); + _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, *i))); } } @@ -149,33 +149,33 @@ Encoder::process_end () } #endif - boost::mutex::scoped_lock lock (_worker_mutex); + boost::mutex::scoped_lock lock (_mutex); - _film->log()->log ("Clearing queue of " + lexical_cast (_encode_queue.size ())); + _film->log()->log ("Clearing queue of " + lexical_cast (_queue.size ())); /* Keep waking workers until the queue is empty */ - while (!_encode_queue.empty ()) { - _film->log()->log ("Waking with " + lexical_cast (_encode_queue.size ()), Log::VERBOSE); - _worker_condition.notify_all (); - _worker_condition.wait (lock); + while (!_queue.empty ()) { + _film->log()->log ("Waking with " + lexical_cast (_queue.size ()), Log::VERBOSE); + _condition.notify_all (); + _condition.wait (lock); } lock.unlock (); - terminate_worker_threads (); + terminate_threads (); - _film->log()->log ("Mopping up " + lexical_cast (_encode_queue.size())); + _film->log()->log ("Mopping up " + lexical_cast (_queue.size())); /* The following sequence of events can occur in the above code: 1. a remote worker takes the last image off the queue 2. the loop above terminates 3. the remote worker fails to encode the image and puts it back on the queue - 4. the remote worker is then terminated by terminate_worker_threads + 4. the remote worker is then terminated by terminate_threads So just mop up anything left in the queue here. */ - for (list >::iterator i = _encode_queue.begin(); i != _encode_queue.end(); ++i) { + for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); try { _writer->write ((*i)->encode_locally(), (*i)->frame ()); @@ -240,16 +240,16 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr= _worker_threads.size() * 2 && !_terminate_encoder) { - TIMING ("decoder sleeps with queue of %1", _encode_queue.size()); - _worker_condition.wait (lock); - TIMING ("decoder wakes with queue of %1", _encode_queue.size()); + while (_queue.size() >= _threads.size() * 2 && !_terminate) { + TIMING ("decoder sleeps with queue of %1", _queue.size()); + _condition.wait (lock); + TIMING ("decoder wakes with queue of %1", _queue.size()); } - if (_terminate_encoder) { + if (_terminate) { return; } @@ -264,8 +264,8 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); - TIMING ("adding to queue of %1", _encode_queue.size ()); - _encode_queue.push_back (boost::shared_ptr ( + TIMING ("adding to queue of %1", _queue.size ()); + _queue.push_back (boost::shared_ptr ( new DCPVideoFrame ( image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), @@ -275,7 +275,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr data) } void -Encoder::terminate_worker_threads () +Encoder::terminate_threads () { - boost::mutex::scoped_lock lock (_worker_mutex); - _terminate_encoder = true; - _worker_condition.notify_all (); + boost::mutex::scoped_lock lock (_mutex); + _terminate = true; + _condition.notify_all (); lock.unlock (); - for (list::iterator i = _worker_threads.begin(); i != _worker_threads.end(); ++i) { + for (list::iterator i = _threads.begin(); i != _threads.end(); ++i) { (*i)->join (); delete *i; } @@ -362,19 +362,19 @@ Encoder::encoder_thread (ServerDescription* server) while (1) { TIMING ("encoder thread %1 sleeps", boost::this_thread::get_id()); - boost::mutex::scoped_lock lock (_worker_mutex); - while (_encode_queue.empty () && !_terminate_encoder) { - _worker_condition.wait (lock); + boost::mutex::scoped_lock lock (_mutex); + while (_queue.empty () && !_terminate) { + _condition.wait (lock); } - if (_terminate_encoder) { + if (_terminate) { return; } - TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _encode_queue.size()); - boost::shared_ptr vf = _encode_queue.front (); + TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); + boost::shared_ptr vf = _queue.front (); _film->log()->log (String::compose ("Encoder thread %1 pops frame %2 from queue", boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); - _encode_queue.pop_front (); + _queue.pop_front (); lock.unlock (); @@ -421,7 +421,7 @@ Encoder::encoder_thread (ServerDescription* server) _film->log()->log ( String::compose ("Encoder thread %1 pushes frame %2 back onto queue after failure", boost::this_thread::get_id(), vf->frame()) ); - _encode_queue.push_front (vf); + _queue.push_front (vf); lock.unlock (); } @@ -430,6 +430,6 @@ Encoder::encoder_thread (ServerDescription* server) } lock.lock (); - _worker_condition.notify_all (); + _condition.notify_all (); } } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 8b02f7004..69a5c5a23 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -21,7 +21,7 @@ #define DVDOMATIC_ENCODER_H /** @file src/encoder.h - * @brief Parent class for classes which can encode video and audio frames. + * @brief Encoder to J2K and WAV for DCP. */ #include @@ -91,7 +91,7 @@ private: void write_audio (boost::shared_ptr audio); void encoder_thread (ServerDescription *); - void terminate_worker_threads (); + void terminate_threads (); /** Film that we are encoding */ boost::shared_ptr _film; @@ -115,11 +115,11 @@ private: #endif bool _have_a_real_frame; - bool _terminate_encoder; - std::list > _encode_queue; - std::list _worker_threads; - mutable boost::mutex _worker_mutex; - boost::condition _worker_condition; + bool _terminate; + std::list > _queue; + std::list _threads; + mutable boost::mutex _mutex; + boost::condition _condition; boost::shared_ptr _writer; }; -- cgit v1.2.3 From 567abac0d7824f27b8fdcd6fb7da7e5ddae62a0f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 8 Feb 2013 12:54:15 +0000 Subject: Some comments. --- src/lib/encoder.cc | 4 +--- src/lib/video_decoder.cc | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 8d8e8c0e4..0c810d12c 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -50,9 +50,7 @@ using namespace boost; int const Encoder::_history_size = 25; -/** @param f Film that we are encoding. - * @param o Options. - */ +/** @param f Film that we are encoding */ Encoder::Encoder (shared_ptr f) : _film (f) , _video_frames_in (0) diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 0fa16bc32..c11b752ae 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -53,6 +53,10 @@ VideoDecoder::emit_video (shared_ptr image, double t) _last_source_time = t; } +/** Called by subclasses to repeat the last video frame that we + * passed to emit_video(). If emit_video hasn't yet been called, + * we will generate a black frame. + */ void VideoDecoder::repeat_last_video () { @@ -64,6 +68,11 @@ VideoDecoder::repeat_last_video () signal_video (_last_image, true, _last_subtitle); } +/** Emit our signal to say that some video data is ready. + * @param image Video frame. + * @param same true if `image' is the same as the last one we emitted. + * @param sub Subtitle for this frame, or 0. + */ void VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub) { @@ -75,6 +84,11 @@ VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr s) { @@ -86,6 +100,9 @@ VideoDecoder::emit_subtitle (shared_ptr s) } } +/** Set which stream of subtitles we should use from our source. + * @param s Stream to use. + */ void VideoDecoder::set_subtitle_stream (shared_ptr s) { -- cgit v1.2.3 From beea3beacba34c11b6b73323f4c3c8590a9aa73e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 11 Feb 2013 00:18:40 +0000 Subject: Basic attempt to catch exceptions in the writer thread and pass them safely back to the GUI. --- src/lib/encoder.cc | 4 ++++ src/lib/exceptions.h | 32 ++++++++++++++++++++++++++++++++ src/lib/writer.cc | 13 ++++++++++--- src/lib/writer.h | 5 +++-- 4 files changed, 49 insertions(+), 5 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0c810d12c..d64622cba 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -251,6 +251,10 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrthrown ()) { + _writer->rethrow (); + } + if (_writer->can_fake_write (_video_frames_out)) { _writer->fake_write (_video_frames_out); _have_a_real_frame = false; diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index bf8e85f0b..e757d2506 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -17,6 +17,9 @@ */ +#ifndef DVDOMATIC_EXCEPTIONS_H +#define DVDOMATIC_EXCEPTIONS_H + /** @file src/exceptions.h * @brief Our exceptions. */ @@ -24,6 +27,8 @@ #include #include #include +#include +#include /** @class StringError * @brief A parent class for exceptions using messages held in a std::string @@ -224,3 +229,30 @@ public: : StringError (s) {} }; + +class ExceptionStore +{ +public: + bool thrown () const { + boost::mutex::scoped_lock lm (_mutex); + return _exception; + } + + void rethrow () { + boost::mutex::scoped_lock lm (_mutex); + boost::rethrow_exception (_exception); + } + +protected: + + void store_current () { + boost::mutex::scoped_lock lm (_mutex); + _exception = boost::current_exception (); + } + +private: + boost::exception_ptr _exception; + mutable boost::mutex _mutex; +}; + +#endif diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 1df8a4301..8a09f254b 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -85,7 +85,7 @@ Writer::Writer (shared_ptr f) _sound_asset_writer = _sound_asset->start_write (); } - + _thread = new boost::thread (boost::bind (&Writer::thread, this)); } @@ -130,6 +130,7 @@ Writer::write (shared_ptr audio) void Writer::thread () +try { while (1) { @@ -221,7 +222,10 @@ Writer::thread () --_queued_full_in_memory; } } - +} +catch (...) +{ + store_current (); } void @@ -237,6 +241,10 @@ Writer::finish () lock.unlock (); _thread->join (); + if (thrown ()) { + rethrow (); + } + delete _thread; _thread = 0; @@ -361,7 +369,6 @@ Writer::can_fake_write (int frame) const return (frame != 0 && frame < _first_nonexistant_frame); } - bool operator< (QueueItem const & a, QueueItem const & b) { diff --git a/src/lib/writer.h b/src/lib/writer.h index cee20acb9..beb16c7b9 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -21,6 +21,7 @@ #include #include #include +#include "exceptions.h" class Film; class EncodedData; @@ -59,7 +60,7 @@ public: bool operator< (QueueItem const & a, QueueItem const & b); bool operator== (QueueItem const & a, QueueItem const & b); -class Writer +class Writer : public ExceptionStore { public: Writer (boost::shared_ptr); @@ -113,7 +114,7 @@ private: due to the limit of frames to be held in memory. */ int _pushed_to_disk; - + boost::shared_ptr _picture_asset; boost::shared_ptr _picture_asset_writer; boost::shared_ptr _sound_asset; -- cgit v1.2.3 From c9831a8704aeae286be6c39bfbdc4b48cff1f087 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 18 Feb 2013 09:55:07 +0000 Subject: Try to fix crash on finishing off DCPs with mono -> 5.1 conversions. --- src/lib/encoder.cc | 42 ++++++++++++++++++++++++------------------ src/lib/encoder.h | 2 +- 2 files changed, 25 insertions(+), 19 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index d64622cba..f25256379 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -140,7 +140,7 @@ Encoder::process_end () } out->set_frames (frames); - _writer->write (out); + write_audio (out); } swr_free (&_swr_context); @@ -319,23 +319,7 @@ Encoder::process_audio (shared_ptr data) } #endif - if (_film->audio_channels() == 1) { - /* We need to switch things around so that the mono channel is on - the centre channel of a 5.1 set (with other channels silent). - */ - - shared_ptr b (new AudioBuffers (6, data->frames ())); - b->make_silent (libdcp::LEFT); - b->make_silent (libdcp::RIGHT); - memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float)); - b->make_silent (libdcp::LFE); - b->make_silent (libdcp::LS); - b->make_silent (libdcp::RS); - - data = b; - } - - _writer->write (data); + write_audio (data); } void @@ -435,3 +419,25 @@ Encoder::encoder_thread (ServerDescription* server) _condition.notify_all (); } } + +void +Encoder::write_audio (shared_ptr data) +{ + if (_film->audio_channels() == 1) { + /* We need to switch things around so that the mono channel is on + the centre channel of a 5.1 set (with other channels silent). + */ + + shared_ptr b (new AudioBuffers (6, data->frames ())); + b->make_silent (libdcp::LEFT); + b->make_silent (libdcp::RIGHT); + memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float)); + b->make_silent (libdcp::LFE); + b->make_silent (libdcp::LS); + b->make_silent (libdcp::RS); + + data = b; + } + + _writer->write (data); +} diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 69a5c5a23..86880bc34 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -88,7 +88,7 @@ private: void frame_done (); - void write_audio (boost::shared_ptr audio); + void write_audio (boost::shared_ptr data); void encoder_thread (ServerDescription *); void terminate_threads (); -- cgit v1.2.3 From eac941aed6e6eed7f0329e42c7a036ed620f8df0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 25 Feb 2013 20:52:20 +0000 Subject: Try to tidy up channel mapping a bit. --- src/lib/encoder.cc | 26 ++++++++++---------- src/lib/util.cc | 65 ++++++++++++++++++++++++++++++++++++++++---------- src/lib/util.h | 15 +++++++++++- src/lib/writer.cc | 6 +++-- src/wx/audio_dialog.cc | 32 +++++++++++++++++-------- 5 files changed, 106 insertions(+), 38 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index f25256379..07139968d 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -423,18 +423,20 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { - if (_film->audio_channels() == 1) { - /* We need to switch things around so that the mono channel is on - the centre channel of a 5.1 set (with other channels silent). - */ - - shared_ptr b (new AudioBuffers (6, data->frames ())); - b->make_silent (libdcp::LEFT); - b->make_silent (libdcp::RIGHT); - memcpy (b->data()[libdcp::CENTRE], data->data()[0], data->frames() * sizeof(float)); - b->make_silent (libdcp::LFE); - b->make_silent (libdcp::LS); - b->make_silent (libdcp::RS); + AudioMapping m (_film->audio_channels ()); + if (m.dcp_channels() != _film->audio_channels()) { + + /* Remap (currently just for mono -> 5.1) */ + + shared_ptr b (new AudioBuffers (m.dcp_channels(), data->frames ())); + for (int i = 0; i < m.dcp_channels(); ++i) { + optional s = m.dcp_to_source (static_cast (i)); + if (!s) { + b->make_silent (i); + } else { + memcpy (b->data()[i], data->data()[s.get()], data->frames() * sizeof(float)); + } + } data = b; } diff --git a/src/lib/util.cc b/src/lib/util.cc index f807bf329..8ad980361 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -445,19 +445,6 @@ dcp_audio_sample_rate (int fs) return 96000; } -int -dcp_audio_channels (int f) -{ - if (f == 1) { - /* The source is mono, so to put the mono channel into - the centre we need to generate a 5.1 soundtrack. - */ - return 6; - } - - return f; -} - bool operator== (Crop const & a, Crop const & b) { return (a.left == b.left && a.right == b.right && a.top == b.top && a.bottom == b.bottom); @@ -918,3 +905,55 @@ audio_channel_name (int c) return channels[c]; } + +AudioMapping::AudioMapping (int c) + : _source_channels (c) +{ + +} + +optional +AudioMapping::source_to_dcp (int c) const +{ + if (c >= _source_channels) { + return optional (); + } + + if (_source_channels == 1) { + /* mono sources to centre */ + return libdcp::CENTRE; + } + + return static_cast (c); +} + +optional +AudioMapping::dcp_to_source (libdcp::Channel c) const +{ + if (_source_channels == 1) { + if (c == libdcp::CENTRE) { + return 0; + } else { + return optional (); + } + } + + if (static_cast (c) >= _source_channels) { + return optional (); + } + + return static_cast (c); +} + +int +AudioMapping::dcp_channels () const +{ + if (_source_channels == 1) { + /* The source is mono, so to put the mono channel into + the centre we need to generate a 5.1 soundtrack. + */ + return 6; + } + + return _source_channels; +} diff --git a/src/lib/util.h b/src/lib/util.h index b76aead41..22c6ea95b 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -29,6 +29,7 @@ #include #include #include +#include #include extern "C" { #include @@ -179,7 +180,6 @@ struct Rect extern std::string crop_string (Position, libdcp::Size); extern int dcp_audio_sample_rate (int); -extern int dcp_audio_channels (int); extern std::string colour_lut_index_to_name (int index); extern int stride_round_up (int, int const *, int); extern int stride_lookup (int c, int const * stride); @@ -269,6 +269,19 @@ private: float** _data; }; +class AudioMapping +{ +public: + AudioMapping (int); + + boost::optional source_to_dcp (int c) const; + boost::optional dcp_to_source (libdcp::Channel c) const; + int dcp_channels () const; + +private: + int _source_channels; +}; + extern int64_t video_frames_to_audio_frames (SourceFrame v, float audio_sample_rate, float frames_per_second); extern bool still_image_file (std::string); extern std::pair cpu_info (); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index c2cc00328..1dad4357d 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -72,13 +72,15 @@ Writer::Writer (shared_ptr f) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - if (dcp_audio_channels (_film->audio_channels()) > 0) { + AudioMapping m (_film->audio_channels ()); + + if (m.dcp_channels() > 0) { _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), "audio.mxf", DCPFrameRate (_film->frames_per_second()).frames_per_second, - dcp_audio_channels (_film->audio_channels()), + m.dcp_channels (), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) ) ); diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index dc297e246..a422e4e46 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -26,6 +26,7 @@ using boost::shared_ptr; using boost::bind; +using boost::optional; AudioDialog::AudioDialog (wxWindow* parent) : wxDialog (parent, wxID_ANY, _("Audio"), wxDefaultPosition, wxSize (640, 512), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) @@ -89,13 +90,15 @@ AudioDialog::setup_channels () if (!_film->audio_stream()) { return; } - - for (int i = 0; i < _film->audio_stream()->channels(); ++i) { - _channel_checkbox[i]->Show (); - } - for (int i = _film->audio_stream()->channels(); i < MAX_AUDIO_CHANNELS; ++i) { - _channel_checkbox[i]->Hide (); + AudioMapping m (_film->audio_stream()->channels ()); + + for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { + if (m.dcp_to_source(static_cast(i))) { + _channel_checkbox[i]->Show (); + } else { + _channel_checkbox[i]->Hide (); + } } } @@ -113,8 +116,13 @@ AudioDialog::try_to_load_analysis () } _plot->set_analysis (a); - _channel_checkbox[0]->SetValue (true); - _plot->set_channel_visible (0, true); + + AudioMapping m (_film->audio_stream()->channels ()); + optional c = m.source_to_dcp (0); + if (c) { + _channel_checkbox[c.get()]->SetValue (true); + _plot->set_channel_visible (0, true); + } for (int i = 0; i < AudioPoint::COUNT; ++i) { _type_checkbox[i]->SetValue (true); @@ -131,8 +139,12 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) } assert (c < MAX_AUDIO_CHANNELS); - - _plot->set_channel_visible (c, _channel_checkbox[c]->GetValue ()); + + AudioMapping m (_film->audio_stream()->channels ()); + optional s = m.dcp_to_source (static_cast (c)); + if (s) { + _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); + } } void -- cgit v1.2.3 From 0d3f5aae5b99832b7c5d55f32f5bccb365caa3fd Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 28 Feb 2013 22:20:07 +0000 Subject: Various markup and tweaks. --- TRANSLATORS | 2 +- i18n.py | 10 +- run/dvdomatic | 3 + src/lib/ab_transcode_job.cc | 4 +- src/lib/config.cc | 54 ++++---- src/lib/dci_metadata.cc | 30 ++-- src/lib/dcp_content_type.cc | 22 +-- src/lib/dcp_video_frame.cc | 62 +++++---- src/lib/decoder.cc | 6 +- src/lib/dolby_cp750.cc | 4 +- src/lib/encoder.cc | 44 +++--- src/lib/examine_content_job.cc | 10 +- src/lib/external_audio_decoder.cc | 12 +- src/lib/ffmpeg_compatibility.cc | 10 +- src/lib/ffmpeg_decoder.cc | 50 +++---- src/lib/film.cc | 284 +++++++++++++++++++------------------- src/lib/filter.cc | 54 ++++---- src/lib/filter_graph.cc | 48 ++++--- src/lib/format.cc | 35 ++--- src/lib/image.cc | 8 +- src/lib/imagemagick_decoder.cc | 4 +- src/lib/job.cc | 23 +-- src/lib/log.cc | 12 +- src/lib/matcher.cc | 10 +- src/lib/scaler.cc | 20 +-- src/lib/scp_dcp_job.cc | 36 ++--- src/lib/server.cc | 44 +++--- src/lib/stream.cc | 4 +- src/lib/subtitle.cc | 6 +- src/lib/timer.cc | 10 +- src/lib/transcode_job.cc | 14 +- src/lib/util.cc | 80 ++++++----- src/lib/video_decoder.cc | 4 +- src/lib/writer.cc | 28 ++-- src/tools/dvdomatic.cc | 10 +- src/wx/config_dialog.cc | 4 +- src/wx/film_editor.cc | 23 ++- src/wx/film_viewer.cc | 2 +- src/wx/properties_dialog.cc | 2 +- src/wx/server_dialog.cc | 2 +- wscript | 4 +- 41 files changed, 580 insertions(+), 514 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/TRANSLATORS b/TRANSLATORS index cbfc875d4..625b03613 100644 --- a/TRANSLATORS +++ b/TRANSLATORS @@ -1,7 +1,7 @@ Translating DVD-o-matic ----------------------- -1. Run ./waf po +1. Run ./waf pot This will generate build/src/lib/dvdomatic.pot and build/src/wx/libdvdomatic-wx.pot. diff --git a/i18n.py b/i18n.py index 10eaa38e9..c22cbdb95 100644 --- a/i18n.py +++ b/i18n.py @@ -2,15 +2,19 @@ import glob import os from waflib import Logs -def pot(dir, sources, name): +def pot(dir, sources, name, all = False): s = "" for f in sources.split('\n'): t = f.strip() if len(t) > 0: s += (os.path.join(dir, t)) + " " - Logs.info('Making %s.pot' % os.path.join('build', dir, name)) - os.system('xgettext -d %s -s --keyword=_ -p %s -o %s.pot %s' % (name, os.path.join('build', dir), name, s)) + if all: + Logs.info('Making %s.pot (extracting all)' % os.path.join('build', dir, name)) + os.system('xgettext -d %s -s --extract-all -p %s -o %s.pot %s' % (name, os.path.join('build', dir), name, s)) + else: + Logs.info('Making %s.pot' % os.path.join('build', dir, name)) + os.system('xgettext -d %s -s --keyword=_ --add-comments=/ -p %s -o %s.pot %s' % (name, os.path.join('build', dir), name, s)) def po_to_mo(dir, name): diff --git a/run/dvdomatic b/run/dvdomatic index ff3897064..31fd09fb9 100755 --- a/run/dvdomatic +++ b/run/dvdomatic @@ -7,6 +7,9 @@ if [ "$1" == "--debug" ]; then elif [ "$1" == "--valgrind" ]; then shift valgrind --tool="memcheck" build/src/tools/dvdomatic $* +elif [ "$1" == "--i18n" ]; then + shift + LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*" else build/src/tools/dvdomatic "$*" fi diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index 025c23c86..4ffdd9af6 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -26,6 +26,8 @@ #include "config.h" #include "encoder.h" +#include "i18n.h" + using std::string; using boost::shared_ptr; @@ -44,7 +46,7 @@ ABTranscodeJob::ABTranscodeJob (shared_ptr f, DecodeOptions o) string ABTranscodeJob::name () const { - return String::compose ("A/B transcode %1", _film->name()); + return String::compose (_("A/B transcode %1"), _film->name()); } void diff --git a/src/lib/config.cc b/src/lib/config.cc index c165859b0..82a31b3cf 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -28,6 +28,8 @@ #include "filter.h" #include "sound_processor.h" +#include "i18n.h" + using std::vector; using std::ifstream; using std::string; @@ -40,9 +42,9 @@ Config* Config::_instance = 0; Config::Config () : _num_local_encoding_threads (2) , _server_port (6192) - , _reference_scaler (Scaler::from_id ("bicubic")) - , _tms_path (".") - , _sound_processor (SoundProcessor::from_id ("dolby_cp750")) + , _reference_scaler (Scaler::from_id (N_("bicubic"))) + , _tms_path (N_(".")) + , _sound_processor (SoundProcessor::from_id (N_("dolby_cp750"))) { _allowed_dcp_frame_rates.push_back (24); _allowed_dcp_frame_rates.push_back (25); @@ -67,27 +69,27 @@ Config::Config () string const k = line.substr (0, s); string const v = line.substr (s + 1); - if (k == "num_local_encoding_threads") { + if (k == N_("num_local_encoding_threads")) { _num_local_encoding_threads = atoi (v.c_str ()); - } else if (k == "default_directory") { + } else if (k == N_("default_directory")) { _default_directory = v; - } else if (k == "server_port") { + } else if (k == N_("server_port")) { _server_port = atoi (v.c_str ()); - } else if (k == "reference_scaler") { + } else if (k == N_("reference_scaler")) { _reference_scaler = Scaler::from_id (v); - } else if (k == "reference_filter") { + } else if (k == N_("reference_filter")) { _reference_filters.push_back (Filter::from_id (v)); - } else if (k == "server") { + } else if (k == N_("server")) { _servers.push_back (ServerDescription::create_from_metadata (v)); - } else if (k == "tms_ip") { + } else if (k == N_("tms_ip")) { _tms_ip = v; - } else if (k == "tms_path") { + } else if (k == N_("tms_path")) { _tms_path = v; - } else if (k == "tms_user") { + } else if (k == N_("tms_user")) { _tms_user = v; - } else if (k == "tms_password") { + } else if (k == N_("tms_password")) { _tms_password = v; - } else if (k == "sound_processor") { + } else if (k == N_("sound_processor")) { _sound_processor = SoundProcessor::from_id (v); } @@ -101,7 +103,7 @@ Config::file () const { boost::filesystem::path p; p /= g_get_user_config_dir (); - p /= ".dvdomatic"; + p /= N_(".dvdomatic"); return p.string (); } @@ -121,24 +123,24 @@ void Config::write () const { ofstream f (file().c_str ()); - f << "num_local_encoding_threads " << _num_local_encoding_threads << "\n" - << "default_directory " << _default_directory << "\n" - << "server_port " << _server_port << "\n" - << "reference_scaler " << _reference_scaler->id () << "\n"; + f << N_("num_local_encoding_threads ") << _num_local_encoding_threads << N_("\n") + << N_("default_directory ") << _default_directory << N_("\n") + << N_("server_port ") << _server_port << N_("\n") + << N_("reference_scaler ") << _reference_scaler->id () << N_("\n"); for (vector::const_iterator i = _reference_filters.begin(); i != _reference_filters.end(); ++i) { - f << "reference_filter " << (*i)->id () << "\n"; + f << N_("reference_filter ") << (*i)->id () << N_("\n"); } for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { - f << "server " << (*i)->as_metadata () << "\n"; + f << N_("server ") << (*i)->as_metadata () << N_("\n"); } - f << "tms_ip " << _tms_ip << "\n"; - f << "tms_path " << _tms_path << "\n"; - f << "tms_user " << _tms_user << "\n"; - f << "tms_password " << _tms_password << "\n"; - f << "sound_processor " << _sound_processor->id () << "\n"; + f << N_("tms_ip ") << _tms_ip << N_("\n"); + f << N_("tms_path ") << _tms_path << N_("\n"); + f << N_("tms_user ") << _tms_user << N_("\n"); + f << N_("tms_password ") << _tms_password << N_("\n"); + f << N_("sound_processor ") << _sound_processor->id () << N_("\n"); _default_dci_metadata.write (f); } diff --git a/src/lib/dci_metadata.cc b/src/lib/dci_metadata.cc index 2b4cc3ae7..758886db4 100644 --- a/src/lib/dci_metadata.cc +++ b/src/lib/dci_metadata.cc @@ -20,36 +20,38 @@ #include #include "dci_metadata.h" +#include "i18n.h" + using namespace std; void DCIMetadata::write (ostream& f) const { - f << "audio_language " << audio_language << "\n"; - f << "subtitle_language " << subtitle_language << "\n"; - f << "territory " << territory << "\n"; - f << "rating " << rating << "\n"; - f << "studio " << studio << "\n"; - f << "facility " << facility << "\n"; - f << "package_type " << package_type << "\n"; + f << N_("audio_language ") << audio_language << N_("\n"); + f << N_("subtitle_language ") << subtitle_language << N_("\n"); + f << N_("territory ") << territory << N_("\n"); + f << N_("rating ") << rating << N_("\n"); + f << N_("studio ") << studio << N_("\n"); + f << N_("facility ") << facility << N_("\n"); + f << N_("package_type ") << package_type << N_("\n"); } void DCIMetadata::read (string k, string v) { - if (k == "audio_language") { + if (k == N_("audio_language")) { audio_language = v; - } else if (k == "subtitle_language") { + } else if (k == N_("subtitle_language")) { subtitle_language = v; - } else if (k == "territory") { + } else if (k == N_("territory")) { territory = v; - } else if (k == "rating") { + } else if (k == N_("rating")) { rating = v; - } else if (k == "studio") { + } else if (k == N_("studio")) { studio = v; - } else if (k == "facility") { + } else if (k == N_("facility")) { facility = v; - } else if (k == "package_type") { + } else if (k == N_("package_type")) { package_type = v; } } diff --git a/src/lib/dcp_content_type.cc b/src/lib/dcp_content_type.cc index 1c96979e4..82bd5fa01 100644 --- a/src/lib/dcp_content_type.cc +++ b/src/lib/dcp_content_type.cc @@ -24,6 +24,8 @@ #include #include "dcp_content_type.h" +#include "i18n.h" + using namespace std; vector DCPContentType::_dcp_content_types; @@ -39,16 +41,16 @@ DCPContentType::DCPContentType (string p, libdcp::ContentKind k, string d) void DCPContentType::setup_dcp_content_types () { - _dcp_content_types.push_back (new DCPContentType ("Feature", libdcp::FEATURE, "FTR")); - _dcp_content_types.push_back (new DCPContentType ("Short", libdcp::SHORT, "SHR")); - _dcp_content_types.push_back (new DCPContentType ("Trailer", libdcp::TRAILER, "TLR")); - _dcp_content_types.push_back (new DCPContentType ("Test", libdcp::TEST, "TST")); - _dcp_content_types.push_back (new DCPContentType ("Transitional", libdcp::TRANSITIONAL, "XSN")); - _dcp_content_types.push_back (new DCPContentType ("Rating", libdcp::RATING, "RTG")); - _dcp_content_types.push_back (new DCPContentType ("Teaser", libdcp::TEASER, "TSR")); - _dcp_content_types.push_back (new DCPContentType ("Policy", libdcp::POLICY, "POL")); - _dcp_content_types.push_back (new DCPContentType ("Public Service Announcement", libdcp::PUBLIC_SERVICE_ANNOUNCEMENT, "PSA")); - _dcp_content_types.push_back (new DCPContentType ("Advertisement", libdcp::ADVERTISEMENT, "ADV")); + _dcp_content_types.push_back (new DCPContentType (_("Feature"), libdcp::FEATURE, N_("FTR"))); + _dcp_content_types.push_back (new DCPContentType (_("Short"), libdcp::SHORT, N_("SHR"))); + _dcp_content_types.push_back (new DCPContentType (_("Trailer"), libdcp::TRAILER, N_("TLR"))); + _dcp_content_types.push_back (new DCPContentType (_("Test"), libdcp::TEST, N_("TST"))); + _dcp_content_types.push_back (new DCPContentType (_("Transitional"), libdcp::TRANSITIONAL, N_("XSN"))); + _dcp_content_types.push_back (new DCPContentType (_("Rating"), libdcp::RATING, N_("RTG"))); + _dcp_content_types.push_back (new DCPContentType (_("Teaser"), libdcp::TEASER, N_("TSR"))); + _dcp_content_types.push_back (new DCPContentType (_("Policy"), libdcp::POLICY, N_("POL"))); + _dcp_content_types.push_back (new DCPContentType (_("Public Service Announcement"), libdcp::PUBLIC_SERVICE_ANNOUNCEMENT, N_("PSA"))); + _dcp_content_types.push_back (new DCPContentType (_("Advertisement"), libdcp::ADVERTISEMENT, N_("ADV"))); } DCPContentType const * diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 9b96724b0..098d222cd 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -56,6 +56,8 @@ #include "log.h" #include "subtitle.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::ofstream; @@ -119,7 +121,7 @@ DCPVideoFrame::create_openjpeg_container () _image = opj_image_create (3, &_cmptparm[0], CLRSPC_SRGB); if (_image == 0) { - throw EncodeError ("could not create libopenjpeg image"); + throw EncodeError (N_("could not create libopenjpeg image")); } _image->x0 = 0; @@ -265,7 +267,7 @@ DCPVideoFrame::encode_locally () _parameters->tcp_numlayers++; _parameters->cp_disto_alloc = 1; _parameters->cp_rsiz = CINEMA2K; - _parameters->cp_comment = strdup ("DVD-o-matic"); + _parameters->cp_comment = strdup (N_("DVD-o-matic")); _parameters->cp_cinema = CINEMA2K_24; /* 3 components, so use MCT */ @@ -278,7 +280,7 @@ DCPVideoFrame::encode_locally () /* get a J2K compressor handle */ _cinfo = opj_create_compress (CODEC_J2K); if (_cinfo == 0) { - throw EncodeError ("could not create JPEG2000 encoder"); + throw EncodeError (N_("could not create JPEG2000 encoder")); } /* Set event manager to null (openjpeg 1.3 bug) */ @@ -289,15 +291,15 @@ DCPVideoFrame::encode_locally () _cio = opj_cio_open ((opj_common_ptr) _cinfo, 0, 0); if (_cio == 0) { - throw EncodeError ("could not open JPEG2000 stream"); + throw EncodeError (N_("could not open JPEG2000 stream")); } int const r = opj_encode (_cinfo, _cio, _image, 0); if (r == 0) { - throw EncodeError ("JPEG2000 encoding failed"); + throw EncodeError (N_("JPEG2000 encoding failed")); } - _log->log (String::compose ("Finished locally-encoded frame %1", _frame)); + _log->log (String::compose (N_("Finished locally-encoded frame %1"), _frame)); return shared_ptr (new LocallyEncodedData (_cio->buffer, cio_tell (_cio))); } @@ -319,35 +321,35 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) socket->connect (*endpoint_iterator); stringstream s; - s << "encode please\n" - << "input_width " << _input->size().width << "\n" - << "input_height " << _input->size().height << "\n" - << "input_pixel_format " << _input->pixel_format() << "\n" - << "output_width " << _out_size.width << "\n" - << "output_height " << _out_size.height << "\n" - << "padding " << _padding << "\n" - << "subtitle_offset " << _subtitle_offset << "\n" - << "subtitle_scale " << _subtitle_scale << "\n" - << "scaler " << _scaler->id () << "\n" - << "frame " << _frame << "\n" - << "frames_per_second " << _frames_per_second << "\n"; + s << N_("encode please\n") + << N_("input_width ") << _input->size().width << N_("\n") + << N_("input_height ") << _input->size().height << N_("\n") + << N_("input_pixel_format ") << _input->pixel_format() << N_("\n") + << N_("output_width ") << _out_size.width << N_("\n") + << N_("output_height ") << _out_size.height << N_("\n") + << N_("padding ") << _padding << N_("\n") + << N_("subtitle_offset ") << _subtitle_offset << N_("\n") + << N_("subtitle_scale ") << _subtitle_scale << N_("\n") + << N_("scaler ") << _scaler->id () << N_("\n") + << N_("frame ") << _frame << N_("\n") + << N_("frames_per_second ") << _frames_per_second << N_("\n"); if (!_post_process.empty()) { - s << "post_process " << _post_process << "\n"; + s << N_("post_process ") << _post_process << N_("\n"); } - s << "colour_lut " << _colour_lut << "\n" - << "j2k_bandwidth " << _j2k_bandwidth << "\n"; + s << N_("colour_lut ") << _colour_lut << N_("\n") + << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); if (_subtitle) { - s << "subtitle_x " << _subtitle->position().x << "\n" - << "subtitle_y " << _subtitle->position().y << "\n" - << "subtitle_width " << _subtitle->image()->size().width << "\n" - << "subtitle_height " << _subtitle->image()->size().height << "\n"; + s << N_("subtitle_x ") << _subtitle->position().x << N_("\n") + << N_("subtitle_y ") << _subtitle->position().y << N_("\n") + << N_("subtitle_width ") << _subtitle->image()->size().width << N_("\n") + << N_("subtitle_height ") << _subtitle->image()->size().height << N_("\n"); } _log->log (String::compose ( - "Sending to remote; pixel format %1, components %2, lines (%3,%4,%5), line sizes (%6,%7,%8)", + N_("Sending to remote; pixel format %1, components %2, lines (%3,%4,%5), line sizes (%6,%7,%8)"), _input->pixel_format(), _input->components(), _input->lines(0), _input->lines(1), _input->lines(2), _input->line_size()[0], _input->line_size()[1], _input->line_size()[2] @@ -364,7 +366,7 @@ DCPVideoFrame::encode_remotely (ServerDescription const * serv) shared_ptr e (new RemotelyEncodedData (socket->read_uint32 ())); socket->read (e->data(), e->size()); - _log->log (String::compose ("Finished remotely-encoded frame %1", _frame)); + _log->log (String::compose (N_("Finished remotely-encoded frame %1"), _frame)); return e; } @@ -381,9 +383,9 @@ EncodedData::EncodedData (string file) _size = boost::filesystem::file_size (file); _data = new uint8_t[_size]; - FILE* f = fopen (file.c_str(), "rb"); + FILE* f = fopen (file.c_str(), N_("rb")); if (!f) { - throw FileError ("could not open file for reading", file); + throw FileError (_("could not open file for reading"), file); } fread (_data, 1, _size, f); @@ -405,7 +407,7 @@ EncodedData::write (shared_ptr film, int frame) const { string const tmp_j2c = film->j2c_path (frame, true); - FILE* f = fopen (tmp_j2c.c_str (), "wb"); + FILE* f = fopen (tmp_j2c.c_str (), N_("wb")); if (!f) { throw WriteFileError (tmp_j2c, errno); diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 30009460f..52b22fa06 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -36,6 +36,8 @@ #include "subtitle.h" #include "filter_graph.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::min; @@ -60,7 +62,7 @@ Decoder::Decoder (boost::shared_ptr f, DecodeOptions o) bool Decoder::seek (double) { - throw DecodeError ("decoder does not support seek"); + throw DecodeError (N_("decoder does not support seek")); } /** Seek so that the next frame we will produce is the same as the last one. @@ -69,5 +71,5 @@ Decoder::seek (double) bool Decoder::seek_to_last () { - throw DecodeError ("decoder does not support seek"); + throw DecodeError (N_("decoder does not support seek")); } diff --git a/src/lib/dolby_cp750.cc b/src/lib/dolby_cp750.cc index 262e57bc7..b45e62b87 100644 --- a/src/lib/dolby_cp750.cc +++ b/src/lib/dolby_cp750.cc @@ -19,10 +19,12 @@ #include "dolby_cp750.h" +#include "i18n.h" + using namespace std; DolbyCP750::DolbyCP750 () - : SoundProcessor ("dolby_cp750", "Dolby CP750") + : SoundProcessor ("dolby_cp750", _("Dolby CP750")) { } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index f25256379..d4a27d01b 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -39,6 +39,8 @@ #include "cross.h" #include "writer.h" +#include "i18n.h" + using std::pair; using std::string; using std::stringstream; @@ -79,7 +81,7 @@ Encoder::process_begin () #ifdef HAVE_SWRESAMPLE stringstream s; - s << "Will resample audio from " << _film->audio_stream()->sample_rate() << " to " << _film->target_audio_sample_rate(); + s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_stream()->sample_rate(), _film->target_audio_sample_rate()); _film->log()->log (s.str ()); /* We will be using planar float data when we call the resampler */ @@ -96,7 +98,7 @@ Encoder::process_begin () swr_init (_swr_context); #else - throw EncodeError ("Cannot resample audio as libswresample is not present"); + throw EncodeError (_("Cannot resample audio as libswresample is not present")); #endif } else { #ifdef HAVE_SWRESAMPLE @@ -132,7 +134,7 @@ Encoder::process_end () int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); if (frames < 0) { - throw EncodeError ("could not run sample-rate converter"); + throw EncodeError (_("could not run sample-rate converter")); } if (frames == 0) { @@ -149,11 +151,11 @@ Encoder::process_end () boost::mutex::scoped_lock lock (_mutex); - _film->log()->log ("Clearing queue of " + lexical_cast (_queue.size ())); + _film->log()->log (String::compose (N_("Clearing queue of %1"), _queue.size ())); /* Keep waking workers until the queue is empty */ while (!_queue.empty ()) { - _film->log()->log ("Waking with " + lexical_cast (_queue.size ()), Log::VERBOSE); + _film->log()->log (String::compose (N_("Waking with %1"), _queue.size ()), Log::VERBOSE); _condition.notify_all (); _condition.wait (lock); } @@ -162,7 +164,7 @@ Encoder::process_end () terminate_threads (); - _film->log()->log ("Mopping up " + lexical_cast (_queue.size())); + _film->log()->log (String::compose (N_("Mopping up %1"), _queue.size())); /* The following sequence of events can occur in the above code: 1. a remote worker takes the last image off the queue @@ -174,12 +176,12 @@ Encoder::process_end () */ for (list >::iterator i = _queue.begin(); i != _queue.end(); ++i) { - _film->log()->log (String::compose ("Encode left-over frame %1", (*i)->frame ())); + _film->log()->log (String::compose (N_("Encode left-over frame %1"), (*i)->frame ())); try { _writer->write ((*i)->encode_locally(), (*i)->frame ()); frame_done (); } catch (std::exception& e) { - _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); + _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); } } @@ -242,9 +244,9 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr= _threads.size() * 2 && !_terminate) { - TIMING ("decoder sleeps with queue of %1", _queue.size()); + TIMING (_("decoder sleeps with queue of %1"), _queue.size()); _condition.wait (lock); - TIMING ("decoder wakes with queue of %1", _queue.size()); + TIMING (_("decoder wakes with queue of %1"), _queue.size()); } if (_terminate) { @@ -266,7 +268,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); - TIMING ("adding to queue of %1", _queue.size ()); + TIMING (_("adding to queue of %1"), _queue.size ()); _queue.push_back (boost::shared_ptr ( new DCPVideoFrame ( image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), @@ -309,7 +311,7 @@ Encoder::process_audio (shared_ptr data) ); if (resampled_frames < 0) { - throw EncodeError ("could not run sample-rate converter"); + throw EncodeError (_("could not run sample-rate converter")); } resampled->set_frames (resampled_frames); @@ -347,7 +349,7 @@ Encoder::encoder_thread (ServerDescription* server) while (1) { - TIMING ("encoder thread %1 sleeps", boost::this_thread::get_id()); + TIMING (N_("encoder thread %1 sleeps"), boost::this_thread::get_id()); boost::mutex::scoped_lock lock (_mutex); while (_queue.empty () && !_terminate) { _condition.wait (lock); @@ -357,9 +359,9 @@ Encoder::encoder_thread (ServerDescription* server) return; } - TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); + TIMING (N_("encoder thread %1 wakes with queue of %2"), boost::this_thread::get_id(), _queue.size()); boost::shared_ptr vf = _queue.front (); - _film->log()->log (String::compose ("Encoder thread %1 pops frame %2 from queue", boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); + _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 from queue"), boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); _queue.pop_front (); lock.unlock (); @@ -371,7 +373,7 @@ Encoder::encoder_thread (ServerDescription* server) encoded = vf->encode_remotely (server); if (remote_backoff > 0) { - _film->log()->log (String::compose ("%1 was lost, but now she is found; removing backoff", server->host_name ())); + _film->log()->log (String::compose (N_("%1 was lost, but now she is found; removing backoff"), server->host_name ())); } /* This job succeeded, so remove any backoff */ @@ -384,18 +386,18 @@ Encoder::encoder_thread (ServerDescription* server) } _film->log()->log ( String::compose ( - "Remote encode of %1 on %2 failed (%3); thread sleeping for %4s", + N_("Remote encode of %1 on %2 failed (%3); thread sleeping for %4s"), vf->frame(), server->host_name(), e.what(), remote_backoff) ); } } else { try { - TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->frame()); + TIMING (N_("encoder thread %1 begins local encode of %2"), boost::this_thread::get_id(), vf->frame()); encoded = vf->encode_locally (); - TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->frame()); + TIMING (N_("encoder thread %1 finishes local encode of %2"), boost::this_thread::get_id(), vf->frame()); } catch (std::exception& e) { - _film->log()->log (String::compose ("Local encode failed (%1)", e.what ())); + _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); } } @@ -405,7 +407,7 @@ Encoder::encoder_thread (ServerDescription* server) } else { lock.lock (); _film->log()->log ( - String::compose ("Encoder thread %1 pushes frame %2 back onto queue after failure", boost::this_thread::get_id(), vf->frame()) + String::compose (N_("Encoder thread %1 pushes frame %2 back onto queue after failure"), boost::this_thread::get_id(), vf->frame()) ); _queue.push_front (vf); lock.unlock (); diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index 31d76c4f7..4b30c9431 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -31,6 +31,8 @@ #include "film.h" #include "video_decoder.h" +#include "i18n.h" + using std::string; using std::vector; using std::pair; @@ -50,10 +52,10 @@ string ExamineContentJob::name () const { if (_film->name().empty ()) { - return "Examine content"; + return _("Examine content"); } - return String::compose ("Examine content of %1", _film->name()); + return String::compose (_("Examine content of %1"), _film->name()); } void @@ -90,7 +92,7 @@ ExamineContentJob::run () _film->set_length (decoders.video->video_frame()); - _film->log()->log (String::compose ("Video length examined as %1 frames", _film->length().get())); + _film->log()->log (String::compose (N_("Video length examined as %1 frames"), _film->length().get())); } else { @@ -99,7 +101,7 @@ ExamineContentJob::run () Decoders d = decoder_factory (_film, DecodeOptions()); _film->set_length (d.video->length()); - _film->log()->log (String::compose ("Video length obtained from header as %1 frames", _film->length().get())); + _film->log()->log (String::compose (N_("Video length obtained from header as %1 frames"), _film->length().get())); } ascend (); diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc index 9c01bfb34..1248b5a3b 100644 --- a/src/lib/external_audio_decoder.cc +++ b/src/lib/external_audio_decoder.cc @@ -23,6 +23,8 @@ #include "film.h" #include "exceptions.h" +#include "i18n.h" + using std::vector; using std::string; using std::stringstream; @@ -67,11 +69,11 @@ ExternalAudioDecoder::open_files (sf_count_t & frames) SF_INFO info; SNDFILE* s = sf_open (files[i].c_str(), SFM_READ, &info); if (!s) { - throw DecodeError ("could not open external audio file for reading"); + throw DecodeError (_("could not open external audio file for reading")); } if (info.channels != 1) { - throw DecodeError ("external audio files must be mono"); + throw DecodeError (_("external audio files must be mono")); } sndfiles.push_back (s); @@ -89,7 +91,7 @@ ExternalAudioDecoder::open_files (sf_count_t & frames) first = false; } else { if (info.frames != frames) { - throw DecodeError ("external audio files have differing lengths"); + throw DecodeError (_("external audio files have differing lengths")); } } } @@ -158,7 +160,7 @@ ExternalAudioStream::create (string t, optional v) stringstream s (t); string type; s >> type; - if (type != "external") { + if (type != N_("external")) { return shared_ptr (); } @@ -182,5 +184,5 @@ ExternalAudioStream::ExternalAudioStream () string ExternalAudioStream::to_string () const { - return String::compose ("external %1 %2", _sample_rate, _channel_layout); + return String::compose (N_("external %1 %2"), _sample_rate, _channel_layout); } diff --git a/src/lib/ffmpeg_compatibility.cc b/src/lib/ffmpeg_compatibility.cc index 09f9276ac..361fa7423 100644 --- a/src/lib/ffmpeg_compatibility.cc +++ b/src/lib/ffmpeg_compatibility.cc @@ -22,6 +22,8 @@ extern "C" { } #include "exceptions.h" +#include "i18n.h" + #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 typedef struct { @@ -67,13 +69,13 @@ get_sink () #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 /* XXX does this leak stuff? */ AVFilter* buffer_sink = new AVFilter; - buffer_sink->name = av_strdup ("avsink"); + buffer_sink->name = av_strdup (N_("avsink")); buffer_sink->priv_size = sizeof (AVSinkContext); buffer_sink->init = avsink_init; buffer_sink->query_formats = avsink_query_formats; buffer_sink->inputs = new AVFilterPad[2]; AVFilterPad* i0 = const_cast (&buffer_sink->inputs[0]); - i0->name = "default"; + i0->name = N_("default"); i0->type = AVMEDIA_TYPE_VIDEO; i0->min_perms = AV_PERM_READ; i0->rej_perms = 0; @@ -91,9 +93,9 @@ get_sink () const_cast (&buffer_sink->outputs[0])->name = 0; return buffer_sink; #else - AVFilter* buffer_sink = avfilter_get_by_name("buffersink"); + AVFilter* buffer_sink = avfilter_get_by_name(N_("buffersink")); if (buffer_sink == 0) { - throw DecodeError ("Could not create buffer sink filter"); + throw DecodeError (N_("Could not create buffer sink filter")); } return buffer_sink; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index d4ed76e37..8834f28ed 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -50,6 +50,8 @@ extern "C" { #include "filter_graph.h" #include "subtitle.h" +#include "i18n.h" + using std::cout; using std::string; using std::vector; @@ -113,7 +115,7 @@ FFmpegDecoder::setup_general () } if (avformat_find_stream_info (_format_context, 0) < 0) { - throw DecodeError ("could not find stream information"); + throw DecodeError (_("could not find stream information")); } /* Find video, audio and subtitle streams and choose the first of each */ @@ -148,12 +150,12 @@ FFmpegDecoder::setup_general () } if (_video_stream < 0) { - throw DecodeError ("could not find video stream"); + throw DecodeError (N_("could not find video stream")); } _frame = avcodec_alloc_frame (); if (_frame == 0) { - throw DecodeError ("could not allocate frame"); + throw DecodeError (N_("could not allocate frame")); } } @@ -164,11 +166,11 @@ FFmpegDecoder::setup_video () _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); if (_video_codec == 0) { - throw DecodeError ("could not find video decoder"); + throw DecodeError (_("could not find video decoder")); } if (avcodec_open2 (_video_codec_context, _video_codec, 0) < 0) { - throw DecodeError ("could not open video decoder"); + throw DecodeError (N_("could not open video decoder")); } } @@ -186,11 +188,11 @@ FFmpegDecoder::setup_audio () _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id); if (_audio_codec == 0) { - throw DecodeError ("could not find audio decoder"); + throw DecodeError (_("could not find audio decoder")); } if (avcodec_open2 (_audio_codec_context, _audio_codec, 0) < 0) { - throw DecodeError ("could not open audio decoder"); + throw DecodeError (N_("could not open audio decoder")); } } @@ -205,11 +207,11 @@ FFmpegDecoder::setup_subtitle () _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); if (_subtitle_codec == 0) { - throw DecodeError ("could not find subtitle decoder"); + throw DecodeError (_("could not find subtitle decoder")); } if (avcodec_open2 (_subtitle_codec_context, _subtitle_codec, 0) < 0) { - throw DecodeError ("could not open subtitle decoder"); + throw DecodeError (N_("could not open subtitle decoder")); } } @@ -224,7 +226,7 @@ FFmpegDecoder::pass () /* Maybe we should fail here, but for now we'll just finish off instead */ char buf[256]; av_strerror (r, buf, sizeof(buf)); - _film->log()->log (String::compose ("error on av_read_frame (%1) (%2)", buf, r)); + _film->log()->log (String::compose (N_("error on av_read_frame (%1) (%2)"), buf, r)); } /* Get any remaining frames */ @@ -265,7 +267,7 @@ FFmpegDecoder::pass () if (r >= 0 && frame_finished) { if (r != _packet.size) { - _film->log()->log (String::compose ("Used only %1 bytes of %2 in packet", r, _packet.size)); + _film->log()->log (String::compose (N_("Used only %1 bytes of %2 in packet"), r, _packet.size)); } if (_opt.video_sync) { @@ -303,7 +305,7 @@ FFmpegDecoder::pass () _film->log()->log ( String::compose ( - "First video at %1, first audio at %2, pushing %3 audio frames of silence for %4 channels (%5 bytes per sample)", + N_("First video at %1, first audio at %2, pushing %3 audio frames of silence for %4 channels (%5 bytes per sample)"), _first_video.get(), _first_audio.get(), s, ffa->channels(), bytes_per_audio_sample() ) ); @@ -443,7 +445,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) break; default: - throw DecodeError (String::compose ("Unrecognised audio sample format (%1)", static_cast (audio_sample_format()))); + throw DecodeError (String::compose (_("Unrecognised audio sample format (%1)"), static_cast (audio_sample_format()))); } return audio; @@ -512,21 +514,21 @@ FFmpegDecoder::stream_name (AVStream* s) const { stringstream n; - AVDictionaryEntry const * lang = av_dict_get (s->metadata, "language", 0, 0); + AVDictionaryEntry const * lang = av_dict_get (s->metadata, N_("language"), 0, 0); if (lang) { n << lang->value; } - AVDictionaryEntry const * title = av_dict_get (s->metadata, "title", 0, 0); + AVDictionaryEntry const * title = av_dict_get (s->metadata, N_("title"), 0, 0); if (title) { if (!n.str().empty()) { - n << " "; + n << N_(" "); } n << title->value; } if (n.str().empty()) { - n << "unknown"; + n << N_("unknown"); } return n.str (); @@ -568,7 +570,7 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame) if (i == _filter_graphs.end ()) { graph.reset (new FilterGraph (_film, this, libdcp::Size (frame->width, frame->height), (AVPixelFormat) frame->format)); _filter_graphs.push_back (graph); - _film->log()->log (String::compose ("New graph for %1x%2, pixel format %3", frame->width, frame->height, frame->format)); + _film->log()->log (String::compose (N_("New graph for %1x%2, pixel format %3"), frame->width, frame->height, frame->format)); } else { graph = *i; } @@ -622,7 +624,7 @@ FFmpegAudioStream::create (string t, optional v) stringstream s (t); string type; s >> type; - if (type != "ffmpeg") { + if (type != N_("ffmpeg")) { return shared_ptr (); } @@ -644,7 +646,7 @@ FFmpegAudioStream::FFmpegAudioStream (string t, optional version) string type; /* Current (marked version 1) */ n >> type >> _id >> _sample_rate >> _channel_layout; - assert (type == "ffmpeg"); + assert (type == N_("ffmpeg")); } for (int i = 0; i < name_index; ++i) { @@ -660,7 +662,7 @@ FFmpegAudioStream::FFmpegAudioStream (string t, optional version) string FFmpegAudioStream::to_string () const { - return String::compose ("ffmpeg %1 %2 %3 %4", _id, _sample_rate, _channel_layout, _name); + return String::compose (N_("ffmpeg %1 %2 %3 %4"), _id, _sample_rate, _channel_layout, _name); } void @@ -674,7 +676,7 @@ FFmpegDecoder::out_with_sync () * av_frame_get_best_effort_timestamp(_frame); _film->log()->log ( - String::compose ("Source video frame ready; source at %1, output at %2", source_pts_seconds, out_pts_seconds), + String::compose (N_("Source video frame ready; source at %1, output at %2"), source_pts_seconds, out_pts_seconds), Log::VERBOSE ); @@ -693,7 +695,7 @@ FFmpegDecoder::out_with_sync () repeat_last_video (); _film->log()->log ( String::compose ( - "Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)", + N_("Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)"), out_pts_seconds, video_frame(), source_pts_seconds, frames_per_second() ) ); @@ -705,7 +707,7 @@ FFmpegDecoder::out_with_sync () filter_and_emit_video (_frame); } else { /* Otherwise we are omitting a frame to keep things right */ - _film->log()->log (String::compose ("Frame removed at %1s", out_pts_seconds)); + _film->log()->log (String::compose (N_("Frame removed at %1s"), out_pts_seconds)); } } diff --git a/src/lib/film.cc b/src/lib/film.cc index addaa0852..c119f1515 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -88,7 +88,7 @@ Film::Film (string d, bool must_exist) , _trust_content_header (true) , _dcp_content_type (0) , _format (0) - , _scaler (Scaler::from_id ("bicubic")) + , _scaler (Scaler::from_id (N_("bicubic"))) , _trim_start (0) , _trim_end (0) , _dcp_ab (false) @@ -114,13 +114,13 @@ Film::Film (string d, bool must_exist) boost::filesystem::path p (boost::filesystem::system_complete (d)); boost::filesystem::path result; for (boost::filesystem::path::iterator i = p.begin(); i != p.end(); ++i) { - if (*i == "..") { - if (boost::filesystem::is_symlink (result) || result.filename() == "..") { + if (*i == N_("..")) { + if (boost::filesystem::is_symlink (result) || result.filename() == N_("..")) { result /= *i; } else { result = result.parent_path (); } - } else if (*i != ".") { + } else if (*i != N_(".")) { result /= *i; } } @@ -141,7 +141,7 @@ Film::Film (string d, bool must_exist) read_metadata (); } - _log = new FileLog (file ("log")); + _log = new FileLog (file (N_("log"))); } Film::Film (Film const & o) @@ -201,16 +201,16 @@ Film::video_state_identifier () const stringstream s; s << format()->id() - << "_" << content_digest() - << "_" << crop().left << "_" << crop().right << "_" << crop().top << "_" << crop().bottom - << "_" << f.first << "_" << f.second - << "_" << scaler()->id() - << "_" << j2k_bandwidth() - << "_" << boost::lexical_cast (colour_lut()); + << N_("_") << content_digest() + << N_("_") << crop().left << N_("_") << crop().right << N_("_") << crop().top << N_("_") << crop().bottom + << N_("_") << f.first << N_("_") << f.second + << N_("_") << scaler()->id() + << N_("_") << j2k_bandwidth() + << N_("_") << boost::lexical_cast (colour_lut()); if (dcp_ab()) { pair fa = Filter::ffmpeg_strings (Config::instance()->reference_filters()); - s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second; + s << N_("ab_") << Config::instance()->reference_scaler()->id() << N_("_") << fa.first << N_("_") << fa.second; } return s.str (); @@ -221,7 +221,7 @@ string Film::info_dir () const { boost::filesystem::path p; - p /= "info"; + p /= N_("info"); p /= video_state_identifier (); return dir (p.string()); } @@ -230,13 +230,13 @@ string Film::video_mxf_dir () const { boost::filesystem::path p; - return dir ("video"); + return dir (N_("video")); } string Film::video_mxf_filename () const { - return video_state_identifier() + ".mxf"; + return video_state_identifier() + N_(".mxf"); } /** Add suitable Jobs to the JobManager to create a DCP for this Film */ @@ -245,52 +245,52 @@ Film::make_dcp () { set_dci_date_today (); - if (dcp_name().find ("/") != string::npos) { - throw BadSettingError ("name", _("cannot contain slashes")); + if (dcp_name().find (N_("/")) != string::npos) { + throw BadSettingError (_("name"), _("cannot contain slashes")); } - log()->log (String::compose ("DVD-o-matic %1 git %2 using %3", dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); + log()->log (String::compose (N_("DVD-o-matic %1 git %2 using %3"), dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); { char buffer[128]; gethostname (buffer, sizeof (buffer)); - log()->log (String::compose ("Starting to make DCP on %1", buffer)); + log()->log (String::compose (N_("Starting to make DCP on %1"), buffer)); } - log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? "still" : "video"))); + log()->log (String::compose (N_("Content is %1; type %2"), content_path(), (content_type() == STILL ? _("still") : _("video")))); if (length()) { - log()->log (String::compose ("Content length %1", length().get())); + log()->log (String::compose (N_("Content length %1"), length().get())); } - log()->log (String::compose ("Content digest %1", content_digest())); - log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads())); - log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth())); + log()->log (String::compose (N_("Content digest %1"), content_digest())); + log()->log (String::compose (N_("%1 threads"), Config::instance()->num_local_encoding_threads())); + log()->log (String::compose (N_("J2K bandwidth %1"), j2k_bandwidth())); #ifdef DVDOMATIC_DEBUG - log()->log ("DVD-o-matic built in debug mode."); + log()->log (N_("DVD-o-matic built in debug mode.")); #else - log()->log ("DVD-o-matic built in optimised mode."); + log()->log (N_("DVD-o-matic built in optimised mode.")); #endif #ifdef LIBDCP_DEBUG - log()->log ("libdcp built in debug mode."); + log()->log (N_("libdcp built in debug mode.")); #else - log()->log ("libdcp built in optimised mode."); + log()->log (N_("libdcp built in optimised mode.")); #endif pair const c = cpu_info (); - log()->log (String::compose ("CPU: %1, %2 processors", c.first, c.second)); + log()->log (String::compose (N_("CPU: %1, %2 processors"), c.first, c.second)); if (format() == 0) { - throw MissingSettingError ("format"); + throw MissingSettingError (_("format")); } if (content().empty ()) { - throw MissingSettingError ("content"); + throw MissingSettingError (_("content")); } if (dcp_content_type() == 0) { - throw MissingSettingError ("content type"); + throw MissingSettingError (_("content type")); } if (name().empty()) { - throw MissingSettingError ("name"); + throw MissingSettingError (_("name")); } DecodeOptions od; @@ -359,73 +359,73 @@ Film::write_metadata () const boost::filesystem::create_directories (directory()); - string const m = file ("metadata"); + string const m = file (N_("metadata")); ofstream f (m.c_str ()); if (!f.good ()) { throw CreateFileError (m); } - f << "version " << state_version << "\n"; + f << N_("version ") << state_version << N_("\n"); /* User stuff */ - f << "name " << _name << "\n"; - f << "use_dci_name " << _use_dci_name << "\n"; - f << "content " << _content << "\n"; - f << "trust_content_header " << (_trust_content_header ? "1" : "0") << "\n"; + f << N_("name ") << _name << N_("\n"); + f << N_("use_dci_name ") << _use_dci_name << N_("\n"); + f << N_("content ") << _content << N_("\n"); + f << N_("trust_content_header ") << (_trust_content_header ? N_("1") : N_("0")) << N_("\n"); if (_dcp_content_type) { - f << "dcp_content_type " << _dcp_content_type->dci_name () << "\n"; + f << N_("dcp_content_type ") << _dcp_content_type->dci_name () << N_("\n"); } if (_format) { - f << "format " << _format->as_metadata () << "\n"; + f << N_("format ") << _format->as_metadata () << N_("\n"); } - f << "left_crop " << _crop.left << "\n"; - f << "right_crop " << _crop.right << "\n"; - f << "top_crop " << _crop.top << "\n"; - f << "bottom_crop " << _crop.bottom << "\n"; + f << N_("left_crop ") << _crop.left << N_("\n"); + f << N_("right_crop ") << _crop.right << N_("\n"); + f << N_("top_crop ") << _crop.top << N_("\n"); + f << N_("bottom_crop ") << _crop.bottom << N_("\n"); for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << "filter " << (*i)->id () << "\n"; + f << N_("filter ") << (*i)->id () << N_("\n"); } - f << "scaler " << _scaler->id () << "\n"; - f << "trim_start " << _trim_start << "\n"; - f << "trim_end " << _trim_end << "\n"; - f << "dcp_ab " << (_dcp_ab ? "1" : "0") << "\n"; + f << N_("scaler ") << _scaler->id () << N_("\n"); + f << N_("trim_start ") << _trim_start << N_("\n"); + f << N_("trim_end ") << _trim_end << N_("\n"); + f << N_("dcp_ab ") << (_dcp_ab ? N_("1") : N_("0")) << N_("\n"); if (_content_audio_stream) { - f << "selected_content_audio_stream " << _content_audio_stream->to_string() << "\n"; + f << N_("selected_content_audio_stream ") << _content_audio_stream->to_string() << N_("\n"); } for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { - f << "external_audio " << *i << "\n"; + f << N_("external_audio ") << *i << N_("\n"); } - f << "use_content_audio " << (_use_content_audio ? "1" : "0") << "\n"; - f << "audio_gain " << _audio_gain << "\n"; - f << "audio_delay " << _audio_delay << "\n"; - f << "still_duration " << _still_duration << "\n"; + f << N_("use_content_audio ") << (_use_content_audio ? N_("1") : N_("0")) << N_("\n"); + f << N_("audio_gain ") << _audio_gain << N_("\n"); + f << N_("audio_delay ") << _audio_delay << N_("\n"); + f << N_("still_duration ") << _still_duration << N_("\n"); if (_subtitle_stream) { - f << "selected_subtitle_stream " << _subtitle_stream->to_string() << "\n"; + f << N_("selected_subtitle_stream ") << _subtitle_stream->to_string() << N_("\n"); } - f << "with_subtitles " << _with_subtitles << "\n"; - f << "subtitle_offset " << _subtitle_offset << "\n"; - f << "subtitle_scale " << _subtitle_scale << "\n"; - f << "colour_lut " << _colour_lut << "\n"; - f << "j2k_bandwidth " << _j2k_bandwidth << "\n"; + f << N_("with_subtitles ") << _with_subtitles << N_("\n"); + f << N_("subtitle_offset ") << _subtitle_offset << N_("\n"); + f << N_("subtitle_scale ") << _subtitle_scale << N_("\n"); + f << N_("colour_lut ") << _colour_lut << N_("\n"); + f << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); _dci_metadata.write (f); - f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << "\n"; - f << "width " << _size.width << "\n"; - f << "height " << _size.height << "\n"; - f << "length " << _length.get_value_or(0) << "\n"; - f << "dcp_intrinsic_duration " << _dcp_intrinsic_duration.get_value_or(0) << "\n"; - f << "content_digest " << _content_digest << "\n"; + f << N_("dci_date ") << boost::gregorian::to_iso_string (_dci_date) << N_("\n"); + f << N_("width ") << _size.width << N_("\n"); + f << N_("height ") << _size.height << N_("\n"); + f << N_("length ") << _length.get_value_or(0) << N_("\n"); + f << N_("dcp_intrinsic_duration ") << _dcp_intrinsic_duration.get_value_or(0) << N_("\n"); + f << N_("content_digest ") << _content_digest << N_("\n"); for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - f << "content_audio_stream " << (*i)->to_string () << "\n"; + f << N_("content_audio_stream ") << (*i)->to_string () << N_("\n"); } - f << "external_audio_stream " << _external_audio_stream->to_string() << "\n"; + f << N_("external_audio_stream ") << _external_audio_stream->to_string() << N_("\n"); for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { - f << "subtitle_stream " << (*i)->to_string () << "\n"; + f << N_("subtitle_stream ") << (*i)->to_string () << N_("\n"); } - f << "frames_per_second " << _frames_per_second << "\n"; + f << N_("frames_per_second ") << _frames_per_second << N_("\n"); _dirty = false; } @@ -447,15 +447,15 @@ Film::read_metadata () boost::optional audio_stream_index; boost::optional subtitle_stream_index; - ifstream f (file ("metadata").c_str()); + ifstream f (file (N_("metadata")).c_str()); if (!f.good()) { - throw OpenFileError (file ("metadata")); + throw OpenFileError (file (N_("metadata"))); } multimap kv = read_key_value (f); /* We need version before anything else */ - multimap::iterator v = kv.find ("version"); + multimap::iterator v = kv.find (N_("version")); if (v != kv.end ()) { version = atoi (v->second.c_str()); } @@ -464,107 +464,107 @@ Film::read_metadata () string const k = i->first; string const v = i->second; - if (k == "audio_sample_rate") { + if (k == N_("audio_sample_rate")) { audio_sample_rate = atoi (v.c_str()); } /* User-specified stuff */ - if (k == "name") { + if (k == N_("name")) { _name = v; - } else if (k == "use_dci_name") { - _use_dci_name = (v == "1"); - } else if (k == "content") { + } else if (k == N_("use_dci_name")) { + _use_dci_name = (v == N_("1")); + } else if (k == N_("content")) { _content = v; - } else if (k == "trust_content_header") { - _trust_content_header = (v == "1"); - } else if (k == "dcp_content_type") { + } else if (k == N_("trust_content_header")) { + _trust_content_header = (v == N_("1")); + } else if (k == N_("dcp_content_type")) { if (version < 3) { _dcp_content_type = DCPContentType::from_pretty_name (v); } else { _dcp_content_type = DCPContentType::from_dci_name (v); } - } else if (k == "format") { + } else if (k == N_("format")) { _format = Format::from_metadata (v); - } else if (k == "left_crop") { + } else if (k == N_("left_crop")) { _crop.left = atoi (v.c_str ()); - } else if (k == "right_crop") { + } else if (k == N_("right_crop")) { _crop.right = atoi (v.c_str ()); - } else if (k == "top_crop") { + } else if (k == N_("top_crop")) { _crop.top = atoi (v.c_str ()); - } else if (k == "bottom_crop") { + } else if (k == N_("bottom_crop")) { _crop.bottom = atoi (v.c_str ()); - } else if (k == "filter") { + } else if (k == N_("filter")) { _filters.push_back (Filter::from_id (v)); - } else if (k == "scaler") { + } else if (k == N_("scaler")) { _scaler = Scaler::from_id (v); - } else if ( ((!version || version < 2) && k == "dcp_trim_start") || k == "trim_start") { + } else if ( ((!version || version < 2) && k == N_("dcp_trim_start")) || k == N_("trim_start")) { _trim_start = atoi (v.c_str ()); - } else if ( ((!version || version < 2) && k == "dcp_trim_end") || k == "trim_end") { + } else if ( ((!version || version < 2) && k == N_("dcp_trim_end")) || k == N_("trim_end")) { _trim_end = atoi (v.c_str ()); - } else if (k == "dcp_ab") { - _dcp_ab = (v == "1"); - } else if (k == "selected_content_audio_stream" || (!version && k == "selected_audio_stream")) { + } else if (k == N_("dcp_ab")) { + _dcp_ab = (v == N_("1")); + } else if (k == N_("selected_content_audio_stream") || (!version && k == N_("selected_audio_stream"))) { if (!version) { audio_stream_index = atoi (v.c_str ()); } else { _content_audio_stream = audio_stream_factory (v, version); } - } else if (k == "external_audio") { + } else if (k == N_("external_audio")) { _external_audio.push_back (v); - } else if (k == "use_content_audio") { - _use_content_audio = (v == "1"); - } else if (k == "audio_gain") { + } else if (k == N_("use_content_audio")) { + _use_content_audio = (v == N_("1")); + } else if (k == N_("audio_gain")) { _audio_gain = atof (v.c_str ()); - } else if (k == "audio_delay") { + } else if (k == N_("audio_delay")) { _audio_delay = atoi (v.c_str ()); - } else if (k == "still_duration") { + } else if (k == N_("still_duration")) { _still_duration = atoi (v.c_str ()); - } else if (k == "selected_subtitle_stream") { + } else if (k == N_("selected_subtitle_stream")) { if (!version) { subtitle_stream_index = atoi (v.c_str ()); } else { _subtitle_stream = subtitle_stream_factory (v, version); } - } else if (k == "with_subtitles") { - _with_subtitles = (v == "1"); - } else if (k == "subtitle_offset") { + } else if (k == N_("with_subtitles")) { + _with_subtitles = (v == N_("1")); + } else if (k == N_("subtitle_offset")) { _subtitle_offset = atoi (v.c_str ()); - } else if (k == "subtitle_scale") { + } else if (k == N_("subtitle_scale")) { _subtitle_scale = atof (v.c_str ()); - } else if (k == "colour_lut") { + } else if (k == N_("colour_lut")) { _colour_lut = atoi (v.c_str ()); - } else if (k == "j2k_bandwidth") { + } else if (k == N_("j2k_bandwidth")) { _j2k_bandwidth = atoi (v.c_str ()); - } else if (k == "dci_date") { + } else if (k == N_("dci_date")) { _dci_date = boost::gregorian::from_undelimited_string (v); } _dci_metadata.read (k, v); /* Cached stuff */ - if (k == "width") { + if (k == N_("width")) { _size.width = atoi (v.c_str ()); - } else if (k == "height") { + } else if (k == N_("height")) { _size.height = atoi (v.c_str ()); - } else if (k == "length") { + } else if (k == N_("length")) { int const vv = atoi (v.c_str ()); if (vv) { _length = vv; } - } else if (k == "dcp_intrinsic_duration") { + } else if (k == N_("dcp_intrinsic_duration")) { int const vv = atoi (v.c_str ()); if (vv) { _dcp_intrinsic_duration = vv; } - } else if (k == "content_digest") { + } else if (k == N_("content_digest")) { _content_digest = v; - } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { + } else if (k == N_("content_audio_stream") || (!version && k == N_("audio_stream"))) { _content_audio_streams.push_back (audio_stream_factory (v, version)); - } else if (k == "external_audio_stream") { + } else if (k == N_("external_audio_stream")) { _external_audio_stream = audio_stream_factory (v, version); - } else if (k == "subtitle_stream") { + } else if (k == N_("subtitle_stream")) { _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == "frames_per_second") { + } else if (k == N_("frames_per_second")) { _frames_per_second = atof (v.c_str ()); } } @@ -714,14 +714,14 @@ Film::dci_name (bool if_created_now) const fixed_name = fixed_name.substr (0, 14); } - d << fixed_name << "_"; + d << fixed_name << N_("_"); if (dcp_content_type()) { - d << dcp_content_type()->dci_name() << "_"; + d << dcp_content_type()->dci_name() << N_("_"); } if (format()) { - d << format()->dci_name() << "_"; + d << format()->dci_name() << N_("_"); } DCIMetadata const dm = dci_metadata (); @@ -729,51 +729,51 @@ Film::dci_name (bool if_created_now) const if (!dm.audio_language.empty ()) { d << dm.audio_language; if (!dm.subtitle_language.empty() && with_subtitles()) { - d << "-" << dm.subtitle_language; + d << N_("-") << dm.subtitle_language; } else { - d << "-XX"; + d << N_("-XX"); } - d << "_"; + d << N_("_"); } if (!dm.territory.empty ()) { d << dm.territory; if (!dm.rating.empty ()) { - d << "-" << dm.rating; + d << N_("-") << dm.rating; } - d << "_"; + d << N_("_"); } switch (audio_channels()) { case 1: - d << "10_"; + d << N_("10_"); break; case 2: - d << "20_"; + d << N_("20_"); break; case 6: - d << "51_"; + d << N_("51_"); break; case 8: - d << "71_"; + d << N_("71_"); break; } - d << "2K_"; + d << N_("2K_"); if (!dm.studio.empty ()) { - d << dm.studio << "_"; + d << dm.studio << N_("_"); } if (if_created_now) { - d << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()) << "_"; + d << boost::gregorian::to_iso_string (boost::gregorian::day_clock::local_day ()) << N_("_"); } else { - d << boost::gregorian::to_iso_string (_dci_date) << "_"; + d << boost::gregorian::to_iso_string (_dci_date) << N_("_"); } if (!dm.facility.empty ()) { - d << dm.facility << "_"; + d << dm.facility << N_("_"); } if (!dm.package_type.empty ()) { @@ -828,7 +828,7 @@ Film::set_content (string c) { string check = directory (); - boost::filesystem::path slash ("/"); + boost::filesystem::path slash (N_("/")); string platform_slash = slash.make_preferred().string (); if (!ends_with (check, platform_slash)) { @@ -901,10 +901,10 @@ Film::set_content (string c) /* Default format */ switch (content_type()) { case STILL: - set_format (Format::from_id ("var-185")); + set_format (Format::from_id (N_("var-185"))); break; case VIDEO: - set_format (Format::from_id ("185")); + set_format (Format::from_id (N_("185"))); break; } @@ -1332,7 +1332,7 @@ Film::info_path (int f) const stringstream s; s.width (8); - s << setfill('0') << f << ".md5"; + s << setfill('0') << f << N_(".md5"); p /= s.str(); @@ -1346,15 +1346,15 @@ string Film::j2c_path (int f, bool t) const { boost::filesystem::path p; - p /= "j2c"; + p /= N_("j2c"); p /= video_state_identifier (); stringstream s; s.width (8); - s << setfill('0') << f << ".j2c"; + s << setfill('0') << f << N_(".j2c"); if (t) { - s << ".tmp"; + s << N_(".tmp"); } p /= s.str(); diff --git a/src/lib/filter.cc b/src/lib/filter.cc index 9a662f90f..4d429b303 100644 --- a/src/lib/filter.cc +++ b/src/lib/filter.cc @@ -27,6 +27,8 @@ extern "C" { #include } +#include "i18n.h" + using namespace std; vector Filter::_filters; @@ -63,30 +65,30 @@ Filter::setup_filters () { /* Note: "none" is a magic id name, so don't use it here */ - maybe_add ("pphb", "Horizontal deblocking filter", "De-blocking", "", "hb"); - maybe_add ("ppvb", "Vertical deblocking filter", "De-blocking", "", "vb"); - maybe_add ("ppha", "Horizontal deblocking filter A", "De-blocking", "", "ha"); - maybe_add ("ppva", "Vertical deblocking filter A", "De-blocking", "", "va"); - maybe_add ("pph1", "Experimental horizontal deblocking filter 1", "De-blocking", "", "h1"); - maybe_add ("pphv", "Experimental vertical deblocking filter 1", "De-blocking", "", "v1"); - maybe_add ("ppdr", "Deringing filter", "Misc", "", "dr"); - maybe_add ("pplb", "Linear blend deinterlacer", "De-interlacing", "", "lb"); - maybe_add ("ppli", "Linear interpolating deinterlacer", "De-interlacing", "", "li"); - maybe_add ("ppci", "Cubic interpolating deinterlacer", "De-interlacing", "", "ci"); - maybe_add ("ppmd", "Median deinterlacer", "De-interlacing", "", "md"); - maybe_add ("ppfd", "FFMPEG deinterlacer", "De-interlacing", "", "fd"); - maybe_add ("ppl5", "FIR low-pass deinterlacer", "De-interlacing", "", "l5"); - maybe_add ("mcdeint", "Motion compensating deinterlacer", "De-interlacing", "mcdeint", ""); - maybe_add ("kerndeint", "Kernel deinterlacer", "De-interlacing", "kerndeint", ""); - maybe_add ("yadif", "Yet Another Deinterlacing Filter", "De-interlacing", "yadif", ""); - maybe_add ("pptn", "Temporal noise reducer", "Noise reduction", "", "tn"); - maybe_add ("ppfq", "Force quantizer", "Misc", "", "fq"); - maybe_add ("gradfun", "Gradient debander", "Misc", "gradfun", ""); - maybe_add ("unsharp", "Unsharp mask and Gaussian blur", "Misc", "unsharp", ""); - maybe_add ("denoise3d", "3D denoiser", "Noise reduction", "denoise3d", ""); - maybe_add ("hqdn3d", "High quality 3D denoiser", "Noise reduction", "hqdn3d", ""); - maybe_add ("telecine", "Telecine filter", "Misc", "telecine", ""); - maybe_add ("ow", "Overcomplete wavelet denoiser", "Noise reduction", "mp=ow", ""); + maybe_add (N_("pphb"), _("Horizontal deblocking filter"), _("De-blocking"), N_(""), N_("hb")); + maybe_add (N_("ppvb"), _("Vertical deblocking filter"), _("De-blocking"), N_(""), N_("vb")); + maybe_add (N_("ppha"), _("Horizontal deblocking filter A"), _("De-blocking"), N_(""), N_("ha")); + maybe_add (N_("ppva"), _("Vertical deblocking filter A"), _("De-blocking"), N_(""), N_("va")); + maybe_add (N_("pph1"), _("Experimental horizontal deblocking filter 1"), _("De-blocking"), N_(""), N_("h1")); + maybe_add (N_("pphv"), _("Experimental vertical deblocking filter 1"), _("De-blocking"), N_(""), N_("v1")); + maybe_add (N_("ppdr"), _("Deringing filter"), _("Misc"), N_(""), N_("dr")); + maybe_add (N_("pplb"), _("Linear blend deinterlacer"), _("De-interlacing"), N_(""), N_("lb")); + maybe_add (N_("ppli"), _("Linear interpolating deinterlacer"), _("De-interlacing"), N_(""), N_("li")); + maybe_add (N_("ppci"), _("Cubic interpolating deinterlacer"), _("De-interlacing"), N_(""), N_("ci")); + maybe_add (N_("ppmd"), _("Median deinterlacer"), _("De-interlacing"), N_(""), N_("md")); + maybe_add (N_("ppfd"), _("FFMPEG deinterlacer"), _("De-interlacing"), N_(""), N_("fd")); + maybe_add (N_("ppl5"), _("FIR low-pass deinterlacer"), _("De-interlacing"), N_(""), N_("l5")); + maybe_add (N_("mcdeint"), _("Motion compensating deinterlacer"), _("De-interlacing"), N_("mcdeint"), N_("")); + maybe_add (N_("kerndeint"), _("Kernel deinterlacer"), _("De-interlacing"), N_("kerndeint"), N_("")); + maybe_add (N_("yadif"), _("Yet Another Deinterlacing Filter"), _("De-interlacing"), N_("yadif"), N_("")); + maybe_add (N_("pptn"), _("Temporal noise reducer"), _("Noise reduction"), N_(""), N_("tn")); + maybe_add (N_("ppfq"), _("Force quantizer"), _("Misc"), N_(""), N_("fq")); + maybe_add (N_("gradfun"), _("Gradient debander"), _("Misc"), N_("gradfun"), N_("")); + maybe_add (N_("unsharp"), _("Unsharp mask and Gaussian blur"), _("Misc"), N_("unsharp"), N_("")); + maybe_add (N_("denoise3d"), _("3D denoiser"), _("Noise reduction"), N_("denoise3d"), N_("")); + maybe_add (N_("hqdn3d"), _("High quality 3D denoiser"), _("Noise reduction"), N_("hqdn3d"), N_("")); + maybe_add (N_("telecine"), _("Telecine filter"), _("Misc"), N_("telecine"), N_("")); + maybe_add (N_("ow"), _("Overcomplete wavelet denoiser"), _("Noise reduction"), N_("mp=ow"), N_("")); } void @@ -118,14 +120,14 @@ Filter::ffmpeg_strings (vector const & filters) for (vector::const_iterator i = filters.begin(); i != filters.end(); ++i) { if (!(*i)->vf().empty ()) { if (!vf.empty ()) { - vf += ","; + vf += N_(","); } vf += (*i)->vf (); } if (!(*i)->pp().empty ()) { if (!pp.empty()) { - pp += ","; + pp += N_(","); } pp += (*i)->pp (); } diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index b0991a2da..045cbaa6a 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -43,6 +43,8 @@ extern "C" { #include "film.h" #include "ffmpeg_decoder.h" +#include "i18n.h" + using std::stringstream; using std::string; using std::list; @@ -63,36 +65,36 @@ FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp: { string filters = Filter::ffmpeg_strings (film->filters()).first; if (!filters.empty ()) { - filters += ","; + filters += N_(","); } filters += crop_string (Position (film->crop().left, film->crop().top), film->cropped_size (decoder->native_size())); AVFilterGraph* graph = avfilter_graph_alloc(); if (graph == 0) { - throw DecodeError ("Could not create filter graph."); + throw DecodeError (N_("could not create filter graph.")); } - AVFilter* buffer_src = avfilter_get_by_name("buffer"); + AVFilter* buffer_src = avfilter_get_by_name(N_("buffer")); if (buffer_src == 0) { - throw DecodeError ("Could not find buffer src filter"); + throw DecodeError (N_("could not find buffer src filter")); } AVFilter* buffer_sink = get_sink (); stringstream a; - a << _size.width << ":" - << _size.height << ":" - << _pixel_format << ":" - << decoder->time_base_numerator() << ":" - << decoder->time_base_denominator() << ":" - << decoder->sample_aspect_ratio_numerator() << ":" + a << _size.width << N_(":") + << _size.height << N_(":") + << _pixel_format << N_(":") + << decoder->time_base_numerator() << N_(":") + << decoder->time_base_denominator() << N_(":") + << decoder->sample_aspect_ratio_numerator() << N_(":") << decoder->sample_aspect_ratio_denominator(); int r; - if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, "in", a.str().c_str(), 0, graph)) < 0) { - throw DecodeError ("could not create buffer source"); + if ((r = avfilter_graph_create_filter (&_buffer_src_context, buffer_src, N_("in"), a.str().c_str(), 0, graph)) < 0) { + throw DecodeError (N_("could not create buffer source")); } AVBufferSinkParams* sink_params = av_buffersink_params_alloc (); @@ -101,34 +103,34 @@ FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp: pixel_fmts[1] = PIX_FMT_NONE; sink_params->pixel_fmts = pixel_fmts; - if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, "out", 0, sink_params, graph) < 0) { - throw DecodeError ("could not create buffer sink."); + if (avfilter_graph_create_filter (&_buffer_sink_context, buffer_sink, N_("out"), 0, sink_params, graph) < 0) { + throw DecodeError (N_("could not create buffer sink.")); } AVFilterInOut* outputs = avfilter_inout_alloc (); - outputs->name = av_strdup("in"); + outputs->name = av_strdup(N_("in")); outputs->filter_ctx = _buffer_src_context; outputs->pad_idx = 0; outputs->next = 0; AVFilterInOut* inputs = avfilter_inout_alloc (); - inputs->name = av_strdup("out"); + inputs->name = av_strdup(N_("out")); inputs->filter_ctx = _buffer_sink_context; inputs->pad_idx = 0; inputs->next = 0; #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 if (avfilter_graph_parse (graph, filters.c_str(), inputs, outputs, 0) < 0) { - throw DecodeError ("could not set up filter graph."); + throw DecodeError (N_("could not set up filter graph.")); } #else if (avfilter_graph_parse (graph, filters.c_str(), &inputs, &outputs, 0) < 0) { - throw DecodeError ("could not set up filter graph."); + throw DecodeError (N_("could not set up filter graph.")); } #endif if (avfilter_graph_config (graph, 0) < 0) { - throw DecodeError ("could not configure filter graph."); + throw DecodeError (N_("could not configure filter graph.")); } /* XXX: leaking `inputs' / `outputs' ? */ @@ -145,7 +147,7 @@ FilterGraph::process (AVFrame const * frame) #if LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR >= 53 && LIBAVFILTER_VERSION_MINOR <= 61 if (av_vsrc_buffer_add_frame (_buffer_src_context, frame, 0) < 0) { - throw DecodeError ("could not push buffer into filter chain."); + throw DecodeError (N_("could not push buffer into filter chain.")); } #elif LIBAVFILTER_VERSION_MAJOR == 2 && LIBAVFILTER_VERSION_MINOR == 15 @@ -155,13 +157,13 @@ FilterGraph::process (AVFrame const * frame) par.den = sample_aspect_ratio_denominator (); if (av_vsrc_buffer_add_frame (_buffer_src_context, frame, 0, par) < 0) { - throw DecodeError ("could not push buffer into filter chain."); + throw DecodeError (N_("could not push buffer into filter chain.")); } #else if (av_buffersrc_write_frame (_buffer_src_context, frame) < 0) { - throw DecodeError ("could not push buffer into filter chain."); + throw DecodeError (N_("could not push buffer into filter chain.")); } #endif @@ -176,7 +178,7 @@ FilterGraph::process (AVFrame const * frame) int r = avfilter_request_frame (_buffer_sink_context->inputs[0]); if (r < 0) { - throw DecodeError ("could not request filtered frame"); + throw DecodeError (N_("could not request filtered frame")); } AVFilterBufferRef* filter_buffer = _buffer_sink_context->inputs[0]->cur_buf; diff --git a/src/lib/format.cc b/src/lib/format.cc index 016c21fde..0e4830cd7 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -30,6 +30,8 @@ #include "format.h" #include "film.h" +#include "i18n.h" + using std::string; using std::setprecision; using std::stringstream; @@ -45,13 +47,13 @@ FixedFormat::name () const { stringstream s; if (!_nickname.empty ()) { - s << _nickname << " ("; + s << _nickname << N_(" ("); } - s << setprecision(3) << (_ratio / 100.0) << ":1"; + s << setprecision(3) << (_ratio / 100.0) << N_(":1"); if (!_nickname.empty ()) { - s << ")"; + s << N_(")"); } return s.str (); @@ -68,19 +70,20 @@ Format::as_metadata () const void Format::setup_formats () { - _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), "119", "1.19", "F")); - _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), "133", "1.33", "F")); - _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), "138", "1.375", "F")); - _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), "133-in-flat", "4:3 within Flat", "F")); - _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), "137", "Academy", "F")); - _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), "166", "1.66", "F")); - _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), "166-in-flat", "1.66 within Flat", "F")); - _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), "178-in-flat", "16:9 within Flat", "F")); - _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), "178", "16:9", "F")); - _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), "185", "Flat", "F")); - _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), "239", "Scope", "S")); - _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), "var-185", "Flat", "F")); - _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), "var-239", "Scope", "S")); + /// TRANSLATORS: these are film picture aspect ratios; "Academy" means 1.37, "Flat" 1.85 and "Scope" 2.39. + _formats.push_back (new FixedFormat (119, libdcp::Size (1285, 1080), N_("119"), _("1.19"), N_("F"))); + _formats.push_back (new FixedFormat (133, libdcp::Size (1436, 1080), N_("133"), _("1.33"), N_("F"))); + _formats.push_back (new FixedFormat (138, libdcp::Size (1485, 1080), N_("138"), _("1.375"), N_("F"))); + _formats.push_back (new FixedFormat (133, libdcp::Size (1998, 1080), N_("133-in-flat"), _("4:3 within Flat"), N_("F"))); + _formats.push_back (new FixedFormat (137, libdcp::Size (1480, 1080), N_("137"), _("Academy"), N_("F"))); + _formats.push_back (new FixedFormat (166, libdcp::Size (1793, 1080), N_("166"), _("1.66"), N_("F"))); + _formats.push_back (new FixedFormat (166, libdcp::Size (1998, 1080), N_("166-in-flat"), _("1.66 within Flat"), N_("F"))); + _formats.push_back (new FixedFormat (178, libdcp::Size (1998, 1080), N_("178-in-flat"), _("16:9 within Flat"), N_("F"))); + _formats.push_back (new FixedFormat (178, libdcp::Size (1920, 1080), N_("178"), _("16:9"), N_("F"))); + _formats.push_back (new FixedFormat (185, libdcp::Size (1998, 1080), N_("185"), _("Flat"), N_("F"))); + _formats.push_back (new FixedFormat (239, libdcp::Size (2048, 858), N_("239"), _("Scope"), N_("S"))); + _formats.push_back (new VariableFormat (libdcp::Size (1998, 1080), N_("var-185"), _("Flat"), N_("F"))); + _formats.push_back (new VariableFormat (libdcp::Size (2048, 858), N_("var-239"), _("Scope"), N_("S"))); } /** @param n Nickname. diff --git a/src/lib/image.cc b/src/lib/image.cc index b7ac13ab1..268c08173 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -40,6 +40,8 @@ extern "C" { #include "exceptions.h" #include "scaler.h" +#include "i18n.h" + using namespace std; using namespace boost; using libdcp::Size; @@ -75,7 +77,7 @@ Image::lines (int n) const case PIX_FMT_YUV444P10LE: return size().height; default: - throw PixelFormatError ("lines()", _pixel_format); + throw PixelFormatError (N_("lines()"), _pixel_format); } return 0; @@ -99,7 +101,7 @@ Image::components () const case PIX_FMT_RGBA: return 1; default: - throw PixelFormatError ("components()", _pixel_format); + throw PixelFormatError (N_("components()"), _pixel_format); } return 0; @@ -218,7 +220,7 @@ Image::post_process (string pp, bool aligned) const case PIX_FMT_YUV444P10LE: pp_format = PP_FORMAT_444; default: - throw PixelFormatError ("post_process", pixel_format()); + throw PixelFormatError (N_("post_process"), pixel_format()); } pp_mode* mode = pp_get_mode_by_name_and_quality (pp.c_str (), PP_QUALITY_MAX); diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 42fe699d7..5dc0b7b06 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -25,6 +25,8 @@ #include "film.h" #include "exceptions.h" +#include "i18n.h" + using std::cout; using boost::shared_ptr; using libdcp::Size; @@ -55,7 +57,7 @@ libdcp::Size ImageMagickDecoder::native_size () const { if (_files.empty ()) { - throw DecodeError ("no still image files found"); + throw DecodeError (_("no still image files found")); } /* Look at the first file and assume its size holds for all */ diff --git a/src/lib/job.cc b/src/lib/job.cc index bfad65a0a..77d367136 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -27,6 +27,8 @@ #include "job.h" #include "util.h" +#include "i18n.h" + using std::string; using std::list; using std::stringstream; @@ -66,11 +68,12 @@ Job::run_wrapper () set_progress (1); set_state (FINISHED_ERROR); - string m = String::compose ("An error occurred whilst handling the file %1.", boost::filesystem::path (e.filename()).leaf()); + string m = String::compose (_("An error occurred whilst handling the file %1."), boost::filesystem::path (e.filename()).leaf()); boost::filesystem::space_info const s = boost::filesystem::space (e.filename()); if (s.available < pow (1024, 3)) { - m += "\n\nThe drive that the film is stored on is low in disc space. Free some more space and try again."; + m += N_("\n\n"); + m += _("The drive that the film is stored on is low in disc space. Free some more space and try again."); } set_error (e.what(), m); @@ -81,7 +84,7 @@ Job::run_wrapper () set_state (FINISHED_ERROR); set_error ( e.what (), - "It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" + _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)") ); } catch (...) { @@ -89,8 +92,8 @@ Job::run_wrapper () set_progress (1); set_state (FINISHED_ERROR); set_error ( - "Unknown error", - "It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" + _("Unknown error"), + _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)") ); } @@ -273,14 +276,16 @@ Job::status () const stringstream s; if (!finished ()) { - s << pc << "%"; + s << pc << N_("%"); if (p >= 0 && t > 10 && r > 0) { - s << "; " << seconds_to_approximate_hms (r) << " remaining"; + /// TRANSLATORS: remaining here follows an amount of time that is remaining + /// on an operation. + s << "; " << seconds_to_approximate_hms (r) << " " << _("remaining"); } } else if (finished_ok ()) { - s << "OK (ran for " << seconds_to_hms (_ran_for) << ")"; + s << String::compose (_("OK (ran for %1)"), seconds_to_hms (_ran_for)); } else if (finished_in_error ()) { - s << "Error (" << error_summary() << ")"; + s << String::compose (_("Error (%1)"), error_summary()); } return s.str (); diff --git a/src/lib/log.cc b/src/lib/log.cc index 7459700ea..ef36a902c 100644 --- a/src/lib/log.cc +++ b/src/lib/log.cc @@ -25,6 +25,8 @@ #include #include "log.h" +#include "i18n.h" + using namespace std; Log::Log () @@ -48,7 +50,7 @@ Log::log (string m, Level l) string a = ctime (&t); stringstream s; - s << a.substr (0, a.length() - 1) << ": " << m; + s << a.substr (0, a.length() - 1) << N_(": ") << m; do_log (s.str ()); } @@ -65,7 +67,7 @@ Log::microsecond_log (string m, Level l) gettimeofday (&tv, 0); stringstream s; - s << tv.tv_sec << ":" << tv.tv_usec << " " << m; + s << tv.tv_sec << N_(":") << tv.tv_usec << N_(" ") << m; do_log (s.str ()); } @@ -79,10 +81,10 @@ Log::set_level (Level l) void Log::set_level (string l) { - if (l == "verbose") { + if (l == N_("verbose")) { set_level (VERBOSE); return; - } else if (l == "timing") { + } else if (l == N_("timing")) { set_level (TIMING); return; } @@ -101,6 +103,6 @@ void FileLog::do_log (string m) { ofstream f (_file.c_str(), fstream::app); - f << m << "\n"; + f << m << N_("\n"); } diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 182fb306c..4cd264338 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -21,6 +21,8 @@ #include "image.h" #include "log.h" +#include "i18n.h" + using std::min; using boost::shared_ptr; @@ -65,7 +67,7 @@ Matcher::process_end () _log->log ( String::compose ( - "Matching processor has seen %1 video frames (which equals %2 audio frames) and %3 audio frames", + N_("Matching processor has seen %1 video frames (which equals %2 audio frames) and %3 audio frames"), _video_frames, video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second), _audio_frames @@ -74,12 +76,12 @@ Matcher::process_end () if (audio_short_by_frames < 0) { - _log->log (String::compose ("%1 too many audio frames", -audio_short_by_frames)); + _log->log (String::compose (N_("%1 too many audio frames"), -audio_short_by_frames)); /* We have seen more audio than video. Emit enough black video frames so that we reverse this */ int const black_video_frames = ceil (-audio_short_by_frames * _frames_per_second / _sample_rate); - _log->log (String::compose ("Emitting %1 frames of black video", black_video_frames)); + _log->log (String::compose (N_("Emitting %1 frames of black video"), black_video_frames)); shared_ptr black (new SimpleImage (_pixel_format.get(), _size.get(), true)); black->make_black (); @@ -92,7 +94,7 @@ Matcher::process_end () } if (audio_short_by_frames > 0) { - _log->log (String::compose ("Emitted %1 too few audio frames", audio_short_by_frames)); + _log->log (String::compose (N_("Emitted %1 too few audio frames"), audio_short_by_frames)); /* Do things in half second blocks as I think there may be limits to what FFmpeg (and in particular the resampler) can cope with. diff --git a/src/lib/scaler.cc b/src/lib/scaler.cc index c81456a15..40a0f05b9 100644 --- a/src/lib/scaler.cc +++ b/src/lib/scaler.cc @@ -28,6 +28,8 @@ extern "C" { } #include "scaler.h" +#include "i18n.h" + using namespace std; vector Scaler::_scalers; @@ -57,15 +59,15 @@ Scaler::all () void Scaler::setup_scalers () { - _scalers.push_back (new Scaler (SWS_BICUBIC, "bicubic", "Bicubic")); - _scalers.push_back (new Scaler (SWS_X, "x", "X")); - _scalers.push_back (new Scaler (SWS_AREA, "area", "Area")); - _scalers.push_back (new Scaler (SWS_GAUSS, "gauss", "Gaussian")); - _scalers.push_back (new Scaler (SWS_LANCZOS, "lanczos", "Lanczos")); - _scalers.push_back (new Scaler (SWS_SINC, "sinc", "Sinc")); - _scalers.push_back (new Scaler (SWS_SPLINE, "spline", "Spline")); - _scalers.push_back (new Scaler (SWS_BILINEAR, "bilinear", "Bilinear")); - _scalers.push_back (new Scaler (SWS_FAST_BILINEAR, "fastbilinear", "Fast Bilinear")); + _scalers.push_back (new Scaler (SWS_BICUBIC, N_("bicubic"), _("Bicubic"))); + _scalers.push_back (new Scaler (SWS_X, N_("x"), _("X"))); + _scalers.push_back (new Scaler (SWS_AREA, N_("area"), _("Area"))); + _scalers.push_back (new Scaler (SWS_GAUSS, N_("gauss"), _("Gaussian"))); + _scalers.push_back (new Scaler (SWS_LANCZOS, N_("lanczos"), _("Lanczos"))); + _scalers.push_back (new Scaler (SWS_SINC, N_("sinc"), _("Sinc"))); + _scalers.push_back (new Scaler (SWS_SPLINE, N_("spline"), _("Spline"))); + _scalers.push_back (new Scaler (SWS_BILINEAR, N_("bilinear"), _("Bilinear"))); + _scalers.push_back (new Scaler (SWS_FAST_BILINEAR, N_("fastbilinear"), _("Fast Bilinear"))); } /** @param id One of our ids. diff --git a/src/lib/scp_dcp_job.cc b/src/lib/scp_dcp_job.cc index 30d02eff8..a9fdfefda 100644 --- a/src/lib/scp_dcp_job.cc +++ b/src/lib/scp_dcp_job.cc @@ -34,6 +34,8 @@ #include "log.h" #include "film.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::min; @@ -47,7 +49,7 @@ public: { session = ssh_new (); if (session == 0) { - throw NetworkError ("Could not start SSH session"); + throw NetworkError (_("could not start SSH session")); } } @@ -81,7 +83,7 @@ public: { scp = ssh_scp_new (s, SSH_SCP_WRITE | SSH_SCP_RECURSIVE, Config::instance()->tms_path().c_str ()); if (!scp) { - throw NetworkError (String::compose ("Could not start SCP session (%1)", ssh_get_error (s))); + throw NetworkError (String::compose (_("could not start SCP session (%1)"), ssh_get_error (s))); } } @@ -96,7 +98,7 @@ public: SCPDCPJob::SCPDCPJob (shared_ptr f) : Job (f) - , _status ("Waiting") + , _status (_("Waiting")) { } @@ -104,17 +106,17 @@ SCPDCPJob::SCPDCPJob (shared_ptr f) string SCPDCPJob::name () const { - return "Copy DCP to TMS"; + return _("Copy DCP to TMS"); } void SCPDCPJob::run () { - _film->log()->log ("SCP DCP job starting"); + _film->log()->log (N_("SCP DCP job starting")); SSHSession ss; - set_status ("connecting"); + set_status (_("connecting")); ssh_options_set (ss.session, SSH_OPTIONS_HOST, Config::instance()->tms_ip().c_str ()); ssh_options_set (ss.session, SSH_OPTIONS_USER, Config::instance()->tms_user().c_str ()); @@ -123,29 +125,29 @@ SCPDCPJob::run () int r = ss.connect (); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not connect to server %1 (%2)", Config::instance()->tms_ip(), ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not connect to server %1 (%2)"), Config::instance()->tms_ip(), ssh_get_error (ss.session))); } int const state = ssh_is_server_known (ss.session); if (state == SSH_SERVER_ERROR) { - throw NetworkError (String::compose ("SSH error (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("SSH error (%1)"), ssh_get_error (ss.session))); } r = ssh_userauth_password (ss.session, 0, Config::instance()->tms_password().c_str ()); if (r != SSH_AUTH_SUCCESS) { - throw NetworkError (String::compose ("Failed to authenticate with server (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Failed to authenticate with server (%1)"), ssh_get_error (ss.session))); } SSHSCP sc (ss.session); r = ssh_scp_init (sc.scp); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not start SCP session (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not start SCP session (%1)"), ssh_get_error (ss.session))); } r = ssh_scp_push_directory (sc.scp, _film->dcp_name().c_str(), S_IRWXU); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not create remote directory %1 (%2)", _film->dcp_name(), ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not create remote directory %1 (%2)"), _film->dcp_name(), ssh_get_error (ss.session))); } string const dcp_dir = _film->dir (_film->dcp_name()); @@ -163,14 +165,14 @@ SCPDCPJob::run () string const leaf = boost::filesystem::path(*i).leaf().generic_string (); - set_status ("copying " + leaf); + set_status (String::compose (_("copying %1"), leaf)); boost::uintmax_t to_do = boost::filesystem::file_size (*i); ssh_scp_push_file (sc.scp, leaf.c_str(), to_do, S_IRUSR | S_IWUSR); - FILE* f = fopen (boost::filesystem::path (*i).string().c_str(), "rb"); + FILE* f = fopen (boost::filesystem::path (*i).string().c_str(), N_("rb")); if (f == 0) { - throw NetworkError (String::compose ("Could not open %1 to send", *i)); + throw NetworkError (String::compose (_("Could not open %1 to send"), *i)); } while (to_do > 0) { @@ -182,7 +184,7 @@ SCPDCPJob::run () r = ssh_scp_write (sc.scp, buffer, t); if (r != SSH_OK) { - throw NetworkError (String::compose ("Could not write to remote file (%1)", ssh_get_error (ss.session))); + throw NetworkError (String::compose (_("Could not write to remote file (%1)"), ssh_get_error (ss.session))); } to_do -= t; bytes_transferred += t; @@ -194,7 +196,7 @@ SCPDCPJob::run () } set_progress (1); - set_status (""); + set_status (N_("")); set_state (FINISHED_OK); } @@ -205,7 +207,7 @@ SCPDCPJob::status () const stringstream s; s << Job::status (); if (!_status.empty ()) { - s << "; " << _status; + s << N_("; ") << _status; } return s.str (); } diff --git a/src/lib/server.cc b/src/lib/server.cc index 3614ed9e4..76a25bfbb 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -37,6 +37,8 @@ #include "config.h" #include "subtitle.h" +#include "i18n.h" + using std::string; using std::stringstream; using std::multimap; @@ -57,7 +59,7 @@ ServerDescription * ServerDescription::create_from_metadata (string v) { vector b; - split (b, v, is_any_of (" ")); + split (b, v, is_any_of (N_(" "))); if (b.size() != 2) { return 0; @@ -71,7 +73,7 @@ string ServerDescription::as_metadata () const { stringstream s; - s << _host_name << " " << _threads; + s << _host_name << N_(" ") << _threads; return s.str (); } @@ -91,24 +93,24 @@ Server::process (shared_ptr socket) stringstream s (buffer.get()); multimap kv = read_key_value (s); - if (get_required_string (kv, "encode") != "please") { + if (get_required_string (kv, N_("encode")) != N_("please")) { return -1; } - libdcp::Size in_size (get_required_int (kv, "input_width"), get_required_int (kv, "input_height")); - int pixel_format_int = get_required_int (kv, "input_pixel_format"); - libdcp::Size out_size (get_required_int (kv, "output_width"), get_required_int (kv, "output_height")); - int padding = get_required_int (kv, "padding"); - int subtitle_offset = get_required_int (kv, "subtitle_offset"); - float subtitle_scale = get_required_float (kv, "subtitle_scale"); - string scaler_id = get_required_string (kv, "scaler"); - int frame = get_required_int (kv, "frame"); - int frames_per_second = get_required_int (kv, "frames_per_second"); - string post_process = get_optional_string (kv, "post_process"); - int colour_lut_index = get_required_int (kv, "colour_lut"); - int j2k_bandwidth = get_required_int (kv, "j2k_bandwidth"); - Position subtitle_position (get_optional_int (kv, "subtitle_x"), get_optional_int (kv, "subtitle_y")); - libdcp::Size subtitle_size (get_optional_int (kv, "subtitle_width"), get_optional_int (kv, "subtitle_height")); + libdcp::Size in_size (get_required_int (kv, N_("input_width")), get_required_int (kv, N_("input_height"))); + int pixel_format_int = get_required_int (kv, N_("input_pixel_format")); + libdcp::Size out_size (get_required_int (kv, N_("output_width")), get_required_int (kv, N_("output_height"))); + int padding = get_required_int (kv, N_("padding")); + int subtitle_offset = get_required_int (kv, N_("subtitle_offset")); + float subtitle_scale = get_required_float (kv, N_("subtitle_scale")); + string scaler_id = get_required_string (kv, N_("scaler")); + int frame = get_required_int (kv, N_("frame")); + int frames_per_second = get_required_int (kv, N_("frames_per_second")); + string post_process = get_optional_string (kv, N_("post_process")); + int colour_lut_index = get_required_int (kv, N_("colour_lut")); + int j2k_bandwidth = get_required_int (kv, N_("j2k_bandwidth")); + Position subtitle_position (get_optional_int (kv, N_("subtitle_x")), get_optional_int (kv, N_("subtitle_y"))); + libdcp::Size subtitle_size (get_optional_int (kv, N_("subtitle_width")), get_optional_int (kv, N_("subtitle_height"))); /* This checks that colour_lut_index is within range */ colour_lut_index_to_name (colour_lut_index); @@ -137,7 +139,7 @@ Server::process (shared_ptr socket) encoded->send (socket); } catch (std::exception& e) { _log->log (String::compose ( - "Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components", + N_("Send failed; frame %1, data size %2, pixel format %3, image size %4x%5, %6 components"), frame, encoded->size(), image->pixel_format(), image->size().width, image->size().height, image->components() ) ); @@ -169,7 +171,7 @@ Server::worker_thread () try { frame = process (socket); } catch (std::exception& e) { - _log->log (String::compose ("Error: %1", e.what())); + _log->log (String::compose (N_("Error: %1"), e.what())); } socket.reset (); @@ -179,7 +181,7 @@ Server::worker_thread () if (frame >= 0) { struct timeval end; gettimeofday (&end, 0); - _log->log (String::compose ("Encoded frame %1 in %2", frame, seconds (end) - seconds (start))); + _log->log (String::compose (N_("Encoded frame %1 in %2"), frame, seconds (end) - seconds (start))); } _worker_condition.notify_all (); @@ -189,7 +191,7 @@ Server::worker_thread () void Server::run (int num_threads) { - _log->log (String::compose ("Server starting with %1 threads", num_threads)); + _log->log (String::compose (N_("Server starting with %1 threads"), num_threads)); for (int i = 0; i < num_threads; ++i) { _worker_threads.push_back (new thread (bind (&Server::worker_thread, this))); diff --git a/src/lib/stream.cc b/src/lib/stream.cc index 4f12f41b9..e5a2bbc2b 100644 --- a/src/lib/stream.cc +++ b/src/lib/stream.cc @@ -23,6 +23,8 @@ #include "ffmpeg_decoder.h" #include "external_audio_decoder.h" +#include "i18n.h" + using std::string; using std::stringstream; using boost::shared_ptr; @@ -47,7 +49,7 @@ SubtitleStream::SubtitleStream (string t, boost::optional) string SubtitleStream::to_string () const { - return String::compose ("%1 %2", _id, _name); + return String::compose (N_("%1 %2"), _id, _name); } /** Create a SubtitleStream from a value returned from to_string(). diff --git a/src/lib/subtitle.cc b/src/lib/subtitle.cc index 5bb91af63..5c1ad9706 100644 --- a/src/lib/subtitle.cc +++ b/src/lib/subtitle.cc @@ -25,6 +25,8 @@ #include "image.h" #include "exceptions.h" +#include "i18n.h" + using namespace std; using namespace boost; using libdcp::Size; @@ -47,13 +49,13 @@ TimedSubtitle::TimedSubtitle (AVSubtitle const & sub) _to = packet_time + (double (sub.end_display_time) / 1e3); if (sub.num_rects > 1) { - throw DecodeError ("multi-part subtitles not yet supported"); + throw DecodeError (_("multi-part subtitles not yet supported")); } AVSubtitleRect const * rect = sub.rects[0]; if (rect->type != SUBTITLE_BITMAP) { - throw DecodeError ("non-bitmap subtitles not yet supported"); + throw DecodeError (_("non-bitmap subtitles not yet supported")); } shared_ptr image (new SimpleImage (PIX_FMT_RGBA, libdcp::Size (rect->w, rect->h), true)); diff --git a/src/lib/timer.cc b/src/lib/timer.cc index a45e80dcb..69a7e3aa9 100644 --- a/src/lib/timer.cc +++ b/src/lib/timer.cc @@ -26,6 +26,8 @@ #include "timer.h" #include "util.h" +#include "i18n.h" + using namespace std; /** @param n Name to use when giving output */ @@ -40,7 +42,7 @@ PeriodTimer::~PeriodTimer () { struct timeval stop; gettimeofday (&stop, 0); - cout << "T: " << _name << ": " << (seconds (stop) - seconds (_start)) << "\n"; + cout << N_("T: ") << _name << N_(": ") << (seconds (stop) - seconds (_start)) << N_("\n"); } /** @param n Name to use when giving output. @@ -80,10 +82,10 @@ StateTimer::~StateTimer () } - set_state (""); + set_state (N_("")); - cout << _name << ":\n"; + cout << _name << N_(":\n"); for (map::iterator i = _totals.begin(); i != _totals.end(); ++i) { - cout << "\t" << i->first << " " << i->second << "\n"; + cout << N_("\t") << i->first << " " << i->second << N_("\n"); } } diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index a4279ef8b..61fad2e2b 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -59,8 +59,8 @@ TranscodeJob::run () { try { - _film->log()->log ("Transcode job starting"); - _film->log()->log (String::compose ("Audio delay is %1ms", _film->audio_delay())); + _film->log()->log (N_("Transcode job starting")); + _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); _encoder.reset (new Encoder (_film)); Transcoder w (_film, _decode_opt, this, _encoder); @@ -70,14 +70,14 @@ TranscodeJob::run () _film->set_dcp_intrinsic_duration (_encoder->video_frames_out ()); - _film->log()->log ("Transcode job completed successfully"); - _film->log()->log (String::compose ("DCP intrinsic duration is %1", _encoder->video_frames_out())); + _film->log()->log (N_("Transcode job completed successfully")); + _film->log()->log (String::compose (N_("DCP intrinsic duration is %1"), _encoder->video_frames_out())); } catch (std::exception& e) { set_progress (1); set_state (FINISHED_ERROR); - _film->log()->log (String::compose ("Transcode job failed (%1)", e.what())); + _film->log()->log (String::compose (N_("Transcode job failed (%1)"), e.what())); throw; } @@ -87,7 +87,7 @@ string TranscodeJob::status () const { if (!_encoder) { - return "0%"; + return _("0%"); } float const fps = _encoder->current_frames_per_second (); @@ -100,7 +100,7 @@ TranscodeJob::status () const s << Job::status (); if (!finished ()) { - s << "; " << fixed << setprecision (1) << fps << " " << _("frames per second"); + s << N_("; ") << fixed << setprecision (1) << fps << N_(" ") << _("frames per second"); } return s.str (); diff --git a/src/lib/util.cc b/src/lib/util.cc index 4ee304600..892a7fd86 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -61,6 +61,8 @@ extern "C" { #include "sound_processor.h" #include "config.h" +#include "i18n.h" + using namespace std; using namespace boost; using libdcp::Size; @@ -83,9 +85,9 @@ seconds_to_hms (int s) m -= (h * 60); stringstream hms; - hms << h << ":"; + hms << h << N_(":"); hms.width (2); - hms << setfill ('0') << m << ":"; + hms << setfill ('0') << m << N_(":"); hms.width (2); hms << setfill ('0') << s; @@ -107,22 +109,22 @@ seconds_to_approximate_hms (int s) if (h > 0) { if (m > 30) { - ap << (h + 1) << " hours"; + ap << (h + 1) << N_(" ") << _("hours"); } else { if (h == 1) { - ap << "1 hour"; + ap << N_("1 ") << _("hour"); } else { - ap << h << " hours"; + ap << h << N_(" ") << _("hours"); } } } else if (m > 0) { if (m == 1) { - ap << "1 minute"; + ap << N_("1 ") << _("minute"); } else { - ap << m << " minutes"; + ap << m << N_(" ") << _("minutes"); } } else { - ap << s << " seconds"; + ap << s << N_(" ") << _("seconds"); } return ap.str (); @@ -135,12 +137,12 @@ seconds_to_approximate_hms (int s) static string demangle (string l) { - string::size_type const b = l.find_first_of ("("); + string::size_type const b = l.find_first_of (N_("(")); if (b == string::npos) { return l; } - string::size_type const p = l.find_last_of ("+"); + string::size_type const p = l.find_last_of (N_("+")); if (p == string::npos) { return l; } @@ -183,7 +185,7 @@ stacktrace (ostream& out, int levels) if (strings) { for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) { - out << " " << demangle (strings[i]) << endl; + out << N_(" ") << demangle (strings[i]) << endl; } free (strings); @@ -198,7 +200,7 @@ static string ffmpeg_version_to_string (int v) { stringstream s; - s << ((v & 0xff0000) >> 16) << "." << ((v & 0xff00) >> 8) << "." << (v & 0xff); + s << ((v & 0xff0000) >> 16) << N_(".") << ((v & 0xff00) >> 8) << N_(".") << (v & 0xff); return s.str (); } @@ -207,16 +209,16 @@ string dependency_version_summary () { stringstream s; - s << "libopenjpeg " << opj_version () << ", " - << "libavcodec " << ffmpeg_version_to_string (avcodec_version()) << ", " - << "libavfilter " << ffmpeg_version_to_string (avfilter_version()) << ", " - << "libavformat " << ffmpeg_version_to_string (avformat_version()) << ", " - << "libavutil " << ffmpeg_version_to_string (avutil_version()) << ", " - << "libpostproc " << ffmpeg_version_to_string (postproc_version()) << ", " - << "libswscale " << ffmpeg_version_to_string (swscale_version()) << ", " - << MagickVersion << ", " - << "libssh " << ssh_version (0) << ", " - << "libdcp " << libdcp::version << " git " << libdcp::git_commit; + s << N_("libopenjpeg ") << opj_version () << N_(", ") + << N_("libavcodec ") << ffmpeg_version_to_string (avcodec_version()) << N_(", ") + << N_("libavfilter ") << ffmpeg_version_to_string (avfilter_version()) << N_(", ") + << N_("libavformat ") << ffmpeg_version_to_string (avformat_version()) << N_(", ") + << N_("libavutil ") << ffmpeg_version_to_string (avutil_version()) << N_(", ") + << N_("libpostproc ") << ffmpeg_version_to_string (postproc_version()) << N_(", ") + << N_("libswscale ") << ffmpeg_version_to_string (swscale_version()) << N_(", ") + << MagickVersion << N_(", ") + << N_("libssh ") << ssh_version (0) << N_(", ") + << N_("libdcp ") << libdcp::version << N_(" git ") << libdcp::git_commit; return s.str (); } @@ -233,6 +235,8 @@ seconds (struct timeval t) void dvdomatic_setup () { + bindtextdomain ("libdvdomatic", LOCALE_DIR); + avfilter_register_all (); Format::setup_formats (); @@ -252,7 +256,7 @@ string crop_string (Position start, libdcp::Size size) { stringstream s; - s << "crop=" << size.width << ":" << size.height << ":" << start.x << ":" << start.y; + s << N_("crop=") << size.width << N_(":") << size.height << N_(":") << start.x << N_(":") << start.y; return s.str (); } @@ -268,7 +272,7 @@ split_at_spaces_considering_quotes (string s) for (string::size_type i = 0; i < s.length(); ++i) { if (s[i] == ' ' && !in_quotes) { out.push_back (c); - c = ""; + c = N_(""); } else if (s[i] == '"') { in_quotes = !in_quotes; } else { @@ -423,7 +427,7 @@ DCPFrameRate::DCPFrameRate (float source_fps) } if (!best) { - throw EncodeError ("cannot find a suitable DCP frame rate for this source"); + throw EncodeError (_("cannot find a suitable DCP frame rate for this source")); } frames_per_second = best->dcp; @@ -476,13 +480,13 @@ colour_lut_index_to_name (int index) { switch (index) { case 0: - return "sRGB"; + return _("sRGB"); case 1: - return "Rec 709"; + return _("Rec 709"); } assert (false); - return ""; + return N_(""); } Socket::Socket (int timeout) @@ -519,7 +523,7 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint) } while (ec == asio::error::would_block); if (ec || !_socket.is_open ()) { - throw NetworkError ("connect timed out"); + throw NetworkError (_("connect timed out")); } } @@ -656,13 +660,13 @@ string get_required_string (multimap const & kv, string k) { if (kv.count (k) > 1) { - throw StringError ("unexpected multiple keys in key-value set"); + throw StringError (N_("unexpected multiple keys in key-value set")); } multimap::const_iterator i = kv.find (k); if (i == kv.end ()) { - throw StringError (String::compose ("missing key %1 in key-value set", k)); + throw StringError (String::compose (_("missing key %1 in key-value set"), k)); } return i->second; @@ -686,12 +690,12 @@ string get_optional_string (multimap const & kv, string k) { if (kv.count (k) > 1) { - throw StringError ("unexpected multiple keys in key-value set"); + throw StringError (N_("unexpected multiple keys in key-value set")); } multimap::const_iterator i = kv.find (k); if (i == kv.end ()) { - return ""; + return N_(""); } return i->second; @@ -701,7 +705,7 @@ int get_optional_int (multimap const & kv, string k) { if (kv.count (k) > 1) { - throw StringError ("unexpected multiple keys in key-value set"); + throw StringError (N_("unexpected multiple keys in key-value set")); } multimap::const_iterator i = kv.find (k); @@ -870,7 +874,7 @@ still_image_file (string f) transform (ext.begin(), ext.end(), ext.begin(), ::tolower); - return (ext == ".tif" || ext == ".tiff" || ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".bmp"); + return (ext == N_(".tif") || ext == N_(".tiff") || ext == N_(".jpg") || ext == N_(".jpeg") || ext == N_(".png") || ext == N_(".bmp")); } /** @return A pair containing CPU model name and the number of processors */ @@ -881,16 +885,16 @@ cpu_info () info.second = 0; #ifdef DVDOMATIC_POSIX - ifstream f ("/proc/cpuinfo"); + ifstream f (N_("/proc/cpuinfo")); while (f.good ()) { string l; getline (f, l); - if (boost::algorithm::starts_with (l, "model name")) { + if (boost::algorithm::starts_with (l, N_("model name"))) { string::size_type const c = l.find (':'); if (c != string::npos) { info.first = l.substr (c + 2); } - } else if (boost::algorithm::starts_with (l, "processor")) { + } else if (boost::algorithm::starts_with (l, N_("processor"))) { ++info.second; } } diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index c1f48cb5e..891720f6b 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -25,6 +25,8 @@ #include "options.h" #include "job.h" +#include "i18n.h" + using boost::shared_ptr; using boost::optional; @@ -76,7 +78,7 @@ VideoDecoder::repeat_last_video () void VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub) { - TIMING ("Decoder emits %1", _video_frame); + TIMING (N_("Decoder emits %1"), _video_frame); Video (image, same, sub); ++_video_frame; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index c2cc00328..d480d502a 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -29,6 +29,8 @@ #include "log.h" #include "dcp_video_frame.h" +#include "i18n.h" + using std::make_pair; using std::pair; using std::string; @@ -76,7 +78,7 @@ Writer::Writer (shared_ptr f) _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), - "audio.mxf", + N_("audio.mxf"), DCPFrameRate (_film->frames_per_second()).frames_per_second, dcp_audio_channels (_film->audio_channels()), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) @@ -147,9 +149,9 @@ try break; } - TIMING ("writer sleeps with a queue of %1", _queue.size()); + TIMING (N_("writer sleeps with a queue of %1"), _queue.size()); _condition.wait (lock); - TIMING ("writer wakes with a queue of %1", _queue.size()); + TIMING (N_("writer wakes with a queue of %1"), _queue.size()); } if (_finish && _queue.empty()) { @@ -168,7 +170,7 @@ try switch (qi.type) { case QueueItem::FULL: { - _film->log()->log (String::compose ("Writer FULL-writes %1 to MXF", qi.frame)); + _film->log()->log (String::compose (N_("Writer FULL-writes %1 to MXF"), qi.frame)); if (!qi.encoded) { qi.encoded.reset (new EncodedData (_film->j2c_path (qi.frame, false))); } @@ -179,14 +181,14 @@ try break; } case QueueItem::FAKE: - _film->log()->log (String::compose ("Writer FAKE-writes %1 to MXF", qi.frame)); + _film->log()->log (String::compose (N_("Writer FAKE-writes %1 to MXF"), qi.frame)); _picture_asset_writer->fake_write (qi.size); _last_written.reset (); ++_fake_written; break; case QueueItem::REPEAT: { - _film->log()->log (String::compose ("Writer REPEAT-writes %1 to MXF", qi.frame)); + _film->log()->log (String::compose (N_("Writer REPEAT-writes %1 to MXF"), qi.frame)); libdcp::FrameInfo const fin = _picture_asset_writer->write (_last_written->data(), _last_written->size()); _last_written->write_info (_film, qi.frame, fin); ++_repeat_written; @@ -215,7 +217,7 @@ try ++_pushed_to_disk; lock.unlock (); - _film->log()->log (String::compose ("Writer full (awaiting %1); pushes %2 to disk", _last_written_frame + 1, qi.frame)); + _film->log()->log (String::compose (N_("Writer full (awaiting %1); pushes %2 to disk"), _last_written_frame + 1, qi.frame)); qi.encoded->write (_film, qi.frame); lock.lock (); qi.encoded.reset (); @@ -270,14 +272,14 @@ Writer::finish () boost::filesystem::path to; to /= _film->dir (_film->dcp_name()); - to /= "video.mxf"; + to /= N_("video.mxf"); boost::filesystem::create_hard_link (from, to); /* And update the asset */ _picture_asset->set_directory (_film->dir (_film->dcp_name ())); - _picture_asset->set_file_name ("video.mxf"); + _picture_asset->set_file_name (N_("video.mxf")); if (_sound_asset) { _sound_asset->set_entry_point (_film->trim_start ()); @@ -302,7 +304,7 @@ Writer::finish () dcp.write_xml (); - _film->log()->log (String::compose ("Wrote %1 FULL, %2 FAKE, %3 REPEAT; %4 pushed to disk", _full_written, _fake_written, _repeat_written, _pushed_to_disk)); + _film->log()->log (String::compose (N_("Wrote %1 FULL, %2 FAKE, %3 REPEAT; %4 pushed to disk"), _full_written, _fake_written, _repeat_written, _pushed_to_disk)); } /** Tell the writer that frame `f' should be a repeat of the frame before it */ @@ -328,7 +330,7 @@ Writer::check_existing_picture_mxf () boost::filesystem::path p; p /= _film->video_mxf_dir (); p /= _film->video_mxf_filename (); - FILE* mxf = fopen (p.string().c_str(), "rb"); + FILE* mxf = fopen (p.string().c_str(), N_("rb")); if (!mxf) { return; } @@ -346,11 +348,11 @@ Writer::check_existing_picture_mxf () string const existing_hash = md5_digest (data.data(), data.size()); if (existing_hash != info.hash) { - _film->log()->log (String::compose ("Existing frame %1 failed hash check", _first_nonexistant_frame)); + _film->log()->log (String::compose (N_("Existing frame %1 failed hash check"), _first_nonexistant_frame)); break; } - _film->log()->log (String::compose ("Have existing frame %1", _first_nonexistant_frame)); + _film->log()->log (String::compose (N_("Have existing frame %1"), _first_nonexistant_frame)); ++_first_nonexistant_frame; } diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc index d1760c327..52e551d2a 100644 --- a/src/tools/dvdomatic.cc +++ b/src/tools/dvdomatic.cc @@ -441,15 +441,9 @@ setup_i18n () if (wxLocale::IsAvailable (language)) { locale = new wxLocale (language, wxLOCALE_LOAD_DEFAULT); - + #ifdef __WXGTK__ - locale->AddCatalogLookupPathPrefix (wxT ("/usr")); - locale->AddCatalogLookupPathPrefix (wxT ("/usr/local")); - locale->AddCatalogLookupPathPrefix (wxT ("build/src/wx/mo")); - locale->AddCatalogLookupPathPrefix (wxT ("build/src/tools/mo")); - wxStandardPaths* paths = (wxStandardPaths*) &wxStandardPaths::Get(); - wxString prefix = paths->GetInstallPrefix(); - locale->AddCatalogLookupPathPrefix (prefix); + locale->AddCatalogLookupPathPrefix (wxT (LOCALE_DIR)); #endif locale->AddCatalog ("libdvdomatic-wx"); diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 07e32a457..bf97d0d3a 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -154,7 +154,7 @@ ConfigDialog::ConfigDialog (wxWindow* parent) _reference_scaler->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (ConfigDialog::reference_scaler_changed), 0, this); pair p = Filter::ffmpeg_strings (config->reference_filters ()); - _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); + _reference_filters->SetLabel (std_to_wx (p.first + N_(" ") + p.second)); _reference_filters_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ConfigDialog::edit_reference_filters_clicked), 0, this); vector servers = config->servers (); @@ -313,7 +313,7 @@ ConfigDialog::reference_filters_changed (vector f) { Config::instance()->set_reference_filters (f); pair p = Filter::ffmpeg_strings (Config::instance()->reference_filters ()); - _reference_filters->SetLabel (std_to_wx (p.first + " " + p.second)); + _reference_filters->SetLabel (std_to_wx (p.first + N_(" ") + p.second)); } void diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 68291a812..b328f04c9 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -162,7 +162,7 @@ FilmEditor::make_film_panel () _still_duration = new wxSpinCtrl (_film_panel); still_control (_still_duration); s->Add (_still_duration, 1, wxEXPAND); - /* TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time */ + /// TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time still_control (add_label_to_sizer (s, _film_panel, _("s"))); grid->Add (s); } @@ -320,7 +320,7 @@ FilmEditor::make_audio_panel () wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_delay = new wxSpinCtrl (_audio_panel); s->Add (video_control (_audio_delay), 1); - /* TRANSLATORS: this is an abbreviation for milliseconds, the unit of time */ + /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time video_control (add_label_to_sizer (s, _audio_panel, _("ms"))); grid->Add (s); } @@ -342,9 +342,8 @@ FilmEditor::make_audio_panel () assert (MAX_AUDIO_CHANNELS == 6); - /* TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency - enhancement channel (sub-woofer)./ - */ + /// TRANSLATORS: these are the names of audio channels; Lfe (sub) is the low-frequency + /// enhancement channel (sub-woofer). wxString const channels[] = { _("Left"), _("Right"), @@ -617,9 +616,9 @@ FilmEditor::film_changed (Film::Property p) break; case Film::LENGTH: if (_film->frames_per_second() > 0 && _film->length()) { - s << _film->length().get() << " frames; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); + s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); } else if (_film->length()) { - s << _film->length().get() << " frames"; + s << _film->length().get() << " " << _("frames"); } _length->SetLabel (std_to_wx (s.str ())); if (_film->length()) { @@ -754,7 +753,7 @@ FilmEditor::set_film (shared_ptr f) if (_film) { FileChanged (_film->directory ()); } else { - FileChanged (""); + FileChanged (N_("")); } film_changed (Film::NAME); @@ -1132,11 +1131,11 @@ FilmEditor::setup_audio_details () } else { stringstream s; if (_film->audio_stream()->channels() == 1) { - s << "1 channel"; + s << _("1 channel"); } else { - s << _film->audio_stream()->channels () << " channels"; + s << _film->audio_stream()->channels () << " " << _("channels"); } - s << ", " << _film->audio_stream()->sample_rate() << "Hz"; + s << ", " << _film->audio_stream()->sample_rate() << _("Hz"); _audio->SetLabel (std_to_wx (s.str ())); } } @@ -1169,7 +1168,7 @@ FilmEditor::setup_dcp_name () { string s = _film->dcp_name (true); if (s.length() > 28) { - _dcp_name->SetLabel (std_to_wx (s.substr (0, 28) + "...")); + _dcp_name->SetLabel (std_to_wx (s.substr (0, 28) + N_("..."))); _dcp_name->SetToolTip (std_to_wx (s)); } else { _dcp_name->SetLabel (std_to_wx (s)); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 96656ce09..3705f38bb 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -51,7 +51,7 @@ FilmViewer::FilmViewer (shared_ptr f, wxWindow* p) : wxPanel (p) , _panel (new wxPanel (this)) , _slider (new wxSlider (this, wxID_ANY, 0, 0, 4096)) - , _play_button (new wxToggleButton (this, wxID_ANY, wxT ("Play"))) + , _play_button (new wxToggleButton (this, wxID_ANY, _("Play"))) , _display_frame_x (0) , _got_frame (false) , _clear_required (false) diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index a57aaf5b9..e93d06dbe 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -54,7 +54,7 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr film) _frames->SetLabel (std_to_wx (lexical_cast (_film->length().get()))); double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824); stringstream s; - s << fixed << setprecision (1) << disk << "Gb"; + s << fixed << setprecision (1) << disk << _("Gb"); _disk->SetLabel (std_to_wx (s.str ())); } else { _frames->SetLabel (_("unknown")); diff --git a/src/wx/server_dialog.cc b/src/wx/server_dialog.cc index 1b5b71dc9..46e3f7127 100644 --- a/src/wx/server_dialog.cc +++ b/src/wx/server_dialog.cc @@ -27,7 +27,7 @@ ServerDialog::ServerDialog (wxWindow* parent, ServerDescription* server) if (server) { _server = server; } else { - _server = new ServerDescription ("localhost", 1); + _server = new ServerDescription (N_("localhost"), 1); } wxFlexGridSizer* table = new wxFlexGridSizer (2, 4, 4); diff --git a/wscript b/wscript index edf01784b..16ef91f3b 100644 --- a/wscript +++ b/wscript @@ -21,7 +21,9 @@ def configure(conf): if conf.options.target_windows: conf.load('winres') - conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS', '-msse', '-mfpmath=sse', '-ffast-math', '-fno-strict-aliasing', '-Wall', '-Wno-attributes', '-Wextra']) + conf.env.append_value('CXXFLAGS', ['-D__STDC_CONSTANT_MACROS', '-msse', '-mfpmath=sse', '-ffast-math', '-fno-strict-aliasing', + '-Wall', '-Wno-attributes', '-Wextra', + '-DLOCALE_DIR="%s/share/locale"' % conf.env.prefix]) if conf.options.target_windows: conf.env.append_value('CXXFLAGS', ['-DDVDOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE']) -- cgit v1.2.3 From 6a516da9a403ce05b2b78b3cf1376f4dfe4be3fe Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 1 Mar 2013 21:35:41 +0000 Subject: Make film hold its DCP frame rate. --- src/lib/ab_transcoder.cc | 2 +- src/lib/analyse_audio_job.cc | 2 +- src/lib/dcp_video_frame.cc | 4 +- src/lib/dcp_video_frame.h | 4 +- src/lib/encoder.cc | 8 +- src/lib/film.cc | 45 +++++++---- src/lib/film.h | 19 +++-- src/lib/transcode_job.cc | 4 +- src/lib/transcoder.cc | 2 +- src/lib/util.cc | 37 +++++---- src/lib/util.h | 10 +-- src/lib/writer.cc | 15 ++-- src/wx/film_editor.cc | 16 ++-- src/wx/film_editor.h | 4 +- src/wx/film_viewer.cc | 6 +- src/wx/properties_dialog.cc | 4 +- test/metadata.ref | 5 +- test/test.cc | 183 +++++++++++++++++++++++-------------------- 18 files changed, 210 insertions(+), 160 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index f47a99fda..4ed5d02ca 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -60,7 +60,7 @@ ABTranscoder::ABTranscoder ( if (_film_a->audio_stream()) { shared_ptr st = _film_a->audio_stream(); - _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->frames_per_second())); + _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate())); _delay_line.reset (new DelayLine (_film_a->log(), st->channels(), _film_a->audio_delay() * st->sample_rate() / 1000)); _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); } diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index ca316f70e..41f918f34 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -66,7 +66,7 @@ AnalyseAudioJob::run () decoders.audio->set_audio_stream (_film->audio_stream ()); decoders.audio->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); - int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->frames_per_second()); + int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->source_frame_rate()); _samples_per_point = total_audio_frames / _num_points; _current.resize (_film->audio_stream()->channels ()); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 098d222cd..67617c63c 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -80,7 +80,7 @@ using libdcp::Size; DCPVideoFrame::DCPVideoFrame ( shared_ptr yuv, shared_ptr sub, Size out, int p, int subtitle_offset, float subtitle_scale, - Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l + Scaler const * s, int f, int dcp_fps, string pp, int clut, int bw, Log* l ) : _input (yuv) , _subtitle (sub) @@ -90,7 +90,7 @@ DCPVideoFrame::DCPVideoFrame ( , _subtitle_scale (subtitle_scale) , _scaler (s) , _frame (f) - , _frames_per_second (DCPFrameRate(fps).frames_per_second) + , _frames_per_second (dcp_fps) , _post_process (pp) , _colour_lut (clut) , _j2k_bandwidth (bw) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index ab458b58f..6794765ac 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -107,7 +107,7 @@ class DCPVideoFrame public: DCPVideoFrame ( boost::shared_ptr, boost::shared_ptr, libdcp::Size, - int, int, float, Scaler const *, int, float, std::string, int, int, Log * + int, int, float, Scaler const *, int, int, std::string, int, int, Log * ); virtual ~DCPVideoFrame (); @@ -130,7 +130,7 @@ private: float _subtitle_scale; Scaler const * _scaler; ///< scaler to use int _frame; ///< frame index within the DCP's intrinsic duration - int _frames_per_second; ///< Frames per second that we will use for the DCP (rounded) + int _frames_per_second; ///< Frames per second that we will use for the DCP std::string _post_process; ///< FFmpeg post-processing string to use int _colour_lut; ///< Colour look-up table to use int _j2k_bandwidth; ///< J2K bandwidth to use diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 3cc643cd6..687dfdd2b 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -233,9 +233,9 @@ Encoder::frame_done () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - DCPFrameRate dfr (_film->frames_per_second ()); + FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); - if (dfr.skip && (_video_frames_in % 2)) { + if (frc.skip && (_video_frames_in % 2)) { ++_video_frames_in; return; } @@ -273,7 +273,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrformat()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), - _film->scaler(), _video_frames_out, _film->frames_per_second(), s.second, + _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), _film->log() ) @@ -286,7 +286,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrrepeat (_video_frames_out); ++_video_frames_out; frame_done (); diff --git a/src/lib/film.cc b/src/lib/film.cc index 510158e94..a661adcc6 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -74,7 +74,7 @@ using boost::starts_with; using boost::optional; using libdcp::Size; -int const Film::state_version = 3; +int const Film::state_version = 4; /** Construct a Film object in a given directory, reading any metadata * file that exists in that directory. An exception will be thrown if @@ -103,7 +103,8 @@ Film::Film (string d, bool must_exist) , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) - , _frames_per_second (0) + , _dcp_frame_rate (0) + , _source_frame_rate (0) , _dirty (false) { set_dci_date_today (); @@ -175,6 +176,7 @@ Film::Film (Film const & o) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) , _dci_date (o._dci_date) + , _dcp_frame_rate (o._dcp_frame_rate) , _size (o._size) , _length (o._length) , _dcp_intrinsic_duration (o._dcp_intrinsic_duration) @@ -182,7 +184,7 @@ Film::Film (Film const & o) , _content_audio_streams (o._content_audio_streams) , _external_audio_stream (o._external_audio_stream) , _subtitle_streams (o._subtitle_streams) - , _frames_per_second (o._frames_per_second) + , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) { @@ -204,6 +206,7 @@ Film::video_state_identifier () const s << format()->id() << N_("_") << content_digest() << N_("_") << crop().left << N_("_") << crop().right << N_("_") << crop().top << N_("_") << crop().bottom + << N_("_") << _dcp_frame_rate << N_("_") << f.first << N_("_") << f.second << N_("_") << scaler()->id() << N_("_") << j2k_bandwidth() @@ -441,6 +444,7 @@ Film::write_metadata () const f << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); _dci_metadata.write (f); f << N_("dci_date ") << boost::gregorian::to_iso_string (_dci_date) << N_("\n"); + f << N_("dcp_frame_rate ") << _dcp_frame_rate << "\n"; f << N_("width ") << _size.width << N_("\n"); f << N_("height ") << _size.height << N_("\n"); f << N_("length ") << _length.get_value_or(0) << N_("\n"); @@ -457,7 +461,7 @@ Film::write_metadata () const f << N_("subtitle_stream ") << (*i)->to_string () << N_("\n"); } - f << N_("frames_per_second ") << _frames_per_second << N_("\n"); + f << N_("source_frame_rate ") << _source_frame_rate << N_("\n"); _dirty = false; } @@ -569,6 +573,8 @@ Film::read_metadata () _j2k_bandwidth = atoi (v.c_str ()); } else if (k == N_("dci_date")) { _dci_date = boost::gregorian::from_undelimited_string (v); + } else if (k == "dcp_frame_rate") { + _dcp_frame_rate = atoi (v.c_str ()); } _dci_metadata.read (k, v); @@ -596,8 +602,8 @@ Film::read_metadata () _external_audio_stream = audio_stream_factory (v, version); } else if (k == N_("subtitle_stream")) { _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == N_("frames_per_second")) { - _frames_per_second = atof (v.c_str ()); + } else if (k == N_("source_frame_rate") || (version < 4 && k == "frames_per_second")) { + _source_frame_rate = atof (v.c_str ()); } } @@ -707,7 +713,7 @@ Film::target_audio_sample_rate () const /* Resample to a DCI-approved sample rate */ double t = dcp_audio_sample_rate (audio_stream()->sample_rate()); - DCPFrameRate dfr (frames_per_second ()); + FrameRateConversion frc (source_frame_rate(), dcp_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -715,8 +721,8 @@ Film::target_audio_sample_rate () const skip/repeat doesn't come into effect here. */ - if (dfr.change_speed) { - t *= _frames_per_second * dfr.factor() / dfr.frames_per_second; + if (frc.change_speed) { + t *= source_frame_rate() * frc.factor() / dcp_frame_rate(); } return rint (t); @@ -725,7 +731,7 @@ Film::target_audio_sample_rate () const int Film::still_duration_in_frames () const { - return still_duration() * frames_per_second(); + return still_duration() * source_frame_rate(); } /** @return a DCI-compliant name for a DCP of this film */ @@ -898,7 +904,7 @@ Film::set_content (string c) Decoders d = decoder_factory (shared_from_this(), DecodeOptions()); set_size (d.video->native_size ()); - set_frames_per_second (d.video->frames_per_second ()); + set_source_frame_rate (d.video->frames_per_second ()); set_subtitle_streams (d.video->subtitle_streams ()); if (d.audio) { set_content_audio_streams (d.audio->audio_streams ()); @@ -1236,6 +1242,17 @@ Film::set_dci_metadata (DCIMetadata m) signal_changed (DCI_METADATA); } + +void +Film::set_dcp_frame_rate (int f) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _dcp_frame_rate = f; + } + signal_changed (DCP_FRAME_RATE); +} + void Film::set_size (libdcp::Size s) { @@ -1307,13 +1324,13 @@ Film::set_subtitle_streams (vector > s) } void -Film::set_frames_per_second (float f) +Film::set_source_frame_rate (float f) { { boost::mutex::scoped_lock lm (_state_mutex); - _frames_per_second = f; + _source_frame_rate = f; } - signal_changed (FRAMES_PER_SECOND); + signal_changed (SOURCE_FRAME_RATE); } void diff --git a/src/lib/film.h b/src/lib/film.h index 847ab434e..9921acbb4 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -148,7 +148,8 @@ public: DCP_INTRINSIC_DURATION, CONTENT_AUDIO_STREAMS, SUBTITLE_STREAMS, - FRAMES_PER_SECOND, + SOURCE_FRAME_RATE, + DCP_FRAME_RATE }; @@ -285,6 +286,11 @@ public: boost::mutex::scoped_lock lm (_state_mutex); return _dci_metadata; } + + int dcp_frame_rate () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _dcp_frame_rate; + } libdcp::Size size () const { boost::mutex::scoped_lock lm (_state_mutex); @@ -311,13 +317,13 @@ public: return _subtitle_streams; } - float frames_per_second () const { + float source_frame_rate () const { boost::mutex::scoped_lock lm (_state_mutex); if (content_type() == STILL) { return 24; } - return _frames_per_second; + return _source_frame_rate; } boost::shared_ptr audio_stream () const; @@ -355,6 +361,7 @@ public: void set_colour_lut (int); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); + void set_dcp_frame_rate (int); void set_size (libdcp::Size); void set_length (SourceFrame); void unset_length (); @@ -362,7 +369,7 @@ public: void set_content_digest (std::string); void set_content_audio_streams (std::vector >); void set_subtitle_streams (std::vector >); - void set_frames_per_second (float); + void set_source_frame_rate (float); /** Emitted when some property has changed */ mutable boost::signals2::signal Changed; @@ -461,6 +468,8 @@ private: DCIMetadata _dci_metadata; /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; + /** Frames per second to run our DCP at */ + int _dcp_frame_rate; /* Data which are cached to speed things up */ @@ -478,7 +487,7 @@ private: /** the subtitle streams that we can use */ std::vector > _subtitle_streams; /** Frames per second of the source */ - float _frames_per_second; + float _source_frame_rate; /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 61fad2e2b..f7cc500fe 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -120,8 +120,8 @@ TranscodeJob::remaining_time () const /* Compute approximate proposed length here, as it's only here that we need it */ int length = _film->length().get(); - DCPFrameRate const dfr (_film->frames_per_second ()); - if (dfr.skip) { + FrameRateConversion const frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + if (frc.skip) { length /= 2; } /* If we are repeating it shouldn't affect transcode time, so don't take it into account */ diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 959fac857..9720ca56a 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -57,7 +57,7 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< if (f->audio_stream()) { shared_ptr st = f->audio_stream(); - _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->frames_per_second())); + _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate())); _delay_line.reset (new DelayLine (f->log(), st->channels(), f->audio_delay() * st->sample_rate() / 1000)); _gain.reset (new Gain (f->log(), f->audio_gain())); } diff --git a/src/lib/util.cc b/src/lib/util.cc index de69636da..85a04ed17 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -375,21 +375,12 @@ public: , dcp (dcp_) {} - bool skip () const { - return !about_equal (source, dcp) && source > dcp; - } - - bool repeat () const { - return !about_equal (source, dcp) && source < dcp; - } - float source; int dcp; }; -/** @param fps Arbitrary source frames-per-second value */ -/** XXX: this could be slow-ish */ -DCPFrameRate::DCPFrameRate (float source_fps) +int +best_dcp_frame_rate (float source_fps) { list const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates (); @@ -427,14 +418,8 @@ DCPFrameRate::DCPFrameRate (float source_fps) ++i; } - if (!best) { - throw EncodeError (_("cannot find a suitable DCP frame rate for this source")); - } - - frames_per_second = best->dcp; - skip = best->skip (); - repeat = best->repeat (); - change_speed = !about_equal (source_fps * factor(), frames_per_second); + assert (best); + return best->dcp; } /** @param An arbitrary sampling rate. @@ -962,3 +947,17 @@ AudioMapping::dcp_channels () const return _source_channels; } + +FrameRateConversion::FrameRateConversion (float source, int dcp) + : skip (false) + , repeat (false) + , change_speed (false) +{ + if (fabs (source / 2.0 - dcp) < (fabs (source - dcp))) { + skip = true; + } else if (fabs (source * 2 - dcp) < fabs (source - dcp)) { + repeat = true; + } + + change_speed = !about_equal (source * factor(), dcp); +} diff --git a/src/lib/util.h b/src/lib/util.h index 22c6ea95b..103907151 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -62,9 +62,9 @@ extern std::string audio_channel_name (int); typedef int SourceFrame; -struct DCPFrameRate +struct FrameRateConversion { - DCPFrameRate (float); + FrameRateConversion (float, int); /** @return factor by which to multiply a source frame rate to get the effective rate after any skip or repeat has happened. @@ -79,14 +79,12 @@ struct DCPFrameRate return 1; } - /** frames per second for the DCP */ - int frames_per_second; /** true to skip every other frame */ bool skip; /** true to repeat every frame once */ bool repeat; /** true if this DCP will run its video faster or slower than the source - * without taking into account `repeat'. + * without taking into account `repeat' nor `skip'. * (e.g. change_speed will be true if * source is 29.97fps, DCP is 30fps * source is 14.50fps, DCP is 30fps @@ -97,6 +95,8 @@ struct DCPFrameRate bool change_speed; }; +int best_dcp_frame_rate (float); + enum ContentType { STILL, ///< content is still images VIDEO ///< content is a video diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 334ecec65..5a2f7c9a9 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -67,8 +67,8 @@ Writer::Writer (shared_ptr f) new libdcp::MonoPictureAsset ( _film->video_mxf_dir (), _film->video_mxf_filename (), - DCPFrameRate (_film->frames_per_second()).frames_per_second, - _film->format()->dcp_size() + _film->dcp_frame_rate (), + _film->format()->dcp_size () ) ); @@ -81,7 +81,7 @@ Writer::Writer (shared_ptr f) new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), N_("audio.mxf"), - DCPFrameRate (_film->frames_per_second()).frames_per_second, + _film->dcp_frame_rate (), m.dcp_channels (), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) ) @@ -289,10 +289,15 @@ Writer::finish () } libdcp::DCP dcp (_film->dir (_film->dcp_name())); - DCPFrameRate dfr (_film->frames_per_second ()); shared_ptr cpl ( - new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second) + new libdcp::CPL ( + _film->dir (_film->dcp_name()), + _film->dcp_name(), + _film->dcp_content_type()->libdcp_kind (), + frames, + _film->dcp_frame_rate () + ) ); dcp.add_cpl (cpl); diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 362243ef3..0a6a35273 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -127,8 +127,8 @@ FilmEditor::make_film_panel () grid->Add (_dcp_content_type); video_control (add_label_to_sizer (grid, _film_panel, _("Original Frame Rate"))); - _frames_per_second = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_frames_per_second), 1, wxALIGN_CENTER_VERTICAL); + _source_frame_rate = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); + grid->Add (video_control (_source_frame_rate), 1, wxALIGN_CENTER_VERTICAL); video_control (add_label_to_sizer (grid, _film_panel, _("Original Size"))); _original_size = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); @@ -596,9 +596,9 @@ FilmEditor::film_changed (Film::Property p) checked_set (_name, _film->name()); setup_dcp_name (); break; - case Film::FRAMES_PER_SECOND: - s << fixed << setprecision(2) << _film->frames_per_second(); - _frames_per_second->SetLabel (std_to_wx (s.str ())); + case Film::SOURCE_FRAME_RATE: + s << fixed << setprecision(2) << _film->source_frame_rate(); + _source_frame_rate->SetLabel (std_to_wx (s.str ())); break; case Film::SIZE: if (_film->size().width == 0 && _film->size().height == 0) { @@ -609,8 +609,8 @@ FilmEditor::film_changed (Film::Property p) } break; case Film::LENGTH: - if (_film->frames_per_second() > 0 && _film->length()) { - s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); + if (_film->source_frame_rate() > 0 && _film->length()) { + s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate()); } else if (_film->length()) { s << _film->length().get() << " " << _("frames"); } @@ -782,7 +782,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::LENGTH); film_changed (Film::CONTENT_AUDIO_STREAMS); film_changed (Film::SUBTITLE_STREAMS); - film_changed (Film::FRAMES_PER_SECOND); + film_changed (Film::SOURCE_FRAME_RATE); } /** Updates the sensitivity of lots of widgets to a given value. diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 2af747bb0..da9bb0301 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -157,8 +157,8 @@ private: wxSpinCtrl* _j2k_bandwidth; /** The Film's DCP content type */ wxChoice* _dcp_content_type; - /** The Film's frames per second */ - wxStaticText* _frames_per_second; + /** The Film's source frame rate */ + wxStaticText* _source_frame_rate; /** The Film's original size */ wxStaticText* _original_size; /** The Film's length */ diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 5eba7fd80..a40a3c78d 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -188,7 +188,7 @@ FilmViewer::timer (wxTimerEvent &) get_frame (); if (_film->length()) { - int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->frames_per_second()); + int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate()); if (new_slider_position != _slider->GetValue()) { _slider->SetValue (new_slider_position); } @@ -237,7 +237,7 @@ FilmViewer::slider_moved (wxScrollEvent &) return; } - if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->frames_per_second()))) { + if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) { return; } @@ -369,7 +369,7 @@ FilmViewer::check_play_state () } if (_play_button->GetValue()) { - _timer.Start (1000 / _film->frames_per_second()); + _timer.Start (1000 / _film->source_frame_rate()); } else { _timer.Stop (); } diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index e93d06dbe..f4acb6b1a 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -52,7 +52,9 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr film) if (_film->length()) { _frames->SetLabel (std_to_wx (lexical_cast (_film->length().get()))); - double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824); + FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + int const dcp_length = _film->length().get() * frc.factor(); + double const disk = ((double) _film->j2k_bandwidth() / 8) * dcp_length / (_film->dcp_frame_rate() * 1073741824); stringstream s; s << fixed << setprecision (1) << disk << _("Gb"); _disk->SetLabel (std_to_wx (s.str ())); diff --git a/test/metadata.ref b/test/metadata.ref index ab40dfe8d..10702f8a0 100644 --- a/test/metadata.ref +++ b/test/metadata.ref @@ -1,4 +1,4 @@ -version 3 +version 4 name fred use_dci_name 1 content @@ -32,10 +32,11 @@ studio facility package_type dci_date 20130211 +dcp_frame_rate 0 width 0 height 0 length 0 dcp_intrinsic_duration 0 content_digest external_audio_stream external 0 0 -frames_per_second 0 +source_frame_rate 0 diff --git a/test/test.cc b/test/test.cc index 8cfc6e467..b4a459fe7 100644 --- a/test/test.cc +++ b/test/test.cc @@ -500,8 +500,8 @@ BOOST_AUTO_TEST_CASE (make_dcp_with_range_test) BOOST_CHECK_EQUAL (JobManager::instance()->errors(), false); } -/* Test the constructor of DCPFrameRate */ -BOOST_AUTO_TEST_CASE (dcp_frame_rate_test) +/* Test best_dcp_frame_rate and FrameRateConversion */ +BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test) { /* Run some tests with a limited range of allowed rates */ @@ -511,71 +511,82 @@ BOOST_AUTO_TEST_CASE (dcp_frame_rate_test) afr.push_back (30); Config::instance()->set_allowed_dcp_frame_rates (afr); - DCPFrameRate dfr = DCPFrameRate (60); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.skip, true); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + int best = best_dcp_frame_rate (60); + FrameRateConversion frc = FrameRateConversion (60, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, true); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); - dfr = DCPFrameRate (50); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.skip, true); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (48); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 24); - BOOST_CHECK_EQUAL (dfr.skip, true); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (50); + frc = FrameRateConversion (50, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, true); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (48); + frc = FrameRateConversion (48, best); + BOOST_CHECK_EQUAL (best, 24); + BOOST_CHECK_EQUAL (frc.skip, true); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); - dfr = DCPFrameRate (30); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (29.97); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, true); + best = best_dcp_frame_rate (30); + frc = FrameRateConversion (30, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (29.97); + frc = FrameRateConversion (29.97, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, true); - dfr = DCPFrameRate (25); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (24); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 24); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (14.5); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, true); - - dfr = DCPFrameRate (12.6); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, true); - - dfr = DCPFrameRate (12.4); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, true); - - dfr = DCPFrameRate (12); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 24); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (25); + frc = FrameRateConversion (25, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (24); + frc = FrameRateConversion (24, best); + BOOST_CHECK_EQUAL (best, 24); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (14.5); + frc = FrameRateConversion (14.5, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, true); + + best = best_dcp_frame_rate (12.6); + frc = FrameRateConversion (12.6, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, true); + + best = best_dcp_frame_rate (12.4); + frc = FrameRateConversion (12.4, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, true); + + best = best_dcp_frame_rate (12); + frc = FrameRateConversion (12, best); + BOOST_CHECK_EQUAL (best, 24); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, false); /* Now add some more rates and see if it will use them in preference to skip/repeat. @@ -586,29 +597,33 @@ BOOST_AUTO_TEST_CASE (dcp_frame_rate_test) afr.push_back (60); Config::instance()->set_allowed_dcp_frame_rates (afr); - dfr = DCPFrameRate (60); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 60); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (60); + frc = FrameRateConversion (60, best); + BOOST_CHECK_EQUAL (best, 60); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); - dfr = DCPFrameRate (50); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 50); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (48); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 48); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (50); + frc = FrameRateConversion (50, best); + BOOST_CHECK_EQUAL (best, 50); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (48); + frc = FrameRateConversion (48, best); + BOOST_CHECK_EQUAL (best, 48); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); } BOOST_AUTO_TEST_CASE (audio_sampling_rate_test) { shared_ptr f = new_test_film ("audio_sampling_rate_test"); - f->set_frames_per_second (24); + f->set_source_frame_rate (24); + f->set_dcp_frame_rate (24); f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000); @@ -619,11 +634,13 @@ BOOST_AUTO_TEST_CASE (audio_sampling_rate_test) f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 80000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 96000); - f->set_frames_per_second (23.976); + f->set_source_frame_rate (23.976); + f->set_dcp_frame_rate (best_dcp_frame_rate (23.976)); f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952); - f->set_frames_per_second (29.97); + f->set_source_frame_rate (29.97); + f->set_dcp_frame_rate (best_dcp_frame_rate (29.97)); f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952); } -- cgit v1.2.3 From bd79dcbba3a58eae1ff366bb0c3b95791dc6010a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 24 Mar 2013 21:44:25 +0000 Subject: Un-mark some strings that do not need translation. --- src/lib/encoder.cc | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 687dfdd2b..7b338407e 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -244,9 +244,9 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr= _threads.size() * 2 && !_terminate) { - TIMING (_("decoder sleeps with queue of %1"), _queue.size()); + TIMING ("decoder sleeps with queue of %1", _queue.size()); _condition.wait (lock); - TIMING (_("decoder wakes with queue of %1"), _queue.size()); + TIMING ("decoder wakes with queue of %1", _queue.size()); } if (_terminate) { @@ -268,7 +268,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); - TIMING (_("adding to queue of %1"), _queue.size ()); + TIMING ("adding to queue of %1", _queue.size ()); _queue.push_back (boost::shared_ptr ( new DCPVideoFrame ( image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), @@ -349,7 +349,7 @@ Encoder::encoder_thread (ServerDescription* server) while (1) { - TIMING (N_("encoder thread %1 sleeps"), boost::this_thread::get_id()); + TIMING ("encoder thread %1 sleeps", boost::this_thread::get_id()); boost::mutex::scoped_lock lock (_mutex); while (_queue.empty () && !_terminate) { _condition.wait (lock); @@ -359,7 +359,7 @@ Encoder::encoder_thread (ServerDescription* server) return; } - TIMING (N_("encoder thread %1 wakes with queue of %2"), boost::this_thread::get_id(), _queue.size()); + TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); boost::shared_ptr vf = _queue.front (); _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 from queue"), boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); _queue.pop_front (); @@ -393,9 +393,9 @@ Encoder::encoder_thread (ServerDescription* server) } else { try { - TIMING (N_("encoder thread %1 begins local encode of %2"), boost::this_thread::get_id(), vf->frame()); + TIMING ("encoder thread %1 begins local encode of %2", boost::this_thread::get_id(), vf->frame()); encoded = vf->encode_locally (); - TIMING (N_("encoder thread %1 finishes local encode of %2"), boost::this_thread::get_id(), vf->frame()); + TIMING ("encoder thread %1 finishes local encode of %2", boost::this_thread::get_id(), vf->frame()); } catch (std::exception& e) { _film->log()->log (String::compose (N_("Local encode failed (%1)"), e.what ())); } -- cgit v1.2.3 From 127672223cca569986e35c91265e269ed5a6561c Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 31 Mar 2013 15:09:49 +0100 Subject: Runs. --- doc/design/content.tex | 6 +- src/lib/ab_transcode_job.cc | 2 +- src/lib/ab_transcode_job.h | 3 +- src/lib/ab_transcoder.cc | 48 ++-- src/lib/ab_transcoder.h | 13 +- src/lib/analyse_audio_job.cc | 30 +-- src/lib/audio_content.cc | 7 + src/lib/audio_content.h | 13 +- src/lib/audio_decoder.cc | 9 +- src/lib/audio_decoder.h | 23 +- src/lib/content.cc | 20 ++ src/lib/content.h | 19 +- src/lib/decoder.cc | 15 +- src/lib/decoder.h | 8 +- src/lib/decoder_factory.cc | 19 +- src/lib/encoder.cc | 32 +-- src/lib/encoder.h | 4 +- src/lib/examine_content_job.cc | 67 +----- src/lib/examine_content_job.h | 17 +- src/lib/exceptions.h | 1 + src/lib/ffmpeg_content.cc | 156 +++++++++++++ src/lib/ffmpeg_content.h | 93 +++++++- src/lib/ffmpeg_decoder.cc | 143 +++--------- src/lib/ffmpeg_decoder.h | 51 ++-- src/lib/film.cc | 462 +++++++----------------------------- src/lib/film.h | 31 ++- src/lib/filter_graph.cc | 2 +- src/lib/filter_graph.h | 2 +- src/lib/format.cc | 19 +- src/lib/format.h | 16 +- src/lib/imagemagick_content.cc | 2 + src/lib/imagemagick_content.h | 3 +- src/lib/imagemagick_decoder.cc | 65 ++---- src/lib/imagemagick_decoder.h | 14 +- src/lib/job.cc | 2 - src/lib/job.h | 3 +- src/lib/playlist.cc | 266 +++++++++++++++++++++ src/lib/playlist.h | 56 ++++- src/lib/scp_dcp_job.h | 2 +- src/lib/sndfile_content.cc | 41 ++++ src/lib/sndfile_content.h | 6 + src/lib/sndfile_decoder.cc | 142 ++---------- src/lib/sndfile_decoder.h | 28 +-- src/lib/stream.cc | 92 -------- src/lib/stream.h | 121 ---------- src/lib/transcode_job.cc | 19 +- src/lib/transcode_job.h | 1 - src/lib/transcoder.cc | 51 ++-- src/lib/transcoder.h | 16 +- src/lib/util.cc | 6 +- src/lib/util.h | 4 +- src/lib/video_content.cc | 28 +++ src/lib/video_content.h | 39 ++++ src/lib/video_decoder.cc | 16 +- src/lib/video_decoder.h | 24 +- src/lib/writer.cc | 8 +- src/lib/writer.h | 4 +- src/lib/wscript | 8 +- src/tools/dvdomatic.cc | 3 - src/tools/makedcp.cc | 2 +- src/wx/audio_dialog.cc | 19 +- src/wx/audio_dialog.h | 2 + src/wx/film_editor.cc | 514 +++++++++++++++-------------------------- src/wx/film_editor.h | 51 ++-- src/wx/film_viewer.cc | 40 ++-- src/wx/properties_dialog.cc | 10 +- test/test.cc | 84 ++----- 67 files changed, 1361 insertions(+), 1762 deletions(-) create mode 100644 src/lib/audio_content.cc create mode 100644 src/lib/content.cc create mode 100644 src/lib/ffmpeg_content.cc create mode 100644 src/lib/imagemagick_content.cc create mode 100644 src/lib/playlist.cc create mode 100644 src/lib/sndfile_content.cc delete mode 100644 src/lib/stream.cc delete mode 100644 src/lib/stream.h create mode 100644 src/lib/video_content.cc (limited to 'src/lib/encoder.cc') diff --git a/doc/design/content.tex b/doc/design/content.tex index a3c5c5835..0f5f17025 100644 --- a/doc/design/content.tex +++ b/doc/design/content.tex @@ -174,7 +174,7 @@ public: \end{verbatim} Then Film has a \texttt{Playlist} which has a -\texttt{vector}. And it can answer questions +\texttt{vector >}. It can answer questions about audio/video length, frame rate, audio channels and so on. \texttt{Playlist} can also be a source of video and audio, so clients can do: @@ -188,6 +188,8 @@ while (!p->pass ()) { } \end{verbatim} -Playlist could be created on-demand for all the difference it would make. +Playlist could be created on-demand for all the difference it would +make. And perhaps it should, since it will hold Decoders which are +probably run-once. \end{document} diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index 4ffdd9af6..f17d43916 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -54,7 +54,7 @@ ABTranscodeJob::run () { try { /* _film_b is the one with reference filters */ - ABTranscoder w (_film_b, _film, _decode_opt, this, shared_ptr (new Encoder (_film))); + ABTranscoder w (_film_b, _film, _decode_opt, shared_from_this ()); w.go (); set_progress (1); set_state (FINISHED_OK); diff --git a/src/lib/ab_transcode_job.h b/src/lib/ab_transcode_job.h index 8e3cbe2d8..5d029a18b 100644 --- a/src/lib/ab_transcode_job.h +++ b/src/lib/ab_transcode_job.h @@ -46,8 +46,7 @@ public: void run (); private: - DecodeOptions _decode_opt; - /** Copy of our Film using the reference filters and scaler */ boost::shared_ptr _film_b; + DecodeOptions _decode_opt; }; diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 3a1cd83d7..0c687008d 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -21,13 +21,11 @@ #include #include "ab_transcoder.h" #include "film.h" -#include "video_decoder.h" -#include "audio_decoder.h" #include "encoder.h" #include "job.h" #include "options.h" #include "image.h" -#include "decoder_factory.h" +#include "playlist.h" #include "matcher.h" #include "delay_line.h" #include "gain.h" @@ -49,31 +47,23 @@ using boost::dynamic_pointer_cast; * @param e Encoder to use. */ -ABTranscoder::ABTranscoder ( - shared_ptr a, shared_ptr b, DecodeOptions o, Job* j, shared_ptr e) +ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, DecodeOptions o, shared_ptr j) : _film_a (a) , _film_b (b) + , _playlist_a (_film_a->playlist ()) + , _playlist_b (_film_b->playlist ()) , _job (j) - , _encoder (e) + , _encoder (new Encoder (_film_a, _playlist_a)) , _combiner (new Combiner (a->log())) { - _da = decoder_factory (_film_a, o); - _db = decoder_factory (_film_b, o); - - if (_film_a->audio_stream()) { - shared_ptr st = _film_a->audio_stream(); - _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate())); - _delay_line.reset (new DelayLine (_film_a->log(), st->channels(), _film_a->audio_delay() * st->sample_rate() / 1000)); + if (_playlist_a->has_audio ()) { + _matcher.reset (new Matcher (_film_a->log(), _playlist_a->audio_frame_rate(), _playlist_a->video_frame_rate())); + _delay_line.reset (new DelayLine (_film_a->log(), _playlist_a->audio_channels(), _film_a->audio_delay() * _playlist_a->audio_frame_rate() / 1000)); _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); } - /* Set up the decoder to use the film's set streams */ - _da.video->set_subtitle_stream (_film_a->subtitle_stream ()); - _db.video->set_subtitle_stream (_film_a->subtitle_stream ()); - _da.audio->set_audio_stream (_film_a->audio_stream ()); - - _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); - _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); + _playlist_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); + _playlist_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); if (_matcher) { _combiner->connect_video (_matcher); @@ -83,7 +73,7 @@ ABTranscoder::ABTranscoder ( } if (_matcher && _delay_line) { - _da.audio->connect_audio (_delay_line); + _playlist_a->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); @@ -95,23 +85,17 @@ ABTranscoder::go () { _encoder->process_begin (); - bool done[3] = { false, false, false }; + bool done[2] = { false, false }; while (1) { - done[0] = _da.video->pass (); - done[1] = _db.video->pass (); - - if (!done[2] && _da.audio && dynamic_pointer_cast (_da.audio) != dynamic_pointer_cast (_da.video)) { - done[2] = _da.audio->pass (); - } else { - done[2] = true; - } + done[0] = _playlist_a->pass (); + done[1] = _playlist_b->pass (); if (_job) { - _da.video->set_progress (_job); + _playlist_a->set_progress (_job); } - if (done[0] && done[1] && done[2]) { + if (done[0] && done[1]) { break; } } diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 58a08af04..14277c562 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -29,16 +29,14 @@ class Job; class Encoder; -class VideoDecoder; -class AudioDecoder; class Image; class Log; -class Subtitle; class Film; class Matcher; class DelayLine; class Gain; class Combiner; +class Playlist; /** @class ABTranscoder * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -51,8 +49,7 @@ public: boost::shared_ptr a, boost::shared_ptr b, DecodeOptions o, - Job* j, - boost::shared_ptr e + boost::shared_ptr j ); void go (); @@ -60,10 +57,10 @@ public: private: boost::shared_ptr _film_a; boost::shared_ptr _film_b; - Job* _job; + boost::shared_ptr _playlist_a; + boost::shared_ptr _playlist_b; + boost::shared_ptr _job; boost::shared_ptr _encoder; - Decoders _da; - Decoders _db; boost::shared_ptr _combiner; boost::shared_ptr _matcher; boost::shared_ptr _delay_line; diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 43eecbcbd..74491943b 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -22,8 +22,7 @@ #include "compose.hpp" #include "film.h" #include "options.h" -#include "decoder_factory.h" -#include "audio_decoder.h" +#include "playlist.h" #include "i18n.h" @@ -52,29 +51,18 @@ AnalyseAudioJob::name () const void AnalyseAudioJob::run () { - if (!_film->audio_stream () || !_film->length()) { - set_progress (1); - set_state (FINISHED_ERROR); - return; - } - - DecodeOptions options; - options.decode_video = false; - - Decoders decoders = decoder_factory (_film, options); - assert (decoders.audio); + shared_ptr playlist = _film->playlist (); + playlist->disable_video (); - decoders.audio->set_audio_stream (_film->audio_stream ()); - decoders.audio->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); + playlist->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); - int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->source_frame_rate()); - _samples_per_point = max (int64_t (1), total_audio_frames / _num_points); + _samples_per_point = max (int64_t (1), playlist->audio_length() / _num_points); - _current.resize (_film->audio_stream()->channels ()); - _analysis.reset (new AudioAnalysis (_film->audio_stream()->channels())); + _current.resize (playlist->audio_channels ()); + _analysis.reset (new AudioAnalysis (playlist->audio_channels())); - while (!decoders.audio->pass()) { - set_progress (float (_done) / total_audio_frames); + while (!playlist->pass()) { + set_progress (float (_done) / playlist->audio_length ()); } _analysis->write (_film->audio_analysis_path ()); diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc new file mode 100644 index 000000000..e9eacfd79 --- /dev/null +++ b/src/lib/audio_content.cc @@ -0,0 +1,7 @@ +#include "audio_content.h" + +AudioContent::AudioContent (boost::filesystem::path f) + : Content (f) +{ + +} diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index 95fd681a7..e18d1082e 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -1,8 +1,19 @@ +#ifndef DVDOMATIC_AUDIO_CONTENT_H +#define DVDOMATIC_AUDIO_CONTENT_H + #include "content.h" +#include "util.h" class AudioContent : public virtual Content { public: - + AudioContent (boost::filesystem::path); + virtual int audio_channels () const = 0; + virtual ContentAudioFrame audio_length () const = 0; + virtual int audio_frame_rate () const = 0; + virtual int64_t audio_channel_layout () const = 0; + }; + +#endif diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index a54c14843..a72cf11bb 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -18,19 +18,12 @@ */ #include "audio_decoder.h" -#include "stream.h" using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f, DecodeOptions o) +AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) : Decoder (f, o) { } - -void -AudioDecoder::set_audio_stream (shared_ptr s) -{ - _audio_stream = s; -} diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 9bef8e0e7..7d2a2bb62 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -25,34 +25,17 @@ #define DVDOMATIC_AUDIO_DECODER_H #include "audio_source.h" -#include "stream.h" #include "decoder.h" +class AudioContent; + /** @class AudioDecoder. * @brief Parent class for audio decoders. */ class AudioDecoder : public AudioSource, public virtual Decoder { public: - AudioDecoder (boost::shared_ptr, DecodeOptions); - - virtual void set_audio_stream (boost::shared_ptr); - - /** @return Audio stream that we are using */ - boost::shared_ptr audio_stream () const { - return _audio_stream; - } - - /** @return All available audio streams */ - std::vector > audio_streams () const { - return _audio_streams; - } - -protected: - /** Audio stream that we are using */ - boost::shared_ptr _audio_stream; - /** All available audio streams */ - std::vector > _audio_streams; + AudioDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); }; #endif diff --git a/src/lib/content.cc b/src/lib/content.cc new file mode 100644 index 000000000..2fb94e959 --- /dev/null +++ b/src/lib/content.cc @@ -0,0 +1,20 @@ +#include +#include "content.h" +#include "util.h" + +using std::string; +using boost::shared_ptr; + +Content::Content (boost::filesystem::path f) + : _file (f) +{ + +} + +void +Content::examine (shared_ptr, shared_ptr, bool) +{ + string const d = md5_digest (_file); + boost::mutex::scoped_lock lm (_mutex); + _digest = d; +} diff --git a/src/lib/content.h b/src/lib/content.h index c848860aa..25c097424 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -1,17 +1,34 @@ +#ifndef DVDOMATIC_CONTENT_H +#define DVDOMATIC_CONTENT_H + #include +#include #include +class Job; +class Film; + class Content { public: + Content (boost::filesystem::path); + + virtual void examine (boost::shared_ptr, boost::shared_ptr, bool); + virtual std::string summary () const = 0; + boost::filesystem::path file () const { boost::mutex::scoped_lock lm (_mutex); return _file; } + boost::signals2::signal Changed; + protected: - boost::mutex _mutex; + mutable boost::mutex _mutex; private: boost::filesystem::path _file; + std::string _digest; }; + +#endif diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 52b22fa06..2fe265c14 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -22,34 +22,21 @@ */ #include -#include -#include #include "film.h" -#include "format.h" #include "options.h" #include "exceptions.h" -#include "image.h" #include "util.h" -#include "log.h" #include "decoder.h" -#include "delay_line.h" -#include "subtitle.h" -#include "filter_graph.h" #include "i18n.h" using std::string; -using std::stringstream; -using std::min; -using std::pair; -using std::list; using boost::shared_ptr; -using boost::optional; /** @param f Film. * @param o Decode options. */ -Decoder::Decoder (boost::shared_ptr f, DecodeOptions o) +Decoder::Decoder (shared_ptr f, DecodeOptions o) : _film (f) , _opt (o) { diff --git a/src/lib/decoder.h b/src/lib/decoder.h index f2f523516..50aa16dba 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -30,7 +30,6 @@ #include #include #include "util.h" -#include "stream.h" #include "video_source.h" #include "audio_source.h" #include "film.h" @@ -53,7 +52,7 @@ class FilterGraph; class Decoder { public: - Decoder (boost::shared_ptr, DecodeOptions); + Decoder (boost::shared_ptr, DecodeOptions); virtual ~Decoder () {} virtual bool pass () = 0; @@ -63,14 +62,13 @@ public: boost::signals2::signal OutputChanged; protected: - /** our Film */ - boost::shared_ptr _film; + boost::shared_ptr _film; /** our decode options */ DecodeOptions _opt; private: virtual void film_changed (Film::Property) {} - + boost::signals2::scoped_connection _film_connection; }; diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index f7f9f4074..feaa1c7ef 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -39,22 +39,5 @@ decoder_factory ( shared_ptr f, DecodeOptions o ) { - if (f->content().empty()) { - return Decoders (); - } - - if (boost::filesystem::is_directory (f->content_path()) || f->content_type() == STILL) { - /* A single image file, or a directory of them */ - return Decoders ( - shared_ptr (new ImageMagickDecoder (f, o)), - shared_ptr (new SndfileDecoder (f, o)) - ); - } - - shared_ptr fd (new FFmpegDecoder (f, o)); - if (f->use_content_audio()) { - return Decoders (fd, fd); - } - - return Decoders (fd, shared_ptr (new SndfileDecoder (f, o))); + return Decoders (); } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 7b338407e..970213793 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -38,6 +38,7 @@ #include "format.h" #include "cross.h" #include "writer.h" +#include "playlist.h" #include "i18n.h" @@ -53,8 +54,9 @@ using namespace boost; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f) +Encoder::Encoder (shared_ptr f, shared_ptr p) : _film (f) + , _playlist (p) , _video_frames_in (0) , _video_frames_out (0) #ifdef HAVE_SWRESAMPLE @@ -77,22 +79,22 @@ Encoder::~Encoder () void Encoder::process_begin () { - if (_film->audio_stream() && _film->audio_stream()->sample_rate() != _film->target_audio_sample_rate()) { + if (_playlist->has_audio() && _playlist->audio_frame_rate() != _film->target_audio_sample_rate()) { #ifdef HAVE_SWRESAMPLE stringstream s; - s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_stream()->sample_rate(), _film->target_audio_sample_rate()); + s << String::compose (N_("Will resample audio from %1 to %2"), _playlist->audio_frame_rate(), _film->target_audio_sample_rate()); _film->log()->log (s.str ()); /* We will be using planar float data when we call the resampler */ _swr_context = swr_alloc_set_opts ( 0, - _film->audio_stream()->channel_layout(), + _playlist->audio_channel_layout(), AV_SAMPLE_FMT_FLTP, _film->target_audio_sample_rate(), - _film->audio_stream()->channel_layout(), + _playlist->audio_channel_layout(), AV_SAMPLE_FMT_FLTP, - _film->audio_stream()->sample_rate(), + _playlist->audio_frame_rate(), 0, 0 ); @@ -118,7 +120,7 @@ Encoder::process_begin () } } - _writer.reset (new Writer (_film)); + _writer.reset (new Writer (_film, _playlist)); } @@ -126,9 +128,9 @@ void Encoder::process_end () { #if HAVE_SWRESAMPLE - if (_film->audio_stream() && _film->audio_stream()->channels() && _swr_context) { + if (_playlist->has_audio() && _playlist->audio_channels() && _swr_context) { - shared_ptr out (new AudioBuffers (_film->audio_stream()->channels(), 256)); + shared_ptr out (new AudioBuffers (_playlist->audio_channels(), 256)); while (1) { int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); @@ -233,7 +235,7 @@ Encoder::frame_done () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + FrameRateConversion frc (_playlist->video_frame_rate(), _film->dcp_frame_rate()); if (frc.skip && (_video_frames_in % 2)) { ++_video_frames_in; @@ -271,7 +273,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr ( new DCPVideoFrame ( - image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), + image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_playlist), _film->subtitle_offset(), _film->subtitle_scale(), _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), @@ -301,9 +303,9 @@ Encoder::process_audio (shared_ptr data) if (_swr_context) { /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_stream()->sample_rate()) + 32; + int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _playlist->audio_frame_rate()) + 32; - shared_ptr resampled (new AudioBuffers (_film->audio_stream()->channels(), max_resampled_frames)); + shared_ptr resampled (new AudioBuffers (_playlist->audio_channels(), max_resampled_frames)); /* Resample audio */ int const resampled_frames = swr_convert ( @@ -425,8 +427,8 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { - AudioMapping m (_film->audio_channels ()); - if (m.dcp_channels() != _film->audio_channels()) { + AudioMapping m (_playlist->audio_channels ()); + if (m.dcp_channels() != _playlist->audio_channels()) { /* Remap (currently just for mono -> 5.1) */ diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 86880bc34..c84ee027a 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -51,6 +51,7 @@ class ServerDescription; class DCPVideoFrame; class EncodedData; class Writer; +class Playlist; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -62,7 +63,7 @@ class Writer; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f); + Encoder (boost::shared_ptr f, boost::shared_ptr); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ @@ -95,6 +96,7 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; + boost::shared_ptr _playlist; /** Mutex for _time_history and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index 4b30c9431..c600132c3 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -17,29 +17,21 @@ */ -/** @file src/examine_content_job.cc - * @brief A class to run through content at high speed to find its length. - */ - #include #include "examine_content_job.h" #include "options.h" -#include "decoder_factory.h" -#include "decoder.h" -#include "transcoder.h" #include "log.h" -#include "film.h" -#include "video_decoder.h" +#include "content.h" #include "i18n.h" using std::string; -using std::vector; -using std::pair; using boost::shared_ptr; -ExamineContentJob::ExamineContentJob (shared_ptr f) +ExamineContentJob::ExamineContentJob (shared_ptr f, shared_ptr c, bool q) : Job (f) + , _content (c) + , _quick (q) { } @@ -51,60 +43,13 @@ ExamineContentJob::~ExamineContentJob () string ExamineContentJob::name () const { - if (_film->name().empty ()) { - return _("Examine content"); - } - - return String::compose (_("Examine content of %1"), _film->name()); + return _("Examine content"); } void ExamineContentJob::run () { - descend (0.5); - _film->set_content_digest (md5_digest (_film->content_path ())); - ascend (); - - descend (0.5); - - /* Set the film's length to either - a) a length judged by running through the content or - b) the length from a decoder's header. - */ - if (!_film->trust_content_header()) { - /* Decode the content to get an accurate length */ - - /* We don't want to use any existing length here, as progress - will be messed up. - */ - _film->unset_length (); - _film->set_crop (Crop ()); - - DecodeOptions o; - o.decode_audio = false; - - Decoders decoders = decoder_factory (_film, o); - - set_progress_unknown (); - while (!decoders.video->pass()) { - /* keep going */ - } - - _film->set_length (decoders.video->video_frame()); - - _film->log()->log (String::compose (N_("Video length examined as %1 frames"), _film->length().get())); - - } else { - - /* Get a quick decoder to get the content's length from its header */ - - Decoders d = decoder_factory (_film, DecodeOptions()); - _film->set_length (d.video->length()); - - _film->log()->log (String::compose (N_("Video length obtained from header as %1 frames"), _film->length().get())); - } - - ascend (); + _content->examine (_film, shared_from_this (), _quick); set_progress (1); set_state (FINISHED_OK); } diff --git a/src/lib/examine_content_job.h b/src/lib/examine_content_job.h index 8ee4f0d60..dc0d53fff 100644 --- a/src/lib/examine_content_job.h +++ b/src/lib/examine_content_job.h @@ -17,22 +17,23 @@ */ -/** @file src/examine_content_job.h - * @brief A class to obtain the length and MD5 digest of a content file. - */ - +#include #include "job.h" -/** @class ExamineContentJob - * @brief A class to obtain the length and MD5 digest of a content file. - */ +class Content; +class Log; + class ExamineContentJob : public Job { public: - ExamineContentJob (boost::shared_ptr); + ExamineContentJob (boost::shared_ptr, boost::shared_ptr, bool); ~ExamineContentJob (); std::string name () const; void run (); + +private: + boost::shared_ptr _content; + bool _quick; }; diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index e45a62353..6920556e5 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -112,6 +112,7 @@ class OpenFileError : public FileError { public: /** @param f File that we were trying to open */ + /* XXX: should be boost::filesystem::path */ OpenFileError (std::string f); }; diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc new file mode 100644 index 000000000..25efb1ebf --- /dev/null +++ b/src/lib/ffmpeg_content.cc @@ -0,0 +1,156 @@ +#include "ffmpeg_content.h" +#include "ffmpeg_decoder.h" +#include "options.h" +#include "compose.hpp" +#include "job.h" +#include "util.h" +#include "log.h" + +#include "i18n.h" + +using std::string; +using boost::shared_ptr; + +int const FFmpegContentProperty::SUBTITLE_STREAMS = 100; +int const FFmpegContentProperty::SUBTITLE_STREAM = 101; +int const FFmpegContentProperty::AUDIO_STREAMS = 102; +int const FFmpegContentProperty::AUDIO_STREAM = 103; + +FFmpegContent::FFmpegContent (boost::filesystem::path f) + : Content (f) + , VideoContent (f) + , AudioContent (f) +{ + +} + +void +FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) +{ + job->descend (0.5); + Content::examine (film, job, quick); + job->ascend (); + + job->set_progress_unknown (); + + DecodeOptions o; + o.decode_audio = false; + shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), o)); + + ContentVideoFrame video_length = 0; + if (quick) { + video_length = decoder->video_length (); + film->log()->log (String::compose ("Video length obtained from header as %1 frames", decoder->video_length ())); + } else { + while (!decoder->pass ()) { + /* keep going */ + } + + video_length = decoder->video_frame (); + film->log()->log (String::compose ("Video length examined as %1 frames", decoder->video_frame ())); + } + + { + boost::mutex::scoped_lock lm (_mutex); + + _video_length = video_length; + + _subtitle_streams = decoder->subtitle_streams (); + if (!_subtitle_streams.empty ()) { + _subtitle_stream = _subtitle_streams.front (); + } + + _audio_streams = decoder->audio_streams (); + if (!_audio_streams.empty ()) { + _audio_stream = _audio_streams.front (); + } + } + + take_from_video_decoder (decoder); + + Changed (VideoContentProperty::VIDEO_LENGTH); + Changed (FFmpegContentProperty::SUBTITLE_STREAMS); + Changed (FFmpegContentProperty::SUBTITLE_STREAM); + Changed (FFmpegContentProperty::AUDIO_STREAMS); + Changed (FFmpegContentProperty::AUDIO_STREAM); +} + +string +FFmpegContent::summary () const +{ + return String::compose (_("Movie: %1"), file().filename ()); +} + +void +FFmpegContent::set_subtitle_stream (FFmpegSubtitleStream s) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _subtitle_stream = s; + } + + Changed (FFmpegContentProperty::SUBTITLE_STREAM); +} + +void +FFmpegContent::set_audio_stream (FFmpegAudioStream s) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _audio_stream = s; + } + + Changed (FFmpegContentProperty::AUDIO_STREAM); +} + +ContentAudioFrame +FFmpegContent::audio_length () const +{ + if (!_audio_stream) { + return 0; + } + + return video_frames_to_audio_frames (_video_length, audio_frame_rate(), video_frame_rate()); +} + +int +FFmpegContent::audio_channels () const +{ + if (!_audio_stream) { + return 0; + } + + return _audio_stream->channels (); +} + +int +FFmpegContent::audio_frame_rate () const +{ + if (!_audio_stream) { + return 0; + } + + return _audio_stream->frame_rate; +} + +int64_t +FFmpegContent::audio_channel_layout () const +{ + if (!_audio_stream) { + return 0; + } + + return _audio_stream->channel_layout; +} + +bool +operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b) +{ + return a.id == b.id; +} + +bool +operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b) +{ + return a.id == b.id; +} diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index 8b3eca62d..83474ea66 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -1,8 +1,97 @@ -#include "content.h" +#ifndef DVDOMATIC_FFMPEG_CONTENT_H +#define DVDOMATIC_FFMPEG_CONTENT_H -class FFmpegContent : public VideoContent, public AudioContent +#include +#include "video_content.h" +#include "audio_content.h" + +class FFmpegAudioStream +{ +public: + FFmpegAudioStream (std::string n, int i, int f, int64_t c) + : name (n) + , id (i) + , frame_rate (f) + , channel_layout (c) + {} + + int channels () const { + return av_get_channel_layout_nb_channels (channel_layout); + } + + std::string name; + int id; + int frame_rate; + int64_t channel_layout; +}; + +extern bool operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b); + +class FFmpegSubtitleStream +{ +public: + FFmpegSubtitleStream (std::string n, int i) + : name (n) + , id (i) + {} + + std::string name; + int id; +}; + +extern bool operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b); + +class FFmpegContentProperty : public VideoContentProperty +{ +public: + static int const SUBTITLE_STREAMS; + static int const SUBTITLE_STREAM; + static int const AUDIO_STREAMS; + static int const AUDIO_STREAM; +}; + +class FFmpegContent : public VideoContent, public AudioContent, public boost::enable_shared_from_this { public: + FFmpegContent (boost::filesystem::path); + void examine (boost::shared_ptr, boost::shared_ptr, bool); + std::string summary () const; + /* AudioContent */ + int audio_channels () const; + ContentAudioFrame audio_length () const; + int audio_frame_rate () const; + int64_t audio_channel_layout () const; + + std::vector subtitle_streams () const { + boost::mutex::scoped_lock lm (_mutex); + return _subtitle_streams; + } + + boost::optional subtitle_stream () const { + boost::mutex::scoped_lock lm (_mutex); + return _subtitle_stream; + } + + std::vector audio_streams () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_streams; + } + + boost::optional audio_stream () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_stream; + } + + void set_subtitle_stream (FFmpegSubtitleStream); + void set_audio_stream (FFmpegAudioStream); + +private: + std::vector _subtitle_streams; + boost::optional _subtitle_stream; + std::vector _audio_streams; + boost::optional _audio_stream; }; + +#endif diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index ac25844e3..c8e46776f 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -62,10 +62,11 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; -FFmpegDecoder::FFmpegDecoder (shared_ptr f, DecodeOptions o) +FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) : Decoder (f, o) - , VideoDecoder (f, o) - , AudioDecoder (f, o) + , VideoDecoder (f, c, o) + , AudioDecoder (f, c, o) + , _ffmpeg_content (c) , _format_context (0) , _video_stream (-1) , _frame (0) @@ -110,8 +111,8 @@ FFmpegDecoder::setup_general () { av_register_all (); - if (avformat_open_input (&_format_context, _film->content_path().c_str(), 0, 0) < 0) { - throw OpenFileError (_film->content_path ()); + if (avformat_open_input (&_format_context, _ffmpeg_content->file().string().c_str(), 0, 0) < 0) { + throw OpenFileError (_ffmpeg_content->file().string ()); } if (avformat_find_stream_info (_format_context, 0) < 0) { @@ -135,17 +136,11 @@ FFmpegDecoder::setup_general () } _audio_streams.push_back ( - shared_ptr ( - new FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout) - ) + FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout) ); } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { - _subtitle_streams.push_back ( - shared_ptr ( - new SubtitleStream (stream_name (s), i) - ) - ); + _subtitle_streams.push_back (FFmpegSubtitleStream (stream_name (s), i)); } } @@ -177,14 +172,11 @@ FFmpegDecoder::setup_video () void FFmpegDecoder::setup_audio () { - if (!_audio_stream) { + if (!_ffmpeg_content->audio_stream ()) { return; } - shared_ptr ffa = dynamic_pointer_cast (_audio_stream); - assert (ffa); - - _audio_codec_context = _format_context->streams[ffa->id()]->codec; + _audio_codec_context = _format_context->streams[_ffmpeg_content->audio_stream()->id]->codec; _audio_codec = avcodec_find_decoder (_audio_codec_context->codec_id); if (_audio_codec == 0) { @@ -199,11 +191,11 @@ FFmpegDecoder::setup_audio () void FFmpegDecoder::setup_subtitle () { - if (!_subtitle_stream || _subtitle_stream->id() >= int (_format_context->nb_streams)) { + if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { return; } - _subtitle_codec_context = _format_context->streams[_subtitle_stream->id()]->codec; + _subtitle_codec_context = _format_context->streams[_ffmpeg_content->subtitle_stream()->id]->codec; _subtitle_codec = avcodec_find_decoder (_subtitle_codec_context->codec_id); if (_subtitle_codec == 0) { @@ -244,7 +236,7 @@ FFmpegDecoder::pass () } } - if (_audio_stream && _opt.decode_audio) { + if (_ffmpeg_content->audio_stream() && _opt.decode_audio) { decode_audio_packet (); } @@ -253,8 +245,6 @@ FFmpegDecoder::pass () avcodec_get_frame_defaults (_frame); - shared_ptr ffa = dynamic_pointer_cast (_audio_stream); - if (_packet.stream_index == _video_stream && _opt.decode_video) { int frame_finished; @@ -272,9 +262,9 @@ FFmpegDecoder::pass () } } - } else if (ffa && _packet.stream_index == ffa->id() && _opt.decode_audio) { + } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _opt.decode_audio) { decode_audio_packet (); - } else if (_subtitle_stream && _packet.stream_index == _subtitle_stream->id() && _opt.decode_subtitles && _first_video) { + } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && _opt.decode_subtitles && _first_video) { int got_subtitle; AVSubtitle sub; @@ -306,19 +296,16 @@ FFmpegDecoder::pass () shared_ptr FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) { - assert (_film->audio_channels()); + assert (_ffmpeg_content->audio_channels()); assert (bytes_per_audio_sample()); - shared_ptr ffa = dynamic_pointer_cast (_audio_stream); - assert (ffa); - /* Deinterleave and convert to float */ - assert ((size % (bytes_per_audio_sample() * ffa->channels())) == 0); + assert ((size % (bytes_per_audio_sample() * _ffmpeg_content->audio_channels())) == 0); int const total_samples = size / bytes_per_audio_sample(); - int const frames = total_samples / _film->audio_channels(); - shared_ptr audio (new AudioBuffers (ffa->channels(), frames)); + int const frames = total_samples / _ffmpeg_content->audio_channels(); + shared_ptr audio (new AudioBuffers (_ffmpeg_content->audio_channels(), frames)); switch (audio_sample_format()) { case AV_SAMPLE_FMT_S16: @@ -330,7 +317,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) audio->data(channel)[sample] = float(*p++) / (1 << 15); ++channel; - if (channel == _film->audio_channels()) { + if (channel == _ffmpeg_content->audio_channels()) { channel = 0; ++sample; } @@ -341,7 +328,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) case AV_SAMPLE_FMT_S16P: { int16_t** p = reinterpret_cast (data); - for (int i = 0; i < _film->audio_channels(); ++i) { + for (int i = 0; i < _ffmpeg_content->audio_channels(); ++i) { for (int j = 0; j < frames; ++j) { audio->data(i)[j] = static_cast(p[i][j]) / (1 << 15); } @@ -358,7 +345,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) audio->data(channel)[sample] = static_cast(*p++) / (1 << 31); ++channel; - if (channel == _film->audio_channels()) { + if (channel == _ffmpeg_content->audio_channels()) { channel = 0; ++sample; } @@ -375,7 +362,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) audio->data(channel)[sample] = *p++; ++channel; - if (channel == _film->audio_channels()) { + if (channel == _ffmpeg_content->audio_channels()) { channel = 0; ++sample; } @@ -386,7 +373,7 @@ FFmpegDecoder::deinterleave_audio (uint8_t** data, int size) case AV_SAMPLE_FMT_FLTP: { float** p = reinterpret_cast (data); - for (int i = 0; i < _film->audio_channels(); ++i) { + for (int i = 0; i < _ffmpeg_content->audio_channels(); ++i) { memcpy (audio->data(i), p[i], frames * sizeof(float)); } } @@ -488,21 +475,6 @@ FFmpegDecoder::bytes_per_audio_sample () const return av_get_bytes_per_sample (audio_sample_format ()); } -void -FFmpegDecoder::set_audio_stream (shared_ptr s) -{ - AudioDecoder::set_audio_stream (s); - setup_audio (); -} - -void -FFmpegDecoder::set_subtitle_stream (shared_ptr s) -{ - VideoDecoder::set_subtitle_stream (s); - setup_subtitle (); - OutputChanged (); -} - void FFmpegDecoder::filter_and_emit_video (AVFrame* frame) { @@ -561,58 +533,6 @@ FFmpegDecoder::do_seek (double p, bool backwards) return r < 0; } -shared_ptr -FFmpegAudioStream::create (string t, optional v) -{ - if (!v) { - /* version < 1; no type in the string, and there's only FFmpeg streams anyway */ - return shared_ptr (new FFmpegAudioStream (t, v)); - } - - stringstream s (t); - string type; - s >> type; - if (type != N_("ffmpeg")) { - return shared_ptr (); - } - - return shared_ptr (new FFmpegAudioStream (t, v)); -} - -FFmpegAudioStream::FFmpegAudioStream (string t, optional version) -{ - stringstream n (t); - - int name_index = 4; - if (!version) { - name_index = 2; - int channels; - n >> _id >> channels; - _channel_layout = av_get_default_channel_layout (channels); - _sample_rate = 0; - } else { - string type; - /* Current (marked version 1) */ - n >> type >> _id >> _sample_rate >> _channel_layout; - assert (type == N_("ffmpeg")); - } - - for (int i = 0; i < name_index; ++i) { - size_t const s = t.find (' '); - if (s != string::npos) { - t = t.substr (s + 1); - } - } - - _name = t; -} - -string -FFmpegAudioStream::to_string () const -{ - return String::compose (N_("ffmpeg %1 %2 %3 %4"), _id, _sample_rate, _channel_layout, _name); -} - void FFmpegDecoder::out_with_sync () { @@ -678,8 +598,8 @@ FFmpegDecoder::film_changed (Film::Property p) } /** @return Length (in video frames) according to our content's header */ -SourceFrame -FFmpegDecoder::length () const +ContentVideoFrame +FFmpegDecoder::video_length () const { return (double(_format_context->duration) / AV_TIME_BASE) * frames_per_second(); } @@ -693,9 +613,6 @@ FFmpegDecoder::frame_time () const void FFmpegDecoder::decode_audio_packet () { - shared_ptr ffa = dynamic_pointer_cast (_audio_stream); - assert (ffa); - /* Audio packets can contain multiple frames, so we may have to call avcodec_decode_audio4 several times. */ @@ -727,17 +644,17 @@ FFmpegDecoder::decode_audio_packet () */ /* frames of silence that we must push */ - int const s = rint ((_first_audio.get() - _first_video.get()) * ffa->sample_rate ()); + int const s = rint ((_first_audio.get() - _first_video.get()) * _ffmpeg_content->audio_frame_rate ()); _film->log()->log ( String::compose ( N_("First video at %1, first audio at %2, pushing %3 audio frames of silence for %4 channels (%5 bytes per sample)"), - _first_video.get(), _first_audio.get(), s, ffa->channels(), bytes_per_audio_sample() + _first_video.get(), _first_audio.get(), s, _ffmpeg_content->audio_channels(), bytes_per_audio_sample() ) ); if (s) { - shared_ptr audio (new AudioBuffers (ffa->channels(), s)); + shared_ptr audio (new AudioBuffers (_ffmpeg_content->audio_channels(), s)); audio->make_silent (); Audio (audio); } @@ -747,7 +664,7 @@ FFmpegDecoder::decode_audio_packet () 0, _audio_codec_context->channels, _frame->nb_samples, audio_sample_format (), 1 ); - assert (_audio_codec_context->channels == _film->audio_channels()); + assert (_audio_codec_context->channels == _ffmpeg_content->audio_channels()); Audio (deinterleave_audio (_frame->data, data_size)); } } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 1bb14ce9c..a0900d89f 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -36,6 +36,7 @@ extern "C" { #include "video_decoder.h" #include "audio_decoder.h" #include "film.h" +#include "ffmpeg_content.h" struct AVFilterGraph; struct AVCodecContext; @@ -50,62 +51,37 @@ class Options; class Image; class Log; -class FFmpegAudioStream : public AudioStream -{ -public: - FFmpegAudioStream (std::string n, int i, int s, int64_t c) - : AudioStream (s, c) - , _name (n) - , _id (i) - {} - - std::string to_string () const; - - std::string name () const { - return _name; - } - - int id () const { - return _id; - } - - static boost::shared_ptr create (std::string t, boost::optional v); - -private: - friend class stream_test; - - FFmpegAudioStream (std::string t, boost::optional v); - - std::string _name; - int _id; -}; - /** @class FFmpegDecoder * @brief A decoder using FFmpeg to decode content. */ class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: - FFmpegDecoder (boost::shared_ptr, DecodeOptions); + FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); ~FFmpegDecoder (); float frames_per_second () const; libdcp::Size native_size () const; - SourceFrame length () const; + ContentVideoFrame video_length () const; int time_base_numerator () const; int time_base_denominator () const; int sample_aspect_ratio_numerator () const; int sample_aspect_ratio_denominator () const; - void set_audio_stream (boost::shared_ptr); - void set_subtitle_stream (boost::shared_ptr); + std::vector subtitle_streams () const { + return _subtitle_streams; + } + + std::vector audio_streams () const { + return _audio_streams; + } bool seek (double); bool seek_to_last (); + bool pass (); private: - bool pass (); bool do_seek (double p, bool); PixelFormat pixel_format () const; AVSampleFormat audio_sample_format () const; @@ -129,6 +105,8 @@ private: std::string stream_name (AVStream* s) const; + boost::shared_ptr _ffmpeg_content; + AVFormatContext* _format_context; int _video_stream; @@ -148,4 +126,7 @@ private: std::list > _filter_graphs; boost::mutex _filter_graphs_mutex; + + std::vector _subtitle_streams; + std::vector _audio_streams; }; diff --git a/src/lib/film.cc b/src/lib/film.cc index 0d969f16d..f69f63fd8 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -52,6 +52,7 @@ #include "audio_decoder.h" #include "sndfile_decoder.h" #include "analyse_audio_job.h" +#include "playlist.h" #include "i18n.h" @@ -135,8 +136,6 @@ Film::Film (string d, bool must_exist) } } - _sndfile_stream = SndfileStream::create (); - if (must_exist) { read_metadata (); } @@ -162,7 +161,6 @@ Film::Film (Film const & o) , _dcp_ab (o._dcp_ab) , _audio_gain (o._audio_gain) , _audio_delay (o._audio_delay) - , _still_duration (o._still_duration) , _with_subtitles (o._with_subtitles) , _subtitle_offset (o._subtitle_offset) , _subtitle_scale (o._subtitle_scale) @@ -186,6 +184,10 @@ Film::video_state_identifier () const { assert (format ()); + return "XXX"; + +#if 0 + pair f = Filter::ffmpeg_strings (filters()); stringstream s; @@ -204,6 +206,7 @@ Film::video_state_identifier () const } return s.str (); +#endif } /** @return The path to the directory to write video frame info files to */ @@ -234,7 +237,7 @@ Film::audio_analysis_path () const { boost::filesystem::path p; p /= "analysis"; - p /= content_digest(); + p /= "XXX";//content_digest(); return file (p.string ()); } @@ -256,12 +259,12 @@ Film::make_dcp () log()->log (String::compose ("Starting to make DCP on %1", buffer)); } - log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? _("still") : _("video")))); - if (length()) { - log()->log (String::compose ("Content length %1", length().get())); - } - log()->log (String::compose ("Content digest %1", content_digest())); - log()->log (String::compose ("Content at %1 fps, DCP at %2 fps", source_frame_rate(), dcp_frame_rate())); +// log()->log (String::compose ("Content is %1; type %2", content_path(), (content_type() == STILL ? _("still") : _("video")))); +// if (length()) { +// log()->log (String::compose ("Content length %1", length().get())); +// } +// log()->log (String::compose ("Content digest %1", content_digest())); +// log()->log (String::compose ("Content at %1 fps, DCP at %2 fps", source_frame_rate(), dcp_frame_rate())); log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads())); log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth())); #ifdef DVDOMATIC_DEBUG @@ -318,17 +321,13 @@ Film::analyse_audio () JobManager::instance()->add (_analyse_audio_job); } -/** Start a job to examine our content file */ +/** Start a job to examine a piece of content */ void -Film::examine_content () +Film::examine_content (shared_ptr c) { - if (_examine_content_job) { - return; - } - - _examine_content_job.reset (new ExamineContentJob (shared_from_this())); - _examine_content_job->Finished.connect (bind (&Film::examine_content_finished, this)); - JobManager::instance()->add (_examine_content_job); + shared_ptr j (new ExamineContentJob (shared_from_this(), c, trust_content_header ())); + j->Finished.connect (bind (&Film::examine_content_finished, this)); + JobManager::instance()->add (j); } void @@ -346,7 +345,7 @@ Film::analyse_audio_finished () void Film::examine_content_finished () { - _examine_content_job.reset (); + /* XXX */ } /** Start a job to send our DCP to the configured TMS */ @@ -395,7 +394,7 @@ Film::write_metadata () const /* User stuff */ f << "name " << _name << endl; f << "use_dci_name " << _use_dci_name << endl; - f << "content " << _content << endl; +// f << "content " << _content << endl; f << "trust_content_header " << (_trust_content_header ? "1" : "0") << endl; if (_dcp_content_type) { f << "dcp_content_type " << _dcp_content_type->dci_name () << endl; @@ -414,19 +413,19 @@ Film::write_metadata () const f << "trim_start " << _trim_start << endl; f << "trim_end " << _trim_end << endl; f << "dcp_ab " << (_dcp_ab ? "1" : "0") << endl; - if (_content_audio_stream) { - f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl; - } - for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { - f << "external_audio " << *i << endl; - } - f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl; +// if (_content_audio_stream) { +// f << "selected_content_audio_stream " << _content_audio_stream->to_string() << endl; +// } +// for (vector::const_iterator i = _external_audio.begin(); i != _external_audio.end(); ++i) { +// f << "external_audio " << *i << endl; +// } +// f << "use_content_audio " << (_use_content_audio ? "1" : "0") << endl; f << "audio_gain " << _audio_gain << endl; f << "audio_delay " << _audio_delay << endl; - f << "still_duration " << _still_duration << endl; - if (_subtitle_stream) { - f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl; - } +// f << "still_duration " << _still_duration << endl; +// if (_subtitle_stream) { +// f << "selected_subtitle_stream " << _subtitle_stream->to_string() << endl; +// } f << "with_subtitles " << _with_subtitles << endl; f << "subtitle_offset " << _subtitle_offset << endl; f << "subtitle_scale " << _subtitle_scale << endl; @@ -435,22 +434,22 @@ Film::write_metadata () const _dci_metadata.write (f); f << "dci_date " << boost::gregorian::to_iso_string (_dci_date) << endl; f << "dcp_frame_rate " << _dcp_frame_rate << endl; - f << "width " << _size.width << endl; - f << "height " << _size.height << endl; - f << "length " << _length.get_value_or(0) << endl; - f << "content_digest " << _content_digest << endl; +// f << "width " << _size.width << endl; +// f << "height " << _size.height << endl; +// f << "length " << _length.get_value_or(0) << endl; +// f << "content_digest " << _content_digest << endl; - for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - f << "content_audio_stream " << (*i)->to_string () << endl; - } +// for (vector >::const_iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { +// f << "content_audio_stream " << (*i)->to_string () << endl; +// } - f << "external_audio_stream " << _sndfile_stream->to_string() << endl; +// f << "external_audio_stream " << _sndfile_stream->to_string() << endl; - for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { - f << "subtitle_stream " << (*i)->to_string () << endl; - } +// for (vector >::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { +// f << "subtitle_stream " << (*i)->to_string () << endl; +// } - f << "source_frame_rate " << _source_frame_rate << endl; +// f << "source_frame_rate " << _source_frame_rate << endl; _dirty = false; } @@ -461,9 +460,9 @@ Film::read_metadata () { boost::mutex::scoped_lock lm (_state_mutex); - _external_audio.clear (); - _content_audio_streams.clear (); - _subtitle_streams.clear (); +// _external_audio.clear (); +// _content_audio_streams.clear (); +// _subtitle_streams.clear (); boost::optional version; @@ -499,7 +498,7 @@ Film::read_metadata () } else if (k == "use_dci_name") { _use_dci_name = (v == "1"); } else if (k == "content") { - _content = v; +// _content = v; } else if (k == "trust_content_header") { _trust_content_header = (v == "1"); } else if (k == "dcp_content_type") { @@ -532,23 +531,23 @@ Film::read_metadata () if (!version) { audio_stream_index = atoi (v.c_str ()); } else { - _content_audio_stream = audio_stream_factory (v, version); +// _content_audio_stream = audio_stream_factory (v, version); } } else if (k == "external_audio") { - _external_audio.push_back (v); +// _external_audio.push_back (v); } else if (k == "use_content_audio") { - _use_content_audio = (v == "1"); +// _use_content_audio = (v == "1"); } else if (k == "audio_gain") { _audio_gain = atof (v.c_str ()); } else if (k == "audio_delay") { _audio_delay = atoi (v.c_str ()); } else if (k == "still_duration") { - _still_duration = atoi (v.c_str ()); +// _still_duration = atoi (v.c_str ()); } else if (k == "selected_subtitle_stream") { if (!version) { subtitle_stream_index = atoi (v.c_str ()); } else { - _subtitle_stream = subtitle_stream_factory (v, version); +// _subtitle_stream = subtitle_stream_factory (v, version); } } else if (k == "with_subtitles") { _with_subtitles = (v == "1"); @@ -570,50 +569,31 @@ Film::read_metadata () /* Cached stuff */ if (k == "width") { - _size.width = atoi (v.c_str ()); +// _size.width = atoi (v.c_str ()); } else if (k == "height") { - _size.height = atoi (v.c_str ()); +// _size.height = atoi (v.c_str ()); } else if (k == "length") { int const vv = atoi (v.c_str ()); if (vv) { - _length = vv; +// _length = vv; } } else if (k == "content_digest") { - _content_digest = v; +// _content_digest = v; } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { - _content_audio_streams.push_back (audio_stream_factory (v, version)); +// _content_audio_streams.push_back (audio_stream_factory (v, version)); } else if (k == "external_audio_stream") { - _sndfile_stream = audio_stream_factory (v, version); +// _sndfile_stream = audio_stream_factory (v, version); } else if (k == "subtitle_stream") { - _subtitle_streams.push_back (subtitle_stream_factory (v, version)); +// _subtitle_streams.push_back (subtitle_stream_factory (v, version)); } else if (k == "source_frame_rate") { - _source_frame_rate = atof (v.c_str ()); +// _source_frame_rate = atof (v.c_str ()); } else if (version < 4 && k == "frames_per_second") { - _source_frame_rate = atof (v.c_str ()); +// _source_frame_rate = atof (v.c_str ()); /* Fill in what would have been used for DCP frame rate by the older version */ - _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate); +// _dcp_frame_rate = best_dcp_frame_rate (_source_frame_rate); } } - if (!version) { - if (audio_sample_rate) { - /* version < 1 didn't specify sample rate in the audio streams, so fill it in here */ - for (vector >::iterator i = _content_audio_streams.begin(); i != _content_audio_streams.end(); ++i) { - (*i)->set_sample_rate (audio_sample_rate.get()); - } - } - - /* also the selected stream was specified as an index */ - if (audio_stream_index && audio_stream_index.get() >= 0 && audio_stream_index.get() < (int) _content_audio_streams.size()) { - _content_audio_stream = _content_audio_streams[audio_stream_index.get()]; - } - - /* similarly the subtitle */ - if (subtitle_stream_index && subtitle_stream_index.get() >= 0 && subtitle_stream_index.get() < (int) _subtitle_streams.size()) { - _subtitle_stream = _subtitle_streams[subtitle_stream_index.get()]; - } - } - _dirty = false; } @@ -661,47 +641,21 @@ Film::file (string f) const return p.string (); } -/** @return full path of the content (actual video) file - * of the Film. - */ -string -Film::content_path () const -{ - boost::mutex::scoped_lock lm (_state_mutex); - if (boost::filesystem::path(_content).has_root_directory ()) { - return _content; - } - - return file (_content); -} - -ContentType -Film::content_type () const -{ - if (boost::filesystem::is_directory (_content)) { - /* Directory of images, we assume */ - return VIDEO; - } - - if (still_image_file (_content)) { - return STILL; - } - - return VIDEO; -} - /** @return The sampling rate that we will resample the audio to */ int Film::target_audio_sample_rate () const { - if (!audio_stream()) { + /* XXX: how often is this method called? */ + + boost::shared_ptr p = playlist (); + if (p->has_audio ()) { return 0; } /* Resample to a DCI-approved sample rate */ - double t = dcp_audio_sample_rate (audio_stream()->sample_rate()); + double t = dcp_audio_sample_rate (p->audio_frame_rate()); - FrameRateConversion frc (source_frame_rate(), dcp_frame_rate()); + FrameRateConversion frc (p->video_frame_rate(), dcp_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -710,18 +664,12 @@ Film::target_audio_sample_rate () const */ if (frc.change_speed) { - t *= source_frame_rate() * frc.factor() / dcp_frame_rate(); + t *= p->video_frame_rate() * frc.factor() / dcp_frame_rate(); } return rint (t); } -int -Film::still_duration_in_frames () const -{ - return still_duration() * source_frame_rate(); -} - /** @return a DCI-compliant name for a DCP of this film */ string Film::dci_name (bool if_created_now) const @@ -768,7 +716,8 @@ Film::dci_name (bool if_created_now) const } } - switch (audio_channels()) { + /* XXX */ + switch (2) { case 1: d << "_10"; break; @@ -846,98 +795,6 @@ Film::set_use_dci_name (bool u) signal_changed (USE_DCI_NAME); } -void -Film::set_content (string c) -{ - string check = directory (); - - boost::filesystem::path slash ("/"); - string platform_slash = slash.make_preferred().string (); - - if (!ends_with (check, platform_slash)) { - check += platform_slash; - } - - if (boost::filesystem::path(c).has_root_directory () && starts_with (c, check)) { - c = c.substr (_directory.length() + 1); - } - - string old_content; - - { - boost::mutex::scoped_lock lm (_state_mutex); - if (c == _content) { - return; - } - - old_content = _content; - _content = c; - } - - /* Reset streams here in case the new content doesn't have one or the other */ - _content_audio_stream = shared_ptr (); - _subtitle_stream = shared_ptr (); - - /* Start off using content audio */ - set_use_content_audio (true); - - /* Create a temporary decoder so that we can get information - about the content. - */ - - try { - Decoders d = decoder_factory (shared_from_this(), DecodeOptions()); - - set_size (d.video->native_size ()); - set_source_frame_rate (d.video->frames_per_second ()); - set_dcp_frame_rate (best_dcp_frame_rate (source_frame_rate ())); - set_subtitle_streams (d.video->subtitle_streams ()); - if (d.audio) { - set_content_audio_streams (d.audio->audio_streams ()); - } - - { - boost::mutex::scoped_lock lm (_state_mutex); - _content = c; - } - - signal_changed (CONTENT); - - /* Start off with the first audio and subtitle streams */ - if (d.audio && !d.audio->audio_streams().empty()) { - set_content_audio_stream (d.audio->audio_streams().front()); - } - - if (!d.video->subtitle_streams().empty()) { - set_subtitle_stream (d.video->subtitle_streams().front()); - } - - examine_content (); - - } catch (...) { - - boost::mutex::scoped_lock lm (_state_mutex); - _content = old_content; - throw; - - } - - /* Default format */ - switch (content_type()) { - case STILL: - set_format (Format::from_id ("var-185")); - break; - case VIDEO: - set_format (Format::from_id ("185")); - break; - } - - /* Still image DCPs must use external audio */ - if (content_type() == STILL) { - set_use_content_audio (false); - } -} - void Film::set_trust_content_header (bool t) { @@ -950,7 +807,8 @@ Film::set_trust_content_header (bool t) if (!_trust_content_header && !content().empty()) { /* We just said that we don't trust the content's header */ - examine_content (); + /* XXX */ +// examine_content (); } } @@ -1091,43 +949,6 @@ Film::set_dcp_ab (bool a) signal_changed (DCP_AB); } -void -Film::set_content_audio_stream (shared_ptr s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _content_audio_stream = s; - } - signal_changed (CONTENT_AUDIO_STREAM); -} - -void -Film::set_external_audio (vector a) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _external_audio = a; - } - - shared_ptr decoder (new SndfileDecoder (shared_from_this(), DecodeOptions())); - if (decoder->audio_stream()) { - _sndfile_stream = decoder->audio_stream (); - } - - signal_changed (EXTERNAL_AUDIO); -} - -void -Film::set_use_content_audio (bool e) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _use_content_audio = e; - } - - signal_changed (USE_CONTENT_AUDIO); -} - void Film::set_audio_gain (float g) { @@ -1148,26 +969,6 @@ Film::set_audio_delay (int d) signal_changed (AUDIO_DELAY); } -void -Film::set_still_duration (int d) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _still_duration = d; - } - signal_changed (STILL_DURATION); -} - -void -Film::set_subtitle_stream (shared_ptr s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _subtitle_stream = s; - } - signal_changed (SUBTITLE_STREAM); -} - void Film::set_with_subtitles (bool w) { @@ -1239,76 +1040,6 @@ Film::set_dcp_frame_rate (int f) signal_changed (DCP_FRAME_RATE); } -void -Film::set_size (libdcp::Size s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _size = s; - } - signal_changed (SIZE); -} - -void -Film::set_length (SourceFrame l) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _length = l; - } - signal_changed (LENGTH); -} - -void -Film::unset_length () -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _length = boost::none; - } - signal_changed (LENGTH); -} - -void -Film::set_content_digest (string d) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _content_digest = d; - } - _dirty = true; -} - -void -Film::set_content_audio_streams (vector > s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _content_audio_streams = s; - } - signal_changed (CONTENT_AUDIO_STREAMS); -} - -void -Film::set_subtitle_streams (vector > s) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _subtitle_streams = s; - } - signal_changed (SUBTITLE_STREAMS); -} - -void -Film::set_source_frame_rate (float f) -{ - { - boost::mutex::scoped_lock lm (_state_mutex); - _source_frame_rate = f; - } - signal_changed (SOURCE_FRAME_RATE); -} - void Film::signal_changed (Property p) { @@ -1322,33 +1053,12 @@ Film::signal_changed (Property p) } } -int -Film::audio_channels () const -{ - shared_ptr s = audio_stream (); - if (!s) { - return 0; - } - - return s->channels (); -} - void Film::set_dci_date_today () { _dci_date = boost::gregorian::day_clock::local_day (); } -boost::shared_ptr -Film::audio_stream () const -{ - if (use_content_audio()) { - return _content_audio_stream; - } - - return _sndfile_stream; -} - string Film::info_path (int f) const { @@ -1404,20 +1114,22 @@ Film::have_dcp () const return true; } -bool -Film::has_audio () const +shared_ptr +Film::playlist () const { - if (use_content_audio()) { - return audio_stream(); - } + boost::mutex::scoped_lock lm (_state_mutex); + return shared_ptr (new Playlist (shared_from_this (), _content)); +} - vector const e = external_audio (); - for (vector::const_iterator i = e.begin(); i != e.end(); ++i) { - if (!i->empty ()) { - return true; - } +void +Film::add_content (shared_ptr c) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _content.push_back (c); } - return false; -} + signal_changed (CONTENT); + examine_content (c); +} diff --git a/src/lib/film.h b/src/lib/film.h index 2e05d64f4..afd57b7c2 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -37,7 +37,6 @@ extern "C" { } #include "dcp_content_type.h" #include "util.h" -#include "stream.h" #include "dci_metadata.h" class Format; @@ -48,6 +47,7 @@ class ExamineContentJob; class AnalyseAudioJob; class ExternalAudioStream; class Content; +class Playlist; /** @class Film * @brief A representation of a video, maybe with sound. @@ -69,7 +69,7 @@ public: std::string video_mxf_filename () const; std::string audio_analysis_path () const; - void examine_content (); + void examine_content (boost::shared_ptr); void analyse_audio (); void send_dcp_to_tms (); @@ -87,9 +87,6 @@ public: std::string file (std::string f) const; std::string dir (std::string d) const; - std::string content_path () const; - ContentType content_type () const; - int target_audio_sample_rate () const; void write_metadata () const; @@ -104,12 +101,12 @@ public: return _dirty; } - int audio_channels () const; - void set_dci_date_today (); bool have_dcp () const; + boost::shared_ptr playlist () const; + /** Identifiers for the parts of our state; used for signalling changes. */ @@ -118,6 +115,7 @@ public: NAME, USE_DCI_NAME, TRUST_CONTENT_HEADER, + CONTENT, DCP_CONTENT_TYPE, FORMAT, CROP, @@ -162,6 +160,11 @@ public: return _trust_content_header; } + std::list > content () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _content; + } + DCPContentType const * dcp_content_type () const { boost::mutex::scoped_lock lm (_state_mutex); return _dcp_content_type; @@ -212,11 +215,6 @@ public: return _audio_delay; } - boost::shared_ptr subtitle_stream () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _subtitle_stream; - } - bool with_subtitles () const { boost::mutex::scoped_lock lm (_state_mutex); return _with_subtitles; @@ -252,15 +250,13 @@ public: return _dcp_frame_rate; } - boost::shared_ptr audio_stream () const; - bool has_audio () const; - /* SET */ void set_directory (std::string); void set_name (std::string); void set_use_dci_name (bool); void set_trust_content_header (bool); + void add_content (boost::shared_ptr); void set_dcp_content_type (DCPContentType const *); void set_format (Format const *); void set_crop (Crop); @@ -297,8 +293,6 @@ private: /** Log to write to */ boost::shared_ptr _log; - /** Any running ExamineContentJob, or 0 */ - boost::shared_ptr _examine_content_job; /** Any running AnalyseAudioJob, or 0 */ boost::shared_ptr _analyse_audio_job; @@ -318,7 +312,8 @@ private: std::string _name; /** True if a auto-generated DCI-compliant name should be used for our DCP */ bool _use_dci_name; - std::list > _content; + typedef std::list > ContentList; + ContentList _content; /** If this is true, we will believe the length specified by the content * file's header; if false, we will run through the whole content file * the first time we see it in order to obtain the length. diff --git a/src/lib/filter_graph.cc b/src/lib/filter_graph.cc index 045cbaa6a..a52c030fe 100644 --- a/src/lib/filter_graph.cc +++ b/src/lib/filter_graph.cc @@ -57,7 +57,7 @@ using libdcp::Size; * @param s Size of the images to process. * @param p Pixel format of the images to process. */ -FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p) +FilterGraph::FilterGraph (shared_ptr film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p) : _buffer_src_context (0) , _buffer_sink_context (0) , _size (s) diff --git a/src/lib/filter_graph.h b/src/lib/filter_graph.h index 7e4e8422b..db86a677d 100644 --- a/src/lib/filter_graph.h +++ b/src/lib/filter_graph.h @@ -37,7 +37,7 @@ class FFmpegDecoder; class FilterGraph { public: - FilterGraph (boost::shared_ptr film, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p); + FilterGraph (boost::shared_ptr, FFmpegDecoder* decoder, libdcp::Size s, AVPixelFormat p); bool can_process (libdcp::Size s, AVPixelFormat p) const; std::list > process (AVFrame const * frame); diff --git a/src/lib/format.cc b/src/lib/format.cc index b506c7000..05b71f2e5 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -29,6 +29,7 @@ #include #include "format.h" #include "film.h" +#include "playlist.h" #include "i18n.h" @@ -206,16 +207,16 @@ FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d * (so there are dcp_padding() pixels on the left and dcp_padding() on the right) */ int -Format::dcp_padding (shared_ptr f) const +Format::dcp_padding (shared_ptr p) const { - int p = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(f) / 100.0)) / 2.0); + int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(p) / 100.0)) / 2.0); /* This comes out -ve for Scope; bodge it */ - if (p < 0) { - p = 0; + if (pad < 0) { + pad = 0; } - return p; + return pad; } float @@ -231,15 +232,15 @@ VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d, } int -VariableFormat::ratio_as_integer (shared_ptr f) const +VariableFormat::ratio_as_integer (shared_ptr p) const { - return rint (ratio_as_float (f) * 100); + return rint (ratio_as_float (p) * 100); } float -VariableFormat::ratio_as_float (shared_ptr f) const +VariableFormat::ratio_as_float (shared_ptr p) const { - return float (f->size().width) / f->size().height; + return float (p->video_size().width) / p->video_size().height; } /** @return A name to be presented to the user */ diff --git a/src/lib/format.h b/src/lib/format.h index 305524628..94c2253de 100644 --- a/src/lib/format.h +++ b/src/lib/format.h @@ -26,7 +26,7 @@ #include #include "util.h" -class Film; +class Playlist; class Format { @@ -42,15 +42,15 @@ public: /** @return the aspect ratio multiplied by 100 * (e.g. 239 for Cinemascope 2.39:1) */ - virtual int ratio_as_integer (boost::shared_ptr f) const = 0; + virtual int ratio_as_integer (boost::shared_ptr f) const = 0; /** @return the ratio as a floating point number */ - virtual float ratio_as_float (boost::shared_ptr f) const = 0; + virtual float ratio_as_float (boost::shared_ptr f) const = 0; /** @return the ratio of the container (including any padding) as a floating point number */ float container_ratio_as_float () const; - int dcp_padding (boost::shared_ptr f) const; + int dcp_padding (boost::shared_ptr) const; /** @return size in pixels of the images that we should * put in a DCP for this ratio. This size will not correspond @@ -115,11 +115,11 @@ class FixedFormat : public Format public: FixedFormat (int, libdcp::Size, std::string, std::string, std::string, std::string); - int ratio_as_integer (boost::shared_ptr) const { + int ratio_as_integer (boost::shared_ptr) const { return _ratio; } - float ratio_as_float (boost::shared_ptr) const { + float ratio_as_float (boost::shared_ptr) const { return _ratio / 100.0; } @@ -136,8 +136,8 @@ class VariableFormat : public Format public: VariableFormat (libdcp::Size, std::string, std::string, std::string, std::string); - int ratio_as_integer (boost::shared_ptr f) const; - float ratio_as_float (boost::shared_ptr f) const; + int ratio_as_integer (boost::shared_ptr f) const; + float ratio_as_float (boost::shared_ptr f) const; std::string name () const; }; diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc new file mode 100644 index 000000000..d0887c0aa --- /dev/null +++ b/src/lib/imagemagick_content.cc @@ -0,0 +1,2 @@ +#include "imagemagick_content.h" + diff --git a/src/lib/imagemagick_content.h b/src/lib/imagemagick_content.h index 2a8197b69..985aa0e8d 100644 --- a/src/lib/imagemagick_content.h +++ b/src/lib/imagemagick_content.h @@ -2,5 +2,6 @@ class ImageMagickContent : public VideoContent { - +public: + ImageMagickContent (boost::filesystem::path); }; diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 5dc0b7b06..aa3c64f93 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -20,6 +20,7 @@ #include #include #include +#include "imagemagick_content.h" #include "imagemagick_decoder.h" #include "image.h" #include "film.h" @@ -32,37 +33,20 @@ using boost::shared_ptr; using libdcp::Size; ImageMagickDecoder::ImageMagickDecoder ( - boost::shared_ptr f, DecodeOptions o) + shared_ptr f, shared_ptr c, DecodeOptions o) : Decoder (f, o) - , VideoDecoder (f, o) + , VideoDecoder (f, c, o) + , _imagemagick_content (c) + , _position (0) { - if (boost::filesystem::is_directory (_film->content_path())) { - for ( - boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator (_film->content_path()); - i != boost::filesystem::directory_iterator(); - ++i) { - - if (still_image_file (i->path().string())) { - _files.push_back (i->path().string()); - } - } - } else { - _files.push_back (_film->content_path ()); - } - - _iter = _files.begin (); + } libdcp::Size ImageMagickDecoder::native_size () const { - if (_files.empty ()) { - throw DecodeError (_("no still image files found")); - } - - /* Look at the first file and assume its size holds for all */ using namespace MagickCore; - Magick::Image* image = new Magick::Image (_film->content_path ()); + Magick::Image* image = new Magick::Image (_imagemagick_content->file().string()); libdcp::Size const s = libdcp::Size (image->columns(), image->rows()); delete image; @@ -72,16 +56,15 @@ ImageMagickDecoder::native_size () const bool ImageMagickDecoder::pass () { - if (_iter == _files.end()) { - if (video_frame() >= _film->still_duration_in_frames()) { - return true; - } - + if (_position > 0 && _position < _imagemagick_content->video_length ()) { repeat_last_video (); + _position++; return false; + } else if (_position >= _imagemagick_content->video_length ()) { + return true; } - Magick::Image* magick_image = new Magick::Image (_film->content_path ()); + Magick::Image* magick_image = new Magick::Image (_imagemagick_content->file().string ()); libdcp::Size size = native_size (); shared_ptr image (new SimpleImage (PIX_FMT_RGB24, size, false)); @@ -104,7 +87,7 @@ ImageMagickDecoder::pass () emit_video (image, 0); - ++_iter; + ++_position; return false; } @@ -118,10 +101,8 @@ ImageMagickDecoder::pixel_format () const bool ImageMagickDecoder::seek_to_last () { - if (_iter == _files.end()) { - _iter = _files.begin(); - } else { - --_iter; + if (_position > 0) { + --_position; } return false; @@ -130,16 +111,14 @@ ImageMagickDecoder::seek_to_last () bool ImageMagickDecoder::seek (double t) { - int const f = t * frames_per_second(); - - _iter = _files.begin (); - for (int i = 0; i < f; ++i) { - if (_iter == _files.end()) { - return true; - } - ++_iter; + int const f = t * _imagemagick_content->video_frame_rate (); + + if (f >= _imagemagick_content->video_length()) { + _position = 0; + return true; } - + + _position = f; return false; } diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 2f4e2c967..b04bd88b1 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -23,10 +23,12 @@ namespace Magick { class Image; } +class ImageMagickContent; + class ImageMagickDecoder : public VideoDecoder { public: - ImageMagickDecoder (boost::shared_ptr, DecodeOptions); + ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); float frames_per_second () const { /* We don't know */ @@ -35,7 +37,7 @@ public: libdcp::Size native_size () const; - SourceFrame length () const { + ContentVideoFrame video_length () const { /* We don't know */ return 0; } @@ -54,9 +56,9 @@ public: bool seek (double); bool seek_to_last (); + bool pass (); protected: - bool pass (); PixelFormat pixel_format () const; int time_base_numerator () const { @@ -79,7 +81,7 @@ protected: private: void film_changed (Film::Property); - - std::list _files; - std::list::iterator _iter; + + boost::shared_ptr _imagemagick_content; + ContentVideoFrame _position; }; diff --git a/src/lib/job.cc b/src/lib/job.cc index ace02b8b3..ff0332d6d 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -34,8 +34,6 @@ using std::list; using std::stringstream; using boost::shared_ptr; -/** @param s Film that we are operating on. - */ Job::Job (shared_ptr f) : _film (f) , _thread (0) diff --git a/src/lib/job.h b/src/lib/job.h index fd036bce2..f5175c525 100644 --- a/src/lib/job.h +++ b/src/lib/job.h @@ -38,7 +38,7 @@ class Film; class Job : public boost::enable_shared_from_this { public: - Job (boost::shared_ptr s); + Job (boost::shared_ptr); virtual ~Job() {} /** @return user-readable name of this job */ @@ -87,7 +87,6 @@ protected: void set_state (State); void set_error (std::string s, std::string d); - /** Film for this job */ boost::shared_ptr _film; private: diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc new file mode 100644 index 000000000..17ecd2f37 --- /dev/null +++ b/src/lib/playlist.cc @@ -0,0 +1,266 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include "playlist.h" +#include "sndfile_content.h" +#include "sndfile_decoder.h" +#include "ffmpeg_content.h" +#include "ffmpeg_decoder.h" +#include "imagemagick_content.h" +#include "imagemagick_decoder.h" + +using std::list; +using boost::shared_ptr; +using boost::dynamic_pointer_cast; + +Playlist::Playlist (shared_ptr f, list > c) + : _video_from (VIDEO_NONE) + , _audio_from (AUDIO_NONE) + , _ffmpeg_decoder_done (false) +{ + for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + shared_ptr fc = dynamic_pointer_cast (*i); + if (fc) { + assert (!_ffmpeg); + _ffmpeg = fc; + _video_from = VIDEO_FFMPEG; + if (_audio_from == AUDIO_NONE) { + _audio_from = AUDIO_FFMPEG; + } + } + + shared_ptr ic = dynamic_pointer_cast (*i); + if (ic) { + _imagemagick.push_back (ic); + if (_video_from == VIDEO_NONE) { + _video_from = VIDEO_IMAGEMAGICK; + } + } + + shared_ptr sc = dynamic_pointer_cast (*i); + if (sc) { + _sndfile.push_back (sc); + _audio_from = AUDIO_SNDFILE; + } + } + + if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + DecodeOptions o; + /* XXX: decodeoptions */ + _ffmpeg_decoder.reset (new FFmpegDecoder (f, _ffmpeg, o)); + } + + if (_video_from == VIDEO_FFMPEG) { + _ffmpeg_decoder->connect_video (shared_from_this ()); + } + + if (_audio_from == AUDIO_FFMPEG) { + _ffmpeg_decoder->connect_audio (shared_from_this ()); + } + + if (_video_from == VIDEO_IMAGEMAGICK) { + for (list >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + DecodeOptions o; + /* XXX: decodeoptions */ + shared_ptr d (new ImageMagickDecoder (f, *i, o)); + _imagemagick_decoders.push_back (d); + d->connect_video (shared_from_this ()); + } + + _imagemagick_decoder = _imagemagick_decoders.begin (); + } + + if (_audio_from == AUDIO_SNDFILE) { + for (list >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + DecodeOptions o; + /* XXX: decodeoptions */ + shared_ptr d (new SndfileDecoder (f, *i, o)); + _sndfile_decoders.push_back (d); + d->connect_audio (shared_from_this ()); + } + } +} + +ContentAudioFrame +Playlist::audio_length () const +{ + switch (_audio_from) { + case AUDIO_NONE: + return 0; + case AUDIO_FFMPEG: + return _ffmpeg->audio_length (); + case AUDIO_SNDFILE: + { + ContentAudioFrame l = 0; + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + l += (*i)->audio_length (); + } + return l; + } + } + + return 0; +} + +int +Playlist::audio_channels () const +{ + switch (_audio_from) { + case AUDIO_NONE: + return 0; + case AUDIO_FFMPEG: + return _ffmpeg->audio_channels (); + case AUDIO_SNDFILE: + { + int c = 0; + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + c += (*i)->audio_channels (); + } + return c; + } + } + + return 0; +} + +int +Playlist::audio_frame_rate () const +{ + switch (_audio_from) { + case AUDIO_NONE: + return 0; + case AUDIO_FFMPEG: + return _ffmpeg->audio_frame_rate (); + case AUDIO_SNDFILE: + return _sndfile.front()->audio_frame_rate (); + } + + return 0; +} + +int64_t +Playlist::audio_channel_layout () const +{ + switch (_audio_from) { + case AUDIO_NONE: + return 0; + case AUDIO_FFMPEG: + return _ffmpeg->audio_channel_layout (); + case AUDIO_SNDFILE: + /* XXX */ + return 0; + } + + return 0; +} + +float +Playlist::video_frame_rate () const +{ + switch (_video_from) { + case VIDEO_NONE: + return 0; + case VIDEO_FFMPEG: + return _ffmpeg->video_frame_rate (); + case VIDEO_IMAGEMAGICK: + return 24; + } + + return 0; +} + +libdcp::Size +Playlist::video_size () const +{ + switch (_video_from) { + case VIDEO_NONE: + return libdcp::Size (); + case VIDEO_FFMPEG: + return _ffmpeg->video_size (); + case VIDEO_IMAGEMAGICK: + /* XXX */ + return _imagemagick.front()->video_size (); + } + + return libdcp::Size (); +} + +bool +Playlist::has_audio () const +{ + return _audio_from != AUDIO_NONE; +} + +void +Playlist::disable_video () +{ + _video_from = VIDEO_NONE; +} + +bool +Playlist::pass () +{ + bool done = true; + + if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + if (!_ffmpeg_decoder_done) { + if (_ffmpeg_decoder->pass ()) { + _ffmpeg_decoder_done = true; + } else { + done = false; + } + } + } + + if (_video_from == VIDEO_IMAGEMAGICK) { + if (_imagemagick_decoder != _imagemagick_decoders.end ()) { + if ((*_imagemagick_decoder)->pass ()) { + _imagemagick_decoder++; + } + + if (_imagemagick_decoder != _imagemagick_decoders.end ()) { + done = false; + } + } + } + + /* XXX: sndfile */ + + return done; +} + +void +Playlist::set_progress (shared_ptr job) +{ + /* XXX */ +} + +void +Playlist::process_video (shared_ptr i, bool same, shared_ptr s) +{ + Video (i, same, s); +} + +void +Playlist::process_audio (shared_ptr b) +{ + Audio (b); +} + diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 4add76344..b42d46036 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -17,14 +17,66 @@ */ +#include #include +#include #include "video_source.h" +#include "audio_source.h" #include "video_sink.h" +#include "audio_sink.h" class Content; +class FFmpegContent; +class FFmpegDecoder; +class ImageMagickContent; +class ImageMagickDecoder; +class SndfileContent; +class SndfileDecoder; +class Job; +class Film; -class Playlist : public VideoSource, public AudioSource +class Playlist : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this { public: - Playlist (std::list >); + Playlist (boost::shared_ptr, std::list >); + + ContentAudioFrame audio_length () const; + int audio_channels () const; + int audio_frame_rate () const; + int64_t audio_channel_layout () const; + bool has_audio () const; + + float video_frame_rate () const; + libdcp::Size video_size () const; + + void disable_video (); + + bool pass (); + void set_progress (boost::shared_ptr); + +private: + void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); + void process_audio (boost::shared_ptr); + + enum { + VIDEO_NONE, + VIDEO_FFMPEG, + VIDEO_IMAGEMAGICK + } _video_from; + + enum { + AUDIO_NONE, + AUDIO_FFMPEG, + AUDIO_SNDFILE + } _audio_from; + + boost::shared_ptr _ffmpeg; + std::list > _imagemagick; + std::list > _sndfile; + + boost::shared_ptr _ffmpeg_decoder; + bool _ffmpeg_decoder_done; + std::list > _imagemagick_decoders; + std::list >::iterator _imagemagick_decoder; + std::list > _sndfile_decoders; }; diff --git a/src/lib/scp_dcp_job.h b/src/lib/scp_dcp_job.h index 08d8e2c78..8c16d53fb 100644 --- a/src/lib/scp_dcp_job.h +++ b/src/lib/scp_dcp_job.h @@ -34,7 +34,7 @@ public: private: void set_status (std::string); - + mutable boost::mutex _status_mutex; std::string _status; }; diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc new file mode 100644 index 000000000..8f5b28901 --- /dev/null +++ b/src/lib/sndfile_content.cc @@ -0,0 +1,41 @@ +#include "sndfile_content.h" +#include "compose.hpp" + +#include "i18n.h" + +using namespace std; + +string +SndfileContent::summary () const +{ + return String::compose (_("Sound file: %1"), file().filename ()); +} + +int +SndfileContent::audio_channels () const +{ + /* XXX */ + return 0; +} + +ContentAudioFrame +SndfileContent::audio_length () const +{ + /* XXX */ + return 0; +} + +int +SndfileContent::audio_frame_rate () const +{ + /* XXX */ + return 0; +} + +int64_t +SndfileContent::audio_channel_layout () const +{ + /* XXX */ + return 0; +} + diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index 382e55c40..e84617ed3 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -3,5 +3,11 @@ class SndfileContent : public AudioContent { public: + std::string summary () const; + /* AudioDecoder */ + int audio_channels () const; + ContentAudioFrame audio_length () const; + int audio_frame_rate () const; + int64_t audio_channel_layout () const; }; diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index 0e3e5e234..8848ff4f8 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -19,6 +19,7 @@ #include #include +#include "sndfile_content.h" #include "sndfile_decoder.h" #include "film.h" #include "exceptions.h" @@ -33,156 +34,53 @@ using std::cout; using boost::shared_ptr; using boost::optional; -SndfileDecoder::SndfileDecoder (shared_ptr f, DecodeOptions o) +/* XXX */ + +SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) : Decoder (f, o) - , AudioDecoder (f, o) + , AudioDecoder (f, c, o) { sf_count_t frames; - vector sf = open_files (frames); - close_files (sf); + SNDFILE* sf = open_file (frames); + sf_close (sf); } -vector -SndfileDecoder::open_files (sf_count_t & frames) +SNDFILE* +SndfileDecoder::open_file (sf_count_t & frames) { - vector const files = _film->external_audio (); - - int N = 0; - for (size_t i = 0; i < files.size(); ++i) { - if (!files[i].empty()) { - N = i + 1; - } - } - - if (N == 0) { - return vector (); - } - - bool first = true; frames = 0; - vector sndfiles; - for (size_t i = 0; i < (size_t) N; ++i) { - if (files[i].empty ()) { - sndfiles.push_back (0); - } else { - SF_INFO info; - SNDFILE* s = sf_open (files[i].c_str(), SFM_READ, &info); - if (!s) { - throw DecodeError (_("could not open external audio file for reading")); - } - - if (info.channels != 1) { - throw DecodeError (_("external audio files must be mono")); - } - - sndfiles.push_back (s); - - if (first) { - shared_ptr st ( - new SndfileStream ( - info.samplerate, av_get_default_channel_layout (N) - ) - ); - - _audio_streams.push_back (st); - _audio_stream = st; - frames = info.frames; - first = false; - } else { - if (info.frames != frames) { - throw DecodeError (_("external audio files have differing lengths")); - } - } - } + SF_INFO info; + SNDFILE* s = sf_open (_sndfile_content->file().string().c_str(), SFM_READ, &info); + if (!s) { + throw DecodeError (_("could not open external audio file for reading")); } - return sndfiles; + frames = info.frames; + return s; } bool SndfileDecoder::pass () { sf_count_t frames; - vector sndfiles = open_files (frames); - if (sndfiles.empty()) { - return true; - } + SNDFILE* sndfile = open_file (frames); /* Do things in half second blocks as I think there may be limits to what FFmpeg (and in particular the resampler) can cope with. */ - sf_count_t const block = _audio_stream->sample_rate() / 2; + sf_count_t const block = _sndfile_content->audio_frame_rate() / 2; - shared_ptr audio (new AudioBuffers (_audio_stream->channels(), block)); + shared_ptr audio (new AudioBuffers (_sndfile_content->audio_channels(), block)); while (frames > 0) { sf_count_t const this_time = min (block, frames); - for (size_t i = 0; i < sndfiles.size(); ++i) { - if (!sndfiles[i]) { - audio->make_silent (i); - } else { - sf_read_float (sndfiles[i], audio->data(i), block); - } - } - + sf_read_float (sndfile, audio->data(0), this_time); audio->set_frames (this_time); Audio (audio); frames -= this_time; } - close_files (sndfiles); + sf_close (sndfile); return true; } - -void -SndfileDecoder::close_files (vector const & sndfiles) -{ - for (size_t i = 0; i < sndfiles.size(); ++i) { - sf_close (sndfiles[i]); - } -} - -shared_ptr -SndfileStream::create () -{ - return shared_ptr (new SndfileStream); -} - -shared_ptr -SndfileStream::create (string t, optional v) -{ - if (!v) { - /* version < 1; no type in the string, and there's only FFmpeg streams anyway */ - return shared_ptr (); - } - - stringstream s (t); - string type; - s >> type; - if (type != N_("external")) { - return shared_ptr (); - } - - return shared_ptr (new SndfileStream (t, v)); -} - -SndfileStream::SndfileStream (string t, optional v) -{ - assert (v); - - stringstream s (t); - string type; - s >> type >> _sample_rate >> _channel_layout; -} - -SndfileStream::SndfileStream () -{ - -} - -string -SndfileStream::to_string () const -{ - return String::compose (N_("external %1 %2"), _sample_rate, _channel_layout); -} diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index e16eab673..c06b97a60 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -20,35 +20,19 @@ #include #include "decoder.h" #include "audio_decoder.h" -#include "stream.h" -class SndfileStream : public AudioStream -{ -public: - SndfileStream (int sample_rate, int64_t layout) - : AudioStream (sample_rate, layout) - {} - - std::string to_string () const; - - static boost::shared_ptr create (); - static boost::shared_ptr create (std::string t, boost::optional v); - -private: - friend class stream_test; - - SndfileStream (); - SndfileStream (std::string t, boost::optional v); -}; +class SndfileContent; class SndfileDecoder : public AudioDecoder { public: - SndfileDecoder (boost::shared_ptr, DecodeOptions); + SndfileDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); bool pass (); private: - std::vector open_files (sf_count_t &); - void close_files (std::vector const &); + SNDFILE* open_file (sf_count_t &); + void close_file (SNDFILE*); + + boost::shared_ptr _sndfile_content; }; diff --git a/src/lib/stream.cc b/src/lib/stream.cc deleted file mode 100644 index bfe7b5eb4..000000000 --- a/src/lib/stream.cc +++ /dev/null @@ -1,92 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - 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 -#include "compose.hpp" -#include "stream.h" -#include "ffmpeg_decoder.h" -#include "sndfile_decoder.h" - -#include "i18n.h" - -using std::string; -using std::stringstream; -using boost::shared_ptr; -using boost::optional; - -/** Construct a SubtitleStream from a value returned from to_string(). - * @param t String returned from to_string(). - * @param v State file version. - */ -SubtitleStream::SubtitleStream (string t, boost::optional) -{ - stringstream n (t); - n >> _id; - - size_t const s = t.find (' '); - if (s != string::npos) { - _name = t.substr (s + 1); - } -} - -/** @return A canonical string representation of this stream */ -string -SubtitleStream::to_string () const -{ - return String::compose (N_("%1 %2"), _id, _name); -} - -/** Create a SubtitleStream from a value returned from to_string(). - * @param t String returned from to_string(). - * @param v State file version. - */ -shared_ptr -SubtitleStream::create (string t, optional v) -{ - return shared_ptr (new SubtitleStream (t, v)); -} - -/** Create an AudioStream from a string returned from to_string(). - * @param t String returned from to_string(). - * @param v State file version. - * @return AudioStream, or 0. - */ -shared_ptr -audio_stream_factory (string t, optional v) -{ - shared_ptr s; - - s = FFmpegAudioStream::create (t, v); - if (!s) { - s = SndfileStream::create (t, v); - } - - return s; -} - -/** Create a SubtitleStream from a string returned from to_string(). - * @param t String returned from to_string(). - * @param v State file version. - * @return SubtitleStream, or 0. - */ -shared_ptr -subtitle_stream_factory (string t, optional v) -{ - return SubtitleStream::create (t, v); -} diff --git a/src/lib/stream.h b/src/lib/stream.h deleted file mode 100644 index 16b06e4bc..000000000 --- a/src/lib/stream.h +++ /dev/null @@ -1,121 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - 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. - -*/ - -/** @file src/lib/stream.h - * @brief Representations of audio and subtitle streams. - * - * Some content may have multiple `streams' of audio and/or subtitles; perhaps - * for multiple languages, or for stereo / surround mixes. These classes represent - * those streams, and know about their details. - */ - -#ifndef DVDOMATIC_STREAM_H -#define DVDOMATIC_STREAM_H - -#include -#include -#include -extern "C" { -#include -} - -/** @class Stream - * @brief Parent class for streams. - */ -class Stream -{ -public: - virtual ~Stream () {} - virtual std::string to_string () const = 0; -}; - -/** @class AudioStream - * @brief A stream of audio data. - */ -struct AudioStream : public Stream -{ -public: - AudioStream (int r, int64_t l) - : _sample_rate (r) - , _channel_layout (l) - {} - - /* Only used for backwards compatibility for state file version < 1 */ - void set_sample_rate (int s) { - _sample_rate = s; - } - - int channels () const { - return av_get_channel_layout_nb_channels (_channel_layout); - } - - int sample_rate () const { - return _sample_rate; - } - - int64_t channel_layout () const { - return _channel_layout; - } - -protected: - AudioStream () - : _sample_rate (0) - , _channel_layout (0) - {} - - int _sample_rate; - int64_t _channel_layout; -}; - -/** @class SubtitleStream - * @brief A stream of subtitle data. - */ -class SubtitleStream : public Stream -{ -public: - SubtitleStream (std::string n, int i) - : _name (n) - , _id (i) - {} - - std::string to_string () const; - - std::string name () const { - return _name; - } - - int id () const { - return _id; - } - - static boost::shared_ptr create (std::string t, boost::optional v); - -private: - friend class stream_test; - - SubtitleStream (std::string t, boost::optional v); - - std::string _name; - int _id; -}; - -boost::shared_ptr audio_stream_factory (std::string t, boost::optional version); -boost::shared_ptr subtitle_stream_factory (std::string t, boost::optional version); - -#endif diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 234ebe051..f8810975b 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -62,8 +62,7 @@ TranscodeJob::run () _film->log()->log (N_("Transcode job starting")); _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); - _encoder.reset (new Encoder (_film)); - Transcoder w (_film, _decode_opt, this, _encoder); + Transcoder w (_film, _decode_opt, shared_from_this ()); w.go (); set_progress (1); set_state (FINISHED_OK); @@ -83,11 +82,13 @@ TranscodeJob::run () string TranscodeJob::status () const { - if (!_encoder) { - return _("0%"); - } +// if (!_encoder) { +// return _("0%"); +// } - float const fps = _encoder->current_frames_per_second (); + /* XXX */ +// float const fps = _encoder->current_frames_per_second (); + float const fps = 0; if (fps == 0) { return Job::status (); } @@ -106,12 +107,15 @@ TranscodeJob::status () const int TranscodeJob::remaining_time () const { + return 0; +#if 0 + XXX float fps = _encoder->current_frames_per_second (); if (fps == 0) { return 0; } - if (!_film->length()) { + if (!_video->length()) { return 0; } @@ -126,4 +130,5 @@ TranscodeJob::remaining_time () const /* We assume that dcp_length() is valid, if it is set */ int const left = length - _encoder->video_frames_out(); return left / fps; +#endif } diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index 9b69e4e65..a409ec97e 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -44,5 +44,4 @@ protected: private: DecodeOptions _decode_opt; - boost::shared_ptr _encoder; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index e0f3a03a2..19d067149 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -36,6 +36,7 @@ #include "gain.h" #include "video_decoder.h" #include "audio_decoder.h" +#include "playlist.h" using std::string; using boost::shared_ptr; @@ -47,68 +48,42 @@ using boost::dynamic_pointer_cast; * @param j Job that we are running under, or 0. * @param e Encoder to use. */ -Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr e) +Transcoder::Transcoder (shared_ptr f, DecodeOptions o, shared_ptr j) : _job (j) - , _encoder (e) - , _decoders (decoder_factory (f, o)) + , _playlist (f->playlist ()) + , _encoder (new Encoder (f, _playlist)) { - assert (_encoder); - - if (f->audio_stream()) { - shared_ptr st = f->audio_stream(); - _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate())); - _delay_line.reset (new DelayLine (f->log(), st->channels(), f->audio_delay() * st->sample_rate() / 1000)); + if (_playlist->has_audio ()) { + _matcher.reset (new Matcher (f->log(), _playlist->audio_frame_rate(), _playlist->video_frame_rate())); + _delay_line.reset (new DelayLine (f->log(), _playlist->audio_channels(), f->audio_delay() * _playlist->audio_frame_rate() / 1000)); _gain.reset (new Gain (f->log(), f->audio_gain())); } - /* Set up the decoder to use the film's set streams */ - _decoders.video->set_subtitle_stream (f->subtitle_stream ()); - if (_decoders.audio) { - _decoders.audio->set_audio_stream (f->audio_stream ()); - } - if (_matcher) { - _decoders.video->connect_video (_matcher); + _playlist->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - _decoders.video->connect_video (_encoder); + _playlist->connect_video (_encoder); } - if (_matcher && _delay_line && _decoders.audio) { - _decoders.audio->connect_audio (_delay_line); + if (_matcher && _delay_line && _playlist->has_audio ()) { + _playlist->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); } } -/** Run the decoder, passing its output to the encoder, until the decoder - * has no more data to present. - */ void Transcoder::go () { _encoder->process_begin (); try { - bool done[2] = { false, false }; - while (1) { - if (!done[0]) { - done[0] = _decoders.video->pass (); - if (_job) { - _decoders.video->set_progress (_job); - } - } - - if (!done[1] && _decoders.audio && dynamic_pointer_cast (_decoders.audio) != dynamic_pointer_cast (_decoders.video)) { - done[1] = _decoders.audio->pass (); - } else { - done[1] = true; - } - - if (done[0] && done[1]) { + if (_playlist->pass ()) { break; } + _playlist->set_progress (_job); } } catch (...) { diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index b0c263d07..8d34af948 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -32,9 +32,8 @@ class Encoder; class Matcher; class VideoFilter; class Gain; -class VideoDecoder; -class AudioDecoder; class DelayLine; +class Playlist; /** @class Transcoder * @brief A class which takes a Film and some Options, then uses those to transcode the film. @@ -48,23 +47,16 @@ public: Transcoder ( boost::shared_ptr f, DecodeOptions o, - Job* j, - boost::shared_ptr e + boost::shared_ptr j ); void go (); - boost::shared_ptr video_decoder () const { - return _decoders.video; - } - protected: /** A Job that is running this Transcoder, or 0 */ - Job* _job; - /** The encoder that we will use */ + boost::shared_ptr _job; + boost::shared_ptr _playlist; boost::shared_ptr _encoder; - /** The decoders that we will use */ - Decoders _decoders; boost::shared_ptr _matcher; boost::shared_ptr _delay_line; boost::shared_ptr _gain; diff --git a/src/lib/util.cc b/src/lib/util.cc index 48cb17c26..024740867 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -347,11 +347,11 @@ md5_digest (void const * data, int size) * @return MD5 digest of file's contents. */ string -md5_digest (string file) +md5_digest (boost::filesystem::path file) { - ifstream f (file.c_str(), ios::binary); + ifstream f (file.string().c_str(), ios::binary); if (!f.good ()) { - throw OpenFileError (file); + throw OpenFileError (file.string()); } f.seekg (0, ios::end); diff --git a/src/lib/util.h b/src/lib/util.h index 3d251cf06..87274cfff 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -57,7 +57,7 @@ extern double seconds (struct timeval); extern void dvdomatic_setup (); extern void dvdomatic_setup_i18n (std::string); extern std::vector split_at_spaces_considering_quotes (std::string); -extern std::string md5_digest (std::string); +extern std::string md5_digest (boost::filesystem::path); extern std::string md5_digest (void const *, int); extern void ensure_ui_thread (); extern std::string audio_channel_name (int); @@ -66,6 +66,8 @@ extern boost::filesystem::path mo_path (); #endif typedef int SourceFrame; +typedef int64_t ContentAudioFrame; +typedef int ContentVideoFrame; struct FrameRateConversion { diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc new file mode 100644 index 000000000..9fc5cf1a2 --- /dev/null +++ b/src/lib/video_content.cc @@ -0,0 +1,28 @@ +#include "video_content.h" +#include "video_decoder.h" + +int const VideoContentProperty::VIDEO_LENGTH = 0; +int const VideoContentProperty::VIDEO_SIZE = 1; +int const VideoContentProperty::VIDEO_FRAME_RATE = 2; + +using boost::shared_ptr; + +VideoContent::VideoContent (boost::filesystem::path f) + : Content (f) + , _video_length (0) +{ + +} + +void +VideoContent::take_from_video_decoder (shared_ptr d) +{ + { + boost::mutex::scoped_lock lm (_mutex); + _video_size = d->native_size (); + _video_frame_rate = d->frames_per_second (); + } + + Changed (VideoContentProperty::VIDEO_SIZE); + Changed (VideoContentProperty::VIDEO_FRAME_RATE); +} diff --git a/src/lib/video_content.h b/src/lib/video_content.h index ee4a64fc4..219130668 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -1,8 +1,47 @@ +#ifndef DVDOMATIC_VIDEO_CONTENT_H +#define DVDOMATIC_VIDEO_CONTENT_H + #include "content.h" +#include "util.h" + +class VideoDecoder; + +class VideoContentProperty +{ +public: + static int const VIDEO_LENGTH; + static int const VIDEO_SIZE; + static int const VIDEO_FRAME_RATE; +}; class VideoContent : public virtual Content { public: + VideoContent (boost::filesystem::path); + + ContentVideoFrame video_length () const { + boost::mutex::scoped_lock lm (_mutex); + return _video_length; + } + + libdcp::Size video_size () const { + boost::mutex::scoped_lock lm (_mutex); + return _video_size; + } + float video_frame_rate () const { + boost::mutex::scoped_lock lm (_mutex); + return _video_frame_rate; + } + +protected: + void take_from_video_decoder (boost::shared_ptr); + ContentVideoFrame _video_length; + +private: + libdcp::Size _video_size; + float _video_frame_rate; }; + +#endif diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 891720f6b..ca1e7ab56 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -30,7 +30,7 @@ using boost::shared_ptr; using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr f, DecodeOptions o) +VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) : Decoder (f, o) , _video_frame (0) , _last_source_time (0) @@ -102,21 +102,15 @@ VideoDecoder::emit_subtitle (shared_ptr s) } } -/** Set which stream of subtitles we should use from our source. - * @param s Stream to use. - */ -void -VideoDecoder::set_subtitle_stream (shared_ptr s) -{ - _subtitle_stream = s; -} - void VideoDecoder::set_progress (Job* j) const { assert (j); - + +#if 0 + XXX if (_film->length()) { j->set_progress (float (_video_frame) / _film->length().get()); } +#endif } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 283ab5d88..a52e5448a 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -21,42 +21,33 @@ #define DVDOMATIC_VIDEO_DECODER_H #include "video_source.h" -#include "stream.h" #include "decoder.h" +class VideoContent; + class VideoDecoder : public VideoSource, public virtual Decoder { public: - VideoDecoder (boost::shared_ptr, DecodeOptions); + VideoDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; /** @return native size in pixels */ virtual libdcp::Size native_size () const = 0; - /** @return length (in source video frames), according to our content's header */ - virtual SourceFrame length () const = 0; + /** @return length according to our content's header */ + virtual ContentVideoFrame video_length () const = 0; virtual int time_base_numerator () const = 0; virtual int time_base_denominator () const = 0; virtual int sample_aspect_ratio_numerator () const = 0; virtual int sample_aspect_ratio_denominator () const = 0; - virtual void set_subtitle_stream (boost::shared_ptr); - void set_progress (Job *) const; int video_frame () const { return _video_frame; } - boost::shared_ptr subtitle_stream () const { - return _subtitle_stream; - } - - std::vector > subtitle_streams () const { - return _subtitle_streams; - } - double last_source_time () const { return _last_source_time; } @@ -69,11 +60,6 @@ protected: void emit_subtitle (boost::shared_ptr); void repeat_last_video (); - /** Subtitle stream to use when decoding */ - boost::shared_ptr _subtitle_stream; - /** Subtitle streams that this decoder's content has */ - std::vector > _subtitle_streams; - private: void signal_video (boost::shared_ptr, bool, boost::shared_ptr); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 2d7ee9ba3..5f5dae98f 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -28,6 +28,7 @@ #include "format.h" #include "log.h" #include "dcp_video_frame.h" +#include "playlist.h" #include "i18n.h" @@ -41,8 +42,9 @@ using boost::shared_ptr; int const Writer::_maximum_frames_in_memory = 8; -Writer::Writer (shared_ptr f) +Writer::Writer (shared_ptr f, shared_ptr p) : _film (f) + , _playlist (p) , _first_nonexistant_frame (0) , _thread (0) , _finish (false) @@ -74,7 +76,7 @@ Writer::Writer (shared_ptr f) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - AudioMapping m (_film->audio_channels ()); + AudioMapping m (_playlist->audio_channels ()); if (m.dcp_channels() > 0) { _sound_asset.reset ( @@ -83,7 +85,7 @@ Writer::Writer (shared_ptr f) N_("audio.mxf"), _film->dcp_frame_rate (), m.dcp_channels (), - dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) + dcp_audio_sample_rate (_playlist->audio_frame_rate()) ) ); diff --git a/src/lib/writer.h b/src/lib/writer.h index beb16c7b9..920f592b6 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -26,6 +26,7 @@ class Film; class EncodedData; class AudioBuffers; +class Playlist; namespace libdcp { class MonoPictureAsset; @@ -63,7 +64,7 @@ bool operator== (QueueItem const & a, QueueItem const & b); class Writer : public ExceptionStore { public: - Writer (boost::shared_ptr); + Writer (boost::shared_ptr, boost::shared_ptr); bool can_fake_write (int) const; @@ -80,6 +81,7 @@ private: /** our Film */ boost::shared_ptr _film; + boost::shared_ptr _playlist; /** the first frame index that does not already exist in our MXF */ int _first_nonexistant_frame; diff --git a/src/lib/wscript b/src/lib/wscript index 5d9f5626a..5510d48a8 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -6,10 +6,12 @@ sources = """ ab_transcoder.cc analyse_audio_job.cc audio_analysis.cc + audio_content.cc audio_decoder.cc audio_source.cc config.cc combiner.cc + content.cc cross.cc dci_metadata.cc dcp_content_type.cc @@ -23,24 +25,27 @@ sources = """ exceptions.cc filter_graph.cc ffmpeg_compatibility.cc + ffmpeg_content.cc ffmpeg_decoder.cc film.cc filter.cc format.cc gain.cc image.cc + imagemagick_content.cc imagemagick_decoder.cc job.cc job_manager.cc log.cc lut.cc matcher.cc + playlist.cc scp_dcp_job.cc scaler.cc server.cc + sndfile_content.cc sndfile_decoder.cc sound_processor.cc - stream.cc subtitle.cc timer.cc transcode_job.cc @@ -48,6 +53,7 @@ sources = """ ui_signaller.cc util.cc version.cc + video_content.cc video_decoder.cc video_source.cc writer.cc diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc index 87c079bee..a78d03794 100644 --- a/src/tools/dvdomatic.cc +++ b/src/tools/dvdomatic.cc @@ -236,9 +236,6 @@ public: set_menu_sensitivity (); - /* XXX: calling these here is a bit of a hack */ - film_editor->setup_visibility (); - film_editor->FileChanged.connect (bind (&Frame::file_changed, this, _1)); if (film) { file_changed (film->directory ()); diff --git a/src/tools/makedcp.cc b/src/tools/makedcp.cc index 0c6390771..226cde113 100644 --- a/src/tools/makedcp.cc +++ b/src/tools/makedcp.cc @@ -151,7 +151,7 @@ main (int argc, char* argv[]) } cout << "DCP for " << film->name() << "\n"; cout << "Test mode: " << (test_mode ? "yes" : "no") << "\n"; - cout << "Content: " << film->content() << "\n"; +// cout << "Content: " << film->content() << "\n"; pair const f = Filter::ffmpeg_strings (film->filters ()); cout << "Filters: " << f.first << " " << f.second << "\n"; diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index 3d17988b6..b7384fd14 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -18,10 +18,11 @@ */ #include +#include "lib/audio_analysis.h" +#include "lib/film.h" +#include "lib/playlist.h" #include "audio_dialog.h" #include "audio_plot.h" -#include "audio_analysis.h" -#include "film.h" #include "wx_util.h" using boost::shared_ptr; @@ -90,6 +91,7 @@ AudioDialog::set_film (boost::shared_ptr f) _film_audio_analysis_succeeded_connection.disconnect (); _film = f; + _playlist = _film->playlist (); try_to_load_analysis (); setup_channels (); @@ -104,11 +106,11 @@ AudioDialog::set_film (boost::shared_ptr f) void AudioDialog::setup_channels () { - if (!_film->audio_stream()) { + if (!_playlist->has_audio()) { return; } - AudioMapping m (_film->audio_stream()->channels ()); + AudioMapping m (_playlist->audio_channels ()); for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (m.dcp_to_source(static_cast(i))) { @@ -134,7 +136,7 @@ AudioDialog::try_to_load_analysis () _plot->set_analysis (a); - AudioMapping m (_film->audio_stream()->channels ()); + AudioMapping m (_playlist->audio_channels ()); optional c = m.source_to_dcp (0); if (c) { _channel_checkbox[c.get()]->SetValue (true); @@ -157,7 +159,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) assert (c < MAX_AUDIO_CHANNELS); - AudioMapping m (_film->audio_stream()->channels ()); + AudioMapping m (_playlist->audio_channels ()); optional s = m.dcp_to_source (static_cast (c)); if (s) { _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); @@ -171,9 +173,8 @@ AudioDialog::film_changed (Film::Property p) case Film::AUDIO_GAIN: _plot->set_gain (_film->audio_gain ()); break; - case Film::CONTENT_AUDIO_STREAM: - case Film::EXTERNAL_AUDIO: - case Film::USE_CONTENT_AUDIO: + case Film::CONTENT: + _playlist = _film->playlist (); setup_channels (); break; default: diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h index 514faeea0..3cb9c1726 100644 --- a/src/wx/audio_dialog.h +++ b/src/wx/audio_dialog.h @@ -25,6 +25,7 @@ class AudioPlot; class Film; +class Playlist; class AudioDialog : public wxDialog { @@ -42,6 +43,7 @@ private: void setup_channels (); boost::shared_ptr _film; + boost::shared_ptr _playlist; AudioPlot* _plot; wxCheckBox* _channel_checkbox[MAX_AUDIO_CHANNELS]; wxCheckBox* _type_checkbox[AudioPoint::COUNT]; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index c1d679665..7dfbf6c50 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -65,12 +66,13 @@ FilmEditor::FilmEditor (shared_ptr f, wxWindow* parent) , _audio_dialog (0) { wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); - SetSizer (s); _notebook = new wxNotebook (this, wxID_ANY); s->Add (_notebook, 1); make_film_panel (); _notebook->AddPage (_film_panel, _("Film"), true); + make_content_panel (); + _notebook->AddPage (_content_panel, _("Content"), false); make_video_panel (); _notebook->AddPage (_video_panel, _("Video"), false); make_audio_panel (); @@ -85,8 +87,9 @@ FilmEditor::FilmEditor (shared_ptr f, wxWindow* parent) bind (&FilmEditor::active_jobs_changed, this, _1) ); - setup_visibility (); setup_formats (); + + SetSizerAndFit (s); } void @@ -117,13 +120,7 @@ FilmEditor::make_film_panel () grid->Add (_edit_dci_button, wxGBPosition (r, 1), wxDefaultSpan); ++r; - add_label_to_grid_bag_sizer (grid, _film_panel, _("Content"), wxGBPosition (r, 0)); - _content = new wxFilePickerCtrl (_film_panel, wxID_ANY, wxT (""), _("Select Content File"), wxT("*.*")); - grid->Add (_content, wxGBPosition (r, 1), wxDefaultSpan, wxEXPAND); - ++r; - _trust_content_header = new wxCheckBox (_film_panel, wxID_ANY, _("Trust content's header")); - video_control (_trust_content_header); grid->Add (_trust_content_header, wxGBPosition (r, 0), wxGBSpan(1, 2)); ++r; @@ -132,9 +129,9 @@ FilmEditor::make_film_panel () grid->Add (_dcp_content_type, wxGBPosition (r, 1)); ++r; - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Frame Rate"), wxGBPosition (r, 0))); + add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Frame Rate"), wxGBPosition (r, 0)); _source_frame_rate = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_source_frame_rate), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + grid->Add (_source_frame_rate, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); ++r; { @@ -149,56 +146,42 @@ FilmEditor::make_film_panel () ++r; _frame_rate_description = new wxStaticText (_film_panel, wxID_ANY, wxT (" \n "), wxDefaultPosition, wxDefaultSize); - grid->Add (video_control (_frame_rate_description), wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6); + grid->Add (_frame_rate_description, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND | wxALIGN_CENTER_VERTICAL | wxALL, 6); wxFont font = _frame_rate_description->GetFont(); font.SetStyle(wxFONTSTYLE_ITALIC); font.SetPointSize(font.GetPointSize() - 1); _frame_rate_description->SetFont(font); ++r; - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Size"), wxGBPosition (r, 0))); + add_label_to_grid_bag_sizer (grid, _film_panel, _("Original Size"), wxGBPosition (r, 0)); _original_size = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_original_size), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + grid->Add (_original_size, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); ++r; - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Length"), wxGBPosition (r, 0))); + add_label_to_grid_bag_sizer (grid, _film_panel, _("Length"), wxGBPosition (r, 0)); _length = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_length), wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); + grid->Add (_length, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); ++r; { - video_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim frames"), wxGBPosition (r, 0))); + add_label_to_grid_bag_sizer (grid, _film_panel, _("Trim frames"), wxGBPosition (r, 0)); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - video_control (add_label_to_sizer (s, _film_panel, _("Start"))); + add_label_to_sizer (s, _film_panel, _("Start")); _trim_start = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (video_control (_trim_start)); - video_control (add_label_to_sizer (s, _film_panel, _("End"))); + s->Add (_trim_start); + add_label_to_sizer (s, _film_panel, _("End")); _trim_end = new wxSpinCtrl (_film_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (64, -1)); - s->Add (video_control (_trim_end)); + s->Add (_trim_end); grid->Add (s, wxGBPosition (r, 1)); } ++r; _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B")); - video_control (_dcp_ab); grid->Add (_dcp_ab, wxGBPosition (r, 0)); ++r; - /* STILL-only stuff */ - { - still_control (add_label_to_grid_bag_sizer (grid, _film_panel, _("Duration"), wxGBPosition (r, 0))); - wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _still_duration = new wxSpinCtrl (_film_panel); - still_control (_still_duration); - s->Add (_still_duration, 1, wxEXPAND); - /// TRANSLATORS: `s' here is an abbreviation for seconds, the unit of time - still_control (add_label_to_sizer (s, _film_panel, _("s"))); - grid->Add (s, wxGBPosition (r, 1)); - } - ++r; - vector const ct = DCPContentType::all (); for (vector::const_iterator i = ct.begin(); i != ct.end(); ++i) { _dcp_content_type->Append (std_to_wx ((*i)->pretty_name ())); @@ -217,7 +200,6 @@ FilmEditor::connect_to_widgets () _use_dci_name->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::use_dci_name_toggled), 0, this); _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this); _format->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this); - _content->Connect (wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::content_changed), 0, this); _trust_content_header->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_header_changed), 0, this); _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this); _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this); @@ -229,7 +211,6 @@ FilmEditor::connect_to_widgets () _dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_frame_rate_changed), 0, this); _best_dcp_frame_rate->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::best_dcp_frame_rate_clicked), 0, this); _dcp_ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::dcp_ab_toggled), 0, this); - _still_duration->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::still_duration_changed), 0, this); _trim_start->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_start_changed), 0, this); _trim_end->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::trim_end_changed), 0, this); _with_subtitles->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::with_subtitles_toggled), 0, this); @@ -237,21 +218,14 @@ FilmEditor::connect_to_widgets () _subtitle_scale->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::subtitle_scale_changed), 0, this); _colour_lut->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::colour_lut_changed), 0, this); _j2k_bandwidth->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::j2k_bandwidth_changed), 0, this); - _subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::subtitle_stream_changed), 0, this); - _audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::audio_stream_changed), 0, this); +// _ffmpeg_subtitle_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::ffmpeg_subtitle_stream_changed), 0, this); +// _ffmpeg_audio_stream->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::ffmpeg_audio_stream_changed), 0, this); _audio_gain->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_gain_changed), 0, this); _audio_gain_calculate_button->Connect ( wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::audio_gain_calculate_button_clicked), 0, this ); _show_audio->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::show_audio_clicked), 0, this); _audio_delay->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::audio_delay_changed), 0, this); - _use_content_audio->Connect (wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler (FilmEditor::use_audio_changed), 0, this); - _use_external_audio->Connect (wxID_ANY, wxEVT_COMMAND_RADIOBUTTON_SELECTED, wxCommandEventHandler (FilmEditor::use_audio_changed), 0, this); - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - _external_audio[i]->Connect ( - wxID_ANY, wxEVT_COMMAND_FILEPICKER_CHANGED, wxCommandEventHandler (FilmEditor::external_audio_changed), 0, this - ); - } } void @@ -300,21 +274,19 @@ FilmEditor::make_video_panel () /* VIDEO-only stuff */ { - video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0))); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Filters"), wxGBPosition (r, 0)); wxSizer* s = new wxBoxSizer (wxHORIZONTAL); _filters = new wxStaticText (_video_panel, wxID_ANY, _("None")); - video_control (_filters); s->Add (_filters, 1, wxEXPAND | wxALIGN_CENTER_VERTICAL | wxTOP | wxBOTTOM | wxRIGHT, 6); _filters_button = new wxButton (_video_panel, wxID_ANY, _("Edit...")); - video_control (_filters_button); s->Add (_filters_button, 0); grid->Add (s, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL); } ++r; - video_control (add_label_to_grid_bag_sizer (grid, _video_panel, _("Scaler"), wxGBPosition (r, 0))); + add_label_to_grid_bag_sizer (grid, _video_panel, _("Scaler"), wxGBPosition (r, 0)); _scaler = new wxChoice (_video_panel, wxID_ANY); - grid->Add (video_control (_scaler), wxGBPosition (r, 1)); + grid->Add (_scaler, wxGBPosition (r, 1)); ++r; vector const sc = Scaler::all (); @@ -345,12 +317,48 @@ FilmEditor::make_video_panel () _top_crop->SetRange (0, 1024); _right_crop->SetRange (0, 1024); _bottom_crop->SetRange (0, 1024); - _still_duration->SetRange (1, 60 * 60); _trim_start->SetRange (0, 100); _trim_end->SetRange (0, 100); _j2k_bandwidth->SetRange (50, 250); } +void +FilmEditor::make_content_panel () +{ + _content_panel = new wxPanel (_notebook); + _content_sizer = new wxBoxSizer (wxVERTICAL); + _content_panel->SetSizer (_content_sizer); + + wxGridBagSizer* grid = new wxGridBagSizer (4, 4); + _content_sizer->Add (grid, 0, wxALL, 8); + + int r = 0; + + { + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + + _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); + s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); + + _content->InsertColumn (0, ""); + + wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); + _content_add = new wxButton (_content_panel, wxID_ANY, _("Add...")); + b->Add (_content_add); + _content_remove = new wxButton (_content_panel, wxID_ANY, _("Remove")); + b->Add (_content_remove); + _content_earlier = new wxButton (_content_panel, wxID_ANY, _("Earlier")); + b->Add (_content_earlier); + _content_later = new wxButton (_content_panel, wxID_ANY, _("Later")); + b->Add (_content_later); + + s->Add (b, 0, wxALL, 4); + + grid->Add (s, wxGBPosition (r, 0), wxGBSpan (1, 2), wxEXPAND); + ++r; + } +} + void FilmEditor::make_audio_panel () { @@ -366,48 +374,26 @@ FilmEditor::make_audio_panel () grid->AddSpacer (0); { - video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Gain"))); + add_label_to_sizer (grid, _audio_panel, _("Audio Gain")); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_gain = new wxSpinCtrl (_audio_panel); - s->Add (video_control (_audio_gain), 1); - video_control (add_label_to_sizer (s, _audio_panel, _("dB"))); + s->Add (_audio_gain, 1); + add_label_to_sizer (s, _audio_panel, _("dB")); _audio_gain_calculate_button = new wxButton (_audio_panel, wxID_ANY, _("Calculate...")); - video_control (_audio_gain_calculate_button); s->Add (_audio_gain_calculate_button, 1, wxEXPAND); grid->Add (s); } { - video_control (add_label_to_sizer (grid, _audio_panel, _("Audio Delay"))); + add_label_to_sizer (grid, _audio_panel, _("Audio Delay")); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _audio_delay = new wxSpinCtrl (_audio_panel); - s->Add (video_control (_audio_delay), 1); + s->Add (_audio_delay, 1); /// TRANSLATORS: this is an abbreviation for milliseconds, the unit of time - video_control (add_label_to_sizer (s, _audio_panel, _("ms"))); + add_label_to_sizer (s, _audio_panel, _("ms")); grid->Add (s); } - { - _use_content_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use content's audio"), wxDefaultPosition, wxDefaultSize, wxRB_GROUP); - grid->Add (video_control (_use_content_audio)); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _audio_stream = new wxChoice (_audio_panel, wxID_ANY); - s->Add (video_control (_audio_stream), 1); - _audio = new wxStaticText (_audio_panel, wxID_ANY, wxT ("")); - s->Add (video_control (_audio), 1, wxALIGN_CENTER_VERTICAL | wxLEFT, 8); - grid->Add (s, 1, wxEXPAND); - } - - _use_external_audio = new wxRadioButton (_audio_panel, wxID_ANY, _("Use external audio")); - grid->Add (_use_external_audio); - grid->AddSpacer (0); - - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - add_label_to_sizer (grid, _audio_panel, std_to_wx (audio_channel_name (i))); - _external_audio[i] = new wxFilePickerCtrl (_audio_panel, wxID_ANY, wxT (""), _("Select Audio File"), wxT ("*.wav")); - grid->Add (_external_audio[i], 1, wxEXPAND); - } - _audio_gain->SetRange (-60, 60); _audio_delay->SetRange (-1000, 1000); } @@ -422,22 +408,21 @@ FilmEditor::make_subtitle_panel () _subtitle_sizer->Add (grid, 0, wxALL, 8); _with_subtitles = new wxCheckBox (_subtitle_panel, wxID_ANY, _("With Subtitles")); - video_control (_with_subtitles); grid->Add (_with_subtitles, 1); - _subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY); - grid->Add (video_control (_subtitle_stream)); + _ffmpeg_subtitle_stream = new wxChoice (_subtitle_panel, wxID_ANY); + grid->Add (_ffmpeg_subtitle_stream); - video_control (add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset"))); + add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Offset")); _subtitle_offset = new wxSpinCtrl (_subtitle_panel); - grid->Add (video_control (_subtitle_offset), 1); + grid->Add (_subtitle_offset, 1); { - video_control (add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale"))); + add_label_to_sizer (grid, _subtitle_panel, _("Subtitle Scale")); wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); _subtitle_scale = new wxSpinCtrl (_subtitle_panel); - s->Add (video_control (_subtitle_scale)); - video_control (add_label_to_sizer (s, _subtitle_panel, _("%"))); + s->Add (_subtitle_scale); + add_label_to_sizer (s, _subtitle_panel, _("%")); grid->Add (s); } @@ -489,22 +474,6 @@ FilmEditor::bottom_crop_changed (wxCommandEvent &) _film->set_bottom_crop (_bottom_crop->GetValue ()); } -/** Called when the content filename has been changed */ -void -FilmEditor::content_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - try { - _film->set_content (wx_to_std (_content->GetPath ())); - } catch (std::exception& e) { - _content->SetPath (std_to_wx (_film->directory ())); - error_dialog (this, wxString::Format (_("Could not set content: %s"), std_to_wx (e.what()).data())); - } -} - void FilmEditor::trust_content_header_changed (wxCommandEvent &) { @@ -611,8 +580,7 @@ FilmEditor::film_changed (Film::Property p) case Film::NONE: break; case Film::CONTENT: - checked_set (_content, _film->content ()); - setup_visibility (); + setup_content (); setup_formats (); setup_subtitle_control_sensitivity (); setup_streams (); @@ -621,14 +589,14 @@ FilmEditor::film_changed (Film::Property p) case Film::TRUST_CONTENT_HEADER: checked_set (_trust_content_header, _film->trust_content_header ()); break; - case Film::SUBTITLE_STREAMS: - setup_subtitle_control_sensitivity (); - setup_streams (); - break; - case Film::CONTENT_AUDIO_STREAMS: - setup_streams (); - setup_show_audio_sensitivity (); - break; +// case Film::SUBTITLE_STREAMS: +// setup_subtitle_control_sensitivity (); +// setup_streams (); +// break; +// case Film::CONTENT_AUDIO_STREAMS: +// setup_streams (); +// setup_show_audio_sensitivity (); +// break; case Film::FORMAT: { int n = 0; @@ -673,32 +641,32 @@ FilmEditor::film_changed (Film::Property p) checked_set (_name, _film->name()); setup_dcp_name (); break; - case Film::SOURCE_FRAME_RATE: - s << fixed << setprecision(2) << _film->source_frame_rate(); - _source_frame_rate->SetLabel (std_to_wx (s.str ())); - break; - case Film::SIZE: - if (_film->size().width == 0 && _film->size().height == 0) { - _original_size->SetLabel (wxT ("")); - } else { - s << _film->size().width << " x " << _film->size().height; - _original_size->SetLabel (std_to_wx (s.str ())); - } - break; - case Film::LENGTH: - if (_film->source_frame_rate() > 0 && _film->length()) { - s << _film->length().get() << " " - << wx_to_std (_("frames")) << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate()); - } else if (_film->length()) { - s << _film->length().get() << " " - << wx_to_std (_("frames")); - } - _length->SetLabel (std_to_wx (s.str ())); - if (_film->length()) { - _trim_start->SetRange (0, _film->length().get()); - _trim_end->SetRange (0, _film->length().get()); - } - break; +// case Film::SOURCE_FRAME_RATE: +// s << fixed << setprecision(2) << _film->source_frame_rate(); +// _source_frame_rate->SetLabel (std_to_wx (s.str ())); +// break; +// case Film::SIZE: +// if (_film->size().width == 0 && _film->size().height == 0) { +// _original_size->SetLabel (wxT ("")); +// } else { +// s << _film->size().width << " x " << _film->size().height; +// _original_size->SetLabel (std_to_wx (s.str ())); +// } +// break; +// case Film::LENGTH: +// if (_film->source_frame_rate() > 0 && _film->length()) { +// s << _film->length().get() << " " +// << wx_to_std (_("frames")) << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate()); +// } else if (_film->length()) { +// s << _film->length().get() << " " +// << wx_to_std (_("frames")); +// } +// _length->SetLabel (std_to_wx (s.str ())); +// if (_film->length()) { +// _trim_start->SetRange (0, _film->length().get()); +// _trim_end->SetRange (0, _film->length().get()); +// } +// break; case Film::DCP_CONTENT_TYPE: checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ())); setup_dcp_name (); @@ -721,9 +689,6 @@ FilmEditor::film_changed (Film::Property p) case Film::AUDIO_DELAY: checked_set (_audio_delay, _film->audio_delay ()); break; - case Film::STILL_DURATION: - checked_set (_still_duration, _film->still_duration ()); - break; case Film::WITH_SUBTITLES: checked_set (_with_subtitles, _film->with_subtitles ()); setup_subtitle_control_sensitivity (); @@ -748,55 +713,36 @@ FilmEditor::film_changed (Film::Property p) case Film::DCI_METADATA: setup_dcp_name (); break; - case Film::CONTENT_AUDIO_STREAM: - if (_film->content_audio_stream()) { - checked_set (_audio_stream, _film->content_audio_stream()->to_string()); - } - setup_dcp_name (); - setup_audio_details (); - setup_audio_control_sensitivity (); - setup_show_audio_sensitivity (); - break; - case Film::USE_CONTENT_AUDIO: - checked_set (_use_content_audio, _film->use_content_audio()); - checked_set (_use_external_audio, !_film->use_content_audio()); - setup_dcp_name (); - setup_audio_details (); - setup_audio_control_sensitivity (); - setup_show_audio_sensitivity (); - break; - case Film::SUBTITLE_STREAM: - if (_film->subtitle_stream()) { - checked_set (_subtitle_stream, _film->subtitle_stream()->to_string()); - } - break; - case Film::EXTERNAL_AUDIO: - { - vector a = _film->external_audio (); - for (size_t i = 0; i < a.size() && i < MAX_AUDIO_CHANNELS; ++i) { - checked_set (_external_audio[i], a[i]); - } - setup_audio_details (); - setup_show_audio_sensitivity (); - break; - } - case Film::DCP_FRAME_RATE: - for (unsigned int i = 0; i < _dcp_frame_rate->GetCount(); ++i) { - if (wx_to_std (_dcp_frame_rate->GetString(i)) == boost::lexical_cast (_film->dcp_frame_rate())) { - if (_dcp_frame_rate->GetSelection() != int(i)) { - _dcp_frame_rate->SetSelection (i); - break; - } - } - } - - if (_film->source_frame_rate()) { - _frame_rate_description->SetLabel (std_to_wx (FrameRateConversion (_film->source_frame_rate(), _film->dcp_frame_rate()).description)); - _best_dcp_frame_rate->Enable (best_dcp_frame_rate (_film->source_frame_rate ()) != _film->dcp_frame_rate ()); - } else { - _frame_rate_description->SetLabel (wxT ("")); - _best_dcp_frame_rate->Disable (); - } +// case Film::CONTENT_AUDIO_STREAM: +// if (_film->content_audio_stream()) { +// checked_set (_audio_stream, _film->content_audio_stream()->to_string()); +// } +// setup_dcp_name (); +// setup_audio_details (); +// setup_show_audio_sensitivity (); +// break; +// case Film::SUBTITLE_STREAM: +// if (_film->subtitle_stream()) { +// checked_set (_subtitle_stream, _film->subtitle_stream()->to_string()); +// } +// break; +// case Film::DCP_FRAME_RATE: +// for (unsigned int i = 0; i < _dcp_frame_rate->GetCount(); ++i) { +// if (wx_to_std (_dcp_frame_rate->GetString(i)) == boost::lexical_cast (_film->dcp_frame_rate())) { +// if (_dcp_frame_rate->GetSelection() != int(i)) { +// _dcp_frame_rate->SetSelection (i); +// break; +// } +// } +// } + +// if (_film->source_frame_rate()) { +// _frame_rate_description->SetLabel (std_to_wx (FrameRateConversion (_film->source_frame_rate(), _film->dcp_frame_rate()).description)); +// _best_dcp_frame_rate->Enable (best_dcp_frame_rate (_film->source_frame_rate ()) != _film->dcp_frame_rate ()); +// } else { +// _frame_rate_description->SetLabel (wxT ("")); +// _best_dcp_frame_rate->Disable (); +// } } } @@ -863,23 +809,14 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::TRIM_START); film_changed (Film::TRIM_END); film_changed (Film::DCP_AB); - film_changed (Film::CONTENT_AUDIO_STREAM); - film_changed (Film::EXTERNAL_AUDIO); - film_changed (Film::USE_CONTENT_AUDIO); film_changed (Film::AUDIO_GAIN); film_changed (Film::AUDIO_DELAY); - film_changed (Film::STILL_DURATION); film_changed (Film::WITH_SUBTITLES); film_changed (Film::SUBTITLE_OFFSET); film_changed (Film::SUBTITLE_SCALE); film_changed (Film::COLOUR_LUT); film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); - film_changed (Film::SIZE); - film_changed (Film::LENGTH); - film_changed (Film::CONTENT_AUDIO_STREAMS); - film_changed (Film::SUBTITLE_STREAMS); - film_changed (Film::SOURCE_FRAME_RATE); film_changed (Film::DCP_FRAME_RATE); } @@ -903,7 +840,7 @@ FilmEditor::set_things_sensitive (bool s) _bottom_crop->Enable (s); _filters_button->Enable (s); _scaler->Enable (s); - _audio_stream->Enable (s); +// _ffmpeg_audio_stream->Enable (s); _dcp_content_type->Enable (s); _dcp_frame_rate->Enable (s); _trim_start->Enable (s); @@ -915,10 +852,8 @@ FilmEditor::set_things_sensitive (bool s) _audio_gain_calculate_button->Enable (s); _show_audio->Enable (s); _audio_delay->Enable (s); - _still_duration->Enable (s); setup_subtitle_control_sensitivity (); - setup_audio_control_sensitivity (); setup_show_audio_sensitivity (); } @@ -966,62 +901,6 @@ FilmEditor::audio_delay_changed (wxCommandEvent &) _film->set_audio_delay (_audio_delay->GetValue ()); } -wxControl * -FilmEditor::video_control (wxControl* c) -{ - _video_controls.push_back (c); - return c; -} - -wxControl * -FilmEditor::still_control (wxControl* c) -{ - _still_controls.push_back (c); - return c; -} - -void -FilmEditor::setup_visibility () -{ - ContentType c = VIDEO; - - if (_film) { - c = _film->content_type (); - } - - for (list::iterator i = _video_controls.begin(); i != _video_controls.end(); ++i) { - (*i)->Show (c == VIDEO); - } - - for (list::iterator i = _still_controls.begin(); i != _still_controls.end(); ++i) { - (*i)->Show (c == STILL); - } - - _notebook->InvalidateBestSize (); - - _film_sizer->Layout (); - _film_sizer->SetSizeHints (_film_panel); - _video_sizer->Layout (); - _video_sizer->SetSizeHints (_video_panel); - _audio_sizer->Layout (); - _audio_sizer->SetSizeHints (_audio_panel); - _subtitle_sizer->Layout (); - _subtitle_sizer->SetSizeHints (_subtitle_panel); - - _notebook->Fit (); - Fit (); -} - -void -FilmEditor::still_duration_changed (wxCommandEvent &) -{ - if (!_film) { - return; - } - - _film->set_still_duration (_still_duration->GetValue ()); -} - void FilmEditor::trim_start_changed (wxCommandEvent &) { @@ -1072,20 +951,7 @@ FilmEditor::audio_gain_calculate_button_clicked (wxCommandEvent &) void FilmEditor::setup_formats () { - ContentType c = VIDEO; - - if (_film) { - c = _film->content_type (); - } - - _formats.clear (); - - vector fmt = Format::all (); - for (vector::iterator i = fmt.begin(); i != fmt.end(); ++i) { - if (c == VIDEO || (c == STILL && dynamic_cast (*i))) { - _formats.push_back (*i); - } - } + _formats = Format::all (); _format->Clear (); for (vector::iterator i = _formats.begin(); i != _formats.end(); ++i) { @@ -1110,7 +976,7 @@ FilmEditor::setup_subtitle_control_sensitivity () { bool h = false; if (_generally_sensitive && _film) { - h = !_film->subtitle_streams().empty(); +// h = !_film->subtitle_streams().empty(); } _with_subtitles->Enable (h); @@ -1120,26 +986,11 @@ FilmEditor::setup_subtitle_control_sensitivity () j = _film->with_subtitles (); } - _subtitle_stream->Enable (j); + _ffmpeg_subtitle_stream->Enable (j); _subtitle_offset->Enable (j); _subtitle_scale->Enable (j); } -void -FilmEditor::setup_audio_control_sensitivity () -{ - _use_content_audio->Enable (_generally_sensitive && _film && !_film->content_audio_streams().empty()); - _use_external_audio->Enable (_generally_sensitive); - - bool const source = _generally_sensitive && _use_content_audio->GetValue(); - bool const external = _generally_sensitive && _use_external_audio->GetValue(); - - _audio_stream->Enable (source); - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - _external_audio[i]->Enable (external); - } -} - void FilmEditor::use_dci_name_toggled (wxCommandEvent &) { @@ -1166,63 +1017,66 @@ FilmEditor::edit_dci_button_clicked (wxCommandEvent &) void FilmEditor::setup_streams () { - _audio_stream->Clear (); - vector > a = _film->content_audio_streams (); - for (vector >::iterator i = a.begin(); i != a.end(); ++i) { - shared_ptr ffa = dynamic_pointer_cast (*i); - assert (ffa); - _audio_stream->Append (std_to_wx (ffa->name()), new wxStringClientData (std_to_wx (ffa->to_string ()))); - } +// _ffmpeg_audio_stream->Clear (); + vector a;// = _film->content_audio_streams (); +// for (vector::iterator i = a.begin(); i != a.end(); ++i) { +// _audio_stream->Append (std_to_wx (ffa->name()), new wxStringClientData (std_to_wx (i->to_string ()))); +// } - if (_film->use_content_audio() && _film->audio_stream()) { - checked_set (_audio_stream, _film->audio_stream()->to_string()); - } - - _subtitle_stream->Clear (); - vector > s = _film->subtitle_streams (); - for (vector >::iterator i = s.begin(); i != s.end(); ++i) { - _subtitle_stream->Append (std_to_wx ((*i)->name()), new wxStringClientData (std_to_wx ((*i)->to_string ()))); - } - if (_film->subtitle_stream()) { - checked_set (_subtitle_stream, _film->subtitle_stream()->to_string()); - } else { - _subtitle_stream->SetSelection (wxNOT_FOUND); - } +// if (_film->use_content_audio() && _film->audio_stream()) { +// checked_set (_audio_stream, _film->audio_stream()->to_string()); +// } + + _ffmpeg_subtitle_stream->Clear (); +// vector > s = _film->subtitle_streams (); +// for (vector >::iterator i = s.begin(); i != s.end(); ++i) { +// _subtitle_stream->Append (std_to_wx ((*i)->name()), new wxStringClientData (std_to_wx ((*i)->to_string ()))); +// } +// if (_film->subtitle_stream()) { +// checked_set (_subtitle_stream, _film->subtitle_stream()->to_string()); +// } else { +// _subtitle_stream->SetSelection (wxNOT_FOUND); +// } } void -FilmEditor::audio_stream_changed (wxCommandEvent &) +FilmEditor::ffmpeg_audio_stream_changed (wxCommandEvent &) { if (!_film) { return; } +#if 0 _film->set_content_audio_stream ( audio_stream_factory ( string_client_data (_audio_stream->GetClientObject (_audio_stream->GetSelection ())), Film::state_version ) ); +#endif } void -FilmEditor::subtitle_stream_changed (wxCommandEvent &) +FilmEditor::ffmpeg_subtitle_stream_changed (wxCommandEvent &) { if (!_film) { return; } +#if 0 _film->set_subtitle_stream ( subtitle_stream_factory ( string_client_data (_subtitle_stream->GetClientObject (_subtitle_stream->GetSelection ())), Film::state_version ) ); +#endif } void FilmEditor::setup_audio_details () { +#if 0 if (!_film->content_audio_stream()) { _audio->SetLabel (wxT ("")); } else { @@ -1235,6 +1089,7 @@ FilmEditor::setup_audio_details () s << ", " << _film->audio_stream()->sample_rate() << wx_to_std (_("Hz")); _audio->SetLabel (std_to_wx (s.str ())); } +#endif } void @@ -1243,23 +1098,6 @@ FilmEditor::active_jobs_changed (bool a) set_things_sensitive (!a); } -void -FilmEditor::use_audio_changed (wxCommandEvent &) -{ - _film->set_use_content_audio (_use_content_audio->GetValue()); -} - -void -FilmEditor::external_audio_changed (wxCommandEvent &) -{ - vector a; - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - a.push_back (wx_to_std (_external_audio[i]->GetPath())); - } - - _film->set_external_audio (a); -} - void FilmEditor::setup_dcp_name () { @@ -1292,11 +1130,23 @@ FilmEditor::best_dcp_frame_rate_clicked (wxCommandEvent &) return; } - _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->source_frame_rate ())); +// _film->set_dcp_frame_rate (best_dcp_frame_rate (_film->source_frame_rate ())); } void FilmEditor::setup_show_audio_sensitivity () { - _show_audio->Enable (_film && _film->has_audio ()); +// _show_audio->Enable (_film && _film->has_audio ()); +} + +void +FilmEditor::setup_content () +{ + _content->DeleteAllItems (); + + list > content = _film->content (); + for (list >::iterator i = content.begin(); i != content.end(); ++i) { + _content->InsertItem (_content->GetItemCount(), std_to_wx ((*i)->summary ())); + } } + diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index e5b619886..6b1d98ea6 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -29,6 +29,7 @@ #include "lib/film.h" class wxNotebook; +class wxListCtrl; class Film; class AudioDialog; @@ -41,12 +42,12 @@ public: FilmEditor (boost::shared_ptr, wxWindow *); void set_film (boost::shared_ptr); - void setup_visibility (); boost::signals2::signal FileChanged; private: void make_film_panel (); + void make_content_panel (); void make_video_panel (); void make_audio_panel (); void make_subtitle_panel (); @@ -60,7 +61,6 @@ private: void right_crop_changed (wxCommandEvent &); void top_crop_changed (wxCommandEvent &); void bottom_crop_changed (wxCommandEvent &); - void content_changed (wxCommandEvent &); void trust_content_header_changed (wxCommandEvent &); void format_changed (wxCommandEvent &); void trim_start_changed (wxCommandEvent &); @@ -77,11 +77,8 @@ private: void subtitle_scale_changed (wxCommandEvent &); void colour_lut_changed (wxCommandEvent &); void j2k_bandwidth_changed (wxCommandEvent &); - void still_duration_changed (wxCommandEvent &); - void audio_stream_changed (wxCommandEvent &); - void subtitle_stream_changed (wxCommandEvent &); - void use_audio_changed (wxCommandEvent &); - void external_audio_changed (wxCommandEvent &); + void ffmpeg_audio_stream_changed (wxCommandEvent &); + void ffmpeg_subtitle_stream_changed (wxCommandEvent &); void dcp_frame_rate_changed (wxCommandEvent &); void best_dcp_frame_rate_clicked (wxCommandEvent &); @@ -94,20 +91,19 @@ private: void set_things_sensitive (bool); void setup_formats (); void setup_subtitle_control_sensitivity (); - void setup_audio_control_sensitivity (); void setup_streams (); void setup_audio_details (); void setup_dcp_name (); void setup_show_audio_sensitivity (); + void setup_content (); - wxControl* video_control (wxControl *); - wxControl* still_control (wxControl *); - void active_jobs_changed (bool); wxNotebook* _notebook; wxPanel* _film_panel; wxSizer* _film_sizer; + wxPanel* _content_panel; + wxSizer* _content_sizer; wxPanel* _video_panel; wxSizer* _video_sizer; wxPanel* _audio_panel; @@ -121,68 +117,47 @@ private: wxTextCtrl* _name; wxStaticText* _dcp_name; wxCheckBox* _use_dci_name; + wxListCtrl* _content; + wxButton* _content_add; + wxButton* _content_remove; + wxButton* _content_earlier; + wxButton* _content_later; wxButton* _edit_dci_button; - /** The Film's format */ wxChoice* _format; wxStaticText* _format_description; - /** The Film's content file */ - wxFilePickerCtrl* _content; wxCheckBox* _trust_content_header; - /** The Film's left crop */ wxSpinCtrl* _left_crop; - /** The Film's right crop */ wxSpinCtrl* _right_crop; - /** The Film's top crop */ wxSpinCtrl* _top_crop; - /** The Film's bottom crop */ wxSpinCtrl* _bottom_crop; - /** Currently-applied filters */ wxStaticText* _filters; - /** Button to open the filters dialogue */ wxButton* _filters_button; - /** The Film's scaler */ wxChoice* _scaler; - wxRadioButton* _use_content_audio; - wxChoice* _audio_stream; - wxRadioButton* _use_external_audio; - wxFilePickerCtrl* _external_audio[MAX_AUDIO_CHANNELS]; - /** The Film's audio gain */ wxSpinCtrl* _audio_gain; - /** A button to open the gain calculation dialogue */ wxButton* _audio_gain_calculate_button; wxButton* _show_audio; - /** The Film's audio delay */ wxSpinCtrl* _audio_delay; wxCheckBox* _with_subtitles; - wxChoice* _subtitle_stream; + wxChoice* _ffmpeg_subtitle_stream; wxSpinCtrl* _subtitle_offset; wxSpinCtrl* _subtitle_scale; wxChoice* _colour_lut; wxSpinCtrl* _j2k_bandwidth; - /** The Film's DCP content type */ wxChoice* _dcp_content_type; - /** The Film's source frame rate */ wxStaticText* _source_frame_rate; wxChoice* _dcp_frame_rate; wxButton* _best_dcp_frame_rate; wxStaticText* _frame_rate_description; - /** The Film's original size */ wxStaticText* _original_size; - /** The Film's length */ wxStaticText* _length; /** The Film's audio details */ wxStaticText* _audio; - /** The Film's duration for still sources */ - wxSpinCtrl* _still_duration; wxSpinCtrl* _trim_start; wxSpinCtrl* _trim_end; /** Selector to generate an A/B comparison DCP */ wxCheckBox* _dcp_ab; - std::list _video_controls; - std::list _still_controls; - std::vector _formats; bool _generally_sensitive; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 08eade4d0..1e2a74be9 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -114,12 +114,10 @@ FilmViewer::film_changed (Film::Property p) } _decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); _decoders.video->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); - _decoders.video->set_subtitle_stream (_film->subtitle_stream()); +// _decoders.video->set_subtitle_stream (_film->subtitle_stream()); calculate_sizes (); get_frame (); _panel->Refresh (); - _slider->Show (_film->content_type() == VIDEO); - _play_button->Show (_film->content_type() == VIDEO); _v_sizer->Layout (); break; } @@ -132,7 +130,7 @@ FilmViewer::film_changed (Film::Property p) break; case Film::SUBTITLE_STREAM: if (_decoders.video) { - _decoders.video->set_subtitle_stream (_film->subtitle_stream ()); +// _decoders.video->set_subtitle_stream (_film->subtitle_stream ()); } break; default: @@ -187,12 +185,12 @@ FilmViewer::timer (wxTimerEvent &) get_frame (); - if (_film->length()) { - int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate()); - if (new_slider_position != _slider->GetValue()) { - _slider->SetValue (new_slider_position); - } - } +// if (_film->length()) { +// int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate()); +// if (new_slider_position != _slider->GetValue()) { +// _slider->SetValue (new_slider_position); +// } +// } } @@ -233,13 +231,13 @@ FilmViewer::paint_panel (wxPaintEvent &) void FilmViewer::slider_moved (wxScrollEvent &) { - if (!_film || !_film->length() || !_decoders.video) { - return; - } +// if (!_film || !_film->length() || !_decoders.video) { +// return; +// } - if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) { - return; - } +// if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) { +// return; +// } get_frame (); _panel->Refresh (); @@ -294,6 +292,7 @@ FilmViewer::raw_to_display () _clear_required = true; } +#if 0 if (_raw_sub) { /* Our output is already cropped by the decoder, so we need to account for that @@ -314,6 +313,7 @@ FilmViewer::raw_to_display () } else { _display_sub.reset (); } +#endif } void @@ -342,9 +342,9 @@ FilmViewer::calculate_sizes () of our _display_frame. */ _display_frame_x = 0; - if (format) { - _display_frame_x = static_cast (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width; - } +// if (format) { +// _display_frame_x = static_cast (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width; +// } _film_size = _out_size; _film_size.width -= _display_frame_x * 2; @@ -369,7 +369,7 @@ FilmViewer::check_play_state () } if (_play_button->GetValue()) { - _timer.Start (1000 / _film->source_frame_rate()); +// _timer.Start (1000 / _film->source_frame_rate()); } else { _timer.Stop (); } diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index 44a713dc3..06e245832 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -50,6 +50,7 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr film) _encoded = new ThreadedStaticText (this, _("counting..."), boost::bind (&PropertiesDialog::frames_already_encoded, this)); table->Add (_encoded, 1, wxALIGN_CENTER_VERTICAL); +#if 0 if (_film->length()) { _frames->SetLabel (std_to_wx (lexical_cast (_film->length().get()))); FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); @@ -62,6 +63,7 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr film) _frames->SetLabel (_("unknown")); _disk->SetLabel (_("unknown")); } +#endif wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); overall_sizer->Add (table, 0, wxALL, 6); @@ -85,9 +87,9 @@ PropertiesDialog::frames_already_encoded () const return ""; } - if (_film->length()) { - /* XXX: encoded_frames() should check which frames have been encoded */ - u << " (" << (_film->encoded_frames() * 100 / _film->length().get()) << "%)"; - } +// if (_film->length()) { +// /* XXX: encoded_frames() should check which frames have been encoded */ +// u << " (" << (_film->encoded_frames() * 100 / _film->length().get()) << "%)"; +// } return u.str (); } diff --git a/test/test.cc b/test/test.cc index 61e192058..efa4848f6 100644 --- a/test/test.cc +++ b/test/test.cc @@ -142,7 +142,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) BOOST_CHECK (f->filters ().empty()); f->set_name ("fred"); - BOOST_CHECK_THROW (f->set_content ("jim"), OpenFileError); +// BOOST_CHECK_THROW (f->set_content ("jim"), OpenFileError); f->set_dcp_content_type (DCPContentType::from_pretty_name ("Short")); f->set_format (Format::from_nickname ("Flat")); f->set_left_crop (1); @@ -183,50 +183,17 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0); } -BOOST_AUTO_TEST_CASE (stream_test) -{ - FFmpegAudioStream a ("ffmpeg 4 44100 1 hello there world", boost::optional (1)); - BOOST_CHECK_EQUAL (a.id(), 4); - BOOST_CHECK_EQUAL (a.sample_rate(), 44100); - BOOST_CHECK_EQUAL (a.channel_layout(), 1); - BOOST_CHECK_EQUAL (a.name(), "hello there world"); - BOOST_CHECK_EQUAL (a.to_string(), "ffmpeg 4 44100 1 hello there world"); - - SndfileStream e ("external 44100 1", boost::optional (1)); - BOOST_CHECK_EQUAL (e.sample_rate(), 44100); - BOOST_CHECK_EQUAL (e.channel_layout(), 1); - BOOST_CHECK_EQUAL (e.to_string(), "external 44100 1"); - - SubtitleStream s ("5 a b c", boost::optional (1)); - BOOST_CHECK_EQUAL (s.id(), 5); - BOOST_CHECK_EQUAL (s.name(), "a b c"); - - shared_ptr ff = audio_stream_factory ("ffmpeg 4 44100 1 hello there world", boost::optional (1)); - shared_ptr cff = dynamic_pointer_cast (ff); - BOOST_CHECK (cff); - BOOST_CHECK_EQUAL (cff->id(), 4); - BOOST_CHECK_EQUAL (cff->sample_rate(), 44100); - BOOST_CHECK_EQUAL (cff->channel_layout(), 1); - BOOST_CHECK_EQUAL (cff->name(), "hello there world"); - BOOST_CHECK_EQUAL (cff->to_string(), "ffmpeg 4 44100 1 hello there world"); - - shared_ptr fe = audio_stream_factory ("external 44100 1", boost::optional (1)); - BOOST_CHECK_EQUAL (fe->sample_rate(), 44100); - BOOST_CHECK_EQUAL (fe->channel_layout(), 1); - BOOST_CHECK_EQUAL (fe->to_string(), "external 44100 1"); -} - BOOST_AUTO_TEST_CASE (format_test) { Format::setup_formats (); Format const * f = Format::from_nickname ("Flat"); BOOST_CHECK (f); - BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr ()), 185); +// BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr ()), 185); f = Format::from_nickname ("Scope"); BOOST_CHECK (f); - BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr ()), 239); +// BOOST_CHECK_EQUAL (f->ratio_as_integer(shared_ptr ()), 239); } BOOST_AUTO_TEST_CASE (util_test) @@ -355,17 +322,6 @@ BOOST_AUTO_TEST_CASE (md5_digest_test) BOOST_CHECK_THROW (md5_digest ("foobar"), OpenFileError); } -BOOST_AUTO_TEST_CASE (paths_test) -{ - shared_ptr f = new_test_film ("paths_test"); - f->set_directory ("build/test/a/b/c/d/e"); - - f->_content = "/foo/bar/baz"; - BOOST_CHECK_EQUAL (f->content_path(), "/foo/bar/baz"); - f->_content = "foo/bar/baz"; - BOOST_CHECK_EQUAL (f->content_path(), "build/test/a/b/c/d/e/foo/bar/baz"); -} - void do_remote_encode (shared_ptr frame, ServerDescription* description, shared_ptr locally_encoded) { @@ -457,7 +413,7 @@ BOOST_AUTO_TEST_CASE (make_dcp_test) { shared_ptr film = new_test_film ("make_dcp_test"); film->set_name ("test_film2"); - film->set_content ("../../../test/test.mp4"); +// film->set_content ("../../../test/test.mp4"); film->set_format (Format::from_nickname ("Flat")); film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test")); film->make_dcp (); @@ -487,8 +443,8 @@ BOOST_AUTO_TEST_CASE (make_dcp_with_range_test) { shared_ptr film = new_test_film ("make_dcp_with_range_test"); film->set_name ("test_film3"); - film->set_content ("../../../test/test.mp4"); - film->examine_content (); +// film->set_content ("../../../test/test.mp4"); +// film->examine_content (); film->set_format (Format::from_nickname ("Flat")); film->set_dcp_content_type (DCPContentType::from_pretty_name ("Test")); film->set_trim_end (42); @@ -649,44 +605,44 @@ BOOST_AUTO_TEST_CASE (audio_sampling_rate_test) Config::instance()->set_allowed_dcp_frame_rates (afr); shared_ptr f = new_test_film ("audio_sampling_rate_test"); - f->set_source_frame_rate (24); +// f->set_source_frame_rate (24); f->set_dcp_frame_rate (24); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 44100, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 44100, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 80000, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 80000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 96000); - f->set_source_frame_rate (23.976); +// f->set_source_frame_rate (23.976); f->set_dcp_frame_rate (best_dcp_frame_rate (23.976)); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952); - f->set_source_frame_rate (29.97); +// f->set_source_frame_rate (29.97); f->set_dcp_frame_rate (best_dcp_frame_rate (29.97)); BOOST_CHECK_EQUAL (f->dcp_frame_rate (), 30); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952); - f->set_source_frame_rate (25); +// f->set_source_frame_rate (25); f->set_dcp_frame_rate (24); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 50000); - f->set_source_frame_rate (25); +// f->set_source_frame_rate (25); f->set_dcp_frame_rate (24); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 44100, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 44100, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 50000); /* Check some out-there conversions (not the best) */ - f->set_source_frame_rate (14.99); +// f->set_source_frame_rate (14.99); f->set_dcp_frame_rate (25); - f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 16000, 0))); +// f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 16000, 0))); /* The FrameRateConversion within target_audio_sample_rate should choose to double-up the 14.99 fps video to 30 and then run it slow at 25. */ -- cgit v1.2.3 From a054c067ab2cbf6c5abc5df4caa08ffaac206f0b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 31 Mar 2013 16:04:10 +0100 Subject: Content can be added and previewed. --- src/lib/ab_transcode_job.cc | 6 +- src/lib/ab_transcode_job.h | 5 +- src/lib/ab_transcoder.cc | 3 +- src/lib/ab_transcoder.h | 1 - src/lib/analyse_audio_job.cc | 1 - src/lib/audio_decoder.cc | 4 +- src/lib/audio_decoder.h | 2 +- src/lib/dcp_video_frame.cc | 1 - src/lib/decoder.cc | 4 +- src/lib/decoder.h | 5 +- src/lib/decoder_factory.cc | 2 +- src/lib/decoder_factory.h | 4 +- src/lib/encoder.cc | 1 - src/lib/examine_content_job.cc | 1 - src/lib/ffmpeg_content.cc | 5 +- src/lib/ffmpeg_decoder.cc | 31 ++++---- src/lib/ffmpeg_decoder.h | 7 +- src/lib/film.cc | 8 +- src/lib/imagemagick_decoder.cc | 7 +- src/lib/imagemagick_decoder.h | 2 +- src/lib/options.h | 43 ----------- src/lib/playlist.cc | 172 ++++++++++++++++++++++++++++++++--------- src/lib/playlist.h | 12 +++ src/lib/sndfile_decoder.cc | 6 +- src/lib/sndfile_decoder.h | 2 +- src/lib/transcode_job.cc | 6 +- src/lib/transcode_job.h | 6 +- src/lib/transcoder.cc | 4 +- src/lib/transcoder.h | 3 - src/lib/video_decoder.cc | 5 +- src/lib/video_decoder.h | 2 +- src/tools/servomatictest.cc | 11 ++- src/wx/film_editor.cc | 1 + src/wx/film_viewer.cc | 63 +++++++-------- src/wx/film_viewer.h | 2 +- 35 files changed, 232 insertions(+), 206 deletions(-) delete mode 100644 src/lib/options.h (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcode_job.cc b/src/lib/ab_transcode_job.cc index f17d43916..2bdff47de 100644 --- a/src/lib/ab_transcode_job.cc +++ b/src/lib/ab_transcode_job.cc @@ -32,11 +32,9 @@ using std::string; using boost::shared_ptr; /** @param f Film to compare. - * @param o Decode options. */ -ABTranscodeJob::ABTranscodeJob (shared_ptr f, DecodeOptions o) +ABTranscodeJob::ABTranscodeJob (shared_ptr f) : Job (f) - , _decode_opt (o) { _film_b.reset (new Film (*_film)); _film_b->set_scaler (Config::instance()->reference_scaler ()); @@ -54,7 +52,7 @@ ABTranscodeJob::run () { try { /* _film_b is the one with reference filters */ - ABTranscoder w (_film_b, _film, _decode_opt, shared_from_this ()); + ABTranscoder w (_film_b, _film, shared_from_this ()); w.go (); set_progress (1); set_state (FINISHED_OK); diff --git a/src/lib/ab_transcode_job.h b/src/lib/ab_transcode_job.h index 5d029a18b..cd82d4247 100644 --- a/src/lib/ab_transcode_job.h +++ b/src/lib/ab_transcode_job.h @@ -23,7 +23,6 @@ #include #include "job.h" -#include "options.h" class Film; @@ -38,8 +37,7 @@ class ABTranscodeJob : public Job { public: ABTranscodeJob ( - boost::shared_ptr f, - DecodeOptions o + boost::shared_ptr f ); std::string name () const; @@ -48,5 +46,4 @@ public: private: /** Copy of our Film using the reference filters and scaler */ boost::shared_ptr _film_b; - DecodeOptions _decode_opt; }; diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 0c687008d..6fc438ee8 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -23,7 +23,6 @@ #include "film.h" #include "encoder.h" #include "job.h" -#include "options.h" #include "image.h" #include "playlist.h" #include "matcher.h" @@ -47,7 +46,7 @@ using boost::dynamic_pointer_cast; * @param e Encoder to use. */ -ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, DecodeOptions o, shared_ptr j) +ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptr j) : _film_a (a) , _film_b (b) , _playlist_a (_film_a->playlist ()) diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 14277c562..090c26fb7 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -48,7 +48,6 @@ public: ABTranscoder ( boost::shared_ptr a, boost::shared_ptr b, - DecodeOptions o, boost::shared_ptr j ); diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 74491943b..6e6dda886 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -21,7 +21,6 @@ #include "analyse_audio_job.h" #include "compose.hpp" #include "film.h" -#include "options.h" #include "playlist.h" #include "i18n.h" diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index a72cf11bb..e2006a795 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -22,8 +22,8 @@ using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) - : Decoder (f, o) +AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) + : Decoder (f) { } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 7d2a2bb62..cbb84b52d 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -35,7 +35,7 @@ class AudioContent; class AudioDecoder : public AudioSource, public virtual Decoder { public: - AudioDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); + AudioDecoder (boost::shared_ptr, boost::shared_ptr); }; #endif diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index d674393a9..e9499871a 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -47,7 +47,6 @@ #include "dcp_video_frame.h" #include "lut.h" #include "config.h" -#include "options.h" #include "exceptions.h" #include "server.h" #include "util.h" diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 2fe265c14..c40446919 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -23,7 +23,6 @@ #include #include "film.h" -#include "options.h" #include "exceptions.h" #include "util.h" #include "decoder.h" @@ -36,9 +35,8 @@ using boost::shared_ptr; /** @param f Film. * @param o Decode options. */ -Decoder::Decoder (shared_ptr f, DecodeOptions o) +Decoder::Decoder (shared_ptr f) : _film (f) - , _opt (o) { _film_connection = f->Changed.connect (bind (&Decoder::film_changed, this, _1)); } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 50aa16dba..4ccdc046f 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -33,7 +33,6 @@ #include "video_source.h" #include "audio_source.h" #include "film.h" -#include "options.h" class Image; class Log; @@ -52,7 +51,7 @@ class FilterGraph; class Decoder { public: - Decoder (boost::shared_ptr, DecodeOptions); + Decoder (boost::shared_ptr); virtual ~Decoder () {} virtual bool pass () = 0; @@ -63,8 +62,6 @@ public: protected: boost::shared_ptr _film; - /** our decode options */ - DecodeOptions _opt; private: virtual void film_changed (Film::Property) {} diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index feaa1c7ef..7940edc2e 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -36,7 +36,7 @@ using boost::dynamic_pointer_cast; Decoders decoder_factory ( - shared_ptr f, DecodeOptions o + shared_ptr f ) { return Decoders (); diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h index 8076b01c7..3fd91f876 100644 --- a/src/lib/decoder_factory.h +++ b/src/lib/decoder_factory.h @@ -24,8 +24,6 @@ * @brief A method to create appropriate decoders for some content. */ -#include "options.h" - class Film; class VideoDecoder; class AudioDecoder; @@ -43,7 +41,7 @@ struct Decoders { }; extern Decoders decoder_factory ( - boost::shared_ptr, DecodeOptions + boost::shared_ptr ); #endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 970213793..00807f863 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -27,7 +27,6 @@ #include #include "encoder.h" #include "util.h" -#include "options.h" #include "film.h" #include "log.h" #include "exceptions.h" diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index c600132c3..aad7f265e 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -19,7 +19,6 @@ #include #include "examine_content_job.h" -#include "options.h" #include "log.h" #include "content.h" diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 25efb1ebf..6109b7212 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -1,6 +1,5 @@ #include "ffmpeg_content.h" #include "ffmpeg_decoder.h" -#include "options.h" #include "compose.hpp" #include "job.h" #include "util.h" @@ -33,9 +32,7 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) job->set_progress_unknown (); - DecodeOptions o; - o.decode_audio = false; - shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), o)); + shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false, false, true)); ContentVideoFrame video_length = 0; if (quick) { diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index c8e46776f..7b56a5971 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -41,7 +41,6 @@ extern "C" { #include "transcoder.h" #include "job.h" #include "filter.h" -#include "options.h" #include "exceptions.h" #include "image.h" #include "util.h" @@ -62,10 +61,10 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; -FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) - : Decoder (f, o) - , VideoDecoder (f, c, o) - , AudioDecoder (f, c, o) +FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) + : Decoder (f) + , VideoDecoder (f, c) + , AudioDecoder (f, c) , _ffmpeg_content (c) , _format_context (0) , _video_stream (-1) @@ -76,13 +75,17 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr= 0 && frame_finished) { filter_and_emit_video (_frame); } } - if (_ffmpeg_content->audio_stream() && _opt.decode_audio) { + if (_ffmpeg_content->audio_stream() && _decode_audio) { decode_audio_packet (); } @@ -245,7 +248,7 @@ FFmpegDecoder::pass () avcodec_get_frame_defaults (_frame); - if (_packet.stream_index == _video_stream && _opt.decode_video) { + if (_packet.stream_index == _video_stream && _decode_video) { int frame_finished; int const r = avcodec_decode_video2 (_video_codec_context, _frame, &frame_finished, &_packet); @@ -255,16 +258,16 @@ FFmpegDecoder::pass () _film->log()->log (String::compose (N_("Used only %1 bytes of %2 in packet"), r, _packet.size)); } - if (_opt.video_sync) { + if (_video_sync) { out_with_sync (); } else { filter_and_emit_video (_frame); } } - } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _opt.decode_audio) { + } else if (_ffmpeg_content->audio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _decode_audio) { decode_audio_packet (); - } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && _opt.decode_subtitles && _first_video) { + } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && _decode_subtitles && _first_video) { int got_subtitle; AVSubtitle sub; @@ -633,9 +636,9 @@ FFmpegDecoder::decode_audio_packet () was before this packet. Until then audio is thrown away. */ - if ((_first_video && _first_video.get() <= source_pts_seconds) || !_opt.decode_video) { + if ((_first_video && _first_video.get() <= source_pts_seconds) || !_decode_video) { - if (!_first_audio && _opt.decode_video) { + if (!_first_audio && _decode_video) { _first_audio = source_pts_seconds; /* This is our first audio frame, and if we've arrived here we must have had our diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index a0900d89f..ef66f09d9 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -57,7 +57,7 @@ class Log; class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: - FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); + FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio, bool subtitles, bool video_sync); ~FFmpegDecoder (); float frames_per_second () const; @@ -129,4 +129,9 @@ private: std::vector _subtitle_streams; std::vector _audio_streams; + + bool _decode_video; + bool _decode_audio; + bool _decode_subtitles; + bool _video_sync; }; diff --git a/src/lib/film.cc b/src/lib/film.cc index f69f63fd8..0e57cf8eb 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -40,7 +40,6 @@ #include "transcode_job.h" #include "scp_dcp_job.h" #include "log.h" -#include "options.h" #include "exceptions.h" #include "examine_content_job.h" #include "scaler.h" @@ -296,15 +295,12 @@ Film::make_dcp () throw MissingSettingError (_("name")); } - DecodeOptions od; - od.decode_subtitles = with_subtitles (); - shared_ptr r; if (dcp_ab()) { - r = JobManager::instance()->add (shared_ptr (new ABTranscodeJob (shared_from_this(), od))); + r = JobManager::instance()->add (shared_ptr (new ABTranscodeJob (shared_from_this()))); } else { - r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this(), od))); + r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this()))); } } diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index aa3c64f93..c3723f610 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -32,10 +32,9 @@ using std::cout; using boost::shared_ptr; using libdcp::Size; -ImageMagickDecoder::ImageMagickDecoder ( - shared_ptr f, shared_ptr c, DecodeOptions o) - : Decoder (f, o) - , VideoDecoder (f, c, o) +ImageMagickDecoder::ImageMagickDecoder (shared_ptr f, shared_ptr c) + : Decoder (f) + , VideoDecoder (f, c) , _imagemagick_content (c) , _position (0) { diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index b04bd88b1..a26e283c0 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -28,7 +28,7 @@ class ImageMagickContent; class ImageMagickDecoder : public VideoDecoder { public: - ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); + ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr); float frames_per_second () const { /* We don't know */ diff --git a/src/lib/options.h b/src/lib/options.h deleted file mode 100644 index 0d2c07fd5..000000000 --- a/src/lib/options.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - 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_OPTIONS_H -#define DVDOMATIC_OPTIONS_H - -/** @file src/options.h - * @brief Options for a decoding operation. - */ - -class DecodeOptions -{ -public: - DecodeOptions () - : decode_video (true) - , decode_audio (true) - , decode_subtitles (false) - , video_sync (true) - {} - - bool decode_video; - bool decode_audio; - bool decode_subtitles; - bool video_sync; -}; - -#endif diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 17ecd2f37..fc9edac48 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -31,9 +31,12 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; Playlist::Playlist (shared_ptr f, list > c) - : _video_from (VIDEO_NONE) + : _film (f) + , _video_from (VIDEO_NONE) , _audio_from (AUDIO_NONE) + , _have_setup_decoders (false) , _ffmpeg_decoder_done (false) + , _video_sync (true) { for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { shared_ptr fc = dynamic_pointer_cast (*i); @@ -60,42 +63,6 @@ Playlist::Playlist (shared_ptr f, list > c) _audio_from = AUDIO_SNDFILE; } } - - if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { - DecodeOptions o; - /* XXX: decodeoptions */ - _ffmpeg_decoder.reset (new FFmpegDecoder (f, _ffmpeg, o)); - } - - if (_video_from == VIDEO_FFMPEG) { - _ffmpeg_decoder->connect_video (shared_from_this ()); - } - - if (_audio_from == AUDIO_FFMPEG) { - _ffmpeg_decoder->connect_audio (shared_from_this ()); - } - - if (_video_from == VIDEO_IMAGEMAGICK) { - for (list >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { - DecodeOptions o; - /* XXX: decodeoptions */ - shared_ptr d (new ImageMagickDecoder (f, *i, o)); - _imagemagick_decoders.push_back (d); - d->connect_video (shared_from_this ()); - } - - _imagemagick_decoder = _imagemagick_decoders.begin (); - } - - if (_audio_from == AUDIO_SNDFILE) { - for (list >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { - DecodeOptions o; - /* XXX: decodeoptions */ - shared_ptr d (new SndfileDecoder (f, *i, o)); - _sndfile_decoders.push_back (d); - d->connect_audio (shared_from_this ()); - } - } } ContentAudioFrame @@ -202,6 +169,27 @@ Playlist::video_size () const return libdcp::Size (); } +ContentVideoFrame +Playlist::video_length () const +{ + switch (_video_from) { + case VIDEO_NONE: + return 0; + case VIDEO_FFMPEG: + return _ffmpeg->video_length (); + case VIDEO_IMAGEMAGICK: + { + ContentVideoFrame l = 0; + for (list >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + l += (*i)->video_length (); + } + return l; + } + } + + return 0; +} + bool Playlist::has_audio () const { @@ -214,9 +202,26 @@ Playlist::disable_video () _video_from = VIDEO_NONE; } +void +Playlist::disable_audio () +{ + _audio_from = AUDIO_NONE; +} + +void +Playlist::disable_subtitles () +{ + /* XXX */ +} + bool Playlist::pass () { + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + bool done = true; if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { @@ -264,3 +269,96 @@ Playlist::process_audio (shared_ptr b) Audio (b); } +bool +Playlist::seek (double t) +{ + bool r = false; + + switch (_video_from) { + case VIDEO_NONE: + break; + case VIDEO_FFMPEG: + if (_ffmpeg_decoder->seek (t)) { + r = true; + } + break; + case VIDEO_IMAGEMAGICK: + if ((*_imagemagick_decoder)->seek (t)) { + r = true; + } + break; + } + + /* XXX: don't seek audio because we don't need to... */ + + return r; +} + +bool +Playlist::seek_to_last () +{ + bool r = false; + + switch (_video_from) { + case VIDEO_NONE: + break; + case VIDEO_FFMPEG: + if (_ffmpeg_decoder->seek_to_last ()) { + r = true; + } + break; + case VIDEO_IMAGEMAGICK: + if ((*_imagemagick_decoder)->seek_to_last ()) { + r = true; + } + break; + } + + /* XXX: don't seek audio because we don't need to... */ + + return r; +} + +void +Playlist::setup_decoders () +{ + if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + _ffmpeg_decoder.reset ( + new FFmpegDecoder ( + _film, _ffmpeg, _video_from == VIDEO_FFMPEG, _audio_from == AUDIO_FFMPEG, _film->with_subtitles(), _video_sync + ) + ); + } + + if (_video_from == VIDEO_FFMPEG) { + _ffmpeg_decoder->connect_video (shared_from_this ()); + } + + if (_audio_from == AUDIO_FFMPEG) { + _ffmpeg_decoder->connect_audio (shared_from_this ()); + } + + if (_video_from == VIDEO_IMAGEMAGICK) { + for (list >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + shared_ptr d (new ImageMagickDecoder (_film, *i)); + _imagemagick_decoders.push_back (d); + d->connect_video (shared_from_this ()); + } + + _imagemagick_decoder = _imagemagick_decoders.begin (); + } + + if (_audio_from == AUDIO_SNDFILE) { + for (list >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + shared_ptr d (new SndfileDecoder (_film, *i)); + _sndfile_decoders.push_back (d); + d->connect_audio (shared_from_this ()); + } + } +} + +void +Playlist::disable_video_sync () +{ + _video_sync = false; +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index b42d46036..d374dc98c 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -48,16 +48,25 @@ public: float video_frame_rate () const; libdcp::Size video_size () const; + ContentVideoFrame video_length () const; void disable_video (); + void disable_audio (); + void disable_subtitles (); + void disable_video_sync (); bool pass (); void set_progress (boost::shared_ptr); + bool seek (double); + bool seek_to_last (); private: void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); void process_audio (boost::shared_ptr); + void setup_decoders (); + boost::shared_ptr _film; + enum { VIDEO_NONE, VIDEO_FFMPEG, @@ -74,9 +83,12 @@ private: std::list > _imagemagick; std::list > _sndfile; + bool _have_setup_decoders; boost::shared_ptr _ffmpeg_decoder; bool _ffmpeg_decoder_done; std::list > _imagemagick_decoders; std::list >::iterator _imagemagick_decoder; std::list > _sndfile_decoders; + + bool _video_sync; }; diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index 8848ff4f8..daa363c5e 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -36,9 +36,9 @@ using boost::optional; /* XXX */ -SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) - : Decoder (f, o) - , AudioDecoder (f, c, o) +SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) + : Decoder (f) + , AudioDecoder (f, c) { sf_count_t frames; SNDFILE* sf = open_file (frames); diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index c06b97a60..9a3ef49b0 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -26,7 +26,7 @@ class SndfileContent; class SndfileDecoder : public AudioDecoder { public: - SndfileDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); + SndfileDecoder (boost::shared_ptr, boost::shared_ptr); bool pass (); diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index f8810975b..8b74f7766 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -39,11 +39,9 @@ using std::setprecision; using boost::shared_ptr; /** @param s Film to use. - * @param o Decode options. */ -TranscodeJob::TranscodeJob (shared_ptr f, DecodeOptions o) +TranscodeJob::TranscodeJob (shared_ptr f) : Job (f) - , _decode_opt (o) { } @@ -62,7 +60,7 @@ TranscodeJob::run () _film->log()->log (N_("Transcode job starting")); _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); - Transcoder w (_film, _decode_opt, shared_from_this ()); + Transcoder w (_film, shared_from_this ()); w.go (); set_progress (1); set_state (FINISHED_OK); diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index a409ec97e..def545958 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -23,7 +23,6 @@ #include #include "job.h" -#include "options.h" class Encoder; @@ -33,7 +32,7 @@ class Encoder; class TranscodeJob : public Job { public: - TranscodeJob (boost::shared_ptr f, DecodeOptions od); + TranscodeJob (boost::shared_ptr f); std::string name () const; void run (); @@ -41,7 +40,4 @@ public: protected: int remaining_time () const; - -private: - DecodeOptions _decode_opt; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 19d067149..070258008 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -32,7 +32,6 @@ #include "film.h" #include "matcher.h" #include "delay_line.h" -#include "options.h" #include "gain.h" #include "video_decoder.h" #include "audio_decoder.h" @@ -44,11 +43,10 @@ using boost::dynamic_pointer_cast; /** Construct a transcoder using a Decoder that we create and a supplied Encoder. * @param f Film that we are transcoding. - * @param o Decode options. * @param j Job that we are running under, or 0. * @param e Encoder to use. */ -Transcoder::Transcoder (shared_ptr f, DecodeOptions o, shared_ptr j) +Transcoder::Transcoder (shared_ptr f, shared_ptr j) : _job (j) , _playlist (f->playlist ()) , _encoder (new Encoder (f, _playlist)) diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 8d34af948..3c47b0c7e 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -18,7 +18,6 @@ */ /** @file src/transcoder.h - * @brief A class which takes a Film and some Options, then uses those to transcode the film. * * A decoder is selected according to the content type, and the encoder can be specified * as a parameter to the constructor. @@ -36,7 +35,6 @@ class DelayLine; class Playlist; /** @class Transcoder - * @brief A class which takes a Film and some Options, then uses those to transcode the film. * * A decoder is selected according to the content type, and the encoder can be specified * as a parameter to the constructor. @@ -46,7 +44,6 @@ class Transcoder public: Transcoder ( boost::shared_ptr f, - DecodeOptions o, boost::shared_ptr j ); diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index ca1e7ab56..33dd433ea 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -22,7 +22,6 @@ #include "film.h" #include "image.h" #include "log.h" -#include "options.h" #include "job.h" #include "i18n.h" @@ -30,8 +29,8 @@ using boost::shared_ptr; using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c, DecodeOptions o) - : Decoder (f, o) +VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c) + : Decoder (f) , _video_frame (0) , _last_source_time (0) { diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index a52e5448a..03dc4777a 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -28,7 +28,7 @@ class VideoContent; class VideoDecoder : public VideoSource, public virtual Decoder { public: - VideoDecoder (boost::shared_ptr, boost::shared_ptr, DecodeOptions); + VideoDecoder (boost::shared_ptr, boost::shared_ptr); /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index f5756c693..d08fefa90 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -28,7 +28,6 @@ #include "scaler.h" #include "server.h" #include "dcp_video_frame.h" -#include "options.h" #include "decoder.h" #include "exceptions.h" #include "scaler.h" @@ -151,12 +150,12 @@ main (int argc, char* argv[]) server = new ServerDescription (server_host, 1); shared_ptr film (new Film (film_dir, true)); - DecodeOptions opt; - opt.decode_audio = false; - opt.decode_subtitles = true; - opt.video_sync = true; + /* XXX */ +// opt.decode_audio = false; +// opt.decode_subtitles = true; +// opt.video_sync = true; - Decoders decoders = decoder_factory (film, opt); + Decoders decoders = decoder_factory (film); try { decoders.video->Video.connect (boost::bind (process_video, _1, _2, _3)); bool done = false; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index ce1c1abe8..f9a91f8fa 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -347,6 +347,7 @@ FilmEditor::make_content_panel () s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); _content->InsertColumn (0, ""); + _content->SetColumnWidth (0, 512); wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); _content_add = new wxButton (_content_panel, wxID_ANY, _("Add...")); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 1e2a74be9..42af4b3c0 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -28,13 +28,13 @@ #include "lib/format.h" #include "lib/util.h" #include "lib/job_manager.h" -#include "lib/options.h" #include "lib/subtitle.h" #include "lib/image.h" #include "lib/scaler.h" #include "lib/exceptions.h" #include "lib/examine_content_job.h" #include "lib/filter.h" +#include "lib/playlist.h" #include "film_viewer.h" #include "wx_util.h" #include "video_decoder.h" @@ -97,24 +97,13 @@ FilmViewer::film_changed (Film::Property p) break; case Film::CONTENT: { - DecodeOptions o; - o.decode_audio = false; - o.decode_subtitles = true; - o.video_sync = false; - - try { - _decoders = decoder_factory (_film, o); - } catch (StringError& e) { - error_dialog (this, wxString::Format (_("Could not open content file (%s)"), std_to_wx(e.what()).data())); - return; - } - - if (_decoders.video == 0) { - break; - } - _decoders.video->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); - _decoders.video->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); -// _decoders.video->set_subtitle_stream (_film->subtitle_stream()); + _playlist = _film->playlist (); + _playlist->disable_audio (); + _playlist->disable_subtitles (); + _playlist->disable_video_sync (); + + _playlist->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); +// _playlist->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); calculate_sizes (); get_frame (); _panel->Refresh (); @@ -129,9 +118,9 @@ FilmViewer::film_changed (Film::Property p) update_from_raw (); break; case Film::SUBTITLE_STREAM: - if (_decoders.video) { +// if (_decoders.video) { // _decoders.video->set_subtitle_stream (_film->subtitle_stream ()); - } +// } break; default: break; @@ -164,7 +153,7 @@ FilmViewer::set_film (shared_ptr f) void FilmViewer::decoder_changed () { - if (_decoders.video == 0 || _decoders.video->seek_to_last ()) { + if (!_playlist == 0 || _playlist->seek_to_last ()) { return; } @@ -176,7 +165,7 @@ FilmViewer::decoder_changed () void FilmViewer::timer (wxTimerEvent &) { - if (!_film || !_decoders.video) { + if (!_playlist) { return; } @@ -185,8 +174,8 @@ FilmViewer::timer (wxTimerEvent &) get_frame (); -// if (_film->length()) { -// int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate()); +// if (_playlist->video_length()) { +// int const new_slider_position = 4096 * _playlist->last_source_time() / (_film->length().get() / _film->source_frame_rate()); // if (new_slider_position != _slider->GetValue()) { // _slider->SetValue (new_slider_position); // } @@ -231,13 +220,13 @@ FilmViewer::paint_panel (wxPaintEvent &) void FilmViewer::slider_moved (wxScrollEvent &) { -// if (!_film || !_film->length() || !_decoders.video) { -// return; -// } + if (!_film || !_playlist) { + return; + } -// if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) { -// return; -// } + if (_playlist->seek (_slider->GetValue() * _playlist->video_length() / (4096 * _playlist->video_frame_rate()))) { + return; + } get_frame (); _panel->Refresh (); @@ -319,7 +308,7 @@ FilmViewer::raw_to_display () void FilmViewer::calculate_sizes () { - if (!_film) { + if (!_film || !_playlist) { return; } @@ -342,9 +331,9 @@ FilmViewer::calculate_sizes () of our _display_frame. */ _display_frame_x = 0; -// if (format) { -// _display_frame_x = static_cast (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width; -// } + if (format) { + _display_frame_x = static_cast (format->dcp_padding (_playlist)) * _out_size.width / format->dcp_size().width; + } _film_size = _out_size; _film_size.width -= _display_frame_x * 2; @@ -392,7 +381,7 @@ FilmViewer::get_frame () /* Clear our raw frame in case we don't get a new one */ _raw_frame.reset (); - if (_decoders.video == 0) { + if (!_playlist) { _display_frame.reset (); return; } @@ -400,7 +389,7 @@ FilmViewer::get_frame () try { _got_frame = false; while (!_got_frame) { - if (_decoders.video->pass ()) { + if (_playlist->pass ()) { /* We didn't get a frame before the decoder gave up, so clear our display frame. */ diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 456301eb4..b552a3dbc 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -58,6 +58,7 @@ private: void active_jobs_changed (bool); boost::shared_ptr _film; + boost::shared_ptr _playlist; wxSizer* _v_sizer; wxPanel* _panel; @@ -65,7 +66,6 @@ private: wxToggleButton* _play_button; wxTimer _timer; - Decoders _decoders; boost::shared_ptr _raw_frame; boost::shared_ptr _raw_sub; boost::shared_ptr _display_frame; -- cgit v1.2.3 From db468a15e50c8491d4b8462ad0676be905f49065 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2013 22:49:31 +0100 Subject: Various bits. --- src/lib/ab_transcoder.cc | 24 ++++---- src/lib/ab_transcoder.h | 6 +- src/lib/analyse_audio_job.cc | 16 +++--- src/lib/audio_decoder.cc | 2 +- src/lib/audio_decoder.h | 2 +- src/lib/encoder.cc | 31 +++++------ src/lib/encoder.h | 4 +- src/lib/ffmpeg_decoder.cc | 6 +- src/lib/ffmpeg_decoder.h | 4 +- src/lib/film.cc | 73 ++++++++++++++++++++---- src/lib/film.h | 15 ++++- src/lib/format.cc | 12 ++-- src/lib/format.h | 16 +++--- src/lib/imagemagick_decoder.cc | 4 +- src/lib/imagemagick_decoder.h | 4 +- src/lib/playlist.cc | 124 +++++++++++++++++++++++++++-------------- src/lib/playlist.h | 77 ++++++++++++++++++------- src/lib/sndfile_decoder.cc | 4 +- src/lib/sndfile_decoder.h | 4 +- src/lib/transcoder.cc | 22 ++++---- src/lib/transcoder.h | 4 +- src/lib/video_decoder.cc | 9 +-- src/lib/video_decoder.h | 2 +- src/lib/writer.cc | 7 +-- src/lib/writer.h | 4 +- src/tools/servomatictest.cc | 8 +-- src/wx/audio_dialog.cc | 11 ++-- src/wx/audio_dialog.h | 2 - src/wx/film_viewer.cc | 40 ++++++------- src/wx/film_viewer.h | 2 +- wscript | 3 + 31 files changed, 336 insertions(+), 206 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 6fc438ee8..6bf092fee 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -49,20 +49,20 @@ using boost::dynamic_pointer_cast; ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptr j) : _film_a (a) , _film_b (b) - , _playlist_a (_film_a->playlist ()) - , _playlist_b (_film_b->playlist ()) + , _player_a (_film_a->player ()) + , _player_b (_film_b->player ()) , _job (j) - , _encoder (new Encoder (_film_a, _playlist_a)) + , _encoder (new Encoder (_film_a)) , _combiner (new Combiner (a->log())) { - if (_playlist_a->has_audio ()) { - _matcher.reset (new Matcher (_film_a->log(), _playlist_a->audio_frame_rate(), _playlist_a->video_frame_rate())); - _delay_line.reset (new DelayLine (_film_a->log(), _playlist_a->audio_channels(), _film_a->audio_delay() * _playlist_a->audio_frame_rate() / 1000)); + if (_film_a->has_audio ()) { + _matcher.reset (new Matcher (_film_a->log(), _film_a->audio_frame_rate(), _film_a->video_frame_rate())); + _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_channels(), _film_a->audio_delay() * _film_a->audio_frame_rate() / 1000)); _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); } - _playlist_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); - _playlist_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); + _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); + _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); if (_matcher) { _combiner->connect_video (_matcher); @@ -72,7 +72,7 @@ ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptrconnect_audio (_delay_line); + _player_a->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); @@ -87,11 +87,11 @@ ABTranscoder::go () bool done[2] = { false, false }; while (1) { - done[0] = _playlist_a->pass (); - done[1] = _playlist_b->pass (); + done[0] = _player_a->pass (); + done[1] = _player_b->pass (); if (_job) { - _playlist_a->set_progress (_job); + _player_a->set_progress (_job); } if (done[0] && done[1]) { diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 5ce4a03da..b1b01d724 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -35,7 +35,7 @@ class Matcher; class DelayLine; class Gain; class Combiner; -class Playlist; +class Player; /** @class ABTranscoder * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -55,8 +55,8 @@ public: private: boost::shared_ptr _film_a; boost::shared_ptr _film_b; - boost::shared_ptr _playlist_a; - boost::shared_ptr _playlist_b; + boost::shared_ptr _player_a; + boost::shared_ptr _player_b; boost::shared_ptr _job; boost::shared_ptr _encoder; boost::shared_ptr _combiner; diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 6e6dda886..e2c9c5b18 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -50,18 +50,18 @@ AnalyseAudioJob::name () const void AnalyseAudioJob::run () { - shared_ptr playlist = _film->playlist (); - playlist->disable_video (); + shared_ptr player = _film->player (); + player->disable_video (); - playlist->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); + player->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); - _samples_per_point = max (int64_t (1), playlist->audio_length() / _num_points); + _samples_per_point = max (int64_t (1), _film->audio_length() / _num_points); - _current.resize (playlist->audio_channels ()); - _analysis.reset (new AudioAnalysis (playlist->audio_channels())); + _current.resize (_film->audio_channels ()); + _analysis.reset (new AudioAnalysis (_film->audio_channels())); - while (!playlist->pass()) { - set_progress (float (_done) / playlist->audio_length ()); + while (!player->pass()) { + set_progress (float (_done) / _film->audio_length ()); } _analysis->write (_film->audio_analysis_path ()); diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index e2006a795..df13a984a 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -22,7 +22,7 @@ using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) +AudioDecoder::AudioDecoder (shared_ptr f) : Decoder (f) { diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index cbb84b52d..24e2796ae 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -35,7 +35,7 @@ class AudioContent; class AudioDecoder : public AudioSource, public virtual Decoder { public: - AudioDecoder (boost::shared_ptr, boost::shared_ptr); + AudioDecoder (boost::shared_ptr); }; #endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 00807f863..5c3e56709 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -53,9 +53,8 @@ using namespace boost; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f, shared_ptr p) +Encoder::Encoder (shared_ptr f) : _film (f) - , _playlist (p) , _video_frames_in (0) , _video_frames_out (0) #ifdef HAVE_SWRESAMPLE @@ -78,22 +77,22 @@ Encoder::~Encoder () void Encoder::process_begin () { - if (_playlist->has_audio() && _playlist->audio_frame_rate() != _film->target_audio_sample_rate()) { + if (_film->has_audio() && _film->audio_frame_rate() != _film->target_audio_sample_rate()) { #ifdef HAVE_SWRESAMPLE stringstream s; - s << String::compose (N_("Will resample audio from %1 to %2"), _playlist->audio_frame_rate(), _film->target_audio_sample_rate()); + s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_frame_rate(), _film->target_audio_sample_rate()); _film->log()->log (s.str ()); /* We will be using planar float data when we call the resampler */ _swr_context = swr_alloc_set_opts ( 0, - _playlist->audio_channel_layout(), + _film->audio_channel_layout(), AV_SAMPLE_FMT_FLTP, _film->target_audio_sample_rate(), - _playlist->audio_channel_layout(), + _film->audio_channel_layout(), AV_SAMPLE_FMT_FLTP, - _playlist->audio_frame_rate(), + _film->audio_frame_rate(), 0, 0 ); @@ -119,7 +118,7 @@ Encoder::process_begin () } } - _writer.reset (new Writer (_film, _playlist)); + _writer.reset (new Writer (_film)); } @@ -127,9 +126,9 @@ void Encoder::process_end () { #if HAVE_SWRESAMPLE - if (_playlist->has_audio() && _playlist->audio_channels() && _swr_context) { + if (_film->has_audio() && _film->audio_channels() && _swr_context) { - shared_ptr out (new AudioBuffers (_playlist->audio_channels(), 256)); + shared_ptr out (new AudioBuffers (_film->audio_channels(), 256)); while (1) { int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); @@ -234,7 +233,7 @@ Encoder::frame_done () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - FrameRateConversion frc (_playlist->video_frame_rate(), _film->dcp_frame_rate()); + FrameRateConversion frc (_film->video_frame_rate(), _film->dcp_frame_rate()); if (frc.skip && (_video_frames_in % 2)) { ++_video_frames_in; @@ -272,7 +271,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr ( new DCPVideoFrame ( - image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_playlist), + image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), @@ -302,9 +301,9 @@ Encoder::process_audio (shared_ptr data) if (_swr_context) { /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _playlist->audio_frame_rate()) + 32; + int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_frame_rate()) + 32; - shared_ptr resampled (new AudioBuffers (_playlist->audio_channels(), max_resampled_frames)); + shared_ptr resampled (new AudioBuffers (_film->audio_channels(), max_resampled_frames)); /* Resample audio */ int const resampled_frames = swr_convert ( @@ -426,8 +425,8 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { - AudioMapping m (_playlist->audio_channels ()); - if (m.dcp_channels() != _playlist->audio_channels()) { + AudioMapping m (_film->audio_channels ()); + if (m.dcp_channels() != _film->audio_channels()) { /* Remap (currently just for mono -> 5.1) */ diff --git a/src/lib/encoder.h b/src/lib/encoder.h index c84ee027a..86880bc34 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -51,7 +51,6 @@ class ServerDescription; class DCPVideoFrame; class EncodedData; class Writer; -class Playlist; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -63,7 +62,7 @@ class Playlist; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f, boost::shared_ptr); + Encoder (boost::shared_ptr f); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ @@ -96,7 +95,6 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; - boost::shared_ptr _playlist; /** Mutex for _time_history and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 7b56a5971..25ca9bb88 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,10 +61,10 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; -FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) +FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) : Decoder (f) - , VideoDecoder (f, c) - , AudioDecoder (f, c) + , VideoDecoder (f) + , AudioDecoder (f) , _ffmpeg_content (c) , _format_context (0) , _video_stream (-1) diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index ef66f09d9..71ecf7906 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -57,7 +57,7 @@ class Log; class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: - FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio, bool subtitles, bool video_sync); + FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio, bool subtitles, bool video_sync); ~FFmpegDecoder (); float frames_per_second () const; @@ -105,7 +105,7 @@ private: std::string stream_name (AVStream* s) const; - boost::shared_ptr _ffmpeg_content; + boost::shared_ptr _ffmpeg_content; AVFormatContext* _format_context; int _video_stream; diff --git a/src/lib/film.cc b/src/lib/film.cc index f2c7a654a..fe16a65fa 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -91,7 +91,8 @@ int const Film::state_version = 4; */ Film::Film (string d, bool must_exist) - : _use_dci_name (true) + : _playlist (new Playlist) + , _use_dci_name (true) , _trust_content_headers (true) , _dcp_content_type (0) , _format (0) @@ -151,6 +152,7 @@ Film::Film (Film const & o) : boost::enable_shared_from_this (o) /* note: the copied film shares the original's log */ , _log (o._log) + , _playlist (new Playlist) , _directory (o._directory) , _name (o._name) , _use_dci_name (o._use_dci_name) @@ -175,7 +177,7 @@ Film::Film (Film const & o) , _dcp_frame_rate (o._dcp_frame_rate) , _dirty (o._dirty) { - + _playlist->setup (_content); } Film::~Film () @@ -554,17 +556,14 @@ Film::file (string f) const int Film::target_audio_sample_rate () const { - /* XXX: how often is this method called? */ - - boost::shared_ptr p = playlist (); - if (p->has_audio ()) { + if (has_audio ()) { return 0; } /* Resample to a DCI-approved sample rate */ - double t = dcp_audio_sample_rate (p->audio_frame_rate()); + double t = dcp_audio_sample_rate (audio_frame_rate()); - FrameRateConversion frc (p->video_frame_rate(), dcp_frame_rate()); + FrameRateConversion frc (video_frame_rate(), dcp_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -573,7 +572,7 @@ Film::target_audio_sample_rate () const */ if (frc.change_speed) { - t *= p->video_frame_rate() * frc.factor() / dcp_frame_rate(); + t *= video_frame_rate() * frc.factor() / dcp_frame_rate(); } return rint (t); @@ -1023,11 +1022,11 @@ Film::have_dcp () const return true; } -shared_ptr -Film::playlist () const +shared_ptr +Film::player () const { boost::mutex::scoped_lock lm (_state_mutex); - return shared_ptr (new Playlist (shared_from_this (), _content)); + return shared_ptr (new Player (shared_from_this (), _playlist)); } void @@ -1036,9 +1035,59 @@ Film::add_content (shared_ptr c) { boost::mutex::scoped_lock lm (_state_mutex); _content.push_back (c); + _playlist->setup (_content); } signal_changed (CONTENT); examine_content (c); } + +ContentAudioFrame +Film::audio_length () const +{ + return _playlist->audio_length (); +} + +int +Film::audio_channels () const +{ + return _playlist->audio_channels (); +} + +int +Film::audio_frame_rate () const +{ + return _playlist->audio_frame_rate (); +} + +int64_t +Film::audio_channel_layout () const +{ + return _playlist->audio_channel_layout (); +} + +bool +Film::has_audio () const +{ + return _playlist->has_audio (); +} + +float +Film::video_frame_rate () const +{ + return _playlist->video_frame_rate (); +} + +libdcp::Size +Film::video_size () const +{ + return _playlist->video_size (); +} + +ContentVideoFrame +Film::video_length () const +{ + return _playlist->video_length (); +} + diff --git a/src/lib/film.h b/src/lib/film.h index f5f944409..6e097d44e 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -47,6 +47,7 @@ class ExamineContentJob; class AnalyseAudioJob; class ExternalAudioStream; class Content; +class Player; class Playlist; /** @class Film @@ -105,7 +106,17 @@ public: bool have_dcp () const; - boost::shared_ptr playlist () const; + boost::shared_ptr player () const; + + ContentAudioFrame audio_length () const; + int audio_channels () const; + int audio_frame_rate () const; + int64_t audio_channel_layout () const; + bool has_audio () const; + + float video_frame_rate () const; + libdcp::Size video_size () const; + ContentVideoFrame video_length () const; /** Identifiers for the parts of our state; used for signalling changes. @@ -301,6 +312,8 @@ private: void analyse_audio_finished (); std::string video_state_identifier () const; + boost::shared_ptr _playlist; + /** Complete path to directory containing the film metadata; * must not be relative. */ diff --git a/src/lib/format.cc b/src/lib/format.cc index 05b71f2e5..538bf7953 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -207,9 +207,9 @@ FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d * (so there are dcp_padding() pixels on the left and dcp_padding() on the right) */ int -Format::dcp_padding (shared_ptr p) const +Format::dcp_padding (shared_ptr f) const { - int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(p) / 100.0)) / 2.0); + int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(f) / 100.0)) / 2.0); /* This comes out -ve for Scope; bodge it */ if (pad < 0) { @@ -232,15 +232,15 @@ VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d, } int -VariableFormat::ratio_as_integer (shared_ptr p) const +VariableFormat::ratio_as_integer (shared_ptr f) const { - return rint (ratio_as_float (p) * 100); + return rint (ratio_as_float (f) * 100); } float -VariableFormat::ratio_as_float (shared_ptr p) const +VariableFormat::ratio_as_float (shared_ptr f) const { - return float (p->video_size().width) / p->video_size().height; + return float (f->video_size().width) / f->video_size().height; } /** @return A name to be presented to the user */ diff --git a/src/lib/format.h b/src/lib/format.h index 94c2253de..cc7502893 100644 --- a/src/lib/format.h +++ b/src/lib/format.h @@ -26,7 +26,7 @@ #include #include "util.h" -class Playlist; +class Film; class Format { @@ -42,15 +42,15 @@ public: /** @return the aspect ratio multiplied by 100 * (e.g. 239 for Cinemascope 2.39:1) */ - virtual int ratio_as_integer (boost::shared_ptr f) const = 0; + virtual int ratio_as_integer (boost::shared_ptr f) const = 0; /** @return the ratio as a floating point number */ - virtual float ratio_as_float (boost::shared_ptr f) const = 0; + virtual float ratio_as_float (boost::shared_ptr f) const = 0; /** @return the ratio of the container (including any padding) as a floating point number */ float container_ratio_as_float () const; - int dcp_padding (boost::shared_ptr) const; + int dcp_padding (boost::shared_ptr) const; /** @return size in pixels of the images that we should * put in a DCP for this ratio. This size will not correspond @@ -115,11 +115,11 @@ class FixedFormat : public Format public: FixedFormat (int, libdcp::Size, std::string, std::string, std::string, std::string); - int ratio_as_integer (boost::shared_ptr) const { + int ratio_as_integer (boost::shared_ptr) const { return _ratio; } - float ratio_as_float (boost::shared_ptr) const { + float ratio_as_float (boost::shared_ptr) const { return _ratio / 100.0; } @@ -136,8 +136,8 @@ class VariableFormat : public Format public: VariableFormat (libdcp::Size, std::string, std::string, std::string, std::string); - int ratio_as_integer (boost::shared_ptr f) const; - float ratio_as_float (boost::shared_ptr f) const; + int ratio_as_integer (boost::shared_ptr f) const; + float ratio_as_float (boost::shared_ptr f) const; std::string name () const; }; diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index c3723f610..279c8bf32 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -32,9 +32,9 @@ using std::cout; using boost::shared_ptr; using libdcp::Size; -ImageMagickDecoder::ImageMagickDecoder (shared_ptr f, shared_ptr c) +ImageMagickDecoder::ImageMagickDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , VideoDecoder (f, c) + , VideoDecoder (f) , _imagemagick_content (c) , _position (0) { diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index a26e283c0..7ad08df03 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -28,7 +28,7 @@ class ImageMagickContent; class ImageMagickDecoder : public VideoDecoder { public: - ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr); + ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr); float frames_per_second () const { /* We don't know */ @@ -82,6 +82,6 @@ protected: private: void film_changed (Film::Property); - boost::shared_ptr _imagemagick_content; + boost::shared_ptr _imagemagick_content; ContentVideoFrame _position; }; diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index fc9edac48..d9bf8ac36 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -30,15 +30,20 @@ using std::list; using boost::shared_ptr; using boost::dynamic_pointer_cast; -Playlist::Playlist (shared_ptr f, list > c) - : _film (f) - , _video_from (VIDEO_NONE) +Playlist::Playlist () + : _video_from (VIDEO_NONE) , _audio_from (AUDIO_NONE) - , _have_setup_decoders (false) - , _ffmpeg_decoder_done (false) - , _video_sync (true) { - for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + +} + +void +Playlist::setup (list > content) +{ + _video_from = VIDEO_NONE; + _audio_from = AUDIO_NONE; + + for (list >::const_iterator i = content.begin(); i != content.end(); ++i) { shared_ptr fc = dynamic_pointer_cast (*i); if (fc) { assert (!_ffmpeg); @@ -76,7 +81,7 @@ Playlist::audio_length () const case AUDIO_SNDFILE: { ContentAudioFrame l = 0; - for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { l += (*i)->audio_length (); } return l; @@ -97,7 +102,7 @@ Playlist::audio_channels () const case AUDIO_SNDFILE: { int c = 0; - for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { c += (*i)->audio_channels (); } return c; @@ -180,7 +185,7 @@ Playlist::video_length () const case VIDEO_IMAGEMAGICK: { ContentVideoFrame l = 0; - for (list >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + for (list >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { l += (*i)->video_length (); } return l; @@ -195,27 +200,40 @@ Playlist::has_audio () const { return _audio_from != AUDIO_NONE; } + +Player::Player (boost::shared_ptr f, boost::shared_ptr p) + : _film (f) + , _playlist (p) + , _video (true) + , _audio (true) + , _subtitles (true) + , _have_setup_decoders (false) + , _ffmpeg_decoder_done (false) + , _video_sync (true) +{ + +} void -Playlist::disable_video () +Player::disable_video () { - _video_from = VIDEO_NONE; + _video = false; } void -Playlist::disable_audio () +Player::disable_audio () { - _audio_from = AUDIO_NONE; + _audio = false; } void -Playlist::disable_subtitles () +Player::disable_subtitles () { - /* XXX */ + _subtitles = false; } bool -Playlist::pass () +Player::pass () { if (!_have_setup_decoders) { setup_decoders (); @@ -224,7 +242,7 @@ Playlist::pass () bool done = true; - if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { if (!_ffmpeg_decoder_done) { if (_ffmpeg_decoder->pass ()) { _ffmpeg_decoder_done = true; @@ -234,7 +252,7 @@ Playlist::pass () } } - if (_video_from == VIDEO_IMAGEMAGICK) { + if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { if (_imagemagick_decoder != _imagemagick_decoders.end ()) { if ((*_imagemagick_decoder)->pass ()) { _imagemagick_decoder++; @@ -252,37 +270,37 @@ Playlist::pass () } void -Playlist::set_progress (shared_ptr job) +Player::set_progress (shared_ptr job) { /* XXX */ } void -Playlist::process_video (shared_ptr i, bool same, shared_ptr s) +Player::process_video (shared_ptr i, bool same, shared_ptr s) { Video (i, same, s); } void -Playlist::process_audio (shared_ptr b) +Player::process_audio (shared_ptr b) { Audio (b); } bool -Playlist::seek (double t) +Player::seek (double t) { bool r = false; - switch (_video_from) { - case VIDEO_NONE: + switch (_playlist->video_from()) { + case Playlist::VIDEO_NONE: break; - case VIDEO_FFMPEG: + case Playlist::VIDEO_FFMPEG: if (_ffmpeg_decoder->seek (t)) { r = true; } break; - case VIDEO_IMAGEMAGICK: + case Playlist::VIDEO_IMAGEMAGICK: if ((*_imagemagick_decoder)->seek (t)) { r = true; } @@ -295,19 +313,19 @@ Playlist::seek (double t) } bool -Playlist::seek_to_last () +Player::seek_to_last () { bool r = false; - switch (_video_from) { - case VIDEO_NONE: + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: break; - case VIDEO_FFMPEG: + case Playlist::VIDEO_FFMPEG: if (_ffmpeg_decoder->seek_to_last ()) { r = true; } break; - case VIDEO_IMAGEMAGICK: + case Playlist::VIDEO_IMAGEMAGICK: if ((*_imagemagick_decoder)->seek_to_last ()) { r = true; } @@ -320,26 +338,32 @@ Playlist::seek_to_last () } void -Playlist::setup_decoders () +Player::setup_decoders () { - if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) { _ffmpeg_decoder.reset ( new FFmpegDecoder ( - _film, _ffmpeg, _video_from == VIDEO_FFMPEG, _audio_from == AUDIO_FFMPEG, _film->with_subtitles(), _video_sync + _film, + _playlist->ffmpeg(), + _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG, + _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, + _subtitles && _film->with_subtitles(), + _video_sync ) ); } - if (_video_from == VIDEO_FFMPEG) { + if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) { _ffmpeg_decoder->connect_video (shared_from_this ()); } - if (_audio_from == AUDIO_FFMPEG) { + if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { _ffmpeg_decoder->connect_audio (shared_from_this ()); } - if (_video_from == VIDEO_IMAGEMAGICK) { - for (list >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { + list > ic = _playlist->imagemagick (); + for (list >::iterator i = ic.begin(); i != ic.end(); ++i) { shared_ptr d (new ImageMagickDecoder (_film, *i)); _imagemagick_decoders.push_back (d); d->connect_video (shared_from_this ()); @@ -348,8 +372,9 @@ Playlist::setup_decoders () _imagemagick_decoder = _imagemagick_decoders.begin (); } - if (_audio_from == AUDIO_SNDFILE) { - for (list >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + list > sc = _playlist->sndfile (); + for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { shared_ptr d (new SndfileDecoder (_film, *i)); _sndfile_decoders.push_back (d); d->connect_audio (shared_from_this ()); @@ -358,7 +383,22 @@ Playlist::setup_decoders () } void -Playlist::disable_video_sync () +Player::disable_video_sync () { _video_sync = false; } + +double +Player::last_video_time () const +{ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + return 0; + case Playlist::VIDEO_FFMPEG: + return _ffmpeg_decoder->last_source_time (); + case Playlist::VIDEO_IMAGEMAGICK: + return (*_imagemagick_decoder)->last_source_time (); + } + + return 0; +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index d374dc98c..827849049 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -35,10 +35,12 @@ class SndfileDecoder; class Job; class Film; -class Playlist : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +class Playlist { public: - Playlist (boost::shared_ptr, std::list >); + Playlist (); + + void setup (std::list >); ContentAudioFrame audio_length () const; int audio_channels () const; @@ -50,6 +52,52 @@ public: libdcp::Size video_size () const; ContentVideoFrame video_length () const; + enum VideoFrom { + VIDEO_NONE, + VIDEO_FFMPEG, + VIDEO_IMAGEMAGICK + }; + + enum AudioFrom { + AUDIO_NONE, + AUDIO_FFMPEG, + AUDIO_SNDFILE + }; + + VideoFrom video_from () const { + return _video_from; + } + + AudioFrom audio_from () const { + return _audio_from; + } + + boost::shared_ptr ffmpeg () const { + return _ffmpeg; + } + + std::list > imagemagick () const { + return _imagemagick; + } + + std::list > sndfile () const { + return _sndfile; + } + +private: + VideoFrom _video_from; + AudioFrom _audio_from; + + boost::shared_ptr _ffmpeg; + std::list > _imagemagick; + std::list > _sndfile; +}; + +class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +{ +public: + Player (boost::shared_ptr, boost::shared_ptr); + void disable_video (); void disable_audio (); void disable_subtitles (); @@ -60,29 +108,20 @@ public: bool seek (double); bool seek_to_last (); + double last_video_time () const; + private: void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); void process_audio (boost::shared_ptr); void setup_decoders (); - - boost::shared_ptr _film; - enum { - VIDEO_NONE, - VIDEO_FFMPEG, - VIDEO_IMAGEMAGICK - } _video_from; + boost::shared_ptr _film; + boost::shared_ptr _playlist; + + bool _video; + bool _audio; + bool _subtitles; - enum { - AUDIO_NONE, - AUDIO_FFMPEG, - AUDIO_SNDFILE - } _audio_from; - - boost::shared_ptr _ffmpeg; - std::list > _imagemagick; - std::list > _sndfile; - bool _have_setup_decoders; boost::shared_ptr _ffmpeg_decoder; bool _ffmpeg_decoder_done; diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index daa363c5e..1f97e5c41 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -36,9 +36,9 @@ using boost::optional; /* XXX */ -SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) +SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , AudioDecoder (f, c) + , AudioDecoder (f) { sf_count_t frames; SNDFILE* sf = open_file (frames); diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index 9a3ef49b0..56fc3a9f0 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -26,7 +26,7 @@ class SndfileContent; class SndfileDecoder : public AudioDecoder { public: - SndfileDecoder (boost::shared_ptr, boost::shared_ptr); + SndfileDecoder (boost::shared_ptr, boost::shared_ptr); bool pass (); @@ -34,5 +34,5 @@ private: SNDFILE* open_file (sf_count_t &); void close_file (SNDFILE*); - boost::shared_ptr _sndfile_content; + boost::shared_ptr _sndfile_content; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 21944c5fc..0ee6f523f 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -47,24 +47,24 @@ using boost::dynamic_pointer_cast; */ Transcoder::Transcoder (shared_ptr f, shared_ptr j) : _job (j) - , _playlist (f->playlist ()) - , _encoder (new Encoder (f, _playlist)) + , _player (f->player ()) + , _encoder (new Encoder (f)) { - if (_playlist->has_audio ()) { - _matcher.reset (new Matcher (f->log(), _playlist->audio_frame_rate(), _playlist->video_frame_rate())); - _delay_line.reset (new DelayLine (f->log(), _playlist->audio_channels(), f->audio_delay() * _playlist->audio_frame_rate() / 1000)); + if (f->has_audio ()) { + _matcher.reset (new Matcher (f->log(), f->audio_frame_rate(), f->video_frame_rate())); + _delay_line.reset (new DelayLine (f->log(), f->audio_channels(), f->audio_delay() * f->audio_frame_rate() / 1000)); _gain.reset (new Gain (f->log(), f->audio_gain())); } if (_matcher) { - _playlist->connect_video (_matcher); + _player->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - _playlist->connect_video (_encoder); + _player->connect_video (_encoder); } - if (_matcher && _delay_line && _playlist->has_audio ()) { - _playlist->connect_audio (_delay_line); + if (_matcher && _delay_line && f->has_audio ()) { + _player->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); @@ -77,10 +77,10 @@ Transcoder::go () _encoder->process_begin (); try { while (1) { - if (_playlist->pass ()) { + if (_player->pass ()) { break; } - _playlist->set_progress (_job); + _player->set_progress (_job); } } catch (...) { diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 856b10f3a..2d032fcf6 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -30,7 +30,7 @@ class Matcher; class VideoFilter; class Gain; class DelayLine; -class Playlist; +class Player; /** @class Transcoder * @@ -50,7 +50,7 @@ public: protected: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; - boost::shared_ptr _playlist; + boost::shared_ptr _player; boost::shared_ptr _encoder; boost::shared_ptr _matcher; boost::shared_ptr _delay_line; diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 33dd433ea..32b06085f 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -29,7 +29,7 @@ using boost::shared_ptr; using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c) +VideoDecoder::VideoDecoder (shared_ptr f) : Decoder (f) , _video_frame (0) , _last_source_time (0) @@ -106,10 +106,7 @@ VideoDecoder::set_progress (Job* j) const { assert (j); -#if 0 - XXX - if (_film->length()) { - j->set_progress (float (_video_frame) / _film->length().get()); + if (_film->video_length()) { + j->set_progress (float (_video_frame) / _film->video_length()); } -#endif } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 03dc4777a..a2fd5b651 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -28,7 +28,7 @@ class VideoContent; class VideoDecoder : public VideoSource, public virtual Decoder { public: - VideoDecoder (boost::shared_ptr, boost::shared_ptr); + VideoDecoder (boost::shared_ptr); /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 5f5dae98f..b08b9caf1 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -42,9 +42,8 @@ using boost::shared_ptr; int const Writer::_maximum_frames_in_memory = 8; -Writer::Writer (shared_ptr f, shared_ptr p) +Writer::Writer (shared_ptr f) : _film (f) - , _playlist (p) , _first_nonexistant_frame (0) , _thread (0) , _finish (false) @@ -76,7 +75,7 @@ Writer::Writer (shared_ptr f, shared_ptr p) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); if (m.dcp_channels() > 0) { _sound_asset.reset ( @@ -85,7 +84,7 @@ Writer::Writer (shared_ptr f, shared_ptr p) N_("audio.mxf"), _film->dcp_frame_rate (), m.dcp_channels (), - dcp_audio_sample_rate (_playlist->audio_frame_rate()) + dcp_audio_sample_rate (_film->audio_frame_rate()) ) ); diff --git a/src/lib/writer.h b/src/lib/writer.h index 920f592b6..beb16c7b9 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -26,7 +26,6 @@ class Film; class EncodedData; class AudioBuffers; -class Playlist; namespace libdcp { class MonoPictureAsset; @@ -64,7 +63,7 @@ bool operator== (QueueItem const & a, QueueItem const & b); class Writer : public ExceptionStore { public: - Writer (boost::shared_ptr, boost::shared_ptr); + Writer (boost::shared_ptr); bool can_fake_write (int) const; @@ -81,7 +80,6 @@ private: /** our Film */ boost::shared_ptr _film; - boost::shared_ptr _playlist; /** the first frame index that does not already exist in our MXF */ int _first_nonexistant_frame; diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index 3d847d690..d7e8bbb0e 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -150,14 +150,14 @@ main (int argc, char* argv[]) server = new ServerDescription (server_host, 1); shared_ptr film (new Film (film_dir, true)); - shared_ptr playlist = film->playlist (); - playlist->disable_audio (); + shared_ptr player = film->player (); + player->disable_audio (); try { - playlist->Video.connect (boost::bind (process_video, _1, _2, _3)); + player->Video.connect (boost::bind (process_video, _1, _2, _3)); bool done = false; while (!done) { - done = playlist->pass (); + done = player->pass (); } } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index b7384fd14..242d37b1e 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -20,7 +20,6 @@ #include #include "lib/audio_analysis.h" #include "lib/film.h" -#include "lib/playlist.h" #include "audio_dialog.h" #include "audio_plot.h" #include "wx_util.h" @@ -91,7 +90,6 @@ AudioDialog::set_film (boost::shared_ptr f) _film_audio_analysis_succeeded_connection.disconnect (); _film = f; - _playlist = _film->playlist (); try_to_load_analysis (); setup_channels (); @@ -106,11 +104,11 @@ AudioDialog::set_film (boost::shared_ptr f) void AudioDialog::setup_channels () { - if (!_playlist->has_audio()) { + if (!_film->has_audio()) { return; } - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (m.dcp_to_source(static_cast(i))) { @@ -136,7 +134,7 @@ AudioDialog::try_to_load_analysis () _plot->set_analysis (a); - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); optional c = m.source_to_dcp (0); if (c) { _channel_checkbox[c.get()]->SetValue (true); @@ -159,7 +157,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) assert (c < MAX_AUDIO_CHANNELS); - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); optional s = m.dcp_to_source (static_cast (c)); if (s) { _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); @@ -174,7 +172,6 @@ AudioDialog::film_changed (Film::Property p) _plot->set_gain (_film->audio_gain ()); break; case Film::CONTENT: - _playlist = _film->playlist (); setup_channels (); break; default: diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h index 3cb9c1726..514faeea0 100644 --- a/src/wx/audio_dialog.h +++ b/src/wx/audio_dialog.h @@ -25,7 +25,6 @@ class AudioPlot; class Film; -class Playlist; class AudioDialog : public wxDialog { @@ -43,7 +42,6 @@ private: void setup_channels (); boost::shared_ptr _film; - boost::shared_ptr _playlist; AudioPlot* _plot; wxCheckBox* _channel_checkbox[MAX_AUDIO_CHANNELS]; wxCheckBox* _type_checkbox[AudioPoint::COUNT]; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 42af4b3c0..79b3d982f 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -97,13 +97,13 @@ FilmViewer::film_changed (Film::Property p) break; case Film::CONTENT: { - _playlist = _film->playlist (); - _playlist->disable_audio (); - _playlist->disable_subtitles (); - _playlist->disable_video_sync (); + _player = _film->player (); + _player->disable_audio (); + _player->disable_subtitles (); + _player->disable_video_sync (); - _playlist->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); -// _playlist->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); + _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); +// _player->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); calculate_sizes (); get_frame (); _panel->Refresh (); @@ -153,7 +153,7 @@ FilmViewer::set_film (shared_ptr f) void FilmViewer::decoder_changed () { - if (!_playlist == 0 || _playlist->seek_to_last ()) { + if (!_player || _player->seek_to_last ()) { return; } @@ -165,7 +165,7 @@ FilmViewer::decoder_changed () void FilmViewer::timer (wxTimerEvent &) { - if (!_playlist) { + if (!_player) { return; } @@ -174,12 +174,12 @@ FilmViewer::timer (wxTimerEvent &) get_frame (); -// if (_playlist->video_length()) { -// int const new_slider_position = 4096 * _playlist->last_source_time() / (_film->length().get() / _film->source_frame_rate()); -// if (new_slider_position != _slider->GetValue()) { -// _slider->SetValue (new_slider_position); -// } -// } + if (_film->video_length()) { + int const new_slider_position = 4096 * _player->last_video_time() / (_film->video_length() / _film->video_frame_rate()); + if (new_slider_position != _slider->GetValue()) { + _slider->SetValue (new_slider_position); + } + } } @@ -220,11 +220,11 @@ FilmViewer::paint_panel (wxPaintEvent &) void FilmViewer::slider_moved (wxScrollEvent &) { - if (!_film || !_playlist) { + if (!_film || !_player) { return; } - if (_playlist->seek (_slider->GetValue() * _playlist->video_length() / (4096 * _playlist->video_frame_rate()))) { + if (_player->seek (_slider->GetValue() * _film->video_length() / (4096 * _film->video_frame_rate()))) { return; } @@ -308,7 +308,7 @@ FilmViewer::raw_to_display () void FilmViewer::calculate_sizes () { - if (!_film || !_playlist) { + if (!_film || !_player) { return; } @@ -332,7 +332,7 @@ FilmViewer::calculate_sizes () */ _display_frame_x = 0; if (format) { - _display_frame_x = static_cast (format->dcp_padding (_playlist)) * _out_size.width / format->dcp_size().width; + _display_frame_x = static_cast (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width; } _film_size = _out_size; @@ -381,7 +381,7 @@ FilmViewer::get_frame () /* Clear our raw frame in case we don't get a new one */ _raw_frame.reset (); - if (!_playlist) { + if (!_player) { _display_frame.reset (); return; } @@ -389,7 +389,7 @@ FilmViewer::get_frame () try { _got_frame = false; while (!_got_frame) { - if (_playlist->pass ()) { + if (_player->pass ()) { /* We didn't get a frame before the decoder gave up, so clear our display frame. */ diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 74ab9798c..1e75045ac 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -57,7 +57,7 @@ private: void active_jobs_changed (bool); boost::shared_ptr _film; - boost::shared_ptr _playlist; + boost::shared_ptr _player; wxSizer* _v_sizer; wxPanel* _panel; diff --git a/wscript b/wscript index fb728ec40..9040738fb 100644 --- a/wscript +++ b/wscript @@ -55,6 +55,7 @@ def configure(conf): if not conf.options.static: conf.check_cfg(package = 'libdcp', atleast_version = '0.41', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True) + conf.check_cfg(package = 'libcxml', atleast_version = '0.01', args = '--cflags --libs', uselib_store = 'CXML', mandatory = True) conf.check_cfg(package = 'libavformat', args = '--cflags --libs', uselib_store = 'AVFORMAT', mandatory = True) conf.check_cfg(package = 'libavfilter', args = '--cflags --libs', uselib_store = 'AVFILTER', mandatory = True) conf.check_cfg(package = 'libavcodec', args = '--cflags --libs', uselib_store = 'AVCODEC', mandatory = True) @@ -71,6 +72,8 @@ def configure(conf): conf.env.HAVE_DCP = 1 conf.env.STLIB_DCP = ['dcp', 'asdcp-libdcp', 'kumu-libdcp'] conf.env.LIB_DCP = ['glibmm-2.4', 'xml++-2.6', 'ssl', 'crypto', 'bz2'] + conf.env.HAVE_CXML = 1 + conf.env.STLIB_CXML = ['cxml'] conf.env.HAVE_AVFORMAT = 1 conf.env.STLIB_AVFORMAT = ['avformat'] conf.env.HAVE_AVFILTER = 1 -- cgit v1.2.3 From 190c074cc1508c0aa429452ea920f8f94ef0d0f2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 4 Apr 2013 00:13:27 +0100 Subject: More various bits. --- src/lib/audio_source.cc | 12 +++++++++++- src/lib/encoder.cc | 2 +- src/lib/encoder.h | 2 +- src/lib/ffmpeg_content.cc | 10 ++++++---- src/lib/ffmpeg_decoder.cc | 12 +++++++++++- src/lib/ffmpeg_decoder.h | 10 ++++++++++ src/lib/film.cc | 2 +- src/lib/playlist.cc | 25 +++++++++++++++++++++++-- src/lib/transcode_job.cc | 34 ++++++++++++++++------------------ src/lib/transcode_job.h | 6 ++++-- src/lib/transcoder.cc | 12 ++++++++++++ src/lib/transcoder.h | 3 +++ src/lib/video_source.cc | 15 ++++++++++++++- src/wx/film_editor.cc | 29 +++++++++++++++++++++++++---- src/wx/film_editor.h | 1 + 15 files changed, 139 insertions(+), 36 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index 53b0dda15..99b59759d 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -21,10 +21,20 @@ #include "audio_sink.h" using boost::shared_ptr; +using boost::weak_ptr; using boost::bind; +static void +process_audio_proxy (weak_ptr sink, shared_ptr audio) +{ + shared_ptr p = sink.lock (); + if (p) { + p->process_audio (audio); + } +} + void AudioSource::connect_audio (shared_ptr s) { - Audio.connect (bind (&AudioSink::process_audio, s, _1)); + Audio.connect (bind (process_audio_proxy, weak_ptr (s), _1)); } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 5c3e56709..a41ebec51 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -193,7 +193,7 @@ Encoder::process_end () * or 0 if not known. */ float -Encoder::current_frames_per_second () const +Encoder::current_encoding_rate () const { boost::mutex::scoped_lock lock (_history_mutex); if (int (_time_history.size()) < _history_size) { diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 2cbd498e8..b85132b72 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -81,7 +81,7 @@ public: /** Called when a processing run has finished */ virtual void process_end (); - float current_frames_per_second () const; + float current_encoding_rate () const; int video_frames_out () const; private: diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index c6344d567..7834cb76e 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -111,12 +111,10 @@ FFmpegContent::as_xml (xmlpp::Node* node) const void FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) { - job->descend (0.5); - Content::examine (film, job, quick); - job->ascend (); - job->set_progress_unknown (); + Content::examine (film, job, quick); + shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false, false, true)); ContentVideoFrame video_length = 0; @@ -166,6 +164,10 @@ FFmpegContent::summary () const string FFmpegContent::information () const { + if (video_length() == 0 || video_frame_rate() == 0) { + return ""; + } + stringstream s; s << String::compose (_("%1 frames; %2 frames per second"), video_length(), video_frame_rate()) << "\n"; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 3a185bd6a..fdc5189a6 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,6 +61,8 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; +boost::mutex FFmpegDecoder::_mutex; + FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) : Decoder (f) , VideoDecoder (f) @@ -92,10 +94,12 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptrstreams[_video_stream]->codec; _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); @@ -175,6 +181,8 @@ FFmpegDecoder::setup_video () void FFmpegDecoder::setup_audio () { + boost::mutex::scoped_lock lm (_mutex); + if (!_ffmpeg_content->audio_stream ()) { return; } @@ -194,6 +202,8 @@ FFmpegDecoder::setup_audio () void FFmpegDecoder::setup_subtitle () { + boost::mutex::scoped_lock lm (_mutex); + if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { return; } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 71ecf7906..5023ac56c 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -82,6 +82,10 @@ public: private: + /* No copy construction */ + FFmpegDecoder (FFmpegDecoder const &); + FFmpegDecoder& operator= (FFmpegDecoder const &); + bool do_seek (double p, bool); PixelFormat pixel_format () const; AVSampleFormat audio_sample_format () const; @@ -134,4 +138,10 @@ private: bool _decode_audio; bool _decode_subtitles; bool _video_sync; + + /* It would appear (though not completely verified) that one must have + a mutex around calls to avcodec_open* and avcodec_close... and here + it is. + */ + static boost::mutex _mutex; }; diff --git a/src/lib/film.cc b/src/lib/film.cc index fd72aa1d5..b21b3454d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -550,7 +550,7 @@ Film::file (string f) const int Film::target_audio_sample_rate () const { - if (has_audio ()) { + if (!has_audio ()) { return 0; } diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 3da7f938b..dc8ad1ef7 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -25,6 +25,7 @@ #include "ffmpeg_decoder.h" #include "imagemagick_content.h" #include "imagemagick_decoder.h" +#include "job.h" using std::list; using std::cout; @@ -219,7 +220,7 @@ Player::Player (boost::shared_ptr f, boost::shared_ptr job) { - /* XXX */ + /* Assume progress can be divined from how far through the video we are */ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (_playlist->video_length ()) { + job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); + } + break; + case Playlist::VIDEO_IMAGEMAGICK: + { + int n = 0; + for (std::list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { + if (_imagemagick_decoder == i) { + job->set_progress (float (n) / _imagemagick_decoders.size ()); + } + ++n; + } + break; + } + } } void diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 8b74f7766..0c3b8c37b 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -60,8 +60,8 @@ TranscodeJob::run () _film->log()->log (N_("Transcode job starting")); _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); - Transcoder w (_film, shared_from_this ()); - w.go (); + _transcoder.reset (new Transcoder (_film, shared_from_this ())); + _transcoder->go (); set_progress (1); set_state (FINISHED_OK); @@ -80,13 +80,11 @@ TranscodeJob::run () string TranscodeJob::status () const { -// if (!_encoder) { -// return _("0%"); -// } + if (!_transcoder) { + return _("0%"); + } - /* XXX */ -// float const fps = _encoder->current_frames_per_second (); - float const fps = 0; + float const fps = _transcoder->current_encoding_rate (); if (fps == 0) { return Job::status (); } @@ -105,28 +103,28 @@ TranscodeJob::status () const int TranscodeJob::remaining_time () const { - return 0; -#if 0 - XXX - float fps = _encoder->current_frames_per_second (); + if (!_transcoder) { + return 0; + } + + float fps = _transcoder->current_encoding_rate (); + if (fps == 0) { return 0; } - if (!_video->length()) { + if (!_film->video_length()) { return 0; } /* Compute approximate proposed length here, as it's only here that we need it */ - int length = _film->length().get(); - FrameRateConversion const frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + int length = _film->video_length(); + FrameRateConversion const frc (_film->video_frame_rate(), _film->dcp_frame_rate()); if (frc.skip) { length /= 2; } /* If we are repeating it shouldn't affect transcode time, so don't take it into account */ - /* We assume that dcp_length() is valid, if it is set */ - int const left = length - _encoder->video_frames_out(); + int const left = length - _transcoder->video_frames_out(); return left / fps; -#endif } diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index def545958..7880a925e 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -24,7 +24,7 @@ #include #include "job.h" -class Encoder; +class Transcoder; /** @class TranscodeJob * @brief A job which transcodes from one format to another. @@ -38,6 +38,8 @@ public: void run (); std::string status () const; -protected: +private: int remaining_time () const; + + boost::shared_ptr _transcoder; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 0ee6f523f..ef3a0e8c1 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -99,3 +99,15 @@ Transcoder::go () } _encoder->process_end (); } + +float +Transcoder::current_encoding_rate () const +{ + return _encoder->current_encoding_rate (); +} + +int +Transcoder::video_frames_out () const +{ + return _encoder->video_frames_out (); +} diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 2d032fcf6..ecc8ebf62 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -47,6 +47,9 @@ public: void go (); + float current_encoding_rate () const; + int video_frames_out () const; + protected: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 56742e2b4..8101a6d36 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -21,10 +21,23 @@ #include "video_sink.h" using boost::shared_ptr; +using boost::weak_ptr; using boost::bind; +static void +process_video_proxy (weak_ptr sink, shared_ptr i, bool same, shared_ptr s) +{ + boost::shared_ptr p = sink.lock (); + if (p) { + p->process_video (i, same, s); + } +} + void VideoSource::connect_video (shared_ptr s) { - Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); + /* If we bind, say, a Playlist (as the VideoSink) to a Decoder (which is owned + by the Playlist) we create a cycle. Use a weak_ptr to break it. + */ + Video.connect (bind (process_video_proxy, boost::weak_ptr (s), _1, _2, _3)); } diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index d55104a95..10cb41df0 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -705,16 +705,17 @@ FilmEditor::film_content_changed (int p) setup_show_audio_sensitivity (); } else if (p == VideoContentProperty::VIDEO_LENGTH) { setup_length (); + setup_content_information (); } else if (p == FFmpegContentProperty::AUDIO_STREAM) { if (_film->ffmpeg_audio_stream()) { - checked_set (_ffmpeg_audio_stream, _film->ffmpeg_audio_stream()->id); + checked_set (_ffmpeg_audio_stream, boost::lexical_cast (_film->ffmpeg_audio_stream()->id)); } setup_dcp_name (); setup_audio_details (); setup_show_audio_sensitivity (); } else if (p == FFmpegContentProperty::SUBTITLE_STREAM) { if (_film->ffmpeg_subtitle_stream()) { - checked_set (_ffmpeg_subtitle_stream, _film->ffmpeg_subtitle_stream()->id); + checked_set (_ffmpeg_subtitle_stream, boost::lexical_cast (_film->ffmpeg_subtitle_stream()->id)); } } } @@ -1117,7 +1118,7 @@ FilmEditor::setup_audio_details () } else { s << _film->audio_channels() << " " << wx_to_std (_("channels")); } - s << ", " << _film->audio_channels() << wx_to_std (_("Hz")); + s << ", " << _film->audio_frame_rate() << wx_to_std (_("Hz")); _audio->SetLabel (std_to_wx (s.str ())); } } @@ -1172,11 +1173,26 @@ FilmEditor::setup_show_audio_sensitivity () void FilmEditor::setup_content () { + string selected_summary; + int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s != -1) { + selected_summary = wx_to_std (_content->GetItemText (s)); + } + _content->DeleteAllItems (); ContentList content = _film->content (); for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { - _content->InsertItem (_content->GetItemCount(), std_to_wx ((*i)->summary ())); + int const t = _content->GetItemCount (); + _content->InsertItem (t, std_to_wx ((*i)->summary ())); + if ((*i)->summary() == selected_summary) { + _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } + } + + if (selected_summary.empty () && !content.empty ()) { + /* Select the first item of content if non was selected before */ + _content->SetItemState (0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); } } @@ -1246,7 +1262,12 @@ void FilmEditor::content_item_selected (wxListEvent &) { setup_content_button_sensitivity (); + setup_content_information (); +} +void +FilmEditor::setup_content_information () +{ int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (s == -1) { _content_information->SetValue (""); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 60da2de4d..97d1e0dd3 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -106,6 +106,7 @@ private: void setup_content_button_sensitivity (); void setup_length (); void setup_format (); + void setup_content_information (); void active_jobs_changed (bool); -- cgit v1.2.3 From 6bc12a2eeb9c84a539688f2f7eb876e3ea278a9f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 4 Apr 2013 10:13:41 +0100 Subject: Split playlist files up; fix build. --- src/lib/ab_transcoder.cc | 2 +- src/lib/analyse_audio_job.cc | 2 +- src/lib/encoder.cc | 2 +- src/lib/film.cc | 1 + src/lib/player.cc | 280 +++++++++++++++++++++++++++++++++++++++++++ src/lib/player.h | 77 ++++++++++++ src/lib/playlist.cc | 250 -------------------------------------- src/lib/playlist.h | 39 ------ src/lib/transcoder.cc | 2 +- src/lib/writer.cc | 2 +- src/lib/wscript | 1 + src/tools/servomatictest.cc | 2 +- src/wx/film_editor.cc | 9 +- src/wx/film_viewer.cc | 2 +- 14 files changed, 371 insertions(+), 300 deletions(-) create mode 100644 src/lib/player.cc create mode 100644 src/lib/player.h (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 6bf092fee..81aa5a4ba 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -24,7 +24,7 @@ #include "encoder.h" #include "job.h" #include "image.h" -#include "playlist.h" +#include "player.h" #include "matcher.h" #include "delay_line.h" #include "gain.h" diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index e2c9c5b18..5ef6515dd 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -21,7 +21,7 @@ #include "analyse_audio_job.h" #include "compose.hpp" #include "film.h" -#include "playlist.h" +#include "player.h" #include "i18n.h" diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index a41ebec51..2a8d8cc16 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -37,7 +37,7 @@ #include "format.h" #include "cross.h" #include "writer.h" -#include "playlist.h" +#include "player.h" #include "i18n.h" diff --git a/src/lib/film.cc b/src/lib/film.cc index b21b3454d..42f4b1c3d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -53,6 +53,7 @@ #include "sndfile_decoder.h" #include "analyse_audio_job.h" #include "playlist.h" +#include "player.h" #include "ffmpeg_content.h" #include "imagemagick_content.h" #include "sndfile_content.h" diff --git a/src/lib/player.cc b/src/lib/player.cc new file mode 100644 index 000000000..6e2e7ed14 --- /dev/null +++ b/src/lib/player.cc @@ -0,0 +1,280 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 "player.h" +#include "film.h" +#include "ffmpeg_decoder.h" +#include "imagemagick_decoder.h" +#include "sndfile_decoder.h" +#include "playlist.h" +#include "job.h" + +using std::list; +using boost::shared_ptr; + +Player::Player (shared_ptr f, shared_ptr p) + : _film (f) + , _playlist (p) + , _video (true) + , _audio (true) + , _subtitles (true) + , _have_setup_decoders (false) + , _ffmpeg_decoder_done (false) + , _video_sync (true) +{ + +} + +void +Player::disable_video () +{ + _video = false; +} + +void +Player::disable_audio () +{ + _audio = false; +} + +void +Player::disable_subtitles () +{ + _subtitles = false; +} + +bool +Player::pass () +{ + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + + bool done = true; + + if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { + if (!_ffmpeg_decoder_done) { + if (_ffmpeg_decoder->pass ()) { + _ffmpeg_decoder_done = true; + } else { + done = false; + } + } + } + + if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { + if (_imagemagick_decoder != _imagemagick_decoders.end ()) { + if ((*_imagemagick_decoder)->pass ()) { + _imagemagick_decoder++; + } + + if (_imagemagick_decoder != _imagemagick_decoders.end ()) { + done = false; + } + } + } + + /* XXX: sndfile */ + + return done; +} + +void +Player::set_progress (shared_ptr job) +{ + /* Assume progress can be divined from how far through the video we are */ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (_playlist->video_length ()) { + job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); + } + break; + case Playlist::VIDEO_IMAGEMAGICK: + { + int n = 0; + for (list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { + if (_imagemagick_decoder == i) { + job->set_progress (float (n) / _imagemagick_decoders.size ()); + } + ++n; + } + break; + } + } +} + +void +Player::process_video (shared_ptr i, bool same, shared_ptr s) +{ + Video (i, same, s); +} + +void +Player::process_audio (shared_ptr b) +{ + Audio (b); +} + +/** @return true on error */ +bool +Player::seek (double t) +{ + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + + bool r = false; + + switch (_playlist->video_from()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (!_ffmpeg_decoder || _ffmpeg_decoder->seek (t)) { + r = true; + } + /* We're seeking, so all `all done' bets are off */ + _ffmpeg_decoder_done = false; + break; + case Playlist::VIDEO_IMAGEMAGICK: + /* Find the decoder that contains this position */ + _imagemagick_decoder = _imagemagick_decoders.begin (); + while (_imagemagick_decoder != _imagemagick_decoders.end ()) { + double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate (); + if (t < this_length) { + break; + } + t -= this_length; + ++_imagemagick_decoder; + } + + if (_imagemagick_decoder != _imagemagick_decoders.end()) { + (*_imagemagick_decoder)->seek (t); + } else { + r = true; + } + break; + } + + /* XXX: don't seek audio because we don't need to... */ + + return r; +} + +bool +Player::seek_to_last () +{ + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + + bool r = false; + + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (!_ffmpeg_decoder || _ffmpeg_decoder->seek_to_last ()) { + r = true; + } + + /* We're seeking, so all `all done' bets are off */ + _ffmpeg_decoder_done = false; + break; + case Playlist::VIDEO_IMAGEMAGICK: + if ((*_imagemagick_decoder)->seek_to_last ()) { + r = true; + } + break; + } + + /* XXX: don't seek audio because we don't need to... */ + + return r; +} + +void +Player::setup_decoders () +{ + if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) { + _ffmpeg_decoder.reset ( + new FFmpegDecoder ( + _film, + _playlist->ffmpeg(), + _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG, + _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, + _subtitles && _film->with_subtitles(), + _video_sync + ) + ); + } + + if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) { + _ffmpeg_decoder->connect_video (shared_from_this ()); + } + + if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { + _ffmpeg_decoder->connect_audio (shared_from_this ()); + } + + if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { + list > ic = _playlist->imagemagick (); + for (list >::iterator i = ic.begin(); i != ic.end(); ++i) { + shared_ptr d (new ImageMagickDecoder (_film, *i)); + _imagemagick_decoders.push_back (d); + d->connect_video (shared_from_this ()); + } + + _imagemagick_decoder = _imagemagick_decoders.begin (); + } + + if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + list > sc = _playlist->sndfile (); + for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { + shared_ptr d (new SndfileDecoder (_film, *i)); + _sndfile_decoders.push_back (d); + d->connect_audio (shared_from_this ()); + } + } +} + +void +Player::disable_video_sync () +{ + _video_sync = false; +} + +double +Player::last_video_time () const +{ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + return 0; + case Playlist::VIDEO_FFMPEG: + return _ffmpeg_decoder->last_source_time (); + case Playlist::VIDEO_IMAGEMAGICK: + return (*_imagemagick_decoder)->last_source_time (); + } + + return 0; +} diff --git a/src/lib/player.h b/src/lib/player.h new file mode 100644 index 000000000..bc728d8f2 --- /dev/null +++ b/src/lib/player.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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_PLAYER_H +#define DVDOMATIC_PLAYER_H + +#include +#include +#include +#include "video_source.h" +#include "audio_source.h" +#include "video_sink.h" +#include "audio_sink.h" + +class FFmpegDecoder; +class ImageMagickDecoder; +class SndfileDecoder; +class Job; +class Film; +class Playlist; + +class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +{ +public: + Player (boost::shared_ptr, boost::shared_ptr); + + void disable_video (); + void disable_audio (); + void disable_subtitles (); + void disable_video_sync (); + + bool pass (); + void set_progress (boost::shared_ptr); + bool seek (double); + bool seek_to_last (); + + double last_video_time () const; + +private: + void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); + void process_audio (boost::shared_ptr); + void setup_decoders (); + + boost::shared_ptr _film; + boost::shared_ptr _playlist; + + bool _video; + bool _audio; + bool _subtitles; + + bool _have_setup_decoders; + boost::shared_ptr _ffmpeg_decoder; + bool _ffmpeg_decoder_done; + std::list > _imagemagick_decoders; + std::list >::iterator _imagemagick_decoder; + std::list > _sndfile_decoders; + + bool _video_sync; +}; + +#endif diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index a7862f116..0a4803f6e 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -208,253 +208,3 @@ Playlist::has_audio () const return _audio_from != AUDIO_NONE; } -Player::Player (boost::shared_ptr f, boost::shared_ptr p) - : _film (f) - , _playlist (p) - , _video (true) - , _audio (true) - , _subtitles (true) - , _have_setup_decoders (false) - , _ffmpeg_decoder_done (false) - , _video_sync (true) -{ - -} - -void -Player::disable_video () -{ - _video = false; -} - -void -Player::disable_audio () -{ - _audio = false; -} - -void -Player::disable_subtitles () -{ - _subtitles = false; -} - -bool -Player::pass () -{ - if (!_have_setup_decoders) { - setup_decoders (); - _have_setup_decoders = true; - } - - bool done = true; - - if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - if (!_ffmpeg_decoder_done) { - if (_ffmpeg_decoder->pass ()) { - _ffmpeg_decoder_done = true; - } else { - done = false; - } - } - } - - if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { - if (_imagemagick_decoder != _imagemagick_decoders.end ()) { - if ((*_imagemagick_decoder)->pass ()) { - _imagemagick_decoder++; - } - - if (_imagemagick_decoder != _imagemagick_decoders.end ()) { - done = false; - } - } - } - - /* XXX: sndfile */ - - return done; -} - -void -Player::set_progress (shared_ptr job) -{ - /* Assume progress can be divined from how far through the video we are */ - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (_playlist->video_length ()) { - job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); - } - break; - case Playlist::VIDEO_IMAGEMAGICK: - { - int n = 0; - for (std::list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { - if (_imagemagick_decoder == i) { - job->set_progress (float (n) / _imagemagick_decoders.size ()); - } - ++n; - } - break; - } - } -} - -void -Player::process_video (shared_ptr i, bool same, shared_ptr s) -{ - Video (i, same, s); -} - -void -Player::process_audio (shared_ptr b) -{ - Audio (b); -} - -/** @return true on error */ -bool -Player::seek (double t) -{ - if (!_have_setup_decoders) { - setup_decoders (); - _have_setup_decoders = true; - } - - bool r = false; - - switch (_playlist->video_from()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (!_ffmpeg_decoder || _ffmpeg_decoder->seek (t)) { - r = true; - } - /* We're seeking, so all `all done' bets are off */ - _ffmpeg_decoder_done = false; - break; - case Playlist::VIDEO_IMAGEMAGICK: - /* Find the decoder that contains this position */ - _imagemagick_decoder = _imagemagick_decoders.begin (); - while (_imagemagick_decoder != _imagemagick_decoders.end ()) { - double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate (); - if (t < this_length) { - break; - } - t -= this_length; - ++_imagemagick_decoder; - } - - if (_imagemagick_decoder != _imagemagick_decoders.end()) { - (*_imagemagick_decoder)->seek (t); - } else { - r = true; - } - break; - } - - /* XXX: don't seek audio because we don't need to... */ - - return r; -} - -bool -Player::seek_to_last () -{ - if (!_have_setup_decoders) { - setup_decoders (); - _have_setup_decoders = true; - } - - bool r = false; - - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (!_ffmpeg_decoder || _ffmpeg_decoder->seek_to_last ()) { - r = true; - } - - /* We're seeking, so all `all done' bets are off */ - _ffmpeg_decoder_done = false; - break; - case Playlist::VIDEO_IMAGEMAGICK: - if ((*_imagemagick_decoder)->seek_to_last ()) { - r = true; - } - break; - } - - /* XXX: don't seek audio because we don't need to... */ - - return r; -} - -void -Player::setup_decoders () -{ - if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) { - _ffmpeg_decoder.reset ( - new FFmpegDecoder ( - _film, - _playlist->ffmpeg(), - _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG, - _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, - _subtitles && _film->with_subtitles(), - _video_sync - ) - ); - } - - if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) { - _ffmpeg_decoder->connect_video (shared_from_this ()); - } - - if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - _ffmpeg_decoder->connect_audio (shared_from_this ()); - } - - if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { - list > ic = _playlist->imagemagick (); - for (list >::iterator i = ic.begin(); i != ic.end(); ++i) { - shared_ptr d (new ImageMagickDecoder (_film, *i)); - _imagemagick_decoders.push_back (d); - d->connect_video (shared_from_this ()); - } - - _imagemagick_decoder = _imagemagick_decoders.begin (); - } - - if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { - list > sc = _playlist->sndfile (); - for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { - shared_ptr d (new SndfileDecoder (_film, *i)); - _sndfile_decoders.push_back (d); - d->connect_audio (shared_from_this ()); - } - } -} - -void -Player::disable_video_sync () -{ - _video_sync = false; -} - -double -Player::last_video_time () const -{ - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - return 0; - case Playlist::VIDEO_FFMPEG: - return _ffmpeg_decoder->last_source_time (); - case Playlist::VIDEO_IMAGEMAGICK: - return (*_imagemagick_decoder)->last_source_time (); - } - - return 0; -} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 480f1b2ed..29a52d433 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -93,42 +93,3 @@ private: std::list > _imagemagick; std::list > _sndfile; }; - -class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this -{ -public: - Player (boost::shared_ptr, boost::shared_ptr); - - void disable_video (); - void disable_audio (); - void disable_subtitles (); - void disable_video_sync (); - - bool pass (); - void set_progress (boost::shared_ptr); - bool seek (double); - bool seek_to_last (); - - double last_video_time () const; - -private: - void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); - void process_audio (boost::shared_ptr); - void setup_decoders (); - - boost::shared_ptr _film; - boost::shared_ptr _playlist; - - bool _video; - bool _audio; - bool _subtitles; - - bool _have_setup_decoders; - boost::shared_ptr _ffmpeg_decoder; - bool _ffmpeg_decoder_done; - std::list > _imagemagick_decoders; - std::list >::iterator _imagemagick_decoder; - std::list > _sndfile_decoders; - - bool _video_sync; -}; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index ef3a0e8c1..6744e9193 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -34,7 +34,7 @@ #include "gain.h" #include "video_decoder.h" #include "audio_decoder.h" -#include "playlist.h" +#include "player.h" using std::string; using boost::shared_ptr; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index b08b9caf1..d413d33f3 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -28,7 +28,7 @@ #include "format.h" #include "log.h" #include "dcp_video_frame.h" -#include "playlist.h" +#include "player.h" #include "i18n.h" diff --git a/src/lib/wscript b/src/lib/wscript index f2bb678aa..32a2cde23 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -38,6 +38,7 @@ sources = """ log.cc lut.cc matcher.cc + player.cc playlist.cc scp_dcp_job.cc scaler.cc diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index d7e8bbb0e..d3222faa3 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -33,7 +33,7 @@ #include "scaler.h" #include "log.h" #include "video_decoder.h" -#include "playlist.h" +#include "player.h" using std::cout; using std::cerr; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 10cb41df0..ab1fe86ce 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -59,6 +59,7 @@ using std::list; using std::vector; using boost::shared_ptr; using boost::dynamic_pointer_cast; +using boost::lexical_cast; /** @param f Film to edit */ FilmEditor::FilmEditor (shared_ptr f, wxWindow* parent) @@ -332,7 +333,7 @@ FilmEditor::make_content_panel () _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); - _content->InsertColumn (0, ""); + _content->InsertColumn (0, wxT("")); _content->SetColumnWidth (0, 512); wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); @@ -1078,7 +1079,7 @@ FilmEditor::ffmpeg_audio_stream_changed (wxCommandEvent &) vector a = _film->ffmpeg_audio_streams (); vector::iterator i = a.begin (); string const s = string_client_data (_ffmpeg_audio_stream->GetClientObject (_ffmpeg_audio_stream->GetSelection ())); - while (i != a.end() && i->id != s) { + while (i != a.end() && lexical_cast (i->id) != s) { ++i; } @@ -1097,7 +1098,7 @@ FilmEditor::ffmpeg_subtitle_stream_changed (wxCommandEvent &) vector a = _film->ffmpeg_subtitle_streams (); vector::iterator i = a.begin (); string const s = string_client_data (_ffmpeg_subtitle_stream->GetClientObject (_ffmpeg_subtitle_stream->GetSelection ())); - while (i != a.end() && i->id != s) { + while (i != a.end() && lexical_cast (i->id) != s) { ++i; } @@ -1270,7 +1271,7 @@ FilmEditor::setup_content_information () { int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (s == -1) { - _content_information->SetValue (""); + _content_information->SetValue (wxT ("")); return; } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 76cff3f65..f6d0f77dc 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -34,7 +34,7 @@ #include "lib/exceptions.h" #include "lib/examine_content_job.h" #include "lib/filter.h" -#include "lib/playlist.h" +#include "lib/player.h" #include "lib/video_content.h" #include "lib/ffmpeg_content.h" #include "film_viewer.h" -- cgit v1.2.3 From 3429cf48ff2ce056413588be4151be82c8114861 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 4 Apr 2013 10:37:32 +0100 Subject: Some unnecessary boost:: removal. --- src/lib/encoder.cc | 9 +++++---- src/lib/film.cc | 12 ++++++------ src/lib/matcher.cc | 4 ++-- src/lib/video_source.cc | 2 +- src/wx/audio_dialog.cc | 2 +- src/wx/film_viewer.cc | 2 +- src/wx/job_manager_view.cc | 4 ++-- 7 files changed, 18 insertions(+), 17 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 2a8d8cc16..568307462 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -48,7 +48,8 @@ using std::vector; using std::list; using std::cout; using std::make_pair; -using namespace boost; +using boost::shared_ptr; +using boost::optional; int const Encoder::_history_size = 25; @@ -231,7 +232,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) +Encoder::process_video (shared_ptr image, bool same, shared_ptr sub) { FrameRateConversion frc (_film->video_frame_rate(), _film->dcp_frame_rate()); @@ -269,7 +270,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr const s = Filter::ffmpeg_strings (_film->filters()); TIMING ("adding to queue of %1", _queue.size ()); - _queue.push_back (boost::shared_ptr ( + _queue.push_back (shared_ptr ( new DCPVideoFrame ( image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), @@ -360,7 +361,7 @@ Encoder::encoder_thread (ServerDescription* server) } TIMING ("encoder thread %1 wakes with queue of %2", boost::this_thread::get_id(), _queue.size()); - boost::shared_ptr vf = _queue.front (); + shared_ptr vf = _queue.front (); _film->log()->log (String::compose (N_("Encoder thread %1 pops frame %2 from queue"), boost::this_thread::get_id(), vf->frame()), Log::VERBOSE); _queue.pop_front (); diff --git a/src/lib/film.cc b/src/lib/film.cc index a9d7b7381..976f65313 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -1178,7 +1178,7 @@ Film::ffmpeg () const vector Film::ffmpeg_subtitle_streams () const { - boost::shared_ptr f = ffmpeg (); + shared_ptr f = ffmpeg (); if (f) { return f->subtitle_streams (); } @@ -1189,7 +1189,7 @@ Film::ffmpeg_subtitle_streams () const boost::optional Film::ffmpeg_subtitle_stream () const { - boost::shared_ptr f = ffmpeg (); + shared_ptr f = ffmpeg (); if (f) { return f->subtitle_stream (); } @@ -1200,7 +1200,7 @@ Film::ffmpeg_subtitle_stream () const vector Film::ffmpeg_audio_streams () const { - boost::shared_ptr f = ffmpeg (); + shared_ptr f = ffmpeg (); if (f) { return f->audio_streams (); } @@ -1211,7 +1211,7 @@ Film::ffmpeg_audio_streams () const boost::optional Film::ffmpeg_audio_stream () const { - boost::shared_ptr f = ffmpeg (); + shared_ptr f = ffmpeg (); if (f) { return f->audio_stream (); } @@ -1222,7 +1222,7 @@ Film::ffmpeg_audio_stream () const void Film::set_ffmpeg_subtitle_stream (FFmpegSubtitleStream s) { - boost::shared_ptr f = ffmpeg (); + shared_ptr f = ffmpeg (); if (f) { f->set_subtitle_stream (s); } @@ -1231,7 +1231,7 @@ Film::set_ffmpeg_subtitle_stream (FFmpegSubtitleStream s) void Film::set_ffmpeg_audio_stream (FFmpegAudioStream s) { - boost::shared_ptr f = ffmpeg (); + shared_ptr f = ffmpeg (); if (f) { f->set_audio_stream (s); } diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 48f6ed912..77ed9b651 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -37,7 +37,7 @@ Matcher::Matcher (shared_ptr log, int sample_rate, float frames_per_second) } void -Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) +Matcher::process_video (shared_ptr i, bool same, shared_ptr s) { Video (i, same, s); _video_frames++; @@ -47,7 +47,7 @@ Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr } void -Matcher::process_audio (boost::shared_ptr b) +Matcher::process_audio (shared_ptr b) { Audio (b); _audio_frames += b->frames (); diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 8101a6d36..1c4d6466c 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -27,7 +27,7 @@ using boost::bind; static void process_video_proxy (weak_ptr sink, shared_ptr i, bool same, shared_ptr s) { - boost::shared_ptr p = sink.lock (); + shared_ptr p = sink.lock (); if (p) { p->process_video (i, same, s); } diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index 242d37b1e..1241c2e76 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -84,7 +84,7 @@ AudioDialog::AudioDialog (wxWindow* parent) } void -AudioDialog::set_film (boost::shared_ptr f) +AudioDialog::set_film (shared_ptr f) { _film_changed_connection.disconnect (); _film_audio_analysis_succeeded_connection.disconnect (); diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index f6d0f77dc..316a42a66 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -290,7 +290,7 @@ FilmViewer::raw_to_display () old_size = _display_frame->size(); } - boost::shared_ptr input = _raw_frame; + shared_ptr input = _raw_frame; pair const s = Filter::ffmpeg_strings (_film->filters()); if (!s.second.empty ()) { diff --git a/src/wx/job_manager_view.cc b/src/wx/job_manager_view.cc index f7d2315cc..a7788ddd0 100644 --- a/src/wx/job_manager_view.cc +++ b/src/wx/job_manager_view.cc @@ -135,7 +135,7 @@ JobManagerView::details_clicked (wxCommandEvent& ev) { wxObject* o = ev.GetEventObject (); - for (map, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) { + for (map, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) { if (i->second.details == o) { string s = i->first->error_summary(); s[0] = toupper (s[0]); @@ -149,7 +149,7 @@ JobManagerView::cancel_clicked (wxCommandEvent& ev) { wxObject* o = ev.GetEventObject (); - for (map, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) { + for (map, JobRecord>::iterator i = _job_records.begin(); i != _job_records.end(); ++i) { if (i->second.cancel == o) { i->first->cancel (); } -- cgit v1.2.3 From 8750efb9e072cf3b42e6c3c29521c7031c0b5dfd Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 6 Apr 2013 14:42:08 +0100 Subject: Basics of content dialogs. --- src/lib/audio_content.cc | 4 ++ src/lib/audio_content.h | 8 +++ src/lib/audio_mapping.cc | 103 +++++++++++++++++++++++++++++++++++ src/lib/audio_mapping.h | 53 ++++++++++++++++++ src/lib/encoder.cc | 3 +- src/lib/sndfile_content.cc | 84 +++++++++++++++++----------- src/lib/sndfile_content.h | 32 +++++++++-- src/lib/sndfile_decoder.cc | 65 +++++++++++----------- src/lib/sndfile_decoder.h | 8 +++ src/lib/util.cc | 52 ------------------ src/lib/util.h | 13 ----- src/lib/writer.cc | 3 +- src/lib/wscript | 1 + src/wx/audio_dialog.cc | 7 ++- src/wx/film_editor.cc | 79 +++++++++++---------------- src/wx/film_editor.h | 5 +- src/wx/imagemagick_content_dialog.cc | 62 +++++++++++++++++++++ src/wx/imagemagick_content_dialog.h | 34 ++++++++++++ src/wx/sndfile_content_dialog.cc | 67 +++++++++++++++++++++++ src/wx/sndfile_content_dialog.h | 36 ++++++++++++ src/wx/wscript | 2 + 21 files changed, 536 insertions(+), 185 deletions(-) create mode 100644 src/lib/audio_mapping.cc create mode 100644 src/lib/audio_mapping.h create mode 100644 src/wx/imagemagick_content_dialog.cc create mode 100644 src/wx/imagemagick_content_dialog.h create mode 100644 src/wx/sndfile_content_dialog.cc create mode 100644 src/wx/sndfile_content_dialog.h (limited to 'src/lib/encoder.cc') diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index 8ca1e83c9..9968f4725 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -22,6 +22,10 @@ using boost::shared_ptr; +int const AudioContentProperty::AUDIO_CHANNELS = 200; +int const AudioContentProperty::AUDIO_LENGTH = 201; +int const AudioContentProperty::AUDIO_FRAME_RATE = 202; + AudioContent::AudioContent (boost::filesystem::path f) : Content (f) { diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index 2bfc20656..d5dbf266b 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -27,6 +27,14 @@ namespace cxml { class Node; } +class AudioContentProperty +{ +public: + static int const AUDIO_CHANNELS; + static int const AUDIO_LENGTH; + static int const AUDIO_FRAME_RATE; +}; + class AudioContent : public virtual Content { public: diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc new file mode 100644 index 000000000..3fc423e10 --- /dev/null +++ b/src/lib/audio_mapping.cc @@ -0,0 +1,103 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 "audio_mapping.h" + +using std::map; +using boost::optional; + +AutomaticAudioMapping::AutomaticAudioMapping (int c) + : _source_channels (c) +{ + +} + +optional +AutomaticAudioMapping::source_to_dcp (int c) const +{ + if (c >= _source_channels) { + return optional (); + } + + if (_source_channels == 1) { + /* mono sources to centre */ + return libdcp::CENTRE; + } + + return static_cast (c); +} + +optional +AutomaticAudioMapping::dcp_to_source (libdcp::Channel c) const +{ + if (_source_channels == 1) { + if (c == libdcp::CENTRE) { + return 0; + } else { + return optional (); + } + } + + if (static_cast (c) >= _source_channels) { + return optional (); + } + + return static_cast (c); +} + +int +AutomaticAudioMapping::dcp_channels () const +{ + if (_source_channels == 1) { + /* The source is mono, so to put the mono channel into + the centre we need to generate a 5.1 soundtrack. + */ + return 6; + } + + return _source_channels; +} + +optional +ConfiguredAudioMapping::dcp_to_source (libdcp::Channel c) const +{ + map::const_iterator i = _source_to_dcp.begin (); + while (i != _source_to_dcp.end() && i->second != c) { + ++i; + } + + if (i == _source_to_dcp.end ()) { + return boost::none; + } + + return i->first; +} + +optional +ConfiguredAudioMapping::source_to_dcp (int c) const +{ + map::const_iterator i = _source_to_dcp.find (c); + if (i == _source_to_dcp.end ()) { + return boost::none; + } + + return i->second; +} + + diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h new file mode 100644 index 000000000..8804bde06 --- /dev/null +++ b/src/lib/audio_mapping.h @@ -0,0 +1,53 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include +#include +#include + +class AudioMapping +{ +public: + virtual boost::optional source_to_dcp (int c) const = 0; + virtual boost::optional dcp_to_source (libdcp::Channel c) const = 0; +}; + +class AutomaticAudioMapping : public AudioMapping +{ +public: + AutomaticAudioMapping (int); + + boost::optional source_to_dcp (int c) const; + boost::optional dcp_to_source (libdcp::Channel c) const; + int dcp_channels () const; + +private: + int _source_channels; +}; + +class ConfiguredAudioMapping : public AudioMapping +{ +public: + boost::optional source_to_dcp (int c) const; + boost::optional dcp_to_source (libdcp::Channel c) const; + +private: + std::map _source_to_dcp; +}; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 568307462..a0b88e33e 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -38,6 +38,7 @@ #include "cross.h" #include "writer.h" #include "player.h" +#include "audio_mapping.h" #include "i18n.h" @@ -426,7 +427,7 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { - AudioMapping m (_film->audio_channels ()); + AutomaticAudioMapping m (_film->audio_channels ()); if (m.dcp_channels() != _film->audio_channels()) { /* Remap (currently just for mono -> 5.1) */ diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index 684405efb..ee4f21eef 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -17,13 +17,18 @@ */ +#include #include "sndfile_content.h" +#include "sndfile_decoder.h" #include "compose.hpp" +#include "job.h" #include "i18n.h" using std::string; +using std::stringstream; using boost::shared_ptr; +using boost::lexical_cast; SndfileContent::SndfileContent (boost::filesystem::path f) : Content (f) @@ -35,9 +40,10 @@ SndfileContent::SndfileContent (boost::filesystem::path f) SndfileContent::SndfileContent (shared_ptr node) : Content (node) , AudioContent (node) - { - + _audio_channels = node->number_child ("AudioChannels"); + _audio_length = node->number_child ("AudioLength"); + _audio_frame_rate = node->number_child ("AudioFrameRate"); } string @@ -49,37 +55,21 @@ SndfileContent::summary () const string SndfileContent::information () const { - return ""; -} - -int -SndfileContent::audio_channels () const -{ - /* XXX */ - return 0; -} - -ContentAudioFrame -SndfileContent::audio_length () const -{ - /* XXX */ - return 0; -} - -int -SndfileContent::audio_frame_rate () const -{ - /* XXX */ - return 0; -} - -int64_t -SndfileContent::audio_channel_layout () const -{ - /* XXX */ - return 0; -} + if (_audio_frame_rate == 0) { + return ""; + } + + stringstream s; + + s << String::compose ( + _("%1 channels, %2kHz, %3 samples"), + audio_channels(), + audio_frame_rate() / 1000.0, + audio_length() + ); + return s.str (); +} bool SndfileContent::valid_file (boost::filesystem::path f) @@ -95,3 +85,33 @@ SndfileContent::clone () const { return shared_ptr (new SndfileContent (*this)); } + +void +SndfileContent::examine (shared_ptr film, shared_ptr job, bool quick) +{ + job->set_progress_unknown (); + Content::examine (film, job, quick); + + SndfileDecoder dec (film, shared_from_this()); + + { + boost::mutex::scoped_lock lm (_mutex); + _audio_channels = dec.audio_channels (); + _audio_length = dec.audio_length (); + _audio_frame_rate = dec.audio_frame_rate (); + } + + signal_changed (AudioContentProperty::AUDIO_CHANNELS); + signal_changed (AudioContentProperty::AUDIO_LENGTH); + signal_changed (AudioContentProperty::AUDIO_FRAME_RATE); +} + +void +SndfileContent::as_xml (xmlpp::Node* node) const +{ + node->add_child("Type")->add_child_text ("Sndfile"); + Content::as_xml (node); + node->add_child("AudioChannels")->add_child_text (lexical_cast (_audio_channels)); + node->add_child("AudioLength")->add_child_text (lexical_cast (_audio_length)); + node->add_child("AudioFrameRate")->add_child_text (lexical_cast (_audio_frame_rate)); +} diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index b696b57a5..27c5f3615 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -17,6 +17,9 @@ */ +extern "C" { +#include +} #include "audio_content.h" namespace cxml { @@ -33,15 +36,36 @@ public: return boost::dynamic_pointer_cast (Content::shared_from_this ()); } + void examine (boost::shared_ptr, boost::shared_ptr, bool); std::string summary () const; std::string information () const; + void as_xml (xmlpp::Node *) const; boost::shared_ptr clone () const; /* AudioContent */ - int audio_channels () const; - ContentAudioFrame audio_length () const; - int audio_frame_rate () const; - int64_t audio_channel_layout () const; + int audio_channels () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_channels; + } + + ContentAudioFrame audio_length () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_length; + } + + int audio_frame_rate () const { + boost::mutex::scoped_lock lm (_mutex); + return _audio_frame_rate; + } + + int64_t audio_channel_layout () const { + return av_get_default_channel_layout (audio_channels ()); + } static bool valid_file (boost::filesystem::path); + +private: + int _audio_channels; + ContentAudioFrame _audio_length; + int _audio_frame_rate; }; diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index 1f97e5c41..c7311112a 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -28,59 +28,62 @@ using std::vector; using std::string; -using std::stringstream; using std::min; using std::cout; using boost::shared_ptr; -using boost::optional; - -/* XXX */ SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) : Decoder (f) , AudioDecoder (f) + , _sndfile_content (c) { - sf_count_t frames; - SNDFILE* sf = open_file (frames); - sf_close (sf); + _sndfile = sf_open (_sndfile_content->file().string().c_str(), SFM_READ, &_info); + if (!_sndfile) { + throw DecodeError (_("could not open audio file for reading")); + } + + _remaining = _info.frames; } -SNDFILE* -SndfileDecoder::open_file (sf_count_t & frames) +SndfileDecoder::~SndfileDecoder () { - frames = 0; - - SF_INFO info; - SNDFILE* s = sf_open (_sndfile_content->file().string().c_str(), SFM_READ, &info); - if (!s) { - throw DecodeError (_("could not open external audio file for reading")); + if (_sndfile) { + sf_close (_sndfile); } - - frames = info.frames; - return s; } bool SndfileDecoder::pass () { - sf_count_t frames; - SNDFILE* sndfile = open_file (frames); - /* Do things in half second blocks as I think there may be limits to what FFmpeg (and in particular the resampler) can cope with. */ sf_count_t const block = _sndfile_content->audio_frame_rate() / 2; + sf_count_t const this_time = min (block, _remaining); + + shared_ptr audio (new AudioBuffers (_sndfile_content->audio_channels(), this_time)); + sf_read_float (_sndfile, audio->data(0), this_time); + audio->set_frames (this_time); + Audio (audio); + _remaining -= this_time; - shared_ptr audio (new AudioBuffers (_sndfile_content->audio_channels(), block)); - while (frames > 0) { - sf_count_t const this_time = min (block, frames); - sf_read_float (sndfile, audio->data(0), this_time); - audio->set_frames (this_time); - Audio (audio); - frames -= this_time; - } + return (_remaining == 0); +} - sf_close (sndfile); +int +SndfileDecoder::audio_channels () const +{ + return _info.channels; +} - return true; +ContentAudioFrame +SndfileDecoder::audio_length () const +{ + return _info.frames; +} + +int +SndfileDecoder::audio_frame_rate () const +{ + return _info.samplerate; } diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index 56fc3a9f0..2900afea0 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -27,12 +27,20 @@ class SndfileDecoder : public AudioDecoder { public: SndfileDecoder (boost::shared_ptr, boost::shared_ptr); + ~SndfileDecoder (); bool pass (); + int audio_channels () const; + ContentAudioFrame audio_length () const; + int audio_frame_rate () const; + private: SNDFILE* open_file (sf_count_t &); void close_file (SNDFILE*); boost::shared_ptr _sndfile_content; + SNDFILE* _sndfile; + SF_INFO _info; + ContentAudioFrame _remaining; }; diff --git a/src/lib/util.cc b/src/lib/util.cc index e0de82c64..1e60b43fc 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -914,58 +914,6 @@ audio_channel_name (int c) return channels[c]; } -AudioMapping::AudioMapping (int c) - : _source_channels (c) -{ - -} - -optional -AudioMapping::source_to_dcp (int c) const -{ - if (c >= _source_channels) { - return optional (); - } - - if (_source_channels == 1) { - /* mono sources to centre */ - return libdcp::CENTRE; - } - - return static_cast (c); -} - -optional -AudioMapping::dcp_to_source (libdcp::Channel c) const -{ - if (_source_channels == 1) { - if (c == libdcp::CENTRE) { - return 0; - } else { - return optional (); - } - } - - if (static_cast (c) >= _source_channels) { - return optional (); - } - - return static_cast (c); -} - -int -AudioMapping::dcp_channels () const -{ - if (_source_channels == 1) { - /* The source is mono, so to put the mono channel into - the centre we need to generate a 5.1 soundtrack. - */ - return 6; - } - - return _source_channels; -} - FrameRateConversion::FrameRateConversion (float source, int dcp) : skip (false) , repeat (false) diff --git a/src/lib/util.h b/src/lib/util.h index 23ebd52bc..1fe6212e4 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -194,19 +194,6 @@ private: float** _data; }; -class AudioMapping -{ -public: - AudioMapping (int); - - boost::optional source_to_dcp (int c) const; - boost::optional dcp_to_source (libdcp::Channel c) const; - int dcp_channels () const; - -private: - int _source_channels; -}; - extern int64_t video_frames_to_audio_frames (ContentVideoFrame v, float audio_sample_rate, float frames_per_second); extern std::pair cpu_info (); diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 5d38860e7..6df1a1f21 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -31,6 +31,7 @@ #include "dcp_video_frame.h" #include "dcp_content_type.h" #include "player.h" +#include "audio_mapping.h" #include "i18n.h" @@ -77,7 +78,7 @@ Writer::Writer (shared_ptr f) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - AudioMapping m (_film->audio_channels ()); + AutomaticAudioMapping m (_film->audio_channels ()); if (m.dcp_channels() > 0) { _sound_asset.reset ( diff --git a/src/lib/wscript b/src/lib/wscript index 32a2cde23..896598a0e 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -8,6 +8,7 @@ sources = """ audio_analysis.cc audio_content.cc audio_decoder.cc + audio_mapping.cc audio_source.cc config.cc combiner.cc diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index 1241c2e76..f53ea7c19 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -20,6 +20,7 @@ #include #include "lib/audio_analysis.h" #include "lib/film.h" +#include "lib/audio_mapping.h" #include "audio_dialog.h" #include "audio_plot.h" #include "wx_util.h" @@ -108,7 +109,7 @@ AudioDialog::setup_channels () return; } - AudioMapping m (_film->audio_channels ()); + AutomaticAudioMapping m (_film->audio_channels ()); for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (m.dcp_to_source(static_cast(i))) { @@ -134,7 +135,7 @@ AudioDialog::try_to_load_analysis () _plot->set_analysis (a); - AudioMapping m (_film->audio_channels ()); + AutomaticAudioMapping m (_film->audio_channels ()); optional c = m.source_to_dcp (0); if (c) { _channel_checkbox[c.get()]->SetValue (true); @@ -157,7 +158,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) assert (c < MAX_AUDIO_CHANNELS); - AudioMapping m (_film->audio_channels ()); + AutomaticAudioMapping m (_film->audio_channels ()); optional s = m.dcp_to_source (static_cast (c)); if (s) { _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 58fc077a3..6c42359fb 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -49,6 +49,8 @@ #include "dci_metadata_dialog.h" #include "scaler.h" #include "audio_dialog.h" +#include "imagemagick_content_dialog.h" +#include "sndfile_content_dialog.h" using std::string; using std::cout; @@ -198,9 +200,9 @@ FilmEditor::connect_to_widgets () _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_item_selected), 0, this); _content_add->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this); _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_remove_clicked), 0, this); + _content_edit->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_edit_clicked), 0, this); _content_earlier->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_earlier_clicked), 0, this); _content_later->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_later_clicked), 0, this); - _imagemagick_video_length->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::imagemagick_video_length_changed), 0, this); _left_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::left_crop_changed), 0, this); _right_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::right_crop_changed), 0, this); _top_crop->Connect (wxID_ANY, wxEVT_COMMAND_SPINCTRL_UPDATED, wxCommandEventHandler (FilmEditor::top_crop_changed), 0, this); @@ -343,6 +345,8 @@ FilmEditor::make_content_panel () b->Add (_content_add); _content_remove = new wxButton (_content_panel, wxID_ANY, _("Remove")); b->Add (_content_remove); + _content_edit = new wxButton (_content_panel, wxID_ANY, _("Edit...")); + b->Add (_content_edit); _content_earlier = new wxButton (_content_panel, wxID_ANY, _("Earlier")); b->Add (_content_earlier); _content_later = new wxButton (_content_panel, wxID_ANY, _("Later")); @@ -355,21 +359,6 @@ FilmEditor::make_content_panel () _content_information = new wxTextCtrl (_content_panel, wxID_ANY, wxT ("\n\n\n\n"), wxDefaultPosition, wxDefaultSize, wxTE_READONLY | wxTE_MULTILINE); _content_sizer->Add (_content_information, 1, wxEXPAND | wxALL, 6); - - wxFlexGridSizer* grid = new wxFlexGridSizer (2, 4, 4); - _content_sizer->Add (grid, 0, wxEXPAND | wxALL, 6); - - { - add_label_to_sizer (grid, _content_panel, (_("Duration"))); - wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); - _imagemagick_video_length = new wxSpinCtrl (_content_panel); - s->Add (_imagemagick_video_length); - /// TRANSLATORS: this is an abbreviation for seconds, the unit of time - add_label_to_sizer (s, _content_panel, _("s")); - grid->Add (s); - } - - _imagemagick_video_length->SetRange (1, 3600); } void @@ -723,14 +712,9 @@ FilmEditor::film_content_changed (weak_ptr content, int property) setup_show_audio_sensitivity (); } else if (property == VideoContentProperty::VIDEO_LENGTH) { setup_length (); - boost::shared_ptr c = content.lock (); if (c && c == selected_content()) { setup_content_information (); - shared_ptr im = dynamic_pointer_cast (c); - if (im) { - checked_set (_imagemagick_video_length, im->video_length() / 24); - } } } else if (property == FFmpegContentProperty::AUDIO_STREAM) { if (_film->ffmpeg_audio_stream()) { @@ -1258,6 +1242,33 @@ FilmEditor::content_remove_clicked (wxCommandEvent &) } } +void +FilmEditor::content_edit_clicked (wxCommandEvent &) +{ + shared_ptr c = selected_content (); + if (!c) { + return; + } + + shared_ptr im = dynamic_pointer_cast (c); + if (im) { + ImageMagickContentDialog* d = new ImageMagickContentDialog (this, im); + int const r = d->ShowModal (); + d->Destroy (); + + if (r == wxID_OK) { + im->set_video_length (d->video_length() * 24); + } + } + + shared_ptr sf = dynamic_pointer_cast (c); + if (sf) { + SndfileContentDialog* d = new SndfileContentDialog (this, sf); + d->ShowModal (); + d->Destroy (); + } +} + void FilmEditor::content_earlier_clicked (wxCommandEvent &) { @@ -1281,15 +1292,6 @@ FilmEditor::content_item_selected (wxListEvent &) { setup_content_button_sensitivity (); setup_content_information (); - - shared_ptr c = selected_content (); - if (c) { - shared_ptr im = dynamic_pointer_cast (c); - _imagemagick_video_length->Enable (im); - if (im) { - checked_set (_imagemagick_video_length, im->video_length() / 24); - } - } } void @@ -1310,27 +1312,12 @@ FilmEditor::setup_content_button_sensitivity () _content_add->Enable (_generally_sensitive); bool const have_selection = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1; + _content_edit->Enable (have_selection && _generally_sensitive); _content_remove->Enable (have_selection && _generally_sensitive); _content_earlier->Enable (have_selection && _generally_sensitive); _content_later->Enable (have_selection && _generally_sensitive); } -void -FilmEditor::imagemagick_video_length_changed (wxCommandEvent &) -{ - shared_ptr c = selected_content (); - if (!c) { - return; - } - - shared_ptr im = dynamic_pointer_cast (c); - if (!im) { - return; - } - - im->set_video_length (_imagemagick_video_length->GetValue() * 24); -} - shared_ptr FilmEditor::selected_content () { diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 2870714f9..b6f6a24ee 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -16,7 +16,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ - + /** @file src/film_editor.h * @brief A wx widget to edit a film's metadata, and perform various functions. */ @@ -66,6 +66,7 @@ private: void content_item_selected (wxListEvent &); void content_add_clicked (wxCommandEvent &); void content_remove_clicked (wxCommandEvent &); + void content_edit_clicked (wxCommandEvent &); void content_earlier_clicked (wxCommandEvent &); void content_later_clicked (wxCommandEvent &); void imagemagick_video_length_changed (wxCommandEvent &); @@ -131,10 +132,10 @@ private: wxListCtrl* _content; wxButton* _content_add; wxButton* _content_remove; + wxButton* _content_edit; wxButton* _content_earlier; wxButton* _content_later; wxTextCtrl* _content_information; - wxSpinCtrl* _imagemagick_video_length; wxButton* _edit_dci_button; wxChoice* _format; wxStaticText* _format_description; diff --git a/src/wx/imagemagick_content_dialog.cc b/src/wx/imagemagick_content_dialog.cc new file mode 100644 index 000000000..726e4b8e2 --- /dev/null +++ b/src/wx/imagemagick_content_dialog.cc @@ -0,0 +1,62 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include "lib/imagemagick_content.h" +#include "imagemagick_content_dialog.h" +#include "wx_util.h" + +using boost::shared_ptr; + +ImageMagickContentDialog::ImageMagickContentDialog (wxWindow* parent, shared_ptr content) + : wxDialog (parent, wxID_ANY, _("Image")) +{ + wxFlexGridSizer* grid = new wxFlexGridSizer (3, 6, 6); + grid->AddGrowableCol (1, 1); + + { + add_label_to_sizer (grid, this, (_("Duration"))); + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + _video_length = new wxSpinCtrl (this); + s->Add (_video_length); + /// TRANSLATORS: this is an abbreviation for seconds, the unit of time + add_label_to_sizer (s, this, _("s")); + grid->Add (s); + } + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (grid, 1, wxEXPAND | wxALL, 6); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); + + checked_set (_video_length, content->video_length () / 24); +} + +int +ImageMagickContentDialog::video_length () const +{ + return _video_length->GetValue (); +} diff --git a/src/wx/imagemagick_content_dialog.h b/src/wx/imagemagick_content_dialog.h new file mode 100644 index 000000000..2fa955929 --- /dev/null +++ b/src/wx/imagemagick_content_dialog.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 + +class wxSpinCtrl; +class ImageMagickContent; + +class ImageMagickContentDialog : public wxDialog +{ +public: + ImageMagickContentDialog (wxWindow *, boost::shared_ptr); + + int video_length () const; + +private: + wxSpinCtrl* _video_length; +}; diff --git a/src/wx/sndfile_content_dialog.cc b/src/wx/sndfile_content_dialog.cc new file mode 100644 index 000000000..f305b158c --- /dev/null +++ b/src/wx/sndfile_content_dialog.cc @@ -0,0 +1,67 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 "lib/util.h" +#include "lib/sndfile_content.h" +#include "sndfile_content_dialog.h" +#include "wx_util.h" + +using boost::shared_ptr; + +SndfileContentDialog::SndfileContentDialog (wxWindow* parent, shared_ptr content) + : wxDialog (parent, wxID_ANY, _("Sound file")) +{ + wxFlexGridSizer* grid = new wxFlexGridSizer (7, 6, 0); + + add_label_to_sizer (grid, this, wxT ("")); + add_label_to_sizer (grid, this, _("L")); + add_label_to_sizer (grid, this, _("R")); + add_label_to_sizer (grid, this, _("C")); + add_label_to_sizer (grid, this, _("Lfe")); + add_label_to_sizer (grid, this, _("Ls")); + add_label_to_sizer (grid, this, _("Rs")); + + _buttons.resize (content->audio_channels ()); + for (int i = 0; i < content->audio_channels(); ++i) { + + if (content->audio_channels() == 1) { + add_label_to_sizer (grid, this, _("Source")); + } else { + add_label_to_sizer (grid, this, wxString::Format (_("Source %d"), i + 1)); + } + + for (int j = 0; j < MAX_AUDIO_CHANNELS; ++j) { + wxRadioButton* b = new wxRadioButton (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, j ? 0 : wxRB_GROUP); + _buttons[i].push_back (b); + grid->Add (b, wxSHRINK); + } + } + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (grid, 1, wxEXPAND | wxALL, 6); + + wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); + if (buttons) { + overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + } + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); +} diff --git a/src/wx/sndfile_content_dialog.h b/src/wx/sndfile_content_dialog.h new file mode 100644 index 000000000..5a328892a --- /dev/null +++ b/src/wx/sndfile_content_dialog.h @@ -0,0 +1,36 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include +#include +#include "lib/audio_mapping.h" + +class SndfileContent; + +class SndfileContentDialog : public wxDialog +{ +public: + SndfileContentDialog (wxWindow *, boost::shared_ptr); + + ConfiguredAudioMapping audio_mapping () const; + +private: + std::vector > _buttons; +}; diff --git a/src/wx/wscript b/src/wx/wscript index 42bb8ca88..bd21af6ce 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -14,11 +14,13 @@ sources = """ filter_dialog.cc filter_view.cc gain_calculator_dialog.cc + imagemagick_content_dialog.cc job_manager_view.cc job_wrapper.cc new_film_dialog.cc properties_dialog.cc server_dialog.cc + sndfile_content_dialog.cc wx_util.cc wx_ui_signaller.cc """ -- cgit v1.2.3 From c921cfe23b593d7c367ad76094308c5f08037374 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 6 Apr 2013 23:57:46 +0100 Subject: Various work on audio channel mapping. --- src/lib/analyse_audio_job.cc | 4 +- src/lib/audio_mapping.cc | 100 ++++++++++++------------- src/lib/audio_mapping.h | 52 +++++++------ src/lib/encoder.cc | 3 + src/lib/ffmpeg_content.cc | 3 +- src/lib/film.cc | 16 +++- src/lib/film.h | 12 ++- src/lib/imagemagick_content.cc | 2 +- src/lib/playlist.cc | 45 +++++++++++ src/lib/playlist.h | 3 + src/lib/sndfile_content.cc | 7 +- src/lib/writer.cc | 6 +- src/wx/audio_dialog.cc | 36 +-------- src/wx/audio_dialog.h | 1 - src/wx/audio_mapping_view.cc | 156 +++++++++++++++++++++++++++++++++++++++ src/wx/audio_mapping_view.h | 35 +++++++++ src/wx/film_editor.cc | 55 +++++++++----- src/wx/film_editor.h | 6 +- src/wx/sndfile_content_dialog.cc | 67 ----------------- src/wx/sndfile_content_dialog.h | 36 --------- src/wx/wscript | 2 +- 21 files changed, 401 insertions(+), 246 deletions(-) create mode 100644 src/wx/audio_mapping_view.cc create mode 100644 src/wx/audio_mapping_view.h delete mode 100644 src/wx/sndfile_content_dialog.cc delete mode 100644 src/wx/sndfile_content_dialog.h (limited to 'src/lib/encoder.cc') diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 5ef6515dd..50096d7c1 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -57,8 +57,8 @@ AnalyseAudioJob::run () _samples_per_point = max (int64_t (1), _film->audio_length() / _num_points); - _current.resize (_film->audio_channels ()); - _analysis.reset (new AudioAnalysis (_film->audio_channels())); + _current.resize (MAX_AUDIO_CHANNELS); + _analysis.reset (new AudioAnalysis (MAX_AUDIO_CHANNELS)); while (!player->pass()) { set_progress (float (_done) / _film->audio_length ()); diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc index 3fc423e10..48cc23307 100644 --- a/src/lib/audio_mapping.cc +++ b/src/lib/audio_mapping.cc @@ -19,85 +19,77 @@ #include "audio_mapping.h" -using std::map; -using boost::optional; - -AutomaticAudioMapping::AutomaticAudioMapping (int c) - : _source_channels (c) +using std::list; +using std::cout; +using std::make_pair; +using std::pair; +using boost::shared_ptr; + +void +AudioMapping::add (Channel c, libdcp::Channel d) { - + _content_to_dcp.push_back (make_pair (c, d)); } -optional -AutomaticAudioMapping::source_to_dcp (int c) const +/* XXX: this is grotty */ +int +AudioMapping::dcp_channels () const { - if (c >= _source_channels) { - return optional (); + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (((int) i->second) > 2) { + return 6; + } } - if (_source_channels == 1) { - /* mono sources to centre */ - return libdcp::CENTRE; - } - - return static_cast (c); + return 2; } -optional -AutomaticAudioMapping::dcp_to_source (libdcp::Channel c) const +list +AudioMapping::dcp_to_content (libdcp::Channel d) const { - if (_source_channels == 1) { - if (c == libdcp::CENTRE) { - return 0; - } else { - return optional (); + list c; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (i->second == d) { + c.push_back (i->first); } } - if (static_cast (c) >= _source_channels) { - return optional (); - } - - return static_cast (c); + return c; } -int -AutomaticAudioMapping::dcp_channels () const +list +AudioMapping::content_channels () const { - if (_source_channels == 1) { - /* The source is mono, so to put the mono channel into - the centre we need to generate a 5.1 soundtrack. - */ - return 6; + list c; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (find (c.begin(), c.end(), i->first) == c.end ()) { + c.push_back (i->first); + } } - return _source_channels; + return c; } -optional -ConfiguredAudioMapping::dcp_to_source (libdcp::Channel c) const +list +AudioMapping::content_to_dcp (Channel c) const { - map::const_iterator i = _source_to_dcp.begin (); - while (i != _source_to_dcp.end() && i->second != c) { - ++i; - } - - if (i == _source_to_dcp.end ()) { - return boost::none; + list d; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + if (i->first == c) { + d.push_back (i->second); + } } - return i->first; + return d; } -optional -ConfiguredAudioMapping::source_to_dcp (int c) const +bool +operator== (AudioMapping::Channel const & a, AudioMapping::Channel const & b) { - map::const_iterator i = _source_to_dcp.find (c); - if (i == _source_to_dcp.end ()) { - return boost::none; - } - - return i->second; + shared_ptr sa = a.content.lock (); + shared_ptr sb = b.content.lock (); + return sa == sb && a.index == b.index; } + diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h index 8804bde06..10ac20b48 100644 --- a/src/lib/audio_mapping.h +++ b/src/lib/audio_mapping.h @@ -17,37 +17,43 @@ */ -#include -#include -#include +#ifndef DVDOMATIC_AUDIO_MAPPING_H +#define DVDOMATIC_AUDIO_MAPPING_H + +#include +#include #include +#include +#include "audio_content.h" class AudioMapping { public: - virtual boost::optional source_to_dcp (int c) const = 0; - virtual boost::optional dcp_to_source (libdcp::Channel c) const = 0; -}; - -class AutomaticAudioMapping : public AudioMapping -{ -public: - AutomaticAudioMapping (int); + struct Channel { + Channel (boost::weak_ptr c, int i) + : content (c) + , index (i) + {} + + boost::weak_ptr content; + int index; + }; + + void add (Channel, libdcp::Channel); - boost::optional source_to_dcp (int c) const; - boost::optional dcp_to_source (libdcp::Channel c) const; int dcp_channels () const; - -private: - int _source_channels; -}; + std::list dcp_to_content (libdcp::Channel) const; + std::list > content_to_dcp () const { + return _content_to_dcp; + } -class ConfiguredAudioMapping : public AudioMapping -{ -public: - boost::optional source_to_dcp (int c) const; - boost::optional dcp_to_source (libdcp::Channel c) const; + std::list content_channels () const; + std::list content_to_dcp (Channel) const; private: - std::map _source_to_dcp; + std::list > _content_to_dcp; }; + +extern bool operator== (AudioMapping::Channel const &, AudioMapping::Channel const &); + +#endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index a0b88e33e..0542587a0 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -427,6 +427,8 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { +#if 0 + XXX AutomaticAudioMapping m (_film->audio_channels ()); if (m.dcp_channels() != _film->audio_channels()) { @@ -444,6 +446,7 @@ Encoder::write_audio (shared_ptr data) data = b; } +#endif _writer->write (data); } diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index cc95105e5..d36abe2c3 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -152,12 +152,13 @@ FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) signal_changed (FFmpegContentProperty::SUBTITLE_STREAM); signal_changed (FFmpegContentProperty::AUDIO_STREAMS); signal_changed (FFmpegContentProperty::AUDIO_STREAM); + signal_changed (AudioContentProperty::AUDIO_CHANNELS); } string FFmpegContent::summary () const { - return String::compose (_("Movie: %1"), file().filename ()); + return String::compose (_("Movie: %1"), file().filename().string()); } string diff --git a/src/lib/film.cc b/src/lib/film.cc index 69d2a28e2..b1f740ec2 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -960,6 +960,7 @@ Film::signal_changed (Property p) case Film::CONTENT: _playlist->setup (content ()); set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ())); + set_audio_mapping (_playlist->default_audio_mapping ()); break; default: break; @@ -1235,12 +1236,25 @@ Film::set_ffmpeg_audio_stream (FFmpegAudioStream s) } } +void +Film::set_audio_mapping (AudioMapping m) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _audio_mapping = m; + } + + signal_changed (AUDIO_MAPPING); +} + void Film::content_changed (boost::weak_ptr c, int p) { if (p == VideoContentProperty::VIDEO_FRAME_RATE) { set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ())); - } + } else if (p == AudioContentProperty::AUDIO_CHANNELS) { + set_audio_mapping (_playlist->default_audio_mapping ()); + } if (ui_signaller) { ui_signaller->emit (boost::bind (boost::ref (ContentChanged), c, p)); diff --git a/src/lib/film.h b/src/lib/film.h index 9c5f561e6..532d32bdc 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -36,6 +36,7 @@ #include "dci_metadata.h" #include "types.h" #include "ffmpeg_content.h" +#include "audio_mapping.h" class DCPContentType; class Format; @@ -146,7 +147,8 @@ public: COLOUR_LUT, J2K_BANDWIDTH, DCI_METADATA, - DCP_FRAME_RATE + DCP_FRAME_RATE, + AUDIO_MAPPING }; @@ -262,6 +264,11 @@ public: return _dcp_frame_rate; } + AudioMapping audio_mapping () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _audio_mapping; + } + /* SET */ void set_directory (std::string); @@ -294,6 +301,7 @@ public: void set_dci_metadata (DCIMetadata); void set_dcp_frame_rate (int); void set_dci_date_today (); + void set_audio_mapping (AudioMapping); /** Emitted when some property has of the Film has changed */ mutable boost::signals2::signal Changed; @@ -314,6 +322,7 @@ private: void read_metadata (); void content_changed (boost::weak_ptr, int); boost::shared_ptr ffmpeg () const; + void setup_default_audio_mapping (); /** Log to write to */ boost::shared_ptr _log; @@ -378,6 +387,7 @@ private: int _dcp_frame_rate; /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; + AudioMapping _audio_mapping; /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index 912c180a8..59fde40bb 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -45,7 +45,7 @@ ImageMagickContent::ImageMagickContent (shared_ptr node) string ImageMagickContent::summary () const { - return String::compose (_("Image: %1"), file().filename ()); + return String::compose (_("Image: %1"), file().filename().string()); } bool diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index e0220ef6f..3f7905fa9 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -30,6 +30,7 @@ using std::list; using std::cout; using std::vector; +using std::min; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; @@ -224,3 +225,47 @@ Playlist::content_changed (weak_ptr c, int p) { ContentChanged (c, p); } + +AudioMapping +Playlist::default_audio_mapping () const +{ + AudioMapping m; + + switch (_audio_from) { + case AUDIO_NONE: + break; + case AUDIO_FFMPEG: + if (_ffmpeg->audio_channels() == 1) { + /* Map mono sources to centre */ + m.add (AudioMapping::Channel (_ffmpeg, 0), libdcp::CENTRE); + } else { + int const N = min (_ffmpeg->audio_channels (), MAX_AUDIO_CHANNELS); + /* Otherwise just start with a 1:1 mapping */ + for (int i = 0; i < N; ++i) { + m.add (AudioMapping::Channel (_ffmpeg, i), (libdcp::Channel) i); + } + } + break; + + case AUDIO_SNDFILE: + { + int n = 0; + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + cout << "sndfile " << (*i)->audio_channels() << "\n"; + for (int j = 0; j < (*i)->audio_channels(); ++j) { + m.add (AudioMapping::Channel (*i, j), (libdcp::Channel) n); + ++n; + if (n >= MAX_AUDIO_CHANNELS) { + break; + } + } + if (n >= MAX_AUDIO_CHANNELS) { + break; + } + } + break; + } + } + + return m; +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 1a24a0227..1d189cb07 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -25,6 +25,7 @@ #include "video_sink.h" #include "audio_sink.h" #include "ffmpeg_content.h" +#include "audio_mapping.h" class Content; class FFmpegContent; @@ -53,6 +54,8 @@ public: libdcp::Size video_size () const; ContentVideoFrame video_length () const; + AudioMapping default_audio_mapping () const; + enum VideoFrom { VIDEO_NONE, VIDEO_FFMPEG, diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index ee4f21eef..539b0dfb5 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -27,12 +27,16 @@ using std::string; using std::stringstream; +using std::cout; using boost::shared_ptr; using boost::lexical_cast; SndfileContent::SndfileContent (boost::filesystem::path f) : Content (f) , AudioContent (f) + , _audio_channels (0) + , _audio_length (0) + , _audio_frame_rate (0) { } @@ -49,7 +53,7 @@ SndfileContent::SndfileContent (shared_ptr node) string SndfileContent::summary () const { - return String::compose (_("Sound file: %1"), file().filename ()); + return String::compose (_("Sound file: %1"), file().filename().string()); } string @@ -115,3 +119,4 @@ SndfileContent::as_xml (xmlpp::Node* node) const node->add_child("AudioLength")->add_child_text (lexical_cast (_audio_length)); node->add_child("AudioFrameRate")->add_child_text (lexical_cast (_audio_frame_rate)); } + diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 6df1a1f21..7258826ba 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -78,15 +78,13 @@ Writer::Writer (shared_ptr f) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - AutomaticAudioMapping m (_film->audio_channels ()); - - if (m.dcp_channels() > 0) { + if (_film->audio_channels() > 0) { _sound_asset.reset ( new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), N_("audio.mxf"), _film->dcp_frame_rate (), - m.dcp_channels (), + _film->audio_mapping().dcp_channels (), dcp_audio_sample_rate (_film->audio_frame_rate()) ) ); diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index f53ea7c19..4c50260fa 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -20,7 +20,6 @@ #include #include "lib/audio_analysis.h" #include "lib/film.h" -#include "lib/audio_mapping.h" #include "audio_dialog.h" #include "audio_plot.h" #include "wx_util.h" @@ -93,7 +92,6 @@ AudioDialog::set_film (shared_ptr f) _film = f; try_to_load_analysis (); - setup_channels (); _plot->set_gain (_film->audio_gain ()); _film_changed_connection = _film->Changed.connect (bind (&AudioDialog::film_changed, this, _1)); @@ -102,23 +100,6 @@ AudioDialog::set_film (shared_ptr f) SetTitle (wxString::Format (_("DVD-o-matic audio - %s"), std_to_wx(_film->name()).data())); } -void -AudioDialog::setup_channels () -{ - if (!_film->has_audio()) { - return; - } - - AutomaticAudioMapping m (_film->audio_channels ()); - - for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { - if (m.dcp_to_source(static_cast(i))) { - _channel_checkbox[i]->Show (); - } else { - _channel_checkbox[i]->Hide (); - } - } -} void AudioDialog::try_to_load_analysis () @@ -135,12 +116,8 @@ AudioDialog::try_to_load_analysis () _plot->set_analysis (a); - AutomaticAudioMapping m (_film->audio_channels ()); - optional c = m.source_to_dcp (0); - if (c) { - _channel_checkbox[c.get()]->SetValue (true); - _plot->set_channel_visible (0, true); - } + _channel_checkbox[0]->SetValue (true); + _plot->set_channel_visible (0, true); for (int i = 0; i < AudioPoint::COUNT; ++i) { _type_checkbox[i]->SetValue (true); @@ -158,11 +135,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) assert (c < MAX_AUDIO_CHANNELS); - AutomaticAudioMapping m (_film->audio_channels ()); - optional s = m.dcp_to_source (static_cast (c)); - if (s) { - _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); - } + _plot->set_channel_visible (c, _channel_checkbox[c]->GetValue ()); } void @@ -172,9 +145,6 @@ AudioDialog::film_changed (Film::Property p) case Film::AUDIO_GAIN: _plot->set_gain (_film->audio_gain ()); break; - case Film::CONTENT: - setup_channels (); - break; default: break; } diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h index 514faeea0..db1d74f30 100644 --- a/src/wx/audio_dialog.h +++ b/src/wx/audio_dialog.h @@ -39,7 +39,6 @@ private: void type_clicked (wxCommandEvent &); void smoothing_changed (wxScrollEvent &); void try_to_load_analysis (); - void setup_channels (); boost::shared_ptr _film; AudioPlot* _plot; diff --git a/src/wx/audio_mapping_view.cc b/src/wx/audio_mapping_view.cc new file mode 100644 index 000000000..d62609d22 --- /dev/null +++ b/src/wx/audio_mapping_view.cc @@ -0,0 +1,156 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include +#include +#include +#include "lib/audio_mapping.h" +#include "audio_mapping_view.h" +#include "wx_util.h" + +using std::cout; +using std::list; +using boost::shared_ptr; + +/* This could go away with wxWidgets 2.9, which has an API call + to find these values. +*/ + +#ifdef __WXMSW__ +#define CHECKBOX_WIDTH 16 +#define CHECKBOX_HEIGHT 16 +#endif + +#ifdef __WXGTK__ +#define CHECKBOX_WIDTH 20 +#define CHECKBOX_HEIGHT 20 +#endif + + +class NoSelectionStringRenderer : public wxGridCellStringRenderer +{ +public: + void Draw (wxGrid& grid, wxGridCellAttr& attr, wxDC& dc, const wxRect& rect, int row, int col, bool) + { + wxGridCellStringRenderer::Draw (grid, attr, dc, rect, row, col, false); + } +}; + +class CheckBoxRenderer : public wxGridCellRenderer +{ +public: + + void Draw (wxGrid& grid, wxGridCellAttr &, wxDC& dc, const wxRect& rect, int row, int col, bool) + { + wxRendererNative::Get().DrawCheckBox ( + &grid, + dc, rect, + grid.GetCellValue (row, col) == "1" ? static_cast(wxCONTROL_CHECKED) : 0 + ); + } + + wxSize GetBestSize (wxGrid &, wxGridCellAttr &, wxDC &, int, int) + { + return wxSize (CHECKBOX_WIDTH + 4, CHECKBOX_HEIGHT + 4); + } + + wxGridCellRenderer* Clone () const + { + return new CheckBoxRenderer; + } +}; + + +AudioMappingView::AudioMappingView (wxWindow* parent) + : wxPanel (parent, wxID_ANY) +{ + _grid = new wxGrid (this, wxID_ANY); + + _grid->CreateGrid (0, 7); + _grid->HideRowLabels (); + _grid->DisableDragRowSize (); + _grid->DisableDragColSize (); + _grid->EnableEditing (false); + _grid->SetCellHighlightPenWidth (0); + _grid->SetDefaultRenderer (new NoSelectionStringRenderer); + + _grid->SetColLabelValue (0, _("Content channel")); + _grid->SetColLabelValue (1, _("L")); + _grid->SetColLabelValue (2, _("R")); + _grid->SetColLabelValue (3, _("C")); + _grid->SetColLabelValue (4, _("Lfe")); + _grid->SetColLabelValue (5, _("Ls")); + _grid->SetColLabelValue (6, _("Rs")); + + _grid->AutoSize (); + + wxBoxSizer* s = new wxBoxSizer (wxVERTICAL); + s->Add (_grid, 1, wxEXPAND); + SetSizerAndFit (s); + + Connect (wxID_ANY, wxEVT_GRID_CELL_LEFT_CLICK, wxGridEventHandler (AudioMappingView::left_click), 0, this); +} + +void +AudioMappingView::left_click (wxGridEvent& ev) +{ + if (ev.GetCol() == 0) { + return; + } + + if (_grid->GetCellValue (ev.GetRow(), ev.GetCol()) == "1") { + _grid->SetCellValue (ev.GetRow(), ev.GetCol(), "0"); + } else { + _grid->SetCellValue (ev.GetRow(), ev.GetCol(), "1"); + } +} + +void +AudioMappingView::set_mapping (AudioMapping map) +{ + if (_grid->GetNumberRows ()) { + _grid->DeleteRows (0, _grid->GetNumberRows ()); + } + + list content_channels = map.content_channels (); + _grid->InsertRows (0, content_channels.size ()); + + for (size_t r = 0; r < content_channels.size(); ++r) { + for (int c = 1; c < 7; ++c) { + _grid->SetCellRenderer (r, c, new CheckBoxRenderer); + } + } + + int n = 0; + for (list::iterator i = content_channels.begin(); i != content_channels.end(); ++i) { + shared_ptr ac = i->content.lock (); + assert (ac); + _grid->SetCellValue (n, 0, wxString::Format ("%s %d", std_to_wx (ac->file().filename().string()), i->index + 1)); + + list const d = map.content_to_dcp (*i); + for (list::const_iterator j = d.begin(); j != d.end(); ++j) { + _grid->SetCellValue (n, static_cast (*j) + 1, "1"); + } + ++n; + } + + _grid->AutoSize (); +} + diff --git a/src/wx/audio_mapping_view.h b/src/wx/audio_mapping_view.h new file mode 100644 index 000000000..36429412f --- /dev/null +++ b/src/wx/audio_mapping_view.h @@ -0,0 +1,35 @@ +/* + Copyright (C) 2013 Carl Hetherington + + 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 +#include +#include + +class AudioMappingView : public wxPanel +{ +public: + AudioMappingView (wxWindow *); + + void set_mapping (AudioMapping); + +private: + void left_click (wxGridEvent &); + + wxGrid* _grid; +}; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 6c42359fb..6f08b6567 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -50,7 +50,7 @@ #include "scaler.h" #include "audio_dialog.h" #include "imagemagick_content_dialog.h" -#include "sndfile_content_dialog.h" +#include "audio_mapping_view.h" using std::string; using std::cout; @@ -197,7 +197,9 @@ FilmEditor::connect_to_widgets () _edit_dci_button->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::edit_dci_button_clicked), 0, this); _format->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::format_changed), 0, this); _trust_content_headers->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::trust_content_headers_changed), 0, this); - _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_item_selected), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_SELECTED, wxListEventHandler (FilmEditor::content_selection_changed), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_DESELECTED, wxListEventHandler (FilmEditor::content_selection_changed), 0, this); + _content->Connect (wxID_ANY, wxEVT_COMMAND_LIST_ITEM_ACTIVATED, wxListEventHandler (FilmEditor::content_activated), 0, this); _content_add->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_add_clicked), 0, this); _content_remove->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_remove_clicked), 0, this); _content_edit->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (FilmEditor::content_edit_clicked), 0, this); @@ -406,6 +408,9 @@ FilmEditor::make_audio_panel () grid->Add (s, 1, wxEXPAND); } + _audio_mapping = new AudioMappingView (_audio_panel); + _audio_sizer->Add (_audio_mapping, 1, wxEXPAND | wxALL, 6); + _audio_gain->SetRange (-60, 60); _audio_delay->SetRange (-1000, 1000); } @@ -691,6 +696,10 @@ FilmEditor::film_changed (Film::Property p) _frame_rate_description->SetLabel (wxT ("")); _best_dcp_frame_rate->Disable (); } + break; + case Film::AUDIO_MAPPING: + _audio_mapping->set_mapping (_film->audio_mapping ()); + break; } } @@ -849,6 +858,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::J2K_BANDWIDTH); film_changed (Film::DCI_METADATA); film_changed (Film::DCP_FRAME_RATE); + film_changed (Film::AUDIO_MAPPING); film_content_changed (boost::shared_ptr (), FFmpegContentProperty::SUBTITLE_STREAMS); film_content_changed (boost::shared_ptr (), FFmpegContentProperty::SUBTITLE_STREAM); @@ -1242,6 +1252,15 @@ FilmEditor::content_remove_clicked (wxCommandEvent &) } } +void +FilmEditor::content_activated (wxListEvent& ev) +{ + ContentList c = _film->content (); + assert (ev.GetIndex() >= 0 && size_t (ev.GetIndex()) < c.size ()); + + edit_content (c[ev.GetIndex()]); +} + void FilmEditor::content_edit_clicked (wxCommandEvent &) { @@ -1250,22 +1269,19 @@ FilmEditor::content_edit_clicked (wxCommandEvent &) return; } + edit_content (c); +} + +void +FilmEditor::edit_content (shared_ptr c) +{ shared_ptr im = dynamic_pointer_cast (c); if (im) { ImageMagickContentDialog* d = new ImageMagickContentDialog (this, im); - int const r = d->ShowModal (); - d->Destroy (); - - if (r == wxID_OK) { - im->set_video_length (d->video_length() * 24); - } - } - - shared_ptr sf = dynamic_pointer_cast (c); - if (sf) { - SndfileContentDialog* d = new SndfileContentDialog (this, sf); d->ShowModal (); d->Destroy (); + + im->set_video_length (d->video_length() * 24); } } @@ -1288,7 +1304,7 @@ FilmEditor::content_later_clicked (wxCommandEvent &) } void -FilmEditor::content_item_selected (wxListEvent &) +FilmEditor::content_selection_changed (wxListEvent &) { setup_content_button_sensitivity (); setup_content_information (); @@ -1311,11 +1327,12 @@ FilmEditor::setup_content_button_sensitivity () { _content_add->Enable (_generally_sensitive); - bool const have_selection = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1; - _content_edit->Enable (have_selection && _generally_sensitive); - _content_remove->Enable (have_selection && _generally_sensitive); - _content_earlier->Enable (have_selection && _generally_sensitive); - _content_later->Enable (have_selection && _generally_sensitive); + shared_ptr selection = selected_content (); + + _content_edit->Enable (selection && _generally_sensitive && dynamic_pointer_cast (selection)); + _content_remove->Enable (selection && _generally_sensitive); + _content_earlier->Enable (selection && _generally_sensitive); + _content_later->Enable (selection && _generally_sensitive); } shared_ptr diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index b6f6a24ee..bc6b045c4 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -33,6 +33,7 @@ class wxListCtrl; class wxListEvent; class Film; class AudioDialog; +class AudioMappingView; /** @class FilmEditor * @brief A wx widget to edit a film's metadata, and perform various functions. @@ -63,7 +64,8 @@ private: void top_crop_changed (wxCommandEvent &); void bottom_crop_changed (wxCommandEvent &); void trust_content_headers_changed (wxCommandEvent &); - void content_item_selected (wxListEvent &); + void content_selection_changed (wxListEvent &); + void content_activated (wxListEvent &); void content_add_clicked (wxCommandEvent &); void content_remove_clicked (wxCommandEvent &); void content_edit_clicked (wxCommandEvent &); @@ -110,6 +112,7 @@ private: void active_jobs_changed (bool); boost::shared_ptr selected_content (); + void edit_content (boost::shared_ptr); wxNotebook* _notebook; wxPanel* _film_panel; @@ -152,6 +155,7 @@ private: wxButton* _show_audio; wxSpinCtrl* _audio_delay; wxChoice* _ffmpeg_audio_stream; + AudioMappingView* _audio_mapping; wxCheckBox* _with_subtitles; wxChoice* _ffmpeg_subtitle_stream; wxSpinCtrl* _subtitle_offset; diff --git a/src/wx/sndfile_content_dialog.cc b/src/wx/sndfile_content_dialog.cc deleted file mode 100644 index f305b158c..000000000 --- a/src/wx/sndfile_content_dialog.cc +++ /dev/null @@ -1,67 +0,0 @@ -/* - Copyright (C) 2013 Carl Hetherington - - 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 "lib/util.h" -#include "lib/sndfile_content.h" -#include "sndfile_content_dialog.h" -#include "wx_util.h" - -using boost::shared_ptr; - -SndfileContentDialog::SndfileContentDialog (wxWindow* parent, shared_ptr content) - : wxDialog (parent, wxID_ANY, _("Sound file")) -{ - wxFlexGridSizer* grid = new wxFlexGridSizer (7, 6, 0); - - add_label_to_sizer (grid, this, wxT ("")); - add_label_to_sizer (grid, this, _("L")); - add_label_to_sizer (grid, this, _("R")); - add_label_to_sizer (grid, this, _("C")); - add_label_to_sizer (grid, this, _("Lfe")); - add_label_to_sizer (grid, this, _("Ls")); - add_label_to_sizer (grid, this, _("Rs")); - - _buttons.resize (content->audio_channels ()); - for (int i = 0; i < content->audio_channels(); ++i) { - - if (content->audio_channels() == 1) { - add_label_to_sizer (grid, this, _("Source")); - } else { - add_label_to_sizer (grid, this, wxString::Format (_("Source %d"), i + 1)); - } - - for (int j = 0; j < MAX_AUDIO_CHANNELS; ++j) { - wxRadioButton* b = new wxRadioButton (this, wxID_ANY, wxT (""), wxDefaultPosition, wxDefaultSize, j ? 0 : wxRB_GROUP); - _buttons[i].push_back (b); - grid->Add (b, wxSHRINK); - } - } - - wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); - overall_sizer->Add (grid, 1, wxEXPAND | wxALL, 6); - - wxSizer* buttons = CreateSeparatedButtonSizer (wxOK); - if (buttons) { - overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); - } - - SetSizer (overall_sizer); - overall_sizer->Layout (); - overall_sizer->SetSizeHints (this); -} diff --git a/src/wx/sndfile_content_dialog.h b/src/wx/sndfile_content_dialog.h deleted file mode 100644 index 5a328892a..000000000 --- a/src/wx/sndfile_content_dialog.h +++ /dev/null @@ -1,36 +0,0 @@ -/* - Copyright (C) 2013 Carl Hetherington - - 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 -#include -#include -#include "lib/audio_mapping.h" - -class SndfileContent; - -class SndfileContentDialog : public wxDialog -{ -public: - SndfileContentDialog (wxWindow *, boost::shared_ptr); - - ConfiguredAudioMapping audio_mapping () const; - -private: - std::vector > _buttons; -}; diff --git a/src/wx/wscript b/src/wx/wscript index bd21af6ce..7f9cde9ac 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -5,6 +5,7 @@ import i18n sources = """ audio_dialog.cc + audio_mapping_view.cc audio_plot.cc config_dialog.cc dci_metadata_dialog.cc @@ -20,7 +21,6 @@ sources = """ new_film_dialog.cc properties_dialog.cc server_dialog.cc - sndfile_content_dialog.cc wx_util.cc wx_ui_signaller.cc """ -- cgit v1.2.3 From 263eee639546964aaa57f5d2d3b24008ecfe8adb Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 7 Apr 2013 12:45:46 +0100 Subject: A few fixes; try to support sndfile audio in player. --- src/lib/encoder.cc | 31 ++-------------------- src/lib/encoder.h | 2 -- src/lib/player.cc | 36 +++++++++++++++++++++---- src/lib/player.h | 7 +++-- src/lib/util.cc | 73 +++++++++++++++++++++++++++++++++++++-------------- src/lib/util.h | 1 + src/wx/film_editor.cc | 5 +++- src/wx/film_viewer.cc | 23 +++++++--------- 8 files changed, 106 insertions(+), 72 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 0542587a0..46d11c556 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -144,7 +144,7 @@ Encoder::process_end () } out->set_frames (frames); - write_audio (out); + _writer->write (out); } swr_free (&_swr_context); @@ -323,7 +323,7 @@ Encoder::process_audio (shared_ptr data) } #endif - write_audio (data); + _writer->write (data); } void @@ -423,30 +423,3 @@ Encoder::encoder_thread (ServerDescription* server) _condition.notify_all (); } } - -void -Encoder::write_audio (shared_ptr data) -{ -#if 0 - XXX - AutomaticAudioMapping m (_film->audio_channels ()); - if (m.dcp_channels() != _film->audio_channels()) { - - /* Remap (currently just for mono -> 5.1) */ - - shared_ptr b (new AudioBuffers (m.dcp_channels(), data->frames ())); - for (int i = 0; i < m.dcp_channels(); ++i) { - optional s = m.dcp_to_source (static_cast (i)); - if (!s) { - b->make_silent (i); - } else { - memcpy (b->data()[i], data->data()[s.get()], data->frames() * sizeof(float)); - } - } - - data = b; - } -#endif - - _writer->write (data); -} diff --git a/src/lib/encoder.h b/src/lib/encoder.h index b85132b72..70e6eea9a 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -88,8 +88,6 @@ private: void frame_done (); - void write_audio (boost::shared_ptr data); - void encoder_thread (ServerDescription *); void terminate_threads (); diff --git a/src/lib/player.cc b/src/lib/player.cc index ac046fcc0..756c3b854 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -22,6 +22,7 @@ #include "ffmpeg_decoder.h" #include "imagemagick_decoder.h" #include "sndfile_decoder.h" +#include "sndfile_content.h" #include "playlist.h" #include "job.h" @@ -95,7 +96,16 @@ Player::pass () } } - /* XXX: sndfile */ + if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + for (list >::iterator i = _sndfile_decoders.begin(); i != _sndfile_decoders.end(); ++i) { + if (!(*i)->pass ()) { + done = false; + } + } + + Audio (_sndfile_buffers); + _sndfile_buffers.reset (); + } return done; } @@ -133,9 +143,25 @@ Player::process_video (shared_ptr i, bool same, shared_ptr s) } void -Player::process_audio (shared_ptr b) +Player::process_audio (weak_ptr c, shared_ptr b) { - Audio (b); + if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + AudioMapping mapping = _film->audio_mapping (); + if (!_sndfile_buffers) { + _sndfile_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ())); + _sndfile_buffers->make_silent (); + } + + for (int i = 0; i < b->channels(); ++i) { + list dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i)); + for (list::iterator j = dcp.begin(); j != dcp.end(); ++j) { + _sndfile_buffers->accumulate (b, i, static_cast (*j)); + } + } + + } else { + Audio (b); + } } /** @return true on error */ @@ -238,7 +264,7 @@ Player::setup_decoders () } if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - _ffmpeg_decoder->connect_audio (shared_from_this ()); + _ffmpeg_decoder->Audio.connect (bind (&Player::process_audio, this, _playlist->ffmpeg (), _1)); } if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { @@ -257,7 +283,7 @@ Player::setup_decoders () for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { shared_ptr d (new SndfileDecoder (_film, *i)); _sndfile_decoders.push_back (d); - d->connect_audio (shared_from_this ()); + d->Audio.connect (bind (&Player::process_audio, this, *i, _1)); } } } diff --git a/src/lib/player.h b/src/lib/player.h index 79203692e..afc856316 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -34,8 +34,9 @@ class SndfileDecoder; class Job; class Film; class Playlist; +class AudioContent; -class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +class Player : public VideoSource, public AudioSource, public VideoSink, public boost::enable_shared_from_this { public: Player (boost::shared_ptr, boost::shared_ptr); @@ -54,7 +55,7 @@ public: private: void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); - void process_audio (boost::shared_ptr); + void process_audio (boost::weak_ptr, boost::shared_ptr); void setup_decoders (); void playlist_changed (); void content_changed (boost::weak_ptr, int); @@ -73,6 +74,8 @@ private: std::list >::iterator _imagemagick_decoder; std::list > _sndfile_decoders; + boost::shared_ptr _sndfile_buffers; + bool _video_sync; }; diff --git a/src/lib/util.cc b/src/lib/util.cc index 1e60b43fc..760b826c7 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -63,8 +63,26 @@ extern "C" { #include "i18n.h" -using namespace std; -using namespace boost; +using std::string; +using std::stringstream; +using std::setfill; +using std::ostream; +using std::endl; +using std::vector; +using std::hex; +using std::setw; +using std::ifstream; +using std::ios; +using std::min; +using std::max; +using std::list; +using std::multimap; +using std::istream; +using std::numeric_limits; +using std::pair; +using boost::shared_ptr; +using boost::thread; +using boost::lexical_cast; using libdcp::Size; thread::id ui_thread; @@ -243,7 +261,7 @@ dvdomatic_setup () Filter::setup_filters (); SoundProcessor::setup_sound_processors (); - ui_thread = this_thread::get_id (); + ui_thread = boost::this_thread::get_id (); } #ifdef DVDOMATIC_WINDOWS @@ -498,16 +516,16 @@ Socket::Socket (int timeout) , _socket (_io_service) , _timeout (timeout) { - _deadline.expires_at (posix_time::pos_infin); + _deadline.expires_at (boost::posix_time::pos_infin); check (); } void Socket::check () { - if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { + if (_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now ()) { _socket.close (); - _deadline.expires_at (posix_time::pos_infin); + _deadline.expires_at (boost::posix_time::pos_infin); } _deadline.async_wait (boost::bind (&Socket::check, this)); @@ -517,14 +535,14 @@ Socket::check () * @param endpoint End-point to connect to. */ void -Socket::connect (asio::ip::basic_resolver_entry const & endpoint) +Socket::connect (boost::asio::ip::basic_resolver_entry const & endpoint) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; - _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; + _socket.async_connect (endpoint, boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one(); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec || !_socket.is_open ()) { throw NetworkError (_("connect timed out")); @@ -538,14 +556,14 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint) void Socket::write (uint8_t const * data, int size) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; - asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + boost::asio::async_write (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one (); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec) { throw NetworkError (ec.message ()); @@ -566,14 +584,14 @@ Socket::write (uint32_t v) void Socket::read (uint8_t* data, int size) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; - asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + boost::asio::async_read (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one (); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec) { throw NetworkError (ec.message ()); @@ -850,11 +868,26 @@ AudioBuffers::move (int from, int to, int frames) } } +/** Add data from from `from', `from_channel' to our channel `to_channel' */ +void +AudioBuffers::accumulate (shared_ptr from, int from_channel, int to_channel) +{ + int const N = frames (); + assert (from->frames() == N); + + float* s = from->data (from_channel); + float* d = _data[to_channel]; + + for (int i = 0; i < N; ++i) { + *d++ += *s++; + } +} + /** Trip an assert if the caller is not in the UI thread */ void ensure_ui_thread () { - assert (this_thread::get_id() == ui_thread); + assert (boost::this_thread::get_id() == ui_thread); } /** @param v Content video frame. diff --git a/src/lib/util.h b/src/lib/util.h index 1fe6212e4..f4af7c22b 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -182,6 +182,7 @@ public: void copy_from (AudioBuffers* from, int frames_to_copy, int read_offset, int write_offset); void move (int from, int to, int frames); + void accumulate (boost::shared_ptr, int, int); private: /** Number of channels */ diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 6f08b6567..071393139 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -1344,6 +1344,9 @@ FilmEditor::selected_content () } ContentList c = _film->content (); - assert (s >= 0 && size_t (s) < c.size ()); + if (s < 0 || size_t (s) >= c.size ()) { + return shared_ptr (); + } + return c[s]; } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 4d8685dd0..bd56efd57 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -84,18 +84,6 @@ FilmViewer::FilmViewer (shared_ptr f, wxWindow* p) _play_button->Connect (wxID_ANY, wxEVT_COMMAND_TOGGLEBUTTON_CLICKED, wxCommandEventHandler (FilmViewer::play_clicked), 0, this); _timer.Connect (wxID_ANY, wxEVT_TIMER, wxTimerEventHandler (FilmViewer::timer), 0, this); - if (f) { - /* We need a player before we set_film() so that the first frame will be displayed */ - _player = f->player (); - _player->disable_audio (); - _player->disable_video_sync (); - /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them - on and off without needing obtain a new Player. - */ - - _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); - } - set_film (f); JobManager::instance()->ActiveJobsChanged.connect ( @@ -142,13 +130,22 @@ FilmViewer::set_film (shared_ptr f) if (_film == f) { return; } - + _film = f; if (!_film) { return; } + _player = f->player (); + _player->disable_audio (); + _player->disable_video_sync (); + /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them + on and off without needing obtain a new Player. + */ + + _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); + _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); film_changed (Film::CONTENT); -- cgit v1.2.3 From 4dee3db5222be7972930dbc621e9ab15a81d33d2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 10 Apr 2013 20:45:07 +0100 Subject: Remove believed unnecessary audio channel layout stuff for resampler. --- src/lib/audio_content.h | 2 -- src/lib/encoder.cc | 13 ++++++++++--- src/lib/ffmpeg_content.cc | 16 +++------------- src/lib/ffmpeg_content.h | 11 +++-------- src/lib/ffmpeg_decoder.cc | 2 +- src/lib/film.cc | 6 ------ src/lib/film.h | 1 - src/lib/imagemagick_decoder.h | 12 ------------ src/lib/playlist.cc | 22 ---------------------- src/lib/playlist.h | 1 - src/lib/sndfile_content.h | 4 ---- 11 files changed, 17 insertions(+), 73 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index d5dbf266b..dbd55943d 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -45,8 +45,6 @@ public: virtual int audio_channels () const = 0; virtual ContentAudioFrame audio_length () const = 0; virtual int audio_frame_rate () const = 0; - virtual int64_t audio_channel_layout () const = 0; - }; #endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 46d11c556..b897c8a31 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -86,13 +86,20 @@ Encoder::process_begin () s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_frame_rate(), _film->target_audio_sample_rate()); _film->log()->log (s.str ()); - /* We will be using planar float data when we call the resampler */ + /* We will be using planar float data when we call the + resampler. As far as I can see, the audio channel + layout is not necessary for our purposes; it seems + only to be used get the number of channels and + decide if rematrixing is needed. It won't be, since + input and output layouts are the same. + */ + _swr_context = swr_alloc_set_opts ( 0, - _film->audio_channel_layout(), + av_get_default_channel_layout (_film->audio_channels ()), AV_SAMPLE_FMT_FLTP, _film->target_audio_sample_rate(), - _film->audio_channel_layout(), + av_get_default_channel_layout (_film->audio_channels ()), AV_SAMPLE_FMT_FLTP, _film->audio_frame_rate(), 0, 0 diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 0424fbc33..577dbd14d 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -216,7 +216,7 @@ FFmpegContent::audio_channels () const return 0; } - return _audio_stream->channels (); + return _audio_stream->channels; } int @@ -229,16 +229,6 @@ FFmpegContent::audio_frame_rate () const return _audio_stream->frame_rate; } -int64_t -FFmpegContent::audio_channel_layout () const -{ - if (!_audio_stream) { - return 0; - } - - return _audio_stream->channel_layout; -} - bool operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b) { @@ -256,7 +246,7 @@ FFmpegAudioStream::FFmpegAudioStream (shared_ptr node) name = node->string_child ("Name"); id = node->number_child ("Id"); frame_rate = node->number_child ("FrameRate"); - channel_layout = node->number_child ("ChannelLayout"); + channels = node->number_child ("Channels"); } void @@ -265,7 +255,7 @@ FFmpegAudioStream::as_xml (xmlpp::Node* root) const root->add_child("Name")->add_child_text (name); root->add_child("Id")->add_child_text (lexical_cast (id)); root->add_child("FrameRate")->add_child_text (lexical_cast (frame_rate)); - root->add_child("ChannelLayout")->add_child_text (lexical_cast (channel_layout)); + root->add_child("Channels")->add_child_text (lexical_cast (channels)); } /** Construct a SubtitleStream from a value returned from to_string(). diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index cc603e680..b49e5790e 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -27,25 +27,21 @@ class FFmpegAudioStream { public: - FFmpegAudioStream (std::string n, int i, int f, int64_t c) + FFmpegAudioStream (std::string n, int i, int f, int c) : name (n) , id (i) , frame_rate (f) - , channel_layout (c) + , channels (c) {} FFmpegAudioStream (boost::shared_ptr); void as_xml (xmlpp::Node *) const; - int channels () const { - return av_get_channel_layout_nb_channels (channel_layout); - } - std::string name; int id; int frame_rate; - int64_t channel_layout; + int channels; }; extern bool operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b); @@ -98,7 +94,6 @@ public: int audio_channels () const; ContentAudioFrame audio_length () const; int audio_frame_rate () const; - int64_t audio_channel_layout () const; std::vector subtitle_streams () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index d0b1de748..eac1d91ae 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -143,7 +143,7 @@ FFmpegDecoder::setup_general () } _audio_streams.push_back ( - FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channel_layout) + FFmpegAudioStream (stream_name (s), i, s->codec->sample_rate, s->codec->channels) ); } else if (s->codec->codec_type == AVMEDIA_TYPE_SUBTITLE) { diff --git a/src/lib/film.cc b/src/lib/film.cc index 35a07b399..5f1b89d0c 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -1131,12 +1131,6 @@ Film::audio_frame_rate () const return _playlist->audio_frame_rate (); } -int64_t -Film::audio_channel_layout () const -{ - return _playlist->audio_channel_layout (); -} - bool Film::has_audio () const { diff --git a/src/lib/film.h b/src/lib/film.h index 532d32bdc..4d994996e 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -106,7 +106,6 @@ public: ContentAudioFrame audio_length () const; int audio_channels () const; int audio_frame_rate () const; - int64_t audio_channel_layout () const; bool has_audio () const; float video_frame_rate () const; diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 52c7bec18..40a89bb15 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -37,18 +37,6 @@ public: libdcp::Size native_size () const; ContentVideoFrame video_length () const; - int audio_channels () const { - return 0; - } - - int audio_sample_rate () const { - return 0; - } - - int64_t audio_channel_layout () const { - return 0; - } - bool seek (double); bool pass (); diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 717c1dace..f346cb6e0 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -143,28 +143,6 @@ Playlist::audio_frame_rate () const return 0; } -int64_t -Playlist::audio_channel_layout () const -{ - /* XXX: assuming that all content has the same layout */ - - switch (_audio_from) { - case AUDIO_FFMPEG: - { - shared_ptr fc = first_ffmpeg (); - if (fc) { - return fc->audio_channel_layout (); - } - break; - } - case AUDIO_SNDFILE: - /* XXX */ - return 0; - } - - return 0; -} - float Playlist::video_frame_rate () const { diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 4dd27f675..6384dce1c 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -47,7 +47,6 @@ public: ContentAudioFrame audio_length () const; int audio_channels () const; int audio_frame_rate () const; - int64_t audio_channel_layout () const; bool has_audio () const; float video_frame_rate () const; diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index 27c5f3615..e8e86b603 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -58,10 +58,6 @@ public: return _audio_frame_rate; } - int64_t audio_channel_layout () const { - return av_get_default_channel_layout (audio_channels ()); - } - static bool valid_file (boost::filesystem::path); private: -- cgit v1.2.3 From 7ee21d16c01b90c22192cd10f118419881fe504e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sat, 13 Apr 2013 12:53:40 +0100 Subject: DVD-o-matic -> DCP-o-matic. --- Doxyfile | 2 +- README | 13 +- TODO | 137 ------ builds/control-12.04-32 | 8 +- builds/control-12.04-64 | 8 +- builds/control-12.10-32 | 8 +- builds/control-12.10-64 | 8 +- cscript | 14 +- cscript.py | 8 - debian/changelog | 136 +++--- debian/copyright | 4 +- debian/files | 2 +- debian/rules | 2 +- doc/mainpage.txt | 20 +- doc/manual/Makefile | 22 +- doc/manual/dvdomatic-html.xsl | 12 - doc/manual/dvdomatic-pdf.xsl | 17 - doc/manual/dvdomatic.css | 19 - doc/manual/dvdomatic.sty | 68 --- doc/manual/dvdomatic.xml | 932 ------------------------------------- dvdomatic.desktop.in | 10 - hacks/python-playback/config.py | 2 - hacks/python-playback/dvdomatic | 209 --------- hacks/python-playback/film.py | 188 -------- hacks/python-playback/film_view.py | 212 --------- hacks/python-playback/player.py | 112 ----- hacks/python-playback/ratio.py | 56 --- hacks/python-playback/screens | 62 --- hacks/python-playback/screens.py | 85 ---- hacks/python-playback/thumbs.py | 76 --- hacks/python-playback/util.py | 7 - hacks/python-playback/xrandr-notes | 17 - icons/128x128/dvdomatic.png | Bin 18365 -> 0 bytes icons/16x16/dvdomatic.png | Bin 211 -> 0 bytes icons/22x22/dvdomatic.png | Bin 994 -> 0 bytes icons/32x32/dvdomatic.png | Bin 1747 -> 0 bytes icons/48x48/dvdomatic.png | Bin 3407 -> 0 bytes icons/64x64/dvdomatic.png | Bin 5421 -> 0 bytes run/dvdomatic | 15 - src/lib/audio_analysis.h | 4 +- src/lib/audio_content.h | 4 +- src/lib/audio_decoder.h | 4 +- src/lib/audio_mapping.h | 4 +- src/lib/audio_sink.h | 4 +- src/lib/audio_source.h | 4 +- src/lib/config.cc | 4 +- src/lib/config.h | 4 +- src/lib/content.h | 4 +- src/lib/cross.cc | 10 +- src/lib/cross.h | 4 +- src/lib/dci_metadata.h | 4 +- src/lib/dcp_content_type.h | 4 +- src/lib/dcp_video_frame.cc | 2 +- src/lib/decoder.h | 4 +- src/lib/encoder.cc | 2 +- src/lib/encoder.h | 4 +- src/lib/exceptions.h | 4 +- src/lib/ffmpeg_content.h | 4 +- src/lib/film.cc | 10 +- src/lib/film.h | 6 +- src/lib/filter.h | 4 +- src/lib/filter_graph.h | 4 +- src/lib/i18n.h | 2 +- src/lib/image.h | 4 +- src/lib/job.cc | 4 +- src/lib/job.h | 4 +- src/lib/job_manager.cc | 2 +- src/lib/log.h | 4 +- src/lib/player.h | 4 +- src/lib/po/es_ES.po | 6 +- src/lib/po/fr_FR.po | 8 +- src/lib/po/it_IT.po | 4 +- src/lib/po/sv_SE.po | 6 +- src/lib/processor.h | 4 +- src/lib/scaler.h | 4 +- src/lib/sound_processor.h | 4 +- src/lib/timer.h | 4 +- src/lib/types.h | 4 +- src/lib/ui_signaller.h | 4 +- src/lib/util.cc | 28 +- src/lib/util.h | 14 +- src/lib/version.h | 4 +- src/lib/video_content.h | 4 +- src/lib/video_decoder.h | 4 +- src/lib/video_sink.h | 4 +- src/lib/video_source.h | 4 +- src/lib/wscript | 10 +- src/tools/dvdomatic.cc | 578 ----------------------- src/tools/makedcp.cc | 12 +- src/tools/po/es_ES.po | 58 +-- src/tools/po/fr_FR.po | 58 +-- src/tools/po/it_IT.po | 56 +-- src/tools/po/sv_SE.po | 58 +-- src/tools/servomatic_cli.cc | 4 +- src/tools/servomatic_gui.cc | 6 +- src/tools/servomatictest.cc | 2 +- src/tools/wscript | 14 +- src/wx/audio_dialog.cc | 2 +- src/wx/config_dialog.cc | 6 +- src/wx/config_dialog.h | 4 +- src/wx/po/es_ES.po | 16 +- src/wx/po/fr_FR.po | 16 +- src/wx/po/it_IT.po | 16 +- src/wx/po/sv_SE.po | 18 +- src/wx/wscript | 12 +- src/wx/wx_util.cc | 2 +- test/test.cc | 14 +- test/wscript | 2 +- windows/dvdomatic.bmp | Bin 343254 -> 0 bytes windows/dvdomatic.ico | Bin 9662 -> 0 bytes windows/dvdomatic.rc | 3 - windows/dvdomatic_taskbar.ico | Bin 1150 -> 0 bytes windows/installer.nsi.32.in | 70 +-- windows/installer.nsi.64.in | 72 +-- wscript | 24 +- 115 files changed, 515 insertions(+), 3345 deletions(-) delete mode 100644 TODO delete mode 100644 cscript.py delete mode 100644 doc/manual/dvdomatic-html.xsl delete mode 100644 doc/manual/dvdomatic-pdf.xsl delete mode 100644 doc/manual/dvdomatic.css delete mode 100644 doc/manual/dvdomatic.sty delete mode 100644 doc/manual/dvdomatic.xml delete mode 100644 dvdomatic.desktop.in delete mode 100644 hacks/python-playback/config.py delete mode 100755 hacks/python-playback/dvdomatic delete mode 100644 hacks/python-playback/film.py delete mode 100644 hacks/python-playback/film_view.py delete mode 100644 hacks/python-playback/player.py delete mode 100644 hacks/python-playback/ratio.py delete mode 100644 hacks/python-playback/screens delete mode 100644 hacks/python-playback/screens.py delete mode 100644 hacks/python-playback/thumbs.py delete mode 100644 hacks/python-playback/util.py delete mode 100644 hacks/python-playback/xrandr-notes delete mode 100644 icons/128x128/dvdomatic.png delete mode 100644 icons/16x16/dvdomatic.png delete mode 100644 icons/22x22/dvdomatic.png delete mode 100644 icons/32x32/dvdomatic.png delete mode 100644 icons/48x48/dvdomatic.png delete mode 100644 icons/64x64/dvdomatic.png delete mode 100755 run/dvdomatic delete mode 100644 src/tools/dvdomatic.cc delete mode 100644 windows/dvdomatic.bmp delete mode 100644 windows/dvdomatic.ico delete mode 100644 windows/dvdomatic.rc delete mode 100644 windows/dvdomatic_taskbar.ico (limited to 'src/lib/encoder.cc') diff --git a/Doxyfile b/Doxyfile index 56f7e1d3c..4ed65e4f1 100644 --- a/Doxyfile +++ b/Doxyfile @@ -26,7 +26,7 @@ DOXYFILE_ENCODING = UTF-8 # identify the project. Note that if you do not use Doxywizard you need # to put quotes around the project name if it contains spaces. -PROJECT_NAME = DVD-o-matic +PROJECT_NAME = DCP-o-matic # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or diff --git a/README b/README index fd3983c29..c218ed1a5 100644 --- a/README +++ b/README @@ -1,4 +1,4 @@ -dvd-o-matic +DCP-o-matic ----------- Hello! @@ -33,27 +33,22 @@ You will need these libraries: libsndfile libssh -and also the command line tool: - - vobcopy (if you want to rip DVDs straight into DVD-o-matic) - Documentation ------------- -There is a manual available at http://carlh.net/software/dvdomatic +There is a manual available at http://carlh.net/software/dcpomatic The DocBook source for this is in doc/manual. In a nutshell ------------- -The `dvdomatic' program is a GTK front-end which is probably easiest +The `dcpomatic' program is a GTK front-end which is probably easiest to use. It will create a directory for a particular project, and write its data to that directory. The basic approach is: "File->New"; specify a directory. -Choose "Jobs->Copy from DVD" to read a DVD from your drive, if you have one. Fill in the fields in the window (most importantly the `content' field: specify your video, and the `Name' field: give your project [and hence DCP] a name.) @@ -76,7 +71,7 @@ Server/client ------------- Running the `servomatic' program on a remote machine will make it -listen on port 6192 (by default) and process requests from a dvdomatic +listen on port 6192 (by default) and process requests from a dcpomatic instance. This has been written with no thought to security, so don't do it over the public internet! The connection will probably need to be 1 Gb/s to make it worthwhile. diff --git a/TODO b/TODO deleted file mode 100644 index 17f02e429..000000000 --- a/TODO +++ /dev/null @@ -1,137 +0,0 @@ -Make a DCP with subs using subtitle edit. - -Look at http://liblqr.wikidot.com/en:manual - -EC2 - -Small instance $0.085 ph -Sintel Trailer 1080p @ 200000 Mbps -1247 frames @ 24fps ie 51.96s -Took 1h20 to encode - -High-CPU medium $0.186 ph -Sintel Trailer 1080p @ 200000 Mbps -1247 frames @ 24fps ie 51.96s -Took 23m to encode - -High-CPU extra-large $0.744 ph -Sintel Trailer 1080p @ 200000 Mbps -1247 frames @ 24fps ie 51.96s - - -Transfer in free -Transfer out $0.120 per GB - - -Port DVD rip - -Write still j2ks straight to a MXF. -md5_data to use openssl -Write all j2ks straight to a MXF? Possible? - -Standardise j2c/j2k -Format name in ~/.dvdomatic screws up with spaces; use ID or something -Thumbnails are poorly named -x-thread signaller -Restartable jobs somehow -More logging -Nice error when trying to thumbnail with no content. -Destroy _buffer_src_context / _buffer_sink_context -Don't start later jobs when one breaks. -Compute time remaining based on more recent information. -Use lexical_cast more -Do deps better - -options summary - -1: L -2: R -3: C -4: Lfe -5: Ls -6: Rs - -City Screen - -Screen 1: "1.37" masking preset, projector only has DCI 133 preset. - -With 1480x1080 alignment in DCI 133: bottom you see purple, yellow; top purple; left and right no lines -With 1480x1080 alignment in DCI Flat: outside masks, but you see bottom purple, yellow; left/right all; top purple - - -Screen 2: no real masking preset, projector has DCI 133 and DCI 137 - -1480x1080, DCI 133 -L yellow purple -R none -B purple -T none -1480x1080, DCI 137 -L all -R all but blue -T purple -B purple - - -Screen 3: projector has DCI 1.38 - -1480x1080 -L, R, T none -B purple + yellow - - -films-0.6: Dolby Countdown looks as though it's 3D. THX Terminator 2 fucked -(these on default settings) -fq/gradfun --- no obvious effect -hqdn3d --- pretty good denoising -ow --- no obvious effect -tn --- interesting; much noise reduction, bad artefacts on movement, colour tint even in black -unsharp --- worse - -Benchmark SWS options: lanczos ? -hqdn3d=0:0:6 ? (turn off chroma/luma blurring) - -Lanczos; no visible effect on Ghostbusters. - - -THX_Monster with master Intel Core 2 Duo E4600 (2.4GHz), slave Intel Core i3 M350 (2.27GHz) -1920 x 1080 original -> DCI Flat -240 frames - -[Gbit: gigabit ethernet rather than 100Mbit] -[im-mod: after modification to memcpy RGB data then to RGB -> XYZ in the encode thread -[hack1]: after modification to pass YUV and to swscale in the encode thread (includes im-mod) -[hack2]: modified hack1 - Time Seconds FPS Speedup relative to 1 local -1 local: 20m57 1257 0.19 x 1 -2 local: 11m24 684 0.35 x 1.84 -2 local [im-mod]: 13m13 -2 local + 1 slave: 6m34 394 0.61 x 3.19 -2 local + 2 slave: 5m13 313 0.77 x 4.02 -2 local + 4 slave: 5m05 303 0.79 x 4.15 -2 local + 4 slave [Gbit]: 2m50 170 1.41 x 7.39 -2 local + 4 slave [Gbit,im-mod]:2m33 -2 local + 4 slave [Gbit,hack1]: 3m20 -2 local + 4 slave [Gbit,hack2]: 2m22 -1 local + 8 slave [Gbit]: 2m28 148 1.62 x 8.49 -2 local + 8 slave [Gbit]: 2m41 161 1.49 x 7.81 -2 local + 8 slave [Gbit,im-mod]:2m35 - - - -Just encode 52s -Encode + Image create 1m27 -Encode + Image create (memcpy, not convert) 53s. - -THX_Monster with master Intel Core i3 M350 (2.27GHz), slave Intel Core 2 Duo E4600 (2.4GHz) -1920 x 1080 original -> DCI Flat -240 frames - - -4 local: 2m45 -4 local [im-mod]: 2m53 -4 local + 2 slave [Gbit]: 2m22 -4 local + 4 slave [Gbit]: 2m21 -4 local + 4 slave [Gbit,in-mod]:2m21 - - diff --git a/builds/control-12.04-32 b/builds/control-12.04-32 index 8cb5aceb3..d31a5e384 100644 --- a/builds/control-12.04-32 +++ b/builds/control-12.04-32 @@ -1,15 +1,15 @@ -Source: dvdomatic +Source: dcpomatic Section: video Priority: extra Maintainer: Carl Hetherington Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7) Standards-Version: 3.9.3 -Homepage: http://carlh.net/software/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +Package: dcpomatic Architecture: i386 Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libsndfile1 (>= 1.0.25), libmagick++4 (>= 8:6.6.9.7), libxml++2.6-2 (>= 2.34.1) Description: Generator of Digital Cinema Packages (DCPs) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant digital projectors. diff --git a/builds/control-12.04-64 b/builds/control-12.04-64 index cdb15a87b..5d41558b6 100644 --- a/builds/control-12.04-64 +++ b/builds/control-12.04-64 @@ -1,15 +1,15 @@ -Source: dvdomatic +Source: dcpomatic Section: video Priority: extra Maintainer: Carl Hetherington Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7) Standards-Version: 3.9.3 -Homepage: http://carlh.net/software/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +Package: dcpomatic Architecture: amd64 Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.46.1 (>= 1.46.1), libboost-thread1.46.1 (>= 1.46.1), libsndfile1 (>= 1.0.25), libmagick++4 (>= 8:6.6.9.7), libxml++2.6-2 (>= 2.34.1) Description: Generator of Digital Cinema Packages (DCPs) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant digital projectors. diff --git a/builds/control-12.10-32 b/builds/control-12.10-32 index 1dc91b701..67933f2ed 100644 --- a/builds/control-12.10-32 +++ b/builds/control-12.10-32 @@ -1,15 +1,15 @@ -Source: dvdomatic +Source: dcpomatic Section: video Priority: extra Maintainer: Carl Hetherington Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7) Standards-Version: 3.9.3 -Homepage: http://carlh.net/software/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +Package: dcpomatic Architecture: i386 Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2) Description: Generator of Digital Cinema Packages (DCPs) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant digital projectors. diff --git a/builds/control-12.10-64 b/builds/control-12.10-64 index ed0b36b2e..cddf80007 100644 --- a/builds/control-12.10-64 +++ b/builds/control-12.10-64 @@ -1,15 +1,15 @@ -Source: dvdomatic +Source: dcpomatic Section: video Priority: extra Maintainer: Carl Hetherington Build-Depends: debhelper (>= 8.0.0), python (>= 2.7.3), g++ (>= 4:4.6.3), pkg-config (>= 0.26), libwxgtk2.8-dev (>= 2.8.12.1), libssh-dev (>= 0.5.2), libboost-filesystem-dev (>= 1.46.0), libboost-thread-dev (>= 1.46.0), libsndfile1-dev (>= 1.0.25), libmagick++-dev (>= 8:6.6.9.7) Standards-Version: 3.9.3 -Homepage: http://carlh.net/software/dvdomatic +Homepage: http://carlh.net/software/dcpomatic -Package: dvdomatic +Package: dcpomatic Architecture: amd64 Depends: libc6 (>= 2.15), libwxgtk2.8-0 (>= 2.8.12.1), libssh-4 (>= 0.5.2), libboost-filesystem1.49.0 (>= 1.49.0), libboost-thread1.49.0 (>= 1.49.0), libsndfile1 (>= 1.0.25), libmagick++5 (>= 8:6.7.7.10), libxml++2.6-2 (>= 2.34.2) Description: Generator of Digital Cinema Packages (DCPs) - DVD-o-matic generates Digital Cinema Packages (DCPs) from video and audio + DCP-o-matic generates Digital Cinema Packages (DCPs) from video and audio files (such as those from DVDs or Blu-Rays) for presentation on DCI-compliant digital projectors. diff --git a/cscript b/cscript index 4873df654..07840c109 100644 --- a/cscript +++ b/cscript @@ -25,13 +25,13 @@ def build(environment, variant, version): shutil.copyfile(os.path.join('builds', 'control-%s' % variant), os.path.join('debian', 'control')) command('./waf dist') f = open(os.path.join('debian', 'files'), 'w') - print >>f,'dvdomatic_%s-1_%s.deb video extra' % (version, cpu) + print >>f,'dcpomatic_%s-1_%s.deb video extra' % (version, cpu) shutil.rmtree('build/deb', ignore_errors=True) os.makedirs('build/deb') os.chdir('build/deb') - shutil.move('../../dvdomatic-%s.tar.bz2' % version, 'dvdomatic_%s.orig.tar.bz2' % version) - command('tar xjf dvdomatic_%s.orig.tar.bz2' % version) - os.chdir('dvdomatic-%s' % version) + shutil.move('../../dcpomatic-%s.tar.bz2' % version, 'dcpomatic_%s.orig.tar.bz2' % version) + command('tar xjf dcpomatic_%s.orig.tar.bz2' % version) + os.chdir('dcpomatic-%s' % version) command('dch -b -v %s-1 "New upstream release."' % version) command('dpkg-source -b .') command('dpkg-buildpackage') @@ -39,9 +39,9 @@ def build(environment, variant, version): def make_pot(): command('./waf pot') - return [os.path.abspath('build/src/lib/libdvdomatic.pot'), - os.path.abspath('build/src/wx/libdvdomatic-wx.pot'), - os.path.abspath('build/src/tools/dvdomatic.pot')] + return [os.path.abspath('build/src/lib/libdcpomatic.pot'), + os.path.abspath('build/src/wx/libdcpomatic-wx.pot'), + os.path.abspath('build/src/tools/dcpomatic.pot')] def make_manual(): os.chdir('doc/manual') diff --git a/cscript.py b/cscript.py deleted file mode 100644 index 9b8fa46c0..000000000 --- a/cscript.py +++ /dev/null @@ -1,8 +0,0 @@ -import cdist - -def builds(): - return ['source'] - -def build_source(): - cdist.build_source_waf() - diff --git a/debian/changelog b/debian/changelog index d1cea437d..0a53eff15 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,298 +1,298 @@ -dvdomatic (0.83-1) UNRELEASED; urgency=low +dcpomatic (0.83-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 10 Apr 2013 12:48:25 +0100 -dvdomatic (0.82-1) UNRELEASED; urgency=low +dcpomatic (0.82-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 09 Apr 2013 23:43:35 +0100 -dvdomatic (0.82beta1-1) UNRELEASED; urgency=low +dcpomatic (0.82beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 09 Apr 2013 21:48:56 +0100 -dvdomatic (0.81-1) UNRELEASED; urgency=low +dcpomatic (0.81-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 09 Apr 2013 19:48:04 +0100 -dvdomatic (0.81beta1-1) UNRELEASED; urgency=low +dcpomatic (0.81beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 09 Apr 2013 15:37:32 +0100 -dvdomatic (0.80-1) UNRELEASED; urgency=low +dcpomatic (0.80-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 07 Apr 2013 23:48:12 +0100 -dvdomatic (0.80beta4-1) UNRELEASED; urgency=low +dcpomatic (0.80beta4-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 07 Apr 2013 23:08:49 +0100 -dvdomatic (0.80beta3-1) UNRELEASED; urgency=low +dcpomatic (0.80beta3-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 07 Apr 2013 22:44:29 +0100 -dvdomatic (0.80beta2-1) UNRELEASED; urgency=low +dcpomatic (0.80beta2-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 07 Apr 2013 22:19:34 +0100 -dvdomatic (0.80beta1-1) UNRELEASED; urgency=low +dcpomatic (0.80beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 07 Apr 2013 18:21:33 +0100 -dvdomatic (0.79-1) UNRELEASED; urgency=low +dcpomatic (0.79-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Mon, 01 Apr 2013 22:37:03 +0100 -dvdomatic (0.78-1) UNRELEASED; urgency=low +dcpomatic (0.78-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 31 Mar 2013 02:43:03 +0100 -dvdomatic (0.78beta16-1) UNRELEASED; urgency=low +dcpomatic (0.78beta16-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 28 Mar 2013 16:28:05 +0000 -dvdomatic (0.78beta15-1) UNRELEASED; urgency=low +dcpomatic (0.78beta15-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 28 Mar 2013 14:25:56 +0000 -dvdomatic (0.78beta14-1) UNRELEASED; urgency=low +dcpomatic (0.78beta14-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 28 Mar 2013 10:38:07 +0000 -dvdomatic (0.78beta13-1) UNRELEASED; urgency=low +dcpomatic (0.78beta13-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 27 Mar 2013 12:26:55 +0000 -dvdomatic (0.78beta12-1) UNRELEASED; urgency=low +dcpomatic (0.78beta12-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 26 Mar 2013 21:13:54 +0000 -dvdomatic (0.78beta11-1) UNRELEASED; urgency=low +dcpomatic (0.78beta11-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 26 Mar 2013 17:34:49 +0000 -dvdomatic (0.78beta10-1) UNRELEASED; urgency=low +dcpomatic (0.78beta10-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 26 Mar 2013 11:35:15 +0000 -dvdomatic (0.78beta9-1) UNRELEASED; urgency=low +dcpomatic (0.78beta9-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 26 Mar 2013 10:36:05 +0000 -dvdomatic (0.78beta8-1) UNRELEASED; urgency=low +dcpomatic (0.78beta8-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 26 Mar 2013 00:59:36 +0000 -dvdomatic (0.78beta7-1) UNRELEASED; urgency=low +dcpomatic (0.78beta7-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 26 Mar 2013 00:19:21 +0000 -dvdomatic (0.78beta6-1) UNRELEASED; urgency=low +dcpomatic (0.78beta6-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Mon, 25 Mar 2013 00:08:10 +0000 -dvdomatic (0.78beta5-1) UNRELEASED; urgency=low +dcpomatic (0.78beta5-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 21 Mar 2013 16:32:21 +0000 -dvdomatic (0.78beta4-1) UNRELEASED; urgency=low +dcpomatic (0.78beta4-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 20 Mar 2013 15:01:10 +0000 -dvdomatic (0.78beta3-1) UNRELEASED; urgency=low +dcpomatic (0.78beta3-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 20 Mar 2013 10:49:17 +0000 -dvdomatic (0.78beta2-1) UNRELEASED; urgency=low +dcpomatic (0.78beta2-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 19 Mar 2013 21:35:50 +0000 -dvdomatic (0.78beta1-1) UNRELEASED; urgency=low +dcpomatic (0.78beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 19 Mar 2013 20:50:54 +0000 -dvdomatic (0.77-1) UNRELEASED; urgency=low +dcpomatic (0.77-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 14 Mar 2013 17:12:03 +0000 -dvdomatic (0.77beta2-1) UNRELEASED; urgency=low +dcpomatic (0.77beta2-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 14 Mar 2013 15:50:43 +0000 -dvdomatic (0.77beta1-1) UNRELEASED; urgency=low +dcpomatic (0.77beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 14 Mar 2013 15:14:01 +0000 -dvdomatic (0.76-1) UNRELEASED; urgency=low +dcpomatic (0.76-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 05 Mar 2013 13:30:28 +0000 -dvdomatic (0.76beta3-1) UNRELEASED; urgency=low +dcpomatic (0.76beta3-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Tue, 05 Mar 2013 12:47:20 +0000 -dvdomatic (0.76beta2-1) UNRELEASED; urgency=low +dcpomatic (0.76beta2-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Fri, 01 Mar 2013 18:32:16 +0000 -dvdomatic (0.76beta1-1) UNRELEASED; urgency=low +dcpomatic (0.76beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Fri, 01 Mar 2013 17:36:55 +0000 -dvdomatic (0.75-1) UNRELEASED; urgency=low +dcpomatic (0.75-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 27 Feb 2013 11:03:07 +0000 -dvdomatic (0.75beta1-1) UNRELEASED; urgency=low +dcpomatic (0.75beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 27 Feb 2013 08:20:42 +0000 -dvdomatic (0.74-1) UNRELEASED; urgency=low +dcpomatic (0.74-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sat, 23 Feb 2013 22:57:20 +0000 -dvdomatic (0.74beta1-1) UNRELEASED; urgency=low +dcpomatic (0.74beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sat, 23 Feb 2013 21:44:22 +0000 -dvdomatic (0.73-1) UNRELEASED; urgency=low +dcpomatic (0.73-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 21 Feb 2013 00:43:40 +0000 -dvdomatic (0.73beta9-1) UNRELEASED; urgency=low +dcpomatic (0.73beta9-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Wed, 20 Feb 2013 23:40:24 +0000 -dvdomatic (0.73beta8-1) UNRELEASED; urgency=low +dcpomatic (0.73beta8-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Mon, 18 Feb 2013 22:35:51 +0000 -dvdomatic (0.73beta7-1) UNRELEASED; urgency=low +dcpomatic (0.73beta7-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Mon, 18 Feb 2013 20:38:51 +0000 -dvdomatic (0.73beta6-1) UNRELEASED; urgency=low +dcpomatic (0.73beta6-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 17 Feb 2013 23:05:56 +0000 -dvdomatic (0.73beta3-1) UNRELEASED; urgency=low +dcpomatic (0.73beta3-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 17 Feb 2013 23:05:05 +0000 -dvdomatic (0.73beta2-1) UNRELEASED; urgency=low +dcpomatic (0.73beta2-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sat, 16 Feb 2013 22:42:32 +0000 -dvdomatic (0.73beta1-1) UNRELEASED; urgency=low +dcpomatic (0.73beta1-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sat, 16 Feb 2013 21:19:24 +0000 -dvdomatic (0.72-1) UNRELEASED; urgency=low +dcpomatic (0.72-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 24 Jan 2013 15:31:57 +0000 -dvdomatic (0.71-1) UNRELEASED; urgency=low +dcpomatic (0.71-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Thu, 24 Jan 2013 11:36:04 +0000 -dvdomatic (0.70-1) UNRELEASED; urgency=low +dcpomatic (0.70-1) UNRELEASED; urgency=low * New upstream release. * New upstream release. @@ -300,7 +300,7 @@ dvdomatic (0.70-1) UNRELEASED; urgency=low -- Carl Hetherington Sat, 12 Jan 2013 23:07:15 +0000 -dvdomatic (0.70beta3-1) UNRELEASED; urgency=low +dcpomatic (0.70beta3-1) UNRELEASED; urgency=low * New upstream release. * New upstream release. @@ -309,13 +309,13 @@ dvdomatic (0.70beta3-1) UNRELEASED; urgency=low -- Carl Hetherington Sun, 06 Jan 2013 23:44:24 +0000 -dvdomatic (0.68-1) UNRELEASED; urgency=low +dcpomatic (0.68-1) UNRELEASED; urgency=low * New upstream release. -- Carl Hetherington Sun, 23 Dec 2012 01:43:44 +0000 -dvdomatic (0.68beta10-1) UNRELEASED; urgency=low +dcpomatic (0.68beta10-1) UNRELEASED; urgency=low * New upstream release. * New upstream release. @@ -325,91 +325,91 @@ dvdomatic (0.68beta10-1) UNRELEASED; urgency=low -- Carl Hetherington Sat, 22 Dec 2012 13:27:27 +0000 -dvdomatic (0.68beta5-1) unstable; urgency=low +dcpomatic (0.68beta5-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Thu, 20 Dec 2012 07:53:46 +0000 -dvdomatic (0.68beta4-1) unstable; urgency=low +dcpomatic (0.68beta4-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Thu, 20 Dec 2012 07:48:45 +0000 -dvdomatic (0.68beta3-1) unstable; urgency=low +dcpomatic (0.68beta3-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Thu, 20 Dec 2012 00:35:45 +0000 -dvdomatic (0.68beta2-1) unstable; urgency=low +dcpomatic (0.68beta2-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Wed, 19 Dec 2012 11:22:58 +0000 -dvdomatic (0.68beta1-1) unstable; urgency=low +dcpomatic (0.68beta1-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Wed, 19 Dec 2012 10:11:13 +0000 -dvdomatic (0.67-1) unstable; urgency=low +dcpomatic (0.67-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Tue, 18 Dec 2012 23:49:27 +0000 -dvdomatic (0.66-1) unstable; urgency=low +dcpomatic (0.66-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Tue, 18 Dec 2012 11:29:04 +0000 -dvdomatic (0.65-1) unstable; urgency=low +dcpomatic (0.65-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Tue, 18 Dec 2012 09:24:56 +0000 -dvdomatic (0.64-1) unstable; urgency=low +dcpomatic (0.64-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Thu, 13 Dec 2012 21:52:09 +0000 -dvdomatic (0.63pre-1) unstable; urgency=low +dcpomatic (0.63pre-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Tue, 11 Dec 2012 23:15:52 +0000 -dvdomatic (0.60-1) unstable; urgency=low +dcpomatic (0.60-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Tue, 11 Dec 2012 22:46:04 +0000 -dvdomatic (0.59-1) unstable; urgency=low +dcpomatic (0.59-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Mon, 10 Dec 2012 20:58:19 +0000 -dvdomatic (0.59beta5-1) unstable; urgency=low +dcpomatic (0.59beta5-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Sun, 09 Dec 2012 23:51:55 +0000 -dvdomatic (0.59beta4-1) unstable; urgency=low +dcpomatic (0.59beta4-1) unstable; urgency=low * New upstream release. -- Carl Hetherington Sun, 09 Dec 2012 21:38:00 +0000 -dvdomatic (0.59beta1-1) unstable; urgency=low +dcpomatic (0.59beta1-1) unstable; urgency=low * Initial release. diff --git a/debian/copyright b/debian/copyright index 2579947e4..0cf23aacd 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,6 +1,6 @@ Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: dvdomatic -Source: +Upstream-Name: dcpomatic +Source: Files: * Copyright: 2012 Carl Hetherington diff --git a/debian/files b/debian/files index 7639f05ac..ca46cf438 100644 --- a/debian/files +++ b/debian/files @@ -1 +1 @@ -dvdomatic_0.59beta1-1_i386.deb video extra +dcpomatic_0.59beta1-1_i386.deb video extra diff --git a/debian/rules b/debian/rules index 3320087a5..ba42e5291 100755 --- a/debian/rules +++ b/debian/rules @@ -19,5 +19,5 @@ override_dh_auto_build: ./waf --nocache build override_dh_auto_install: - ./waf --nocache install --destdir=debian/dvdomatic + ./waf --nocache install --destdir=debian/dcpomatic diff --git a/doc/mainpage.txt b/doc/mainpage.txt index 59c578899..649c9c609 100644 --- a/doc/mainpage.txt +++ b/doc/mainpage.txt @@ -1,37 +1,37 @@ -/** @mainpage DVD-o-matic +/** @mainpage DCP-o-matic * - * DVD-o-matic is a tool to create digital cinema packages (DCPs) from + * DCP-o-matic is a tool to create digital cinema packages (DCPs) from * video files, or from sets of TIFF image files. It is written in C++ * and distributed under the GPL. * * Video files are decoded using FFmpeg (http://ffmpeg.org), so any video - * supported by FFmpeg should be usable with DVD-o-matic. DVD-o-matic's output has been + * supported by FFmpeg should be usable with DCP-o-matic. DCP-o-matic's output has been * tested on numerous digital projectors. * - * DVD-o-matic allows you to crop black borders from movies, scale them to the correct + * DCP-o-matic allows you to crop black borders from movies, scale them to the correct * aspect ratio and apply FFmpeg filters. The time-consuming encoding of JPEG2000 files * can be parallelised amongst any number of processors on the local host and any number * of servers over a network. * - * DVD-o-matic can also make DCPs from still images, for advertisements and such-like. + * DCP-o-matic can also make DCPs from still images, for advertisements and such-like. * - * Parts of DVD-o-matic are based on OpenDCP (http://code.google.com/p/opendcp), + * Parts of DCP-o-matic are based on OpenDCP (http://code.google.com/p/opendcp), * written by Terrence Meiczinger. * - * DVD-o-matic uses libopenjpeg (http://code.google.com/p/openjpeg/) for JPEG2000 encoding + * DCP-o-matic uses libopenjpeg (http://code.google.com/p/openjpeg/) for JPEG2000 encoding * and libsndfile (http://www.mega-nerd.com/libsndfile/) for WAV file manipulation. It * also makes heavy use of the boost libraries (http://www.boost.org/). ImageMagick * (http://www.imagemagick.org/) is used for still-image encoding and decoding, and the GUI is * built using wxWidgets (http://wxwidgets.org/). It also uses libmhash (http://mhash.sourceforge.net/) * for debugging purposes. * - * Thanks are due to the authors and communities of all DVD-o-matic's dependencies. + * Thanks are due to the authors and communities of all DCP-o-matic's dependencies. * - * DVD-o-matic is distributed in the hope that there are still cinemas with projectionists + * DCP-o-matic is distributed in the hope that there are still cinemas with projectionists * who might want to use it. As Mark Kermode says, "if it doesn't have a projectionist * it's not a cinema - it's a sweetshop with a video-screen." * * Email correspondance is welcome to cth@carlh.net * - * More details can be found at http://carlh.net/software/dvdomatic + * More details can be found at http://carlh.net/software/dcpomatic */ diff --git a/doc/manual/Makefile b/doc/manual/Makefile index 94abc8516..115d7c3c8 100644 --- a/doc/manual/Makefile +++ b/doc/manual/Makefile @@ -1,4 +1,4 @@ -# DVD-o-matic manual makefile +# DCP-o-matic manual makefile all: html pdf @@ -8,7 +8,7 @@ SCREENSHOTS := file-new.png video-new-film.png still-new-film.png click-content- still-select-content-file.png examine-thumbs.png \ calculate-audio-gain.png prefs.png making-dcp.png filters.png film-tab.png video-tab.png audio-tab.png subtitles-tab.png -XML := dvdomatic.xml +XML := dcpomatic.xml GRAPHICS := @@ -70,7 +70,7 @@ diagrams/%.pdf: diagrams/%.svg # HTML # -html: $(XML) dvdomatic-html.xsl extensions-html.ent dvdomatic.css \ +html: $(XML) dcpomatic-html.xsl extensions-html.ent dcpomatic.css \ $(addprefix html/screenshots/,$(SCREENSHOTS)) \ $(subst .svg,.png,$(addprefix diagrams/,$(DIAGRAMS))) \ $(subst .svg,.png,$(addprefix graphics/,$(GRAPHICS))) \ @@ -80,19 +80,19 @@ html: $(XML) dvdomatic-html.xsl extensions-html.ent dvdomatic.css \ cp extensions-html.ent extensions.ent # DocBoox -> html - xmlto html -m dvdomatic-html.xsl dvdomatic.xml --skip-validation -o html + xmlto html -m dcpomatic-html.xsl dcpomatic.xml --skip-validation -o html # Copy graphics and CSS in # mkdir -p html/diagrams html/graphics # cp diagrams/*.png html/diagrams # cp graphics/*.png html/graphics - cp dvdomatic.css html + cp dcpomatic.css html # # PDF # -pdf: $(XML) dvdomatic-pdf.xsl extensions-pdf.ent screenshots/*.png $(subst .svg,.pdf,$(addprefix diagrams/,$(DIAGRAMS))) +pdf: $(XML) dcpomatic-pdf.xsl extensions-pdf.ent screenshots/*.png $(subst .svg,.pdf,$(addprefix diagrams/,$(DIAGRAMS))) # The DocBook needs to know what file extensions to look for # for screenshots and diagrams; use the correct file to tell it. @@ -100,14 +100,14 @@ pdf: $(XML) dvdomatic-pdf.xsl extensions-pdf.ent screenshots/*.png $(subst .svg, mkdir -p pdf - dblatex -p dvdomatic-pdf.xsl -s dvdomatic.sty -r pptex.py -T native dvdomatic.xml -t pdf -o pdf/dvdomatic.pdf + dblatex -p dcpomatic-pdf.xsl -s dcpomatic.sty -r pptex.py -T native dcpomatic.xml -t pdf -o pdf/dcpomatic.pdf # # LaTeX (handy for debugging) # -tex: $(XML) dvdomatic-pdf.xsl extensions-pdf.ent +tex: $(XML) dcpomatic-pdf.xsl extensions-pdf.ent # The DocBook needs to know what file extensions to look for # for screenshots and diagrams; use the correct file to tell it. @@ -116,8 +116,8 @@ tex: $(XML) dvdomatic-pdf.xsl extensions-pdf.ent mkdir -p tex # -P removes the revhistory table - dblatex -P doc.collab.show=0 -P latex.output.revhistory=0 -p dvdomatic-pdf.xsl -s dvdomatic.sty -r pptex.py -T native dvdomatic.xml -t tex -o tex/dvdomatic.tex + dblatex -P doc.collab.show=0 -P latex.output.revhistory=0 -p dcpomatic-pdf.xsl -s dcpomatic.sty -r pptex.py -T native dcpomatic.xml -t tex -o tex/dcpomatic.tex -clean:; rm -rf html pdf diagrams/*.pdf diagrams/*.png graphics/*.png *.aux dvdomatic.cb dvdomatic.cb2 dvdomatic.glo dvdomatic.idx dvdomatic.ilg - rm -rf dvdomatic.ind dvdomatic.lof dvdomatic.log dvdomatic.tex dvdomatic.toc extensions.ent dvdomatic.out +clean:; rm -rf html pdf diagrams/*.pdf diagrams/*.png graphics/*.png *.aux dcpomatic.cb dcpomatic.cb2 dcpomatic.glo dcpomatic.idx dcpomatic.ilg + rm -rf dcpomatic.ind dcpomatic.lof dcpomatic.log dcpomatic.tex dcpomatic.toc extensions.ent dcpomatic.out diff --git a/doc/manual/dvdomatic-html.xsl b/doc/manual/dvdomatic-html.xsl deleted file mode 100644 index 059d7ead7..000000000 --- a/doc/manual/dvdomatic-html.xsl +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - diff --git a/doc/manual/dvdomatic-pdf.xsl b/doc/manual/dvdomatic-pdf.xsl deleted file mode 100644 index 414fb64b8..000000000 --- a/doc/manual/dvdomatic-pdf.xsl +++ /dev/null @@ -1,17 +0,0 @@ - - - - -colorlinks,linkcolor=black,urlcolor=black - - -0 -0 - - -scale=0.6 - - -3 - - diff --git a/doc/manual/dvdomatic.css b/doc/manual/dvdomatic.css deleted file mode 100644 index 0e4982f20..000000000 --- a/doc/manual/dvdomatic.css +++ /dev/null @@ -1,19 +0,0 @@ -body { - font-family: luxi sans, sans-serif; - margin-left: 4em; - margin-right: 4em; - margin-top: 1em; - margin-bottom: 1em; - background-color: #E2E8EE; -} - -div.sidebar { - margin-left: 1em; - margin-right: 1em; - padding-left: 1em; - padding-right: 1em; - border-color: #000000; - border-width: 2px; - border-style: solid; - background-color: #E2E8EE; -} diff --git a/doc/manual/dvdomatic.sty b/doc/manual/dvdomatic.sty deleted file mode 100644 index 834e581fc..000000000 --- a/doc/manual/dvdomatic.sty +++ /dev/null @@ -1,68 +0,0 @@ -%% -%% This style is derivated from the docbook one -%% -\NeedsTeXFormat{LaTeX2e} -\ProvidesPackage{ardour}[2007/04/04 My DocBook Style] - -%% Just use the original package and pass the options -\RequirePackageWithOptions{docbook} - -% Use a nice font -\usepackage{lmodern} - -% Define \dbend as the dangerous bend sign -\font\manual=manfnt -\def\dbend{{\manual\char127}} - -% Redefine sidebar environment to use the dangerous bend style -% Danger, Will Robinson! -\def\sidebar{\begin{trivlist}\item[]\noindent% -\begingroup\hangindent=2pc\hangafter=-2%\clubpenalty=10000% -\def\par{\endgraf\endgroup}% -\hbox to0pt{\hskip-\hangindent\dbend\hfill}\ignorespaces} -\def\endsidebar{\par\end{trivlist}} - - -% Futz with the title page; basically a copy of -% /usr/share/texmf/tex/latex/dblatex/style/dbk_title.sty -% with authors added. - -\def\DBKcover{ -\ifthenelse{\equal{\DBKedition}{}}{\def\edhead{}}{\def\edhead{Ed. \DBKedition}} - -\pagestyle{empty} - -% interligne double -\setlength{\oldbaselineskip}{\baselineskip} -\setlength{\baselineskip}{2\oldbaselineskip} -\textsf{ -\vfill -\vspace{2.5cm} -\begin{center} - \huge{\textbf{\DBKtitle}}\\ % - \ \\ % - \ \\ % - \Large{\DBKauthor}\\ % - \ifx\DBKsubtitle\relax\else% - \underline{\ \ \ \ \ \ \ \ \ \ \ }\\ % - \ \\ % - \huge{\textbf{\DBKsubtitle}}\\ % - \fi -\end{center} -\vfill -\setlength{\baselineskip}{\oldbaselineskip} -\hspace{1cm} -\vspace{1cm} -\begin{center} -\begin{tabular}{p{7cm} p{7cm}} -\Large{\DBKreference{} \edhead} & \\ -\end{tabular} -\end{center} -} - -% Format for the other pages -\newpage -\setlength{\baselineskip}{\oldbaselineskip} -%\chead[]{\DBKcheadfront} -\lfoot[]{} -} diff --git a/doc/manual/dvdomatic.xml b/doc/manual/dvdomatic.xml deleted file mode 100644 index 58315eca6..000000000 --- a/doc/manual/dvdomatic.xml +++ /dev/null @@ -1,932 +0,0 @@ - - - - -%dbcent; - -%extensions; -]> - - - -DVD-o-matic -CarlHetherington - - - -Introduction - - -Hello, and welcome to DVD-o-matic! - - -
-What is DVD-o-matic? - - -DVD-o-matic is a program to generate Digital -Cinema Packages (DCPs) from DVDs, Blu-Rays, video files such as MP4 -and AVI, or still images. The resulting DCPs will play on modern digital -cinema projectors. - - - -You might find it useful to make DVDs easier to present, to encode -independently-shot feature films, or to generate local advertising for -your cinema. - - -
- -
-Licence - - -DVD-o-matic is licensed under the GNU GPL. - - -
- -
- - -Installation - -
-Windows - - -To install DVD-o-matic on Windows, simply download the installer from -http://carlh.net -and double-click it. Click through the installer wizard, and -DVD-o-matic will be installed onto your machine. - - - -If you are using a 32-bit version of Windows, you will need the 32-bit -installer. For 64-bit Windows, either installer will work, but I -suggest you used the 64-bit version as it will allow DVD-o-matic to -use more memory. You may find that DVD-o-matic crashes if you run -many parallel encoding threads (more than 4) on the 32-bit -version. - - -
- -
-Ubuntu Linux - - -You can install DVD-o-matic on Ubuntu 12.04 (‘Precise -Pangolin’) or 12.10 (‘Quantal Quetzal’) using -.deb packages: download the appropriate package from -http://carlh.net and -double-click it. Ubuntu will install the necessary bits and pieces -and set DVD-o-matic up for you. - - -
- -
-Other Linux distributions - - -Installation on non-Ubuntu Linux is currently a little involved, as -there are no packages available (yet); you will have to compile it -from source. If you are using a non-Ubuntu distribution, do let me -know via the mailing -list and I will see about building some packages. - - - -The following dependencies are required: - -FFmpeg -libsndfile -OpenSSL -libopenjpeg -ImageMagick -Boost -libssh -GTK -wxWidgets -libdcp - - - - -Once you have installed the development packages for the dependencies, -download the source code from http://carlh.net, -unpack it and run the following commands from inside the source -directory: - - - -./waf configure -./waf build -sudo ./waf install - - - -With any luck, this will build and install DVD-o-matic on your system. To run it, enter: - - - -dvdomatic - - - -in a shell. - - -
-
- - -Creating a video DCP - - -In this chapter we will see how to create a video DCP using -DVD-o-matic. We will gloss over some of the finer details, which are -explained in later chapters. - - -
-Creating a new film - - -Let's make a very simple DCP to see how DVD-o-matic works. First, we -need some content. Download the low-resolution trailer for the open -movie Sintel from their -website. Generally, of course, one would want to use the -highest-resolution material available, but for this test we will use -the low-resolution version to save everyone's bandwidth bills. - - - -Now, start DVD-o-matic and its window will open. First, we will -create a new ‘film’. A ‘film’ is how DVD-o-matic refers to -a piece of content, along with some settings, which we will make into -a DCP. DVD-o-matic stores its data in a folder on your disk while it -creates the DCP. You can create a new film by selecting -New from the File menu, as -shown in . - - -
- Creating a new film - - - - - -
- - -This will open a dialogue box for the new film, as shown in . - - -
- Dialogue box for creating a new film - - - - - -
- - -In this dialogue box you can choose a name for the film. This will be -used to name the folder to store its data in, and also as the initial -name for the DCP itself. You can also choose whereabouts you want to create -the film. In the example from the figure, DVD-o-matic will create a -folder called ‘DCP Test’ inside my home folder (carl) into which it -will write its working files. - - - -If you always create your DCPs in a particular folder, you can use -DVD-o-matic's Preferences to make life a little -easier by setting the default folder that DVD-o-matic will offer in this dialogue. -See . - - -
- -
-Selecting content - - -The next step is to set the content that you want to use. Click the -content selector, as shown in , and a file chooser will -open for you to select the content file to use, as shown in . - - -
- Opening the content selector - - - - - -
- -
- Selecting a video content file - - - - - -
- - -Select your content file and click Open. In this -case we are using the Sintel trailer that we downloaded earlier. - - - -When you do this, DVD-o-matic will take a look at your file. After a -short while (when the progress bar at the bottom right of the window -has finished), you can look through your content using the slider to -the right of the window, as shown in . - - -
- Examining the content - - - - - -
- - -Dragging the slider will move through your video. You can also click -the Play button to play the content back. Note -that there will be no sound, and playback might not be entirely -accurate (it may be slightly slower or faster than it should be, for -example). This player is really only intended for brief inspection of -content; if you need to check it more thoroughly, use another player -such as Totem, mplayer or VLC. - - -
- -
-Setting up - - -Now there are a few things to set up to describe how the DCP should be -created. The settings are divided into four tabs: film, video, audio and subtitles. - - -
-Film tab - - -The ‘film’ tab contains settings that pertain to the whole film, as shown in . - - -
- Film settings tab - - - - - -
- - -The first thing here is the name. This is generally set to the title -of the film that is being encoded. If Use DCI -name is not ticked, the name that you specify will be used -as-is for the name of the DCP. If Use DCI name -is ticked, the name that you enter will be used as part of a -DCI-compliant name. - - - -Underneath the name field is a preview of the name that the DCP will -get. To use a DCI-compliant name, tick the Use DCI -name checkbox. The DCI name will be composed using details -of your content's soundtrack, the current date and other things that -can be specified in the DCI name details dialogue box, which you can -open by clicking on the Details button. - - - -If the DCP name is long, it may not all be visible. You can see the -full name by hovering the mouse pointer over the partial name. - - - -The Trust content's header button starts off -checked, and this means that DVD-o-matic will use the content's header -information to determine its length. If, for some reason, this header -length is wrong, uncheck the Trust content's -header button and DVD-o-matic will run through the content -to find its exact length. This may take a while for large pieces of content. - - - -Next up is the content type. This can be -‘feature’, ‘trailer’ or whatever; select the -required type from the drop-down list. - - - -The trim frames settings allow you to trim frames -from the beginning and end of the content; any trimmed frames will not -be included in the DCP. - - -
- -
-Video tab - - -This tab contains settings related to the picture in your DCP, as shown in . - - -
- Video settings tab - - - - - -
- - -The first option on this tab is the format. This will govern the -shape that DVD-o-matic will make your image into. Select the aspect -ratio that your content should be presented in. The ‘4:3 within -Flat’ and ‘16:9 within Flat’ settings will put the -image at the specified ratio within a Flat (1.85:1) frame, so that you -can project the DCP using your projector's Flat preset. - - - -The remaining options can often be left alone, but may sometimes be -useful. The ‘crop’ settings can be used to crop your -content, which can be used to remove black borders from round the -edges of DVD images, for example. The specified number of pixels will -be trimmed from each edge, and the content image in the right of the -window will be updated to show the effect of the crop. - - - -The ‘filters’ settings allow you to apply various video -filters to the image. These may be useful to try to improve -poor-quality sources like DVDs. We will discuss filtering later in the manual. - - - - -The ‘scaler’ is the method that will be used to scale up -your content to the required size for the DCP, if required. We will -discuss the options in more detail later; Bicubic is a fine choice in -most situations. - - - - -The ‘colour look-up table’ specifies the colour space that -your input content will be expected to be in. If in doubt, leave it -set to ‘sRGB’. - - - -Finally, the ‘JPEG2000 bandwidth’ setting changes how big the final -image files used within the DCP will be. Larger numbers will give -better quality, but correspondingly larger DCPs. The bandwidth can be -between 50 and 250 megabits per second (MBps). - - -
- -
-Audio tab - - -This tab contains settings related to the sound in your DCP, as shown in . - - -
- Audio settings tab - - - - - -
- - - -‘Audio Gain’ is used to alter the volume of the -soundtrack. The specified gain (in dB) will be applied to each sound -channel before it is written to the DCP. - - - -If you use a sound processor that DVD-o-matic knows about, it can help -you calculate changes in gain that you should apply. Say, for -example, that you make a test DCP and find that you have to run it at -volume 5 instead of volume 7 to get a good sound level in the screen. -If this is the case, click the Calculate... -button next to the audio gain entry, and the dialogue box in will open. - - -
- Calculating audio gain - - - - - -
- - -For our example, put 5 in the first box and 7 in the second and click -OK. DVD-o-matic will calculate the audio gain -that it should apply to make this happen. Then you can re-make the -DCP (this will be reasonably fast, as the video data will already have -been done) and it should play back at the correct volume with 7 on -your sound-rack fader. - - - -Current versions of DVD-o-matic only know about the Dolby CP750. If -you use a different sound processor, and know the gain curve of its -volume control, get in -touch. - - - -‘Audio Delay’ is used to adjust the synchronisation -between audio and video. A positive delay will move the audio later -with respect to the video, and a negative delay will move it earlier. - - - -By default the Use content‘s audio button -will be selected. This means that the DCP will use one of the -soundtracks from your content file; you can select the soundtrack that -you wish to use from the drop-down box. - - - -Note that if your content's audio is mono, DVD-o-matic will place it -in the centre channel in the DCP. - - - -Alternatively, you can supply different sound files by clicking the -Use external audio button and choosing a WAV file -for any channels that you want to appear in the DCP. These files can -be any bit depth and sampling rate, and will be re-sampled and -bit-depth converted if required. - - -
-
-Subtitles tab - - -This tab contains settings related to subtitles in your DCP, as shown in . - - -
- Subtitle settings tab - - - - - -
- - -DVD-o-matic will extract subtitles from the content, if present, and -they can be ‘burnt into’ the DCP (that is, they are -included in the image and not overlaid by the projector). Note that -DVD and Blu-Ray subtitles are stored as bitmaps, so it is not possible -(automatically) to use non-burnt-in subtitles with these sources. -Select the With Subtitles checkbox to enable -subtitles. The offset control moves the -subtitles up and down the image, and the scale -control changes their size. - - - -Future versions of DVD-o-matic will hopefully include the option to -use text subtitles (as is the norm with most professionally-mastered -DCPs). - - -
-
- -
-Making the DCP - - -Now that we have set everything up, choose Make -DCP from the Jobs menu. DVD-o-matic -will encode your DCP. This may take some time (many hours in some -cases). While the job is in progress, DVD-o-matic will update you on -how it is getting on with the progress bar in the bottom of its window, as shown in . - - -
- Making the DCP - - - - - -
- - -When it has finished, the DCP will end up on your disk inside the -film's directory. You can then copy this to a projector via a USB -stick, hard-drive or network connection. - - - -Alternatively, if you have a projector or TMS that is accessible via -SCP across your network, you can upload the content directly from -DVD-o-matic. See . - - -
-
- - - -Creating a still-image DCP - - -DVD-o-matic can also be used to create DCPs of a still image, perhaps -for an advertisement or an on-screen announcement. This chapter shows you -how to do it. - - - -As with video DCPs, the first step is to create a new -‘Film’; select New from the -File menu and the new film dialogue will open as -shown in . - - -
- Dialogue box for creating a new film - - - - - -
- - -Enter a name and click OK. Then we set up the -content; click the content selector as before, and this time we will -choose an image file, as shown in . - - -
- Selecting a still content file - - - - - -
- - -Setting up for a still image DCP is somewhat simpler than for a video; -the tabs are all the same, but many options are removed and a few are added. - - - -As with video, you can select a content type and the format (ratio) -that your image should be presented in. It will be scaled and padded -to fit the selected ratio, but in such a way that the pixel aspect -ratio is preserved. In other words, the image will not be stretched, -merely scaled; if you want to stretch your image, you will need to do -so in a separate program before importing it into DVD-o-matic. You -can also crop your image, if you so choose, and then set a duration -(in seconds) that the image should appear on screen. - - - -Still-image DCPs can include sound; this can be added from the -Audio tab. If your specified duration is shorter -than the audio, the audio will be cut off at the duration; if it is -longer, silence will be added after your audio. - - - -Finally, as with video, you can choose Make DCP -from the Jobs menu to create your DCP. This will -be much quicker than creating a video DCP, as DVD-o-matic only needs -to encode a single frame which it can then repeat. - - -
- - - -Preferences - - -DVD-o-matic provides a few preferences which can be used to modify its -behaviour. This chapter explains those options. - - -
-The preferences dialogue - - -The preferences dialogue is opened by choosing -Preferences... from the Edit -menu. The dialogue is shown in . - - -
- Preferences - - - - - -
- -
-TMS setup - - -The first part of the dialogue gives some options for specifying -details about your TMS. If you do this, and your TMS accepts SSH -connections, you can upload DCPs directly from DVD-o-matic to the TMS. -This is discussed in . - - - -TMS IP address should be set to the IP address of -your TMS, TMS target path to the place that DCPs -should be uploaded to (which will be relative to the home directory of -the SSH user). Finally, the user name and password are the -credentials required to log into the TMS via SSH. - -
- -
-Threads - - -When DVD-o-matic is encoding DCPs it can use multiple parallel threads -to speed things up. Set this value to the number of threads -DVD-o-matic should use. This would typically be set to the number of -processors (or processor cores) in your machine. - - -
- -
-Default directory for new films - - -This is the directory which DVD-o-matic will suggest initially as a place to put new films. - - -
- -
-A/B options - - -These options are for DVD-o-matic's special mode of making A/B -comparison DCPs for checking the performance of video filters. Their -use is described in . - - -
- -
-Encoding servers - - -If you have spare machines sitting around on your network not doing -much, they can be pressed into service to speed up DCP encodes. This -is done by running a small server program on the machine, which will -encode video sent to it by the ‘master’ DVD-o-matic. This -option is described in more detail in . -Use these preferences to specify the encoding servers that should be -used. - - -
- -
-
- - -Advanced topics - -This chapter describes some parts of DVD-o-matic that are -probably not essential, but which you might find useful in some -circumstances. - - -
-Filtering - - -DVD-o-matic offers a variety of filters that can be applied to your -video content. You can set up the filters by clicking the -Edit button next to the filters entry in the -setup area of the DVD-o-matic window; this opens the filters selector -as shown in . - - -
- Filters selector - - - - - -
- - -After changing the filters setup, you will need to regenerate the DCP -to see the effect on the cinema screen. The preview in DVD-o-matic -will update itself whenever filters are changed, though of course this -image is much smaller and of lower resolution than a projected image! - - -
- -
-Scaling - - -If your source material is not of the DCI-specified size, or if it -uses non-square pixels, DVD-o-matic will need to scale it. The -algorithm used to scale is set up by the Scaler -entry in the film setup area. We think ‘Bicubic’ is the -best all-round option, but tests are ongoing. - - -
- -
-TMS upload - - -If you have configured details of a TMS in the preferences dialogue -() you can upload a completed DCP -straight to your TMS buy choosing Send DCP to TMS -from the Jobs menu. - - -
- - -
-A/B comparison - - -When evaluating the effects of different filters or scalers on the -image quality, A/B mode might be useful. In this mode, DVD-o-matic -will generate a DCP where the left half of the image uses some -‘reference’ filtering and scaling, and the right half of -the image uses a different set of filters and a different scaler. -This DCP can then be played back on a projector and the image quality -evaluated. - - - -To enable A/B mode, click the A/B checkbox in the setup area of the -DVD-o-matic window. When you generate your DCP, the left half of the -screen will use the filters and scaler specified in the preferences dialogue, and the right -half will use the filters and scaler specified in the film setup. - - -
- -
-Encoding servers - - -One way to increase the speed of DCP encoding is to use more -than one machine at the same time. An instance of DVD-o-matic can -offload some of the time-consuming JPEG2000 encoding to any number of -other machines on a network. To do this, one ‘master’ -machine runs DVD-o-matic, and the ‘server’ machines run -a small program called ‘servomatic’. - - -
-Running the servers - - -There are two options for the encoding server; -servomatic_cli, which runs on the command line, and -servomatic_gui, which has a simple GUI. The command line -version is well-suited to headless servers, especially on Linux, and -the GUI version works best on Windows where it will put an icon in the -system tray. - - - -To run the command line version, simply enter: - - - -servomatic_cli - - - -at a command prompt. If you are running the program on a machine with -a multi-core processor, you can run multiple parallel encoding threads -by doing something like: - - - -servomatic_cli -t 4 - - - -to run 4 threads in parallel. - - - -To run the GUI version on windows, run the ‘DVD-o-matic encode -server’ from the start menu. An icon will appear in the system -tray; right-click it to open a menu from whence you can quit the -server or open a window to show its status. - - -
-
-Setting up DVD-o-matic - - -Once your servers are running, you need to tell your master -DVD-o-matic instance about them. Start DVD-o-matic and open the -Preferences dialog from the -Edit menu. At the bottom of this dialog is a -section where you can add, edit and remove encoding servers. For each -encoding server you need only specify its IP address and the number of -threads that it is running, so that DVD-o-matic knows how many -parallel encode jobs to send to the server. - - - -Once this is done, any encodes that you start will split the workload -up between the master machine and the servers. - - -
-
-Some notes about encode servers - - -DVD-o-matic does not mind if servers come and go; if a server -disappears, DVD-o-matic will stop sending work to it, and will check -it every minute or so in case it has come back online. - - - -You will probably find that using a 1Gb/s or faster network will -provide a significant speed-up compared to a 100Mb/s network. - - - -Making changes to the server configuration in the master DVD-o-matic -will have no effect while an encode is running; the changes will only -be noticed when a new encode is started. - - -
-
- -
- - -
diff --git a/dvdomatic.desktop.in b/dvdomatic.desktop.in deleted file mode 100644 index 65067eb3b..000000000 --- a/dvdomatic.desktop.in +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Encoding=UTF-8 -Version=1.0 -Type=Application -Terminal=false -Exec=@PREFIX@/bin/dvdomatic -Name=DVD-o-matic -Icon=dvdomatic -Comment=DCP generator -Categories=AudioVideo;Video diff --git a/hacks/python-playback/config.py b/hacks/python-playback/config.py deleted file mode 100644 index fecf261f5..000000000 --- a/hacks/python-playback/config.py +++ /dev/null @@ -1,2 +0,0 @@ - -LEFT_SCREEN_WIDTH = 1366 diff --git a/hacks/python-playback/dvdomatic b/hacks/python-playback/dvdomatic deleted file mode 100755 index ce405f37e..000000000 --- a/hacks/python-playback/dvdomatic +++ /dev/null @@ -1,209 +0,0 @@ -#!/usr/bin/python - -import os -import operator -import traceback -import pygtk -pygtk.require('2.0') -import gtk -import glib -import gobject -import film -import film_view -import player -import screens -import thumbs -import ratio -import util - -FILM_DIRECTORY = '/home/carl/DVD' - -current_player = None -films = [] -inhibit_selection_update = False - -def find_films(): - global films - films = [] - for root, dirs, files in os.walk(FILM_DIRECTORY): - for name in files: - if os.path.basename(name) == 'info': - films.append(film.Film(os.path.join(root, os.path.dirname(name)))) - - films.sort(key = operator.attrgetter('name')) - -def update_film_store(): - global film_store - global films - global inhibit_selection_update - inhibit_selection_update = True - film_store.clear() - for f in films: - film_store.append([f.name]) - inhibit_selection_update = False - -def update_screen_store(screen_store, screens): - screen_store.clear() - for s in screens.screens: - screen_store.append([s.name]) - -def create_film_tree_view(film_store): - view = gtk.TreeView(film_store) - column = gtk.TreeViewColumn() - view.append_column(column) - cell = gtk.CellRendererText() - column.pack_start(cell) - column.add_attribute(cell, 'text', 0) - view.get_selection().set_mode(gtk.SELECTION_SINGLE) - return view - -def create_screen_view(screen_store): - view = gtk.TreeView(screen_store) - column = gtk.TreeViewColumn() - view.append_column(column) - cell = gtk.CellRendererText() - column.pack_start(cell) - column.add_attribute(cell, 'text', 0) - view.get_selection().set_mode(gtk.SELECTION_SINGLE) - return view - -def get_selected_film(): - (model, iter) = film_tree_view.get_selection().get_selected() - - for f in films: - if f.name == model.get(iter, 0)[0]: - return f - - return None - -# @return Selected screen name -def get_selected_screen(): - (model, iter) = screen_view.get_selection().get_selected() - return model.get(iter, 0)[0] - -def film_selected(selection): - if inhibit_selection_update: - return - - film_view.set(get_selected_film()) - check_for_playability() - -def screen_selected(selection): - check_for_playability() - -def check_for_playability(): - f = get_selected_film() - if screens.get_format(get_selected_screen(), f.ratio) is not None: - play_button.set_label("Play") - play_button.set_sensitive(True) - else: - play_button.set_label("Cannot play: no setting for %s on screen %s" % (ratio.find(f.ratio).name(), get_selected_screen())) - play_button.set_sensitive(False) - -def update_status(s): - global current_player - if current_player is None: - s.set_text("Not playing") - return True - - position = current_player.time_pos - if position is None: - return True - position_hms = util.s_to_hms(position) - - length = current_player.length - if length is None: - return True - - remaining = length - position - remaining_hms = util.s_to_hms(remaining) - s.set_text("Playing: %d:%02d:%02d, %d:%02d:%02d remaining" % (position_hms[0], position_hms[1], position_hms[2], remaining_hms[0], remaining_hms[1], remaining_hms[2])) - return True - -def play_clicked(b): - global current_player - f = get_selected_film() - current_player = player.get_player(f, screens.get_format(get_selected_screen(), f.ratio)) - print current_player.args - -def stop_clicked(b): - global current_player - if current_player is not None: - current_player.stop() - current_player = None - -def add_film_clicked(b): - global films - c = gtk.FileChooserDialog("New Film", main_window, gtk.FILE_CHOOSER_ACTION_CREATE_FOLDER, (("Add", gtk.RESPONSE_OK))) - c.set_current_folder(FILM_DIRECTORY) - if c.run() == gtk.RESPONSE_OK: - f = film.Film() - f.data = c.get_filename() - f.name = os.path.basename(c.get_filename()) - f.write() - find_films() - update_film_store() - c.hide() - - for i in range(0, len(films)): - if films[i].name == f.name: - film_tree_view.get_selection().select_path((i, )) - -main_window = gtk.Window(gtk.WINDOW_TOPLEVEL) -main_window.set_title("DVD-o-matic") -main_window.maximize() - -main_hbox = gtk.HBox() -main_hbox.set_spacing(12) -main_hbox.set_border_width(12) -main_window.add(main_hbox) - -find_films() -film_view = film_view.FilmView(main_window) -screens = screens.Screens("screens") - -left_vbox = gtk.VBox() -left_vbox.set_spacing(12) -main_hbox.pack_start(left_vbox, False, False) -right_vbox = gtk.VBox() -right_vbox.set_spacing(12) -main_hbox.pack_start(right_vbox) - -film_store = gtk.ListStore(gobject.TYPE_STRING) -update_film_store() - -film_tree_view = create_film_tree_view(film_store) -left_vbox.pack_start(film_tree_view, True, True) -film_tree_view.get_selection().select_path((0, )) -film_tree_view.get_selection().connect("changed", film_selected) - -add_film_button = gtk.Button(stock = gtk.STOCK_ADD) -left_vbox.pack_start(add_film_button, False, False) -add_film_button.connect("clicked", add_film_clicked) - -screen_store = gtk.ListStore(gobject.TYPE_STRING) -update_screen_store(screen_store, screens) - -screen_view = create_screen_view(screen_store) -left_vbox.pack_start(screen_view, False, False) -screen_view.get_selection().select_path((0, )) -screen_view.get_selection().connect("changed", screen_selected) - -right_vbox.pack_start(film_view, False, False) -film_view.set(films[0]) - -play_button = gtk.Button("Play") -right_vbox.pack_start(play_button) -play_button.connect("clicked", play_clicked) - -stop_button = gtk.Button("Stop") -right_vbox.pack_start(stop_button) -stop_button.connect("clicked", stop_clicked) - -status = gtk.Label() -right_vbox.pack_start(status, False, False) -glib.timeout_add_seconds(1, update_status, status) - -check_for_playability() -main_window.show_all() -gtk.main() diff --git a/hacks/python-playback/film.py b/hacks/python-playback/film.py deleted file mode 100644 index 3ad128027..000000000 --- a/hacks/python-playback/film.py +++ /dev/null @@ -1,188 +0,0 @@ -import os -import subprocess -import shlex -import shutil -import player - -class Film: - def __init__(self, data = None): - # File or directory containing content - self.content = None - # True if content is in DVD format - self.dvd = False - # DVD title number - self.dvd_title = 1 - # Directory containing metadata - self.data = None - # Film name - self.name = None - # Number of pixels by which to crop the content from each edge - self.left_crop = 0 - self.top_crop = 0 - self.right_crop = 0 - self.bottom_crop = 0 - # Use deinterlacing filter - self.deinterlace = False - # Target ratio - self.ratio = 1.85 - # Audio stream ID to play - self.aid = None - - self.width = None - self.height = None - self.fps = None - self.length = None - - if data is not None: - self.data = data - f = open(os.path.join(self.data, 'info'), 'r') - while 1: - l = f.readline() - if l == '': - break - - d = l.strip() - - s = d.find(' ') - if s != -1: - key = d[:s] - value = d[s+1:] - - if key == 'name': - self.name = value - elif key == 'content': - self.content = value - elif key == 'dvd': - self.dvd = int(value) == 1 - elif key == 'dvd_title': - self.dvd_title = int(value) - elif key == 'left_crop': - self.left_crop = int(value) - elif key == 'top_crop': - self.top_crop = int(value) - elif key == 'right_crop': - self.right_crop = int(value) - elif key == 'bottom_crop': - self.bottom_crop = int(value) - elif key == 'deinterlace': - self.deinterlace = int(value) == 1 - elif key == 'ratio': - self.ratio = float(value) - elif key == 'aid': - self.aid = int(value) - elif key == 'width': - self.width = int(value) - elif key == 'height': - self.height = int(value) - elif key == 'fps': - self.fps = float(value) - elif key == 'length': - self.length = float(value) - - if self.width is None or self.height is None or self.fps is None or self.length is None: - self.update_content_metadata() - - def write(self): - try: - os.mkdir(self.data) - except OSError: - pass - - f = open(os.path.join(self.data, 'info'), 'w') - self.write_datum(f, 'name', self.name) - self.write_datum(f, 'content', self.content) - self.write_datum(f, 'dvd', int(self.dvd)) - self.write_datum(f, 'dvd_title', self.dvd_title) - self.write_datum(f, 'left_crop', self.left_crop) - self.write_datum(f, 'top_crop', self.top_crop) - self.write_datum(f, 'right_crop', self.right_crop) - self.write_datum(f, 'bottom_crop', self.bottom_crop) - self.write_datum(f, 'deinterlace', int(self.deinterlace)) - self.write_datum(f, 'ratio', self.ratio) - self.write_datum(f, 'aid', self.aid) - self.write_datum(f, 'width', self.width) - self.write_datum(f, 'height', self.height) - self.write_datum(f, 'fps', self.fps) - self.write_datum(f, 'length', self.length) - - def write_datum(self, f, key, value): - if value is not None: - print >>f,'%s %s' % (key, str(value)) - - def thumbs_dir(self): - t = os.path.join(self.data, 'thumbs') - - try: - os.mkdir(t) - except OSError: - pass - - return t - - def thumb(self, n): - return os.path.join(self.thumbs_dir(), str('%08d.png' % (n + 1))) - - def thumbs(self): - return len(os.listdir(self.thumbs_dir())) - - def remove_thumbs(self): - shutil.rmtree(self.thumbs_dir()) - - def make_thumbs(self): - num_thumbs = 128 - cl = self.player_command_line() - if self.length is not None: - sstep = self.length / num_thumbs - else: - sstep = 100 - cl.extra = '-vo png -frames %d -sstep %d -nosound' % (num_thumbs, sstep) - os.chdir(self.thumbs_dir()) - os.system(cl.get(True)) - - def set_dvd(self, d): - self.dvd = d - self.remove_thumbs() - - def set_dvd_title(self, t): - self.dvd_title = t - self.remove_thumbs() - - def set_content(self, c): - if c == self.content: - return - - self.content = c - self.update_content_metadata() - - def player_command_line(self): - cl = player.CommandLine() - cl.dvd = self.dvd - cl.dvd_title = self.dvd_title - cl.content = self.content - return cl - - def update_content_metadata(self): - if self.content is None: - return - - self.width = None - self.height = None - self.fps = None - self.length = None - - cl = self.player_command_line() - cl.extra = '-identify -vo null -ao null -frames 0' - text = subprocess.check_output(shlex.split(cl.get(True))).decode('utf-8') - lines = text.split('\n') - for l in lines: - s = l.strip() - b = s.split('=') - if len(b) == 2: - if b[0] == 'ID_VIDEO_WIDTH': - self.width = int(b[1]) - elif b[0] == 'ID_VIDEO_HEIGHT': - self.height = int(b[1]) - elif b[0] == 'ID_VIDEO_FPS': - self.fps = float(b[1]) - elif b[0] == 'ID_LENGTH': - self.length = float(b[1]) diff --git a/hacks/python-playback/film_view.py b/hacks/python-playback/film_view.py deleted file mode 100644 index c11b2e657..000000000 --- a/hacks/python-playback/film_view.py +++ /dev/null @@ -1,212 +0,0 @@ -import os -import pygtk -pygtk.require('2.0') -import gtk -import ratio -import util -import thumbs - -class FilmView(gtk.HBox): - def __init__(self, parent): - gtk.HBox.__init__(self) - - self.parent_window = parent - - self.inhibit_save = True - - self.table = gtk.Table() - self.pack_start(self.table, True, True) - - self.table.set_row_spacings(4) - self.table.set_col_spacings(12) - self.film_name = gtk.Entry() - self.ratio = gtk.combo_box_new_text() - for r in ratio.ratios: - self.ratio.append_text(r.name()) - self.content_file_radio = gtk.RadioButton() - self.content_file_radio.set_label("File") - self.content_file_chooser = gtk.FileChooserDialog("Content", self.parent_window, gtk.FILE_CHOOSER_ACTION_OPEN, (("Select", gtk.RESPONSE_OK))) - self.content_file_button = gtk.FileChooserButton(self.content_file_chooser) - self.content_folder_radio = gtk.RadioButton() - self.content_folder_radio.set_label("Folder") - self.content_folder_radio.set_group(self.content_file_radio) - self.content_folder_chooser = gtk.FileChooserDialog("Content", self.parent_window, gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, (("Select", gtk.RESPONSE_OK))) - self.content_folder_button = gtk.FileChooserButton(self.content_folder_chooser) - self.dvd = gtk.CheckButton("DVD") - self.dvd_title = gtk.SpinButton() - self.dvd_title.set_range(0, 32) - self.dvd_title.set_increments(1, 4) - self.deinterlace = gtk.CheckButton("Deinterlace") - self.left_crop = self.crop_spinbutton() - self.right_crop = self.crop_spinbutton() - self.top_crop = self.crop_spinbutton() - self.bottom_crop = self.crop_spinbutton() - - # Information about the content (immutable) - self.source_size = self.label() - self.fps = self.label() - self.length = self.label() - - # Buttons - self.thumbs_button = gtk.Button("Show Thumbnails") - - self.film_name.connect("changed", self.changed, self) - self.ratio.connect("changed", self.changed, self) - self.deinterlace.connect("toggled", self.changed, self) - self.thumbs_button.connect("clicked", self.thumbs_clicked, self) - self.content_file_radio.connect("toggled", self.content_radio_toggled, self) - self.content_folder_radio.connect("toggled", self.content_radio_toggled, self) - self.content_file_button.connect("file-set", self.content_file_chooser_file_set, self) - self.content_folder_button.connect("file-set", self.content_folder_chooser_file_set, self) - self.dvd.connect("toggled", self.changed, self) - self.dvd_title.connect("value-changed", self.changed, self) - - n = 0 - self.table.attach(self.label("Film"), 0, 1, n, n + 1) - self.table.attach(self.film_name, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Ratio"), 0, 1, n, n + 1) - self.table.attach(self.ratio, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Content"), 0, 1, n, n + 1) - b = gtk.HBox() - b.set_spacing(4) - b.pack_start(self.content_file_radio, False, False) - b.pack_start(self.content_file_button, True, True) - b.pack_start(self.content_folder_radio, False, False) - b.pack_start(self.content_folder_button, True, True) - self.table.attach(b, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.dvd, 0, 2, n, n + 1) - n += 1 - self.table.attach(self.label("DVD title"), 0, 1, n, n + 1) - self.table.attach(self.dvd_title, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.deinterlace, 0, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Left Crop"), 0, 1, n, n + 1) - self.table.attach(self.left_crop, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Right Crop"), 0, 1, n, n + 1) - self.table.attach(self.right_crop, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Top Crop"), 0, 1, n, n + 1) - self.table.attach(self.top_crop, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Bottom Crop"), 0, 1, n, n + 1) - self.table.attach(self.bottom_crop, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Source size"), 0, 1, n, n + 1) - self.table.attach(self.source_size, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Frames per second"), 0, 1, n, n + 1) - self.table.attach(self.fps, 1, 2, n, n + 1) - n += 1 - self.table.attach(self.label("Length"), 0, 1, n, n + 1) - self.table.attach(self.length, 1, 2, n, n + 1) - - self.right_vbox = gtk.VBox() - self.pack_start(self.right_vbox, False, False) - - self.right_vbox.pack_start(self.thumbs_button, False, False) - - self.inhibit_save = False - - def set(self, film): - self.inhibit_save = True - - self.film = film - self.film_name.set_text(film.name) - self.ratio.set_active(ratio.ratio_to_index(film.ratio)) - if film.content is not None: - if os.path.isfile(film.content): - self.set_content_is_file(True) - self.content_file_button.set_filename(film.content) - else: - self.set_content_is_file(False) - self.content_folder_button.set_filename(film.content) - self.dvd.set_active(film.dvd) - self.dvd_title.set_value(film.dvd_title) - self.dvd_title.set_sensitive(film.dvd) - self.deinterlace.set_active(film.deinterlace) - self.left_crop.set_value(film.left_crop) - self.right_crop.set_value(film.right_crop) - self.top_crop.set_value(film.top_crop) - self.bottom_crop.set_value(film.bottom_crop) - - # Content information - if film.width is not None and film.height is not None: - self.source_size.set_text("%dx%d" % (film.width, film.height)) - else: - self.source_size.set_text("Unknown") - if film.fps is not None: - self.fps.set_text(str(film.fps)) - if film.length is not None: - self.length.set_text("%d:%02d:%02d" % util.s_to_hms(film.length)) - - self.inhibit_save = False - - def set_content_is_file(self, f): - self.content_file_button.set_sensitive(f) - self.content_folder_button.set_sensitive(not f) - self.content_file_radio.set_active(f) - self.content_folder_radio.set_active(not f) - - def label(self, text = ""): - l = gtk.Label(text) - l.set_alignment(0, 0.5) - return l - - def changed(self, a, b): - self.dvd_title.set_sensitive(self.dvd.get_active()) - self.save_film() - - def crop_spinbutton(self): - s = gtk.SpinButton() - s.set_range(0, 1024) - s.set_increments(1, 16) - s.connect("value-changed", self.changed, self) - return s - - def save_film(self): - if self.inhibit_save: - return - - self.film.name = self.film_name.get_text() - self.film.ratio = ratio.index_to_ratio(self.ratio.get_active()).ratio - - if self.content_file_radio.get_active(): - self.film.set_content(self.content_file_button.get_filename()) - else: - self.film.set_content(self.content_folder_button.get_filename()) - self.film.set_dvd(self.dvd.get_active()) - self.film.set_dvd_title(self.dvd_title.get_value_as_int()) - self.film.deinterlace = self.deinterlace.get_active() - self.film.left_crop = self.left_crop.get_value_as_int() - self.film.right_crop = self.right_crop.get_value_as_int() - self.film.top_crop = self.top_crop.get_value_as_int() - self.film.bottom_crop = self.bottom_crop.get_value_as_int() - self.film.write() - - def thumbs_clicked(self, a, b): - if self.film.thumbs() == 0: - self.film.make_thumbs() - - t = thumbs.Thumbs(self.film) - t.run() - t.hide() - self.left_crop.set_value(t.left_crop()) - self.right_crop.set_value(t.right_crop()) - self.top_crop.set_value(t.top_crop()) - self.bottom_crop.set_value(t.bottom_crop()) - - def content_file_chooser_file_set(self, a, b): - self.changed(a, b) - - def content_folder_chooser_file_set(self, a, b): - self.changed(a, b) - - def content_radio_toggled(self, a, b): - self.set_content_is_file(self.content_file_radio.get_active()) - self.changed(a, b) - diff --git a/hacks/python-playback/player.py b/hacks/python-playback/player.py deleted file mode 100644 index 5cc8da711..000000000 --- a/hacks/python-playback/player.py +++ /dev/null @@ -1,112 +0,0 @@ -import os -import threading -import subprocess -import shlex -import select -import film -import config -import mplayer - -class CommandLine: - def __init__(self): - self.position_x = 0 - self.position_y = 0 - self.output_width = None - self.output_height = None - self.mov = False - self.delay = None - self.dvd = False - self.dvd_title = 1 - self.content = None - self.extra = '' - self.crop_x = None - self.crop_y = None - self.crop_w = None - self.crop_h = None - self.deinterlace = False - self.aid = None - - def get(self, with_binary): - # hqdn3d? - # nr, unsharp? - # -vo x11 appears to be necessary to prevent unwanted hardware scaling - # -noaspect stops mplayer rescaling to the movie's specified aspect ratio - args = '-vo x11 -noaspect -ao pulse -noborder -noautosub -nosub -sws 10 ' - args += '-geometry %d:%d ' % (self.position_x, self.position_y) - - # Video filters (passed to -vf) - - filters = [] - - if self.crop_x is not None or self.crop_y is not None or self.crop_w is not None or self.crop_h is not None: - crop = 'crop=' - if self.crop_w is not None and self.crop_h is not None: - crop += '%d:%d' % (self.crop_w, self.crop_h) - if self.crop_x is not None and self.crop_x is not None: - crop += ':%d:%d' % (self.crop_x, self.crop_y) - filters.append(crop) - - if self.output_width is not None or self.output_height is not None: - filters.append('scale=%d:%d' % (self.output_width, self.output_height)) - - # Post processing - pp = [] - if self.deinterlace: - pp.append('lb') - - # Deringing filter - pp.append('dr') - - if len(pp) > 0: - pp_string = 'pp=' - for i in range(0, len(pp)): - pp_string += pp[i] - if i < len(pp) - 1: - pp += ',' - - filters.append(pp_string) - - if len(filters) > 0: - args += '-vf ' - for i in range(0, len(filters)): - args += filters[i] - if i < len(filters) - 1: - args += ',' - args += ' ' - - if self.mov: - args += '-demuxer mov ' - if self.delay is not None: - args += '-delay %f ' % float(args.delay) - if self.aid is not None: - args += '-aid %s ' % self.aid - - args += self.extra - - if self.dvd: - data_specifier = 'dvd://%d -dvd-device \"%s\"' % (self.dvd_title, self.content) - else: - data_specifier = '\"%s\"' % self.content - - if with_binary: - return 'mplayer %s %s' % (args, data_specifier) - - return '%s %s' % (args, data_specifier) - -def get_player(film, format): - cl = CommandLine() - cl.dvd = film.dvd - cl.dvd_title = film.dvd_title - cl.content = film.content - cl.crop_w = film.width - film.left_crop - film.right_crop - cl.crop_h = film.height - film.top_crop - film.bottom_crop - cl.position_x = format.x - if format.external: - cl.position_x = format.x + config.LEFT_SCREEN_WIDTH - cl.position_y = format.y - cl.output_width = format.width - cl.output_height = format.height - cl.deinterlace = film.deinterlace - cl.aid = film.aid - return mplayer.Player(cl.get(False)) - diff --git a/hacks/python-playback/ratio.py b/hacks/python-playback/ratio.py deleted file mode 100644 index 62320dc8a..000000000 --- a/hacks/python-playback/ratio.py +++ /dev/null @@ -1,56 +0,0 @@ -# Class to describe a Ratio, and a collection of common -# (and not-so-common) film ratios collected from Wikipedia. - -class Ratio: - def __init__(self, ratio, nickname = None): - self.nickname = nickname - self.ratio = ratio - - # @return presentation name of this ratio - def name(self): - if self.nickname is not None: - return "%.2f (%s)" % (self.ratio, self.nickname) - - return "%.2f" % self.ratio - -ratios = [] -ratios.append(Ratio(1.33, '4:3')) -ratios.append(Ratio(1.37, 'Academy')) -ratios.append(Ratio(1.78, '16:9')) -ratios.append(Ratio(1.85, 'Flat / widescreen')) -ratios.append(Ratio(2.39, 'CinemaScope / Panavision')) -ratios.append(Ratio(1.15, 'Movietone')) -ratios.append(Ratio(1.43, 'IMAX')) -ratios.append(Ratio(1.5)) -ratios.append(Ratio(1.56, '14:9')) -ratios.append(Ratio(1.6, '16:10')) -ratios.append(Ratio(1.67)) -ratios.append(Ratio(2, 'SuperScope')) -ratios.append(Ratio(2.2, 'Todd-AO')) -ratios.append(Ratio(2.35, 'Early CinemaScope / Panavision')) -ratios.append(Ratio(2.37, '21:9')) -ratios.append(Ratio(2.55, 'CinemaScope 55')) -ratios.append(Ratio(2.59, 'Cinerama')) -ratios.append(Ratio(2.76, 'Ultra Panavision')) -ratios.append(Ratio(2.93, 'MGM Camera 65')) -ratios.append(Ratio(4, 'Polyvision')) - -# Find a Ratio object from a fractional ratio -def find(ratio): - for r in ratios: - if r.ratio == ratio: - return r - - return None - -# @return the ith ratio -def index_to_ratio(i): - return ratios[i] - -# @return the index within the ratios list of a given fractional ratio -def ratio_to_index(r): - for i in range(0, len(ratios)): - if ratios[i].ratio == r: - return i - - return None diff --git a/hacks/python-playback/screens b/hacks/python-playback/screens deleted file mode 100644 index f389cb1c4..000000000 --- a/hacks/python-playback/screens +++ /dev/null @@ -1,62 +0,0 @@ -# Screen 1 (untested) -screen 1 -ratio 1.85 -x 175 -y 100 -width 1550 -height 950 -external 1 -ratio 2.39 -x 0 -y 200 -width 2000 -height 860 -external 1 - -# Screen 2 -screen 2 -ratio 1.85 -x 175 -y 100 -width 1550 -height 950 -external 1 -ratio 2.39 -x 0 -y 200 -width 2000 -height 860 -external 1 - -# Screen 3 (untested) -screen 3 -ratio 1.85 -x 175 -y 100 -width 1550 -height 950 -external 1 -ratio 2.39 -x 0 -y 200 -width 2000 -height 860 -external 1 - -# Carl's Laptop -screen laptop -ratio 1.85 -x 0 -y 0 -width 1366 -height 738 -ratio 2.39 -x 0 -y 0 -width 1366 -height 572 -ratio 1.78 -x 0 -y 0 -width 1366 -height 767 diff --git a/hacks/python-playback/screens.py b/hacks/python-playback/screens.py deleted file mode 100644 index 4230a4cf8..000000000 --- a/hacks/python-playback/screens.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/python - -class Screen: - def __init__(self): - self.name = None - self.formats = [] - -class Format: - def __init__(self): - self.ratio = None - self.x = None - self.y = None - self.width = None - self.height = None - self.external = False - -class Screens: - def __init__(self, file): - - self.screens = [] - - f = open(file, 'r') - current_screen = None - current_format = None - while 1: - l = f.readline() - if l == '': - break - if len(l) > 0 and l[0] == '#': - continue - - s = l.strip() - - if len(s) == 0: - continue - - b = s.split() - - if len(b) != 2: - print "WARNING: ignored line `%s' in screens file" % (s) - continue - - if b[0] == 'screen': - if current_format is not None: - current_screen.formats.append(current_format) - current_format = None - - if current_screen is not None: - self.screens.append(current_screen) - current_screen = None - - current_screen = Screen() - current_screen.name = b[1] - elif b[0] == 'ratio': - if current_format is not None: - current_screen.formats.append(current_format) - current_format = None - - current_format = Format() - current_format.ratio = float(b[1]) - elif b[0] == 'x': - current_format.x = int(b[1]) - elif b[0] == 'y': - current_format.y = int(b[1]) - elif b[0] == 'width': - current_format.width = int(b[1]) - elif b[0] == 'height': - current_format.height = int(b[1]) - elif b[0] == 'external': - current_format.external = int(b[1]) == 1 - - if current_format is not None: - current_screen.formats.append(current_format) - - if current_screen is not None: - self.screens.append(current_screen) - - def get_format(self, screen, ratio): - for s in self.screens: - if s.name == screen: - for f in s.formats: - if f.ratio == ratio: - return f - - return None diff --git a/hacks/python-playback/thumbs.py b/hacks/python-playback/thumbs.py deleted file mode 100644 index 921f82f5d..000000000 --- a/hacks/python-playback/thumbs.py +++ /dev/null @@ -1,76 +0,0 @@ -# GUI to display thumbnails and allow cropping -# to be set up - -import os -import sys -import pygtk -pygtk.require('2.0') -import gtk -import film -import player - -class Thumbs(gtk.Dialog): - def __init__(self, film): - gtk.Dialog.__init__(self) - self.film = film - self.controls = gtk.Table() - self.controls.set_col_spacings(4) - self.thumb_adj = gtk.Adjustment(0, 0, self.film.thumbs() - 1, 1, 10) - self.add_control("Thumbnail", self.thumb_adj, 0) - self.left_crop_adj = gtk.Adjustment(self.film.left_crop, 0, 1024, 1, 128) - self.add_control("Left crop", self.left_crop_adj, 1) - self.right_crop_adj = gtk.Adjustment(self.film.right_crop, 0, 1024, 1, 128) - self.add_control("Right crop", self.right_crop_adj, 2) - self.top_crop_adj = gtk.Adjustment(self.film.top_crop, 0, 1024, 1, 128) - self.add_control("Top crop", self.top_crop_adj, 3) - self.bottom_crop_adj = gtk.Adjustment(self.film.bottom_crop, 0, 1024, 1, 128) - self.add_control("Bottom crop", self.bottom_crop_adj, 4) - self.display_image = gtk.Image() - self.update_display() - window_box = gtk.HBox() - window_box.set_spacing(12) - - controls_vbox = gtk.VBox() - controls_vbox.set_spacing(4) - controls_vbox.pack_start(self.controls, False, False) - - window_box.pack_start(controls_vbox, True, True) - window_box.pack_start(self.display_image) - - self.set_title("%s Thumbnails" % film.name) - self.get_content_area().add(window_box) - self.add_button("Close", gtk.RESPONSE_ACCEPT) - self.show_all() - - for a in [self.thumb_adj, self.left_crop_adj, self.right_crop_adj, self.top_crop_adj, self.bottom_crop_adj]: - a.connect('value-changed', self.update_display, self) - - def add_control(self, name, adj, n): - l = gtk.Label(name) - l.set_alignment(1, 0.5) - self.controls.attach(l, 0, 1, n, n + 1) - s = gtk.SpinButton(adj) - self.controls.attach(s, 1, 2, n, n + 1) - - def update_display(self, a = None, b = None): - thumb_pixbuf = gtk.gdk.pixbuf_new_from_file(self.film.thumb(self.thumb_adj.get_value())) - self.width = thumb_pixbuf.get_width() - self.height = thumb_pixbuf.get_height() - left = self.left_crop() - right = self.right_crop() - top = self.top_crop() - bottom = self.bottom_crop() - pixbuf = thumb_pixbuf.subpixbuf(left, top, self.width - left - right, self.height - top - bottom) - self.display_image.set_from_pixbuf(pixbuf) - - def top_crop(self): - return int(self.top_crop_adj.get_value()) - - def bottom_crop(self): - return int(self.bottom_crop_adj.get_value()) - - def left_crop(self): - return int(self.left_crop_adj.get_value()) - - def right_crop(self): - return int(self.right_crop_adj.get_value()) diff --git a/hacks/python-playback/util.py b/hacks/python-playback/util.py deleted file mode 100644 index d78abdd00..000000000 --- a/hacks/python-playback/util.py +++ /dev/null @@ -1,7 +0,0 @@ - -def s_to_hms(s): - m = int(s / 60) - s -= (m * 60) - h = int(m / 60) - m -= (h * 60) - return (h, m, s) diff --git a/hacks/python-playback/xrandr-notes b/hacks/python-playback/xrandr-notes deleted file mode 100644 index eeabf1423..000000000 --- a/hacks/python-playback/xrandr-notes +++ /dev/null @@ -1,17 +0,0 @@ -Recommended 1680 x 1050, 60 fps -xrandr --output HDMI1 --mode 0xbc - -List modes -xrandr --verbose -q - -2048 x 1024, 24 fps -xrandr --output HDMI1 --mode 0xd1 - -cvt -to give modeline, then -xrandr --newmode modeline -then add -xrandr --verbose --addmode HDMI1 modename -then activate -xrandr --output HDMI1 --mode foo - diff --git a/icons/128x128/dvdomatic.png b/icons/128x128/dvdomatic.png deleted file mode 100644 index 9936b39af..000000000 Binary files a/icons/128x128/dvdomatic.png and /dev/null differ diff --git a/icons/16x16/dvdomatic.png b/icons/16x16/dvdomatic.png deleted file mode 100644 index 3c5a10f2d..000000000 Binary files a/icons/16x16/dvdomatic.png and /dev/null differ diff --git a/icons/22x22/dvdomatic.png b/icons/22x22/dvdomatic.png deleted file mode 100644 index dddb86298..000000000 Binary files a/icons/22x22/dvdomatic.png and /dev/null differ diff --git a/icons/32x32/dvdomatic.png b/icons/32x32/dvdomatic.png deleted file mode 100644 index 8cecf08f8..000000000 Binary files a/icons/32x32/dvdomatic.png and /dev/null differ diff --git a/icons/48x48/dvdomatic.png b/icons/48x48/dvdomatic.png deleted file mode 100644 index 07bf2d10b..000000000 Binary files a/icons/48x48/dvdomatic.png and /dev/null differ diff --git a/icons/64x64/dvdomatic.png b/icons/64x64/dvdomatic.png deleted file mode 100644 index 35564a8a2..000000000 Binary files a/icons/64x64/dvdomatic.png and /dev/null differ diff --git a/run/dvdomatic b/run/dvdomatic deleted file mode 100755 index dbc63d44a..000000000 --- a/run/dvdomatic +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash - -export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:$LD_LIBRARY_PATH -if [ "$1" == "--debug" ]; then - shift - gdb --args build/src/tools/dvdomatic $* -elif [ "$1" == "--valgrind" ]; then - shift - valgrind --tool="memcheck" build/src/tools/dvdomatic $* -elif [ "$1" == "--i18n" ]; then - shift - LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*" -else - build/src/tools/dvdomatic $* -fi diff --git a/src/lib/audio_analysis.h b/src/lib/audio_analysis.h index 6e0e2b78a..ec6905105 100644 --- a/src/lib/audio_analysis.h +++ b/src/lib/audio_analysis.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_AUDIO_ANALYSIS_H -#define DVDOMATIC_AUDIO_ANALYSIS_H +#ifndef DCPOMATIC_AUDIO_ANALYSIS_H +#define DCPOMATIC_AUDIO_ANALYSIS_H #include #include diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index dbd55943d..2362786d9 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_AUDIO_CONTENT_H -#define DVDOMATIC_AUDIO_CONTENT_H +#ifndef DCPOMATIC_AUDIO_CONTENT_H +#define DCPOMATIC_AUDIO_CONTENT_H #include "content.h" #include "util.h" diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 24e2796ae..418fc6da2 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -21,8 +21,8 @@ * @brief Parent class for audio decoders. */ -#ifndef DVDOMATIC_AUDIO_DECODER_H -#define DVDOMATIC_AUDIO_DECODER_H +#ifndef DCPOMATIC_AUDIO_DECODER_H +#define DCPOMATIC_AUDIO_DECODER_H #include "audio_source.h" #include "decoder.h" diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h index 4f2cdb7f8..248d2570e 100644 --- a/src/lib/audio_mapping.h +++ b/src/lib/audio_mapping.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_AUDIO_MAPPING_H -#define DVDOMATIC_AUDIO_MAPPING_H +#ifndef DCPOMATIC_AUDIO_MAPPING_H +#define DCPOMATIC_AUDIO_MAPPING_H #include #include diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index 11d578a60..085491657 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_AUDIO_SINK_H -#define DVDOMATIC_AUDIO_SINK_H +#ifndef DCPOMATIC_AUDIO_SINK_H +#define DCPOMATIC_AUDIO_SINK_H class AudioSink { diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index 5a1510d3c..ee5c606dc 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -21,8 +21,8 @@ * @brief Parent class for classes which emit audio data. */ -#ifndef DVDOMATIC_AUDIO_SOURCE_H -#define DVDOMATIC_AUDIO_SOURCE_H +#ifndef DCPOMATIC_AUDIO_SOURCE_H +#define DCPOMATIC_AUDIO_SOURCE_H #include diff --git a/src/lib/config.cc b/src/lib/config.cc index 2defa0539..354940b1c 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -155,9 +155,9 @@ Config::file (bool old) const boost::filesystem::path p; p /= g_get_user_config_dir (); if (old) { - p /= ".dvdomatic"; + p /= ".dcpomatic"; } else { - p /= ".dvdomatic.xml"; + p /= ".dcpomatic.xml"; } return p.string (); } diff --git a/src/lib/config.h b/src/lib/config.h index 13d36d236..57f4fb8a9 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -21,8 +21,8 @@ * @brief Class holding configuration. */ -#ifndef DVDOMATIC_CONFIG_H -#define DVDOMATIC_CONFIG_H +#ifndef DCPOMATIC_CONFIG_H +#define DCPOMATIC_CONFIG_H #include #include diff --git a/src/lib/content.h b/src/lib/content.h index c8aa6b0e0..d39fc9e1a 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_CONTENT_H -#define DVDOMATIC_CONTENT_H +#ifndef DCPOMATIC_CONTENT_H +#define DCPOMATIC_CONTENT_H #include #include diff --git a/src/lib/cross.cc b/src/lib/cross.cc index 2c66ab53a..f232f1779 100644 --- a/src/lib/cross.cc +++ b/src/lib/cross.cc @@ -18,20 +18,20 @@ */ #include "cross.h" -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX #include #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS #include "windows.h" #endif void -dvdomatic_sleep (int s) +dcpomatic_sleep (int s) { -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX sleep (s); #endif -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS Sleep (s * 1000); #endif } diff --git a/src/lib/cross.h b/src/lib/cross.h index 110660b16..00457c968 100644 --- a/src/lib/cross.h +++ b/src/lib/cross.h @@ -17,8 +17,8 @@ */ -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS #define WEXITSTATUS(w) (w) #endif -void dvdomatic_sleep (int); +void dcpomatic_sleep (int); diff --git a/src/lib/dci_metadata.h b/src/lib/dci_metadata.h index f61dae5a8..b87609ed0 100644 --- a/src/lib/dci_metadata.h +++ b/src/lib/dci_metadata.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_DCI_METADATA_H -#define DVDOMATIC_DCI_METADATA_H +#ifndef DCPOMATIC_DCI_METADATA_H +#define DCPOMATIC_DCI_METADATA_H #include #include diff --git a/src/lib/dcp_content_type.h b/src/lib/dcp_content_type.h index 960bb0129..14204bd72 100644 --- a/src/lib/dcp_content_type.h +++ b/src/lib/dcp_content_type.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_DCP_CONTENT_TYPE_H -#define DVDOMATIC_DCP_CONTENT_TYPE_H +#ifndef DCPOMATIC_DCP_CONTENT_TYPE_H +#define DCPOMATIC_DCP_CONTENT_TYPE_H /** @file src/content_type.h * @brief A description of the type of content for a DCP (e.g. feature, trailer etc.) diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index e9499871a..da51665d1 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -266,7 +266,7 @@ DCPVideoFrame::encode_locally () _parameters->tcp_numlayers++; _parameters->cp_disto_alloc = 1; _parameters->cp_rsiz = CINEMA2K; - _parameters->cp_comment = strdup (N_("DVD-o-matic")); + _parameters->cp_comment = strdup (N_("DCP-o-matic")); _parameters->cp_cinema = CINEMA2K_24; /* 3 components, so use MCT */ diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 0fffef257..72b866ffe 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -21,8 +21,8 @@ * @brief Parent class for decoders of content. */ -#ifndef DVDOMATIC_DECODER_H -#define DVDOMATIC_DECODER_H +#ifndef DCPOMATIC_DECODER_H +#define DCPOMATIC_DECODER_H #include #include diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index b897c8a31..a8e3547a1 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -423,7 +423,7 @@ Encoder::encoder_thread (ServerDescription* server) } if (remote_backoff > 0) { - dvdomatic_sleep (remote_backoff); + dcpomatic_sleep (remote_backoff); } lock.lock (); diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 70e6eea9a..56007fd48 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_ENCODER_H -#define DVDOMATIC_ENCODER_H +#ifndef DCPOMATIC_ENCODER_H +#define DCPOMATIC_ENCODER_H /** @file src/encoder.h * @brief Encoder to J2K and WAV for DCP. diff --git a/src/lib/exceptions.h b/src/lib/exceptions.h index 6920556e5..6bad7c924 100644 --- a/src/lib/exceptions.h +++ b/src/lib/exceptions.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_EXCEPTIONS_H -#define DVDOMATIC_EXCEPTIONS_H +#ifndef DCPOMATIC_EXCEPTIONS_H +#define DCPOMATIC_EXCEPTIONS_H /** @file src/exceptions.h * @brief Our exceptions. diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index b49e5790e..8bf4d42a5 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_FFMPEG_CONTENT_H -#define DVDOMATIC_FFMPEG_CONTENT_H +#ifndef DCPOMATIC_FFMPEG_CONTENT_H +#define DCPOMATIC_FFMPEG_CONTENT_H #include #include "video_content.h" diff --git a/src/lib/film.cc b/src/lib/film.cc index 6ab6551da..67605ffca 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -254,7 +254,7 @@ Film::make_dcp () throw BadSettingError (_("name"), _("cannot contain slashes")); } - log()->log (String::compose ("DVD-o-matic %1 git %2 using %3", dvdomatic_version, dvdomatic_git_commit, dependency_version_summary())); + log()->log (String::compose ("DCP-o-matic %1 git %2 using %3", dcpomatic_version, dcpomatic_git_commit, dependency_version_summary())); { char buffer[128]; @@ -270,10 +270,10 @@ Film::make_dcp () // log()->log (String::compose ("Content at %1 fps, DCP at %2 fps", source_frame_rate(), dcp_frame_rate())); log()->log (String::compose ("%1 threads", Config::instance()->num_local_encoding_threads())); log()->log (String::compose ("J2K bandwidth %1", j2k_bandwidth())); -#ifdef DVDOMATIC_DEBUG - log()->log ("DVD-o-matic built in debug mode."); +#ifdef DCPOMATIC_DEBUG + log()->log ("DCP-o-matic built in debug mode."); #else - log()->log ("DVD-o-matic built in optimised mode."); + log()->log ("DCP-o-matic built in optimised mode."); #endif #ifdef LIBDCP_DEBUG log()->log ("libdcp built in debug mode."); @@ -432,7 +432,7 @@ Film::read_metadata () boost::mutex::scoped_lock lm (_state_mutex); if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) { - throw StringError (_("This film was created with an older version of DVD-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!")); + throw StringError (_("This film was created with an older version of DCP-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!")); } cxml::File f (file ("metadata.xml"), "Metadata"); diff --git a/src/lib/film.h b/src/lib/film.h index 4d994996e..ffa5d0690 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -22,8 +22,8 @@ * how they should be presented in a DCP. */ -#ifndef DVDOMATIC_FILM_H -#define DVDOMATIC_FILM_H +#ifndef DCPOMATIC_FILM_H +#define DCPOMATIC_FILM_H #include #include @@ -336,7 +336,7 @@ private: /** Mutex for _directory */ mutable boost::mutex _directory_mutex; - /** Name for DVD-o-matic */ + /** Name for DCP-o-matic */ std::string _name; /** True if a auto-generated DCI-compliant name should be used for our DCP */ bool _use_dci_name; diff --git a/src/lib/filter.h b/src/lib/filter.h index 205d92482..7587312c2 100644 --- a/src/lib/filter.h +++ b/src/lib/filter.h @@ -21,8 +21,8 @@ * @brief A class to describe one of FFmpeg's video or post-processing filters. */ -#ifndef DVDOMATIC_FILTER_H -#define DVDOMATIC_FILTER_H +#ifndef DCPOMATIC_FILTER_H +#define DCPOMATIC_FILTER_H #include #include diff --git a/src/lib/filter_graph.h b/src/lib/filter_graph.h index db86a677d..1ff5527ab 100644 --- a/src/lib/filter_graph.h +++ b/src/lib/filter_graph.h @@ -21,8 +21,8 @@ * @brief A graph of FFmpeg filters. */ -#ifndef DVDOMATIC_FILTER_GRAPH_H -#define DVDOMATIC_FILTER_GRAPH_H +#ifndef DCPOMATIC_FILTER_GRAPH_H +#define DCPOMATIC_FILTER_GRAPH_H #include "util.h" #include "ffmpeg_compatibility.h" diff --git a/src/lib/i18n.h b/src/lib/i18n.h index 46bb1d565..890313bc6 100644 --- a/src/lib/i18n.h +++ b/src/lib/i18n.h @@ -19,5 +19,5 @@ #include -#define _(x) dgettext ("libdvdomatic", x) +#define _(x) dgettext ("libdcpomatic", x) #define N_(x) x diff --git a/src/lib/image.h b/src/lib/image.h index 6b9ade99e..1d7d75dfc 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -21,8 +21,8 @@ * @brief A set of classes to describe video images. */ -#ifndef DVDOMATIC_IMAGE_H -#define DVDOMATIC_IMAGE_H +#ifndef DCPOMATIC_IMAGE_H +#define DCPOMATIC_IMAGE_H #include #include diff --git a/src/lib/job.cc b/src/lib/job.cc index ff0332d6d..2a4986f0d 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -87,7 +87,7 @@ Job::run_wrapper () set_state (FINISHED_ERROR); set_error ( e.what (), - _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)") + _("It is not known what caused this error. The best idea is to report the problem to the DCP-o-matic mailing list (dcpomatic@carlh.net)") ); } catch (...) { @@ -96,7 +96,7 @@ Job::run_wrapper () set_state (FINISHED_ERROR); set_error ( _("Unknown error"), - _("It is not known what caused this error. The best idea is to report the problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)") + _("It is not known what caused this error. The best idea is to report the problem to the DCP-o-matic mailing list (dcpomatic@carlh.net)") ); } diff --git a/src/lib/job.h b/src/lib/job.h index f5175c525..2119db2f3 100644 --- a/src/lib/job.h +++ b/src/lib/job.h @@ -21,8 +21,8 @@ * @brief A parent class to represent long-running tasks which are run in their own thread. */ -#ifndef DVDOMATIC_JOB_H -#define DVDOMATIC_JOB_H +#ifndef DCPOMATIC_JOB_H +#define DCPOMATIC_JOB_H #include #include diff --git a/src/lib/job_manager.cc b/src/lib/job_manager.cc index 910597628..f96275467 100644 --- a/src/lib/job_manager.cc +++ b/src/lib/job_manager.cc @@ -126,7 +126,7 @@ JobManager::scheduler () } } - dvdomatic_sleep (1); + dcpomatic_sleep (1); } } diff --git a/src/lib/log.h b/src/lib/log.h index 3a2cfcbfd..3ad6516c1 100644 --- a/src/lib/log.h +++ b/src/lib/log.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_LOG_H -#define DVDOMATIC_LOG_H +#ifndef DCPOMATIC_LOG_H +#define DCPOMATIC_LOG_H /** @file src/log.h * @brief A very simple logging class. diff --git a/src/lib/player.h b/src/lib/player.h index 8a82ab298..dbfde09a6 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_PLAYER_H -#define DVDOMATIC_PLAYER_H +#ifndef DCPOMATIC_PLAYER_H +#define DCPOMATIC_PLAYER_H #include #include diff --git a/src/lib/po/es_ES.po b/src/lib/po/es_ES.po index 17051bd98..5c8d642e3 100644 --- a/src/lib/po/es_ES.po +++ b/src/lib/po/es_ES.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: LIBDVDOMATIC\n" +"Project-Id-Version: LIBDCPOMATIC\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-04-02 19:10-0500\n" @@ -250,10 +250,10 @@ msgstr "Horizontal deblocking filter A" #: src/lib/job.cc:92 src/lib/job.cc:101 msgid "" "It is not known what caused this error. The best idea is to report the " -"problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" +"problem to the DCP-o-matic mailing list (dcpomatic@carlh.net)" msgstr "" "Error desconocido. La mejor idea es informar del problema a la lista de " -"correo de DVD-O-matic (dvdomatic@carlh.net)" +"correo de DCP-o-matic (dcpomatic@carlh.net)" #: src/lib/filter.cc:82 msgid "Kernel deinterlacer" diff --git a/src/lib/po/fr_FR.po b/src/lib/po/fr_FR.po index d9d945b52..af6890d97 100644 --- a/src/lib/po/fr_FR.po +++ b/src/lib/po/fr_FR.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVD-o-matic FRENCH\n" +"Project-Id-Version: DCP-o-matic FRENCH\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-03-20 00:39+0100\n" @@ -248,10 +248,10 @@ msgstr "Filtre dé-bloc horizontal" #: src/lib/job.cc:92 src/lib/job.cc:101 msgid "" "It is not known what caused this error. The best idea is to report the " -"problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" +"problem to the DCP-o-matic mailing list (dcpomatic@carlh.net)" msgstr "" -"Erreur indéterminée. Merci de rapporter le problème à la liste DVD-o-matic " -"(dvdomatic@carlh.net)" +"Erreur indéterminée. Merci de rapporter le problème à la liste DCP-o-matic " +"(dcpomatic@carlh.net)" #: src/lib/filter.cc:82 msgid "Kernel deinterlacer" diff --git a/src/lib/po/it_IT.po b/src/lib/po/it_IT.po index 992eda107..c1ca26ea3 100644 --- a/src/lib/po/it_IT.po +++ b/src/lib/po/it_IT.po @@ -248,10 +248,10 @@ msgstr "Filtro A sblocco orizzontale" #: src/lib/job.cc:92 src/lib/job.cc:101 msgid "" "It is not known what caused this error. The best idea is to report the " -"problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" +"problem to the DCP-o-matic mailing list (dcpomatic@carlh.net)" msgstr "" "Non sappiamo cosa ha causato questo errore. La cosa migliore è inviare un " -"report del problema alla mailing list di DVD-o-matic (dvdomatic@carlh.net)" +"report del problema alla mailing list di DCP-o-matic (dcpomatic@carlh.net)" #: src/lib/filter.cc:82 msgid "Kernel deinterlacer" diff --git a/src/lib/po/sv_SE.po b/src/lib/po/sv_SE.po index d574261c8..c8695ce4d 100644 --- a/src/lib/po/sv_SE.po +++ b/src/lib/po/sv_SE.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVD-o-matic\n" +"Project-Id-Version: DCP-o-matic\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-04-09 10:13+0100\n" @@ -249,10 +249,10 @@ msgstr "Filter för horisontal kantighetsutjämning A" #: src/lib/job.cc:92 src/lib/job.cc:101 msgid "" "It is not known what caused this error. The best idea is to report the " -"problem to the DVD-o-matic mailing list (dvdomatic@carlh.net)" +"problem to the DCP-o-matic mailing list (dcpomatic@carlh.net)" msgstr "" "Det är inte känt vad som orsakade detta fel. Bästa sättet att rapportera " -"problemet är till DVD-o-matics mejl-lista (dvdomatic@carlh.net)" +"problemet är till DCP-o-matics mejl-lista (dcpomatic@carlh.net)" #: src/lib/filter.cc:82 msgid "Kernel deinterlacer" diff --git a/src/lib/processor.h b/src/lib/processor.h index 1ba396f2f..5dbafab7f 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -21,8 +21,8 @@ * @brief Parent class for classes which accept and then emit video or audio data. */ -#ifndef DVDOMATIC_PROCESSOR_H -#define DVDOMATIC_PROCESSOR_H +#ifndef DCPOMATIC_PROCESSOR_H +#define DCPOMATIC_PROCESSOR_H #include "video_source.h" #include "video_sink.h" diff --git a/src/lib/scaler.h b/src/lib/scaler.h index c80f4b7db..a736e92de 100644 --- a/src/lib/scaler.h +++ b/src/lib/scaler.h @@ -21,8 +21,8 @@ * @brief A class to describe one of FFmpeg's software scalers. */ -#ifndef DVDOMATIC_SCALER_H -#define DVDOMATIC_SCALER_H +#ifndef DCPOMATIC_SCALER_H +#define DCPOMATIC_SCALER_H #include #include diff --git a/src/lib/sound_processor.h b/src/lib/sound_processor.h index 2edf38840..bdbe72ba2 100644 --- a/src/lib/sound_processor.h +++ b/src/lib/sound_processor.h @@ -21,8 +21,8 @@ * @brief A class to describe a sound processor. */ -#ifndef DVDOMATIC_SOUND_PROCESSOR_H -#define DVDOMATIC_SOUND_PROCESSOR_H +#ifndef DCPOMATIC_SOUND_PROCESSOR_H +#define DCPOMATIC_SOUND_PROCESSOR_H #include #include diff --git a/src/lib/timer.h b/src/lib/timer.h index f509a7492..173d0d961 100644 --- a/src/lib/timer.h +++ b/src/lib/timer.h @@ -22,8 +22,8 @@ * @brief Some timing classes for debugging and profiling. */ -#ifndef DVDOMATIC_TIMER_H -#define DVDOMATIC_TIMER_H +#ifndef DCPOMATIC_TIMER_H +#define DCPOMATIC_TIMER_H #include #include diff --git a/src/lib/types.h b/src/lib/types.h index f821a74ac..c2bb9d853 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_TYPES_H -#define DVDOMATIC_TYPES_H +#ifndef DCPOMATIC_TYPES_H +#define DCPOMATIC_TYPES_H #include #include diff --git a/src/lib/ui_signaller.h b/src/lib/ui_signaller.h index 221bcbe95..428ab698f 100644 --- a/src/lib/ui_signaller.h +++ b/src/lib/ui_signaller.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_UI_SIGNALLER_H -#define DVDOMATIC_UI_SIGNALLER_H +#ifndef DCPOMATIC_UI_SIGNALLER_H +#define DCPOMATIC_UI_SIGNALLER_H #include #include diff --git a/src/lib/util.cc b/src/lib/util.cc index 06da94294..ad08c6ab4 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -27,7 +27,7 @@ #include #include #include -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX #include #include #endif @@ -148,7 +148,7 @@ seconds_to_approximate_hms (int s) return ap.str (); } -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX /** @param l Mangled C++ identifier. * @return Demangled version. */ @@ -247,11 +247,11 @@ seconds (struct timeval t) return t.tv_sec + (double (t.tv_usec) / 1e6); } -/** Call the required functions to set up DVD-o-matic's static arrays, etc. +/** Call the required functions to set up DCP-o-matic's static arrays, etc. * Must be called from the UI thread, if there is one. */ void -dvdomatic_setup () +dcpomatic_setup () { avfilter_register_all (); @@ -264,7 +264,7 @@ dvdomatic_setup () ui_thread = boost::this_thread::get_id (); } -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS boost::filesystem::path mo_path () { @@ -279,9 +279,9 @@ mo_path () #endif void -dvdomatic_setup_i18n (string lang) +dcpomatic_setup_i18n (string lang) { -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX lang += ".UTF8"; #endif @@ -297,15 +297,15 @@ dvdomatic_setup_i18n (string lang) } setlocale (LC_ALL, ""); - textdomain ("libdvdomatic"); + textdomain ("libdcpomatic"); -#ifdef DVDOMATIC_WINDOWS - bindtextdomain ("libdvdomatic", mo_path().string().c_str()); - bind_textdomain_codeset ("libdvdomatic", "UTF8"); +#ifdef DCPOMATIC_WINDOWS + bindtextdomain ("libdcpomatic", mo_path().string().c_str()); + bind_textdomain_codeset ("libdcpomatic", "UTF8"); #endif -#ifdef DVDOMATIC_POSIX - bindtextdomain ("libdvdomatic", POSIX_LOCALE_PREFIX); +#ifdef DCPOMATIC_POSIX + bindtextdomain ("libdcpomatic", POSIX_LOCALE_PREFIX); #endif } @@ -909,7 +909,7 @@ cpu_info () pair info; info.second = 0; -#ifdef DVDOMATIC_POSIX +#ifdef DCPOMATIC_POSIX ifstream f (N_("/proc/cpuinfo")); while (f.good ()) { string l; diff --git a/src/lib/util.h b/src/lib/util.h index f4af7c22b..065801a88 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -22,8 +22,8 @@ * @brief Some utility functions and classes. */ -#ifndef DVDOMATIC_UTIL_H -#define DVDOMATIC_UTIL_H +#ifndef DCPOMATIC_UTIL_H +#define DCPOMATIC_UTIL_H #include #include @@ -39,7 +39,7 @@ extern "C" { #include "compose.hpp" #include "types.h" -#ifdef DVDOMATIC_DEBUG +#ifdef DCPOMATIC_DEBUG #define TIMING(...) _film->log()->microsecond_log (String::compose (__VA_ARGS__), Log::TIMING); #else #define TIMING(...) @@ -55,14 +55,14 @@ extern std::string seconds_to_approximate_hms (int); extern void stacktrace (std::ostream &, int); extern std::string dependency_version_summary (); extern double seconds (struct timeval); -extern void dvdomatic_setup (); -extern void dvdomatic_setup_i18n (std::string); +extern void dcpomatic_setup (); +extern void dcpomatic_setup_i18n (std::string); extern std::vector split_at_spaces_considering_quotes (std::string); extern std::string md5_digest (boost::filesystem::path); extern std::string md5_digest (void const *, int); extern void ensure_ui_thread (); extern std::string audio_channel_name (int); -#ifdef DVDOMATIC_WINDOWS +#ifdef DCPOMATIC_WINDOWS extern boost::filesystem::path mo_path (); #endif @@ -117,7 +117,7 @@ extern std::string get_optional_string (std::multimap /** @class Socket * @brief A class to wrap a boost::asio::ip::tcp::socket with some things - * that are useful for DVD-o-matic. + * that are useful for DCP-o-matic. * * This class wraps some things that I could not work out how to do with boost; * most notably, sync read/write calls with timeouts. diff --git a/src/lib/version.h b/src/lib/version.h index 71639e3bc..518862fc4 100644 --- a/src/lib/version.h +++ b/src/lib/version.h @@ -1,3 +1,3 @@ -extern char const * dvdomatic_version; -extern char const * dvdomatic_git_commit; +extern char const * dcpomatic_version; +extern char const * dcpomatic_git_commit; diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 3d2c4cab2..75e507d4d 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_VIDEO_CONTENT_H -#define DVDOMATIC_VIDEO_CONTENT_H +#ifndef DCPOMATIC_VIDEO_CONTENT_H +#define DCPOMATIC_VIDEO_CONTENT_H #include "content.h" #include "util.h" diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 05cf99a96..23817c055 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_VIDEO_DECODER_H -#define DVDOMATIC_VIDEO_DECODER_H +#ifndef DCPOMATIC_VIDEO_DECODER_H +#define DCPOMATIC_VIDEO_DECODER_H #include "video_source.h" #include "decoder.h" diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 7c128cf73..c68651005 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_VIDEO_SINK_H -#define DVDOMATIC_VIDEO_SINK_H +#ifndef DCPOMATIC_VIDEO_SINK_H +#define DCPOMATIC_VIDEO_SINK_H #include #include "util.h" diff --git a/src/lib/video_source.h b/src/lib/video_source.h index e60e7dfd0..e7c9805ef 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -21,8 +21,8 @@ * @brief Parent class for classes which emit video data. */ -#ifndef DVDOMATIC_VIDEO_SOURCE_H -#define DVDOMATIC_VIDEO_SOURCE_H +#ifndef DCPOMATIC_VIDEO_SOURCE_H +#define DCPOMATIC_VIDEO_SOURCE_H #include #include diff --git a/src/lib/wscript b/src/lib/wscript index 2a26c2bfe..fddebe8e6 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -66,7 +66,7 @@ def build(bld): else: obj = bld(features = 'cxx cxxshlib') - obj.name = 'libdvdomatic' + obj.name = 'libdcpomatic' obj.export_includes = ['.'] obj.uselib = """ AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE @@ -78,12 +78,12 @@ def build(bld): if bld.env.STATIC: obj.uselib += ' XML++' obj.source = sources + " version.cc" - obj.target = 'dvdomatic' + obj.target = 'dcpomatic' - i18n.po_to_mo(os.path.join('src', 'lib'), 'libdvdomatic', bld) + i18n.po_to_mo(os.path.join('src', 'lib'), 'libdcpomatic', bld) def pot(bld): - i18n.pot(os.path.join('src', 'lib'), sources, 'libdvdomatic') + i18n.pot(os.path.join('src', 'lib'), sources, 'libdcpomatic') def pot_merge(bld): - i18n.pot_merge(os.path.join('src', 'lib'), 'libdvdomatic') + i18n.pot_merge(os.path.join('src', 'lib'), 'libdcpomatic') diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc deleted file mode 100644 index 768819abc..000000000 --- a/src/tools/dvdomatic.cc +++ /dev/null @@ -1,578 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - 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 -#include -#ifdef __WXMSW__ -#include -#endif -#include -#include -#include -#include "wx/film_viewer.h" -#include "wx/film_editor.h" -#include "wx/job_manager_view.h" -#include "wx/config_dialog.h" -#include "wx/job_wrapper.h" -#include "wx/wx_util.h" -#include "wx/new_film_dialog.h" -#include "wx/properties_dialog.h" -#include "wx/wx_ui_signaller.h" -#include "lib/film.h" -#include "lib/format.h" -#include "lib/config.h" -#include "lib/filter.h" -#include "lib/util.h" -#include "lib/scaler.h" -#include "lib/exceptions.h" -#include "lib/version.h" -#include "lib/ui_signaller.h" -#include "lib/log.h" - -using std::cout; -using std::string; -using std::wstring; -using std::stringstream; -using std::map; -using std::make_pair; -using std::exception; -using boost::shared_ptr; - -static FilmEditor* film_editor = 0; -static FilmViewer* film_viewer = 0; -static shared_ptr film; -static std::string log_level; -static std::string film_to_load; -static std::string film_to_create; -static wxMenu* jobs_menu = 0; -static wxLocale* locale = 0; - -static void set_menu_sensitivity (); - -class FilmChangedDialog -{ -public: - FilmChangedDialog () - { - _dialog = new wxMessageDialog ( - 0, - wxString::Format (_("Save changes to film \"%s\" before closing?"), std_to_wx (film->name ()).data()), - _("Film changed"), - wxYES_NO | wxYES_DEFAULT | wxICON_QUESTION - ); - } - - ~FilmChangedDialog () - { - _dialog->Destroy (); - } - - int run () - { - return _dialog->ShowModal (); - } - -private: - wxMessageDialog* _dialog; -}; - - -void -maybe_save_then_delete_film () -{ - if (!film) { - return; - } - - if (film->dirty ()) { - FilmChangedDialog d; - switch (d.run ()) { - case wxID_NO: - break; - case wxID_YES: - film->write_metadata (); - break; - } - } - - film.reset (); -} - -enum Sensitivity { - ALWAYS, - NEEDS_FILM -}; - -map menu_items; - -void -add_item (wxMenu* menu, wxString text, int id, Sensitivity sens) -{ - wxMenuItem* item = menu->Append (id, text); - menu_items.insert (make_pair (item, sens)); -} - -void -set_menu_sensitivity () -{ - for (map::iterator i = menu_items.begin(); i != menu_items.end(); ++i) { - if (i->second == NEEDS_FILM) { - i->first->Enable (film != 0); - } else { - i->first->Enable (true); - } - } -} - -enum { - ID_file_new = 1, - ID_file_open, - ID_file_save, - ID_file_properties, - ID_file_quit, - ID_edit_preferences, - ID_jobs_make_dcp, - ID_jobs_send_dcp_to_tms, - ID_jobs_show_dcp, - ID_jobs_analyse_audio, - ID_help_about -}; - -void -setup_menu (wxMenuBar* m) -{ - wxMenu* file = new wxMenu; - add_item (file, _("New..."), ID_file_new, ALWAYS); - add_item (file, _("&Open..."), ID_file_open, ALWAYS); - file->AppendSeparator (); - add_item (file, _("&Save"), ID_file_save, NEEDS_FILM); - file->AppendSeparator (); - add_item (file, _("&Properties..."), ID_file_properties, NEEDS_FILM); - file->AppendSeparator (); - add_item (file, _("&Quit"), ID_file_quit, ALWAYS); - - wxMenu* edit = new wxMenu; - add_item (edit, _("&Preferences..."), ID_edit_preferences, ALWAYS); - - jobs_menu = new wxMenu; - add_item (jobs_menu, _("&Make DCP"), ID_jobs_make_dcp, NEEDS_FILM); - add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM); - add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM); - jobs_menu->AppendSeparator (); - add_item (jobs_menu, _("&Analyse audio"), ID_jobs_analyse_audio, NEEDS_FILM); - - wxMenu* help = new wxMenu; - add_item (help, _("About"), ID_help_about, ALWAYS); - - m->Append (file, _("&File")); - m->Append (edit, _("&Edit")); - m->Append (jobs_menu, _("&Jobs")); - m->Append (help, _("&Help")); -} - -bool -window_closed (wxCommandEvent &) -{ - maybe_save_then_delete_film (); - return false; -} - -class Frame : public wxFrame -{ -public: - Frame (wxString const & title) - : wxFrame (NULL, -1, title) - { - wxMenuBar* bar = new wxMenuBar; - setup_menu (bar); - SetMenuBar (bar); - - Connect (ID_file_new, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_new)); - Connect (ID_file_open, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_open)); - Connect (ID_file_save, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_save)); - Connect (ID_file_properties, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_properties)); - Connect (ID_file_quit, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::file_quit)); - Connect (ID_edit_preferences, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::edit_preferences)); - Connect (ID_jobs_make_dcp, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_make_dcp)); - Connect (ID_jobs_send_dcp_to_tms, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_send_dcp_to_tms)); - Connect (ID_jobs_show_dcp, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_show_dcp)); - Connect (ID_jobs_analyse_audio, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::jobs_analyse_audio)); - Connect (ID_help_about, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (Frame::help_about)); - - Connect (wxID_ANY, wxEVT_MENU_OPEN, wxMenuEventHandler (Frame::menu_opened)); - - wxPanel* panel = new wxPanel (this); - wxSizer* s = new wxBoxSizer (wxHORIZONTAL); - s->Add (panel, 1, wxEXPAND); - SetSizer (s); - - film_editor = new FilmEditor (film, panel); - film_viewer = new FilmViewer (film, panel); - JobManagerView* job_manager_view = new JobManagerView (panel); - - _top_sizer = new wxBoxSizer (wxHORIZONTAL); - _top_sizer->Add (film_editor, 0, wxALL, 6); - _top_sizer->Add (film_viewer, 1, wxEXPAND | wxALL, 6); - - wxBoxSizer* main_sizer = new wxBoxSizer (wxVERTICAL); - main_sizer->Add (_top_sizer, 2, wxEXPAND | wxALL, 6); - main_sizer->Add (job_manager_view, 1, wxEXPAND | wxALL, 6); - panel->SetSizer (main_sizer); - - set_menu_sensitivity (); - - film_editor->FileChanged.connect (bind (&Frame::file_changed, this, _1)); - if (film) { - file_changed (film->directory ()); - } else { - file_changed (""); - } - - set_film (); - - film_editor->Connect (wxID_ANY, wxEVT_SIZE, wxSizeEventHandler (Frame::film_editor_sized), 0, this); - } - -private: - - void film_editor_sized (wxSizeEvent &) - { - static bool in_layout = false; - if (!in_layout) { - in_layout = true; - _top_sizer->Layout (); - in_layout = false; - } - } - - void menu_opened (wxMenuEvent& ev) - { - if (ev.GetMenu() != jobs_menu) { - return; - } - - bool const have_dcp = film && film->have_dcp(); - jobs_menu->Enable (ID_jobs_send_dcp_to_tms, have_dcp); - jobs_menu->Enable (ID_jobs_show_dcp, have_dcp); - } - - void set_film () - { - film_viewer->set_film (film); - film_editor->set_film (film); - set_menu_sensitivity (); - } - - void file_changed (string f) - { - stringstream s; - s << wx_to_std (_("DVD-o-matic")); - if (!f.empty ()) { - s << " - " << f; - } - - SetTitle (std_to_wx (s.str())); - } - - void file_new (wxCommandEvent &) - { - NewFilmDialog* d = new NewFilmDialog (this); - int const r = d->ShowModal (); - - if (r == wxID_OK) { - - if (boost::filesystem::exists (d->get_path())) { - error_dialog (this, std_to_wx (String::compose (wx_to_std (_("The directory %1 already exists.")), d->get_path().c_str()))); - return; - } - - maybe_save_then_delete_film (); - film.reset (new Film (d->get_path (), false)); - film->log()->set_level (log_level); - film->set_name (boost::filesystem::path (d->get_path()).filename().generic_string()); - set_film (); - } - - d->Destroy (); - } - - void file_open (wxCommandEvent &) - { - wxDirDialog* c = new wxDirDialog (this, _("Select film to open"), wxStandardPaths::Get().GetDocumentsDir(), wxDEFAULT_DIALOG_STYLE | wxDD_DIR_MUST_EXIST); - int r; - while (1) { - r = c->ShowModal (); - if (r == wxID_OK && c->GetPath() == wxStandardPaths::Get().GetDocumentsDir()) { - error_dialog (this, _("You did not select a folder. Make sure that you select a folder before clicking Open.")); - } else { - break; - } - } - - if (r == wxID_OK) { - maybe_save_then_delete_film (); - try { - film.reset (new Film (wx_to_std (c->GetPath ()))); - film->log()->set_level (log_level); - set_film (); - } catch (std::exception& e) { - wxString p = c->GetPath (); - wxCharBuffer b = p.ToUTF8 (); - error_dialog (this, wxString::Format (_("Could not open film at %s (%s)"), p.data(), std_to_wx (e.what()).data())); - } - } - - c->Destroy (); - } - - void file_save (wxCommandEvent &) - { - film->write_metadata (); - } - - void file_properties (wxCommandEvent &) - { - PropertiesDialog* d = new PropertiesDialog (this, film); - d->ShowModal (); - d->Destroy (); - } - - void file_quit (wxCommandEvent &) - { - maybe_save_then_delete_film (); - Close (true); - } - - void edit_preferences (wxCommandEvent &) - { - ConfigDialog* d = new ConfigDialog (this); - d->ShowModal (); - d->Destroy (); - Config::instance()->write (); - } - - void jobs_make_dcp (wxCommandEvent &) - { - JobWrapper::make_dcp (this, film); - } - - void jobs_send_dcp_to_tms (wxCommandEvent &) - { - film->send_dcp_to_tms (); - } - - void jobs_show_dcp (wxCommandEvent &) - { -#ifdef __WXMSW__ - string d = film->directory(); - wstring w; - w.assign (d.begin(), d.end()); - ShellExecute (0, L"open", w.c_str(), 0, 0, SW_SHOWDEFAULT); -#else - int r = system ("which nautilus"); - if (WEXITSTATUS (r) == 0) { - system (string ("nautilus " + film->directory()).c_str ()); - } else { - int r = system ("which konqueror"); - if (WEXITSTATUS (r) == 0) { - system (string ("konqueror " + film->directory()).c_str ()); - } - } -#endif - } - - void jobs_analyse_audio (wxCommandEvent &) - { - film->analyse_audio (); - } - - void help_about (wxCommandEvent &) - { - wxAboutDialogInfo info; - info.SetName (_("DVD-o-matic")); - if (strcmp (dvdomatic_git_commit, "release") == 0) { - info.SetVersion (std_to_wx (String::compose ("version %1", dvdomatic_version))); - } else { - info.SetVersion (std_to_wx (String::compose ("version %1 git %2", dvdomatic_version, dvdomatic_git_commit))); - } - info.SetDescription (_("Free, open-source DCP generation from almost anything.")); - info.SetCopyright (_("(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen")); - - wxArrayString authors; - authors.Add (wxT ("Carl Hetherington")); - authors.Add (wxT ("Terrence Meiczinger")); - authors.Add (wxT ("Paul Davis")); - authors.Add (wxT ("Ole Laursen")); - info.SetDevelopers (authors); - - wxArrayString translators; - translators.Add (wxT ("Olivier Perriere")); - translators.Add (wxT ("Lilian Lefranc")); - translators.Add (wxT ("Thierry Journet")); - translators.Add (wxT ("Massimiliano Broggi")); - translators.Add (wxT ("Manuel AC")); - translators.Add (wxT ("Adam Klotblixt")); - info.SetTranslators (translators); - - info.SetWebSite (wxT ("http://carlh.net/software/dvdomatic")); - wxAboutBox (info); - } - - wxSizer* _top_sizer; -}; - -#if wxMINOR_VERSION == 9 -static const wxCmdLineEntryDesc command_line_description[] = { - { wxCMD_LINE_OPTION, "l", "log", "set log level (silent, verbose or timing)", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_SWITCH, "n", "new", "create new film", wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_PARAM, 0, 0, "film to load or create", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_NONE, "", "", "", wxCmdLineParamType (0), 0 } -}; -#else -static const wxCmdLineEntryDesc command_line_description[] = { - { wxCMD_LINE_OPTION, wxT("l"), wxT("log"), wxT("set log level (silent, verbose or timing)"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_SWITCH, wxT("n"), wxT("new"), wxT("create new film"), wxCMD_LINE_VAL_NONE, wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_PARAM, 0, 0, wxT("film to load or create"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | wxCMD_LINE_PARAM_OPTIONAL }, - { wxCMD_LINE_NONE, wxT(""), wxT(""), wxT(""), wxCmdLineParamType (0), 0 } -}; -#endif - -void -setup_i18n () -{ - int language = wxLANGUAGE_DEFAULT; - - if (Config::instance()->language()) { - wxLanguageInfo const * li = wxLocale::FindLanguageInfo (std_to_wx (Config::instance()->language().get())); - if (li) { - language = li->Language; - } - } - - if (wxLocale::IsAvailable (language)) { - locale = new wxLocale (language, wxLOCALE_LOAD_DEFAULT); - -#ifdef DVDOMATIC_WINDOWS - locale->AddCatalogLookupPathPrefix (std_to_wx (mo_path().string())); -#endif - - locale->AddCatalog (wxT ("libdvdomatic-wx")); - locale->AddCatalog (wxT ("dvdomatic")); - - if (!locale->IsOk()) { - delete locale; - locale = new wxLocale (wxLANGUAGE_ENGLISH); - language = wxLANGUAGE_ENGLISH; - } - } - - if (locale) { - dvdomatic_setup_i18n (wx_to_std (locale->GetCanonicalName ())); - } -} - -class App : public wxApp -{ - bool OnInit () - { - if (!wxApp::OnInit()) { - return false; - } - -#ifdef DVDOMATIC_POSIX - unsetenv ("UBUNTU_MENUPROXY"); -#endif - - wxInitAllImageHandlers (); - - /* Enable i18n; this will create a Config object - to look for a force-configured language. This Config - object will be wrong, however, because dvdomatic_setup - hasn't yet been called and there aren't any scalers, filters etc. - set up yet. - */ - setup_i18n (); - - /* Set things up, including scalers / filters etc. - which will now be internationalised correctly. - */ - dvdomatic_setup (); - - /* Force the configuration to be re-loaded correctly next - time it is needed. - */ - Config::drop (); - - if (!film_to_load.empty() && boost::filesystem::is_directory (film_to_load)) { - try { - film.reset (new Film (film_to_load)); - film->log()->set_level (log_level); - } catch (exception& e) { - error_dialog (0, std_to_wx (String::compose (wx_to_std (_("Could not load film %1 (%2)")), film_to_load, e.what()))); - } - } - - if (!film_to_create.empty ()) { - film.reset (new Film (film_to_create, false)); - film->log()->set_level (log_level); - film->set_name (boost::filesystem::path (film_to_create).filename().generic_string ()); - } - - Frame* f = new Frame (_("DVD-o-matic")); - SetTopWindow (f); - f->Maximize (); - f->Show (); - - ui_signaller = new wxUISignaller (this); - this->Connect (-1, wxEVT_IDLE, wxIdleEventHandler (App::idle)); - - return true; - } - - void OnInitCmdLine (wxCmdLineParser& parser) - { - parser.SetDesc (command_line_description); - parser.SetSwitchChars (wxT ("-")); - } - - bool OnCmdLineParsed (wxCmdLineParser& parser) - { - if (parser.GetParamCount() > 0) { - if (parser.Found (wxT ("new"))) { - film_to_create = wx_to_std (parser.GetParam (0)); - } else { - film_to_load = wx_to_std (parser.GetParam(0)); - } - } - - wxString log; - if (parser.Found (wxT ("log"), &log)) { - log_level = wx_to_std (log); - } - - return true; - } - - void idle (wxIdleEvent &) - { - ui_signaller->ui_idle (); - } -}; - -IMPLEMENT_APP (App) diff --git a/src/tools/makedcp.cc b/src/tools/makedcp.cc index 85134b3c5..e2e1874c4 100644 --- a/src/tools/makedcp.cc +++ b/src/tools/makedcp.cc @@ -47,9 +47,9 @@ static void help (string n) { cerr << "Syntax: " << n << " [OPTION] \n" - << " -v, --version show DVD-o-matic version\n" + << " -v, --version show DCP-o-matic version\n" << " -h, --help show this help\n" - << " -d, --deps list DVD-o-matic dependency details and quit\n" + << " -d, --deps list DCP-o-matic dependency details and quit\n" << " -t, --test run in test mode (repeatable UUID generation, timestamps etc.)\n" << " -n, --no-progress do not print progress to stdout\n" << " -r, --no-remote do not use any remote servers\n" @@ -87,7 +87,7 @@ main (int argc, char* argv[]) switch (c) { case 'v': - cout << "dvdomatic version " << dvdomatic_version << " " << dvdomatic_git_commit << "\n"; + cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n"; exit (EXIT_SUCCESS); case 'h': help (argv[0]); @@ -117,13 +117,13 @@ main (int argc, char* argv[]) film_dir = argv[optind]; - dvdomatic_setup (); + dcpomatic_setup (); if (no_remote) { Config::instance()->set_servers (vector ()); } - cout << "DVD-o-matic " << dvdomatic_version << " git " << dvdomatic_git_commit; + cout << "DCP-o-matic " << dcpomatic_version << " git " << dcpomatic_git_commit; char buf[256]; if (gethostname (buf, 256) == 0) { cout << " on " << buf; @@ -162,7 +162,7 @@ main (int argc, char* argv[]) bool error = false; while (!should_stop) { - dvdomatic_sleep (5); + dcpomatic_sleep (5); list > jobs = JobManager::instance()->get (); diff --git a/src/tools/po/es_ES.po b/src/tools/po/es_ES.po index abfbfef6d..d35f104c6 100644 --- a/src/tools/po/es_ES.po +++ b/src/tools/po/es_ES.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVDOMATIC\n" +"Project-Id-Version: DCPOMATIC\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-03-23 21:08-0500\n" @@ -17,111 +17,111 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.5\n" -#: src/tools/dvdomatic.cc:177 +#: src/tools/dcpomatic.cc:177 msgid "&Analyse audio" msgstr "&Analizar audio" -#: src/tools/dvdomatic.cc:183 +#: src/tools/dcpomatic.cc:183 msgid "&Edit" msgstr "&Editar" -#: src/tools/dvdomatic.cc:182 +#: src/tools/dcpomatic.cc:182 msgid "&File" msgstr "&Archivo" -#: src/tools/dvdomatic.cc:185 +#: src/tools/dcpomatic.cc:185 msgid "&Help" msgstr "&Ayuda" -#: src/tools/dvdomatic.cc:184 +#: src/tools/dcpomatic.cc:184 msgid "&Jobs" msgstr "&Tareas" -#: src/tools/dvdomatic.cc:173 +#: src/tools/dcpomatic.cc:173 msgid "&Make DCP" msgstr "&Crear DCP" -#: src/tools/dvdomatic.cc:161 +#: src/tools/dcpomatic.cc:161 msgid "&Open..." msgstr "&Abrir..." -#: src/tools/dvdomatic.cc:170 +#: src/tools/dcpomatic.cc:170 msgid "&Preferences..." msgstr "&Preferencias..." -#: src/tools/dvdomatic.cc:165 +#: src/tools/dcpomatic.cc:165 msgid "&Properties..." msgstr "&Propiedades..." -#: src/tools/dvdomatic.cc:167 +#: src/tools/dcpomatic.cc:167 msgid "&Quit" msgstr "&Salir" -#: src/tools/dvdomatic.cc:163 +#: src/tools/dcpomatic.cc:163 msgid "&Save" msgstr "&Guardar" -#: src/tools/dvdomatic.cc:174 +#: src/tools/dcpomatic.cc:174 msgid "&Send DCP to TMS" msgstr "&Enviar DCP al TMS" -#: src/tools/dvdomatic.cc:417 +#: src/tools/dcpomatic.cc:417 msgid "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" msgstr "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" -#: src/tools/dvdomatic.cc:180 +#: src/tools/dcpomatic.cc:180 msgid "About" msgstr "Acerca de" -#: src/tools/dvdomatic.cc:527 +#: src/tools/dcpomatic.cc:527 #, fuzzy msgid "Could not load film %1 (%2)" msgstr "No se pudo cargar la película %s (%s)" -#: src/tools/dvdomatic.cc:339 +#: src/tools/dcpomatic.cc:339 #, c-format msgid "Could not open film at %s (%s)" msgstr "No se pudo cargar la película en %s (%s)" -#: src/tools/dvdomatic.cc:287 src/tools/dvdomatic.cc:410 -#: src/tools/dvdomatic.cc:531 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +#: src/tools/dcpomatic.cc:287 src/tools/dcpomatic.cc:410 +#: src/tools/dcpomatic.cc:531 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" -#: src/tools/dvdomatic.cc:75 +#: src/tools/dcpomatic.cc:75 msgid "Film changed" msgstr "Película cambiada" -#: src/tools/dvdomatic.cc:416 +#: src/tools/dcpomatic.cc:416 msgid "Free, open-source DCP generation from almost anything." msgstr "" "Generación de DCP a partir de casi cualquier fuente, libre y de código " "abierto." -#: src/tools/dvdomatic.cc:160 +#: src/tools/dcpomatic.cc:160 msgid "New..." msgstr "Nuevo..." -#: src/tools/dvdomatic.cc:175 +#: src/tools/dcpomatic.cc:175 msgid "S&how DCP" msgstr "&Mostrar DCP" -#: src/tools/dvdomatic.cc:74 +#: src/tools/dcpomatic.cc:74 msgid "Save changes to film \"%s\" before closing?" msgstr "" -#: src/tools/dvdomatic.cc:319 +#: src/tools/dcpomatic.cc:319 msgid "Select film to open" msgstr "Selecciona la película a abrir" -#: src/tools/dvdomatic.cc:303 +#: src/tools/dcpomatic.cc:303 #, fuzzy msgid "The directory %1 already exists." msgstr "La carpeta %s ya existe." -#: src/tools/dvdomatic.cc:324 +#: src/tools/dcpomatic.cc:324 msgid "" "You did not select a folder. Make sure that you select a folder before " "clicking Open." diff --git a/src/tools/po/fr_FR.po b/src/tools/po/fr_FR.po index b40c86877..ef2246992 100644 --- a/src/tools/po/fr_FR.po +++ b/src/tools/po/fr_FR.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVD-o-matic FRENCH\n" +"Project-Id-Version: DCP-o-matic FRENCH\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-03-13 22:33+0100\n" @@ -16,109 +16,109 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: src/tools/dvdomatic.cc:177 +#: src/tools/dcpomatic.cc:177 msgid "&Analyse audio" msgstr "&Analyser le son" -#: src/tools/dvdomatic.cc:183 +#: src/tools/dcpomatic.cc:183 msgid "&Edit" msgstr "&Edition" -#: src/tools/dvdomatic.cc:182 +#: src/tools/dcpomatic.cc:182 msgid "&File" msgstr "&Fichier" -#: src/tools/dvdomatic.cc:185 +#: src/tools/dcpomatic.cc:185 msgid "&Help" msgstr "&Aide" -#: src/tools/dvdomatic.cc:184 +#: src/tools/dcpomatic.cc:184 msgid "&Jobs" msgstr "&Travaux" -#: src/tools/dvdomatic.cc:173 +#: src/tools/dcpomatic.cc:173 msgid "&Make DCP" msgstr "&Créer le DCP" -#: src/tools/dvdomatic.cc:161 +#: src/tools/dcpomatic.cc:161 msgid "&Open..." msgstr "&Ouvrir..." -#: src/tools/dvdomatic.cc:170 +#: src/tools/dcpomatic.cc:170 msgid "&Preferences..." msgstr "&Préférences..." -#: src/tools/dvdomatic.cc:165 +#: src/tools/dcpomatic.cc:165 msgid "&Properties..." msgstr "&Propriétés..." -#: src/tools/dvdomatic.cc:167 +#: src/tools/dcpomatic.cc:167 msgid "&Quit" msgstr "&Quitter" -#: src/tools/dvdomatic.cc:163 +#: src/tools/dcpomatic.cc:163 msgid "&Save" msgstr "&Enregistrer" -#: src/tools/dvdomatic.cc:174 +#: src/tools/dcpomatic.cc:174 msgid "&Send DCP to TMS" msgstr "&Envoyer le DCP dans le TMS" -#: src/tools/dvdomatic.cc:417 +#: src/tools/dcpomatic.cc:417 msgid "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" msgstr "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" -#: src/tools/dvdomatic.cc:180 +#: src/tools/dcpomatic.cc:180 msgid "About" msgstr "A Propos" -#: src/tools/dvdomatic.cc:527 +#: src/tools/dcpomatic.cc:527 #, fuzzy msgid "Could not load film %1 (%2)" msgstr "Impossible de charger le film %s (%s)" -#: src/tools/dvdomatic.cc:339 +#: src/tools/dcpomatic.cc:339 #, c-format msgid "Could not open film at %s (%s)" msgstr "Impossible d'ouvrir le film à %s (%s)" -#: src/tools/dvdomatic.cc:287 src/tools/dvdomatic.cc:410 -#: src/tools/dvdomatic.cc:531 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +#: src/tools/dcpomatic.cc:287 src/tools/dcpomatic.cc:410 +#: src/tools/dcpomatic.cc:531 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" -#: src/tools/dvdomatic.cc:75 +#: src/tools/dcpomatic.cc:75 msgid "Film changed" msgstr "Film changé" -#: src/tools/dvdomatic.cc:416 +#: src/tools/dcpomatic.cc:416 msgid "Free, open-source DCP generation from almost anything." msgstr "Création de DCP libre et open-source à partir de presque tout." -#: src/tools/dvdomatic.cc:160 +#: src/tools/dcpomatic.cc:160 msgid "New..." msgstr "Nouveau..." -#: src/tools/dvdomatic.cc:175 +#: src/tools/dcpomatic.cc:175 msgid "S&how DCP" msgstr "Voir le DCP" -#: src/tools/dvdomatic.cc:74 +#: src/tools/dcpomatic.cc:74 msgid "Save changes to film \"%s\" before closing?" msgstr "" -#: src/tools/dvdomatic.cc:319 +#: src/tools/dcpomatic.cc:319 msgid "Select film to open" msgstr "Sélectionner le film à ouvrir" -#: src/tools/dvdomatic.cc:303 +#: src/tools/dcpomatic.cc:303 #, fuzzy msgid "The directory %1 already exists." msgstr "Le dossier %s existe déjà." -#: src/tools/dvdomatic.cc:324 +#: src/tools/dcpomatic.cc:324 msgid "" "You did not select a folder. Make sure that you select a folder before " "clicking Open." diff --git a/src/tools/po/it_IT.po b/src/tools/po/it_IT.po index 38cbec157..998f70059 100644 --- a/src/tools/po/it_IT.po +++ b/src/tools/po/it_IT.po @@ -17,107 +17,107 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.5\n" -#: src/tools/dvdomatic.cc:177 +#: src/tools/dcpomatic.cc:177 msgid "&Analyse audio" msgstr "&Analizza audio" -#: src/tools/dvdomatic.cc:183 +#: src/tools/dcpomatic.cc:183 msgid "&Edit" msgstr "&Modifica" -#: src/tools/dvdomatic.cc:182 +#: src/tools/dcpomatic.cc:182 msgid "&File" msgstr "&File" -#: src/tools/dvdomatic.cc:185 +#: src/tools/dcpomatic.cc:185 msgid "&Help" msgstr "&Aiuto" -#: src/tools/dvdomatic.cc:184 +#: src/tools/dcpomatic.cc:184 msgid "&Jobs" msgstr "&Lavori" -#: src/tools/dvdomatic.cc:173 +#: src/tools/dcpomatic.cc:173 msgid "&Make DCP" msgstr "&Crea DCP" -#: src/tools/dvdomatic.cc:161 +#: src/tools/dcpomatic.cc:161 msgid "&Open..." msgstr "&Apri..." -#: src/tools/dvdomatic.cc:170 +#: src/tools/dcpomatic.cc:170 msgid "&Preferences..." msgstr "&Preferenze..." -#: src/tools/dvdomatic.cc:165 +#: src/tools/dcpomatic.cc:165 msgid "&Properties..." msgstr "&Proprieta'..." -#: src/tools/dvdomatic.cc:167 +#: src/tools/dcpomatic.cc:167 msgid "&Quit" msgstr "&Esci" -#: src/tools/dvdomatic.cc:163 +#: src/tools/dcpomatic.cc:163 msgid "&Save" msgstr "&Salva" -#: src/tools/dvdomatic.cc:174 +#: src/tools/dcpomatic.cc:174 msgid "&Send DCP to TMS" msgstr "&Invia DCP a TMS" -#: src/tools/dvdomatic.cc:417 +#: src/tools/dcpomatic.cc:417 msgid "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" msgstr "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" -#: src/tools/dvdomatic.cc:180 +#: src/tools/dcpomatic.cc:180 msgid "About" msgstr "Informazioni" -#: src/tools/dvdomatic.cc:527 +#: src/tools/dcpomatic.cc:527 msgid "Could not load film %1 (%2)" msgstr "Non posso caricare il film %s (%s)" -#: src/tools/dvdomatic.cc:339 +#: src/tools/dcpomatic.cc:339 #, c-format msgid "Could not open film at %s (%s)" msgstr "Non posso aprire il film in %s (%s)" -#: src/tools/dvdomatic.cc:287 src/tools/dvdomatic.cc:410 -#: src/tools/dvdomatic.cc:531 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +#: src/tools/dcpomatic.cc:287 src/tools/dcpomatic.cc:410 +#: src/tools/dcpomatic.cc:531 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" -#: src/tools/dvdomatic.cc:75 +#: src/tools/dcpomatic.cc:75 msgid "Film changed" msgstr "Film modificato" -#: src/tools/dvdomatic.cc:416 +#: src/tools/dcpomatic.cc:416 msgid "Free, open-source DCP generation from almost anything." msgstr "Genera DCP da quasi tutto, free e open-source." -#: src/tools/dvdomatic.cc:160 +#: src/tools/dcpomatic.cc:160 msgid "New..." msgstr "Nuovo" -#: src/tools/dvdomatic.cc:175 +#: src/tools/dcpomatic.cc:175 msgid "S&how DCP" msgstr "&Mostra DCP" -#: src/tools/dvdomatic.cc:74 +#: src/tools/dcpomatic.cc:74 msgid "Save changes to film \"%s\" before closing?" msgstr "Salvare i cambiamenti del film \"%s\" prima di chiudere?" -#: src/tools/dvdomatic.cc:319 +#: src/tools/dcpomatic.cc:319 msgid "Select film to open" msgstr "Seleziona il film da aprire" -#: src/tools/dvdomatic.cc:303 +#: src/tools/dcpomatic.cc:303 msgid "The directory %1 already exists." msgstr "La directory %s esiste gia'." -#: src/tools/dvdomatic.cc:324 +#: src/tools/dcpomatic.cc:324 msgid "" "You did not select a folder. Make sure that you select a folder before " "clicking Open." diff --git a/src/tools/po/sv_SE.po b/src/tools/po/sv_SE.po index 57254770c..4765c2d98 100644 --- a/src/tools/po/sv_SE.po +++ b/src/tools/po/sv_SE.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVD-o-matic\n" +"Project-Id-Version: DCP-o-matic\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-04-09 10:12+0100\n" @@ -17,108 +17,108 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 1.5.5\n" -#: src/tools/dvdomatic.cc:177 +#: src/tools/dcpomatic.cc:177 msgid "&Analyse audio" msgstr "&Analysera audio" -#: src/tools/dvdomatic.cc:183 +#: src/tools/dcpomatic.cc:183 msgid "&Edit" msgstr "&Redigera" -#: src/tools/dvdomatic.cc:182 +#: src/tools/dcpomatic.cc:182 msgid "&File" msgstr "&Fil" -#: src/tools/dvdomatic.cc:185 +#: src/tools/dcpomatic.cc:185 msgid "&Help" msgstr "&Hjälp" -#: src/tools/dvdomatic.cc:184 +#: src/tools/dcpomatic.cc:184 msgid "&Jobs" msgstr "&Jobb" -#: src/tools/dvdomatic.cc:173 +#: src/tools/dcpomatic.cc:173 msgid "&Make DCP" msgstr "&Skapa DCP" -#: src/tools/dvdomatic.cc:161 +#: src/tools/dcpomatic.cc:161 msgid "&Open..." msgstr "&Öppna" -#: src/tools/dvdomatic.cc:170 +#: src/tools/dcpomatic.cc:170 msgid "&Preferences..." msgstr "&Inställningar" -#: src/tools/dvdomatic.cc:165 +#: src/tools/dcpomatic.cc:165 msgid "&Properties..." msgstr "&Egenskaper" -#: src/tools/dvdomatic.cc:167 +#: src/tools/dcpomatic.cc:167 msgid "&Quit" msgstr "&Avsluta" -#: src/tools/dvdomatic.cc:163 +#: src/tools/dcpomatic.cc:163 msgid "&Save" msgstr "&Spara" -#: src/tools/dvdomatic.cc:174 +#: src/tools/dcpomatic.cc:174 msgid "&Send DCP to TMS" msgstr "&Skicka DCP till TMS" -#: src/tools/dvdomatic.cc:417 +#: src/tools/dcpomatic.cc:417 msgid "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" msgstr "" "(C) 2012-2013 Carl Hetherington, Terrence Meiczinger, Paul Davis, Ole Laursen" -#: src/tools/dvdomatic.cc:180 +#: src/tools/dcpomatic.cc:180 msgid "About" msgstr "Om" -#: src/tools/dvdomatic.cc:527 +#: src/tools/dcpomatic.cc:527 msgid "Could not load film %1 (%2)" msgstr "Kunde inte öppna filmen %1 (%2)" -#: src/tools/dvdomatic.cc:339 +#: src/tools/dcpomatic.cc:339 #, c-format msgid "Could not open film at %s (%s)" msgstr "Kunde inte öppna filmen vid %s (%s)" -#: src/tools/dvdomatic.cc:287 src/tools/dvdomatic.cc:410 -#: src/tools/dvdomatic.cc:531 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +#: src/tools/dcpomatic.cc:287 src/tools/dcpomatic.cc:410 +#: src/tools/dcpomatic.cc:531 +msgid "DCP-o-matic" +msgstr "DCP-o-matic" -#: src/tools/dvdomatic.cc:75 +#: src/tools/dcpomatic.cc:75 msgid "Film changed" msgstr "Film ändrad" -#: src/tools/dvdomatic.cc:416 +#: src/tools/dcpomatic.cc:416 msgid "Free, open-source DCP generation from almost anything." msgstr "" "Fri, öppen-källkodsprogramvara för DCP-generering från nästan vad som helst." -#: src/tools/dvdomatic.cc:160 +#: src/tools/dcpomatic.cc:160 msgid "New..." msgstr "Ny..." -#: src/tools/dvdomatic.cc:175 +#: src/tools/dcpomatic.cc:175 msgid "S&how DCP" msgstr "&Visa DCP" -#: src/tools/dvdomatic.cc:74 +#: src/tools/dcpomatic.cc:74 msgid "Save changes to film \"%s\" before closing?" msgstr "Spara ändringarna till filmen \"%s\" före avslut?" -#: src/tools/dvdomatic.cc:319 +#: src/tools/dcpomatic.cc:319 msgid "Select film to open" msgstr "Välj film att öppna" -#: src/tools/dvdomatic.cc:303 +#: src/tools/dcpomatic.cc:303 msgid "The directory %1 already exists." msgstr "Katalogen %1 finns redan." -#: src/tools/dvdomatic.cc:324 +#: src/tools/dcpomatic.cc:324 msgid "" "You did not select a folder. Make sure that you select a folder before " "clicking Open." diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc index 6626d45b9..76d085034 100644 --- a/src/tools/servomatic_cli.cc +++ b/src/tools/servomatic_cli.cc @@ -51,7 +51,7 @@ static void help (string n) { cerr << "Syntax: " << n << " [OPTION]\n" - << " -v, --version show DVD-o-matic version\n" + << " -v, --version show DCP-o-matic version\n" << " -h, --help show this help\n" << " -t, --threads number of parallel encoding threads to use\n"; } @@ -78,7 +78,7 @@ main (int argc, char* argv[]) switch (c) { case 'v': - cout << "dvdomatic version " << dvdomatic_version << " " << dvdomatic_git_commit << "\n"; + cout << "dcpomatic version " << dcpomatic_version << " " << dcpomatic_git_commit << "\n"; exit (EXIT_SUCCESS); case 'h': help (argv[0]); diff --git a/src/tools/servomatic_gui.cc b/src/tools/servomatic_gui.cc index 5e36660eb..152e063c1 100644 --- a/src/tools/servomatic_gui.cc +++ b/src/tools/servomatic_gui.cc @@ -61,7 +61,7 @@ class StatusDialog : public wxDialog { public: StatusDialog () - : wxDialog (0, wxID_ANY, _("DVD-o-matic encode server"), wxDefaultPosition, wxSize (600, 80), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + : wxDialog (0, wxID_ANY, _("DCP-o-matic encode server"), wxDefaultPosition, wxSize (600, 80), wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) , _timer (this, ID_timer) { _sizer = new wxFlexGridSizer (1, 6, 6); @@ -103,7 +103,7 @@ public: wxIcon icon; icon.CopyFromBitmap (bitmap); #endif - SetIcon (icon, std_to_wx ("DVD-o-matic encode server")); + SetIcon (icon, std_to_wx ("DCP-o-matic encode server")); Connect (ID_status, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (TaskBarIcon::status)); Connect (ID_quit, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler (TaskBarIcon::quit)); @@ -147,7 +147,7 @@ private: return false; } - dvdomatic_setup (); + dcpomatic_setup (); _icon = new TaskBarIcon; _thread = new thread (bind (&App::main_thread, this)); diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index d3222faa3..42cc76871 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -145,7 +145,7 @@ main (int argc, char* argv[]) exit (EXIT_FAILURE); } - dvdomatic_setup (); + dcpomatic_setup (); server = new ServerDescription (server_host, 1); shared_ptr film (new Film (film_dir, true)); diff --git a/src/tools/wscript b/src/tools/wscript index 9cc7e9d1b..f0ffb8e89 100644 --- a/src/tools/wscript +++ b/src/tools/wscript @@ -8,25 +8,25 @@ def build(bld): obj = bld(features = 'cxx cxxprogram') obj.uselib = 'BOOST_THREAD OPENJPEG DCP CXML AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC' obj.includes = ['..'] - obj.use = ['libdvdomatic'] + obj.use = ['libdcpomatic'] obj.source = '%s.cc' % t obj.target = t if not bld.env.DISABLE_GUI: - for t in ['dvdomatic', 'servomatic_gui']: + for t in ['dcpomatic', 'servomatic_gui']: obj = bld(features = 'cxx cxxprogram') obj.uselib = 'DCP CXML OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC' obj.includes = ['..'] - obj.use = ['libdvdomatic', 'libdvdomatic-wx'] + obj.use = ['libdcpomatic', 'libdcpomatic-wx'] obj.source = '%s.cc' % t if bld.env.TARGET_WINDOWS: - obj.source += ' ../../windows/dvdomatic.rc' + obj.source += ' ../../windows/dcpomatic.rc' obj.target = t - i18n.po_to_mo(os.path.join('src', 'tools'), 'dvdomatic', bld) + i18n.po_to_mo(os.path.join('src', 'tools'), 'dcpomatic', bld) def pot(bld): - i18n.pot(os.path.join('src', 'tools'), 'dvdomatic.cc', 'dvdomatic') + i18n.pot(os.path.join('src', 'tools'), 'dcpomatic.cc', 'dcpomatic') def pot_merge(bld): - i18n.pot_merge(os.path.join('src', 'tools'), 'dvdomatic') + i18n.pot_merge(os.path.join('src', 'tools'), 'dcpomatic') diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index bed7aac6d..15d746839 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -100,7 +100,7 @@ AudioDialog::set_film (shared_ptr f) _film_changed_connection = _film->Changed.connect (bind (&AudioDialog::film_changed, this, _1)); _film_audio_analysis_succeeded_connection = _film->AudioAnalysisSucceeded.connect (bind (&AudioDialog::try_to_load_analysis, this)); - SetTitle (wxString::Format (_("DVD-o-matic audio - %s"), std_to_wx(_film->name()).data())); + SetTitle (wxString::Format (_("DCP-o-matic audio - %s"), std_to_wx(_film->name()).data())); } diff --git a/src/wx/config_dialog.cc b/src/wx/config_dialog.cc index 1d025f3fa..4ae8f1eb4 100644 --- a/src/wx/config_dialog.cc +++ b/src/wx/config_dialog.cc @@ -18,7 +18,7 @@ */ /** @file src/config_dialog.cc - * @brief A dialogue to edit DVD-o-matic configuration. + * @brief A dialogue to edit DCP-o-matic configuration. */ #include @@ -41,7 +41,7 @@ using namespace std; using boost::bind; ConfigDialog::ConfigDialog (wxWindow* parent) - : wxDialog (parent, wxID_ANY, _("DVD-o-matic Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) + : wxDialog (parent, wxID_ANY, _("DCP-o-matic Preferences"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { wxFlexGridSizer* table = new wxFlexGridSizer (3, 6, 6); table->AddGrowableCol (1, 1); @@ -58,7 +58,7 @@ ConfigDialog::ConfigDialog (wxWindow* parent) table->AddSpacer (0); table->AddSpacer (0); - wxStaticText* restart = add_label_to_sizer (table, this, _("(restart DVD-o-matic to see language changes)")); + wxStaticText* restart = add_label_to_sizer (table, this, _("(restart DCP-o-matic to see language changes)")); wxFont font = restart->GetFont(); font.SetStyle (wxFONTSTYLE_ITALIC); font.SetPointSize (font.GetPointSize() - 1); diff --git a/src/wx/config_dialog.h b/src/wx/config_dialog.h index f6f3b3707..a2fc1f4b1 100644 --- a/src/wx/config_dialog.h +++ b/src/wx/config_dialog.h @@ -18,7 +18,7 @@ */ /** @file src/config_dialog.h - * @brief A dialogue to edit DVD-o-matic configuration. + * @brief A dialogue to edit DCP-o-matic configuration. */ #include @@ -31,7 +31,7 @@ class DirPickerCtrl; class ServerDescription; /** @class ConfigDialog - * @brief A dialogue to edit DVD-o-matic configuration. + * @brief A dialogue to edit DCP-o-matic configuration. */ class ConfigDialog : public wxDialog { diff --git a/src/wx/po/es_ES.po b/src/wx/po/es_ES.po index 207708589..abb6b780f 100644 --- a/src/wx/po/es_ES.po +++ b/src/wx/po/es_ES.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: libdvdomatic-wx\n" +"Project-Id-Version: libdcpomatic-wx\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-04-02 19:08-0500\n" @@ -22,7 +22,7 @@ msgid "%" msgstr "%" #: src/wx/config_dialog.cc:61 -msgid "(restart DVD-o-matic to see language changes)" +msgid "(restart DCP-o-matic to see language changes)" msgstr "" #: src/wx/film_editor.cc:1269 @@ -141,17 +141,17 @@ msgid "DCP Name" msgstr "Nombre DCP" #: src/wx/wx_util.cc:61 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +msgid "DCP-o-matic" +msgstr "DCP-o-matic" #: src/wx/config_dialog.cc:44 -msgid "DVD-o-matic Preferences" -msgstr "Preferencias DVD-o-matic" +msgid "DCP-o-matic Preferences" +msgstr "Preferencias DCP-o-matic" #: src/wx/audio_dialog.cc:101 #, fuzzy, c-format -msgid "DVD-o-matic audio - %s" -msgstr "Audio DVD-o-matic - %1" +msgid "DCP-o-matic audio - %s" +msgstr "Audio DCP-o-matic - %1" #: src/wx/config_dialog.cc:102 msgid "Default DCI name details" diff --git a/src/wx/po/fr_FR.po b/src/wx/po/fr_FR.po index 80ee5dbfd..2aac7114c 100644 --- a/src/wx/po/fr_FR.po +++ b/src/wx/po/fr_FR.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVD-o-matic FRENCH\n" +"Project-Id-Version: DCP-o-matic FRENCH\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-03-20 00:34+0100\n" @@ -21,7 +21,7 @@ msgid "%" msgstr "%" #: src/wx/config_dialog.cc:61 -msgid "(restart DVD-o-matic to see language changes)" +msgid "(restart DCP-o-matic to see language changes)" msgstr "" #: src/wx/film_editor.cc:1269 @@ -140,17 +140,17 @@ msgid "DCP Name" msgstr "Nom du DCP" #: src/wx/wx_util.cc:61 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +msgid "DCP-o-matic" +msgstr "DCP-o-matic" #: src/wx/config_dialog.cc:44 -msgid "DVD-o-matic Preferences" -msgstr "Préférences DVD-o-matic" +msgid "DCP-o-matic Preferences" +msgstr "Préférences DCP-o-matic" #: src/wx/audio_dialog.cc:101 #, c-format -msgid "DVD-o-matic audio - %s" -msgstr "Son DVD-o-matic - %s" +msgid "DCP-o-matic audio - %s" +msgstr "Son DCP-o-matic - %s" #: src/wx/config_dialog.cc:102 msgid "Default DCI name details" diff --git a/src/wx/po/it_IT.po b/src/wx/po/it_IT.po index 78fd0dee9..7b06495e8 100644 --- a/src/wx/po/it_IT.po +++ b/src/wx/po/it_IT.po @@ -22,8 +22,8 @@ msgid "%" msgstr "%" #: src/wx/config_dialog.cc:61 -msgid "(restart DVD-o-matic to see language changes)" -msgstr "(riavviare DVD-o-matic per vedere i cambiamenti di lingua)" +msgid "(restart DCP-o-matic to see language changes)" +msgstr "(riavviare DCP-o-matic per vedere i cambiamenti di lingua)" #: src/wx/film_editor.cc:1269 msgid "1 channel" @@ -141,17 +141,17 @@ msgid "DCP Name" msgstr "Nome del DCP" #: src/wx/wx_util.cc:61 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +msgid "DCP-o-matic" +msgstr "DCP-o-matic" #: src/wx/config_dialog.cc:44 -msgid "DVD-o-matic Preferences" -msgstr "Preferenze DVD-o-matic" +msgid "DCP-o-matic Preferences" +msgstr "Preferenze DCP-o-matic" #: src/wx/audio_dialog.cc:101 #, c-format -msgid "DVD-o-matic audio - %s" -msgstr "Audio DVD-o-matic - %s" +msgid "DCP-o-matic audio - %s" +msgstr "Audio DCP-o-matic - %s" #: src/wx/config_dialog.cc:102 msgid "Default DCI name details" diff --git a/src/wx/po/sv_SE.po b/src/wx/po/sv_SE.po index e52589ff0..96fafadeb 100644 --- a/src/wx/po/sv_SE.po +++ b/src/wx/po/sv_SE.po @@ -5,7 +5,7 @@ # msgid "" msgstr "" -"Project-Id-Version: DVD-o-matic\n" +"Project-Id-Version: DCP-o-matic\n" "Report-Msgid-Bugs-To: \n" "POT-Creation-Date: 2013-04-09 11:14+0100\n" "PO-Revision-Date: 2013-04-09 10:13+0100\n" @@ -22,8 +22,8 @@ msgid "%" msgstr "%" #: src/wx/config_dialog.cc:61 -msgid "(restart DVD-o-matic to see language changes)" -msgstr "(starta om DVD-o-matic för att se språkändringar)" +msgid "(restart DCP-o-matic to see language changes)" +msgstr "(starta om DCP-o-matic för att se språkändringar)" #: src/wx/film_editor.cc:1269 msgid "1 channel" @@ -141,17 +141,17 @@ msgid "DCP Name" msgstr "DCP Namn" #: src/wx/wx_util.cc:61 -msgid "DVD-o-matic" -msgstr "DVD-o-matic" +msgid "DCP-o-matic" +msgstr "DCP-o-matic" #: src/wx/config_dialog.cc:44 -msgid "DVD-o-matic Preferences" -msgstr "DVD-o-matic Inställningar" +msgid "DCP-o-matic Preferences" +msgstr "DCP-o-matic Inställningar" #: src/wx/audio_dialog.cc:101 #, c-format -msgid "DVD-o-matic audio - %s" -msgstr "DVD-o-matic audio - %s" +msgid "DCP-o-matic audio - %s" +msgstr "DCP-o-matic audio - %s" #: src/wx/config_dialog.cc:102 msgid "Default DCI name details" diff --git a/src/wx/wscript b/src/wx/wscript index 7f9cde9ac..09bf40393 100644 --- a/src/wx/wscript +++ b/src/wx/wscript @@ -34,18 +34,18 @@ def build(bld): else: obj = bld(features = 'cxx cxxshlib') - obj.name = 'libdvdomatic-wx' + obj.name = 'libdcpomatic-wx' obj.includes = [ '..' ] obj.export_includes = ['.'] obj.uselib = 'WXWIDGETS' - obj.use = 'libdvdomatic' + obj.use = 'libdcpomatic' obj.source = sources - obj.target = 'dvdomatic-wx' + obj.target = 'dcpomatic-wx' - i18n.po_to_mo(os.path.join('src', 'wx'), 'libdvdomatic-wx', bld) + i18n.po_to_mo(os.path.join('src', 'wx'), 'libdcpomatic-wx', bld) def pot(bld): - i18n.pot(os.path.join('src', 'wx'), sources, 'libdvdomatic-wx') + i18n.pot(os.path.join('src', 'wx'), sources, 'libdcpomatic-wx') def pot_merge(bld): - i18n.pot_merge(os.path.join('src', 'wx'), 'libdvdomatic-wx') + i18n.pot_merge(os.path.join('src', 'wx'), 'libdcpomatic-wx') diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index 720a058cb..3dad6e7fd 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -58,7 +58,7 @@ add_label_to_grid_bag_sizer (wxGridBagSizer* s, wxWindow* p, wxString t, wxGBPos void error_dialog (wxWindow* parent, wxString m) { - wxMessageDialog* d = new wxMessageDialog (parent, m, _("DVD-o-matic"), wxOK); + wxMessageDialog* d = new wxMessageDialog (parent, m, _("DCP-o-matic"), wxOK); d->ShowModal (); d->Destroy (); } diff --git a/test/test.cc b/test/test.cc index 592bad836..39a921d36 100644 --- a/test/test.cc +++ b/test/test.cc @@ -42,7 +42,7 @@ #include "sndfile_decoder.h" #include "dcp_content_type.h" #define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE dvdomatic_test +#define BOOST_TEST_MODULE dcpomatic_test #include using std::string; @@ -90,7 +90,7 @@ new_test_film (string name) BOOST_AUTO_TEST_CASE (make_black_test) { /* This needs to happen in the first test */ - dvdomatic_setup (); + dcpomatic_setup (); libdcp::Size in_size (512, 512); libdcp::Size out_size (1024, 1024); @@ -392,7 +392,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) new thread (boost::bind (&Server::run, server, 2)); /* Let the server get itself ready */ - dvdomatic_sleep (1); + dcpomatic_sleep (1); ServerDescription description ("localhost", 2); @@ -421,7 +421,7 @@ BOOST_AUTO_TEST_CASE (make_dcp_test) film->write_metadata (); while (JobManager::instance()->work_to_do ()) { - dvdomatic_sleep (1); + dcpomatic_sleep (1); } BOOST_CHECK_EQUAL (JobManager::instance()->errors(), false); @@ -452,7 +452,7 @@ BOOST_AUTO_TEST_CASE (make_dcp_with_range_test) film->make_dcp (); while (JobManager::instance()->work_to_do() && !JobManager::instance()->errors()) { - dvdomatic_sleep (1); + dcpomatic_sleep (1); } BOOST_CHECK_EQUAL (JobManager::instance()->errors(), false); @@ -689,10 +689,10 @@ BOOST_AUTO_TEST_CASE (job_manager_test) shared_ptr a (new TestJob (f)); JobManager::instance()->add (a); - dvdomatic_sleep (1); + dcpomatic_sleep (1); BOOST_CHECK_EQUAL (a->running (), true); a->set_finished_ok (); - dvdomatic_sleep (2); + dcpomatic_sleep (2); BOOST_CHECK_EQUAL (a->finished_ok(), true); } diff --git a/test/wscript b/test/wscript index 493270903..61c391663 100644 --- a/test/wscript +++ b/test/wscript @@ -9,7 +9,7 @@ def build(bld): obj = bld(features = 'cxx cxxprogram') obj.name = 'unit-tests' obj.uselib = 'BOOST_TEST CXML DCP OPENJPEG AVFORMAT AVFILTER AVCODEC AVUTIL SWSCALE POSTPROC' - obj.use = 'libdvdomatic' + obj.use = 'libdcpomatic' obj.source = 'test.cc' obj.target = 'unit-tests' obj.install_path = '' diff --git a/windows/dvdomatic.bmp b/windows/dvdomatic.bmp deleted file mode 100644 index 0a196f7a0..000000000 Binary files a/windows/dvdomatic.bmp and /dev/null differ diff --git a/windows/dvdomatic.ico b/windows/dvdomatic.ico deleted file mode 100644 index 225008cfe..000000000 Binary files a/windows/dvdomatic.ico and /dev/null differ diff --git a/windows/dvdomatic.rc b/windows/dvdomatic.rc deleted file mode 100644 index 17790cf0d..000000000 --- a/windows/dvdomatic.rc +++ /dev/null @@ -1,3 +0,0 @@ -id ICON "dvdomatic.ico" -taskbar_icon ICON "dvdomatic_taskbar.ico" -#include "wx-2.9/wx/msw/wx.rc" diff --git a/windows/dvdomatic_taskbar.ico b/windows/dvdomatic_taskbar.ico deleted file mode 100644 index f4489fa14..000000000 Binary files a/windows/dvdomatic_taskbar.ico and /dev/null differ diff --git a/windows/installer.nsi.32.in b/windows/installer.nsi.32.in index 553a94d2b..15a0a1886 100644 --- a/windows/installer.nsi.32.in +++ b/windows/installer.nsi.32.in @@ -1,14 +1,14 @@ !include "MUI2.nsh" -Name "DVD-o-matic" +Name "DCP-o-matic" RequestExecutionLevel admin -outFile "DVD-o-matic @version@ 32-bit Installer.exe" -!define MUI_ICON "%resources%/dvdomatic.ico" -!define MUI_UNICON "%resources%/dvdomatic.ico" -!define MUI_SPECIALBITMAP "%resources%/dvdomatic.bmp" +outFile "DCP-o-matic @version@ 32-bit Installer.exe" +!define MUI_ICON "%resources%/dcpomatic.ico" +!define MUI_UNICON "%resources%/dcpomatic.ico" +!define MUI_SPECIALBITMAP "%resources%/dcpomatic.bmp" -InstallDir "$PROGRAMFILES\DVD-o-matic" +InstallDir "$PROGRAMFILES\DCP-o-matic" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "../../COPYING" @@ -81,9 +81,9 @@ File "%deps%/bin/libexpat-1.dll" File "%deps%/bin/libbz2.dll" File "%deps%/bin/cxml.dll" -File "%binaries%/src/wx/dvdomatic-wx.dll" -File "%binaries%/src/lib/dvdomatic.dll" -File "%binaries%/src/tools/dvdomatic.exe" +File "%binaries%/src/wx/dcpomatic-wx.dll" +File "%binaries%/src/lib/dcpomatic.dll" +File "%binaries%/src/tools/dcpomatic.exe" File "%binaries%/src/tools/servomatic_cli.exe" File "%binaries%/src/tools/servomatic_gui.exe" @@ -95,32 +95,32 @@ SetOutPath "$PROFILE\.magick" File "%deps%/etc/ImageMagick/delegates.xml" SetOutPath "$INSTDIR\locale\fr\LC_MESSAGES" -File "%binaries%/src/lib/mo/fr_FR/libdvdomatic.mo" -File "%binaries%/src/wx/mo/fr_FR/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/fr_FR/dvdomatic.mo" +File "%binaries%/src/lib/mo/fr_FR/libdcpomatic.mo" +File "%binaries%/src/wx/mo/fr_FR/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/fr_FR/dcpomatic.mo" SetOutPath "$INSTDIR\locale\it\LC_MESSAGES" -File "%binaries%/src/lib/mo/it_IT/libdvdomatic.mo" -File "%binaries%/src/wx/mo/it_IT/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/it_IT/dvdomatic.mo" +File "%binaries%/src/lib/mo/it_IT/libdcpomatic.mo" +File "%binaries%/src/wx/mo/it_IT/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/it_IT/dcpomatic.mo" SetOutPath "$INSTDIR\locale\es\LC_MESSAGES" -File "%binaries%/src/lib/mo/es_ES/libdvdomatic.mo" -File "%binaries%/src/wx/mo/es_ES/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/es_ES/dvdomatic.mo" +File "%binaries%/src/lib/mo/es_ES/libdcpomatic.mo" +File "%binaries%/src/wx/mo/es_ES/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/es_ES/dcpomatic.mo" SetOutPath "$INSTDIR\locale\sv\LC_MESSAGES" -File "%binaries%/src/lib/mo/sv_SE/libdvdomatic.mo" -File "%binaries%/src/wx/mo/sv_SE/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/sv_SE/dvdomatic.mo" +File "%binaries%/src/lib/mo/sv_SE/libdcpomatic.mo" +File "%binaries%/src/wx/mo/sv_SE/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/sv_SE/dcpomatic.mo" -CreateShortCut "$DESKTOP\DVD-o-matic.lnk" "$INSTDIR\bin\dvdomatic.exe" "" -CreateShortCut "$DESKTOP\DVD-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" +CreateShortCut "$DESKTOP\DCP-o-matic.lnk" "$INSTDIR\bin\dcpomatic.exe" "" +CreateShortCut "$DESKTOP\DCP-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" -CreateDirectory "$SMPROGRAMS\DVD-o-matic" -CreateShortCut "$SMPROGRAMS\DVD-o-matic\Uninstall DVD-o-matic.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 -CreateShortCut "$SMPROGRAMS\DVD-o-matic\DVD-o-matic.lnk" "$INSTDIR\bin\dvdomatic.exe" "" "$INSTDIR\bin\dvdomatic.exe" 0 -CreateShortCut "$SMPROGRAMS\DVD-o-matic\DVD-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" "$INSTDIR\bin\servomatic_gui.exe" 0 +CreateDirectory "$SMPROGRAMS\DCP-o-matic" +CreateShortCut "$SMPROGRAMS\DCP-o-matic\Uninstall DCP-o-matic.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 +CreateShortCut "$SMPROGRAMS\DCP-o-matic\DCP-o-matic.lnk" "$INSTDIR\bin\dcpomatic.exe" "" "$INSTDIR\bin\dcpomatic.exe" 0 +CreateShortCut "$SMPROGRAMS\DCP-o-matic\DCP-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" "$INSTDIR\bin\servomatic_gui.exe" 0 -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" "DisplayName" "DVD-o-matic (remove only)" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" "UninstallString" "$INSTDIR\Uninstall.exe" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" "DisplayName" "DCP-o-matic (remove only)" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" "UninstallString" "$INSTDIR\Uninstall.exe" WriteUninstaller "$INSTDIR\Uninstall.exe" @@ -131,11 +131,11 @@ Section "Uninstall" RMDir /r "$INSTDIR\*.*" RMDir "$INSTDIR" -Delete "$DESKTOP\DVD-o-matic.lnk" -Delete "$DESKTOP\DVD-o-matic encode server.lnk" -Delete "$SMPROGRAMS\DVD-o-matic\*.*" -RmDir "$SMPROGRAMS\DVD-o-matic" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DVD-o-matic" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" +Delete "$DESKTOP\DCP-o-matic.lnk" +Delete "$DESKTOP\DCP-o-matic encode server.lnk" +Delete "$SMPROGRAMS\DCP-o-matic\*.*" +RmDir "$SMPROGRAMS\DCP-o-matic" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DCP-o-matic" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" SectionEnd diff --git a/windows/installer.nsi.64.in b/windows/installer.nsi.64.in index bb5456936..566907e39 100644 --- a/windows/installer.nsi.64.in +++ b/windows/installer.nsi.64.in @@ -1,16 +1,16 @@ !include "MUI2.nsh" !include "x64.nsh" -Name "DVD-o-matic" +Name "DCP-o-matic" RequestExecutionLevel admin -outFile "DVD-o-matic @version@ 64-bit Installer.exe" -!define MUI_ICON "%resources%/dvdomatic.ico" -!define MUI_UNICON "%resources%/dvdomatic.ico" -!define MUI_SPECIALBITMAP "%resources%/dvdomatic.bmp" +outFile "DCP-o-matic @version@ 64-bit Installer.exe" +!define MUI_ICON "%resources%/dcpomatic.ico" +!define MUI_UNICON "%resources%/dcpomatic.ico" +!define MUI_SPECIALBITMAP "%resources%/dcpomatic.bmp" -InstallDir "$PROGRAMFILES\DVD-o-matic" +InstallDir "$PROGRAMFILES\DCP-o-matic" !insertmacro MUI_PAGE_WELCOME !insertmacro MUI_PAGE_LICENSE "../../COPYING" @@ -32,7 +32,7 @@ ${If} ${RunningX64} ; disable registry redirection (enable access to 64-bit portion of registry) SetRegView 64 ; change install dir - StrCpy $INSTDIR "$PROGRAMFILES64\DVD-o-matic" + StrCpy $INSTDIR "$PROGRAMFILES64\DCP-o-matic" ${EndIf} SetOutPath "$INSTDIR\bin" @@ -91,9 +91,9 @@ File "%deps%/bin/libexpat-1.dll" File "%deps%/bin/libbz2.dll" File "%deps%/bin/cxml.dll" -File "%binaries%/src/wx/dvdomatic-wx.dll" -File "%binaries%/src/lib/dvdomatic.dll" -File "%binaries%/src/tools/dvdomatic.exe" +File "%binaries%/src/wx/dcpomatic-wx.dll" +File "%binaries%/src/lib/dcpomatic.dll" +File "%binaries%/src/tools/dcpomatic.exe" File "%binaries%/src/tools/servomatic_cli.exe" File "%binaries%/src/tools/servomatic_gui.exe" @@ -105,32 +105,32 @@ SetOutPath "$PROFILE\.magick" File "%deps%/etc/ImageMagick/delegates.xml" SetOutPath "$INSTDIR\locale\fr\LC_MESSAGES" -File "%binaries%/src/lib/mo/fr_FR/libdvdomatic.mo" -File "%binaries%/src/wx/mo/fr_FR/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/fr_FR/dvdomatic.mo" +File "%binaries%/src/lib/mo/fr_FR/libdcpomatic.mo" +File "%binaries%/src/wx/mo/fr_FR/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/fr_FR/dcpomatic.mo" SetOutPath "$INSTDIR\locale\it\LC_MESSAGES" -File "%binaries%/src/lib/mo/it_IT/libdvdomatic.mo" -File "%binaries%/src/wx/mo/it_IT/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/it_IT/dvdomatic.mo" +File "%binaries%/src/lib/mo/it_IT/libdcpomatic.mo" +File "%binaries%/src/wx/mo/it_IT/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/it_IT/dcpomatic.mo" SetOutPath "$INSTDIR\locale\es\LC_MESSAGES" -File "%binaries%/src/lib/mo/es_ES/libdvdomatic.mo" -File "%binaries%/src/wx/mo/es_ES/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/es_ES/dvdomatic.mo" +File "%binaries%/src/lib/mo/es_ES/libdcpomatic.mo" +File "%binaries%/src/wx/mo/es_ES/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/es_ES/dcpomatic.mo" SetOutPath "$INSTDIR\locale\sv\LC_MESSAGES" -File "%binaries%/src/lib/mo/sv_SE/libdvdomatic.mo" -File "%binaries%/src/wx/mo/sv_SE/libdvdomatic-wx.mo" -File "%binaries%/src/tools/mo/sv_SE/dvdomatic.mo" +File "%binaries%/src/lib/mo/sv_SE/libdcpomatic.mo" +File "%binaries%/src/wx/mo/sv_SE/libdcpomatic-wx.mo" +File "%binaries%/src/tools/mo/sv_SE/dcpomatic.mo" -CreateShortCut "$DESKTOP\DVD-o-matic.lnk" "$INSTDIR\bin\dvdomatic.exe" "" -CreateShortCut "$DESKTOP\DVD-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" +CreateShortCut "$DESKTOP\DCP-o-matic.lnk" "$INSTDIR\bin\dcpomatic.exe" "" +CreateShortCut "$DESKTOP\DCP-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" -CreateDirectory "$SMPROGRAMS\DVD-o-matic" -CreateShortCut "$SMPROGRAMS\DVD-o-matic\Uninstall DVD-o-matic.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 -CreateShortCut "$SMPROGRAMS\DVD-o-matic\DVD-o-matic.lnk" "$INSTDIR\bin\dvdomatic.exe" "" "$INSTDIR\bin\dvdomatic.exe" 0 -CreateShortCut "$SMPROGRAMS\DVD-o-matic\DVD-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" "$INSTDIR\bin\servomatic_gui.exe" 0 +CreateDirectory "$SMPROGRAMS\DCP-o-matic" +CreateShortCut "$SMPROGRAMS\DCP-o-matic\Uninstall DCP-o-matic.lnk" "$INSTDIR\Uninstall.exe" "" "$INSTDIR\Uninstall.exe" 0 +CreateShortCut "$SMPROGRAMS\DCP-o-matic\DCP-o-matic.lnk" "$INSTDIR\bin\dcpomatic.exe" "" "$INSTDIR\bin\dcpomatic.exe" 0 +CreateShortCut "$SMPROGRAMS\DCP-o-matic\DCP-o-matic encode server.lnk" "$INSTDIR\bin\servomatic_gui.exe" "" "$INSTDIR\bin\servomatic_gui.exe" 0 -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" "DisplayName" "DVD-o-matic (remove only)" -WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" "UninstallString" "$INSTDIR\Uninstall.exe" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" "DisplayName" "DCP-o-matic (remove only)" +WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" "UninstallString" "$INSTDIR\Uninstall.exe" WriteUninstaller "$INSTDIR\Uninstall.exe" @@ -141,11 +141,11 @@ Section "Uninstall" RMDir /r "$INSTDIR\*.*" RMDir "$INSTDIR" -Delete "$DESKTOP\DVD-o-matic.lnk" -Delete "$DESKTOP\DVD-o-matic encode server.lnk" -Delete "$SMPROGRAMS\DVD-o-matic\*.*" -RmDir "$SMPROGRAMS\DVD-o-matic" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DVD-o-matic" -DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DVD-o-matic" +Delete "$DESKTOP\DCP-o-matic.lnk" +Delete "$DESKTOP\DCP-o-matic encode server.lnk" +Delete "$SMPROGRAMS\DCP-o-matic\*.*" +RmDir "$SMPROGRAMS\DCP-o-matic" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\DCP-o-matic" +DeleteRegKey HKEY_LOCAL_MACHINE "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\DCP-o-matic" SectionEnd diff --git a/wscript b/wscript index 502f27fd1..f784d760d 100644 --- a/wscript +++ b/wscript @@ -2,7 +2,7 @@ import subprocess import os import sys -APPNAME = 'dvdomatic' +APPNAME = 'dcpomatic' VERSION = '0.84pre' def options(opt): @@ -25,7 +25,7 @@ def configure(conf): '-Wall', '-Wno-attributes', '-Wextra']) if conf.options.target_windows: - conf.env.append_value('CXXFLAGS', ['-DDVDOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE']) + conf.env.append_value('CXXFLAGS', ['-DDCPOMATIC_WINDOWS', '-DWIN32_LEAN_AND_MEAN', '-DBOOST_USE_WINDOWS_H', '-DUNICODE']) wxrc = os.popen('wx-config --rescomp').read().split()[1:] conf.env.append_value('WINRCFLAGS', wxrc) if conf.options.enable_debug: @@ -35,9 +35,9 @@ def configure(conf): boost_lib_suffix = '-mt' boost_thread = 'boost_thread_win32-mt' else: - conf.env.append_value('CXXFLAGS', '-DDVDOMATIC_POSIX') + conf.env.append_value('CXXFLAGS', '-DDCPOMATIC_POSIX') conf.env.append_value('CXXFLAGS', '-DPOSIX_LOCALE_PREFIX="%s/share/locale"' % conf.env['PREFIX']) - conf.env.append_value('CXXFLAGS', '-DPOSIX_ICON_PREFIX="%s/share/dvdomatic"' % conf.env['PREFIX']) + conf.env.append_value('CXXFLAGS', '-DPOSIX_ICON_PREFIX="%s/share/dcpomatic"' % conf.env['PREFIX']) boost_lib_suffix = '' boost_thread = 'boost_thread' conf.env.append_value('LINKFLAGS', '-pthread') @@ -50,7 +50,7 @@ def configure(conf): conf.env.VERSION = VERSION if conf.options.enable_debug: - conf.env.append_value('CXXFLAGS', ['-g', '-DDVDOMATIC_DEBUG']) + conf.env.append_value('CXXFLAGS', ['-g', '-DDCPOMATIC_DEBUG']) else: conf.env.append_value('CXXFLAGS', '-O2') @@ -228,16 +228,16 @@ def build(bld): d = { 'PREFIX' : '${PREFIX' } obj = bld(features = 'subst') - obj.source = 'dvdomatic.desktop.in' - obj.target = 'dvdomatic.desktop' + obj.source = 'dcpomatic.desktop.in' + obj.target = 'dcpomatic.desktop' obj.dict = d - bld.install_files('${PREFIX}/share/applications', 'dvdomatic.desktop') + bld.install_files('${PREFIX}/share/applications', 'dcpomatic.desktop') for r in ['22x22', '32x32', '48x48', '64x64', '128x128']: - bld.install_files('${PREFIX}/share/icons/hicolor/%s/apps' % r, 'icons/%s/dvdomatic.png' % r) + bld.install_files('${PREFIX}/share/icons/hicolor/%s/apps' % r, 'icons/%s/dcpomatic.png' % r) if not bld.env.TARGET_WINDOWS: - bld.install_files('${PREFIX}/share/dvdomatic', 'icons/taskbar_icon.png') + bld.install_files('${PREFIX}/share/dcpomatic', 'icons/taskbar_icon.png') bld.add_post_fun(post) @@ -259,8 +259,8 @@ def create_version_cc(version): try: text = '#include "version.h"\n' - text += 'char const * dvdomatic_git_commit = \"%s\";\n' % commit - text += 'char const * dvdomatic_version = \"%s\";\n' % version + text += 'char const * dcpomatic_git_commit = \"%s\";\n' % commit + text += 'char const * dcpomatic_version = \"%s\";\n' % version print('Writing version information to src/lib/version.cc') o = open('src/lib/version.cc', 'w') o.write(text) -- cgit v1.2.3 From 7fb622a18582f18fcc6cfe140a262fd6cc8cad88 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 14 Apr 2013 00:48:27 +0100 Subject: Fix mapping of audio in DCP. --- src/lib/audio_mapping.cc | 2 +- src/lib/encoder.cc | 6 +++--- src/lib/player.cc | 31 ++++++++++++++++--------------- src/lib/player.h | 2 +- 4 files changed, 21 insertions(+), 20 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc index b85ea7314..2e8077565 100644 --- a/src/lib/audio_mapping.cc +++ b/src/lib/audio_mapping.cc @@ -41,7 +41,7 @@ int AudioMapping::dcp_channels () const { for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { - if (((int) i->second) > 2) { + if (((int) i->second) >= 2) { return 6; } } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index b897c8a31..d6a57ae6b 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -135,9 +135,9 @@ void Encoder::process_end () { #if HAVE_SWRESAMPLE - if (_film->has_audio() && _film->audio_channels() && _swr_context) { + if (_film->has_audio() && _swr_context) { - shared_ptr out (new AudioBuffers (_film->audio_channels(), 256)); + shared_ptr out (new AudioBuffers (_film->audio_mapping().dcp_channels(), 256)); while (1) { int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); @@ -312,7 +312,7 @@ Encoder::process_audio (shared_ptr data) /* Compute the resampled frames count and add 32 for luck */ int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_frame_rate()) + 32; - shared_ptr resampled (new AudioBuffers (_film->audio_channels(), max_resampled_frames)); + shared_ptr resampled (new AudioBuffers (_film->audio_mapping().dcp_channels(), max_resampled_frames)); /* Resample audio */ int const resampled_frames = swr_convert ( diff --git a/src/lib/player.cc b/src/lib/player.cc index 92c2929ac..c77059b0a 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -92,8 +92,8 @@ Player::pass () } } - Audio (_sndfile_buffers); - _sndfile_buffers.reset (); + Audio (_audio_buffers); + _audio_buffers.reset (); } return done; @@ -126,22 +126,23 @@ Player::process_video (shared_ptr i, bool same, shared_ptr s) void Player::process_audio (weak_ptr c, shared_ptr b) { - if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) { - AudioMapping mapping = _film->audio_mapping (); - if (!_sndfile_buffers) { - _sndfile_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ())); - _sndfile_buffers->make_silent (); - } + AudioMapping mapping = _film->audio_mapping (); + if (!_audio_buffers) { + _audio_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ())); + _audio_buffers->make_silent (); + } - for (int i = 0; i < b->channels(); ++i) { - list dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i)); - for (list::iterator j = dcp.begin(); j != dcp.end(); ++j) { - _sndfile_buffers->accumulate (b, i, static_cast (*j)); - } + for (int i = 0; i < b->channels(); ++i) { + list dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i)); + for (list::iterator j = dcp.begin(); j != dcp.end(); ++j) { + _audio_buffers->accumulate (b, i, static_cast (*j)); } + } - } else { - Audio (b); + if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) { + /* We can just emit this audio now as it will all be here */ + Audio (_audio_buffers); + _audio_buffers.reset (); } } diff --git a/src/lib/player.h b/src/lib/player.h index 8a82ab298..7a99d6561 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -70,7 +70,7 @@ private: std::list >::iterator _video_decoder; std::list > _sndfile_decoders; - boost::shared_ptr _sndfile_buffers; + boost::shared_ptr _audio_buffers; bool _video_sync; }; -- cgit v1.2.3 From a4a30d3a84998801fd6132da2d9ce789351c5a8e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 16 Apr 2013 12:28:15 +0100 Subject: Fix setup of resampler channel counts. --- src/lib/encoder.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 3201e6ecb..f56440dd7 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -93,13 +93,13 @@ Encoder::process_begin () decide if rematrixing is needed. It won't be, since input and output layouts are the same. */ - + _swr_context = swr_alloc_set_opts ( 0, - av_get_default_channel_layout (_film->audio_channels ()), + av_get_default_channel_layout (_film->audio_mapping().dcp_channels ()), AV_SAMPLE_FMT_FLTP, _film->target_audio_sample_rate(), - av_get_default_channel_layout (_film->audio_channels ()), + av_get_default_channel_layout (_film->audio_mapping().dcp_channels ()), AV_SAMPLE_FMT_FLTP, _film->audio_frame_rate(), 0, 0 -- cgit v1.2.3 From 8dd9ea3086b4934f2719648ffa6333c0d106ff36 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 01:02:25 +0100 Subject: Some const correctness. --- src/lib/analyse_audio_job.cc | 2 +- src/lib/analyse_audio_job.h | 2 +- src/lib/audio_sink.h | 4 +- src/lib/audio_source.h | 4 +- src/lib/combiner.cc | 6 +-- src/lib/combiner.h | 4 +- src/lib/delay_line.cc | 4 +- src/lib/delay_line.h | 4 +- src/lib/encoder.cc | 4 +- src/lib/encoder.h | 4 +- src/lib/gain.cc | 2 +- src/lib/gain.h | 2 +- src/lib/image.cc | 6 +++ src/lib/image.h | 6 +++ src/lib/matcher.cc | 9 +++-- src/lib/matcher.h | 10 ++--- src/lib/trimmer.cc | 10 +++-- src/lib/trimmer.h | 4 +- src/lib/util.cc | 90 +++++++++++++++++++++++++++++--------------- src/lib/util.h | 1 + src/lib/video_sink.h | 4 +- src/lib/video_source.h | 4 +- src/tools/servomatictest.cc | 2 +- src/wx/film_viewer.cc | 4 +- src/wx/film_viewer.h | 6 +-- test/test.cc | 8 ++-- 26 files changed, 125 insertions(+), 81 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 43eecbcbd..88cd65fee 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -84,7 +84,7 @@ AnalyseAudioJob::run () } void -AnalyseAudioJob::audio (shared_ptr b) +AnalyseAudioJob::audio (shared_ptr b) { for (int i = 0; i < b->frames(); ++i) { for (int j = 0; j < b->channels(); ++j) { diff --git a/src/lib/analyse_audio_job.h b/src/lib/analyse_audio_job.h index dc1e073ee..5435e0a7c 100644 --- a/src/lib/analyse_audio_job.h +++ b/src/lib/analyse_audio_job.h @@ -31,7 +31,7 @@ public: void run (); private: - void audio (boost::shared_ptr); + void audio (boost::shared_ptr); int64_t _done; int64_t _samples_per_point; diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index f34b24f88..69b3a4b75 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -24,14 +24,14 @@ class AudioSink { public: /** Call with some audio data */ - virtual void process_audio (boost::shared_ptr) = 0; + virtual void process_audio (boost::shared_ptr) = 0; }; class TimedAudioSink { public: /** Call with some audio data */ - virtual void process_audio (boost::shared_ptr, double t) = 0; + virtual void process_audio (boost::shared_ptr, double t) = 0; }; #endif diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index e255d566d..c13f1636b 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -35,7 +35,7 @@ class AudioSource { public: /** Emitted when some audio data is ready */ - boost::signals2::signal)> Audio; + boost::signals2::signal)> Audio; void connect_audio (boost::shared_ptr); }; @@ -46,7 +46,7 @@ class TimedAudioSource { public: /** Emitted when some audio data is ready */ - boost::signals2::signal, double)> Audio; + boost::signals2::signal, double)> Audio; void connect_audio (boost::shared_ptr); void connect_audio (boost::shared_ptr); diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 0a9eaf6b6..250528aeb 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -33,9 +33,9 @@ Combiner::Combiner (shared_ptr log) * @param image Frame image. */ void -Combiner::process_video (shared_ptr image, bool, shared_ptr, double) +Combiner::process_video (shared_ptr image, bool, shared_ptr, double) { - _image = image; + _image = image->clone (); } /** Process video for the right half of the frame. @@ -43,7 +43,7 @@ Combiner::process_video (shared_ptr image, bool, shared_ptr, do * @param sub Subtitle (which will be put onto the whole frame) */ void -Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, double t) +Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, double t) { /* Copy the right half of this image into our _image */ /* XXX: this should probably be in the Image class */ diff --git a/src/lib/combiner.h b/src/lib/combiner.h index a8f1fa804..7ed316e26 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -33,8 +33,8 @@ class Combiner : public TimedVideoProcessor public: Combiner (boost::shared_ptr log); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); - void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, double); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); + void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, double); private: /** The image that we are currently working on */ diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index 9e6baeba8..b0180800a 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -37,7 +37,7 @@ DelayLine::DelayLine (shared_ptr log, double seconds) } void -DelayLine::process_audio (shared_ptr data, double t) +DelayLine::process_audio (shared_ptr data, double t) { if (_seconds > 0) { t += _seconds; @@ -47,7 +47,7 @@ DelayLine::process_audio (shared_ptr data, double t) } void -DelayLine::process_video (boost::shared_ptr image, bool same, boost::shared_ptr sub, double t) +DelayLine::process_video (shared_ptr image, bool same, boost::shared_ptr sub, double t) { if (_seconds < 0) { t += _seconds; diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 90f1dcfa7..781dce88a 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -26,8 +26,8 @@ class DelayLine : public TimedAudioVideoProcessor public: DelayLine (boost::shared_ptr log, double); - void process_video (boost::shared_ptr, bool, boost::shared_ptr, double); - void process_audio (boost::shared_ptr, double); + void process_video (boost::shared_ptr, bool, boost::shared_ptr, double); + void process_audio (boost::shared_ptr, double); private: double _seconds; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 7b338407e..7a1eea069 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -231,7 +231,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) +Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); @@ -294,7 +294,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr data) +Encoder::process_audio (shared_ptr data) { #if HAVE_SWRESAMPLE /* Maybe sample-rate convert */ diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 86880bc34..70e81a7e0 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -73,10 +73,10 @@ public: * @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 i, bool same, boost::shared_ptr s); + void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); /** Call with some audio data */ - void process_audio (boost::shared_ptr); + void process_audio (boost::shared_ptr); /** Called when a processing run has finished */ virtual void process_end (); diff --git a/src/lib/gain.cc b/src/lib/gain.cc index df7011d2e..ccd779d71 100644 --- a/src/lib/gain.cc +++ b/src/lib/gain.cc @@ -30,7 +30,7 @@ Gain::Gain (shared_ptr log, float gain) } void -Gain::process_audio (shared_ptr b) +Gain::process_audio (shared_ptr b) { if (_gain != 0) { float const linear_gain = pow (10, _gain / 20); diff --git a/src/lib/gain.h b/src/lib/gain.h index d462e5aee..61fef5e85 100644 --- a/src/lib/gain.h +++ b/src/lib/gain.h @@ -24,7 +24,7 @@ class Gain : public AudioProcessor public: Gain (boost::shared_ptr log, float gain); - void process_audio (boost::shared_ptr); + void process_audio (boost::shared_ptr); private: float _gain; diff --git a/src/lib/image.cc b/src/lib/image.cc index 2355d22e5..9bcbb87ab 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -583,6 +583,12 @@ SimpleImage::aligned () const return _aligned; } +shared_ptr +SimpleImage::clone () const +{ + return shared_ptr (new SimpleImage (*this)); +} + FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b) : Image (p) , _buffer (b) diff --git a/src/lib/image.h b/src/lib/image.h index 6b9ade99e..31035d272 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -70,6 +70,8 @@ public: virtual bool aligned () const = 0; + virtual boost::shared_ptr clone () const = 0; + int components () const; int lines (int) const; @@ -118,6 +120,9 @@ private: /* Not allowed */ FilterBufferImage (FilterBufferImage const &); FilterBufferImage& operator= (FilterBufferImage const &); + boost::shared_ptr clone () const { + assert (false); + } AVFilterBufferRef* _buffer; int* _line_size; @@ -139,6 +144,7 @@ public: int * stride () const; libdcp::Size size () const; bool aligned () const; + boost::shared_ptr clone () const; protected: void allocate (); diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index dd0312f67..9924c003a 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -41,7 +41,7 @@ Matcher::Matcher (shared_ptr log, int sample_rate, float frames_per_second) } void -Matcher::process_video (boost::shared_ptr image, bool same, boost::shared_ptr sub, double t) +Matcher::process_video (boost::shared_ptr image, bool same, boost::shared_ptr sub, double t) { _pixel_format = image->pixel_format (); _size = image->size (); @@ -90,7 +90,7 @@ Matcher::process_video (boost::shared_ptr image, bool same, boost::shared } void -Matcher::process_audio (boost::shared_ptr b, double t) +Matcher::process_audio (boost::shared_ptr b, double t) { _channels = b->channels (); @@ -202,8 +202,9 @@ void Matcher::repeat_last_video () { if (!_last_image) { - _last_image.reset (new SimpleImage (_pixel_format.get(), _size.get(), true)); - _last_image->make_black (); + shared_ptr im (new SimpleImage (_pixel_format.get(), _size.get(), true)); + im->make_black (); + _last_image = im; } Video (_last_image, true, _last_subtitle); diff --git a/src/lib/matcher.h b/src/lib/matcher.h index f54aa4b6a..41aa373a4 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -25,8 +25,8 @@ class Matcher : public Processor, public TimedAudioSink, public TimedVideoSink, { public: Matcher (boost::shared_ptr log, int sample_rate, float frames_per_second); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); - void process_audio (boost::shared_ptr, double); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); + void process_audio (boost::shared_ptr, double); void process_end (); private: @@ -43,19 +43,19 @@ private: boost::optional _channels; struct AudioRecord { - AudioRecord (boost::shared_ptr a, double t) + AudioRecord (boost::shared_ptr a, double t) : audio (a) , time (t) {} - boost::shared_ptr audio; + boost::shared_ptr audio; double time; }; std::list _pending_audio; boost::optional _first_input; - boost::shared_ptr _last_image; + boost::shared_ptr _last_image; boost::shared_ptr _last_subtitle; bool _had_first_video; diff --git a/src/lib/trimmer.cc b/src/lib/trimmer.cc index 68364e50a..39ec44fcb 100644 --- a/src/lib/trimmer.cc +++ b/src/lib/trimmer.cc @@ -56,7 +56,7 @@ Trimmer::Trimmer ( } void -Trimmer::process_video (shared_ptr image, bool same, shared_ptr sub) +Trimmer::process_video (shared_ptr image, bool same, shared_ptr sub) { if (_video_in >= _video_start && _video_in <= _video_end) { Video (image, same, sub); @@ -66,7 +66,7 @@ Trimmer::process_video (shared_ptr image, bool same, shared_ptr } void -Trimmer::process_audio (shared_ptr audio) +Trimmer::process_audio (shared_ptr audio) { int64_t offset = _audio_start - _audio_in; if (offset > audio->frames()) { @@ -91,8 +91,10 @@ Trimmer::process_audio (shared_ptr audio) _audio_in += audio->frames (); if (offset != 0 || length != audio->frames ()) { - audio->move (offset, 0, length); - audio->set_frames (length); + shared_ptr copy (new AudioBuffers (audio)); + copy->move (offset, 0, length); + copy->set_frames (length); + audio = copy; } Audio (audio); diff --git a/src/lib/trimmer.h b/src/lib/trimmer.h index ff7e9514d..45b3f149a 100644 --- a/src/lib/trimmer.h +++ b/src/lib/trimmer.h @@ -24,8 +24,8 @@ class Trimmer : public AudioVideoProcessor public: Trimmer (boost::shared_ptr, int, int, int, int, float, int); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); - void process_audio (boost::shared_ptr); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); + void process_audio (boost::shared_ptr); private: friend class trimmer_test; diff --git a/src/lib/util.cc b/src/lib/util.cc index e43b598ab..859aa6de7 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -63,11 +63,24 @@ extern "C" { #include "i18n.h" -using namespace std; -using namespace boost; +using std::cout; +using std::string; +using std::stringstream; +using std::list; +using std::ostream; +using std::vector; +using std::ifstream; +using std::istream; +using std::min; +using std::max; +using std::multimap; +using std::pair; +using boost::shared_ptr; +using boost::lexical_cast; +using boost::optional; using libdcp::Size; -thread::id ui_thread; +boost::thread::id ui_thread; /** Convert some number of seconds to a string representation * in hours, minutes and seconds. @@ -87,9 +100,9 @@ seconds_to_hms (int s) stringstream hms; hms << h << N_(":"); hms.width (2); - hms << setfill ('0') << m << N_(":"); + hms << std::setfill ('0') << m << N_(":"); hms.width (2); - hms << setfill ('0') << s; + hms << std::setfill ('0') << s; return hms.str (); } @@ -185,7 +198,7 @@ stacktrace (ostream& out, int levels) if (strings) { for (i = 0; i < size && (levels == 0 || i < size_t(levels)); i++) { - out << N_(" ") << demangle (strings[i]) << endl; + out << N_(" ") << demangle (strings[i]) << "\n"; } free (strings); @@ -243,7 +256,7 @@ dvdomatic_setup () Filter::setup_filters (); SoundProcessor::setup_sound_processors (); - ui_thread = this_thread::get_id (); + ui_thread = boost::this_thread::get_id (); } #ifdef DVDOMATIC_WINDOWS @@ -338,7 +351,7 @@ md5_digest (void const * data, int size) stringstream s; for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { - s << hex << setfill('0') << setw(2) << ((int) digest[i]); + s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]); } return s.str (); @@ -350,14 +363,14 @@ md5_digest (void const * data, int size) string md5_digest (string file) { - ifstream f (file.c_str(), ios::binary); + ifstream f (file.c_str(), std::ios::binary); if (!f.good ()) { throw OpenFileError (file); } - f.seekg (0, ios::end); + f.seekg (0, std::ios::end); int bytes = f.tellg (); - f.seekg (0, ios::beg); + f.seekg (0, std::ios::beg); int const buffer_size = 64 * 1024; char buffer[buffer_size]; @@ -376,7 +389,7 @@ md5_digest (string file) stringstream s; for (int i = 0; i < MD5_DIGEST_LENGTH; ++i) { - s << hex << setfill('0') << setw(2) << ((int) digest[i]); + s << std::hex << std::setfill('0') << std::setw(2) << ((int) digest[i]); } return s.str (); @@ -441,8 +454,8 @@ best_dcp_frame_rate (float source_fps) } /* Pick the best one, bailing early if we hit an exact match */ - float error = numeric_limits::max (); - boost::optional best; + float error = std::numeric_limits::max (); + optional best; list::iterator i = candidates.begin(); while (i != candidates.end()) { @@ -509,16 +522,16 @@ Socket::Socket (int timeout) , _socket (_io_service) , _timeout (timeout) { - _deadline.expires_at (posix_time::pos_infin); + _deadline.expires_at (boost::posix_time::pos_infin); check (); } void Socket::check () { - if (_deadline.expires_at() <= asio::deadline_timer::traits_type::now ()) { + if (_deadline.expires_at() <= boost::asio::deadline_timer::traits_type::now ()) { _socket.close (); - _deadline.expires_at (posix_time::pos_infin); + _deadline.expires_at (boost::posix_time::pos_infin); } _deadline.async_wait (boost::bind (&Socket::check, this)); @@ -528,14 +541,14 @@ Socket::check () * @param endpoint End-point to connect to. */ void -Socket::connect (asio::ip::basic_resolver_entry const & endpoint) +Socket::connect (boost::asio::ip::basic_resolver_entry const & endpoint) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; - _socket.async_connect (endpoint, lambda::var(ec) = lambda::_1); + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; + _socket.async_connect (endpoint, boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one(); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec || !_socket.is_open ()) { throw NetworkError (_("connect timed out")); @@ -549,14 +562,14 @@ Socket::connect (asio::ip::basic_resolver_entry const & endpoint) void Socket::write (uint8_t const * data, int size) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; - asio::async_write (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + boost::asio::async_write (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one (); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec) { throw NetworkError (ec.message ()); @@ -577,14 +590,14 @@ Socket::write (uint32_t v) void Socket::read (uint8_t* data, int size) { - _deadline.expires_from_now (posix_time::seconds (_timeout)); - system::error_code ec = asio::error::would_block; + _deadline.expires_from_now (boost::posix_time::seconds (_timeout)); + boost::system::error_code ec = boost::asio::error::would_block; - asio::async_read (_socket, asio::buffer (data, size), lambda::var(ec) = lambda::_1); + boost::asio::async_read (_socket, boost::asio::buffer (data, size), boost::lambda::var(ec) = boost::lambda::_1); do { _io_service.run_one (); - } while (ec == asio::error::would_block); + } while (ec == boost::asio::error::would_block); if (ec) { throw NetworkError (ec.message ()); @@ -761,6 +774,21 @@ AudioBuffers::AudioBuffers (AudioBuffers const & other) } } +/* XXX: it's a shame that this is a copy-and-paste of the above; + probably fixable with c++0x. +*/ +AudioBuffers::AudioBuffers (boost::shared_ptr other) + : _channels (other->_channels) + , _frames (other->_frames) + , _allocated_frames (other->_frames) +{ + _data = new float*[_channels]; + for (int i = 0; i < _channels; ++i) { + _data[i] = new float[_frames]; + memcpy (_data[i], other->_data[i], _frames * sizeof (float)); + } +} + /** AudioBuffers destructor */ AudioBuffers::~AudioBuffers () { @@ -865,7 +893,7 @@ AudioBuffers::move (int from, int to, int frames) void ensure_ui_thread () { - assert (this_thread::get_id() == ui_thread); + assert (boost::this_thread::get_id() == ui_thread); } /** @param v Source video frame. diff --git a/src/lib/util.h b/src/lib/util.h index 31d0fc967..99670110e 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -241,6 +241,7 @@ class AudioBuffers public: AudioBuffers (int channels, int frames); AudioBuffers (AudioBuffers const &); + AudioBuffers (boost::shared_ptr); ~AudioBuffers (); float** data () const { diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 32c7f3b38..0170c7350 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -34,7 +34,7 @@ public: * @param same true if i is the same as last time we were called. * @param s A subtitle that should be on this frame, or 0. */ - virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) = 0; + virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) = 0; }; class TimedVideoSink @@ -46,7 +46,7 @@ public: * @param s A subtitle that should be on this frame, or 0. * @param t Source timestamp. */ - virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double t) = 0; + virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double t) = 0; }; #endif diff --git a/src/lib/video_source.h b/src/lib/video_source.h index e4a8ab058..748cb6fe9 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -45,7 +45,7 @@ public: * Second parameter is true if the image is the same as the last one that was emitted. * Third parameter is either 0 or a subtitle that should be on this frame. */ - boost::signals2::signal, bool, boost::shared_ptr)> Video; + boost::signals2::signal, bool, boost::shared_ptr)> Video; void connect_video (boost::shared_ptr); }; @@ -63,7 +63,7 @@ public: * Third parameter is either 0 or a subtitle that should be on this frame. * Fourth parameter is the source timestamp of this frame. */ - boost::signals2::signal, bool, boost::shared_ptr, double)> Video; + boost::signals2::signal, bool, boost::shared_ptr, double)> Video; void connect_video (boost::shared_ptr); void connect_video (boost::shared_ptr); diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index f5756c693..5e1cf49b4 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -47,7 +47,7 @@ static shared_ptr log_ (new FileLog ("servomatictest.log")); static int frame = 0; void -process_video (shared_ptr image, bool, shared_ptr sub) +process_video (shared_ptr image, bool, shared_ptr sub) { shared_ptr local ( new DCPVideoFrame ( diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 8508ec2a2..4f2985a06 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -308,7 +308,7 @@ FilmViewer::raw_to_display () return; } - boost::shared_ptr input = _raw_frame; + boost::shared_ptr input = _raw_frame; pair const s = Filter::ffmpeg_strings (_film->filters()); if (!s.second.empty ()) { @@ -400,7 +400,7 @@ FilmViewer::check_play_state () } void -FilmViewer::process_video (shared_ptr image, bool, shared_ptr sub, double t) +FilmViewer::process_video (shared_ptr image, bool, shared_ptr sub, double t) { _raw_frame = image; _raw_sub = sub; diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index a78c772a4..ed5874fbc 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -48,7 +48,7 @@ private: void slider_moved (wxScrollEvent &); void play_clicked (wxCommandEvent &); void timer (wxTimerEvent &); - void process_video (boost::shared_ptr, bool, boost::shared_ptr, double); + void process_video (boost::shared_ptr, bool, boost::shared_ptr, double); void calculate_sizes (); void check_play_state (); void update_from_raw (); @@ -72,9 +72,9 @@ private: wxTimer _timer; Decoders _decoders; - boost::shared_ptr _raw_frame; + boost::shared_ptr _raw_frame; boost::shared_ptr _raw_sub; - boost::shared_ptr _display_frame; + boost::shared_ptr _display_frame; /* The x offset at which we display the actual film content; this corresponds to the film's padding converted to our coordinates. */ diff --git a/test/test.cc b/test/test.cc index 595d8fc93..496c91519 100644 --- a/test/test.cc +++ b/test/test.cc @@ -123,17 +123,17 @@ BOOST_AUTO_TEST_CASE (make_black_test) } } -shared_ptr trimmer_test_last_video; -shared_ptr trimmer_test_last_audio; +shared_ptr trimmer_test_last_video; +shared_ptr trimmer_test_last_audio; void -trimmer_test_video_helper (shared_ptr image, bool, shared_ptr) +trimmer_test_video_helper (shared_ptr image, bool, shared_ptr) { trimmer_test_last_video = image; } void -trimmer_test_audio_helper (shared_ptr audio) +trimmer_test_audio_helper (shared_ptr audio) { trimmer_test_last_audio = audio; } -- cgit v1.2.3 From 7b2ec1dd69951649f2c912fcf90b22913b1f6c3a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 25 Apr 2013 13:44:02 +0100 Subject: Remove Image::clone in favour of a copy constructor for SimpleImage; clean up A/B transcoder slightly; fix combiner if image strides differ; try to fix problems when destroying Encoders; fix SimpleImage copy constructor to cope with aligned images; don't call encoder::process_end if the encode throws an exception. --- src/lib/ab_transcoder.cc | 14 +++++--------- src/lib/combiner.cc | 7 +++---- src/lib/encoder.cc | 4 +++- src/lib/image.cc | 34 +++++++++++++++++++++++++++------- src/lib/image.h | 7 +------ src/lib/transcoder.cc | 37 ++++++++++++++++--------------------- 6 files changed, 55 insertions(+), 48 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 26643b50e..d8f13dae4 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -122,25 +122,21 @@ ABTranscoder::go () } else { done[2] = true; } - + if (_job) { _da.video->set_progress (_job); } - + if (done[0] && done[1] && done[2]) { break; } } - - if (_delay_line) { - _delay_line->process_end (); - } + + _delay_line->process_end (); if (_matcher) { _matcher->process_end (); } - if (_gain) { - _gain->process_end (); - } + _gain->process_end (); _encoder->process_end (); } diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 250528aeb..367cefa7f 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -35,7 +35,7 @@ Combiner::Combiner (shared_ptr log) void Combiner::process_video (shared_ptr image, bool, shared_ptr, double) { - _image = image->clone (); + _image.reset (new SimpleImage (image)); } /** Process video for the right half of the frame. @@ -50,15 +50,14 @@ Combiner::process_video_b (shared_ptr image, bool, shared_ptrcomponents(); ++i) { int const line_size = image->line_size()[i]; int const half_line_size = line_size / 2; - int const stride = image->stride()[i]; uint8_t* p = _image->data()[i]; uint8_t* q = image->data()[i]; for (int j = 0; j < image->lines (i); ++j) { memcpy (p + half_line_size, q + half_line_size, half_line_size); - p += stride; - q += stride; + p += _image->stride()[i]; + q += image->stride()[i]; } } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 7a1eea069..cff9899ac 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -333,7 +333,9 @@ Encoder::terminate_threads () lock.unlock (); for (list::iterator i = _threads.begin(); i != _threads.end(); ++i) { - (*i)->join (); + if ((*i)->joinable ()) { + (*i)->join (); + } delete *i; } } diff --git a/src/lib/image.cc b/src/lib/image.cc index 9bcbb87ab..1be41fecf 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -509,7 +509,33 @@ SimpleImage::SimpleImage (SimpleImage const & other) allocate (); for (int i = 0; i < components(); ++i) { - memcpy (_data[i], other._data[i], _line_size[i] * lines(i)); + uint8_t* p = _data[i]; + uint8_t* q = other._data[i]; + for (int j = 0; j < lines(i); ++j) { + memcpy (p, q, _line_size[i]); + p += stride()[i]; + q += other.stride()[i]; + } + } +} + +SimpleImage::SimpleImage (shared_ptr other) + : Image (*other.get()) +{ + _size = other->size (); + _aligned = true; + + allocate (); + + for (int i = 0; i < components(); ++i) { + assert(line_size()[i] == other->line_size()[i]); + uint8_t* p = _data[i]; + uint8_t* q = other->data()[i]; + for (int j = 0; j < lines(i); ++j) { + memcpy (p, q, line_size()[i]); + p += stride()[i]; + q += other->stride()[i]; + } } } @@ -583,12 +609,6 @@ SimpleImage::aligned () const return _aligned; } -shared_ptr -SimpleImage::clone () const -{ - return shared_ptr (new SimpleImage (*this)); -} - FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b) : Image (p) , _buffer (b) diff --git a/src/lib/image.h b/src/lib/image.h index 31035d272..62961a92e 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -70,8 +70,6 @@ public: virtual bool aligned () const = 0; - virtual boost::shared_ptr clone () const = 0; - int components () const; int lines (int) const; @@ -120,9 +118,6 @@ private: /* Not allowed */ FilterBufferImage (FilterBufferImage const &); FilterBufferImage& operator= (FilterBufferImage const &); - boost::shared_ptr clone () const { - assert (false); - } AVFilterBufferRef* _buffer; int* _line_size; @@ -136,6 +131,7 @@ class SimpleImage : public Image public: SimpleImage (AVPixelFormat, libdcp::Size, bool); SimpleImage (SimpleImage const &); + SimpleImage (boost::shared_ptr); SimpleImage& operator= (SimpleImage const &); ~SimpleImage (); @@ -144,7 +140,6 @@ public: int * stride () const; libdcp::Size size () const; bool aligned () const; - boost::shared_ptr clone () const; protected: void allocate (); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 4d3f29e83..faafcaf8b 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -103,31 +103,26 @@ void Transcoder::go () { _encoder->process_begin (); - try { - bool done[2] = { false, false }; - - while (1) { - if (!done[0]) { - done[0] = _decoders.video->pass (); - if (_job) { - _decoders.video->set_progress (_job); - } - } - - if (!done[1] && _decoders.audio && dynamic_pointer_cast (_decoders.audio) != dynamic_pointer_cast (_decoders.video)) { - done[1] = _decoders.audio->pass (); - } else { - done[1] = true; - } - if (done[0] && done[1]) { - break; + bool done[2] = { false, false }; + + while (1) { + if (!done[0]) { + done[0] = _decoders.video->pass (); + if (_job) { + _decoders.video->set_progress (_job); } } - } catch (...) { - _encoder->process_end (); - throw; + if (!done[1] && _decoders.audio && dynamic_pointer_cast (_decoders.audio) != dynamic_pointer_cast (_decoders.video)) { + done[1] = _decoders.audio->pass (); + } else { + done[1] = true; + } + + if (done[0] && done[1]) { + break; + } } _delay_line->process_end (); -- cgit v1.2.3 From 83742c7e6edcf958e0820abc77c029f4ada4880f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 8 May 2013 16:58:19 +0100 Subject: Better fix for still (no sound) DCP crash. --- src/lib/encoder.cc | 4 ++++ src/lib/sndfile_decoder.cc | 6 ------ src/lib/transcoder.cc | 2 +- 3 files changed, 5 insertions(+), 7 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index cff9899ac..8549962ff 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -296,6 +296,10 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ void Encoder::process_audio (shared_ptr data) { + if (!data->frames ()) { + return; + } + #if HAVE_SWRESAMPLE /* Maybe sample-rate convert */ if (_swr_context) { diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index d70478a1b..fdaf2eeaa 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -102,20 +102,14 @@ SndfileDecoder::pass () sf_count_t const block = _audio_stream->sample_rate() / 2; shared_ptr audio (new AudioBuffers (_audio_stream->channels(), block)); sf_count_t const this_time = min (block, _frames - _done); - bool have_sound = false; for (size_t i = 0; i < _sndfiles.size(); ++i) { if (!_sndfiles[i]) { audio->make_silent (i); } else { sf_read_float (_sndfiles[i], audio->data(i), this_time); - have_sound = true; } } - if (!have_sound) { - return true; - } - audio->set_frames (this_time); Audio (audio, double(_done) / _audio_stream->sample_rate()); _done += this_time; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index faafcaf8b..48cf402d7 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -56,7 +56,7 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< assert (_encoder); shared_ptr st = f->audio_stream(); - if (st) { + if (st && st->sample_rate ()) { _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate())); } _delay_line.reset (new DelayLine (f->log(), f->audio_delay() / 1000.0f)); -- cgit v1.2.3 From fd040c2bd27fde35424a384174ecb56c643764cd Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 8 May 2013 20:37:53 +0100 Subject: Some tidying up. Do encode progress in the writer to improve progress bar movement with still-image DCPs (#130). --- src/lib/ab_transcoder.cc | 41 +++++++++++++---------------------------- src/lib/ab_transcoder.h | 2 -- src/lib/encoder.cc | 5 +++-- src/lib/encoder.h | 8 +++++--- src/lib/player.cc | 12 ------------ src/lib/player.h | 1 - src/lib/transcoder.cc | 11 ++++------- src/lib/transcoder.h | 4 +++- src/lib/writer.cc | 8 +++++++- src/lib/writer.h | 4 +++- 10 files changed, 38 insertions(+), 58 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 2e0d41e7d..f75491dce 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -47,27 +47,25 @@ using boost::dynamic_pointer_cast; * @param e Encoder to use. */ -ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptr j) - : _film_a (a) - , _film_b (b) - , _player_a (_film_a->player ()) - , _player_b (_film_b->player ()) +ABTranscoder::ABTranscoder (shared_ptr film_a, shared_ptr film_b, shared_ptr j) + : _player_a (film_a->player ()) + , _player_b (film_b->player ()) , _job (j) - , _encoder (new Encoder (_film_a)) - , _combiner (new Combiner (a->log())) + , _encoder (new Encoder (film_a, j)) + , _combiner (new Combiner (film_a->log())) { - _matcher.reset (new Matcher (_film_a->log(), _film_a->audio_frame_rate(), _film_a->video_frame_rate())); - _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_delay() * _film_a->audio_frame_rate() / 1000)); - _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); + _matcher.reset (new Matcher (film_a->log(), film_a->audio_frame_rate(), film_a->video_frame_rate())); + _delay_line.reset (new DelayLine (film_a->log(), film_a->audio_delay() * film_a->audio_frame_rate() / 1000)); + _gain.reset (new Gain (film_a->log(), film_a->audio_gain())); _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); - int const trim_start = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_start() : 0; - int const trim_end = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_end() : 0; + int const trim_start = film_a->trim_type() == Film::ENCODE ? film_a->trim_start() : 0; + int const trim_end = film_a->trim_type() == Film::ENCODE ? film_a->trim_end() : 0; _trimmer.reset (new Trimmer ( - _film_a->log(), trim_start, trim_end, _film_a->content_length(), - _film_a->audio_frame_rate(), _film_a->video_frame_rate(), _film_a->dcp_frame_rate() + film_a->log(), trim_start, trim_end, film_a->content_length(), + film_a->audio_frame_rate(), film_a->video_frame_rate(), film_a->dcp_frame_rate() )); @@ -88,20 +86,7 @@ ABTranscoder::go () { _encoder->process_begin (); - bool done[2] = { false, false }; - - while (1) { - done[0] = _player_a->pass (); - done[1] = _player_b->pass (); - - if (_job) { - _player_a->set_progress (_job); - } - - if (done[0] && done[1]) { - break; - } - } + while (!_player_a->pass () || !_player_b->pass ()) {} _delay_line->process_end (); _matcher->process_end (); diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 1fef66b88..134bce3e4 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -54,8 +54,6 @@ public: void go (); private: - boost::shared_ptr _film_a; - boost::shared_ptr _film_b; boost::shared_ptr _player_a; boost::shared_ptr _player_b; boost::shared_ptr _job; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c1d1041ae..d25e0d0f8 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -55,8 +55,9 @@ using boost::optional; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f) +Encoder::Encoder (shared_ptr f, shared_ptr j) : _film (f) + , _job (j) , _video_frames_in (0) , _video_frames_out (0) #ifdef HAVE_SWRESAMPLE @@ -127,7 +128,7 @@ Encoder::process_begin () } } - _writer.reset (new Writer (_film)); + _writer.reset (new Writer (_film, _job)); } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index f95d42661..6cf5540c5 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -51,6 +51,7 @@ class ServerDescription; class DCPVideoFrame; class EncodedData; class Writer; +class Job; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -62,11 +63,11 @@ class Writer; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f); + Encoder (boost::shared_ptr f, boost::shared_ptr); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ - virtual void process_begin (); + void process_begin (); /** Call with a frame of video. * @param i Video frame image. @@ -79,7 +80,7 @@ public: void process_audio (boost::shared_ptr); /** Called when a processing run has finished */ - virtual void process_end (); + void process_end (); float current_encoding_rate () const; int video_frames_out () const; @@ -93,6 +94,7 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; + boost::shared_ptr _job; /** Mutex for _time_history and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/player.cc b/src/lib/player.cc index 68a962cdd..95036cfe0 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -121,18 +121,6 @@ Player::pass () return done; } -void -Player::set_progress (shared_ptr job) -{ - /* Assume progress can be divined from how far through the video we are */ - - if (_video_decoder >= _video_decoders.size() || !_playlist->video_length()) { - return; - } - - job->set_progress ((_video_start[_video_decoder] + _video_decoders[_video_decoder]->video_frame()) / _playlist->video_length ()); -} - void Player::process_video (shared_ptr i, bool same, shared_ptr s, double t) { diff --git a/src/lib/player.h b/src/lib/player.h index 20b83bfdb..b6fb41f6e 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -49,7 +49,6 @@ public: void disable_subtitles (); bool pass (); - void set_progress (boost::shared_ptr); bool seek (double); void seek_back (); void seek_forward (); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 2e33931bd..f8fe0c8d5 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -36,6 +36,7 @@ #include "audio_decoder.h" #include "player.h" #include "trimmer.h" +#include "job.h" using std::string; using boost::shared_ptr; @@ -49,7 +50,7 @@ using boost::dynamic_pointer_cast; Transcoder::Transcoder (shared_ptr f, shared_ptr j) : _job (j) , _player (f->player ()) - , _encoder (new Encoder (f)) + , _encoder (new Encoder (f, j)) { _matcher.reset (new Matcher (f->log(), f->audio_frame_rate(), f->video_frame_rate())); _delay_line.reset (new DelayLine (f->log(), f->audio_delay() * f->audio_frame_rate() / 1000)); @@ -82,13 +83,9 @@ void Transcoder::go () { _encoder->process_begin (); - while (1) { - if (_player->pass ()) { - break; - } - _player->set_progress (_job); - } + while (!_player->pass ()) {} + _delay_line->process_end (); if (_matcher) { _matcher->process_end (); diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 97ecaabfc..48b453fe4 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -17,6 +17,8 @@ */ +#include "types.h" + /** @file src/transcoder.h * * A decoder is selected according to the content type, and the encoder can be specified @@ -51,7 +53,7 @@ public: float current_encoding_rate () const; int video_frames_out () const; -protected: +private: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; boost::shared_ptr _player; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index b545848cb..c7d2cf8b4 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -34,6 +34,7 @@ #include "player.h" #include "audio_mapping.h" #include "config.h" +#include "job.h" #include "i18n.h" @@ -47,8 +48,9 @@ using boost::shared_ptr; int const Writer::_maximum_frames_in_memory = 8; -Writer::Writer (shared_ptr f) +Writer::Writer (shared_ptr f, shared_ptr j) : _film (f) + , _job (j) , _first_nonexistant_frame (0) , _thread (0) , _finish (false) @@ -202,6 +204,10 @@ try } } lock.lock (); + + if (_film->video_length ()) { + _job->set_progress (float(_full_written + _fake_written + _repeat_written) / _film->video_length()); + } ++_last_written_frame; } diff --git a/src/lib/writer.h b/src/lib/writer.h index beb16c7b9..62714edf3 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -26,6 +26,7 @@ class Film; class EncodedData; class AudioBuffers; +class Job; namespace libdcp { class MonoPictureAsset; @@ -63,7 +64,7 @@ bool operator== (QueueItem const & a, QueueItem const & b); class Writer : public ExceptionStore { public: - Writer (boost::shared_ptr); + Writer (boost::shared_ptr, boost::shared_ptr); bool can_fake_write (int) const; @@ -80,6 +81,7 @@ private: /** our Film */ boost::shared_ptr _film; + boost::shared_ptr _job; /** the first frame index that does not already exist in our MXF */ int _first_nonexistant_frame; -- cgit v1.2.3 From 76052960d07a611889967f5927e2adb0d867ea07 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 10 May 2013 21:55:06 +0100 Subject: Make libswresample mandatory. --- src/lib/encoder.cc | 12 ------------ src/lib/encoder.h | 6 ------ src/wx/film_editor.cc | 2 -- wscript | 10 +++------- 4 files changed, 3 insertions(+), 27 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index d25e0d0f8..8e0d1cd91 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -60,9 +60,7 @@ Encoder::Encoder (shared_ptr f, shared_ptr j) , _job (j) , _video_frames_in (0) , _video_frames_out (0) -#ifdef HAVE_SWRESAMPLE , _swr_context (0) -#endif , _have_a_real_frame (false) , _terminate (false) { @@ -81,7 +79,6 @@ void Encoder::process_begin () { if (_film->has_audio() && _film->audio_frame_rate() != _film->target_audio_sample_rate()) { -#ifdef HAVE_SWRESAMPLE stringstream s; s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_frame_rate(), _film->target_audio_sample_rate()); @@ -107,13 +104,8 @@ Encoder::process_begin () ); swr_init (_swr_context); -#else - throw EncodeError (_("Cannot resample audio as libswresample is not present")); -#endif } else { -#ifdef HAVE_SWRESAMPLE _swr_context = 0; -#endif } for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { @@ -135,7 +127,6 @@ Encoder::process_begin () void Encoder::process_end () { -#if HAVE_SWRESAMPLE if (_film->has_audio() && _swr_context) { shared_ptr out (new AudioBuffers (_film->audio_mapping().dcp_channels(), 256)); @@ -157,7 +148,6 @@ Encoder::process_end () swr_free (&_swr_context); } -#endif boost::mutex::scoped_lock lock (_mutex); @@ -306,7 +296,6 @@ Encoder::process_video (shared_ptr image, bool same, shared_ptr data) { -#if HAVE_SWRESAMPLE /* Maybe sample-rate convert */ if (_swr_context) { @@ -329,7 +318,6 @@ Encoder::process_audio (shared_ptr data) /* And point our variables at the resampled audio */ data = resampled; } -#endif _writer->write (data); } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 6cf5540c5..a3a484856 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -33,12 +33,8 @@ #include extern "C" { #include -} -#ifdef HAVE_SWRESAMPLE -extern "C" { #include } -#endif #include "util.h" #include "video_sink.h" #include "audio_sink.h" @@ -110,9 +106,7 @@ private: /** Number of video frames written for the DCP so far */ int _video_frames_out; -#if HAVE_SWRESAMPLE SwrContext* _swr_context; -#endif bool _have_a_real_frame; bool _terminate; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index ca43ffb8a..528e3840f 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -810,7 +810,6 @@ FilmEditor::setup_frame_rate_description () if (_film->video_frame_rate()) { d << std_to_wx (FrameRateConversion (_film->video_frame_rate(), _film->dcp_frame_rate()).description); ++lines; -#ifdef HAVE_SWRESAMPLE if (_film->audio_frame_rate() && _film->audio_frame_rate() != _film->target_audio_sample_rate ()) { d << wxString::Format ( _("Audio will be resampled from %dHz to %dHz\n"), @@ -819,7 +818,6 @@ FilmEditor::setup_frame_rate_description () ); ++lines; } -#endif } for (int i = lines; i < 2; ++i) { diff --git a/wscript b/wscript index 169e46257..50d6d9040 100644 --- a/wscript +++ b/wscript @@ -62,7 +62,7 @@ def configure(conf): conf.check_cfg(package = 'libavcodec', args = '--cflags --libs', uselib_store = 'AVCODEC', mandatory = True) conf.check_cfg(package = 'libavutil', args = '--cflags --libs', uselib_store = 'AVUTIL', mandatory = True) conf.check_cfg(package = 'libswscale', args = '--cflags --libs', uselib_store = 'SWSCALE', mandatory = True) - conf.check_cfg(package = 'libswresample', args = '--cflags --libs', uselib_store = 'SWRESAMPLE', mandatory = False) + conf.check_cfg(package = 'libswresample', args = '--cflags --libs', uselib_store = 'SWRESAMPLE', mandatory = True) conf.check_cfg(package = 'libpostproc', args = '--cflags --libs', uselib_store = 'POSTPROC', mandatory = True) else: # This is hackio grotesquio for static builds (ie for .deb packages). We need to link some things @@ -87,14 +87,10 @@ def configure(conf): conf.env.STLIB_AVUTIL = ['avutil'] conf.env.HAVE_SWSCALE = 1 conf.env.STLIB_SWSCALE = ['swscale'] - conf.env.HAVE_SWRESAMPLE = 1 - conf.env.STLIB_SWRESAMPLE = ['swresample'] conf.env.HAVE_POSTPROC = 1 conf.env.STLIB_POSTPROC = ['postproc'] - - # This doesn't seem to be set up, and we need it otherwise resampling support - # won't be included. Hack upon a hack, obviously - conf.env.append_value('CXXFLAGS', ['-DHAVE_SWRESAMPLE=1']) + conf.env.HAVE_SWRESAMPLE = 1 + conv.env.STLIB_SWRESAMPLE = ['swresample'] conf.check_cfg(package = 'sndfile', args = '--cflags --libs', uselib_store = 'SNDFILE', mandatory = True) conf.check_cfg(package = 'glib-2.0', args = '--cflags --libs', uselib_store = 'GLIB', mandatory = True) -- cgit v1.2.3 From d683883c4dc25cb612f6d5feb1e772016182e722 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 10 May 2013 23:06:17 +0100 Subject: Move SRC (badly) to AudioDecoder. --- src/lib/audio_decoder.cc | 104 ++++++++++++++++++++++++++++++++++++++++++++- src/lib/audio_decoder.h | 12 +++++- src/lib/encoder.cc | 76 --------------------------------- src/lib/encoder.h | 2 - src/lib/ffmpeg_decoder.cc | 2 +- src/lib/sndfile_decoder.cc | 2 +- 6 files changed, 116 insertions(+), 82 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index df13a984a..68554daf9 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -18,12 +18,114 @@ */ #include "audio_decoder.h" +#include "exceptions.h" +#include "log.h" +#include "i18n.h" + +using std::stringstream; using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f) +AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) : Decoder (f) + , _audio_content (c) { + if (_audio_content->audio_frame_rate() != _film->target_audio_sample_rate()) { + + stringstream s; + s << String::compose ("Will resample audio from %1 to %2", _audio_content->audio_frame_rate(), _film->target_audio_sample_rate()); + _film->log()->log (s.str ()); + + /* We will be using planar float data when we call the + resampler. As far as I can see, the audio channel + layout is not necessary for our purposes; it seems + only to be used get the number of channels and + decide if rematrixing is needed. It won't be, since + input and output layouts are the same. + */ + _swr_context = swr_alloc_set_opts ( + 0, + av_get_default_channel_layout (MAX_AUDIO_CHANNELS), + AV_SAMPLE_FMT_FLTP, + _film->target_audio_sample_rate(), + av_get_default_channel_layout (MAX_AUDIO_CHANNELS), + AV_SAMPLE_FMT_FLTP, + _audio_content->audio_frame_rate(), + 0, 0 + ); + + swr_init (_swr_context); + } else { + _swr_context = 0; + } +} + +AudioDecoder::~AudioDecoder () +{ + if (_swr_context) { + swr_free (&_swr_context); + } } + + +#if 0 +void +AudioDecoder::process_end () +{ + if (_film->has_audio() && _swr_context) { + + shared_ptr out (new AudioBuffers (_film->audio_mapping().dcp_channels(), 256)); + + while (1) { + int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); + + if (frames < 0) { + throw EncodeError (_("could not run sample-rate converter")); + } + + if (frames == 0) { + break; + } + + out->set_frames (frames); + _writer->write (out); + } + + } +} +#endif + +void +AudioDecoder::emit_audio (shared_ptr data, Time time) +{ + /* XXX: map audio to 5.1 */ + + /* Maybe sample-rate convert */ + if (_swr_context) { + + /* Compute the resampled frames count and add 32 for luck */ + int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _audio_content->audio_frame_rate()) + 32; + + shared_ptr resampled (new AudioBuffers (MAX_AUDIO_CHANNELS, max_resampled_frames)); + + /* Resample audio */ + int const resampled_frames = swr_convert ( + _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) data->data(), data->frames() + ); + + if (resampled_frames < 0) { + throw EncodeError (_("could not run sample-rate converter")); + } + + resampled->set_frames (resampled_frames); + + /* And point our variables at the resampled audio */ + data = resampled; + } + + Audio (data, time); +} + + diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index c393e95f1..8db16e369 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -26,6 +26,9 @@ #include "audio_source.h" #include "decoder.h" +extern "C" { +#include +} class AudioContent; @@ -35,7 +38,14 @@ class AudioContent; class AudioDecoder : public TimedAudioSource, public virtual Decoder { public: - AudioDecoder (boost::shared_ptr); + AudioDecoder (boost::shared_ptr, boost::shared_ptr); + ~AudioDecoder (); + + void emit_audio (boost::shared_ptr, Time); + +private: + boost::shared_ptr _audio_content; + SwrContext* _swr_context; }; #endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 8e0d1cd91..f91a2c4e2 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -60,7 +60,6 @@ Encoder::Encoder (shared_ptr f, shared_ptr j) , _job (j) , _video_frames_in (0) , _video_frames_out (0) - , _swr_context (0) , _have_a_real_frame (false) , _terminate (false) { @@ -78,36 +77,6 @@ Encoder::~Encoder () void Encoder::process_begin () { - if (_film->has_audio() && _film->audio_frame_rate() != _film->target_audio_sample_rate()) { - - stringstream s; - s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_frame_rate(), _film->target_audio_sample_rate()); - _film->log()->log (s.str ()); - - /* We will be using planar float data when we call the - resampler. As far as I can see, the audio channel - layout is not necessary for our purposes; it seems - only to be used get the number of channels and - decide if rematrixing is needed. It won't be, since - input and output layouts are the same. - */ - - _swr_context = swr_alloc_set_opts ( - 0, - av_get_default_channel_layout (_film->audio_mapping().dcp_channels ()), - AV_SAMPLE_FMT_FLTP, - _film->target_audio_sample_rate(), - av_get_default_channel_layout (_film->audio_mapping().dcp_channels ()), - AV_SAMPLE_FMT_FLTP, - _film->audio_frame_rate(), - 0, 0 - ); - - swr_init (_swr_context); - } else { - _swr_context = 0; - } - for (int i = 0; i < Config::instance()->num_local_encoding_threads (); ++i) { _threads.push_back (new boost::thread (boost::bind (&Encoder::encoder_thread, this, (ServerDescription *) 0))); } @@ -127,28 +96,6 @@ Encoder::process_begin () void Encoder::process_end () { - if (_film->has_audio() && _swr_context) { - - shared_ptr out (new AudioBuffers (_film->audio_mapping().dcp_channels(), 256)); - - while (1) { - int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); - - if (frames < 0) { - throw EncodeError (_("could not run sample-rate converter")); - } - - if (frames == 0) { - break; - } - - out->set_frames (frames); - _writer->write (out); - } - - swr_free (&_swr_context); - } - boost::mutex::scoped_lock lock (_mutex); _film->log()->log (String::compose (N_("Clearing queue of %1"), _queue.size ())); @@ -296,29 +243,6 @@ Encoder::process_video (shared_ptr image, bool same, shared_ptr data) { - /* Maybe sample-rate convert */ - if (_swr_context) { - - /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_frame_rate()) + 32; - - shared_ptr resampled (new AudioBuffers (_film->audio_mapping().dcp_channels(), max_resampled_frames)); - - /* Resample audio */ - int const resampled_frames = swr_convert ( - _swr_context, (uint8_t **) resampled->data(), max_resampled_frames, (uint8_t const **) data->data(), data->frames() - ); - - if (resampled_frames < 0) { - throw EncodeError (_("could not run sample-rate converter")); - } - - resampled->set_frames (resampled_frames); - - /* And point our variables at the resampled audio */ - data = resampled; - } - _writer->write (data); } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index a3a484856..cce26efc8 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -106,8 +106,6 @@ private: /** Number of video frames written for the DCP so far */ int _video_frames_out; - SwrContext* _swr_context; - bool _have_a_real_frame; bool _terminate; std::list > _queue; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index b857860bd..0e704bb14 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -66,7 +66,7 @@ boost::mutex FFmpegDecoder::_mutex; FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles) : Decoder (f) , VideoDecoder (f) - , AudioDecoder (f) + , AudioDecoder (f, c) , _ffmpeg_content (c) , _format_context (0) , _video_stream (-1) diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index dd9e654c7..dc22475cd 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -34,7 +34,7 @@ using boost::shared_ptr; SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , AudioDecoder (f) + , AudioDecoder (f, c) , _sndfile_content (c) , _deinterleave_buffer (0) { -- cgit v1.2.3 From 0db016f90ae722fc8b72d465e21d9f153f72b340 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 10 May 2013 23:31:25 +0100 Subject: Remove Timed*Sink and Timed*Source> --- src/lib/audio_decoder.h | 2 +- src/lib/audio_sink.h | 9 +-------- src/lib/audio_source.cc | 26 +++----------------------- src/lib/audio_source.h | 16 ++-------------- src/lib/combiner.cc | 2 +- src/lib/combiner.h | 6 +++--- src/lib/encoder.cc | 4 ++-- src/lib/encoder.h | 4 ++-- src/lib/player.h | 2 +- src/lib/processor.h | 17 ----------------- src/lib/video_decoder.h | 2 +- src/lib/video_sink.h | 14 +------------- src/lib/video_source.cc | 26 +++----------------------- src/lib/video_source.h | 22 +--------------------- 14 files changed, 22 insertions(+), 130 deletions(-) (limited to 'src/lib/encoder.cc') diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 8db16e369..1c7287a55 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -35,7 +35,7 @@ class AudioContent; /** @class AudioDecoder. * @brief Parent class for audio decoders. */ -class AudioDecoder : public TimedAudioSource, public virtual Decoder +class AudioDecoder : public AudioSource, public virtual Decoder { public: AudioDecoder (boost::shared_ptr, boost::shared_ptr); diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index ee39f9ee7..2e3ead005 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -24,14 +24,7 @@ class AudioSink { public: /** Call with some audio data */ - virtual void process_audio (boost::shared_ptr) = 0; -}; - -class TimedAudioSink -{ -public: - /** Call with some audio data */ - virtual void process_audio (boost::shared_ptr, double t) = 0; + virtual void process_audio (boost::shared_ptr, Time) = 0; }; #endif diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index 2867bcc24..e61721646 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -25,38 +25,18 @@ using boost::weak_ptr; using boost::bind; static void -process_audio_proxy (weak_ptr sink, shared_ptr audio) +process_audio_proxy (weak_ptr sink, shared_ptr audio, Time time) { shared_ptr p = sink.lock (); if (p) { - p->process_audio (audio); + p->process_audio (audio, time); } } void AudioSource::connect_audio (shared_ptr s) { - Audio.connect (bind (process_audio_proxy, weak_ptr (s), _1)); + Audio.connect (bind (process_audio_proxy, weak_ptr (s), _1, _2)); } -void -TimedAudioSource::connect_audio (shared_ptr s) -{ - Audio.connect (bind (process_audio_proxy, weak_ptr (s), _1)); -} - -static void -timed_process_audio_proxy (weak_ptr sink, shared_ptr audio, double t) -{ - shared_ptr p = sink.lock (); - if (p) { - p->process_audio (audio, t); - } -} - -void -TimedAudioSource::connect_audio (shared_ptr s) -{ - Audio.connect (bind (timed_process_audio_proxy, weak_ptr (s), _1, _2)); -} diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index c7f0a09ed..ef47e969b 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -25,31 +25,19 @@ #define DCPOMATIC_AUDIO_SOURCE_H #include +#include "types.h" class AudioBuffers; class AudioSink; -class TimedAudioSink; /** A class that emits audio data */ class AudioSource { public: /** Emitted when some audio data is ready */ - boost::signals2::signal)> Audio; + boost::signals2::signal, Time)> Audio; void connect_audio (boost::shared_ptr); }; - -/** A class that emits audio data with timestamps */ -class TimedAudioSource -{ -public: - /** Emitted when some audio data is ready */ - boost::signals2::signal, double)> Audio; - - void connect_audio (boost::shared_ptr); - void connect_audio (boost::shared_ptr); -}; - #endif diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 367cefa7f..9f9461ec2 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -23,7 +23,7 @@ using boost::shared_ptr; Combiner::Combiner (shared_ptr log) - : TimedVideoProcessor (log) + : VideoProcessor (log) { } diff --git a/src/lib/combiner.h b/src/lib/combiner.h index 7ed316e26..062297f0d 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -28,13 +28,13 @@ * one image used for the left half of the screen and the other for * the right. */ -class Combiner : public TimedVideoProcessor +class Combiner : public VideoProcessor { public: Combiner (boost::shared_ptr log); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); - void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, double); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, Time); + void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, Time); private: /** The image that we are currently working on */ diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index f91a2c4e2..6cb384e20 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -178,7 +178,7 @@ Encoder::frame_done () } void -Encoder::process_video (shared_ptr image, bool same, shared_ptr sub) +Encoder::process_video (shared_ptr image, bool same, shared_ptr sub, Time) { FrameRateConversion frc (_film->video_frame_rate(), _film->dcp_frame_rate()); @@ -241,7 +241,7 @@ Encoder::process_video (shared_ptr image, bool same, shared_ptr data) +Encoder::process_audio (shared_ptr data, Time) { _writer->write (data); } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index cce26efc8..b6d3663fd 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -70,10 +70,10 @@ public: * @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 i, bool same, boost::shared_ptr s); + void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, Time); /** Call with some audio data */ - void process_audio (boost::shared_ptr); + void process_audio (boost::shared_ptr, Time); /** Called when a processing run has finished */ void process_end (); diff --git a/src/lib/player.h b/src/lib/player.h index b6fb41f6e..b1be2f456 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -39,7 +39,7 @@ class AudioContent; * @brief A class which can `play' a Playlist; emitting its audio and video. */ -class Player : public TimedVideoSource, public TimedAudioSource, public TimedVideoSink, public boost::enable_shared_from_this +class Player : public VideoSource, public AudioSource, public VideoSink, public boost::enable_shared_from_this { public: Player (boost::shared_ptr, boost::shared_ptr); diff --git a/src/lib/processor.h b/src/lib/processor.h index 7b7735faa..5dbafab7f 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -67,15 +67,6 @@ public: {} }; -class TimedAudioVideoProcessor : public Processor, public TimedVideoSource, public TimedVideoSink, public TimedAudioSource, public TimedAudioSink -{ -public: - TimedAudioVideoProcessor (boost::shared_ptr log) - : Processor (log) - {} -}; - - /** @class AudioProcessor * @brief A processor which handles just audio data. */ @@ -104,12 +95,4 @@ public: {} }; -class TimedVideoProcessor : public Processor, public TimedVideoSource, public TimedVideoSink -{ -public: - TimedVideoProcessor (boost::shared_ptr log) - : Processor (log) - {} -}; - #endif diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 0b05b2f71..88730f518 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -25,7 +25,7 @@ class VideoContent; -class VideoDecoder : public TimedVideoSource, public virtual Decoder +class VideoDecoder : public VideoSource, public virtual Decoder { public: VideoDecoder (boost::shared_ptr); diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 6239bc557..2da42528c 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -34,19 +34,7 @@ public: * @param same true if i is the same as last time we were called. * @param s A subtitle that should be on this frame, or 0. */ - virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) = 0; -}; - -class TimedVideoSink -{ -public: - /** Call with a frame of video. - * @param i Video frame image. - * @param same true if i is the same as last time we were called. - * @param s A subtitle that should be on this frame, or 0. - * @param t Source timestamp. - */ - virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double t) = 0; + virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, Time) = 0; }; #endif diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 4d505f9fe..39043c860 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -25,11 +25,11 @@ using boost::weak_ptr; using boost::bind; static void -process_video_proxy (weak_ptr sink, shared_ptr i, bool same, shared_ptr s) +process_video_proxy (weak_ptr sink, shared_ptr image, bool same, shared_ptr sub, Time time) { shared_ptr p = sink.lock (); if (p) { - p->process_video (i, same, s); + p->process_video (image, same, sub, time); } } @@ -39,26 +39,6 @@ VideoSource::connect_video (shared_ptr s) /* If we bind, say, a Player (as the VideoSink) to a Decoder (which is owned by the Player) we create a cycle. Use a weak_ptr to break it. */ - Video.connect (bind (process_video_proxy, weak_ptr (s), _1, _2, _3)); + Video.connect (bind (process_video_proxy, weak_ptr (s), _1, _2, _3, _4)); } -void -TimedVideoSource::connect_video (shared_ptr s) -{ - Video.connect (bind (process_video_proxy, weak_ptr (s), _1, _2, _3)); -} - -static void -timed_process_video_proxy (weak_ptr sink, shared_ptr i, bool same, shared_ptr s, double t) -{ - shared_ptr p = sink.lock (); - if (p) { - p->process_video (i, same, s, t); - } -} - -void -TimedVideoSource::connect_video (shared_ptr s) -{ - Video.connect (bind (timed_process_video_proxy, weak_ptr (s), _1, _2, _3, _4)); -} diff --git a/src/lib/video_source.h b/src/lib/video_source.h index 9b4c9b4a2..7ad554480 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -29,7 +29,6 @@ #include "util.h" class VideoSink; -class TimedVideoSink; class Subtitle; class Image; @@ -45,28 +44,9 @@ public: * Second parameter is true if the image is the same as the last one that was emitted. * Third parameter is either 0 or a subtitle that should be on this frame. */ - boost::signals2::signal, bool, boost::shared_ptr)> Video; + boost::signals2::signal, bool, boost::shared_ptr, Time)> Video; void connect_video (boost::shared_ptr); }; -/** @class TimedVideoSource - * @param A class that emits video data with timestamps. - */ -class TimedVideoSource -{ -public: - - /** Emitted when a video frame is ready. - * First parameter is the video image. - * Second parameter is true if the image is the same as the last one that was emitted. - * Third parameter is either 0 or a subtitle that should be on this frame. - * Fourth parameter is the source timestamp of this frame. - */ - boost::signals2::signal, bool, boost::shared_ptr, double)> Video; - - void connect_video (boost::shared_ptr); - void connect_video (boost::shared_ptr); -}; - #endif -- cgit v1.2.3 From 21ce34c2cd04a2e7e133ff693b84c054182f4f91 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 16 May 2013 08:36:47 +0100 Subject: Compiles; strange hang on adding content to a film. --- src/lib/analyse_audio_job.cc | 4 +- src/lib/audio_buffers.cc | 222 +++++++++++++++++++++ src/lib/audio_buffers.h | 67 +++++++ src/lib/audio_content.cc | 6 - src/lib/audio_content.h | 5 +- src/lib/audio_decoder.cc | 14 +- src/lib/audio_decoder.h | 1 + src/lib/audio_mapping.cc | 51 ++--- src/lib/audio_mapping.h | 28 +-- src/lib/audio_sink.h | 2 + src/lib/combiner.cc | 4 +- src/lib/content.h | 2 +- src/lib/decoder.h | 1 - src/lib/encoder.cc | 17 +- src/lib/encoder.h | 2 - src/lib/ffmpeg_content.cc | 33 +++- src/lib/ffmpeg_content.h | 5 +- src/lib/ffmpeg_decoder.cc | 5 +- src/lib/film.cc | 188 ++++++------------ src/lib/film.h | 48 ++--- src/lib/format.cc | 3 +- src/lib/format.h | 2 +- src/lib/imagemagick_content.cc | 7 + src/lib/imagemagick_content.h | 1 + src/lib/player.cc | 338 +++++++++++++++----------------- src/lib/player.h | 53 ++--- src/lib/playlist.cc | 419 +++++++++++++--------------------------- src/lib/playlist.h | 77 +++----- src/lib/sndfile_content.cc | 14 +- src/lib/sndfile_content.h | 5 +- src/lib/sndfile_decoder.cc | 3 +- src/lib/subtitle.h | 2 +- src/lib/transcode_job.cc | 13 +- src/lib/types.h | 10 +- src/lib/util.cc | 227 +--------------------- src/lib/util.h | 50 +---- src/lib/video_content.cc | 6 - src/lib/video_content.h | 1 - src/lib/video_decoder.cc | 4 +- src/lib/writer.cc | 47 ++--- src/lib/wscript | 1 + src/wx/audio_dialog.cc | 4 - src/wx/audio_mapping_view.cc | 8 +- src/wx/ffmpeg_content_dialog.cc | 2 +- src/wx/film_editor.cc | 149 ++++---------- src/wx/film_editor.h | 6 - src/wx/film_viewer.cc | 18 +- src/wx/properties_dialog.cc | 10 +- src/wx/timeline.cc | 102 ++++------ src/wx/timeline.h | 16 +- src/wx/timeline_dialog.cc | 4 +- src/wx/timeline_dialog.h | 2 +- test/test.cc | 32 +-- wscript | 2 +- 54 files changed, 990 insertions(+), 1353 deletions(-) create mode 100644 src/lib/audio_buffers.cc create mode 100644 src/lib/audio_buffers.h (limited to 'src/lib/encoder.cc') diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index f3c55b208..0ed33827c 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -55,13 +55,13 @@ AnalyseAudioJob::run () player->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); - _samples_per_point = max (int64_t (1), _film->audio_length() / _num_points); + _samples_per_point = max (int64_t (1), _film->time_to_audio_frames (_film->length()) / _num_points); _current.resize (MAX_AUDIO_CHANNELS); _analysis.reset (new AudioAnalysis (MAX_AUDIO_CHANNELS)); while (!player->pass()) { - set_progress (float (_done) / _film->audio_length ()); + set_progress (float (_done) / _film->time_to_audio_frames (_film->length ())); } _analysis->write (_film->audio_analysis_path ()); diff --git a/src/lib/audio_buffers.cc b/src/lib/audio_buffers.cc new file mode 100644 index 000000000..cd8fcd35b --- /dev/null +++ b/src/lib/audio_buffers.cc @@ -0,0 +1,222 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington + + 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 +#include +#include +#include "audio_buffers.h" + +using std::bad_alloc; +using boost::shared_ptr; + +/** Construct an AudioBuffers. Audio data is undefined after this constructor. + * @param channels Number of channels. + * @param frames Number of frames to reserve space for. + */ +AudioBuffers::AudioBuffers (int channels, int frames) + : _channels (channels) + , _frames (frames) + , _allocated_frames (frames) +{ + _data = static_cast (malloc (_channels * sizeof (float *))); + if (!_data) { + throw bad_alloc (); + } + + for (int i = 0; i < _channels; ++i) { + _data[i] = static_cast (malloc (frames * sizeof (float))); + if (!_data[i]) { + throw bad_alloc (); + } + } +} + +/** Copy constructor. + * @param other Other AudioBuffers; data is copied. + */ +AudioBuffers::AudioBuffers (AudioBuffers const & other) + : _channels (other._channels) + , _frames (other._frames) + , _allocated_frames (other._frames) +{ + _data = static_cast (malloc (_channels * sizeof (float *))); + if (!_data) { + throw bad_alloc (); + } + + for (int i = 0; i < _channels; ++i) { + _data[i] = static_cast (malloc (_frames * sizeof (float))); + if (!_data[i]) { + throw bad_alloc (); + } + memcpy (_data[i], other._data[i], _frames * sizeof (float)); + } +} + +/* XXX: it's a shame that this is a copy-and-paste of the above; + probably fixable with c++0x. +*/ +AudioBuffers::AudioBuffers (boost::shared_ptr other) + : _channels (other->_channels) + , _frames (other->_frames) + , _allocated_frames (other->_frames) +{ + _data = static_cast (malloc (_channels * sizeof (float *))); + if (!_data) { + throw bad_alloc (); + } + + for (int i = 0; i < _channels; ++i) { + _data[i] = static_cast (malloc (_frames * sizeof (float))); + if (!_data[i]) { + throw bad_alloc (); + } + memcpy (_data[i], other->_data[i], _frames * sizeof (float)); + } +} + +/** AudioBuffers destructor */ +AudioBuffers::~AudioBuffers () +{ + for (int i = 0; i < _channels; ++i) { + free (_data[i]); + } + + free (_data); +} + +/** @param c Channel index. + * @return Buffer for this channel. + */ +float* +AudioBuffers::data (int c) const +{ + assert (c >= 0 && c < _channels); + return _data[c]; +} + +/** Set the number of frames that these AudioBuffers will report themselves + * as having. + * @param f Frames; must be less than or equal to the number of allocated frames. + */ +void +AudioBuffers::set_frames (int f) +{ + assert (f <= _allocated_frames); + _frames = f; +} + +/** Make all samples on all channels silent */ +void +AudioBuffers::make_silent () +{ + for (int i = 0; i < _channels; ++i) { + make_silent (i); + } +} + +/** Make all samples on a given channel silent. + * @param c Channel. + */ +void +AudioBuffers::make_silent (int c) +{ + assert (c >= 0 && c < _channels); + + for (int i = 0; i < _frames; ++i) { + _data[c][i] = 0; + } +} + +/** Copy data from another AudioBuffers to this one. All channels are copied. + * @param from AudioBuffers to copy from; must have the same number of channels as this. + * @param frames_to_copy Number of frames to copy. + * @param read_offset Offset to read from in `from'. + * @param write_offset Offset to write to in `to'. + */ +void +AudioBuffers::copy_from (AudioBuffers const * from, int frames_to_copy, int read_offset, int write_offset) +{ + assert (from->channels() == channels()); + + assert (from); + assert (read_offset >= 0 && (read_offset + frames_to_copy) <= from->_allocated_frames); + assert (write_offset >= 0 && (write_offset + frames_to_copy) <= _allocated_frames); + + for (int i = 0; i < _channels; ++i) { + memcpy (_data[i] + write_offset, from->_data[i] + read_offset, frames_to_copy * sizeof(float)); + } +} + +/** Move audio data around. + * @param from Offset to move from. + * @param to Offset to move to. + * @param frames Number of frames to move. + */ + +void +AudioBuffers::move (int from, int to, int frames) +{ + if (frames == 0) { + return; + } + + assert (from >= 0); + assert (from < _frames); + assert (to >= 0); + assert (to < _frames); + assert (frames > 0); + assert (frames <= _frames); + assert ((from + frames) <= _frames); + assert ((to + frames) <= _frames); + + for (int i = 0; i < _channels; ++i) { + memmove (_data[i] + to, _data[i] + from, frames * sizeof(float)); + } +} + +/** Add data from from `from', `from_channel' to our channel `to_channel' */ +void +AudioBuffers::accumulate (AudioBuffers const * from, int from_channel, int to_channel) +{ + int const N = frames (); + assert (from->frames() == N); + + float* s = from->data (from_channel); + float* d = _data[to_channel]; + + for (int i = 0; i < N; ++i) { + *d++ += *s++; + } +} + +void +AudioBuffers::ensure_size (int frames) +{ + if (_allocated_frames >= frames) { + return; + } + + for (int i = 0; i < _channels; ++i) { + _data[i] = static_cast (realloc (_data[i], _frames * sizeof (float))); + if (!_data[i]) { + throw bad_alloc (); + } + } +} diff --git a/src/lib/audio_buffers.h b/src/lib/audio_buffers.h new file mode 100644 index 000000000..5e7b9fda4 --- /dev/null +++ b/src/lib/audio_buffers.h @@ -0,0 +1,67 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington + + 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 + +/** @class AudioBuffers + * @brief A class to hold multi-channel audio data in float format. + */ +class AudioBuffers +{ +public: + AudioBuffers (int channels, int frames); + AudioBuffers (AudioBuffers const &); + AudioBuffers (boost::shared_ptr); + ~AudioBuffers (); + + void ensure_size (int); + + float** data () const { + return _data; + } + + float* data (int) const; + + int channels () const { + return _channels; + } + + int frames () const { + return _frames; + } + + void set_frames (int f); + + void make_silent (); + void make_silent (int c); + + void copy_from (AudioBuffers const * from, int frames_to_copy, int read_offset, int write_offset); + void move (int from, int to, int frames); + void accumulate (AudioBuffers const *, int, int); + +private: + /** Number of channels */ + int _channels; + /** Number of frames (where a frame is one sample across all channels) */ + int _frames; + /** Number of frames that _data can hold */ + int _allocated_frames; + /** Audio data (so that, e.g. _data[2][6] is channel 2, sample 6) */ + float** _data; +}; diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index dfa48d97e..9968f4725 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -43,9 +43,3 @@ AudioContent::AudioContent (AudioContent const & o) { } - -Time -AudioContent::temporal_length () const -{ - return audio_length() / audio_frame_rate(); -} diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index 18107843c..87858488c 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -44,9 +44,8 @@ public: virtual int audio_channels () const = 0; virtual ContentAudioFrame audio_length () const = 0; - virtual int audio_frame_rate () const = 0; - - Time temporal_length () const; + virtual int content_audio_frame_rate () const = 0; + virtual int output_audio_frame_rate (boost::shared_ptr) const = 0; }; #endif diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 68554daf9..e1c93ac77 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -18,6 +18,7 @@ */ #include "audio_decoder.h" +#include "audio_buffers.h" #include "exceptions.h" #include "log.h" @@ -30,11 +31,12 @@ using boost::shared_ptr; AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) : Decoder (f) , _audio_content (c) + , _output_audio_frame_rate (_audio_content->output_audio_frame_rate (f)) { - if (_audio_content->audio_frame_rate() != _film->target_audio_sample_rate()) { + if (_audio_content->content_audio_frame_rate() != _output_audio_frame_rate) { stringstream s; - s << String::compose ("Will resample audio from %1 to %2", _audio_content->audio_frame_rate(), _film->target_audio_sample_rate()); + s << String::compose ("Will resample audio from %1 to %2", _audio_content->content_audio_frame_rate(), _output_audio_frame_rate); _film->log()->log (s.str ()); /* We will be using planar float data when we call the @@ -49,10 +51,10 @@ AudioDecoder::AudioDecoder (shared_ptr f, shared_ptrtarget_audio_sample_rate(), + _output_audio_frame_rate, av_get_default_channel_layout (MAX_AUDIO_CHANNELS), AV_SAMPLE_FMT_FLTP, - _audio_content->audio_frame_rate(), + _audio_content->content_audio_frame_rate(), 0, 0 ); @@ -74,7 +76,7 @@ AudioDecoder::~AudioDecoder () void AudioDecoder::process_end () { - if (_film->has_audio() && _swr_context) { + if (_swr_context) { shared_ptr out (new AudioBuffers (_film->audio_mapping().dcp_channels(), 256)); @@ -106,7 +108,7 @@ AudioDecoder::emit_audio (shared_ptr data, Time time) if (_swr_context) { /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _audio_content->audio_frame_rate()) + 32; + int const max_resampled_frames = ceil ((int64_t) data->frames() * _output_audio_frame_rate / _audio_content->content_audio_frame_rate()) + 32; shared_ptr resampled (new AudioBuffers (MAX_AUDIO_CHANNELS, max_resampled_frames)); diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 1c7287a55..94845ec23 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -46,6 +46,7 @@ public: private: boost::shared_ptr _audio_content; SwrContext* _swr_context; + int _output_audio_frame_rate; }; #endif diff --git a/src/lib/audio_mapping.cc b/src/lib/audio_mapping.cc index 7e28aa5c4..e1fa0c220 100644 --- a/src/lib/audio_mapping.cc +++ b/src/lib/audio_mapping.cc @@ -31,7 +31,7 @@ using boost::lexical_cast; using boost::dynamic_pointer_cast; void -AudioMapping::add (Channel c, libdcp::Channel d) +AudioMapping::add (int c, libdcp::Channel d) { _content_to_dcp.push_back (make_pair (c, d)); } @@ -40,7 +40,7 @@ AudioMapping::add (Channel c, libdcp::Channel d) int AudioMapping::dcp_channels () const { - for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { if (((int) i->second) >= 2) { return 6; } @@ -49,11 +49,11 @@ AudioMapping::dcp_channels () const return 2; } -list +list AudioMapping::dcp_to_content (libdcp::Channel d) const { - list c; - for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + list c; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { if (i->second == d) { c.push_back (i->first); } @@ -62,11 +62,11 @@ AudioMapping::dcp_to_content (libdcp::Channel d) const return c; } -list +list AudioMapping::content_channels () const { - list c; - for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + list c; + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { if (find (c.begin(), c.end(), i->first) == c.end ()) { c.push_back (i->first); } @@ -76,10 +76,10 @@ AudioMapping::content_channels () const } list -AudioMapping::content_to_dcp (Channel c) const +AudioMapping::content_to_dcp (int c) const { list d; - for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { if (i->first == c) { d.push_back (i->second); } @@ -91,41 +91,18 @@ AudioMapping::content_to_dcp (Channel c) const void AudioMapping::as_xml (xmlpp::Node* node) const { - for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { + for (list >::const_iterator i = _content_to_dcp.begin(); i != _content_to_dcp.end(); ++i) { xmlpp::Node* t = node->add_child ("Map"); - shared_ptr c = i->first.content.lock (); - t->add_child ("Content")->add_child_text (c->digest ()); - t->add_child ("ContentIndex")->add_child_text (lexical_cast (i->first.index)); + t->add_child ("ContentIndex")->add_child_text (lexical_cast (i->first)); t->add_child ("DCP")->add_child_text (lexical_cast (i->second)); } } void -AudioMapping::set_from_xml (ContentList const & content, shared_ptr node) +AudioMapping::set_from_xml (shared_ptr node) { list > const c = node->node_children ("Map"); for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { - string const c = (*i)->string_child ("Content"); - ContentList::const_iterator j = content.begin (); - while (j != content.end() && (*j)->digest() != c) { - ++j; - } - - if (j == content.end ()) { - continue; - } - - shared_ptr ac = dynamic_pointer_cast (*j); - assert (ac); - - add (AudioMapping::Channel (ac, (*i)->number_child ("ContentIndex")), static_cast ((*i)->number_child ("DCP"))); + add ((*i)->number_child ("ContentIndex"), static_cast ((*i)->number_child ("DCP"))); } } - -bool -operator== (AudioMapping::Channel const & a, AudioMapping::Channel const & b) -{ - shared_ptr sa = a.content.lock (); - shared_ptr sb = b.content.lock (); - return sa == sb && a.index == b.index; -} diff --git a/src/lib/audio_mapping.h b/src/lib/audio_mapping.h index 248d2570e..3c471d3f4 100644 --- a/src/lib/audio_mapping.h +++ b/src/lib/audio_mapping.h @@ -30,33 +30,21 @@ class AudioMapping { public: void as_xml (xmlpp::Node *) const; - void set_from_xml (ContentList const &, boost::shared_ptr); - - struct Channel { - Channel (boost::weak_ptr c, int i) - : content (c) - , index (i) - {} - - boost::weak_ptr content; - int index; - }; - - void add (Channel, libdcp::Channel); + void set_from_xml (boost::shared_ptr); + + void add (int, libdcp::Channel); int dcp_channels () const; - std::list dcp_to_content (libdcp::Channel) const; - std::list > content_to_dcp () const { + std::list dcp_to_content (libdcp::Channel) const; + std::list > content_to_dcp () const { return _content_to_dcp; } - std::list content_channels () const; - std::list content_to_dcp (Channel) const; + std::list content_channels () const; + std::list content_to_dcp (int) const; private: - std::list > _content_to_dcp; + std::list > _content_to_dcp; }; -extern bool operator== (AudioMapping::Channel const &, AudioMapping::Channel const &); - #endif diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index 2e3ead005..1aad5edf9 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -20,6 +20,8 @@ #ifndef DCPOMATIC_AUDIO_SINK_H #define DCPOMATIC_AUDIO_SINK_H +class AudioBuffers; + class AudioSink { public: diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 9f9461ec2..0afb9807a 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -33,7 +33,7 @@ Combiner::Combiner (shared_ptr log) * @param image Frame image. */ void -Combiner::process_video (shared_ptr image, bool, shared_ptr, double) +Combiner::process_video (shared_ptr image, bool, shared_ptr, Time) { _image.reset (new SimpleImage (image)); } @@ -43,7 +43,7 @@ Combiner::process_video (shared_ptr image, bool, shared_ptr image, bool, shared_ptr sub, double t) +Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, Time t) { /* Copy the right half of this image into our _image */ /* XXX: this should probably be in the Image class */ diff --git a/src/lib/content.h b/src/lib/content.h index e1cf41df0..9f465570b 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -46,7 +46,7 @@ public: virtual std::string information () const = 0; virtual void as_xml (xmlpp::Node *) const; virtual boost::shared_ptr clone () const = 0; - virtual Time temporal_length () const = 0; + virtual Time length (boost::shared_ptr) const = 0; boost::filesystem::path file () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 02ccaa42b..ae0d0c671 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -29,7 +29,6 @@ #include #include #include -#include "util.h" #include "video_source.h" #include "audio_source.h" #include "film.h" diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 6cb384e20..95e98ab76 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -58,7 +58,6 @@ int const Encoder::_history_size = 25; Encoder::Encoder (shared_ptr f, shared_ptr j) : _film (f) , _job (j) - , _video_frames_in (0) , _video_frames_out (0) , _have_a_real_frame (false) , _terminate (false) @@ -180,13 +179,6 @@ Encoder::frame_done () void Encoder::process_video (shared_ptr image, bool same, shared_ptr sub, Time) { - FrameRateConversion frc (_film->video_frame_rate(), _film->dcp_frame_rate()); - - if (frc.skip && (_video_frames_in % 2)) { - ++_video_frames_in; - return; - } - boost::mutex::scoped_lock lock (_mutex); /* Wait until the queue has gone down a bit */ @@ -220,7 +212,7 @@ Encoder::process_video (shared_ptr image, bool same, shared_ptrformat()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), - _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second, + _film->scaler(), _video_frames_out, _film->dcp_video_frame_rate(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), _film->log() ) @@ -230,14 +222,7 @@ Encoder::process_video (shared_ptr image, bool same, shared_ptrrepeat (_video_frames_out); - ++_video_frames_out; - frame_done (); - } } void diff --git a/src/lib/encoder.h b/src/lib/encoder.h index b6d3663fd..6815fa6f6 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -101,8 +101,6 @@ private: /** Number of frames that we should keep history for */ static int const _history_size; - /** Number of video frames received so far */ - ContentVideoFrame _video_frames_in; /** Number of video frames written for the DCP so far */ int _video_frames_out; diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index a61f777c8..55281ff9b 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -206,7 +206,7 @@ FFmpegContent::audio_length () const return 0; } - return video_frames_to_audio_frames (_video_length, audio_frame_rate(), video_frame_rate()); + return video_frames_to_audio_frames (_video_length, content_audio_frame_rate(), video_frame_rate()); } int @@ -220,7 +220,7 @@ FFmpegContent::audio_channels () const } int -FFmpegContent::audio_frame_rate () const +FFmpegContent::content_audio_frame_rate () const { if (!_audio_stream) { return 0; @@ -229,6 +229,28 @@ FFmpegContent::audio_frame_rate () const return _audio_stream->frame_rate; } +int +FFmpegContent::output_audio_frame_rate (shared_ptr film) const +{ + /* Resample to a DCI-approved sample rate */ + double t = dcp_audio_frame_rate (content_audio_frame_rate ()); + + FrameRateConversion frc (video_frame_rate(), film->dcp_video_frame_rate()); + + /* Compensate if the DCP is being run at a different frame rate + to the source; that is, if the video is run such that it will + look different in the DCP compared to the source (slower or faster). + skip/repeat doesn't come into effect here. + */ + + if (frc.change_speed) { + t *= video_frame_rate() * frc.factor() / film->dcp_video_frame_rate(); + cout << "-> " << t << "\n"; + } + + return rint (t); +} + bool operator== (FFmpegSubtitleStream const & a, FFmpegSubtitleStream const & b) { @@ -281,8 +303,9 @@ FFmpegContent::clone () const return shared_ptr (new FFmpegContent (*this)); } -double -FFmpegContent::temporal_length () const +Time +FFmpegContent::length (shared_ptr film) const { - return video_length() / video_frame_rate(); + FrameRateConversion frc (video_frame_rate (), film->dcp_video_frame_rate ()); + return video_length() * frc.factor() * TIME_HZ / film->dcp_video_frame_rate (); } diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index 6d7151498..540df041f 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -89,12 +89,13 @@ public: std::string information () const; void as_xml (xmlpp::Node *) const; boost::shared_ptr clone () const; - double temporal_length () const; + Time length (boost::shared_ptr) const; /* AudioContent */ int audio_channels () const; ContentAudioFrame audio_length () const; - int audio_frame_rate () const; + int content_audio_frame_rate () const; + int output_audio_frame_rate (boost::shared_ptr) const; std::vector subtitle_streams () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 0e704bb14..d21a93e29 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -48,6 +48,7 @@ extern "C" { #include "ffmpeg_decoder.h" #include "filter_graph.h" #include "subtitle.h" +#include "audio_buffers.h" #include "i18n.h" @@ -219,8 +220,10 @@ FFmpegDecoder::setup_subtitle () bool FFmpegDecoder::pass () { - int r = av_read_frame (_format_context, &_packet); + cout << "FFmpeg::pass\n"; + int r = av_read_frame (_format_context, &_packet); + if (r < 0) { if (r != AVERROR_EOF) { /* Maybe we should fail here, but for now we'll just finish off instead */ diff --git a/src/lib/film.cc b/src/lib/film.cc index b8102d315..646b114da 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -108,7 +108,7 @@ Film::Film (string d, bool must_exist) , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) - , _dcp_frame_rate (0) + , _dcp_video_frame_rate (0) , _dirty (false) { set_dci_date_today (); @@ -179,7 +179,7 @@ Film::Film (Film const & o) , _colour_lut (o._colour_lut) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) - , _dcp_frame_rate (o._dcp_frame_rate) + , _dcp_video_frame_rate (o._dcp_video_frame_rate) , _dci_date (o._dci_date) , _dirty (o._dirty) { @@ -198,7 +198,7 @@ Film::video_state_identifier () const s << format()->id() << "_" << _playlist->video_digest() << "_" << crop().left << "_" << crop().right << "_" << crop().top << "_" << crop().bottom - << "_" << _dcp_frame_rate + << "_" << _dcp_video_frame_rate << "_" << f.first << "_" << f.second << "_" << scaler()->id() << "_" << j2k_bandwidth() @@ -315,8 +315,8 @@ Film::make_dcp () throw MissingSettingError (_("format")); } - if (_playlist->content().empty ()) { - throw MissingSettingError (_("content")); + if (_playlist->regions().empty ()) { + throw StringError (_("You must add some content to the DCP before creating it")); } if (dcp_content_type() == 0) { @@ -450,9 +450,8 @@ Film::write_metadata () const root->add_child("ColourLUT")->add_child_text (boost::lexical_cast (_colour_lut)); root->add_child("J2KBandwidth")->add_child_text (boost::lexical_cast (_j2k_bandwidth)); _dci_metadata.as_xml (root->add_child ("DCIMetadata")); - root->add_child("DCPFrameRate")->add_child_text (boost::lexical_cast (_dcp_frame_rate)); + root->add_child("DCPVideoFrameRate")->add_child_text (boost::lexical_cast (_dcp_video_frame_rate)); root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date)); - _audio_mapping.as_xml (root->add_child("AudioMapping")); _playlist->as_xml (root->add_child ("Playlist")); doc.write_to_file_formatted (file ("metadata.xml")); @@ -524,11 +523,10 @@ Film::read_metadata () _colour_lut = f.number_child ("ColourLUT"); _j2k_bandwidth = f.number_child ("J2KBandwidth"); _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); - _dcp_frame_rate = f.number_child ("DCPFrameRate"); + _dcp_video_frame_rate = f.number_child ("DCPVideoFrameRate"); _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate")); _playlist->set_from_xml (f.node_child ("Playlist")); - _audio_mapping.set_from_xml (_playlist->content(), f.node_child ("AudioMapping")); _dirty = false; } @@ -577,32 +575,6 @@ Film::file (string f) const return p.string (); } -/** @return The sampling rate that we will resample the audio to */ -int -Film::target_audio_sample_rate () const -{ - if (!has_audio ()) { - return 0; - } - - /* Resample to a DCI-approved sample rate */ - double t = dcp_audio_sample_rate (audio_frame_rate()); - - FrameRateConversion frc (video_frame_rate(), dcp_frame_rate()); - - /* Compensate if the DCP is being run at a different frame rate - to the source; that is, if the video is run such that it will - look different in the DCP compared to the source (slower or faster). - skip/repeat doesn't come into effect here. - */ - - if (frc.change_speed) { - t *= video_frame_rate() * frc.factor() / dcp_frame_rate(); - } - - return rint (t); -} - /** @return a DCI-compliant name for a DCP of this film */ string Film::dci_name (bool if_created_now) const @@ -649,22 +621,7 @@ Film::dci_name (bool if_created_now) const } } - switch (audio_channels ()) { - case 1: - d << "_10"; - break; - case 2: - d << "_20"; - break; - case 6: - d << "_51"; - break; - case 8: - d << "_71"; - break; - } - - d << "_2K"; + d << "_51_2K"; if (!dm.studio.empty ()) { d << "_" << dm.studio; @@ -738,11 +695,11 @@ Film::set_trust_content_headers (bool t) signal_changed (TRUST_CONTENT_HEADERS); - ContentList content = _playlist->content (); - if (!_trust_content_headers && !content.empty()) { + Playlist::RegionList regions = _playlist->regions (); + if (!_trust_content_headers && !regions.empty()) { /* We just said that we don't trust the content's header */ - for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { - examine_content (*i); + for (Playlist::RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { + examine_content (i->content); } } } @@ -976,13 +933,13 @@ Film::set_dci_metadata (DCIMetadata m) void -Film::set_dcp_frame_rate (int f) +Film::set_dcp_video_frame_rate (int f) { { boost::mutex::scoped_lock lm (_state_mutex); - _dcp_frame_rate = f; + _dcp_video_frame_rate = f; } - signal_changed (DCP_FRAME_RATE); + signal_changed (DCP_VIDEO_FRAME_RATE); } void @@ -995,8 +952,7 @@ Film::signal_changed (Property p) switch (p) { case Film::CONTENT: - set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ())); - set_audio_mapping (_playlist->default_audio_mapping ()); + set_dcp_video_frame_rate (_playlist->best_dcp_frame_rate ()); break; default: break; @@ -1082,10 +1038,10 @@ Film::playlist () const return _playlist; } -ContentList -Film::content () const +Playlist::RegionList +Film::regions () const { - return _playlist->content (); + return _playlist->regions (); } void @@ -1101,64 +1057,10 @@ Film::remove_content (shared_ptr c) _playlist->remove (c); } -void -Film::move_content_earlier (shared_ptr c) -{ - _playlist->move_earlier (c); -} - -void -Film::move_content_later (shared_ptr c) -{ - _playlist->move_later (c); -} - -ContentAudioFrame -Film::audio_length () const -{ - return _playlist->audio_length (); -} - -int -Film::audio_channels () const -{ - return _playlist->audio_channels (); -} - -int -Film::audio_frame_rate () const -{ - return _playlist->audio_frame_rate (); -} - -bool -Film::has_audio () const -{ - return _playlist->has_audio (); -} - -float -Film::video_frame_rate () const -{ - return _playlist->video_frame_rate (); -} - -libdcp::Size -Film::video_size () const +Time +Film::length () const { - return _playlist->video_size (); -} - -ContentVideoFrame -Film::video_length () const -{ - return _playlist->video_length (); -} - -ContentVideoFrame -Film::content_length () const -{ - return _playlist->content_length (); + return _playlist->length (shared_from_this ()); } bool @@ -1167,24 +1069,17 @@ Film::has_subtitles () const return _playlist->has_subtitles (); } -void -Film::set_audio_mapping (AudioMapping m) +OutputVideoFrame +Film::best_dcp_video_frame_rate () const { - { - boost::mutex::scoped_lock lm (_state_mutex); - _audio_mapping = m; - } - - signal_changed (AUDIO_MAPPING); + return _playlist->best_dcp_frame_rate (); } void Film::playlist_content_changed (boost::weak_ptr c, int p) { if (p == VideoContentProperty::VIDEO_FRAME_RATE) { - set_dcp_frame_rate (best_dcp_frame_rate (video_frame_rate ())); - } else if (p == AudioContentProperty::AUDIO_CHANNELS) { - set_audio_mapping (_playlist->default_audio_mapping ()); + set_dcp_video_frame_rate (_playlist->best_dcp_frame_rate ()); } if (ui_signaller) { @@ -1209,3 +1104,34 @@ Film::set_loop (int c) { _playlist->set_loop (c); } + +OutputAudioFrame +Film::time_to_audio_frames (Time t) const +{ + return t * dcp_audio_frame_rate () / TIME_HZ; +} + +OutputVideoFrame +Film::time_to_video_frames (Time t) const +{ + return t * dcp_video_frame_rate () / TIME_HZ; +} + +Time +Film::audio_frames_to_time (OutputAudioFrame f) const +{ + return f * TIME_HZ / dcp_audio_frame_rate (); +} + +Time +Film::video_frames_to_time (OutputVideoFrame f) const +{ + return f * TIME_HZ / dcp_video_frame_rate (); +} + +OutputAudioFrame +Film::dcp_audio_frame_rate () const +{ + /* XXX */ + return 48000; +} diff --git a/src/lib/film.h b/src/lib/film.h index 18255a15e..cfc55c0ac 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -36,7 +36,7 @@ #include "dci_metadata.h" #include "types.h" #include "ffmpeg_content.h" -#include "audio_mapping.h" +#include "playlist.h" class DCPContentType; class Format; @@ -48,7 +48,6 @@ class AnalyseAudioJob; class ExternalAudioStream; class Content; class Player; -class Playlist; /** @class Film * @brief A representation of some audio and video content, and details of @@ -87,8 +86,6 @@ public: std::string file (std::string f) const; std::string dir (std::string d) const; - int target_audio_sample_rate () const; - void write_metadata () const; libdcp::Size cropped_size (libdcp::Size) const; @@ -105,27 +102,24 @@ public: boost::shared_ptr player () const; boost::shared_ptr playlist () const; - /* Proxies for some Playlist methods */ + OutputAudioFrame dcp_audio_frame_rate () const; - ContentList content () const; + OutputAudioFrame time_to_audio_frames (Time) const; + OutputVideoFrame time_to_video_frames (Time) const; + Time video_frames_to_time (OutputVideoFrame) const; + Time audio_frames_to_time (OutputAudioFrame) const; - ContentAudioFrame audio_length () const; - int audio_channels () const; - int audio_frame_rate () const; - bool has_audio () const; + /* Proxies for some Playlist methods */ - bool has_subtitles () const; - - float video_frame_rate () const; - libdcp::Size video_size () const; - ContentVideoFrame video_length () const; + Playlist::RegionList regions () const; - ContentVideoFrame content_length () const; + Time length () const; + bool has_subtitles () const; + OutputVideoFrame best_dcp_video_frame_rate () const; void set_loop (int); int loop () const; - enum TrimType { CPL, ENCODE @@ -159,7 +153,7 @@ public: COLOUR_LUT, J2K_BANDWIDTH, DCI_METADATA, - DCP_FRAME_RATE, + DCP_VIDEO_FRAME_RATE, AUDIO_MAPPING }; @@ -271,14 +265,10 @@ public: return _dci_metadata; } - int dcp_frame_rate () const { - boost::mutex::scoped_lock lm (_state_mutex); - return _dcp_frame_rate; - } - - AudioMapping audio_mapping () const { + /* XXX: -> "video_frame_rate" */ + int dcp_video_frame_rate () const { boost::mutex::scoped_lock lm (_state_mutex); - return _audio_mapping; + return _dcp_video_frame_rate; } /* SET */ @@ -289,8 +279,6 @@ public: void set_trust_content_headers (bool); void add_content (boost::shared_ptr); void remove_content (boost::shared_ptr); - void move_content_earlier (boost::shared_ptr); - void move_content_later (boost::shared_ptr); void set_dcp_content_type (DCPContentType const *); void set_format (Format const *); void set_crop (Crop); @@ -312,9 +300,8 @@ public: void set_colour_lut (int); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); - void set_dcp_frame_rate (int); + void set_dcp_video_frame_rate (int); void set_dci_date_today (); - void set_audio_mapping (AudioMapping); /** Emitted when some property has of the Film has changed */ mutable boost::signals2::signal Changed; @@ -398,10 +385,9 @@ private: /** DCI naming stuff */ DCIMetadata _dci_metadata; /** Frames per second to run our DCP at */ - int _dcp_frame_rate; + int _dcp_video_frame_rate; /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; - AudioMapping _audio_mapping; /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --git a/src/lib/format.cc b/src/lib/format.cc index f5026c0da..688b22f16 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -208,7 +208,8 @@ VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d) float VariableFormat::ratio (shared_ptr f) const { - libdcp::Size const c = f->cropped_size (f->video_size ()); + /* XXX */ + libdcp::Size const c;// = f->cropped_size (f->video_size ()); return float (c.width) / c.height; } diff --git a/src/lib/format.h b/src/lib/format.h index d45a3a10a..29347a3fd 100644 --- a/src/lib/format.h +++ b/src/lib/format.h @@ -24,7 +24,7 @@ #include #include -#include "util.h" +#include class Film; diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index 9e5f00ba0..2e42e25f3 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -98,3 +98,10 @@ ImageMagickContent::set_video_length (ContentVideoFrame len) signal_changed (VideoContentProperty::VIDEO_LENGTH); } + +Time +ImageMagickContent::length (shared_ptr film) const +{ + FrameRateConversion frc (24, film->dcp_video_frame_rate ()); + return video_length() * frc.factor() * TIME_HZ / film->dcp_video_frame_rate (); +} diff --git a/src/lib/imagemagick_content.h b/src/lib/imagemagick_content.h index b1e7f9495..366049002 100644 --- a/src/lib/imagemagick_content.h +++ b/src/lib/imagemagick_content.h @@ -38,6 +38,7 @@ public: std::string summary () const; void as_xml (xmlpp::Node *) const; boost::shared_ptr clone () const; + Time length (boost::shared_ptr) const; void set_video_length (ContentVideoFrame); diff --git a/src/lib/player.cc b/src/lib/player.cc index 95036cfe0..9cc166204 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -27,9 +27,11 @@ #include "sndfile_content.h" #include "playlist.h" #include "job.h" +#include "image.h" using std::list; using std::cout; +using std::min; using std::vector; using boost::shared_ptr; using boost::weak_ptr; @@ -42,6 +44,11 @@ Player::Player (shared_ptr f, shared_ptr p) , _audio (true) , _subtitles (true) , _have_valid_decoders (false) + , _position (0) + , _audio_buffers (MAX_AUDIO_CHANNELS, 0) + , _last_video (0) + , _last_was_black (false) + , _last_audio (0) { _playlist->Changed.connect (bind (&Player::playlist_changed, this)); _playlist->ContentChanged.connect (bind (&Player::content_changed, this, _1, _2)); @@ -72,118 +79,118 @@ Player::pass () setup_decoders (); _have_valid_decoders = true; } - - bool done = true; - - if (_video && _video_decoder < _video_decoders.size ()) { - - /* Run video decoder; this may also produce audio */ - - if (_video_decoders[_video_decoder]->pass ()) { - _video_decoder++; - } - - if (_video_decoder < _video_decoders.size ()) { - done = false; - } - - } - - if (!_video && _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG && _sequential_audio_decoder < _audio_decoders.size ()) { - - /* We're not producing video, so we may need to run FFmpeg content to get the audio */ - - if (_audio_decoders[_sequential_audio_decoder]->pass ()) { - _sequential_audio_decoder++; - } - - if (_sequential_audio_decoder < _audio_decoders.size ()) { - done = false; - } - - } - - if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { - - /* We're getting audio from SndfileContent */ - - for (vector >::iterator i = _audio_decoders.begin(); i != _audio_decoders.end(); ++i) { - if (!(*i)->pass ()) { - done = false; - } - } - Audio (_audio_buffers, _audio_time.get()); - _audio_buffers.reset (); - _audio_time = boost::none; - } - - return done; + cout << "-> Player::pass\n"; + + /* Here we are just finding the active decoder with the earliest last emission time, then + calling pass on it. If there is no decoder, we skip our position on until there is. + Hence this method will cause video and audio to be emitted, and it is up to the + process_{video,audio} methods to tidy it up. + */ + + Time earliest_pos = TIME_MAX; + shared_ptr earliest; + Time next_wait = TIME_MAX; + + for (list >::iterator i = _decoders.begin(); i != _decoders.end(); ++i) { + Time const ts = (*i)->region.time; + Time const te = (*i)->region.time + (*i)->region.content->length (_film); + if (ts <= _position && te > _position) { + Time const pos = ts + (*i)->last; + if (pos < earliest_pos) { + earliest_pos = pos; + earliest = *i; + } + } + + if (ts > _position) { + next_wait = min (next_wait, ts - _position); + } + } + + if (earliest) { + earliest->decoder->pass (); + _position = earliest->last; + } else if (next_wait < TIME_MAX) { + _position += next_wait; + } else { + cout << "<- Player::pass\n"; + return true; + } + + cout << "<- Player::pass\n"; + return false; } void -Player::process_video (shared_ptr i, bool same, shared_ptr s, double t) +Player::process_video (shared_ptr rd, shared_ptr image, bool same, shared_ptr sub, Time time) { - Video (i, same, s, _video_start[_video_decoder] + t); + shared_ptr vd = dynamic_pointer_cast (rd->decoder); + + Time const global_time = rd->region.time + time; + while ((global_time - _last_video) > 1) { + /* Fill in with black */ + emit_black_frame (); + } + + Video (image, same, sub, global_time); + rd->last = time; + _last_video = global_time; + _last_was_black = false; } void -Player::process_audio (weak_ptr c, shared_ptr b, double t) +Player::process_audio (shared_ptr rd, shared_ptr audio, Time time) { - AudioMapping mapping = _film->audio_mapping (); - if (!_audio_buffers) { - _audio_buffers.reset (new AudioBuffers (mapping.dcp_channels(), b->frames ())); - _audio_buffers->make_silent (); - _audio_time = t; - if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - _audio_time = _audio_time.get() + _audio_start[_sequential_audio_decoder]; - } - } - - for (int i = 0; i < b->channels(); ++i) { - list dcp = mapping.content_to_dcp (AudioMapping::Channel (c, i)); - for (list::iterator j = dcp.begin(); j != dcp.end(); ++j) { - _audio_buffers->accumulate (b, i, static_cast (*j)); - } - } - - if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - /* We can just emit this audio now as it will all be here */ - Audio (_audio_buffers, t); - _audio_buffers.reset (); - _audio_time = boost::none; - } + /* XXX: mapping */ + + /* The time of this audio may indicate that some of our buffered audio is not going to + be added to any more, so it can be emitted. + */ + + if (time > _last_audio) { + /* We can emit some audio from our buffers */ + OutputAudioFrame const N = min (_film->time_to_audio_frames (time - _last_audio), static_cast (_audio_buffers.frames())); + shared_ptr emit (new AudioBuffers (_audio_buffers.channels(), N)); + emit->copy_from (&_audio_buffers, N, 0, 0); + Audio (emit, _last_audio); + _last_audio += _film->audio_frames_to_time (N); + + /* And remove it from our buffers */ + if (_audio_buffers.frames() > N) { + _audio_buffers.move (N, 0, _audio_buffers.frames() - N); + } + _audio_buffers.set_frames (_audio_buffers.frames() - N); + } + + /* Now accumulate the new audio into our buffers */ + + if (_audio_buffers.frames() == 0) { + /* We have no remaining data. Emit silence up to the start of this new data */ + if ((time - _last_audio) > 0) { + emit_silence (time - _last_audio); + } + } + + _audio_buffers.ensure_size (time - _last_audio + audio->frames()); + _audio_buffers.accumulate (audio.get(), 0, _film->time_to_audio_frames (time - _last_audio)); + rd->last = time + _film->audio_frames_to_time (audio->frames ()); } /** @return true on error */ bool -Player::seek (double t) +Player::seek (Time t) { if (!_have_valid_decoders) { setup_decoders (); _have_valid_decoders = true; } - if (_video_decoders.empty ()) { + if (_decoders.empty ()) { return true; } - /* Find the decoder that contains this position */ - _video_decoder = 0; - while (1) { - ++_video_decoder; - if (_video_decoder >= _video_decoders.size () || t < _video_start[_video_decoder]) { - --_video_decoder; - t -= _video_start[_video_decoder]; - break; - } - } - - if (_video_decoder < _video_decoders.size()) { - _video_decoders[_video_decoder]->seek (t); - } else { - return true; - } + /* XXX */ /* XXX: don't seek audio because we don't need to... */ @@ -207,106 +214,60 @@ Player::seek_forward () void Player::setup_decoders () { - vector > old_video_decoders = _video_decoders; + list > old_decoders = _decoders; - _video_decoders.clear (); - _video_decoder = 0; - _audio_decoders.clear (); - _sequential_audio_decoder = 0; + _decoders.clear (); - _video_start.clear(); - _audio_start.clear(); + Playlist::RegionList regions = _playlist->regions (); + for (Playlist::RegionList::iterator i = regions.begin(); i != regions.end(); ++i) { - double video_so_far = 0; - double audio_so_far = 0; + shared_ptr rd (new RegionDecoder); + rd->region = *i; + + /* XXX: into content? */ - for (int l = 0; l < _playlist->loop(); ++l) { - list > vc = _playlist->video (); - for (list >::iterator i = vc.begin(); i != vc.end(); ++i) { - - shared_ptr video_content; - shared_ptr audio_content; - shared_ptr video_decoder; - shared_ptr audio_decoder; - - /* XXX: into content? */ + shared_ptr fc = dynamic_pointer_cast (i->content); + if (fc) { + shared_ptr fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles)); - shared_ptr fc = dynamic_pointer_cast (*i); - if (fc) { - shared_ptr fd ( - new FFmpegDecoder ( - _film, fc, _video, - _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, - _subtitles - ) - ); - - video_content = fc; - audio_content = fc; - video_decoder = fd; - audio_decoder = fd; - - video_decoder->connect_video (shared_from_this ()); - } - - shared_ptr ic = dynamic_pointer_cast (*i); - if (ic) { - video_content = ic; - - /* See if we can re-use an old ImageMagickDecoder */ - for (vector >::const_iterator i = old_video_decoders.begin(); i != old_video_decoders.end(); ++i) { - shared_ptr imd = dynamic_pointer_cast (*i); - if (imd && imd->content() == ic) { - video_decoder = *i; - } - } + fd->Video.connect (bind (&Player::process_video, this, rd, _1, _2, _3, _4)); + fd->Audio.connect (bind (&Player::process_audio, this, rd, _1, _2)); - if (!video_decoder) { - video_decoder.reset (new ImageMagickDecoder (_film, ic)); - video_decoder->connect_video (shared_from_this ()); - } - } - - _video_decoders.push_back (video_decoder); - _video_start.push_back (video_so_far); - video_so_far += video_content->video_length() / video_content->video_frame_rate(); - - if (audio_decoder && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - audio_decoder->Audio.connect (bind (&Player::process_audio, this, audio_content, _1, _2)); - _audio_decoders.push_back (audio_decoder); - _audio_start.push_back (audio_so_far); - audio_so_far += double(audio_content->audio_length()) / audio_content->audio_frame_rate(); - } + rd->decoder = fd; } - _video_decoder = 0; - _sequential_audio_decoder = 0; - - if (_playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + shared_ptr ic = dynamic_pointer_cast (i->content); + if (ic) { + shared_ptr id; - list > ac = _playlist->audio (); - for (list >::iterator i = ac.begin(); i != ac.end(); ++i) { - - shared_ptr sc = dynamic_pointer_cast (*i); - assert (sc); - - shared_ptr d (new SndfileDecoder (_film, sc)); - d->Audio.connect (bind (&Player::process_audio, this, sc, _1, _2)); - _audio_decoders.push_back (d); - _audio_start.push_back (audio_so_far); + /* See if we can re-use an old ImageMagickDecoder */ + for (list >::const_iterator i = old_decoders.begin(); i != old_decoders.end(); ++i) { + shared_ptr imd = dynamic_pointer_cast ((*i)->decoder); + if (imd && imd->content() == ic) { + id = imd; + } + } + + if (!id) { + id.reset (new ImageMagickDecoder (_film, ic)); + id->Video.connect (bind (&Player::process_video, this, rd, _1, _2, _3, _4)); } + + rd->decoder = id; } - } -} -double -Player::last_video_time () const -{ - if (_video_decoder >= _video_decoders.size ()) { - return 0; + shared_ptr sc = dynamic_pointer_cast (i->content); + if (sc) { + shared_ptr sd (new SndfileDecoder (_film, sc)); + sd->Audio.connect (bind (&Player::process_audio, this, rd, _1, _2)); + + rd->decoder = sd; + } + + _decoders.push_back (rd); } - - return _video_start[_video_decoder] + _video_decoders[_video_decoder]->last_content_time (); + + _position = 0; } void @@ -327,3 +288,26 @@ Player::playlist_changed () { _have_valid_decoders = false; } + +void +Player::emit_black_frame () +{ + shared_ptr image (new SimpleImage (AV_PIX_FMT_RGB24, libdcp::Size (128, 128), true)); + Video (image, _last_was_black, shared_ptr (), _last_video); + _last_video += _film->video_frames_to_time (1); +} + +void +Player::emit_silence (Time t) +{ + OutputAudioFrame frames = _film->time_to_audio_frames (t); + while (frames) { + /* Do this in half-second chunks so we don't overwhelm anybody */ + OutputAudioFrame this_time = min (_film->dcp_audio_frame_rate() / 2, frames); + shared_ptr silence (new AudioBuffers (MAX_AUDIO_CHANNELS, this_time)); + silence->make_silent (); + Audio (silence, _last_audio); + _last_audio += _film->audio_frames_to_time (this_time); + frames -= this_time; + } +} diff --git a/src/lib/player.h b/src/lib/player.h index b1be2f456..c9bf2a00b 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -27,19 +27,20 @@ #include "audio_source.h" #include "video_sink.h" #include "audio_sink.h" +#include "playlist.h" +#include "audio_buffers.h" -class VideoDecoder; -class AudioDecoder; class Job; class Film; class Playlist; class AudioContent; +class Decoder; /** @class Player * @brief A class which can `play' a Playlist; emitting its audio and video. */ -class Player : public VideoSource, public AudioSource, public VideoSink, public boost::enable_shared_from_this +class Player : public VideoSource, public AudioSource, public boost::enable_shared_from_this { public: Player (boost::shared_ptr, boost::shared_ptr); @@ -49,18 +50,34 @@ public: void disable_subtitles (); bool pass (); - bool seek (double); + bool seek (Time); void seek_back (); void seek_forward (); - double last_video_time () const; + Time last_video () const { + return _last_video; + } private: - void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double); - void process_audio (boost::weak_ptr, boost::shared_ptr, double); + + struct RegionDecoder + { + RegionDecoder () + : last (0) + {} + + Playlist::Region region; + boost::shared_ptr decoder; + Time last; + }; + + void process_video (boost::shared_ptr, boost::shared_ptr, bool, boost::shared_ptr, Time); + void process_audio (boost::shared_ptr, boost::shared_ptr, Time); void setup_decoders (); void playlist_changed (); void content_changed (boost::weak_ptr, int); + void emit_black_frame (); + void emit_silence (Time); boost::shared_ptr _film; boost::shared_ptr _playlist; @@ -71,21 +88,13 @@ private: /** Our decoders are ready to go; if this is false the decoders must be (re-)created before they are used */ bool _have_valid_decoders; - /** Video decoders in order of presentation */ - std::vector > _video_decoders; - /** Start positions of each video decoder in seconds*/ - std::vector _video_start; - /** Index of current video decoder */ - size_t _video_decoder; - /** Audio decoders in order of presentation (if they are from FFmpeg) */ - std::vector > _audio_decoders; - /** Start positions of each audio decoder (if they are from FFmpeg) in seconds */ - std::vector _audio_start; - /** Current audio decoder index if we are running them sequentially; otherwise undefined */ - size_t _sequential_audio_decoder; - - boost::shared_ptr _audio_buffers; - boost::optional _audio_time; + std::list > _decoders; + + Time _position; + AudioBuffers _audio_buffers; + Time _last_video; + bool _last_was_black; + Time _last_audio; }; #endif diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index f1dd881b3..8f4a35ac2 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -29,6 +29,8 @@ #include "imagemagick_decoder.h" #include "imagemagick_content.h" #include "job.h" +#include "config.h" +#include "util.h" #include "i18n.h" @@ -39,171 +41,24 @@ using std::min; using std::max; using std::string; using std::stringstream; +using boost::optional; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; using boost::lexical_cast; Playlist::Playlist () - : _audio_from (AUDIO_FFMPEG) - , _loop (1) + : _loop (1) { } Playlist::Playlist (shared_ptr other) - : _audio_from (other->_audio_from) - , _loop (other->_loop) + : _loop (other->_loop) { - for (ContentList::const_iterator i = other->_content.begin(); i != other->_content.end(); ++i) { - _content.push_back ((*i)->clone ()); + for (RegionList::const_iterator i = other->_regions.begin(); i != other->_regions.end(); ++i) { + _regions.push_back (Region (i->content->clone(), i->time, this)); } - - setup (); -} - -void -Playlist::setup () -{ - _audio_from = AUDIO_FFMPEG; - - _video.clear (); - _audio.clear (); - - for (list::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) { - i->disconnect (); - } - - _content_connections.clear (); - - for (ContentList::const_iterator i = _content.begin(); i != _content.end(); ++i) { - - /* Video is video */ - shared_ptr vc = dynamic_pointer_cast (*i); - if (vc) { - _video.push_back (vc); - } - - /* FFmpegContent is audio if we are doing AUDIO_FFMPEG */ - shared_ptr fc = dynamic_pointer_cast (*i); - if (fc && _audio_from == AUDIO_FFMPEG) { - _audio.push_back (fc); - } - - /* SndfileContent trumps FFmpegContent for audio */ - shared_ptr sc = dynamic_pointer_cast (*i); - if (sc) { - if (_audio_from == AUDIO_FFMPEG) { - /* This is our fist SndfileContent; clear any FFmpegContent and - say that we are using Sndfile. - */ - _audio.clear (); - _audio_from = AUDIO_SNDFILE; - } - - _audio.push_back (sc); - } - - _content_connections.push_back ((*i)->Changed.connect (bind (&Playlist::content_changed, this, _1, _2))); - } -} - -/** @return Length of our audio */ -ContentAudioFrame -Playlist::audio_length () const -{ - ContentAudioFrame len = 0; - - switch (_audio_from) { - case AUDIO_FFMPEG: - /* FFmpeg content is sequential */ - for (list >::const_iterator i = _audio.begin(); i != _audio.end(); ++i) { - len += (*i)->audio_length (); - } - break; - case AUDIO_SNDFILE: - /* Sndfile content is simultaneous */ - for (list >::const_iterator i = _audio.begin(); i != _audio.end(); ++i) { - len = max (len, (*i)->audio_length ()); - } - break; - } - - return len * _loop; -} - -/** @return number of audio channels */ -int -Playlist::audio_channels () const -{ - int channels = 0; - - switch (_audio_from) { - case AUDIO_FFMPEG: - /* FFmpeg audio is sequential, so use the maximum channel count */ - for (list >::const_iterator i = _audio.begin(); i != _audio.end(); ++i) { - channels = max (channels, (*i)->audio_channels ()); - } - break; - case AUDIO_SNDFILE: - /* Sndfile audio is simultaneous, so it's the sum of the channel counts */ - for (list >::const_iterator i = _audio.begin(); i != _audio.end(); ++i) { - channels += (*i)->audio_channels (); - } - break; - } - - return channels; -} - -int -Playlist::audio_frame_rate () const -{ - if (_audio.empty ()) { - return 0; - } - - /* XXX: assuming that all content has the same rate */ - return _audio.front()->audio_frame_rate (); -} - -float -Playlist::video_frame_rate () const -{ - if (_video.empty ()) { - return 0; - } - - /* XXX: assuming all the same */ - return _video.front()->video_frame_rate (); -} - -libdcp::Size -Playlist::video_size () const -{ - if (_video.empty ()) { - return libdcp::Size (); - } - - /* XXX: assuming all the same */ - return _video.front()->video_size (); -} - -ContentVideoFrame -Playlist::video_length () const -{ - ContentVideoFrame len = 0; - for (list >::const_iterator i = _video.begin(); i != _video.end(); ++i) { - len += (*i)->video_length (); - } - - return len * _loop; -} - -bool -Playlist::has_audio () const -{ - return !_audio.empty (); } void @@ -212,62 +67,19 @@ Playlist::content_changed (weak_ptr c, int p) ContentChanged (c, p); } -AudioMapping -Playlist::default_audio_mapping () const -{ - AudioMapping m; - if (_audio.empty ()) { - return m; - } - - switch (_audio_from) { - case AUDIO_FFMPEG: - { - /* XXX: assumes all the same */ - if (_audio.front()->audio_channels() == 1) { - /* Map mono sources to centre */ - m.add (AudioMapping::Channel (_audio.front(), 0), libdcp::CENTRE); - } else { - int const N = min (_audio.front()->audio_channels (), MAX_AUDIO_CHANNELS); - /* Otherwise just start with a 1:1 mapping */ - for (int i = 0; i < N; ++i) { - m.add (AudioMapping::Channel (_audio.front(), i), (libdcp::Channel) i); - } - } - break; - } - - case AUDIO_SNDFILE: - { - int n = 0; - for (list >::const_iterator i = _audio.begin(); i != _audio.end(); ++i) { - for (int j = 0; j < (*i)->audio_channels(); ++j) { - m.add (AudioMapping::Channel (*i, j), (libdcp::Channel) n); - ++n; - if (n >= MAX_AUDIO_CHANNELS) { - break; - } - } - if (n >= MAX_AUDIO_CHANNELS) { - break; - } - } - break; - } - } - - return m; -} - string Playlist::audio_digest () const { string t; - for (list >::const_iterator i = _audio.begin(); i != _audio.end(); ++i) { - t += (*i)->digest (); + for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { + if (!dynamic_pointer_cast (i->content)) { + continue; + } + + t += i->content->digest (); - shared_ptr fc = dynamic_pointer_cast (*i); + shared_ptr fc = dynamic_pointer_cast (i->content); if (fc) { t += lexical_cast (fc->audio_stream()->id); } @@ -283,9 +95,13 @@ Playlist::video_digest () const { string t; - for (list >::const_iterator i = _video.begin(); i != _video.end(); ++i) { - t += (*i)->digest (); - shared_ptr fc = dynamic_pointer_cast (*i); + for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { + if (!dynamic_pointer_cast (i->content)) { + continue; + } + + t += i->content->digest (); + shared_ptr fc = dynamic_pointer_cast (i->content); if (fc && fc->subtitle_stream()) { t += fc->subtitle_stream()->id; } @@ -296,48 +112,22 @@ Playlist::video_digest () const return md5_digest (t.c_str(), t.length()); } -ContentVideoFrame -Playlist::content_length () const -{ - float const vfr = video_frame_rate() > 0 ? video_frame_rate() : 24; - int const afr = audio_frame_rate() > 0 ? audio_frame_rate() : 48000; - - return max ( - video_length(), - ContentVideoFrame (audio_length() * vfr / afr) - ); -} - void Playlist::set_from_xml (shared_ptr node) { - list > c = node->node_children ("Content"); + list > c = node->node_children ("Region"); for (list >::iterator i = c.begin(); i != c.end(); ++i) { - - string const type = (*i)->string_child ("Type"); - boost::shared_ptr c; - - if (type == "FFmpeg") { - c.reset (new FFmpegContent (*i)); - } else if (type == "ImageMagick") { - c.reset (new ImageMagickContent (*i)); - } else if (type == "Sndfile") { - c.reset (new SndfileContent (*i)); - } - - _content.push_back (c); + _regions.push_back (Region (*i, this)); } _loop = node->number_child ("Loop"); - - setup (); } void Playlist::as_xml (xmlpp::Node* node) { - for (ContentList::iterator i = _content.begin(); i != _content.end(); ++i) { - (*i)->as_xml (node->add_child ("Content")); + for (RegionList::iterator i = _regions.begin(); i != _regions.end(); ++i) { + i->as_xml (node->add_child ("Region")); } node->add_child("Loop")->add_child_text(lexical_cast (_loop)); @@ -346,87 +136,146 @@ Playlist::as_xml (xmlpp::Node* node) void Playlist::add (shared_ptr c) { - _content.push_back (c); - setup (); + _regions.push_back (Region (c, 0, this)); Changed (); } void Playlist::remove (shared_ptr c) { - ContentList::iterator i = find (_content.begin(), _content.end(), c); - if (i != _content.end ()) { - _content.erase (i); + RegionList::iterator i = _regions.begin (); + while (i != _regions.end() && i->content != c) { + ++i; } + + if (i != _regions.end ()) { + _regions.erase (i); + Changed (); + } +} - setup (); +void +Playlist::set_loop (int l) +{ + _loop = l; Changed (); } -void -Playlist::move_earlier (shared_ptr c) +bool +Playlist::has_subtitles () const { - ContentList::iterator i = find (_content.begin(), _content.end(), c); - if (i == _content.begin () || i == _content.end()) { - return; + for (RegionList::const_iterator i = _regions.begin(); i != _regions.end(); ++i) { + shared_ptr fc = dynamic_pointer_cast (i->content); + if (fc && !fc->subtitle_streams().empty()) { + return true; + } } - ContentList::iterator j = i; - --j; - - swap (*i, *j); - - setup (); - Changed (); + return false; } -void -Playlist::move_later (shared_ptr c) +Playlist::Region::Region (shared_ptr c, Time t, Playlist* p) + : content (c) + , time (t) { - ContentList::iterator i = find (_content.begin(), _content.end(), c); - if (i == _content.end()) { - return; - } + connection = c->Changed.connect (bind (&Playlist::content_changed, p, _1, _2)); +} - ContentList::iterator j = i; - ++j; - if (j == _content.end ()) { - return; +Playlist::Region::Region (shared_ptr node, Playlist* p) +{ + shared_ptr content_node = node->node_child ("Content"); + string const type = content_node->string_child ("Type"); + + if (type == "FFmpeg") { + content.reset (new FFmpegContent (content_node)); + } else if (type == "ImageMagick") { + content.reset (new ImageMagickContent (content_node)); + } else if (type == "Sndfile") { + content.reset (new SndfileContent (content_node)); } - swap (*i, *j); - - setup (); - Changed (); + time = node->number_child