blob: 1060aedf135182befc3c7c6df51e50b56304c443
1 | /* |
2 | * a very simple circular buffer FIFO implementation |
3 | * Copyright (c) 2000, 2001, 2002 Fabrice Bellard |
4 | * Copyright (c) 2006 Roman Shaposhnik |
5 | * |
6 | * This file is part of FFmpeg. |
7 | * |
8 | * FFmpeg is free software; you can redistribute it and/or |
9 | * modify it under the terms of the GNU Lesser General Public |
10 | * License as published by the Free Software Foundation; either |
11 | * version 2.1 of the License, or (at your option) any later version. |
12 | * |
13 | * FFmpeg is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 | * Lesser General Public License for more details. |
17 | * |
18 | * You should have received a copy of the GNU Lesser General Public |
19 | * License along with FFmpeg; if not, write to the Free Software |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
21 | */ |
22 | |
23 | #include "avassert.h" |
24 | #include "common.h" |
25 | #include "fifo.h" |
26 | |
27 | static AVFifoBuffer *fifo_alloc_common(void *buffer, size_t size) |
28 | { |
29 | AVFifoBuffer *f; |
30 | if (!buffer) |
31 | return NULL; |
32 | f = av_mallocz(sizeof(AVFifoBuffer)); |
33 | if (!f) { |
34 | av_free(buffer); |
35 | return NULL; |
36 | } |
37 | f->buffer = buffer; |
38 | f->end = f->buffer + size; |
39 | av_fifo_reset(f); |
40 | return f; |
41 | } |
42 | |
43 | AVFifoBuffer *av_fifo_alloc(unsigned int size) |
44 | { |
45 | void *buffer = av_malloc(size); |
46 | return fifo_alloc_common(buffer, size); |
47 | } |
48 | |
49 | AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size) |
50 | { |
51 | void *buffer = av_malloc_array(nmemb, size); |
52 | return fifo_alloc_common(buffer, nmemb * size); |
53 | } |
54 | |
55 | void av_fifo_free(AVFifoBuffer *f) |
56 | { |
57 | if (f) { |
58 | av_freep(&f->buffer); |
59 | av_free(f); |
60 | } |
61 | } |
62 | |
63 | void av_fifo_freep(AVFifoBuffer **f) |
64 | { |
65 | if (f) { |
66 | av_fifo_free(*f); |
67 | *f = NULL; |
68 | } |
69 | } |
70 | |
71 | void av_fifo_reset(AVFifoBuffer *f) |
72 | { |
73 | f->wptr = f->rptr = f->buffer; |
74 | f->wndx = f->rndx = 0; |
75 | } |
76 | |
77 | int av_fifo_size(const AVFifoBuffer *f) |
78 | { |
79 | return (uint32_t)(f->wndx - f->rndx); |
80 | } |
81 | |
82 | int av_fifo_space(const AVFifoBuffer *f) |
83 | { |
84 | return f->end - f->buffer - av_fifo_size(f); |
85 | } |
86 | |
87 | int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size) |
88 | { |
89 | unsigned int old_size = f->end - f->buffer; |
90 | |
91 | if (old_size < new_size) { |
92 | int len = av_fifo_size(f); |
93 | AVFifoBuffer *f2 = av_fifo_alloc(new_size); |
94 | |
95 | if (!f2) |
96 | return AVERROR(ENOMEM); |
97 | av_fifo_generic_read(f, f2->buffer, len, NULL); |
98 | f2->wptr += len; |
99 | f2->wndx += len; |
100 | av_free(f->buffer); |
101 | *f = *f2; |
102 | av_free(f2); |
103 | } |
104 | return 0; |
105 | } |
106 | |
107 | int av_fifo_grow(AVFifoBuffer *f, unsigned int size) |
108 | { |
109 | unsigned int old_size = f->end - f->buffer; |
110 | if(size + (unsigned)av_fifo_size(f) < size) |
111 | return AVERROR(EINVAL); |
112 | |
113 | size += av_fifo_size(f); |
114 | |
115 | if (old_size < size) |
116 | return av_fifo_realloc2(f, FFMAX(size, 2*old_size)); |
117 | return 0; |
118 | } |
119 | |
120 | /* src must NOT be const as it can be a context for func that may need |
121 | * updating (like a pointer or byte counter) */ |
122 | int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, |
123 | int (*func)(void *, void *, int)) |
124 | { |
125 | int total = size; |
126 | uint32_t wndx= f->wndx; |
127 | uint8_t *wptr= f->wptr; |
128 | |
129 | do { |
130 | int len = FFMIN(f->end - wptr, size); |
131 | if (func) { |
132 | len = func(src, wptr, len); |
133 | if (len <= 0) |
134 | break; |
135 | } else { |
136 | memcpy(wptr, src, len); |
137 | src = (uint8_t *)src + len; |
138 | } |
139 | // Write memory barrier needed for SMP here in theory |
140 | wptr += len; |
141 | if (wptr >= f->end) |
142 | wptr = f->buffer; |
143 | wndx += len; |
144 | size -= len; |
145 | } while (size > 0); |
146 | f->wndx= wndx; |
147 | f->wptr= wptr; |
148 | return total - size; |
149 | } |
150 | |
151 | int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)) |
152 | { |
153 | uint8_t *rptr = f->rptr; |
154 | |
155 | av_assert2(offset >= 0); |
156 | |
157 | /* |
158 | * *ndx are indexes modulo 2^32, they are intended to overflow, |
159 | * to handle *ndx greater than 4gb. |
160 | */ |
161 | av_assert2(buf_size + (unsigned)offset <= f->wndx - f->rndx); |
162 | |
163 | if (offset >= f->end - rptr) |
164 | rptr += offset - (f->end - f->buffer); |
165 | else |
166 | rptr += offset; |
167 | |
168 | while (buf_size > 0) { |
169 | int len; |
170 | |
171 | if (rptr >= f->end) |
172 | rptr -= f->end - f->buffer; |
173 | |
174 | len = FFMIN(f->end - rptr, buf_size); |
175 | if (func) |
176 | func(dest, rptr, len); |
177 | else { |
178 | memcpy(dest, rptr, len); |
179 | dest = (uint8_t *)dest + len; |
180 | } |
181 | |
182 | buf_size -= len; |
183 | rptr += len; |
184 | } |
185 | |
186 | return 0; |
187 | } |
188 | |
189 | int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size, |
190 | void (*func)(void *, void *, int)) |
191 | { |
192 | // Read memory barrier needed for SMP here in theory |
193 | uint8_t *rptr = f->rptr; |
194 | |
195 | do { |
196 | int len = FFMIN(f->end - rptr, buf_size); |
197 | if (func) |
198 | func(dest, rptr, len); |
199 | else { |
200 | memcpy(dest, rptr, len); |
201 | dest = (uint8_t *)dest + len; |
202 | } |
203 | // memory barrier needed for SMP here in theory |
204 | rptr += len; |
205 | if (rptr >= f->end) |
206 | rptr -= f->end - f->buffer; |
207 | buf_size -= len; |
208 | } while (buf_size > 0); |
209 | |
210 | return 0; |
211 | } |
212 | |
213 | int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size, |
214 | void (*func)(void *, void *, int)) |
215 | { |
216 | // Read memory barrier needed for SMP here in theory |
217 | do { |
218 | int len = FFMIN(f->end - f->rptr, buf_size); |
219 | if (func) |
220 | func(dest, f->rptr, len); |
221 | else { |
222 | memcpy(dest, f->rptr, len); |
223 | dest = (uint8_t *)dest + len; |
224 | } |
225 | // memory barrier needed for SMP here in theory |
226 | av_fifo_drain(f, len); |
227 | buf_size -= len; |
228 | } while (buf_size > 0); |
229 | return 0; |
230 | } |
231 | |
232 | /** Discard data from the FIFO. */ |
233 | void av_fifo_drain(AVFifoBuffer *f, int size) |
234 | { |
235 | av_assert2(av_fifo_size(f) >= size); |
236 | f->rptr += size; |
237 | if (f->rptr >= f->end) |
238 | f->rptr -= f->end - f->buffer; |
239 | f->rndx += size; |
240 | } |
241 |