Buffer frame to sync with vsync in SDL

This commit is contained in:
Iwan Timmer 2017-03-18 15:37:39 +01:00
parent bea030c52b
commit a85d6105b8
5 changed files with 41 additions and 16 deletions

View File

@ -33,7 +33,11 @@ static SDL_Texture *bmp;
SDL_mutex *mutex;
int sdlCurrentFrame, sdlNextFrame;
void sdl_init(int width, int height, bool fullscreen) {
sdlCurrentFrame = sdlNextFrame = 0;
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS)) {
fprintf(stderr, "Could not initialize SDL - %s\n", SDL_GetError());
exit(1);
@ -65,7 +69,6 @@ void sdl_init(int width, int height, bool fullscreen) {
exit(1);
}
sdlinput_init();
}
@ -90,14 +93,16 @@ void sdl_loop() {
done = true;
else if (event.type == SDL_USEREVENT) {
if (event.user.code == SDL_CODE_FRAME) {
if (SDL_LockMutex(mutex) == 0) {
if (++sdlCurrentFrame <= sdlNextFrame - SDL_BUFFER_FRAMES) {
//Skip frame
} else if (SDL_LockMutex(mutex) == 0) {
Uint8** data = ((Uint8**) event.user.data1);
int* linesize = ((int*) event.user.data2);
SDL_UpdateYUVTexture(bmp, NULL, data[0], linesize[0], data[1], linesize[1], data[2], linesize[2]);
SDL_UnlockMutex(mutex);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bmp, NULL, NULL);
SDL_RenderPresent(renderer);
SDL_UnlockMutex(mutex);
} else
fprintf(stderr, "Couldn't lock mutex\n");
}

View File

@ -31,9 +31,12 @@
#define SDL_CODE_FRAME 0
#define SDL_BUFFER_FRAMES 2
void sdl_init(int width, int height, bool fullscreen);
void sdl_loop();
SDL_mutex *mutex;
int sdlCurrentFrame, sdlNextFrame;
#endif /* HAVE_SDL */

View File

@ -35,7 +35,10 @@
static AVPacket pkt;
static AVCodec* decoder;
static AVCodecContext* decoder_ctx;
static AVFrame* dec_frame;
static AVFrame** dec_frames;
static int dec_frames_cnt;
static int current_frame, next_frame;
enum decoders {SOFTWARE, VDPAU};
enum decoders decoder_system;
@ -44,7 +47,7 @@ enum decoders decoder_system;
// This function must be called before
// any other decoding functions
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count) {
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count) {
// Initialize the avcodec library and register codecs
av_log_set_level(AV_LOG_QUIET);
avcodec_register_all();
@ -114,12 +117,21 @@ int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread
return err;
}
dec_frame = av_frame_alloc();
if (dec_frame == NULL) {
printf("Couldn't allocate frame");
dec_frames_cnt = buffer_count;
dec_frames = malloc(buffer_count * sizeof(AVFrame*));
if (dec_frames == NULL) {
fprintf(stderr, "Couldn't allocate frames");
return -1;
}
for (int i = 0; i < buffer_count; i++) {
dec_frames[i] = av_frame_alloc();
if (dec_frames[i] == NULL) {
fprintf(stderr, "Couldn't allocate frame");
return -1;
}
}
#ifdef HAVE_VDPAU
if (decoder_system == VDPAU)
vdpau_init(decoder_ctx, width, height);
@ -136,18 +148,20 @@ void ffmpeg_destroy(void) {
av_free(decoder_ctx);
decoder_ctx = NULL;
}
if (dec_frame) {
av_frame_free(&dec_frame);
dec_frame = NULL;
if (dec_frames) {
for (int i = 0; i < dec_frames_cnt; i++) {
if (dec_frames[i])
av_frame_free(&dec_frames[i]);
}
}
}
AVFrame* ffmpeg_get_frame() {
if (decoder_system == SOFTWARE)
return dec_frame;
return dec_frames[current_frame];
#ifdef HAVE_VDPAU
else if (decoder_system == VDPAU)
return vdpau_get_frame(dec_frame);
return vdpau_get_frame(dec_frames[current_frame]);
#endif
}
@ -162,7 +176,7 @@ int ffmpeg_decode(unsigned char* indata, int inlen) {
while (pkt.size > 0) {
got_pic = 0;
err = avcodec_decode_video2(decoder_ctx, dec_frame, &got_pic, &pkt);
err = avcodec_decode_video2(decoder_ctx, dec_frames[next_frame], &got_pic, &pkt);
if (err < 0) {
char errorstring[512];
av_strerror(err, errorstring, sizeof(errorstring));
@ -176,6 +190,8 @@ int ffmpeg_decode(unsigned char* indata, int inlen) {
}
if (got_pic) {
current_frame = next_frame;
next_frame = (current_frame+1) % dec_frames_cnt;
return 1;
}

View File

@ -34,7 +34,7 @@
// Uses hardware acceleration
#define HARDWARE_ACCELERATION 0x40
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int thread_count);
int ffmpeg_init(int videoFormat, int width, int height, int perf_lvl, int buffer_count, int thread_count);
void ffmpeg_destroy(void);
int ffmpeg_draw_frame(AVFrame *pict);

View File

@ -37,7 +37,7 @@ static void sdl_setup(int videoFormat, int width, int height, int redrawRate, vo
if (drFlags & FORCE_HARDWARE_ACCELERATION)
avc_flags |= HARDWARE_ACCELERATION;
if (ffmpeg_init(videoFormat, width, height, avc_flags, 2) < 0) {
if (ffmpeg_init(videoFormat, width, height, avc_flags, SDL_BUFFER_FRAMES, 2) < 0) {
fprintf(stderr, "Couldn't initialize video decoding\n");
exit(1);
}
@ -66,6 +66,7 @@ static int sdl_submit_decode_unit(PDECODE_UNIT decodeUnit) {
if (SDL_LockMutex(mutex) == 0) {
int ret = ffmpeg_decode(ffmpeg_buffer, length);
if (ret == 1) {
sdlNextFrame++;
AVFrame* frame = ffmpeg_get_frame();
SDL_Event event;