[FFmpeg-devel] [PATCH] avcodec/mmaldec: use decoupled dataflow

Andreas Rheinhardt andreas.rheinhardt at outlook.com
Thu Sep 23 22:40:03 EEST 2021


Ho Ming Shun:
> MMAL is an fundamentally an asynchronous decoder, which was a bad fit
> for the legacy dataflow API. Often multiple packets are enqueued before
> a flood of frames are returned from MMAL.
> 
> The previous lockstep dataflow meant that any delay in returning packets
> from the VPU would cause ctx->queue_decoded_frames to grow with no way
> of draining the queue.
> 
> Testing this with mpv streaming from an RTSP source reduced decode
> latency from 2s to about 0.2s.
> 
> Signed-off-by: Ho Ming Shun <cyph1984 at gmail.com>
> ---
>  libavcodec/mmaldec.c | 30 +++++++++++++++++++++++-------
>  1 file changed, 23 insertions(+), 7 deletions(-)
> 
> diff --git a/libavcodec/mmaldec.c b/libavcodec/mmaldec.c
> index 96140bf53d..3d7cc90cd2 100644
> --- a/libavcodec/mmaldec.c
> +++ b/libavcodec/mmaldec.c
> @@ -570,6 +570,7 @@ static int ffmmal_add_packet(AVCodecContext *avctx, AVPacket *avpkt,
>  
>  done:
>      av_buffer_unref(&buf);
> +    av_packet_unref(avpkt);
>      return ret;
>  }
>  
> @@ -655,6 +656,12 @@ static int ffmal_copy_frame(AVCodecContext *avctx,  AVFrame *frame,
>                        avctx->pix_fmt, avctx->width, avctx->height);
>      }
>  
> +    frame->sample_aspect_ratio = avctx->sample_aspect_ratio;
> +    frame->width = avctx->width;
> +    frame->width = avctx->width;
> +    frame->height = avctx->height;
> +    frame->format = avctx->pix_fmt;
> +
>      frame->pts = buffer->pts == MMAL_TIME_UNKNOWN ? AV_NOPTS_VALUE : buffer->pts;
>      frame->pkt_dts = AV_NOPTS_VALUE;
>  
> @@ -763,12 +770,12 @@ done:
>      return ret;
>  }
>  
> -static int ffmmal_decode(AVCodecContext *avctx, void *data, int *got_frame,
> -                         AVPacket *avpkt)
> +static int ffmmal_receive_frame(AVCodecContext *avctx, AVFrame *frame)
>  {
>      MMALDecodeContext *ctx = avctx->priv_data;
> -    AVFrame *frame = data;
>      int ret = 0;
> +    AVPacket avpkt;

You are adding a new AVPacket; and you are not even zeroing it. This is
even worse than the current code (and it might even be dangerous:
ff_decode_get_packet() expects initialized, blank packets, not
uninitialized ones; what you are doing only works because this decoder
does not have an automatically inserted bitstream filter).

You will have to add an actually allocated packet for this; or one could
reuse the spare packet of the DecodeSimpleContext that is unused for
decoders implementing the receive_frame API.

It is easy to fix the deprecation issue if one already has a spare
packet: Just put the extradata into said packet.
My guess that your patch does not exhibit any deep conflicts with mine
turned out to be correct: the only part where there is a real conflict
is in the fact that it doesn't make any sense any more to treat the
packet as const, given that a decoder implementing the receive_frame API
is supposed to unref the packets it receives on its own.
While I regard not wrapping the extradata in a packet as cleaner, the
code actually becomes simpler if one does so (as I will demonstrate
lateron). In other words: I drop my patches.

> +    int got_frame = 0;
>  
>      if (avctx->extradata_size && !ctx->extradata_sent) {
>          AVPacket pkt = {0};
> @@ -782,7 +789,11 @@ FF_ENABLE_DEPRECATION_WARNINGS
>              return ret;
>      }
>  
> -    if ((ret = ffmmal_add_packet(avctx, avpkt, 0)) < 0)
> +    ret = ff_decode_get_packet(avctx, &avpkt);
> +    if(ret == 0) {
> +        if ((ret = ffmmal_add_packet(avctx, &avpkt, 0)) < 0)
> +            return ret;
> +    } else if(ret < 0 && !(ret == AVERROR(EAGAIN)))
>          return ret;
>  
>      if ((ret = ffmmal_fill_input_port(avctx)) < 0)
> @@ -791,7 +802,7 @@ FF_ENABLE_DEPRECATION_WARNINGS
>      if ((ret = ffmmal_fill_output_port(avctx)) < 0)
>          return ret;
>  
> -    if ((ret = ffmmal_read_frame(avctx, frame, got_frame)) < 0)
> +    if ((ret = ffmmal_read_frame(avctx, frame, &got_frame)) < 0)
>          return ret;
>  
>      // ffmmal_read_frame() can block for a while. Since the decoder is
> @@ -803,7 +814,12 @@ FF_ENABLE_DEPRECATION_WARNINGS
>      if ((ret = ffmmal_fill_input_port(avctx)) < 0)
>          return ret;
>  
> -    return ret;
> +    if(!got_frame && ret == 0)
> +        return AVERROR(EAGAIN);
> +    else
> +        return ret;
> +
> +

Unnecessary newlines.

>  }
>  
>  static const AVCodecHWConfigInternal *const mmal_hw_configs[] = {
> @@ -835,7 +851,7 @@ static const AVOption options[]={
>          .priv_data_size = sizeof(MMALDecodeContext), \
>          .init           = ffmmal_init_decoder, \
>          .close          = ffmmal_close_decoder, \
> -        .decode         = ffmmal_decode, \
> +        .receive_frame  = ffmmal_receive_frame, \
>          .flush          = ffmmal_flush, \
>          .priv_class     = &ffmmal_##NAME##_dec_class, \
>          .capabilities   = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_HARDWARE, \
> 



More information about the ffmpeg-devel mailing list