mirror of https://github.com/mpv-player/mpv
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).
This commit is contained in:
parent
c28bafcfb6
commit
1a7f062503
|
@ -39,8 +39,20 @@
|
||||||
#include <libavutil/pixdesc.h>
|
#include <libavutil/pixdesc.h>
|
||||||
#include <libavutil/common.h>
|
#include <libavutil/common.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
#include "lavc.h"
|
#include "lavc.h"
|
||||||
|
|
||||||
|
#if HAVE_PTHREADS
|
||||||
|
#include <pthread.h>
|
||||||
|
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 {
|
typedef struct FramePool {
|
||||||
struct FrameBuffer *list;
|
struct FrameBuffer *list;
|
||||||
// used to deal with frames that live past the time the pool should live
|
// 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;
|
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;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
buf = pool->list;
|
buf = pool->list;
|
||||||
if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
|
if (buf->w != s->width || buf->h != s->height || buf->pix_fmt != s->pix_fmt) {
|
||||||
pool->list = buf->next;
|
pool->list = buf->next;
|
||||||
av_freep(&buf->base[0]);
|
av_freep(&buf->base[0]);
|
||||||
av_free(buf);
|
av_free(buf);
|
||||||
if ((ret = alloc_buffer(pool, s)) < 0)
|
if ((ret = alloc_buffer(pool, s)) < 0) {
|
||||||
|
pool_unlock();
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
buf = pool->list;
|
buf = pool->list;
|
||||||
}
|
}
|
||||||
av_assert0(!buf->refcount);
|
av_assert0(!buf->refcount);
|
||||||
|
@ -160,6 +178,8 @@ int mp_codec_get_buffer(AVCodecContext *s, AVFrame *frame)
|
||||||
pool->list = buf->next;
|
pool->list = buf->next;
|
||||||
pool->refcount++;
|
pool->refcount++;
|
||||||
|
|
||||||
|
pool_unlock();
|
||||||
|
|
||||||
frame->opaque = buf;
|
frame->opaque = buf;
|
||||||
frame->type = FF_BUFFER_TYPE_USER;
|
frame->type = FF_BUFFER_TYPE_USER;
|
||||||
frame->extended_data = frame->data;
|
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)
|
void mp_buffer_ref(struct FrameBuffer *buf)
|
||||||
{
|
{
|
||||||
|
pool_lock();
|
||||||
buf->refcount++;
|
buf->refcount++;
|
||||||
|
pool_unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void mp_buffer_unref(struct FrameBuffer *buf)
|
void mp_buffer_unref(struct FrameBuffer *buf)
|
||||||
{
|
{
|
||||||
FramePool *pool = buf->pool;
|
FramePool *pool = buf->pool;
|
||||||
|
bool pool_dead;
|
||||||
|
|
||||||
|
pool_lock();
|
||||||
|
|
||||||
av_assert0(pool->refcount > 0);
|
av_assert0(pool->refcount > 0);
|
||||||
av_assert0(buf->refcount > 0);
|
av_assert0(buf->refcount > 0);
|
||||||
|
@ -204,17 +229,23 @@ void mp_buffer_unref(struct FrameBuffer *buf)
|
||||||
pool->refcount--;
|
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);
|
mp_buffer_pool_free(&pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool mp_buffer_is_unique(struct FrameBuffer *buf)
|
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
|
// Decoder has a reference, but doesn't want to use it. (ffmpeg has no good
|
||||||
// way of transferring frame ownership to the user.)
|
// way of transferring frame ownership to the user.)
|
||||||
if (buf->used_by_decoder && !buf->needed_by_decoder)
|
if (buf->used_by_decoder && !buf->needed_by_decoder)
|
||||||
refcount--;
|
refcount--;
|
||||||
|
pool_unlock();
|
||||||
return refcount == 1;
|
return refcount == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,6 +273,8 @@ void mp_buffer_pool_free(struct FramePool **p_pool)
|
||||||
if (!pool)
|
if (!pool)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
pool_lock();
|
||||||
|
|
||||||
while (pool->list) {
|
while (pool->list) {
|
||||||
FrameBuffer *buf = pool->list;
|
FrameBuffer *buf = pool->list;
|
||||||
pool->list = buf->next;
|
pool->list = buf->next;
|
||||||
|
@ -253,5 +286,7 @@ void mp_buffer_pool_free(struct FramePool **p_pool)
|
||||||
if (pool->refcount == 0)
|
if (pool->refcount == 0)
|
||||||
av_free(pool);
|
av_free(pool);
|
||||||
|
|
||||||
|
pool_unlock();
|
||||||
|
|
||||||
*p_pool = NULL;
|
*p_pool = NULL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue