瀏覽代碼

libobs,UI: Add P216/P416 pixel formats

Will be useful for ProRes.
jpark37 2 年之前
父節點
當前提交
463bf0dff5

+ 3 - 1
UI/data/locale/en-US.ini

@@ -1148,7 +1148,7 @@ Basic.Settings.Advanced.General.ProcessPriority.Normal="Normal"
 Basic.Settings.Advanced.General.ProcessPriority.BelowNormal="Below Normal"
 Basic.Settings.Advanced.General.ProcessPriority.Idle="Idle"
 Basic.Settings.Advanced.FormatWarning="Warning: Color formats other than NV12/P010 are primarily intended for recording, and are not recommended when streaming. Streaming may incur increased CPU usage due to color format conversion."
-Basic.Settings.Advanced.FormatWarning10BitSdr="Warning: 10-bit formats are more commonly used with HDR color spaces."
+Basic.Settings.Advanced.FormatWarningPreciseSdr="Warning: High-precision formats are more commonly used with HDR color spaces."
 Basic.Settings.Advanced.FormatWarning2100="Warning: Rec. 2100 should use a format with more precision."
 Basic.Settings.Advanced.Audio.BufferingTime="Audio Buffering Time"
 Basic.Settings.Advanced.Video.ColorFormat="Color Format"
@@ -1157,6 +1157,8 @@ Basic.Settings.Advanced.Video.ColorFormat.I420="I420 (8-bit, 4:2:0, 3 planes)"
 Basic.Settings.Advanced.Video.ColorFormat.I444="I444 (8-bit, 4:4:4, 3 planes)"
 Basic.Settings.Advanced.Video.ColorFormat.P010="P010 (10-bit, 4:2:0, 2 planes)"
 Basic.Settings.Advanced.Video.ColorFormat.I010="I010 (10-bit, 4:2:0, 3 planes)"
+Basic.Settings.Advanced.Video.ColorFormat.P216="P216 (16-bit, 4:2:2, 2 planes)"
+Basic.Settings.Advanced.Video.ColorFormat.P416="P416 (16-bit, 4:4:4, 2 planes)"
 Basic.Settings.Advanced.Video.ColorFormat.BGRA="BGRA (8-bit)"
 Basic.Settings.Advanced.Video.ColorSpace="Color Space"
 Basic.Settings.Advanced.Video.ColorSpace.sRGB="sRGB"

+ 4 - 0
UI/window-basic-main.cpp

@@ -4393,6 +4393,10 @@ static inline enum video_format GetVideoFormatFromName(const char *name)
 		return VIDEO_FORMAT_I010;
 	else if (astrcmpi(name, "P010") == 0)
 		return VIDEO_FORMAT_P010;
+	else if (astrcmpi(name, "P216") == 0)
+		return VIDEO_FORMAT_P216;
+	else if (astrcmpi(name, "P416") == 0)
+		return VIDEO_FORMAT_P416;
 #if 0 //currently unsupported
 	else if (astrcmpi(name, "YVYU") == 0)
 		return VIDEO_FORMAT_YVYU;

+ 9 - 3
UI/window-basic-settings.cpp

@@ -1006,6 +1006,8 @@ void OBSBasicSettings::LoadColorSpaces()
 #define CF_I444_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.I444")
 #define CF_P010_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P010")
 #define CF_I010_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.I010")
+#define CF_P216_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P216")
+#define CF_P416_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.P416")
 #define CF_BGRA_STR QTStr("Basic.Settings.Advanced.Video.ColorFormat.BGRA")
 
 void OBSBasicSettings::LoadColorFormats()
@@ -1015,6 +1017,8 @@ void OBSBasicSettings::LoadColorFormats()
 	ui->colorFormat->addItem(CF_I444_STR, "I444");
 	ui->colorFormat->addItem(CF_P010_STR, "P010");
 	ui->colorFormat->addItem(CF_I010_STR, "I010");
+	ui->colorFormat->addItem(CF_P216_STR, "P216");
+	ui->colorFormat->addItem(CF_P416_STR, "P416");
 	ui->colorFormat->addItem(CF_BGRA_STR, "RGB"); // Avoid config break
 }
 
