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

Ming Shun Ho cyph1984 at gmail.com
Fri Sep 24 09:29:39 EEST 2021


On Fri, Sep 24, 2021 at 3:40 AM Andreas Rheinhardt
<andreas.rheinhardt at outlook.com> wrote:
>
> 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).

Ah thanks for that.

>
> 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.

Ok. Kind of scary because I don't see anyone else doing this.

>
> It is easy to fix the deprecation issue if one already has a spare
> packet: Just put the extradata into said packet.

I realized I do not need another spare packet. Previous decode based API
needed another AVPacket for extra_data because avpkt was passed in as
a function parameter.

Will post another version of this series to fix all warnings and switch to
receive_frame (for latency reasons most importantly).

> 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, \
> >
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
>
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request at ffmpeg.org with subject "unsubscribe".


More information about the ffmpeg-devel mailing list