From 1a7f062503ee26e2fdd5ad4a0fdd934bb9688037 Mon Sep 17 00:00:00 2001 From: wm4 Date: Sun, 28 Jul 2013 00:11:15 +0200 Subject: lavc_dr1: make reference counting thread-safe See previous commits. This time, the lock is kept for rather long times (e.g. for the duration of a big image memory allocation), but this (probably) still doesn't matter at all. This also affects legacy code only (pre-refcounting libavcodec). --- video/decode/lavc_dr1.c | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-) diff --git a/video/decode/lavc_dr1.c b/video/decode/lavc_dr1.c index 85f70b0284..5dc73c3ea8 100644 --- a/video/decode/lavc_dr1.c +++ b/video/decode/lavc_dr1.c @@ -39,8 +39,20 @@ #include #include +#include "config.h" + #include "lavc.h" +#if HAVE_PTHREADS +#include +static pthread_mutex_t pool_mutex = PTHREAD_MUTEX_INITIALIZER; +#define pool_lock() pthread_mutex_lock(&pool_mutex) +#define pool_unlock() pthread_mutex_unlock(&pool_mutex) +#else +#define pool_lock() 0 +#define pool_unlock() 0 +#endif + typedef struct FramePool { struct FrameBuffer *list; // used to deal with frames that live past the time the pool should live @@ -142,16 +154,22 @@ int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame) return -1; } - if (!pool->list && (ret = alloc_buffer(pool, s)) < 0) + pool_lock(); + + if (!pool->list && (ret = alloc_buffer(pool, s)) < 0) { + pool_unlock(); return ret; + } buf = pool->list; if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) { pool->list = buf->next; av_freep(&buf->base[0]); av_free(buf); - if ((ret = alloc_buffer(pool, s)) < 0) + if ((ret = alloc_buffer(pool, s)) < 0) { + pool_unlock(); return ret; + } buf = pool->list; } av_assert0(!buf->refcount); @@ -160,6 +178,8 @@ int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame) pool->list = buf->next; pool->refcount++; + pool_unlock(); + frame->opaque = buf; frame->type = FF_BUFFER_TYPE_USER; frame->extended_data = frame->data; @@ -184,12 +204,17 @@ int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame) void mp_buffer_ref(struct FrameBuffer *buf) { + pool_lock(); buf->refcount++; + pool_unlock(); } void mp_buffer_unref(struct FrameBuffer *buf) { FramePool *pool = buf->pool; + bool pool_dead; + + pool_lock(); av_assert0(pool->refcount > 0); av_assert0(buf->refcount > 0); @@ -204,17 +229,23 @@ void mp_buffer_unref(struct FrameBuffer *buf) pool->refcount--; } - if (pool->dead && pool->refcount == 0) + pool_dead = pool->dead && pool->refcount == 0; + pool_unlock(); + + if (pool_dead) mp_buffer_pool_free(&pool); } bool mp_buffer_is_unique(struct FrameBuffer *buf) { - int refcount = buf->refcount; + int refcount; + pool_lock(); + refcount = buf->refcount; // Decoder has a reference, but doesn't want to use it. (ffmpeg has no good // way of transferring frame ownership to the user.) if (buf->used_by_decoder && !buf->needed_by_decoder) refcount--; + pool_unlock(); return refcount == 1; } @@ -242,6 +273,8 @@ void mp_buffer_pool_free(struct FramePool **p_pool) if (!pool) return; + pool_lock(); + while (pool->list) { FrameBuffer *buf = pool->list; pool->list = buf->next; @@ -253,5 +286,7 @@ void mp_buffer_pool_free(struct FramePool **p_pool) if (pool->refcount == 0) av_free(pool); + pool_unlock(); + *p_pool = NULL; } -- cgit v1.2.3