Make EmptyVideo work with stereo a little better.
authorCarl Hetherington <cth@carlh.net>
Sun, 15 May 2022 22:37:30 +0000 (00:37 +0200)
committerCarl Hetherington <cth@carlh.net>
Mon, 16 May 2022 19:39:28 +0000 (21:39 +0200)
src/lib/empty_video.cc
src/lib/empty_video.h
src/lib/player.cc
test/empty_test.cc
test/player_test.cc

index c578559e017e27f9d1f3145117a664349ac78156..b99f911f2238fe8424fe043416e37d66451f3e6f 100644 (file)
@@ -35,23 +35,54 @@ using std::cout;
 using std::dynamic_pointer_cast;
 using std::function;
 using std::list;
+using std::make_pair;
+using std::pair;
 using std::shared_ptr;
 using namespace dcpomatic;
 
 
 EmptyVideo::EmptyVideo (shared_ptr<const Film> film, shared_ptr<const Playlist> playlist, DCPTime length)
 {
-       list<DCPTimePeriod> full;
+       list<DCPTimePeriod> full_left;
+       list<DCPTimePeriod> full_right;
+       list<DCPTimePeriod> full_both;
        for (auto i: playlist->content()) {
                if (i->video && i->video->use() && i->can_be_played() && i->paths_valid()) {
-                       full.push_back (DCPTimePeriod(i->position(), i->end(film)));
+                       auto period = DCPTimePeriod(i->position(), i->end(film));
+                       if (i->video->frame_type() == VideoFrameType::THREE_D_LEFT) {
+                               full_left.push_back (period);
+                       } else if (i->video->frame_type() == VideoFrameType::THREE_D_RIGHT) {
+                               full_right.push_back (period);
+                       } else {
+                               full_both.push_back (period);
+                       }
                }
        }
 
-       _periods = subtract (DCPTimePeriod(DCPTime(), length), coalesce(full));
+       auto const whole = DCPTimePeriod(DCPTime(), length);
+
+       auto empty_both = subtract(subtract(subtract({whole}, full_left), full_right), full_both);
+       auto empty_left = subtract(subtract(subtract({whole}, full_left), full_both), empty_both);
+       auto empty_right = subtract(subtract(subtract({whole}, full_right), full_both), empty_both);
+
+       for (auto left: empty_left) {
+               _periods.push_back (make_pair(left, Eyes::LEFT));
+       }
+
+       for (auto right: empty_right) {
+               _periods.push_back (make_pair(right, Eyes::RIGHT));
+       }
+
+       for (auto both: empty_both) {
+               _periods.push_back (make_pair(both, Eyes::BOTH));
+       }
+
+       _periods.sort([](std::pair<DCPTimePeriod, Eyes> const& a, std::pair<DCPTimePeriod, Eyes> const& b) {
+               return a.first < b.first;
+       });
 
        if (!_periods.empty()) {
-               _position = _periods.front().from;
+               _position = _periods.front().first.from;
        }
 }
 
