From e13bb8f479519f5a40d35c03cc7001fd408aa875 Mon Sep 17 00:00:00 2001 From: John Bradley Date: Tue, 10 Mar 2015 12:53:17 -0500 Subject: [PATCH] obs-ffmpeg: Cache swscale context during frame callback Some codecs don't report the correct dimensions until the first frame is rendered. --- plugins/obs-ffmpeg/obs-ffmpeg-source.c | 63 ++++++++++++-------------- 1 file changed, 29 insertions(+), 34 deletions(-) diff --git a/plugins/obs-ffmpeg/obs-ffmpeg-source.c b/plugins/obs-ffmpeg/obs-ffmpeg-source.c index dee9cb764..2341ab2ab 100644 --- a/plugins/obs-ffmpeg/obs-ffmpeg-source.c +++ b/plugins/obs-ffmpeg/obs-ffmpeg-source.c @@ -104,12 +104,31 @@ static bool set_obs_frame_colorprops(struct ff_frame *frame, return true; } +bool update_sws_context(struct ffmpeg_source *source, AVFrame *frame) +{ + source->sws_ctx = sws_getCachedContext( + source->sws_ctx, + frame->width, + frame->height, + frame->format, + frame->width, + frame->height, + AV_PIX_FMT_BGRA, + SWS_BILINEAR, + NULL, NULL, NULL); + + return source->sws_ctx != NULL; +} + static bool video_frame_scale(struct ff_frame *frame, struct ffmpeg_source *s, struct obs_source_frame *obs_frame) { int linesize = frame->frame->width * 4; uint8_t *picture_data = malloc(linesize * frame->frame->height); + + update_sws_context(s, frame->frame); + sws_scale( s->sws_ctx, (uint8_t const *const *)frame->frame->data, @@ -176,7 +195,10 @@ static bool video_frame(struct ff_frame *frame, void *opaque) obs_frame.width = frame->frame->width; obs_frame.height = frame->frame->height; - if (s->sws_ctx != NULL) + enum video_format format = + ffmpeg_to_obs_video_format(frame->frame->format); + + if (s->is_forcing_scale || format == VIDEO_FORMAT_NONE) return video_frame_scale(frame, s, &obs_frame); else if (s->is_hw_decoding) return video_frame_hwaccel(frame, s->source, &obs_frame); @@ -211,33 +233,6 @@ static bool audio_frame(struct ff_frame *frame, void *opaque) return true; } -static bool video_format(AVCodecContext *codec_context, void *opaque) -{ - struct ffmpeg_source *s = opaque; - if (s->sws_ctx) - sws_freeContext(s->sws_ctx); - - enum video_format obs_video_format = - ffmpeg_to_obs_video_format(codec_context->pix_fmt); - - if (obs_video_format == VIDEO_FORMAT_NONE || s->is_forcing_scale) { - s->sws_ctx = sws_getContext( - codec_context->width, - codec_context->height, - codec_context->pix_fmt, - codec_context->width, - codec_context->height, - AV_PIX_FMT_BGRA, - SWS_BILINEAR, - NULL, - NULL, - NULL - ); - } - - return true; -} - static bool is_local_file_modified(obs_properties_t *props, obs_property_t *prop, obs_data_t *settings) { @@ -347,11 +342,6 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings) if (s->demuxer != NULL) ff_demuxer_free(s->demuxer); - if (s->sws_ctx != NULL) { - sws_freeContext(s->sws_ctx); - s->sws_ctx = NULL; - } - s->demuxer = ff_demuxer_init(); s->demuxer->options.is_hw_decoding = s->is_hw_decoding; s->demuxer->options.is_looping = is_looping; @@ -376,7 +366,7 @@ static void ffmpeg_source_update(void *data, obs_data_t *settings) } ff_demuxer_set_callbacks(&s->demuxer->video_callbacks, - video_frame, video_format, + video_frame, NULL, NULL, NULL, NULL, s); ff_demuxer_set_callbacks(&s->demuxer->audio_callbacks, @@ -408,6 +398,11 @@ static void ffmpeg_source_destroy(void *data) struct ffmpeg_source *s = data; ff_demuxer_free(s->demuxer); + + if (s->sws_ctx != NULL) { + sws_freeContext(s->sws_ctx); + } + bfree(s); }