From 758c1ba16ab87152621f6c7c62c2e011a2ae2712 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Tue, 11 Jan 2022 16:42:30 +0100 Subject: [PATCH] Fix failure to decode multiple video frames from one packet (#2159). --- src/lib/ffmpeg_decoder.cc | 24 ++++++++++++------------ test/ffmpeg_decoder_error_test.cc | 11 +++++++++++ test/player_test.cc | 2 +- 3 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/lib/ffmpeg_decoder.cc b/src/lib/ffmpeg_decoder.cc index f64ccbd3b..b2a1bbbe0 100644 --- a/src/lib/ffmpeg_decoder.cc +++ b/src/lib/ffmpeg_decoder.cc @@ -538,17 +538,19 @@ FFmpegDecoder::decode_and_process_video_packet (AVPacket* packet) LOG_WARNING("avcodec_send_packet returned %1 for a video packet", r); } - r = avcodec_receive_frame (context, _video_frame); - if (r == AVERROR(EAGAIN) || r == AVERROR_EOF || (r < 0 && !packet)) { - /* More input is required, no more frames are coming, or we are flushing and there was - * some error which we just want to ignore. - */ - return false; - } else if (r < 0) { - throw DecodeError (N_("avcodec_receive_frame"), N_("FFmpeg::decode_and_process_video_packet"), r); - } + while (true) { + r = avcodec_receive_frame (context, _video_frame); + if (r == AVERROR(EAGAIN) || r == AVERROR_EOF || (r < 0 && !packet)) { + /* More input is required, no more frames are coming, or we are flushing and there was + * some error which we just want to ignore. + */ + return false; + } else if (r < 0) { + throw DecodeError (N_("avcodec_receive_frame"), N_("FFmpeg::decode_and_process_video_packet"), r); + } - process_video_frame (); + process_video_frame (); + } return true; } @@ -557,8 +559,6 @@ FFmpegDecoder::decode_and_process_video_packet (AVPacket* packet) void FFmpegDecoder::process_video_frame () { - /* We assume we'll only get one frame here, which I think is safe */ - boost::mutex::scoped_lock lm (_filter_graphs_mutex); shared_ptr graph; diff --git a/test/ffmpeg_decoder_error_test.cc b/test/ffmpeg_decoder_error_test.cc index 368f54e3c..414c61384 100644 --- a/test/ffmpeg_decoder_error_test.cc +++ b/test/ffmpeg_decoder_error_test.cc @@ -22,6 +22,7 @@ #include "lib/content.h" #include "lib/content_factory.h" #include "lib/dcpomatic_time.h" +#include "lib/player.h" #include "test.h" #include @@ -46,3 +47,13 @@ BOOST_AUTO_TEST_CASE (check_exception_during_flush) } + +BOOST_AUTO_TEST_CASE (check_exception_with_multiple_video_frames_per_packet) +{ + auto content = content_factory(TestPaths::private_data() / "chk.mkv").front(); + auto film = new_test_film2 ("check_exception_with_multiple_video_frames_per_packet", { content }); + auto player = std::make_shared(film, film->playlist()); + + while (!player->pass()) {} +} + diff --git a/test/player_test.cc b/test/player_test.cc index cafb14586..0d3af5f8c 100644 --- a/test/player_test.cc +++ b/test/player_test.cc @@ -210,7 +210,7 @@ BOOST_AUTO_TEST_CASE (player_interleave_test) player->Audio.connect (bind (&audio, _1, _2)); video_frames = audio_frames = 0; while (!player->pass ()) { - BOOST_CHECK (abs(video_frames - (audio_frames / 2000)) < 8); + BOOST_CHECK (abs(video_frames - (audio_frames / 2000)) <= 8); } } -- 2.30.2