@@ -2599,7 +2603,8 @@ void OBSBasicSettings::UpdateColorFormatSpaceWarning()
 	switch (ui->colorSpace->currentIndex()) {
 	case 3: /* Rec.2100 (PQ) */
 	case 4: /* Rec.2100 (HLG) */
-		if (format == "P010") {
+		if ((format == "P010") || (format == "P216") ||
+		    (format == "P416")) {
 			ui->advancedMsg2->clear();
 		} else if (format == "I010") {
 			ui->advancedMsg2->setText(
@@ -2612,9 +2617,10 @@ void OBSBasicSettings::UpdateColorFormatSpaceWarning()
 	default:
 		if (format == "NV12") {
 			ui->advancedMsg2->clear();
-		} else if ((format == "I010") || (format == "P010")) {
+		} else if ((format == "I010") || (format == "P010") ||
+			   (format == "P216") || (format == "P416")) {
 			ui->advancedMsg2->setText(QTStr(
-				"Basic.Settings.Advanced.FormatWarning10BitSdr"));
+				"Basic.Settings.Advanced.FormatWarningPreciseSdr"));
 		} else {
 			ui->advancedMsg2->setText(
 				QTStr("Basic.Settings.Advanced.FormatWarning"));

+ 10 - 0
docs/sphinx/reference-libobs-media-io.rst

@@ -48,6 +48,16 @@ Video Handler
    - VIDEO_FORMAT_I010
    - VIDEO_FORMAT_P010
 
+   - VIDEO_FORMAT_I210
+
+   - VIDEO_FORMAT_I412
+
+   - VIDEO_FORMAT_YA2L
+
+   - VIDEO_FORMAT_P216
+
+   - VIDEO_FORMAT_P416
+
 ---------------------
 
 .. enum:: video_trc

+ 15 - 0
docs/sphinx/reference-outputs.rst

@@ -747,6 +747,21 @@ Functions used by outputs
            /* planar 4:2:0 format, 10 bpp */
            VIDEO_FORMAT_I010, /* three-plane */
            VIDEO_FORMAT_P010, /* two-plane, luma and packed chroma */
+
+           /* planar 4:2:2 format, 10 bpp */
+           VIDEO_FORMAT_I210,
+
+           /* planar 4:4:4 format, 12 bpp */
+           VIDEO_FORMAT_I412,
+
+           /* planar 4:4:4:4 format, 12 bpp */
+           VIDEO_FORMAT_YA2L,
+
+           /* planar 4:2:2 format, 16 bpp */
+           VIDEO_FORMAT_P216, /* two-plane, luma and packed chroma */
+
+           /* planar 4:4:4 format, 16 bpp */
+           VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */
    };
 
    enum video_colorspace {

+ 15 - 0
docs/sphinx/reference-sources.rst

@@ -1425,6 +1425,21 @@ Functions used by sources
            /* planar 4:2:0 format, 10 bpp */
            VIDEO_FORMAT_I010, /* three-plane */
            VIDEO_FORMAT_P010, /* two-plane, luma and packed chroma */
+
+           /* planar 4:2:2 format, 10 bpp */
+           VIDEO_FORMAT_I210,
+
+           /* planar 4:4:4 format, 12 bpp */
+           VIDEO_FORMAT_I412,
+
+           /* planar 4:4:4:4 format, 12 bpp */
+           VIDEO_FORMAT_YA2L,
+
+           /* planar 4:2:2 format, 16 bpp */
+           VIDEO_FORMAT_P216, /* two-plane, luma and packed chroma */
+
+           /* planar 4:4:4 format, 16 bpp */
+           VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */
    };
 
    struct obs_source_frame {

+ 230 - 0
libobs/data/format_conversion.effect

@@ -252,6 +252,58 @@ float PS_P010_SRGB_Y(FragPos frag_in) : TARGET
 	return y;
 }
 
+float PS_P216_PQ_Y_709_2020(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum;
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_st2084(rgb);
+	float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
+	return y;
+}
+
+float PS_P216_HLG_Y_709_2020(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum;
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_hlg(rgb, hdr_lw);
+	float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
+	return y;
+}
+
+float PS_P216_SRGB_Y(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
+	rgb = srgb_linear_to_nonlinear(rgb);
+	float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
+	return y;
+}
+
+float PS_P416_PQ_Y_709_2020(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum;
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_st2084(rgb);
+	float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
+	return y;
+}
+
+float PS_P416_HLG_Y_709_2020(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum;
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_hlg(rgb, hdr_lw);
+	float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
+	return y;
+}
+
+float PS_P416_SRGB_Y(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
+	rgb = srgb_linear_to_nonlinear(rgb);
+	float y = dot(color_vec0.xyz, rgb) + color_vec0.w;
+	return y;
+}
+
 float PS_I010_PQ_Y_709_2020(FragPos frag_in) : TARGET
 {
 	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb * sdr_white_nits_over_maximum;
@@ -333,6 +385,76 @@ float2 PS_P010_SRGB_UV_Wide(FragTexWide frag_in) : TARGET
 	return uv;
 }
 
+float2 PS_P216_PQ_UV_709_2020_Wide(FragTexWide frag_in) : TARGET
+{
+	float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb;
+	float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb;
+	float3 rgb = (rgb_left + rgb_right) * (0.5 * sdr_white_nits_over_maximum);
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_st2084(rgb);
+	float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
+	float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
+	float2 uv = float2(u, v);
+	return uv;
+}
+
+float2 PS_P216_HLG_UV_709_2020_Wide(FragTexWide frag_in) : TARGET
+{
+	float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb;
+	float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb;
+	float3 rgb = (rgb_left + rgb_right) * (0.5 * sdr_white_nits_over_maximum);
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_hlg(rgb, hdr_lw);
+	float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
+	float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
+	float2 uv = float2(u, v);
+	return uv;
+}
+
+float2 PS_P216_SRGB_UV_Wide(FragTexWide frag_in) : TARGET
+{
+	float3 rgb_left = image.Sample(def_sampler, frag_in.uuv.xz).rgb;
+	float3 rgb_right = image.Sample(def_sampler, frag_in.uuv.yz).rgb;
+	float3 rgb = (rgb_left + rgb_right) * 0.5;
+	rgb = srgb_linear_to_nonlinear(rgb);
+	float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
+	float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
+	float2 uv = float2(u, v);
+	return uv;
+}
+
+float2 PS_P416_PQ_UV_709_2020(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_st2084(rgb);
+	float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
+	float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
+	float2 uv = float2(u, v);
+	return uv;
+}
+
+float2 PS_P416_HLG_UV_709_2020(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
+	rgb = rec709_to_rec2020(rgb);
+	rgb = linear_to_hlg(rgb, hdr_lw);
+	float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
+	float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
+	float2 uv = float2(u, v);
+	return uv;
+}
+
+float2 PS_P416_SRGB_UV(FragPos frag_in) : TARGET
+{
+	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
+	rgb = srgb_linear_to_nonlinear(rgb);
+	float u = dot(color_vec1.xyz, rgb) + color_vec1.w;
+	float v = dot(color_vec2.xyz, rgb) + color_vec2.w;
+	float2 uv = float2(u, v);
+	return uv;
+}
+
 float PS_U(FragPos frag_in) : TARGET
 {
 	float3 rgb = image.Load(int3(frag_in.pos.xy, 0)).rgb;
@@ -1044,6 +1166,114 @@ technique P010_SRGB_UV
 	}
 }
 
+technique P216_PQ_Y
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P216_PQ_Y_709_2020(frag_in);
+	}
+}
+
+technique P216_HLG_Y
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P216_HLG_Y_709_2020(frag_in);
+	}
+}
+
+technique P216_SRGB_Y
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P216_SRGB_Y(frag_in);
+	}
+}
+
+technique P216_PQ_UV
+{
+	pass
+	{
+		vertex_shader = VSTexPos_Left(id);
+		pixel_shader  = PS_P216_PQ_UV_709_2020_Wide(frag_in);
+	}
+}
+
+technique P216_HLG_UV
+{
+	pass
+	{
+		vertex_shader = VSTexPos_Left(id);
+		pixel_shader  = PS_P216_HLG_UV_709_2020_Wide(frag_in);
+	}
+}
+
+technique P216_SRGB_UV
+{
+	pass
+	{
+		vertex_shader = VSTexPos_Left(id);
+		pixel_shader  = PS_P216_SRGB_UV_Wide(frag_in);
+	}
+}
+
+technique P416_PQ_Y
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P416_PQ_Y_709_2020(frag_in);
+	}
+}
+
+technique P416_HLG_Y
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P416_HLG_Y_709_2020(frag_in);
+	}
+}
+
+technique P416_SRGB_Y
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P416_SRGB_Y(frag_in);
+	}
+}
+
+technique P416_PQ_UV
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P416_PQ_UV_709_2020(frag_in);
+	}
+}
+
+technique P416_HLG_UV
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P416_HLG_UV_709_2020(frag_in);
+	}
+}
+
+technique P416_SRGB_UV
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PS_P416_SRGB_UV(frag_in);
+	}
+}
+
 technique UYVY_Reverse
 {
 	pass

+ 33 - 0
libobs/media-io/video-frame.c

@@ -303,6 +303,33 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
 		frame->linesize[1] = cbcr_width * 2;
 		break;
 	}
