Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. AVFifoBuffer *av_fifo_alloc(unsigned int size)
  28. {
  29.     AVFifoBuffer *f = av_mallocz(sizeof(AVFifoBuffer));
  30.     if (!f)
  31.         return NULL;
  32.     f->buffer = av_malloc(size);
  33.     f->end    = f->buffer + size;
  34.     av_fifo_reset(f);
  35.     if (!f->buffer)
  36.         av_freep(&f);
  37.     return f;
  38. }
  39.  
  40. void av_fifo_free(AVFifoBuffer *f)
  41. {
  42.     if (f) {
  43.         av_freep(&f->buffer);
  44.         av_free(f);
  45.     }
  46. }
  47.  
  48. void av_fifo_reset(AVFifoBuffer *f)
  49. {
  50.     f->wptr = f->rptr = f->buffer;
  51.     f->wndx = f->rndx = 0;
  52. }
  53.  
  54. int av_fifo_size(AVFifoBuffer *f)
  55. {
  56.     return (uint32_t)(f->wndx - f->rndx);
  57. }
  58.  
  59. int av_fifo_space(AVFifoBuffer *f)
  60. {
  61.     return f->end - f->buffer - av_fifo_size(f);
  62. }
  63.  
  64. int av_fifo_realloc2(AVFifoBuffer *f, unsigned int new_size)
  65. {
  66.     unsigned int old_size = f->end - f->buffer;
  67.  
  68.     if (old_size < new_size) {
  69.         int len          = av_fifo_size(f);
  70.         AVFifoBuffer *f2 = av_fifo_alloc(new_size);
  71.  
  72.         if (!f2)
  73.             return AVERROR(ENOMEM);
  74.         av_fifo_generic_read(f, f2->buffer, len, NULL);
  75.         f2->wptr += len;
  76.         f2->wndx += len;
  77.         av_free(f->buffer);
  78.         *f = *f2;
  79.         av_free(f2);
  80.     }
  81.     return 0;
  82. }
  83.  
  84. int av_fifo_grow(AVFifoBuffer *f, unsigned int size)
  85. {
  86.     unsigned int old_size = f->end - f->buffer;
  87.     if(size + (unsigned)av_fifo_size(f) < size)
  88.         return AVERROR(EINVAL);
  89.  
  90.     size += av_fifo_size(f);
  91.  
  92.     if (old_size < size)
  93.         return av_fifo_realloc2(f, FFMAX(size, 2*size));
  94.     return 0;
  95. }
  96.  
  97. /* src must NOT be const as it can be a context for func that may need
  98.  * updating (like a pointer or byte counter) */
  99. int av_fifo_generic_write(AVFifoBuffer *f, void *src, int size,
  100.                           int (*func)(void *, void *, int))
  101. {
  102.     int total = size;
  103.     uint32_t wndx= f->wndx;
  104.     uint8_t *wptr= f->wptr;
  105.  
  106.     do {
  107.         int len = FFMIN(f->end - wptr, size);
  108.         if (func) {
  109.             if (func(src, wptr, len) <= 0)
  110.                 break;
  111.         } else {
  112.             memcpy(wptr, src, len);
  113.             src = (uint8_t *)src + len;
  114.         }
  115. // Write memory barrier needed for SMP here in theory
  116.         wptr += len;
  117.         if (wptr >= f->end)
  118.             wptr = f->buffer;
  119.         wndx    += len;
  120.         size    -= len;
  121.     } while (size > 0);
  122.     f->wndx= wndx;
  123.     f->wptr= wptr;
  124.     return total - size;
  125. }
  126.  
  127. int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size,
  128.                          void (*func)(void *, void *, int))
  129. {
  130. // Read memory barrier needed for SMP here in theory
  131.     do {
  132.         int len = FFMIN(f->end - f->rptr, buf_size);
  133.         if (func)
  134.             func(dest, f->rptr, len);
  135.         else {
  136.             memcpy(dest, f->rptr, len);
  137.             dest = (uint8_t *)dest + len;
  138.         }
  139. // memory barrier needed for SMP here in theory
  140.         av_fifo_drain(f, len);
  141.         buf_size -= len;
  142.     } while (buf_size > 0);
  143.     return 0;
  144. }
  145.  
  146. /** Discard data from the FIFO. */
  147. void av_fifo_drain(AVFifoBuffer *f, int size)
  148. {
  149.     av_assert2(av_fifo_size(f) >= size);
  150.     f->rptr += size;
  151.     if (f->rptr >= f->end)
  152.         f->rptr -= f->end - f->buffer;
  153.     f->rndx += size;
  154. }
  155.  
  156. #ifdef TEST
  157.  
  158. int main(void)
  159. {
  160.     /* create a FIFO buffer */
  161.     AVFifoBuffer *fifo = av_fifo_alloc(13 * sizeof(int));
  162.     int i, j, n;
  163.  
  164.     /* fill data */
  165.     for (i = 0; av_fifo_space(fifo) >= sizeof(int); i++)
  166.         av_fifo_generic_write(fifo, &i, sizeof(int), NULL);
  167.  
  168.     /* peek at FIFO */
  169.     n = av_fifo_size(fifo) / sizeof(int);
  170.     for (i = -n + 1; i < n; i++) {
  171.         int *v = (int *)av_fifo_peek2(fifo, i * sizeof(int));
  172.         printf("%d: %d\n", i, *v);
  173.     }
  174.     printf("\n");
  175.  
  176.     /* read data */
  177.     for (i = 0; av_fifo_size(fifo) >= sizeof(int); i++) {
  178.         av_fifo_generic_read(fifo, &j, sizeof(int), NULL);
  179.         printf("%d ", j);
  180.     }
  181.     printf("\n");
  182.  
  183.     av_fifo_free(fifo);
  184.  
  185.     return 0;
  186. }
  187.  
  188. #endif
  189.