mirror of
https://github.com/libretro/RetroArch
synced 2025-02-07 21:39:54 +00:00
Merge branch 'no-video-fifo' of git://github.com/hasenbanck/RetroArch
This commit is contained in:
commit
7aa914fde7
@ -1966,7 +1966,7 @@ endif
|
||||
ifeq ($(HAVE_FFMPEG), 1)
|
||||
OBJ += record/drivers/record_ffmpeg.o \
|
||||
cores/libretro-ffmpeg/ffmpeg_core.o \
|
||||
cores/libretro-ffmpeg/swsbuffer.o \
|
||||
cores/libretro-ffmpeg/video_buffer.o \
|
||||
$(LIBRETRO_COMM_DIR)/rthreads/tpool.o
|
||||
|
||||
LIBS += $(AVCODEC_LIBS) $(AVFORMAT_LIBS) $(AVUTIL_LIBS) $(SWSCALE_LIBS) $(SWRESAMPLE_LIBS) $(FFMPEG_LIBS)
|
||||
|
@ -19,7 +19,7 @@ SWRESAMPLE_DIR := $(BASE_DIR)/libswresample
|
||||
INCFLAGS += -I$(BASE_DIR) -I$(CORE_DIR) -I$(LIBRETRO_COMM_DIR)/include -I$(LIBRETRO_COMM_DIR)/include/compat
|
||||
|
||||
LIBRETRO_SOURCE += $(CORE_DIR)/ffmpeg_core.c \
|
||||
$(CORE_DIR)/swsbuffer.c \
|
||||
$(CORE_DIR)/video_buffer.c \
|
||||
$(LIBRETRO_COMM_DIR)/rthreads/tpool.c \
|
||||
$(LIBRETRO_COMM_DIR)/queues/fifo_queue.c \
|
||||
$(LIBRETRO_COMM_DIR)/rthreads/rthreads.c
|
||||
|
@ -50,7 +50,7 @@ extern "C" {
|
||||
#include <rthreads/tpool.h>
|
||||
#include <queues/fifo_queue.h>
|
||||
#include <string/stdstring.h>
|
||||
#include "swsbuffer.h"
|
||||
#include "video_buffer.h"
|
||||
|
||||
#include <libretro.h>
|
||||
#ifdef RARCH_INTERNAL
|
||||
@ -90,7 +90,7 @@ static enum AVColorSpace colorspace;
|
||||
|
||||
static unsigned sw_decoder_threads;
|
||||
static unsigned sw_sws_threads;
|
||||
static swsbuffer_t *swsbuffer;
|
||||
static video_buffer_t *video_buffer;
|
||||
static tpool_t *tpool;
|
||||
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
@ -141,20 +141,17 @@ static double pts_bias;
|
||||
|
||||
/* Threaded FIFOs. */
|
||||
static volatile bool decode_thread_dead;
|
||||
static fifo_buffer_t *video_decode_fifo;
|
||||
static fifo_buffer_t *audio_decode_fifo;
|
||||
static scond_t *fifo_cond;
|
||||
static scond_t *fifo_decode_cond;
|
||||
static slock_t *fifo_lock;
|
||||
static slock_t *decode_thread_lock;
|
||||
static sthread_t *decode_thread_handle;
|
||||
static double decode_last_video_time;
|
||||
static double decode_last_audio_time;
|
||||
static bool main_sleeping;
|
||||
|
||||
static uint32_t *video_frame_temp_buffer;
|
||||
|
||||
static bool main_sleeping;
|
||||
|
||||
/* Seeking. */
|
||||
static bool do_seek;
|
||||
static double seek_time;
|
||||
@ -459,7 +456,7 @@ static void check_variables(bool firststart)
|
||||
{
|
||||
sw_decoder_threads = strtoul(sw_threads_var.value, NULL, 0);
|
||||
}
|
||||
/* Scale the sws threads based on core count but use at min 2 and max 4 threads */
|
||||
/* Scale the sws threads based on core count but use at least 2 and at most 4 threads */
|
||||
sw_sws_threads = MIN(MAX(2, sw_decoder_threads / 2), 4);
|
||||
}
|
||||
}
|
||||
@ -492,8 +489,9 @@ static void seek_frame(int seek_frames)
|
||||
}
|
||||
audio_frames = frame_cnt * media.sample_rate / media.interpolate_fps;
|
||||
|
||||
if (video_decode_fifo)
|
||||
fifo_clear(video_decode_fifo);
|
||||
tpool_wait(tpool);
|
||||
video_buffer_clear(video_buffer);
|
||||
|
||||
if (audio_decode_fifo)
|
||||
fifo_clear(audio_decode_fifo);
|
||||
scond_signal(fifo_decode_cond);
|
||||
@ -692,24 +690,19 @@ void CORE_PREFIX(retro_run)(void)
|
||||
|
||||
while (!decode_thread_dead && min_pts > frames[1].pts)
|
||||
{
|
||||
size_t to_read_frame_bytes;
|
||||
int64_t pts = 0;
|
||||
|
||||
slock_lock(fifo_lock);
|
||||
to_read_frame_bytes = media.width * media.height * sizeof(uint32_t) + sizeof(int64_t);
|
||||
|
||||
while (!decode_thread_dead && fifo_read_avail(video_decode_fifo) < to_read_frame_bytes)
|
||||
{
|
||||
main_sleeping = true;
|
||||
scond_signal(fifo_decode_cond);
|
||||
scond_wait(fifo_cond, fifo_lock);
|
||||
main_sleeping = false;
|
||||
}
|
||||
if (!decode_thread_dead)
|
||||
video_buffer_wait_for_finished_slot(video_buffer);
|
||||
|
||||
if (!decode_thread_dead)
|
||||
{
|
||||
uint32_t *data = video_frame_temp_buffer;
|
||||
fifo_read(video_decode_fifo, &pts, sizeof(int64_t));
|
||||
|
||||
video_decoder_context_t *ctx = NULL;
|
||||
video_buffer_get_finished_slot(video_buffer, &ctx);
|
||||
pts = ctx->pts;
|
||||
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
||||
if (use_gl)
|
||||
{
|
||||
@ -723,7 +716,11 @@ void CORE_PREFIX(retro_run)(void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
fifo_read(video_decode_fifo, data, media.width * media.height * sizeof(uint32_t));
|
||||
const uint8_t *src = ctx->target->data[0];
|
||||
int stride = ctx->target->linesize[0];
|
||||
int width = media.width * sizeof(uint32_t);
|
||||
for (unsigned y = 0; y < media.height; y++, src += stride, data += width/4)
|
||||
memcpy(data, src, width);
|
||||
|
||||
#ifndef HAVE_OPENGLES
|
||||
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||
@ -744,14 +741,17 @@ void CORE_PREFIX(retro_run)(void)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fifo_read(video_decode_fifo, data, media.width * media.height * sizeof(uint32_t));
|
||||
const uint8_t *src = ctx->target->data[0];
|
||||
int stride = ctx->target->linesize[0];
|
||||
size_t width = media.width * sizeof(uint32_t);
|
||||
for (unsigned y = 0; y < media.height; y++, src += stride, data += width/4)
|
||||
memcpy(data, src, width);
|
||||
|
||||
dupe = false;
|
||||
}
|
||||
video_buffer_open_slot(video_buffer, ctx);
|
||||
}
|
||||
|
||||
scond_signal(fifo_decode_cond);
|
||||
slock_unlock(fifo_lock);
|
||||
|
||||
frames[1].pts = av_q2d(fctx->streams[video_stream_index]->time_base) * pts;
|
||||
}
|
||||
|
||||
@ -1289,7 +1289,7 @@ static void sws_worker_thread(void *arg)
|
||||
{
|
||||
int ret = 0;
|
||||
AVFrame *tmp_frame = NULL;
|
||||
sws_context_t *ctx = (sws_context_t*) arg;
|
||||
video_decoder_context_t *ctx = (video_decoder_context_t*) arg;
|
||||
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
if (hw_decoding_enabled)
|
||||
@ -1318,75 +1318,25 @@ static void sws_worker_thread(void *arg)
|
||||
#endif
|
||||
}
|
||||
|
||||
swsbuffer_finish_slot(swsbuffer, ctx);
|
||||
}
|
||||
ctx->pts = ctx->source->best_effort_timestamp;
|
||||
|
||||
#ifdef HAVE_SSA
|
||||
static void add_frame_to_fifo(size_t frame_size, ASS_Track *ass_track_active)
|
||||
#else
|
||||
static void add_frame_to_fifo(size_t frame_size)
|
||||
#endif
|
||||
{
|
||||
sws_context_t *ctx = NULL;
|
||||
|
||||
swsbuffer_get_finished_slot(swsbuffer, &ctx);
|
||||
size_t decoded_size;
|
||||
int64_t pts = ctx->source->best_effort_timestamp;
|
||||
double video_time = pts * av_q2d(fctx->streams[video_stream_index]->time_base);
|
||||
|
||||
#ifdef HAVE_SSA
|
||||
if (ass_render && ass_track_active)
|
||||
double video_time = ctx->pts * av_q2d(fctx->streams[video_stream_index]->time_base);
|
||||
if (ass_render && ctx->ass_track_active)
|
||||
{
|
||||
int change = 0;
|
||||
ASS_Image *img = ass_render_frame(ass_render, ass_track_active,
|
||||
ASS_Image *img = ass_render_frame(ass_render, ctx->ass_track_active,
|
||||
1000 * video_time, &change);
|
||||
|
||||
/*
|
||||
* Do it on CPU for now.
|
||||
* We're in a thread anyways, so shouldn't really matter.
|
||||
*/
|
||||
render_ass_img(ctx->target, img);
|
||||
}
|
||||
#endif
|
||||
|
||||
decoded_size = frame_size + sizeof(pts);
|
||||
|
||||
slock_lock(fifo_lock);
|
||||
while (!decode_thread_dead && (video_decode_fifo != NULL)
|
||||
&& fifo_write_avail(video_decode_fifo) < decoded_size)
|
||||
{
|
||||
if (!main_sleeping)
|
||||
scond_wait(fifo_decode_cond, fifo_lock);
|
||||
else
|
||||
{
|
||||
fifo_clear(video_decode_fifo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
decode_last_video_time = video_time;
|
||||
if (!decode_thread_dead)
|
||||
{
|
||||
int stride;
|
||||
unsigned y;
|
||||
const uint8_t *src = NULL;
|
||||
|
||||
fifo_write(video_decode_fifo, &pts, sizeof(pts));
|
||||
src = ctx->target->data[0];
|
||||
stride = ctx->target->linesize[0];
|
||||
|
||||
for (y = 0; y < media.height; y++, src += stride)
|
||||
fifo_write(video_decode_fifo, src, media.width * sizeof(uint32_t));
|
||||
}
|
||||
scond_signal(fifo_cond);
|
||||
slock_unlock(fifo_lock);
|
||||
|
||||
av_frame_unref(ctx->source);
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
av_frame_unref(ctx->hw_source);
|
||||
#endif
|
||||
|
||||
swsbuffer_open_slot(swsbuffer, ctx);
|
||||
video_buffer_finish_slot(video_buffer, ctx);
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSA
|
||||
@ -1396,7 +1346,24 @@ static void decode_video(AVCodecContext *ctx, AVPacket *pkt, size_t frame_size)
|
||||
#endif
|
||||
{
|
||||
int ret = 0;
|
||||
sws_context_t *sws_ctx = NULL;
|
||||
video_decoder_context_t *decoder_ctx = NULL;
|
||||
|
||||
/* Stop decoding thread until video_buffer is not full again */
|
||||
while (!decode_thread_dead && !video_buffer_has_open_slot(video_buffer))
|
||||
{
|
||||
/* If we don't buffer enough video frames we can run into a deadlock.
|
||||
* for now drop frames in this case. This could happen with MP4 files
|
||||
* since the often save the audio frames into the stream.
|
||||
* Longterm solution: audio and video decoding in their own threads
|
||||
* with their own file handle. */
|
||||
if (main_sleeping)
|
||||
{
|
||||
log_cb(RETRO_LOG_ERROR, "[FFMPEG] Thread: Video deadlock detected.\n");
|
||||
tpool_wait(tpool);
|
||||
video_buffer_clear(video_buffer);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = avcodec_send_packet(ctx, pkt)) < 0)
|
||||
{
|
||||
@ -1408,24 +1375,11 @@ static void decode_video(AVCodecContext *ctx, AVPacket *pkt, size_t frame_size)
|
||||
return;
|
||||
}
|
||||
|
||||
/* Stop decoding thread until swsbuffer is not full again */
|
||||
while (!swsbuffer_has_open_slot(swsbuffer))
|
||||
while (!decode_thread_dead && video_buffer_has_open_slot(video_buffer))
|
||||
{
|
||||
while(swsbuffer_has_finished_slot(swsbuffer))
|
||||
{
|
||||
#ifdef HAVE_SSA
|
||||
add_frame_to_fifo(frame_size, ass_track_active);
|
||||
#else
|
||||
add_frame_to_fifo(frame_size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
video_buffer_get_open_slot(video_buffer, &decoder_ctx);
|
||||
|
||||
while (swsbuffer_has_open_slot(swsbuffer))
|
||||
{
|
||||
swsbuffer_get_open_slot(swsbuffer, &sws_ctx);
|
||||
|
||||
ret = avcodec_receive_frame(ctx, sws_ctx->source);
|
||||
ret = avcodec_receive_frame(ctx, decoder_ctx->source);
|
||||
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
|
||||
{
|
||||
ret = -42;
|
||||
@ -1444,7 +1398,7 @@ static void decode_video(AVCodecContext *ctx, AVPacket *pkt, size_t frame_size)
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
if (hw_decoding_enabled)
|
||||
/* Copy data from VRAM to RAM */
|
||||
if ((ret = av_hwframe_transfer_data(sws_ctx->hw_source, sws_ctx->source, 0)) < 0)
|
||||
if ((ret = av_hwframe_transfer_data(decoder_ctx->hw_source, decoder_ctx->source, 0)) < 0)
|
||||
{
|
||||
#ifdef __cplusplus
|
||||
log_cb(RETRO_LOG_ERROR, "[FFMPEG] Error transferring the data to system memory: %d\n", ret);
|
||||
@ -1455,21 +1409,16 @@ static void decode_video(AVCodecContext *ctx, AVPacket *pkt, size_t frame_size)
|
||||
}
|
||||
#endif
|
||||
|
||||
tpool_add_work(tpool, sws_worker_thread, sws_ctx);
|
||||
|
||||
while(swsbuffer_has_finished_slot(swsbuffer))
|
||||
{
|
||||
#ifdef HAVE_SSA
|
||||
add_frame_to_fifo(frame_size, ass_track_active);
|
||||
#else
|
||||
add_frame_to_fifo(frame_size);
|
||||
decoder_ctx->ass_track_active = ass_track_active;
|
||||
#endif
|
||||
}
|
||||
|
||||
tpool_add_work(tpool, sws_worker_thread, decoder_ctx);
|
||||
|
||||
end:
|
||||
if (ret < 0)
|
||||
{
|
||||
swsbuffer_return_open_slot(swsbuffer, sws_ctx);
|
||||
video_buffer_return_open_slot(video_buffer, decoder_ctx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1523,7 +1472,7 @@ static int16_t *decode_audio(AVCodecContext *ctx, AVPacket *pkt,
|
||||
(const uint8_t**)frame->data,
|
||||
frame->nb_samples);
|
||||
|
||||
pts = av_frame_get_best_effort_timestamp(frame);
|
||||
pts = frame->best_effort_timestamp;
|
||||
slock_lock(fifo_lock);
|
||||
|
||||
while (!decode_thread_dead && fifo_write_avail(audio_decode_fifo) < required_buffer)
|
||||
@ -1559,7 +1508,6 @@ static void decode_thread_seek(double time)
|
||||
if (seek_to < 0)
|
||||
seek_to = 0;
|
||||
|
||||
decode_last_video_time = time;
|
||||
decode_last_audio_time = time;
|
||||
|
||||
if(avformat_seek_file(fctx, -1, INT64_MIN, seek_to, INT64_MAX, 0) < 0)
|
||||
@ -1606,7 +1554,7 @@ static void decode_thread(void *data)
|
||||
if (video_stream_index >= 0)
|
||||
{
|
||||
frame_size = avpicture_get_size(PIX_FMT_RGB32, media.width, media.height);
|
||||
swsbuffer = swsbuffer_create(sw_sws_threads, frame_size, media.width, media.height);
|
||||
video_buffer = video_buffer_create(32, frame_size, media.width, media.height);
|
||||
tpool = tpool_create(sw_sws_threads);
|
||||
log_cb(RETRO_LOG_INFO, "[FFMPEG] Configured filtering threads: %d\n", sw_sws_threads);
|
||||
}
|
||||
@ -1631,20 +1579,18 @@ static void decode_thread(void *data)
|
||||
|
||||
if (seek)
|
||||
{
|
||||
if (video_stream_index >= 0)
|
||||
{
|
||||
tpool_wait(tpool);
|
||||
swsbuffer_clear(swsbuffer);
|
||||
}
|
||||
|
||||
decode_thread_seek(seek_time_thread);
|
||||
|
||||
slock_lock(fifo_lock);
|
||||
do_seek = false;
|
||||
seek_time = 0.0;
|
||||
|
||||
if (video_decode_fifo)
|
||||
fifo_clear(video_decode_fifo);
|
||||
if (video_stream_index >= 0)
|
||||
{
|
||||
tpool_wait(tpool);
|
||||
video_buffer_clear(video_buffer);
|
||||
}
|
||||
|
||||
if (audio_decode_fifo)
|
||||
fifo_clear(audio_decode_fifo);
|
||||
|
||||
@ -1719,12 +1665,6 @@ static void decode_thread(void *data)
|
||||
av_frame_free(&aud_frame);
|
||||
av_freep(&audio_buffer);
|
||||
|
||||
if (video_stream_index >= 0)
|
||||
{
|
||||
tpool_destroy(tpool);
|
||||
swsbuffer_destroy(swsbuffer);
|
||||
}
|
||||
|
||||
slock_lock(fifo_lock);
|
||||
decode_thread_dead = true;
|
||||
scond_signal(fifo_cond);
|
||||
@ -1836,8 +1776,12 @@ void CORE_PREFIX(retro_unload_game)(void)
|
||||
if (decode_thread_handle)
|
||||
{
|
||||
slock_lock(fifo_lock);
|
||||
|
||||
tpool_wait(tpool);
|
||||
video_buffer_clear(video_buffer);
|
||||
decode_thread_dead = true;
|
||||
scond_signal(fifo_decode_cond);
|
||||
|
||||
slock_unlock(fifo_lock);
|
||||
sthread_join(decode_thread_handle);
|
||||
}
|
||||
@ -1852,8 +1796,6 @@ void CORE_PREFIX(retro_unload_game)(void)
|
||||
if (decode_thread_lock)
|
||||
slock_free(decode_thread_lock);
|
||||
|
||||
if (video_decode_fifo)
|
||||
fifo_free(video_decode_fifo);
|
||||
if (audio_decode_fifo)
|
||||
fifo_free(audio_decode_fifo);
|
||||
|
||||
@ -1861,10 +1803,8 @@ void CORE_PREFIX(retro_unload_game)(void)
|
||||
fifo_decode_cond = NULL;
|
||||
fifo_lock = NULL;
|
||||
decode_thread_lock = NULL;
|
||||
video_decode_fifo = NULL;
|
||||
audio_decode_fifo = NULL;
|
||||
|
||||
decode_last_video_time = 0.0;
|
||||
decode_last_audio_time = 0.0;
|
||||
|
||||
frames[0].pts = frames[1].pts = 0.0;
|
||||
@ -1994,11 +1934,6 @@ bool CORE_PREFIX(retro_load_game)(const struct retro_game_info *info)
|
||||
|
||||
if (video_stream_index >= 0 || is_fft)
|
||||
{
|
||||
/* video fifo is 2 frames deep */
|
||||
video_decode_fifo = fifo_new(
|
||||
media.width * media.height * sizeof(uint32_t) * 2
|
||||
);
|
||||
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
||||
use_gl = true;
|
||||
hw_render.context_reset = context_reset;
|
||||
@ -2014,15 +1949,15 @@ bool CORE_PREFIX(retro_load_game)(const struct retro_game_info *info)
|
||||
if (!CORE_PREFIX(environ_cb)(RETRO_ENVIRONMENT_SET_HW_RENDER, &hw_render))
|
||||
{
|
||||
use_gl = false;
|
||||
log_cb(RETRO_LOG_ERROR, "[FFMPEG] Cannot initialize HW render.");
|
||||
log_cb(RETRO_LOG_ERROR, "[FFMPEG] Cannot initialize HW render.\n");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (audio_streams_num > 0)
|
||||
{
|
||||
/* audio fifo is 1 second deep */
|
||||
/* audio fifo is 4 seconds deep */
|
||||
audio_decode_fifo = fifo_new(
|
||||
media.sample_rate * sizeof(int16_t) * 2
|
||||
media.sample_rate * sizeof(int16_t) * 2 * 4
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1,185 +0,0 @@
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
#include "swsbuffer.h"
|
||||
|
||||
enum kbStatus
|
||||
{
|
||||
KB_OPEN,
|
||||
KB_IN_PROGRESS,
|
||||
KB_FINISHED
|
||||
};
|
||||
|
||||
struct swsbuffer
|
||||
{
|
||||
sws_context_t *buffer;
|
||||
enum kbStatus *status;
|
||||
size_t size;
|
||||
slock_t *lock;
|
||||
int64_t head;
|
||||
int64_t tail;
|
||||
};
|
||||
|
||||
swsbuffer_t *swsbuffer_create(size_t num, int frame_size, int width, int height)
|
||||
{
|
||||
swsbuffer_t *b = malloc(sizeof (swsbuffer_t));
|
||||
if (b == NULL)
|
||||
return NULL;
|
||||
|
||||
b->status = malloc(sizeof(enum kbStatus) * num);
|
||||
if (b->status == NULL)
|
||||
return NULL;
|
||||
for (int i = 0; i < num; i++)
|
||||
b->status[i] = KB_OPEN;
|
||||
|
||||
b->lock = slock_new();
|
||||
if (b->lock == NULL)
|
||||
return NULL;
|
||||
|
||||
b->buffer = malloc(sizeof(sws_context_t) * num);
|
||||
if (b->buffer == NULL)
|
||||
return NULL;
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
b->buffer[i].index = i;
|
||||
b->buffer[i].sws = sws_alloc_context();
|
||||
b->buffer[i].source = av_frame_alloc();
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
b->buffer[i].hw_source = av_frame_alloc();
|
||||
#endif
|
||||
b->buffer[i].target = av_frame_alloc();
|
||||
b->buffer[i].frame_buf = av_malloc(frame_size);
|
||||
|
||||
avpicture_fill((AVPicture*)b->buffer[i].target, (const uint8_t*)b->buffer[i].frame_buf,
|
||||
PIX_FMT_RGB32, width, height);
|
||||
}
|
||||
|
||||
b->size = num;
|
||||
b->head = 0;
|
||||
b->tail = 0;
|
||||
return b;
|
||||
}
|
||||
|
||||
void swsbuffer_destroy(swsbuffer_t *swsbuffer)
|
||||
{
|
||||
if (swsbuffer != NULL) {
|
||||
slock_free(swsbuffer->lock);
|
||||
free(swsbuffer->status);
|
||||
for (int i = 0; i < swsbuffer->size; i++)
|
||||
{
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
av_frame_free(&swsbuffer->buffer[i].hw_source);
|
||||
#endif
|
||||
av_frame_free(&swsbuffer->buffer[i].source);
|
||||
av_frame_free(&swsbuffer->buffer[i].target);
|
||||
av_freep(&swsbuffer->buffer[i].frame_buf);
|
||||
sws_freeContext(swsbuffer->buffer[i].sws);
|
||||
}
|
||||
free(swsbuffer->buffer);
|
||||
free(swsbuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void swsbuffer_clear(swsbuffer_t *swsbuffer)
|
||||
{
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
swsbuffer->head = 0;
|
||||
swsbuffer->tail = 0;
|
||||
for (int i = 0; i < swsbuffer->size; i++)
|
||||
swsbuffer->status[i] = KB_OPEN;
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
}
|
||||
|
||||
void swsbuffer_get_open_slot(swsbuffer_t *swsbuffer, sws_context_t **context)
|
||||
{
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[swsbuffer->head] == KB_OPEN)
|
||||
{
|
||||
*context = &swsbuffer->buffer[swsbuffer->head];
|
||||
swsbuffer->status[swsbuffer->head] = KB_IN_PROGRESS;
|
||||
swsbuffer->head++;
|
||||
swsbuffer->head %= swsbuffer->size;
|
||||
}
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
}
|
||||
|
||||
void swsbuffer_return_open_slot(swsbuffer_t *swsbuffer, sws_context_t *context)
|
||||
{
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[context->index] == KB_IN_PROGRESS)
|
||||
{
|
||||
swsbuffer->status[context->index] = KB_OPEN;
|
||||
swsbuffer->head--;
|
||||
swsbuffer->head %= swsbuffer->size;
|
||||
}
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
}
|
||||
|
||||
void swsbuffer_open_slot(swsbuffer_t *swsbuffer, sws_context_t *context)
|
||||
{
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[context->index] == KB_FINISHED)
|
||||
{
|
||||
swsbuffer->status[context->index] = KB_OPEN;
|
||||
swsbuffer->tail++;
|
||||
swsbuffer->tail %= (swsbuffer->size);
|
||||
}
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
}
|
||||
|
||||
void swsbuffer_get_finished_slot(swsbuffer_t *swsbuffer, sws_context_t **context)
|
||||
{
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[swsbuffer->tail] == KB_FINISHED)
|
||||
*context = &swsbuffer->buffer[swsbuffer->tail];
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
}
|
||||
|
||||
void swsbuffer_finish_slot(swsbuffer_t *swsbuffer, sws_context_t *context)
|
||||
{
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[context->index] == KB_IN_PROGRESS)
|
||||
swsbuffer->status[context->index] = KB_FINISHED;
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
}
|
||||
|
||||
bool swsbuffer_has_open_slot(swsbuffer_t *swsbuffer)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[swsbuffer->head] == KB_OPEN)
|
||||
ret = true;
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool swsbuffer_has_finished_slot(swsbuffer_t *swsbuffer)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
slock_lock(swsbuffer->lock);
|
||||
|
||||
if (swsbuffer->status[swsbuffer->tail] == KB_FINISHED)
|
||||
ret = true;
|
||||
|
||||
slock_unlock(swsbuffer->lock);
|
||||
|
||||
return ret;
|
||||
}
|
@ -1,166 +0,0 @@
|
||||
#ifndef __LIBRETRO_SDK_SWSBUFFER_H__
|
||||
#define __LIBRETRO_SDK_SWSBUFFER_H__
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
|
||||
#include <libavutil/frame.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include <retro_inline.h>
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifndef PIX_FMT_RGB32
|
||||
#define PIX_FMT_RGB32 AV_PIX_FMT_RGB32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* sws_context
|
||||
*
|
||||
* Context object for the sws worker threads.
|
||||
*
|
||||
*/
|
||||
struct sws_context
|
||||
{
|
||||
int index;
|
||||
struct SwsContext *sws;
|
||||
AVFrame *source;
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
AVFrame *hw_source;
|
||||
#endif
|
||||
AVFrame *target;
|
||||
void *frame_buf;
|
||||
};
|
||||
typedef struct sws_context sws_context_t;
|
||||
|
||||
/**
|
||||
* swsbuffer
|
||||
*
|
||||
* The swsbuffer is a ring buffer, that can be used as a
|
||||
* buffer for many workers while keeping the order.
|
||||
*
|
||||
* It is thread safe in a sensem that it is designed to work
|
||||
* with one work coordinator, that allocates work slots for
|
||||
* workers threads to work on and later collect the work
|
||||
* product in the same order, as the slots were allocated.
|
||||
*
|
||||
*/
|
||||
struct swsbuffer;
|
||||
typedef struct swsbuffer swsbuffer_t;
|
||||
|
||||
/**
|
||||
* swsbuffer_create:
|
||||
* @num : Size of the buffer.
|
||||
* @frame_size : Size of the target frame.
|
||||
* @width : Width of the target frame.
|
||||
* @height : Height of the target frame.
|
||||
*
|
||||
* Create a swsbuffer.
|
||||
*
|
||||
* Returns: swsbuffer.
|
||||
*/
|
||||
swsbuffer_t *swsbuffer_create(size_t num, int frame_size, int width, int height);
|
||||
|
||||
/**
|
||||
* swsbuffer_destroy:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
*
|
||||
* Destory a swsbuffer.
|
||||
*
|
||||
* Does also free the buffer allocated with swsbuffer_create().
|
||||
* User has to shut down any external worker threads that may have
|
||||
* a reference to this swsbuffer.
|
||||
*
|
||||
**/
|
||||
void swsbuffer_destroy(swsbuffer_t *swsbuffer);
|
||||
|
||||
/**
|
||||
* swsbuffer_clear:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
*
|
||||
* Clears a swsbuffer.
|
||||
*
|
||||
**/
|
||||
void swsbuffer_clear(swsbuffer_t *swsbuffer);
|
||||
|
||||
/**
|
||||
* swsbuffer_get_open_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
* @contex : sws context.
|
||||
*
|
||||
* Returns the next open context inside the ring buffer
|
||||
* and it's index. The status of the slot will be marked as
|
||||
* 'in progress' until slot is marked as finished with
|
||||
* swsbuffer_finish_slot();
|
||||
*
|
||||
**/
|
||||
void swsbuffer_get_open_slot(swsbuffer_t *swsbuffer, sws_context_t **context);
|
||||
|
||||
/**
|
||||
* swsbuffer_return_open_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
* @contex : sws context.
|
||||
*
|
||||
* Marks the given sws context that is "in progress" as "open" again.
|
||||
*
|
||||
**/
|
||||
void swsbuffer_return_open_slot(swsbuffer_t *swsbuffer, sws_context_t *context);
|
||||
|
||||
/**
|
||||
* swsbuffer_open_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
* @context : sws context.
|
||||
*
|
||||
* Sets the status of the given context from "finished" to "open".
|
||||
* The slot is then available for producers to claim again with swsbuffer_get_open_slot().
|
||||
**/
|
||||
void swsbuffer_open_slot(swsbuffer_t *swsbuffer, sws_context_t *context);
|
||||
|
||||
/**
|
||||
* swsbuffer_get_finished_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
* @context : sws context.
|
||||
*
|
||||
* Returns a reference for the next context inside
|
||||
* the ring buffer. User needs to use swsbuffer_open_slot()
|
||||
* to open the slot in the ringbuffer for the next
|
||||
* work assignment. User is free to re-allocate or
|
||||
* re-use the context.
|
||||
*
|
||||
*/
|
||||
void swsbuffer_get_finished_slot(swsbuffer_t *swsbuffer, sws_context_t **context);
|
||||
|
||||
/**
|
||||
* swsbuffer_finish_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
* @context : sws context.
|
||||
*
|
||||
* Sets the status of the given context from "in progress" to "finished".
|
||||
* This is normally done by a producer. User can then retrieve the finished work
|
||||
* context by calling swsbuffer_get_finished_slot().
|
||||
*/
|
||||
void swsbuffer_finish_slot(swsbuffer_t *swsbuffer, sws_context_t *context);
|
||||
|
||||
/**
|
||||
* swsbuffer_has_open_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
*
|
||||
* Returns true if the buffer has a open slot available.
|
||||
*/
|
||||
bool swsbuffer_has_open_slot(swsbuffer_t *swsbuffer);
|
||||
|
||||
/**
|
||||
* swsbuffer_has_finished_slot:
|
||||
* @swsbuffer : sswsbuffer.
|
||||
*
|
||||
* Returns true if the buffers next slot is finished and a
|
||||
* context available.
|
||||
*/
|
||||
bool swsbuffer_has_finished_slot(swsbuffer_t *swsbuffer);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
244
cores/libretro-ffmpeg/video_buffer.c
Normal file
244
cores/libretro-ffmpeg/video_buffer.c
Normal file
@ -0,0 +1,244 @@
|
||||
#include <libavformat/avformat.h>
|
||||
|
||||
#include <rthreads/rthreads.h>
|
||||
|
||||
#include "video_buffer.h"
|
||||
|
||||
enum kbStatus
|
||||
{
|
||||
KB_OPEN,
|
||||
KB_IN_PROGRESS,
|
||||
KB_FINISHED
|
||||
};
|
||||
|
||||
struct video_buffer
|
||||
{
|
||||
video_decoder_context_t *buffer;
|
||||
enum kbStatus *status;
|
||||
size_t size;
|
||||
slock_t *lock;
|
||||
scond_t *open_cond;
|
||||
scond_t *finished_cond;
|
||||
int64_t head;
|
||||
int64_t tail;
|
||||
};
|
||||
|
||||
video_buffer_t *video_buffer_create(size_t num, int frame_size, int width, int height)
|
||||
{
|
||||
video_buffer_t *b = malloc(sizeof (video_buffer_t));
|
||||
if (!b)
|
||||
return NULL;
|
||||
|
||||
b->lock = NULL;
|
||||
b->open_cond = NULL;
|
||||
b->finished_cond = NULL;
|
||||
b->buffer = NULL;
|
||||
b->size = num;
|
||||
b->head = 0;
|
||||
b->tail = 0;
|
||||
|
||||
b->status = malloc(sizeof(enum kbStatus) * num);
|
||||
if (!b->status)
|
||||
goto fail;
|
||||
for (int i = 0; i < num; i++)
|
||||
b->status[i] = KB_OPEN;
|
||||
|
||||
b->lock = slock_new();
|
||||
b->open_cond = scond_new();
|
||||
b->finished_cond = scond_new();
|
||||
if (!b->lock || !b->open_cond || !b->finished_cond)
|
||||
goto fail;
|
||||
|
||||
b->buffer = malloc(sizeof(video_decoder_context_t) * num);
|
||||
if (!b->buffer)
|
||||
goto fail;
|
||||
|
||||
for (int i = 0; i < num; i++)
|
||||
{
|
||||
b->buffer[i].index = i;
|
||||
b->buffer[i].pts = 0;
|
||||
b->buffer[i].sws = sws_alloc_context();
|
||||
b->buffer[i].source = av_frame_alloc();
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
b->buffer[i].hw_source = av_frame_alloc();
|
||||
#endif
|
||||
b->buffer[i].target = av_frame_alloc();
|
||||
b->buffer[i].frame_buf = av_malloc(frame_size);
|
||||
|
||||
avpicture_fill((AVPicture*)b->buffer[i].target, (const uint8_t*)b->buffer[i].frame_buf,
|
||||
PIX_FMT_RGB32, width, height);
|
||||
|
||||
if (!b->buffer[i].sws ||
|
||||
!b->buffer[i].source ||
|
||||
!b->buffer[i].hw_source ||
|
||||
!b->buffer[i].target ||
|
||||
!b->buffer[i].frame_buf)
|
||||
goto fail;
|
||||
}
|
||||
return b;
|
||||
|
||||
fail:
|
||||
video_buffer_destroy(b);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void video_buffer_destroy(video_buffer_t *video_buffer)
|
||||
{
|
||||
if (!video_buffer)
|
||||
return;
|
||||
|
||||
slock_free(video_buffer->lock);
|
||||
scond_free(video_buffer->open_cond);
|
||||
scond_free(video_buffer->finished_cond);
|
||||
free(video_buffer->status);
|
||||
if (video_buffer->buffer)
|
||||
for (int i = 0; i < video_buffer->size; i++)
|
||||
{
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
av_frame_free(&video_buffer->buffer[i].hw_source);
|
||||
#endif
|
||||
av_frame_free(&video_buffer->buffer[i].source);
|
||||
av_frame_free(&video_buffer->buffer[i].target);
|
||||
av_freep(&video_buffer->buffer[i].frame_buf);
|
||||
sws_freeContext(video_buffer->buffer[i].sws);
|
||||
}
|
||||
free(video_buffer->buffer);
|
||||
free(video_buffer);
|
||||
}
|
||||
|
||||
void video_buffer_clear(video_buffer_t *video_buffer)
|
||||
{
|
||||
if (!video_buffer)
|
||||
return;
|
||||
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
scond_signal(video_buffer->open_cond);
|
||||
scond_signal(video_buffer->finished_cond);
|
||||
|
||||
video_buffer->head = 0;
|
||||
video_buffer->tail = 0;
|
||||
for (int i = 0; i < video_buffer->size; i++)
|
||||
video_buffer->status[i] = KB_OPEN;
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
}
|
||||
|
||||
void video_buffer_get_open_slot(video_buffer_t *video_buffer, video_decoder_context_t **context)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[video_buffer->head] == KB_OPEN)
|
||||
{
|
||||
*context = &video_buffer->buffer[video_buffer->head];
|
||||
video_buffer->status[video_buffer->head] = KB_IN_PROGRESS;
|
||||
video_buffer->head++;
|
||||
video_buffer->head %= video_buffer->size;
|
||||
}
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
}
|
||||
|
||||
void video_buffer_return_open_slot(video_buffer_t *video_buffer, video_decoder_context_t *context)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[context->index] == KB_IN_PROGRESS)
|
||||
{
|
||||
video_buffer->status[context->index] = KB_OPEN;
|
||||
video_buffer->head--;
|
||||
video_buffer->head %= video_buffer->size;
|
||||
}
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
}
|
||||
|
||||
void video_buffer_open_slot(video_buffer_t *video_buffer, video_decoder_context_t *context)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[context->index] == KB_FINISHED)
|
||||
{
|
||||
video_buffer->status[context->index] = KB_OPEN;
|
||||
video_buffer->tail++;
|
||||
video_buffer->tail %= (video_buffer->size);
|
||||
scond_signal(video_buffer->open_cond);
|
||||
}
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
}
|
||||
|
||||
void video_buffer_get_finished_slot(video_buffer_t *video_buffer, video_decoder_context_t **context)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[video_buffer->tail] == KB_FINISHED)
|
||||
*context = &video_buffer->buffer[video_buffer->tail];
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
}
|
||||
|
||||
void video_buffer_finish_slot(video_buffer_t *video_buffer, video_decoder_context_t *context)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[context->index] == KB_IN_PROGRESS)
|
||||
{
|
||||
video_buffer->status[context->index] = KB_FINISHED;
|
||||
scond_signal(video_buffer->finished_cond);
|
||||
}
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
}
|
||||
|
||||
bool video_buffer_wait_for_open_slot(video_buffer_t *video_buffer)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
while (video_buffer->status[video_buffer->head] != KB_OPEN)
|
||||
scond_wait(video_buffer->open_cond, video_buffer->lock);
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool video_buffer_wait_for_finished_slot(video_buffer_t *video_buffer)
|
||||
{
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
while (video_buffer->status[video_buffer->tail] != KB_FINISHED)
|
||||
scond_wait(video_buffer->finished_cond, video_buffer->lock);
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool video_buffer_has_open_slot(video_buffer_t *video_buffer)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[video_buffer->head] == KB_OPEN)
|
||||
ret = true;
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool video_buffer_has_finished_slot(video_buffer_t *video_buffer)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
slock_lock(video_buffer->lock);
|
||||
|
||||
if (video_buffer->status[video_buffer->tail] == KB_FINISHED)
|
||||
ret = true;
|
||||
|
||||
slock_unlock(video_buffer->lock);
|
||||
|
||||
return ret;
|
||||
}
|
196
cores/libretro-ffmpeg/video_buffer.h
Normal file
196
cores/libretro-ffmpeg/video_buffer.h
Normal file
@ -0,0 +1,196 @@
|
||||
#ifndef __LIBRETRO_SDK_SWSBUFFER_H__
|
||||
#define __LIBRETRO_SDK_SWSBUFFER_H__
|
||||
|
||||
#include <retro_common_api.h>
|
||||
|
||||
#include <boolean.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef HAVE_SSA
|
||||
#include <ass/ass.h>
|
||||
#endif
|
||||
|
||||
#include <libavutil/frame.h>
|
||||
#include <libswscale/swscale.h>
|
||||
|
||||
#include <retro_miscellaneous.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
#ifndef PIX_FMT_RGB32
|
||||
#define PIX_FMT_RGB32 AV_PIX_FMT_RGB32
|
||||
#endif
|
||||
|
||||
/**
|
||||
* video_decoder_context
|
||||
*
|
||||
* Context object for the sws worker threads.
|
||||
*
|
||||
*/
|
||||
struct video_decoder_context
|
||||
{
|
||||
int index;
|
||||
int64_t pts;
|
||||
struct SwsContext *sws;
|
||||
AVFrame *source;
|
||||
#if LIBAVUTIL_VERSION_MAJOR > 55
|
||||
AVFrame *hw_source;
|
||||
#endif
|
||||
AVFrame *target;
|
||||
#ifdef HAVE_SSA
|
||||
ASS_Track *ass_track_active;
|
||||
#endif
|
||||
uint8_t *frame_buf;
|
||||
};
|
||||
typedef struct video_decoder_context video_decoder_context_t;
|
||||
|
||||
/**
|
||||
* video_buffer
|
||||
*
|
||||
* The video_buffer is a ring buffer, that can be used as a
|
||||
* buffer for many workers while keeping the order.
|
||||
*
|
||||
* It is thread safe in a sensem that it is designed to work
|
||||
* with one work coordinator, that allocates work slots for
|
||||
* workers threads to work on and later collect the work
|
||||
* product in the same order, as the slots were allocated.
|
||||
*
|
||||
*/
|
||||
struct video_buffer;
|
||||
typedef struct video_buffer video_buffer_t;
|
||||
|
||||
/**
|
||||
* video_buffer_create:
|
||||
* @num : Size of the buffer.
|
||||
* @frame_size : Size of the target frame.
|
||||
* @width : Width of the target frame.
|
||||
* @height : Height of the target frame.
|
||||
*
|
||||
* Create a video_buffer.
|
||||
*
|
||||
* Returns: A video buffer.
|
||||
*/
|
||||
video_buffer_t *video_buffer_create(size_t num, int frame_size, int width, int height);
|
||||
|
||||
/**
|
||||
* video_buffer_destroy:
|
||||
* @video_buffer : video buffer.
|
||||
*
|
||||
* Destory a video_buffer.
|
||||
*
|
||||
* Does also free the buffer allocated with video_buffer_create().
|
||||
* User has to shut down any external worker threads that may have
|
||||
* a reference to this video_buffer.
|
||||
*
|
||||
**/
|
||||
void video_buffer_destroy(video_buffer_t *video_buffer);
|
||||
|
||||
/**
|
||||
* video_buffer_clear:
|
||||
* @video_buffer : video buffer.
|
||||
*
|
||||
* Clears a video_buffer.
|
||||
*
|
||||
**/
|
||||
void video_buffer_clear(video_buffer_t *video_buffer);
|
||||
|
||||
/**
|
||||
* video_buffer_get_open_slot:
|
||||
* @video_buffer : video buffer.
|
||||
* @contex : sws context.
|
||||
*
|
||||
* Returns the next open context inside the ring buffer
|
||||
* and it's index. The status of the slot will be marked as
|
||||
* 'in progress' until slot is marked as finished with
|
||||
* video_buffer_finish_slot();
|
||||
*
|
||||
**/
|
||||
void video_buffer_get_open_slot(video_buffer_t *video_buffer, video_decoder_context_t **context);
|
||||
|
||||
/**
|
||||
* video_buffer_return_open_slot:
|
||||
* @video_buffer : video buffer.
|
||||
* @contex : sws context.
|
||||
*
|
||||
* Marks the given sws context that is "in progress" as "open" again.
|
||||
*
|
||||
**/
|
||||
void video_buffer_return_open_slot(video_buffer_t *video_buffer, video_decoder_context_t *context);
|
||||
|
||||
/**
|
||||
* video_buffer_open_slot:
|
||||
* @video_buffer : video buffer.
|
||||
* @context : sws context.
|
||||
*
|
||||
* Sets the status of the given context from "finished" to "open".
|
||||
* The slot is then available for producers to claim again with video_buffer_get_open_slot().
|
||||
**/
|
||||
void video_buffer_open_slot(video_buffer_t *video_buffer, video_decoder_context_t *context);
|
||||
|
||||
/**
|
||||
* video_buffer_get_finished_slot:
|
||||
* @video_buffer : video buffer.
|
||||
* @context : sws context.
|
||||
*
|
||||
* Returns a reference for the next context inside
|
||||
* the ring buffer. User needs to use video_buffer_open_slot()
|
||||
* to open the slot in the ringbuffer for the next
|
||||
* work assignment. User is free to re-allocate or
|
||||
* re-use the context.
|
||||
*
|
||||
*/
|
||||
void video_buffer_get_finished_slot(video_buffer_t *video_buffer, video_decoder_context_t **context);
|
||||
|
||||
/**
|
||||
* video_buffer_finish_slot:
|
||||
* @video_buffer : video buffer.
|
||||
* @context : sws context.
|
||||
*
|
||||
* Sets the status of the given context from "in progress" to "finished".
|
||||
* This is normally done by a producer. User can then retrieve the finished work
|
||||
* context by calling video_buffer_get_finished_slot().
|
||||
*/
|
||||
void video_buffer_finish_slot(video_buffer_t *video_buffer, video_decoder_context_t *context);
|
||||
|
||||
/**
|
||||
* video_buffer_wait_for_open_slot:
|
||||
* @video_buffer : video buffer.
|
||||
*
|
||||
* Blocks until open slot is available.
|
||||
*
|
||||
* Returns true if the buffer has a open slot available.
|
||||
*/
|
||||
bool video_buffer_wait_for_open_slot(video_buffer_t *video_buffer);
|
||||
|
||||
/**
|
||||
* video_buffer_wait_for_finished_slot:
|
||||
* @video_buffer : video buffer.
|
||||
*
|
||||
* Blocks until finished slot is available.
|
||||
*
|
||||
* Returns true if the buffers next slot is finished and a
|
||||
* context available.
|
||||
*/
|
||||
bool video_buffer_wait_for_finished_slot(video_buffer_t *video_buffer);
|
||||
|
||||
/**
|
||||
* bool video_buffer_has_open_slot(video_buffer_t *video_buffer)
|
||||
:
|
||||
* @video_buffer : video buffer.
|
||||
*
|
||||
* Returns true if the buffer has a open slot available.
|
||||
*/
|
||||
bool video_buffer_has_open_slot(video_buffer_t *video_buffer);
|
||||
|
||||
/**
|
||||
* video_buffer_has_finished_slot:
|
||||
* @video_buffer : video buffer.
|
||||
*
|
||||
* Returns true if the buffers next slot is finished and a
|
||||
* context available.
|
||||
*/
|
||||
bool video_buffer_has_finished_slot(video_buffer_t *video_buffer);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user