+
+	case VIDEO_FORMAT_P216: {
+		size = width * height * 2;
+		ALIGN_SIZE(size, alignment);
+		offsets[0] = size;
+		const uint32_t cbcr_width = (width + 1) & (UINT32_MAX - 1);
+		size += cbcr_width * height * 2;
+		ALIGN_SIZE(size, alignment);
+		frame->data[0] = bmalloc(size);
+		frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
+		frame->linesize[0] = width * 2;
+		frame->linesize[1] = cbcr_width * 2;
+		break;
+	}
+
+	case VIDEO_FORMAT_P416: {
+		size = width * height * 2;
+		ALIGN_SIZE(size, alignment);
+		offsets[0] = size;
+		size += width * height * 4;
+		ALIGN_SIZE(size, alignment);
+		frame->data[0] = bmalloc(size);
+		frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
+		frame->linesize[0] = width * 2;
+		frame->linesize[1] = width * 4;
+		break;
+	}
 	}
 }
 
@@ -362,5 +389,11 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
 		memcpy(dst->data[2], src->data[2], src->linesize[2] * cy);
 		memcpy(dst->data[3], src->data[3], src->linesize[3] * cy);
 		break;
+
+	case VIDEO_FORMAT_P216:
+	case VIDEO_FORMAT_P416:
+		memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
+		memcpy(dst->data[1], src->data[1], src->linesize[1] * cy);
+		break;
 	}
 }

