lavc/container_fifo: move to lavu and make public

This can be useful in other places, e.g. it can replace objpool in
fftools.

The API is modified in the following nontrivial ways:
* opaque pointers can be passed through to all user callbacks
* read and write were previously separate callbacks in order to
  accomodate the caller wishing to write a new reference to the FIFO and
  keep the original one; the two callbacks are now merged into one, and
  a flags argument is added that allows to request such behaviour on a
  per-call basis
* new peek and drain functions
pull/391/head
Anton Khirnov 3 months ago
parent 56ba57b672
commit 2e956d9c0f
  1. 5
      doc/APIchanges
  2. 2
      libavcodec/Makefile
  3. 89
      libavcodec/container_fifo.h
  4. 10
      libavcodec/hevc/hevcdec.c
  5. 2
      libavcodec/hevc/hevcdec.h
  6. 4
      libavcodec/hevc/refs.c
  7. 2
      libavutil/Makefile
  8. 116
      libavutil/container_fifo.c
  9. 130
      libavutil/container_fifo.h

@ -2,10 +2,13 @@ The last version increases of all libraries were on 2024-03-07
API changes, most recent first:
2024-12-15 - xxxxxxxxxx - lavu 59.51.100 - refstruct.h
2024-12-15 - xxxxxxxxxx - lavu 59.51.100 - refstruct.h container_fifo.h
Add a new public header refstruct.h with new API for
reference-counted objects.
Add a new public header container_fifo.h with new API for
a FIFO of container objects (e.g. AVFrame or AVPacket).
2024-12-13 - xxxxxxxxxx - lavu 59.50.100 - channel_layout.h
Add AV_CH_LAYOUT_9POINT1POINT6 and AV_CHANNEL_LAYOUT_9POINT1POINT6.

@ -442,7 +442,7 @@ OBJS-$(CONFIG_HCA_DECODER) += hcadec.o
OBJS-$(CONFIG_HCOM_DECODER) += hcom.o
OBJS-$(CONFIG_HDR_DECODER) += hdrdec.o
OBJS-$(CONFIG_HDR_ENCODER) += hdrenc.o
OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o container_fifo.o
OBJS-$(CONFIG_HEVC_DECODER) += aom_film_grain.o h274.o
OBJS-$(CONFIG_HEVC_AMF_ENCODER) += amfenc_hevc.o
OBJS-$(CONFIG_HEVC_CUVID_DECODER) += cuviddec.o
OBJS-$(CONFIG_HEVC_D3D12VA_ENCODER) += d3d12va_encode_hevc.o h265_profile_level.o \

@ -1,89 +0,0 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVCODEC_CONTAINER_FIFO_H
#define AVCODEC_CONTAINER_FIFO_H
#include <stddef.h>
/**
* ContainerFifo is a FIFO for "containers" - dynamically allocated reusable
* structs (e.g. AVFrame or AVPacket). ContainerFifo uses an internal pool of
* such containers to avoid allocating and freeing them repeatedly.
*/
typedef struct ContainerFifo ContainerFifo;
/**
* Allocate a new ContainerFifo for the container type defined by provided
* callbacks.
*
* @param container_alloc allocate a new container instance and return a pointer
* to it, or NULL on failure
* @param container_reset reset the provided container instance to a clean state
* @param container_free free the provided container instance
* @param fifo_write transfer the contents of src to dst, where src is a
* container instance provided to ff_container_fifo_write()
* @param fifo_read transfer the contents of src to dst in other cases
*
* @note fifo_read() and fifo_write() are different parameters in order to allow
* fifo_write() implementations that make a new reference in dst, leaving
* src untouched (see e.g. ff_container_fifo_alloc_avframe())
*/
ContainerFifo*
ff_container_fifo_alloc(void* (*container_alloc)(void),
void (*container_reset)(void *obj),
void (*container_free) (void *obj),
int (*fifo_write) (void *dst, void *src),
int (*fifo_read) (void *dst, void *src));
/**
* Allocate a ContainerFifo instance for AVFrames.
* Note that ff_container_fifo_write() will call av_frame_ref() on src, making a
* new reference in dst and leaving src untouched.
*
* @param flags unused currently
*/
ContainerFifo *ff_container_fifo_alloc_avframe(unsigned flags);
/**
* Free a ContainerFifo and everything in it.
*/
void ff_container_fifo_free(ContainerFifo **pf);
/**
* Write the contents of obj to the FIFO.
*
* The fifo_write() callback previously provided to ff_container_fifo_alloc()
* will be called with obj as src in order to perform the actual transfer.
*/
int ff_container_fifo_write(ContainerFifo *pf, void *obj);
/**
* Read the next available object from the FIFO into obj.
*
* The fifo_read() callback previously provided to ff_container_fifo_alloc()
* will be called with obj as dst in order to perform the actual transfer.
*/
int ff_container_fifo_read(ContainerFifo *pf, void *obj);
/**
* @return number of objects available for reading
*/
size_t ff_container_fifo_can_read(ContainerFifo *pf);
#endif // AVCODEC_CONTAINER_FIFO_H

