Browse Source

obs-ffmpeg: Improve color space handling

Add support for VIDEO_CS_SRGB.

Use SMPTE 170M for 601 instead of undef/BT470BG. This is the
American/Chromium way of handling 601.

Add color metadata to the container file as well via ffmpeg-mux.
jpark37 5 years ago
parent
commit
37f01b35f6

+ 20 - 0
plugins/obs-ffmpeg/ffmpeg-mux/ffmpeg-mux.c

@@ -79,6 +79,10 @@ struct main_params {
 	int height;
 	int fps_num;
 	int fps_den;
+	int color_primaries;
+	int color_trc;
+	int colorspace;
+	int color_range;
 	char *acodec;
 	char *muxer_settings;
 };
@@ -249,6 +253,18 @@ static bool init_params(int *argc, char ***argv, struct main_params *params,
 			return false;
 		if (!get_opt_int(argc, argv, &params->height, "video height"))
 			return false;
+		if (!get_opt_int(argc, argv, &params->color_primaries,
+				 "video color primaries"))
+			return false;
+		if (!get_opt_int(argc, argv, &params->color_trc,
+				 "video color trc"))
+			return false;
+		if (!get_opt_int(argc, argv, &params->colorspace,
+				 "video colorspace"))
+			return false;
+		if (!get_opt_int(argc, argv, &params->color_range,
+				 "video color range"))
+			return false;
 		if (!get_opt_int(argc, argv, &params->fps_num, "video fps num"))
 			return false;
 		if (!get_opt_int(argc, argv, &params->fps_den, "video fps den"))
@@ -327,6 +343,10 @@ static void create_video_stream(struct ffmpeg_mux *ffm)
 	context->height = ffm->params.height;
 	context->coded_width = ffm->params.width;
 	context->coded_height = ffm->params.height;
+	context->color_primaries = ffm->params.color_primaries;
+	context->color_trc = ffm->params.color_trc;
+	context->colorspace = ffm->params.colorspace;
+	context->color_range = ffm->params.color_range;
 	context->extradata = extradata;
 	context->extradata_size = ffm->video_header.size;
 	context->time_base =

+ 19 - 3
plugins/obs-ffmpeg/jim-nvenc.c

@@ -429,9 +429,25 @@ static bool init_encoder(struct nvenc_data *enc, obs_data_t *settings)
 	vui_params->videoSignalTypePresentFlag = 1;
 	vui_params->videoFullRangeFlag = (voi->range == VIDEO_RANGE_FULL);
 	vui_params->colourDescriptionPresentFlag = 1;
-	vui_params->colourMatrix = (voi->colorspace == VIDEO_CS_709) ? 1 : 5;
-	vui_params->colourPrimaries = 1;
-	vui_params->transferCharacteristics = 1;
+
+	switch (voi->colorspace) {
+	case VIDEO_CS_DEFAULT:
+	case VIDEO_CS_601:
+		vui_params->colourPrimaries = 6;
+		vui_params->transferCharacteristics = 6;
+		vui_params->colourMatrix = 6;
+		break;
+	case VIDEO_CS_709:
+		vui_params->colourPrimaries = 1;
+		vui_params->transferCharacteristics = 1;
+		vui_params->colourMatrix = 1;
+		break;
+	case VIDEO_CS_SRGB:
+		vui_params->colourPrimaries = 1;
+		vui_params->transferCharacteristics = 13;
+		vui_params->colourMatrix = 1;
+		break;
+	}
 
 	enc->bframes = bf > 0;
 

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

@@ -156,10 +156,37 @@ static void add_video_encoder_params(struct ffmpeg_muxer *stream,
 
 	obs_data_release(settings);
 
-	dstr_catf(cmd, "%s %d %d %d %d %d ", obs_encoder_get_codec(vencoder),
-		  bitrate, obs_output_get_width(stream->output),
-		  obs_output_get_height(stream->output), (int)info->fps_num,
-		  (int)info->fps_den);
+	enum AVColorPrimaries pri = AVCOL_PRI_UNSPECIFIED;
+	enum AVColorTransferCharacteristic trc = AVCOL_TRC_UNSPECIFIED;
+	enum AVColorSpace spc = AVCOL_SPC_UNSPECIFIED;
+	switch (info->colorspace) {
+	case VIDEO_CS_DEFAULT:
+	case VIDEO_CS_601:
+		pri = AVCOL_PRI_SMPTE170M;
+		trc = AVCOL_TRC_SMPTE170M;
+		spc = AVCOL_SPC_SMPTE170M;
+		break;
+	case VIDEO_CS_709:
+		pri = AVCOL_PRI_BT709;
+		trc = AVCOL_TRC_BT709;
+		spc = AVCOL_SPC_BT709;
+		break;
+	case VIDEO_CS_SRGB:
+		pri = AVCOL_PRI_BT709;
+		trc = AVCOL_TRC_IEC61966_2_1;
+		spc = AVCOL_SPC_BT709;
+		break;
+	}
+
+	const enum AVColorRange range = (info->range == VIDEO_RANGE_FULL)
+						? AVCOL_RANGE_JPEG
+						: AVCOL_RANGE_MPEG;
+
+	dstr_catf(cmd, "%s %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, (int)info->fps_num, (int)info->fps_den);
 }
 
 static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder)

+ 19 - 3
plugins/obs-ffmpeg/obs-ffmpeg-nvenc.c

@@ -235,14 +235,30 @@ static bool nvenc_update(void *data, obs_data_t *settings)
 	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->colorspace = info.colorspace == VIDEO_CS_709
-					   ? AVCOL_SPC_BT709
-					   : AVCOL_SPC_BT470BG;
 	enc->context->color_range = info.range == VIDEO_RANGE_FULL
 					    ? AVCOL_RANGE_JPEG
 					    : AVCOL_RANGE_MPEG;
 	enc->context->max_b_frames = bf;
 
+	switch (info.colorspace) {
+	case VIDEO_CS_DEFAULT:
+	case VIDEO_CS_601:
+		enc->context->color_trc = AVCOL_TRC_SMPTE170M;
+		enc->context->color_primaries = AVCOL_PRI_SMPTE170M;
+		enc->context->colorspace = AVCOL_SPC_SMPTE170M;
+		break;
+	case VIDEO_CS_709:
+		enc->context->color_trc = AVCOL_TRC_BT709;
+		enc->context->color_primaries = AVCOL_PRI_BT709;
+		enc->context->colorspace = AVCOL_SPC_BT709;
+		break;
+	case VIDEO_CS_SRGB:
+		enc->context->color_trc = AVCOL_TRC_IEC61966_2_1;
+		enc->context->color_primaries = AVCOL_PRI_BT709;
+		enc->context->colorspace = AVCOL_SPC_BT709;
+		break;
+	}
+
 	if (keyint_sec)
 		enc->context->gop_size =
 			keyint_sec * voi->fps_num / voi->fps_den;

+ 37 - 10
plugins/obs-ffmpeg/obs-ffmpeg-output.c

@@ -169,8 +169,10 @@ static bool open_video_codec(struct ffmpeg_data *data)
 	data->vframe->format = context->pix_fmt;
 	data->vframe->width = context->width;
 	data->vframe->height = context->height;
-	data->vframe->colorspace = data->config.color_space;
 	data->vframe->color_range = data->config.color_range;
+	data->vframe->color_primaries = data->config.color_primaries;
+	data->vframe->color_trc = data->config.color_trc;
+	data->vframe->colorspace = data->config.colorspace;
 
 	ret = av_frame_get_buffer(data->vframe, base_get_alignment());
 	if (ret < 0) {
@@ -225,8 +227,10 @@ static bool create_video_stream(struct ffmpeg_data *data)
 	context->time_base = (AVRational){ovi.fps_den, ovi.fps_num};
 	context->gop_size = data->config.gop_size;
 	context->pix_fmt = closest_format;
-	context->colorspace = data->config.color_space;
 	context->color_range = data->config.color_range;
+	context->color_primaries = data->config.color_primaries;
+	context->color_trc = data->config.color_trc;
+	context->colorspace = data->config.colorspace;
 	context->thread_count = 0;
 
 	data->video->time_base = context->time_base;
@@ -1057,16 +1061,39 @@ static bool try_connect(struct ffmpeg_output *output)
 	config.audio_tracks = (int)obs_output_get_mixers(output->output);
 	config.audio_mix_count = get_audio_mix_count(config.audio_tracks);
 
+	config.color_range = voi->range == VIDEO_RANGE_FULL ? AVCOL_RANGE_JPEG
+							    : AVCOL_RANGE_MPEG;
+	switch (voi->colorspace) {
+	case VIDEO_CS_DEFAULT:
+	case VIDEO_CS_601:
+		config.color_primaries = AVCOL_PRI_SMPTE170M;
+		config.color_trc = AVCOL_TRC_SMPTE170M;
+		break;
+	case VIDEO_CS_709:
+		config.color_primaries = AVCOL_PRI_BT709;
+		config.color_trc = AVCOL_TRC_BT709;
+		break;
+	case VIDEO_CS_SRGB:
+		config.color_primaries = AVCOL_PRI_BT709;
+		config.color_trc = AVCOL_TRC_IEC61966_2_1;
+		break;
+	}
+
 	if (format_is_yuv(voi->format)) {
-		config.color_range = voi->range == VIDEO_RANGE_FULL
-					     ? AVCOL_RANGE_JPEG
-					     : AVCOL_RANGE_MPEG;
-		config.color_space = voi->colorspace == VIDEO_CS_709
-					     ? AVCOL_SPC_BT709
-					     : AVCOL_SPC_BT470BG;
+		switch (voi->colorspace) {
+		case VIDEO_CS_DEFAULT:
+		case VIDEO_CS_601:
+			config.colorspace = AVCOL_SPC_SMPTE170M;
+			break;
+		case VIDEO_CS_709:
+			config.colorspace = AVCOL_SPC_BT709;
+			break;
+		case VIDEO_CS_SRGB:
+			config.colorspace = AVCOL_SPC_BT709;
+			break;
+		}
 	} else {
-		config.color_range = AVCOL_RANGE_UNSPECIFIED;
-		config.color_space = AVCOL_SPC_RGB;
+		config.colorspace = AVCOL_SPC_RGB;
 	}
 
 	if (config.format == AV_PIX_FMT_NONE) {

+ 3 - 1
plugins/obs-ffmpeg/obs-ffmpeg-output.h

@@ -23,7 +23,9 @@ struct ffmpeg_cfg {
 	int audio_tracks;
 	enum AVPixelFormat format;
 	enum AVColorRange color_range;
-	enum AVColorSpace color_space;
+	enum AVColorPrimaries color_primaries;
+	enum AVColorTransferCharacteristic color_trc;
+	enum AVColorSpace colorspace;
 	int scale_width;
 	int scale_height;
 	int width;