Fix failure to decode multiple video frames from one packet (#2159). v2.15.183
authorCarl Hetherington <cth@carlh.net>
Tue, 11 Jan 2022 15:42:30 +0000 (16:42 +0100)
committerCarl Hetherington <cth@carlh.net>
Tue, 11 Jan 2022 21:16:16 +0000 (22:16 +0100)
src/lib/ffmpeg_decoder.cc
test/ffmpeg_decoder_error_test.cc
test/player_test.cc

index f64ccbd3b6305249c4522ee69d175dee6bb26849..b2a1bbbe0eba06b00a3be8d1721f83dab6bfdab9 100644 (file)
@@ -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<VideoFilterGraph> graph;
index 368f54e3ccce7c0020cc2f622935ef56937ec4e1..414c6138496c31f14bb1e8c8cedf58c548d3cdab 100644 (file)
@@ -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 <boost/test/unit_test.hpp>
 
@@ -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<Player>(film, film->playlist());
+
+       while (!player->pass()) {}
+}
+
index cafb14586a1e56421449c7e97b5b0c3366c4a5fc..0d3af5f8c73abc3d8984df70d17db0fd3cfbdd36 100644 (file)
@@ -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);
        }
 }