diff mbox series

[FFmpeg-devel,02/12] avcodec/mediacodecdec: don't break out if both input and output port return try again

Message ID tencent_F0DF3FB756759D60E0E05BBA35DD81643409@qq.com
State New
Headers show
Series Add MediaCodec encoder and NDK MediaCodec support | expand

Checks

Context Check Description
yinshiyou/make_loongarch64 success Make finished
yinshiyou/make_fate_loongarch64 success Make fate finished
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Zhao Zhili Oct. 24, 2022, 3:16 a.m. UTC
From: Zhao Zhili <zhilizhao@tencent.com>

At the beginning of decoding, if we feed mediacodec too fast, the
input port will return try again. It takes some time for mediacodec
to consume bitstream and output frame. So the output port also return
try again. It possible that mediacodec_receive_frame doesn't consume
any AVPacket and no AVFrame is output. Then both avcodec_send_packet()
and avcodec_receive_frame() return EAGAIN, which shouldn't happen.

This bug can be produced with decoding benchmark on Pixel 3.

Signed-off-by: Zhao Zhili <zhilizhao@tencent.com>
---
 libavcodec/mediacodecdec.c | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)
diff mbox series

Patch

diff --git a/libavcodec/mediacodecdec.c b/libavcodec/mediacodecdec.c
index 322b448d27..2c66f38541 100644
--- a/libavcodec/mediacodecdec.c
+++ b/libavcodec/mediacodecdec.c
@@ -444,7 +444,16 @@  static int mediacodec_receive_frame(AVCodecContext *avctx, AVFrame *frame)
             index = ff_AMediaCodec_dequeueInputBuffer(s->ctx->codec, 0);
             if (index < 0) {
                 /* no space, block for an output frame to appear */
-                return ff_mediacodec_dec_receive(avctx, s->ctx, frame, true);
+                ret = ff_mediacodec_dec_receive(avctx, s->ctx, frame, true);
+                /* Try again if both input port and output port return EAGAIN.
+                 * If no data is consumed and no frame in output, it can make
+                 * both avcodec_send_packet() and avcodec_receive_frame()
+                 * return EAGAIN, which violate the design.
+                 */
+                if (ff_AMediaCodec_infoTryAgainLater(s->ctx->codec, index) &&
+                    ret == AVERROR(EAGAIN))
+                    continue;
+                return ret;
             }
             s->ctx->current_input_buffer = index;
         }