+ 18 - 6
libobs/media-io/video-io.h

@@ -74,14 +74,20 @@ enum video_format {
 	VIDEO_FORMAT_I010, /* three-plane */
 	VIDEO_FORMAT_P010, /* two-plane, luma and packed chroma */
 
-	/* planar 4:2:2 10 bits */
-	VIDEO_FORMAT_I210, // Little Endian
+	/* planar 4:2:2 format, 10 bpp */
+	VIDEO_FORMAT_I210,
 
-	/* planar 4:4:4 12 bits */
-	VIDEO_FORMAT_I412, // Little Endian
+	/* planar 4:4:4 format, 12 bpp */
+	VIDEO_FORMAT_I412,
 
-	/* planar 4:4:4 12 bits with alpha */
-	VIDEO_FORMAT_YA2L, // Little Endian
+	/* planar 4:4:4:4 format, 12 bpp */
+	VIDEO_FORMAT_YA2L,
+
+	/* planar 4:2:2 format, 16 bpp */
+	VIDEO_FORMAT_P216, /* two-plane, luma and packed chroma */
+
+	/* planar 4:4:4 format, 16 bpp */
+	VIDEO_FORMAT_P416, /* two-plane, luma and packed chroma */
 };
 
 enum video_trc {
@@ -145,6 +151,8 @@ static inline bool format_is_yuv(enum video_format format)
 	case VIDEO_FORMAT_AYUV:
 	case VIDEO_FORMAT_I010:
 	case VIDEO_FORMAT_P010:
+	case VIDEO_FORMAT_P216:
+	case VIDEO_FORMAT_P416:
 		return true;
 	case VIDEO_FORMAT_NONE:
 	case VIDEO_FORMAT_RGBA:
@@ -203,6 +211,10 @@ static inline const char *get_video_format_name(enum video_format format)
 		return "I010";
 	case VIDEO_FORMAT_P010:
 		return "P010";
+	case VIDEO_FORMAT_P216:
+		return "P216";
+	case VIDEO_FORMAT_P416:
+		return "P416";
 	case VIDEO_FORMAT_NONE:;
 	}
 

+ 4 - 0
libobs/media-io/video-matrices.c

