ソースを参照

obs-ffmpeg: Improve chroma location decision

The chroma location doesn't just depend on pixel format, but we're just
trying to pick something reasonable for now.
jpark37 2 年 前
コミット
e8792ac791

+ 5 - 4
plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c

@@ -99,6 +99,7 @@ struct main_params {
 	int color_trc;
 	int colorspace;
 	int color_range;
+	int chroma_sample_location;
 	int max_luminance;
 	char *acodec;
 	char *muxer_settings;
@@ -369,6 +370,9 @@ static bool init_params(int *argc, char ***argv, struct main_params *params,
 		if (!get_opt_int(argc, argv, &params->color_range,
 				 "video color range"))
 			return false;
+		if (!get_opt_int(argc, argv, &params->chroma_sample_location,
+				 "video chroma sample location"))
+			return false;
 		if (!get_opt_int(argc, argv, &params->max_luminance,
 				 "video max luminance"))
 			return false;
@@ -459,10 +463,7 @@ static void create_video_stream(struct ffmpeg_mux *ffm)
 	context->color_trc = ffm->params.color_trc;
 	context->colorspace = ffm->params.colorspace;
 	context->color_range = ffm->params.color_range;
-	context->chroma_sample_location =
-		(ffm->params.colorspace == AVCOL_SPC_BT2020_NCL)
-			? AVCHROMA_LOC_TOPLEFT
-			: AVCHROMA_LOC_LEFT;
+	context->chroma_sample_location = ffm->params.chroma_sample_location;
 	context->extradata = extradata;
 	context->extradata_size = ffm->video_header.size;
 	context->time_base =

+ 34 - 5
plugins/obs-ffmpeg/obs-ffmpeg-formats.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include <libavcodec/avcodec.h>
+#include <libavutil/pixdesc.h>
 
 static inline int64_t rescale_ts(int64_t val, AVCodecContext *context,
 				 AVRational new_base)
@@ -47,11 +48,9 @@ obs_to_ffmpeg_video_format(enum video_format format)
 		return AV_PIX_FMT_YUVA422P;
 	case VIDEO_FORMAT_YUVA:
 		return AV_PIX_FMT_YUVA444P;
-	case VIDEO_FORMAT_YA2L:
 #if LIBAVUTIL_BUILD >= AV_VERSION_INT(56, 31, 100)
+	case VIDEO_FORMAT_YA2L:
 		return AV_PIX_FMT_YUVA444P12LE;
-#else
-		return AV_PIX_FMT_NONE;
 #endif
 	case VIDEO_FORMAT_I010:
 		return AV_PIX_FMT_YUV420P10LE;
@@ -59,11 +58,41 @@ obs_to_ffmpeg_video_format(enum video_format format)
 		return AV_PIX_FMT_P010LE;
 	case VIDEO_FORMAT_NONE:
 	case VIDEO_FORMAT_AYUV:
-		/* not supported by FFmpeg */
+	default:
 		return AV_PIX_FMT_NONE;
 	}
+}
+
+static enum AVChromaLocation
+determine_chroma_location(enum AVPixelFormat pix_fmt,
+			  enum AVColorSpace colorspace)
+{
+	const AVPixFmtDescriptor *const desc = av_pix_fmt_desc_get(pix_fmt);
+	if (desc) {
+		const unsigned log_chroma_w = desc->log2_chroma_w;
+		const unsigned log_chroma_h = desc->log2_chroma_h;
+		switch (log_chroma_h) {
+		case 0:
+			switch (log_chroma_w) {
+			case 0:
+				/* 4:4:4 */
+				return AVCHROMA_LOC_CENTER;
+			case 1:
+				/* 4:2:2 */
+				return AVCHROMA_LOC_LEFT;
+			}
+			break;
+		case 1:
+			if (log_chroma_w == 1) {
+				/* 4:2:0 */
+				return (colorspace == AVCOL_SPC_BT2020_NCL)
+					       ? AVCHROMA_LOC_TOPLEFT
+					       : AVCHROMA_LOC_LEFT;
+			}
+		}
+	}
 
-	return AV_PIX_FMT_NONE;
+	return AVCHROMA_LOC_UNSPECIFIED;
 }
 
 static inline enum audio_format

