summaryrefslogtreecommitdiffstats
path: root/video/mp_image_pool.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-07-05 23:56:00 +0200
committerwm4 <wm4@nowhere>2015-07-05 23:56:00 +0200
commit7b9d72658898574f4b001bcc496bf3532d4b3cc5 (patch)
tree9feae56717daaf423375a21ff6af29915655b895 /video/mp_image_pool.c
parent34b223d730c97225accae4107a032c9b7ebf2194 (diff)
downloadmpv-7b9d72658898574f4b001bcc496bf3532d4b3cc5.tar.bz2
mpv-7b9d72658898574f4b001bcc496bf3532d4b3cc5.tar.xz
video: replace our own refcounting with libavutil's
mpv had refcounted frames before libav*, so we were not using libavutil's facilities. Change this and drop our own code. Since AVFrames are not actually refcounted, and only the image data they reference, the semantics change a bit. This affects mainly mp_image_pool, which was operating on whole images instead of buffers. While we could work on AVBufferRefs instead (and use AVBufferPool), this doesn't work for use with hardware decoding, which doesn't map cleanly to FFmpeg's reference counting. But it worked out. One weird consequence is that we still need our custom image data allocation function (for normal image data), because AVFrame's uses multiple buffers. There also seems to be a timing-dependent problem with vaapi (the pool appears to be "leaking" surfaces). I don't know if this is a new problem, or whether the code changes just happened to cause it more often. Raising the number of reserved surfaces seemed to fix it, but since it appears to be timing dependent, and I couldn't find anything wrong with the code, I'm just going to assume it's not a new bug.
Diffstat (limited to 'video/mp_image_pool.c')
-rw-r--r--video/mp_image_pool.c32
1 files changed, 29 insertions, 3 deletions
diff --git a/video/mp_image_pool.c b/video/mp_image_pool.c
index 173c018ec3..5992c631f9 100644
--- a/video/mp_image_pool.c
+++ b/video/mp_image_pool.c
@@ -22,6 +22,8 @@
#include <pthread.h>
#include <assert.h>
+#include <libavutil/buffer.h>
+
#include "talloc.h"
#include "common/common.h"
@@ -94,9 +96,9 @@ void mp_image_pool_clear(struct mp_image_pool *pool)
// This is the only function that is allowed to run in a different thread.
// (Consider passing an image to another thread, which frees it.)
-static void unref_image(void *ptr)
+static void unref_image(void *opaque, uint8_t *data)
{
- struct mp_image *img = ptr;
+ struct mp_image *img = opaque;
struct image_flags *it = img->priv;
bool alive;
pool_lock();
@@ -135,11 +137,31 @@ struct mp_image *mp_image_pool_get_no_alloc(struct mp_image_pool *pool, int fmt,
pool_unlock();
if (!new)
return NULL;
+
+ // Reference the new image. Since mp_image_pool is not declared thread-safe,
+ // and unreffing images from other threads does not allocate new images,
+ // no synchronization is required here.
+ for (int p = 0; p < MP_MAX_PLANES; p++)
+ assert(!!new->bufs[p] == !p); // only 1 AVBufferRef
+
+ struct mp_image *ref = mp_image_new_dummy_ref(new);
+
+ // This assumes the buffer is at this point exclusively owned by us: we
+ // can't track whether the buffer is unique otherwise.
+ // (av_buffer_is_writable() checks the refcount of the new buffer only.)
+ int flags = av_buffer_is_writable(new->bufs[0]) ? 0 : AV_BUFFER_FLAG_READONLY;
+ ref->bufs[0] = av_buffer_create(new->bufs[0]->data, new->bufs[0]->size,
+ unref_image, new, flags);
+ if (!ref->bufs[0]) {
+ talloc_free(ref);
+ return NULL;
+ }
+
struct image_flags *it = new->priv;
assert(!it->referenced && it->pool_alive);
it->referenced = true;
it->order = ++pool->lru_counter;
- return mp_image_new_custom_ref(new, new, unref_image);
+ return ref;
}
// Return a new image of given format/size. The only difference to
@@ -204,6 +226,10 @@ bool mp_image_pool_make_writeable(struct mp_image_pool *pool,
return true;
}
+// Call cb(cb_data, fmt, w, h) to allocate an image. Note that the resulting
+// image must use only 1 AVBufferRef. The returned image must also be owned
+// exclusively by the image pool, otherwise mp_image_is_writeable() will not
+// work due to FFmpeg restrictions.
void mp_image_pool_set_allocator(struct mp_image_pool *pool,
mp_image_allocator cb, void *cb_data)
{