浏览代码

obs-ffmpeg: Cache swscale context during frame callback

Some codecs don't report the correct dimensions until the first
frame is rendered.
John Bradley 10 年之前
父节点
当前提交
e13bb8f479
共有 1 个文件被更改,包括 29 次插入34 次删除
  1. 29 34
      plugins/obs-ffmpeg/obs-ffmpeg-source.c

+ 29 - 34
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);
 }