summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorCarl Hetherington <cth@carlh.net>2016-05-09 19:58:37 +0100
committerCarl Hetherington <cth@carlh.net>2016-05-18 11:50:29 +0100
commit19f94521139aac13ef8fb4eaa55855b2ada307b4 (patch)
tree6e4b457c1fa46c674433fb1a5d2a9cd0f07c5a11 /src/lib
parent0a2d40420813403a96352c6dc895d23fcd9994c0 (diff)
Move video frame rate ('prepared-for') into Content.
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/audio_content.cc45
-rw-r--r--src/lib/audio_content.h5
-rw-r--r--src/lib/audio_decoder.h4
-rw-r--r--src/lib/content.cc32
-rw-r--r--src/lib/content.h22
-rw-r--r--src/lib/dcp_content.cc10
-rw-r--r--src/lib/dcp_content.h2
-rw-r--r--src/lib/dcp_decoder.cc10
-rw-r--r--src/lib/dcp_subtitle_content.cc4
-rw-r--r--src/lib/ffmpeg_content.cc10
-rw-r--r--src/lib/ffmpeg_content.h2
-rw-r--r--src/lib/ffmpeg_decoder.cc6
-rw-r--r--src/lib/film.cc2
-rw-r--r--src/lib/image_content.cc2
-rw-r--r--src/lib/image_decoder.cc4
-rw-r--r--src/lib/image_examiner.cc4
-rw-r--r--src/lib/player.cc20
-rw-r--r--src/lib/playlist.cc14
-rw-r--r--src/lib/sndfile_content.cc2
-rw-r--r--src/lib/subtitle_content.cc32
-rw-r--r--src/lib/subtitle_content.h6
-rw-r--r--src/lib/text_subtitle_content.cc2
-rw-r--r--src/lib/video_content.cc72
-rw-r--r--src/lib/video_content.h14
-rw-r--r--src/lib/video_decoder.cc12
-rw-r--r--src/lib/video_decoder.h12
26 files changed, 139 insertions, 211 deletions
diff --git a/src/lib/audio_content.cc b/src/lib/audio_content.cc
index a903cfb9a..a0c9950a6 100644
--- a/src/lib/audio_content.cc
+++ b/src/lib/audio_content.cc
@@ -47,7 +47,6 @@ using boost::optional;
int const AudioContentProperty::STREAMS = 200;
int const AudioContentProperty::GAIN = 201;
int const AudioContentProperty::DELAY = 202;
-int const AudioContentProperty::VIDEO_FRAME_RATE = 203;
AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film)
: ContentPart (parent, film)
@@ -62,7 +61,12 @@ AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film, cxml::
{
_gain = node->number_child<double> ("AudioGain");
_delay = node->number_child<int> ("AudioDelay");
- _video_frame_rate = node->optional_number_child<double> ("AudioVideoFrameRate");
+
+ /* Backwards compatibility */
+ optional<double> r = node->optional_number_child<double> ("AudioVideoFrameRate");
+ if (r) {
+ _parent->set_video_frame_rate (r.get ());
+ }
}
AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film, vector<shared_ptr<Content> > c)
@@ -79,16 +83,10 @@ AudioContent::AudioContent (Content* parent, shared_ptr<const Film> film, vector
if (c[i]->audio->delay() != ref->delay()) {
throw JoinError (_("Content to be joined must have the same audio delay."));
}
-
- if (c[i]->audio->video_frame_rate() != ref->video_frame_rate()) {
- throw JoinError (_("Content to be joined must have the same video frame rate."));
- }
}
_gain = ref->gain ();
_delay = ref->delay ();
- /* Preserve the optional<> part of this */
- _video_frame_rate = ref->_video_frame_rate;
_streams = ref->streams ();
}
@@ -98,9 +96,6 @@ AudioContent::as_xml (xmlpp::Node* node) const
boost::mutex::scoped_lock lm (_mutex);
node->add_child("AudioGain")->add_child_text (raw_convert<string> (_gain));
node->add_child("AudioDelay")->add_child_text (raw_convert<string> (_delay));
- if (_video_frame_rate) {
- node->add_child("AudioVideoFrameRate")->add_child_text (raw_convert<string> (_video_frame_rate.get()));
- }
}
void
@@ -184,7 +179,7 @@ AudioContent::resampled_frame_rate () const
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- FrameRateChange frc (video_frame_rate(), film->video_frame_rate());
+ FrameRateChange frc (_parent->active_video_frame_rate(), film->video_frame_rate());
/* Compensate if the DCP is being run at a different frame rate
to the source; that is, if the video is run such that it will
@@ -295,7 +290,7 @@ AudioContent::add_properties (list<UserProperty>& p) const
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- FrameRateChange const frc (video_frame_rate(), film->video_frame_rate());
+ FrameRateChange const frc (_parent->active_video_frame_rate(), film->video_frame_rate());
ContentTime const c (_parent->full_length(), frc);
p.push_back (
@@ -327,30 +322,6 @@ AudioContent::add_properties (list<UserProperty>& p) const
}
void
-AudioContent::set_video_frame_rate (double r)
-{
- maybe_set (_video_frame_rate, r, AudioContentProperty::VIDEO_FRAME_RATE);
-}
-
-double
-AudioContent::video_frame_rate () const
-{
- {
- boost::mutex::scoped_lock lm (_mutex);
- if (_video_frame_rate) {
- return _video_frame_rate.get ();
- }
- }
-
- /* No frame rate specified, so assume this content has been
- prepared for any concurrent video content.
- */
- shared_ptr<const Film> film = _film.lock ();
- DCPOMATIC_ASSERT (film);
- return film->active_frame_rate_change(_parent->position()).source;
-}
-
-void
AudioContent::set_streams (vector<AudioStreamPtr> streams)
{
{
diff --git a/src/lib/audio_content.h b/src/lib/audio_content.h
index cfce3fb83..7de0742a5 100644
--- a/src/lib/audio_content.h
+++ b/src/lib/audio_content.h
@@ -37,7 +37,6 @@ public:
static int const STREAMS;
static int const GAIN;
static int const DELAY;
- static int const VIDEO_FRAME_RATE;
};
class AudioContent : public ContentPart
@@ -69,9 +68,6 @@ public:
return _delay;
}
- double video_frame_rate () const;
- void set_video_frame_rate (double r);
-
std::string processing_description () const;
std::vector<AudioStreamPtr> streams () const {
@@ -92,7 +88,6 @@ private:
double _gain;
/** Delay to apply to audio (positive moves audio later) in milliseconds */
int _delay;
- boost::optional<double> _video_frame_rate;
std::vector<AudioStreamPtr> _streams;
};
diff --git a/src/lib/audio_decoder.h b/src/lib/audio_decoder.h
index 679cdd5c5..31d0785c6 100644
--- a/src/lib/audio_decoder.h
+++ b/src/lib/audio_decoder.h
@@ -42,10 +42,6 @@ class AudioDecoder : public virtual Decoder, public boost::enable_shared_from_th
public:
AudioDecoder (boost::shared_ptr<const AudioContent>, bool fast, boost::shared_ptr<Log> log);
- boost::shared_ptr<const AudioContent> audio_content () const {
- return _audio_content;
- }
-
/** Try to fetch some audio from a specific place in this content.
* @param frame Frame to start from (after resampling, if applicable)
* @param length Frames to get (after resampling, if applicable)
diff --git a/src/lib/content.cc b/src/lib/content.cc
index 3b9c3e3a1..ff35eeab7 100644
--- a/src/lib/content.cc
+++ b/src/lib/content.cc
@@ -50,6 +50,7 @@ int const ContentProperty::POSITION = 401;
int const ContentProperty::LENGTH = 402;
int const ContentProperty::TRIM_START = 403;
int const ContentProperty::TRIM_END = 404;
+int const ContentProperty::VIDEO_FRAME_RATE = 405;
Content::Content (shared_ptr<const Film> film)
: _film (film)
@@ -157,7 +158,6 @@ Content::signal_changed (int p)
{
try {
emit (boost::bind (boost::ref (Changed), shared_from_this (), p, _change_signals_frequent));
- changed (p);
} catch (boost::bad_weak_ptr) {
/* This must be during construction; never mind */
}
@@ -308,3 +308,33 @@ Content::reel_split_points () const
t.push_back (position().round_up (film()->video_frame_rate()));
return t;
}
+
+void
+Content::set_video_frame_rate (double r)
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ _video_frame_rate = r;
+ }
+
+ signal_changed (ContentProperty::VIDEO_FRAME_RATE);
+}
+
+double
+Content::active_video_frame_rate () const
+{
+ {
+ boost::mutex::scoped_lock lm (_mutex);
+ if (_video_frame_rate) {
+ return _video_frame_rate.get ();
+ }
+ }
+
+ /* No frame rate specified, so assume this content has been
+ prepared for any concurrent video content or perhaps
+ just the DCP rate.
+ */
+ shared_ptr<const Film> film = _film.lock ();
+ DCPOMATIC_ASSERT (film);
+ return film->active_frame_rate_change(position()).source;
+}
diff --git a/src/lib/content.h b/src/lib/content.h
index 60dd89b97..53de14ac1 100644
--- a/src/lib/content.h
+++ b/src/lib/content.h
@@ -54,6 +54,7 @@ public:
static int const LENGTH;
static int const TRIM_START;
static int const TRIM_END;
+ static int const VIDEO_FRAME_RATE;
};
/** @class Content
@@ -93,8 +94,6 @@ public:
*/
virtual std::list<DCPTime> reel_split_points () const;
- virtual void changed (int) {}
-
boost::shared_ptr<Content> clone () const;
void set_path (boost::filesystem::path);
@@ -158,6 +157,15 @@ public:
DCPTime length_after_trim () const;
+ boost::optional<double> video_frame_rate () const {
+ boost::mutex::scoped_lock lm (_mutex);
+ return _video_frame_rate;
+ }
+
+ void set_video_frame_rate (double r);
+
+ double active_video_frame_rate () const;
+
void set_change_signals_frequent (bool f) {
_change_signals_frequent = f;
}
@@ -189,10 +197,20 @@ protected:
std::vector<boost::filesystem::path> _paths;
private:
+ friend struct ffmpeg_pts_offset_test;
+ friend struct best_dcp_frame_rate_test_single;
+ friend struct best_dcp_frame_rate_test_double;
+ friend struct audio_sampling_rate_test;
+
std::string _digest;
DCPTime _position;
ContentTime _trim_start;
ContentTime _trim_end;
+ /** The video frame rate that this content is or was prepared to be used with,
+ * or empty if the effective rate of this content should be dictated by something
+ * else (either some video happening at the same time, or the rate of the DCP).
+ */
+ boost::optional<double> _video_frame_rate;
bool _change_signals_frequent;
};
diff --git a/src/lib/dcp_content.cc b/src/lib/dcp_content.cc
index 43b404f60..6a6f6efc5 100644
--- a/src/lib/dcp_content.cc
+++ b/src/lib/dcp_content.cc
@@ -193,7 +193,7 @@ DCPContent::as_xml (xmlpp::Node* node) const
DCPTime
DCPContent::full_length () const
{
- FrameRateChange const frc (video->frame_rate (), film()->video_frame_rate ());
+ FrameRateChange const frc (active_video_frame_rate (), film()->video_frame_rate ());
return DCPTime::from_frames (llrint (video->length () * frc.factor ()), film()->video_frame_rate ());
}
@@ -363,11 +363,3 @@ DCPContent::can_reference_subtitle (list<string>& why_not) const
/* XXX: this needs to be fixed */
return true;
}
-
-void
-DCPContent::changed (int property)
-{
- if (property == VideoContentProperty::FRAME_RATE && subtitle) {
- subtitle->set_video_frame_rate (video->frame_rate ());
- }
-}
diff --git a/src/lib/dcp_content.h b/src/lib/dcp_content.h
index 269a0373c..5c80587dd 100644
--- a/src/lib/dcp_content.h
+++ b/src/lib/dcp_content.h
@@ -65,8 +65,6 @@ public:
void set_default_colour_conversion ();
std::list<DCPTime> reel_split_points () const;
- void changed (int property);
-
boost::filesystem::path directory () const;
bool encrypted () const {
diff --git a/src/lib/dcp_decoder.cc b/src/lib/dcp_decoder.cc
index 1c25587e0..8008fe515 100644
--- a/src/lib/dcp_decoder.cc
+++ b/src/lib/dcp_decoder.cc
@@ -44,7 +44,7 @@ using boost::shared_ptr;
using boost::dynamic_pointer_cast;
DCPDecoder::DCPDecoder (shared_ptr<const DCPContent> c, shared_ptr<Log> log, bool fast)
- : VideoDecoder (c->video, log)
+ : VideoDecoder (c, log)
, AudioDecoder (c->audio, fast, log)
, SubtitleDecoder (c->subtitle)
, _dcp_content (c)
@@ -74,7 +74,7 @@ DCPDecoder::pass (PassReason reason, bool)
++i;
}
- double const vfr = _dcp_content->video->frame_rate ();
+ double const vfr = _dcp_content->active_video_frame_rate ();
/* Frame within the (played part of the) reel that is coming up next */
int64_t const frame = _next.frames_round (vfr);
@@ -157,8 +157,8 @@ DCPDecoder::seek (ContentTime t, bool accurate)
SubtitleDecoder::seek (t, accurate);
_reel = _reels.begin ();
- while (_reel != _reels.end() && t >= ContentTime::from_frames ((*_reel)->main_picture()->duration(), _dcp_content->video->frame_rate ())) {
- t -= ContentTime::from_frames ((*_reel)->main_picture()->duration(), _dcp_content->video->frame_rate ());
+ while (_reel != _reels.end() && t >= ContentTime::from_frames ((*_reel)->main_picture()->duration(), _dcp_content->active_video_frame_rate ())) {
+ t -= ContentTime::from_frames ((*_reel)->main_picture()->duration(), _dcp_content->active_video_frame_rate ());
++_reel;
}
@@ -178,7 +178,7 @@ DCPDecoder::text_subtitles_during (ContentTimePeriod period, bool starting) cons
/* XXX: inefficient */
list<ContentTimePeriod> ctp;
- double const vfr = _dcp_content->video->frame_rate ();
+ double const vfr = _dcp_content->active_video_frame_rate ();
BOOST_FOREACH (shared_ptr<dcp::Reel> r, _reels) {
if (!r->main_subtitle ()) {
diff --git a/src/lib/dcp_subtitle_content.cc b/src/lib/dcp_subtitle_content.cc
index eabcaaafe..a6beacb0d 100644
--- a/src/lib/dcp_subtitle_content.cc
+++ b/src/lib/dcp_subtitle_content.cc
@@ -67,7 +67,7 @@ DCPSubtitleContent::examine (shared_ptr<Job> job)
shared_ptr<dcp::SMPTESubtitleAsset> smpte = dynamic_pointer_cast<dcp::SMPTESubtitleAsset> (sc);
if (smpte) {
subtitle->set_language (smpte->language().get_value_or (""));
- subtitle->set_video_frame_rate (smpte->edit_rate().numerator);
+ set_video_frame_rate (smpte->edit_rate().numerator);
}
_length = ContentTime::from_seconds (sc->latest_subtitle_out().as_seconds ());
@@ -80,7 +80,7 @@ DCPSubtitleContent::examine (shared_ptr<Job> job)
DCPTime
DCPSubtitleContent::full_length () const
{
- FrameRateChange const frc (subtitle->video_frame_rate(), film()->video_frame_rate());
+ FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate());
return DCPTime (_length, frc);
}
diff --git a/src/lib/ffmpeg_content.cc b/src/lib/ffmpeg_content.cc
index 463722778..f249a1c35 100644
--- a/src/lib/ffmpeg_content.cc
+++ b/src/lib/ffmpeg_content.cc
@@ -296,7 +296,7 @@ operator!= (FFmpegStream const & a, FFmpegStream const & b)
DCPTime
FFmpegContent::full_length () const
{
- FrameRateChange const frc (video->frame_rate (), film()->video_frame_rate ());
+ FrameRateChange const frc (active_video_frame_rate (), film()->video_frame_rate ());
return DCPTime::from_frames (llrint (video->length_after_3d_combine() * frc.factor()), film()->video_frame_rate());
}
@@ -499,14 +499,6 @@ FFmpegContent::signal_subtitle_stream_changed ()
signal_changed (FFmpegContentProperty::SUBTITLE_STREAM);
}
-void
-FFmpegContent::changed (int property)
-{
- if (property == VideoContentProperty::FRAME_RATE && subtitle) {
- subtitle->set_video_frame_rate (video->frame_rate ());
- }
-}
-
vector<shared_ptr<FFmpegAudioStream> >
FFmpegContent::ffmpeg_audio_streams () const
{
diff --git a/src/lib/ffmpeg_content.h b/src/lib/ffmpeg_content.h
index b11486bf1..8d6b995f5 100644
--- a/src/lib/ffmpeg_content.h
+++ b/src/lib/ffmpeg_content.h
@@ -65,8 +65,6 @@ public:
void set_filters (std::vector<Filter const *> const &);
- void changed (int property);
-
std::vector<boost::shared_ptr<FFmpegSubtitleStream> > subtitle_streams () const {
boost::mutex::scoped_lock lm (_mutex);
return _subtitle_streams;
diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc
index 57327b63d..68dcd5186 100644
--- a/src/lib/ffmpeg_decoder.cc
+++ b/src/lib/ffmpeg_decoder.cc
@@ -72,12 +72,12 @@ using boost::split;
using dcp::Size;
FFmpegDecoder::FFmpegDecoder (shared_ptr<const FFmpegContent> c, shared_ptr<Log> log, bool fast)
- : VideoDecoder (c->video, log)
+ : VideoDecoder (c, log)
, AudioDecoder (c->audio, fast, log)
, SubtitleDecoder (c->subtitle)
, FFmpeg (c)
, _log (log)
- , _pts_offset (pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->video->frame_rate()))
+ , _pts_offset (pts_offset (c->ffmpeg_audio_streams(), c->first_video(), c->active_video_frame_rate()))
{
}
@@ -413,7 +413,7 @@ FFmpegDecoder::decode_video_packet ()
double const pts = i->second * av_q2d (_format_context->streams[_video_stream]->time_base) + _pts_offset.seconds ();
video (
shared_ptr<ImageProxy> (new RawImageProxy (image)),
- llrint (pts * _ffmpeg_content->video->frame_rate ())
+ llrint (pts * _ffmpeg_content->active_video_frame_rate ())
);
} else {
LOG_WARNING_NC ("Dropping frame without PTS");
diff --git a/src/lib/film.cc b/src/lib/film.cc
index 3d5d625e1..87a317e57 100644
--- a/src/lib/film.cc
+++ b/src/lib/film.cc
@@ -1096,7 +1096,7 @@ Film::playlist_content_changed (weak_ptr<Content> c, int p, bool frequent)
{
_dirty = true;
- if (p == VideoContentProperty::FRAME_RATE) {
+ if (p == ContentProperty::VIDEO_FRAME_RATE) {
set_video_frame_rate (_playlist->best_dcp_frame_rate ());
} else if (p == AudioContentProperty::STREAMS) {
signal_changed (NAME);
diff --git a/src/lib/image_content.cc b/src/lib/image_content.cc
index 29af451b7..57212c589 100644
--- a/src/lib/image_content.cc
+++ b/src/lib/image_content.cc
@@ -124,7 +124,7 @@ ImageContent::full_length () const
{
shared_ptr<const Film> film = _film.lock ();
DCPOMATIC_ASSERT (film);
- FrameRateChange const frc (video->frame_rate(), film->video_frame_rate());
+ FrameRateChange const frc (active_video_frame_rate(), film->video_frame_rate());
return DCPTime::from_frames (llrint (video->length_after_3d_combine() * frc.factor ()), film->video_frame_rate ());
}
diff --git a/src/lib/image_decoder.cc b/src/lib/image_decoder.cc
index c3a11ce97..6c46b9c08 100644
--- a/src/lib/image_decoder.cc
+++ b/src/lib/image_decoder.cc
@@ -35,7 +35,7 @@ using boost::shared_ptr;
using dcp::Size;
ImageDecoder::ImageDecoder (shared_ptr<const ImageContent> c, shared_ptr<Log> log)
- : VideoDecoder (c->video, log)
+ : VideoDecoder (c, log)
, _image_content (c)
, _video_position (0)
{
@@ -71,5 +71,5 @@ void
ImageDecoder::seek (ContentTime time, bool accurate)
{
VideoDecoder::seek (time, accurate);
- _video_position = time.frames_round (_image_content->video->frame_rate ());
+ _video_position = time.frames_round (_image_content->active_video_frame_rate ());
}
diff --git a/src/lib/image_examiner.cc b/src/lib/image_examiner.cc
index 8e15a9d48..e0be15794 100644
--- a/src/lib/image_examiner.cc
+++ b/src/lib/image_examiner.cc
@@ -85,9 +85,9 @@ ImageExaminer::video_size () const
optional<double>
ImageExaminer::video_frame_rate () const
{
- if (_image_content->video->has_own_frame_rate()) {
+ if (_image_content->video_frame_rate()) {
/* The content already knows what frame rate it should be */
- return _image_content->video->frame_rate();
+ return _image_content->video_frame_rate().get();
}
/* Don't know */
diff --git a/src/lib/player.cc b/src/lib/player.cc
index 617085a7b..2abb6a30c 100644
--- a/src/lib/player.cc
+++ b/src/lib/player.cc
@@ -80,19 +80,19 @@ using boost::scoped_ptr;
static bool
has_video (Content* c)
{
- return c->video;
+ return static_cast<bool>(c->video);
}
static bool
has_audio (Content* c)
{
- return c->audio;
+ return static_cast<bool>(c->audio);
}
static bool
has_subtitle (Content* c)
{
- return c->subtitle;
+ return static_cast<bool>(c->subtitle);
}
Player::Player (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist)
@@ -132,13 +132,13 @@ Player::setup_pieces ()
shared_ptr<const FFmpegContent> fc = dynamic_pointer_cast<const FFmpegContent> (i);
if (fc) {
decoder.reset (new FFmpegDecoder (fc, _film->log(), _fast));
- frc = FrameRateChange (fc->video->frame_rate(), _film->video_frame_rate());
+ frc = FrameRateChange (fc->active_video_frame_rate(), _film->video_frame_rate());
}
shared_ptr<const DCPContent> dc = dynamic_pointer_cast<const DCPContent> (i);
if (dc) {
decoder.reset (new DCPDecoder (dc, _film->log(), _fast));
- frc = FrameRateChange (dc->video->frame_rate(), _film->video_frame_rate());
+ frc = FrameRateChange (dc->active_video_frame_rate(), _film->video_frame_rate());
}
/* ImageContent */
@@ -156,7 +156,7 @@ Player::setup_pieces ()
decoder.reset (new ImageDecoder (ic, _film->log()));
}
- frc = FrameRateChange (ic->video->frame_rate(), _film->video_frame_rate());
+ frc = FrameRateChange (ic->active_video_frame_rate(), _film->video_frame_rate());
}
/* SndfileContent */
@@ -180,7 +180,7 @@ Player::setup_pieces ()
}
if (best_overlap) {
- frc = FrameRateChange (best_overlap->video->frame_rate(), _film->video_frame_rate ());
+ frc = FrameRateChange (best_overlap->active_video_frame_rate(), _film->video_frame_rate ());
} else {
/* No video overlap; e.g. if the DCP is just audio */
frc = FrameRateChange (_film->video_frame_rate(), _film->video_frame_rate ());
@@ -196,14 +196,14 @@ Player::setup_pieces ()
shared_ptr<const TextSubtitleContent> rc = dynamic_pointer_cast<const TextSubtitleContent> (i);
if (rc) {
decoder.reset (new TextSubtitleDecoder (rc));
- frc = FrameRateChange (rc->subtitle->video_frame_rate(), _film->video_frame_rate());
+ frc = FrameRateChange (rc->active_video_frame_rate(), _film->video_frame_rate());
}
/* DCPSubtitleContent */
shared_ptr<const DCPSubtitleContent> dsc = dynamic_pointer_cast<const DCPSubtitleContent> (i);
if (dsc) {
decoder.reset (new DCPSubtitleDecoder (dsc));
- frc = FrameRateChange (dsc->subtitle->video_frame_rate(), _film->video_frame_rate());
+ frc = FrameRateChange (dsc->active_video_frame_rate(), _film->video_frame_rate());
}
shared_ptr<VideoDecoder> vd = dynamic_pointer_cast<VideoDecoder> (decoder);
@@ -248,6 +248,7 @@ Player::playlist_content_changed (weak_ptr<Content> w, int property, bool freque
Changed (frequent);
} else if (
+ property == ContentProperty::VIDEO_FRAME_RATE ||
property == SubtitleContentProperty::USE ||
property == SubtitleContentProperty::X_OFFSET ||
property == SubtitleContentProperty::Y_OFFSET ||
@@ -256,7 +257,6 @@ Player::playlist_content_changed (weak_ptr<Content> w, int property, bool freque
property == SubtitleContentProperty::FONTS ||
property == VideoContentProperty::CROP ||
property == VideoContentProperty::SCALE ||
- property == VideoContentProperty::FRAME_RATE ||
property == VideoContentProperty::FADE_IN ||
property == VideoContentProperty::FADE_OUT ||
property == VideoContentProperty::COLOUR_CONVERSION
diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc
index 24a38f2cd..b473bee8a 100644
--- a/src/lib/playlist.cc
+++ b/src/lib/playlist.cc
@@ -266,14 +266,14 @@ Playlist::best_dcp_frame_rate () const
float this_error = 0;
BOOST_FOREACH (shared_ptr<Content> j, _content) {
- if (!j->video || !j->video->has_own_frame_rate()) {
+ if (!j->video || !j->video_frame_rate()) {
continue;
}
/* Best error for this content; we could use the content as-is or double its rate */
float best_error = min (
- float (fabs (i->source - j->video->frame_rate ())),
- float (fabs (i->source - j->video->frame_rate () * 2))
+ float (fabs (i->source - j->video_frame_rate().get())),
+ float (fabs (i->source - j->video_frame_rate().get() * 2))
);
/* Use the largest difference between DCP and source as the "error" */
@@ -375,7 +375,13 @@ Playlist::active_frame_rate_change (DCPTime t, int dcp_video_frame_rate) const
/* This is the first piece of content (going backwards...) that starts before t,
so it's the active one.
*/
- return FrameRateChange ((*i)->video->frame_rate(), dcp_video_frame_rate);
+ if ((*i)->video_frame_rate ()) {
+ /* This content specified a rate, so use it */
+ return FrameRateChange ((*i)->video_frame_rate().get(), dcp_video_frame_rate);
+ } else {
+ /* No specified rate so just use the DCP one */
+ return FrameRateChange (dcp_video_frame_rate, dcp_video_frame_rate);
+ }
}
}
diff --git a/src/lib/sndfile_content.cc b/src/lib/sndfile_content.cc
index f8e58885e..2b28ba8b4 100644
--- a/src/lib/sndfile_content.cc
+++ b/src/lib/sndfile_content.cc
@@ -114,6 +114,6 @@ SndfileContent::examine (shared_ptr<Job> job)
DCPTime
SndfileContent::full_length () const
{
- FrameRateChange const frc (audio->video_frame_rate(), film()->video_frame_rate());
+ FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate());
return DCPTime::from_frames (audio_length() / frc.speed_up, audio->stream()->frame_rate ());
}
diff --git a/src/lib/subtitle_content.cc b/src/lib/subtitle_content.cc
index 2066793fb..228376c34 100644
--- a/src/lib/subtitle_content.cc
+++ b/src/lib/subtitle_content.cc
@@ -47,10 +47,9 @@ int const SubtitleContentProperty::USE = 504;
int const SubtitleContentProperty::BURN = 505;
int const SubtitleContentProperty::LANGUAGE = 506;
int const SubtitleContentProperty::FONTS = 507;
-int const SubtitleContentProperty::VIDEO_FRAME_RATE = 508;
-int const SubtitleContentProperty::COLOUR = 509;
-int const SubtitleContentProperty::OUTLINE = 510;
-int const SubtitleContentProperty::OUTLINE_COLOUR = 511;
+int const SubtitleContentProperty::COLOUR = 508;
+int const SubtitleContentProperty::OUTLINE = 509;
+int const SubtitleContentProperty::OUTLINE_COLOUR = 510;
SubtitleContent::SubtitleContent (Content* parent, shared_ptr<const Film> film)
: ContentPart (parent, film)
@@ -86,7 +85,6 @@ SubtitleContent::SubtitleContent (Content* parent, shared_ptr<const Film> film,
node->optional_number_child<int>("OutlineGreen").get_value_or(255),
node->optional_number_child<int>("OutlineBlue").get_value_or(255)
)
- , _frame_rate (node->optional_number_child<double>("SubtitleFrameRate"))
{
if (version >= 32) {
_use = node->bool_child ("UseSubtitles");
@@ -316,27 +314,3 @@ SubtitleContent::set_language (string language)
{
maybe_set (_language, language, SubtitleContentProperty::LANGUAGE);
}
-
-void
-SubtitleContent::set_video_frame_rate (double r)
-{
- maybe_set (_frame_rate, r, SubtitleContentProperty::VIDEO_FRAME_RATE);
-}
-
-double
-SubtitleContent::video_frame_rate () const
-{
- {
- boost::mutex::scoped_lock lm (_mutex);
- if (_frame_rate) {
- return _frame_rate.get ();
- }
- }
-
- /* No frame rate specified, so assume this content has been
- prepared for any concurrent video content.
- */
- shared_ptr<const Film> film = _film.lock ();
- DCPOMATIC_ASSERT (film);
- return film->active_frame_rate_change(_parent->position()).source;
-}
diff --git a/src/lib/subtitle_content.h b/src/lib/subtitle_content.h
index cb61ad9a8..09cc92709 100644
--- a/src/lib/subtitle_content.h
+++ b/src/lib/subtitle_content.h
@@ -38,7 +38,6 @@ public:
static int const BURN;
static int const LANGUAGE;
static int const FONTS;
- static int const VIDEO_FRAME_RATE;
static int const COLOUR;
static int const OUTLINE;
static int const OUTLINE_COLOUR;
@@ -130,9 +129,6 @@ public:
return _outline_colour;
}
- double video_frame_rate () const;
- void set_video_frame_rate (double r);
-
protected:
/** subtitle language (e.g. "German") or empty if it is not known */
std::string _language;
@@ -161,8 +157,6 @@ private:
bool _outline;
dcp::Colour _outline_colour;
std::list<boost::signals2::connection> _font_connections;
- /** Video frame rate that this content has been prepared for, if known */
- boost::optional<double> _frame_rate;
};
#endif
diff --git a/src/lib/text_subtitle_content.cc b/src/lib/text_subtitle_content.cc
index 0ad41114e..c7be4c19b 100644
--- a/src/lib/text_subtitle_content.cc
+++ b/src/lib/text_subtitle_content.cc
@@ -86,6 +86,6 @@ TextSubtitleContent::as_xml (xmlpp::Node* node) const
DCPTime
TextSubtitleContent::full_length () const
{
- FrameRateChange const frc (subtitle->video_frame_rate(), film()->video_frame_rate ());
+ FrameRateChange const frc (active_video_frame_rate(), film()->video_frame_rate ());
return DCPTime (_length, frc);
}
diff --git a/src/lib/video_content.cc b/src/lib/video_content.cc
index 0533a12e5..ff5a4cb17 100644
--- a/src/lib/video_content.cc
+++ b/src/lib/video_content.cc
@@ -42,13 +42,12 @@
#define LOG_GENERAL(...) film->log()->log (String::compose (__VA_ARGS__), LogEntry::TYPE_GENERAL);
int const VideoContentProperty::SIZE = 0;
-int const VideoContentProperty::FRAME_RATE = 1;
-int const VideoContentProperty::FRAME_TYPE = 2;
-int const VideoContentProperty::CROP = 3;
-int const VideoContentProperty::SCALE = 4;
-int const VideoContentProperty::COLOUR_CONVERSION = 5;
-int const VideoContentProperty::FADE_IN = 6;
-int const VideoContentProperty::FADE_OUT = 7;
+int const VideoContentProperty::FRAME_TYPE = 1;
+int const VideoContentProperty::CROP = 2;
+int const VideoContentProperty::SCALE = 3;
+int const VideoContentProperty::COLOUR_CONVERSION = 4;
+int const VideoContentProperty::FADE_IN = 5;
+int const VideoContentProperty::FADE_OUT = 6;
using std::string;
using std::setprecision;
@@ -81,7 +80,13 @@ VideoContent::VideoContent (Content* parent, shared_ptr<const Film> film, cxml::
{
_size.width = node->number_child<int> ("VideoWidth");
_size.height = node->number_child<int> ("VideoHeight");
- _frame_rate = node->optional_number_child<double> ("VideoFrameRate");
+
+ /* Backwards compatibility */
+ optional<double> r = node->optional_number_child<double>("VideoFrameRate");
+ if (r) {
+ _parent->set_video_frame_rate (r.get ());
+ }
+
_length = node->number_child<Frame> ("VideoLength");
_frame_type = static_cast<VideoFrameType> (node->number_child<int> ("VideoFrameType"));
_sample_aspect_ratio = node->optional_number_child<double> ("SampleAspectRatio");
@@ -128,10 +133,6 @@ VideoContent::VideoContent (Content* parent, shared_ptr<const Film> film, vector
throw JoinError (_("Content to be joined must have the same picture size."));
}
- if (c[i]->video->frame_rate() != ref->frame_rate()) {
- throw JoinError (_("Content to be joined must have the same video frame rate."));
- }
-
if (c[i]->video->frame_type() != ref->frame_type()) {
throw JoinError (_("Content to be joined must have the same video frame type."));
}
@@ -160,7 +161,6 @@ VideoContent::VideoContent (Content* parent, shared_ptr<const Film> film, vector
}
_size = ref->size ();
- _frame_rate = ref->frame_rate ();
_frame_type = ref->frame_type ();
_crop = ref->crop ();
_scale = ref->scale ();
@@ -176,9 +176,6 @@ VideoContent::as_xml (xmlpp::Node* node) const
node->add_child("VideoLength")->add_child_text (raw_convert<string> (_length));
node->add_child("VideoWidth")->add_child_text (raw_convert<string> (_size.width));
node->add_child("VideoHeight")->add_child_text (raw_convert<string> (_size.height));
- if (_frame_rate) {
- node->add_child("VideoFrameRate")->add_child_text (raw_convert<string> (_frame_rate.get()));
- }
node->add_child("VideoFrameType")->add_child_text (raw_convert<string> (static_cast<int> (_frame_type)));
if (_sample_aspect_ratio) {
node->add_child("SampleAspectRatio")->add_child_text (raw_convert<string> (_sample_aspect_ratio.get ()));
@@ -198,7 +195,6 @@ VideoContent::take_from_examiner (shared_ptr<VideoExaminer> d)
{
/* These examiner calls could call other content methods which take a lock on the mutex */
dcp::Size const vs = d->video_size ();
- optional<double> const vfr = d->video_frame_rate ();
Frame vl = d->video_length ();
optional<double> const ar = d->sample_aspect_ratio ();
bool const yuv = d->yuv ();
@@ -206,7 +202,6 @@ VideoContent::take_from_examiner (shared_ptr<VideoExaminer> d)
{
boost::mutex::scoped_lock lm (_mutex);
_size = vs;
- _frame_rate = vfr;
_length = vl;
_sample_aspect_ratio = ar;
_yuv = yuv;
@@ -221,8 +216,11 @@ VideoContent::take_from_examiner (shared_ptr<VideoExaminer> d)
DCPOMATIC_ASSERT (film);
LOG_GENERAL ("Video length obtained from header as %1 frames", _length);
+ if (d->video_frame_rate()) {
+ _parent->set_video_frame_rate (d->video_frame_rate().get());
+ }
+
_parent->signal_changed (VideoContentProperty::SIZE);
- _parent->signal_changed (VideoContentProperty::FRAME_RATE);
_parent->signal_changed (VideoContentProperty::SCALE);
_parent->signal_changed (ContentProperty::LENGTH);
}
@@ -251,11 +249,10 @@ string
VideoContent::technical_summary () const
{
string s = String::compose (
- N_("video: length %1 frames, size %2x%3, rate %4"),
+ N_("video: length %1 frames, size %2x%3"),
length_after_3d_combine(),
size().width,
- size().height,
- frame_rate()
+ size().height
);
if (sample_aspect_ratio ()) {
@@ -325,12 +322,17 @@ VideoContent::fade (Frame f) const
{
DCPOMATIC_ASSERT (f >= 0);
- Frame const ts = _parent->trim_start().frames_round(frame_rate());
+ shared_ptr<const Film> film = _film.lock ();
+ DCPOMATIC_ASSERT (film);
+
+ double const vfr = _parent->active_video_frame_rate ();
+
+ Frame const ts = _parent->trim_start().frames_round(vfr);
if ((f - ts) < fade_in()) {
return double (f - ts) / fade_in();
}
- Frame fade_out_start = length() - _parent->trim_end().frames_round(frame_rate()) - fade_out();
+ Frame fade_out_start = length() - _parent->trim_end().frames_round(vfr) - fade_out();
if (f >= fade_out_start) {
return 1 - double (f - fade_out_start) / fade_out();
}
@@ -396,12 +398,6 @@ VideoContent::processing_description () const
d << " (" << fixed << setprecision(2) << container_size.ratio () << ":1)\n";
}
- d << _("Content frame rate");
- d << " " << fixed << setprecision(4) << frame_rate() << "\n";
-
- FrameRateChange frc (frame_rate(), film->video_frame_rate ());
- d << frc.description () << "\n";
-
return d.str ();
}
@@ -410,16 +406,6 @@ VideoContent::add_properties (list<UserProperty>& p) const
{
p.push_back (UserProperty (_("Video"), _("Length"), raw_convert<string> (length ()), _("video frames")));
p.push_back (UserProperty (_("Video"), _("Size"), raw_convert<string> (size().width) + "x" + raw_convert<string> (size().height)));
- p.push_back (UserProperty (_("Video"), _("Frame rate"), raw_convert<string> (frame_rate(), 5), _("frames per second")));
-}
-
-double
-VideoContent::frame_rate () const
-{
- boost::mutex::scoped_lock lm (_mutex);
- shared_ptr<const Film> film = _film.lock ();
- DCPOMATIC_ASSERT (film);
- return _frame_rate.get_value_or (film->video_frame_rate ());
}
void
@@ -459,12 +445,6 @@ VideoContent::set_scale (VideoContentScale s)
}
void
-VideoContent::set_frame_rate (double r)
-{
- maybe_set (_frame_rate, r, VideoContentProperty::FRAME_RATE);
-}
-
-void
VideoContent::set_frame_type (VideoFrameType t)
{
maybe_set (_frame_type, t, VideoContentProperty::FRAME_TYPE);
diff --git a/src/lib/video_content.h b/src/lib/video_content.h
index 432775651..03ffb0fa8 100644
--- a/src/lib/video_content.h
+++ b/src/lib/video_content.h
@@ -39,7 +39,6 @@ class VideoContentProperty
{
public:
static int const SIZE;
- static int const FRAME_RATE;
static int const FRAME_TYPE;
static int const CROP;
static int const SCALE;
@@ -78,18 +77,7 @@ public:
return _size;
}
- double frame_rate () const;
-
- /** @return true if this content has a specific video frame rate, false
- * if it should use the DCP's rate.
- */
- bool has_own_frame_rate () const {
- boost::mutex::scoped_lock lm (_mutex);
- return static_cast<bool>(_frame_rate);
- }
-
void set_frame_type (VideoFrameType);
- void set_frame_rate (double);
void set_left_crop (int);
void set_right_crop (int);
@@ -189,8 +177,6 @@ private:
void setup_default_colour_conversion ();
Frame _length;
- /** Video frame rate, or not set if this content should use the DCP's frame rate */
- boost::optional<double> _frame_rate;
boost::optional<ColourConversion> _colour_conversion;
dcp::Size _size;
VideoFrameType _frame_type;
diff --git a/src/lib/video_decoder.cc b/src/lib/video_decoder.cc
index 08f79c3d8..8862eaa6e 100644
--- a/src/lib/video_decoder.cc
+++ b/src/lib/video_decoder.cc
@@ -34,7 +34,7 @@ using std::back_inserter;
using boost::shared_ptr;
using boost::optional;
-VideoDecoder::VideoDecoder (shared_ptr<const VideoContent> c, shared_ptr<Log> log)
+VideoDecoder::VideoDecoder (shared_ptr<const Content> c, shared_ptr<Log> log)
#ifdef DCPOMATIC_DEBUG
: test_gaps (0)
, _video_content (c)
@@ -45,7 +45,7 @@ VideoDecoder::VideoDecoder (shared_ptr<const VideoContent> c, shared_ptr<Log> lo
, _last_seek_accurate (true)
, _ignore_video (false)
{
- _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_content->size(), true));
+ _black_image.reset (new Image (AV_PIX_FMT_RGB24, _video_content->video->size(), true));
_black_image->make_black ();
}
@@ -83,7 +83,7 @@ VideoDecoder::get_video (Frame frame, bool accurate)
_log->log (String::compose ("VD has request for %1", frame), LogEntry::TYPE_DEBUG_DECODE);
if (_decoded_video.empty() || frame < _decoded_video.front().frame || frame > (_decoded_video.back().frame + 1)) {
- seek (ContentTime::from_frames (frame, _video_content->frame_rate()), accurate);
+ seek (ContentTime::from_frames (frame, _video_content->active_video_frame_rate()), accurate);
}
list<ContentVideo> dec;
@@ -257,7 +257,7 @@ VideoDecoder::video (shared_ptr<const ImageProxy> image, Frame frame)
/* Work out what we are going to push into _decoded_video next */
list<ContentVideo> to_push;
- switch (_video_content->frame_type ()) {
+ switch (_video_content->video->frame_type ()) {
case VIDEO_FRAME_TYPE_2D:
to_push.push_back (ContentVideo (image, EYES_BOTH, PART_WHOLE, frame));
break;
@@ -297,7 +297,7 @@ VideoDecoder::video (shared_ptr<const ImageProxy> image, Frame frame)
optional<Frame> to;
if (_decoded_video.empty() && _last_seek_time && _last_seek_accurate) {
- from = _last_seek_time->frames_round (_video_content->frame_rate ());
+ from = _last_seek_time->frames_round (_video_content->active_video_frame_rate ());
to = to_push.front().frame;
} else if (!_decoded_video.empty ()) {
from = _decoded_video.back().frame + 1;
@@ -313,7 +313,7 @@ VideoDecoder::video (shared_ptr<const ImageProxy> image, Frame frame)
}
if (from) {
- switch (_video_content->frame_type ()) {
+ switch (_video_content->video->frame_type ()) {
case VIDEO_FRAME_TYPE_2D:
fill_one_eye (from.get(), to.get (), EYES_BOTH);
break;
diff --git a/src/lib/video_decoder.h b/src/lib/video_decoder.h
index c787faa04..669a5ef1e 100644
--- a/src/lib/video_decoder.h
+++ b/src/lib/video_decoder.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2012-2015 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
@@ -42,14 +42,10 @@ class Log;
class VideoDecoder : public virtual Decoder
{
public:
- VideoDecoder (boost::shared_ptr<const VideoContent> c, boost::shared_ptr<Log> log);
+ VideoDecoder (boost::shared_ptr<const Content> c, boost::shared_ptr<Log> log);
std::list<ContentVideo> get_video (Frame frame, bool accurate);
- boost::shared_ptr<const VideoContent> video_content () const {
- return _video_content;
- }
-
void set_ignore_video ();
#ifdef DCPOMATIC_DEBUG
@@ -59,6 +55,8 @@ public:
protected:
friend struct video_decoder_fill_test1;
friend struct video_decoder_fill_test2;
+ friend struct ffmpeg_pts_offset_test;
+ friend void ffmpeg_decoder_sequential_test_one (boost::filesystem::path file, float fps, int gaps, int video_length);
void seek (ContentTime time, bool accurate);
void video (boost::shared_ptr<const ImageProxy>, Frame frame);
@@ -66,7 +64,7 @@ protected:
void fill_one_eye (Frame from, Frame to, Eyes);
void fill_both_eyes (Frame from, Frame to, Eyes);
- boost::shared_ptr<const VideoContent> _video_content;
+ boost::shared_ptr<const Content> _video_content;
boost::shared_ptr<Log> _log;
std::list<ContentVideo> _decoded_video;
boost::shared_ptr<Image> _black_image;