diff options
| author | Carl Hetherington <cth@carlh.net> | 2016-05-09 19:58:37 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2016-05-18 11:50:29 +0100 |
| commit | 19f94521139aac13ef8fb4eaa55855b2ada307b4 (patch) | |
| tree | 6e4b457c1fa46c674433fb1a5d2a9cd0f07c5a11 /src/lib | |
| parent | 0a2d40420813403a96352c6dc895d23fcd9994c0 (diff) | |
Move video frame rate ('prepared-for') into Content.
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/audio_content.cc | 45 | ||||
| -rw-r--r-- | src/lib/audio_content.h | 5 | ||||
| -rw-r--r-- | src/lib/audio_decoder.h | 4 | ||||
| -rw-r--r-- | src/lib/content.cc | 32 | ||||
| -rw-r--r-- | src/lib/content.h | 22 | ||||
| -rw-r--r-- | src/lib/dcp_content.cc | 10 | ||||
| -rw-r--r-- | src/lib/dcp_content.h | 2 | ||||
| -rw-r--r-- | src/lib/dcp_decoder.cc | 10 | ||||
| -rw-r--r-- | src/lib/dcp_subtitle_content.cc | 4 | ||||
| -rw-r--r-- | src/lib/ffmpeg_content.cc | 10 | ||||
| -rw-r--r-- | src/lib/ffmpeg_content.h | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 6 | ||||
| -rw-r--r-- | src/lib/film.cc | 2 | ||||
| -rw-r--r-- | src/lib/image_content.cc | 2 | ||||
| -rw-r--r-- | src/lib/image_decoder.cc | 4 | ||||
| -rw-r--r-- | src/lib/image_examiner.cc | 4 | ||||
| -rw-r--r-- | src/lib/player.cc | 20 | ||||
| -rw-r--r-- | src/lib/playlist.cc | 14 | ||||
| -rw-r--r-- | src/lib/sndfile_content.cc | 2 | ||||
| -rw-r--r-- | src/lib/subtitle_content.cc | 32 | ||||
| -rw-r--r-- | src/lib/subtitle_content.h | 6 | ||||
| -rw-r--r-- | src/lib/text_subtitle_content.cc | 2 | ||||
| -rw-r--r-- | src/lib/video_content.cc | 72 | ||||
| -rw-r--r-- | src/lib/video_content.h | 14 | ||||
| -rw-r--r-- | src/lib/video_decoder.cc | 12 | ||||
| -rw-r--r-- | src/lib/video_decoder.h | 12 |
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; |