@ -28,6 +28,7 @@
#include "libavutil/attributes.h"
#include "libavutil/avstring.h"
#include "libavutil/common.h"
#include "libavutil/container_fifo.h"
#include "libavutil/film_grain_params.h"
#include "libavutil/internal.h"
#include "libavutil/md5.h"
@ -41,7 +42,6 @@
#include "bswapdsp.h"
#include "cabac_functions.h"
#include "codec_internal.h"
#include "container_fifo.h"
#include "decode.h"
#include "golomb.h"
#include "hevc.h"
@ -3748,7 +3748,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame)
s->pkt_dts = AV_NOPTS_VALUE;
if (ff_container_fifo_can_read(s->output_fifo))
if (av_container_fifo_can_read(s->output_fifo))
goto do_output;
av_packet_unref(avpkt);
@ -3786,7 +3786,7 @@ static int hevc_receive_frame(AVCodecContext *avctx, AVFrame *frame)
return ret;
do_output:
if (ff_container_fifo_read(s->output_fifo, frame) >= 0) {
if (av_container_fifo_read(s->output_fifo, frame, 0) >= 0) {
if (!(avctx->export_side_data & AV_CODEC_EXPORT_DATA_FILM_GRAIN))
av_frame_remove_side_data(frame, AV_FRAME_DATA_FILM_GRAIN_PARAMS);
@ -3846,7 +3846,7 @@ static av_cold int hevc_decode_free(AVCodecContext *avctx)
av_freep(&s->md5_ctx);
ff_container_fifo_free(&s->output_fifo);
av_container_fifo_free(&s->output_fifo);
for (int layer = 0; layer < FF_ARRAY_ELEMS(s->layers); layer++) {
HEVCLayerContext *l = &s->layers[layer];
@ -3890,7 +3890,7 @@ static av_cold int hevc_init_context(AVCodecContext *avctx)
s->local_ctx[0].logctx = avctx;
s->local_ctx[0].common_cabac_state = &s->cabac;
s->output_fifo = ff_container_fifo_alloc_avframe(0);
s->output_fifo = av_container_fifo_alloc_avframe(0);
if (!s->output_fifo)
return AVERROR(ENOMEM);

@ -502,7 +502,7 @@ typedef struct HEVCContext {
/** 1 if the independent slice segment header was successfully parsed */
uint8_t slice_initialized;
struct ContainerFifo *output_fifo;
struct AVContainerFifo *output_fifo;
HEVCParamSets ps;
HEVCSEI sei;

@ -21,10 +21,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/container_fifo.h"
#include "libavutil/mem.h"
#include "libavutil/stereo3d.h"
#include "container_fifo.h"
#include "decode.h"
#include "hevc.h"
#include "hevcdec.h"
@ -267,7 +267,7 @@ int ff_hevc_output_frames(HEVCContext *s,
if (output) {
f->pkt_dts = s->pkt_dts;
ret = ff_container_fifo_write(s->output_fifo, f);
ret = av_container_fifo_write(s->output_fifo, f, AV_CONTAINER_FIFO_FLAG_REF);
}
ff_hevc_unref_frame(frame, HEVC_FRAME_FLAG_OUTPUT);
if (ret < 0)

@ -19,6 +19,7 @@ HEADERS = adler32.h \
camellia.h \
channel_layout.h \
common.h \
container_fifo.h \
cpu.h \
crc.h \
csp.h \
@ -119,6 +120,7 @@ OBJS = adler32.o \
cast5.o \
camellia.o \
channel_layout.o \
container_fifo.o \
cpu.o \
crc.o \
csp.o \

@ -16,32 +16,32 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "libavutil/error.h"
#include "libavutil/fifo.h"
#include "libavutil/frame.h"
#include "libavutil/mem.h"
#include "avassert.h"
#include "container_fifo.h"
#include "libavutil/refstruct.h"
#include "error.h"
#include "fifo.h"
#include "frame.h"
#include "mem.h"
#include "refstruct.h"
struct ContainerFifo {
struct AVContainerFifo {
AVFifo *fifo;
AVRefStructPool *pool;
void* (*container_alloc)(void);
void (*container_reset)(void *obj);
void (*container_free) (void *obj);
int (*fifo_write) (void *dst, void *src);
int (*fifo_read) (void *dst, void *src);
void *opaque;
void* (*container_alloc)(void *opaque);
void (*container_reset)(void *opaque, void *obj);
void (*container_free) (void *opaque, void *obj);
int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags);
};
static int container_fifo_init_entry(AVRefStructOpaque opaque, void *obj)
{
ContainerFifo *cf = opaque.nc;
AVContainerFifo *cf = opaque.nc;
void **pobj = obj;
*pobj = cf->container_alloc();
*pobj = cf->container_alloc(cf->opaque);
if (!*pobj)
return AVERROR(ENOMEM);
@ -50,34 +50,35 @@ static int container_fifo_init_entry(AVRefStructOpaque opaque, void *obj)
static void container_fifo_reset_entry(AVRefStructOpaque opaque, void *obj)
{
ContainerFifo *cf = opaque.nc;
cf->container_reset(*(void**)obj);
AVContainerFifo *cf = opaque.nc;
cf->container_reset(cf->opaque, *(void**)obj);
}
static void container_fifo_free_entry(AVRefStructOpaque opaque, void *obj)
{
ContainerFifo *cf = opaque.nc;
cf->container_free(*(void**)obj);
AVContainerFifo *cf = opaque.nc;
cf->container_free(cf->opaque, *(void**)obj);
}
ContainerFifo*
ff_container_fifo_alloc(void* (*container_alloc)(void),
void (*container_reset)(void *obj),
void (*container_free) (void *obj),
int (*fifo_write) (void *dst, void *src),
int (*fifo_read) (void *dst, void *src))
AVContainerFifo*
av_container_fifo_alloc(void *opaque,
void* (*container_alloc)(void *opaque),
void (*container_reset)(void *opaque, void *obj),
void (*container_free) (void *opaque, void *obj),
int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags),
unsigned flags)
{
ContainerFifo *cf;
AVContainerFifo *cf;
cf = av_mallocz(sizeof(*cf));
if (!cf)
return NULL;
cf->opaque = opaque;
cf->container_alloc = container_alloc;
cf->container_reset = container_reset;
cf->container_free = container_free;
cf->fifo_write = fifo_write;
cf->fifo_read = fifo_read;
cf->fifo_transfer = fifo_transfer;
cf->fifo = av_fifo_alloc2(1, sizeof(void*), AV_FIFO_FLAG_AUTO_GROW);
if (!cf->fifo)
@ -93,13 +94,13 @@ ff_container_fifo_alloc(void* (*container_alloc)(void),
return cf;
fail:
ff_container_fifo_free(&cf);
av_container_fifo_free(&cf);
return NULL;
}
void ff_container_fifo_free(ContainerFifo **pcf)
void av_container_fifo_free(AVContainerFifo **pcf)
{
ContainerFifo *cf;
AVContainerFifo *cf;
if (!*pcf)
return;
@ -118,7 +119,7 @@ void ff_container_fifo_free(ContainerFifo **pcf)
av_freep(pcf);
}
int ff_container_fifo_read(ContainerFifo *cf, void *obj)
int av_container_fifo_read(AVContainerFifo *cf, void *obj, unsigned flags)
{
void **psrc;
int ret;
@ -127,13 +128,38 @@ int ff_container_fifo_read(ContainerFifo *cf, void *obj)
if (ret < 0)
return ret;
ret = cf->fifo_read(obj, *psrc);
ret = cf->fifo_transfer(cf->opaque, obj, *psrc, flags);
av_refstruct_unref(&psrc);
return ret;
}
int ff_container_fifo_write(ContainerFifo *cf, void *obj)
int av_container_fifo_peek(AVContainerFifo *cf, void **pdst, size_t offset)
{
void **pobj;
int ret;
ret = av_fifo_peek(cf->fifo, &pobj, 1, offset);
if (ret < 0)
return ret;
*pdst = *pobj;
return 0;
}
void av_container_fifo_drain(AVContainerFifo *cf, size_t nb_elems)
{
av_assert0(nb_elems <= av_fifo_can_read(cf->fifo));
while (nb_elems--) {
void **pobj;
int ret = av_fifo_read(cf->fifo, &pobj, 1);
av_assert0(ret >= 0);
av_refstruct_unref(&pobj);
}
}
int av_container_fifo_write(AVContainerFifo *cf, void *obj, unsigned flags)
{
void **pdst;
int ret;
@ -142,7 +168,7 @@ int ff_container_fifo_write(ContainerFifo *cf, void *obj)
if (!pdst)
return AVERROR(ENOMEM);
ret = cf->fifo_write(*pdst, obj);
ret = cf->fifo_transfer(cf->opaque, *pdst, obj, flags);
if (ret < 0)
goto fail;
@ -156,40 +182,38 @@ fail:
return ret;
}
size_t ff_container_fifo_can_read(ContainerFifo *cf)
size_t av_container_fifo_can_read(const AVContainerFifo *cf)
{
return av_fifo_can_read(cf->fifo);
}
static void *frame_alloc(void)
static void *frame_alloc(void *opaque)
{
return av_frame_alloc();
}
static void frame_reset(void *obj)
static void frame_reset(void *opaque, void *obj)
{
av_frame_unref(obj);
}
static void frame_free(void *obj)
static void frame_free(void *opaque, void *obj)
{
AVFrame *frame = obj;
av_frame_free(&frame);
}
static int frame_ref(void *dst, void *src)
static int frame_transfer(void *opaque, void *dst, void *src, unsigned flags)
{
return av_frame_ref(dst, src);
}
if (flags & AV_CONTAINER_FIFO_FLAG_REF)
return av_frame_ref(dst, src);
static int frame_move_ref(void *dst, void *src)
{
av_frame_move_ref(dst, src);
return 0;
}
ContainerFifo *ff_container_fifo_alloc_avframe(unsigned flags)
AVContainerFifo *av_container_fifo_alloc_avframe(unsigned flags)
{
return ff_container_fifo_alloc(frame_alloc, frame_reset, frame_free,
frame_ref, frame_move_ref);
return av_container_fifo_alloc(NULL, frame_alloc, frame_reset, frame_free,
frame_transfer, 0);
}

@ -0,0 +1,130 @@
/*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef AVUTIL_CONTAINER_FIFO_H
#define AVUTIL_CONTAINER_FIFO_H
#include <stddef.h>
/**
* AVContainerFifo is a FIFO for "containers" - dynamically allocated reusable
* structs (e.g. AVFrame or AVPacket). AVContainerFifo uses an internal pool of
* such containers to avoid allocating and freeing them repeatedly.
*/
typedef struct AVContainerFifo AVContainerFifo;
enum AVContainerFifoFlags {
/**
* Signal to av_container_fifo_write() that it should make a new reference
* to data in src rather than consume its contents.
*
* @note you must handle this flag manually in your own fifo_transfer()
* callback
*/
AV_CONTAINER_FIFO_FLAG_REF = (1 << 0),
/**
* This and all higher bits in flags may be set to any value by the caller
* and are guaranteed to be passed through to the fifo_transfer() callback
* and not be interpreted by AVContainerFifo code.
*/
AV_CONTAINER_FIFO_FLAG_USER = (1 << 16),
};
/**
* Allocate a new AVContainerFifo for the container type defined by provided
* callbacks.
*
* @param opaque user data that will be passed to the callbacks provided to this
* function
* @param container_alloc allocate a new container instance and return a pointer
* to it, or NULL on failure
* @param container_reset reset the provided container instance to a clean state
* @param container_free free the provided container instance
* @param fifo_transfer Transfer the contents of container src to dst.
* @param flags currently unused
*
* @return newly allocated AVContainerFifo, or NULL on failure
*/
AVContainerFifo*
av_container_fifo_alloc(void *opaque,
void* (*container_alloc)(void *opaque),
void (*container_reset)(void *opaque, void *obj),
void (*container_free) (void *opaque, void *obj),
int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags),
unsigned flags);
/**
* Allocate an AVContainerFifo instance for AVFrames.
*
* @param flags currently unused
*/
AVContainerFifo *av_container_fifo_alloc_avframe(unsigned flags);
/**
* Free a AVContainerFifo and everything in it.
*/
void av_container_fifo_free(AVContainerFifo **cf);
/**
* Write the contents of obj to the FIFO.
*
* The fifo_transfer() callback previously provided to av_container_fifo_alloc()
* will be called with obj as src in order to perform the actual transfer.
*/
int av_container_fifo_write(AVContainerFifo *cf, void *obj, unsigned flags);
/**
* Read the next available object from the FIFO into obj.
*
* The fifo_read() callback previously provided to av_container_fifo_alloc()
* will be called with obj as dst in order to perform the actual transfer.
*/
int av_container_fifo_read(AVContainerFifo *cf, void *obj, unsigned flags);
/**
* Access objects stored in the FIFO without retrieving them. The
* fifo_transfer() callback will NOT be invoked and the FIFO state will not be
* modified.
*
* @param pobj Pointer to the object stored in the FIFO will be written here on
* success. The object remains owned by the FIFO and the caller may
* only access it as long as the FIFO is not modified.
* @param offset Position of the object to retrieve - 0 is the next item that
* would be read, 1 the one after, etc. Must be smaller than
* av_container_fifo_can_read().
*
* @retval 0 success, a pointer was written into pobj
* @retval AVERROR(EINVAL) invalid offset value
*/
int av_container_fifo_peek(AVContainerFifo *cf, void **pobj, size_t offset);
/**
* Discard the specified number of elements from the FIFO.
*
* @param nb_elems number of elements to discard, MUST NOT be larger than
* av_fifo_can_read(f)
*/
void av_container_fifo_drain(AVContainerFifo *cf, size_t nb_elems);
/**
* @return number of objects available for reading
*/
size_t av_container_fifo_can_read(const AVContainerFifo *cf);
#endif // AVCODEC_CONTAINER_FIFO_H
Loading…
Cancel
Save