Properly support asynchronous decoders that return multiple frames at a time

This commit is contained in:
Cameron Gutman 2021-12-11 18:15:49 -06:00
parent 9579b2c85e
commit 80128e8293

View File

@ -902,6 +902,7 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
{ {
PLENTRY entry = du->bufferList; PLENTRY entry = du->bufferList;
int err; int err;
bool submittedFrame = false;
SDL_assert(!m_TestOnly); SDL_assert(!m_TestOnly);
@ -991,6 +992,10 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
m_FramesIn++; m_FramesIn++;
// We can receive 0 or more frames after submission of a packet, so we must
// try to read until we get EAGAIN to ensure the queue is drained. Some decoders
// run asynchronously and may return several frames at once after warming up.
do {
AVFrame* frame = av_frame_alloc(); AVFrame* frame = av_frame_alloc();
if (!frame) { if (!frame) {
// Failed to allocate a frame but we did submit, // Failed to allocate a frame but we did submit,
@ -1011,6 +1016,7 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
av_log_set_level(AV_LOG_INFO); av_log_set_level(AV_LOG_INFO);
// Store the presentation time // Store the presentation time
// FIXME: This is wrong when reading a batch of frames
frame->pts = du->presentationTimeMs; frame->pts = du->presentationTimeMs;
// Capture a frame timestamp to measuring pacing delay // Capture a frame timestamp to measuring pacing delay
@ -1029,10 +1035,18 @@ int FFmpegVideoDecoder::submitDecodeUnit(PDECODE_UNIT du)
// Queue the frame for rendering (or render now if pacer is disabled) // Queue the frame for rendering (or render now if pacer is disabled)
m_Pacer->submitFrame(frame); m_Pacer->submitFrame(frame);
submittedFrame = true;
} }
else { else {
av_frame_free(&frame); av_frame_free(&frame);
}
} while (err == 0);
// Treat this as a failed decode if we don't manage to receive a single frame or
// if we finish the loop above with an error other than EAGAIN. Note that some
// limited number of "failed decodes" with EAGAIN are expected for asynchronous
// decoders, so we only reset the decoder if we get a ton of them in a row.
if (!submittedFrame || err != AVERROR(EAGAIN)) {
char errorstring[512]; char errorstring[512];
av_strerror(err, errorstring, sizeof(errorstring)); av_strerror(err, errorstring, sizeof(errorstring));
SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION, SDL_LogWarn(SDL_LOG_CATEGORY_APPLICATION,