فهرست منبع

obs-ffmpeg: Add max luminance metadata for PQ

Necessary for video player to remap display ranges.
jpark37 3 سال پیش
والد
کامیت
0d72c314d4

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

@@ -30,6 +30,7 @@
 #include <libavcodec/avcodec.h>
 #include <libavformat/avformat.h>
 #include <libavutil/channel_layout.h>
+#include <libavutil/mastering_display_metadata.h>
 
 #define ANSI_COLOR_RED "\x1b[0;91m"
 #define ANSI_COLOR_MAGENTA "\x1b[0;95m"
@@ -93,6 +94,7 @@ struct main_params {
 	int color_trc;
 	int colorspace;
 	int color_range;
+	int max_luminance;
 	char *acodec;
 	char *muxer_settings;
 };
@@ -320,6 +322,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->max_luminance,
+				 "video max luminance"))
+			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"))
@@ -415,6 +420,18 @@ static void create_video_stream(struct ffmpeg_mux *ffm)
 #endif
 	ffm->video_stream->avg_frame_rate = av_inv_q(context->time_base);
 
+	if (ffm->params.max_luminance > 0) {
+		AVMasteringDisplayMetadata *const mastering =
+			av_mastering_display_metadata_alloc();
+		mastering->max_luminance =
+			av_make_q(ffm->params.max_luminance, 1);
+		mastering->has_luminance = 1;
+		av_stream_add_side_data(ffm->video_stream,
+					AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
+					(uint8_t *)mastering,
+					sizeof(*mastering));
+	}
+
 	if (ffm->output->oformat->flags & AVFMT_GLOBALHEADER)
 		context->flags |= CODEC_FLAG_GLOBAL_H;
 

+ 8 - 2
plugins/obs-ffmpeg/obs-ffmpeg-mux.c

@@ -162,11 +162,17 @@ static void add_video_encoder_params(struct ffmpeg_muxer *stream,
 						? AVCOL_RANGE_JPEG
 						: AVCOL_RANGE_MPEG;
 
-	dstr_catf(cmd, "%s %d %d %d %d %d %d %d %d %d ",
+	const int max_luminance =
+		(trc == AVCOL_TRC_SMPTE2084)
+			? (int)obs_get_video_hdr_nominal_peak_level()
+			: 0;
+
+	dstr_catf(cmd, "%s %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, (int)info->fps_num, (int)info->fps_den);
+		  (int)spc, (int)range, max_luminance, (int)info->fps_num,
+		  (int)info->fps_den);
 }
 
 static void add_audio_encoder_params(struct dstr *cmd, obs_encoder_t *aencoder)

+ 13 - 0
plugins/obs-ffmpeg/obs-ffmpeg-output.c

@@ -26,6 +26,7 @@
 #include "obs-ffmpeg-formats.h"
 #include "obs-ffmpeg-compat.h"
 #include <libavutil/channel_layout.h>
+#include <libavutil/mastering_display_metadata.h>
 
 struct ffmpeg_output {
 	obs_output_t *output;
@@ -222,6 +223,18 @@ static bool create_video_stream(struct ffmpeg_data *data)
 			data->config.video_encoder))
 		return false;
 
+	if (data->config.color_trc == AVCOL_TRC_SMPTE2084) {
+		AVMasteringDisplayMetadata *const mastering =
+			av_mastering_display_metadata_alloc();
+		mastering->max_luminance = av_make_q(
+			(int)obs_get_video_hdr_nominal_peak_level(), 1);
+		mastering->has_luminance = 1;
+		av_stream_add_side_data(data->video,
+					AV_PKT_DATA_MASTERING_DISPLAY_METADATA,
+					(uint8_t *)mastering,
+					sizeof(*mastering));
+	}
+
 	closest_format = data->config.format;
 	if (data->vcodec->pix_fmts) {
 		closest_format = avcodec_find_best_pix_fmt_of_list(

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

@@ -27,6 +27,7 @@ struct ffmpeg_cfg {
 	enum AVColorPrimaries color_primaries;
 	enum AVColorTransferCharacteristic color_trc;
 	enum AVColorSpace colorspace;
+	int max_luminance;
 	int scale_width;
 	int scale_height;
 	int width;