container_fifo.c (5592B)
1 /* 2 * This file is part of FFmpeg. 3 * 4 * FFmpeg is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2.1 of the License, or (at your option) any later version. 8 * 9 * FFmpeg is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with FFmpeg; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 #include "avassert.h" 20 #include "container_fifo.h" 21 #include "error.h" 22 #include "fifo.h" 23 #include "frame.h" 24 #include "mem.h" 25 #include "refstruct.h" 26 27 struct AVContainerFifo { 28 AVFifo *fifo; 29 AVRefStructPool *pool; 30 31 void *opaque; 32 void* (*container_alloc)(void *opaque); 33 void (*container_reset)(void *opaque, void *obj); 34 void (*container_free) (void *opaque, void *obj); 35 int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags); 36 37 }; 38 39 static int container_fifo_init_entry(AVRefStructOpaque opaque, void *obj) 40 { 41 AVContainerFifo *cf = opaque.nc; 42 void **pobj = obj; 43 44 *pobj = cf->container_alloc(cf->opaque); 45 if (!*pobj) 46 return AVERROR(ENOMEM); 47 48 return 0; 49 } 50 51 static void container_fifo_reset_entry(AVRefStructOpaque opaque, void *obj) 52 { 53 AVContainerFifo *cf = opaque.nc; 54 cf->container_reset(cf->opaque, *(void**)obj); 55 } 56 57 static void container_fifo_free_entry(AVRefStructOpaque opaque, void *obj) 58 { 59 AVContainerFifo *cf = opaque.nc; 60 cf->container_free(cf->opaque, *(void**)obj); 61 } 62 63 AVContainerFifo* 64 av_container_fifo_alloc(void *opaque, 65 void* (*container_alloc)(void *opaque), 66 void (*container_reset)(void *opaque, void *obj), 67 void (*container_free) (void *opaque, void *obj), 68 int (*fifo_transfer) (void *opaque, void *dst, void *src, unsigned flags), 69 unsigned flags) 70 { 71 AVContainerFifo *cf; 72 73 cf = av_mallocz(sizeof(*cf)); 74 if (!cf) 75 return NULL; 76 77 cf->opaque = opaque; 78 cf->container_alloc = container_alloc; 79 cf->container_reset = container_reset; 80 cf->container_free = container_free; 81 cf->fifo_transfer = fifo_transfer; 82 83 cf->fifo = av_fifo_alloc2(1, sizeof(void*), AV_FIFO_FLAG_AUTO_GROW); 84 if (!cf->fifo) 85 goto fail; 86 87 cf->pool = av_refstruct_pool_alloc_ext(sizeof(void*), 0, cf, 88 container_fifo_init_entry, 89 container_fifo_reset_entry, 90 container_fifo_free_entry, 91 NULL); 92 if (!cf->pool) 93 goto fail; 94 95 return cf; 96 fail: 97 av_container_fifo_free(&cf); 98 return NULL; 99 } 100 101 void av_container_fifo_free(AVContainerFifo **pcf) 102 { 103 AVContainerFifo *cf; 104 105 if (!*pcf) 106 return; 107 108 cf = *pcf; 109 110 if (cf->fifo) { 111 void *obj; 112 while (av_fifo_read(cf->fifo, &obj, 1) >= 0) 113 av_refstruct_unref(&obj); 114 av_fifo_freep2(&cf->fifo); 115 } 116 117 av_refstruct_pool_uninit(&cf->pool); 118 119 av_freep(pcf); 120 } 121 122 int av_container_fifo_read(AVContainerFifo *cf, void *obj, unsigned flags) 123 { 124 void **psrc; 125 int ret; 126 127 ret = av_fifo_read(cf->fifo, &psrc, 1); 128 if (ret < 0) 129 return ret; 130 131 ret = cf->fifo_transfer(cf->opaque, obj, *psrc, flags); 132 av_refstruct_unref(&psrc); 133 134 return ret; 135 } 136 137 int av_container_fifo_peek(AVContainerFifo *cf, void **pdst, size_t offset) 138 { 139 void **pobj; 140 int ret; 141 142 ret = av_fifo_peek(cf->fifo, &pobj, 1, offset); 143 if (ret < 0) 144 return ret; 145 146 *pdst = *pobj; 147 148 return 0; 149 } 150 151 void av_container_fifo_drain(AVContainerFifo *cf, size_t nb_elems) 152 { 153 av_assert0(nb_elems <= av_fifo_can_read(cf->fifo)); 154 while (nb_elems--) { 155 void **pobj; 156 int ret = av_fifo_read(cf->fifo, &pobj, 1); 157 av_assert0(ret >= 0); 158 av_refstruct_unref(&pobj); 159 } 160 } 161 162 int av_container_fifo_write(AVContainerFifo *cf, void *obj, unsigned flags) 163 { 164 void **pdst; 165 int ret; 166 167 pdst = av_refstruct_pool_get(cf->pool); 168 if (!pdst) 169 return AVERROR(ENOMEM); 170 171 ret = cf->fifo_transfer(cf->opaque, *pdst, obj, flags); 172 if (ret < 0) 173 goto fail; 174 175 ret = av_fifo_write(cf->fifo, &pdst, 1); 176 if (ret < 0) 177 goto fail; 178 179 return 0; 180 fail: 181 av_refstruct_unref(&pdst); 182 return ret; 183 } 184 185 size_t av_container_fifo_can_read(const AVContainerFifo *cf) 186 { 187 return av_fifo_can_read(cf->fifo); 188 } 189 190 static void *frame_alloc(void *opaque) 191 { 192 return av_frame_alloc(); 193 } 194 195 static void frame_reset(void *opaque, void *obj) 196 { 197 av_frame_unref(obj); 198 } 199 200 static void frame_free(void *opaque, void *obj) 201 { 202 AVFrame *frame = obj; 203 av_frame_free(&frame); 204 } 205 206 static int frame_transfer(void *opaque, void *dst, void *src, unsigned flags) 207 { 208 if (flags & AV_CONTAINER_FIFO_FLAG_REF) 209 return av_frame_ref(dst, src); 210 211 av_frame_move_ref(dst, src); 212 return 0; 213 } 214 215 AVContainerFifo *av_container_fifo_alloc_avframe(unsigned flags) 216 { 217 return av_container_fifo_alloc(NULL, frame_alloc, frame_reset, frame_free, 218 frame_transfer, 0); 219 }