History

lavu/fifo: Add new AVFifo API based upon the notion of element size

Many AVFifoBuffer users operate on fixed-size elements (e.g. pointers), but the current FIFO API deals exclusively in bytes, requiring extra complexity in all these callers. Add a new AVFifo API creating a FIFO with an element size that may be larger than a byte. All operations on such a FIFO then operate on complete elements. This API does not reuse AVFifoBuffer and its API at all, but instead uses an opaque struct called AVFifo. The AVFifoBuffer API will be deprecated in a future commit once all of its users have been switched to the new API. Not reusing AVFifoBuffer also allowed to use the full range of size_t from the beginning.

Anton Khirnov committed 4 years ago

Commit 7329b221 parent 5939c8d4 files · +415 −1Browse files

Unified · Split

4 files
  1. doc/APIchanges +9 −0
  2. libavutil/fifo.c +226 −0
  3. libavutil/fifo.h +179 −0
  4. libavutil/version.h +1 −1
doc/APIchanges+9−0
@@ -14,6 +14,15 @@ libavutil: 2021-04-27 · 13 unmodified lines
14 14
15API changes, most recent first:15API changes, most recent first:
16 16
172022-02-07 - xxxxxxxxxx - lavu 57.20.100 - fifo.h
18 Add a new FIFO API, which allows setting a FIFO element size.
19 This API operates on these elements rather than on bytes.
20 Add av_fifo_alloc2(), av_fifo_elem_size(), av_fifo_can_read(),
21 av_fifo_can_write(), av_fifo_grow2(), av_fifo_drain2(), av_fifo_write(),
22 av_fifo_write_from_cb(), av_fifo_read(), av_fifo_read_to_cb(),
23 av_fifo_peek(), av_fifo_peek_to_cb(), av_fifo_drain2(), av_fifo_reset2(),
24 av_fifo_freep2().
25
172022-01-26 - af94ab7c7c0 - lavu 57.19.100 - tx.h262022-01-26 - af94ab7c7c0 - lavu 57.19.100 - tx.h
18 Add AV_TX_FLOAT_RDFT, AV_TX_DOUBLE_RDFT and AV_TX_INT32_RDFT.27 Add AV_TX_FLOAT_RDFT, AV_TX_DOUBLE_RDFT and AV_TX_INT32_RDFT.
19 28
libavutil/fifo.c+226−0
@@ -26,6 +26,232 @@ · 25 unmodified lines
26#include "common.h"26#include "common.h"
27#include "fifo.h"27#include "fifo.h"
28 28
29struct AVFifo {
30 uint8_t *buffer;
31
32 size_t elem_size, nb_elems;
33 size_t offset_r, offset_w;
34 // distinguishes the ambiguous situation offset_r == offset_w
35 int is_empty;
36};
37
38AVFifo *av_fifo_alloc2(size_t nb_elems, size_t elem_size,
39 unsigned int flags)
40{
41 AVFifo *f;
42 void *buffer = NULL;
43
44 if (!elem_size)
45 return NULL;
46
47 if (nb_elems) {
48 buffer = av_realloc_array(NULL, nb_elems, elem_size);
49 if (!buffer)
50 return NULL;
51 }
52 f = av_mallocz(sizeof(*f));
53 if (!f) {
54 av_free(buffer);
55 return NULL;
56 }
57 f->buffer = buffer;
58 f->nb_elems = nb_elems;
59 f->elem_size = elem_size;
60 f->is_empty = 1;
61
62 return f;
63}
64
65size_t av_fifo_elem_size(const AVFifo *f)
66{
67 return f->elem_size;
68}
69
70size_t av_fifo_can_read(const AVFifo *f)
71{
72 if (f->offset_w <= f->offset_r && !f->is_empty)
73 return f->nb_elems - f->offset_r + f->offset_w;
74 return f->offset_w - f->offset_r;
75}
76
77size_t av_fifo_can_write(const AVFifo *f)
78{
79 return f->nb_elems - av_fifo_can_read(f);
80}
81
82int av_fifo_grow2(AVFifo *f, size_t inc)
83{
84 uint8_t *tmp;
85
86 if (inc > SIZE_MAX - f->nb_elems)
87 return AVERROR(EINVAL);
88
89 tmp = av_realloc_array(f->buffer, f->nb_elems + inc, f->elem_size);
90 if (!tmp)
91 return AVERROR(ENOMEM);
92 f->buffer = tmp;
93
94 // move the data from the beginning of the ring buffer
95 // to the newly allocated space
96 if (f->offset_w <= f->offset_r && !f->is_empty) {
97 const size_t copy = FFMIN(inc, f->offset_w);
98 memcpy(tmp + f->nb_elems * f->elem_size, tmp, copy * f->elem_size);
99 if (copy < f->offset_w) {
100 memmove(tmp, tmp + copy * f->elem_size,
101 (f->offset_w - copy) * f->elem_size);
102 f->offset_w -= copy;
103 } else
104 f->offset_w = f->nb_elems + copy;
105 }
106
107 f->nb_elems += inc;
108
109 return 0;
110}
111
112static int fifo_write_common(AVFifo *f, const uint8_t *buf, size_t *nb_elems,
113 AVFifoCB read_cb, void *opaque)
114{
115 size_t to_write = *nb_elems;
116 size_t offset_w = f->offset_w;
117 int ret = 0;
118
119 if (to_write > av_fifo_can_write(f))
120 return AVERROR(ENOSPC);
121
122 while (to_write > 0) {
123 size_t len = FFMIN(f->nb_elems - offset_w, to_write);
124 uint8_t *wptr = f->buffer + offset_w * f->elem_size;
125
126 if (read_cb) {
127 ret = read_cb(opaque, wptr, &len);
128 if (ret < 0 || len == 0)
129 break;
130 } else {
131 memcpy(wptr, buf, len * f->elem_size);
132 buf += len * f->elem_size;
133 }
134 offset_w += len;
135 if (offset_w >= f->nb_elems)
136 offset_w = 0;
137 to_write -= len;
138 }
139 f->offset_w = offset_w;
140
141 if (*nb_elems != to_write)
142 f->is_empty = 0;
143 *nb_elems -= to_write;
144
145 return ret;
146}
147
148int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems)
149{
150 return fifo_write_common(f, buf, &nb_elems, NULL, NULL);
151}
152
153int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb,
154 void *opaque, size_t *nb_elems)
155{
156 return fifo_write_common(f, NULL, nb_elems, read_cb, opaque);
157}
158
159static int fifo_peek_common(const AVFifo *f, uint8_t *buf, size_t *nb_elems,
160 size_t offset, AVFifoCB write_cb, void *opaque)
161{
162 size_t to_read = *nb_elems;
163 size_t offset_r = f->offset_r;
164 size_t can_read = av_fifo_can_read(f);
165 int ret = 0;
166
167 if (offset > can_read || to_read > can_read - offset) {
168 *nb_elems = 0;
169 return AVERROR(EINVAL);
170 }
171
172 if (offset_r >= f->nb_elems - offset)
173 offset_r -= f->nb_elems - offset;
174 else
175 offset_r += offset;
176
177 while (to_read > 0) {
178 size_t len = FFMIN(f->nb_elems - offset_r, to_read);
179 uint8_t *rptr = f->buffer + offset_r * f->elem_size;
180
181 if (write_cb) {
182 ret = write_cb(opaque, rptr, &len);
183 if (ret < 0 || len == 0)
184 break;
185 } else {
186 memcpy(buf, rptr, len * f->elem_size);
187 buf += len * f->elem_size;
188 }
189 offset_r += len;
190 if (offset_r >= f->nb_elems)
191 offset_r = 0;
192 to_read -= len;
193 }
194
195 *nb_elems -= to_read;
196
197 return ret;
198}
199
200int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems)
201{
202 int ret = fifo_peek_common(f, buf, &nb_elems, 0, NULL, NULL);
203 av_fifo_drain2(f, nb_elems);
204 return ret;
205}
206
207int av_fifo_read_to_cb(AVFifo *f, AVFifoCB write_cb,
208 void *opaque, size_t *nb_elems)
209{
210 int ret = fifo_peek_common(f, NULL, nb_elems, 0, write_cb, opaque);
211 av_fifo_drain2(f, *nb_elems);
212 return ret;
213}
214
215int av_fifo_peek(AVFifo *f, void *buf, size_t nb_elems, size_t offset)
216{
217 return fifo_peek_common(f, buf, &nb_elems, offset, NULL, NULL);
218}
219
220int av_fifo_peek_to_cb(AVFifo *f, AVFifoCB write_cb, void *opaque,
221 size_t *nb_elems, size_t offset)
222{
223 return fifo_peek_common(f, NULL, nb_elems, offset, write_cb, opaque);
224}
225
226void av_fifo_drain2(AVFifo *f, size_t size)
227{
228 const size_t cur_size = av_fifo_can_read(f);
229
230 av_assert0(cur_size >= size);
231 if (cur_size == size)
232 f->is_empty = 1;
233
234 if (f->offset_r >= f->nb_elems - size)
235 f->offset_r -= f->nb_elems - size;
236 else
237 f->offset_r += size;
238}
239
240void av_fifo_reset2(AVFifo *f)
241{
242 f->offset_r = f->offset_w = 0;
243 f->is_empty = 1;
244}
245
246void av_fifo_freep2(AVFifo **f)
247{
248 if (*f) {
249 av_freep(&(*f)->buffer);
250 av_freep(f);
251 }
252}
253
254
29#define OLD_FIFO_SIZE_MAX (size_t)FFMIN3(INT_MAX, UINT32_MAX, SIZE_MAX)255#define OLD_FIFO_SIZE_MAX (size_t)FFMIN3(INT_MAX, UINT32_MAX, SIZE_MAX)
30 256
31AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size)257AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size)
libavutil/fifo.h+179−0
@@ -28,6 +28,185 @@ · 27 unmodified lines
28#include "avutil.h"28#include "avutil.h"
29#include "attributes.h"29#include "attributes.h"
30 30
31typedef struct AVFifo AVFifo;
32
33/**
34 * Callback for writing or reading from a FIFO, passed to (and invoked from) the
35 * av_fifo_*_cb() functions. It may be invoked multiple times from a single
36 * av_fifo_*_cb() call and may process less data than the maximum size indicated
37 * by nb_elems.
38 *
39 * @param opaque the opaque pointer provided to the av_fifo_*_cb() function
40 * @param buf the buffer for reading or writing the data, depending on which
41 * av_fifo_*_cb function is called
42 * @param nb_elems On entry contains the maximum number of elements that can be
43 * read from / written into buf. On success, the callback should
44 * update it to contain the number of elements actually written.
45 *
46 * @return 0 on success, a negative error code on failure (will be returned from
47 * the invoking av_fifo_*_cb() function)
48 */
49typedef int AVFifoCB(void *opaque, void *buf, size_t *nb_elems);
50
51/**
52 * Allocate and initialize an AVFifo with a given element size.
53 *
54 * @param elems initial number of elements that can be stored in the FIFO
55 * @param elem_size Size in bytes of a single element. Further operations on
56 * the returned FIFO will implicitly use this element size.
57 * @param flags currently unused, must be 0
58 *
59 * @return newly-allocated AVFifo on success, a negative error code on failure
60 */
61AVFifo *av_fifo_alloc2(size_t elems, size_t elem_size,
62 unsigned int flags);
63
64/**
65 * @return Element size for FIFO operations. This element size is set at
66 * FIFO allocation and remains constant during its lifetime
67 */
68size_t av_fifo_elem_size(const AVFifo *f);
69
70/**
71 * @return number of elements available for reading from the given FIFO.
72 */
73size_t av_fifo_can_read(const AVFifo *f);
74
75/**
76 * @return number of elements that can be written into the given FIFO.
77 */
78size_t av_fifo_can_write(const AVFifo *f);
79
80/**
81 * Enlarge an AVFifo.
82 *
83 * On success, the FIFO will be large enough to hold exactly
84 * inc + av_fifo_can_read() + av_fifo_can_write()
85 * elements. In case of failure, the old FIFO is kept unchanged.
86 *
87 * @param f AVFifo to resize
88 * @param inc number of elements to allocate for, in addition to the current
89 * allocated size
90 * @return a non-negative number on success, a negative error code on failure
91 */
92int av_fifo_grow2(AVFifo *f, size_t inc);
93
94/**
95 * Write data into a FIFO.
96 *
97 * In case nb_elems > av_fifo_can_write(f), nothing is written and an error
98 * is returned.
99 *
100 * @param f the FIFO buffer
101 * @param buf Data to be written. nb_elems * av_fifo_elem_size(f) bytes will be
102 * read from buf on success.
103 * @param nb_elems number of elements to write into FIFO
104 *
105 * @return a non-negative number on success, a negative error code on failure
106 */
107int av_fifo_write(AVFifo *f, const void *buf, size_t nb_elems);
108
109/**
110 * Write data from a user-provided callback into a FIFO.
111 *
112 * @param f the FIFO buffer
113 * @param read_cb Callback supplying the data to the FIFO. May be called
114 * multiple times.
115 * @param opaque opaque user data to be provided to read_cb
116 * @param nb_elems Should point to the maximum number of elements that can be
117 * written. Will be updated to contain the number of elements
118 * actually written.
119 *
120 * @return non-negative number on success, a negative error code on failure
121 */
122int av_fifo_write_from_cb(AVFifo *f, AVFifoCB read_cb,
123 void *opaque, size_t *nb_elems);
124
125/**
126 * Read data from a FIFO.
127 *
128 * In case nb_elems > av_fifo_can_read(f), nothing is read and an error
129 * is returned.
130 *
131 * @param f the FIFO buffer
132 * @param buf Buffer to store the data. nb_elems * av_fifo_elem_size(f) bytes
133 * will be written into buf on success.
134 * @param nb_elems number of elements to read from FIFO
135 *
136 * @return a non-negative number on success, a negative error code on failure
137 */
138int av_fifo_read(AVFifo *f, void *buf, size_t nb_elems);
139
140/**
141 * Feed data from a FIFO into a user-provided callback.
142 *
143 * @param f the FIFO buffer
144 * @param write_cb Callback the data will be supplied to. May be called
145 * multiple times.
146 * @param opaque opaque user data to be provided to write_cb
147 * @param nb_elems Should point to the maximum number of elements that can be
148 * read. Will be updated to contain the total number of elements
149 * actually sent to the callback.
150 *
151 * @return non-negative number on success, a negative error code on failure
152 */
153int av_fifo_read_to_cb(AVFifo *f, AVFifoCB write_cb,
154 void *opaque, size_t *nb_elems);
155
156/**
157 * Read data from a FIFO without modifying FIFO state.
158 *
159 * Returns an error if an attempt is made to peek to nonexistent elements
160 * (i.e. if offset + nb_elems is larger than av_fifo_can_read(f)).
161 *
162 * @param f the FIFO buffer
163 * @param buf Buffer to store the data. nb_elems * av_fifo_elem_size(f) bytes
164 * will be written into buf.
165 * @param nb_elems number of elements to read from FIFO
166 * @param offset number of initial elements to skip.
167 *
168 * @return a non-negative number on success, a negative error code on failure
169 */
170int av_fifo_peek(AVFifo *f, void *buf, size_t nb_elems, size_t offset);
171
172/**
173 * Feed data from a FIFO into a user-provided callback.
174 *
175 * @param f the FIFO buffer
176 * @param write_cb Callback the data will be supplied to. May be called
177 * multiple times.
178 * @param opaque opaque user data to be provided to write_cb
179 * @param nb_elems Should point to the maximum number of elements that can be
180 * read. Will be updated to contain the total number of elements
181 * actually sent to the callback.
182 * @param offset number of initial elements to skip; offset + *nb_elems must not
183 * be larger than av_fifo_can_read(f).
184 *
185 * @return a non-negative number on success, a negative error code on failure
186 */
187int av_fifo_peek_to_cb(AVFifo *f, AVFifoCB write_cb, void *opaque,
188 size_t *nb_elems, size_t offset);
189
190/**
191 * Discard the specified amount of data from an AVFifo.
192 * @param size number of elements to discard, MUST NOT be larger than
193 * av_fifo_can_read(f)
194 */
195void av_fifo_drain2(AVFifo *f, size_t size);
196
197/*
198 * Empty the AVFifo.
199 * @param f AVFifo to reset
200 */
201void av_fifo_reset2(AVFifo *f);
202
203/**
204 * Free an AVFifo and reset pointer to NULL.
205 * @param f Pointer to an AVFifo to free. *f == NULL is allowed.
206 */
207void av_fifo_freep2(AVFifo **f);
208
209
31typedef struct AVFifoBuffer {210typedef struct AVFifoBuffer {
32 uint8_t *buffer;211 uint8_t *buffer;
33 uint8_t *rptr, *wptr, *end;212 uint8_t *rptr, *wptr, *end;
libavutil/version.h+1−1
@@ -79,7 +79,7 @@ · 78 unmodified lines
79 */79 */
80 80
81#define LIBAVUTIL_VERSION_MAJOR 5781#define LIBAVUTIL_VERSION_MAJOR 57
82#define LIBAVUTIL_VERSION_MINOR 1982#define LIBAVUTIL_VERSION_MINOR 20
83#define LIBAVUTIL_VERSION_MICRO 10083#define LIBAVUTIL_VERSION_MICRO 100
84 84
85#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \85#define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t