فهرست منبع

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);
 }