[FFmpeg-devel] [PATCH 2/5] lavc/container_fifo: move to lavu and make public
Anton Khirnov
anton at khirnov.net
Wed Dec 11 16:05:04 EET 2024
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
---
doc/APIchanges | 5 +-
libavcodec/Makefile | 2 +-
libavcodec/container_fifo.h | 89 --------------
libavcodec/hevc/hevcdec.c | 10 +-
libavcodec/hevc/hevcdec.h | 2 +-
libavcodec/hevc/refs.c | 4 +-
libavutil/Makefile | 2 +
{libavcodec => libavutil}/container_fifo.c | 116 ++++++++++--------
libavutil/container_fifo.h | 130 +++++++++++++++++++++
9 files changed, 215 insertions(+), 145 deletions(-)
delete mode 100644 libavcodec/container_fifo.h
rename {libavcodec => libavutil}/container_fifo.c (51%)
create mode 100644 libavutil/container_fifo.h
diff --git a/doc/APIchanges b/doc/APIchanges
index 13789fcea4..5d75b6077d 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -2,10 +2,13 @@ The last version increases of all libraries were on 2024-03-07
API changes, most recent first:
-2024-12-xx - xxxxxxxxxx - lavu 59.50.100 - refstruct.h
+2024-12-xx - xxxxxxxxxx - lavu 59.50.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-05 - xxxxxxxxxx - lavu 59.49.100 - csp.h
Add av_csp_itu_eotf() and av_csp_itu_eotf_inv().
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index cd64013998..c946444175 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -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 \
diff --git a/libavcodec/container_fifo.h b/libavcodec/container_fifo.h
deleted file mode 100644
index dd8b1d380f..0000000000
--- a/libavcodec/container_fifo.h
+++ /dev/null
@@ -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
diff --git a/libavcodec/hevc/hevcdec.c b/libavcodec/hevc/hevcdec.c
index 421579efe5..1a2f668053 100644
--- a/libavcodec/hevc/hevcdec.c
+++ b/libavcodec/hevc/hevcdec.c
@@ -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);
diff --git a/libavcodec/hevc/hevcdec.h b/libavcodec/hevc/hevcdec.h
index b7a762089b..4e95035688 100644
--- a/libavcodec/hevc/hevcdec.h
+++ b/libavcodec/hevc/hevcdec.h
@@ -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;
diff --git a/libavcodec/hevc/refs.c b/libavcodec/hevc/refs.c
index a467786f38..dd7f7f95a8 100644
--- a/libavcodec/hevc/refs.c
+++ b/libavcodec/hevc/refs.c
@@ -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)
diff --git a/libavutil/Makefile b/libavutil/Makefile
index ae1ad5199a..f8031815bd 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -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 \
diff --git a/libavcodec/container_fifo.c b/libavutil/container_fifo.c
similarity index 51%
rename from libavcodec/container_fifo.c
rename to libavutil/container_fifo.c
index e1799e5eb7..34a78e7ef3 100644
--- a/libavcodec/container_fifo.c
+++ b/libavutil/container_fifo.c
@@ -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);
}
diff --git a/libavutil/container_fifo.h b/libavutil/container_fifo.h
new file mode 100644
index 0000000000..1a32b1e042
--- /dev/null
+++ b/libavutil/container_fifo.h
@@ -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_write()
+ * 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_write() 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
--
2.43.0
More information about the ffmpeg-devel
mailing list