@@ -269,6 +269,10 @@ bool video_format_get_parameters_for_format(enum video_colorspace color_space,
 	case VIDEO_FORMAT_YA2L:
 		bpc = 12;
 		break;
+	case VIDEO_FORMAT_P216:
+	case VIDEO_FORMAT_P416:
+		bpc = 16;
+		break;
 	default:
 		bpc = 8;
 		break;

+ 8 - 6
libobs/media-io/video-scaler-ffmpeg.c

@@ -68,23 +68,25 @@ get_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;
 	case VIDEO_FORMAT_P010:
 		return AV_PIX_FMT_P010LE;
+#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
+	case VIDEO_FORMAT_P216:
+		return AV_PIX_FMT_P216LE;
+	case VIDEO_FORMAT_P416:
+		return AV_PIX_FMT_P416LE;
+#endif
 	case VIDEO_FORMAT_NONE:
 	case VIDEO_FORMAT_AYUV:
-		/* not supported by FFmpeg */
+	default:
 		return AV_PIX_FMT_NONE;
 	}
-
-	return AV_PIX_FMT_NONE;
 }
 
 static inline int get_ffmpeg_scale_type(enum video_scale_type type)

+ 2 - 0
libobs/obs-internal.h

@@ -909,6 +909,8 @@ convert_video_format(enum video_format format, enum video_trc trc)
 		case VIDEO_FORMAT_I210:
 		case VIDEO_FORMAT_I412:
 		case VIDEO_FORMAT_YA2L:
+		case VIDEO_FORMAT_P216:
+		case VIDEO_FORMAT_P416:
 			return GS_RGBA16F;
 		default:
 			return GS_BGRX;

+ 27 - 0
libobs/obs-video.c

@@ -729,6 +729,33 @@ static void set_gpu_converted_data(struct video_frame *output,
 
 		break;
 	}
+	case VIDEO_FORMAT_P216: {
+		const uint32_t width_x2 = info->width * 2;
+		const uint32_t height = info->height;
+
+		set_gpu_converted_plane(width_x2, height, input->linesize[0],
+					output->linesize[0], input->data[0],
+					output->data[0]);
+
+		set_gpu_converted_plane(width_x2, height, input->linesize[1],
+					output->linesize[1], input->data[1],
+					output->data[1]);
+
+		break;
+	}
+	case VIDEO_FORMAT_P416: {
+		const uint32_t height = info->height;
+
+		set_gpu_converted_plane(info->width * 2, height,
+					input->linesize[0], output->linesize[0],
+					input->data[0], output->data[0]);
+
+		set_gpu_converted_plane(info->width * 4, height,
+					input->linesize[1], output->linesize[1],
+					input->data[1], output->data[1]);
+
+		break;
+	}
 
 	case VIDEO_FORMAT_NONE:
 	case VIDEO_FORMAT_YVYU:

+ 82 - 2
libobs/obs.c

@@ -109,6 +109,36 @@ static inline void calc_gpu_conversion_sizes(struct obs_core_video_mix *video)
 			video->conversion_techs[1] = "P010_SRGB_UV";
 		}
 		break;
+	case VIDEO_FORMAT_P216:
+		video->conversion_needed = true;
+		video->conversion_width_i = 1.f / (float)info->width;
+		video->conversion_height_i = 1.f / (float)info->height;
+		if (info->colorspace == VIDEO_CS_2100_PQ) {
+			video->conversion_techs[0] = "P216_PQ_Y";
+			video->conversion_techs[1] = "P216_PQ_UV";
+		} else if (info->colorspace == VIDEO_CS_2100_HLG) {
+			video->conversion_techs[0] = "P216_HLG_Y";
+			video->conversion_techs[1] = "P216_HLG_UV";
+		} else {
+			video->conversion_techs[0] = "P216_SRGB_Y";
+			video->conversion_techs[1] = "P216_SRGB_UV";
+		}
+		break;
+	case VIDEO_FORMAT_P416:
+		video->conversion_needed = true;
+		video->conversion_width_i = 1.f / (float)info->width;
+		video->conversion_height_i = 1.f / (float)info->height;
+		if (info->colorspace == VIDEO_CS_2100_PQ) {
+			video->conversion_techs[0] = "P416_PQ_Y";
+			video->conversion_techs[1] = "P416_PQ_UV";
+		} else if (info->colorspace == VIDEO_CS_2100_HLG) {
+			video->conversion_techs[0] = "P416_HLG_Y";
+			video->conversion_techs[1] = "P416_HLG_UV";
+		} else {
+			video->conversion_techs[0] = "P416_SRGB_Y";
+			video->conversion_techs[1] = "P416_SRGB_UV";
+		}
+		break;
 	default:
 		break;
 	}
