f5a478f6 |
/* |
89c9ff50 |
* a very simple circular buffer FIFO implementation |
f5a478f6 |
* Copyright (c) 2000, 2001, 2002 Fabrice Bellard
* Copyright (c) 2006 Roman Shaposhnik
* |
b78e7197 |
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or |
f5a478f6 |
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either |
b78e7197 |
* version 2.1 of the License, or (at your option) any later version. |
f5a478f6 |
* |
b78e7197 |
* FFmpeg is distributed in the hope that it will be useful, |
f5a478f6 |
* 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 |
b78e7197 |
* License along with FFmpeg; if not, write to the Free Software |
f5a478f6 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ |
cc84f304 |
#include "avassert.h" |
f5a478f6 |
#include "common.h"
#include "fifo.h"
|
7336e39f |
static AVFifoBuffer *fifo_alloc_common(void *buffer, size_t size) |
f5a478f6 |
{ |
7336e39f |
AVFifoBuffer *f;
if (!buffer)
return NULL;
f = av_mallocz(sizeof(AVFifoBuffer));
if (!f) {
av_free(buffer); |
41dd680d |
return NULL; |
7336e39f |
}
f->buffer = buffer; |
73142e75 |
f->end = f->buffer + size; |
32b936d0 |
av_fifo_reset(f); |
41dd680d |
return f; |
f5a478f6 |
}
|
7336e39f |
AVFifoBuffer *av_fifo_alloc(unsigned int size)
{
void *buffer = av_malloc(size);
return fifo_alloc_common(buffer, size);
}
AVFifoBuffer *av_fifo_alloc_array(size_t nmemb, size_t size)
{
void *buffer = av_malloc_array(nmemb, size);
return fifo_alloc_common(buffer, nmemb * size);
}
|
f5a478f6 |
void av_fifo_free(AVFifoBuffer *f)
{ |
f1b29223 |
if (f) { |
17354407 |
av_freep(&f->buffer); |
c900635f |
av_free(f); |
41dd680d |
} |
f5a478f6 |
}
|
351f6118 |
void av_fifo_freep(AVFifoBuffer **f)
{
if (f) {
av_fifo_free(*f);
*f = NULL;
}
}
|
32b936d0 |
void av_fifo_reset(AVFifoBuffer *f)
{
f->wptr = f->rptr = f->buffer;
f->wndx = f->rndx = 0;
}
|
5182a2a2 |
int av_fifo_size(const AVFifoBuffer *f) |
f5a478f6 |
{ |
0a71e78c |
return (uint32_t)(f->wndx - f->rndx); |
f5a478f6 |
}
|
5182a2a2 |
int av_fifo_space(const AVFifoBuffer *f) |
7b09db35 |
{
return f->end - f->buffer - av_fifo_size(f);
}
|
f1b29223 |
int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
{
unsigned int old_size = f->end - f->buffer; |
f5a478f6 |
|
f1b29223 |
if (old_size < new_size) { |
73142e75 |
int len = av_fifo_size(f); |
f1b29223 |
AVFifoBuffer *f2 = av_fifo_alloc(new_size); |
f5a478f6 |
|
41dd680d |
if (!f2) |
2e81bb5e |
return AVERROR(ENOMEM); |
3898eed8 |
av_fifo_generic_read(f, f2->buffer, len, NULL); |
41dd680d |
f2->wptr += len;
f2->wndx += len; |
96e39edc |
av_free(f->buffer); |
f1b29223 |
*f = *f2; |
41dd680d |
av_free(f2); |
f5a478f6 |
} |
8257b835 |
return 0; |
f5a478f6 |
}
|
f8196759 |
int av_fifo_grow(AVFifoBuffer *f, unsigned int size)
{
unsigned int old_size = f->end - f->buffer;
if(size + (unsigned)av_fifo_size(f) < size)
return AVERROR(EINVAL);
size += av_fifo_size(f);
if (old_size < size)
return av_fifo_realloc2(f, FFMAX(size, 2*size));
return 0;
}
|
73142e75 |
/* src must NOT be const as it can be a context for func that may need
* updating (like a pointer or byte counter) */
int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size,
int (*func)(void *, void *, int)) |
49cec199 |
{
int total = size; |
9eb0d8ba |
uint32_t wndx= f->wndx;
uint8_t *wptr= f->wptr;
|
50b44685 |
do { |
9eb0d8ba |
int len = FFMIN(f->end - wptr, size); |
f1b29223 |
if (func) { |
fcbea93c |
len = func(src, wptr, len);
if (len <= 0) |
49cec199 |
break;
} else { |
9eb0d8ba |
memcpy(wptr, src, len); |
73142e75 |
src = (uint8_t *)src + len; |
49cec199 |
} |
a9364759 |
// Write memory barrier needed for SMP here in theory |
9eb0d8ba |
wptr += len;
if (wptr >= f->end)
wptr = f->buffer; |
7bd417c2 |
wndx += len; |
73142e75 |
size -= len; |
50b44685 |
} while (size > 0); |
9eb0d8ba |
f->wndx= wndx;
f->wptr= wptr; |
49cec199 |
return total - size; |
f5a478f6 |
}
|
2fa01995 |
int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size,
void (*func)(void *, void *, int))
{
// Read memory barrier needed for SMP here in theory
uint8_t *rptr = f->rptr;
uint32_t rndx = f->rndx;
do {
int len = FFMIN(f->end - f->rptr, buf_size);
if (func)
func(dest, f->rptr, len);
else {
memcpy(dest, f->rptr, len);
dest = (uint8_t *)dest + len;
}
// memory barrier needed for SMP here in theory
av_fifo_drain(f, len);
buf_size -= len;
} while (buf_size > 0);
f->rptr = rptr;
f->rndx = rndx;
return 0;
}
|
73142e75 |
int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size,
void (*func)(void *, void *, int)) |
f5a478f6 |
{ |
a9364759 |
// Read memory barrier needed for SMP here in theory |
50b44685 |
do { |
870a12d1 |
int len = FFMIN(f->end - f->rptr, buf_size); |
73142e75 |
if (func)
func(dest, f->rptr, len);
else { |
765d4f3b |
memcpy(dest, f->rptr, len); |
73142e75 |
dest = (uint8_t *)dest + len; |
765d4f3b |
} |
a9364759 |
// memory barrier needed for SMP here in theory |
3da97cfd |
av_fifo_drain(f, len); |
f5a478f6 |
buf_size -= len; |
50b44685 |
} while (buf_size > 0); |
f5a478f6 |
return 0;
}
|
89c9ff50 |
/** Discard data from the FIFO. */ |
f5a478f6 |
void av_fifo_drain(AVFifoBuffer *f, int size)
{ |
cc84f304 |
av_assert2(av_fifo_size(f) >= size); |
f5a478f6 |
f->rptr += size;
if (f->rptr >= f->end)
f->rptr -= f->end - f->buffer; |
0a71e78c |
f->rndx += size; |
f5a478f6 |
} |
1717ba0c |
#ifdef TEST
int main(void)
{
/* create a FIFO buffer */
AVFifoBuffer *fifo = av_fifo_alloc(13 * sizeof(int));
int i, j, n;
/* fill data */
for (i = 0; av_fifo_space(fifo) >= sizeof(int); i++)
av_fifo_generic_write(fifo, &i, sizeof(int), NULL);
/* peek at FIFO */ |
73142e75 |
n = av_fifo_size(fifo) / sizeof(int);
for (i = -n + 1; i < n; i++) {
int *v = (int *)av_fifo_peek2(fifo, i * sizeof(int)); |
1717ba0c |
printf("%d: %d\n", i, *v);
}
printf("\n");
/* read data */
for (i = 0; av_fifo_size(fifo) >= sizeof(int); i++) {
av_fifo_generic_read(fifo, &j, sizeof(int), NULL);
printf("%d ", j);
}
printf("\n");
av_fifo_free(fifo);
return 0;
}
#endif |