You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

393 lines
9.1KB

  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. #include <stdint.h>
  19. #include <string.h>
  20. #include "atomic.h"
  21. #include "buffer_internal.h"
  22. #include "common.h"
  23. #include "mem.h"
  24. #include "thread.h"
  25. #define USE_ATOMICS !(HAVE_PTHREADS || HAVE_W32THREADS)
  26. AVBufferRef *av_buffer_create(uint8_t *data, int size,
  27. void (*free)(void *opaque, uint8_t *data),
  28. void *opaque, int flags)
  29. {
  30. AVBufferRef *ref = NULL;
  31. AVBuffer *buf = NULL;
  32. buf = av_mallocz(sizeof(*buf));
  33. if (!buf)
  34. return NULL;
  35. buf->data = data;
  36. buf->size = size;
  37. buf->free = free ? free : av_buffer_default_free;
  38. buf->opaque = opaque;
  39. buf->refcount = 1;
  40. if (flags & AV_BUFFER_FLAG_READONLY)
  41. buf->flags |= BUFFER_FLAG_READONLY;
  42. ref = av_mallocz(sizeof(*ref));
  43. if (!ref) {
  44. av_freep(&buf);
  45. return NULL;
  46. }
  47. ref->buffer = buf;
  48. ref->data = data;
  49. ref->size = size;
  50. return ref;
  51. }
  52. void av_buffer_default_free(void *opaque, uint8_t *data)
  53. {
  54. av_free(data);
  55. }
  56. AVBufferRef *av_buffer_alloc(int size)
  57. {
  58. AVBufferRef *ret = NULL;
  59. uint8_t *data = NULL;
  60. data = av_malloc(size);
  61. if (!data)
  62. return NULL;
  63. ret = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
  64. if (!ret)
  65. av_freep(&data);
  66. return ret;
  67. }
  68. AVBufferRef *av_buffer_allocz(int size)
  69. {
  70. AVBufferRef *ret = av_buffer_alloc(size);
  71. if (!ret)
  72. return NULL;
  73. memset(ret->data, 0, size);
  74. return ret;
  75. }
  76. AVBufferRef *av_buffer_ref(AVBufferRef *buf)
  77. {
  78. AVBufferRef *ret = av_mallocz(sizeof(*ret));
  79. if (!ret)
  80. return NULL;
  81. *ret = *buf;
  82. avpriv_atomic_int_add_and_fetch(&buf->buffer->refcount, 1);
  83. return ret;
  84. }
  85. void av_buffer_unref(AVBufferRef **buf)
  86. {
  87. AVBuffer *b;
  88. if (!buf || !*buf)
  89. return;
  90. b = (*buf)->buffer;
  91. av_freep(buf);
  92. if (!avpriv_atomic_int_add_and_fetch(&b->refcount, -1)) {
  93. b->free(b->opaque, b->data);
  94. av_freep(&b);
  95. }
  96. }
  97. int av_buffer_is_writable(const AVBufferRef *buf)
  98. {
  99. if (buf->buffer->flags & AV_BUFFER_FLAG_READONLY)
  100. return 0;
  101. return avpriv_atomic_int_get(&buf->buffer->refcount) == 1;
  102. }
  103. void *av_buffer_get_opaque(const AVBufferRef *buf)
  104. {
  105. return buf->buffer->opaque;
  106. }
  107. int av_buffer_get_ref_count(const AVBufferRef *buf)
  108. {
  109. return buf->buffer->refcount;
  110. }
  111. int av_buffer_make_writable(AVBufferRef **pbuf)
  112. {
  113. AVBufferRef *newbuf, *buf = *pbuf;
  114. if (av_buffer_is_writable(buf))
  115. return 0;
  116. newbuf = av_buffer_alloc(buf->size);
  117. if (!newbuf)
  118. return AVERROR(ENOMEM);
  119. memcpy(newbuf->data, buf->data, buf->size);
  120. av_buffer_unref(pbuf);
  121. *pbuf = newbuf;
  122. return 0;
  123. }
  124. int av_buffer_realloc(AVBufferRef **pbuf, int size)
  125. {
  126. AVBufferRef *buf = *pbuf;
  127. uint8_t *tmp;
  128. if (!buf) {
  129. /* allocate a new buffer with av_realloc(), so it will be reallocatable
  130. * later */
  131. uint8_t *data = av_realloc(NULL, size);
  132. if (!data)
  133. return AVERROR(ENOMEM);
  134. buf = av_buffer_create(data, size, av_buffer_default_free, NULL, 0);
  135. if (!buf) {
  136. av_freep(&data);
  137. return AVERROR(ENOMEM);
  138. }
  139. buf->buffer->flags |= BUFFER_FLAG_REALLOCATABLE;
  140. *pbuf = buf;
  141. return 0;
  142. } else if (buf->size == size)
  143. return 0;
  144. if (!(buf->buffer->flags & BUFFER_FLAG_REALLOCATABLE) ||
  145. !av_buffer_is_writable(buf)) {
  146. /* cannot realloc, allocate a new reallocable buffer and copy data */
  147. AVBufferRef *new = NULL;
  148. av_buffer_realloc(&new, size);
  149. if (!new)
  150. return AVERROR(ENOMEM);
  151. memcpy(new->data, buf->data, FFMIN(size, buf->size));
  152. av_buffer_unref(pbuf);
  153. *pbuf = new;
  154. return 0;
  155. }
  156. tmp = av_realloc(buf->buffer->data, size);
  157. if (!tmp)
  158. return AVERROR(ENOMEM);
  159. buf->buffer->data = buf->data = tmp;
  160. buf->buffer->size = buf->size = size;
  161. return 0;
  162. }
  163. AVBufferPool *av_buffer_pool_init(int size, AVBufferRef* (*alloc)(int size))
  164. {
  165. AVBufferPool *pool = av_mallocz(sizeof(*pool));
  166. if (!pool)
  167. return NULL;
  168. ff_mutex_init(&pool->mutex, NULL);
  169. pool->size = size;
  170. pool->alloc = alloc ? alloc : av_buffer_alloc;
  171. avpriv_atomic_int_set(&pool->refcount, 1);
  172. return pool;
  173. }
  174. /*
  175. * This function gets called when the pool has been uninited and
  176. * all the buffers returned to it.
  177. */
  178. static void buffer_pool_free(AVBufferPool *pool)
  179. {
  180. while (pool->pool) {
  181. BufferPoolEntry *buf = pool->pool;
  182. pool->pool = buf->next;
  183. buf->free(buf->opaque, buf->data);
  184. av_freep(&buf);
  185. }
  186. ff_mutex_destroy(&pool->mutex);
  187. av_freep(&pool);
  188. }
  189. void av_buffer_pool_uninit(AVBufferPool **ppool)
  190. {
  191. AVBufferPool *pool;
  192. if (!ppool || !*ppool)
  193. return;
  194. pool = *ppool;
  195. *ppool = NULL;
  196. if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
  197. buffer_pool_free(pool);
  198. }
  199. /* remove the whole buffer list from the pool and return it */
  200. static BufferPoolEntry *get_pool(AVBufferPool *pool)
  201. {
  202. BufferPoolEntry *cur = *(void * volatile *)&pool->pool, *last = NULL;
  203. while (cur != last) {
  204. last = cur;
  205. cur = avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, last, NULL);
  206. if (!cur)
  207. return NULL;
  208. }
  209. return cur;
  210. }
  211. static void add_to_pool(BufferPoolEntry *buf)
  212. {
  213. AVBufferPool *pool;
  214. BufferPoolEntry *cur, *end = buf;
  215. if (!buf)
  216. return;
  217. pool = buf->pool;
  218. while (end->next)
  219. end = end->next;
  220. while (avpriv_atomic_ptr_cas((void * volatile *)&pool->pool, NULL, buf)) {
  221. /* pool is not empty, retrieve it and append it to our list */
  222. cur = get_pool(pool);
  223. end->next = cur;
  224. while (end->next)
  225. end = end->next;
  226. }
  227. }
  228. static void pool_release_buffer(void *opaque, uint8_t *data)
  229. {
  230. BufferPoolEntry *buf = opaque;
  231. AVBufferPool *pool = buf->pool;
  232. if(CONFIG_MEMORY_POISONING)
  233. memset(buf->data, FF_MEMORY_POISON, pool->size);
  234. #if USE_ATOMICS
  235. add_to_pool(buf);
  236. #else
  237. ff_mutex_lock(&pool->mutex);
  238. buf->next = pool->pool;
  239. pool->pool = buf;
  240. ff_mutex_unlock(&pool->mutex);
  241. #endif
  242. if (!avpriv_atomic_int_add_and_fetch(&pool->refcount, -1))
  243. buffer_pool_free(pool);
  244. }
  245. /* allocate a new buffer and override its free() callback so that
  246. * it is returned to the pool on free */
  247. static AVBufferRef *pool_alloc_buffer(AVBufferPool *pool)
  248. {
  249. BufferPoolEntry *buf;
  250. AVBufferRef *ret;
  251. ret = pool->alloc(pool->size);
  252. if (!ret)
  253. return NULL;
  254. buf = av_mallocz(sizeof(*buf));
  255. if (!buf) {
  256. av_buffer_unref(&ret);
  257. return NULL;
  258. }
  259. buf->data = ret->buffer->data;
  260. buf->opaque = ret->buffer->opaque;
  261. buf->free = ret->buffer->free;
  262. buf->pool = pool;
  263. ret->buffer->opaque = buf;
  264. ret->buffer->free = pool_release_buffer;
  265. #if USE_ATOMICS
  266. avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
  267. avpriv_atomic_int_add_and_fetch(&pool->nb_allocated, 1);
  268. #endif
  269. return ret;
  270. }
  271. AVBufferRef *av_buffer_pool_get(AVBufferPool *pool)
  272. {
  273. AVBufferRef *ret;
  274. BufferPoolEntry *buf;
  275. #if USE_ATOMICS
  276. /* check whether the pool is empty */
  277. buf = get_pool(pool);
  278. if (!buf && pool->refcount <= pool->nb_allocated) {
  279. av_log(NULL, AV_LOG_DEBUG, "Pool race dectected, spining to avoid overallocation and eventual OOM\n");
  280. while (!buf && avpriv_atomic_int_get(&pool->refcount) <= avpriv_atomic_int_get(&pool->nb_allocated))
  281. buf = get_pool(pool);
  282. }
  283. if (!buf)
  284. return pool_alloc_buffer(pool);
  285. /* keep the first entry, return the rest of the list to the pool */
  286. add_to_pool(buf->next);
  287. buf->next = NULL;
  288. ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
  289. buf, 0);
  290. if (!ret) {
  291. add_to_pool(buf);
  292. return NULL;
  293. }
  294. #else
  295. ff_mutex_lock(&pool->mutex);
  296. buf = pool->pool;
  297. if (buf) {
  298. ret = av_buffer_create(buf->data, pool->size, pool_release_buffer,
  299. buf, 0);
  300. if (ret) {
  301. pool->pool = buf->next;
  302. buf->next = NULL;
  303. }
  304. } else {
  305. ret = pool_alloc_buffer(pool);
  306. }
  307. ff_mutex_unlock(&pool->mutex);
  308. #endif
  309. if (ret)
  310. avpriv_atomic_int_add_and_fetch(&pool->refcount, 1);
  311. return ret;
  312. }