Merge pull request #23606 from mshabunin:fix-ffmpeg-packet-limit

videoio/FFmpeg: increased packet read attempt limit, allow configuring it

resolves #9455
related #3225

* Use different counters for wrong packets recieved by demuxer and errors from decoder
* Allow modifying these counters via environment variables `OPENCV_FFMPEG_READ_ATTEMPTS`/`OPENCV_FFMPEG_DECODE_ATTEMPTS`
* Added logging when reading breaks at one of error limits

Notes:
* I've been able to reproduce original issue with a video file with 14 total streams (video + audio + subtitles), at some point in the video only packets from the last stream are being sent by the demuxer, thus exceeding our limit. For my specific video total number of packets from wrong stream was about 2700. I've chosen 4096 as default value.
* Default limit of decoding attempts is quite low, because I'm not sure in which cases it can be exceeded (network stream?). I tried to read 8k video from the disk, but it did not cause break at decode point.
pull/23637/head
Maksim Shabunin 2 years ago committed by GitHub
parent bcb49d71b4
commit 001a2c5195
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 26
      modules/videoio/src/cap_ffmpeg_impl.hpp

@ -40,6 +40,7 @@
// //
//M*/ //M*/
#include <opencv2/core/utils/configuration.private.hpp>
#include "cap_ffmpeg_legacy_api.hpp" #include "cap_ffmpeg_legacy_api.hpp"
#include "opencv2/core/utils/logger.hpp" #include "opencv2/core/utils/logger.hpp"
#include "cap_interface.hpp" #include "cap_interface.hpp"
@ -1428,8 +1429,10 @@ bool CvCapture_FFMPEG::grabFrame()
{ {
bool valid = false; bool valid = false;
int count_errs = 0; static const size_t max_read_attempts = cv::utils::getConfigurationParameterSizeT("OPENCV_FFMPEG_READ_ATTEMPTS", 4096);
const int max_number_of_attempts = 1 << 9; static const size_t max_decode_attempts = cv::utils::getConfigurationParameterSizeT("OPENCV_FFMPEG_DECODE_ATTEMPTS", 64);
size_t cur_read_attempts = 0;
size_t cur_decode_attempts = 0;
if( !ic || !video_st || !context ) return false; if( !ic || !video_st || !context ) return false;
@ -1484,9 +1487,15 @@ bool CvCapture_FFMPEG::grabFrame()
if( packet.stream_index != video_stream ) if( packet.stream_index != video_stream )
{ {
_opencv_ffmpeg_av_packet_unref (&packet); _opencv_ffmpeg_av_packet_unref (&packet);
count_errs++; if (++cur_read_attempts > max_read_attempts)
if (count_errs > max_number_of_attempts) {
CV_LOG_WARNING(NULL,
"packet read max attempts exceeded, if your video have "
"multiple streams (video, audio) try to increase attempt "
"limit by setting environment variable OPENCV_FFMPEG_READ_ATTEMPTS "
"(current value is " << max_read_attempts << ")");
break; break;
}
continue; continue;
} }
@ -1514,9 +1523,14 @@ bool CvCapture_FFMPEG::grabFrame()
} }
else else
{ {
count_errs++; if (++cur_decode_attempts > max_decode_attempts)
if (count_errs > max_number_of_attempts) {
CV_LOG_WARNING(NULL,
"frame decode max attempts exceeded, try to increase attempt "
"limit by setting environment variable OPENCV_FFMPEG_DECODE_ATTEMPTS "
"(current value is " << max_decode_attempts << ")");
break; break;
}
} }
} }

Loading…
Cancel
Save