From b1c7c71160d243dfc3d2dfc8683dbca9adf3294b Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 19 Feb 2021 22:02:36 +0100 Subject: [PATCH] Use a callback to notify a new frame Make the decoder independant of the SDL even mechanism, by registering a callback on the video_buffer. --- app/src/decoder.c | 6 ------ app/src/scrcpy.c | 20 +++++++++++++++++++- app/src/video_buffer.c | 18 ++++++++++++++++-- app/src/video_buffer.h | 12 +++++++++++- 4 files changed, 46 insertions(+), 10 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 7eb2ae0c..f9a997b0 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -19,13 +19,7 @@ push_frame(struct decoder *decoder) { &previous_frame_skipped); if (previous_frame_skipped) { fps_counter_add_skipped_frame(decoder->fps_counter); - // the previous EVENT_NEW_FRAME will consume this frame - return; } - static SDL_Event new_frame_event = { - .type = EVENT_NEW_FRAME, - }; - SDL_PushEvent(&new_frame_event); } void diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index a671c5e4..31d58910 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -267,6 +267,19 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) { free(local_fmt); } +static void +video_buffer_on_frame_available(struct video_buffer *vb, void *userdata) { + (void) vb; + (void) userdata; + + static SDL_Event new_frame_event = { + .type = EVENT_NEW_FRAME, + }; + + // Post the event on the UI thread + SDL_PushEvent(&new_frame_event); +} + bool scrcpy(const struct scrcpy_options *options) { if (!server_init(&server)) { @@ -333,7 +346,12 @@ scrcpy(const struct scrcpy_options *options) { } fps_counter_initialized = true; - if (!video_buffer_init(&video_buffer, options->render_expired_frames)) { + static const struct video_buffer_callbacks video_buffer_cbs = { + .on_frame_available = video_buffer_on_frame_available, + }; + + if (!video_buffer_init(&video_buffer, options->render_expired_frames, + &video_buffer_cbs, NULL)) { goto end; } video_buffer_initialized = true; diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index e7e150a2..05555254 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -7,7 +7,9 @@ #include "util/log.h" bool -video_buffer_init(struct video_buffer *vb, bool wait_consumer) { +video_buffer_init(struct video_buffer *vb, bool wait_consumer, + const struct video_buffer_callbacks *cbs, + void *cbs_userdata) { vb->producer_frame = av_frame_alloc(); if (!vb->producer_frame) { goto error_0; @@ -43,6 +45,11 @@ video_buffer_init(struct video_buffer *vb, bool wait_consumer) { // there is initially no frame, so consider it has already been consumed vb->pending_frame_consumed = true; + assert(cbs); + assert(cbs->on_frame_available); + vb->cbs = cbs; + vb->cbs_userdata = cbs_userdata; + return true; error_3: @@ -95,10 +102,17 @@ video_buffer_producer_offer_frame(struct video_buffer *vb, video_buffer_swap_producer_frame(vb); - *previous_frame_skipped = !vb->pending_frame_consumed; + bool skipped = !vb->pending_frame_consumed; + *previous_frame_skipped = skipped; vb->pending_frame_consumed = false; sc_mutex_unlock(&vb->mutex); + + if (!skipped) { + // If skipped, then the previous call will consume this frame, the + // callback must not be called + vb->cbs->on_frame_available(vb, vb->cbs_userdata); + } } const AVFrame * diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index 6c5d197c..ae78b095 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -39,10 +39,20 @@ struct video_buffer { sc_cond pending_frame_consumed_cond; bool pending_frame_consumed; + + const struct video_buffer_callbacks *cbs; + void *cbs_userdata; +}; + +struct video_buffer_callbacks { + // Called when a new frame can be consumed by + // video_buffer_consumer_take_frame(vb) + void (*on_frame_available)(struct video_buffer *vb, void *userdata); }; bool -video_buffer_init(struct video_buffer *vb, bool wait_consumer); +video_buffer_init(struct video_buffer *vb, bool wait_consumer, + const struct video_buffer_callbacks *cbs, void *cbs_userdata); void video_buffer_destroy(struct video_buffer *vb);