buffer.c (10042B)
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 <stdatomic.h> 20 #include <stdint.h> 21 #include <string.h> 22 23 #include "avassert.h" 24 #include "buffer_internal.h" 25 #include "common.h" 26 #include "mem.h" 27 #include "thread.h" 28 29 static AVBufferRef *buffer_create(AVBuffer *buf, uint8_t *data, size_t size, 30 void (*free)(void *opaque, uint8_t *data), 31 void *opaque, int flags) 32 { 33 AVBufferRef *ref = NULL; 34 35 buf->data = data; 36 buf->size = size; 37 buf->free = free ? free : av_buffer_default_free; 38 buf->opaque = opaque; 39 40 atomic_init(&buf->refcount, 1); 41 42 buf->flags = flags; 43 44 ref = av_mallocz(sizeof(*ref)); 45 if (!ref) 46 return NULL; 47 48 ref->buffer = buf; 49 ref->data = data; 50 ref->size = size; 51 52 return ref; 53 } 54 55 AVBufferRef *av_buffer_create(uint8_t *data, size_t size, 56 void (*free)(void *opaque, uint8_t *data), 57 void *opaque, int flags) 58 { 59 AVBufferRef *ret; 60 AVBuffer *buf = av_mallocz(sizeof(*buf)); 61 if (!buf) 62 return NULL; 63 64 ret = buffer_create(buf, data, size, free, opaque, flags); 65 if (!ret) { 66 av_free(buf); 67 return NULL; 68 } 69 return ret; 70 } 71 72 void av_buffer_default_free(void *opaque, uint8_t *data) 73 { 74 av_free(data); 75 } 76 77 AVBufferRef *av_buffer_alloc(size_t size) 78 { 79 AVBufferRef *ret = NULL; 80 uint8_t *data = NULL; 81 82 data = av_malloc(size); 83 if (!data) 84 return NULL; 85 86 ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); 87 if (!ret) 88 av_freep(&data); 89 90 return ret; 91 } 92 93 AVBufferRef *av_buffer_allocz(size_t size) 94 { 95 AVBufferRef *ret = av_buffer_alloc(size); 96 if (!ret) 97 return NULL; 98 99 memset(ret->data, 0, size); 100 return ret; 101 } 102 103 AVBufferRef *av_buffer_ref(const AVBufferRef *buf) 104 { 105 AVBufferRef *ret = av_mallocz(sizeof(*ret)); 106 107 if (!ret) 108 return NULL; 109 110 *ret = *buf; 111 112 atomic_fetch_add_explicit(&buf->buffer->refcount, 1, memory_order_relaxed); 113 114 return ret; 115 } 116 117 static void buffer_replace(AVBufferRef **dst, AVBufferRef **src) 118 { 119 AVBuffer *b; 120 121 b = (*dst)->buffer; 122 123 if (src) { 124 **dst = **src; 125 av_freep(src); 126 } else 127 av_freep(dst); 128 129 if (atomic_fetch_sub_explicit(&b->refcount, 1, memory_order_acq_rel) == 1) { 130 /* b->free below might already free the structure containing *b, 131 * so we have to read the flag now to avoid use-after-free. */ 132 int free_avbuffer = !(b->flags_internal & BUFFER_FLAG_NO_FREE); 133 b->free(b->opaque, b->data); 134 if (free_avbuffer) 135 av_free(b); 136 } 137 } 138 139 void av_buffer_unref(AVBufferRef **buf) 140 { 141 if (!buf || !*buf) 142 return; 143 144 buffer_replace(buf, NULL); 145 } 146 147 int av_buffer_is_writable(const AVBufferRef *buf) 148 { 149 if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY) 150 return 0; 151 152 return atomic_load(&buf->buffer->refcount) == 1; 153 } 154 155 void *av_buffer_get_opaque(const AVBufferRef *buf) 156 { 157 return buf->buffer->opaque; 158 } 159 160 int av_buffer_get_ref_count(const AVBufferRef *buf) 161 { 162 return atomic_load(&buf->buffer->refcount); 163 } 164 165 int av_buffer_make_writable(AVBufferRef **pbuf) 166 { 167 AVBufferRef *newbuf, *buf = *pbuf; 168 169 if (av_buffer_is_writable(buf)) 170 return 0; 171 172 newbuf = av_buffer_alloc(buf->size); 173 if (!newbuf) 174 return AVERROR(ENOMEM); 175 176 memcpy(newbuf->data, buf->data, buf->size); 177 178 buffer_replace(pbuf, &newbuf); 179 180 return 0; 181 } 182 183 int av_buffer_realloc(AVBufferRef **pbuf, size_t size) 184 { 185 AVBufferRef *buf = *pbuf; 186 uint8_t *tmp; 187 int ret; 188 189 if (!buf) { 190 /* allocate a new buffer with av_realloc(), so it will be reallocatable 191 * later */ 192 uint8_t *data = av_realloc(NULL, size); 193 if (!data) 194 return AVERROR(ENOMEM); 195 196 buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0); 197 if (!buf) { 198 av_freep(&data); 199 return AVERROR(ENOMEM); 200 } 201 202 buf->buffer->flags_internal |= BUFFER_FLAG_REALLOCATABLE; 203 *pbuf = buf; 204 205 return 0; 206 } else if (buf->size == size) 207 return 0; 208 209 if (!(buf->buffer->flags_internal & BUFFER_FLAG_REALLOCATABLE) || 210 !av_buffer_is_writable(buf) || buf->data != buf->buffer->data) { 211 /* cannot realloc, allocate a new reallocable buffer and copy data */ 212 AVBufferRef *new = NULL; 213 214 ret = av_buffer_realloc(&new, size); 215 if (ret < 0) 216 return ret; 217 218 memcpy(new->data, buf->data, FFMIN(size, buf->size)); 219 220 buffer_replace(pbuf, &new); 221 return 0; 222 } 223 224 tmp = av_realloc(buf->buffer->data, size); 225 if (!tmp) 226 return AVERROR(ENOMEM); 227 228 buf->buffer->data = buf->data = tmp; 229 buf->buffer->size = buf->size = size; 230 return 0; 231 } 232 233 int av_buffer_replace(AVBufferRef **pdst, const AVBufferRef *src) 234 { 235 AVBufferRef *dst = *pdst; 236 AVBufferRef *tmp; 237 238 if (!src) { 239 av_buffer_unref(pdst); 240 return 0; 241 } 242 243 if (dst && dst->buffer == src->buffer) { 244 /* make sure the data pointers match */ 245 dst->data = src->data; 246 dst->size = src->size; 247 return 0; 248 } 249 250 tmp = av_buffer_ref(src); 251 if (!tmp) 252 return AVERROR(ENOMEM); 253 254 av_buffer_unref(pdst); 255 *pdst = tmp; 256 return 0; 257 } 258 259 AVBufferPool *av_buffer_pool_init2(size_t size, void *opaque, 260 AVBufferRef* (*alloc)(void *opaque, size_t size), 261 void (*pool_free)(void *opaque)) 262 { 263 AVBufferPool *pool = av_mallocz(sizeof(*pool)); 264 if (!pool) 265 return NULL; 266 267 if (ff_mutex_init(&pool->mutex, NULL)) { 268 av_free(pool); 269 return NULL; 270 } 271 272 pool->size = size; 273 pool->opaque = opaque; 274 pool->alloc2 = alloc; 275 pool->alloc = av_buffer_alloc; // fallback 276 pool->pool_free = pool_free; 277 278 atomic_init(&pool->refcount, 1); 279 280 return pool; 281 } 282 283 AVBufferPool *av_buffer_pool_init(size_t size, AVBufferRef* (*alloc)(size_t size)) 284 { 285 AVBufferPool *pool = av_mallocz(sizeof(*pool)); 286 if (!pool) 287 return NULL; 288 289 if (ff_mutex_init(&pool->mutex, NULL)) { 290 av_free(pool); 291 return NULL; 292 } 293 294 pool->size = size; 295 pool->alloc = alloc ? alloc : av_buffer_alloc; 296 297 atomic_init(&pool->refcount, 1); 298 299 return pool; 300 } 301 302 static void buffer_pool_flush(AVBufferPool *pool) 303 { 304 while (pool->pool) { 305 BufferPoolEntry *buf = pool->pool; 306 pool->pool = buf->next; 307 308 buf->free(buf->opaque, buf->data); 309 av_freep(&buf); 310 } 311 } 312 313 /* 314 * This function gets called when the pool has been uninited and 315 * all the buffers returned to it. 316 */ 317 static void buffer_pool_free(AVBufferPool *pool) 318 { 319 buffer_pool_flush(pool); 320 ff_mutex_destroy(&pool->mutex); 321 322 if (pool->pool_free) 323 pool->pool_free(pool->opaque); 324 325 av_freep(&pool); 326 } 327 328 void av_buffer_pool_uninit(AVBufferPool **ppool) 329 { 330 AVBufferPool *pool; 331 332 if (!ppool || !*ppool) 333 return; 334 pool = *ppool; 335 *ppool = NULL; 336 337 ff_mutex_lock(&pool->mutex); 338 buffer_pool_flush(pool); 339 ff_mutex_unlock(&pool->mutex); 340 341 if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) 342 buffer_pool_free(pool); 343 } 344 345 static void pool_release_buffer(void *opaque, uint8_t *data) 346 { 347 BufferPoolEntry *buf = opaque; 348 AVBufferPool *pool = buf->pool; 349 350 ff_mutex_lock(&pool->mutex); 351 buf->next = pool->pool; 352 pool->pool = buf; 353 ff_mutex_unlock(&pool->mutex); 354 355 if (atomic_fetch_sub_explicit(&pool->refcount, 1, memory_order_acq_rel) == 1) 356 buffer_pool_free(pool); 357 } 358 359 /* allocate a new buffer and override its free() callback so that 360 * it is returned to the pool on free */ 361 static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool) 362 { 363 BufferPoolEntry *buf; 364 AVBufferRef *ret; 365 366 av_assert0(pool->alloc || pool->alloc2); 367 368 ret = pool->alloc2 ? pool->alloc2(pool->opaque, pool->size) : 369 pool->alloc(pool->size); 370 if (!ret) 371 return NULL; 372 373 buf = av_mallocz(sizeof(*buf)); 374 if (!buf) { 375 av_buffer_unref(&ret); 376 return NULL; 377 } 378 379 buf->data = ret->buffer->data; 380 buf->opaque = ret->buffer->opaque; 381 buf->free = ret->buffer->free; 382 buf->pool = pool; 383 384 ret->buffer->opaque = buf; 385 ret->buffer->free = pool_release_buffer; 386 387 return ret; 388 } 389 390 AVBufferRef *av_buffer_pool_get(AVBufferPool *pool) 391 { 392 AVBufferRef *ret; 393 BufferPoolEntry *buf; 394 395 ff_mutex_lock(&pool->mutex); 396 buf = pool->pool; 397 if (buf) { 398 memset(&buf->buffer, 0, sizeof(buf->buffer)); 399 ret = buffer_create(&buf->buffer, buf->data, pool->size, 400 pool_release_buffer, buf, 0); 401 if (ret) { 402 pool->pool = buf->next; 403 buf->next = NULL; 404 buf->buffer.flags_internal |= BUFFER_FLAG_NO_FREE; 405 } 406 } else { 407 ret = pool_alloc_buffer(pool); 408 } 409 ff_mutex_unlock(&pool->mutex); 410 411 if (ret) 412 atomic_fetch_add_explicit(&pool->refcount, 1, memory_order_relaxed); 413 414 return ret; 415 } 416 417 void *av_buffer_pool_buffer_get_opaque(const AVBufferRef *ref) 418 { 419 BufferPoolEntry *buf = ref->buffer->opaque; 420 av_assert0(buf); 421 return buf->opaque; 422 }