From 9db7ed5f6499de903313a85d59bb70302e97e7ff Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 17 Jan 2013 00:24:13 +0000 Subject: shared_ptr is a bit excessive for DecodeOptions. --- src/lib/decoder.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib/decoder.cc') diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 7066b488e..fd0abee41 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -46,10 +46,10 @@ using boost::shared_ptr; using boost::optional; /** @param f Film. - * @param o Options. + * @param o Decode options. * @param j Job that we are running within, or 0 */ -Decoder::Decoder (boost::shared_ptr f, boost::shared_ptr o, Job* j) +Decoder::Decoder (boost::shared_ptr f, DecodeOptions o, Job* j) : _film (f) , _opt (o) , _job (j) -- cgit v1.2.3 From 2e536ef0971edefea23810b99f7706881072783b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 8 Feb 2013 13:07:16 +0000 Subject: Shuffle Job pointers around slightly. --- src/lib/ab_transcoder.cc | 8 +++++--- src/lib/audio_decoder.cc | 4 ++-- src/lib/audio_decoder.h | 2 +- src/lib/decoder.cc | 5 +---- src/lib/decoder.h | 5 +---- src/lib/decoder_factory.cc | 10 +++++----- src/lib/decoder_factory.h | 3 +-- src/lib/examine_content_job.cc | 4 ++-- src/lib/external_audio_decoder.cc | 6 +++--- src/lib/external_audio_decoder.h | 2 +- src/lib/ffmpeg_decoder.cc | 8 ++++---- src/lib/ffmpeg_decoder.h | 2 +- src/lib/film.cc | 4 ++-- src/lib/imagemagick_decoder.cc | 6 +++--- src/lib/imagemagick_decoder.h | 2 +- src/lib/transcoder.cc | 6 ++++-- src/lib/video_decoder.cc | 12 +++++++----- src/lib/video_decoder.h | 4 ++-- src/wx/film_viewer.cc | 2 +- 19 files changed, 47 insertions(+), 48 deletions(-) (limited to 'src/lib/decoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index fc4fb8daa..f47a99fda 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -55,8 +55,8 @@ ABTranscoder::ABTranscoder ( , _job (j) , _encoder (e) { - _da = decoder_factory (_film_a, o, j); - _db = decoder_factory (_film_b, o, j); + _da = decoder_factory (_film_a, o); + _db = decoder_factory (_film_b, o); if (_film_a->audio_stream()) { shared_ptr st = _film_a->audio_stream(); @@ -98,7 +98,9 @@ ABTranscoder::go () bool const vb = _db.video->pass (); bool const a = _da.audio->pass (); - _da.video->set_progress (); + if (_job) { + _da.video->set_progress (_job); + } if (va && vb && a) { break; diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index a038dd2bb..a54c14843 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -23,8 +23,8 @@ using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f, DecodeOptions o, Job* j) - : Decoder (f, o, j) +AudioDecoder::AudioDecoder (shared_ptr f, DecodeOptions o) + : Decoder (f, o) { } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 3bf585f4d..9bef8e0e7 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -34,7 +34,7 @@ class AudioDecoder : public AudioSource, public virtual Decoder { public: - AudioDecoder (boost::shared_ptr, DecodeOptions, Job *); + AudioDecoder (boost::shared_ptr, DecodeOptions); virtual void set_audio_stream (boost::shared_ptr); diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index fd0abee41..30009460f 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -26,7 +26,6 @@ #include #include "film.h" #include "format.h" -#include "job.h" #include "options.h" #include "exceptions.h" #include "image.h" @@ -47,12 +46,10 @@ using boost::optional; /** @param f Film. * @param o Decode options. - * @param j Job that we are running within, or 0 */ -Decoder::Decoder (boost::shared_ptr f, DecodeOptions o, Job* j) +Decoder::Decoder (boost::shared_ptr f, DecodeOptions o) : _film (f) , _opt (o) - , _job (j) { _film_connection = f->Changed.connect (bind (&Decoder::film_changed, this, _1)); } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index cc4c87373..f2f523516 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -36,7 +36,6 @@ #include "film.h" #include "options.h" -class Job; class Image; class Log; class DelayLine; @@ -54,7 +53,7 @@ class FilterGraph; class Decoder { public: - Decoder (boost::shared_ptr, DecodeOptions, Job *); + Decoder (boost::shared_ptr, DecodeOptions); virtual ~Decoder () {} virtual bool pass () = 0; @@ -68,8 +67,6 @@ protected: boost::shared_ptr _film; /** our decode options */ DecodeOptions _opt; - /** associated Job, or 0 */ - Job* _job; private: virtual void film_changed (Film::Property) {} diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index c4d818f49..59e15722d 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -36,21 +36,21 @@ using boost::dynamic_pointer_cast; Decoders decoder_factory ( - shared_ptr f, DecodeOptions o, Job* j + shared_ptr f, DecodeOptions o ) { 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, j)), - shared_ptr (new ExternalAudioDecoder (f, o, j)) + shared_ptr (new ImageMagickDecoder (f, o)), + shared_ptr (new ExternalAudioDecoder (f, o)) ); } - shared_ptr fd (new FFmpegDecoder (f, o, j)); + shared_ptr fd (new FFmpegDecoder (f, o)); if (f->use_content_audio()) { return Decoders (fd, fd); } - return Decoders (fd, shared_ptr (new ExternalAudioDecoder (f, o, j))); + return Decoders (fd, shared_ptr (new ExternalAudioDecoder (f, o))); } diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h index 445a1c8a2..8076b01c7 100644 --- a/src/lib/decoder_factory.h +++ b/src/lib/decoder_factory.h @@ -27,7 +27,6 @@ #include "options.h" class Film; -class Job; class VideoDecoder; class AudioDecoder; @@ -44,7 +43,7 @@ struct Decoders { }; extern Decoders decoder_factory ( - boost::shared_ptr, DecodeOptions, Job * + boost::shared_ptr, DecodeOptions ); #endif diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index 69a757e2b..94e5320fe 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -81,7 +81,7 @@ ExamineContentJob::run () DecodeOptions o; o.decode_audio = false; - Decoders decoders = decoder_factory (_film, o, this); + Decoders decoders = decoder_factory (_film, o); set_progress_unknown (); while (!decoders.video->pass()) { @@ -96,7 +96,7 @@ ExamineContentJob::run () /* Get a quick decoder to get the content's length from its header */ - Decoders d = decoder_factory (_film, DecodeOptions(), 0); + 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())); diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc index 366051418..9c01bfb34 100644 --- a/src/lib/external_audio_decoder.cc +++ b/src/lib/external_audio_decoder.cc @@ -31,9 +31,9 @@ using std::cout; using boost::shared_ptr; using boost::optional; -ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr f, DecodeOptions o, Job* j) - : Decoder (f, o, j) - , AudioDecoder (f, o, j) +ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr f, DecodeOptions o) + : Decoder (f, o) + , AudioDecoder (f, o) { sf_count_t frames; vector sf = open_files (frames); diff --git a/src/lib/external_audio_decoder.h b/src/lib/external_audio_decoder.h index 37e53bca7..6f010abb1 100644 --- a/src/lib/external_audio_decoder.h +++ b/src/lib/external_audio_decoder.h @@ -44,7 +44,7 @@ private: class ExternalAudioDecoder : public AudioDecoder { public: - ExternalAudioDecoder (boost::shared_ptr, DecodeOptions, Job *); + ExternalAudioDecoder (boost::shared_ptr, DecodeOptions); bool pass (); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 81f405644..1f11f70a0 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -60,10 +60,10 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; -FFmpegDecoder::FFmpegDecoder (shared_ptr f, DecodeOptions o, Job* j) - : Decoder (f, o, j) - , VideoDecoder (f, o, j) - , AudioDecoder (f, o, j) +FFmpegDecoder::FFmpegDecoder (shared_ptr f, DecodeOptions o) + : Decoder (f, o) + , VideoDecoder (f, o) + , AudioDecoder (f, o) , _format_context (0) , _video_stream (-1) , _frame (0) diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 9a4e65ebc..17308eb56 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -86,7 +86,7 @@ private: class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: - FFmpegDecoder (boost::shared_ptr, DecodeOptions, Job *); + FFmpegDecoder (boost::shared_ptr, DecodeOptions); ~FFmpegDecoder (); float frames_per_second () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index 59f79e666..ff4d3b8f5 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -857,7 +857,7 @@ Film::set_content (string c) */ try { - Decoders d = decoder_factory (shared_from_this(), DecodeOptions(), 0); + Decoders d = decoder_factory (shared_from_this(), DecodeOptions()); set_size (d.video->native_size ()); set_frames_per_second (d.video->frames_per_second ()); @@ -1079,7 +1079,7 @@ Film::set_external_audio (vector a) _external_audio = a; } - shared_ptr decoder (new ExternalAudioDecoder (shared_from_this(), DecodeOptions(), 0)); + shared_ptr decoder (new ExternalAudioDecoder (shared_from_this(), DecodeOptions())); if (decoder->audio_stream()) { _external_audio_stream = decoder->audio_stream (); } diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 99b9e1d34..42fe699d7 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -30,9 +30,9 @@ using boost::shared_ptr; using libdcp::Size; ImageMagickDecoder::ImageMagickDecoder ( - boost::shared_ptr f, DecodeOptions o, Job* j) - : Decoder (f, o, j) - , VideoDecoder (f, o, j) + boost::shared_ptr f, DecodeOptions o) + : Decoder (f, o) + , VideoDecoder (f, o) { if (boost::filesystem::is_directory (_film->content_path())) { for ( diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index 84a6f15f9..0e375f6e9 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -26,7 +26,7 @@ namespace Magick { class ImageMagickDecoder : public VideoDecoder { public: - ImageMagickDecoder (boost::shared_ptr, DecodeOptions, Job *); + ImageMagickDecoder (boost::shared_ptr, DecodeOptions); float frames_per_second () const { /* We don't know */ diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 93963761e..959fac857 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -51,7 +51,7 @@ using boost::dynamic_pointer_cast; Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr e) : _job (j) , _encoder (e) - , _decoders (decoder_factory (f, o, j)) + , _decoders (decoder_factory (f, o)) { assert (_encoder); @@ -96,7 +96,9 @@ Transcoder::go () while (1) { if (!done[0]) { done[0] = _decoders.video->pass (); - _decoders.video->set_progress (); + if (_job) { + _decoders.video->set_progress (_job); + } } if (!done[1] && _decoders.audio && dynamic_pointer_cast (_decoders.audio) != dynamic_pointer_cast (_decoders.video)) { diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index c11b752ae..c1f48cb5e 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -28,8 +28,8 @@ using boost::shared_ptr; using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr f, DecodeOptions o, Job* j) - : Decoder (f, o, j) +VideoDecoder::VideoDecoder (shared_ptr f, DecodeOptions o) + : Decoder (f, o) , _video_frame (0) , _last_source_time (0) { @@ -110,9 +110,11 @@ VideoDecoder::set_subtitle_stream (shared_ptr s) } void -VideoDecoder::set_progress () const +VideoDecoder::set_progress (Job* j) const { - if (_job && _film->length()) { - _job->set_progress (float (_video_frame) / _film->length().get()); + assert (j); + + if (_film->length()) { + j->set_progress (float (_video_frame) / _film->length().get()); } } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index ef1ab041a..283ab5d88 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -27,7 +27,7 @@ class VideoDecoder : public VideoSource, public virtual Decoder { public: - VideoDecoder (boost::shared_ptr, DecodeOptions, Job *); + VideoDecoder (boost::shared_ptr, DecodeOptions); /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; @@ -43,7 +43,7 @@ public: virtual void set_subtitle_stream (boost::shared_ptr); - void set_progress () const; + void set_progress (Job *) const; int video_frame () const { return _video_frame; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 4e5f38300..4e779a693 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -101,7 +101,7 @@ FilmViewer::film_changed (Film::Property p) o.decode_audio = false; o.decode_subtitles = true; o.video_sync = false; - _decoders = decoder_factory (_film, o, 0); + _decoders = decoder_factory (_film, o); _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()); -- 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/decoder.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 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/decoder.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/decoder.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 b66010a281acd3e3e58ef7202bce55023fc29d7f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 9 Apr 2013 23:43:00 +0100 Subject: Merge ImageMagick and FFmpeg content into VideoContent list; remove seek_to_last hacks. --- run/dvdomatic | 4 +- src/lib/decoder.cc | 11 +-- src/lib/decoder.h | 1 - src/lib/ffmpeg_decoder.cc | 16 +--- src/lib/ffmpeg_decoder.h | 2 - src/lib/film.cc | 3 +- src/lib/imagemagick_content.cc | 2 +- src/lib/imagemagick_decoder.cc | 10 -- src/lib/imagemagick_decoder.h | 1 - src/lib/player.cc | 205 ++++++++++++++--------------------------- src/lib/player.h | 10 +- src/lib/playlist.cc | 178 ++++++++++++++++++----------------- src/lib/playlist.h | 24 +---- src/lib/video_decoder.cc | 4 +- src/lib/video_decoder.h | 6 +- src/tools/dvdomatic.cc | 21 ++++- src/wx/film_viewer.cc | 2 +- 17 files changed, 196 insertions(+), 304 deletions(-) (limited to 'src/lib/decoder.cc') diff --git a/run/dvdomatic b/run/dvdomatic index 147c001cd..dbc63d44a 100755 --- a/run/dvdomatic +++ b/run/dvdomatic @@ -3,7 +3,7 @@ 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 "$*" + gdb --args build/src/tools/dvdomatic $* elif [ "$1" == "--valgrind" ]; then shift valgrind --tool="memcheck" build/src/tools/dvdomatic $* @@ -11,5 +11,5 @@ elif [ "$1" == "--i18n" ]; then shift LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 build/src/tools/dvdomatic "$*" else - build/src/tools/dvdomatic "$*" + build/src/tools/dvdomatic $* fi diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index c40446919..082ad5076 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -41,7 +41,7 @@ Decoder::Decoder (shared_ptr f) _film_connection = f->Changed.connect (bind (&Decoder::film_changed, this, _1)); } -/** Seek to a position as a source timestamp in seconds. +/** Seek to a position as a content timestamp in seconds. * @return true on error. */ bool @@ -49,12 +49,3 @@ Decoder::seek (double) { throw DecodeError (N_("decoder does not support seek")); } - -/** Seek so that the next frame we will produce is the same as the last one. - * @return true on error. - */ -bool -Decoder::seek_to_last () -{ - throw DecodeError (N_("decoder does not support seek")); -} diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 34accf6c7..0fffef257 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -56,7 +56,6 @@ public: virtual bool pass () = 0; virtual bool seek (double); - virtual bool seek_to_last (); protected: boost::shared_ptr _film; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index a0949f635..d0b1de748 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -518,22 +518,12 @@ FFmpegDecoder::filter_and_emit_video (AVFrame* frame) bool FFmpegDecoder::seek (double p) { - return do_seek (p, false); -} - -bool -FFmpegDecoder::seek_to_last () -{ - /* This AVSEEK_FLAG_BACKWARD in do_seek is a bit of a hack; without it, if we ask for a seek to the same place as last time + /* This use of AVSEEK_FLAG_BACKWARD is a bit of a hack; without it, if we ask for a seek to the same place as last time (used when we change decoder parameters and want to re-fetch the frame) we end up going forwards rather than staying in the same place. */ - return do_seek (last_source_time(), true); -} - -bool -FFmpegDecoder::do_seek (double p, bool backwards) -{ + bool const backwards = (p == last_content_time()); + int64_t const vt = p / av_q2d (_format_context->streams[_video_stream]->time_base); int const r = av_seek_frame (_format_context, _video_stream, vt, backwards ? AVSEEK_FLAG_BACKWARD : 0); diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index cd37d20c6..f6a53874a 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -77,7 +77,6 @@ public: } bool seek (double); - bool seek_to_last (); bool pass (); private: @@ -86,7 +85,6 @@ private: FFmpegDecoder (FFmpegDecoder const &); FFmpegDecoder& operator= (FFmpegDecoder const &); - bool do_seek (double p, bool); PixelFormat pixel_format () const; AVSampleFormat audio_sample_format () const; int bytes_per_audio_sample () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index b36dc8f9c..35a07b399 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -69,6 +69,7 @@ using std::setfill; using std::min; using std::make_pair; using std::endl; +using std::cout; using std::list; using boost::shared_ptr; using boost::lexical_cast; @@ -1084,7 +1085,6 @@ Film::move_content_earlier (shared_ptr c) --j; swap (*i, *j); - _playlist->setup (_content); } signal_changed (CONTENT); @@ -1107,7 +1107,6 @@ Film::move_content_later (shared_ptr c) } swap (*i, *j); - _playlist->setup (_content); } signal_changed (CONTENT); diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index 59fde40bb..24f6d338d 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -32,7 +32,7 @@ ImageMagickContent::ImageMagickContent (boost::filesystem::path f) : Content (f) , VideoContent (f) { - + } ImageMagickContent::ImageMagickContent (shared_ptr node) diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 6a2be1a7c..7049b7d6e 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -105,16 +105,6 @@ ImageMagickDecoder::pixel_format () const return PIX_FMT_RGB24; } -bool -ImageMagickDecoder::seek_to_last () -{ - if (_position > 0) { - --_position; - } - - return false; -} - bool ImageMagickDecoder::seek (double t) { diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index cb524b44b..52c7bec18 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -50,7 +50,6 @@ public: } bool seek (double); - bool seek_to_last (); bool pass (); protected: diff --git a/src/lib/player.cc b/src/lib/player.cc index 756c3b854..19899f6da 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -20,7 +20,9 @@ #include "player.h" #include "film.h" #include "ffmpeg_decoder.h" +#include "ffmpeg_content.h" #include "imagemagick_decoder.h" +#include "imagemagick_content.h" #include "sndfile_decoder.h" #include "sndfile_content.h" #include "playlist.h" @@ -39,7 +41,6 @@ Player::Player (shared_ptr f, shared_ptr p) , _audio (true) , _subtitles (true) , _have_valid_decoders (false) - , _ffmpeg_decoder_done (false) , _video_sync (true) { _playlist->Changed.connect (bind (&Player::playlist_changed, this)); @@ -74,25 +75,13 @@ Player::pass () 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 (_video_decoder != _video_decoders.end ()) { + if ((*_video_decoder)->pass ()) { + _video_decoder++; } - } - - 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; - } + + if (_video_decoder != _video_decoders.end ()) { + done = false; } } @@ -114,26 +103,18 @@ 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; + + if (_video_decoder == _video_decoders.end() || !_playlist->video_length()) { + return; } + + ContentVideoFrame p = 0; + list >::iterator i = _video_decoders.begin (); + while (i != _video_decoders.end() && i != _video_decoder) { + p += (*i)->video_length (); } + + job->set_progress (float ((*_video_decoder)->video_frame ()) / _playlist->video_length ()); } void @@ -173,109 +154,67 @@ Player::seek (double t) _have_valid_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; + /* Find the decoder that contains this position */ + _video_decoder = _video_decoders.begin (); + while (_video_decoder != _video_decoders.end ()) { + double const this_length = (*_video_decoder)->video_length() / _film->video_frame_rate (); + if (t < this_length) { + break; } - - 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_valid_decoders) { - setup_decoders (); - _have_valid_decoders = true; + t -= this_length; + ++_video_decoder; } - - 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; + if (_video_decoder != _video_decoders.end()) { + (*_video_decoder)->seek (t); + } else { + return true; } /* XXX: don't seek audio because we don't need to... */ - return r; + return false; } 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 (_video) { + list > vc = _playlist->video (); + for (list >::iterator i = vc.begin(); i != vc.end(); ++i) { + + shared_ptr d; + + /* XXX: into content? */ + + 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 && _film->with_subtitles(), + _video_sync + ) + ); + + if (_playlist->audio_from() == Playlist::AUDIO_FFMPEG) { + fd->Audio.connect (bind (&Player::process_audio, this, fc, _1)); + } + + d = fd; + } - if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - _ffmpeg_decoder->Audio.connect (bind (&Player::process_audio, this, _playlist->ffmpeg (), _1)); - } + shared_ptr ic = dynamic_pointer_cast (*i); + if (ic) { + d.reset (new ImageMagickDecoder (_film, ic)); + } - 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 ()); + _video_decoders.push_back (d); } - _imagemagick_decoder = _imagemagick_decoders.begin (); + _video_decoder = _video_decoders.begin (); } if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { @@ -297,23 +236,12 @@ Player::disable_video_sync () 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: - { - double t = 0; - for (list >::const_iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoder; ++i) { - t += (*i)->video_length() / (*i)->video_frame_rate (); - } - - return t + (*_imagemagick_decoder)->last_source_time (); - } + double t = 0; + for (list >::const_iterator i = _video_decoders.begin(); i != _video_decoder; ++i) { + t += (*i)->video_length() / (*i)->video_frame_rate (); } - return 0; + return t + (*_video_decoder)->last_content_time (); } void @@ -326,6 +254,7 @@ Player::content_changed (weak_ptr w, int p) if (p == VideoContentProperty::VIDEO_LENGTH) { if (dynamic_pointer_cast (c)) { + /* FFmpeg content length changes are serious; we need new decoders */ _have_valid_decoders = false; } } diff --git a/src/lib/player.h b/src/lib/player.h index afc856316..8a82ab298 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -28,8 +28,7 @@ #include "video_sink.h" #include "audio_sink.h" -class FFmpegDecoder; -class ImageMagickDecoder; +class VideoDecoder; class SndfileDecoder; class Job; class Film; @@ -49,7 +48,6 @@ public: bool pass (); void set_progress (boost::shared_ptr); bool seek (double); - bool seek_to_last (); double last_video_time () const; @@ -68,10 +66,8 @@ private: bool _subtitles; bool _have_valid_decoders; - boost::shared_ptr _ffmpeg_decoder; - bool _ffmpeg_decoder_done; - std::list > _imagemagick_decoders; - std::list >::iterator _imagemagick_decoder; + std::list > _video_decoders; + std::list >::iterator _video_decoder; std::list > _sndfile_decoders; boost::shared_ptr _sndfile_buffers; diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 3f7905fa9..d26dae730 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -21,9 +21,9 @@ #include "playlist.h" #include "sndfile_content.h" #include "sndfile_decoder.h" -#include "ffmpeg_content.h" +#include "video_content.h" #include "ffmpeg_decoder.h" -#include "imagemagick_content.h" +#include "ffmpeg_content.h" #include "imagemagick_decoder.h" #include "job.h" @@ -31,13 +31,13 @@ using std::list; using std::cout; using std::vector; using std::min; +using std::max; using boost::shared_ptr; using boost::weak_ptr; using boost::dynamic_pointer_cast; Playlist::Playlist () - : _video_from (VIDEO_NONE) - , _audio_from (AUDIO_NONE) + : _audio_from (AUDIO_FFMPEG) { } @@ -45,11 +45,9 @@ Playlist::Playlist () void Playlist::setup (ContentList content) { - _video_from = VIDEO_NONE; - _audio_from = AUDIO_NONE; + _audio_from = AUDIO_FFMPEG; - _ffmpeg.reset (); - _imagemagick.clear (); + _video.clear (); _sndfile.clear (); for (list::iterator i = _content_connections.begin(); i != _content_connections.end(); ++i) { @@ -59,24 +57,11 @@ Playlist::setup (ContentList content) _content_connections.clear (); for (ContentList::const_iterator i = content.begin(); i != content.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 vc = dynamic_pointer_cast (*i); + if (vc) { + _video.push_back (vc); } - 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); @@ -92,53 +77,65 @@ Playlist::setup (ContentList content) ContentAudioFrame Playlist::audio_length () const { + ContentAudioFrame len = 0; + switch (_audio_from) { - case AUDIO_NONE: - return 0; case AUDIO_FFMPEG: - return _ffmpeg->audio_length (); + for (list >::const_iterator i = _video.begin(); i != _video.end(); ++i) { + shared_ptr fc = dynamic_pointer_cast (*i); + if (fc) { + len += fc->audio_length (); + } + } + break; case AUDIO_SNDFILE: - { - ContentAudioFrame l = 0; for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { - l += (*i)->audio_length (); + len += (*i)->audio_length (); } - return l; - } + break; } - return 0; + return len; } int Playlist::audio_channels () const { + int channels = 0; + switch (_audio_from) { - case AUDIO_NONE: - return 0; case AUDIO_FFMPEG: - return _ffmpeg->audio_channels (); + for (list >::const_iterator i = _video.begin(); i != _video.end(); ++i) { + shared_ptr fc = dynamic_pointer_cast (*i); + if (fc) { + channels = max (channels, fc->audio_channels ()); + } + } + break; case AUDIO_SNDFILE: - { - int c = 0; for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { - c += (*i)->audio_channels (); + channels += (*i)->audio_channels (); } - return c; - } + break; } - return 0; + return channels; } int Playlist::audio_frame_rate () const { + /* XXX: assuming that all content has the same rate */ + switch (_audio_from) { - case AUDIO_NONE: - return 0; case AUDIO_FFMPEG: - return _ffmpeg->audio_frame_rate (); + { + shared_ptr fc = first_ffmpeg (); + if (fc) { + return fc->audio_channels (); + } + break; + } case AUDIO_SNDFILE: return _sndfile.front()->audio_frame_rate (); } @@ -149,11 +146,17 @@ Playlist::audio_frame_rate () const int64_t Playlist::audio_channel_layout () const { + /* XXX: assuming that all content has the same layout */ + switch (_audio_from) { - case AUDIO_NONE: - return 0; case AUDIO_FFMPEG: - return _ffmpeg->audio_channel_layout (); + { + shared_ptr fc = first_ffmpeg (); + if (fc) { + return fc->audio_channel_layout (); + } + break; + } case AUDIO_SNDFILE: /* XXX */ return 0; @@ -165,59 +168,41 @@ Playlist::audio_channel_layout () const float Playlist::video_frame_rate () const { - switch (_video_from) { - case VIDEO_NONE: + if (_video.empty ()) { return 0; - case VIDEO_FFMPEG: - return _ffmpeg->video_frame_rate (); - case VIDEO_IMAGEMAGICK: - return 24; } - - return 0; + + /* XXX: assuming all the same */ + return _video.front()->video_frame_rate (); } libdcp::Size Playlist::video_size () const { - switch (_video_from) { - case VIDEO_NONE: + if (_video.empty ()) { return libdcp::Size (); - case VIDEO_FFMPEG: - return _ffmpeg->video_size (); - case VIDEO_IMAGEMAGICK: - /* XXX */ - return _imagemagick.front()->video_size (); } - return libdcp::Size (); + /* XXX: assuming all the same */ + return _video.front()->video_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; + ContentVideoFrame len = 0; + for (list >::const_iterator i = _video.begin(); i != _video.end(); ++i) { + len += (*i)->video_length (); } - } - - return 0; + + return len; } bool Playlist::has_audio () const { - return _audio_from != AUDIO_NONE; + /* XXX */ + return true; } void @@ -226,32 +211,51 @@ Playlist::content_changed (weak_ptr c, int p) ContentChanged (c, p); } +shared_ptr +Playlist::first_ffmpeg () const +{ + for (list >::const_iterator i = _video.begin(); i != _video.end(); ++i) { + shared_ptr fc = dynamic_pointer_cast (*i); + if (fc) { + return fc; + } + } + + return shared_ptr (); +} + + AudioMapping Playlist::default_audio_mapping () const { AudioMapping m; switch (_audio_from) { - case AUDIO_NONE: - break; case AUDIO_FFMPEG: - if (_ffmpeg->audio_channels() == 1) { + { + shared_ptr fc = first_ffmpeg (); + if (!fc) { + break; + } + + /* XXX: assumes all the same */ + if (fc->audio_channels() == 1) { /* Map mono sources to centre */ - m.add (AudioMapping::Channel (_ffmpeg, 0), libdcp::CENTRE); + m.add (AudioMapping::Channel (fc, 0), libdcp::CENTRE); } else { - int const N = min (_ffmpeg->audio_channels (), MAX_AUDIO_CHANNELS); + int const N = min (fc->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); + m.add (AudioMapping::Channel (fc, 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; diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 1d189cb07..4dd27f675 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -56,32 +56,17 @@ public: AudioMapping default_audio_mapping () 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 > video () const { + return _video; } std::list > sndfile () const { @@ -93,12 +78,11 @@ public: private: void content_changed (boost::weak_ptr, int); + boost::shared_ptr first_ffmpeg () const; - VideoFrom _video_from; AudioFrom _audio_from; - boost::shared_ptr _ffmpeg; - std::list > _imagemagick; + std::list > _video; std::list > _sndfile; std::list _content_connections; diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index fd2b28d7f..99d711693 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -32,7 +32,7 @@ using boost::optional; VideoDecoder::VideoDecoder (shared_ptr f) : Decoder (f) , _video_frame (0) - , _last_source_time (0) + , _last_content_time (0) { } @@ -88,7 +88,7 @@ VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr, bool, boost::shared_ptr, double); int _video_frame; - double _last_source_time; + double _last_content_time; boost::shared_ptr _timed_subtitle; diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc index 6c27892b0..239b4a517 100644 --- a/src/tools/dvdomatic.cc +++ b/src/tools/dvdomatic.cc @@ -59,6 +59,7 @@ 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; @@ -439,13 +440,15 @@ private: #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_PARAM, 0, 0, "film to load", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | 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_PARAM, 0, 0, wxT("film to load"), wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_MULTIPLE | 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 @@ -525,6 +528,12 @@ class App : public wxApp } } + 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 (); @@ -545,11 +554,15 @@ class App : public wxApp bool OnCmdLineParsed (wxCmdLineParser& parser) { if (parser.GetParamCount() > 0) { - film_to_load = wx_to_std (parser.GetParam(0)); + if (parser.FoundSwitch (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)) { + if (parser.Found (wxT ("log"), &log)) { log_level = wx_to_std (log); } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index f8373d3fd..8fca8f370 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -157,7 +157,7 @@ FilmViewer::set_film (shared_ptr f) void FilmViewer::update_from_decoder () { - if (!_player || _player->seek_to_last ()) { + if (!_player || _player->seek (_player->last_video_time ())) { return; } -- cgit v1.2.3 From 11c70b0e3051517e7bb96a7d6fa53053dab6e978 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 22 May 2013 00:20:29 +0100 Subject: Half-way through trying to make seek work again. --- src/lib/decoder.cc | 6 ++---- src/lib/decoder.h | 2 +- src/lib/ffmpeg_decoder.cc | 37 ++++++++++++++++++++++++++++--------- src/lib/ffmpeg_decoder.h | 4 ++-- src/lib/player.cc | 27 ++++++++++++++++++++++++++- src/lib/player.h | 1 + src/lib/video_decoder.h | 4 ++-- src/wx/film_viewer.cc | 7 +++++++ 8 files changed, 69 insertions(+), 19 deletions(-) (limited to 'src/lib/decoder.cc') diff --git a/src/lib/decoder.cc b/src/lib/decoder.cc index 082ad5076..2308bbd98 100644 --- a/src/lib/decoder.cc +++ b/src/lib/decoder.cc @@ -41,11 +41,9 @@ Decoder::Decoder (shared_ptr f) _film_connection = f->Changed.connect (bind (&Decoder::film_changed, this, _1)); } -/** Seek to a position as a content timestamp in seconds. - * @return true on error. - */ +/** @return true on error */ bool -Decoder::seek (double) +Decoder::seek (Time) { throw DecodeError (N_("decoder does not support seek")); } diff --git a/src/lib/decoder.h b/src/lib/decoder.h index ae0d0c671..3876e6c1a 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -54,7 +54,7 @@ public: virtual ~Decoder () {} virtual bool pass () = 0; - virtual bool seek (double); + virtual bool seek (Time); virtual bool seek_back () { return true; } diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index fcb2e82ba..0ca9fc535 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -224,7 +224,9 @@ FFmpegDecoder::setup_subtitle () bool FFmpegDecoder::pass () { + cout << "ffd pass.\n"; int r = av_read_frame (_format_context, &_packet); + cout << "A " << r << "\n"; if (r < 0) { if (r != AVERROR_EOF) { @@ -255,7 +257,9 @@ FFmpegDecoder::pass () avcodec_get_frame_defaults (_frame); if (_packet.stream_index == _video_stream && _decode_video) { + cout << "dvp\n"; decode_video_packet (); + cout << "ok.\n"; } 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 && _decode_subtitles) { @@ -279,7 +283,8 @@ FFmpegDecoder::pass () avsubtitle_free (&sub); } } - + + cout << "out.\n"; av_free_packet (&_packet); return false; } @@ -472,9 +477,9 @@ FFmpegDecoder::bytes_per_audio_sample () const } bool -FFmpegDecoder::seek (double p) +FFmpegDecoder::seek (Time t) { - return do_seek (p, false, false); + return do_seek (t, false, false); } bool @@ -484,7 +489,7 @@ FFmpegDecoder::seek_back () return true; } - return do_seek (last_content_time() - 2.5 / video_frame_rate(), true, true); + return do_seek (last_content_time() - 2.5 * TIME_HZ / video_frame_rate(), true, true); } bool @@ -494,13 +499,15 @@ FFmpegDecoder::seek_forward () return true; } - return do_seek (last_content_time() - 0.5 / video_frame_rate(), true, true); + return do_seek (last_content_time() - 0.5 * TIME_HZ / video_frame_rate(), true, true); } bool -FFmpegDecoder::do_seek (double p, bool backwards, bool accurate) +FFmpegDecoder::do_seek (Time t, bool backwards, bool accurate) { - int64_t const vt = p / av_q2d (_format_context->streams[_video_stream]->time_base); + int64_t const vt = t / (av_q2d (_format_context->streams[_video_stream]->time_base) * TIME_HZ); + + cout << "seek to " << vt << " (acc=" << accurate << ") (sec " << (vt * av_q2d (_format_context->streams[_video_stream]->time_base)) << "\n"; int const r = av_seek_frame (_format_context, _video_stream, vt, backwards ? AVSEEK_FLAG_BACKWARD : 0); @@ -532,7 +539,8 @@ FFmpegDecoder::do_seek (double p, bool backwards, bool accurate) av_free_packet (&_packet); } } - + + cout << "seek ok.\n"; return r < 0; } @@ -597,11 +605,15 @@ bool FFmpegDecoder::decode_video_packet () { int frame_finished; + cout << "avc decode v2\n"; if (avcodec_decode_video2 (_video_codec_context, _frame, &frame_finished, &_packet) < 0 || !frame_finished) { return false; } + cout << "done that.\n"; boost::mutex::scoped_lock lm (_filter_graphs_mutex); + + cout << "got lock.\n"; shared_ptr graph; @@ -609,6 +621,8 @@ FFmpegDecoder::decode_video_packet () while (i != _filter_graphs.end() && !(*i)->can_process (libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)) { ++i; } + + cout << "found graph.\n"; if (i == _filter_graphs.end ()) { graph.reset (new FilterGraph (_film, this, libdcp::Size (_frame->width, _frame->height), (AVPixelFormat) _frame->format)); @@ -617,8 +631,11 @@ FFmpegDecoder::decode_video_packet () } else { graph = *i; } - + + + cout << "pushed in.\n"; list > images = graph->process (_frame); + cout << "got " << images.size() << "\n"; for (list >::iterator i = images.begin(); i != images.end(); ++i) { int64_t const bet = av_frame_get_best_effort_timestamp (_frame); @@ -626,7 +643,9 @@ FFmpegDecoder::decode_video_packet () /* XXX: may need to insert extra frames / remove frames here ... (as per old Matcher) */ + cout << "emitting.\n"; emit_video (*i, false, bet * av_q2d (_format_context->streams[_video_stream]->time_base) * TIME_HZ); + cout << "emitted.\n"; } else { _film->log()->log ("Dropping frame without PTS"); } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 7aadef105..1c3f252fd 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -78,7 +78,7 @@ public: return _audio_streams; } - bool seek (double); + bool seek (Time); bool seek_forward (); bool seek_back (); bool pass (); @@ -96,7 +96,7 @@ private: PixelFormat pixel_format () const; AVSampleFormat audio_sample_format () const; int bytes_per_audio_sample () const; - bool do_seek (double, bool, bool); + bool do_seek (Time, bool, bool); void setup_general (); void setup_video (); diff --git a/src/lib/player.cc b/src/lib/player.cc index 5d4635e5a..dd250d2e1 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -109,9 +109,11 @@ Player::pass () } if (earliest) { + cout << "pass on decoder...\n"; earliest->decoder->pass (); _position = earliest->last; } else if (next_wait < TIME_MAX) { + cout << "nw " << next_wait << " for " << _position << "\n"; _position += next_wait; } else { return true; @@ -126,8 +128,10 @@ Player::process_video (shared_ptr dr, shared_ptr ima shared_ptr vd = dynamic_pointer_cast (dr->decoder); Time const global_time = dr->content->time() + time; + cout << "need to fill in " << global_time << " vs " << _last_video << "\n"; while ((global_time - _last_video) > 1) { /* Fill in with black */ + cout << "(b)\n"; emit_black_frame (); } @@ -188,7 +192,28 @@ Player::seek (Time t) return true; } - /* XXX */ + cout << "seek to " << t << "\n"; + + Time current_time = 0; + shared_ptr current; + for (list >::iterator i = _decoders.begin(); i != _decoders.end(); ++i) { + shared_ptr v = dynamic_pointer_cast ((*i)->decoder); + if (!v) { + continue; + } + + if ((*i)->content->time() < t && (*i)->content->time() >= current_time) { + current_time = (*i)->content->time(); + current = v; + } + } + + if (current) { + cout << "got a decoder to seek to " << (t - current_time) << ".\n"; + current->seek (t - current_time); + _position = t; + _last_video = t; + } /* XXX: don't seek audio because we don't need to... */ diff --git a/src/lib/player.h b/src/lib/player.h index 44b95e076..4b9635157 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -92,6 +92,7 @@ private: bool _have_valid_decoders; std::list > _decoders; + /* XXX: position and last_video? Need both? */ Time _position; AudioBuffers _audio_buffers; Time _last_video; diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 286a0d6e4..147dc60be 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -48,7 +48,7 @@ public: return _video_frame; } - double last_content_time () const { + Time last_content_time () const { return _last_content_time; } @@ -62,7 +62,7 @@ protected: private: boost::shared_ptr _video_content; int _video_frame; - double _last_content_time; + Time _last_content_time; boost::shared_ptr _timed_subtitle; }; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 6a40e88f7..fa834ca08 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -428,22 +428,29 @@ FilmViewer::get_frame () return; } + cout << "getting frame...\n"; + try { _got_frame = false; while (!_got_frame) { + cout << "pass...\n"; if (_player->pass ()) { + cout << "passed.\n"; /* We didn't get a frame before the decoder gave up, so clear our display frame. */ _display_frame.reset (); break; } + cout << "passed.\n"; } } catch (DecodeError& e) { _play_button->SetValue (false); check_play_state (); error_dialog (this, wxString::Format (_("Could not decode video for view (%s)"), std_to_wx(e.what()).data())); } + + cout << "...got frame.\n"; } void -- cgit v1.2.3 From 596441a4e8cf03a88113646ca6da2f90e721a38b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 22 May 2013 17:36:11 +0100 Subject: Various hacks. --- src/lib/audio_decoder.cc | 5 +- src/lib/audio_decoder.h | 3 + src/lib/content.cc | 14 ++- src/lib/content.h | 13 ++- src/lib/decoder.cc | 11 -- src/lib/decoder.h | 41 +++++--- src/lib/ffmpeg_decoder.cc | 60 +++-------- src/lib/ffmpeg_decoder.h | 15 ++- src/lib/filter_graph.cc | 5 +- src/lib/imagemagick_decoder.cc | 6 ++ src/lib/imagemagick_decoder.h | 25 +---- src/lib/player.cc | 229 ++++++++++++++++++++++------------------- src/lib/player.h | 33 +++--- src/lib/sndfile_decoder.cc | 6 ++ src/lib/sndfile_decoder.h | 1 + src/lib/video_content.h | 1 + src/lib/video_decoder.cc | 16 +-- src/lib/video_decoder.h | 27 ++--- src/lib/video_source.h | 1 + src/wx/film_viewer.cc | 7 -- 20 files changed, 235 insertions(+), 284 deletions(-) (limited to 'src/lib/decoder.cc') diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index e1c93ac77..fbc66c335 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -30,6 +30,7 @@ using boost::shared_ptr; AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) : Decoder (f) + , _next_audio (0) , _audio_content (c) , _output_audio_frame_rate (_audio_content->output_audio_frame_rate (f)) { @@ -104,7 +105,7 @@ AudioDecoder::emit_audio (shared_ptr data, Time time) { /* XXX: map audio to 5.1 */ - /* Maybe sample-rate convert */ + /* Maybe resample */ if (_swr_context) { /* Compute the resampled frames count and add 32 for luck */ @@ -128,6 +129,8 @@ AudioDecoder::emit_audio (shared_ptr data, Time time) } Audio (data, time); + + _next_audio = time + _film->audio_frames_to_time (data->frames()); } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 94845ec23..8af519576 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -43,6 +43,9 @@ public: void emit_audio (boost::shared_ptr, Time); +protected: + Time _next_audio; + private: boost::shared_ptr _audio_content; SwrContext* _swr_context; diff --git a/src/lib/content.cc b/src/lib/content.cc index 618dafee2..43d0ef958 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -29,9 +29,15 @@ using std::string; using boost::shared_ptr; using boost::lexical_cast; +Content::Content (Time s) + : _start (s) +{ + +} + Content::Content (boost::filesystem::path f) : _file (f) - , _time (0) + , _start (0) { } @@ -40,14 +46,14 @@ Content::Content (shared_ptr node) { _file = node->string_child ("File"); _digest = node->string_child ("Digest"); - _time = node->number_child