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. 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*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(AVFifoBuffer *f, void *dest, int buf_size,
  152.                          void (*func)(void *, void *, int))
  153. {
  154. // Read memory barrier needed for SMP here in theory
  155.     uint8_t *rptr = f->rptr;
  156.     uint32_t rndx = f->rndx;
  157.  
  158.     do {
  159.         int len = FFMIN(f->end - f->rptr, buf_size);
  160.         if (func)
  161.             func(dest, f->rptr, len);
  162.         else {
  163.             memcpy(dest, f->rptr, len);
  164.             dest = (uint8_t *)dest + len;
  165.         }
  166. // memory barrier needed for SMP here in theory
  167.         av_fifo_drain(f, len);
  168.         buf_size -= len;
  169.     } while (buf_size > 0);
  170.  
  171.     f->rptr = rptr;
  172.     f->rndx = rndx;
  173.  
  174.     return 0;
  175. }
  176.  
  177. int av_fifo_generic_read(AVFifoBuffer *f, void *dest, int buf_size,
  178.                          void (*func)(void *, void *, int))
  179. {
  180. // Read memory barrier needed for SMP here in theory
  181.     do {
  182.         int len = FFMIN(f->end - f->rptr, buf_size);
  183.         if (func)
  184.             func(dest, f->rptr, len);
  185.         else {
  186.             memcpy(dest, f->rptr, len);
  187.             dest = (uint8_t *)dest + len;
  188.         }
  189. // memory barrier needed for SMP here in theory
  190.         av_fifo_drain(f, len);
  191.         buf_size -= len;
  192.     } while (buf_size > 0);
  193.     return 0;
  194. }
  195.  
  196. /** Discard data from the FIFO. */
  197. void av_fifo_drain(AVFifoBuffer *f, int size)
  198. {
  199.     av_assert2(av_fifo_size(f) >= size);
  200.     f->rptr += size;
  201.     if (f->rptr >= f->end)
  202.         f->rptr -= f->end - f->buffer;
  203.     f->rndx += size;
  204. }
  205.  
  206. #ifdef TEST
  207.  
  208. int main(void)
  209. {
  210.     /* create a FIFO buffer */
  211.     AVFifoBuffer *fifo = av_fifo_alloc(13 * sizeof(int));
  212.     int i, j, n;
  213.  
  214.     /* fill data */
  215.     for (i = 0; av_fifo_space(fifo) >= sizeof(int); i++)
  216.         av_fifo_generic_write(fifo, &i, sizeof(int), NULL);
  217.  
  218.     /* peek at FIFO */
  219.     n = av_fifo_size(fifo) / sizeof(int);
  220.     for (i = -n + 1; i < n; i++) {
  221.         int *v = (int *)av_fifo_peek2(fifo, i * sizeof(int));
  222.         printf("%d: %d\n", i, *v);
  223.     }
  224.     printf("\n");
  225.  
  226.     /* read data */
  227.     for (i = 0; av_fifo_size(fifo) >= sizeof(int); i++) {
  228.         av_fifo_generic_read(fifo, &j, sizeof(int), NULL);
  229.         printf("%d ", j);
  230.     }
  231.     printf("\n");
  232.  
  233.     av_fifo_free(fifo);
  234.  
  235.     return 0;
  236. }
  237.  
  238. #endif
  239.