Browse Source

libobs: Add support for reading I420 PQ

Not normally a valid combination, but Xbox writes 8-bit HDR videos.
jpark37 3 years ago
parent
commit
2a0d8d1c9c
4 changed files with 64 additions and 30 deletions
  1. 30 8
      libobs/data/format_conversion.effect
  2. 23 17
      libobs/obs-internal.h
  3. 1 1
      libobs/obs-source-deinterlace.c
  4. 10 4
      libobs/obs-source.c

+ 30 - 8
libobs/data/format_conversion.effect

@@ -477,6 +477,19 @@ float3 PSPlanar420_Reverse(VertTexPos frag_in) : TARGET
 	return rgb;
 }
 
+float4 PSPlanar420_PQ_Reverse(VertTexPos frag_in) : TARGET
+{
+	float y = image.Load(int3(frag_in.pos.xy, 0)).x;
+	int3 xy0_chroma = int3(frag_in.uv, 0);
+	float cb = image1.Load(xy0_chroma).x;
+	float cr = image2.Load(xy0_chroma).x;
+	float3 yuv = float3(y, cb, cr);
+	float3 pq = YUV_to_RGB(yuv);
+	float3 hdr2020 = st2084_to_linear(pq) * maximum_over_sdr_white_nits;
+	float3 rgb = rec2020_to_rec709(hdr2020);
+	return float4(rgb, 1.);
+}
+
 float4 PSPlanar420A_Reverse(VertTexPos frag_in) : TARGET
 {
 	int3 xy0_luma = int3(frag_in.pos.xy, 0);
@@ -511,7 +524,7 @@ float4 PSPlanar422_10LE_Reverse(FragPosWide frag_in) : TARGET
 	yuv *= 65535. / 1023.;
 	float3 rgb = YUV_to_RGB(yuv);
 	rgb = srgb_nonlinear_to_linear(rgb);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSPlanar422A_Reverse(FragPosWide frag_in) : TARGET
@@ -548,7 +561,7 @@ float4 PSPlanar444_12LE_Reverse(FragPos frag_in) : TARGET
 	yuv *= 65535. / 4095.;
 	float3 rgb = YUV_to_RGB(yuv);
 	rgb = srgb_nonlinear_to_linear(rgb);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSPlanar444A_Reverse(FragPos frag_in) : TARGET
@@ -603,7 +616,7 @@ float4 PSI010_SRGB_Reverse(VertTexPos frag_in) : TARGET
 	float3 yuv = float3(y, cb, cr);
 	float3 rgb = YUV_to_RGB(yuv);
 	rgb = srgb_nonlinear_to_linear(rgb);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSI010_PQ_2020_709_Reverse(VertTexPos frag_in) : TARGET
@@ -617,7 +630,7 @@ float4 PSI010_PQ_2020_709_Reverse(VertTexPos frag_in) : TARGET
 	float3 pq = YUV_to_RGB(yuv);
 	float3 hdr2020 = st2084_to_linear(pq) * maximum_over_sdr_white_nits;
 	float3 rgb = rec2020_to_rec709(hdr2020);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSI010_HLG_2020_709_Reverse(VertTexPos frag_in) : TARGET
@@ -631,7 +644,7 @@ float4 PSI010_HLG_2020_709_Reverse(VertTexPos frag_in) : TARGET
 	float3 hlg = YUV_to_RGB(yuv);
 	float3 hdr2020 = hlg_to_linear(hlg, hlg_exponent) * maximum_over_sdr_white_nits;
 	float3 rgb = rec2020_to_rec709(hdr2020);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSP010_SRGB_Reverse(VertTexPos frag_in) : TARGET
@@ -641,7 +654,7 @@ float4 PSP010_SRGB_Reverse(VertTexPos frag_in) : TARGET
 	float3 yuv = float3(y, cbcr);
 	float3 rgb = YUV_to_RGB(yuv);
 	rgb = srgb_nonlinear_to_linear(rgb);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSP010_PQ_2020_709_Reverse(VertTexPos frag_in) : TARGET
@@ -652,7 +665,7 @@ float4 PSP010_PQ_2020_709_Reverse(VertTexPos frag_in) : TARGET
 	float3 pq = YUV_to_RGB(yuv);
 	float3 hdr2020 = st2084_to_linear(pq) * maximum_over_sdr_white_nits;
 	float3 rgb = rec2020_to_rec709(hdr2020);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float4 PSP010_HLG_2020_709_Reverse(VertTexPos frag_in) : TARGET
@@ -663,7 +676,7 @@ float4 PSP010_HLG_2020_709_Reverse(VertTexPos frag_in) : TARGET
 	float3 hlg = YUV_to_RGB(yuv);
 	float3 hdr2020 = hlg_to_linear(hlg, hlg_exponent) * maximum_over_sdr_white_nits;
 	float3 rgb = rec2020_to_rec709(hdr2020);
-	return float4(rgb, 1.0);
+	return float4(rgb, 1.);
 }
 
 float3 PSY800_Limited(FragPos frag_in) : TARGET
@@ -943,6 +956,15 @@ technique I420_Reverse
 	}
 }
 
+technique I420_PQ_Reverse
+{
+	pass
+	{
+		vertex_shader = VSTexPosHalfHalf_Reverse(id);
+		pixel_shader  = PSPlanar420_PQ_Reverse(frag_in);
+	}
+}
+
 technique I40A_Reverse
 {
 	pass

+ 23 - 17
libobs/obs-internal.h

@@ -879,25 +879,31 @@ static inline bool frame_out_of_bounds(const obs_source_t *source, uint64_t ts)
 }
 
 static inline enum gs_color_format