@@ -62,26 +93,26 @@ EmptyVideo::set_position (DCPTime position)
        _position = position;
 
        for (auto i: _periods) {
-               if (i.contains(_position)) {
+               if (i.first.contains(_position)) {
                        return;
                }
        }
 
        for (auto i: _periods) {
-               if (i.from > _position) {
-                       _position = i.from;
+               if (i.first.from > _position) {
+                       _position = i.first.from;
                        return;
                }
        }
 }
 
 
-DCPTimePeriod
+pair<DCPTimePeriod, Eyes>
 EmptyVideo::period_at_position () const
 {
        for (auto i: _periods) {
-               if (i.contains(_position)) {
-                       return DCPTimePeriod (_position, i.to);
+               if (i.first.contains(_position)) {
+                       return make_pair(DCPTimePeriod(_position, i.first.to), i.second);
                }
        }
 
@@ -94,7 +125,7 @@ EmptyVideo::done () const
 {
        DCPTime latest;
        for (auto i: _periods) {
-               latest = max (latest, i.to);
+               latest = max (latest, i.first.to);
        }
 
        return _position >= latest;
index cf315bc441cc108b0abecfd6bfb5fb376faef5ba..5659ba5040fa9cb4df15973f2804fd47abf23689 100644 (file)
 #include "dcpomatic_time.h"
 #include "playlist.h"
 #include <list>
+#include <utility>
 
 
 struct empty_video_test1;
 struct empty_video_test2;
 struct empty_video_test3;
 struct empty_video_test_with_overlapping_content;
+struct empty_video_test_with_three_d1;
+struct empty_video_test_with_three_d2;
 struct player_subframe_test;
 
 
@@ -46,7 +49,7 @@ public:
                return _position;
        }
 
-       dcpomatic::DCPTimePeriod period_at_position () const;
+       std::pair<dcpomatic::DCPTimePeriod, Eyes> period_at_position () const;
 
        bool done () const;
 
@@ -57,9 +60,11 @@ private:
        friend struct ::empty_video_test2;
        friend struct ::empty_video_test3;
        friend struct ::empty_video_test_with_overlapping_content;
+       friend struct empty_video_test_with_three_d1;
+       friend struct empty_video_test_with_three_d2;
        friend struct ::player_subframe_test;
 
-       std::list<dcpomatic::DCPTimePeriod> _periods;
+       std::list<std::pair<dcpomatic::DCPTimePeriod, Eyes>> _periods;
        dcpomatic::DCPTime _position;
 };
 
index 66b731645a1d4ef74521d2e4f116ed2aea57b90f..392c929a31f7923f505207d2db72c69c1330b649 100644 (file)
@@ -710,10 +710,13 @@ Player::pass ()
                break;
        }
        case BLACK:
+       {
                LOG_DEBUG_PLAYER ("Emit black for gap at %1", to_string(_black.position()));
-               emit_video (black_player_video_frame(Eyes::BOTH), _black.position());
+               auto period = _black.period_at_position();
+               emit_video (black_player_video_frame(period.second), _black.position());
                _black.set_position (_black.position() + one_video_frame());
                break;
+       }
        case SILENT:
        {
                LOG_DEBUG_PLAYER ("Emit silence for gap at %1", to_string(_silent.position()));
index 5e6424a2abb5db915d4324aa0a6d1ad8fc598a37..758ceee18fe5cf032832c9ee7f7abd3e465bea53 100644 (file)
@@ -72,11 +72,11 @@ BOOST_AUTO_TEST_CASE (empty_video_test1)
        EmptyVideo black (film, film->playlist(), film->playlist()->length(film));
        BOOST_REQUIRE_EQUAL (black._periods.size(), 2U);
        auto i = black._periods.begin();
-       BOOST_CHECK (i->from == DCPTime::from_frames(0, vfr));
-       BOOST_CHECK (i->to ==   DCPTime::from_frames(2, vfr));
+       BOOST_CHECK (i->first.from == DCPTime::from_frames(0, vfr));
+       BOOST_CHECK (i->first.to ==   DCPTime::from_frames(2, vfr));
        ++i;
-       BOOST_CHECK (i->from == DCPTime::from_frames(5, vfr));
-       BOOST_CHECK (i->to ==   DCPTime::from_frames(7, vfr));
+       BOOST_CHECK (i->first.from == DCPTime::from_frames(5, vfr));
+       BOOST_CHECK (i->first.to ==   DCPTime::from_frames(7, vfr));
 }
 
 
@@ -140,8 +140,8 @@ BOOST_AUTO_TEST_CASE (empty_video_test2)
 
        EmptyVideo black (film, film->playlist(), film->playlist()->length(film));
        BOOST_REQUIRE_EQUAL (black._periods.size(), 1U);
-       BOOST_CHECK (black._periods.front().from == DCPTime::from_frames(3, vfr));
-       BOOST_CHECK (black._periods.front().to == DCPTime::from_frames(7, vfr));
+       BOOST_CHECK (black._periods.front().first.from == DCPTime::from_frames(3, vfr));
+       BOOST_CHECK (black._periods.front().first.to == DCPTime::from_frames(7, vfr));
 
        /* position should initially be the start of the first empty period */
        BOOST_CHECK (black.position() == DCPTime::from_frames(3, vfr));
@@ -224,8 +224,8 @@ BOOST_AUTO_TEST_CASE (empty_video_test3)
        playlist->add (film, contentB);
        EmptyVideo black (film, playlist, playlist->length(film));
        BOOST_REQUIRE_EQUAL (black._periods.size(), 1U);
-       BOOST_CHECK (black._periods.front().from == DCPTime::from_frames(0, vfr));
-       BOOST_CHECK (black._periods.front().to == DCPTime::from_frames(7, vfr));
+       BOOST_CHECK (black._periods.front().first.from == DCPTime::from_frames(0, vfr));
+       BOOST_CHECK (black._periods.front().first.to == DCPTime::from_frames(7, vfr));
 
        /* position should initially be the start of the first empty period */
        BOOST_CHECK (black.position() == DCPTime::from_frames(0, vfr));
@@ -321,3 +321,86 @@ BOOST_AUTO_TEST_CASE (empty_audio_test_with_overlapping_content)
        BOOST_REQUIRE (silent._periods.empty());
 }
 
