Fix seek with respect to video/audio frame boundary alignment.
authorCarl Hetherington <cth@carlh.net>
Wed, 18 Dec 2013 12:09:35 +0000 (12:09 +0000)
committerCarl Hetherington <cth@carlh.net>
Wed, 18 Dec 2013 12:09:35 +0000 (12:09 +0000)
src/lib/audio_merger.h
src/lib/player.cc
src/lib/util.cc
src/lib/util.h
test/ffmpeg_seek_test.cc
test/util_test.cc

index 2a1cc761b1f141aef886d3de88fb09957ec44b15..f068b504e8dcbff0c0215a146de00550480bea97 100644 (file)
@@ -37,6 +37,8 @@ public:
        TimedAudioBuffers<T>
        pull (T time)
        {
+               assert (time >= _last_pull);
+               
                TimedAudioBuffers<T> out;
                
                F const to_return = _t_to_f (time - _last_pull);
index 56bf0767dff9c33f358fe81316a50281b9d6bf7d..d60dfb6a9b339508fd2bf1fb5fe1f9586674f036 100644 (file)
@@ -351,8 +351,10 @@ Player::seek (DCPTime t, bool accurate)
                (*i)->decoder->seek (ct, accurate);
        }
 
-       _video_position = _audio_position = t;
-       _audio_merger.clear (t);
+       _video_position = time_round_up (t, TIME_HZ / _film->video_frame_rate());
+       _audio_position = time_round_up (t, TIME_HZ / _film->audio_frame_rate());
+
+       _audio_merger.clear (_audio_position);
 
        if (!accurate) {
                /* We just did an inaccurate seek, so it's likely that the next thing seen
index d5a07192c9f2694842b37161a88a878e71e216c8..381c47a9ae606253a7207a492351965987638c58 100644 (file)
@@ -915,3 +915,10 @@ fit_ratio_within (float ratio, libdcp::Size full_frame)
        
        return libdcp::Size (full_frame.width, rint (full_frame.width / ratio));
 }
+
+DCPTime
+time_round_up (DCPTime t, DCPTime nearest)
+{
+       DCPTime const a = t + nearest - 1;
+       return a - (a % nearest);
+}
index 9b201a50e7ab6cf92e59c2233809d1828d0b5ca7..892b473f739a21de88827d8aecd94682b3f2fe24 100644 (file)
@@ -119,6 +119,7 @@ struct FrameRateChange
 
 extern int dcp_audio_frame_rate (int);
 extern int stride_round_up (int, int const *, int);
+extern DCPTime time_round_up (DCPTime, DCPTime);
 extern std::multimap<std::string, std::string> read_key_value (std::istream& s);
 extern int get_required_int (std::multimap<std::string, std::string> const & kv, std::string k);
 extern float get_required_float (std::multimap<std::string, std::string> const & kv, std::string k);
index f587d6cc6d91c69b64af555c80c561e7c1b56807..e66a1918cd1ec1aa00349af5c691124680e6f4a1 100644 (file)
@@ -28,11 +28,13 @@ using std::cout;
 using std::string;
 using std::stringstream;
 using boost::shared_ptr;
+using boost::optional;
 
 #define FFMPEG_SEEK_TEST_DEBUG 1
 
-boost::optional<DCPTime> first_video;
-boost::optional<DCPTime> first_audio;
+optional<DCPTime> first_video;
+optional<DCPTime> first_audio;
+shared_ptr<Film> film;
 
 static void
 process_video (shared_ptr<PlayerImage>, Eyes, ColourConversion, bool, DCPTime t)
@@ -77,14 +79,18 @@ check (shared_ptr<Player> p, DCPTime t)
        cout << "First video " << print_time (first_video.get(), 24) << "\n";
        cout << "First audio " << print_time (first_audio.get(), 24) << "\n";
 #endif 
-       
+
+       /* Outputs should be on or after seek time */
        BOOST_CHECK (first_video.get() >= t);
        BOOST_CHECK (first_audio.get() >= t);
+       /* And should be rounded to frame boundaries */
+       BOOST_CHECK ((first_video.get() % (TIME_HZ / film->video_frame_rate())) == 0);
+       BOOST_CHECK ((first_audio.get() % (TIME_HZ / film->audio_frame_rate())) == 0);
 }
 
 BOOST_AUTO_TEST_CASE (ffmpeg_seek_test)
 {
-       shared_ptr<Film> film = new_test_film ("ffmpeg_audio_test");
+       film = new_test_film ("ffmpeg_audio_test");
        film->set_name ("ffmpeg_audio_test");
        film->set_container (Ratio::from_id ("185"));
        shared_ptr<FFmpegContent> c (new FFmpegContent (film, "test/data/staircase.mov"));
index 4dccb49c6c1d95302fb031794b90d1ba97217357..5733c7d03d69070b2fa195e43665c1b337f146c7 100644 (file)
@@ -53,3 +53,17 @@ BOOST_AUTO_TEST_CASE (md5_digest_test)
        p.push_back ("foobar");
        BOOST_CHECK_THROW (md5_digest (p, shared_ptr<Job> ()), std::runtime_error);
 }
+
+/* Straightforward test of time_round_up_test */
+BOOST_AUTO_TEST_CASE (time_round_up_test)
+{
+       BOOST_CHECK_EQUAL (time_round_up (0, 2), 0);
+       BOOST_CHECK_EQUAL (time_round_up (1, 2), 2);
+       BOOST_CHECK_EQUAL (time_round_up (2, 2), 2);
+       BOOST_CHECK_EQUAL (time_round_up (3, 2), 4);
+       
+       BOOST_CHECK_EQUAL (time_round_up (0, 42), 0);
+       BOOST_CHECK_EQUAL (time_round_up (1, 42), 42);
+       BOOST_CHECK_EQUAL (time_round_up (42, 42), 42);
+       BOOST_CHECK_EQUAL (time_round_up (43, 42), 84);
+}