From cb9c42bdcb198b0e3ebed893e00257b95f4dcedb Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Tue, 23 Feb 2021 19:59:43 +0100 Subject: [PATCH] Use a callback to notify frame skip 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, notify frame skip via a consumer callback. This allows to manage the skipped and rendered frames count at the same place, and remove fps_counter from decoder. --- app/src/decoder.c | 17 ++--------------- app/src/decoder.h | 4 +--- app/src/scrcpy.c | 2 +- app/src/screen.c | 11 ++++++++++- app/src/video_buffer.c | 11 +++++------ app/src/video_buffer.h | 8 +++++--- 6 files changed, 24 insertions(+), 29 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 7b016d21..7da959c6 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -11,22 +11,9 @@ #include "util/buffer_util.h" #include "util/log.h" -// 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); - } -} - 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 @@ -66,7 +53,7 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) { decoder->video_buffer->producer_frame); if (!ret) { // a frame was received - push_frame(decoder); + video_buffer_producer_offer_frame(decoder->video_buffer); } else if (ret != AVERROR(EAGAIN)) { LOGE("Could not receive video frame: %d", ret); return false; diff --git a/app/src/decoder.h b/app/src/decoder.h index 306cc77c..bbd7a9a7 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -10,14 +10,12 @@ 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/scrcpy.c b/app/src/scrcpy.c index f3bfecfb..e7879d5b 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -346,7 +346,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 397aa2d1..bcccdd32 100644 --- a/app/src/screen.c +++ b/app/src/screen.c @@ -204,6 +204,14 @@ on_frame_available(struct video_buffer *vb, void *userdata) { SDL_PushEvent(&new_frame_event); } +static void +on_frame_skipped(struct video_buffer *vb, void *userdata) { + (void) vb; + + struct screen *screen = userdata; + fps_counter_add_skipped_frame(screen->fps_counter); +} + void screen_init(struct screen *screen, struct video_buffer *vb, struct fps_counter *fps_counter) { @@ -213,9 +221,10 @@ screen_init(struct screen *screen, struct video_buffer *vb, static const struct video_buffer_callbacks cbs = { .on_frame_available = on_frame_available, + .on_frame_skipped = on_frame_skipped, }; - video_buffer_set_consumer_callbacks(vb, &cbs, NULL); + video_buffer_set_consumer_callbacks(vb, &cbs, screen); } static inline SDL_Texture * diff --git a/app/src/video_buffer.c b/app/src/video_buffer.c index c145de08..3ebffa7e 100644 --- a/app/src/video_buffer.c +++ b/app/src/video_buffer.c @@ -98,8 +98,7 @@ video_buffer_set_consumer_callbacks(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) { assert(vb->cbs); sc_mutex_lock(&vb->mutex); @@ -113,14 +112,14 @@ 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; 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 + if (skipped) { + if (vb->cbs->on_frame_skipped) + vb->cbs->on_frame_skipped(vb, vb->cbs_userdata); + } else { vb->cbs->on_frame_available(vb, vb->cbs_userdata); } } diff --git a/app/src/video_buffer.h b/app/src/video_buffer.h index a41521a3..4d11e3ab 100644 --- a/app/src/video_buffer.h +++ b/app/src/video_buffer.h @@ -49,6 +49,10 @@ struct video_buffer_callbacks { // video_buffer_consumer_take_frame(vb) // This callback is mandatory (it must not be NULL). void (*on_frame_available)(struct video_buffer *vb, void *userdata); + + // Called when a pending frame has been overwritten by the producer + // This callback is optional (it may be NULL). + void (*on_frame_skipped)(struct video_buffer *vb, void *userdata); }; bool @@ -63,10 +67,8 @@ video_buffer_set_consumer_callbacks(struct video_buffer *vb, void *cbs_userdata); // 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