-convert_video_format(enum video_format format)
+convert_video_format(enum video_format format, enum video_trc trc)
 {
-	switch (format) {
-	case VIDEO_FORMAT_RGBA:
-		return GS_RGBA;
-	case VIDEO_FORMAT_BGRA:
-	case VIDEO_FORMAT_I40A:
-	case VIDEO_FORMAT_I42A:
-	case VIDEO_FORMAT_YUVA:
-	case VIDEO_FORMAT_AYUV:
-		return GS_BGRA;
-	case VIDEO_FORMAT_I010:
-	case VIDEO_FORMAT_P010:
-	case VIDEO_FORMAT_I210:
-	case VIDEO_FORMAT_I412:
-	case VIDEO_FORMAT_YA2L:
+	switch (trc) {
+	case VIDEO_TRC_PQ:
+	case VIDEO_TRC_HLG:
 		return GS_RGBA16F;
 	default:
-		return GS_BGRX;
+		switch (format) {
+		case VIDEO_FORMAT_RGBA:
+			return GS_RGBA;
+		case VIDEO_FORMAT_BGRA:
+		case VIDEO_FORMAT_I40A:
+		case VIDEO_FORMAT_I42A:
+		case VIDEO_FORMAT_YUVA:
+		case VIDEO_FORMAT_AYUV:
+			return GS_BGRA;
+		case VIDEO_FORMAT_I010:
+		case VIDEO_FORMAT_P010:
+		case VIDEO_FORMAT_I210:
+		case VIDEO_FORMAT_I412:
+		case VIDEO_FORMAT_YA2L:
+			return GS_RGBA16F;
+		default:
+			return GS_BGRX;
+		}
 	}
 }
 
@@ -905,7 +911,7 @@ static inline enum gs_color_space convert_video_space(enum video_format format,
 						      enum video_trc trc)
 {
 	enum gs_color_space space = GS_CS_SRGB;
-	if (convert_video_format(format) == GS_RGBA16F) {
+	if (convert_video_format(format, trc) == GS_RGBA16F) {
 		space = (trc == VIDEO_TRC_SRGB) ? GS_CS_SRGB_16F
 						: GS_CS_709_EXTENDED;
 	}

+ 1 - 1
libobs/obs-source-deinterlace.c

@@ -234,7 +234,7 @@ void deinterlace_process_last_frame(obs_source_t *s, uint64_t sys_time)
 void set_deinterlace_texture_size(obs_source_t *source)
 {
 	const enum gs_color_format format =
-		convert_video_format(source->async_format);
+		convert_video_format(source->async_format, source->async_trc);
 
 	if (source->async_gpu_conversion) {
 		source->async_prev_texrender =

+ 10 - 4
libobs/obs-source.c

@@ -1546,6 +1546,7 @@ enum convert_type {
 	CONVERT_NONE,
 	CONVERT_NV12,
 	CONVERT_420,
+	CONVERT_420_PQ,
 	CONVERT_420_A,
 	CONVERT_422,
 	CONVERT_422P10LE,
@@ -1572,7 +1573,7 @@ static inline enum convert_type get_convert_type(enum video_format format,
 {
 	switch (format) {
 	case VIDEO_FORMAT_I420:
-		return CONVERT_420;
+		return (trc == VIDEO_TRC_PQ) ? CONVERT_420_PQ : CONVERT_420;
 	case VIDEO_FORMAT_NV12:
 		return CONVERT_NV12;
 	case VIDEO_FORMAT_I444:
@@ -1874,7 +1875,8 @@ static inline bool set_rgb_limited_sizes(struct obs_source *source,
 {
 	source->async_convert_width[0] = frame->width;
 	source->async_convert_height[0] = frame->height;
-	source->async_texture_formats[0] = convert_video_format(frame->format);
+	source->async_texture_formats[0] =
+		convert_video_format(frame->format, frame->trc);
 	source->async_channel_count = 1;
 	return true;
 }
@@ -1935,6 +1937,7 @@ static inline bool init_gpu_conversion(struct obs_source *source,
 		return set_packed422_sizes(source, frame);
 
 	case CONVERT_420:
+	case CONVERT_420_PQ:
 		return set_planar420_sizes(source, frame);
 
 	case CONVERT_422:
@@ -2026,7 +2029,8 @@ bool set_async_texture_size(struct obs_source *source,
 	source->async_texrender = NULL;
 	source->async_prev_texrender = NULL;
 
-	const enum gs_color_format format = convert_video_format(frame->format);
+	const enum gs_color_format format =
+		convert_video_format(frame->format, frame->trc);
 	const bool async_gpu_conversion = (cur != CONVERT_NONE) &&
 					  init_gpu_conversion(source, frame);
 	source->async_gpu_conversion = async_gpu_conversion;
@@ -2064,6 +2068,7 @@ static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
 	case CONVERT_RGB_LIMITED:
 	case CONVERT_BGR3:
 	case CONVERT_420:
+	case CONVERT_420_PQ:
 	case CONVERT_422:
 	case CONVERT_422P10LE:
 	case CONVERT_NV12:
@@ -2107,7 +2112,8 @@ static const char *select_conversion_technique(enum video_format format,
 		return "YVYU_Reverse";
 
 	case VIDEO_FORMAT_I420:
-		return "I420_Reverse";
+		return (trc == VIDEO_TRC_PQ) ? "I420_PQ_Reverse"
+					     : "I420_Reverse";
 
 	case VIDEO_FORMAT_NV12:
 		return "NV12_Reverse";