2019-03-02 22:16:55 +08:00
|
|
|
#include "video_buffer.h"
|
|
|
|
|
|
|
|
#include <SDL2/SDL_assert.h>
|
|
|
|
#include <SDL2/SDL_mutex.h>
|
|
|
|
#include <libavutil/avutil.h>
|
|
|
|
#include <libavformat/avformat.h>
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
#include "lock_util.h"
|
|
|
|
#include "log.h"
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
bool
|
2019-03-03 03:09:56 +08:00
|
|
|
video_buffer_init(struct video_buffer *vb) {
|
2019-03-02 22:16:55 +08:00
|
|
|
if (!(vb->decoding_frame = av_frame_alloc())) {
|
|
|
|
goto error_0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(vb->rendering_frame = av_frame_alloc())) {
|
|
|
|
goto error_1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!(vb->mutex = SDL_CreateMutex())) {
|
|
|
|
goto error_2;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef SKIP_FRAMES
|
|
|
|
if (!(vb->rendering_frame_consumed_cond = SDL_CreateCond())) {
|
|
|
|
SDL_DestroyMutex(vb->mutex);
|
|
|
|
goto error_2;
|
|
|
|
}
|
2019-03-03 06:52:22 +08:00
|
|
|
vb->interrupted = false;
|
2019-03-02 22:16:55 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
// there is initially no rendering frame, so consider it has already been
|
|
|
|
// consumed
|
2019-03-03 06:52:22 +08:00
|
|
|
vb->rendering_frame_consumed = true;
|
2019-03-02 22:16:55 +08:00
|
|
|
fps_counter_init(&vb->fps_counter);
|
|
|
|
|
2019-03-03 06:52:22 +08:00
|
|
|
return true;
|
2019-03-02 22:16:55 +08:00
|
|
|
|
|
|
|
error_2:
|
|
|
|
av_frame_free(&vb->rendering_frame);
|
|
|
|
error_1:
|
|
|
|
av_frame_free(&vb->decoding_frame);
|
|
|
|
error_0:
|
2019-03-03 06:52:22 +08:00
|
|
|
return false;
|
2019-03-02 22:16:55 +08:00
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
|
|
|
video_buffer_destroy(struct video_buffer *vb) {
|
2019-03-02 22:16:55 +08:00
|
|
|
#ifndef SKIP_FRAMES
|
|
|
|
SDL_DestroyCond(vb->rendering_frame_consumed_cond);
|
|
|
|
#endif
|
|
|
|
SDL_DestroyMutex(vb->mutex);
|
|
|
|
av_frame_free(&vb->rendering_frame);
|
|
|
|
av_frame_free(&vb->decoding_frame);
|
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
static void
|
|
|
|
video_buffer_swap_frames(struct video_buffer *vb) {
|
2019-03-02 22:16:55 +08:00
|
|
|
AVFrame *tmp = vb->decoding_frame;
|
|
|
|
vb->decoding_frame = vb->rendering_frame;
|
|
|
|
vb->rendering_frame = tmp;
|
|
|
|
}
|
|
|
|
|
2019-03-03 07:26:48 +08:00
|
|
|
void
|
|
|
|
video_buffer_offer_decoded_frame(struct video_buffer *vb,
|
|
|
|
bool *previous_frame_skipped) {
|
2019-03-02 22:16:55 +08:00
|
|
|
mutex_lock(vb->mutex);
|
|
|
|
#ifndef SKIP_FRAMES
|
|
|
|
// if SKIP_FRAMES is disabled, then the decoder must wait for the current
|
|
|
|
// frame to be consumed
|
2019-03-03 00:01:52 +08:00
|
|
|
while (!vb->rendering_frame_consumed && !vb->interrupted) {
|
2019-03-02 22:16:55 +08:00
|
|
|
cond_wait(vb->rendering_frame_consumed_cond, vb->mutex);
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
if (vb->fps_counter.started && !vb->rendering_frame_consumed) {
|
|
|
|
fps_counter_add_skipped_frame(&vb->fps_counter);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
video_buffer_swap_frames(vb);
|
|
|
|
|
2019-03-03 07:26:48 +08:00
|
|
|
*previous_frame_skipped = !vb->rendering_frame_consumed;
|
2019-03-03 06:52:22 +08:00
|
|
|
vb->rendering_frame_consumed = false;
|
2019-03-02 22:16:55 +08:00
|
|
|
|
|
|
|
mutex_unlock(vb->mutex);
|
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
const AVFrame *
|
|
|
|
video_buffer_consume_rendered_frame(struct video_buffer *vb) {
|
2019-03-02 22:16:55 +08:00
|
|
|
SDL_assert(!vb->rendering_frame_consumed);
|
2019-03-03 06:52:22 +08:00
|
|
|
vb->rendering_frame_consumed = true;
|
2019-03-02 22:16:55 +08:00
|
|
|
if (vb->fps_counter.started) {
|
|
|
|
fps_counter_add_rendered_frame(&vb->fps_counter);
|
|
|
|
}
|
|
|
|
#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(vb->rendering_frame_consumed_cond);
|
|
|
|
#endif
|
|
|
|
return vb->rendering_frame;
|
|
|
|
}
|
|
|
|
|
2019-03-03 03:09:56 +08:00
|
|
|
void
|
|
|
|
video_buffer_interrupt(struct video_buffer *vb) {
|
2019-03-02 22:16:55 +08:00
|
|
|
#ifdef SKIP_FRAMES
|
|
|
|
(void) vb; // unused
|
|
|
|
#else
|
|
|
|
mutex_lock(vb->mutex);
|
2019-03-03 06:52:22 +08:00
|
|
|
vb->interrupted = true;
|
2019-03-02 22:16:55 +08:00
|
|
|
mutex_unlock(vb->mutex);
|
|
|
|
// wake up blocking wait
|
|
|
|
cond_signal(vb->rendering_frame_consumed_cond);
|
|
|
|
#endif
|
|
|
|
}
|