diff options
Diffstat (limited to 'video/out/dr_helper.c')
-rw-r--r-- | video/out/dr_helper.c | 36 |
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); } } |