summaryrefslogtreecommitdiffstats
path: root/video/out/dr_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/dr_helper.c')
-rw-r--r--video/out/dr_helper.c36
1 files changed, 33 insertions, 3 deletions
diff --git a/video/out/dr_helper.c b/video/out/dr_helper.c
index e826d08dc4..78d4633efb 100644
--- a/video/out/dr_helper.c
+++ b/video/out/dr_helper.c
@@ -12,7 +12,10 @@
#include "dr_helper.h"
struct dr_helper {
+ pthread_mutex_t thread_lock;
pthread_t thread;
+ bool thread_valid; // (POSIX defines no "unset" pthread_t value yet)
+
struct mp_dispatch_queue *dispatch;
atomic_ullong dr_in_flight;
@@ -28,6 +31,8 @@ static void dr_helper_destroy(void *ptr)
// All references must have been freed on destruction, or we'll have
// dangling pointers.
assert(atomic_load(&dr->dr_in_flight) == 0);
+
+ pthread_mutex_destroy(&dr->thread_lock);
}
struct dr_helper *dr_helper_create(struct mp_dispatch_queue *dispatch,
@@ -38,15 +43,34 @@ struct dr_helper *dr_helper_create(struct mp_dispatch_queue *dispatch,
struct dr_helper *dr = talloc_ptrtype(NULL, dr);
talloc_set_destructor(dr, dr_helper_destroy);
*dr = (struct dr_helper){
- .thread = pthread_self(),
.dispatch = dispatch,
.dr_in_flight = ATOMIC_VAR_INIT(0),
.get_image = get_image,
.get_image_ctx = get_image_ctx,
};
+ pthread_mutex_init(&dr->thread_lock, NULL);
return dr;
}
+void dr_helper_acquire_thread(struct dr_helper *dr)
+{
+ pthread_mutex_lock(&dr->thread_lock);
+ assert(!dr->thread_valid); // fails on API user errors
+ dr->thread_valid = true;
+ dr->thread = pthread_self();
+ pthread_mutex_unlock(&dr->thread_lock);
+}
+
+void dr_helper_release_thread(struct dr_helper *dr)
+{
+ pthread_mutex_lock(&dr->thread_lock);
+ // Fails on API user errors.
+ assert(dr->thread_valid);
+ assert(pthread_equal(dr->thread, pthread_self()));
+ dr->thread_valid = false;
+ pthread_mutex_unlock(&dr->thread_lock);
+}
+
struct free_dr_context {
struct dr_helper *dr;
AVBufferRef *ref;
@@ -66,13 +90,19 @@ static void dr_thread_free(void *ptr)
static void free_dr_buffer_on_dr_thread(void *opaque, uint8_t *data)
{
struct free_dr_context *ctx = opaque;
+ struct dr_helper *dr = ctx->dr;
+
+ pthread_mutex_lock(&dr->thread_lock);
+ bool on_this_thread =
+ dr->thread_valid && pthread_equal(ctx->dr->thread, pthread_self());
+ pthread_mutex_unlock(&dr->thread_lock);
// The image could be unreffed even on the DR thread. In practice, this
// matters most on DR destruction.
- if (pthread_equal(ctx->dr->thread, pthread_self())) {
+ if (on_this_thread) {
dr_thread_free(ctx);
} else {
- mp_dispatch_run(ctx->dr->dispatch, dr_thread_free, ctx);
+ mp_dispatch_enqueue(dr->dispatch, dr_thread_free, ctx);
}
}