Use a callback to notify a new frame
Make the decoder independant of the SDL even mechanism, by making the consumer register a callback on the video_buffer.
This commit is contained in:
parent
c50b958ee4
commit
fb9f9848bd
4 changed files with 59 additions and 7 deletions
|
@ -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
|
||||
|
|
|
@ -191,12 +191,31 @@ screen_update_content_rect(struct screen *screen) {
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
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);
|
||||
}
|
||||
|
||||
void
|
||||
screen_init(struct screen *screen, struct video_buffer *vb,
|
||||
struct fps_counter *fps_counter) {
|
||||
*screen = (struct screen) SCREEN_INITIALIZER;
|
||||
screen->vb = vb;
|
||||
screen->fps_counter = fps_counter;
|
||||
|
||||
static const struct video_buffer_callbacks cbs = {
|
||||
.on_frame_available = on_frame_available,
|
||||
};
|
||||
|
||||
video_buffer_set_consumer_callbacks(vb, &cbs, NULL);
|
||||
}
|
||||
|
||||
static inline SDL_Texture *
|
||||
|
|
|
@ -43,6 +43,10 @@ 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;
|
||||
|
||||
// The callbacks must be set by the consumer via
|
||||
// video_buffer_set_consumer_callbacks()
|
||||
vb->cbs = NULL;
|
||||
|
||||
return true;
|
||||
|
||||
error_3:
|
||||
|
@ -82,9 +86,22 @@ video_buffer_swap_consumer_frame(struct video_buffer *vb) {
|
|||
vb->pending_frame = tmp;
|
||||
}
|
||||
|
||||
void
|
||||
video_buffer_set_consumer_callbacks(struct video_buffer *vb,
|
||||
const struct video_buffer_callbacks *cbs,
|
||||
void *cbs_userdata) {
|
||||
assert(!vb->cbs); // must be set only once
|
||||
assert(cbs);
|
||||
assert(cbs->on_frame_available);
|
||||
vb->cbs = cbs;
|
||||
vb->cbs_userdata = cbs_userdata;
|
||||
}
|
||||
|
||||
void
|
||||
video_buffer_producer_offer_frame(struct video_buffer *vb,
|
||||
bool *previous_frame_skipped) {
|
||||
assert(vb->cbs);
|
||||
|
||||
sc_mutex_lock(&vb->mutex);
|
||||
if (vb->wait_consumer) {
|
||||
// wait for the current (expired) frame to be consumed
|
||||
|
@ -95,10 +112,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 *
|
||||
|
|
|
@ -39,6 +39,16 @@ 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)
|
||||
// This callback is mandatory (it must not be NULL).
|
||||
void (*on_frame_available)(struct video_buffer *vb, void *userdata);
|
||||
};
|
||||
|
||||
bool
|
||||
|
@ -47,6 +57,11 @@ video_buffer_init(struct video_buffer *vb, bool wait_consumer);
|
|||
void
|
||||
video_buffer_destroy(struct video_buffer *vb);
|
||||
|
||||
void
|
||||
video_buffer_set_consumer_callbacks(struct video_buffer *vb,
|
||||
const struct video_buffer_callbacks *cbs,
|
||||
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
|
||||
|
|
Loading…
Reference in a new issue