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_factory.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/decoder_factory.cc') diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index 2a0d828e2..c4d818f49 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, shared_ptr o, Job* j + shared_ptr f, DecodeOptions o, Job* j ) { if (boost::filesystem::is_directory (f->content_path()) || f->content_type() == STILL) { -- 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_factory.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 e118ae9353cc3a3052cad2d07b43ec40e56f0074 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 12 Feb 2013 19:37:05 +0000 Subject: Don't try to make decoders when there is no content. --- src/lib/decoder_factory.cc | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'src/lib/decoder_factory.cc') diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index 59e15722d..478ccd1c1 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -39,6 +39,10 @@ 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 ( -- cgit v1.2.3 From 9c4c94748ee6bcdec09c63974a4f06d3835db4c5 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 17 Mar 2013 15:51:42 +0000 Subject: Rename ExternalAudioDecoder -> SndfileDecoder. --- src/lib/decoder_factory.cc | 6 +- src/lib/external_audio_decoder.cc | 188 -------------------------------------- src/lib/external_audio_decoder.h | 54 ----------- src/lib/film.cc | 16 ++-- src/lib/film.h | 2 +- src/lib/sndfile_decoder.cc | 188 ++++++++++++++++++++++++++++++++++++++ src/lib/sndfile_decoder.h | 54 +++++++++++ src/lib/stream.cc | 4 +- src/lib/wscript | 2 +- src/wx/film_editor.cc | 1 - test/test.cc | 4 +- 11 files changed, 259 insertions(+), 260 deletions(-) delete mode 100644 src/lib/external_audio_decoder.cc delete mode 100644 src/lib/external_audio_decoder.h create mode 100644 src/lib/sndfile_decoder.cc create mode 100644 src/lib/sndfile_decoder.h (limited to 'src/lib/decoder_factory.cc') diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc index 478ccd1c1..f7f9f4074 100644 --- a/src/lib/decoder_factory.cc +++ b/src/lib/decoder_factory.cc @@ -25,7 +25,7 @@ #include "ffmpeg_decoder.h" #include "imagemagick_decoder.h" #include "film.h" -#include "external_audio_decoder.h" +#include "sndfile_decoder.h" #include "decoder_factory.h" using std::string; @@ -47,7 +47,7 @@ decoder_factory ( /* A single image file, or a directory of them */ return Decoders ( shared_ptr (new ImageMagickDecoder (f, o)), - shared_ptr (new ExternalAudioDecoder (f, o)) + shared_ptr (new SndfileDecoder (f, o)) ); } @@ -56,5 +56,5 @@ decoder_factory ( return Decoders (fd, fd); } - return Decoders (fd, shared_ptr (new ExternalAudioDecoder (f, o))); + return Decoders (fd, shared_ptr (new SndfileDecoder (f, o))); } diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc deleted file mode 100644 index 1248b5a3b..000000000 --- a/src/lib/external_audio_decoder.cc +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include "external_audio_decoder.h" -#include "film.h" -#include "exceptions.h" - -#include "i18n.h" - -using std::vector; -using std::string; -using std::stringstream; -using std::min; -using std::cout; -using boost::shared_ptr; -using boost::optional; - -ExternalAudioDecoder::ExternalAudioDecoder (shared_ptr f, DecodeOptions o) - : Decoder (f, o) - , AudioDecoder (f, o) -{ - sf_count_t frames; - vector sf = open_files (frames); - close_files (sf); -} - -vector -ExternalAudioDecoder::open_files (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 ExternalAudioStream ( - 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")); - } - } - } - } - - return sndfiles; -} - -bool -ExternalAudioDecoder::pass () -{ - sf_count_t frames; - vector sndfiles = open_files (frames); - if (sndfiles.empty()) { - return true; - } - - /* 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; - - shared_ptr audio (new AudioBuffers (_audio_stream->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); - } - } - - audio->set_frames (this_time); - Audio (audio); - frames -= this_time; - } - - close_files (sndfiles); - - return true; -} - -void -ExternalAudioDecoder::close_files (vector const & sndfiles) -{ - for (size_t i = 0; i < sndfiles.size(); ++i) { - sf_close (sndfiles[i]); - } -} - -shared_ptr -ExternalAudioStream::create () -{ - return shared_ptr (new ExternalAudioStream); -} - -shared_ptr -ExternalAudioStream::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 ExternalAudioStream (t, v)); -} - -ExternalAudioStream::ExternalAudioStream (string t, optional v) -{ - assert (v); - - stringstream s (t); - string type; - s >> type >> _sample_rate >> _channel_layout; -} - -ExternalAudioStream::ExternalAudioStream () -{ - -} - -string -ExternalAudioStream::to_string () const -{ - return String::compose (N_("external %1 %2"), _sample_rate, _channel_layout); -} diff --git a/src/lib/external_audio_decoder.h b/src/lib/external_audio_decoder.h deleted file mode 100644 index 6f010abb1..000000000 --- a/src/lib/external_audio_decoder.h +++ /dev/null @@ -1,54 +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 "decoder.h" -#include "audio_decoder.h" -#include "stream.h" - -class ExternalAudioStream : public AudioStream -{ -public: - ExternalAudioStream (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; - - ExternalAudioStream (); - ExternalAudioStream (std::string t, boost::optional v); -}; - -class ExternalAudioDecoder : public AudioDecoder -{ -public: - ExternalAudioDecoder (boost::shared_ptr, DecodeOptions); - - bool pass (); - -private: - std::vector open_files (sf_count_t &); - void close_files (std::vector const &); -}; diff --git a/src/lib/film.cc b/src/lib/film.cc index 77f9828cd..c84042451 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -50,7 +50,7 @@ #include "ui_signaller.h" #include "video_decoder.h" #include "audio_decoder.h" -#include "external_audio_decoder.h" +#include "sndfile_decoder.h" #include "analyse_audio_job.h" #include "i18n.h" @@ -138,7 +138,7 @@ Film::Film (string d, bool must_exist) } } - _external_audio_stream = ExternalAudioStream::create (); + _sndfile_stream = SndfileStream::create (); if (must_exist) { read_metadata (); @@ -183,7 +183,7 @@ Film::Film (Film const & o) , _length (o._length) , _content_digest (o._content_digest) , _content_audio_streams (o._content_audio_streams) - , _external_audio_stream (o._external_audio_stream) + , _sndfile_stream (o._sndfile_stream) , _subtitle_streams (o._subtitle_streams) , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) @@ -459,7 +459,7 @@ Film::write_metadata () const f << "content_audio_stream " << (*i)->to_string () << endl; } - f << "external_audio_stream " << _external_audio_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; @@ -598,7 +598,7 @@ Film::read_metadata () } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { _content_audio_streams.push_back (audio_stream_factory (v, version)); } else if (k == "external_audio_stream") { - _external_audio_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)); } else if (k == "source_frame_rate") { @@ -1127,9 +1127,9 @@ Film::set_external_audio (vector a) _external_audio = a; } - shared_ptr decoder (new ExternalAudioDecoder (shared_from_this(), DecodeOptions())); + shared_ptr decoder (new SndfileDecoder (shared_from_this(), DecodeOptions())); if (decoder->audio_stream()) { - _external_audio_stream = decoder->audio_stream (); + _sndfile_stream = decoder->audio_stream (); } signal_changed (EXTERNAL_AUDIO); @@ -1364,7 +1364,7 @@ Film::audio_stream () const return _content_audio_stream; } - return _external_audio_stream; + return _sndfile_stream; } string diff --git a/src/lib/film.h b/src/lib/film.h index 698e7ef46..adc4b0eec 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -476,7 +476,7 @@ private: /** The audio streams in our content */ std::vector > _content_audio_streams; /** A stream to represent possible external audio (will always exist) */ - boost::shared_ptr _external_audio_stream; + boost::shared_ptr _sndfile_stream; /** the subtitle streams that we can use */ std::vector > _subtitle_streams; /** Frames per second of the source */ diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc new file mode 100644 index 000000000..0e3e5e234 --- /dev/null +++ b/src/lib/sndfile_decoder.cc @@ -0,0 +1,188 @@ +/* + Copyright (C) 2012 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include "sndfile_decoder.h" +#include "film.h" +#include "exceptions.h" + +#include "i18n.h" + +using std::vector; +using std::string; +using std::stringstream; +using std::min; +using std::cout; +using boost::shared_ptr; +using boost::optional; + +SndfileDecoder::SndfileDecoder (shared_ptr f, DecodeOptions o) + : Decoder (f, o) + , AudioDecoder (f, o) +{ + sf_count_t frames; + vector sf = open_files (frames); + close_files (sf); +} + +vector +SndfileDecoder::open_files (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")); + } + } + } + } + + return sndfiles; +} + +bool +SndfileDecoder::pass () +{ + sf_count_t frames; + vector sndfiles = open_files (frames); + if (sndfiles.empty()) { + return true; + } + + /* 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; + + shared_ptr audio (new AudioBuffers (_audio_stream->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); + } + } + + audio->set_frames (this_time); + Audio (audio); + frames -= this_time; + } + + close_files (sndfiles); + + 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 new file mode 100644 index 000000000..e16eab673 --- /dev/null +++ b/src/lib/sndfile_decoder.h @@ -0,0 +1,54 @@ +/* + Copyright (C) 2012-2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include "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 SndfileDecoder : public AudioDecoder +{ +public: + SndfileDecoder (boost::shared_ptr, DecodeOptions); + + bool pass (); + +private: + std::vector open_files (sf_count_t &); + void close_files (std::vector const &); +}; diff --git a/src/lib/stream.cc b/src/lib/stream.cc index e5a2bbc2b..bfe7b5eb4 100644 --- a/src/lib/stream.cc +++ b/src/lib/stream.cc @@ -21,7 +21,7 @@ #include "compose.hpp" #include "stream.h" #include "ffmpeg_decoder.h" -#include "external_audio_decoder.h" +#include "sndfile_decoder.h" #include "i18n.h" @@ -74,7 +74,7 @@ audio_stream_factory (string t, optional v) s = FFmpegAudioStream::create (t, v); if (!s) { - s = ExternalAudioStream::create (t, v); + s = SndfileStream::create (t, v); } return s; diff --git a/src/lib/wscript b/src/lib/wscript index d36a24e7a..de39345d5 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -20,7 +20,6 @@ sources = """ dolby_cp750.cc encoder.cc examine_content_job.cc - external_audio_decoder.cc filter_graph.cc ffmpeg_compatibility.cc ffmpeg_decoder.cc @@ -38,6 +37,7 @@ sources = """ scp_dcp_job.cc scaler.cc server.cc + sndfile_decoder.cc sound_processor.cc stream.cc subtitle.cc diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 20dbc88ef..2553d0bd5 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -37,7 +37,6 @@ #include "lib/filter.h" #include "lib/config.h" #include "lib/ffmpeg_decoder.h" -#include "lib/external_audio_decoder.h" #include "filter_dialog.h" #include "wx_util.h" #include "film_editor.h" diff --git a/test/test.cc b/test/test.cc index 448168f24..f31b3b1ca 100644 --- a/test/test.cc +++ b/test/test.cc @@ -39,7 +39,7 @@ #include "subtitle.h" #include "scaler.h" #include "ffmpeg_decoder.h" -#include "external_audio_decoder.h" +#include "sndfile_decoder.h" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE dvdomatic_test #include @@ -191,7 +191,7 @@ BOOST_AUTO_TEST_CASE (stream_test) BOOST_CHECK_EQUAL (a.name(), "hello there world"); BOOST_CHECK_EQUAL (a.to_string(), "ffmpeg 4 44100 1 hello there world"); - ExternalAudioStream e ("external 44100 1", boost::optional (1)); + 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"); -- 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_factory.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_factory.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 b468ccabdb13fca86ae8a324239d83490ef5832e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2013 02:25:02 +0100 Subject: XML metadata and some other bits. --- src/lib/ab_transcoder.h | 1 - src/lib/audio_content.cc | 9 ++ src/lib/audio_content.h | 5 + src/lib/config.cc | 89 ++++++++++--- src/lib/config.h | 3 +- src/lib/content.cc | 16 +++ src/lib/content.h | 7 + src/lib/dci_metadata.cc | 33 +++-- src/lib/dci_metadata.h | 12 +- src/lib/decoder_factory.cc | 43 ------ src/lib/decoder_factory.h | 47 ------- src/lib/ffmpeg_content.cc | 86 ++++++++++++ src/lib/ffmpeg_content.h | 10 ++ src/lib/film.cc | 293 +++++++++++++++-------------------------- src/lib/film.h | 10 +- src/lib/imagemagick_content.cc | 9 ++ src/lib/imagemagick_content.h | 5 + src/lib/server.cc | 23 ++-- src/lib/server.h | 9 +- src/lib/sndfile_content.cc | 11 +- src/lib/sndfile_content.h | 5 + src/lib/transcoder.cc | 1 - src/lib/transcoder.h | 2 - src/lib/video_content.cc | 22 ++++ src/lib/video_content.h | 3 + src/lib/wscript | 3 +- src/tools/makedcp.cc | 2 +- src/tools/servomatictest.cc | 13 +- src/wx/audio_plot.cc | 1 - src/wx/film_editor.cc | 18 +-- src/wx/film_editor.h | 4 +- src/wx/film_viewer.h | 1 - test/test.cc | 4 +- 33 files changed, 443 insertions(+), 357 deletions(-) delete mode 100644 src/lib/decoder_factory.cc delete mode 100644 src/lib/decoder_factory.h (limited to 'src/lib/decoder_factory.cc') diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 090c26fb7..5ce4a03da 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -25,7 +25,6 @@ #include #include #include "util.h" -#include "decoder_factory.h" class Job; class Encoder; diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index e9eacfd79..74b8ea2ce 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -1,7 +1,16 @@ +#include #include "audio_content.h" +using boost::shared_ptr; + AudioContent::AudioContent (boost::filesystem::path f) : Content (f) { } + +AudioContent::AudioContent (shared_ptr node) + : Content (node) +{ + +} diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index e18d1082e..f3dd81efb 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -4,10 +4,15 @@ #include "content.h" #include "util.h" +namespace cxml { + class Node; +} + class AudioContent : public virtual Content { public: AudioContent (boost::filesystem::path); + AudioContent (boost::shared_ptr); virtual int audio_channels () const = 0; virtual ContentAudioFrame audio_length () const = 0; diff --git a/src/lib/config.cc b/src/lib/config.cc index 5dce3748d..2defa0539 100644 --- a/src/lib/config.cc +++ b/src/lib/config.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include "config.h" #include "server.h" #include "scaler.h" @@ -34,7 +35,9 @@ using std::vector; using std::ifstream; using std::string; using std::ofstream; +using std::list; using boost::shared_ptr; +using boost::optional; Config* Config::_instance = 0; @@ -52,8 +55,51 @@ Config::Config () _allowed_dcp_frame_rates.push_back (48); _allowed_dcp_frame_rates.push_back (50); _allowed_dcp_frame_rates.push_back (60); + + if (!boost::filesystem::exists (file (false))) { + read_old_metadata (); + return; + } + + cxml::File f (file (false), "Config"); + optional c; + + _num_local_encoding_threads = f.number_child ("NumLocalEncodingThreads"); + _default_directory = f.string_child ("DefaultDirectory"); + _server_port = f.number_child ("ServerPort"); + c = f.optional_string_child ("ReferenceScaler"); + if (c) { + _reference_scaler = Scaler::from_id (c.get ()); + } + + list > filters = f.node_children ("ReferenceFilter"); + for (list >::iterator i = filters.begin(); i != filters.end(); ++i) { + _reference_filters.push_back (Filter::from_id ((*i)->content ())); + } - ifstream f (file().c_str ()); + list > servers = f.node_children ("Server"); + for (list >::iterator i = servers.begin(); i != servers.end(); ++i) { + _servers.push_back (new ServerDescription (*i)); + } + + _tms_ip = f.string_child ("TMSIP"); + _tms_path = f.string_child ("TMSPath"); + _tms_user = f.string_child ("TMSUser"); + _tms_password = f.string_child ("TMSPassword"); + + c = f.optional_string_child ("SoundProcessor"); + if (c) { + _sound_processor = SoundProcessor::from_id (c.get ()); + } + + _language = f.optional_string_child ("Language"); + _default_dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); +} + +void +Config::read_old_metadata () +{ + ifstream f (file(true).c_str ()); string line; while (getline (f, line)) { if (line.empty ()) { @@ -98,17 +144,21 @@ Config::Config () _language = v; } - _default_dci_metadata.read (k, v); + _default_dci_metadata.read_old_metadata (k, v); } } /** @return Filename to write configuration to */ string -Config::file () const +Config::file (bool old) const { boost::filesystem::path p; p /= g_get_user_config_dir (); - p /= N_(".dvdomatic"); + if (old) { + p /= ".dvdomatic"; + } else { + p /= ".dvdomatic.xml"; + } return p.string (); } @@ -127,35 +177,38 @@ Config::instance () void Config::write () const { - ofstream f (file().c_str ()); - 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"); + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("Config"); + root->add_child("NumLocalEncodingThreads")->add_child_text (boost::lexical_cast (_num_local_encoding_threads)); + root->add_child("DefaultDirectory")->add_child_text (_default_directory); + root->add_child("ServerPort")->add_child_text (boost::lexical_cast (_server_port)); if (_reference_scaler) { - f << "reference_scaler " << _reference_scaler->id () << "\n"; + root->add_child("ReferenceScaler")->add_child_text (_reference_scaler->id ()); } for (vector::const_iterator i = _reference_filters.begin(); i != _reference_filters.end(); ++i) { - f << N_("reference_filter ") << (*i)->id () << N_("\n"); + root->add_child("ReferenceFilter")->add_child_text ((*i)->id ()); } for (vector::const_iterator i = _servers.begin(); i != _servers.end(); ++i) { - f << N_("server ") << (*i)->as_metadata () << N_("\n"); + (*i)->as_xml (root->add_child ("Server")); } - 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"); + root->add_child("TMSIP")->add_child_text (_tms_ip); + root->add_child("TMSPath")->add_child_text (_tms_path); + root->add_child("TMSUser")->add_child_text (_tms_user); + root->add_child("TMSPassword")->add_child_text (_tms_password); if (_sound_processor) { - f << "sound_processor " << _sound_processor->id () << "\n"; + root->add_child("SoundProcessor")->add_child_text (_sound_processor->id ()); } if (_language) { - f << "language " << _language.get() << "\n"; + root->add_child("Language")->add_child_text (_language.get()); } - _default_dci_metadata.write (f); + _default_dci_metadata.as_xml (root->add_child ("DCIMetadata")); + + doc.write_to_file_formatted (file (false)); } string diff --git a/src/lib/config.h b/src/lib/config.h index 011ca716f..13d36d236 100644 --- a/src/lib/config.h +++ b/src/lib/config.h @@ -177,7 +177,8 @@ public: private: Config (); - std::string file () const; + std::string file (bool) const; + void read_old_metadata (); /** number of threads to use for J2K encoding on the local machine */ int _num_local_encoding_threads; diff --git a/src/lib/content.cc b/src/lib/content.cc index 2fb94e959..977f2e2a7 100644 --- a/src/lib/content.cc +++ b/src/lib/content.cc @@ -1,4 +1,6 @@ #include +#include +#include #include "content.h" #include "util.h" @@ -11,6 +13,20 @@ Content::Content (boost::filesystem::path f) } +Content::Content (shared_ptr node) +{ + _file = node->string_child ("File"); + _digest = node->string_child ("Digest"); +} + +void +Content::as_xml (xmlpp::Node* node) const +{ + boost::mutex::scoped_lock lm (_mutex); + node->add_child("File")->add_child_text (_file.string()); + node->add_child("Digest")->add_child_text (_digest); +} + void Content::examine (shared_ptr, shared_ptr, bool) { diff --git a/src/lib/content.h b/src/lib/content.h index 25c097424..3a94d2297 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -4,6 +4,11 @@ #include #include #include +#include + +namespace cxml { + class Node; +} class Job; class Film; @@ -12,9 +17,11 @@ class Content { public: Content (boost::filesystem::path); + Content (boost::shared_ptr); virtual void examine (boost::shared_ptr, boost::shared_ptr, bool); virtual std::string summary () const = 0; + virtual void as_xml (xmlpp::Node *) const; boost::filesystem::path file () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/dci_metadata.cc b/src/lib/dci_metadata.cc index 758886db4..f25b3ddb0 100644 --- a/src/lib/dci_metadata.cc +++ b/src/lib/dci_metadata.cc @@ -18,26 +18,39 @@ */ #include +#include #include "dci_metadata.h" #include "i18n.h" -using namespace std; +using std::string; +using boost::shared_ptr; + +DCIMetadata::DCIMetadata (shared_ptr node) +{ + audio_language = node->string_child ("AudioLanguage"); + subtitle_language = node->string_child ("SubtitleLanguage"); + territory = node->string_child ("Territory"); + rating = node->string_child ("Rating"); + studio = node->string_child ("Studio"); + facility = node->string_child ("Facility"); + package_type = node->string_child ("PackageType"); +} void -DCIMetadata::write (ostream& f) const +DCIMetadata::as_xml (xmlpp::Node* root) const { - 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"); + root->add_child("AudioLanguage")->add_child_text (audio_language); + root->add_child("SubtitleLanguage")->add_child_text (subtitle_language); + root->add_child("Territory")->add_child_text (territory); + root->add_child("Rating")->add_child_text (rating); + root->add_child("Studio")->add_child_text (studio); + root->add_child("Facility")->add_child_text (facility); + root->add_child("PackageType")->add_child_text (package_type); } void -DCIMetadata::read (string k, string v) +DCIMetadata::read_old_metadata (string k, string v) { if (k == N_("audio_language")) { audio_language = v; diff --git a/src/lib/dci_metadata.h b/src/lib/dci_metadata.h index eecdc7655..f61dae5a8 100644 --- a/src/lib/dci_metadata.h +++ b/src/lib/dci_metadata.h @@ -21,12 +21,20 @@ #define DVDOMATIC_DCI_METADATA_H #include +#include + +namespace cxml { + class Node; +} class DCIMetadata { public: - void read (std::string, std::string); - void write (std::ostream &) const; + DCIMetadata () {} + DCIMetadata (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + void read_old_metadata (std::string, std::string); std::string audio_language; std::string subtitle_language; diff --git a/src/lib/decoder_factory.cc b/src/lib/decoder_factory.cc deleted file mode 100644 index 7940edc2e..000000000 --- a/src/lib/decoder_factory.cc +++ /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. - -*/ - -/** @file src/decoder_factory.cc - * @brief A method to create an appropriate decoder for some content. - */ - -#include -#include "ffmpeg_decoder.h" -#include "imagemagick_decoder.h" -#include "film.h" -#include "sndfile_decoder.h" -#include "decoder_factory.h" - -using std::string; -using std::pair; -using std::make_pair; -using boost::shared_ptr; -using boost::dynamic_pointer_cast; - -Decoders -decoder_factory ( - shared_ptr f - ) -{ - return Decoders (); -} diff --git a/src/lib/decoder_factory.h b/src/lib/decoder_factory.h deleted file mode 100644 index 3fd91f876..000000000 --- a/src/lib/decoder_factory.h +++ /dev/null @@ -1,47 +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_DECODER_FACTORY_H -#define DVDOMATIC_DECODER_FACTORY_H - -/** @file src/decoder_factory.h - * @brief A method to create appropriate decoders for some content. - */ - -class Film; -class VideoDecoder; -class AudioDecoder; - -struct Decoders { - Decoders () {} - - Decoders (boost::shared_ptr v, boost::shared_ptr a) - : video (v) - , audio (a) - {} - - boost::shared_ptr video; - boost::shared_ptr audio; -}; - -extern Decoders decoder_factory ( - boost::shared_ptr - ); - -#endif diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 6109b7212..42e04e838 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -1,3 +1,4 @@ +#include #include "ffmpeg_content.h" #include "ffmpeg_decoder.h" #include "compose.hpp" @@ -8,7 +9,10 @@ #include "i18n.h" using std::string; +using std::vector; +using std::list; using boost::shared_ptr; +using boost::lexical_cast; int const FFmpegContentProperty::SUBTITLE_STREAMS = 100; int const FFmpegContentProperty::SUBTITLE_STREAM = 101; @@ -23,6 +27,54 @@ FFmpegContent::FFmpegContent (boost::filesystem::path f) } +FFmpegContent::FFmpegContent (shared_ptr node) + : Content (node) + , VideoContent (node) + , AudioContent (node) +{ + list > c = node->node_children ("SubtitleStream"); + for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + _subtitle_streams.push_back (FFmpegSubtitleStream (*i)); + if ((*i)->optional_number_child ("Selected")) { + _subtitle_stream = _subtitle_streams.back (); + } + } + + c = node->node_children ("AudioStream"); + for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + _audio_streams.push_back (FFmpegAudioStream (*i)); + if ((*i)->optional_number_child ("Selected")) { + _audio_stream = _audio_streams.back (); + } + } +} + +void +FFmpegContent::as_xml (xmlpp::Node* node) const +{ + node->add_child("Type")->add_child_text ("FFmpeg"); + Content::as_xml (node); + VideoContent::as_xml (node); + + boost::mutex::scoped_lock lm (_mutex); + + for (vector::const_iterator i = _subtitle_streams.begin(); i != _subtitle_streams.end(); ++i) { + xmlpp::Node* t = node->add_child("SubtitleStream"); + if (_subtitle_stream && *i == _subtitle_stream.get()) { + t->add_child("Selected")->add_child_text("1"); + } + i->as_xml (t); + } + + for (vector::const_iterator i = _audio_streams.begin(); i != _audio_streams.end(); ++i) { + xmlpp::Node* t = node->add_child("AudioStream"); + if (_audio_stream && *i == _audio_stream.get()) { + t->add_child("Selected")->add_child_text("1"); + } + i->as_xml (t); + } +} + void FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) { @@ -151,3 +203,37 @@ operator== (FFmpegAudioStream const & a, FFmpegAudioStream const & b) { return a.id == b.id; } + +FFmpegAudioStream::FFmpegAudioStream (shared_ptr node) +{ + name = node->string_child ("Name"); + id = node->number_child ("Id"); + frame_rate = node->number_child ("FrameRate"); + channel_layout = node->number_child ("ChannelLayout"); +} + +void +FFmpegAudioStream::as_xml (xmlpp::Node* root) const +{ + root->add_child("Name")->add_child_text (name); + root->add_child("Id")->add_child_text (lexical_cast (id)); + root->add_child("FrameRate")->add_child_text (lexical_cast (frame_rate)); + root->add_child("ChannelLayout")->add_child_text (lexical_cast (channel_layout)); +} + +/** Construct a SubtitleStream from a value returned from to_string(). + * @param t String returned from to_string(). + * @param v State file version. + */ +FFmpegSubtitleStream::FFmpegSubtitleStream (shared_ptr node) +{ + name = node->string_child ("Name"); + id = node->number_child ("Id"); +} + +void +FFmpegSubtitleStream::as_xml (xmlpp::Node* root) const +{ + root->add_child("Name")->add_child_text (name); + root->add_child("Id")->add_child_text (lexical_cast (id)); +} diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h index 83474ea66..95e24b7b3 100644 --- a/src/lib/ffmpeg_content.h +++ b/src/lib/ffmpeg_content.h @@ -15,6 +15,10 @@ public: , channel_layout (c) {} + FFmpegAudioStream (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + int channels () const { return av_get_channel_layout_nb_channels (channel_layout); } @@ -35,6 +39,10 @@ public: , id (i) {} + FFmpegSubtitleStream (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; + std::string name; int id; }; @@ -54,9 +62,11 @@ class FFmpegContent : public VideoContent, public AudioContent, public boost::en { public: FFmpegContent (boost::filesystem::path); + FFmpegContent (boost::shared_ptr); void examine (boost::shared_ptr, boost::shared_ptr, bool); std::string summary () const; + void as_xml (xmlpp::Node *) const; /* AudioContent */ int audio_channels () const; diff --git a/src/lib/film.cc b/src/lib/film.cc index d22f67e67..a6a53b3fc 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -29,6 +29,8 @@ #include #include #include +#include +#include #include "film.h" #include "format.h" #include "job.h" @@ -43,7 +45,6 @@ #include "exceptions.h" #include "examine_content_job.h" #include "scaler.h" -#include "decoder_factory.h" #include "config.h" #include "version.h" #include "ui_signaller.h" @@ -52,6 +53,9 @@ #include "sndfile_decoder.h" #include "analyse_audio_job.h" #include "playlist.h" +#include "ffmpeg_content.h" +#include "imagemagick_content.h" +#include "sndfile_content.h" #include "i18n.h" @@ -67,6 +71,7 @@ using std::setfill; using std::min; using std::make_pair; using std::endl; +using std::list; using boost::shared_ptr; using boost::lexical_cast; using boost::to_upper_copy; @@ -93,7 +98,7 @@ Film::Film (string d, bool must_exist) , _scaler (Scaler::from_id ("bicubic")) , _trim_start (0) , _trim_end (0) - , _dcp_ab (false) + , _ab (false) , _audio_gain (0) , _audio_delay (0) , _with_subtitles (false) @@ -157,7 +162,7 @@ Film::Film (Film const & o) , _scaler (o._scaler) , _trim_start (o._trim_start) , _trim_end (o._trim_end) - , _dcp_ab (o._dcp_ab) + , _ab (o._ab) , _audio_gain (o._audio_gain) , _audio_delay (o._audio_delay) , _with_subtitles (o._with_subtitles) @@ -199,7 +204,7 @@ Film::video_state_identifier () const << "_" << j2k_bandwidth() << "_" << boost::lexical_cast (colour_lut()); - if (dcp_ab()) { + if (ab()) { pair fa = Filter::ffmpeg_strings (Config::instance()->reference_filters()); s << "ab_" << Config::instance()->reference_scaler()->id() << "_" << fa.first << "_" << fa.second; } @@ -297,7 +302,7 @@ Film::make_dcp () shared_ptr r; - if (dcp_ab()) { + if (ab()) { r = JobManager::instance()->add (shared_ptr (new ABTranscodeJob (shared_from_this()))); } else { r = JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this()))); @@ -375,77 +380,54 @@ Film::encoded_frames () const void Film::write_metadata () const { + ContentList the_content = content (); + boost::mutex::scoped_lock lm (_state_mutex); boost::filesystem::create_directories (directory()); - string const m = file ("metadata"); - ofstream f (m.c_str ()); - if (!f.good ()) { - throw CreateFileError (m); - } - - f << "version " << state_version << endl; + xmlpp::Document doc; + xmlpp::Element* root = doc.create_root_node ("Metadata"); - /* User stuff */ - f << "name " << _name << endl; - f << "use_dci_name " << _use_dci_name << endl; -// f << "content " << _content << endl; - f << "trust_content_headers " << (_trust_content_headers ? "1" : "0") << endl; + root->add_child("Version")->add_child_text (boost::lexical_cast (state_version)); + root->add_child("Name")->add_child_text (_name); + root->add_child("UseDCIName")->add_child_text (_use_dci_name ? "1" : "0"); + root->add_child("TrustContentHeaders")->add_child_text (_trust_content_headers ? "1" : "0"); if (_dcp_content_type) { - f << "dcp_content_type " << _dcp_content_type->dci_name () << endl; + root->add_child("DCPContentType")->add_child_text (_dcp_content_type->dci_name ()); } if (_format) { - f << "format " << _format->as_metadata () << endl; + root->add_child("Format")->add_child_text (_format->id ()); } - f << "left_crop " << _crop.left << endl; - f << "right_crop " << _crop.right << endl; - f << "top_crop " << _crop.top << endl; - f << "bottom_crop " << _crop.bottom << endl; - for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { - f << "filter " << (*i)->id () << endl; - } - f << "scaler " << _scaler->id () << endl; - 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; - 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 << "with_subtitles " << _with_subtitles << endl; - f << "subtitle_offset " << _subtitle_offset << endl; - f << "subtitle_scale " << _subtitle_scale << endl; - f << "colour_lut " << _colour_lut << endl; - f << "j2k_bandwidth " << _j2k_bandwidth << endl; - _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; - -// 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; + root->add_child("LeftCrop")->add_child_text (boost::lexical_cast (_crop.left)); + root->add_child("RightCrop")->add_child_text (boost::lexical_cast (_crop.right)); + root->add_child("TopCrop")->add_child_text (boost::lexical_cast (_crop.top)); + root->add_child("BottomCrop")->add_child_text (boost::lexical_cast (_crop.bottom)); -// 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; + for (vector::const_iterator i = _filters.begin(); i != _filters.end(); ++i) { + root->add_child("Filter")->add_child_text ((*i)->id ()); + } + + root->add_child("Scaler")->add_child_text (_scaler->id ()); + root->add_child("TrimStart")->add_child_text (boost::lexical_cast (_trim_start)); + root->add_child("TrimEnd")->add_child_text (boost::lexical_cast (_trim_end)); + root->add_child("AB")->add_child_text (_ab ? "1" : "0"); + root->add_child("AudioGain")->add_child_text (boost::lexical_cast (_audio_gain)); + root->add_child("AudioDelay")->add_child_text (boost::lexical_cast (_audio_delay)); + root->add_child("WithSubtitles")->add_child_text (_with_subtitles ? "1" : "0"); + root->add_child("SubtitleOffset")->add_child_text (boost::lexical_cast (_subtitle_offset)); + root->add_child("SubtitleScale")->add_child_text (boost::lexical_cast (_subtitle_scale)); + root->add_child("ColourLUT")->add_child_text (boost::lexical_cast (_colour_lut)); + root->add_child("J2KBandwidth")->add_child_text (boost::lexical_cast (_j2k_bandwidth)); + _dci_metadata.as_xml (root->add_child ("DCIMetadata")); + root->add_child("DCIDate")->add_child_text (boost::gregorian::to_iso_string (_dci_date)); + root->add_child("DCPFrameRate")->add_child_text (boost::lexical_cast (_dcp_frame_rate)); + + for (ContentList::iterator i = the_content.begin(); i != the_content.end(); ++i) { + (*i)->as_xml (root->add_child ("Content")); + } + + doc.write_to_file_formatted (file ("metadata.xml")); _dirty = false; } @@ -456,137 +438,68 @@ Film::read_metadata () { boost::mutex::scoped_lock lm (_state_mutex); -// _external_audio.clear (); -// _content_audio_streams.clear (); -// _subtitle_streams.clear (); - - boost::optional version; - - /* Backward compatibility things */ - boost::optional audio_sample_rate; - boost::optional audio_stream_index; - boost::optional subtitle_stream_index; - - ifstream f (file ("metadata").c_str()); - if (!f.good()) { - throw OpenFileError (file ("metadata")); + if (boost::filesystem::exists (file ("metadata")) && !boost::filesystem::exists (file ("metadata.xml"))) { + throw StringError (_("This film was created with an older version of DVD-o-matic, and unfortunately it cannot be loaded into this version. You will need to create a new Film, re-add your content and set it up again. Sorry!")); } + + cxml::File f (file ("metadata.xml"), "Metadata"); - multimap kv = read_key_value (f); + _name = f.string_child ("Name"); + _use_dci_name = f.bool_child ("UseDCIName"); + _trust_content_headers = f.bool_child ("TrustContentHeaders"); - /* We need version before anything else */ - multimap::iterator v = kv.find ("version"); - if (v != kv.end ()) { - version = atoi (v->second.c_str()); + { + optional c = f.optional_string_child ("DCPContentType"); + if (c) { + _dcp_content_type = DCPContentType::from_dci_name (c.get ()); + } } - - for (multimap::const_iterator i = kv.begin(); i != kv.end(); ++i) { - string const k = i->first; - string const v = i->second; - if (k == "audio_sample_rate") { - audio_sample_rate = atoi (v.c_str()); + { + optional c = f.optional_string_child ("Format"); + if (c) { + _format = Format::from_id (c.get ()); } + } - /* User-specified stuff */ - if (k == "name") { - _name = v; - } else if (k == "use_dci_name") { - _use_dci_name = (v == "1"); - } else if (k == "content") { -// _content = v; - } else if (k == "trust_content_headers") { - _trust_content_headers = (v == "1"); - } else if (k == "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") { - _format = Format::from_metadata (v); - } else if (k == "left_crop") { - _crop.left = atoi (v.c_str ()); - } else if (k == "right_crop") { - _crop.right = atoi (v.c_str ()); - } else if (k == "top_crop") { - _crop.top = atoi (v.c_str ()); - } else if (k == "bottom_crop") { - _crop.bottom = atoi (v.c_str ()); - } else if (k == "filter") { - _filters.push_back (Filter::from_id (v)); - } else if (k == "scaler") { - _scaler = Scaler::from_id (v); - } else if ( ((!version || version < 2) && k == "dcp_trim_start") || k == "trim_start") { - _trim_start = atoi (v.c_str ()); - } else if ( ((!version || version < 2) && k == "dcp_trim_end") || k == "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")) { - if (!version) { - audio_stream_index = atoi (v.c_str ()); - } else { -// _content_audio_stream = audio_stream_factory (v, version); - } - } else if (k == "external_audio") { -// _external_audio.push_back (v); - } else if (k == "use_content_audio") { -// _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 ()); - } else if (k == "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") { - _subtitle_offset = atoi (v.c_str ()); - } else if (k == "subtitle_scale") { - _subtitle_scale = atof (v.c_str ()); - } else if (k == "colour_lut") { - _colour_lut = atoi (v.c_str ()); - } else if (k == "j2k_bandwidth") { - _j2k_bandwidth = atoi (v.c_str ()); - } else if (k == "dci_date") { - _dci_date = boost::gregorian::from_undelimited_string (v); - } else if (k == "dcp_frame_rate") { - _dcp_frame_rate = atoi (v.c_str ()); + _crop.left = f.number_child ("CropLeft"); + _crop.right = f.number_child ("CropRight"); + _crop.top = f.number_child ("CropTop"); + _crop.bottom = f.number_child ("CropBottom"); + + { + list > c = f.node_children ("Filter"); + for (list >::iterator i = c.begin(); i != c.end(); ++i) { + _filters.push_back (Filter::from_id ((*i)->content ())); } + } - _dci_metadata.read (k, v); + _scaler = Scaler::from_id (f.string_child ("Scaler")); + _trim_start = f.number_child ("TrimStart"); + _trim_end = f.number_child ("TrimEnd"); + _ab = f.bool_child ("AB"); + _audio_gain = f.number_child ("AudioGain"); + _audio_delay = f.number_child ("AudioDelay"); + _with_subtitles = f.bool_child ("WithSubtitles"); + _subtitle_offset = f.number_child ("SubtitleOffset"); + _subtitle_scale = f.number_child ("SubtitleScale"); + _colour_lut = f.number_child ("ColourLUT"); + _j2k_bandwidth = f.number_child ("J2KBandwidth"); + _dci_metadata = DCIMetadata (f.node_child ("DCIMetadata")); + _dci_date = boost::gregorian::from_undelimited_string (f.string_child ("DCIDate")); + _dcp_frame_rate = f.number_child ("DCPFrameRate"); + + list > c = f.node_children ("Content"); + for (list >::iterator i = c.begin(); i != c.end(); ++i) { + + string const type = (*i)->string_child ("Type"); - /* Cached stuff */ - if (k == "width") { -// _size.width = atoi (v.c_str ()); - } else if (k == "height") { -// _size.height = atoi (v.c_str ()); - } else if (k == "length") { - int const vv = atoi (v.c_str ()); - if (vv) { -// _length = vv; - } - } else if (k == "content_digest") { -// _content_digest = v; - } else if (k == "content_audio_stream" || (!version && k == "audio_stream")) { -// _content_audio_streams.push_back (audio_stream_factory (v, version)); - } else if (k == "external_audio_stream") { -// _sndfile_stream = audio_stream_factory (v, version); - } else if (k == "subtitle_stream") { -// _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == "source_frame_rate") { -// _source_frame_rate = atof (v.c_str ()); - } else if (version < 4 && k == "frames_per_second") { -// _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); + if (type == "FFmpeg") { + _content.push_back (shared_ptr (new FFmpegContent (*i))); + } else if (type == "ImageMagick") { + _content.push_back (shared_ptr (new ImageMagickContent (*i))); + } else if (type == "Sndfile") { + _content.push_back (shared_ptr (new SndfileContent (*i))); } } @@ -936,13 +849,13 @@ Film::set_trim_end (int t) } void -Film::set_dcp_ab (bool a) +Film::set_ab (bool a) { { boost::mutex::scoped_lock lm (_state_mutex); - _dcp_ab = a; + _ab = a; } - signal_changed (DCP_AB); + signal_changed (AB); } void diff --git a/src/lib/film.h b/src/lib/film.h index 928866161..f5f944409 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -123,7 +123,7 @@ public: SCALER, TRIM_START, TRIM_END, - DCP_AB, + AB, AUDIO_GAIN, AUDIO_DELAY, STILL_DURATION, @@ -200,9 +200,9 @@ public: return _trim_end; } - bool dcp_ab () const { + bool ab () const { boost::mutex::scoped_lock lm (_state_mutex); - return _dcp_ab; + return _ab; } float audio_gain () const { @@ -268,7 +268,7 @@ public: void set_scaler (Scaler const *); void set_trim_start (int); void set_trim_end (int); - void set_dcp_ab (bool); + void set_ab (bool); void set_audio_gain (float); void set_audio_delay (int); void set_still_duration (int); @@ -333,7 +333,7 @@ private: is the video without any filters or post-processing, and the right half has the specified filters and post-processing. */ - bool _dcp_ab; + bool _ab; /** Gain to apply to audio in dB */ float _audio_gain; /** Delay to apply to audio (positive moves audio later) in milliseconds */ diff --git a/src/lib/imagemagick_content.cc b/src/lib/imagemagick_content.cc index d096bff84..cb712b417 100644 --- a/src/lib/imagemagick_content.cc +++ b/src/lib/imagemagick_content.cc @@ -1,9 +1,11 @@ +#include #include "imagemagick_content.h" #include "compose.hpp" #include "i18n.h" using std::string; +using boost::shared_ptr; ImageMagickContent::ImageMagickContent (boost::filesystem::path f) : Content (f) @@ -13,6 +15,13 @@ ImageMagickContent::ImageMagickContent (boost::filesystem::path f) _video_length = 10 * 24; } +ImageMagickContent::ImageMagickContent (shared_ptr node) + : Content (node) + , VideoContent (node) +{ + +} + string ImageMagickContent::summary () const { diff --git a/src/lib/imagemagick_content.h b/src/lib/imagemagick_content.h index 0dd5baba8..99b614512 100644 --- a/src/lib/imagemagick_content.h +++ b/src/lib/imagemagick_content.h @@ -1,9 +1,14 @@ #include "video_content.h" +namespace cxml { + class Node; +} + class ImageMagickContent : public VideoContent { public: ImageMagickContent (boost::filesystem::path); + ImageMagickContent (boost::shared_ptr); std::string summary () const; diff --git a/src/lib/server.cc b/src/lib/server.cc index 9c5a77f68..ca0bec580 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -29,6 +29,7 @@ #include #include #include +#include #include "server.h" #include "util.h" #include "scaler.h" @@ -51,6 +52,19 @@ using boost::bind; using boost::scoped_array; using libdcp::Size; +ServerDescription::ServerDescription (shared_ptr node) +{ + _host_name = node->string_child ("HostName"); + _threads = node->number_child ("Threads"); +} + +void +ServerDescription::as_xml (xmlpp::Node* root) const +{ + root->add_child("HostName")->add_child_text (_host_name); + root->add_child("Threads")->add_child_text (boost::lexical_cast (_threads)); +} + /** Create a server description from a string of metadata returned from as_metadata(). * @param v Metadata. * @return ServerDescription, or 0. @@ -68,15 +82,6 @@ ServerDescription::create_from_metadata (string v) return new ServerDescription (b[0], atoi (b[1].c_str ())); } -/** @return Description of this server as text */ -string -ServerDescription::as_metadata () const -{ - stringstream s; - s << _host_name << N_(" ") << _threads; - return s.str (); -} - Server::Server (shared_ptr log) : _log (log) { diff --git a/src/lib/server.h b/src/lib/server.h index 89aeca626..398401a55 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -26,10 +26,15 @@ #include #include #include +#include #include "log.h" class Socket; +namespace cxml { + class Node; +} + /** @class ServerDescription * @brief Class to describe a server to which we can send encoding work. */ @@ -44,6 +49,8 @@ public: , _threads (t) {} + ServerDescription (boost::shared_ptr); + /** @return server's host name or IP address in string form */ std::string host_name () const { return _host_name; @@ -62,7 +69,7 @@ public: _threads = t; } - std::string as_metadata () const; + void as_xml (xmlpp::Node *) const; static ServerDescription * create_from_metadata (std::string v); diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc index 53df4deea..4794e4d31 100644 --- a/src/lib/sndfile_content.cc +++ b/src/lib/sndfile_content.cc @@ -3,7 +3,8 @@ #include "i18n.h" -using namespace std; +using std::string; +using boost::shared_ptr; SndfileContent::SndfileContent (boost::filesystem::path f) : Content (f) @@ -12,6 +13,14 @@ SndfileContent::SndfileContent (boost::filesystem::path f) } +SndfileContent::SndfileContent (shared_ptr node) + : Content (node) + , AudioContent (node) + +{ + +} + string SndfileContent::summary () const { diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index 10cb428a1..b9a500c88 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -1,9 +1,14 @@ #include "audio_content.h" +namespace cxml { + class Node; +} + class SndfileContent : public AudioContent { public: SndfileContent (boost::filesystem::path); + SndfileContent (boost::shared_ptr); std::string summary () const; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 070258008..21944c5fc 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -28,7 +28,6 @@ #include #include "transcoder.h" #include "encoder.h" -#include "decoder_factory.h" #include "film.h" #include "matcher.h" #include "delay_line.h" diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 3c47b0c7e..856b10f3a 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -23,8 +23,6 @@ * as a parameter to the constructor. */ -#include "decoder_factory.h" - class Film; class Job; class Encoder; diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc index 9fc5cf1a2..8a4414c18 100644 --- a/src/lib/video_content.cc +++ b/src/lib/video_content.cc @@ -1,3 +1,4 @@ +#include #include "video_content.h" #include "video_decoder.h" @@ -5,7 +6,9 @@ int const VideoContentProperty::VIDEO_LENGTH = 0; int const VideoContentProperty::VIDEO_SIZE = 1; int const VideoContentProperty::VIDEO_FRAME_RATE = 2; +using std::string; using boost::shared_ptr; +using boost::lexical_cast; VideoContent::VideoContent (boost::filesystem::path f) : Content (f) @@ -14,6 +17,25 @@ VideoContent::VideoContent (boost::filesystem::path f) } +VideoContent::VideoContent (shared_ptr node) + : Content (node) +{ + _video_length = node->number_child ("VideoLength"); + _video_size.width = node->number_child ("VideoWidth"); + _video_size.height = node->number_child ("VideoHeight"); + _video_frame_rate = node->number_child ("VideoFrameRate"); +} + +void +VideoContent::as_xml (xmlpp::Node* node) const +{ + boost::mutex::scoped_lock lm (_mutex); + node->add_child("VideoLength")->add_child_text (lexical_cast (_video_length)); + node->add_child("VideoWidth")->add_child_text (lexical_cast (_video_size.width)); + node->add_child("VideoHeight")->add_child_text (lexical_cast (_video_size.height)); + node->add_child("VideoFrameRate")->add_child_text (lexical_cast (_video_frame_rate)); +} + void VideoContent::take_from_video_decoder (shared_ptr d) { diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 219130668..7c9db890a 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -18,6 +18,9 @@ class VideoContent : public virtual Content { public: VideoContent (boost::filesystem::path); + VideoContent (boost::shared_ptr); + + void as_xml (xmlpp::Node *) const; ContentVideoFrame video_length () const { boost::mutex::scoped_lock lm (_mutex); diff --git a/src/lib/wscript b/src/lib/wscript index 5510d48a8..303a9951f 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -17,7 +17,6 @@ sources = """ dcp_content_type.cc dcp_video_frame.cc decoder.cc - decoder_factory.cc delay_line.cc dolby_cp750.cc encoder.cc @@ -70,7 +69,7 @@ def build(bld): obj.uselib = """ AVCODEC AVUTIL AVFORMAT AVFILTER SWSCALE SWRESAMPLE BOOST_FILESYSTEM BOOST_THREAD BOOST_DATETIME BOOST_SIGNALS2 - SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP GLIB LZMA + SNDFILE OPENJPEG POSTPROC TIFF MAGICK SSH DCP CXML GLIB LZMA """ if bld.env.TARGET_WINDOWS: obj.uselib += ' WINSOCK2' diff --git a/src/tools/makedcp.cc b/src/tools/makedcp.cc index 226cde113..85134b3c5 100644 --- a/src/tools/makedcp.cc +++ b/src/tools/makedcp.cc @@ -146,7 +146,7 @@ main (int argc, char* argv[]) film->log()->set_level ((Log::Level) log_level); cout << "\nMaking "; - if (film->dcp_ab()) { + if (film->ab()) { cout << "A/B "; } cout << "DCP for " << film->name() << "\n"; diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index d08fefa90..3d847d690 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -32,8 +32,8 @@ #include "exceptions.h" #include "scaler.h" #include "log.h" -#include "decoder_factory.h" #include "video_decoder.h" +#include "playlist.h" using std::cout; using std::cerr; @@ -150,17 +150,14 @@ main (int argc, char* argv[]) server = new ServerDescription (server_host, 1); shared_ptr film (new Film (film_dir, true)); - /* XXX */ -// opt.decode_audio = false; -// opt.decode_subtitles = true; -// opt.video_sync = true; + shared_ptr playlist = film->playlist (); + playlist->disable_audio (); - Decoders decoders = decoder_factory (film); try { - decoders.video->Video.connect (boost::bind (process_video, _1, _2, _3)); + playlist->Video.connect (boost::bind (process_video, _1, _2, _3)); bool done = false; while (!done) { - done = decoders.video->pass (); + done = playlist->pass (); } } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; diff --git a/src/wx/audio_plot.cc b/src/wx/audio_plot.cc index cf44eb69f..2a6210164 100644 --- a/src/wx/audio_plot.cc +++ b/src/wx/audio_plot.cc @@ -21,7 +21,6 @@ #include #include #include "audio_plot.h" -#include "lib/decoder_factory.h" #include "lib/audio_decoder.h" #include "lib/audio_analysis.h" #include "wx/wx_util.h" diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 40f4f0362..560c4ef27 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -175,8 +175,8 @@ FilmEditor::make_film_panel () } ++r; - _dcp_ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B")); - grid->Add (_dcp_ab, wxGBPosition (r, 0)); + _ab = new wxCheckBox (_film_panel, wxID_ANY, _("A/B")); + grid->Add (_ab, wxGBPosition (r, 0)); ++r; vector const ct = DCPContentType::all (); @@ -212,7 +212,7 @@ FilmEditor::connect_to_widgets () _dcp_content_type->Connect (wxID_ANY, wxEVT_COMMAND_CHOICE_SELECTED, wxCommandEventHandler (FilmEditor::dcp_content_type_changed), 0, this); _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); + _ab->Connect (wxID_ANY, wxEVT_COMMAND_CHECKBOX_CLICKED, wxCommandEventHandler (FilmEditor::ab_toggled), 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); @@ -489,13 +489,13 @@ FilmEditor::trust_content_headers_changed (wxCommandEvent &) /** Called when the DCP A/B switch has been toggled */ void -FilmEditor::dcp_ab_toggled (wxCommandEvent &) +FilmEditor::ab_toggled (wxCommandEvent &) { if (!_film) { return; } - _film->set_dcp_ab (_dcp_ab->GetValue ()); + _film->set_ab (_ab->GetValue ()); } /** Called when the name widget has been changed */ @@ -674,8 +674,8 @@ FilmEditor::film_changed (Film::Property p) checked_set (_dcp_content_type, DCPContentType::as_index (_film->dcp_content_type ())); setup_dcp_name (); break; - case Film::DCP_AB: - checked_set (_dcp_ab, _film->dcp_ab ()); + case Film::AB: + checked_set (_ab, _film->ab ()); break; case Film::SCALER: checked_set (_scaler, Scaler::as_index (_film->scaler ())); @@ -811,7 +811,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::SCALER); film_changed (Film::TRIM_START); film_changed (Film::TRIM_END); - film_changed (Film::DCP_AB); + film_changed (Film::AB); film_changed (Film::AUDIO_GAIN); film_changed (Film::AUDIO_DELAY); film_changed (Film::WITH_SUBTITLES); @@ -849,7 +849,7 @@ FilmEditor::set_things_sensitive (bool s) _dcp_frame_rate->Enable (s); _trim_start->Enable (s); _trim_end->Enable (s); - _dcp_ab->Enable (s); + _ab->Enable (s); _colour_lut->Enable (s); _j2k_bandwidth->Enable (s); _audio_gain->Enable (s); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 50457bdce..80072d48a 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -72,7 +72,7 @@ private: void trim_start_changed (wxCommandEvent &); void trim_end_changed (wxCommandEvent &); void dcp_content_type_changed (wxCommandEvent &); - void dcp_ab_toggled (wxCommandEvent &); + void ab_toggled (wxCommandEvent &); void scaler_changed (wxCommandEvent &); void audio_gain_changed (wxCommandEvent &); void audio_gain_calculate_button_clicked (wxCommandEvent &); @@ -162,7 +162,7 @@ private: wxSpinCtrl* _trim_start; wxSpinCtrl* _trim_end; /** Selector to generate an A/B comparison DCP */ - wxCheckBox* _dcp_ab; + wxCheckBox* _ab; std::vector _formats; diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index b552a3dbc..74ab9798c 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -23,7 +23,6 @@ #include #include "lib/film.h" -#include "lib/decoder_factory.h" class wxToggleButton; class FFmpegPlayer; diff --git a/test/test.cc b/test/test.cc index efa4848f6..5cf3dc56d 100644 --- a/test/test.cc +++ b/test/test.cc @@ -155,7 +155,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) f->set_filters (f_filters); f->set_trim_start (42); f->set_trim_end (99); - f->set_dcp_ab (true); + f->set_ab (true); f->write_metadata (); stringstream s; @@ -177,7 +177,7 @@ BOOST_AUTO_TEST_CASE (film_metadata_test) BOOST_CHECK_EQUAL (g_filters.back(), Filter::from_id ("unsharp")); BOOST_CHECK_EQUAL (g->trim_start(), 42); BOOST_CHECK_EQUAL (g->trim_end(), 99); - BOOST_CHECK_EQUAL (g->dcp_ab(), true); + BOOST_CHECK_EQUAL (g->ab(), true); g->write_metadata (); BOOST_CHECK_EQUAL (::system (s.str().c_str ()), 0); -- cgit v1.2.3