+ 2 - 4
plugins/obs-ffmpeg/obs-ffmpeg-mpegts.c

@@ -206,10 +206,8 @@ static bool create_video_stream(struct ffmpeg_output *stream,
 	context->color_primaries = data->config.color_primaries;
 	context->color_trc = data->config.color_trc;
 	context->colorspace = data->config.colorspace;
-	context->chroma_sample_location =
-		(data->config.colorspace == AVCOL_SPC_BT2020_NCL)
-			? AVCHROMA_LOC_TOPLEFT
-			: AVCHROMA_LOC_LEFT;
+	context->chroma_sample_location = determine_chroma_location(
+		data->config.format, data->config.colorspace);
 	context->thread_count = 0;
 
 	data->video->time_base = context->time_base;

+ 7 - 3
plugins/obs-ffmpeg/obs-ffmpeg-mux.c

@@ -16,6 +16,7 @@
 ******************************************************************************/
 #include "ffmpeg-mux/ffmpeg-mux.h"
 #include "obs-ffmpeg-mux.h"
+#include "obs-ffmpeg-formats.h"
 
 #ifdef _WIN32
 #include "util/windows/win-version.h"
@@ -192,12 +193,15 @@ static void add_video_encoder_params(struct ffmpeg_muxer *stream,
 			? (int)obs_get_video_hdr_nominal_peak_level()
 			: ((trc == AVCOL_TRC_ARIB_STD_B67) ? 1000 : 0);
 
-	dstr_catf(cmd, "%s %d %d %d %d %d %d %d %d %d %d %d ",
+	dstr_catf(cmd, "%s %d %d %d %d %d %d %d %d %d %d %d %d ",
 		  obs_encoder_get_codec(vencoder), bitrate,
 		  obs_output_get_width(stream->output),
 		  obs_output_get_height(stream->output), (int)pri, (int)trc,
-		  (int)spc, (int)range, max_luminance, (int)info->fps_num,
-		  (int)info->fps_den, (int)codec_tag);
+		  (int)spc, (int)range,
+		  (int)determine_chroma_location(
+			  obs_to_ffmpeg_video_format(info->format), spc),
+		  max_luminance, (int)info->fps_num, (int)info->fps_den,
+		  (int)codec_tag);
 }
 
 static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder)

+ 4 - 8
plugins/obs-ffmpeg/obs-ffmpeg-output.c

@@ -152,10 +152,8 @@ static bool open_video_codec(struct ffmpeg_data *data)
 	data->vframe->color_primaries = data->config.color_primaries;
 	data->vframe->color_trc = data->config.color_trc;
 	data->vframe->colorspace = data->config.colorspace;
