diff options
| author | Carl Hetherington <cth@carlh.net> | 2025-03-05 19:58:24 +0100 |
|---|---|---|
| committer | Carl Hetherington <cth@carlh.net> | 2025-03-06 22:57:34 +0100 |
| commit | 3b908673629f4a475abcf1aa56f3b03c60fca13a (patch) | |
| tree | 8dff258d0cbec9f69d4f1ebf9c6f75e8633df656 | |
| parent | 8f65aa1a9a63a05ff809a35b0708607d6f77dc7c (diff) | |
Fix black frames when raising frame rate by a lot (#2993).
| -rw-r--r-- | src/lib/player.cc | 17 | ||||
| -rw-r--r-- | test/player_test.cc | 26 |
2 files changed, 39 insertions, 4 deletions
diff --git a/src/lib/player.cc b/src/lib/player.cc index fd99e7732..4c988c804 100644 --- a/src/lib/player.cc +++ b/src/lib/player.cc @@ -997,7 +997,16 @@ Player::emit_video_until(DCPTime time) emit_video(to_do.first, to_do.second); }; - auto const age_threshold = one_video_frame() * 2; + auto film = _film.lock(); + DCPOMATIC_ASSERT(film); + + auto const age_threshold = [this, film](pair<shared_ptr<PlayerVideo>, dcpomatic::DCPTime> video) { + if (auto content = video.first->content().lock()) { + return one_video_frame() * (std::ceil(film->video_frame_rate() / content->video_frame_rate().get_value_or(24)) + 1); + } else { + return one_video_frame() * 2; + } + }; while (_next_video_time.get_value_or({}) < time) { auto left = _last_video[Eyes::LEFT]; @@ -1010,12 +1019,12 @@ Player::emit_video_until(DCPTime time) left.first && right.first && (!both.first || (left.second >= both.second && right.second >= both.second)) && - (left.second - next) < age_threshold && - (right.second - next) < age_threshold + (left.second - next) < age_threshold(left) && + (right.second - next) < age_threshold(right) ) { frame(left.first, next); frame(right.first, next); - } else if (both.first && (both.second - next) < age_threshold) { + } else if (both.first && (both.second - next) < age_threshold(both)) { frame(both.first, next); LOG_DEBUG_PLAYER("Content %1 selected for DCP %2 (age %3)", to_string(both.second), to_string(next), to_string(both.second - next)); } else { diff --git a/test/player_test.cc b/test/player_test.cc index eb49bc4df..60b365eb1 100644 --- a/test/player_test.cc +++ b/test/player_test.cc @@ -731,3 +731,29 @@ BOOST_AUTO_TEST_CASE(unmapped_audio_does_not_raise_buffer_error) butler.rethrow(); } + +BOOST_AUTO_TEST_CASE(frames_are_copied_correctly_for_low_frame_rates) +{ + auto content = content_factory("test/data/flat_red.png"); + auto film = new_test_film("frames_are_copied_correctly_for_low_frame_rates", content); + + content[0]->set_video_frame_rate(film, 10); + film->set_video_frame_rate(30); + + Player player(film, Image::Alignment::COMPACT, false); + Butler butler(film, player, AudioMapping(), 2, bind(PlayerVideo::force, AV_PIX_FMT_RGB24), VideoRange::FULL, Image::Alignment::PADDED, true, false, Butler::Audio::ENABLED); + + /* Check that only red frames come out - previously there would be some black ones mixed in */ + for (auto i = 0; i < 24; ++i) { + auto frame = butler.get_video(Butler::Behaviour::BLOCKING); + auto image = frame.first->image([](AVPixelFormat) { return AV_PIX_FMT_RGB24; }, VideoRange::FULL, false); + for (int y = 0; y < image->size().height; ++y) { + uint8_t const* p = image->data()[0] + image->stride()[0] * y; + for (int x = 0; x < image->size().width; ++x) { + BOOST_REQUIRE_EQUAL(p[0], 255); + BOOST_REQUIRE_EQUAL(p[1], 0); + BOOST_REQUIRE_EQUAL(p[2], 0); + } + } + } +} |