+
+BOOST_AUTO_TEST_CASE (empty_video_test_with_three_d1)
+{
+       auto film = new_test_film2 ("empty_video_test_with_three_d1");
+       film->set_sequence (false);
+
+       auto both1 = make_shared<ImageContent>("test/data/simple_testcard_640x480.png");
+       auto left = make_shared<ImageContent>("test/data/simple_testcard_640x480.png");
+       auto right = make_shared<ImageContent>("test/data/simple_testcard_640x480.png");
+       auto both2 = make_shared<ImageContent>("test/data/simple_testcard_640x480.png");
+
+       film->examine_and_add_content (both1);
+       film->examine_and_add_content (left);
+       film->examine_and_add_content (right);
+       film->examine_and_add_content (both2);
+       BOOST_REQUIRE (!wait_for_jobs());
+
+       int const vfr = film->video_frame_rate ();
+
+       both1->video->set_length (vfr * 1);
+       both1->set_position (film, DCPTime(0));
+
+       left->video->set_length (vfr * 2);
+       left->video->set_frame_type (VideoFrameType::THREE_D_LEFT);
+       left->set_position (film, DCPTime::from_seconds(2));
+
+       right->video->set_length (vfr * 2);
+       right->video->set_frame_type (VideoFrameType::THREE_D_RIGHT);
+       right->set_position (film, DCPTime::from_seconds(3));
+
+       both2->video->set_length (vfr * 1);
+       both2->set_position (film, DCPTime::from_seconds(6));
+
+       EmptyVideo black(film, film->playlist(), film->playlist()->length(film));
+
+       for (auto i: black._periods) {
+               std::cout << to_string(i.first.from) << " " << to_string(i.first.to) << " " << static_cast<int>(i.second) << "\n";
+       }
+       BOOST_REQUIRE_EQUAL (black._periods.size(), 4U);
+       auto i = black._periods.begin();
+       BOOST_CHECK (i->first.from == DCPTime::from_seconds(1));
+       BOOST_CHECK (i->first.to ==   DCPTime::from_seconds(2));
+       BOOST_CHECK (i->second ==     Eyes::BOTH);
+       ++i;
+       BOOST_CHECK (i->first.from == DCPTime::from_seconds(2));
+       BOOST_CHECK (i->first.to ==   DCPTime::from_seconds(3));
+       BOOST_CHECK (i->second ==     Eyes::RIGHT);
+       ++i;
+       BOOST_CHECK (i->first.from == DCPTime::from_seconds(4));
+       BOOST_CHECK (i->first.to ==   DCPTime::from_seconds(5));
+       BOOST_CHECK (i->second ==     Eyes::LEFT);
+       ++i;
+       BOOST_CHECK (i->first.from == DCPTime::from_seconds(5));
+       BOOST_CHECK (i->first.to ==   DCPTime::from_seconds(6));
+       BOOST_CHECK (i->second ==     Eyes::BOTH);
+}
+
+
+BOOST_AUTO_TEST_CASE (empty_video_test_with_three_d2)
+{
+       auto film = new_test_film2 ("empty_video_test_with_three_d2");
+       film->set_sequence (false);
+
+       auto both = make_shared<ImageContent>("test/data/simple_testcard_640x480.png");
+       auto right = make_shared<ImageContent>("test/data/simple_testcard_640x480.png");
+
+       film->examine_and_add_content (both);
+       film->examine_and_add_content (right);
+       BOOST_REQUIRE (!wait_for_jobs());
+
+       int const vfr = film->video_frame_rate ();
+
+       both->video->set_length (vfr * 1);
+       both->set_position (film, DCPTime(0));
+
+       right->video->set_length (vfr * 1);
+       right->video->set_frame_type (VideoFrameType::THREE_D_RIGHT);
+       right->set_position (film, DCPTime::from_seconds(0));
+
+       EmptyVideo black(film, film->playlist(), film->playlist()->length(film));
+       BOOST_REQUIRE (black._periods.empty());
+}
+
index 3fb8691a5222571560b3e1bf25fe1c8387b9d58e..3954fbbaeaebe6ff3cc9f7e0439ec2465fd0b41a 100644 (file)
@@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE (player_subframe_test)
        auto player = std::make_shared<Player>(film, Image::Alignment::COMPACT);
        player->setup_pieces ();
        BOOST_REQUIRE_EQUAL (player->_black._periods.size(), 1U);
-       BOOST_CHECK (player->_black._periods.front() == DCPTimePeriod(DCPTime::from_frames(3 * 24, 24), DCPTime::from_frames(3 * 24 + 1, 24)));
+       BOOST_CHECK (player->_black._periods.front().first == DCPTimePeriod(DCPTime::from_frames(3 * 24, 24), DCPTime::from_frames(3 * 24 + 1, 24)));
        BOOST_REQUIRE_EQUAL (player->_silent._periods.size(), 1U);
        BOOST_CHECK (player->_silent._periods.front() == DCPTimePeriod(DCPTime(289920), DCPTime::from_frames(3 * 24 + 1, 24)));
 }