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));
}
}
/** @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)
return _fast;
}
-protected:
void audio (AudioStreamPtr stream, boost::shared_ptr<const AudioBuffers>, ContentTime);
void flush ();
void seek (ContentTime t, bool accurate);
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 ();
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);
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;
#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>
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 ()) {
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
);
}
}
- 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 ()) {
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 ())
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 ())) {
* @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);
/*
- 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 ();
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 ();
++_next;
}
- text_subtitle (p, s);
+ subtitle->text_subtitle (p, s);
return false;
}
class DCPSubtitleContent;
-class DCPSubtitleDecoder : public SubtitleDecoder, public DCPSubtitle
+class DCPSubtitleDecoder : public DCPSubtitle, public Decoder
{
public:
DCPSubtitleDecoder (boost::shared_ptr<const DCPSubtitleContent>);
#include <boost/utility.hpp>
class Decoded;
+class VideoDecoder;
+class AudioDecoder;
+class SubtitleDecoder;
/** @class Decoder.
* @brief Parent class for decoders of content.
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
*/
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;
};
#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>
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
while (decode_video_packet ()) {}
decode_audio_packet ();
- AudioDecoder::flush ();
+ audio->flush ();
}
bool
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 ();
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.
}
if (data->frames() > 0) {
- audio (*stream, data, ct);
+ audio->audio (*stream, data, ct);
}
}
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 ())
);
static_cast<double> (rect->h) / vs.height
);
- image_subtitle (period, image, scaled_rect);
+ subtitle->image_subtitle (period, image, scaled_rect);
}
void
}
}
- text_subtitle (period, ss);
+ subtitle->text_subtitle (period, ss);
}
/*
- 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
*/
#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>
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);
/*
- 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"
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
}
}
- video (_image, _video_position);
+ video->video (_image, _video_position);
++_video_position;
return false;
}
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 ());
}
*/
-#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);
}
private:
- bool pass (PassReason, bool);
+ bool pass (Decoder::PassReason, bool);
void seek (ContentTime, bool);
boost::shared_ptr<const ImageContent> _image_content;
#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"
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 ())));
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 ()
}
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;
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;
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);
/*
- 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
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)
{
}
* (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 */
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
/*
- 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
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) {
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),
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)
)
}
}
- text_subtitle (content_time_period (_subtitles[_next]), out);
+ subtitle->text_subtitle (content_time_period (_subtitles[_next]), out);
++_next;
return false;
class TextSubtitleContent;
-class TextSubtitleDecoder : public SubtitleDecoder, public TextSubtitle
+class TextSubtitleDecoder : public Decoder, public TextSubtitle
{
public:
TextSubtitleDecoder (boost::shared_ptr<const TextSubtitleContent>);
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)
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;
} 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 ());
}
/** @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;
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;
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) {
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);
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) {
/*
- 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;
}
};
-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)
{
}
}
- 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;
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 ());
}
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;
}
#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>
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)
#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>
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);
}
#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>
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
}
#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>
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);
}
#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>
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;
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);