@@ -237,6 +267,26 @@ static bool obs_init_gpu_conversion(struct obs_core_video_mix *video)
 		if (!video->convert_textures[0] || !video->convert_textures[1])
 			success = false;
 		break;
+	case VIDEO_FORMAT_P216:
+		video->convert_textures[0] =
+			gs_texture_create(info->width, info->height, GS_R16, 1,
+					  NULL, GS_RENDER_TARGET);
+		video->convert_textures[1] =
+			gs_texture_create(info->width / 2, info->height,
+					  GS_RG16, 1, NULL, GS_RENDER_TARGET);
+		if (!video->convert_textures[0] || !video->convert_textures[1])
+			success = false;
+		break;
+	case VIDEO_FORMAT_P416:
+		video->convert_textures[0] =
+			gs_texture_create(info->width, info->height, GS_R16, 1,
+					  NULL, GS_RENDER_TARGET);
+		video->convert_textures[1] =
+			gs_texture_create(info->width, info->height, GS_RG16, 1,
+					  NULL, GS_RENDER_TARGET);
+		if (!video->convert_textures[0] || !video->convert_textures[1])
+			success = false;
+		break;
 	default:
 		break;
 	}
@@ -328,6 +378,26 @@ static bool obs_init_gpu_copy_surfaces(struct obs_core_video_mix *video,
 		if (!video->copy_surfaces[i][1])
 			return false;
 		break;
+	case VIDEO_FORMAT_P216:
+		video->copy_surfaces[i][0] = gs_stagesurface_create(
+			info->width, info->height, GS_R16);
+		if (!video->copy_surfaces[i][0])
+			return false;
+		video->copy_surfaces[i][1] = gs_stagesurface_create(
+			info->width / 2, info->height, GS_RG16);
+		if (!video->copy_surfaces[i][1])
+			return false;
+		break;
+	case VIDEO_FORMAT_P416:
+		video->copy_surfaces[i][0] = gs_stagesurface_create(
+			info->width, info->height, GS_R16);
+		if (!video->copy_surfaces[i][0])
+			return false;
+		video->copy_surfaces[i][1] = gs_stagesurface_create(
+			info->width, info->height, GS_RG16);
+		if (!video->copy_surfaces[i][1])
+			return false;
+		break;
 	default:
 		break;
 	}
@@ -349,6 +419,8 @@ static bool obs_init_textures(struct obs_core_video_mix *video)
 	case VIDEO_FORMAT_I210:
 	case VIDEO_FORMAT_I412:
 	case VIDEO_FORMAT_YA2L:
+	case VIDEO_FORMAT_P216:
+	case VIDEO_FORMAT_P416:
 		format = GS_RGBA16F;
 		break;
 	default:
@@ -398,9 +470,17 @@ static bool obs_init_textures(struct obs_core_video_mix *video)
 		space = GS_CS_709_EXTENDED;
 		break;
 	default:
-		if (info->format == VIDEO_FORMAT_I010 ||
-		    info->format == VIDEO_FORMAT_P010)
+		switch (info->format) {
+		case VIDEO_FORMAT_I010:
+		case VIDEO_FORMAT_P010:
+		case VIDEO_FORMAT_P216:
+		case VIDEO_FORMAT_P416:
 			space = GS_CS_SRGB_16F;
+			break;
+		default:
+			space = GS_CS_SRGB;
+			break;
+		}
 		break;
 	}
 

+ 6 - 0
plugins/obs-ffmpeg/obs-ffmpeg-formats.h

@@ -56,6 +56,12 @@ obs_to_ffmpeg_video_format(enum video_format format)
 		return AV_PIX_FMT_YUV420P10LE;
 	case VIDEO_FORMAT_P010:
 		return AV_PIX_FMT_P010LE;
+#if LIBAVUTIL_BUILD >= AV_VERSION_INT(57, 17, 100)
+	case VIDEO_FORMAT_P216:
+		return AV_PIX_FMT_P216LE;
+	case VIDEO_FORMAT_P416:
+		return AV_PIX_FMT_P416LE;
+#endif
 	case VIDEO_FORMAT_NONE:
 	case VIDEO_FORMAT_AYUV:
 	default: