diff options
| -rwxr-xr-x | run/tests | 2 | ||||
| -rw-r--r-- | src/lib/ffmpeg_decoder.cc | 19 | ||||
| -rw-r--r-- | test/ffmpeg_decoder_seek_test.cc | 19 |
3 files changed, 33 insertions, 7 deletions
@@ -3,7 +3,7 @@ # e.g. --run_tests=foo set -e -PRIVATE_GIT="81e32cb5962320333839b7020d14d9f291b8ff2d" +PRIVATE_GIT="e92043f43b024812f2b5f8c8faed159a15a87aaf" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" source $DIR/environment diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index ebbc242e3..c70733c4c 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -431,12 +431,19 @@ FFmpegDecoder::seek (ContentTime time, bool accurate) if (u < ContentTime ()) { u = ContentTime (); } - av_seek_frame ( - _format_context, - stream.get(), - u.seconds() / av_q2d (_format_context->streams[stream.get()]->time_base), - AVSEEK_FLAG_BACKWARD - ); + + auto seek = [&](int flag) { + return av_seek_frame( + _format_context, + stream.get(), + u.seconds() / av_q2d (_format_context->streams[stream.get()]->time_base), + flag + ); + }; + + if (seek(AVSEEK_FLAG_BACKWARD) < 0) { + DCPOMATIC_ASSERT(seek(AVSEEK_FLAG_ANY) >= 0); + }; /* Force re-creation of filter graphs to reset them, to make sure they don't have any pre-seek frames. diff --git a/test/ffmpeg_decoder_seek_test.cc b/test/ffmpeg_decoder_seek_test.cc index 43967e458..ee0da99da 100644 --- a/test/ffmpeg_decoder_seek_test.cc +++ b/test/ffmpeg_decoder_seek_test.cc @@ -133,3 +133,22 @@ BOOST_AUTO_TEST_CASE(ffmpeg_decoder_seek_test) } ); } + + +BOOST_AUTO_TEST_CASE(seek_when_backward_fails) +{ + auto content = make_shared<FFmpegContent>(TestPaths::private_data() / "strange_keyframes.mp4"); + auto film = new_test_film("seek_when_backward_fails", { content }); + auto decoder = make_shared<FFmpegDecoder>(film, content, false); + decoder->video->Data.connect(bind(&store, _1)); + + /* Due to a bug this seek would fail silently, giving us different frame each time */ + for (auto i = 0; i < 3; ++i) { + decoder->seek(dcpomatic::ContentTime(), true); + stored = {}; + while (!decoder->pass() && !stored) {} + BOOST_REQUIRE(static_cast<bool>(stored)); + BOOST_CHECK(stored->time == dcpomatic::ContentTime()); + } +} + |
