diff mbox series

[FFmpeg-devel] avcodec/mmaldec: fix decoder freeze when flushing

Message ID 20210916134652.22781-1-cyph1984@gmail.com
State New
Headers show
Series [FFmpeg-devel] avcodec/mmaldec: fix decoder freeze when flushing | expand

Checks

Context Check Description
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished
andriy/make_ppc success Make finished
andriy/make_fate_ppc success Make fate finished

Commit Message

Ming Shun Ho Sept. 16, 2021, 1:46 p.m. UTC
When mmal_flush is called before any packets are sent,
enabling/disabling the MMAL ports seems to cause the decoder to not
output any packets after flushing.

Bug is triggered when using 'mpv --hwdec=mmal --start=1 test.mp4'.

Proposed workaround in MPV: https://github.com/mpv-player/mpv/pull/9189

Signed-off-by: Ho Ming Shun <cyph1984@gmail.com>
---
 libavcodec/mmaldec.c | 38 +++++++++++++++++++++++---------------
 1 file changed, 23 insertions(+), 15 deletions(-)
diff mbox series

Patch

diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c
index 8c7d749742..6c3e5d99b6 100644
--- a/libavcodec/mmaldec.c
+++ b/libavcodec/mmaldec.c
@@ -145,19 +145,21 @@  static int ffmmal_set_ref(AVFrame *frame, FFPoolRef *pool,
     return 0;
 }
 
-static void ffmmal_stop_decoder(AVCodecContext *avctx)
+static void ffmmal_stop_decoder(AVCodecContext *avctx, int flush_ports)
 {
     MMALDecodeContext *ctx = avctx->priv_data;
     MMAL_COMPONENT_T *decoder = ctx->decoder;
     MMAL_BUFFER_HEADER_T *buffer;
 
-    mmal_port_disable(decoder->input[0]);
-    mmal_port_disable(decoder->output[0]);
-    mmal_port_disable(decoder->control);
+    if(flush_ports) {
+        mmal_port_disable(decoder->input[0]);
+        mmal_port_disable(decoder->output[0]);
+        mmal_port_disable(decoder->control);
 
-    mmal_port_flush(decoder->input[0]);
-    mmal_port_flush(decoder->output[0]);
-    mmal_port_flush(decoder->control);
+        mmal_port_flush(decoder->input[0]);
+        mmal_port_flush(decoder->output[0]);
+        mmal_port_flush(decoder->control);
+    }
 
     while ((buffer = mmal_queue_get(ctx->queue_decoded_frames)))
         mmal_buffer_header_release(buffer);
@@ -185,7 +187,7 @@  static av_cold int ffmmal_close_decoder(AVCodecContext *avctx)
     MMALDecodeContext *ctx = avctx->priv_data;
 
     if (ctx->decoder)
-        ffmmal_stop_decoder(avctx);
+        ffmmal_stop_decoder(avctx, 1);
 
     mmal_component_destroy(ctx->decoder);
     ctx->decoder = NULL;
@@ -456,14 +458,20 @@  static void ffmmal_flush(AVCodecContext *avctx)
     MMAL_COMPONENT_T *decoder = ctx->decoder;
     MMAL_STATUS_T status;
 
-    ffmmal_stop_decoder(avctx);
+    // MMAL will freeze if ports are enabled/disabled/flushed before
+    // buffers are sent
+    int flush_ports = ctx->packets_sent || ctx->extradata_sent;
 
-    if ((status = mmal_port_enable(decoder->control, control_port_cb)))
-        goto fail;
-    if ((status = mmal_port_enable(decoder->input[0], input_callback)))
-        goto fail;
-    if ((status = mmal_port_enable(decoder->output[0], output_callback)))
-        goto fail;
+    ffmmal_stop_decoder(avctx, flush_ports);
+
+    if(flush_ports) {
+        if ((status = mmal_port_enable(decoder->control, control_port_cb)))
+            goto fail;
+        if ((status = mmal_port_enable(decoder->input[0], input_callback)))
+            goto fail;
+        if ((status = mmal_port_enable(decoder->output[0], output_callback)))
+            goto fail;
+    }
 
     return;