diff --git a/libavutil/fifo.c b/libavutil/fifo.c index 1a227087be..7bd48a2271 100644 --- a/libavutil/fifo.c +++ b/libavutil/fifo.c @@ -148,6 +148,44 @@ int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size, return total - size; } +int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)) +{ + uint8_t *rptr = f->rptr; + + av_assert2(offset >= 0); + + /* + * *ndx are indexes modulo 2^32, they are intended to overflow, + * to handle *ndx greater than 4gb. + */ + av_assert2(buf_size + (unsigned)offset <= f->wndx - f->rndx); + + if (offset >= f->end - rptr) + rptr += offset - (f->end - f->buffer); + else + rptr += offset; + + while (buf_size > 0) { + int len; + + if (rptr >= f->end) + rptr -= f->end - f->buffer; + + len = FFMIN(f->end - rptr, buf_size); + if (func) + func(dest, rptr, len); + else { + memcpy(dest, rptr, len); + dest = (uint8_t *)dest + len; + } + + buf_size -= len; + rptr += len; + } + + return 0; +} + int av_fifo_generic_peek(AVFifoBuffer *f, void *dest, int buf_size, void (*func)(void *, void *, int)) { @@ -221,6 +259,14 @@ int main(void) } printf("\n"); + /* peek_at at FIFO */ + n = av_fifo_size(fifo) / sizeof(int); + for (i = 0; i < n; i++) { + av_fifo_generic_peek_at(fifo, &j, i * sizeof(int), sizeof(j), NULL); + printf("%d: %d\n", i, j); + } + printf("\n"); + /* read data */ for (i = 0; av_fifo_size(fifo) >= sizeof(int); i++) { av_fifo_generic_read(fifo, &j, sizeof(int), NULL); @@ -228,6 +274,21 @@ int main(void) } printf("\n"); + /* test *ndx overflow */ + av_fifo_reset(fifo); + fifo->rndx = fifo->wndx = ~(uint32_t)0 - 5; + + /* fill data */ + for (i = 0; av_fifo_space(fifo) >= sizeof(int); i++) + av_fifo_generic_write(fifo, &i, sizeof(int), NULL); + + /* peek_at at FIFO */ + n = av_fifo_size(fifo) / sizeof(int); + for (i = 0; i < n; i++) { + av_fifo_generic_peek_at(fifo, &j, i * sizeof(int), sizeof(j), NULL); + printf("%d: %d\n", i, j); + } + av_fifo_free(fifo); return 0; diff --git a/libavutil/fifo.h b/libavutil/fifo.h index 0e4070b99e..dc7bc6f0dd 100644 --- a/libavutil/fifo.h +++ b/libavutil/fifo.h @@ -83,6 +83,17 @@ int av_fifo_size(const AVFifoBuffer *f); */ int av_fifo_space(const AVFifoBuffer *f); +/** + * Feed data at specific position from an AVFifoBuffer to a user-supplied callback. + * Similar as av_fifo_gereric_read but without discarding data. + * @param f AVFifoBuffer to read from + * @param offset offset from current read position + * @param buf_size number of bytes to read + * @param func generic read function + * @param dest data destination + */ +int av_fifo_generic_peek_at(AVFifoBuffer *f, void *dest, int offset, int buf_size, void (*func)(void*, void*, int)); + /** * Feed data from an AVFifoBuffer to a user-supplied callback. * Similar as av_fifo_gereric_read but without discarding data. diff --git a/tests/ref/fate/fifo b/tests/ref/fate/fifo index 18a5691fee..162d754b06 100644 --- a/tests/ref/fate/fifo +++ b/tests/ref/fate/fifo @@ -24,4 +24,31 @@ 11: 11 12: 12 +0: 0 +1: 1 +2: 2 +3: 3 +4: 4 +5: 5 +6: 6 +7: 7 +8: 8 +9: 9 +10: 10 +11: 11 +12: 12 + 0 1 2 3 4 5 6 7 8 9 10 11 12 +0: 0 +1: 1 +2: 2 +3: 3 +4: 4 +5: 5 +6: 6 +7: 7 +8: 8 +9: 9 +10: 10 +11: 11 +12: 12