From: Carl Hetherington Date: Tue, 10 May 2016 13:29:14 +0000 (+0100) Subject: Basics of splitting up Decoder tree like Content. X-Git-Tag: v2.8.4~27 X-Git-Url: https://main.carlh.net/gitweb/?p=dcpomatic.git;a=commitdiff_plain;h=504c63b3d62038bc486ca8a09e77fbb403907edd Basics of splitting up Decoder tree like Content. --- diff --git a/src/lib/audio_decoder.cc b/src/lib/audio_decoder.cc index 705fdbef1..7ceb9680b 100644 --- a/src/lib/audio_decoder.cc +++ b/src/lib/audio_decoder.cc @@ -30,13 +30,13 @@ using std::cout; using std::map; using boost::shared_ptr; -AudioDecoder::AudioDecoder (shared_ptr content, bool fast, shared_ptr log) +AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr content, bool fast, shared_ptr log) : _audio_content (content) , _ignore_audio (false) , _fast (fast) { BOOST_FOREACH (AudioStreamPtr i, content->streams ()) { - _streams[i] = shared_ptr (new AudioDecoderStream (_audio_content, i, this, log)); + _streams[i] = shared_ptr (new AudioDecoderStream (_audio_content, i, parent, log)); } } diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h index 31d0785c6..a56847daf 100644 --- a/src/lib/audio_decoder.h +++ b/src/lib/audio_decoder.h @@ -37,10 +37,10 @@ class Log; /** @class AudioDecoder. * @brief Parent class for audio decoders. */ -class AudioDecoder : public virtual Decoder, public boost::enable_shared_from_this +class AudioDecoder : public boost::enable_shared_from_this { public: - AudioDecoder (boost::shared_ptr, bool fast, boost::shared_ptr log); + AudioDecoder (Decoder* parent, boost::shared_ptr, bool fast, boost::shared_ptr log); /** Try to fetch some audio from a specific place in this content. * @param frame Frame to start from (after resampling, if applicable) @@ -56,7 +56,6 @@ public: return _fast; } -protected: void audio (AudioStreamPtr stream, boost::shared_ptr, ContentTime); void flush (); void seek (ContentTime t, bool accurate); diff --git a/src/lib/audio_decoder_stream.cc b/src/lib/audio_decoder_stream.cc index cd2e3a388..bbe26b6ef 100644 --- a/src/lib/audio_decoder_stream.cc +++ b/src/lib/audio_decoder_stream.cc @@ -39,14 +39,14 @@ using std::max; using boost::optional; using boost::shared_ptr; -AudioDecoderStream::AudioDecoderStream (shared_ptr content, AudioStreamPtr stream, AudioDecoder* decoder, shared_ptr log) +AudioDecoderStream::AudioDecoderStream (shared_ptr content, AudioStreamPtr stream, Decoder* decoder, shared_ptr log) : _content (content) , _stream (stream) , _decoder (decoder) , _log (log) { if (content->resampled_frame_rate() != _stream->frame_rate() && _stream->channels() > 0) { - _resampler.reset (new Resampler (_stream->frame_rate(), content->resampled_frame_rate(), _stream->channels (), decoder->fast ())); + _resampler.reset (new Resampler (_stream->frame_rate(), content->resampled_frame_rate(), _stream->channels (), decoder->audio->fast ())); } reset_decoded (); diff --git a/src/lib/audio_decoder_stream.h b/src/lib/audio_decoder_stream.h index 90269a0f4..265bbe004 100644 --- a/src/lib/audio_decoder_stream.h +++ b/src/lib/audio_decoder_stream.h @@ -29,11 +29,12 @@ class AudioContent; class AudioDecoder; class Resampler; class Log; +class Decoder; class AudioDecoderStream { public: - AudioDecoderStream (boost::shared_ptr, AudioStreamPtr, AudioDecoder* decoder, boost::shared_ptr log); + AudioDecoderStream (boost::shared_ptr, AudioStreamPtr, Decoder* decoder, boost::shared_ptr log); ContentAudio get (Frame time, Frame length, bool accurate); void audio (boost::shared_ptr, ContentTime); @@ -47,7 +48,7 @@ private: boost::shared_ptr _content; AudioStreamPtr _stream; - AudioDecoder* _decoder; + Decoder* _decoder; boost::shared_ptr _log; boost::shared_ptr _resampler; boost::optional _position; diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc index 8008fe515..2a7691666 100644 --- a/src/lib/dcp_decoder.cc +++ b/src/lib/dcp_decoder.cc @@ -20,7 +20,10 @@ #include "dcp_decoder.h" #include "dcp_content.h" #include "audio_content.h" +#include "video_decoder.h" +#include "audio_decoder.h" #include "j2k_image_proxy.h" +#include "subtitle_decoder.h" #include "image.h" #include "config.h" #include @@ -44,11 +47,20 @@ using boost::shared_ptr; using boost::dynamic_pointer_cast; DCPDecoder::DCPDecoder (shared_ptr c, shared_ptr log, bool fast) - : VideoDecoder (c, log) - , AudioDecoder (c->audio, fast, log) - , SubtitleDecoder (c->subtitle) - , _dcp_content (c) + : _dcp_content (c) { + video.reset (new VideoDecoder (this, c, log)); + audio.reset (new AudioDecoder (this, c->audio, fast, log)); + + subtitle.reset ( + new SubtitleDecoder ( + this, + c->subtitle, + bind (&DCPDecoder::image_subtitles_during, this, _1, _2), + bind (&DCPDecoder::text_subtitles_during, this, _1, _2) + ) + ); + dcp::DCP dcp (c->directory ()); dcp.read (false, 0, true); if (c->kdm ()) { @@ -85,14 +97,14 @@ DCPDecoder::pass (PassReason reason, bool) shared_ptr stereo = dynamic_pointer_cast (asset); int64_t const entry_point = (*_reel)->main_picture()->entry_point (); if (mono) { - video (shared_ptr (new J2KImageProxy (mono->get_frame (entry_point + frame), asset->size())), offset + frame); + video->video (shared_ptr (new J2KImageProxy (mono->get_frame (entry_point + frame), asset->size())), offset + frame); } else { - video ( + video->video ( shared_ptr (new J2KImageProxy (stereo->get_frame (entry_point + frame), asset->size(), dcp::EYE_LEFT)), offset + frame ); - video ( + video->video ( shared_ptr (new J2KImageProxy (stereo->get_frame (entry_point + frame), asset->size(), dcp::EYE_RIGHT)), offset + frame ); @@ -114,7 +126,7 @@ DCPDecoder::pass (PassReason reason, bool) } } - audio (_dcp_content->audio->stream(), data, ContentTime::from_frames (offset, vfr) + _next); + audio->audio (_dcp_content->audio->stream(), data, ContentTime::from_frames (offset, vfr) + _next); } if ((*_reel)->main_subtitle ()) { @@ -127,7 +139,7 @@ DCPDecoder::pass (PassReason reason, bool) if (!subs.empty ()) { /* XXX: assuming that all `subs' are at the same time; maybe this is ok */ - text_subtitle ( + subtitle->text_subtitle ( ContentTimePeriod ( ContentTime::from_frames (offset - entry_point, vfr) + ContentTime::from_seconds (subs.front().in().as_seconds ()), ContentTime::from_frames (offset - entry_point, vfr) + ContentTime::from_seconds (subs.front().out().as_seconds ()) @@ -152,9 +164,9 @@ DCPDecoder::pass (PassReason reason, bool) void DCPDecoder::seek (ContentTime t, bool accurate) { - VideoDecoder::seek (t, accurate); - AudioDecoder::seek (t, accurate); - SubtitleDecoder::seek (t, accurate); + video->seek (t, accurate); + audio->seek (t, accurate); + subtitle->seek (t, accurate); _reel = _reels.begin (); while (_reel != _reels.end() && t >= ContentTime::from_frames ((*_reel)->main_picture()->duration(), _dcp_content->active_video_frame_rate ())) { diff --git a/src/lib/dcp_decoder.h b/src/lib/dcp_decoder.h index ce9a3ef9a..6e58c4904 100644 --- a/src/lib/dcp_decoder.h +++ b/src/lib/dcp_decoder.h @@ -21,18 +21,17 @@ * @brief A decoder of existing DCPs. */ -#include "video_decoder.h" -#include "audio_decoder.h" -#include "subtitle_decoder.h" +#include "decoder.h" namespace dcp { class Reel; } class DCPContent; +class Log; struct dcp_subtitle_within_dcp_test; -class DCPDecoder : public VideoDecoder, public AudioDecoder, public SubtitleDecoder +class DCPDecoder : public Decoder { public: DCPDecoder (boost::shared_ptr, boost::shared_ptr log, bool fast); diff --git a/src/lib/dcp_subtitle_decoder.cc b/src/lib/dcp_subtitle_decoder.cc index 964ee6f20..23f5dd529 100644 --- a/src/lib/dcp_subtitle_decoder.cc +++ b/src/lib/dcp_subtitle_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington + Copyright (C) 2014-2016 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 @@ -25,10 +25,19 @@ using std::list; using std::cout; using boost::shared_ptr; +using boost::bind; DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr content) - : SubtitleDecoder (content->subtitle) { + subtitle.reset ( + new SubtitleDecoder ( + this, + content->subtitle, + bind (&DCPSubtitleDecoder::image_subtitles_during, this, _1, _2), + bind (&DCPSubtitleDecoder::text_subtitles_during, this, _1, _2) + ) + ); + shared_ptr c (load (content->path (0))); _subtitles = c->subtitles (); _next = _subtitles.begin (); @@ -37,7 +46,7 @@ DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr con void DCPSubtitleDecoder::seek (ContentTime time, bool accurate) { - SubtitleDecoder::seek (time, accurate); + subtitle->seek (time, accurate); _next = _subtitles.begin (); list::const_iterator i = _subtitles.begin (); @@ -68,7 +77,7 @@ DCPSubtitleDecoder::pass (PassReason, bool) ++_next; } - text_subtitle (p, s); + subtitle->text_subtitle (p, s); return false; } diff --git a/src/lib/dcp_subtitle_decoder.h b/src/lib/dcp_subtitle_decoder.h index 1f5377622..fcefc0201 100644 --- a/src/lib/dcp_subtitle_decoder.h +++ b/src/lib/dcp_subtitle_decoder.h @@ -22,7 +22,7 @@ class DCPSubtitleContent; -class DCPSubtitleDecoder : public SubtitleDecoder, public DCPSubtitle +class DCPSubtitleDecoder : public DCPSubtitle, public Decoder { public: DCPSubtitleDecoder (boost::shared_ptr); diff --git a/src/lib/decoder.h b/src/lib/decoder.h index 10bb45310..979c6cf58 100644 --- a/src/lib/decoder.h +++ b/src/lib/decoder.h @@ -29,6 +29,9 @@ #include class Decoded; +class VideoDecoder; +class AudioDecoder; +class SubtitleDecoder; /** @class Decoder. * @brief Parent class for decoders of content. @@ -38,8 +41,15 @@ class Decoder : public boost::noncopyable public: virtual ~Decoder () {} -protected: - friend class AudioDecoderStream; + boost::shared_ptr video; + boost::shared_ptr audio; + boost::shared_ptr subtitle; + + enum PassReason { + PASS_REASON_VIDEO, + PASS_REASON_AUDIO, + PASS_REASON_SUBTITLE + }; /** Seek so that the next pass() will yield the next thing * (video/sound frame, subtitle etc.) at or after the requested @@ -51,12 +61,6 @@ protected: */ virtual void seek (ContentTime time, bool accurate) = 0; - enum PassReason { - PASS_REASON_VIDEO, - PASS_REASON_AUDIO, - PASS_REASON_SUBTITLE - }; - /** @return true if this decoder has already returned all its data and will give no more */ virtual bool pass (PassReason, bool accurate) = 0; }; diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index d84bb2a52..2f123e484 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -27,14 +27,17 @@ #include "util.h" #include "log.h" #include "ffmpeg_decoder.h" +#include "subtitle_decoder.h" #include "ffmpeg_audio_stream.h" #include "ffmpeg_subtitle_stream.h" #include "video_filter_graph.h" #include "audio_buffers.h" #include "ffmpeg_content.h" #include "raw_image_proxy.h" +#include "video_decoder.h" #include "film.h" #include "md5_digester.h" +#include "audio_decoder.h" #include "compose.hpp" #include #include @@ -72,17 +75,30 @@ using boost::split; using dcp::Size; FFmpegDecoder::FFmpegDecoder (shared_ptr c, shared_ptr log, bool fast) - : VideoDecoder (c, log) - , AudioDecoder (c->audio, fast, log) - , SubtitleDecoder (c->subtitle) - , FFmpeg (c) + : FFmpeg (c) , _log (log) { if (c->video) { + video.reset (new VideoDecoder (this, c, log)); _pts_offset = pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate()); } else { _pts_offset = ContentTime (); } + + if (c->audio) { + audio.reset (new AudioDecoder (this, c->audio, fast, log)); + } + + if (c->subtitle) { + subtitle.reset ( + new SubtitleDecoder ( + this, + c->subtitle, + bind (&FFmpegDecoder::image_subtitles_during, this, _1, _2), + bind (&FFmpegDecoder::text_subtitles_during, this, _1, _2) + ) + ); + } } void @@ -98,7 +114,7 @@ FFmpegDecoder::flush () while (decode_video_packet ()) {} decode_audio_packet (); - AudioDecoder::flush (); + audio->flush (); } bool @@ -125,7 +141,7 @@ FFmpegDecoder::pass (PassReason reason, bool accurate) int const si = _packet.stream_index; shared_ptr fc = _ffmpeg_content; - if (_video_stream && si == _video_stream.get() && !_ignore_video && (accurate || reason != PASS_REASON_SUBTITLE)) { + if (_video_stream && si == _video_stream.get() && !video->ignore_video() && (accurate || reason != PASS_REASON_SUBTITLE)) { decode_video_packet (); } else if (fc->subtitle_stream() && fc->subtitle_stream()->uses_index (_format_context, si)) { decode_subtitle_packet (); @@ -284,9 +300,9 @@ FFmpegDecoder::bytes_per_audio_sample (shared_ptr stream) con void FFmpegDecoder::seek (ContentTime time, bool accurate) { - VideoDecoder::seek (time, accurate); - AudioDecoder::seek (time, accurate); - SubtitleDecoder::seek (time, accurate); + video->seek (time, accurate); + audio->seek (time, accurate); + subtitle->seek (time, accurate); /* If we are doing an `accurate' seek, we need to use pre-roll, as we don't really know what the seek will give us. @@ -379,7 +395,7 @@ FFmpegDecoder::decode_audio_packet () } if (data->frames() > 0) { - audio (*stream, data, ct); + audio->audio (*stream, data, ct); } } @@ -424,7 +440,7 @@ FFmpegDecoder::decode_video_packet () if (i->second != AV_NOPTS_VALUE) { double const pts = i->second * av_q2d (_format_context->streams[_video_stream.get()]->time_base) + _pts_offset.seconds (); - video ( + video->video ( shared_ptr (new RawImageProxy (image)), llrint (pts * _ffmpeg_content->active_video_frame_rate ()) ); @@ -568,7 +584,7 @@ FFmpegDecoder::decode_bitmap_subtitle (AVSubtitleRect const * rect, ContentTimeP static_cast (rect->h) / vs.height ); - image_subtitle (period, image, scaled_rect); + subtitle->image_subtitle (period, image, scaled_rect); } void @@ -635,5 +651,5 @@ FFmpegDecoder::decode_ass_subtitle (string ass, ContentTimePeriod period) } } - text_subtitle (period, ss); + subtitle->text_subtitle (period, ss); } diff --git a/src/lib/ffmpeg_decoder.h b/src/lib/ffmpeg_decoder.h index 990d643a7..40ccb9793 100644 --- a/src/lib/ffmpeg_decoder.h +++ b/src/lib/ffmpeg_decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2014 Carl Hetherington + Copyright (C) 2012-2016 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 @@ -22,9 +22,7 @@ */ #include "util.h" -#include "video_decoder.h" -#include "audio_decoder.h" -#include "subtitle_decoder.h" +#include "decoder.h" #include "ffmpeg.h" extern "C" { #include @@ -36,12 +34,13 @@ extern "C" { class Log; class VideoFilterGraph; class FFmpegAudioStream; +class AudioBuffers; struct ffmpeg_pts_offset_test; /** @class FFmpegDecoder * @brief A decoder using FFmpeg to decode content. */ -class FFmpegDecoder : public VideoDecoder, public AudioDecoder, public SubtitleDecoder, public FFmpeg +class FFmpegDecoder : public FFmpeg, public Decoder { public: FFmpegDecoder (boost::shared_ptr, boost::shared_ptr, bool fast); diff --git a/src/lib/image_decoder.cc b/src/lib/image_decoder.cc index 6c46b9c08..71157dd5d 100644 --- a/src/lib/image_decoder.cc +++ b/src/lib/image_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2012-2013 Carl Hetherington + Copyright (C) 2012-2016 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 @@ -17,16 +17,18 @@ */ -#include -#include -#include #include "image_content.h" #include "image_decoder.h" +#include "video_decoder.h" #include "image.h" #include "magick_image_proxy.h" #include "j2k_image_proxy.h" #include "film.h" #include "exceptions.h" +#include "video_content.h" +#include +#include +#include #include "i18n.h" @@ -35,11 +37,10 @@ using boost::shared_ptr; using dcp::Size; ImageDecoder::ImageDecoder (shared_ptr c, shared_ptr log) - : VideoDecoder (c, log) - , _image_content (c) + : _image_content (c) , _video_position (0) { - + video.reset (new VideoDecoder (this, c, log)); } bool @@ -62,7 +63,7 @@ ImageDecoder::pass (PassReason, bool) } } - video (_image, _video_position); + video->video (_image, _video_position); ++_video_position; return false; } @@ -70,6 +71,6 @@ ImageDecoder::pass (PassReason, bool) void ImageDecoder::seek (ContentTime time, bool accurate) { - VideoDecoder::seek (time, accurate); + video->seek (time, accurate); _video_position = time.frames_round (_image_content->active_video_frame_rate ()); } diff --git a/src/lib/image_decoder.h b/src/lib/image_decoder.h index 9d81cdac1..862baffee 100644 --- a/src/lib/image_decoder.h +++ b/src/lib/image_decoder.h @@ -17,11 +17,13 @@ */ -#include "video_decoder.h" +#include "decoder.h" class ImageContent; +class Log; +class ImageProxy; -class ImageDecoder : public VideoDecoder +class ImageDecoder : public Decoder { public: ImageDecoder (boost::shared_ptr c, boost::shared_ptr log); @@ -31,7 +33,7 @@ public: } private: - bool pass (PassReason, bool); + bool pass (Decoder::PassReason, bool); void seek (ContentTime, bool); boost::shared_ptr _image_content; diff --git a/src/lib/player.cc b/src/lib/player.cc index 2abb6a30c..ba386e39a 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -20,6 +20,7 @@ #include "player.h" #include "film.h" #include "ffmpeg_decoder.h" +#include "video_decoder.h" #include "audio_buffers.h" #include "audio_content.h" #include "ffmpeg_content.h" @@ -206,14 +207,12 @@ Player::setup_pieces () frc = FrameRateChange (dsc->active_video_frame_rate(), _film->video_frame_rate()); } - shared_ptr vd = dynamic_pointer_cast (decoder); - if (vd && _ignore_video) { - vd->set_ignore_video (); + if (decoder->video && _ignore_video) { + decoder->video->set_ignore_video (); } - shared_ptr ad = dynamic_pointer_cast (decoder); - if (ad && _ignore_audio) { - ad->set_ignore_audio (); + if (decoder->audio && _ignore_audio) { + decoder->audio->set_ignore_audio (); } _pieces.push_back (shared_ptr (new Piece (i, decoder, frc.get ()))); diff --git a/src/lib/sndfile_decoder.cc b/src/lib/sndfile_decoder.cc index b05750ac8..7762ab1e4 100644 --- a/src/lib/sndfile_decoder.cc +++ b/src/lib/sndfile_decoder.cc @@ -35,12 +35,11 @@ using boost::shared_ptr; SndfileDecoder::SndfileDecoder (shared_ptr c, bool fast, shared_ptr log) : Sndfile (c) - , AudioDecoder (c->audio, fast, log) , _done (0) , _remaining (_info.frames) , _deinterleave_buffer (0) { - + audio.reset (new AudioDecoder (this, c->audio, fast, log)); } SndfileDecoder::~SndfileDecoder () @@ -87,7 +86,7 @@ SndfileDecoder::pass (PassReason, bool) } data->set_frames (this_time); - audio (_sndfile_content->audio->stream (), data, ContentTime::from_frames (_done, _info.samplerate)); + audio->audio (_sndfile_content->audio->stream (), data, ContentTime::from_frames (_done, _info.samplerate)); _done += this_time; _remaining -= this_time; @@ -97,7 +96,7 @@ SndfileDecoder::pass (PassReason, bool) void SndfileDecoder::seek (ContentTime t, bool accurate) { - AudioDecoder::seek (t, accurate); + audio->seek (t, accurate); _done = t.frames_round (_info.samplerate); _remaining = _info.frames - _done; diff --git a/src/lib/sndfile_decoder.h b/src/lib/sndfile_decoder.h index 6f3a6cc48..d3f9342b3 100644 --- a/src/lib/sndfile_decoder.h +++ b/src/lib/sndfile_decoder.h @@ -22,7 +22,7 @@ class SndfileContent; -class SndfileDecoder : public Sndfile, public AudioDecoder +class SndfileDecoder : public Sndfile, public Decoder { public: SndfileDecoder (boost::shared_ptr c, bool fast, boost::shared_ptr log); diff --git a/src/lib/subtitle_decoder.cc b/src/lib/subtitle_decoder.cc index 454243b52..e9692b99f 100644 --- a/src/lib/subtitle_decoder.cc +++ b/src/lib/subtitle_decoder.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013-2015 Carl Hetherington + Copyright (C) 2013-2016 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 @@ -27,9 +27,18 @@ using std::list; using std::cout; using boost::shared_ptr; using boost::optional; - -SubtitleDecoder::SubtitleDecoder (shared_ptr c) - : _subtitle_content (c) +using boost::function; + +SubtitleDecoder::SubtitleDecoder ( + Decoder* parent, + shared_ptr c, + function (ContentTimePeriod, bool)> image_subtitles_during, + function (ContentTimePeriod, bool)> text_subtitles_during + ) + : _parent (parent) + , _subtitle_content (c) + , _image_subtitles_during (image_subtitles_during) + , _text_subtitles_during (text_subtitles_during) { } @@ -72,7 +81,7 @@ SubtitleDecoder::get (list const & subs, list const & sp, * (a) give us what we want, or * (b) hit the end of the decoder. */ - while (!pass(PASS_REASON_SUBTITLE, accurate) && (subs.empty() || (subs.back().period().to < sp.back().to))) {} + while (!_parent->pass(Decoder::PASS_REASON_SUBTITLE, accurate) && (subs.empty() || (subs.back().period().to < sp.back().to))) {} /* Now look for what we wanted in the data we have collected */ /* XXX: inefficient */ @@ -107,13 +116,13 @@ SubtitleDecoder::get (list const & subs, list const & sp, list SubtitleDecoder::get_text_subtitles (ContentTimePeriod period, bool starting, bool accurate) { - return get (_decoded_text_subtitles, text_subtitles_during (period, starting), period, starting, accurate); + return get (_decoded_text_subtitles, _text_subtitles_during (period, starting), period, starting, accurate); } list SubtitleDecoder::get_image_subtitles (ContentTimePeriod period, bool starting, bool accurate) { - return get (_decoded_image_subtitles, image_subtitles_during (period, starting), period, starting, accurate); + return get (_decoded_image_subtitles, _image_subtitles_during (period, starting), period, starting, accurate); } void diff --git a/src/lib/subtitle_decoder.h b/src/lib/subtitle_decoder.h index ef62d8b88..317755107 100644 --- a/src/lib/subtitle_decoder.h +++ b/src/lib/subtitle_decoder.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 Carl Hetherington + Copyright (C) 2013-2016 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 @@ -28,33 +28,43 @@ class Image; -class SubtitleDecoder : public virtual Decoder +class SubtitleDecoder { public: - SubtitleDecoder (boost::shared_ptr); + /** Second parameter to the _during functions is true if we + * want only subtitles that start during the period, + * otherwise we want subtitles that overlap the period. + */ + SubtitleDecoder ( + Decoder* parent, + boost::shared_ptr, + boost::function (ContentTimePeriod, bool)> image_subtitles_during, + boost::function (ContentTimePeriod, bool)> text_subtitles_during + ); std::list get_image_subtitles (ContentTimePeriod period, bool starting, bool accurate); std::list get_text_subtitles (ContentTimePeriod period, bool starting, bool accurate); -protected: void seek (ContentTime, bool); void image_subtitle (ContentTimePeriod period, boost::shared_ptr, dcpomatic::Rect); void text_subtitle (ContentTimePeriod period, std::list); + boost::shared_ptr content () const { + return _subtitle_content; + } + +private: + Decoder* _parent; std::list _decoded_image_subtitles; std::list _decoded_text_subtitles; boost::shared_ptr _subtitle_content; -private: template std::list get (std::list const & subs, std::list const & sp, ContentTimePeriod period, bool starting, bool accurate); - /** @param starting true if we want only subtitles that start during the period, otherwise - * we want subtitles that overlap the period. - */ - virtual std::list image_subtitles_during (ContentTimePeriod period, bool starting) const = 0; - virtual std::list text_subtitles_during (ContentTimePeriod period, bool starting) const = 0; + boost::function (ContentTimePeriod, bool)> _image_subtitles_during; + boost::function (ContentTimePeriod, bool)> _text_subtitles_during; }; #endif diff --git a/src/lib/text_subtitle_decoder.cc b/src/lib/text_subtitle_decoder.cc index 94604cd71..f76bb7f75 100644 --- a/src/lib/text_subtitle_decoder.cc +++ b/src/lib/text_subtitle_decoder.cc @@ -34,17 +34,23 @@ using boost::optional; using boost::dynamic_pointer_cast; TextSubtitleDecoder::TextSubtitleDecoder (shared_ptr content) - : SubtitleDecoder (content->subtitle) - , TextSubtitle (content) + : TextSubtitle (content) , _next (0) { - + subtitle.reset ( + new SubtitleDecoder ( + this, + content->subtitle, + bind (&TextSubtitleDecoder::image_subtitles_during, this, _1, _2), + bind (&TextSubtitleDecoder::text_subtitles_during, this, _1, _2) + ) + ); } void TextSubtitleDecoder::seek (ContentTime time, bool accurate) { - SubtitleDecoder::seek (time, accurate); + subtitle->seek (time, accurate); _next = 0; while (_next < _subtitles.size() && ContentTime::from_seconds (_subtitles[_next].from.all_as_seconds ()) < time) { @@ -79,7 +85,7 @@ TextSubtitleDecoder::pass (PassReason, bool) j.italic, j.bold, /* force the colour to whatever is configured */ - _subtitle_content->colour(), + subtitle->content()->colour(), j.font_size.points (72 * 11), 1.0, dcp::Time (_subtitles[_next].from.all_as_seconds(), 1000), @@ -93,8 +99,8 @@ TextSubtitleDecoder::pass (PassReason, bool) dcp::VALIGN_TOP, dcp::DIRECTION_LTR, j.text, - _subtitle_content->outline() ? dcp::BORDER : dcp::NONE, - _subtitle_content->outline_colour(), + subtitle->content()->outline() ? dcp::BORDER : dcp::NONE, + subtitle->content()->outline_colour(), dcp::Time (0, 1000), dcp::Time (0, 1000) ) @@ -102,7 +108,7 @@ TextSubtitleDecoder::pass (PassReason, bool) } } - text_subtitle (content_time_period (_subtitles[_next]), out); + subtitle->text_subtitle (content_time_period (_subtitles[_next]), out); ++_next; return false; diff --git a/src/lib/text_subtitle_decoder.h b/src/lib/text_subtitle_decoder.h index 67d2caca8..9e37ecc3b 100644 --- a/src/lib/text_subtitle_decoder.h +++ b/src/lib/text_subtitle_decoder.h @@ -25,7 +25,7 @@ class TextSubtitleContent; -class TextSubtitleDecoder : public SubtitleDecoder, public TextSubtitle +class TextSubtitleDecoder : public Decoder, public TextSubtitle { public: TextSubtitleDecoder (boost::shared_ptr); diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc index 8862eaa6e..fce5b367a 100644 --- a/src/lib/video_decoder.cc +++ b/src/lib/video_decoder.cc @@ -34,12 +34,14 @@ using std::back_inserter; using boost::shared_ptr; using boost::optional; -VideoDecoder::VideoDecoder (shared_ptr c, shared_ptr log) +VideoDecoder::VideoDecoder (Decoder* parent, shared_ptr c, shared_ptr log) #ifdef DCPOMATIC_DEBUG : test_gaps (0) - , _video_content (c) + , _parent (parent), + _video_content (c) #else - : _video_content (c) + : _parent (parent) + , _video_content (c) #endif , _log (log) , _last_seek_accurate (true) @@ -105,7 +107,7 @@ VideoDecoder::get_video (Frame frame, bool accurate) break; } - if (pass (PASS_REASON_VIDEO, accurate)) { + if (_parent->pass (Decoder::PASS_REASON_VIDEO, accurate)) { /* The decoder has nothing more for us */ no_data = true; break; @@ -128,7 +130,7 @@ VideoDecoder::get_video (Frame frame, bool accurate) } else { /* Any frame will do: use the first one that comes out of pass() */ - while (_decoded_video.empty() && !pass (PASS_REASON_VIDEO, accurate)) {} + while (_decoded_video.empty() && !_parent->pass (Decoder::PASS_REASON_VIDEO, accurate)) {} if (!_decoded_video.empty ()) { dec.push_back (_decoded_video.front ()); } diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h index 669a5ef1e..c14a877f2 100644 --- a/src/lib/video_decoder.h +++ b/src/lib/video_decoder.h @@ -39,20 +39,22 @@ class Log; /** @class VideoDecoder * @brief Parent for classes which decode video. */ -class VideoDecoder : public virtual Decoder +class VideoDecoder { public: - VideoDecoder (boost::shared_ptr c, boost::shared_ptr log); + VideoDecoder (Decoder* parent, boost::shared_ptr c, boost::shared_ptr log); std::list get_video (Frame frame, bool accurate); void set_ignore_video (); + bool ignore_video () const { + return _ignore_video; + } #ifdef DCPOMATIC_DEBUG int test_gaps; #endif -protected: friend struct video_decoder_fill_test1; friend struct video_decoder_fill_test2; friend struct ffmpeg_pts_offset_test; @@ -60,10 +62,14 @@ protected: void seek (ContentTime time, bool accurate); void video (boost::shared_ptr, Frame frame); + +private: + std::list decoded_video (Frame frame); void fill_one_eye (Frame from, Frame to, Eyes); void fill_both_eyes (Frame from, Frame to, Eyes); + Decoder* _parent; boost::shared_ptr _video_content; boost::shared_ptr _log; std::list _decoded_video; diff --git a/src/wx/subtitle_panel.cc b/src/wx/subtitle_panel.cc index 3a0063c95..1d6325dfd 100644 --- a/src/wx/subtitle_panel.cc +++ b/src/wx/subtitle_panel.cc @@ -377,7 +377,7 @@ SubtitlePanel::subtitle_view_clicked () ContentList c = _parent->selected_subtitle (); DCPOMATIC_ASSERT (c.size() == 1); - shared_ptr decoder; + shared_ptr decoder; shared_ptr sr = dynamic_pointer_cast (c.front ()); if (sr) { diff --git a/src/wx/subtitle_view.cc b/src/wx/subtitle_view.cc index 916f1eedc..a33a401df 100644 --- a/src/wx/subtitle_view.cc +++ b/src/wx/subtitle_view.cc @@ -28,7 +28,7 @@ using std::list; using boost::shared_ptr; using boost::dynamic_pointer_cast; -SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr decoder, DCPTime position) +SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr decoder, DCPTime position) : wxDialog (parent, wxID_ANY, _("Subtitles"), wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) { _list = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); @@ -65,7 +65,7 @@ SubtitleView::SubtitleView (wxWindow* parent, shared_ptr film, shared_ptr< sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); } - list subs = decoder->get_text_subtitles (ContentTimePeriod (ContentTime(), ContentTime::max ()), true, true); + list subs = decoder->subtitle->get_text_subtitles (ContentTimePeriod (ContentTime(), ContentTime::max ()), true, true); FrameRateChange const frc = film->active_frame_rate_change (position); int n = 0; for (list::const_iterator i = subs.begin(); i != subs.end(); ++i) { diff --git a/src/wx/subtitle_view.h b/src/wx/subtitle_view.h index f5a61890b..d95f26668 100644 --- a/src/wx/subtitle_view.h +++ b/src/wx/subtitle_view.h @@ -1,5 +1,5 @@ /* - Copyright (C) 2014 Carl Hetherington + Copyright (C) 2014-2016 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 @@ -21,12 +21,12 @@ #include #include -class SubtitleDecoder; +class Decoder; class SubtitleView : public wxDialog { public: - SubtitleView (wxWindow *, boost::shared_ptr, boost::shared_ptr, DCPTime position); + SubtitleView (wxWindow *, boost::shared_ptr, boost::shared_ptr, DCPTime position); private: wxListCtrl* _list; diff --git a/test/audio_decoder_test.cc b/test/audio_decoder_test.cc index 21480a5c3..5eabc4074 100644 --- a/test/audio_decoder_test.cc +++ b/test/audio_decoder_test.cc @@ -58,14 +58,15 @@ public: } }; -class TestAudioDecoder : public AudioDecoder +class TestAudioDecoder : public Decoder { public: TestAudioDecoder (shared_ptr content, shared_ptr log) - : AudioDecoder (content->audio, false, log) - , _test_audio_content (content) + : _test_audio_content (content) , _position (0) - {} + { + audio.reset (new AudioDecoder (this, content->audio, false, log)); + } bool pass (PassReason, bool) { @@ -81,7 +82,7 @@ public: } } - audio (_test_audio_content->audio->stream(), buffers, ContentTime::from_frames (_position, 48000)); + audio->audio (_test_audio_content->audio->stream(), buffers, ContentTime::from_frames (_position, 48000)); _position += N; return N < 2000; @@ -89,7 +90,7 @@ public: void seek (ContentTime t, bool accurate) { - AudioDecoder::seek (t, accurate); + audio->seek (t, accurate); _position = t.frames_round (_test_audio_content->audio->resampled_frame_rate ()); } @@ -105,7 +106,7 @@ static ContentAudio get (Frame from, Frame length) { decoder->seek (ContentTime::from_frames (from, content->audio->resampled_frame_rate ()), true); - ContentAudio ca = decoder->get_audio (content->audio->stream(), from, length, true); + ContentAudio ca = decoder->audio->get_audio (content->audio->stream(), from, length, true); BOOST_CHECK_EQUAL (ca.frame, from); return ca; } diff --git a/test/dcp_subtitle_test.cc b/test/dcp_subtitle_test.cc index 8a4677162..80e0a3dd1 100644 --- a/test/dcp_subtitle_test.cc +++ b/test/dcp_subtitle_test.cc @@ -29,6 +29,8 @@ #include "lib/dcp_decoder.h" #include "lib/dcp_content_type.h" #include "lib/subtitle_content.h" +#include "lib/content_subtitle.h" +#include "lib/subtitle_decoder.h" #include "test.h" #include @@ -84,7 +86,7 @@ BOOST_AUTO_TEST_CASE (dcp_subtitle_within_dcp_test) BOOST_CHECK_EQUAL (ctp.back().from, ContentTime::from_seconds (25 + 12 * 0.04)); BOOST_CHECK_EQUAL (ctp.back().to, ContentTime::from_seconds (26 + 4 * 0.04)); - list subs = decoder->get_text_subtitles ( + list subs = decoder->subtitle->get_text_subtitles ( ContentTimePeriod ( ContentTime::from_seconds (25), ContentTime::from_seconds (26) diff --git a/test/ffmpeg_decoder_seek_test.cc b/test/ffmpeg_decoder_seek_test.cc index 2a9b4da71..83efc4201 100644 --- a/test/ffmpeg_decoder_seek_test.cc +++ b/test/ffmpeg_decoder_seek_test.cc @@ -29,6 +29,8 @@ #include "lib/ffmpeg_decoder.h" #include "lib/null_log.h" #include "lib/film.h" +#include "lib/content_video.h" +#include "lib/video_decoder.h" #include "test.h" #include #include @@ -44,7 +46,7 @@ static void check (shared_ptr decoder, int frame) { list v; - v = decoder->get_video (frame, true); + v = decoder->video->get_video (frame, true); BOOST_CHECK (v.size() == 1); BOOST_CHECK_EQUAL (v.front().frame, frame); } diff --git a/test/ffmpeg_decoder_sequential_test.cc b/test/ffmpeg_decoder_sequential_test.cc index ac3064aa0..e1e29ab17 100644 --- a/test/ffmpeg_decoder_sequential_test.cc +++ b/test/ffmpeg_decoder_sequential_test.cc @@ -25,6 +25,8 @@ #include "lib/ffmpeg_content.h" #include "lib/ffmpeg_decoder.h" #include "lib/null_log.h" +#include "lib/content_video.h" +#include "lib/video_decoder.h" #include "lib/film.h" #include "test.h" #include @@ -53,20 +55,20 @@ ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int shared_ptr log (new NullLog); shared_ptr decoder (new FFmpegDecoder (content, log, false)); - BOOST_REQUIRE (decoder->_video_content->video_frame_rate()); - BOOST_CHECK_CLOSE (decoder->_video_content->video_frame_rate().get(), fps, 0.01); + BOOST_REQUIRE (decoder->video->_video_content->video_frame_rate()); + BOOST_CHECK_CLOSE (decoder->video->_video_content->video_frame_rate().get(), fps, 0.01); #ifdef DCPOMATIC_DEBUG - decoder->test_gaps = 0; + decoder->video->test_gaps = 0; #endif for (Frame i = 0; i < video_length; ++i) { list v; - v = decoder->get_video (i, true); + v = decoder->video->get_video (i, true); BOOST_REQUIRE_EQUAL (v.size(), 1U); BOOST_CHECK_EQUAL (v.front().frame, i); } #ifdef DCPOMATIC_DEBUG - BOOST_CHECK_EQUAL (decoder->test_gaps, gaps); + BOOST_CHECK_EQUAL (decoder->video->test_gaps, gaps); #endif } diff --git a/test/seek_zero_test.cc b/test/seek_zero_test.cc index 332c39db9..0c65fa3b8 100644 --- a/test/seek_zero_test.cc +++ b/test/seek_zero_test.cc @@ -30,6 +30,9 @@ #include "lib/ffmpeg_decoder.h" #include "lib/ffmpeg_audio_stream.h" #include "lib/content_video.h" +#include "lib/video_content_scale.h" +#include "lib/video_content.h" +#include "lib/video_decoder.h" #include "test.h" #include @@ -61,7 +64,7 @@ BOOST_AUTO_TEST_CASE (seek_zero_test) Frame const first_frame = video_delay.round_up (content->active_video_frame_rate ()).frames_round (content->active_video_frame_rate ()); FFmpegDecoder decoder (content, film->log(), false); - list a = decoder.get_video (first_frame, true); + list a = decoder.video->get_video (first_frame, true); BOOST_CHECK (a.size() == 1); BOOST_CHECK_EQUAL (a.front().frame, first_frame); } diff --git a/test/video_decoder_fill_test.cc b/test/video_decoder_fill_test.cc index 190a469d0..539392718 100644 --- a/test/video_decoder_fill_test.cc +++ b/test/video_decoder_fill_test.cc @@ -20,6 +20,8 @@ #include #include "lib/image_decoder.h" #include "lib/image_content.h" +#include "lib/content_video.h" +#include "lib/video_decoder.h" #include "lib/film.h" #include "test.h" #include @@ -34,19 +36,19 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test1) shared_ptr c (new ImageContent (film, "test/data/simple_testcard_640x480.png")); ImageDecoder decoder (c, film->log()); - decoder.fill_one_eye (0, 4, EYES_BOTH); - BOOST_CHECK_EQUAL (decoder._decoded_video.size(), 4U); - list::iterator i = decoder._decoded_video.begin(); + decoder.video->fill_one_eye (0, 4, EYES_BOTH); + BOOST_CHECK_EQUAL (decoder.video->_decoded_video.size(), 4U); + list::iterator i = decoder.video->_decoded_video.begin(); for (int j = 0; j < 4; ++j) { BOOST_CHECK_EQUAL (i->frame, j); ++i; } - decoder._decoded_video.clear (); + decoder.video->_decoded_video.clear (); - decoder.fill_one_eye (0, 7, EYES_BOTH); - BOOST_CHECK_EQUAL (decoder._decoded_video.size(), 7); - i = decoder._decoded_video.begin(); + decoder.video->fill_one_eye (0, 7, EYES_BOTH); + BOOST_CHECK_EQUAL (decoder.video->_decoded_video.size(), 7); + i = decoder.video->_decoded_video.begin(); for (int j = 0; j < 7; ++j) { BOOST_CHECK_EQUAL (i->frame, j); ++i; @@ -59,18 +61,18 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test2) shared_ptr c (new ImageContent (film, "test/data/simple_testcard_640x480.png")); ImageDecoder decoder (c, film->log()); - decoder.fill_both_eyes (0, 4, EYES_LEFT); - BOOST_CHECK_EQUAL (decoder._decoded_video.size(), 8); - list::iterator i = decoder._decoded_video.begin(); + decoder.video->fill_both_eyes (0, 4, EYES_LEFT); + BOOST_CHECK_EQUAL (decoder.video->_decoded_video.size(), 8); + list::iterator i = decoder.video->_decoded_video.begin(); for (int j = 0; j < 8; ++j) { BOOST_CHECK_EQUAL (i->frame, j / 2); BOOST_CHECK_EQUAL (i->eyes, (j % 2) == 0 ? EYES_LEFT : EYES_RIGHT); ++i; } - decoder.fill_both_eyes (0, 7, EYES_RIGHT); - BOOST_CHECK_EQUAL (decoder._decoded_video.size(), 15); - i = decoder._decoded_video.begin(); + decoder.video->fill_both_eyes (0, 7, EYES_RIGHT); + BOOST_CHECK_EQUAL (decoder.video->_decoded_video.size(), 15); + i = decoder.video->_decoded_video.begin(); for (int j = 0; j < 15; ++j) { BOOST_CHECK_EQUAL (i->frame, j / 2); BOOST_CHECK_EQUAL (i->eyes, (j % 2) == 0 ? EYES_LEFT : EYES_RIGHT);