[FFmpeg-devel] [PATCH] Use AVBufferPool in MOV

Arnaud Masserann arnaud1602 at gmail.com
Fri Nov 22 20:07:41 EET 2024


A few questions:

- Should the pools be per-stream (in MOVStreamContext) or per file (in
MOVContext) ?
- I added an av_get_pooled_packet(AVBufferPool*) function in the
avformat API. This might be undesirable. Possible alternatives:
   - Adding a av_get_pooled_packet(AVBufferPool*[32]) function
instead; this matches the way mpegts uses the pool, but is probably
too restrictive since it forces all future users to have this array of
32 pools.
   - Duplicating av_get_packet in mov.c; but then
append_packet_chunked needs to be duplicated too.

Feedback is welcome.

On Fri, Nov 22, 2024 at 6:46 PM Arnaud Masserann <arnaud1602 at gmail.com> wrote:
>
> Most demuxers allocate a new buffer for each packet.
> For MOV, this can be problematic, because of some high-bitrate
> codecs like ProRes/HAPQ/NotchLC.
>
> Use pools of buffer instead.
>
> For some test media, demuxing goes from 20ms/frame to 11ms/frame,
> close to the perf of ReadFile (10ms/frame), making it possible
> to read the media at 60Hz.
>
> Signed-off-by: Arnaud Masserann <Arnaud1602 at gmail.com>
> ---
>  libavformat/avformat.h | 12 ++++++++++++
>  libavformat/isom.h     |  2 ++
>  libavformat/mov.c      | 20 ++++++++++++++++++--
>  libavformat/utils.c    | 29 +++++++++++++++++++++++++++++
>  4 files changed, 61 insertions(+), 2 deletions(-)
>
> diff --git a/libavformat/avformat.h b/libavformat/avformat.h
> index 56c1c80289..25f2e59b22 100644
> --- a/libavformat/avformat.h
> +++ b/libavformat/avformat.h
> @@ -440,6 +440,18 @@ int av_get_packet(AVIOContext *s, AVPacket *pkt, int size);
>   */
>  int av_append_packet(AVIOContext *s, AVPacket *pkt, int size);
>
> +
> +/**
> + * Like av_get_packet, but allocates the AVPacket's buffer from a pool.
> + *
> + * @param s    associated IO context
> + * @param pool the pool of buffers; must be initialized with a sufficient size
> + * @param pkt packet
> + * @param size desired payload size
> + * @return >0 (read size) if OK, AVERROR_xxx otherwise
> + */
> +int av_get_pooled_packet(AVIOContext *s, AVBufferPool* pool, AVPacket *pkt, int size);
> +
>  /*************************************************/
>  /* input/output formats */
>
> diff --git a/libavformat/isom.h b/libavformat/isom.h
> index 4723397048..c608f30e04 100644
> --- a/libavformat/isom.h
> +++ b/libavformat/isom.h
> @@ -273,6 +273,8 @@ typedef struct MOVStreamContext {
>      } cenc;
>
>      struct IAMFDemuxContext *iamf;
> +
> +    AVBufferPool* pools[32];
>  } MOVStreamContext;
>
>  typedef struct HEIFItem {
> diff --git a/libavformat/mov.c b/libavformat/mov.c
> index a2333ac1fd..2668bdf78f 100644
> --- a/libavformat/mov.c
> +++ b/libavformat/mov.c
> @@ -9583,6 +9583,7 @@ static void mov_free_encryption_index(MOVEncryptionIndex **index) {
>  static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
>  {
>      MOVStreamContext *sc = st->priv_data;
> +    int i;
>
>      if (!sc || --sc->refcount) {
>          st->priv_data = NULL;
> @@ -9639,6 +9640,9 @@ static void mov_free_stream_context(AVFormatContext *s, AVStream *st)
>          ff_iamf_read_deinit(sc->iamf);
>  #endif
>      av_freep(&sc->iamf);
> +
> +    for (i = 0; i < FF_ARRAY_ELEMS(sc->pools); i++)
> +        av_buffer_pool_uninit(&sc->pools[i]);
>  }
>
>  static int mov_read_close(AVFormatContext *s)
> @@ -10544,6 +10548,16 @@ static int mov_finalize_packet(AVFormatContext *s, AVStream *st, AVIndexEntry *s
>      return 0;
>  }
>
> +static AVBufferPool *mov_pool_get(AVBufferPool* pools[32], int size)
> +{
> +    int index = av_log2(size + AV_INPUT_BUFFER_PADDING_SIZE);
> +    if (!pools[index]) {
> +        int pool_size = 2 << index;
> +        pools[index] = av_buffer_pool_init(pool_size, NULL);
> +    }
> +    return pools[index];
> +}
> +
>  static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
>  {
>      MOVContext *mov = s->priv_data;
> @@ -10617,8 +10631,10 @@ static int mov_read_packet(AVFormatContext *s, AVPacket *pkt)
>                  return FFERROR_REDO;
>          }
>  #endif
> -        else
> -            ret = av_get_packet(sc->pb, pkt, sample->size);
> +        else{
> +            AVBufferPool* pool = mov_pool_get(sc->pools, sample->size);
> +            ret = av_get_pooled_packet(sc->pb, pool, pkt, sample->size);
> +        }
>          if (ret < 0) {
>              if (should_retry(sc->pb, ret)) {
>                  mov_current_sample_dec(sc);
> diff --git a/libavformat/utils.c b/libavformat/utils.c
> index e9ded627ad..869e97c089 100644
> --- a/libavformat/utils.c
> +++ b/libavformat/utils.c
> @@ -104,6 +104,35 @@ FF_ENABLE_DEPRECATION_WARNINGS
>      return append_packet_chunked(s, pkt, size);
>  }
>
> +int av_get_pooled_packet(AVIOContext *s, AVBufferPool* pool, AVPacket *pkt, int size)
> +{
> +#if FF_API_INIT_PACKET
> +FF_DISABLE_DEPRECATION_WARNINGS
> +    av_init_packet(pkt);
> +    pkt->data = NULL;
> +    pkt->size = 0;
> +FF_ENABLE_DEPRECATION_WARNINGS
> +#else
> +    av_packet_unref(pkt);
> +#endif
> +    pkt->pos  = avio_tell(s);
> +
> +    if(!pool)
> +        return AVERROR(ENOMEM);
> +
> +    pkt->buf = av_buffer_pool_get(pool);;
> +    if(!pkt->buf)
> +        return AVERROR(ENOMEM);
> +
> +    if(pkt->buf->size < size){
> +        av_packet_unref(pkt); // TODO test this
> +        return AVERROR(ENOMEM);
> +    }
> +
> +    return append_packet_chunked(s, pkt, size);
> +}
> +
> +
>  int av_append_packet(AVIOContext *s, AVPacket *pkt, int size)
>  {
>      if (!pkt->size)
> --
> 2.38.1.windows.1
>


More information about the ffmpeg-devel mailing list