summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/APIchanges9
-rw-r--r--libavutil/fifo.c226
-rw-r--r--libavutil/fifo.h179
-rw-r--r--libavutil/version.h2
4 files changed, 415 insertions, 1 deletions
diff --git a/doc/APIchanges b/doc/APIchanges
index 315a04c952..ca9c476346 100644
--- a/doc/APIchanges
+++ b/doc/APIchanges
@@ -14,6 +14,15 @@ libavutil: 2021-04-27
API changes, most recent first:
+2022-02-07 - xxxxxxxxxx - lavu 57.20.100 - fifo.h
+ Add a new FIFO API, which allows setting a FIFO element size.
+ This API operates on these elements rather than on bytes.
+ Add av_fifo_alloc2(), av_fifo_elem_size(), av_fifo_can_read(),
+ av_fifo_can_write(), av_fifo_grow2(), av_fifo_drain2(), av_fifo_write(),
+ av_fifo_write_from_cb(), av_fifo_read(), av_fifo_read_to_cb(),
+ av_fifo_peek(), av_fifo_peek_to_cb(), av_fifo_drain2(), av_fifo_reset2(),
+ av_fifo_freep2().
+
2022-01-26 - af94ab7c7c0 - lavu 57.19.100 - tx.h
Add AV_TX_FLOAT_RDFT, AV_TX_DOUBLE_RDFT and AV_TX_INT32_RDFT.
diff --git a/libavutil/fifo.c b/libavutil/fifo.c
index 55621f0dca..0001ccbd43 100644
--- a/libavutil/fifo.c
+++ b/libavutil/fifo.c
@@ -26,6 +26,232 @@
#include "common.h"
#include "fifo.h"
+struct AVFifo {
+ uint8_t *buffer;
+
+ size_t elem_size, nb_elems;
+ size_t offset_r, offset_w;
+ // distinguishes the ambiguous situation offset_r == offset_w
+ int is_empty;
+};
+
+AVFifo *av_fifo_alloc2(size_t nb_elems, size_t elem_size,
+ unsigned int flags)
+{
+ AVFifo *f;
+ void *buffer = NULL;
+
+ if (!elem_size)
+ return NULL;
+
+ if (nb_elems) {
+ buffer = av_realloc_array(NULL, nb_elems, elem_size);
+ if (!buffer)
+ return NULL;
+ }
+ f = av_mallocz(sizeof(*f));
+ if (!f) {
+ av_free(buffer);
+ return NULL;
+ }
+ f->buffer = buffer;
+ f->nb_elems = nb_elems;
+ f->elem_size = elem_size;
+ f->is_empty = 1;
+
+ return f;
+}
+
+size_t av_fifo_elem_size(const AVFifo *f)
+{
+ return f->elem_size;
+}
+
+size_t av_fifo_can_read(const AVFifo *f)
+{
+ if (f->offset_w <= f->offset_r && !f->is_empty)
+ return f->nb_elems - f->offset_r + f->offset_w;
+ return f->offset_w - f->offset_r;
+}
+
+size_t av_fifo_can_write(const AVFifo *f)
+{
+ return f->nb_elems - av_fifo_can_read(f);
+}
+
+int av_fifo_grow2(AVFifo *f, size_t inc)
+{
+ uint8_t *tmp;
+
+ if (inc > SIZE_MAX - f->nb_elems)
+ return AVERROR(EINVAL);
+
+ tmp = av_realloc_array(f->buffer, f->nb_elems + inc, f->elem_size);
+ if (!tmp)
+ return AVERROR(ENOMEM);
+ f->buffer = tmp;
+
+ // move the data from the beginning of the ring buffer
+ // to the newly allocated space
+ if (f->offset_w <= f->offset_r && !f->is_empty) {
+ const size_t copy = FFMIN(inc, f->offset_w);
+ memcpy(tmp + f->nb_elems * f->elem_size, tmp, copy * f->elem_size);
+ if (copy < f->offset_w) {
+ memmove(tmp, tmp + copy * f->elem_size,
+ (f->offset_w - copy) * f->elem_size);
+ f->offset_w -= copy;
+ } else
+ f->offset_w = f->nb_elems + copy;
+ }
+
+ f->nb_elems += inc;
+
+ return 0;
+}
+
+static int fifo_write_common(AVFifo *f, const uint8_t *buf, size_t *nb_elems,
+ AVFifoCB read_cb, void *opaque)
+{
+ size_t to_write = *nb_elems;
+ size_t offset_w = f->offset_w;
+ int ret = 0;
+
+ if (to_write > av_fifo_can_write(f))
+ return AVERROR(ENOSPC);
+
+ while (to_write > 0) {
+ size_t len = FFMIN(f->nb_elems - offset_w, to_write);
+ uint8_t *wptr = f->buffer + offset_w * f->elem_size;
+
+ if (read_cb) {
+ ret = read_cb(opaque, wptr, &len);
+ if (ret < 0 || len == 0)
+ break;
+ } else {
+ memcpy(wptr, buf, len * f->elem_size);
+ buf += len * f->elem_size;
+ }
+ offset_w += len;
+ if (offset_w >= f->nb_elems)
+ offset_w = 0;
+ to_write -= len;
+ }
+ f->offset_w = offset_w;
+
+ if (*nb_elems != to_write)
+ f->is_empty = 0;
+ *nb_elems -= to_write;
+
+ return ret;
+}
+
+int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
+{
+ return fifo_write_common(f, buf, &nb_elems, NULL, NULL);
+}
+
+int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb,
+ void *opaque, size_t *nb_elems)
+{
+ return fifo_write_common(f, NULL, nb_elems, read_cb, opaque);
+}
+
+static int fifo_peek_common(const AVFifo *f, uint8_t *buf, size_t *nb_elems,
+ size_t offset, AVFifoCB write_cb, void *opaque)
+{
+ size_t to_read = *nb_elems;
+ size_t offset_r = f->offset_r;
+ size_t can_read = av_fifo_can_read(f);
+ int ret = 0;
+
+ if (offset > can_read || to_read > can_read - offset) {
+ *nb_elems = 0;
+ return AVERROR(EINVAL);
+ }
+
+ if (offset_r >= f->nb_elems - offset)
+ offset_r -= f->nb_elems - offset;
+ else
+ offset_r += offset;
+
+ while (to_read > 0) {
+ size_t len = FFMIN(f->nb_elems - offset_r, to_read);
+ uint8_t *rptr = f->buffer + offset_r * f->elem_size;
+
+ if (write_cb) {
+ ret = write_cb(opaque, rptr, &len);
+ if (ret < 0 || len == 0)
+ break;
+ } else {
+ memcpy(buf, rptr, len * f->elem_size);
+ buf += len * f->elem_size;
+ }
+ offset_r += len;
+ if (offset_r >= f->nb_elems)
+ offset_r = 0;
+ to_read -= len;
+ }
+
+ *nb_elems -= to_read;
+
+ return ret;
+}
+
+int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
+{
+ int ret = fifo_peek_common(f, buf, &nb_elems, 0, NULL, NULL);
+ av_fifo_drain2(f, nb_elems);
+ return ret;
+}
+
+int av_fifo_read_to_cb(AVFifo *f, AVFifoCB write_cb,
+ void *opaque, size_t *nb_elems)
+{
+ int ret = fifo_peek_common(f, NULL, nb_elems, 0, write_cb, opaque);
+ av_fifo_drain2(f, *nb_elems);
+ return ret;
+}
+
+int av_fifo_peek(AVFifo *f, void *buf, size_t nb_elems, size_t offset)
+{
+ return fifo_peek_common(f, buf, &nb_elems, offset, NULL, NULL);
+}
+
+int av_fifo_peek_to_cb(AVFifo *f, AVFifoCB write_cb, void *opaque,
+ size_t *nb_elems, size_t offset)
+{
+ return fifo_peek_common(f, NULL, nb_elems, offset, write_cb, opaque);
+}
+
+void av_fifo_drain2(AVFifo *f, size_t size)
+{
+ const size_t cur_size = av_fifo_can_read(f);
+
+ av_assert0(cur_size >= size);
+ if (cur_size == size)
+ f->is_empty = 1;
+
+ if (f->offset_r >= f->nb_elems - size)
+ f->offset_r -= f->nb_elems - size;
+ else
+ f->offset_r += size;
+}
+
+void av_fifo_reset2(AVFifo *f)
+{
+ f->offset_r = f->offset_w = 0;
+ f->is_empty = 1;
+}
+
+void av_fifo_freep2(AVFifo **f)
+{
+ if (*f) {
+ av_freep(&(*f)->buffer);
+ av_freep(f);
+ }
+}
+
+
#define OLD_FIFO_SIZE_MAX (size_t)FFMIN3(INT_MAX, UINT32_MAX, SIZE_MAX)
AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size)
diff --git a/libavutil/fifo.h b/libavutil/fifo.h
index f4fd291e59..f455022e3c 100644
--- a/libavutil/fifo.h
+++ b/libavutil/fifo.h
@@ -28,6 +28,185 @@
#include "avutil.h"
#include "attributes.h"
+typedef struct AVFifo AVFifo;
+
+/**
+ * Callback for writing or reading from a FIFO, passed to (and invoked from) the
+ * av_fifo_*_cb() functions. It may be invoked multiple times from a single
+ * av_fifo_*_cb() call and may process less data than the maximum size indicated
+ * by nb_elems.
+ *
+ * @param opaque the opaque pointer provided to the av_fifo_*_cb() function
+ * @param buf the buffer for reading or writing the data, depending on which
+ * av_fifo_*_cb function is called
+ * @param nb_elems On entry contains the maximum number of elements that can be
+ * read from / written into buf. On success, the callback should
+ * update it to contain the number of elements actually written.
+ *
+ * @return 0 on success, a negative error code on failure (will be returned from
+ * the invoking av_fifo_*_cb() function)
+ */
+typedef int AVFifoCB(void *opaque, void *buf, size_t *nb_elems);
+
+/**
+ * Allocate and initialize an AVFifo with a given element size.
+ *
+ * @param elems initial number of elements that can be stored in the FIFO
+ * @param elem_size Size in bytes of a single element. Further operations on
+ * the returned FIFO will implicitly use this element size.
+ * @param flags currently unused, must be 0
+ *
+ * @return newly-allocated AVFifo on success, a negative error code on failure
+ */
+AVFifo *av_fifo_alloc2(size_t elems, size_t elem_size,
+ unsigned int flags);
+
+/**
+ * @return Element size for FIFO operations. This element size is set at
+ * FIFO allocation and remains constant during its lifetime
+ */
+size_t av_fifo_elem_size(const AVFifo *f);
+
+/**
+ * @return number of elements available for reading from the given FIFO.
+ */
+size_t av_fifo_can_read(const AVFifo *f);
+
+/**
+ * @return number of elements that can be written into the given FIFO.
+ */
+size_t av_fifo_can_write(const AVFifo *f);
+
+/**
+ * Enlarge an AVFifo.
+ *
+ * On success, the FIFO will be large enough to hold exactly
+ * inc + av_fifo_can_read() + av_fifo_can_write()
+ * elements. In case of failure, the old FIFO is kept unchanged.
+ *
+ * @param f AVFifo to resize
+ * @param inc number of elements to allocate for, in addition to the current
+ * allocated size
+ * @return a non-negative number on success, a negative error code on failure
+ */
+int av_fifo_grow2(AVFifo *f, size_t inc);
+
+/**
+ * Write data into a FIFO.
+ *
+ * In case nb_elems > av_fifo_can_write(f), nothing is written and an error
+ * is returned.
+ *
+ * @param f the FIFO buffer
+ * @param buf Data to be written. nb_elems * av_fifo_elem_size(f) bytes will be
+ * read from buf on success.
+ * @param nb_elems number of elements to write into FIFO
+ *
+ * @return a non-negative number on success, a negative error code on failure
+ */
+int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems);
+
+/**
+ * Write data from a user-provided callback into a FIFO.
+ *
+ * @param f the FIFO buffer
+ * @param read_cb Callback supplying the data to the FIFO. May be called
+ * multiple times.
+ * @param opaque opaque user data to be provided to read_cb
+ * @param nb_elems Should point to the maximum number of elements that can be
+ * written. Will be updated to contain the number of elements
+ * actually written.
+ *
+ * @return non-negative number on success, a negative error code on failure
+ */
+int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb,
+ void *opaque, size_t *nb_elems);
+
+/**
+ * Read data from a FIFO.
+ *
+ * In case nb_elems > av_fifo_can_read(f), nothing is read and an error
+ * is returned.
+ *
+ * @param f the FIFO buffer
+ * @param buf Buffer to store the data. nb_elems * av_fifo_elem_size(f) bytes
+ * will be written into buf on success.
+ * @param nb_elems number of elements to read from FIFO
+ *
+ * @return a non-negative number on success, a negative error code on failure
+ */
+int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems);
+
+/**
+ * Feed data from a FIFO into a user-provided callback.
+ *
+ * @param f the FIFO buffer
+ * @param write_cb Callback the data will be supplied to. May be called
+ * multiple times.
+ * @param opaque opaque user data to be provided to write_cb
+ * @param nb_elems Should point to the maximum number of elements that can be
+ * read. Will be updated to contain the total number of elements
+ * actually sent to the callback.
+ *
+ * @return non-negative number on success, a negative error code on failure
+ */
+int av_fifo_read_to_cb(AVFifo *f, AVFifoCB write_cb,
+ void *opaque, size_t *nb_elems);
+
+/**
+ * Read data from a FIFO without modifying FIFO state.
+ *
+ * Returns an error if an attempt is made to peek to nonexistent elements
+ * (i.e. if offset + nb_elems is larger than av_fifo_can_read(f)).
+ *
+ * @param f the FIFO buffer
+ * @param buf Buffer to store the data. nb_elems * av_fifo_elem_size(f) bytes
+ * will be written into buf.
+ * @param nb_elems number of elements to read from FIFO
+ * @param offset number of initial elements to skip.
+ *
+ * @return a non-negative number on success, a negative error code on failure
+ */
+int av_fifo_peek(AVFifo *f, void *buf, size_t nb_elems, size_t offset);
+
+/**
+ * Feed data from a FIFO into a user-provided callback.
+ *
+ * @param f the FIFO buffer
+ * @param write_cb Callback the data will be supplied to. May be called
+ * multiple times.
+ * @param opaque opaque user data to be provided to write_cb
+ * @param nb_elems Should point to the maximum number of elements that can be
+ * read. Will be updated to contain the total number of elements
+ * actually sent to the callback.
+ * @param offset number of initial elements to skip; offset + *nb_elems must not
+ * be larger than av_fifo_can_read(f).
+ *
+ * @return a non-negative number on success, a negative error code on failure
+ */
+int av_fifo_peek_to_cb(AVFifo *f, AVFifoCB write_cb, void *opaque,
+ size_t *nb_elems, size_t offset);
+
+/**
+ * Discard the specified amount of data from an AVFifo.
+ * @param size number of elements to discard, MUST NOT be larger than
+ * av_fifo_can_read(f)
+ */
+void av_fifo_drain2(AVFifo *f, size_t size);
+
+/*
+ * Empty the AVFifo.
+ * @param f AVFifo to reset
+ */
+void av_fifo_reset2(AVFifo *f);
+
+/**
+ * Free an AVFifo and reset pointer to NULL.
+ * @param f Pointer to an AVFifo to free. *f == NULL is allowed.
+ */
+void av_fifo_freep2(AVFifo **f);
+
+
typedef struct AVFifoBuffer {
uint8_t *buffer;
uint8_t *rptr, *wptr, *end;
diff --git a/libavutil/version.h b/libavutil/version.h
index 331b8f6ea9..f961077849 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
*/
#define LIBAVUTIL_VERSION_MAJOR 57
-#define LIBAVUTIL_VERSION_MINOR 19
+#define LIBAVUTIL_VERSION_MINOR 20
#define LIBAVUTIL_VERSION_MICRO 100
#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \