From 6627459cc5de0d9c972dbeb702d07e8efa098092 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Fri, 19 Feb 2021 22:31:44 +0100 Subject: [PATCH] Expose skipped frames to the consumer A skipped frame is detected when the producer offers a frame while the current pending frame has not been consumed. However, the producer (in practice the decoder) is not interested in the fact that a frame has been skipped, only the consumer (the renderer) is. Therefore, expose the skipped count in consumer_take_frame() instead of a flag in the producer_offer_frame(). This allows to manage the skipped and rendered frames count at the same place, and remove fps_counter from decoder. --- app/src/decoder.c | 11 ++--------- app/src/decoder.h | 5 +---- app/src/fps_counter.c | 4 ++-- app/src/fps_counter.h | 2 +- app/src/scrcpy.c | 2 +- app/src/screen.c | 5 ++++- app/src/video_buffer.c | 18 ++++++++++++++---- app/src/video_buffer.h | 10 ++++++---- 8 files changed, 31 insertions(+), 26 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index f9a997b0..99119aa6 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -14,19 +14,12 @@ // set the decoded frame as ready for rendering, and notify static void push_frame(struct decoder *decoder) { - bool previous_frame_skipped; - video_buffer_producer_offer_frame(decoder->video_buffer, - &previous_frame_skipped); - if (previous_frame_skipped) { - fps_counter_add_skipped_frame(decoder->fps_counter); - } + video_buffer_producer_offer_frame(decoder->video_buffer); } void -decoder_init(struct decoder *decoder, struct video_buffer *vb, - struct fps_counter *fps_counter) { +decoder_init(struct decoder *decoder, struct video_buffer *vb) { decoder->video_buffer = vb; - decoder->fps_counter = fps_counter; } bool diff --git a/app/src/decoder.h b/app/src/decoder.h index 306cc77c..27afcd8e 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -10,14 +10,11 @@ struct video_buffer; struct decoder { struct video_buffer *video_buffer; - struct fps_counter *fps_counter; - AVCodecContext *codec_ctx; }; void -decoder_init(struct decoder *decoder, struct video_buffer *vb, - struct fps_counter *fps_counter); +decoder_init(struct decoder *decoder, struct video_buffer *vb); bool decoder_open(struct decoder *decoder, const AVCodec *codec); diff --git a/app/src/fps_counter.c b/app/src/fps_counter.c index 281c58cf..939be2be 100644 --- a/app/src/fps_counter.c +++ b/app/src/fps_counter.c @@ -168,7 +168,7 @@ fps_counter_add_rendered_frame(struct fps_counter *counter) { } void -fps_counter_add_skipped_frame(struct fps_counter *counter) { +fps_counter_add_skipped_frames(struct fps_counter *counter, unsigned n) { if (!is_started(counter)) { return; } @@ -176,6 +176,6 @@ fps_counter_add_skipped_frame(struct fps_counter *counter) { sc_mutex_lock(&counter->mutex); uint32_t now = SDL_GetTicks(); check_interval_expired(counter, now); - ++counter->nr_skipped; + counter->nr_skipped += n; sc_mutex_unlock(&counter->mutex); } diff --git a/app/src/fps_counter.h b/app/src/fps_counter.h index de252586..9ce3b878 100644 --- a/app/src/fps_counter.h +++ b/app/src/fps_counter.h @@ -54,6 +54,6 @@ void fps_counter_add_rendered_frame(struct fps_counter *counter); void -fps_counter_add_skipped_frame(struct fps_counter *counter); +fps_counter_add_skipped_frames(struct fps_counter *counter, unsigned n); #endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index 31d58910..567b17e7 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -364,7 +364,7 @@ scrcpy(const struct scrcpy_options *options) { file_handler_initialized = true; } - decoder_init(&decoder, &video_buffer, &fps_counter); + decoder_init(&decoder, &video_buffer); dec = &decoder; } diff --git a/app/src/screen.c b/app/src/screen.c index 31dab89c..5e757c9d 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -453,8 +453,11 @@ update_texture(struct screen *screen, const AVFrame *frame) { static bool screen_update_frame(struct screen *screen) { - const AVFrame *frame = video_buffer_consumer_take_frame(screen->vb); + unsigned skipped; + const AVFrame *frame = + video_buffer_consumer_take_frame(screen->vb, &skipped); + fps_counter_add_skipped_frames(screen->fps_counter, skipped); fps_counter_add_rendered_frame(screen->fps_counter); struct size new_frame_size = {frame->width, frame->height}; diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index 05555254..70d6e07d 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -45,6 +45,8 @@ 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; + vb->skipped = 0; + assert(cbs); assert(cbs->on_frame_available); vb->cbs = cbs; @@ -90,8 +92,7 @@ video_buffer_swap_consumer_frame(struct video_buffer *vb) { } void -video_buffer_producer_offer_frame(struct video_buffer *vb, - bool *previous_frame_skipped) { +video_buffer_producer_offer_frame(struct video_buffer *vb) { sc_mutex_lock(&vb->mutex); if (vb->wait_consumer) { // wait for the current (expired) frame to be consumed @@ -103,7 +104,10 @@ video_buffer_producer_offer_frame(struct video_buffer *vb, video_buffer_swap_producer_frame(vb); bool skipped = !vb->pending_frame_consumed; - *previous_frame_skipped = skipped; + if (skipped) { + ++vb->skipped; + } + vb->pending_frame_consumed = false; sc_mutex_unlock(&vb->mutex); @@ -116,7 +120,7 @@ video_buffer_producer_offer_frame(struct video_buffer *vb, } const AVFrame * -video_buffer_consumer_take_frame(struct video_buffer *vb) { +video_buffer_consumer_take_frame(struct video_buffer *vb, unsigned *skipped) { sc_mutex_lock(&vb->mutex); assert(!vb->pending_frame_consumed); vb->pending_frame_consumed = true; @@ -127,6 +131,12 @@ video_buffer_consumer_take_frame(struct video_buffer *vb) { // unblock video_buffer_offer_decoded_frame() sc_cond_signal(&vb->pending_frame_consumed_cond); } + + if (skipped) { + *skipped = vb->skipped; + } + vb->skipped = 0; // reset + sc_mutex_unlock(&vb->mutex); // consumer_frame is only written from this thread, no need to lock diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index ae78b095..96456f32 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -40,6 +40,8 @@ struct video_buffer { sc_cond pending_frame_consumed_cond; bool pending_frame_consumed; + unsigned skipped; + const struct video_buffer_callbacks *cbs; void *cbs_userdata; }; @@ -58,15 +60,15 @@ void video_buffer_destroy(struct video_buffer *vb); // set the producer frame as ready for consuming -// the output flag is set to report whether the previous frame has been skipped void -video_buffer_producer_offer_frame(struct video_buffer *vb, - bool *previous_frame_skipped); +video_buffer_producer_offer_frame(struct video_buffer *vb); // mark the consumer frame as consumed and return it // the frame is valid until the next call to this function +// the output parameter "skipped" indicates how many produced frames have been +// skipped const AVFrame * -video_buffer_consumer_take_frame(struct video_buffer *vb); +video_buffer_consumer_take_frame(struct video_buffer *vb, unsigned *skipped); // wake up and avoid any blocking call void