From a85d6105b82d574a4e4a06b403b19360a41e4014 Mon Sep 17 00:00:00 2001 From: Iwan Timmer Date: Sat, 18 Mar 2017 15:37:39 +0100 Subject: [PATCH] Buffer frame to sync with vsync in SDL --- src/sdl.c | 11 ++++++++--- src/sdl.h | 3 +++ src/video/ffmpeg.c | 38 +++++++++++++++++++++++++++----------- src/video/ffmpeg.h | 2 +- src/video/sdl.c | 3 ++- 5 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/sdl.c b/src/sdl.c index 6552748..63d0a72 100644 --- a/src/sdl.c +++ b/src/sdl.c @@ -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"); } diff --git a/src/sdl.h b/src/sdl.h index b670209..c26322e 100644 --- a/src/sdl.h +++ b/src/sdl.h @@ -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 */ diff --git a/src/video/ffmpeg.c b/src/video/ffmpeg.c index 0377763..5884823 100644 --- a/src/video/ffmpeg.c +++ b/src/video/ffmpeg.c @@ -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; } diff --git a/src/video/ffmpeg.h b/src/video/ffmpeg.h index 2714222..e65f585 100644 --- a/src/video/ffmpeg.h +++ b/src/video/ffmpeg.h @@ -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); diff --git a/src/video/sdl.c b/src/video/sdl.c index 5a9734f..9bc64e5 100644 --- a/src/video/sdl.c +++ b/src/video/sdl.c @@ -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;