-	data->vframe->chroma_location =
-		(data->config.colorspace == AVCOL_SPC_BT2020_NCL)
-			? AVCHROMA_LOC_TOPLEFT
-			: AVCHROMA_LOC_LEFT;
+	data->vframe->chroma_location = determine_chroma_location(
+		context->pix_fmt, data->config.colorspace);
 
 	ret = av_frame_get_buffer(data->vframe, base_get_alignment());
 	if (ret < 0) {
@@ -262,10 +260,8 @@ static bool create_video_stream(struct ffmpeg_data *data)
 	context->color_primaries = data->config.color_primaries;
 	context->color_trc = data->config.color_trc;
 	context->colorspace = data->config.colorspace;
-	context->chroma_sample_location =
-		(data->config.colorspace == AVCOL_SPC_BT2020_NCL)
-			? AVCHROMA_LOC_TOPLEFT
-			: AVCHROMA_LOC_LEFT;
+	context->chroma_sample_location = determine_chroma_location(
+		closest_format, data->config.colorspace);
 	context->thread_count = 0;
 
 	data->video->time_base = context->time_base;

+ 3 - 1
plugins/obs-ffmpeg/obs-ffmpeg-vaapi.c

@@ -145,6 +145,8 @@ static bool vaapi_init_codec(struct vaapi_encoder *enc, const char *path)
 	enc->vframe->height = enc->context->height;
 	enc->vframe->colorspace = enc->context->colorspace;
 	enc->vframe->color_range = enc->context->color_range;
+	enc->vframe->chroma_location = determine_chroma_location(
+		enc->context->pix_fmt, enc->context->colorspace);
 
 	ret = av_frame_get_buffer(enc->vframe, base_get_alignment());
 	if (ret < 0) {
@@ -700,7 +702,7 @@ static obs_properties_t *vaapi_properties(void *unused)
 				char card[128];
 				int ret = snprintf(card, sizeof(card),
 						   "Card%d: %s", i - 28, path);
-				if (ret >= sizeof(card))
+				if (ret >= (int)sizeof(card))
 					blog(LOG_DEBUG,
 					     "obs-ffmpeg-vaapi: A format truncation may have occurred."
 					     " This can be ignored since it is quite improbable.");

+ 13 - 8
plugins/obs-ffmpeg/obs-ffmpeg-video-encoders.c

@@ -68,46 +68,51 @@ void ffmpeg_video_encoder_update(struct ffmpeg_video_encoder *enc, int bitrate,
 				 const char *ffmpeg_opts)
 {
 	const int rate = bitrate * 1000;
+	const enum AVPixelFormat pix_fmt =
+		obs_to_ffmpeg_video_format(info->format);
 	enc->context->bit_rate = rate;
 	enc->context->rc_buffer_size = rate;
 	enc->context->width = obs_encoder_get_width(enc->encoder);
 	enc->context->height = obs_encoder_get_height(enc->encoder);
 	enc->context->time_base = (AVRational){voi->fps_den, voi->fps_num};
-	enc->context->pix_fmt = obs_to_ffmpeg_video_format(info->format);
+	enc->context->pix_fmt = pix_fmt;
 	enc->context->color_range = info->range == VIDEO_RANGE_FULL
 					    ? AVCOL_RANGE_JPEG
 					    : AVCOL_RANGE_MPEG;
 
+	enum AVColorSpace colorspace = AVCOL_SPC_UNSPECIFIED;
 	switch (info->colorspace) {
 	case VIDEO_CS_601:
 		enc->context->color_primaries = AVCOL_PRI_SMPTE170M;
 		enc->context->color_trc = AVCOL_TRC_SMPTE170M;
-		enc->context->colorspace = AVCOL_SPC_SMPTE170M;
+		colorspace = AVCOL_SPC_SMPTE170M;
 		break;
 	case VIDEO_CS_DEFAULT:
 	case VIDEO_CS_709:
 		enc->context->color_primaries = AVCOL_PRI_BT709;
 		enc->context->color_trc = AVCOL_TRC_BT709;
-		enc->context->colorspace = AVCOL_SPC_BT709;
+		colorspace = AVCOL_SPC_BT709;
 		break;
 	case VIDEO_CS_SRGB:
 		enc->context->color_primaries = AVCOL_PRI_BT709;
 		enc->context->color_trc = AVCOL_TRC_IEC61966_2_1;
-		enc->context->colorspace = AVCOL_SPC_BT709;
+		colorspace = AVCOL_SPC_BT709;
 		break;
 	case VIDEO_CS_2100_PQ:
 		enc->context->color_primaries = AVCOL_PRI_BT2020;
 		enc->context->color_trc = AVCOL_TRC_SMPTE2084;
-		enc->context->colorspace = AVCOL_SPC_BT2020_NCL;
-		enc->context->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
+		colorspace = AVCOL_SPC_BT2020_NCL;
 		break;
 	case VIDEO_CS_2100_HLG:
 		enc->context->color_primaries = AVCOL_PRI_BT2020;
 		enc->context->color_trc = AVCOL_TRC_ARIB_STD_B67;
-		enc->context->colorspace = AVCOL_SPC_BT2020_NCL;
-		enc->context->chroma_sample_location = AVCHROMA_LOC_TOPLEFT;
+		colorspace = AVCOL_SPC_BT2020_NCL;
 	}
 
+	enc->context->colorspace = colorspace;
+	enc->context->chroma_sample_location =
+		determine_chroma_location(pix_fmt, colorspace);
+
 	if (keyint_sec)
 		enc->context->gop_size =
 			keyint_sec * voi->fps_num / voi->fps_den;