Basics of splitting up Decoder tree like Content.
authorCarl Hetherington <cth@carlh.net>
Tue, 10 May 2016 13:29:14 +0000 (14:29 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 18 May 2016 10:50:29 +0000 (11:50 +0100)
31 files changed:
src/lib/audio_decoder.cc
src/lib/audio_decoder.h
src/lib/audio_decoder_stream.cc
src/lib/audio_decoder_stream.h
src/lib/dcp_decoder.cc
src/lib/dcp_decoder.h
src/lib/dcp_subtitle_decoder.cc
src/lib/dcp_subtitle_decoder.h
src/lib/decoder.h
src/lib/ffmpeg_decoder.cc
src/lib/ffmpeg_decoder.h
src/lib/image_decoder.cc
src/lib/image_decoder.h
src/lib/player.cc
src/lib/sndfile_decoder.cc
src/lib/sndfile_decoder.h
src/lib/subtitle_decoder.cc
src/lib/subtitle_decoder.h
src/lib/text_subtitle_decoder.cc
src/lib/text_subtitle_decoder.h
src/lib/video_decoder.cc
src/lib/video_decoder.h
src/wx/subtitle_panel.cc
src/wx/subtitle_view.cc
src/wx/subtitle_view.h
test/audio_decoder_test.cc
test/dcp_subtitle_test.cc
test/ffmpeg_decoder_seek_test.cc
test/ffmpeg_decoder_sequential_test.cc
test/seek_zero_test.cc
test/video_decoder_fill_test.cc

index 705fdbef1cf32ecaca36cac604bfddcd83b3317f..7ceb9680bf95b3be487ed6d3dd42e7ce4ece58b3 100644 (file)
@@ -30,13 +30,13 @@ using std::cout;
 using std::map;
 using boost::shared_ptr;
 
-AudioDecoder::AudioDecoder (shared_ptr<const AudioContent> content, bool fast, shared_ptr<Log> log)
+AudioDecoder::AudioDecoder (Decoder* parent, shared_ptr<const AudioContent> content, bool fast, shared_ptr<Log> log)
        : _audio_content (content)
        , _ignore_audio (false)
        , _fast (fast)
 {
        BOOST_FOREACH (AudioStreamPtr i, content->streams ()) {
-               _streams[i] = shared_ptr<AudioDecoderStream> (new AudioDecoderStream (_audio_content, i, this, log));
+               _streams[i] = shared_ptr<AudioDecoderStream> (new AudioDecoderStream (_audio_content, i, parent, log));
        }
 }
 
index 31d0785c6cbc9c9aab196cbb480e85e5fcf6b420..a56847daf293588c0003b166c9054d0188e61f8a 100644 (file)
@@ -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<AudioDecoder>
+class AudioDecoder : public boost::enable_shared_from_this<AudioDecoder>
 {
 public:
-       AudioDecoder (boost::shared_ptr<const AudioContent>, bool fast, boost::shared_ptr<Log> log);
+       AudioDecoder (Decoder* parent, boost::shared_ptr<const AudioContent>, bool fast, boost::shared_ptr<Log> 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<const AudioBuffers>, ContentTime);
        void flush ();
        void seek (ContentTime t, bool accurate);
index cd2e3a38811d8fe9794564aa17ed7b72c7c45dbe..bbe26b6eff86cc75057f7e5595eb775e495d61bc 100644 (file)
@@ -39,14 +39,14 @@ using std::max;
 using boost::optional;
 using boost::shared_ptr;
 
-AudioDecoderStream::AudioDecoderStream (shared_ptr<const AudioContent> content, AudioStreamPtr stream, AudioDecoder* decoder, shared_ptr<Log> log)
+AudioDecoderStream::AudioDecoderStream (shared_ptr<const AudioContent> content, AudioStreamPtr stream, Decoder* decoder, shared_ptr<Log> 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 ();
index 90269a0f41d132e1f8303fd687926c27dd5ff663..265bbe0044f36479569e59e626b547206acd91e8 100644 (file)
@@ -29,11 +29,12 @@ class AudioContent;
 class AudioDecoder;
 class Resampler;
 class Log;
+class Decoder;
 
 class AudioDecoderStream
 {
 public:
-       AudioDecoderStream (boost::shared_ptr<const AudioContent>, AudioStreamPtr, AudioDecoder* decoder, boost::shared_ptr<Log> log);
+       AudioDecoderStream (boost::shared_ptr<const AudioContent>, AudioStreamPtr, Decoder* decoder, boost::shared_ptr<Log> log);
 
        ContentAudio get (Frame time, Frame length, bool accurate);
        void audio (boost::shared_ptr<const AudioBuffers>, ContentTime);
@@ -47,7 +48,7 @@ private:
 
        boost::shared_ptr<const AudioContent> _content;
        AudioStreamPtr _stream;
-       AudioDecoder* _decoder;
+       Decoder* _decoder;
        boost::shared_ptr<Log> _log;
        boost::shared_ptr<Resampler> _resampler;
        boost::optional<Frame> _position;
index 8008fe515590fa52df974e4e14ac4f59e3eaff56..2a769166692b8064ec288210ea0b2dc377949086 100644 (file)
 #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 <dcp/dcp.h>
@@ -44,11 +47,20 @@ using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
 DCPDecoder::DCPDecoder (shared_ptr<const DCPContent> c, shared_ptr<Log> 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<dcp::StereoPictureAsset> stereo = dynamic_pointer_cast<dcp::StereoPictureAsset> (asset);
                int64_t const entry_point = (*_reel)->main_picture()->entry_point ();
                if (mono) {
-                       video (shared_ptr<ImageProxy> (new J2KImageProxy (mono->get_frame (entry_point + frame), asset->size())), offset + frame);
+                       video->video (shared_ptr<ImageProxy> (new J2KImageProxy (mono->get_frame (entry_point + frame), asset->size())), offset + frame);
                } else {
-                       video (
+                       video->video (
                                shared_ptr<ImageProxy> (new J2KImageProxy (stereo->get_frame (entry_point + frame), asset->size(), dcp::EYE_LEFT)),
                                offset + frame
                                );
 
-                       video (
+                       video->video (
                                shared_ptr<ImageProxy> (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 ())) {
index ce9a3ef9af3dd7af03e311f2052f58a4abdf8b36..6e58c490453cb1dfaf1de29fb5a483bd18db1f20 100644 (file)
  *  @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<const DCPContent>, boost::shared_ptr<Log> log, bool fast);
index 964ee6f202cea7e8ef0b5d503dab34ac07b446fb..23f5dd52992e224f1ef8fbf0b6b1978fc367040b 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
 
     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
 using std::list;
 using std::cout;
 using boost::shared_ptr;
+using boost::bind;
 
 DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr<const DCPSubtitleContent> 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<dcp::SubtitleAsset> c (load (content->path (0)));
        _subtitles = c->subtitles ();
        _next = _subtitles.begin ();
@@ -37,7 +46,7 @@ DCPSubtitleDecoder::DCPSubtitleDecoder (shared_ptr<const DCPSubtitleContent> con
 void
 DCPSubtitleDecoder::seek (ContentTime time, bool accurate)
 {
-       SubtitleDecoder::seek (time, accurate);
+       subtitle->seek (time, accurate);
 
        _next = _subtitles.begin ();
        list<dcp::SubtitleString>::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;
 }
index 1f53776228fcb7513fb0012f4f4c88c39d3c2843..fcefc0201c492326c8a44655f353546c8969afa2 100644 (file)
@@ -22,7 +22,7 @@
 
 class DCPSubtitleContent;
 
-class DCPSubtitleDecoder : public SubtitleDecoder, public DCPSubtitle
+class DCPSubtitleDecoder : public DCPSubtitle, public Decoder
 {
 public:
        DCPSubtitleDecoder (boost::shared_ptr<const DCPSubtitleContent>);
index 10bb4531032e4d0068340b14c985d9b401ac2fb5..979c6cf582777766b867212a61cc67a7a174890f 100644 (file)
@@ -29,6 +29,9 @@
 #include <boost/utility.hpp>
 
 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<VideoDecoder> video;
+       boost::shared_ptr<AudioDecoder> audio;
+       boost::shared_ptr<SubtitleDecoder> 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;
 };
index d84bb2a52e67d1aead102d5af1242cb474e1a433..2f123e484eb5786115e95ad78c31825c8c498fe9 100644 (file)
 #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 <dcp/subtitle_string.h>
 #include <sub/ssa_reader.h>
@@ -72,17 +75,30 @@ using boost::split;
 using dcp::Size;
 
 FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> 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<const FFmpegContent> 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<FFmpegAudioStream> 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<ImageProxy> (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<double> (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);
 }
index 990d643a704d6ab5223cdb2bebc9467d736f18e6..40ccb9793e57290d971253ec38c6164255fc2f6b 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     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 <libavcodec/avcodec.h>
@@ -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<const FFmpegContent>, boost::shared_ptr<Log>, bool fast);
index 6c46b9c08597090f0af2497e456afe68ab0fd667..71157dd5dcaa8b54eaf980c5f8a54ae18e61e8de 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     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
 
 */
 
-#include <iostream>
-#include <boost/filesystem.hpp>
-#include <Magick++.h>
 #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 <Magick++.h>
+#include <boost/filesystem.hpp>
+#include <iostream>
 
 #include "i18n.h"
 
@@ -35,11 +37,10 @@ using boost::shared_ptr;
 using dcp::Size;
 
 ImageDecoder::ImageDecoder (shared_ptr<const ImageContent> c, shared_ptr<Log> 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 ());
 }
index 9d81cdac18248087a9a4982c0c97fa59eedd3632..862baffee9aa9cfa381449680d51b972e9091dcf 100644 (file)
 
 */
 
-#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<const ImageContent> c, boost::shared_ptr<Log> log);
@@ -31,7 +33,7 @@ public:
        }
 
 private:
-       bool pass (PassReason, bool);
+       bool pass (Decoder::PassReason, bool);
        void seek (ContentTime, bool);
 
        boost::shared_ptr<const ImageContent> _image_content;
index 2abb6a30c2a6d3a53b45eea27104f65b3b180d67..ba386e39aaa7ef44caa55bdf0d8aa662a295ecef 100644 (file)
@@ -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<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (decoder);
-               if (vd && _ignore_video) {
-                       vd->set_ignore_video ();
+               if (decoder->video && _ignore_video) {
+                       decoder->video->set_ignore_video ();
                }
 
-               shared_ptr<AudioDecoder> ad = dynamic_pointer_cast<AudioDecoder> (decoder);
-               if (ad && _ignore_audio) {
-                       ad->set_ignore_audio ();
+               if (decoder->audio && _ignore_audio) {
+                       decoder->audio->set_ignore_audio ();
                }
 
                _pieces.push_back (shared_ptr<Piece> (new Piece (i, decoder, frc.get ())));
index b05750ac8dc3aa7675fcd677b4da070a58a157ae..7762ab1e4c037b9b8d49c33213fc9ed05ebca5d3 100644 (file)
@@ -35,12 +35,11 @@ using boost::shared_ptr;
 
 SndfileDecoder::SndfileDecoder (shared_ptr<const SndfileContent> c, bool fast, shared_ptr<Log> 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;
index 6f3a6cc48df47ef366eeea49661c69ae6e74c6b9..d3f9342b3a0ca6a71ea02350049042bfe04a8dd1 100644 (file)
@@ -22,7 +22,7 @@
 
 class SndfileContent;
 
-class SndfileDecoder : public Sndfile, public AudioDecoder
+class SndfileDecoder : public Sndfile, public Decoder
 {
 public:
        SndfileDecoder (boost::shared_ptr<const SndfileContent> c, bool fast, boost::shared_ptr<Log> log);
index 454243b524d279b65eeaa7b57eacdc4f43cabab9..e9692b99f586f752a53928f9f2492b1716d12e5b 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013-2015 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
 
     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<const SubtitleContent> c)
-       : _subtitle_content (c)
+using boost::function;
+
+SubtitleDecoder::SubtitleDecoder (
+       Decoder* parent,
+       shared_ptr<const SubtitleContent> c,
+       function<list<ContentTimePeriod> (ContentTimePeriod, bool)> image_subtitles_during,
+       function<list<ContentTimePeriod> (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<T> const & subs, list<ContentTimePeriod> 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<T> const & subs, list<ContentTimePeriod> const & sp,
 list<ContentTextSubtitle>
 SubtitleDecoder::get_text_subtitles (ContentTimePeriod period, bool starting, bool accurate)
 {
-       return get<ContentTextSubtitle> (_decoded_text_subtitles, text_subtitles_during (period, starting), period, starting, accurate);
+       return get<ContentTextSubtitle> (_decoded_text_subtitles, _text_subtitles_during (period, starting), period, starting, accurate);
 }
 
 list<ContentImageSubtitle>
 SubtitleDecoder::get_image_subtitles (ContentTimePeriod period, bool starting, bool accurate)
 {
-       return get<ContentImageSubtitle> (_decoded_image_subtitles, image_subtitles_during (period, starting), period, starting, accurate);
+       return get<ContentImageSubtitle> (_decoded_image_subtitles, _image_subtitles_during (period, starting), period, starting, accurate);
 }
 
 void
index ef62d8b88355f73c6a6f4e308e036664296fce1c..317755107abaca3b6445c972ea56ae68c84aa6b2 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2013 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2013-2016 Carl Hetherington <cth@carlh.net>
 
     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
 
 class Image;
 
-class SubtitleDecoder : public virtual Decoder
+class SubtitleDecoder
 {
 public:
-       SubtitleDecoder (boost::shared_ptr<const SubtitleContent>);
+       /** 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<const SubtitleContent>,
+               boost::function<std::list<ContentTimePeriod> (ContentTimePeriod, bool)> image_subtitles_during,
+               boost::function<std::list<ContentTimePeriod> (ContentTimePeriod, bool)> text_subtitles_during
+               );
 
        std::list<ContentImageSubtitle> get_image_subtitles (ContentTimePeriod period, bool starting, bool accurate);
        std::list<ContentTextSubtitle> get_text_subtitles (ContentTimePeriod period, bool starting, bool accurate);
 
-protected:
        void seek (ContentTime, bool);
 
        void image_subtitle (ContentTimePeriod period, boost::shared_ptr<Image>, dcpomatic::Rect<double>);
        void text_subtitle (ContentTimePeriod period, std::list<dcp::SubtitleString>);
 
+       boost::shared_ptr<const SubtitleContent> content () const {
+               return _subtitle_content;
+       }
+
+private:
+       Decoder* _parent;
        std::list<ContentImageSubtitle> _decoded_image_subtitles;
        std::list<ContentTextSubtitle> _decoded_text_subtitles;
        boost::shared_ptr<const SubtitleContent> _subtitle_content;
 
-private:
        template <class T>
        std::list<T> get (std::list<T> const & subs, std::list<ContentTimePeriod> 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<ContentTimePeriod> image_subtitles_during (ContentTimePeriod period, bool starting) const = 0;
-       virtual std::list<ContentTimePeriod> text_subtitles_during (ContentTimePeriod period, bool starting) const = 0;
+       boost::function<std::list<ContentTimePeriod> (ContentTimePeriod, bool)> _image_subtitles_during;
+       boost::function<std::list<ContentTimePeriod> (ContentTimePeriod, bool)> _text_subtitles_during;
 };
 
 #endif
index 94604cd714aae108dfd297ce6ed3a96ba5fd78e9..f76bb7f75f60b9578c5f3fd9a6a0d7326df9dfc2 100644 (file)
@@ -34,17 +34,23 @@ using boost::optional;
 using boost::dynamic_pointer_cast;
 
 TextSubtitleDecoder::TextSubtitleDecoder (shared_ptr<const TextSubtitleContent> 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;
index 67d2caca826971d85599f2daa308524aa4383921..9e37ecc3bcfc3e09711e5c3182d1fca84c686bb4 100644 (file)
@@ -25,7 +25,7 @@
 
 class TextSubtitleContent;
 
-class TextSubtitleDecoder : public SubtitleDecoder, public TextSubtitle
+class TextSubtitleDecoder : public Decoder, public TextSubtitle
 {
 public:
        TextSubtitleDecoder (boost::shared_ptr<const TextSubtitleContent>);
index 8862eaa6e5a8abaa68140260db7c65a728485234..fce5b367ab00b4ceb7cb2d61c7c6656c3353f641 100644 (file)
@@ -34,12 +34,14 @@ using std::back_inserter;
 using boost::shared_ptr;
 using boost::optional;
 
-VideoDecoder::VideoDecoder (shared_ptr<const Content> c, shared_ptr<Log> log)
+VideoDecoder::VideoDecoder (Decoder* parent, shared_ptr<const Content> c, shared_ptr<Log> 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 ());
                }
index 669a5ef1edc0a87b793f3ceb9f81264525348dfb..c14a877f267e793ad2d4fd6ffc0728a7801c6184 100644 (file)
@@ -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<const Content> c, boost::shared_ptr<Log> log);
+       VideoDecoder (Decoder* parent, boost::shared_ptr<const Content> c, boost::shared_ptr<Log> log);
 
        std::list<ContentVideo> 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<const ImageProxy>, Frame frame);
+
+private:
+
        std::list<ContentVideo> 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<const Content> _video_content;
        boost::shared_ptr<Log> _log;
        std::list<ContentVideo> _decoded_video;
index 3a0063c952315cf8a4287e1d39c638e9f5cbe12a..1d6325dfd1a7209433494351f5b92ad255c94ee6 100644 (file)
@@ -377,7 +377,7 @@ SubtitlePanel::subtitle_view_clicked ()
        ContentList c = _parent->selected_subtitle ();
        DCPOMATIC_ASSERT (c.size() == 1);
 
-       shared_ptr<SubtitleDecoder> decoder;
+       shared_ptr<Decoder> decoder;
 
        shared_ptr<TextSubtitleContent> sr = dynamic_pointer_cast<TextSubtitleContent> (c.front ());
        if (sr) {
index 916f1eedcdf39ea1afedba5b0ceca5a0399e25f9..a33a401df2fb087617709a3daa055d84d566b01d 100644 (file)
@@ -28,7 +28,7 @@ using std::list;
 using boost::shared_ptr;
 using boost::dynamic_pointer_cast;
 
-SubtitleView::SubtitleView (wxWindow* parent, shared_ptr<Film> film, shared_ptr<SubtitleDecoder> decoder, DCPTime position)
+SubtitleView::SubtitleView (wxWindow* parent, shared_ptr<Film> film, shared_ptr<Decoder> 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> film, shared_ptr<
                sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
        }
 
-       list<ContentTextSubtitle> subs = decoder->get_text_subtitles (ContentTimePeriod (ContentTime(), ContentTime::max ()), true, true);
+       list<ContentTextSubtitle> 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<ContentTextSubtitle>::const_iterator i = subs.begin(); i != subs.end(); ++i) {
index f5a61890bba83c48068b55b133bb68790f4dcbcd..d95f26668b63f9a06dd9ec84e1277151c7e41ea7 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2014 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2014-2016 Carl Hetherington <cth@carlh.net>
 
     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
 #include <wx/wx.h>
 #include <wx/listctrl.h>
 
-class SubtitleDecoder;
+class Decoder;
 
 class SubtitleView : public wxDialog
 {
 public:
-       SubtitleView (wxWindow *, boost::shared_ptr<Film>, boost::shared_ptr<SubtitleDecoder>, DCPTime position);
+       SubtitleView (wxWindow *, boost::shared_ptr<Film>, boost::shared_ptr<Decoder>, DCPTime position);
 
 private:
        wxListCtrl* _list;
index 21480a5c3f1da89c5246054f4e217039786680ec..5eabc4074c80abf25c15b4b3524af062cb2b1ebe 100644 (file)
@@ -58,14 +58,15 @@ public:
        }
 };
 
-class TestAudioDecoder : public AudioDecoder
+class TestAudioDecoder : public Decoder
 {
 public:
        TestAudioDecoder (shared_ptr<TestAudioContent> content, shared_ptr<Log> 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;
 }
index 8a46771620a32ff191fd405679e0e9847f5db3b1..80e0a3dd1a12704e68d6695a1c17d505763ee6e5 100644 (file)
@@ -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 <iostream>
 
@@ -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<ContentTextSubtitle> subs = decoder->get_text_subtitles (
+       list<ContentTextSubtitle> subs = decoder->subtitle->get_text_subtitles (
                ContentTimePeriod (
                        ContentTime::from_seconds (25),
                        ContentTime::from_seconds (26)
index 2a9b4da715ed35ef2cab298f8b654a2759911157..83efc4201f3ac675421fb641d2ed0b39787e0e13 100644 (file)
@@ -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 <boost/test/unit_test.hpp>
 #include <boost/filesystem.hpp>
@@ -44,7 +46,7 @@ static void
 check (shared_ptr<FFmpegDecoder> decoder, int frame)
 {
        list<ContentVideo> 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);
 }
index ac3064aa04b9e9610af8ce3bfddc60dac832d015..e1e29ab17ab02d9c462d68923038b1d93ac55273 100644 (file)
@@ -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 <boost/filesystem.hpp>
@@ -53,20 +55,20 @@ ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int
        shared_ptr<Log> log (new NullLog);
        shared_ptr<FFmpegDecoder> 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<ContentVideo> 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
 }
 
index 332c39db9f2093e24766409dd4ed2143c0a06d21..0c65fa3b8aacc25e444d6853c2de5bc83e2d8cc6 100644 (file)
@@ -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 <iostream>
 
@@ -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<ContentVideo> a = decoder.get_video (first_frame, true);
+       list<ContentVideo> a = decoder.video->get_video (first_frame, true);
        BOOST_CHECK (a.size() == 1);
        BOOST_CHECK_EQUAL (a.front().frame, first_frame);
 }
index 190a469d0e8494577014043ec2d3838efb9b7412..53939271833460d256d54a6ff82779ab1221f229 100644 (file)
@@ -20,6 +20,8 @@
 #include <boost/test/unit_test.hpp>
 #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 <iostream>
@@ -34,19 +36,19 @@ BOOST_AUTO_TEST_CASE (video_decoder_fill_test1)
        shared_ptr<ImageContent> 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<ContentVideo>::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<ContentVideo>::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<ImageContent> 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<ContentVideo>::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<ContentVideo>::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);