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/transcoder.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 87a1fb3f2..93963761e 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -48,7 +48,7 @@ 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, shared_ptr o, Job* j, shared_ptr e) +Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr e) : _job (j) , _encoder (e) , _decoders (decoder_factory (f, o, j)) -- cgit v1.2.3 From 2e536ef0971edefea23810b99f7706881072783b Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 8 Feb 2013 13:07:16 +0000 Subject: Shuffle Job pointers around slightly. --- src/lib/ab_transcoder.cc | 8 +++++--- src/lib/audio_decoder.cc | 4 ++-- src/lib/audio_decoder.h | 2 +- src/lib/decoder.cc | 5 +---- src/lib/decoder.h | 5 +---- src/lib/decoder_factory.cc | 10 +++++----- src/lib/decoder_factory.h | 3 +-- src/lib/examine_content_job.cc | 4 ++-- src/lib/external_audio_decoder.cc | 6 +++--- src/lib/external_audio_decoder.h | 2 +- src/lib/ffmpeg_decoder.cc | 8 ++++---- src/lib/ffmpeg_decoder.h | 2 +- src/lib/film.cc | 4 ++-- src/lib/imagemagick_decoder.cc | 6 +++--- src/lib/imagemagick_decoder.h | 2 +- src/lib/transcoder.cc | 6 ++++-- src/lib/video_decoder.cc | 12 +++++++----- src/lib/video_decoder.h | 4 ++-- src/wx/film_viewer.cc | 2 +- 19 files changed, 47 insertions(+), 48 deletions(-) (limited to 'src/lib/transcoder.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 6a516da9a403ce05b2b78b3cf1376f4dfe4be3fe Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 1 Mar 2013 21:35:41 +0000 Subject: Make film hold its DCP frame rate. --- src/lib/ab_transcoder.cc | 2 +- src/lib/analyse_audio_job.cc | 2 +- src/lib/dcp_video_frame.cc | 4 +- src/lib/dcp_video_frame.h | 4 +- src/lib/encoder.cc | 8 +- src/lib/film.cc | 45 +++++++---- src/lib/film.h | 19 +++-- src/lib/transcode_job.cc | 4 +- src/lib/transcoder.cc | 2 +- src/lib/util.cc | 37 +++++---- src/lib/util.h | 10 +-- src/lib/writer.cc | 15 ++-- src/wx/film_editor.cc | 16 ++-- src/wx/film_editor.h | 4 +- src/wx/film_viewer.cc | 6 +- src/wx/properties_dialog.cc | 4 +- test/metadata.ref | 5 +- test/test.cc | 183 +++++++++++++++++++++++-------------------- 18 files changed, 210 insertions(+), 160 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index f47a99fda..4ed5d02ca 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -60,7 +60,7 @@ ABTranscoder::ABTranscoder ( if (_film_a->audio_stream()) { shared_ptr st = _film_a->audio_stream(); - _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->frames_per_second())); + _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate())); _delay_line.reset (new DelayLine (_film_a->log(), st->channels(), _film_a->audio_delay() * st->sample_rate() / 1000)); _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); } diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index ca316f70e..41f918f34 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -66,7 +66,7 @@ AnalyseAudioJob::run () decoders.audio->set_audio_stream (_film->audio_stream ()); decoders.audio->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); - int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->frames_per_second()); + int64_t total_audio_frames = video_frames_to_audio_frames (_film->length().get(), _film->audio_stream()->sample_rate(), _film->source_frame_rate()); _samples_per_point = total_audio_frames / _num_points; _current.resize (_film->audio_stream()->channels ()); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 098d222cd..67617c63c 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -80,7 +80,7 @@ using libdcp::Size; DCPVideoFrame::DCPVideoFrame ( shared_ptr yuv, shared_ptr sub, Size out, int p, int subtitle_offset, float subtitle_scale, - Scaler const * s, int f, float fps, string pp, int clut, int bw, Log* l + Scaler const * s, int f, int dcp_fps, string pp, int clut, int bw, Log* l ) : _input (yuv) , _subtitle (sub) @@ -90,7 +90,7 @@ DCPVideoFrame::DCPVideoFrame ( , _subtitle_scale (subtitle_scale) , _scaler (s) , _frame (f) - , _frames_per_second (DCPFrameRate(fps).frames_per_second) + , _frames_per_second (dcp_fps) , _post_process (pp) , _colour_lut (clut) , _j2k_bandwidth (bw) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index ab458b58f..6794765ac 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -107,7 +107,7 @@ class DCPVideoFrame public: DCPVideoFrame ( boost::shared_ptr, boost::shared_ptr, libdcp::Size, - int, int, float, Scaler const *, int, float, std::string, int, int, Log * + int, int, float, Scaler const *, int, int, std::string, int, int, Log * ); virtual ~DCPVideoFrame (); @@ -130,7 +130,7 @@ private: float _subtitle_scale; Scaler const * _scaler; ///< scaler to use int _frame; ///< frame index within the DCP's intrinsic duration - int _frames_per_second; ///< Frames per second that we will use for the DCP (rounded) + int _frames_per_second; ///< Frames per second that we will use for the DCP std::string _post_process; ///< FFmpeg post-processing string to use int _colour_lut; ///< Colour look-up table to use int _j2k_bandwidth; ///< J2K bandwidth to use diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 3cc643cd6..687dfdd2b 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -233,9 +233,9 @@ Encoder::frame_done () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - DCPFrameRate dfr (_film->frames_per_second ()); + FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); - if (dfr.skip && (_video_frames_in % 2)) { + if (frc.skip && (_video_frames_in % 2)) { ++_video_frames_in; return; } @@ -273,7 +273,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrformat()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), - _film->scaler(), _video_frames_out, _film->frames_per_second(), s.second, + _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), _film->log() ) @@ -286,7 +286,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptrrepeat (_video_frames_out); ++_video_frames_out; frame_done (); diff --git a/src/lib/film.cc b/src/lib/film.cc index 510158e94..a661adcc6 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -74,7 +74,7 @@ using boost::starts_with; using boost::optional; using libdcp::Size; -int const Film::state_version = 3; +int const Film::state_version = 4; /** Construct a Film object in a given directory, reading any metadata * file that exists in that directory. An exception will be thrown if @@ -103,7 +103,8 @@ Film::Film (string d, bool must_exist) , _colour_lut (0) , _j2k_bandwidth (200000000) , _dci_metadata (Config::instance()->default_dci_metadata ()) - , _frames_per_second (0) + , _dcp_frame_rate (0) + , _source_frame_rate (0) , _dirty (false) { set_dci_date_today (); @@ -175,6 +176,7 @@ Film::Film (Film const & o) , _j2k_bandwidth (o._j2k_bandwidth) , _dci_metadata (o._dci_metadata) , _dci_date (o._dci_date) + , _dcp_frame_rate (o._dcp_frame_rate) , _size (o._size) , _length (o._length) , _dcp_intrinsic_duration (o._dcp_intrinsic_duration) @@ -182,7 +184,7 @@ Film::Film (Film const & o) , _content_audio_streams (o._content_audio_streams) , _external_audio_stream (o._external_audio_stream) , _subtitle_streams (o._subtitle_streams) - , _frames_per_second (o._frames_per_second) + , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) { @@ -204,6 +206,7 @@ Film::video_state_identifier () const s << format()->id() << N_("_") << content_digest() << N_("_") << crop().left << N_("_") << crop().right << N_("_") << crop().top << N_("_") << crop().bottom + << N_("_") << _dcp_frame_rate << N_("_") << f.first << N_("_") << f.second << N_("_") << scaler()->id() << N_("_") << j2k_bandwidth() @@ -441,6 +444,7 @@ Film::write_metadata () const f << N_("j2k_bandwidth ") << _j2k_bandwidth << N_("\n"); _dci_metadata.write (f); f << N_("dci_date ") << boost::gregorian::to_iso_string (_dci_date) << N_("\n"); + f << N_("dcp_frame_rate ") << _dcp_frame_rate << "\n"; f << N_("width ") << _size.width << N_("\n"); f << N_("height ") << _size.height << N_("\n"); f << N_("length ") << _length.get_value_or(0) << N_("\n"); @@ -457,7 +461,7 @@ Film::write_metadata () const f << N_("subtitle_stream ") << (*i)->to_string () << N_("\n"); } - f << N_("frames_per_second ") << _frames_per_second << N_("\n"); + f << N_("source_frame_rate ") << _source_frame_rate << N_("\n"); _dirty = false; } @@ -569,6 +573,8 @@ Film::read_metadata () _j2k_bandwidth = atoi (v.c_str ()); } else if (k == N_("dci_date")) { _dci_date = boost::gregorian::from_undelimited_string (v); + } else if (k == "dcp_frame_rate") { + _dcp_frame_rate = atoi (v.c_str ()); } _dci_metadata.read (k, v); @@ -596,8 +602,8 @@ Film::read_metadata () _external_audio_stream = audio_stream_factory (v, version); } else if (k == N_("subtitle_stream")) { _subtitle_streams.push_back (subtitle_stream_factory (v, version)); - } else if (k == N_("frames_per_second")) { - _frames_per_second = atof (v.c_str ()); + } else if (k == N_("source_frame_rate") || (version < 4 && k == "frames_per_second")) { + _source_frame_rate = atof (v.c_str ()); } } @@ -707,7 +713,7 @@ Film::target_audio_sample_rate () const /* Resample to a DCI-approved sample rate */ double t = dcp_audio_sample_rate (audio_stream()->sample_rate()); - DCPFrameRate dfr (frames_per_second ()); + FrameRateConversion frc (source_frame_rate(), dcp_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -715,8 +721,8 @@ Film::target_audio_sample_rate () const skip/repeat doesn't come into effect here. */ - if (dfr.change_speed) { - t *= _frames_per_second * dfr.factor() / dfr.frames_per_second; + if (frc.change_speed) { + t *= source_frame_rate() * frc.factor() / dcp_frame_rate(); } return rint (t); @@ -725,7 +731,7 @@ Film::target_audio_sample_rate () const int Film::still_duration_in_frames () const { - return still_duration() * frames_per_second(); + return still_duration() * source_frame_rate(); } /** @return a DCI-compliant name for a DCP of this film */ @@ -898,7 +904,7 @@ Film::set_content (string c) Decoders d = decoder_factory (shared_from_this(), DecodeOptions()); set_size (d.video->native_size ()); - set_frames_per_second (d.video->frames_per_second ()); + set_source_frame_rate (d.video->frames_per_second ()); set_subtitle_streams (d.video->subtitle_streams ()); if (d.audio) { set_content_audio_streams (d.audio->audio_streams ()); @@ -1236,6 +1242,17 @@ Film::set_dci_metadata (DCIMetadata m) signal_changed (DCI_METADATA); } + +void +Film::set_dcp_frame_rate (int f) +{ + { + boost::mutex::scoped_lock lm (_state_mutex); + _dcp_frame_rate = f; + } + signal_changed (DCP_FRAME_RATE); +} + void Film::set_size (libdcp::Size s) { @@ -1307,13 +1324,13 @@ Film::set_subtitle_streams (vector > s) } void -Film::set_frames_per_second (float f) +Film::set_source_frame_rate (float f) { { boost::mutex::scoped_lock lm (_state_mutex); - _frames_per_second = f; + _source_frame_rate = f; } - signal_changed (FRAMES_PER_SECOND); + signal_changed (SOURCE_FRAME_RATE); } void diff --git a/src/lib/film.h b/src/lib/film.h index 847ab434e..9921acbb4 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -148,7 +148,8 @@ public: DCP_INTRINSIC_DURATION, CONTENT_AUDIO_STREAMS, SUBTITLE_STREAMS, - FRAMES_PER_SECOND, + SOURCE_FRAME_RATE, + DCP_FRAME_RATE }; @@ -285,6 +286,11 @@ public: boost::mutex::scoped_lock lm (_state_mutex); return _dci_metadata; } + + int dcp_frame_rate () const { + boost::mutex::scoped_lock lm (_state_mutex); + return _dcp_frame_rate; + } libdcp::Size size () const { boost::mutex::scoped_lock lm (_state_mutex); @@ -311,13 +317,13 @@ public: return _subtitle_streams; } - float frames_per_second () const { + float source_frame_rate () const { boost::mutex::scoped_lock lm (_state_mutex); if (content_type() == STILL) { return 24; } - return _frames_per_second; + return _source_frame_rate; } boost::shared_ptr audio_stream () const; @@ -355,6 +361,7 @@ public: void set_colour_lut (int); void set_j2k_bandwidth (int); void set_dci_metadata (DCIMetadata); + void set_dcp_frame_rate (int); void set_size (libdcp::Size); void set_length (SourceFrame); void unset_length (); @@ -362,7 +369,7 @@ public: void set_content_digest (std::string); void set_content_audio_streams (std::vector >); void set_subtitle_streams (std::vector >); - void set_frames_per_second (float); + void set_source_frame_rate (float); /** Emitted when some property has changed */ mutable boost::signals2::signal Changed; @@ -461,6 +468,8 @@ private: DCIMetadata _dci_metadata; /** The date that we should use in a DCI name */ boost::gregorian::date _dci_date; + /** Frames per second to run our DCP at */ + int _dcp_frame_rate; /* Data which are cached to speed things up */ @@ -478,7 +487,7 @@ private: /** the subtitle streams that we can use */ std::vector > _subtitle_streams; /** Frames per second of the source */ - float _frames_per_second; + float _source_frame_rate; /** true if our state has changed since we last saved it */ mutable bool _dirty; diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 61fad2e2b..f7cc500fe 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -120,8 +120,8 @@ TranscodeJob::remaining_time () const /* Compute approximate proposed length here, as it's only here that we need it */ int length = _film->length().get(); - DCPFrameRate const dfr (_film->frames_per_second ()); - if (dfr.skip) { + FrameRateConversion const frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + if (frc.skip) { length /= 2; } /* If we are repeating it shouldn't affect transcode time, so don't take it into account */ diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 959fac857..9720ca56a 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -57,7 +57,7 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< if (f->audio_stream()) { shared_ptr st = f->audio_stream(); - _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->frames_per_second())); + _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate())); _delay_line.reset (new DelayLine (f->log(), st->channels(), f->audio_delay() * st->sample_rate() / 1000)); _gain.reset (new Gain (f->log(), f->audio_gain())); } diff --git a/src/lib/util.cc b/src/lib/util.cc index de69636da..85a04ed17 100644 --- a/src/lib/util.cc +++ b/src/lib/util.cc @@ -375,21 +375,12 @@ public: , dcp (dcp_) {} - bool skip () const { - return !about_equal (source, dcp) && source > dcp; - } - - bool repeat () const { - return !about_equal (source, dcp) && source < dcp; - } - float source; int dcp; }; -/** @param fps Arbitrary source frames-per-second value */ -/** XXX: this could be slow-ish */ -DCPFrameRate::DCPFrameRate (float source_fps) +int +best_dcp_frame_rate (float source_fps) { list const allowed_dcp_frame_rates = Config::instance()->allowed_dcp_frame_rates (); @@ -427,14 +418,8 @@ DCPFrameRate::DCPFrameRate (float source_fps) ++i; } - if (!best) { - throw EncodeError (_("cannot find a suitable DCP frame rate for this source")); - } - - frames_per_second = best->dcp; - skip = best->skip (); - repeat = best->repeat (); - change_speed = !about_equal (source_fps * factor(), frames_per_second); + assert (best); + return best->dcp; } /** @param An arbitrary sampling rate. @@ -962,3 +947,17 @@ AudioMapping::dcp_channels () const return _source_channels; } + +FrameRateConversion::FrameRateConversion (float source, int dcp) + : skip (false) + , repeat (false) + , change_speed (false) +{ + if (fabs (source / 2.0 - dcp) < (fabs (source - dcp))) { + skip = true; + } else if (fabs (source * 2 - dcp) < fabs (source - dcp)) { + repeat = true; + } + + change_speed = !about_equal (source * factor(), dcp); +} diff --git a/src/lib/util.h b/src/lib/util.h index 22c6ea95b..103907151 100644 --- a/src/lib/util.h +++ b/src/lib/util.h @@ -62,9 +62,9 @@ extern std::string audio_channel_name (int); typedef int SourceFrame; -struct DCPFrameRate +struct FrameRateConversion { - DCPFrameRate (float); + FrameRateConversion (float, int); /** @return factor by which to multiply a source frame rate to get the effective rate after any skip or repeat has happened. @@ -79,14 +79,12 @@ struct DCPFrameRate return 1; } - /** frames per second for the DCP */ - int frames_per_second; /** true to skip every other frame */ bool skip; /** true to repeat every frame once */ bool repeat; /** true if this DCP will run its video faster or slower than the source - * without taking into account `repeat'. + * without taking into account `repeat' nor `skip'. * (e.g. change_speed will be true if * source is 29.97fps, DCP is 30fps * source is 14.50fps, DCP is 30fps @@ -97,6 +95,8 @@ struct DCPFrameRate bool change_speed; }; +int best_dcp_frame_rate (float); + enum ContentType { STILL, ///< content is still images VIDEO ///< content is a video diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 334ecec65..5a2f7c9a9 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -67,8 +67,8 @@ Writer::Writer (shared_ptr f) new libdcp::MonoPictureAsset ( _film->video_mxf_dir (), _film->video_mxf_filename (), - DCPFrameRate (_film->frames_per_second()).frames_per_second, - _film->format()->dcp_size() + _film->dcp_frame_rate (), + _film->format()->dcp_size () ) ); @@ -81,7 +81,7 @@ Writer::Writer (shared_ptr f) new libdcp::SoundAsset ( _film->dir (_film->dcp_name()), N_("audio.mxf"), - DCPFrameRate (_film->frames_per_second()).frames_per_second, + _film->dcp_frame_rate (), m.dcp_channels (), dcp_audio_sample_rate (_film->audio_stream()->sample_rate()) ) @@ -289,10 +289,15 @@ Writer::finish () } libdcp::DCP dcp (_film->dir (_film->dcp_name())); - DCPFrameRate dfr (_film->frames_per_second ()); shared_ptr cpl ( - new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second) + new libdcp::CPL ( + _film->dir (_film->dcp_name()), + _film->dcp_name(), + _film->dcp_content_type()->libdcp_kind (), + frames, + _film->dcp_frame_rate () + ) ); dcp.add_cpl (cpl); diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 362243ef3..0a6a35273 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -127,8 +127,8 @@ FilmEditor::make_film_panel () grid->Add (_dcp_content_type); video_control (add_label_to_sizer (grid, _film_panel, _("Original Frame Rate"))); - _frames_per_second = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); - grid->Add (video_control (_frames_per_second), 1, wxALIGN_CENTER_VERTICAL); + _source_frame_rate = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); + grid->Add (video_control (_source_frame_rate), 1, wxALIGN_CENTER_VERTICAL); video_control (add_label_to_sizer (grid, _film_panel, _("Original Size"))); _original_size = new wxStaticText (_film_panel, wxID_ANY, wxT ("")); @@ -596,9 +596,9 @@ FilmEditor::film_changed (Film::Property p) checked_set (_name, _film->name()); setup_dcp_name (); break; - case Film::FRAMES_PER_SECOND: - s << fixed << setprecision(2) << _film->frames_per_second(); - _frames_per_second->SetLabel (std_to_wx (s.str ())); + case Film::SOURCE_FRAME_RATE: + s << fixed << setprecision(2) << _film->source_frame_rate(); + _source_frame_rate->SetLabel (std_to_wx (s.str ())); break; case Film::SIZE: if (_film->size().width == 0 && _film->size().height == 0) { @@ -609,8 +609,8 @@ FilmEditor::film_changed (Film::Property p) } break; case Film::LENGTH: - if (_film->frames_per_second() > 0 && _film->length()) { - s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->frames_per_second()); + if (_film->source_frame_rate() > 0 && _film->length()) { + s << _film->length().get() << " " << _("frames") << "; " << seconds_to_hms (_film->length().get() / _film->source_frame_rate()); } else if (_film->length()) { s << _film->length().get() << " " << _("frames"); } @@ -782,7 +782,7 @@ FilmEditor::set_film (shared_ptr f) film_changed (Film::LENGTH); film_changed (Film::CONTENT_AUDIO_STREAMS); film_changed (Film::SUBTITLE_STREAMS); - film_changed (Film::FRAMES_PER_SECOND); + film_changed (Film::SOURCE_FRAME_RATE); } /** Updates the sensitivity of lots of widgets to a given value. diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 2af747bb0..da9bb0301 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -157,8 +157,8 @@ private: wxSpinCtrl* _j2k_bandwidth; /** The Film's DCP content type */ wxChoice* _dcp_content_type; - /** The Film's frames per second */ - wxStaticText* _frames_per_second; + /** The Film's source frame rate */ + wxStaticText* _source_frame_rate; /** The Film's original size */ wxStaticText* _original_size; /** The Film's length */ diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 5eba7fd80..a40a3c78d 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -188,7 +188,7 @@ FilmViewer::timer (wxTimerEvent &) get_frame (); if (_film->length()) { - int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->frames_per_second()); + int const new_slider_position = 4096 * _decoders.video->last_source_time() / (_film->length().get() / _film->source_frame_rate()); if (new_slider_position != _slider->GetValue()) { _slider->SetValue (new_slider_position); } @@ -237,7 +237,7 @@ FilmViewer::slider_moved (wxScrollEvent &) return; } - if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->frames_per_second()))) { + if (_decoders.video->seek (_slider->GetValue() * _film->length().get() / (4096 * _film->source_frame_rate()))) { return; } @@ -369,7 +369,7 @@ FilmViewer::check_play_state () } if (_play_button->GetValue()) { - _timer.Start (1000 / _film->frames_per_second()); + _timer.Start (1000 / _film->source_frame_rate()); } else { _timer.Stop (); } diff --git a/src/wx/properties_dialog.cc b/src/wx/properties_dialog.cc index e93d06dbe..f4acb6b1a 100644 --- a/src/wx/properties_dialog.cc +++ b/src/wx/properties_dialog.cc @@ -52,7 +52,9 @@ PropertiesDialog::PropertiesDialog (wxWindow* parent, shared_ptr film) if (_film->length()) { _frames->SetLabel (std_to_wx (lexical_cast (_film->length().get()))); - double const disk = ((double) _film->j2k_bandwidth() / 8) * _film->length().get() / (_film->frames_per_second () * 1073741824); + FrameRateConversion frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + int const dcp_length = _film->length().get() * frc.factor(); + double const disk = ((double) _film->j2k_bandwidth() / 8) * dcp_length / (_film->dcp_frame_rate() * 1073741824); stringstream s; s << fixed << setprecision (1) << disk << _("Gb"); _disk->SetLabel (std_to_wx (s.str ())); diff --git a/test/metadata.ref b/test/metadata.ref index ab40dfe8d..10702f8a0 100644 --- a/test/metadata.ref +++ b/test/metadata.ref @@ -1,4 +1,4 @@ -version 3 +version 4 name fred use_dci_name 1 content @@ -32,10 +32,11 @@ studio facility package_type dci_date 20130211 +dcp_frame_rate 0 width 0 height 0 length 0 dcp_intrinsic_duration 0 content_digest external_audio_stream external 0 0 -frames_per_second 0 +source_frame_rate 0 diff --git a/test/test.cc b/test/test.cc index 8cfc6e467..b4a459fe7 100644 --- a/test/test.cc +++ b/test/test.cc @@ -500,8 +500,8 @@ BOOST_AUTO_TEST_CASE (make_dcp_with_range_test) BOOST_CHECK_EQUAL (JobManager::instance()->errors(), false); } -/* Test the constructor of DCPFrameRate */ -BOOST_AUTO_TEST_CASE (dcp_frame_rate_test) +/* Test best_dcp_frame_rate and FrameRateConversion */ +BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test) { /* Run some tests with a limited range of allowed rates */ @@ -511,71 +511,82 @@ BOOST_AUTO_TEST_CASE (dcp_frame_rate_test) afr.push_back (30); Config::instance()->set_allowed_dcp_frame_rates (afr); - DCPFrameRate dfr = DCPFrameRate (60); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.skip, true); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + int best = best_dcp_frame_rate (60); + FrameRateConversion frc = FrameRateConversion (60, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, true); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); - dfr = DCPFrameRate (50); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.skip, true); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (48); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 24); - BOOST_CHECK_EQUAL (dfr.skip, true); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (50); + frc = FrameRateConversion (50, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, true); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (48); + frc = FrameRateConversion (48, best); + BOOST_CHECK_EQUAL (best, 24); + BOOST_CHECK_EQUAL (frc.skip, true); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); - dfr = DCPFrameRate (30); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (29.97); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, true); + best = best_dcp_frame_rate (30); + frc = FrameRateConversion (30, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (29.97); + frc = FrameRateConversion (29.97, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, true); - dfr = DCPFrameRate (25); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (24); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 24); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (14.5); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 30); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, true); - - dfr = DCPFrameRate (12.6); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, true); - - dfr = DCPFrameRate (12.4); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 25); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, true); - - dfr = DCPFrameRate (12); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 24); - BOOST_CHECK_EQUAL (dfr.repeat, true); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (25); + frc = FrameRateConversion (25, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (24); + frc = FrameRateConversion (24, best); + BOOST_CHECK_EQUAL (best, 24); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (14.5); + frc = FrameRateConversion (14.5, best); + BOOST_CHECK_EQUAL (best, 30); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, true); + + best = best_dcp_frame_rate (12.6); + frc = FrameRateConversion (12.6, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, true); + + best = best_dcp_frame_rate (12.4); + frc = FrameRateConversion (12.4, best); + BOOST_CHECK_EQUAL (best, 25); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, true); + + best = best_dcp_frame_rate (12); + frc = FrameRateConversion (12, best); + BOOST_CHECK_EQUAL (best, 24); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, true); + BOOST_CHECK_EQUAL (frc.change_speed, false); /* Now add some more rates and see if it will use them in preference to skip/repeat. @@ -586,29 +597,33 @@ BOOST_AUTO_TEST_CASE (dcp_frame_rate_test) afr.push_back (60); Config::instance()->set_allowed_dcp_frame_rates (afr); - dfr = DCPFrameRate (60); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 60); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (60); + frc = FrameRateConversion (60, best); + BOOST_CHECK_EQUAL (best, 60); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); - dfr = DCPFrameRate (50); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 50); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); - - dfr = DCPFrameRate (48); - BOOST_CHECK_EQUAL (dfr.frames_per_second, 48); - BOOST_CHECK_EQUAL (dfr.skip, false); - BOOST_CHECK_EQUAL (dfr.repeat, false); - BOOST_CHECK_EQUAL (dfr.change_speed, false); + best = best_dcp_frame_rate (50); + frc = FrameRateConversion (50, best); + BOOST_CHECK_EQUAL (best, 50); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); + + best = best_dcp_frame_rate (48); + frc = FrameRateConversion (48, best); + BOOST_CHECK_EQUAL (best, 48); + BOOST_CHECK_EQUAL (frc.skip, false); + BOOST_CHECK_EQUAL (frc.repeat, false); + BOOST_CHECK_EQUAL (frc.change_speed, false); } BOOST_AUTO_TEST_CASE (audio_sampling_rate_test) { shared_ptr f = new_test_film ("audio_sampling_rate_test"); - f->set_frames_per_second (24); + f->set_source_frame_rate (24); + f->set_dcp_frame_rate (24); f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 48000); @@ -619,11 +634,13 @@ BOOST_AUTO_TEST_CASE (audio_sampling_rate_test) f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 80000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 96000); - f->set_frames_per_second (23.976); + f->set_source_frame_rate (23.976); + f->set_dcp_frame_rate (best_dcp_frame_rate (23.976)); f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952); - f->set_frames_per_second (29.97); + f->set_source_frame_rate (29.97); + f->set_dcp_frame_rate (best_dcp_frame_rate (29.97)); f->set_content_audio_stream (shared_ptr (new FFmpegAudioStream ("a", 42, 48000, 0))); BOOST_CHECK_EQUAL (f->target_audio_sample_rate(), 47952); } -- cgit v1.2.3 From 18614dda0d53b713ace5ad1df57298d049dba87f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 5 Mar 2013 23:10:16 +0000 Subject: Split timed from untimed sinks / sources. Should produce same output, in theory. --- src/lib/ab_transcoder.cc | 7 ++++--- src/lib/audio_decoder.h | 2 +- src/lib/audio_sink.h | 7 +++++++ src/lib/audio_source.cc | 6 ++++++ src/lib/audio_source.h | 12 +++++++++++ src/lib/combiner.cc | 8 ++++---- src/lib/combiner.h | 6 +++--- src/lib/delay_line.cc | 7 ++++--- src/lib/delay_line.h | 4 ++-- src/lib/external_audio_decoder.cc | 4 +++- src/lib/ffmpeg_decoder.cc | 8 +++++--- src/lib/gain.cc | 2 +- src/lib/gain.h | 2 +- src/lib/imagemagick_decoder.cc | 3 ++- src/lib/matcher.cc | 6 +++--- src/lib/matcher.h | 6 +++--- src/lib/processor.h | 42 --------------------------------------- src/lib/transcoder.cc | 3 ++- src/lib/video_decoder.cc | 10 +++++----- src/lib/video_decoder.h | 6 +++--- src/lib/video_sink.h | 12 +++++++++++ src/lib/video_source.cc | 6 ++++++ src/lib/video_source.h | 23 +++++++++++++++++++-- test/test.cc | 6 ++++-- 24 files changed, 114 insertions(+), 84 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 4ed5d02ca..373549b57 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -70,14 +70,15 @@ ABTranscoder::ABTranscoder ( _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)); + _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); + _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); if (_matcher) { _combiner->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - _combiner->connect_video (_encoder); + /* Remove timestamp from the output of the combiner */ + _combiner->Video.connect (bind (&Encoder::process_video, _encoder, _1, _2, _3)); } if (_matcher && _delay_line) { diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 9bef8e0e7..cfe94b528 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -31,7 +31,7 @@ /** @class AudioDecoder. * @brief Parent class for audio decoders. */ -class AudioDecoder : public AudioSource, public virtual Decoder +class AudioDecoder : public TimedAudioSource, public virtual Decoder { public: AudioDecoder (boost::shared_ptr, DecodeOptions); diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index 11d578a60..a222bd6a0 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -27,4 +27,11 @@ public: virtual void process_audio (boost::shared_ptr) = 0; }; +class TimedAudioSink +{ +public: + /** Call with some audio data */ + virtual void process_audio (boost::shared_ptr, double t) = 0; +}; + #endif diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index 53b0dda15..bca3562cf 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -28,3 +28,9 @@ AudioSource::connect_audio (shared_ptr s) { Audio.connect (bind (&AudioSink::process_audio, s, _1)); } + +void +TimedAudioSource::connect_audio (shared_ptr s) +{ + Audio.connect (bind (&TimedAudioSink::process_audio, s, _1, _2)); +} diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index 5a1510d3c..3dc998cca 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -28,6 +28,7 @@ class AudioBuffers; class AudioSink; +class TimedAudioSink; /** A class that emits audio data */ class AudioSource @@ -39,4 +40,15 @@ public: void connect_audio (boost::shared_ptr); }; + +/** A class that emits audio data with timestamps */ +class TimedAudioSource +{ +public: + /** Emitted when some audio data is ready */ + boost::signals2::signal, double)> Audio; + + void connect_audio (boost::shared_ptr); +}; + #endif diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 68aafd2a2..e628f3a84 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -23,7 +23,7 @@ using boost::shared_ptr; Combiner::Combiner (Log* log) - : VideoProcessor (log) + : Processor (log) { } @@ -33,7 +33,7 @@ Combiner::Combiner (Log* log) * @param image Frame image. */ void -Combiner::process_video (shared_ptr image, bool, shared_ptr) +Combiner::process_video (shared_ptr image, bool, shared_ptr, double) { _image = image; } @@ -43,7 +43,7 @@ Combiner::process_video (shared_ptr image, bool, shared_ptr) * @param sub Subtitle (which will be put onto the whole frame) */ void -Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub) +Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, double t) { /* Copy the right half of this image into our _image */ /* XXX: this should probably be in the Image class */ @@ -62,6 +62,6 @@ Combiner::process_video_b (shared_ptr image, bool, shared_ptr s } } - Video (_image, false, sub); + Video (_image, false, sub, t); _image.reset (); } diff --git a/src/lib/combiner.h b/src/lib/combiner.h index 7fad1aeae..c52c53ed9 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -28,13 +28,13 @@ * one image used for the left half of the screen and the other for * the right. */ -class Combiner : public VideoProcessor +class Combiner : public Processor, public TimedVideoSink, public TimedVideoSource { public: Combiner (Log* log); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); - void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double t); + void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, double t); private: /** The image that we are currently working on */ diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index 4ad172781..84785cfc6 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -31,7 +31,7 @@ using boost::shared_ptr; * @param frames Delay in frames, +ve to move audio later. */ DelayLine::DelayLine (Log* log, int channels, int frames) - : AudioProcessor (log) + : Processor (log) , _negative_delay_remaining (0) , _frames (frames) { @@ -47,8 +47,9 @@ DelayLine::DelayLine (Log* log, int channels, int frames) } } +/* XXX: can we just get rid of all this and fiddle with the timestamp? */ void -DelayLine::process_audio (shared_ptr data) +DelayLine::process_audio (shared_ptr data, double t) { if (_buffers) { /* We have some buffers, so we are moving the audio later */ @@ -89,5 +90,5 @@ DelayLine::process_audio (shared_ptr data) } } - Audio (data); + Audio (data, t); } diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 4d6f1313b..8c4a3953c 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -23,12 +23,12 @@ class AudioBuffers; /** A delay line for audio */ -class DelayLine : public AudioProcessor +class DelayLine : public Processor, public TimedAudioSink, public TimedAudioSource { public: DelayLine (Log* log, int channels, int frames); - void process_audio (boost::shared_ptr); + void process_audio (boost::shared_ptr, double); private: boost::shared_ptr _buffers; diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc index 1248b5a3b..50e5852c5 100644 --- a/src/lib/external_audio_decoder.cc +++ b/src/lib/external_audio_decoder.cc @@ -115,6 +115,7 @@ ExternalAudioDecoder::pass () sf_count_t const block = _audio_stream->sample_rate() / 2; shared_ptr audio (new AudioBuffers (_audio_stream->channels(), block)); + sf_count_t done = 0; while (frames > 0) { sf_count_t const this_time = min (block, frames); for (size_t i = 0; i < sndfiles.size(); ++i) { @@ -126,7 +127,8 @@ ExternalAudioDecoder::pass () } audio->set_frames (this_time); - Audio (audio); + Audio (audio, double(done) / _audio_stream->sample_rate()); + done += this_time; frames -= this_time; } diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index ac25844e3..32c8e224a 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -640,7 +640,8 @@ FFmpegDecoder::out_with_sync () if (delta > one_frame) { int const extra = rint (delta / one_frame); for (int i = 0; i < extra; ++i) { - repeat_last_video (); + /* XXX: timestamp is wrong */ + repeat_last_video (source_pts_seconds); _film->log()->log ( String::compose ( N_("Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)"), @@ -739,7 +740,8 @@ FFmpegDecoder::decode_audio_packet () if (s) { shared_ptr audio (new AudioBuffers (ffa->channels(), s)); audio->make_silent (); - Audio (audio); + /* XXX: this time stamp is wrong */ + Audio (audio, source_pts_seconds); } } @@ -748,7 +750,7 @@ FFmpegDecoder::decode_audio_packet () ); assert (_audio_codec_context->channels == _film->audio_channels()); - Audio (deinterleave_audio (_frame->data, data_size)); + Audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds ); } } diff --git a/src/lib/gain.cc b/src/lib/gain.cc index cec3b3c62..35ce27cea 100644 --- a/src/lib/gain.cc +++ b/src/lib/gain.cc @@ -23,7 +23,7 @@ using boost::shared_ptr; /** @param gain gain in dB */ Gain::Gain (Log* log, float gain) - : AudioProcessor (log) + : Processor (log) , _gain (gain) { diff --git a/src/lib/gain.h b/src/lib/gain.h index 716ee9b51..449473582 100644 --- a/src/lib/gain.h +++ b/src/lib/gain.h @@ -19,7 +19,7 @@ #include "processor.h" -class Gain : public AudioProcessor +class Gain : public Processor, public AudioSink, public AudioSource { public: Gain (Log* log, float gain); diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 5dc0b7b06..38dace6de 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -77,7 +77,8 @@ ImageMagickDecoder::pass () return true; } - repeat_last_video (); + /* XXX: timestamp is wrong */ + repeat_last_video (0); return false; } diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 4cd264338..3a513b24e 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -27,7 +27,7 @@ using std::min; using boost::shared_ptr; Matcher::Matcher (Log* log, int sample_rate, float frames_per_second) - : AudioVideoProcessor (log) + : Processor (log) , _sample_rate (sample_rate) , _frames_per_second (frames_per_second) , _video_frames (0) @@ -37,7 +37,7 @@ Matcher::Matcher (Log* log, int sample_rate, float frames_per_second) } void -Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) +Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double) { Video (i, same, s); _video_frames++; @@ -47,7 +47,7 @@ Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr } void -Matcher::process_audio (boost::shared_ptr b) +Matcher::process_audio (boost::shared_ptr b, double) { Audio (b); _audio_frames += b->frames (); diff --git a/src/lib/matcher.h b/src/lib/matcher.h index 60bb87432..4a66f4e70 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -21,12 +21,12 @@ #include "processor.h" #include "ffmpeg_compatibility.h" -class Matcher : public AudioVideoProcessor +class Matcher : public Processor, public TimedVideoSink, public TimedAudioSink, public VideoSource, public AudioSource { public: Matcher (Log* log, int sample_rate, float frames_per_second); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); - void process_audio (boost::shared_ptr); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double t); + void process_audio (boost::shared_ptr, double t); void process_end (); private: diff --git a/src/lib/processor.h b/src/lib/processor.h index 19d7c4b0c..863bfdbb5 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -53,46 +53,4 @@ protected: Log* _log; ///< log to write to }; -/** @class AudioVideoProcessor - * @brief A processor which handles both video and audio data. - */ -class AudioVideoProcessor : public Processor, public VideoSource, public VideoSink, public AudioSource, public AudioSink -{ -public: - /** Construct an AudioVideoProcessor. - * @param log Log to write to. - */ - AudioVideoProcessor (Log* log) - : Processor (log) - {} -}; - -/** @class AudioProcessor - * @brief A processor which handles just audio data. - */ -class AudioProcessor : public Processor, public AudioSource, public AudioSink -{ -public: - /** Construct an AudioProcessor. - * @param log Log to write to. - */ - AudioProcessor (Log* log) - : Processor (log) - {} -}; - -/** @class VideoProcessor - * @brief A processor which handles just video data. - */ -class VideoProcessor : public Processor, public VideoSource, public VideoSink -{ -public: - /** Construct an VideoProcessor. - * @param log Log to write to. - */ - VideoProcessor (Log* log) - : Processor (log) - {} -}; - #endif diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 9720ca56a..3beda2b8b 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -72,7 +72,8 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< _decoders.video->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - _decoders.video->connect_video (_encoder); + /* Discard timestamps here */ + _decoders.video->Video.connect (boost::bind (&Encoder::process_video, _encoder, _1, _2, _3)); } if (_matcher && _delay_line && _decoders.audio) { diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 891720f6b..773688b34 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -51,7 +51,7 @@ VideoDecoder::emit_video (shared_ptr image, double t) sub = _timed_subtitle->subtitle (); } - signal_video (image, false, sub); + signal_video (image, false, sub, t); _last_source_time = t; } @@ -60,14 +60,14 @@ VideoDecoder::emit_video (shared_ptr image, double t) * we will generate a black frame. */ void -VideoDecoder::repeat_last_video () +VideoDecoder::repeat_last_video (double t) { if (!_last_image) { _last_image.reset (new SimpleImage (pixel_format(), native_size(), true)); _last_image->make_black (); } - signal_video (_last_image, true, _last_subtitle); + signal_video (_last_image, true, _last_subtitle, t); } /** Emit our signal to say that some video data is ready. @@ -76,10 +76,10 @@ VideoDecoder::repeat_last_video () * @param sub Subtitle for this frame, or 0. */ void -VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub) +VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub, double t) { TIMING (N_("Decoder emits %1"), _video_frame); - Video (image, same, sub); + Video (image, same, sub, t); ++_video_frame; _last_image = image; diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 283ab5d88..5e9c60d08 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -24,7 +24,7 @@ #include "stream.h" #include "decoder.h" -class VideoDecoder : public VideoSource, public virtual Decoder +class VideoDecoder : public TimedVideoSource, public virtual Decoder { public: VideoDecoder (boost::shared_ptr, DecodeOptions); @@ -67,7 +67,7 @@ protected: void emit_video (boost::shared_ptr, double); void emit_subtitle (boost::shared_ptr); - void repeat_last_video (); + void repeat_last_video (double t); /** Subtitle stream to use when decoding */ boost::shared_ptr _subtitle_stream; @@ -75,7 +75,7 @@ protected: std::vector > _subtitle_streams; private: - void signal_video (boost::shared_ptr, bool, boost::shared_ptr); + void signal_video (boost::shared_ptr, bool, boost::shared_ptr, double); int _video_frame; double _last_source_time; diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 7c128cf73..32c7f3b38 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -37,4 +37,16 @@ public: virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) = 0; }; +class TimedVideoSink +{ +public: + /** Call with a frame of video. + * @param i Video frame image. + * @param same true if i is the same as last time we were called. + * @param s A subtitle that should be on this frame, or 0. + * @param t Source timestamp. + */ + virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double t) = 0; +}; + #endif diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 56742e2b4..af6f941fd 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -28,3 +28,9 @@ VideoSource::connect_video (shared_ptr s) { Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); } + +void +TimedVideoSource::connect_video (shared_ptr s) +{ + Video.connect (bind (&TimedVideoSink::process_video, s, _1, _2, _3, _4)); +} diff --git a/src/lib/video_source.h b/src/lib/video_source.h index 893629160..705b0023a 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -29,11 +29,12 @@ #include "util.h" class VideoSink; +class TimedVideoSink; class Subtitle; class Image; -/** @class VideoSink - * @param A class that emits video data. +/** @class VideoSource + * @param A class that emits video data without timestamps. */ class VideoSource { @@ -49,4 +50,22 @@ public: void connect_video (boost::shared_ptr); }; +/** @class TimedVideoSource + * @param A class that emits video data with timestamps. + */ +class TimedVideoSource +{ +public: + + /** Emitted when a video frame is ready. + * First parameter is the video image. + * Second parameter is true if the image is the same as the last one that was emitted. + * Third parameter is either 0 or a subtitle that should be on this frame. + * Fourth parameter is the source timestamp of this frame. + */ + boost::signals2::signal, bool, boost::shared_ptr, double)> Video; + + void connect_video (boost::shared_ptr); +}; + #endif diff --git a/test/test.cc b/test/test.cc index 15c34ca78..b2af8ab22 100644 --- a/test/test.cc +++ b/test/test.cc @@ -273,7 +273,8 @@ do_positive_delay_line_test (int delay_length, int data_length) } /* This only works because the delay line modifies the parameter */ - d.process_audio (data); + /* XXX: timestamp is wrong */ + d.process_audio (data, 0); returned += data->frames (); for (int j = 0; j < data->frames(); ++j) { @@ -316,7 +317,8 @@ do_negative_delay_line_test (int delay_length, int data_length) } /* This only works because the delay line modifies the parameter */ - d.process_audio (data); + /* XXX: timestamp is wrong */ + d.process_audio (data, 0); returned += data->frames (); for (int j = 0; j < data->frames(); ++j) { -- cgit v1.2.3 From 422341d1cb6bc8cbb6be76eac239c40cb4061c79 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 6 Mar 2013 00:51:44 +0000 Subject: Revert "Split timed from untimed sinks / sources. Should produce same output, in theory." This reverts commit 18614dda0d53b713ace5ad1df57298d049dba87f. --- src/lib/ab_transcoder.cc | 7 +++---- src/lib/audio_decoder.h | 2 +- src/lib/audio_sink.h | 7 ------- src/lib/audio_source.cc | 6 ------ src/lib/audio_source.h | 12 ----------- src/lib/combiner.cc | 8 ++++---- src/lib/combiner.h | 6 +++--- src/lib/delay_line.cc | 7 +++---- src/lib/delay_line.h | 4 ++-- src/lib/external_audio_decoder.cc | 4 +--- src/lib/ffmpeg_decoder.cc | 8 +++----- src/lib/gain.cc | 2 +- src/lib/gain.h | 2 +- src/lib/imagemagick_decoder.cc | 3 +-- src/lib/matcher.cc | 6 +++--- src/lib/matcher.h | 6 +++--- src/lib/processor.h | 42 +++++++++++++++++++++++++++++++++++++++ src/lib/transcoder.cc | 3 +-- src/lib/video_decoder.cc | 10 +++++----- src/lib/video_decoder.h | 6 +++--- src/lib/video_sink.h | 12 ----------- src/lib/video_source.cc | 6 ------ src/lib/video_source.h | 23 ++------------------- test/test.cc | 6 ++---- 24 files changed, 84 insertions(+), 114 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 373549b57..4ed5d02ca 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -70,15 +70,14 @@ ABTranscoder::ABTranscoder ( _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, _4)); - _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); + _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)); if (_matcher) { _combiner->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - /* Remove timestamp from the output of the combiner */ - _combiner->Video.connect (bind (&Encoder::process_video, _encoder, _1, _2, _3)); + _combiner->connect_video (_encoder); } if (_matcher && _delay_line) { diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index cfe94b528..9bef8e0e7 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -31,7 +31,7 @@ /** @class AudioDecoder. * @brief Parent class for audio decoders. */ -class AudioDecoder : public TimedAudioSource, public virtual Decoder +class AudioDecoder : public AudioSource, public virtual Decoder { public: AudioDecoder (boost::shared_ptr, DecodeOptions); diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index a222bd6a0..11d578a60 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -27,11 +27,4 @@ public: virtual void process_audio (boost::shared_ptr) = 0; }; -class TimedAudioSink -{ -public: - /** Call with some audio data */ - virtual void process_audio (boost::shared_ptr, double t) = 0; -}; - #endif diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index bca3562cf..53b0dda15 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -28,9 +28,3 @@ AudioSource::connect_audio (shared_ptr s) { Audio.connect (bind (&AudioSink::process_audio, s, _1)); } - -void -TimedAudioSource::connect_audio (shared_ptr s) -{ - Audio.connect (bind (&TimedAudioSink::process_audio, s, _1, _2)); -} diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index 3dc998cca..5a1510d3c 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -28,7 +28,6 @@ class AudioBuffers; class AudioSink; -class TimedAudioSink; /** A class that emits audio data */ class AudioSource @@ -40,15 +39,4 @@ public: void connect_audio (boost::shared_ptr); }; - -/** A class that emits audio data with timestamps */ -class TimedAudioSource -{ -public: - /** Emitted when some audio data is ready */ - boost::signals2::signal, double)> Audio; - - void connect_audio (boost::shared_ptr); -}; - #endif diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index e628f3a84..68aafd2a2 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -23,7 +23,7 @@ using boost::shared_ptr; Combiner::Combiner (Log* log) - : Processor (log) + : VideoProcessor (log) { } @@ -33,7 +33,7 @@ Combiner::Combiner (Log* log) * @param image Frame image. */ void -Combiner::process_video (shared_ptr image, bool, shared_ptr, double) +Combiner::process_video (shared_ptr image, bool, shared_ptr) { _image = image; } @@ -43,7 +43,7 @@ Combiner::process_video (shared_ptr image, bool, shared_ptr, do * @param sub Subtitle (which will be put onto the whole frame) */ void -Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, double t) +Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub) { /* Copy the right half of this image into our _image */ /* XXX: this should probably be in the Image class */ @@ -62,6 +62,6 @@ Combiner::process_video_b (shared_ptr image, bool, shared_ptr s } } - Video (_image, false, sub, t); + Video (_image, false, sub); _image.reset (); } diff --git a/src/lib/combiner.h b/src/lib/combiner.h index c52c53ed9..7fad1aeae 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -28,13 +28,13 @@ * one image used for the left half of the screen and the other for * the right. */ -class Combiner : public Processor, public TimedVideoSink, public TimedVideoSource +class Combiner : public VideoProcessor { public: Combiner (Log* log); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double t); - void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, double t); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); + void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s); private: /** The image that we are currently working on */ diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index 84785cfc6..4ad172781 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -31,7 +31,7 @@ using boost::shared_ptr; * @param frames Delay in frames, +ve to move audio later. */ DelayLine::DelayLine (Log* log, int channels, int frames) - : Processor (log) + : AudioProcessor (log) , _negative_delay_remaining (0) , _frames (frames) { @@ -47,9 +47,8 @@ DelayLine::DelayLine (Log* log, int channels, int frames) } } -/* XXX: can we just get rid of all this and fiddle with the timestamp? */ void -DelayLine::process_audio (shared_ptr data, double t) +DelayLine::process_audio (shared_ptr data) { if (_buffers) { /* We have some buffers, so we are moving the audio later */ @@ -90,5 +89,5 @@ DelayLine::process_audio (shared_ptr data, double t) } } - Audio (data, t); + Audio (data); } diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 8c4a3953c..4d6f1313b 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -23,12 +23,12 @@ class AudioBuffers; /** A delay line for audio */ -class DelayLine : public Processor, public TimedAudioSink, public TimedAudioSource +class DelayLine : public AudioProcessor { public: DelayLine (Log* log, int channels, int frames); - void process_audio (boost::shared_ptr, double); + void process_audio (boost::shared_ptr); private: boost::shared_ptr _buffers; diff --git a/src/lib/external_audio_decoder.cc b/src/lib/external_audio_decoder.cc index 50e5852c5..1248b5a3b 100644 --- a/src/lib/external_audio_decoder.cc +++ b/src/lib/external_audio_decoder.cc @@ -115,7 +115,6 @@ ExternalAudioDecoder::pass () sf_count_t const block = _audio_stream->sample_rate() / 2; shared_ptr audio (new AudioBuffers (_audio_stream->channels(), block)); - sf_count_t done = 0; while (frames > 0) { sf_count_t const this_time = min (block, frames); for (size_t i = 0; i < sndfiles.size(); ++i) { @@ -127,8 +126,7 @@ ExternalAudioDecoder::pass () } audio->set_frames (this_time); - Audio (audio, double(done) / _audio_stream->sample_rate()); - done += this_time; + Audio (audio); frames -= this_time; } diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 32c8e224a..ac25844e3 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -640,8 +640,7 @@ FFmpegDecoder::out_with_sync () if (delta > one_frame) { int const extra = rint (delta / one_frame); for (int i = 0; i < extra; ++i) { - /* XXX: timestamp is wrong */ - repeat_last_video (source_pts_seconds); + repeat_last_video (); _film->log()->log ( String::compose ( N_("Extra video frame inserted at %1s; source frame %2, source PTS %3 (at %4 fps)"), @@ -740,8 +739,7 @@ FFmpegDecoder::decode_audio_packet () if (s) { shared_ptr audio (new AudioBuffers (ffa->channels(), s)); audio->make_silent (); - /* XXX: this time stamp is wrong */ - Audio (audio, source_pts_seconds); + Audio (audio); } } @@ -750,7 +748,7 @@ FFmpegDecoder::decode_audio_packet () ); assert (_audio_codec_context->channels == _film->audio_channels()); - Audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds ); + Audio (deinterleave_audio (_frame->data, data_size)); } } diff --git a/src/lib/gain.cc b/src/lib/gain.cc index 35ce27cea..cec3b3c62 100644 --- a/src/lib/gain.cc +++ b/src/lib/gain.cc @@ -23,7 +23,7 @@ using boost::shared_ptr; /** @param gain gain in dB */ Gain::Gain (Log* log, float gain) - : Processor (log) + : AudioProcessor (log) , _gain (gain) { diff --git a/src/lib/gain.h b/src/lib/gain.h index 449473582..716ee9b51 100644 --- a/src/lib/gain.h +++ b/src/lib/gain.h @@ -19,7 +19,7 @@ #include "processor.h" -class Gain : public Processor, public AudioSink, public AudioSource +class Gain : public AudioProcessor { public: Gain (Log* log, float gain); diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index 38dace6de..5dc0b7b06 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -77,8 +77,7 @@ ImageMagickDecoder::pass () return true; } - /* XXX: timestamp is wrong */ - repeat_last_video (0); + repeat_last_video (); return false; } diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 3a513b24e..4cd264338 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -27,7 +27,7 @@ using std::min; using boost::shared_ptr; Matcher::Matcher (Log* log, int sample_rate, float frames_per_second) - : Processor (log) + : AudioVideoProcessor (log) , _sample_rate (sample_rate) , _frames_per_second (frames_per_second) , _video_frames (0) @@ -37,7 +37,7 @@ Matcher::Matcher (Log* log, int sample_rate, float frames_per_second) } void -Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double) +Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) { Video (i, same, s); _video_frames++; @@ -47,7 +47,7 @@ Matcher::process_video (boost::shared_ptr i, bool same, boost::shared_ptr } void -Matcher::process_audio (boost::shared_ptr b, double) +Matcher::process_audio (boost::shared_ptr b) { Audio (b); _audio_frames += b->frames (); diff --git a/src/lib/matcher.h b/src/lib/matcher.h index 4a66f4e70..60bb87432 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -21,12 +21,12 @@ #include "processor.h" #include "ffmpeg_compatibility.h" -class Matcher : public Processor, public TimedVideoSink, public TimedAudioSink, public VideoSource, public AudioSource +class Matcher : public AudioVideoProcessor { public: Matcher (Log* log, int sample_rate, float frames_per_second); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double t); - void process_audio (boost::shared_ptr, double t); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); + void process_audio (boost::shared_ptr); void process_end (); private: diff --git a/src/lib/processor.h b/src/lib/processor.h index 863bfdbb5..19d7c4b0c 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -53,4 +53,46 @@ protected: Log* _log; ///< log to write to }; +/** @class AudioVideoProcessor + * @brief A processor which handles both video and audio data. + */ +class AudioVideoProcessor : public Processor, public VideoSource, public VideoSink, public AudioSource, public AudioSink +{ +public: + /** Construct an AudioVideoProcessor. + * @param log Log to write to. + */ + AudioVideoProcessor (Log* log) + : Processor (log) + {} +}; + +/** @class AudioProcessor + * @brief A processor which handles just audio data. + */ +class AudioProcessor : public Processor, public AudioSource, public AudioSink +{ +public: + /** Construct an AudioProcessor. + * @param log Log to write to. + */ + AudioProcessor (Log* log) + : Processor (log) + {} +}; + +/** @class VideoProcessor + * @brief A processor which handles just video data. + */ +class VideoProcessor : public Processor, public VideoSource, public VideoSink +{ +public: + /** Construct an VideoProcessor. + * @param log Log to write to. + */ + VideoProcessor (Log* log) + : Processor (log) + {} +}; + #endif diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 3beda2b8b..9720ca56a 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -72,8 +72,7 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< _decoders.video->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - /* Discard timestamps here */ - _decoders.video->Video.connect (boost::bind (&Encoder::process_video, _encoder, _1, _2, _3)); + _decoders.video->connect_video (_encoder); } if (_matcher && _delay_line && _decoders.audio) { diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 773688b34..891720f6b 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -51,7 +51,7 @@ VideoDecoder::emit_video (shared_ptr image, double t) sub = _timed_subtitle->subtitle (); } - signal_video (image, false, sub, t); + signal_video (image, false, sub); _last_source_time = t; } @@ -60,14 +60,14 @@ VideoDecoder::emit_video (shared_ptr image, double t) * we will generate a black frame. */ void -VideoDecoder::repeat_last_video (double t) +VideoDecoder::repeat_last_video () { if (!_last_image) { _last_image.reset (new SimpleImage (pixel_format(), native_size(), true)); _last_image->make_black (); } - signal_video (_last_image, true, _last_subtitle, t); + signal_video (_last_image, true, _last_subtitle); } /** Emit our signal to say that some video data is ready. @@ -76,10 +76,10 @@ VideoDecoder::repeat_last_video (double t) * @param sub Subtitle for this frame, or 0. */ void -VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub, double t) +VideoDecoder::signal_video (shared_ptr image, bool same, shared_ptr sub) { TIMING (N_("Decoder emits %1"), _video_frame); - Video (image, same, sub, t); + Video (image, same, sub); ++_video_frame; _last_image = image; diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 5e9c60d08..283ab5d88 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -24,7 +24,7 @@ #include "stream.h" #include "decoder.h" -class VideoDecoder : public TimedVideoSource, public virtual Decoder +class VideoDecoder : public VideoSource, public virtual Decoder { public: VideoDecoder (boost::shared_ptr, DecodeOptions); @@ -67,7 +67,7 @@ protected: void emit_video (boost::shared_ptr, double); void emit_subtitle (boost::shared_ptr); - void repeat_last_video (double t); + void repeat_last_video (); /** Subtitle stream to use when decoding */ boost::shared_ptr _subtitle_stream; @@ -75,7 +75,7 @@ protected: std::vector > _subtitle_streams; private: - void signal_video (boost::shared_ptr, bool, boost::shared_ptr, double); + void signal_video (boost::shared_ptr, bool, boost::shared_ptr); int _video_frame; double _last_source_time; diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 32c7f3b38..7c128cf73 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -37,16 +37,4 @@ public: virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) = 0; }; -class TimedVideoSink -{ -public: - /** Call with a frame of video. - * @param i Video frame image. - * @param same true if i is the same as last time we were called. - * @param s A subtitle that should be on this frame, or 0. - * @param t Source timestamp. - */ - virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double t) = 0; -}; - #endif diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index af6f941fd..56742e2b4 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -28,9 +28,3 @@ VideoSource::connect_video (shared_ptr s) { Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); } - -void -TimedVideoSource::connect_video (shared_ptr s) -{ - Video.connect (bind (&TimedVideoSink::process_video, s, _1, _2, _3, _4)); -} diff --git a/src/lib/video_source.h b/src/lib/video_source.h index 705b0023a..893629160 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -29,12 +29,11 @@ #include "util.h" class VideoSink; -class TimedVideoSink; class Subtitle; class Image; -/** @class VideoSource - * @param A class that emits video data without timestamps. +/** @class VideoSink + * @param A class that emits video data. */ class VideoSource { @@ -50,22 +49,4 @@ public: void connect_video (boost::shared_ptr); }; -/** @class TimedVideoSource - * @param A class that emits video data with timestamps. - */ -class TimedVideoSource -{ -public: - - /** Emitted when a video frame is ready. - * First parameter is the video image. - * Second parameter is true if the image is the same as the last one that was emitted. - * Third parameter is either 0 or a subtitle that should be on this frame. - * Fourth parameter is the source timestamp of this frame. - */ - boost::signals2::signal, bool, boost::shared_ptr, double)> Video; - - void connect_video (boost::shared_ptr); -}; - #endif diff --git a/test/test.cc b/test/test.cc index b2af8ab22..15c34ca78 100644 --- a/test/test.cc +++ b/test/test.cc @@ -273,8 +273,7 @@ do_positive_delay_line_test (int delay_length, int data_length) } /* This only works because the delay line modifies the parameter */ - /* XXX: timestamp is wrong */ - d.process_audio (data, 0); + d.process_audio (data); returned += data->frames (); for (int j = 0; j < data->frames(); ++j) { @@ -317,8 +316,7 @@ do_negative_delay_line_test (int delay_length, int data_length) } /* This only works because the delay line modifies the parameter */ - /* XXX: timestamp is wrong */ - d.process_audio (data, 0); + d.process_audio (data); returned += data->frames (); for (int j = 0; j < data->frames(); ++j) { -- cgit v1.2.3 From e3ce330c4dc3f59f4e2b942bb6111c308a3d83eb Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 6 Mar 2013 22:56:51 +0000 Subject: Remove believed never-failing checks for audio streams. --- src/lib/transcoder.cc | 33 +++++++++++---------------------- 1 file changed, 11 insertions(+), 22 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 3beda2b8b..ae88116a0 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -55,33 +55,22 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< { 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)); - _gain.reset (new Gain (f->log(), f->audio_gain())); - } + 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)); + _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 ()); - } + _decoders.audio->set_audio_stream (f->audio_stream ()); - if (_matcher) { - _decoders.video->connect_video (_matcher); - _matcher->connect_video (_encoder); - } else { - /* Discard timestamps here */ - _decoders.video->Video.connect (boost::bind (&Encoder::process_video, _encoder, _1, _2, _3)); - } + _decoders.video->connect_video (_matcher); + _matcher->connect_video (_encoder); - if (_matcher && _delay_line && _decoders.audio) { - _decoders.audio->connect_audio (_delay_line); - _delay_line->connect_audio (_matcher); - _matcher->connect_audio (_gain); - _gain->connect_audio (_encoder); - } + _decoders.audio->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 -- cgit v1.2.3 From 7a9a8229b57139ece3f9848910087310c06169c7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 6 Mar 2013 23:08:07 +0000 Subject: Try doing delay line by fiddling timestamps. Fix up confusion in A/B transcoder similar to that in standard one. --- src/lib/ab_transcoder.cc | 30 ++++++--------- src/lib/delay_line.cc | 67 ++++++++------------------------- src/lib/delay_line.h | 11 ++---- src/lib/transcoder.cc | 17 +++------ test/test.cc | 98 ------------------------------------------------ 5 files changed, 36 insertions(+), 187 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 373549b57..3af32f988 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -58,12 +58,10 @@ ABTranscoder::ABTranscoder ( _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)); - _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); - } + 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(), _film_a->audio_delay() / 1000.0f)); + _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 ()); @@ -73,20 +71,14 @@ ABTranscoder::ABTranscoder ( _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); - if (_matcher) { - _combiner->connect_video (_matcher); - _matcher->connect_video (_encoder); - } else { - /* Remove timestamp from the output of the combiner */ - _combiner->Video.connect (bind (&Encoder::process_video, _encoder, _1, _2, _3)); - } + _combiner->connect_video (_delay_line); + _delay_line->connect_video (_matcher); + _matcher->connect_video (_encoder); - if (_matcher && _delay_line) { - _da.audio->connect_audio (_delay_line); - _delay_line->connect_audio (_matcher); - _matcher->connect_audio (_gain); - _gain->connect_audio (_encoder); - } + _da.audio->connect_audio (_delay_line); + _delay_line->connect_audio (_matcher); + _matcher->connect_audio (_gain); + _gain->connect_audio (_encoder); } void diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index 84785cfc6..924a1f082 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -27,68 +27,31 @@ using std::min; using boost::shared_ptr; -/** @param channels Number of channels of audio. - * @param frames Delay in frames, +ve to move audio later. +/* @param seconds Delay in seconds, +ve to move audio later. */ -DelayLine::DelayLine (Log* log, int channels, int frames) +DelayLine::DelayLine (Log* log, double seconds) : Processor (log) - , _negative_delay_remaining (0) - , _frames (frames) + , _seconds (seconds) { - if (_frames > 0) { - /* We need a buffer to keep some data in */ - _buffers.reset (new AudioBuffers (channels, _frames)); - _buffers->make_silent (); - } else if (_frames < 0) { - /* We can do -ve delays just by chopping off - the start, so no buffer needed. - */ - _negative_delay_remaining = -_frames; - } + } -/* XXX: can we just get rid of all this and fiddle with the timestamp? */ void DelayLine::process_audio (shared_ptr data, double t) { - if (_buffers) { - /* We have some buffers, so we are moving the audio later */ - - /* Copy the input data */ - AudioBuffers input (*data.get ()); - - int to_do = data->frames (); - - /* Write some of our buffer to the output */ - int const from_buffer = min (to_do, _buffers->frames()); - data->copy_from (_buffers.get(), from_buffer, 0, 0); - to_do -= from_buffer; - - /* Write some of the input to the output */ - int const from_input = to_do; - data->copy_from (&input, from_input, 0, from_buffer); - - int const left_in_buffer = _buffers->frames() - from_buffer; - - /* Shuffle our buffer down */ - _buffers->move (from_buffer, 0, left_in_buffer); - - /* Copy remaining input data to our buffer */ - _buffers->copy_from (&input, input.frames() - from_input, from_input, left_in_buffer); - - } else { + if (_seconds > 0) { + t += _seconds; + } - /* Chop the initial data off until _negative_delay_remaining - is zero, then just pass data. - */ + Audio (data, t); +} - int const to_do = min (data->frames(), _negative_delay_remaining); - if (to_do) { - data->move (to_do, 0, data->frames() - to_do); - data->set_frames (data->frames() - to_do); - _negative_delay_remaining -= to_do; - } +void +DelayLine::process_video (boost::shared_ptr image, bool same, boost::shared_ptr sub, double t) +{ + if (_seconds < 0) { + t += _seconds; } - Audio (data, t); + Video (image, same, sub, t); } diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 8c4a3953c..a52fb981c 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -20,18 +20,15 @@ #include #include "processor.h" -class AudioBuffers; - /** A delay line for audio */ -class DelayLine : public Processor, public TimedAudioSink, public TimedAudioSource +class DelayLine : public Processor, public TimedAudioSink, public TimedAudioSource, public TimedVideoSink, public TimedVideoSource { public: - DelayLine (Log* log, int channels, int frames); + DelayLine (Log* log, double); + void process_video (boost::shared_ptr, bool, boost::shared_ptr, double); void process_audio (boost::shared_ptr, double); private: - boost::shared_ptr _buffers; - int _negative_delay_remaining; ///< number of frames of negative delay that remain to emit - int _frames; + double _seconds; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index ae88116a0..8e5e15e7f 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -57,14 +57,15 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< 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)); + _delay_line.reset (new DelayLine (f->log(), f->audio_delay() / 1000.0f)); _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 ()); _decoders.audio->set_audio_stream (f->audio_stream ()); - _decoders.video->connect_video (_matcher); + _decoders.video->connect_video (_delay_line); + _delay_line->connect_video (_matcher); _matcher->connect_video (_encoder); _decoders.audio->connect_audio (_delay_line); @@ -107,14 +108,8 @@ Transcoder::go () throw; } - if (_delay_line) { - _delay_line->process_end (); - } - if (_matcher) { - _matcher->process_end (); - } - if (_gain) { - _gain->process_end (); - } + _delay_line->process_end (); + _matcher->process_end (); + _gain->process_end (); _encoder->process_end (); } diff --git a/test/test.cc b/test/test.cc index b2af8ab22..5e85e0dd5 100644 --- a/test/test.cc +++ b/test/test.cc @@ -28,7 +28,6 @@ #include "job_manager.h" #include "util.h" #include "exceptions.h" -#include "delay_line.h" #include "image.h" #include "log.h" #include "dcp_video_frame.h" @@ -251,103 +250,6 @@ public: void do_log (string) {} }; -void -do_positive_delay_line_test (int delay_length, int data_length) -{ - NullLog log; - - DelayLine d (&log, 6, delay_length); - shared_ptr data (new AudioBuffers (6, data_length)); - - int in = 0; - int out = 0; - int returned = 0; - int zeros = 0; - - for (int i = 0; i < 64; ++i) { - for (int j = 0; j < data_length; ++j) { - for (int c = 0; c < 6; ++c ) { - data->data(c)[j] = in; - ++in; - } - } - - /* This only works because the delay line modifies the parameter */ - /* XXX: timestamp is wrong */ - d.process_audio (data, 0); - returned += data->frames (); - - for (int j = 0; j < data->frames(); ++j) { - if (zeros < delay_length) { - for (int c = 0; c < 6; ++c) { - BOOST_CHECK_EQUAL (data->data(c)[j], 0); - } - ++zeros; - } else { - for (int c = 0; c < 6; ++c) { - BOOST_CHECK_EQUAL (data->data(c)[j], out); - ++out; - } - } - } - } - - BOOST_CHECK_EQUAL (returned, 64 * data_length); -} - -void -do_negative_delay_line_test (int delay_length, int data_length) -{ - NullLog log; - - DelayLine d (&log, 6, delay_length); - shared_ptr data (new AudioBuffers (6, data_length)); - - int in = 0; - int out = -delay_length * 6; - int returned = 0; - - for (int i = 0; i < 256; ++i) { - data->set_frames (data_length); - for (int j = 0; j < data_length; ++j) { - for (int c = 0; c < 6; ++c) { - data->data(c)[j] = in; - ++in; - } - } - - /* This only works because the delay line modifies the parameter */ - /* XXX: timestamp is wrong */ - d.process_audio (data, 0); - returned += data->frames (); - - for (int j = 0; j < data->frames(); ++j) { - for (int c = 0; c < 6; ++c) { - BOOST_CHECK_EQUAL (data->data(c)[j], out); - ++out; - } - } - } - - returned += -delay_length; - BOOST_CHECK_EQUAL (returned, 256 * data_length); -} - -BOOST_AUTO_TEST_CASE (delay_line_test) -{ - do_positive_delay_line_test (64, 128); - do_positive_delay_line_test (128, 64); - do_positive_delay_line_test (3, 512); - do_positive_delay_line_test (512, 3); - - do_positive_delay_line_test (0, 64); - - do_negative_delay_line_test (-64, 128); - do_negative_delay_line_test (-128, 64); - do_negative_delay_line_test (-3, 512); - do_negative_delay_line_test (-512, 3); -} - BOOST_AUTO_TEST_CASE (md5_digest_test) { string const t = md5_digest ("test/md5.test"); -- cgit v1.2.3 From bb95f333f15ace7c032bb5b5761b512b6fe2e84e Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 8 Mar 2013 21:03:28 +0000 Subject: Numerous fixes to A/B mode so that at least it doesn't crash (#72). --- src/lib/ab_transcoder.cc | 17 +++++++++++++---- src/lib/combiner.cc | 2 +- src/lib/combiner.h | 2 +- src/lib/dcp_video_frame.cc | 2 +- src/lib/dcp_video_frame.h | 4 ++-- src/lib/delay_line.cc | 2 +- src/lib/delay_line.h | 2 +- src/lib/film.cc | 9 +++++---- src/lib/film.h | 4 ++-- src/lib/gain.cc | 2 +- src/lib/gain.h | 2 +- src/lib/matcher.cc | 2 +- src/lib/matcher.h | 2 +- src/lib/processor.h | 10 +++++----- src/lib/server.cc | 2 +- src/lib/server.h | 4 ++-- src/lib/transcoder.cc | 1 - src/tools/dvdomatic.cc | 10 +++++++--- src/tools/servomatic_cli.cc | 9 ++++++--- src/tools/servomatic_gui.cc | 13 ++++++++----- src/tools/servomatictest.cc | 6 +++--- test/test.cc | 14 +++++++------- 22 files changed, 70 insertions(+), 51 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 4ed5d02ca..3a1cd83d7 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -40,6 +40,7 @@ using std::string; using boost::shared_ptr; +using boost::dynamic_pointer_cast; /** @param a Film to use for the left half of the screen. * @param b Film to use for the right half of the screen. @@ -54,6 +55,7 @@ ABTranscoder::ABTranscoder ( , _film_b (b) , _job (j) , _encoder (e) + , _combiner (new Combiner (a->log())) { _da = decoder_factory (_film_a, o); _db = decoder_factory (_film_b, o); @@ -92,17 +94,24 @@ void ABTranscoder::go () { _encoder->process_begin (); + + bool done[3] = { false, false, false }; while (1) { - bool const va = _da.video->pass (); - bool const vb = _db.video->pass (); - bool const a = _da.audio->pass (); + 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; + } if (_job) { _da.video->set_progress (_job); } - if (va && vb && a) { + if (done[0] && done[1] && done[2]) { break; } } diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 68aafd2a2..12ce4a96e 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -22,7 +22,7 @@ using boost::shared_ptr; -Combiner::Combiner (Log* log) +Combiner::Combiner (shared_ptr log) : VideoProcessor (log) { diff --git a/src/lib/combiner.h b/src/lib/combiner.h index 7fad1aeae..68026eaff 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -31,7 +31,7 @@ class Combiner : public VideoProcessor { public: - Combiner (Log* log); + Combiner (boost::shared_ptr log); void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s); diff --git a/src/lib/dcp_video_frame.cc b/src/lib/dcp_video_frame.cc index 67617c63c..d735122b5 100644 --- a/src/lib/dcp_video_frame.cc +++ b/src/lib/dcp_video_frame.cc @@ -80,7 +80,7 @@ using libdcp::Size; DCPVideoFrame::DCPVideoFrame ( shared_ptr yuv, shared_ptr sub, Size out, int p, int subtitle_offset, float subtitle_scale, - Scaler const * s, int f, int dcp_fps, string pp, int clut, int bw, Log* l + Scaler const * s, int f, int dcp_fps, string pp, int clut, int bw, shared_ptr l ) : _input (yuv) , _subtitle (sub) diff --git a/src/lib/dcp_video_frame.h b/src/lib/dcp_video_frame.h index 6794765ac..4ceb07d26 100644 --- a/src/lib/dcp_video_frame.h +++ b/src/lib/dcp_video_frame.h @@ -107,7 +107,7 @@ class DCPVideoFrame public: DCPVideoFrame ( boost::shared_ptr, boost::shared_ptr, libdcp::Size, - int, int, float, Scaler const *, int, int, std::string, int, int, Log * + int, int, float, Scaler const *, int, int, std::string, int, int, boost::shared_ptr ); virtual ~DCPVideoFrame (); @@ -135,7 +135,7 @@ private: int _colour_lut; ///< Colour look-up table to use int _j2k_bandwidth; ///< J2K bandwidth to use - Log* _log; ///< log + boost::shared_ptr _log; ///< log opj_image_cmptparm_t _cmptparm[3]; ///< libopenjpeg's opj_image_cmptparm_t opj_image* _image; ///< libopenjpeg's image container diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index 4ad172781..53da9a412 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -30,7 +30,7 @@ using boost::shared_ptr; /** @param channels Number of channels of audio. * @param frames Delay in frames, +ve to move audio later. */ -DelayLine::DelayLine (Log* log, int channels, int frames) +DelayLine::DelayLine (shared_ptr log, int channels, int frames) : AudioProcessor (log) , _negative_delay_remaining (0) , _frames (frames) diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 4d6f1313b..c51784f35 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -26,7 +26,7 @@ class AudioBuffers; class DelayLine : public AudioProcessor { public: - DelayLine (Log* log, int channels, int frames); + DelayLine (boost::shared_ptr log, int channels, int frames); void process_audio (boost::shared_ptr); diff --git a/src/lib/film.cc b/src/lib/film.cc index 20e08c037..8028f40ef 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -144,12 +144,13 @@ Film::Film (string d, bool must_exist) read_metadata (); } - _log = new FileLog (file ("log")); + _log.reset (new FileLog (file ("log"))); } Film::Film (Film const & o) : boost::enable_shared_from_this (o) - , _log (0) + /* note: the copied film shares the original's log */ + , _log (o._log) , _directory (o._directory) , _name (o._name) , _use_dci_name (o._use_dci_name) @@ -188,12 +189,12 @@ Film::Film (Film const & o) , _source_frame_rate (o._source_frame_rate) , _dirty (o._dirty) { - + } Film::~Film () { - delete _log; + } string diff --git a/src/lib/film.h b/src/lib/film.h index 88f6fbcd7..2ab4a9450 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -77,7 +77,7 @@ public: /** @return Logger. * It is safe to call this from any thread. */ - Log* log () const { + boost::shared_ptr log () const { return _log; } @@ -382,7 +382,7 @@ public: private: /** Log to write to */ - Log* _log; + boost::shared_ptr _log; /** Any running ExamineContentJob, or 0 */ boost::shared_ptr _examine_content_job; diff --git a/src/lib/gain.cc b/src/lib/gain.cc index cec3b3c62..df7011d2e 100644 --- a/src/lib/gain.cc +++ b/src/lib/gain.cc @@ -22,7 +22,7 @@ using boost::shared_ptr; /** @param gain gain in dB */ -Gain::Gain (Log* log, float gain) +Gain::Gain (shared_ptr log, float gain) : AudioProcessor (log) , _gain (gain) { diff --git a/src/lib/gain.h b/src/lib/gain.h index 716ee9b51..d462e5aee 100644 --- a/src/lib/gain.h +++ b/src/lib/gain.h @@ -22,7 +22,7 @@ class Gain : public AudioProcessor { public: - Gain (Log* log, float gain); + Gain (boost::shared_ptr log, float gain); void process_audio (boost::shared_ptr); diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 4cd264338..48f6ed912 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -26,7 +26,7 @@ using std::min; using boost::shared_ptr; -Matcher::Matcher (Log* log, int sample_rate, float frames_per_second) +Matcher::Matcher (shared_ptr log, int sample_rate, float frames_per_second) : AudioVideoProcessor (log) , _sample_rate (sample_rate) , _frames_per_second (frames_per_second) diff --git a/src/lib/matcher.h b/src/lib/matcher.h index 60bb87432..b1680e131 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -24,7 +24,7 @@ class Matcher : public AudioVideoProcessor { public: - Matcher (Log* log, int sample_rate, float frames_per_second); + Matcher (boost::shared_ptr log, int sample_rate, float frames_per_second); void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); void process_audio (boost::shared_ptr); void process_end (); diff --git a/src/lib/processor.h b/src/lib/processor.h index 19d7c4b0c..1ba396f2f 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -40,7 +40,7 @@ public: /** Construct a Processor. * @param log Log to use. */ - Processor (Log* log) + Processor (boost::shared_ptr log) : _log (log) {} @@ -50,7 +50,7 @@ public: virtual void process_end () {} protected: - Log* _log; ///< log to write to + boost::shared_ptr _log; ///< log to write to }; /** @class AudioVideoProcessor @@ -62,7 +62,7 @@ public: /** Construct an AudioVideoProcessor. * @param log Log to write to. */ - AudioVideoProcessor (Log* log) + AudioVideoProcessor (boost::shared_ptr log) : Processor (log) {} }; @@ -76,7 +76,7 @@ public: /** Construct an AudioProcessor. * @param log Log to write to. */ - AudioProcessor (Log* log) + AudioProcessor (boost::shared_ptr log) : Processor (log) {} }; @@ -90,7 +90,7 @@ public: /** Construct an VideoProcessor. * @param log Log to write to. */ - VideoProcessor (Log* log) + VideoProcessor (boost::shared_ptr log) : Processor (log) {} }; diff --git a/src/lib/server.cc b/src/lib/server.cc index 76a25bfbb..9c5a77f68 100644 --- a/src/lib/server.cc +++ b/src/lib/server.cc @@ -77,7 +77,7 @@ ServerDescription::as_metadata () const return s.str (); } -Server::Server (Log* log) +Server::Server (shared_ptr log) : _log (log) { diff --git a/src/lib/server.h b/src/lib/server.h index 32ba8dc4b..89aeca626 100644 --- a/src/lib/server.h +++ b/src/lib/server.h @@ -76,7 +76,7 @@ private: class Server { public: - Server (Log* log); + Server (boost::shared_ptr log); void run (int num_threads); @@ -88,5 +88,5 @@ private: std::list > _queue; boost::mutex _worker_mutex; boost::condition _worker_condition; - Log* _log; + boost::shared_ptr _log; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 9720ca56a..e0f3a03a2 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -38,7 +38,6 @@ #include "audio_decoder.h" using std::string; -using std::cout; using boost::shared_ptr; using boost::dynamic_pointer_cast; diff --git a/src/tools/dvdomatic.cc b/src/tools/dvdomatic.cc index 4874e6ef8..230e02c88 100644 --- a/src/tools/dvdomatic.cc +++ b/src/tools/dvdomatic.cc @@ -482,12 +482,16 @@ class App : public wxApp #ifdef DVDOMATIC_POSIX unsetenv ("UBUNTU_MENUPROXY"); #endif - + + /* This needs to be before setup_i18n, as setup_i18n() will + create a Config object, which needs Scalers to have + been created. + */ + dvdomatic_setup (); + wxInitAllImageHandlers (); setup_i18n (); - dvdomatic_setup (); - if (!film_to_load.empty() && boost::filesystem::is_directory (film_to_load)) { try { film.reset (new Film (film_to_load)); diff --git a/src/tools/servomatic_cli.cc b/src/tools/servomatic_cli.cc index f8e713193..6626d45b9 100644 --- a/src/tools/servomatic_cli.cc +++ b/src/tools/servomatic_cli.cc @@ -42,7 +42,10 @@ #include "log.h" #include "version.h" -using namespace std; +using std::cerr; +using std::string; +using std::cout; +using boost::shared_ptr; static void help (string n) @@ -87,8 +90,8 @@ main (int argc, char* argv[]) } Scaler::setup_scalers (); - FileLog log ("servomatic.log"); - Server server (&log); + shared_ptr log (new FileLog ("servomatic.log")); + Server server (log); server.run (num_threads); return 0; } diff --git a/src/tools/servomatic_gui.cc b/src/tools/servomatic_gui.cc index 610ba8005..dd169725f 100644 --- a/src/tools/servomatic_gui.cc +++ b/src/tools/servomatic_gui.cc @@ -25,8 +25,11 @@ #include "lib/server.h" #include "lib/config.h" -using namespace std; -using namespace boost; +using std::cout; +using std::string; +using boost::shared_ptr; +using boost::thread; +using boost::bind; enum { ID_status = 1, @@ -52,7 +55,7 @@ private: string _log; }; -static MemoryLog memory_log; +static shared_ptr memory_log (new MemoryLog); class StatusDialog : public wxDialog { @@ -77,7 +80,7 @@ public: private: void update (wxTimerEvent &) { - _text->ChangeValue (std_to_wx (memory_log.get ())); + _text->ChangeValue (std_to_wx (memory_log->get ())); _sizer->Layout (); } @@ -141,7 +144,7 @@ private: void main_thread () { - Server server (&memory_log); + Server server (memory_log); server.run (Config::instance()->num_local_encoding_threads ()); } diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index 91ad02120..f5756c693 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -43,7 +43,7 @@ using std::pair; using boost::shared_ptr; static ServerDescription* server; -static FileLog log_ ("servomatictest.log"); +static shared_ptr log_ (new FileLog ("servomatictest.log")); static int frame = 0; void @@ -53,14 +53,14 @@ process_video (shared_ptr image, bool, shared_ptr sub) new DCPVideoFrame ( image, sub, libdcp::Size (1024, 1024), 0, 0, 0, - Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_) + Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, log_) ); shared_ptr remote ( new DCPVideoFrame ( image, sub, libdcp::Size (1024, 1024), 0, 0, 0, - Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, &log_) + Scaler::from_id ("bicubic"), frame, 24, "", 0, 250000000, log_) ); cout << "Frame " << frame << ": "; diff --git a/test/test.cc b/test/test.cc index 15c34ca78..448168f24 100644 --- a/test/test.cc +++ b/test/test.cc @@ -254,9 +254,9 @@ public: void do_positive_delay_line_test (int delay_length, int data_length) { - NullLog log; + shared_ptr log (new NullLog); - DelayLine d (&log, 6, delay_length); + DelayLine d (log, 6, delay_length); shared_ptr data (new AudioBuffers (6, data_length)); int in = 0; @@ -297,9 +297,9 @@ do_positive_delay_line_test (int delay_length, int data_length) void do_negative_delay_line_test (int delay_length, int data_length) { - NullLog log; + shared_ptr log (new NullLog); - DelayLine d (&log, 6, delay_length); + DelayLine d (log, 6, delay_length); shared_ptr data (new AudioBuffers (6, data_length)); int in = 0; @@ -406,7 +406,7 @@ BOOST_AUTO_TEST_CASE (client_server_test) shared_ptr subtitle (new Subtitle (Position (50, 60), sub_image)); - FileLog log ("build/test/client_server_test.log"); + shared_ptr log (new FileLog ("build/test/client_server_test.log")); shared_ptr frame ( new DCPVideoFrame ( @@ -422,14 +422,14 @@ BOOST_AUTO_TEST_CASE (client_server_test) "", 0, 200000000, - &log + log ) ); shared_ptr locally_encoded = frame->encode_locally (); BOOST_ASSERT (locally_encoded); - Server* server = new Server (&log); + Server* server = new Server (log); new thread (boost::bind (&Server::run, server, 2)); -- 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/transcoder.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/transcoder.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/transcoder.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 From db468a15e50c8491d4b8462ad0676be905f49065 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 1 Apr 2013 22:49:31 +0100 Subject: Various bits. --- src/lib/ab_transcoder.cc | 24 ++++---- src/lib/ab_transcoder.h | 6 +- src/lib/analyse_audio_job.cc | 16 +++--- src/lib/audio_decoder.cc | 2 +- src/lib/audio_decoder.h | 2 +- src/lib/encoder.cc | 31 +++++------ src/lib/encoder.h | 4 +- src/lib/ffmpeg_decoder.cc | 6 +- src/lib/ffmpeg_decoder.h | 4 +- src/lib/film.cc | 73 ++++++++++++++++++++---- src/lib/film.h | 15 ++++- src/lib/format.cc | 12 ++-- src/lib/format.h | 16 +++--- src/lib/imagemagick_decoder.cc | 4 +- src/lib/imagemagick_decoder.h | 4 +- src/lib/playlist.cc | 124 +++++++++++++++++++++++++++-------------- src/lib/playlist.h | 77 ++++++++++++++++++------- src/lib/sndfile_decoder.cc | 4 +- src/lib/sndfile_decoder.h | 4 +- src/lib/transcoder.cc | 22 ++++---- src/lib/transcoder.h | 4 +- src/lib/video_decoder.cc | 9 +-- src/lib/video_decoder.h | 2 +- src/lib/writer.cc | 7 +-- src/lib/writer.h | 4 +- src/tools/servomatictest.cc | 8 +-- src/wx/audio_dialog.cc | 11 ++-- src/wx/audio_dialog.h | 2 - src/wx/film_viewer.cc | 40 ++++++------- src/wx/film_viewer.h | 2 +- wscript | 3 + 31 files changed, 336 insertions(+), 206 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 6fc438ee8..6bf092fee 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -49,20 +49,20 @@ using boost::dynamic_pointer_cast; ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptr j) : _film_a (a) , _film_b (b) - , _playlist_a (_film_a->playlist ()) - , _playlist_b (_film_b->playlist ()) + , _player_a (_film_a->player ()) + , _player_b (_film_b->player ()) , _job (j) - , _encoder (new Encoder (_film_a, _playlist_a)) + , _encoder (new Encoder (_film_a)) , _combiner (new Combiner (a->log())) { - if (_playlist_a->has_audio ()) { - _matcher.reset (new Matcher (_film_a->log(), _playlist_a->audio_frame_rate(), _playlist_a->video_frame_rate())); - _delay_line.reset (new DelayLine (_film_a->log(), _playlist_a->audio_channels(), _film_a->audio_delay() * _playlist_a->audio_frame_rate() / 1000)); + if (_film_a->has_audio ()) { + _matcher.reset (new Matcher (_film_a->log(), _film_a->audio_frame_rate(), _film_a->video_frame_rate())); + _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_channels(), _film_a->audio_delay() * _film_a->audio_frame_rate() / 1000)); _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); } - _playlist_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); - _playlist_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); + _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3)); + _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3)); if (_matcher) { _combiner->connect_video (_matcher); @@ -72,7 +72,7 @@ ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptrconnect_audio (_delay_line); + _player_a->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); @@ -87,11 +87,11 @@ ABTranscoder::go () bool done[2] = { false, false }; while (1) { - done[0] = _playlist_a->pass (); - done[1] = _playlist_b->pass (); + done[0] = _player_a->pass (); + done[1] = _player_b->pass (); if (_job) { - _playlist_a->set_progress (_job); + _player_a->set_progress (_job); } if (done[0] && done[1]) { diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 5ce4a03da..b1b01d724 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -35,7 +35,7 @@ class Matcher; class DelayLine; class Gain; class Combiner; -class Playlist; +class Player; /** @class ABTranscoder * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -55,8 +55,8 @@ public: private: boost::shared_ptr _film_a; boost::shared_ptr _film_b; - boost::shared_ptr _playlist_a; - boost::shared_ptr _playlist_b; + boost::shared_ptr _player_a; + boost::shared_ptr _player_b; boost::shared_ptr _job; boost::shared_ptr _encoder; boost::shared_ptr _combiner; diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 6e6dda886..e2c9c5b18 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -50,18 +50,18 @@ AnalyseAudioJob::name () const void AnalyseAudioJob::run () { - shared_ptr playlist = _film->playlist (); - playlist->disable_video (); + shared_ptr player = _film->player (); + player->disable_video (); - playlist->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); + player->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1)); - _samples_per_point = max (int64_t (1), playlist->audio_length() / _num_points); + _samples_per_point = max (int64_t (1), _film->audio_length() / _num_points); - _current.resize (playlist->audio_channels ()); - _analysis.reset (new AudioAnalysis (playlist->audio_channels())); + _current.resize (_film->audio_channels ()); + _analysis.reset (new AudioAnalysis (_film->audio_channels())); - while (!playlist->pass()) { - set_progress (float (_done) / playlist->audio_length ()); + while (!player->pass()) { + set_progress (float (_done) / _film->audio_length ()); } _analysis->write (_film->audio_analysis_path ()); diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index e2006a795..df13a984a 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -22,7 +22,7 @@ using boost::optional; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr f, shared_ptr c) +AudioDecoder::AudioDecoder (shared_ptr f) : Decoder (f) { diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index cbb84b52d..24e2796ae 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -35,7 +35,7 @@ class AudioContent; class AudioDecoder : public AudioSource, public virtual Decoder { public: - AudioDecoder (boost::shared_ptr, boost::shared_ptr); + AudioDecoder (boost::shared_ptr); }; #endif diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 00807f863..5c3e56709 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -53,9 +53,8 @@ using namespace boost; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f, shared_ptr p) +Encoder::Encoder (shared_ptr f) : _film (f) - , _playlist (p) , _video_frames_in (0) , _video_frames_out (0) #ifdef HAVE_SWRESAMPLE @@ -78,22 +77,22 @@ Encoder::~Encoder () void Encoder::process_begin () { - if (_playlist->has_audio() && _playlist->audio_frame_rate() != _film->target_audio_sample_rate()) { + if (_film->has_audio() && _film->audio_frame_rate() != _film->target_audio_sample_rate()) { #ifdef HAVE_SWRESAMPLE stringstream s; - s << String::compose (N_("Will resample audio from %1 to %2"), _playlist->audio_frame_rate(), _film->target_audio_sample_rate()); + s << String::compose (N_("Will resample audio from %1 to %2"), _film->audio_frame_rate(), _film->target_audio_sample_rate()); _film->log()->log (s.str ()); /* We will be using planar float data when we call the resampler */ _swr_context = swr_alloc_set_opts ( 0, - _playlist->audio_channel_layout(), + _film->audio_channel_layout(), AV_SAMPLE_FMT_FLTP, _film->target_audio_sample_rate(), - _playlist->audio_channel_layout(), + _film->audio_channel_layout(), AV_SAMPLE_FMT_FLTP, - _playlist->audio_frame_rate(), + _film->audio_frame_rate(), 0, 0 ); @@ -119,7 +118,7 @@ Encoder::process_begin () } } - _writer.reset (new Writer (_film, _playlist)); + _writer.reset (new Writer (_film)); } @@ -127,9 +126,9 @@ void Encoder::process_end () { #if HAVE_SWRESAMPLE - if (_playlist->has_audio() && _playlist->audio_channels() && _swr_context) { + if (_film->has_audio() && _film->audio_channels() && _swr_context) { - shared_ptr out (new AudioBuffers (_playlist->audio_channels(), 256)); + shared_ptr out (new AudioBuffers (_film->audio_channels(), 256)); while (1) { int const frames = swr_convert (_swr_context, (uint8_t **) out->data(), 256, 0, 0); @@ -234,7 +233,7 @@ Encoder::frame_done () void Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr sub) { - FrameRateConversion frc (_playlist->video_frame_rate(), _film->dcp_frame_rate()); + FrameRateConversion frc (_film->video_frame_rate(), _film->dcp_frame_rate()); if (frc.skip && (_video_frames_in % 2)) { ++_video_frames_in; @@ -272,7 +271,7 @@ Encoder::process_video (shared_ptr image, bool same, boost::shared_ptr ( new DCPVideoFrame ( - image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_playlist), + image, sub, _film->format()->dcp_size(), _film->format()->dcp_padding (_film), _film->subtitle_offset(), _film->subtitle_scale(), _film->scaler(), _video_frames_out, _film->dcp_frame_rate(), s.second, _film->colour_lut(), _film->j2k_bandwidth(), @@ -302,9 +301,9 @@ Encoder::process_audio (shared_ptr data) if (_swr_context) { /* Compute the resampled frames count and add 32 for luck */ - int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _playlist->audio_frame_rate()) + 32; + int const max_resampled_frames = ceil ((int64_t) data->frames() * _film->target_audio_sample_rate() / _film->audio_frame_rate()) + 32; - shared_ptr resampled (new AudioBuffers (_playlist->audio_channels(), max_resampled_frames)); + shared_ptr resampled (new AudioBuffers (_film->audio_channels(), max_resampled_frames)); /* Resample audio */ int const resampled_frames = swr_convert ( @@ -426,8 +425,8 @@ Encoder::encoder_thread (ServerDescription* server) void Encoder::write_audio (shared_ptr data) { - AudioMapping m (_playlist->audio_channels ()); - if (m.dcp_channels() != _playlist->audio_channels()) { + AudioMapping m (_film->audio_channels ()); + if (m.dcp_channels() != _film->audio_channels()) { /* Remap (currently just for mono -> 5.1) */ diff --git a/src/lib/encoder.h b/src/lib/encoder.h index c84ee027a..86880bc34 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -51,7 +51,6 @@ class ServerDescription; class DCPVideoFrame; class EncodedData; class Writer; -class Playlist; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -63,7 +62,7 @@ class Playlist; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f, boost::shared_ptr); + Encoder (boost::shared_ptr f); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ @@ -96,7 +95,6 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; - boost::shared_ptr _playlist; /** Mutex for _time_history and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 7b56a5971..25ca9bb88 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,10 +61,10 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; -FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) +FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) : Decoder (f) - , VideoDecoder (f, c) - , AudioDecoder (f, c) + , VideoDecoder (f) + , AudioDecoder (f) , _ffmpeg_content (c) , _format_context (0) , _video_stream (-1) diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index ef66f09d9..71ecf7906 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -57,7 +57,7 @@ class Log; class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: - FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio, bool subtitles, bool video_sync); + FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio, bool subtitles, bool video_sync); ~FFmpegDecoder (); float frames_per_second () const; @@ -105,7 +105,7 @@ private: std::string stream_name (AVStream* s) const; - boost::shared_ptr _ffmpeg_content; + boost::shared_ptr _ffmpeg_content; AVFormatContext* _format_context; int _video_stream; diff --git a/src/lib/film.cc b/src/lib/film.cc index f2c7a654a..fe16a65fa 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -91,7 +91,8 @@ int const Film::state_version = 4; */ Film::Film (string d, bool must_exist) - : _use_dci_name (true) + : _playlist (new Playlist) + , _use_dci_name (true) , _trust_content_headers (true) , _dcp_content_type (0) , _format (0) @@ -151,6 +152,7 @@ Film::Film (Film const & o) : boost::enable_shared_from_this (o) /* note: the copied film shares the original's log */ , _log (o._log) + , _playlist (new Playlist) , _directory (o._directory) , _name (o._name) , _use_dci_name (o._use_dci_name) @@ -175,7 +177,7 @@ Film::Film (Film const & o) , _dcp_frame_rate (o._dcp_frame_rate) , _dirty (o._dirty) { - + _playlist->setup (_content); } Film::~Film () @@ -554,17 +556,14 @@ Film::file (string f) const int Film::target_audio_sample_rate () const { - /* XXX: how often is this method called? */ - - boost::shared_ptr p = playlist (); - if (p->has_audio ()) { + if (has_audio ()) { return 0; } /* Resample to a DCI-approved sample rate */ - double t = dcp_audio_sample_rate (p->audio_frame_rate()); + double t = dcp_audio_sample_rate (audio_frame_rate()); - FrameRateConversion frc (p->video_frame_rate(), dcp_frame_rate()); + FrameRateConversion frc (video_frame_rate(), dcp_frame_rate()); /* Compensate if the DCP is being run at a different frame rate to the source; that is, if the video is run such that it will @@ -573,7 +572,7 @@ Film::target_audio_sample_rate () const */ if (frc.change_speed) { - t *= p->video_frame_rate() * frc.factor() / dcp_frame_rate(); + t *= video_frame_rate() * frc.factor() / dcp_frame_rate(); } return rint (t); @@ -1023,11 +1022,11 @@ Film::have_dcp () const return true; } -shared_ptr -Film::playlist () const +shared_ptr +Film::player () const { boost::mutex::scoped_lock lm (_state_mutex); - return shared_ptr (new Playlist (shared_from_this (), _content)); + return shared_ptr (new Player (shared_from_this (), _playlist)); } void @@ -1036,9 +1035,59 @@ Film::add_content (shared_ptr c) { boost::mutex::scoped_lock lm (_state_mutex); _content.push_back (c); + _playlist->setup (_content); } signal_changed (CONTENT); examine_content (c); } + +ContentAudioFrame +Film::audio_length () const +{ + return _playlist->audio_length (); +} + +int +Film::audio_channels () const +{ + return _playlist->audio_channels (); +} + +int +Film::audio_frame_rate () const +{ + return _playlist->audio_frame_rate (); +} + +int64_t +Film::audio_channel_layout () const +{ + return _playlist->audio_channel_layout (); +} + +bool +Film::has_audio () const +{ + return _playlist->has_audio (); +} + +float +Film::video_frame_rate () const +{ + return _playlist->video_frame_rate (); +} + +libdcp::Size +Film::video_size () const +{ + return _playlist->video_size (); +} + +ContentVideoFrame +Film::video_length () const +{ + return _playlist->video_length (); +} + diff --git a/src/lib/film.h b/src/lib/film.h index f5f944409..6e097d44e 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -47,6 +47,7 @@ class ExamineContentJob; class AnalyseAudioJob; class ExternalAudioStream; class Content; +class Player; class Playlist; /** @class Film @@ -105,7 +106,17 @@ public: bool have_dcp () const; - boost::shared_ptr playlist () const; + boost::shared_ptr player () const; + + ContentAudioFrame audio_length () const; + int audio_channels () const; + int audio_frame_rate () const; + int64_t audio_channel_layout () const; + bool has_audio () const; + + float video_frame_rate () const; + libdcp::Size video_size () const; + ContentVideoFrame video_length () const; /** Identifiers for the parts of our state; used for signalling changes. @@ -301,6 +312,8 @@ private: void analyse_audio_finished (); std::string video_state_identifier () const; + boost::shared_ptr _playlist; + /** Complete path to directory containing the film metadata; * must not be relative. */ diff --git a/src/lib/format.cc b/src/lib/format.cc index 05b71f2e5..538bf7953 100644 --- a/src/lib/format.cc +++ b/src/lib/format.cc @@ -207,9 +207,9 @@ FixedFormat::FixedFormat (int r, libdcp::Size dcp, string id, string n, string d * (so there are dcp_padding() pixels on the left and dcp_padding() on the right) */ int -Format::dcp_padding (shared_ptr p) const +Format::dcp_padding (shared_ptr f) const { - int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(p) / 100.0)) / 2.0); + int pad = rint ((_dcp_size.width - (_dcp_size.height * ratio_as_integer(f) / 100.0)) / 2.0); /* This comes out -ve for Scope; bodge it */ if (pad < 0) { @@ -232,15 +232,15 @@ VariableFormat::VariableFormat (libdcp::Size dcp, string id, string n, string d, } int -VariableFormat::ratio_as_integer (shared_ptr p) const +VariableFormat::ratio_as_integer (shared_ptr f) const { - return rint (ratio_as_float (p) * 100); + return rint (ratio_as_float (f) * 100); } float -VariableFormat::ratio_as_float (shared_ptr p) const +VariableFormat::ratio_as_float (shared_ptr f) const { - return float (p->video_size().width) / p->video_size().height; + return float (f->video_size().width) / f->video_size().height; } /** @return A name to be presented to the user */ diff --git a/src/lib/format.h b/src/lib/format.h index 94c2253de..cc7502893 100644 --- a/src/lib/format.h +++ b/src/lib/format.h @@ -26,7 +26,7 @@ #include #include "util.h" -class Playlist; +class Film; class Format { @@ -42,15 +42,15 @@ public: /** @return the aspect ratio multiplied by 100 * (e.g. 239 for Cinemascope 2.39:1) */ - virtual int ratio_as_integer (boost::shared_ptr f) const = 0; + virtual int ratio_as_integer (boost::shared_ptr f) const = 0; /** @return the ratio as a floating point number */ - virtual float ratio_as_float (boost::shared_ptr f) const = 0; + virtual float ratio_as_float (boost::shared_ptr f) const = 0; /** @return the ratio of the container (including any padding) as a floating point number */ float container_ratio_as_float () const; - int dcp_padding (boost::shared_ptr) const; + int dcp_padding (boost::shared_ptr) const; /** @return size in pixels of the images that we should * put in a DCP for this ratio. This size will not correspond @@ -115,11 +115,11 @@ class FixedFormat : public Format public: FixedFormat (int, libdcp::Size, std::string, std::string, std::string, std::string); - int ratio_as_integer (boost::shared_ptr) const { + int ratio_as_integer (boost::shared_ptr) const { return _ratio; } - float ratio_as_float (boost::shared_ptr) const { + float ratio_as_float (boost::shared_ptr) const { return _ratio / 100.0; } @@ -136,8 +136,8 @@ class VariableFormat : public Format public: VariableFormat (libdcp::Size, std::string, std::string, std::string, std::string); - int ratio_as_integer (boost::shared_ptr f) const; - float ratio_as_float (boost::shared_ptr f) const; + int ratio_as_integer (boost::shared_ptr f) const; + float ratio_as_float (boost::shared_ptr f) const; std::string name () const; }; diff --git a/src/lib/imagemagick_decoder.cc b/src/lib/imagemagick_decoder.cc index c3723f610..279c8bf32 100644 --- a/src/lib/imagemagick_decoder.cc +++ b/src/lib/imagemagick_decoder.cc @@ -32,9 +32,9 @@ using std::cout; using boost::shared_ptr; using libdcp::Size; -ImageMagickDecoder::ImageMagickDecoder (shared_ptr f, shared_ptr c) +ImageMagickDecoder::ImageMagickDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , VideoDecoder (f, c) + , VideoDecoder (f) , _imagemagick_content (c) , _position (0) { diff --git a/src/lib/imagemagick_decoder.h b/src/lib/imagemagick_decoder.h index a26e283c0..7ad08df03 100644 --- a/src/lib/imagemagick_decoder.h +++ b/src/lib/imagemagick_decoder.h @@ -28,7 +28,7 @@ class ImageMagickContent; class ImageMagickDecoder : public VideoDecoder { public: - ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr); + ImageMagickDecoder (boost::shared_ptr, boost::shared_ptr); float frames_per_second () const { /* We don't know */ @@ -82,6 +82,6 @@ protected: private: void film_changed (Film::Property); - boost::shared_ptr _imagemagick_content; + boost::shared_ptr _imagemagick_content; ContentVideoFrame _position; }; diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index fc9edac48..d9bf8ac36 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -30,15 +30,20 @@ using std::list; using boost::shared_ptr; using boost::dynamic_pointer_cast; -Playlist::Playlist (shared_ptr f, list > c) - : _film (f) - , _video_from (VIDEO_NONE) +Playlist::Playlist () + : _video_from (VIDEO_NONE) , _audio_from (AUDIO_NONE) - , _have_setup_decoders (false) - , _ffmpeg_decoder_done (false) - , _video_sync (true) { - for (list >::const_iterator i = c.begin(); i != c.end(); ++i) { + +} + +void +Playlist::setup (list > content) +{ + _video_from = VIDEO_NONE; + _audio_from = AUDIO_NONE; + + for (list >::const_iterator i = content.begin(); i != content.end(); ++i) { shared_ptr fc = dynamic_pointer_cast (*i); if (fc) { assert (!_ffmpeg); @@ -76,7 +81,7 @@ Playlist::audio_length () const case AUDIO_SNDFILE: { ContentAudioFrame l = 0; - for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { l += (*i)->audio_length (); } return l; @@ -97,7 +102,7 @@ Playlist::audio_channels () const case AUDIO_SNDFILE: { int c = 0; - for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + for (list >::const_iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { c += (*i)->audio_channels (); } return c; @@ -180,7 +185,7 @@ Playlist::video_length () const case VIDEO_IMAGEMAGICK: { ContentVideoFrame l = 0; - for (list >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + for (list >::const_iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { l += (*i)->video_length (); } return l; @@ -195,27 +200,40 @@ Playlist::has_audio () const { return _audio_from != AUDIO_NONE; } + +Player::Player (boost::shared_ptr f, boost::shared_ptr p) + : _film (f) + , _playlist (p) + , _video (true) + , _audio (true) + , _subtitles (true) + , _have_setup_decoders (false) + , _ffmpeg_decoder_done (false) + , _video_sync (true) +{ + +} void -Playlist::disable_video () +Player::disable_video () { - _video_from = VIDEO_NONE; + _video = false; } void -Playlist::disable_audio () +Player::disable_audio () { - _audio_from = AUDIO_NONE; + _audio = false; } void -Playlist::disable_subtitles () +Player::disable_subtitles () { - /* XXX */ + _subtitles = false; } bool -Playlist::pass () +Player::pass () { if (!_have_setup_decoders) { setup_decoders (); @@ -224,7 +242,7 @@ Playlist::pass () bool done = true; - if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { if (!_ffmpeg_decoder_done) { if (_ffmpeg_decoder->pass ()) { _ffmpeg_decoder_done = true; @@ -234,7 +252,7 @@ Playlist::pass () } } - if (_video_from == VIDEO_IMAGEMAGICK) { + if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { if (_imagemagick_decoder != _imagemagick_decoders.end ()) { if ((*_imagemagick_decoder)->pass ()) { _imagemagick_decoder++; @@ -252,37 +270,37 @@ Playlist::pass () } void -Playlist::set_progress (shared_ptr job) +Player::set_progress (shared_ptr job) { /* XXX */ } void -Playlist::process_video (shared_ptr i, bool same, shared_ptr s) +Player::process_video (shared_ptr i, bool same, shared_ptr s) { Video (i, same, s); } void -Playlist::process_audio (shared_ptr b) +Player::process_audio (shared_ptr b) { Audio (b); } bool -Playlist::seek (double t) +Player::seek (double t) { bool r = false; - switch (_video_from) { - case VIDEO_NONE: + switch (_playlist->video_from()) { + case Playlist::VIDEO_NONE: break; - case VIDEO_FFMPEG: + case Playlist::VIDEO_FFMPEG: if (_ffmpeg_decoder->seek (t)) { r = true; } break; - case VIDEO_IMAGEMAGICK: + case Playlist::VIDEO_IMAGEMAGICK: if ((*_imagemagick_decoder)->seek (t)) { r = true; } @@ -295,19 +313,19 @@ Playlist::seek (double t) } bool -Playlist::seek_to_last () +Player::seek_to_last () { bool r = false; - switch (_video_from) { - case VIDEO_NONE: + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: break; - case VIDEO_FFMPEG: + case Playlist::VIDEO_FFMPEG: if (_ffmpeg_decoder->seek_to_last ()) { r = true; } break; - case VIDEO_IMAGEMAGICK: + case Playlist::VIDEO_IMAGEMAGICK: if ((*_imagemagick_decoder)->seek_to_last ()) { r = true; } @@ -320,26 +338,32 @@ Playlist::seek_to_last () } void -Playlist::setup_decoders () +Player::setup_decoders () { - if (_video_from == VIDEO_FFMPEG || _audio_from == AUDIO_FFMPEG) { + if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) { _ffmpeg_decoder.reset ( new FFmpegDecoder ( - _film, _ffmpeg, _video_from == VIDEO_FFMPEG, _audio_from == AUDIO_FFMPEG, _film->with_subtitles(), _video_sync + _film, + _playlist->ffmpeg(), + _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG, + _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, + _subtitles && _film->with_subtitles(), + _video_sync ) ); } - if (_video_from == VIDEO_FFMPEG) { + if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) { _ffmpeg_decoder->connect_video (shared_from_this ()); } - if (_audio_from == AUDIO_FFMPEG) { + if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { _ffmpeg_decoder->connect_audio (shared_from_this ()); } - if (_video_from == VIDEO_IMAGEMAGICK) { - for (list >::iterator i = _imagemagick.begin(); i != _imagemagick.end(); ++i) { + if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { + list > ic = _playlist->imagemagick (); + for (list >::iterator i = ic.begin(); i != ic.end(); ++i) { shared_ptr d (new ImageMagickDecoder (_film, *i)); _imagemagick_decoders.push_back (d); d->connect_video (shared_from_this ()); @@ -348,8 +372,9 @@ Playlist::setup_decoders () _imagemagick_decoder = _imagemagick_decoders.begin (); } - if (_audio_from == AUDIO_SNDFILE) { - for (list >::iterator i = _sndfile.begin(); i != _sndfile.end(); ++i) { + if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + list > sc = _playlist->sndfile (); + for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { shared_ptr d (new SndfileDecoder (_film, *i)); _sndfile_decoders.push_back (d); d->connect_audio (shared_from_this ()); @@ -358,7 +383,22 @@ Playlist::setup_decoders () } void -Playlist::disable_video_sync () +Player::disable_video_sync () { _video_sync = false; } + +double +Player::last_video_time () const +{ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + return 0; + case Playlist::VIDEO_FFMPEG: + return _ffmpeg_decoder->last_source_time (); + case Playlist::VIDEO_IMAGEMAGICK: + return (*_imagemagick_decoder)->last_source_time (); + } + + return 0; +} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index d374dc98c..827849049 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -35,10 +35,12 @@ class SndfileDecoder; class Job; class Film; -class Playlist : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +class Playlist { public: - Playlist (boost::shared_ptr, std::list >); + Playlist (); + + void setup (std::list >); ContentAudioFrame audio_length () const; int audio_channels () const; @@ -50,6 +52,52 @@ public: libdcp::Size video_size () const; ContentVideoFrame video_length () const; + enum VideoFrom { + VIDEO_NONE, + VIDEO_FFMPEG, + VIDEO_IMAGEMAGICK + }; + + enum AudioFrom { + AUDIO_NONE, + AUDIO_FFMPEG, + AUDIO_SNDFILE + }; + + VideoFrom video_from () const { + return _video_from; + } + + AudioFrom audio_from () const { + return _audio_from; + } + + boost::shared_ptr ffmpeg () const { + return _ffmpeg; + } + + std::list > imagemagick () const { + return _imagemagick; + } + + std::list > sndfile () const { + return _sndfile; + } + +private: + VideoFrom _video_from; + AudioFrom _audio_from; + + boost::shared_ptr _ffmpeg; + std::list > _imagemagick; + std::list > _sndfile; +}; + +class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +{ +public: + Player (boost::shared_ptr, boost::shared_ptr); + void disable_video (); void disable_audio (); void disable_subtitles (); @@ -60,29 +108,20 @@ public: bool seek (double); bool seek_to_last (); + double last_video_time () const; + private: void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); void process_audio (boost::shared_ptr); void setup_decoders (); - - boost::shared_ptr _film; - enum { - VIDEO_NONE, - VIDEO_FFMPEG, - VIDEO_IMAGEMAGICK - } _video_from; + boost::shared_ptr _film; + boost::shared_ptr _playlist; + + bool _video; + bool _audio; + bool _subtitles; - enum { - AUDIO_NONE, - AUDIO_FFMPEG, - AUDIO_SNDFILE - } _audio_from; - - boost::shared_ptr _ffmpeg; - std::list > _imagemagick; - std::list > _sndfile; - bool _have_setup_decoders; boost::shared_ptr _ffmpeg_decoder; bool _ffmpeg_decoder_done; diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index daa363c5e..1f97e5c41 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -36,9 +36,9 @@ using boost::optional; /* XXX */ -SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) +SndfileDecoder::SndfileDecoder (shared_ptr f, shared_ptr c) : Decoder (f) - , AudioDecoder (f, c) + , AudioDecoder (f) { sf_count_t frames; SNDFILE* sf = open_file (frames); diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index 9a3ef49b0..56fc3a9f0 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -26,7 +26,7 @@ class SndfileContent; class SndfileDecoder : public AudioDecoder { public: - SndfileDecoder (boost::shared_ptr, boost::shared_ptr); + SndfileDecoder (boost::shared_ptr, boost::shared_ptr); bool pass (); @@ -34,5 +34,5 @@ private: SNDFILE* open_file (sf_count_t &); void close_file (SNDFILE*); - boost::shared_ptr _sndfile_content; + boost::shared_ptr _sndfile_content; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 21944c5fc..0ee6f523f 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -47,24 +47,24 @@ using boost::dynamic_pointer_cast; */ Transcoder::Transcoder (shared_ptr f, shared_ptr j) : _job (j) - , _playlist (f->playlist ()) - , _encoder (new Encoder (f, _playlist)) + , _player (f->player ()) + , _encoder (new Encoder (f)) { - if (_playlist->has_audio ()) { - _matcher.reset (new Matcher (f->log(), _playlist->audio_frame_rate(), _playlist->video_frame_rate())); - _delay_line.reset (new DelayLine (f->log(), _playlist->audio_channels(), f->audio_delay() * _playlist->audio_frame_rate() / 1000)); + if (f->has_audio ()) { + _matcher.reset (new Matcher (f->log(), f->audio_frame_rate(), f->video_frame_rate())); + _delay_line.reset (new DelayLine (f->log(), f->audio_channels(), f->audio_delay() * f->audio_frame_rate() / 1000)); _gain.reset (new Gain (f->log(), f->audio_gain())); } if (_matcher) { - _playlist->connect_video (_matcher); + _player->connect_video (_matcher); _matcher->connect_video (_encoder); } else { - _playlist->connect_video (_encoder); + _player->connect_video (_encoder); } - if (_matcher && _delay_line && _playlist->has_audio ()) { - _playlist->connect_audio (_delay_line); + if (_matcher && _delay_line && f->has_audio ()) { + _player->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); _gain->connect_audio (_encoder); @@ -77,10 +77,10 @@ Transcoder::go () _encoder->process_begin (); try { while (1) { - if (_playlist->pass ()) { + if (_player->pass ()) { break; } - _playlist->set_progress (_job); + _player->set_progress (_job); } } catch (...) { diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 856b10f3a..2d032fcf6 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -30,7 +30,7 @@ class Matcher; class VideoFilter; class Gain; class DelayLine; -class Playlist; +class Player; /** @class Transcoder * @@ -50,7 +50,7 @@ public: protected: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; - boost::shared_ptr _playlist; + boost::shared_ptr _player; boost::shared_ptr _encoder; boost::shared_ptr _matcher; boost::shared_ptr _delay_line; diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 33dd433ea..32b06085f 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -29,7 +29,7 @@ using boost::shared_ptr; using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr f, shared_ptr c) +VideoDecoder::VideoDecoder (shared_ptr f) : Decoder (f) , _video_frame (0) , _last_source_time (0) @@ -106,10 +106,7 @@ VideoDecoder::set_progress (Job* j) const { assert (j); -#if 0 - XXX - if (_film->length()) { - j->set_progress (float (_video_frame) / _film->length().get()); + if (_film->video_length()) { + j->set_progress (float (_video_frame) / _film->video_length()); } -#endif } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 03dc4777a..a2fd5b651 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -28,7 +28,7 @@ class VideoContent; class VideoDecoder : public VideoSource, public virtual Decoder { public: - VideoDecoder (boost::shared_ptr, boost::shared_ptr); + VideoDecoder (boost::shared_ptr); /** @return video frames per second, or 0 if unknown */ virtual float frames_per_second () const = 0; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index 5f5dae98f..b08b9caf1 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -42,9 +42,8 @@ using boost::shared_ptr; int const Writer::_maximum_frames_in_memory = 8; -Writer::Writer (shared_ptr f, shared_ptr p) +Writer::Writer (shared_ptr f) : _film (f) - , _playlist (p) , _first_nonexistant_frame (0) , _thread (0) , _finish (false) @@ -76,7 +75,7 @@ Writer::Writer (shared_ptr f, shared_ptr p) _picture_asset_writer = _picture_asset->start_write (_first_nonexistant_frame > 0); - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); if (m.dcp_channels() > 0) { _sound_asset.reset ( @@ -85,7 +84,7 @@ Writer::Writer (shared_ptr f, shared_ptr p) N_("audio.mxf"), _film->dcp_frame_rate (), m.dcp_channels (), - dcp_audio_sample_rate (_playlist->audio_frame_rate()) + dcp_audio_sample_rate (_film->audio_frame_rate()) ) ); diff --git a/src/lib/writer.h b/src/lib/writer.h index 920f592b6..beb16c7b9 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -26,7 +26,6 @@ class Film; class EncodedData; class AudioBuffers; -class Playlist; namespace libdcp { class MonoPictureAsset; @@ -64,7 +63,7 @@ bool operator== (QueueItem const & a, QueueItem const & b); class Writer : public ExceptionStore { public: - Writer (boost::shared_ptr, boost::shared_ptr); + Writer (boost::shared_ptr); bool can_fake_write (int) const; @@ -81,7 +80,6 @@ private: /** our Film */ boost::shared_ptr _film; - boost::shared_ptr _playlist; /** the first frame index that does not already exist in our MXF */ int _first_nonexistant_frame; diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index 3d847d690..d7e8bbb0e 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -150,14 +150,14 @@ main (int argc, char* argv[]) server = new ServerDescription (server_host, 1); shared_ptr film (new Film (film_dir, true)); - shared_ptr playlist = film->playlist (); - playlist->disable_audio (); + shared_ptr player = film->player (); + player->disable_audio (); try { - playlist->Video.connect (boost::bind (process_video, _1, _2, _3)); + player->Video.connect (boost::bind (process_video, _1, _2, _3)); bool done = false; while (!done) { - done = playlist->pass (); + done = player->pass (); } } catch (std::exception& e) { cerr << "Error: " << e.what() << "\n"; diff --git a/src/wx/audio_dialog.cc b/src/wx/audio_dialog.cc index b7384fd14..242d37b1e 100644 --- a/src/wx/audio_dialog.cc +++ b/src/wx/audio_dialog.cc @@ -20,7 +20,6 @@ #include #include "lib/audio_analysis.h" #include "lib/film.h" -#include "lib/playlist.h" #include "audio_dialog.h" #include "audio_plot.h" #include "wx_util.h" @@ -91,7 +90,6 @@ AudioDialog::set_film (boost::shared_ptr f) _film_audio_analysis_succeeded_connection.disconnect (); _film = f; - _playlist = _film->playlist (); try_to_load_analysis (); setup_channels (); @@ -106,11 +104,11 @@ AudioDialog::set_film (boost::shared_ptr f) void AudioDialog::setup_channels () { - if (!_playlist->has_audio()) { + if (!_film->has_audio()) { return; } - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); for (int i = 0; i < MAX_AUDIO_CHANNELS; ++i) { if (m.dcp_to_source(static_cast(i))) { @@ -136,7 +134,7 @@ AudioDialog::try_to_load_analysis () _plot->set_analysis (a); - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); optional c = m.source_to_dcp (0); if (c) { _channel_checkbox[c.get()]->SetValue (true); @@ -159,7 +157,7 @@ AudioDialog::channel_clicked (wxCommandEvent& ev) assert (c < MAX_AUDIO_CHANNELS); - AudioMapping m (_playlist->audio_channels ()); + AudioMapping m (_film->audio_channels ()); optional s = m.dcp_to_source (static_cast (c)); if (s) { _plot->set_channel_visible (s.get(), _channel_checkbox[c]->GetValue ()); @@ -174,7 +172,6 @@ AudioDialog::film_changed (Film::Property p) _plot->set_gain (_film->audio_gain ()); break; case Film::CONTENT: - _playlist = _film->playlist (); setup_channels (); break; default: diff --git a/src/wx/audio_dialog.h b/src/wx/audio_dialog.h index 3cb9c1726..514faeea0 100644 --- a/src/wx/audio_dialog.h +++ b/src/wx/audio_dialog.h @@ -25,7 +25,6 @@ class AudioPlot; class Film; -class Playlist; class AudioDialog : public wxDialog { @@ -43,7 +42,6 @@ private: void setup_channels (); boost::shared_ptr _film; - boost::shared_ptr _playlist; AudioPlot* _plot; wxCheckBox* _channel_checkbox[MAX_AUDIO_CHANNELS]; wxCheckBox* _type_checkbox[AudioPoint::COUNT]; diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 42af4b3c0..79b3d982f 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -97,13 +97,13 @@ FilmViewer::film_changed (Film::Property p) break; case Film::CONTENT: { - _playlist = _film->playlist (); - _playlist->disable_audio (); - _playlist->disable_subtitles (); - _playlist->disable_video_sync (); + _player = _film->player (); + _player->disable_audio (); + _player->disable_subtitles (); + _player->disable_video_sync (); - _playlist->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); -// _playlist->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); + _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); +// _player->OutputChanged.connect (boost::bind (&FilmViewer::decoder_changed, this)); calculate_sizes (); get_frame (); _panel->Refresh (); @@ -153,7 +153,7 @@ FilmViewer::set_film (shared_ptr f) void FilmViewer::decoder_changed () { - if (!_playlist == 0 || _playlist->seek_to_last ()) { + if (!_player || _player->seek_to_last ()) { return; } @@ -165,7 +165,7 @@ FilmViewer::decoder_changed () void FilmViewer::timer (wxTimerEvent &) { - if (!_playlist) { + if (!_player) { return; } @@ -174,12 +174,12 @@ FilmViewer::timer (wxTimerEvent &) get_frame (); -// if (_playlist->video_length()) { -// int const new_slider_position = 4096 * _playlist->last_source_time() / (_film->length().get() / _film->source_frame_rate()); -// if (new_slider_position != _slider->GetValue()) { -// _slider->SetValue (new_slider_position); -// } -// } + if (_film->video_length()) { + int const new_slider_position = 4096 * _player->last_video_time() / (_film->video_length() / _film->video_frame_rate()); + if (new_slider_position != _slider->GetValue()) { + _slider->SetValue (new_slider_position); + } + } } @@ -220,11 +220,11 @@ FilmViewer::paint_panel (wxPaintEvent &) void FilmViewer::slider_moved (wxScrollEvent &) { - if (!_film || !_playlist) { + if (!_film || !_player) { return; } - if (_playlist->seek (_slider->GetValue() * _playlist->video_length() / (4096 * _playlist->video_frame_rate()))) { + if (_player->seek (_slider->GetValue() * _film->video_length() / (4096 * _film->video_frame_rate()))) { return; } @@ -308,7 +308,7 @@ FilmViewer::raw_to_display () void FilmViewer::calculate_sizes () { - if (!_film || !_playlist) { + if (!_film || !_player) { return; } @@ -332,7 +332,7 @@ FilmViewer::calculate_sizes () */ _display_frame_x = 0; if (format) { - _display_frame_x = static_cast (format->dcp_padding (_playlist)) * _out_size.width / format->dcp_size().width; + _display_frame_x = static_cast (format->dcp_padding (_film)) * _out_size.width / format->dcp_size().width; } _film_size = _out_size; @@ -381,7 +381,7 @@ FilmViewer::get_frame () /* Clear our raw frame in case we don't get a new one */ _raw_frame.reset (); - if (!_playlist) { + if (!_player) { _display_frame.reset (); return; } @@ -389,7 +389,7 @@ FilmViewer::get_frame () try { _got_frame = false; while (!_got_frame) { - if (_playlist->pass ()) { + if (_player->pass ()) { /* We didn't get a frame before the decoder gave up, so clear our display frame. */ diff --git a/src/wx/film_viewer.h b/src/wx/film_viewer.h index 74ab9798c..1e75045ac 100644 --- a/src/wx/film_viewer.h +++ b/src/wx/film_viewer.h @@ -57,7 +57,7 @@ private: void active_jobs_changed (bool); boost::shared_ptr _film; - boost::shared_ptr _playlist; + boost::shared_ptr _player; wxSizer* _v_sizer; wxPanel* _panel; diff --git a/wscript b/wscript index fb728ec40..9040738fb 100644 --- a/wscript +++ b/wscript @@ -55,6 +55,7 @@ def configure(conf): if not conf.options.static: conf.check_cfg(package = 'libdcp', atleast_version = '0.41', args = '--cflags --libs', uselib_store = 'DCP', mandatory = True) + conf.check_cfg(package = 'libcxml', atleast_version = '0.01', args = '--cflags --libs', uselib_store = 'CXML', mandatory = True) conf.check_cfg(package = 'libavformat', args = '--cflags --libs', uselib_store = 'AVFORMAT', mandatory = True) conf.check_cfg(package = 'libavfilter', args = '--cflags --libs', uselib_store = 'AVFILTER', mandatory = True) conf.check_cfg(package = 'libavcodec', args = '--cflags --libs', uselib_store = 'AVCODEC', mandatory = True) @@ -71,6 +72,8 @@ def configure(conf): conf.env.HAVE_DCP = 1 conf.env.STLIB_DCP = ['dcp', 'asdcp-libdcp', 'kumu-libdcp'] conf.env.LIB_DCP = ['glibmm-2.4', 'xml++-2.6', 'ssl', 'crypto', 'bz2'] + conf.env.HAVE_CXML = 1 + conf.env.STLIB_CXML = ['cxml'] conf.env.HAVE_AVFORMAT = 1 conf.env.STLIB_AVFORMAT = ['avformat'] conf.env.HAVE_AVFILTER = 1 -- cgit v1.2.3 From 190c074cc1508c0aa429452ea920f8f94ef0d0f2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 4 Apr 2013 00:13:27 +0100 Subject: More various bits. --- src/lib/audio_source.cc | 12 +++++++++++- src/lib/encoder.cc | 2 +- src/lib/encoder.h | 2 +- src/lib/ffmpeg_content.cc | 10 ++++++---- src/lib/ffmpeg_decoder.cc | 12 +++++++++++- src/lib/ffmpeg_decoder.h | 10 ++++++++++ src/lib/film.cc | 2 +- src/lib/playlist.cc | 25 +++++++++++++++++++++++-- src/lib/transcode_job.cc | 34 ++++++++++++++++------------------ src/lib/transcode_job.h | 6 ++++-- src/lib/transcoder.cc | 12 ++++++++++++ src/lib/transcoder.h | 3 +++ src/lib/video_source.cc | 15 ++++++++++++++- src/wx/film_editor.cc | 29 +++++++++++++++++++++++++---- src/wx/film_editor.h | 1 + 15 files changed, 139 insertions(+), 36 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index 53b0dda15..99b59759d 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -21,10 +21,20 @@ #include "audio_sink.h" using boost::shared_ptr; +using boost::weak_ptr; using boost::bind; +static void +process_audio_proxy (weak_ptr sink, shared_ptr audio) +{ + shared_ptr p = sink.lock (); + if (p) { + p->process_audio (audio); + } +} + void AudioSource::connect_audio (shared_ptr s) { - Audio.connect (bind (&AudioSink::process_audio, s, _1)); + Audio.connect (bind (process_audio_proxy, weak_ptr (s), _1)); } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 5c3e56709..a41ebec51 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -193,7 +193,7 @@ Encoder::process_end () * or 0 if not known. */ float -Encoder::current_frames_per_second () const +Encoder::current_encoding_rate () const { boost::mutex::scoped_lock lock (_history_mutex); if (int (_time_history.size()) < _history_size) { diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 2cbd498e8..b85132b72 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -81,7 +81,7 @@ public: /** Called when a processing run has finished */ virtual void process_end (); - float current_frames_per_second () const; + float current_encoding_rate () const; int video_frames_out () const; private: diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index c6344d567..7834cb76e 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -111,12 +111,10 @@ FFmpegContent::as_xml (xmlpp::Node* node) const void FFmpegContent::examine (shared_ptr film, shared_ptr job, bool quick) { - job->descend (0.5); - Content::examine (film, job, quick); - job->ascend (); - job->set_progress_unknown (); + Content::examine (film, job, quick); + shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false, false, true)); ContentVideoFrame video_length = 0; @@ -166,6 +164,10 @@ FFmpegContent::summary () const string FFmpegContent::information () const { + if (video_length() == 0 || video_frame_rate() == 0) { + return ""; + } + stringstream s; s << String::compose (_("%1 frames; %2 frames per second"), video_length(), video_frame_rate()) << "\n"; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 3a185bd6a..fdc5189a6 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -61,6 +61,8 @@ using boost::optional; using boost::dynamic_pointer_cast; using libdcp::Size; +boost::mutex FFmpegDecoder::_mutex; + FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles, bool video_sync) : Decoder (f) , VideoDecoder (f) @@ -92,10 +94,12 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptrstreams[_video_stream]->codec; _video_codec = avcodec_find_decoder (_video_codec_context->codec_id); @@ -175,6 +181,8 @@ FFmpegDecoder::setup_video () void FFmpegDecoder::setup_audio () { + boost::mutex::scoped_lock lm (_mutex); + if (!_ffmpeg_content->audio_stream ()) { return; } @@ -194,6 +202,8 @@ FFmpegDecoder::setup_audio () void FFmpegDecoder::setup_subtitle () { + boost::mutex::scoped_lock lm (_mutex); + if (!_ffmpeg_content->subtitle_stream() || _ffmpeg_content->subtitle_stream()->id >= int (_format_context->nb_streams)) { return; } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 71ecf7906..5023ac56c 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -82,6 +82,10 @@ public: private: + /* No copy construction */ + FFmpegDecoder (FFmpegDecoder const &); + FFmpegDecoder& operator= (FFmpegDecoder const &); + bool do_seek (double p, bool); PixelFormat pixel_format () const; AVSampleFormat audio_sample_format () const; @@ -134,4 +138,10 @@ private: bool _decode_audio; bool _decode_subtitles; bool _video_sync; + + /* It would appear (though not completely verified) that one must have + a mutex around calls to avcodec_open* and avcodec_close... and here + it is. + */ + static boost::mutex _mutex; }; diff --git a/src/lib/film.cc b/src/lib/film.cc index fd72aa1d5..b21b3454d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -550,7 +550,7 @@ Film::file (string f) const int Film::target_audio_sample_rate () const { - if (has_audio ()) { + if (!has_audio ()) { return 0; } diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 3da7f938b..dc8ad1ef7 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -25,6 +25,7 @@ #include "ffmpeg_decoder.h" #include "imagemagick_content.h" #include "imagemagick_decoder.h" +#include "job.h" using std::list; using std::cout; @@ -219,7 +220,7 @@ Player::Player (boost::shared_ptr f, boost::shared_ptr job) { - /* XXX */ + /* Assume progress can be divined from how far through the video we are */ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (_playlist->video_length ()) { + job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); + } + break; + case Playlist::VIDEO_IMAGEMAGICK: + { + int n = 0; + for (std::list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { + if (_imagemagick_decoder == i) { + job->set_progress (float (n) / _imagemagick_decoders.size ()); + } + ++n; + } + break; + } + } } void diff --git a/src/lib/transcode_job.cc b/src/lib/transcode_job.cc index 8b74f7766..0c3b8c37b 100644 --- a/src/lib/transcode_job.cc +++ b/src/lib/transcode_job.cc @@ -60,8 +60,8 @@ TranscodeJob::run () _film->log()->log (N_("Transcode job starting")); _film->log()->log (String::compose (N_("Audio delay is %1ms"), _film->audio_delay())); - Transcoder w (_film, shared_from_this ()); - w.go (); + _transcoder.reset (new Transcoder (_film, shared_from_this ())); + _transcoder->go (); set_progress (1); set_state (FINISHED_OK); @@ -80,13 +80,11 @@ TranscodeJob::run () string TranscodeJob::status () const { -// if (!_encoder) { -// return _("0%"); -// } + if (!_transcoder) { + return _("0%"); + } - /* XXX */ -// float const fps = _encoder->current_frames_per_second (); - float const fps = 0; + float const fps = _transcoder->current_encoding_rate (); if (fps == 0) { return Job::status (); } @@ -105,28 +103,28 @@ TranscodeJob::status () const int TranscodeJob::remaining_time () const { - return 0; -#if 0 - XXX - float fps = _encoder->current_frames_per_second (); + if (!_transcoder) { + return 0; + } + + float fps = _transcoder->current_encoding_rate (); + if (fps == 0) { return 0; } - if (!_video->length()) { + if (!_film->video_length()) { return 0; } /* Compute approximate proposed length here, as it's only here that we need it */ - int length = _film->length().get(); - FrameRateConversion const frc (_film->source_frame_rate(), _film->dcp_frame_rate()); + int length = _film->video_length(); + FrameRateConversion const frc (_film->video_frame_rate(), _film->dcp_frame_rate()); if (frc.skip) { length /= 2; } /* If we are repeating it shouldn't affect transcode time, so don't take it into account */ - /* We assume that dcp_length() is valid, if it is set */ - int const left = length - _encoder->video_frames_out(); + int const left = length - _transcoder->video_frames_out(); return left / fps; -#endif } diff --git a/src/lib/transcode_job.h b/src/lib/transcode_job.h index def545958..7880a925e 100644 --- a/src/lib/transcode_job.h +++ b/src/lib/transcode_job.h @@ -24,7 +24,7 @@ #include #include "job.h" -class Encoder; +class Transcoder; /** @class TranscodeJob * @brief A job which transcodes from one format to another. @@ -38,6 +38,8 @@ public: void run (); std::string status () const; -protected: +private: int remaining_time () const; + + boost::shared_ptr _transcoder; }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 0ee6f523f..ef3a0e8c1 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -99,3 +99,15 @@ Transcoder::go () } _encoder->process_end (); } + +float +Transcoder::current_encoding_rate () const +{ + return _encoder->current_encoding_rate (); +} + +int +Transcoder::video_frames_out () const +{ + return _encoder->video_frames_out (); +} diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 2d032fcf6..ecc8ebf62 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -47,6 +47,9 @@ public: void go (); + float current_encoding_rate () const; + int video_frames_out () const; + protected: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 56742e2b4..8101a6d36 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -21,10 +21,23 @@ #include "video_sink.h" using boost::shared_ptr; +using boost::weak_ptr; using boost::bind; +static void +process_video_proxy (weak_ptr sink, shared_ptr i, bool same, shared_ptr s) +{ + boost::shared_ptr p = sink.lock (); + if (p) { + p->process_video (i, same, s); + } +} + void VideoSource::connect_video (shared_ptr s) { - Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); + /* If we bind, say, a Playlist (as the VideoSink) to a Decoder (which is owned + by the Playlist) we create a cycle. Use a weak_ptr to break it. + */ + Video.connect (bind (process_video_proxy, boost::weak_ptr (s), _1, _2, _3)); } diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index d55104a95..10cb41df0 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -705,16 +705,17 @@ FilmEditor::film_content_changed (int p) setup_show_audio_sensitivity (); } else if (p == VideoContentProperty::VIDEO_LENGTH) { setup_length (); + setup_content_information (); } else if (p == FFmpegContentProperty::AUDIO_STREAM) { if (_film->ffmpeg_audio_stream()) { - checked_set (_ffmpeg_audio_stream, _film->ffmpeg_audio_stream()->id); + checked_set (_ffmpeg_audio_stream, boost::lexical_cast (_film->ffmpeg_audio_stream()->id)); } setup_dcp_name (); setup_audio_details (); setup_show_audio_sensitivity (); } else if (p == FFmpegContentProperty::SUBTITLE_STREAM) { if (_film->ffmpeg_subtitle_stream()) { - checked_set (_ffmpeg_subtitle_stream, _film->ffmpeg_subtitle_stream()->id); + checked_set (_ffmpeg_subtitle_stream, boost::lexical_cast (_film->ffmpeg_subtitle_stream()->id)); } } } @@ -1117,7 +1118,7 @@ FilmEditor::setup_audio_details () } else { s << _film->audio_channels() << " " << wx_to_std (_("channels")); } - s << ", " << _film->audio_channels() << wx_to_std (_("Hz")); + s << ", " << _film->audio_frame_rate() << wx_to_std (_("Hz")); _audio->SetLabel (std_to_wx (s.str ())); } } @@ -1172,11 +1173,26 @@ FilmEditor::setup_show_audio_sensitivity () void FilmEditor::setup_content () { + string selected_summary; + int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + if (s != -1) { + selected_summary = wx_to_std (_content->GetItemText (s)); + } + _content->DeleteAllItems (); ContentList content = _film->content (); for (ContentList::iterator i = content.begin(); i != content.end(); ++i) { - _content->InsertItem (_content->GetItemCount(), std_to_wx ((*i)->summary ())); + int const t = _content->GetItemCount (); + _content->InsertItem (t, std_to_wx ((*i)->summary ())); + if ((*i)->summary() == selected_summary) { + _content->SetItemState (t, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + } + } + + if (selected_summary.empty () && !content.empty ()) { + /* Select the first item of content if non was selected before */ + _content->SetItemState (0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); } } @@ -1246,7 +1262,12 @@ void FilmEditor::content_item_selected (wxListEvent &) { setup_content_button_sensitivity (); + setup_content_information (); +} +void +FilmEditor::setup_content_information () +{ int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (s == -1) { _content_information->SetValue (""); diff --git a/src/wx/film_editor.h b/src/wx/film_editor.h index 60da2de4d..97d1e0dd3 100644 --- a/src/wx/film_editor.h +++ b/src/wx/film_editor.h @@ -106,6 +106,7 @@ private: void setup_content_button_sensitivity (); void setup_length (); void setup_format (); + void setup_content_information (); void active_jobs_changed (bool); -- cgit v1.2.3 From 6bc12a2eeb9c84a539688f2f7eb876e3ea278a9f Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 4 Apr 2013 10:13:41 +0100 Subject: Split playlist files up; fix build. --- src/lib/ab_transcoder.cc | 2 +- src/lib/analyse_audio_job.cc | 2 +- src/lib/encoder.cc | 2 +- src/lib/film.cc | 1 + src/lib/player.cc | 280 +++++++++++++++++++++++++++++++++++++++++++ src/lib/player.h | 77 ++++++++++++ src/lib/playlist.cc | 250 -------------------------------------- src/lib/playlist.h | 39 ------ src/lib/transcoder.cc | 2 +- src/lib/writer.cc | 2 +- src/lib/wscript | 1 + src/tools/servomatictest.cc | 2 +- src/wx/film_editor.cc | 9 +- src/wx/film_viewer.cc | 2 +- 14 files changed, 371 insertions(+), 300 deletions(-) create mode 100644 src/lib/player.cc create mode 100644 src/lib/player.h (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 6bf092fee..81aa5a4ba 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -24,7 +24,7 @@ #include "encoder.h" #include "job.h" #include "image.h" -#include "playlist.h" +#include "player.h" #include "matcher.h" #include "delay_line.h" #include "gain.h" diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index e2c9c5b18..5ef6515dd 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -21,7 +21,7 @@ #include "analyse_audio_job.h" #include "compose.hpp" #include "film.h" -#include "playlist.h" +#include "player.h" #include "i18n.h" diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index a41ebec51..2a8d8cc16 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -37,7 +37,7 @@ #include "format.h" #include "cross.h" #include "writer.h" -#include "playlist.h" +#include "player.h" #include "i18n.h" diff --git a/src/lib/film.cc b/src/lib/film.cc index b21b3454d..42f4b1c3d 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -53,6 +53,7 @@ #include "sndfile_decoder.h" #include "analyse_audio_job.h" #include "playlist.h" +#include "player.h" #include "ffmpeg_content.h" #include "imagemagick_content.h" #include "sndfile_content.h" diff --git a/src/lib/player.cc b/src/lib/player.cc new file mode 100644 index 000000000..6e2e7ed14 --- /dev/null +++ b/src/lib/player.cc @@ -0,0 +1,280 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "player.h" +#include "film.h" +#include "ffmpeg_decoder.h" +#include "imagemagick_decoder.h" +#include "sndfile_decoder.h" +#include "playlist.h" +#include "job.h" + +using std::list; +using boost::shared_ptr; + +Player::Player (shared_ptr f, shared_ptr p) + : _film (f) + , _playlist (p) + , _video (true) + , _audio (true) + , _subtitles (true) + , _have_setup_decoders (false) + , _ffmpeg_decoder_done (false) + , _video_sync (true) +{ + +} + +void +Player::disable_video () +{ + _video = false; +} + +void +Player::disable_audio () +{ + _audio = false; +} + +void +Player::disable_subtitles () +{ + _subtitles = false; +} + +bool +Player::pass () +{ + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + + bool done = true; + + if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { + if (!_ffmpeg_decoder_done) { + if (_ffmpeg_decoder->pass ()) { + _ffmpeg_decoder_done = true; + } else { + done = false; + } + } + } + + if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { + if (_imagemagick_decoder != _imagemagick_decoders.end ()) { + if ((*_imagemagick_decoder)->pass ()) { + _imagemagick_decoder++; + } + + if (_imagemagick_decoder != _imagemagick_decoders.end ()) { + done = false; + } + } + } + + /* XXX: sndfile */ + + return done; +} + +void +Player::set_progress (shared_ptr job) +{ + /* Assume progress can be divined from how far through the video we are */ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (_playlist->video_length ()) { + job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); + } + break; + case Playlist::VIDEO_IMAGEMAGICK: + { + int n = 0; + for (list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { + if (_imagemagick_decoder == i) { + job->set_progress (float (n) / _imagemagick_decoders.size ()); + } + ++n; + } + break; + } + } +} + +void +Player::process_video (shared_ptr i, bool same, shared_ptr s) +{ + Video (i, same, s); +} + +void +Player::process_audio (shared_ptr b) +{ + Audio (b); +} + +/** @return true on error */ +bool +Player::seek (double t) +{ + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + + bool r = false; + + switch (_playlist->video_from()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (!_ffmpeg_decoder || _ffmpeg_decoder->seek (t)) { + r = true; + } + /* We're seeking, so all `all done' bets are off */ + _ffmpeg_decoder_done = false; + break; + case Playlist::VIDEO_IMAGEMAGICK: + /* Find the decoder that contains this position */ + _imagemagick_decoder = _imagemagick_decoders.begin (); + while (_imagemagick_decoder != _imagemagick_decoders.end ()) { + double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate (); + if (t < this_length) { + break; + } + t -= this_length; + ++_imagemagick_decoder; + } + + if (_imagemagick_decoder != _imagemagick_decoders.end()) { + (*_imagemagick_decoder)->seek (t); + } else { + r = true; + } + break; + } + + /* XXX: don't seek audio because we don't need to... */ + + return r; +} + +bool +Player::seek_to_last () +{ + if (!_have_setup_decoders) { + setup_decoders (); + _have_setup_decoders = true; + } + + bool r = false; + + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + break; + case Playlist::VIDEO_FFMPEG: + if (!_ffmpeg_decoder || _ffmpeg_decoder->seek_to_last ()) { + r = true; + } + + /* We're seeking, so all `all done' bets are off */ + _ffmpeg_decoder_done = false; + break; + case Playlist::VIDEO_IMAGEMAGICK: + if ((*_imagemagick_decoder)->seek_to_last ()) { + r = true; + } + break; + } + + /* XXX: don't seek audio because we don't need to... */ + + return r; +} + +void +Player::setup_decoders () +{ + if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) { + _ffmpeg_decoder.reset ( + new FFmpegDecoder ( + _film, + _playlist->ffmpeg(), + _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG, + _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, + _subtitles && _film->with_subtitles(), + _video_sync + ) + ); + } + + if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) { + _ffmpeg_decoder->connect_video (shared_from_this ()); + } + + if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { + _ffmpeg_decoder->connect_audio (shared_from_this ()); + } + + if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { + list > ic = _playlist->imagemagick (); + for (list >::iterator i = ic.begin(); i != ic.end(); ++i) { + shared_ptr d (new ImageMagickDecoder (_film, *i)); + _imagemagick_decoders.push_back (d); + d->connect_video (shared_from_this ()); + } + + _imagemagick_decoder = _imagemagick_decoders.begin (); + } + + if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { + list > sc = _playlist->sndfile (); + for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { + shared_ptr d (new SndfileDecoder (_film, *i)); + _sndfile_decoders.push_back (d); + d->connect_audio (shared_from_this ()); + } + } +} + +void +Player::disable_video_sync () +{ + _video_sync = false; +} + +double +Player::last_video_time () const +{ + switch (_playlist->video_from ()) { + case Playlist::VIDEO_NONE: + return 0; + case Playlist::VIDEO_FFMPEG: + return _ffmpeg_decoder->last_source_time (); + case Playlist::VIDEO_IMAGEMAGICK: + return (*_imagemagick_decoder)->last_source_time (); + } + + return 0; +} diff --git a/src/lib/player.h b/src/lib/player.h new file mode 100644 index 000000000..bc728d8f2 --- /dev/null +++ b/src/lib/player.h @@ -0,0 +1,77 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef DVDOMATIC_PLAYER_H +#define DVDOMATIC_PLAYER_H + +#include +#include +#include +#include "video_source.h" +#include "audio_source.h" +#include "video_sink.h" +#include "audio_sink.h" + +class FFmpegDecoder; +class ImageMagickDecoder; +class SndfileDecoder; +class Job; +class Film; +class Playlist; + +class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this +{ +public: + Player (boost::shared_ptr, boost::shared_ptr); + + void disable_video (); + void disable_audio (); + void disable_subtitles (); + void disable_video_sync (); + + bool pass (); + void set_progress (boost::shared_ptr); + bool seek (double); + bool seek_to_last (); + + double last_video_time () const; + +private: + void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); + void process_audio (boost::shared_ptr); + void setup_decoders (); + + boost::shared_ptr _film; + boost::shared_ptr _playlist; + + bool _video; + bool _audio; + bool _subtitles; + + bool _have_setup_decoders; + boost::shared_ptr _ffmpeg_decoder; + bool _ffmpeg_decoder_done; + std::list > _imagemagick_decoders; + std::list >::iterator _imagemagick_decoder; + std::list > _sndfile_decoders; + + bool _video_sync; +}; + +#endif diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index a7862f116..0a4803f6e 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -208,253 +208,3 @@ Playlist::has_audio () const return _audio_from != AUDIO_NONE; } -Player::Player (boost::shared_ptr f, boost::shared_ptr p) - : _film (f) - , _playlist (p) - , _video (true) - , _audio (true) - , _subtitles (true) - , _have_setup_decoders (false) - , _ffmpeg_decoder_done (false) - , _video_sync (true) -{ - -} - -void -Player::disable_video () -{ - _video = false; -} - -void -Player::disable_audio () -{ - _audio = false; -} - -void -Player::disable_subtitles () -{ - _subtitles = false; -} - -bool -Player::pass () -{ - if (!_have_setup_decoders) { - setup_decoders (); - _have_setup_decoders = true; - } - - bool done = true; - - if (_playlist->video_from() == Playlist::VIDEO_FFMPEG || _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - if (!_ffmpeg_decoder_done) { - if (_ffmpeg_decoder->pass ()) { - _ffmpeg_decoder_done = true; - } else { - done = false; - } - } - } - - if (_playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { - if (_imagemagick_decoder != _imagemagick_decoders.end ()) { - if ((*_imagemagick_decoder)->pass ()) { - _imagemagick_decoder++; - } - - if (_imagemagick_decoder != _imagemagick_decoders.end ()) { - done = false; - } - } - } - - /* XXX: sndfile */ - - return done; -} - -void -Player::set_progress (shared_ptr job) -{ - /* Assume progress can be divined from how far through the video we are */ - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (_playlist->video_length ()) { - job->set_progress (float(_ffmpeg_decoder->video_frame()) / _playlist->video_length ()); - } - break; - case Playlist::VIDEO_IMAGEMAGICK: - { - int n = 0; - for (std::list >::iterator i = _imagemagick_decoders.begin(); i != _imagemagick_decoders.end(); ++i) { - if (_imagemagick_decoder == i) { - job->set_progress (float (n) / _imagemagick_decoders.size ()); - } - ++n; - } - break; - } - } -} - -void -Player::process_video (shared_ptr i, bool same, shared_ptr s) -{ - Video (i, same, s); -} - -void -Player::process_audio (shared_ptr b) -{ - Audio (b); -} - -/** @return true on error */ -bool -Player::seek (double t) -{ - if (!_have_setup_decoders) { - setup_decoders (); - _have_setup_decoders = true; - } - - bool r = false; - - switch (_playlist->video_from()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (!_ffmpeg_decoder || _ffmpeg_decoder->seek (t)) { - r = true; - } - /* We're seeking, so all `all done' bets are off */ - _ffmpeg_decoder_done = false; - break; - case Playlist::VIDEO_IMAGEMAGICK: - /* Find the decoder that contains this position */ - _imagemagick_decoder = _imagemagick_decoders.begin (); - while (_imagemagick_decoder != _imagemagick_decoders.end ()) { - double const this_length = (*_imagemagick_decoder)->video_length() / _film->video_frame_rate (); - if (t < this_length) { - break; - } - t -= this_length; - ++_imagemagick_decoder; - } - - if (_imagemagick_decoder != _imagemagick_decoders.end()) { - (*_imagemagick_decoder)->seek (t); - } else { - r = true; - } - break; - } - - /* XXX: don't seek audio because we don't need to... */ - - return r; -} - -bool -Player::seek_to_last () -{ - if (!_have_setup_decoders) { - setup_decoders (); - _have_setup_decoders = true; - } - - bool r = false; - - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - break; - case Playlist::VIDEO_FFMPEG: - if (!_ffmpeg_decoder || _ffmpeg_decoder->seek_to_last ()) { - r = true; - } - - /* We're seeking, so all `all done' bets are off */ - _ffmpeg_decoder_done = false; - break; - case Playlist::VIDEO_IMAGEMAGICK: - if ((*_imagemagick_decoder)->seek_to_last ()) { - r = true; - } - break; - } - - /* XXX: don't seek audio because we don't need to... */ - - return r; -} - -void -Player::setup_decoders () -{ - if ((_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) || (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG)) { - _ffmpeg_decoder.reset ( - new FFmpegDecoder ( - _film, - _playlist->ffmpeg(), - _video && _playlist->video_from() == Playlist::VIDEO_FFMPEG, - _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, - _subtitles && _film->with_subtitles(), - _video_sync - ) - ); - } - - if (_video && _playlist->video_from() == Playlist::VIDEO_FFMPEG) { - _ffmpeg_decoder->connect_video (shared_from_this ()); - } - - if (_audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG) { - _ffmpeg_decoder->connect_audio (shared_from_this ()); - } - - if (_video && _playlist->video_from() == Playlist::VIDEO_IMAGEMAGICK) { - list > ic = _playlist->imagemagick (); - for (list >::iterator i = ic.begin(); i != ic.end(); ++i) { - shared_ptr d (new ImageMagickDecoder (_film, *i)); - _imagemagick_decoders.push_back (d); - d->connect_video (shared_from_this ()); - } - - _imagemagick_decoder = _imagemagick_decoders.begin (); - } - - if (_audio && _playlist->audio_from() == Playlist::AUDIO_SNDFILE) { - list > sc = _playlist->sndfile (); - for (list >::iterator i = sc.begin(); i != sc.end(); ++i) { - shared_ptr d (new SndfileDecoder (_film, *i)); - _sndfile_decoders.push_back (d); - d->connect_audio (shared_from_this ()); - } - } -} - -void -Player::disable_video_sync () -{ - _video_sync = false; -} - -double -Player::last_video_time () const -{ - switch (_playlist->video_from ()) { - case Playlist::VIDEO_NONE: - return 0; - case Playlist::VIDEO_FFMPEG: - return _ffmpeg_decoder->last_source_time (); - case Playlist::VIDEO_IMAGEMAGICK: - return (*_imagemagick_decoder)->last_source_time (); - } - - return 0; -} diff --git a/src/lib/playlist.h b/src/lib/playlist.h index 480f1b2ed..29a52d433 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -93,42 +93,3 @@ private: std::list > _imagemagick; std::list > _sndfile; }; - -class Player : public VideoSource, public AudioSource, public VideoSink, public AudioSink, public boost::enable_shared_from_this -{ -public: - Player (boost::shared_ptr, boost::shared_ptr); - - void disable_video (); - void disable_audio (); - void disable_subtitles (); - void disable_video_sync (); - - bool pass (); - void set_progress (boost::shared_ptr); - bool seek (double); - bool seek_to_last (); - - double last_video_time () const; - -private: - void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s); - void process_audio (boost::shared_ptr); - void setup_decoders (); - - boost::shared_ptr _film; - boost::shared_ptr _playlist; - - bool _video; - bool _audio; - bool _subtitles; - - bool _have_setup_decoders; - boost::shared_ptr _ffmpeg_decoder; - bool _ffmpeg_decoder_done; - std::list > _imagemagick_decoders; - std::list >::iterator _imagemagick_decoder; - std::list > _sndfile_decoders; - - bool _video_sync; -}; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index ef3a0e8c1..6744e9193 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -34,7 +34,7 @@ #include "gain.h" #include "video_decoder.h" #include "audio_decoder.h" -#include "playlist.h" +#include "player.h" using std::string; using boost::shared_ptr; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index b08b9caf1..d413d33f3 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -28,7 +28,7 @@ #include "format.h" #include "log.h" #include "dcp_video_frame.h" -#include "playlist.h" +#include "player.h" #include "i18n.h" diff --git a/src/lib/wscript b/src/lib/wscript index f2bb678aa..32a2cde23 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -38,6 +38,7 @@ sources = """ log.cc lut.cc matcher.cc + player.cc playlist.cc scp_dcp_job.cc scaler.cc diff --git a/src/tools/servomatictest.cc b/src/tools/servomatictest.cc index d7e8bbb0e..d3222faa3 100644 --- a/src/tools/servomatictest.cc +++ b/src/tools/servomatictest.cc @@ -33,7 +33,7 @@ #include "scaler.h" #include "log.h" #include "video_decoder.h" -#include "playlist.h" +#include "player.h" using std::cout; using std::cerr; diff --git a/src/wx/film_editor.cc b/src/wx/film_editor.cc index 10cb41df0..ab1fe86ce 100644 --- a/src/wx/film_editor.cc +++ b/src/wx/film_editor.cc @@ -59,6 +59,7 @@ using std::list; using std::vector; using boost::shared_ptr; using boost::dynamic_pointer_cast; +using boost::lexical_cast; /** @param f Film to edit */ FilmEditor::FilmEditor (shared_ptr f, wxWindow* parent) @@ -332,7 +333,7 @@ FilmEditor::make_content_panel () _content = new wxListCtrl (_content_panel, wxID_ANY, wxDefaultPosition, wxSize (320, 160), wxLC_REPORT | wxLC_NO_HEADER | wxLC_SINGLE_SEL); s->Add (_content, 1, wxEXPAND | wxTOP | wxBOTTOM, 6); - _content->InsertColumn (0, ""); + _content->InsertColumn (0, wxT("")); _content->SetColumnWidth (0, 512); wxBoxSizer* b = new wxBoxSizer (wxVERTICAL); @@ -1078,7 +1079,7 @@ FilmEditor::ffmpeg_audio_stream_changed (wxCommandEvent &) vector a = _film->ffmpeg_audio_streams (); vector::iterator i = a.begin (); string const s = string_client_data (_ffmpeg_audio_stream->GetClientObject (_ffmpeg_audio_stream->GetSelection ())); - while (i != a.end() && i->id != s) { + while (i != a.end() && lexical_cast (i->id) != s) { ++i; } @@ -1097,7 +1098,7 @@ FilmEditor::ffmpeg_subtitle_stream_changed (wxCommandEvent &) vector a = _film->ffmpeg_subtitle_streams (); vector::iterator i = a.begin (); string const s = string_client_data (_ffmpeg_subtitle_stream->GetClientObject (_ffmpeg_subtitle_stream->GetSelection ())); - while (i != a.end() && i->id != s) { + while (i != a.end() && lexical_cast (i->id) != s) { ++i; } @@ -1270,7 +1271,7 @@ FilmEditor::setup_content_information () { int const s = _content->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); if (s == -1) { - _content_information->SetValue (""); + _content_information->SetValue (wxT ("")); return; } diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index 76cff3f65..f6d0f77dc 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -34,7 +34,7 @@ #include "lib/exceptions.h" #include "lib/examine_content_job.h" #include "lib/filter.h" -#include "lib/playlist.h" +#include "lib/player.h" #include "lib/video_content.h" #include "lib/ffmpeg_content.h" #include "film_viewer.h" -- cgit v1.2.3 From 164bf3eaae49f654d609c747850b3f564fa20102 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 11 Apr 2013 14:24:52 +0100 Subject: Try to fix lack of subs in the viewer after they are turned on. --- src/lib/player.cc | 2 +- src/lib/transcoder.cc | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/player.cc b/src/lib/player.cc index c66d091cf..92c2929ac 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -197,7 +197,7 @@ Player::setup_decoders () new FFmpegDecoder ( _film, fc, _video, _audio && _playlist->audio_from() == Playlist::AUDIO_FFMPEG, - _subtitles && _film->with_subtitles(), + _subtitles, _video_sync ) ); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 6744e9193..e0e127d33 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -56,6 +56,10 @@ Transcoder::Transcoder (shared_ptr f, shared_ptr j) _gain.reset (new Gain (f->log(), f->audio_gain())); } + if (!f->with_subtitles ()) { + _player->disable_subtitles (); + } + if (_matcher) { _player->connect_video (_matcher); _matcher->connect_video (_encoder); -- cgit v1.2.3 From 9303bb36391c2ce3c471dafffefbcbbaf3995be0 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 12 Apr 2013 20:29:17 +0100 Subject: Seems wrong to try to complete an encode if it has thrown an exception. --- src/lib/transcoder.cc | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index e0e127d33..2a8ce5044 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -79,19 +79,13 @@ void Transcoder::go () { _encoder->process_begin (); - try { - while (1) { - if (_player->pass ()) { - break; - } - _player->set_progress (_job); + while (1) { + if (_player->pass ()) { + break; } - - } catch (...) { - _encoder->process_end (); - throw; + _player->set_progress (_job); } - + if (_delay_line) { _delay_line->process_end (); } -- cgit v1.2.3 From 3f2365fcf3a1ffc50901eb2e4af246aa4c83e272 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Apr 2013 16:24:03 +0100 Subject: Repair very bad merge. Mysterious. --- src/lib/ab_transcoder.cc | 4 ++-- src/lib/audio_decoder.h | 2 +- src/lib/audio_sink.h | 7 +++++++ src/lib/audio_source.cc | 6 ++++++ src/lib/audio_source.h | 12 ++++++++++++ src/lib/combiner.cc | 8 ++++---- src/lib/combiner.h | 6 +++--- src/lib/delay_line.cc | 4 ++-- src/lib/delay_line.h | 4 ++-- src/lib/matcher.cc | 2 +- src/lib/matcher.h | 6 +++--- src/lib/processor.h | 17 +++++++++++++++++ src/lib/sndfile_decoder.cc | 5 +++-- src/lib/transcoder.cc | 9 --------- src/lib/video_decoder.h | 2 +- src/lib/video_sink.h | 12 ++++++++++++ src/lib/video_source.cc | 6 ++++++ src/lib/video_source.h | 23 +++++++++++++++++++++-- 18 files changed, 103 insertions(+), 32 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 7db13afcc..6eef397c2 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -70,8 +70,8 @@ ABTranscoder::ABTranscoder ( _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)); + _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); + _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); _combiner->connect_video (_delay_line); _delay_line->connect_video (_matcher); diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 9bef8e0e7..cfe94b528 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -31,7 +31,7 @@ /** @class AudioDecoder. * @brief Parent class for audio decoders. */ -class AudioDecoder : public AudioSource, public virtual Decoder +class AudioDecoder : public TimedAudioSource, public virtual Decoder { public: AudioDecoder (boost::shared_ptr, DecodeOptions); diff --git a/src/lib/audio_sink.h b/src/lib/audio_sink.h index 11d578a60..f34b24f88 100644 --- a/src/lib/audio_sink.h +++ b/src/lib/audio_sink.h @@ -27,4 +27,11 @@ public: virtual void process_audio (boost::shared_ptr) = 0; }; +class TimedAudioSink +{ +public: + /** Call with some audio data */ + virtual void process_audio (boost::shared_ptr, double t) = 0; +}; + #endif diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index 53b0dda15..bca3562cf 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -28,3 +28,9 @@ AudioSource::connect_audio (shared_ptr s) { Audio.connect (bind (&AudioSink::process_audio, s, _1)); } + +void +TimedAudioSource::connect_audio (shared_ptr s) +{ + Audio.connect (bind (&TimedAudioSink::process_audio, s, _1, _2)); +} diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index 5a1510d3c..3dc998cca 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -28,6 +28,7 @@ class AudioBuffers; class AudioSink; +class TimedAudioSink; /** A class that emits audio data */ class AudioSource @@ -39,4 +40,15 @@ public: void connect_audio (boost::shared_ptr); }; + +/** A class that emits audio data with timestamps */ +class TimedAudioSource +{ +public: + /** Emitted when some audio data is ready */ + boost::signals2::signal, double)> Audio; + + void connect_audio (boost::shared_ptr); +}; + #endif diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 12ce4a96e..006dd2697 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -23,7 +23,7 @@ using boost::shared_ptr; Combiner::Combiner (shared_ptr log) - : VideoProcessor (log) + : TimedVideoProcessor (log) { } @@ -33,7 +33,7 @@ Combiner::Combiner (shared_ptr log) * @param image Frame image. */ void -Combiner::process_video (shared_ptr image, bool, shared_ptr) +Combiner::process_video (shared_ptr image, bool, shared_ptr, double t) { _image = image; } @@ -43,7 +43,7 @@ Combiner::process_video (shared_ptr image, bool, shared_ptr) * @param sub Subtitle (which will be put onto the whole frame) */ void -Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub) +Combiner::process_video_b (shared_ptr image, bool, shared_ptr sub, double t) { /* Copy the right half of this image into our _image */ /* XXX: this should probably be in the Image class */ @@ -62,6 +62,6 @@ Combiner::process_video_b (shared_ptr image, bool, shared_ptr s } } - Video (_image, false, sub); + Video (_image, false, sub, t); _image.reset (); } diff --git a/src/lib/combiner.h b/src/lib/combiner.h index 68026eaff..a8f1fa804 100644 --- a/src/lib/combiner.h +++ b/src/lib/combiner.h @@ -28,13 +28,13 @@ * one image used for the left half of the screen and the other for * the right. */ -class Combiner : public VideoProcessor +class Combiner : public TimedVideoProcessor { public: Combiner (boost::shared_ptr log); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); - void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); + void process_video_b (boost::shared_ptr i, bool, boost::shared_ptr s, double); private: /** The image that we are currently working on */ diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc index c8e593a18..9e6baeba8 100644 --- a/src/lib/delay_line.cc +++ b/src/lib/delay_line.cc @@ -30,14 +30,14 @@ using boost::shared_ptr; /* @param seconds Delay in seconds, +ve to move audio later. */ DelayLine::DelayLine (shared_ptr log, double seconds) - : Processor (log) + : TimedAudioVideoProcessor (log) , _seconds (seconds) { } void -DelayLine::process_audio (shared_ptr data) +DelayLine::process_audio (shared_ptr data, double t) { if (_seconds > 0) { t += _seconds; diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h index 7a8b11c69..90f1dcfa7 100644 --- a/src/lib/delay_line.h +++ b/src/lib/delay_line.h @@ -20,8 +20,8 @@ #include #include "processor.h" -/** A delay line for audio */ -class DelayLine : public Processor, public TimedAudioSink, public TimedAudioSource, public TimedVideoSink, public TimedVideoSource +/** A delay line */ +class DelayLine : public TimedAudioVideoProcessor { public: DelayLine (boost::shared_ptr log, double); diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc index 69d12e2c4..34ddc86d6 100644 --- a/src/lib/matcher.cc +++ b/src/lib/matcher.cc @@ -29,7 +29,7 @@ using std::list; using boost::shared_ptr; Matcher::Matcher (shared_ptr log, int sample_rate, float frames_per_second) - : AudioVideoProcessor (log) + : Processor (log) , _sample_rate (sample_rate) , _frames_per_second (frames_per_second) , _video_frames (0) diff --git a/src/lib/matcher.h b/src/lib/matcher.h index 4ec0a3e96..f54aa4b6a 100644 --- a/src/lib/matcher.h +++ b/src/lib/matcher.h @@ -21,12 +21,12 @@ #include "processor.h" #include "ffmpeg_compatibility.h" -class Matcher : public AudioVideoProcessor +class Matcher : public Processor, public TimedAudioSink, public TimedVideoSink, public AudioSource, public VideoSource { public: Matcher (boost::shared_ptr log, int sample_rate, float frames_per_second); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); - void process_audio (boost::shared_ptr); + void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); + void process_audio (boost::shared_ptr, double); void process_end (); private: diff --git a/src/lib/processor.h b/src/lib/processor.h index 1ba396f2f..603239f8f 100644 --- a/src/lib/processor.h +++ b/src/lib/processor.h @@ -67,6 +67,15 @@ public: {} }; +class TimedAudioVideoProcessor : public Processor, public TimedVideoSource, public TimedVideoSink, public TimedAudioSource, public TimedAudioSink +{ +public: + TimedAudioVideoProcessor (boost::shared_ptr log) + : Processor (log) + {} +}; + + /** @class AudioProcessor * @brief A processor which handles just audio data. */ @@ -95,4 +104,12 @@ public: {} }; +class TimedVideoProcessor : public Processor, public TimedVideoSource, public TimedVideoSink +{ +public: + TimedVideoProcessor (boost::shared_ptr log) + : Processor (log) + {} +}; + #endif diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index 0e3e5e234..af59c049c 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -113,8 +113,8 @@ SndfileDecoder::pass () 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)); + sf_count_t done = 0; while (frames > 0) { sf_count_t const this_time = min (block, frames); for (size_t i = 0; i < sndfiles.size(); ++i) { @@ -126,7 +126,8 @@ SndfileDecoder::pass () } audio->set_frames (this_time); - Audio (audio); + Audio (audio, double(done) / _audio_stream->sample_rate()); + done += this_time; frames -= this_time; } diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 8046080de..23fb5b788 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -63,18 +63,9 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< _decoders.video->set_subtitle_stream (f->subtitle_stream ()); _decoders.audio->set_audio_stream (f->audio_stream ()); -<<<<<<< HEAD _decoders.video->connect_video (_delay_line); _delay_line->connect_video (_matcher); _matcher->connect_video (_encoder); -======= - if (_matcher) { - _decoders.video->connect_video (_matcher); - _matcher->connect_video (_encoder); - } else { - _decoders.video->connect_video (_encoder); - } ->>>>>>> master _decoders.audio->connect_audio (_delay_line); _delay_line->connect_audio (_matcher); diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index f8612dff2..6e4fd48c0 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -24,7 +24,7 @@ #include "stream.h" #include "decoder.h" -class VideoDecoder : public VideoSource, public virtual Decoder +class VideoDecoder : public TimedVideoSource, public virtual Decoder { public: VideoDecoder (boost::shared_ptr, DecodeOptions); diff --git a/src/lib/video_sink.h b/src/lib/video_sink.h index 7c128cf73..32c7f3b38 100644 --- a/src/lib/video_sink.h +++ b/src/lib/video_sink.h @@ -37,4 +37,16 @@ public: virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s) = 0; }; +class TimedVideoSink +{ +public: + /** Call with a frame of video. + * @param i Video frame image. + * @param same true if i is the same as last time we were called. + * @param s A subtitle that should be on this frame, or 0. + * @param t Source timestamp. + */ + virtual void process_video (boost::shared_ptr i, bool same, boost::shared_ptr s, double t) = 0; +}; + #endif diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index 56742e2b4..af6f941fd 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -28,3 +28,9 @@ VideoSource::connect_video (shared_ptr s) { Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); } + +void +TimedVideoSource::connect_video (shared_ptr s) +{ + Video.connect (bind (&TimedVideoSink::process_video, s, _1, _2, _3, _4)); +} diff --git a/src/lib/video_source.h b/src/lib/video_source.h index 893629160..705b0023a 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -29,11 +29,12 @@ #include "util.h" class VideoSink; +class TimedVideoSink; class Subtitle; class Image; -/** @class VideoSink - * @param A class that emits video data. +/** @class VideoSource + * @param A class that emits video data without timestamps. */ class VideoSource { @@ -49,4 +50,22 @@ public: void connect_video (boost::shared_ptr); }; +/** @class TimedVideoSource + * @param A class that emits video data with timestamps. + */ +class TimedVideoSource +{ +public: + + /** Emitted when a video frame is ready. + * First parameter is the video image. + * Second parameter is true if the image is the same as the last one that was emitted. + * Third parameter is either 0 or a subtitle that should be on this frame. + * Fourth parameter is the source timestamp of this frame. + */ + boost::signals2::signal, bool, boost::shared_ptr, double)> Video; + + void connect_video (boost::shared_ptr); +}; + #endif -- cgit v1.2.3 From 074e70083a115eaac2b593b1c42962ff7e0c3951 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 22 Apr 2013 13:33:20 +0100 Subject: Try to fix it. --- src/lib/transcoder.cc | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 23fb5b788..e00b2f1e0 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -55,21 +55,33 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< assert (_encoder); shared_ptr st = f->audio_stream(); - _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate())); + if (st) { + _matcher.reset (new Matcher (f->log(), st->sample_rate(), f->source_frame_rate())); + } _delay_line.reset (new DelayLine (f->log(), f->audio_delay() / 1000.0f)); _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 ()); - _decoders.audio->set_audio_stream (f->audio_stream ()); + if (f->audio_stream ()) { + _decoders.audio->set_audio_stream (f->audio_stream ()); + } _decoders.video->connect_video (_delay_line); - _delay_line->connect_video (_matcher); - _matcher->connect_video (_encoder); + if (_matcher) { + _delay_line->connect_video (_matcher); + _matcher->connect_video (_encoder); + } else { + _delay_line->Video.connect (bind (&Encoder::process_video, _encoder, _1, _2, _3)); + } _decoders.audio->connect_audio (_delay_line); - _delay_line->connect_audio (_matcher); - _matcher->connect_audio (_gain); + if (_matcher) { + _delay_line->connect_audio (_matcher); + _matcher->connect_audio (_gain); + } else { + _delay_line->Audio.connect (bind (&Encoder::process_audio, _encoder, _1)); + } _gain->connect_audio (_encoder); } @@ -108,7 +120,9 @@ Transcoder::go () } _delay_line->process_end (); - _matcher->process_end (); + if (_matcher) { + _matcher->process_end (); + } _gain->process_end (); _encoder->process_end (); } -- cgit v1.2.3 From 425ef773dbf91d2fecd8e2fbdc20becbfbda46f8 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 23 Apr 2013 16:17:20 +0100 Subject: Connect Trimmer clsas. --- src/lib/ab_transcoder.cc | 37 ++++++++++++++++++++++++++++++------- src/lib/ab_transcoder.h | 2 ++ src/lib/audio_source.cc | 6 ++++++ src/lib/audio_source.h | 1 + src/lib/transcoder.cc | 19 +++++++++++++++---- src/lib/transcoder.h | 2 ++ src/lib/video_source.cc | 8 ++++++++ src/lib/video_source.h | 1 + 8 files changed, 65 insertions(+), 11 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 6eef397c2..26643b50e 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -32,6 +32,7 @@ #include "delay_line.h" #include "gain.h" #include "combiner.h" +#include "trimmer.h" /** @file src/ab_transcoder.cc * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -61,26 +62,48 @@ ABTranscoder::ABTranscoder ( _db = decoder_factory (_film_b, o); shared_ptr st = _film_a->audio_stream(); - _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate())); + if (st) { + _matcher.reset (new Matcher (_film_a->log(), st->sample_rate(), _film_a->source_frame_rate())); + } _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_delay() / 1000.0f)); _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); + int const sr = st ? st->sample_rate() : 0; + int const trim_start = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_start() : 0; + int const trim_end = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_end() : 0; + _trimmer.reset (new Trimmer ( + _film_a->log(), trim_start, trim_end, _film_a->length().get(), + sr, _film_a->source_frame_rate(), _film_a->dcp_frame_rate() + )); + /* 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 ()); + if (_film_a->audio_stream ()) { + _da.audio->set_audio_stream (_film_a->audio_stream ()); + } _da.video->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); _db.video->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); _combiner->connect_video (_delay_line); - _delay_line->connect_video (_matcher); - _matcher->connect_video (_encoder); + if (_matcher) { + _delay_line->connect_video (_matcher); + _matcher->connect_video (_trimmer); + } else { + _delay_line->connect_video (_trimmer); + } + _trimmer->connect_video (_encoder); _da.audio->connect_audio (_delay_line); - _delay_line->connect_audio (_matcher); - _matcher->connect_audio (_gain); - _gain->connect_audio (_encoder); + if (_matcher) { + _delay_line->connect_audio (_matcher); + _matcher->connect_audio (_gain); + } else { + _delay_line->connect_audio (_gain); + } + _gain->connect_audio (_trimmer); + _trimmer->connect_audio (_encoder); } void diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 58a08af04..4f1b14e48 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -39,6 +39,7 @@ class Matcher; class DelayLine; class Gain; class Combiner; +class Trimmer; /** @class ABTranscoder * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -68,5 +69,6 @@ private: boost::shared_ptr _matcher; boost::shared_ptr _delay_line; boost::shared_ptr _gain; + boost::shared_ptr _trimmer; boost::shared_ptr _image; }; diff --git a/src/lib/audio_source.cc b/src/lib/audio_source.cc index bca3562cf..d77e89367 100644 --- a/src/lib/audio_source.cc +++ b/src/lib/audio_source.cc @@ -34,3 +34,9 @@ TimedAudioSource::connect_audio (shared_ptr s) { Audio.connect (bind (&TimedAudioSink::process_audio, s, _1, _2)); } + +void +TimedAudioSource::connect_audio (shared_ptr s) +{ + Audio.connect (bind (&AudioSink::process_audio, s, _1)); +} diff --git a/src/lib/audio_source.h b/src/lib/audio_source.h index 3dc998cca..e255d566d 100644 --- a/src/lib/audio_source.h +++ b/src/lib/audio_source.h @@ -48,6 +48,7 @@ public: /** Emitted when some audio data is ready */ boost::signals2::signal, double)> Audio; + void connect_audio (boost::shared_ptr); void connect_audio (boost::shared_ptr); }; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index e00b2f1e0..a10789e11 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 "trimmer.h" using std::string; using boost::shared_ptr; @@ -61,6 +62,14 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< _delay_line.reset (new DelayLine (f->log(), f->audio_delay() / 1000.0f)); _gain.reset (new Gain (f->log(), f->audio_gain())); + int const sr = st ? st->sample_rate() : 0; + int const trim_start = f->trim_type() == Film::ENCODE ? f->trim_start() : 0; + int const trim_end = f->trim_type() == Film::ENCODE ? f->trim_end() : 0; + _trimmer.reset (new Trimmer ( + f->log(), trim_start, trim_end, f->length().get(), + sr, f->source_frame_rate(), f->dcp_frame_rate() + )); + /* Set up the decoder to use the film's set streams */ _decoders.video->set_subtitle_stream (f->subtitle_stream ()); if (f->audio_stream ()) { @@ -70,19 +79,21 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< _decoders.video->connect_video (_delay_line); if (_matcher) { _delay_line->connect_video (_matcher); - _matcher->connect_video (_encoder); + _matcher->connect_video (_trimmer); } else { - _delay_line->Video.connect (bind (&Encoder::process_video, _encoder, _1, _2, _3)); + _delay_line->connect_video (_trimmer); } + _trimmer->connect_video (_encoder); _decoders.audio->connect_audio (_delay_line); if (_matcher) { _delay_line->connect_audio (_matcher); _matcher->connect_audio (_gain); } else { - _delay_line->Audio.connect (bind (&Encoder::process_audio, _encoder, _1)); + _delay_line->connect_audio (_gain); } - _gain->connect_audio (_encoder); + _gain->connect_audio (_trimmer); + _trimmer->connect_audio (_encoder); } /** Run the decoder, passing its output to the encoder, until the decoder diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index b0c263d07..f5b8ae6e3 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -35,6 +35,7 @@ class Gain; class VideoDecoder; class AudioDecoder; class DelayLine; +class Trimmer; /** @class Transcoder * @brief A class which takes a Film and some Options, then uses those to transcode the film. @@ -68,4 +69,5 @@ protected: boost::shared_ptr _matcher; boost::shared_ptr _delay_line; boost::shared_ptr _gain; + boost::shared_ptr _trimmer; }; diff --git a/src/lib/video_source.cc b/src/lib/video_source.cc index af6f941fd..539243402 100644 --- a/src/lib/video_source.cc +++ b/src/lib/video_source.cc @@ -34,3 +34,11 @@ TimedVideoSource::connect_video (shared_ptr s) { Video.connect (bind (&TimedVideoSink::process_video, s, _1, _2, _3, _4)); } + +void +TimedVideoSource::connect_video (shared_ptr s) +{ + Video.connect (bind (&VideoSink::process_video, s, _1, _2, _3)); +} + + diff --git a/src/lib/video_source.h b/src/lib/video_source.h index 705b0023a..e4a8ab058 100644 --- a/src/lib/video_source.h +++ b/src/lib/video_source.h @@ -65,6 +65,7 @@ public: */ boost::signals2::signal, bool, boost::shared_ptr, double)> Video; + void connect_video (boost::shared_ptr); void connect_video (boost::shared_ptr); }; -- cgit v1.2.3 From 6aa1a3e3808319d26659d3008a83f79f695fb6b2 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 24 Apr 2013 16:28:16 +0100 Subject: Try to fix crash with still-image DCPs. --- src/lib/transcoder.cc | 2 +- src/lib/trimmer.cc | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index a10789e11..4d3f29e83 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -66,7 +66,7 @@ Transcoder::Transcoder (shared_ptr f, DecodeOptions o, Job* j, shared_ptr< int const trim_start = f->trim_type() == Film::ENCODE ? f->trim_start() : 0; int const trim_end = f->trim_type() == Film::ENCODE ? f->trim_end() : 0; _trimmer.reset (new Trimmer ( - f->log(), trim_start, trim_end, f->length().get(), + f->log(), trim_start, trim_end, f->length().get_value_or(0), sr, f->source_frame_rate(), f->dcp_frame_rate() )); diff --git a/src/lib/trimmer.cc b/src/lib/trimmer.cc index 0746b7410..b7afc9299 100644 --- a/src/lib/trimmer.cc +++ b/src/lib/trimmer.cc @@ -28,7 +28,8 @@ using boost::shared_ptr; Trimmer::Trimmer ( shared_ptr log, int video_trim_start, - int video_trim_end, int video_length, + int video_trim_end, + int video_length, int audio_sample_rate, float frames_per_second, int dcp_frames_per_second -- cgit v1.2.3 From 7b2ec1dd69951649f2c912fcf90b22913b1f6c3a Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 25 Apr 2013 13:44:02 +0100 Subject: Remove Image::clone in favour of a copy constructor for SimpleImage; clean up A/B transcoder slightly; fix combiner if image strides differ; try to fix problems when destroying Encoders; fix SimpleImage copy constructor to cope with aligned images; don't call encoder::process_end if the encode throws an exception. --- src/lib/ab_transcoder.cc | 14 +++++--------- src/lib/combiner.cc | 7 +++---- src/lib/encoder.cc | 4 +++- src/lib/image.cc | 34 +++++++++++++++++++++++++++------- src/lib/image.h | 7 +------ src/lib/transcoder.cc | 37 ++++++++++++++++--------------------- 6 files changed, 55 insertions(+), 48 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 26643b50e..d8f13dae4 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -122,25 +122,21 @@ ABTranscoder::go () } else { done[2] = true; } - + if (_job) { _da.video->set_progress (_job); } - + if (done[0] && done[1] && done[2]) { break; } } - - if (_delay_line) { - _delay_line->process_end (); - } + + _delay_line->process_end (); if (_matcher) { _matcher->process_end (); } - if (_gain) { - _gain->process_end (); - } + _gain->process_end (); _encoder->process_end (); } diff --git a/src/lib/combiner.cc b/src/lib/combiner.cc index 250528aeb..367cefa7f 100644 --- a/src/lib/combiner.cc +++ b/src/lib/combiner.cc @@ -35,7 +35,7 @@ Combiner::Combiner (shared_ptr log) void Combiner::process_video (shared_ptr image, bool, shared_ptr, double) { - _image = image->clone (); + _image.reset (new SimpleImage (image)); } /** Process video for the right half of the frame. @@ -50,15 +50,14 @@ Combiner::process_video_b (shared_ptr image, bool, shared_ptrcomponents(); ++i) { int const line_size = image->line_size()[i]; int const half_line_size = line_size / 2; - int const stride = image->stride()[i]; uint8_t* p = _image->data()[i]; uint8_t* q = image->data()[i]; for (int j = 0; j < image->lines (i); ++j) { memcpy (p + half_line_size, q + half_line_size, half_line_size); - p += stride; - q += stride; + p += _image->stride()[i]; + q += image->stride()[i]; } } diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 7a1eea069..cff9899ac 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -333,7 +333,9 @@ Encoder::terminate_threads () lock.unlock (); for (list::iterator i = _threads.begin(); i != _threads.end(); ++i) { - (*i)->join (); + if ((*i)->joinable ()) { + (*i)->join (); + } delete *i; } } diff --git a/src/lib/image.cc b/src/lib/image.cc index 9bcbb87ab..1be41fecf 100644 --- a/src/lib/image.cc +++ b/src/lib/image.cc @@ -509,7 +509,33 @@ SimpleImage::SimpleImage (SimpleImage const & other) allocate (); for (int i = 0; i < components(); ++i) { - memcpy (_data[i], other._data[i], _line_size[i] * lines(i)); + uint8_t* p = _data[i]; + uint8_t* q = other._data[i]; + for (int j = 0; j < lines(i); ++j) { + memcpy (p, q, _line_size[i]); + p += stride()[i]; + q += other.stride()[i]; + } + } +} + +SimpleImage::SimpleImage (shared_ptr other) + : Image (*other.get()) +{ + _size = other->size (); + _aligned = true; + + allocate (); + + for (int i = 0; i < components(); ++i) { + assert(line_size()[i] == other->line_size()[i]); + uint8_t* p = _data[i]; + uint8_t* q = other->data()[i]; + for (int j = 0; j < lines(i); ++j) { + memcpy (p, q, line_size()[i]); + p += stride()[i]; + q += other->stride()[i]; + } } } @@ -583,12 +609,6 @@ SimpleImage::aligned () const return _aligned; } -shared_ptr -SimpleImage::clone () const -{ - return shared_ptr (new SimpleImage (*this)); -} - FilterBufferImage::FilterBufferImage (AVPixelFormat p, AVFilterBufferRef* b) : Image (p) , _buffer (b) diff --git a/src/lib/image.h b/src/lib/image.h index 31035d272..62961a92e 100644 --- a/src/lib/image.h +++ b/src/lib/image.h @@ -70,8 +70,6 @@ public: virtual bool aligned () const = 0; - virtual boost::shared_ptr clone () const = 0; - int components () const; int lines (int) const; @@ -120,9 +118,6 @@ private: /* Not allowed */ FilterBufferImage (FilterBufferImage const &); FilterBufferImage& operator= (FilterBufferImage const &); - boost::shared_ptr clone () const { - assert (false); - } AVFilterBufferRef* _buffer; int* _line_size; @@ -136,6 +131,7 @@ class SimpleImage : public Image public: SimpleImage (AVPixelFormat, libdcp::Size, bool); SimpleImage (SimpleImage const &); + SimpleImage (boost::shared_ptr); SimpleImage& operator= (SimpleImage const &); ~SimpleImage (); @@ -144,7 +140,6 @@ public: int * stride () const; libdcp::Size size () const; bool aligned () const; - boost::shared_ptr clone () const; protected: void allocate (); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 4d3f29e83..faafcaf8b 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -103,31 +103,26 @@ void Transcoder::go () { _encoder->process_begin (); - try { - bool done[2] = { false, false }; - - while (1) { - if (!done[0]) { - done[0] = _decoders.video->pass (); - if (_job) { - _decoders.video->set_progress (_job); - } - } - - if (!done[1] && _decoders.audio && dynamic_pointer_cast (_decoders.audio) != dynamic_pointer_cast (_decoders.video)) { - done[1] = _decoders.audio->pass (); - } else { - done[1] = true; - } - if (done[0] && done[1]) { - break; + bool done[2] = { false, false }; + + while (1) { + if (!done[0]) { + done[0] = _decoders.video->pass (); + if (_job) { + _decoders.video->set_progress (_job); } } - } catch (...) { - _encoder->process_end (); - throw; + if (!done[1] && _decoders.audio && dynamic_pointer_cast (_decoders.audio) != dynamic_pointer_cast (_decoders.video)) { + done[1] = _decoders.audio->pass (); + } else { + done[1] = true; + } + + if (done[0] && done[1]) { + break; + } } _delay_line->process_end (); -- cgit v1.2.3 From fd040c2bd27fde35424a384174ecb56c643764cd Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 8 May 2013 20:37:53 +0100 Subject: Some tidying up. Do encode progress in the writer to improve progress bar movement with still-image DCPs (#130). --- src/lib/ab_transcoder.cc | 41 +++++++++++++---------------------------- src/lib/ab_transcoder.h | 2 -- src/lib/encoder.cc | 5 +++-- src/lib/encoder.h | 8 +++++--- src/lib/player.cc | 12 ------------ src/lib/player.h | 1 - src/lib/transcoder.cc | 11 ++++------- src/lib/transcoder.h | 4 +++- src/lib/writer.cc | 8 +++++++- src/lib/writer.h | 4 +++- 10 files changed, 38 insertions(+), 58 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index 2e0d41e7d..f75491dce 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -47,27 +47,25 @@ using boost::dynamic_pointer_cast; * @param e Encoder to use. */ -ABTranscoder::ABTranscoder (shared_ptr a, shared_ptr b, shared_ptr j) - : _film_a (a) - , _film_b (b) - , _player_a (_film_a->player ()) - , _player_b (_film_b->player ()) +ABTranscoder::ABTranscoder (shared_ptr film_a, shared_ptr film_b, shared_ptr j) + : _player_a (film_a->player ()) + , _player_b (film_b->player ()) , _job (j) - , _encoder (new Encoder (_film_a)) - , _combiner (new Combiner (a->log())) + , _encoder (new Encoder (film_a, j)) + , _combiner (new Combiner (film_a->log())) { - _matcher.reset (new Matcher (_film_a->log(), _film_a->audio_frame_rate(), _film_a->video_frame_rate())); - _delay_line.reset (new DelayLine (_film_a->log(), _film_a->audio_delay() * _film_a->audio_frame_rate() / 1000)); - _gain.reset (new Gain (_film_a->log(), _film_a->audio_gain())); + _matcher.reset (new Matcher (film_a->log(), film_a->audio_frame_rate(), film_a->video_frame_rate())); + _delay_line.reset (new DelayLine (film_a->log(), film_a->audio_delay() * film_a->audio_frame_rate() / 1000)); + _gain.reset (new Gain (film_a->log(), film_a->audio_gain())); _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); - int const trim_start = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_start() : 0; - int const trim_end = _film_a->trim_type() == Film::ENCODE ? _film_a->trim_end() : 0; + int const trim_start = film_a->trim_type() == Film::ENCODE ? film_a->trim_start() : 0; + int const trim_end = film_a->trim_type() == Film::ENCODE ? film_a->trim_end() : 0; _trimmer.reset (new Trimmer ( - _film_a->log(), trim_start, trim_end, _film_a->content_length(), - _film_a->audio_frame_rate(), _film_a->video_frame_rate(), _film_a->dcp_frame_rate() + film_a->log(), trim_start, trim_end, film_a->content_length(), + film_a->audio_frame_rate(), film_a->video_frame_rate(), film_a->dcp_frame_rate() )); @@ -88,20 +86,7 @@ ABTranscoder::go () { _encoder->process_begin (); - bool done[2] = { false, false }; - - while (1) { - done[0] = _player_a->pass (); - done[1] = _player_b->pass (); - - if (_job) { - _player_a->set_progress (_job); - } - - if (done[0] && done[1]) { - break; - } - } + while (!_player_a->pass () || !_player_b->pass ()) {} _delay_line->process_end (); _matcher->process_end (); diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 1fef66b88..134bce3e4 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -54,8 +54,6 @@ public: void go (); private: - boost::shared_ptr _film_a; - boost::shared_ptr _film_b; boost::shared_ptr _player_a; boost::shared_ptr _player_b; boost::shared_ptr _job; diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index c1d1041ae..d25e0d0f8 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -55,8 +55,9 @@ using boost::optional; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f) +Encoder::Encoder (shared_ptr f, shared_ptr j) : _film (f) + , _job (j) , _video_frames_in (0) , _video_frames_out (0) #ifdef HAVE_SWRESAMPLE @@ -127,7 +128,7 @@ Encoder::process_begin () } } - _writer.reset (new Writer (_film)); + _writer.reset (new Writer (_film, _job)); } diff --git a/src/lib/encoder.h b/src/lib/encoder.h index f95d42661..6cf5540c5 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -51,6 +51,7 @@ class ServerDescription; class DCPVideoFrame; class EncodedData; class Writer; +class Job; /** @class Encoder * @brief Encoder to J2K and WAV for DCP. @@ -62,11 +63,11 @@ class Writer; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f); + Encoder (boost::shared_ptr f, boost::shared_ptr); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ - virtual void process_begin (); + void process_begin (); /** Call with a frame of video. * @param i Video frame image. @@ -79,7 +80,7 @@ public: void process_audio (boost::shared_ptr); /** Called when a processing run has finished */ - virtual void process_end (); + void process_end (); float current_encoding_rate () const; int video_frames_out () const; @@ -93,6 +94,7 @@ private: /** Film that we are encoding */ boost::shared_ptr _film; + boost::shared_ptr _job; /** Mutex for _time_history and _last_frame */ mutable boost::mutex _history_mutex; diff --git a/src/lib/player.cc b/src/lib/player.cc index 68a962cdd..95036cfe0 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -121,18 +121,6 @@ Player::pass () return done; } -void -Player::set_progress (shared_ptr job) -{ - /* Assume progress can be divined from how far through the video we are */ - - if (_video_decoder >= _video_decoders.size() || !_playlist->video_length()) { - return; - } - - job->set_progress ((_video_start[_video_decoder] + _video_decoders[_video_decoder]->video_frame()) / _playlist->video_length ()); -} - void Player::process_video (shared_ptr i, bool same, shared_ptr s, double t) { diff --git a/src/lib/player.h b/src/lib/player.h index 20b83bfdb..b6fb41f6e 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -49,7 +49,6 @@ public: void disable_subtitles (); bool pass (); - void set_progress (boost::shared_ptr); bool seek (double); void seek_back (); void seek_forward (); diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index 2e33931bd..f8fe0c8d5 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -36,6 +36,7 @@ #include "audio_decoder.h" #include "player.h" #include "trimmer.h" +#include "job.h" using std::string; using boost::shared_ptr; @@ -49,7 +50,7 @@ using boost::dynamic_pointer_cast; Transcoder::Transcoder (shared_ptr f, shared_ptr j) : _job (j) , _player (f->player ()) - , _encoder (new Encoder (f)) + , _encoder (new Encoder (f, j)) { _matcher.reset (new Matcher (f->log(), f->audio_frame_rate(), f->video_frame_rate())); _delay_line.reset (new DelayLine (f->log(), f->audio_delay() * f->audio_frame_rate() / 1000)); @@ -82,13 +83,9 @@ void Transcoder::go () { _encoder->process_begin (); - while (1) { - if (_player->pass ()) { - break; - } - _player->set_progress (_job); - } + while (!_player->pass ()) {} + _delay_line->process_end (); if (_matcher) { _matcher->process_end (); diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 97ecaabfc..48b453fe4 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -17,6 +17,8 @@ */ +#include "types.h" + /** @file src/transcoder.h * * A decoder is selected according to the content type, and the encoder can be specified @@ -51,7 +53,7 @@ public: float current_encoding_rate () const; int video_frames_out () const; -protected: +private: /** A Job that is running this Transcoder, or 0 */ boost::shared_ptr _job; boost::shared_ptr _player; diff --git a/src/lib/writer.cc b/src/lib/writer.cc index b545848cb..c7d2cf8b4 100644 --- a/src/lib/writer.cc +++ b/src/lib/writer.cc @@ -34,6 +34,7 @@ #include "player.h" #include "audio_mapping.h" #include "config.h" +#include "job.h" #include "i18n.h" @@ -47,8 +48,9 @@ using boost::shared_ptr; int const Writer::_maximum_frames_in_memory = 8; -Writer::Writer (shared_ptr f) +Writer::Writer (shared_ptr f, shared_ptr j) : _film (f) + , _job (j) , _first_nonexistant_frame (0) , _thread (0) , _finish (false) @@ -202,6 +204,10 @@ try } } lock.lock (); + + if (_film->video_length ()) { + _job->set_progress (float(_full_written + _fake_written + _repeat_written) / _film->video_length()); + } ++_last_written_frame; } diff --git a/src/lib/writer.h b/src/lib/writer.h index beb16c7b9..62714edf3 100644 --- a/src/lib/writer.h +++ b/src/lib/writer.h @@ -26,6 +26,7 @@ class Film; class EncodedData; class AudioBuffers; +class Job; namespace libdcp { class MonoPictureAsset; @@ -63,7 +64,7 @@ bool operator== (QueueItem const & a, QueueItem const & b); class Writer : public ExceptionStore { public: - Writer (boost::shared_ptr); + Writer (boost::shared_ptr, boost::shared_ptr); bool can_fake_write (int) const; @@ -80,6 +81,7 @@ private: /** our Film */ boost::shared_ptr _film; + boost::shared_ptr _job; /** the first frame index that does not already exist in our MXF */ int _first_nonexistant_frame; -- cgit v1.2.3 From 540aac0bc5ca6cbf393c650e97236a9677124a30 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Fri, 10 May 2013 21:28:26 +0100 Subject: Remove gain/delay_line/matcher/trimmer. --- src/lib/ab_transcoder.cc | 35 +------- src/lib/ab_transcoder.h | 8 -- src/lib/delay_line.cc | 57 ------------- src/lib/delay_line.h | 34 -------- src/lib/gain.cc | 45 ---------- src/lib/gain.h | 31 ------- src/lib/matcher.cc | 213 ----------------------------------------------- src/lib/matcher.h | 63 -------------- src/lib/transcoder.cc | 34 +------- src/lib/transcoder.h | 8 -- src/lib/trimmer.cc | 115 ------------------------- src/lib/trimmer.h | 40 --------- src/lib/wscript | 4 - test/test.cc | 75 ----------------- 14 files changed, 4 insertions(+), 758 deletions(-) delete mode 100644 src/lib/delay_line.cc delete mode 100644 src/lib/delay_line.h delete mode 100644 src/lib/gain.cc delete mode 100644 src/lib/gain.h delete mode 100644 src/lib/matcher.cc delete mode 100644 src/lib/matcher.h delete mode 100644 src/lib/trimmer.cc delete mode 100644 src/lib/trimmer.h (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ab_transcoder.cc b/src/lib/ab_transcoder.cc index f75491dce..91c4665a7 100644 --- a/src/lib/ab_transcoder.cc +++ b/src/lib/ab_transcoder.cc @@ -25,11 +25,7 @@ #include "job.h" #include "image.h" #include "player.h" -#include "matcher.h" -#include "delay_line.h" -#include "gain.h" #include "combiner.h" -#include "trimmer.h" /** @file src/ab_transcoder.cc * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -54,44 +50,17 @@ ABTranscoder::ABTranscoder (shared_ptr film_a, shared_ptr film_b, sh , _encoder (new Encoder (film_a, j)) , _combiner (new Combiner (film_a->log())) { - _matcher.reset (new Matcher (film_a->log(), film_a->audio_frame_rate(), film_a->video_frame_rate())); - _delay_line.reset (new DelayLine (film_a->log(), film_a->audio_delay() * film_a->audio_frame_rate() / 1000)); - _gain.reset (new Gain (film_a->log(), film_a->audio_gain())); - _player_a->Video.connect (bind (&Combiner::process_video, _combiner, _1, _2, _3, _4)); _player_b->Video.connect (bind (&Combiner::process_video_b, _combiner, _1, _2, _3, _4)); - int const trim_start = film_a->trim_type() == Film::ENCODE ? film_a->trim_start() : 0; - int const trim_end = film_a->trim_type() == Film::ENCODE ? film_a->trim_end() : 0; - _trimmer.reset (new Trimmer ( - film_a->log(), trim_start, trim_end, film_a->content_length(), - film_a->audio_frame_rate(), film_a->video_frame_rate(), film_a->dcp_frame_rate() - )); - - - _combiner->connect_video (_delay_line); - _delay_line->connect_video (_matcher); - _matcher->connect_video (_trimmer); - _trimmer->connect_video (_encoder); - - _player_a->connect_audio (_delay_line); - _delay_line->connect_audio (_matcher); - _matcher->connect_audio (_gain); - _gain->connect_audio (_trimmer); - _trimmer->connect_audio (_encoder); + _combiner->connect_video (_encoder); + _player_a->connect_audio (_encoder); } void ABTranscoder::go () { _encoder->process_begin (); - while (!_player_a->pass () || !_player_b->pass ()) {} - - _delay_line->process_end (); - _matcher->process_end (); - _gain->process_end (); - _trimmer->process_end (); _encoder->process_end (); } - diff --git a/src/lib/ab_transcoder.h b/src/lib/ab_transcoder.h index 134bce3e4..54d7ed0be 100644 --- a/src/lib/ab_transcoder.h +++ b/src/lib/ab_transcoder.h @@ -31,12 +31,8 @@ class Encoder; class Image; class Log; class Film; -class Matcher; -class DelayLine; -class Gain; class Combiner; class Player; -class Trimmer; /** @class ABTranscoder * @brief A transcoder which uses one Film for the left half of the screen, and a different one @@ -59,9 +55,5 @@ private: boost::shared_ptr _job; boost::shared_ptr _encoder; boost::shared_ptr _combiner; - boost::shared_ptr _matcher; - boost::shared_ptr _delay_line; - boost::shared_ptr _gain; - boost::shared_ptr _trimmer; boost::shared_ptr _image; }; diff --git a/src/lib/delay_line.cc b/src/lib/delay_line.cc deleted file mode 100644 index b0180800a..000000000 --- a/src/lib/delay_line.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (C) 2012 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include "delay_line.h" -#include "util.h" - -using std::min; -using boost::shared_ptr; - -/* @param seconds Delay in seconds, +ve to move audio later. - */ -DelayLine::DelayLine (shared_ptr log, double seconds) - : TimedAudioVideoProcessor (log) - , _seconds (seconds) -{ - -} - -void -DelayLine::process_audio (shared_ptr data, double t) -{ - if (_seconds > 0) { - t += _seconds; - } - - Audio (data, t); -} - -void -DelayLine::process_video (shared_ptr image, bool same, boost::shared_ptr sub, double t) -{ - if (_seconds < 0) { - t += _seconds; - } - - Video (image, same, sub, t); -} diff --git a/src/lib/delay_line.h b/src/lib/delay_line.h deleted file mode 100644 index 781dce88a..000000000 --- a/src/lib/delay_line.h +++ /dev/null @@ -1,34 +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 "processor.h" - -/** A delay line */ -class DelayLine : public TimedAudioVideoProcessor -{ -public: - DelayLine (boost::shared_ptr log, double); - - void process_video (boost::shared_ptr, bool, boost::shared_ptr, double); - void process_audio (boost::shared_ptr, double); - -private: - double _seconds; -}; diff --git a/src/lib/gain.cc b/src/lib/gain.cc deleted file mode 100644 index ccd779d71..000000000 --- a/src/lib/gain.cc +++ /dev/null @@ -1,45 +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 "gain.h" - -using boost::shared_ptr; - -/** @param gain gain in dB */ -Gain::Gain (shared_ptr log, float gain) - : AudioProcessor (log) - , _gain (gain) -{ - -} - -void -Gain::process_audio (shared_ptr b) -{ - if (_gain != 0) { - float const linear_gain = pow (10, _gain / 20); - for (int i = 0; i < b->channels(); ++i) { - for (int j = 0; j < b->frames(); ++j) { - b->data(i)[j] *= linear_gain; - } - } - } - - Audio (b); -} diff --git a/src/lib/gain.h b/src/lib/gain.h deleted file mode 100644 index 61fef5e85..000000000 --- a/src/lib/gain.h +++ /dev/null @@ -1,31 +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 "processor.h" - -class Gain : public AudioProcessor -{ -public: - Gain (boost::shared_ptr log, float gain); - - void process_audio (boost::shared_ptr); - -private: - float _gain; -}; diff --git a/src/lib/matcher.cc b/src/lib/matcher.cc deleted file mode 100644 index c56a56301..000000000 --- a/src/lib/matcher.cc +++ /dev/null @@ -1,213 +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 "matcher.h" -#include "image.h" -#include "log.h" - -#include "i18n.h" - -using std::min; -using std::cout; -using std::list; -using boost::shared_ptr; - -Matcher::Matcher (shared_ptr log, int sample_rate, float frames_per_second) - : Processor (log) - , _sample_rate (sample_rate) - , _frames_per_second (frames_per_second) - , _video_frames (0) - , _audio_frames (0) - , _had_first_video (false) - , _had_first_audio (false) -{ - -} - -void -Matcher::process_video (shared_ptr image, bool same, boost::shared_ptr sub, double t) -{ - _pixel_format = image->pixel_format (); - _size = image->size (); - - _log->log(String::compose("Matcher video @ %1 [audio=%2, video=%3, pending_audio=%4]", t, _audio_frames, _video_frames, _pending_audio.size())); - - if (!_first_input) { - _first_input = t; - } - - bool const this_is_first_video = !_had_first_video; - _had_first_video = true; - - if (this_is_first_video && _had_first_audio) { - /* First video since we got audio */ - fix_start (t); - } - - /* Video before audio is fine, since we can make up an arbitrary difference - with audio samples (contrasting with video which is quantised to frames) - */ - - /* Difference between where this video is and where it should be */ - double const delta = t - _first_input.get() - _video_frames / _frames_per_second; - double const one_frame = 1 / _frames_per_second; - - if (delta > one_frame) { - /* Insert frames to make up the difference */ - int const extra = rint (delta / one_frame); - for (int i = 0; i < extra; ++i) { - repeat_last_video (); - _log->log (String::compose ("Extra video frame inserted at %1s", _video_frames / _frames_per_second)); - } - } - - if (delta > -one_frame) { - Video (image, same, sub); - ++_video_frames; - } else { - /* We are omitting a frame to keep things right */ - _log->log (String::compose ("Frame removed at %1s", t)); - } - - _last_image = image; - _last_subtitle = sub; -} - -void -Matcher::process_audio (shared_ptr b, double t) -{ - _channels = b->channels (); - - _log->log (String::compose ( - "Matcher audio (%1 frames) @ %2 [video=%3, audio=%4, pending_audio=%5]", - b->frames(), t, _video_frames, _audio_frames, _pending_audio.size() - ) - ); - - if (!_first_input) { - _first_input = t; - } - - bool const this_is_first_audio = _had_first_audio; - _had_first_audio = true; - - if (!_had_first_video) { - /* No video yet; we must postpone these data until we have some */ - _pending_audio.push_back (AudioRecord (b, t)); - } else if (this_is_first_audio && !_had_first_video) { - /* First audio since we got video */ - _pending_audio.push_back (AudioRecord (b, t)); - fix_start (_first_input.get ()); - } else { - /* Normal running. We assume audio time stamps are consecutive */ - Audio (b); - _audio_frames += b->frames (); - } -} - -void -Matcher::process_end () -{ - if (_audio_frames == 0 || !_pixel_format || !_size || !_channels) { - /* We won't do anything */ - return; - } - - _log->log (String::compose ("Matcher has seen %1 video frames (which equals %2 audio frames) and %3 audio frames", - _video_frames, video_frames_to_audio_frames (_video_frames, _sample_rate, _frames_per_second), _audio_frames)); - - match ((double (_audio_frames) / _sample_rate) - (double (_video_frames) / _frames_per_second)); -} - -void -Matcher::fix_start (double first_video) -{ - assert (!_pending_audio.empty ()); - - _log->log (String::compose ("Fixing start; video at %1, audio at %2", first_video, _pending_audio.front().time)); - - match (first_video - _pending_audio.front().time); - - for (list::iterator i = _pending_audio.begin(); i != _pending_audio.end(); ++i) { - process_audio (i->audio, i->time); - } - - _pending_audio.clear (); -} - -void -Matcher::match (double extra_video_needed) -{ - _log->log (String::compose ("Match %1", extra_video_needed)); - - if (extra_video_needed > 0) { - - /* Emit black video frames */ - - int const black_video_frames = ceil (extra_video_needed * _frames_per_second); - - _log->log (String::compose (N_("Emitting %1 frames of black video"), black_video_frames)); - - shared_ptr black (new SimpleImage (_pixel_format.get(), _size.get(), true)); - black->make_black (); - for (int i = 0; i < black_video_frames; ++i) { - Video (black, i != 0, shared_ptr()); - ++_video_frames; - } - - extra_video_needed -= black_video_frames / _frames_per_second; - } - - if (extra_video_needed < 0) { - - /* Emit silence */ - - int64_t to_do = -extra_video_needed * _sample_rate; - _log->log (String::compose (N_("Emitting %1 frames of silence"), to_do)); - - /* Do things in half second blocks as I think there may be limits - to what FFmpeg (and in particular the resampler) can cope with. - */ - int64_t const block = _sample_rate / 2; - shared_ptr b (new AudioBuffers (_channels.get(), block)); - b->make_silent (); - - while (to_do > 0) { - int64_t const this_time = min (to_do, block); - b->set_frames (this_time); - Audio (b); - _audio_frames += b->frames (); - to_do -= this_time; - } - } -} - -void -Matcher::repeat_last_video () -{ - if (!_last_image) { - shared_ptr im (new SimpleImage (_pixel_format.get(), _size.get(), true)); - im->make_black (); - _last_image = im; - } - - Video (_last_image, true, _last_subtitle); - ++_video_frames; -} - diff --git a/src/lib/matcher.h b/src/lib/matcher.h deleted file mode 100644 index 41aa373a4..000000000 --- a/src/lib/matcher.h +++ /dev/null @@ -1,63 +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 "processor.h" -#include "ffmpeg_compatibility.h" - -class Matcher : public Processor, public TimedAudioSink, public TimedVideoSink, public AudioSource, public VideoSource -{ -public: - Matcher (boost::shared_ptr log, int sample_rate, float frames_per_second); - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s, double); - void process_audio (boost::shared_ptr, double); - void process_end (); - -private: - void fix_start (double); - void match (double); - void repeat_last_video (); - - int _sample_rate; - float _frames_per_second; - int _video_frames; - int64_t _audio_frames; - boost::optional _pixel_format; - boost::optional _size; - boost::optional _channels; - - struct AudioRecord { - AudioRecord (boost::shared_ptr a, double t) - : audio (a) - , time (t) - {} - - boost::shared_ptr audio; - double time; - }; - - std::list _pending_audio; - - boost::optional _first_input; - boost::shared_ptr _last_image; - boost::shared_ptr _last_subtitle; - - bool _had_first_video; - bool _had_first_audio; -}; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index f8fe0c8d5..d4c5210dc 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -29,13 +29,9 @@ #include "transcoder.h" #include "encoder.h" #include "film.h" -#include "matcher.h" -#include "delay_line.h" -#include "gain.h" #include "video_decoder.h" #include "audio_decoder.h" #include "player.h" -#include "trimmer.h" #include "job.h" using std::string; @@ -52,45 +48,19 @@ Transcoder::Transcoder (shared_ptr f, shared_ptr j) , _player (f->player ()) , _encoder (new Encoder (f, j)) { - _matcher.reset (new Matcher (f->log(), f->audio_frame_rate(), f->video_frame_rate())); - _delay_line.reset (new DelayLine (f->log(), f->audio_delay() * f->audio_frame_rate() / 1000)); - _gain.reset (new Gain (f->log(), f->audio_gain())); - - int const trim_start = f->trim_type() == Film::ENCODE ? f->trim_start() : 0; - int const trim_end = f->trim_type() == Film::ENCODE ? f->trim_end() : 0; - _trimmer.reset (new Trimmer ( - f->log(), trim_start, trim_end, f->content_length(), - f->audio_frame_rate(), f->video_frame_rate(), f->dcp_frame_rate() - )); - if (!f->with_subtitles ()) { _player->disable_subtitles (); } - _player->connect_video (_delay_line); - _delay_line->connect_video (_matcher); - _matcher->connect_video (_trimmer); - _trimmer->connect_video (_encoder); - - _player->connect_audio (_delay_line); - _delay_line->connect_audio (_matcher); - _matcher->connect_audio (_gain); - _gain->connect_audio (_trimmer); - _trimmer->connect_audio (_encoder); + _player->connect_video (_encoder); + _player->connect_audio (_encoder); } void Transcoder::go () { _encoder->process_begin (); - while (!_player->pass ()) {} - - _delay_line->process_end (); - if (_matcher) { - _matcher->process_end (); - } - _gain->process_end (); _encoder->process_end (); } diff --git a/src/lib/transcoder.h b/src/lib/transcoder.h index 48b453fe4..f7da3bd01 100644 --- a/src/lib/transcoder.h +++ b/src/lib/transcoder.h @@ -28,12 +28,8 @@ class Film; class Job; class Encoder; -class Matcher; class VideoFilter; -class Gain; -class DelayLine; class Player; -class Trimmer; /** @class Transcoder * @@ -58,8 +54,4 @@ private: boost::shared_ptr _job; boost::shared_ptr _player; boost::shared_ptr _encoder; - boost::shared_ptr _matcher; - boost::shared_ptr _delay_line; - boost::shared_ptr _gain; - boost::shared_ptr _trimmer; }; diff --git a/src/lib/trimmer.cc b/src/lib/trimmer.cc deleted file mode 100644 index b7afc9299..000000000 --- a/src/lib/trimmer.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* - Copyright (C) 2013 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include "trimmer.h" - -using std::cout; -using std::max; -using boost::shared_ptr; - -/** @param audio_sample_rate Audio sampling rate, or 0 if there is no audio */ -Trimmer::Trimmer ( - shared_ptr log, - int video_trim_start, - int video_trim_end, - int video_length, - int audio_sample_rate, - float frames_per_second, - int dcp_frames_per_second - ) - : AudioVideoProcessor (log) - , _video_start (video_trim_start) - , _video_end (video_length - video_trim_end) - , _video_in (0) - , _audio_in (0) -{ - FrameRateConversion frc (frames_per_second, dcp_frames_per_second); - - if (frc.skip) { - _video_start /= 2; - _video_end /= 2; - } else if (frc.repeat) { - _video_start *= 2; - _video_end *= 2; - } - - if (audio_sample_rate) { - _audio_start = video_frames_to_audio_frames (_video_start, audio_sample_rate, frames_per_second); - _audio_end = video_frames_to_audio_frames (_video_end, audio_sample_rate, frames_per_second); - } - - /* XXX: this is a hack; this flag means that no trim is happening at the end of the film, and I'm - using that to prevent audio trim being rounded to video trim, which breaks the current set - of regression tests. This could be removed if a) the regression tests are regenerated and b) - I can work out what DCP length should be. - */ - _no_trim = (_video_start == 0) && (_video_end == (video_length - video_trim_end)); -} - -void -Trimmer::process_video (shared_ptr image, bool same, shared_ptr sub) -{ - if (_no_trim || (_video_in >= _video_start && _video_in <= _video_end)) { - Video (image, same, sub); - } - - ++_video_in; -} - -void -Trimmer::process_audio (shared_ptr audio) -{ - if (_no_trim) { - Audio (audio); - return; - } - - int64_t offset = _audio_start - _audio_in; - if (offset > audio->frames()) { - _audio_in += audio->frames (); - return; - } - - if (offset < 0) { - offset = 0; - } - - int64_t length = _audio_end - max (_audio_in, _audio_start); - if (length < 0) { - _audio_in += audio->frames (); - return; - } - - if (length > (audio->frames() - offset)) { - length = audio->frames () - offset; - } - - _audio_in += audio->frames (); - - if (offset != 0 || length != audio->frames ()) { - shared_ptr copy (new AudioBuffers (audio)); - copy->move (offset, 0, length); - copy->set_frames (length); - audio = copy; - } - - Audio (audio); -} - diff --git a/src/lib/trimmer.h b/src/lib/trimmer.h deleted file mode 100644 index 98a118fb2..000000000 --- a/src/lib/trimmer.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - Copyright (C) 2013 Carl Hetherington - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include "processor.h" - -class Trimmer : public AudioVideoProcessor -{ -public: - Trimmer (boost::shared_ptr, int, int, int, int, float, int); - - void process_video (boost::shared_ptr i, bool, boost::shared_ptr s); - void process_audio (boost::shared_ptr); - -private: - friend class trimmer_test; - - int _video_start; - int _video_end; - int _video_in; - int64_t _audio_start; - int64_t _audio_end; - int64_t _audio_in; - bool _no_trim; -}; diff --git a/src/lib/wscript b/src/lib/wscript index e53ac5a84..bce6c644c 100644 --- a/src/lib/wscript +++ b/src/lib/wscript @@ -18,7 +18,6 @@ sources = """ dcp_content_type.cc dcp_video_frame.cc decoder.cc - delay_line.cc dolby_cp750.cc encoder.cc examine_content_job.cc @@ -30,7 +29,6 @@ sources = """ film.cc filter.cc format.cc - gain.cc image.cc imagemagick_content.cc imagemagick_decoder.cc @@ -38,7 +36,6 @@ sources = """ job_manager.cc log.cc lut.cc - matcher.cc player.cc playlist.cc scp_dcp_job.cc @@ -52,7 +49,6 @@ sources = """ transcode_job.cc transcoder.cc types.cc - trimmer.cc ui_signaller.cc util.cc video_content.cc diff --git a/test/test.cc b/test/test.cc index 1cf651405..2c957fd35 100644 --- a/test/test.cc +++ b/test/test.cc @@ -40,7 +40,6 @@ #include "ffmpeg_decoder.h" #include "sndfile_decoder.h" #include "dcp_content_type.h" -#include "trimmer.h" #define BOOST_TEST_DYN_LINK #define BOOST_TEST_MODULE dcpomatic_test #include @@ -124,80 +123,6 @@ BOOST_AUTO_TEST_CASE (make_black_test) } } -shared_ptr trimmer_test_last_video; -shared_ptr trimmer_test_last_audio; - -void -trimmer_test_video_helper (shared_ptr image, bool, shared_ptr) -{ - trimmer_test_last_video = image; -} - -void -trimmer_test_audio_helper (shared_ptr audio) -{ - trimmer_test_last_audio = audio; -} - -BOOST_AUTO_TEST_CASE (trimmer_passthrough_test) -{ - Trimmer trimmer (shared_ptr (), 0, 0, 200, 48000, 25, 25); - trimmer.Video.connect (bind (&trimmer_test_video_helper, _1, _2, _3)); - trimmer.Audio.connect (bind (&trimmer_test_audio_helper, _1)); - - shared_ptr video (new SimpleImage (PIX_FMT_RGB24, libdcp::Size (1998, 1080), true)); - shared_ptr audio (new AudioBuffers (6, 42 * 1920)); - - trimmer.process_video (video, false, shared_ptr ()); - trimmer.process_audio (audio); - - BOOST_CHECK_EQUAL (video.get(), trimmer_test_last_video.get()); - BOOST_CHECK_EQUAL (audio.get(), trimmer_test_last_audio.get()); - BOOST_CHECK_EQUAL (audio->frames(), trimmer_test_last_audio->frames()); -} - - -/** Test the audio handling of the Trimmer */ -BOOST_AUTO_TEST_CASE (trimmer_audio_test) -{ - Trimmer trimmer (shared_ptr (), 25, 75, 200, 48000, 25, 25); - - trimmer.Audio.connect (bind (&trimmer_test_audio_helper, _1)); - - /* 21 video frames-worth of audio frames; should be completely stripped */ - trimmer_test_last_audio.reset (); - shared_ptr audio (new AudioBuffers (6, 21 * 1920)); - trimmer.process_audio (audio); - BOOST_CHECK (trimmer_test_last_audio == 0); - - /* 42 more video frames-worth, 4 should be stripped from the start */ - audio.reset (new AudioBuffers (6, 42 * 1920)); - trimmer.process_audio (audio); - BOOST_CHECK (trimmer_test_last_audio); - BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 38 * 1920); - - /* 42 more video frames-worth, should be kept as-is */ - trimmer_test_last_audio.reset (); - audio.reset (new AudioBuffers (6, 42 * 1920)); - trimmer.process_audio (audio); - BOOST_CHECK (trimmer_test_last_audio); - BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 42 * 1920); - - /* 25 more video frames-worth, 5 should be trimmed from the end */ - trimmer_test_last_audio.reset (); - audio.reset (new AudioBuffers (6, 25 * 1920)); - trimmer.process_audio (audio); - BOOST_CHECK (trimmer_test_last_audio); - BOOST_CHECK_EQUAL (trimmer_test_last_audio->frames(), 20 * 1920); - - /* Now some more; all should be trimmed */ - trimmer_test_last_audio.reset (); - audio.reset (new AudioBuffers (6, 100 * 1920)); - trimmer.process_audio (audio); - BOOST_CHECK (trimmer_test_last_audio == 0); -} - - BOOST_AUTO_TEST_CASE (film_metadata_test) { setup_test_config (); -- cgit v1.2.3 From 6e52f83418c64d5cbd0e613a5fc96ea32881d4d9 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Sun, 16 Jun 2013 15:52:32 +0100 Subject: Fix subtitle controls in the viewer. --- src/lib/ffmpeg_content.cc | 2 +- src/lib/ffmpeg_decoder.cc | 5 ++--- src/lib/ffmpeg_decoder.h | 3 +-- src/lib/player.cc | 15 +++++++-------- src/lib/player.h | 2 -- src/lib/transcoder.cc | 4 ---- src/lib/video_decoder.cc | 30 ++++++++++++++++-------------- src/wx/film_viewer.cc | 5 +---- 8 files changed, 28 insertions(+), 38 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc index 7a67ee5b8..4a1534887 100644 --- a/src/lib/ffmpeg_content.cc +++ b/src/lib/ffmpeg_content.cc @@ -132,7 +132,7 @@ FFmpegContent::examine (shared_ptr job) shared_ptr film = _film.lock (); assert (film); - shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false, false)); + shared_ptr decoder (new FFmpegDecoder (film, shared_from_this (), true, false)); ContentVideoFrame video_length = 0; video_length = decoder->video_length (); diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 2f890c0cd..7ebb31084 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -63,7 +63,7 @@ using libdcp::Size; boost::mutex FFmpegDecoder::_mutex; -FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio, bool subtitles) +FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptr c, bool video, bool audio) : Decoder (f) , VideoDecoder (f, c) , AudioDecoder (f, c) @@ -79,7 +79,6 @@ FFmpegDecoder::FFmpegDecoder (shared_ptr f, shared_ptraudio_stream() && _packet.stream_index == _ffmpeg_content->audio_stream()->id && _decode_audio) { decode_audio_packet (); - } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id && _decode_subtitles) { + } else if (_ffmpeg_content->subtitle_stream() && _packet.stream_index == _ffmpeg_content->subtitle_stream()->id) { int got_subtitle; AVSubtitle sub; diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 2d295db7b..3cfb54e09 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -59,7 +59,7 @@ class Film; class FFmpegDecoder : public VideoDecoder, public AudioDecoder { public: - FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio, bool subtitles); + FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool video, bool audio); ~FFmpegDecoder (); /* Decoder */ @@ -139,7 +139,6 @@ private: bool _decode_video; bool _decode_audio; - bool _decode_subtitles; /* It would appear (though not completely verified) that one must have a mutex around calls to avcodec_open* and avcodec_close... and here diff --git a/src/lib/player.cc b/src/lib/player.cc index 1931ec0f5..6d7c3cfbd 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -58,7 +58,6 @@ Player::Player (shared_ptr f, shared_ptr p) , _playlist (p) , _video (true) , _audio (true) - , _subtitles (true) , _have_valid_pieces (false) , _position (0) , _audio_buffers (f->dcp_audio_channels(), 0) @@ -80,12 +79,6 @@ Player::disable_audio () _audio = false; } -void -Player::disable_subtitles () -{ - _subtitles = false; -} - bool Player::pass () { @@ -291,10 +284,13 @@ Player::setup_pieces () shared_ptr fc = dynamic_pointer_cast (*i); if (fc) { - shared_ptr fd (new FFmpegDecoder (_film, fc, _video, _audio, _subtitles)); + shared_ptr fd (new FFmpegDecoder (_film, fc, _video, _audio)); fd->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3)); fd->Audio.connect (bind (&Player::process_audio, this, *i, _1, _2)); + if (_video_container_size) { + fd->set_video_container_size (_video_container_size.get ()); + } decoder = fd; cout << "\tFFmpeg @ " << fc->start() << " -- " << fc->end() << "\n"; @@ -315,6 +311,9 @@ Player::setup_pieces () if (!id) { id.reset (new ImageMagickDecoder (_film, ic)); id->Video.connect (bind (&Player::process_video, this, *i, _1, _2, _3)); + if (_video_container_size) { + id->set_video_container_size (_video_container_size.get ()); + } } decoder = id; diff --git a/src/lib/player.h b/src/lib/player.h index 95f419b5e..60cf88422 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -49,7 +49,6 @@ public: void disable_video (); void disable_audio (); - void disable_subtitles (); bool pass (); void seek (Time); @@ -80,7 +79,6 @@ private: bool _video; bool _audio; - bool _subtitles; /** Our pieces are ready to go; if this is false the pieces must be (re-)created before they are used */ bool _have_valid_pieces; diff --git a/src/lib/transcoder.cc b/src/lib/transcoder.cc index d4c5210dc..847be2f1c 100644 --- a/src/lib/transcoder.cc +++ b/src/lib/transcoder.cc @@ -48,10 +48,6 @@ Transcoder::Transcoder (shared_ptr f, shared_ptr j) , _player (f->player ()) , _encoder (new Encoder (f, j)) { - if (!f->with_subtitles ()) { - _player->disable_subtitles (); - } - _player->connect_video (_encoder); _player->connect_audio (_encoder); } diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 58aceb407..54d14e2c6 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -61,20 +61,22 @@ VideoDecoder::video (shared_ptr image, bool same, Time t) shared_ptr out = image->scale_and_convert_to_rgb (image_size, film->scaler(), true); - shared_ptr sub; - if (_timed_subtitle && _timed_subtitle->displayed_at (t)) { - sub = _timed_subtitle->subtitle (); - } - - if (sub) { - dcpomatic::Rect const tx = subtitle_transformed_area ( - float (image_size.width) / video_size().width, - float (image_size.height) / video_size().height, - sub->area(), film->subtitle_offset(), film->subtitle_scale() - ); - - shared_ptr im = sub->image()->scale (tx.size(), film->scaler(), true); - out->alpha_blend (im, tx.position()); + if (film->with_subtitles ()) { + shared_ptr sub; + if (_timed_subtitle && _timed_subtitle->displayed_at (t)) { + sub = _timed_subtitle->subtitle (); + } + + if (sub) { + dcpomatic::Rect const tx = subtitle_transformed_area ( + float (image_size.width) / video_size().width, + float (image_size.height) / video_size().height, + sub->area(), film->subtitle_offset(), film->subtitle_scale() + ); + + shared_ptr im = sub->image()->scale (tx.size(), film->scaler(), true); + out->alpha_blend (im, tx.position()); + } } if (image_size != container_size) { diff --git a/src/wx/film_viewer.cc b/src/wx/film_viewer.cc index d2ec01de7..c7a44364f 100644 --- a/src/wx/film_viewer.cc +++ b/src/wx/film_viewer.cc @@ -129,6 +129,7 @@ FilmViewer::film_changed (Film::Property p) case Film::WITH_SUBTITLES: case Film::SUBTITLE_OFFSET: case Film::SUBTITLE_SCALE: + update_from_decoder (); raw_to_display (); _panel->Refresh (); _panel->Update (); @@ -161,10 +162,6 @@ FilmViewer::set_film (shared_ptr f) _player = f->player (); _player->disable_audio (); - /* Don't disable subtitles here as we may need them, and it's nice to be able to turn them - on and off without needing obtain a new Player. - */ - _player->Video.connect (bind (&FilmViewer::process_video, this, _1, _2, _3)); _film->Changed.connect (boost::bind (&FilmViewer::film_changed, this, _1)); -- cgit v1.2.3 From 50cb31af16240b248700dab1484d7f07656c66df Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Thu, 20 Jun 2013 17:34:23 +0100 Subject: Various fixes to make audio analysis sort-of work. --- src/lib/analyse_audio_job.cc | 33 ++++++++++++++++++++--------- src/lib/analyse_audio_job.h | 6 ++++-- src/lib/audio_analysis.cc | 10 ++++----- src/lib/audio_analysis.h | 5 +++-- src/lib/audio_buffers.cc | 6 ++++++ src/lib/audio_content.cc | 27 ++++++++++++++++++++++++ src/lib/audio_content.h | 5 +++-- src/lib/audio_decoder.cc | 5 ++--- src/lib/content.h | 2 -- src/lib/encoder.cc | 2 +- src/lib/encoder.h | 4 ++-- src/lib/examine_content_job.cc | 3 +-- src/lib/examine_content_job.h | 2 +- src/lib/ffmpeg_decoder.cc | 6 +----- src/lib/film.cc | 48 ++++++++++++++---------------------------- src/lib/film.h | 9 ++------ src/lib/job.cc | 2 +- src/lib/job.h | 4 ++-- src/lib/player.cc | 33 ++--------------------------- src/lib/playlist.cc | 23 -------------------- src/lib/playlist.h | 1 - src/lib/scp_dcp_job.cc | 2 +- src/lib/scp_dcp_job.h | 2 +- src/lib/transcode_job.cc | 2 +- src/lib/transcode_job.h | 2 +- src/lib/transcoder.cc | 2 +- src/lib/transcoder.h | 2 +- src/lib/writer.cc | 2 +- src/lib/writer.h | 4 ++-- src/tools/dcpomatic.cc | 9 -------- src/wx/about_dialog.cc | 4 ++-- src/wx/audio_dialog.cc | 32 +++++++++++----------------- src/wx/audio_dialog.h | 9 ++++---- src/wx/audio_plot.cc | 10 +++++++-- src/wx/film_editor.cc | 36 +++++++++++++++---------------- 35 files changed, 155 insertions(+), 199 deletions(-) (limited to 'src/lib/transcoder.cc') diff --git a/src/lib/analyse_audio_job.cc b/src/lib/analyse_audio_job.cc index 3a44a408f..2848c1ed7 100644 --- a/src/lib/analyse_audio_job.cc +++ b/src/lib/analyse_audio_job.cc @@ -33,8 +33,9 @@ using boost::shared_ptr; int const AnalyseAudioJob::_num_points = 1024; -AnalyseAudioJob::AnalyseAudioJob (shared_ptr f) +AnalyseAudioJob::AnalyseAudioJob (shared_ptr f, shared_ptr c) : Job (f) + , _content (c) , _done (0) , _samples_per_point (1) { @@ -44,13 +45,25 @@ AnalyseAudioJob::AnalyseAudioJob (shared_ptr f) string AnalyseAudioJob::name () const { - return String::compose (_("Analyse audio of %1"), _film->name()); + shared_ptr content = _content.lock (); + if (!content) { + return ""; + } + + return String::compose (_("Analyse audio of %1"), content->file().filename()); } void AnalyseAudioJob::run () { - shared_ptr player = _film->player (); + shared_ptr content = _content.lock (); + if (!content) { + return; + } + + shared_ptr playlist (new Playlist); + playlist->add (content); + shared_ptr player (new Player (_film, playlist)); player->disable_video (); player->Audio.connect (bind (&AnalyseAudioJob::audio, this, _1, _2)); @@ -61,18 +74,18 @@ AnalyseAudioJob::run () _analysis.reset (new AudioAnalysis (_film->dcp_audio_channels ())); _done = 0; - while (player->pass ()) { - set_progress (double (_done) / _film->length ()); + while (!player->pass ()) { + set_progress (double (_film->audio_frames_to_time (_done)) / _film->length ()); } - _analysis->write (_film->audio_analysis_path ()); + _analysis->write (content->audio_analysis_path ()); set_progress (1); set_state (FINISHED_OK); } void -AnalyseAudioJob::audio (shared_ptr b, Time t) +AnalyseAudioJob::audio (shared_ptr b, Time) { for (int i = 0; i < b->frames(); ++i) { for (int j = 0; j < b->channels(); ++j) { @@ -88,12 +101,12 @@ AnalyseAudioJob::audio (shared_ptr b, Time t) if ((_done % _samples_per_point) == 0) { _current[j][AudioPoint::RMS] = sqrt (_current[j][AudioPoint::RMS] / _samples_per_point); _analysis->add_point (j, _current[j]); - + _current[j] = AudioPoint (); } } - } - _done = t; + ++_done; + } } diff --git a/src/lib/analyse_audio_job.h b/src/lib/analyse_audio_job.h index a0786a017..3d4881983 100644 --- a/src/lib/analyse_audio_job.h +++ b/src/lib/analyse_audio_job.h @@ -22,11 +22,12 @@ #include "types.h" class AudioBuffers; +class AudioContent; class AnalyseAudioJob : public Job { public: - AnalyseAudioJob (boost::shared_ptr f); + AnalyseAudioJob (boost::shared_ptr, boost::shared_ptr); std::string name () const; void run (); @@ -34,7 +35,8 @@ public: private: void audio (boost::shared_ptr, Time); - Time _done; + boost::weak_ptr _content; + OutputAudioFrame _done; int64_t _samples_per_point; std::vector _current; diff --git a/src/lib/audio_analysis.cc b/src/lib/audio_analysis.cc index 9d708bbfd..e12516620 100644 --- a/src/lib/audio_analysis.cc +++ b/src/lib/audio_analysis.cc @@ -62,9 +62,9 @@ AudioAnalysis::AudioAnalysis (int channels) _data.resize (channels); } -AudioAnalysis::AudioAnalysis (string filename) +AudioAnalysis::AudioAnalysis (boost::filesystem::path filename) { - ifstream f (filename.c_str ()); + ifstream f (filename.string().c_str ()); int channels; f >> channels; @@ -107,10 +107,10 @@ AudioAnalysis::points (int c) const } void -AudioAnalysis::write (string filename) +AudioAnalysis::write (boost::filesystem::path filename) { - string tmp = filename + ".tmp"; - + string tmp = filename.string() + ".tmp"; + ofstream f (tmp.c_str ()); f << _data.size() << "\n"; for (vector >::iterator i = _data.begin(); i != _data.end(); ++i) { diff --git a/src/lib/audio_analysis.h b/src/lib/audio_analysis.h index ec6905105..d57eba90a 100644 --- a/src/lib/audio_analysis.h +++ b/src/lib/audio_analysis.h @@ -23,6 +23,7 @@ #include #include #include +#include class AudioPoint { @@ -50,7 +51,7 @@ class AudioAnalysis { public: AudioAnalysis (int c); - AudioAnalysis (std::string); + AudioAnalysis (boost::filesystem::path); void add_point (int c, AudioPoint const & p); @@ -58,7 +59,7 @@ public: int points (int c) const; int channels () const; - void write (std::string); + void write (boost::filesystem::path); private: std::vector > _data; diff --git a/src/lib/audio_buffers.cc b/src/lib/audio_buffers.cc index c3e89f130..403babaf7 100644 --- a/src/lib/audio_buffers.cc +++ b/src/lib/audio_buffers.cc @@ -206,6 +206,9 @@ AudioBuffers::accumulate_channel (AudioBuffers const * from, int from_channel, i } } +/** Ensure we have space for at least a certain number of frames. If we extend + * the buffers, fill the new space with silence. + */ void AudioBuffers::ensure_size (int frames) { @@ -218,6 +221,9 @@ AudioBuffers::ensure_size (int frames) if (!_data[i]) { throw bad_alloc (); } + for (int j = _allocated_frames; j < frames; ++j) { + _data[i][j] = 0; + } } _allocated_frames = frames; diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc index 9940574f9..e93f348f4 100644 --- a/src/lib/audio_content.cc +++ b/src/lib/audio_content.cc @@ -19,11 +19,14 @@ #include #include "audio_content.h" +#include "analyse_audio_job.h" +#include "job_manager.h" #include "film.h" using std::string; using boost::shared_ptr; using boost::lexical_cast; +using boost::dynamic_pointer_cast; int const AudioContentProperty::AUDIO_CHANNELS = 200; int const AudioContentProperty::AUDIO_LENGTH = 201; @@ -93,3 +96,27 @@ AudioContent::set_audio_delay (int d) signal_changed (AudioContentProperty::AUDIO_DELAY); } + +void +AudioContent::analyse_audio (boost::function finished) +{ + shared_ptr film = _film.lock (); + if (!film) { + return; + } + + shared_ptr job (new AnalyseAudioJob (film, dynamic_pointer_cast (shared_from_this()))); + job->Finished.connect (finished); + JobManager::instance()->add (job); +} + +boost::filesystem::path +AudioContent::audio_analysis_path () const +{ + shared_ptr film = _film.lock (); + if (!film) { + return boost::filesystem::path (); + } + + return film->audio_analysis_path (dynamic_pointer_cast (shared_from_this ())); +} diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h index 8fc658a76..73a00ca7d 100644 --- a/src/lib/audio_content.h +++ b/src/lib/audio_content.h @@ -1,5 +1,3 @@ -/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ - /* Copyright (C) 2013 Carl Hetherington @@ -57,6 +55,9 @@ public: virtual AudioMapping audio_mapping () const = 0; virtual void set_audio_mapping (AudioMapping) = 0; + void analyse_audio (boost::function); + boost::filesystem::path audio_analysis_path () const; + void set_audio_gain (float); void set_audio_delay (int); diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index bbd4ced6c..a9e01908c 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -59,10 +59,10 @@ AudioDecoder::AudioDecoder (shared_ptr f, shared_ptraudio_channels ()), AV_SAMPLE_FMT_FLTP, _audio_content->output_audio_frame_rate(), - av_get_default_channel_layout (MAX_AUDIO_CHANNELS), + av_get_default_channel_layout (_audio_content->audio_channels ()), AV_SAMPLE_FMT_FLTP, _audio_content->content_audio_frame_rate(), 0, 0 @@ -152,7 +152,6 @@ AudioDecoder::audio (shared_ptr data, Time time) } Audio (dcp_mapped, time); - cout << "bumping n.a. by " << data->frames() << " ie " << film->audio_frames_to_time(data->frames()) << "\n"; _next_audio = time + film->audio_frames_to_time (data->frames()); } diff --git a/src/lib/content.h b/src/lib/content.h index 5e8f98428..e33f517ab 100644 --- a/src/lib/content.h +++ b/src/lib/content.h @@ -1,5 +1,3 @@ -/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ - /* Copyright (C) 2013 Carl Hetherington diff --git a/src/lib/encoder.cc b/src/lib/encoder.cc index 4dff19ea6..8b2db0eb3 100644 --- a/src/lib/encoder.cc +++ b/src/lib/encoder.cc @@ -47,7 +47,7 @@ using boost::optional; int const Encoder::_history_size = 25; /** @param f Film that we are encoding */ -Encoder::Encoder (shared_ptr f, shared_ptr j) +Encoder::Encoder (shared_ptr f, shared_ptr j) : _film (f) , _job (j) , _video_frames_out (0) diff --git a/src/lib/encoder.h b/src/lib/encoder.h index 8f724525c..3fe707b51 100644 --- a/src/lib/encoder.h +++ b/src/lib/encoder.h @@ -58,7 +58,7 @@ class Job; class Encoder : public VideoSink, public AudioSink { public: - Encoder (boost::shared_ptr f, boost::shared_ptr); + Encoder (boost::shared_ptr f, boost::shared_ptr); virtual ~Encoder (); /** Called to indicate that a processing run is about to begin */ @@ -87,7 +87,7 @@ private: void terminate_threads (); /** Film that we are encoding */ - boost::shared_ptr _film; + boost::shared_ptr _film; boost::shared_ptr _job; /** Mutex for _time_history and _last_frame */ diff --git a/src/lib/examine_content_job.cc b/src/lib/examine_content_job.cc index f68a1eea0..3cab9716d 100644 --- a/src/lib/examine_content_job.cc +++ b/src/lib/examine_content_job.cc @@ -28,7 +28,7 @@ using std::string; using boost::shared_ptr; -ExamineContentJob::ExamineContentJob (shared_ptr f, shared_ptr c) +ExamineContentJob::ExamineContentJob (shared_ptr f, shared_ptr c) : Job (f) , _content (c) { @@ -49,7 +49,6 @@ void ExamineContentJob::run () { _content->examine (shared_from_this ()); - _film->add_content (_content); set_progress (1); set_state (FINISHED_OK); } diff --git a/src/lib/examine_content_job.h b/src/lib/examine_content_job.h index 86f1ab111..b6903b86b 100644 --- a/src/lib/examine_content_job.h +++ b/src/lib/examine_content_job.h @@ -26,7 +26,7 @@ class Log; class ExamineContentJob : public Job { public: - ExamineContentJob (boost::shared_ptr, boost::shared_ptr); + ExamineContentJob (boost::shared_ptr, boost::shared_ptr); ~ExamineContentJob (); std::string name () const; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 36078a463..2e586b8f7 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -1,5 +1,3 @@ -/* -*- c-basic-offset: 8; default-tab-width: 8; -*- */ - /* Copyright (C) 2012 Carl Hetherington @@ -278,8 +276,6 @@ FFmpegDecoder::pass () } avsubtitle_free (&sub); } - } else { - cout << "[ffmpeg] other packet.\n"; } av_free_packet (&_packet); @@ -541,7 +537,7 @@ FFmpegDecoder::decode_audio_packet () ); assert (_audio_codec_context->channels == _ffmpeg_content->audio_channels()); - audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds); + audio (deinterleave_audio (_frame->data, data_size), source_pts_seconds * TIME_HZ); } copy_packet.data += decode_result; diff --git a/src/lib/film.cc b/src/lib/film.cc index a29f6c331..ad565aca0 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -45,7 +45,6 @@ #include "config.h" #include "version.h" #include "ui_signaller.h" -#include "analyse_audio_job.h" #include "playlist.h" #include "player.h" #include "ffmpeg_content.h" @@ -72,6 +71,7 @@ using std::endl; using std::cout; using std::list; using boost::shared_ptr; +using boost::weak_ptr; using boost::lexical_cast; using boost::dynamic_pointer_cast; using boost::to_upper_copy; @@ -222,13 +222,12 @@ Film::filename_safe_name () const return o; } -string -Film::audio_analysis_path () const +boost::filesystem::path +Film::audio_analysis_path (shared_ptr c) const { - boost::filesystem::path p; - p /= "analysis"; - p /= _playlist->audio_digest(); - return file (p.string ()); + boost::filesystem::path p = dir ("analysis"); + p /= c->digest(); + return p; } /** Add suitable Jobs to the JobManager to create a DCP for this Film */ @@ -289,31 +288,6 @@ Film::make_dcp () JobManager::instance()->add (shared_ptr (new TranscodeJob (shared_from_this()))); } -/** Start a job to analyse the audio in our Playlist */ -void -Film::analyse_audio () -{ - if (_analyse_audio_job) { - return; - } - - _analyse_audio_job.reset (new AnalyseAudioJob (shared_from_this())); - _analyse_audio_job->Finished.connect (bind (&Film::analyse_audio_finished, this)); - JobManager::instance()->add (_analyse_audio_job); -} - -void -Film::analyse_audio_finished () -{ - ensure_ui_thread (); - - if (_analyse_audio_job->finished_ok ()) { - AudioAnalysisSucceeded (); - } - - _analyse_audio_job.reset (); -} - /** Start a job to send our DCP to the configured TMS */ void Film::send_dcp_to_tms () @@ -782,9 +756,19 @@ void Film::examine_and_add_content (shared_ptr c) { shared_ptr j (new ExamineContentJob (shared_from_this(), c)); + j->Finished.connect (bind (&Film::add_content_weak, this, boost::weak_ptr (c))); JobManager::instance()->add (j); } +void +Film::add_content_weak (weak_ptr c) +{ + shared_ptr content = c.lock (); + if (content) { + add_content (content); + } +} + void Film::add_content (shared_ptr c) { diff --git a/src/lib/film.h b/src/lib/film.h index 5f06a1dc7..5bb9acf29 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -63,12 +63,11 @@ public: std::string info_path (int f) const; std::string internal_video_mxf_dir () const; std::string internal_video_mxf_filename () const; - std::string audio_analysis_path () const; + boost::filesystem::path audio_analysis_path (boost::shared_ptr) const; std::string dcp_video_mxf_filename () const; std::string dcp_audio_mxf_filename () const; - void analyse_audio (); void send_dcp_to_tms (); void make_dcp (); @@ -244,24 +243,20 @@ public: /** Emitted when some property of our content has changed */ mutable boost::signals2::signal, int)> ContentChanged; - boost::signals2::signal AudioAnalysisSucceeded; - /** Current version number of the state file */ static int const state_version; private: void signal_changed (Property); - void analyse_audio_finished (); std::string video_state_identifier () const; void playlist_changed (); void playlist_content_changed (boost::weak_ptr, int); std::string filename_safe_name () const; + void add_content_weak (boost::weak_ptr); /** Log to write to */ boost::shared_ptr _log; - /** Any running AnalyseAudioJob, or 0 */ - boost::shared_ptr _analyse_audio_job; boost::shared_ptr _playlist; /** Complete path to directory containing the film metadata; diff --git a/src/lib/job.cc b/src/lib/job.cc index 2e6385d62..4969c4099 100644 --- a/src/lib/job.cc +++ b/src/lib/job.cc @@ -35,7 +35,7 @@ using std::list; using std::stringstream; using boost::shared_ptr; -Job::Job (shared_ptr f) +Job::Job (shared_ptr f) : _film (f) , _thread (0) , _state (NEW) diff --git a/src/lib/job.h b/src/lib/job.h index 40e90b73c..5a4775180 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); + Job (boost::shared_ptr); virtual ~Job() {} /** @return user-readable name of this job */ @@ -91,7 +91,7 @@ protected: void set_state (State); void set_error (std::string s, std::string d); - boost::shared_ptr _film; + boost::shared_ptr _film; private: diff --git a/src/lib/player.cc b/src/lib/player.cc index 60686e781..c05897c23 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -95,11 +95,6 @@ Player::pass () shared_ptr earliest; for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { - cout << "check " << (*i)->content->file() - << " start=" << (*i)->content->start() - << ", position=" << (*i)->decoder->position() - << ", end=" << (*i)->content->end() << "\n"; - if ((*i)->decoder->done ()) { continue; } @@ -110,7 +105,6 @@ Player::pass () Time const t = (*i)->content->start() + (*i)->decoder->position(); if (t < earliest_t) { - cout << "\t candidate; " << t << " " << (t / TIME_HZ) << ".\n"; earliest_t = t; earliest = *i; } @@ -121,23 +115,8 @@ Player::pass () return true; } - cout << "PASS:\n"; - cout << "\tpass " << earliest->content->file() << " "; - if (dynamic_pointer_cast (earliest->content)) { - cout << " FFmpeg.\n"; - } else if (dynamic_pointer_cast (earliest->content)) { - cout << " ImageMagickContent.\n"; - } else if (dynamic_pointer_cast (earliest->content)) { - cout << " SndfileContent.\n"; - } else if (dynamic_pointer_cast (earliest->decoder)) { - cout << " Black.\n"; - } else if (dynamic_pointer_cast (earliest->decoder)) { - cout << " Silence.\n"; - } - earliest->decoder->pass (); _position = earliest->content->start() + earliest->decoder->position (); - cout << "\tpassed to " << _position << " " << (_position / TIME_HZ) << "\n"; return false; } @@ -169,6 +148,8 @@ Player::process_audio (weak_ptr weak_content, shared_ptrstart (); + cout << "Player gets " << audio->frames() << " @ " << time << " cf " << _next_audio << "\n"; + if (time > _next_audio) { /* We can emit some audio from our buffers */ OutputAudioFrame const N = _film->time_to_audio_frames (time - _next_audio); @@ -216,13 +197,10 @@ Player::seek (Time t) return; } -// cout << "seek to " << t << " " << (t / TIME_HZ) << "\n"; - for (list >::iterator i = _pieces.begin(); i != _pieces.end(); ++i) { Time s = t - (*i)->content->start (); s = max (static_cast