Move frame swapping logic to frame.c
Expose frames_offer_decoded_frame() and frames_consume_rendered_frame() so that callers are not exposed to frame swapping (between the decoding and rendering frames) details.
This commit is contained in:
parent
0d7f050389
commit
629c296207
4 changed files with 58 additions and 27 deletions
|
@ -21,24 +21,11 @@ static int read_packet(void *opaque, uint8_t *buf, int buf_size) {
|
||||||
|
|
||||||
// set the decoded frame as ready for rendering, and notify
|
// set the decoded frame as ready for rendering, and notify
|
||||||
static void push_frame(struct decoder *decoder) {
|
static void push_frame(struct decoder *decoder) {
|
||||||
struct frames *frames = decoder->frames;
|
SDL_bool previous_frame_consumed = frames_offer_decoded_frame(decoder->frames);
|
||||||
mutex_lock(frames->mutex);
|
if (!previous_frame_consumed) {
|
||||||
#ifndef SKIP_FRAMES
|
// the previous EVENT_NEW_FRAME will consume this frame
|
||||||
// if SKIP_FRAMES is disabled, then the decoder must wait for the current
|
return;
|
||||||
// frame to be consumed
|
|
||||||
while (!frames->rendering_frame_consumed) {
|
|
||||||
cond_wait(frames->rendering_frame_consumed_cond, frames->mutex);
|
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
if (!frames->rendering_frame_consumed) {
|
|
||||||
SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, "Skip frame");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
frames_swap(frames);
|
|
||||||
frames->rendering_frame_consumed = SDL_FALSE;
|
|
||||||
mutex_unlock(frames->mutex);
|
|
||||||
|
|
||||||
static SDL_Event new_frame_event = {
|
static SDL_Event new_frame_event = {
|
||||||
.type = EVENT_NEW_FRAME,
|
.type = EVENT_NEW_FRAME,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,9 +1,14 @@
|
||||||
#include "frames.h"
|
#include "frames.h"
|
||||||
|
|
||||||
|
#include <SDL2/SDL_assert.h>
|
||||||
|
#include <SDL2/SDL_log.h>
|
||||||
#include <SDL2/SDL_mutex.h>
|
#include <SDL2/SDL_mutex.h>
|
||||||
#include <libavutil/avutil.h>
|
#include <libavutil/avutil.h>
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
#include "lockutil.h"
|
||||||
|
|
||||||
SDL_bool frames_init(struct frames *frames) {
|
SDL_bool frames_init(struct frames *frames) {
|
||||||
if (!(frames->decoding_frame = av_frame_alloc())) {
|
if (!(frames->decoding_frame = av_frame_alloc())) {
|
||||||
goto error_0;
|
goto error_0;
|
||||||
|
@ -24,6 +29,8 @@ SDL_bool frames_init(struct frames *frames) {
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// there is initially no rendering frame, so consider it has already been
|
||||||
|
// consumed
|
||||||
frames->rendering_frame_consumed = SDL_TRUE;
|
frames->rendering_frame_consumed = SDL_TRUE;
|
||||||
|
|
||||||
return SDL_TRUE;
|
return SDL_TRUE;
|
||||||
|
@ -45,8 +52,43 @@ void frames_destroy(struct frames *frames) {
|
||||||
av_frame_free(&frames->decoding_frame);
|
av_frame_free(&frames->decoding_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void frames_swap(struct frames *frames) {
|
static void frames_swap(struct frames *frames) {
|
||||||
AVFrame *tmp = frames->decoding_frame;
|
AVFrame *tmp = frames->decoding_frame;
|
||||||
frames->decoding_frame = frames->rendering_frame;
|
frames->decoding_frame = frames->rendering_frame;
|
||||||
frames->rendering_frame = tmp;
|
frames->rendering_frame = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDL_bool frames_offer_decoded_frame(struct frames *frames) {
|
||||||
|
mutex_lock(frames->mutex);
|
||||||
|
SDL_bool previous_frame_consumed;
|
||||||
|
#ifndef SKIP_FRAMES
|
||||||
|
// if SKIP_FRAMES is disabled, then the decoder must wait for the current
|
||||||
|
// frame to be consumed
|
||||||
|
while (!frames->rendering_frame_consumed) {
|
||||||
|
cond_wait(frames->rendering_frame_consumed_cond, frames->mutex);
|
||||||
|
}
|
||||||
|
// by definition, we are not skipping the frames
|
||||||
|
previous_frame_consumed = SDL_TRUE;
|
||||||
|
#else
|
||||||
|
previous_frame_consumed = frames->rendering_frame_consumed;
|
||||||
|
if (!previous_frame_consumed) {
|
||||||
|
SDL_LogDebug(SDL_LOG_CATEGORY_RENDER, "Skip frame");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
frames_swap(frames);
|
||||||
|
frames->rendering_frame_consumed = SDL_FALSE;
|
||||||
|
mutex_unlock(frames->mutex);
|
||||||
|
return previous_frame_consumed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AVFrame *frames_consume_rendered_frame(struct frames *frames) {
|
||||||
|
SDL_assert(!frames->rendering_frame_consumed);
|
||||||
|
frames->rendering_frame_consumed = SDL_TRUE;
|
||||||
|
#ifndef SKIP_FRAMES
|
||||||
|
// if SKIP_FRAMES is disabled, then notify the decoder the current frame is
|
||||||
|
// consumed, so that it may push a new one
|
||||||
|
cond_signal(frames->rendering_frame_consumed_cond);
|
||||||
|
#endif
|
||||||
|
return frames->rendering_frame;
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,15 @@ struct frames {
|
||||||
SDL_bool frames_init(struct frames *frames);
|
SDL_bool frames_init(struct frames *frames);
|
||||||
void frames_destroy(struct frames *frames);
|
void frames_destroy(struct frames *frames);
|
||||||
|
|
||||||
void frames_swap(struct frames *frames);
|
// set the decoder frame as ready for rendering
|
||||||
|
// this function locks frames->mutex during its execution
|
||||||
|
// returns true if the previous frame had been consumed
|
||||||
|
SDL_bool frames_offer_decoded_frame(struct frames *frames);
|
||||||
|
|
||||||
|
// mark the rendering frame as consumed and return it
|
||||||
|
// MUST be called with frames->mutex locked!!!
|
||||||
|
// the caller is expected to render the returned frame to some texture before
|
||||||
|
// unlocking frames->mutex
|
||||||
|
const AVFrame *frames_consume_rendered_frame(struct frames *frames);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -48,14 +48,7 @@ static void count_frame(void) {
|
||||||
|
|
||||||
static SDL_bool handle_new_frame(void) {
|
static SDL_bool handle_new_frame(void) {
|
||||||
mutex_lock(frames.mutex);
|
mutex_lock(frames.mutex);
|
||||||
AVFrame *frame = frames.rendering_frame;
|
const AVFrame *frame = frames_consume_rendered_frame(&frames);
|
||||||
frames.rendering_frame_consumed = SDL_TRUE;
|
|
||||||
#ifndef SKIP_FRAMES
|
|
||||||
// if SKIP_FRAMES is disabled, then notify the decoder the current frame is
|
|
||||||
// consumed, so that it may push a new one
|
|
||||||
cond_signal(frames.rendering_frame_consumed_cond);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!screen_update(&screen, frame)){
|
if (!screen_update(&screen, frame)){
|
||||||
mutex_unlock(frames.mutex);
|
mutex_unlock(frames.mutex);
|
||||||
return SDL_FALSE;
|
return SDL_FALSE;
|
||||||
|
|
Loading…
Reference in a new issue