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

View File

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

View File

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

View File

@ -34,7 +34,7 @@
// Uses hardware acceleration // Uses hardware acceleration
#define HARDWARE_ACCELERATION 0x40 #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); void ffmpeg_destroy(void);
int ffmpeg_draw_frame(AVFrame *pict); 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) if (drFlags & FORCE_HARDWARE_ACCELERATION)
avc_flags |= 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"); fprintf(stderr, "Couldn't initialize video decoding\n");
exit(1); exit(1);
} }
@ -66,6 +66,7 @@ static int sdl_submit_decode_unit(PDECODE_UNIT decodeUnit) {
if (SDL_LockMutex(mutex) == 0) { if (SDL_LockMutex(mutex) == 0) {
int ret = ffmpeg_decode(ffmpeg_buffer, length); int ret = ffmpeg_decode(ffmpeg_buffer, length);
if (ret == 1) { if (ret == 1) {
sdlNextFrame++;
AVFrame* frame = ffmpeg_get_frame(); AVFrame* frame = ffmpeg_get_frame();
SDL_Event event; SDL_Event event;