[FFmpeg-devel] [PATCH 08/35] lavu/fifo: add new FIFO read/peek functions
Andreas Rheinhardt
andreas.rheinhardt at outlook.com
Thu Jan 13 19:41:12 EET 2022
Anton Khirnov:
> As for writing, use separate functions for reading to a buffer and a
> callback. Allow the callbacks to limit the amount of data read,
> similarly to what is done for writing.
>
> Consistently use size_t for sizes.
> ---
> doc/APIchanges | 3 ++-
> libavutil/fifo.c | 68 ++++++++++++++++++++++++++++++++++++++++++++++++
> libavutil/fifo.h | 60 ++++++++++++++++++++++++++++++++++++++++++
> 3 files changed, 130 insertions(+), 1 deletion(-)
>
> diff --git a/doc/APIchanges b/doc/APIchanges
> index 0b179c30e5..f64759d69d 100644
> --- a/doc/APIchanges
> +++ b/doc/APIchanges
> @@ -19,7 +19,8 @@ API changes, most recent first:
> Operations on FIFOs created with this function on these elements
> rather than bytes.
> Add 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_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().
>
> 2022-01-xx - xxxxxxxxxx - lavu fifo.h
> Access to all AVFifoBuffer members is deprecated. The struct will
> diff --git a/libavutil/fifo.c b/libavutil/fifo.c
> index 1d94fff457..ea944bc936 100644
> --- a/libavutil/fifo.c
> +++ b/libavutil/fifo.c
> @@ -265,6 +265,74 @@ int av_fifo_write_from_cb(AVFifoBuffer *f, AVFifoCB read_cb,
> return fifo_write_common(f, NULL, nb_elems, read_cb, opaque);
> }
>
> +static int fifo_peek_common(const AVFifoBuffer *f, uint8_t *buf, size_t *nb_elems,
> + size_t offset, AVFifoCB write_cb, void *opaque)
> +{
> + const FifoBuffer *fb = (FifoBuffer*)f;
> + size_t to_read = *nb_elems;
> + size_t offset_r = fb->offset_r;
> + int ret = 0;
> +
> + if (offset > av_fifo_can_read(f) ||
> + to_read > av_fifo_can_read(f) - offset) {
You are calling av_fifo_can_read() multiple times.
> + *nb_elems = 0;
> + return AVERROR(EINVAL);
> + }
> +
> + if (offset_r >= fb->nb_elems - offset)
> + offset_r -= fb->nb_elems - offset;
> + else
> + offset_r += offset;
> +
> + do {
Shouldn't this be a while loop?
> + size_t len = FFMIN(fb->nb_elems - offset_r, to_read);
> + uint8_t *rptr = f->buffer + offset_r * fb->elem_size;
> +
> + if (write_cb) {
> + ret = write_cb(opaque, rptr, &len);
> + if (ret < 0 || len == 0)
> + break;
> + } else {
> + memcpy(buf, rptr, len * fb->elem_size);
> + buf += len * fb->elem_size;
> + }
> + offset_r += len;
> + if (offset_r >= fb->nb_elems)
> + offset_r = 0;
> + to_read -= len;
> + } while (to_read > 0);
> +
> + *nb_elems -= to_read;
> +
> + return ret;
> +}
> +
> +int av_fifo_read(AVFifoBuffer *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);
In contrast to the current av_fifo_generic_read() the callback will
still see the non-drained FIFO if the callback is called multiple times.
I don't know whether this slight behaviour change can cause problems
when updating.
> + return ret;
> +}
> +
> +int av_fifo_read_to_cb(AVFifoBuffer *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(AVFifoBuffer *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(AVFifoBuffer *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);
> +}
> +
> int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
> {
> FifoBuffer *fb = (FifoBuffer*)f;
> diff --git a/libavutil/fifo.h b/libavutil/fifo.h
> index ac1245ff39..c7be5e8f7d 100644
> --- a/libavutil/fifo.h
> +++ b/libavutil/fifo.h
> @@ -189,6 +189,66 @@ int av_fifo_write(AVFifoBuffer *f, const void *buf, size_t nb_elems);
> int av_fifo_write_from_cb(AVFifoBuffer *f, AVFifoCB read_cb,
> void *opaque, size_t *nb_elems);
>
> +/**
> + * Read data from a FIFO.
> + *
> + * @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
> + *
> + * @return a non-negative number on success, a negative error code on failure
> + */
> +int av_fifo_read(AVFifoBuffer *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(AVFifoBuffer *f, AVFifoCB write_cb,
> + void *opaque, size_t *nb_elems);
> +
> +/**
> + * Read data from a FIFO without modifying FIFO state.
> + *
> + * @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; 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(AVFifoBuffer *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(AVFifoBuffer *f, AVFifoCB write_cb, void *opaque,
Ok, seems like we differ on our naming: I'd call this a read_cb, because
it reads from the fifo, but it of course also writes, so it seems fine
given that you are consistent.
> + size_t *nb_elems, size_t offset);
> +
> /**
> * Discard the specified amount of data from an AVFifoBuffer.
> * @param size number of elements to discard, MUST NOT be larger than
>
More information about the ffmpeg-devel
mailing list