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.
This commit is contained in:
Romain Vimont 2021-02-19 22:02:36 +01:00
parent 72df2c23f9
commit b1c7c71160
4 changed files with 46 additions and 10 deletions

View File

@ -19,13 +19,7 @@ push_frame(struct decoder *decoder) {
&previous_frame_skipped); &previous_frame_skipped);
if (previous_frame_skipped) { if (previous_frame_skipped) {
fps_counter_add_skipped_frame(decoder->fps_counter); 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 void

View File

@ -267,6 +267,19 @@ av_log_callback(void *avcl, int level, const char *fmt, va_list vl) {
free(local_fmt); 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 bool
scrcpy(const struct scrcpy_options *options) { scrcpy(const struct scrcpy_options *options) {
if (!server_init(&server)) { if (!server_init(&server)) {
@ -333,7 +346,12 @@ scrcpy(const struct scrcpy_options *options) {
} }
fps_counter_initialized = true; 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; goto end;
} }
video_buffer_initialized = true; video_buffer_initialized = true;

View File

@ -7,7 +7,9 @@
#include "util/log.h" #include "util/log.h"
bool 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(); vb->producer_frame = av_frame_alloc();
if (!vb->producer_frame) { if (!vb->producer_frame) {
goto error_0; 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 // there is initially no frame, so consider it has already been consumed
vb->pending_frame_consumed = true; vb->pending_frame_consumed = true;
assert(cbs);
assert(cbs->on_frame_available);
vb->cbs = cbs;
vb->cbs_userdata = cbs_userdata;
return true; return true;
error_3: error_3:
@ -95,10 +102,17 @@ video_buffer_producer_offer_frame(struct video_buffer *vb,
video_buffer_swap_producer_frame(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; vb->pending_frame_consumed = false;
sc_mutex_unlock(&vb->mutex); 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 * const AVFrame *

View File

@ -39,10 +39,20 @@ struct video_buffer {
sc_cond pending_frame_consumed_cond; sc_cond pending_frame_consumed_cond;
bool pending_frame_consumed; 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 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 void
video_buffer_destroy(struct video_buffer *vb); video_buffer_destroy(struct video_buffer *vb);