From ac954a8bd44018347d7cc1b498ac25ed7b1133de Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 13:45:10 +0100 Subject: Add friend for tests. --- src/lib/job_manager.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/lib') diff --git a/src/lib/job_manager.h b/src/lib/job_manager.h index cc1c1d28f..82095a143 100644 --- a/src/lib/job_manager.h +++ b/src/lib/job_manager.h @@ -45,6 +45,9 @@ public: static JobManager* instance (); private: + /* This function is part of the test suite */ + friend void ::wait_for_jobs (); + JobManager (); void scheduler (); -- cgit v1.2.3 From 7c1be062777bb4d49c0c9b55755c11608b1521eb Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 13:45:30 +0100 Subject: Add friend for tests. --- src/lib/video_content.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/lib') diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 46c8efdeb..5b9a17b57 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -88,6 +88,8 @@ protected: private: friend class ffmpeg_pts_offset_test; + friend class best_dcp_frame_rate_test; + friend class audio_sampling_rate_test; libdcp::Size _video_size; float _video_frame_rate; -- cgit v1.2.3 From c044402e6c0262b4813ffee6e8df53469cef8487 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 14:20:23 +0100 Subject: Decide best DCP rate based on the largest difference between a particular content's frame rate and the DCP one, rather than a sum of all the differences. --- src/lib/playlist.cc | 5 +++-- src/lib/video_content.h | 3 ++- test/frame_rate_test.cc | 31 +++++++++++++++++++++++++++++-- 3 files changed, 34 insertions(+), 5 deletions(-) (limited to 'src/lib') diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 9e7f7f5f5..703a14663 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -221,7 +221,7 @@ Playlist::best_dcp_frame_rate () const candidates.push_back (FrameRateCandidate (float (*i) * 2, *i)); } - /* Pick the best one, bailing early if we hit an exact match */ + /* Pick the best one */ float error = std::numeric_limits::max (); optional best; list::iterator i = candidates.begin(); @@ -234,7 +234,8 @@ Playlist::best_dcp_frame_rate () const continue; } - this_error += fabs (i->source - vc->video_frame_rate ()); + /* Use the largest difference between DCP and source as the "error" */ + this_error = max (this_error, float (fabs (i->source - vc->video_frame_rate ()))); } if (this_error < error) { diff --git a/src/lib/video_content.h b/src/lib/video_content.h index 5b9a17b57..697a0ecc3 100644 --- a/src/lib/video_content.h +++ b/src/lib/video_content.h @@ -88,7 +88,8 @@ protected: private: friend class ffmpeg_pts_offset_test; - friend class best_dcp_frame_rate_test; + friend class best_dcp_frame_rate_test_single; + friend class best_dcp_frame_rate_test_double; friend class audio_sampling_rate_test; libdcp::Size _video_size; diff --git a/test/frame_rate_test.cc b/test/frame_rate_test.cc index b7e8a3ce4..89a74e086 100644 --- a/test/frame_rate_test.cc +++ b/test/frame_rate_test.cc @@ -20,9 +20,9 @@ /* Test Playlist::best_dcp_frame_rate and FrameRateConversion with a single piece of content. */ -BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test) +BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test_single) { - shared_ptr film = new_test_film ("best_dcp_frame_rate_test"); + shared_ptr film = new_test_film ("best_dcp_frame_rate_test_single"); /* Get any piece of content, it doesn't matter what */ shared_ptr content (new FFmpegContent (film, "test/data/test.mp4")); film->add_content (content); @@ -179,6 +179,33 @@ BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test) BOOST_CHECK_EQUAL (frc.change_speed, true); } +/* Test Playlist::best_dcp_frame_rate and FrameRateConversion + with two pieces of content. +*/ +BOOST_AUTO_TEST_CASE (best_dcp_frame_rate_test_double) +{ + shared_ptr film = new_test_film ("best_dcp_frame_rate_test_double"); + /* Get any old content, it doesn't matter what */ + shared_ptr A (new FFmpegContent (film, "test/data/test.mp4")); + film->add_content (A); + shared_ptr B (new FFmpegContent (film, "test/data/test.mp4")); + film->add_content (B); + wait_for_jobs (); + + /* Run some tests with a limited range of allowed rates */ + + std::list afr; + afr.push_back (24); + afr.push_back (25); + afr.push_back (30); + Config::instance()->set_allowed_dcp_frame_rates (afr); + + A->_video_frame_rate = 30; + B->_video_frame_rate = 24; + BOOST_CHECK_EQUAL (film->playlist()->best_dcp_frame_rate(), 25); +} + + BOOST_AUTO_TEST_CASE (audio_sampling_rate_test) { shared_ptr film = new_test_film ("audio_sampling_rate_test"); -- cgit v1.2.3 From 6de3f68aa2bec3f8a1c35a587f56fdee5e105ed3 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 16:33:39 +0100 Subject: DVD -> DCP. --- src/lib/sndfile_content.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/sndfile_content.h b/src/lib/sndfile_content.h index 3d3f0c36c..e3b775e8b 100644 --- a/src/lib/sndfile_content.h +++ b/src/lib/sndfile_content.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_SNDFILE_CONTENT_H -#define DVDOMATIC_SNDFILE_CONTENT_H +#ifndef DCPOMATIC_SNDFILE_CONTENT_H +#define DCPOMATIC_SNDFILE_CONTENT_H extern "C" { #include -- cgit v1.2.3 From a2cca95b459a93906c39ca8bd4b31b995108f6ca Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 16:33:47 +0100 Subject: DVD -> DCP. --- src/lib/rect.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/rect.h b/src/lib/rect.h index df1869841..6f4709c08 100644 --- a/src/lib/rect.h +++ b/src/lib/rect.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_RECT_H -#define DVDOMATIC_RECT_H +#ifndef DCPOMATIC_RECT_H +#define DCPOMATIC_RECT_H #include "position.h" -- cgit v1.2.3 From 482c89b5888c19ddcd6d171b5db3715aa55f8916 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 16:35:03 +0100 Subject: Add comment note. --- src/lib/ffmpeg_decoder.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/lib') diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index 18834c90e..11cea8fb1 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -338,7 +338,7 @@ FFmpegDecoder::seek (VideoContent::Frame frame, bool accurate) _video_position = rint ( (av_frame_get_best_effort_timestamp (_frame) * time_base + _video_pts_offset) * _ffmpeg_content->video_frame_rate() ); - + if (_video_position >= (frame - 1)) { av_free_packet (&_packet); break; @@ -451,6 +451,8 @@ FFmpegDecoder::decode_video_packet () /* This PTS is more than one frame forward in time of where we think we should be; emit a black frame. */ + + /* XXX: I think this should be a copy of the last frame... */ boost::shared_ptr black ( new Image ( static_cast (_frame->format), -- cgit v1.2.3 From c1bae7f0dac684147e00f5f51dcd5544ba13ee53 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 16:35:31 +0100 Subject: Maybe re-sequence video when DCP frame rate changes. --- src/lib/film.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/lib') diff --git a/src/lib/film.cc b/src/lib/film.cc index f306006c9..295f80ccb 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -632,6 +632,9 @@ Film::signal_changed (Property p) case Film::CONTENT: set_dcp_video_frame_rate (_playlist->best_dcp_frame_rate ()); break; + case Film::DCP_VIDEO_FRAME_RATE: + _playlist->maybe_sequence_video (); + break; default: break; } -- cgit v1.2.3 From 49c7639efbd0c7e014e9ddf3380b6d7f1fed9285 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 16:35:55 +0100 Subject: DVD -> DCP. --- src/lib/position.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/lib') diff --git a/src/lib/position.h b/src/lib/position.h index f904fe661..8768bf5a8 100644 --- a/src/lib/position.h +++ b/src/lib/position.h @@ -17,8 +17,8 @@ */ -#ifndef DVDOMATIC_POSITION_H -#define DVDOMATIC_POSITION_H +#ifndef DCPOMATIC_POSITION_H +#define DCPOMATIC_POSITION_H /** @struct Position * @brief A position. -- cgit v1.2.3 From 1bb4bd728a445de0728c897211bf079c714d4f41 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Mon, 15 Jul 2013 16:36:49 +0100 Subject: Add some player tests. Fix seek with content at non-DCP frame rate. A few other small fixes. --- src/lib/player.cc | 24 ++++++++-- src/lib/player.h | 5 +++ src/lib/playlist.cc | 40 ++++++++++------- src/lib/playlist.h | 1 + test/play_test.cc | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 174 insertions(+), 19 deletions(-) create mode 100644 test/play_test.cc (limited to 'src/lib') diff --git a/src/lib/player.cc b/src/lib/player.cc index c8c206424..6ee8c5029 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -138,7 +138,7 @@ Player::pass () continue; } - if (dynamic_pointer_cast ((*i)->decoder)) { + if (_video && dynamic_pointer_cast ((*i)->decoder)) { if ((*i)->video_position < earliest_t) { earliest_t = (*i)->video_position; earliest = *i; @@ -146,7 +146,7 @@ Player::pass () } } - if (dynamic_pointer_cast ((*i)->decoder)) { + if (_audio && dynamic_pointer_cast ((*i)->decoder)) { if ((*i)->audio_position < earliest_t) { earliest_t = (*i)->audio_position; earliest = *i; @@ -238,6 +238,10 @@ Player::process_video (weak_ptr weak_piece, shared_ptr image work_image = im; } +#ifdef DCPOMATIC_DEBUG + _last_video = piece->content; +#endif + Video (work_image, same, time); time += TIME_HZ / _film->dcp_video_frame_rate(); @@ -348,7 +352,10 @@ Player::flush () } -/** @return true on error */ +/** Seek so that the next pass() will yield (approximately) the requested frame. + * Pass accurate = true to try harder to get close to the request. + * @return true on error + */ void Player::seek (Time t, bool accurate) { @@ -374,11 +381,16 @@ Player::seek (Time t, bool accurate) (*i)->video_position = (*i)->audio_position = vc->start() + s; FrameRateConversion frc (vc->video_frame_rate(), _film->dcp_video_frame_rate()); - VideoContent::Frame f = s * vc->video_frame_rate() / (frc.factor() * TIME_HZ); + /* Here we are converting from time (in the DCP) to a frame number in the content. + Hence we need to use the DCP's frame rate and the double/skip correction, not + the source's rate. + */ + VideoContent::Frame f = s * _film->dcp_video_frame_rate() / (frc.factor() * TIME_HZ); dynamic_pointer_cast((*i)->decoder)->seek (f, accurate); } _video_position = _audio_position = t; + /* XXX: don't seek audio because we don't need to... */ } @@ -501,6 +513,10 @@ Player::resampler (shared_ptr c) void Player::emit_black () { +#ifdef DCPOMATIC_DEBUG + _last_video.reset (); +#endif + /* XXX: use same here */ Video (_black_frame, false, _video_position); _video_position += _film->video_frames_to_time (1); diff --git a/src/lib/player.h b/src/lib/player.h index b3eadd7c0..92a358043 100644 --- a/src/lib/player.h +++ b/src/lib/player.h @@ -75,6 +75,7 @@ public: boost::signals2::signal Changed; private: + friend class PlayerWrapper; void process_video (boost::weak_ptr, boost::shared_ptr, bool, VideoContent::Frame); void process_audio (boost::weak_ptr, boost::shared_ptr, AudioContent::Frame); @@ -126,6 +127,10 @@ private: Time from; Time to; } _out_subtitle; + +#ifdef DCPOMATIC_DEBUG + boost::shared_ptr _last_video; +#endif }; #endif diff --git a/src/lib/playlist.cc b/src/lib/playlist.cc index 703a14663..0d6462f6c 100644 --- a/src/lib/playlist.cc +++ b/src/lib/playlist.cc @@ -72,25 +72,35 @@ Playlist::~Playlist () void Playlist::content_changed (weak_ptr c, int p) { - if (p == ContentProperty::LENGTH && _sequence_video && !_sequencing_video) { - _sequencing_video = true; - - ContentList cl = _content; - sort (cl.begin(), cl.end(), ContentSorter ()); - Time last = 0; - for (ContentList::iterator i = cl.begin(); i != cl.end(); ++i) { - if (!dynamic_pointer_cast (*i)) { - continue; - } + if (p == ContentProperty::LENGTH) { + maybe_sequence_video (); + } - (*i)->set_start (last); - last = (*i)->end (); - } + ContentChanged (c, p); +} - _sequencing_video = false; +void +Playlist::maybe_sequence_video () +{ + if (!_sequence_video || _sequencing_video) { + return; } - ContentChanged (c, p); + _sequencing_video = true; + + ContentList cl = _content; + sort (cl.begin(), cl.end(), ContentSorter ()); + Time last = 0; + for (ContentList::iterator i = cl.begin(); i != cl.end(); ++i) { + if (!dynamic_pointer_cast (*i)) { + continue; + } + + (*i)->set_start (last); + last = (*i)->end (); + } + + _sequencing_video = false; } string diff --git a/src/lib/playlist.h b/src/lib/playlist.h index cf0f09b31..805df4d70 100644 --- a/src/lib/playlist.h +++ b/src/lib/playlist.h @@ -86,6 +86,7 @@ public: Time video_end () const; void set_sequence_video (bool); + void maybe_sequence_video (); mutable boost::signals2::signal Changed; mutable boost::signals2::signal, int)> ContentChanged; diff --git a/test/play_test.cc b/test/play_test.cc new file mode 100644 index 000000000..12f80a282 --- /dev/null +++ b/test/play_test.cc @@ -0,0 +1,123 @@ +/* + Copyright (C) 2013 Carl Hetherington + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "player.h" + +/* This test needs stuff in Player that is only included in debug mode */ +#ifdef DCPOMATIC_DEBUG + +using boost::optional; + +struct Video +{ + boost::shared_ptr content; + boost::shared_ptr image; + Time time; +}; + +class PlayerWrapper +{ +public: + PlayerWrapper (shared_ptr p) + : _player (p) + { + _player->Video.connect (bind (&PlayerWrapper::process_video, this, _1, _2, _3)); + } + + void process_video (shared_ptr i, bool, Time t) + { + Video v; + v.content = _player->_last_video; + v.image = i; + v.time = t; + _queue.push_front (v); + } + + optional