Selaa lähdekoodia

libobs: Add VIDEO_FORMAT_R10L

Support 10-bit packed format that DeckLink uses.
jpark37 2 vuotta sitten
vanhempi
sitoutus
7669da1ea8

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

@@ -60,6 +60,8 @@ Video Handler
 
    - VIDEO_FORMAT_V210
 
+   - VIDEO_FORMAT_R10L
+
 ---------------------
 
 .. enum:: video_trc

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

@@ -827,6 +827,9 @@ Functions used by outputs
 
            /* packed 4:2:2 format, 10 bpp */
            VIDEO_FORMAT_V210,
+
+           /* packed uncompressed 10-bit format */
+           VIDEO_FORMAT_R10L,
    };
 
    enum video_colorspace {

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

@@ -1470,6 +1470,9 @@ Functions used by sources
 
            /* packed 4:2:2 format, 10 bpp */
            VIDEO_FORMAT_V210,
+
+           /* packed uncompressed 10-bit format */
+           VIDEO_FORMAT_R10L,
    };
 
    struct obs_source_frame {

+ 120 - 0
libobs/data/format_conversion.effect

@@ -1054,6 +1054,72 @@ float3 PSBGR3_Full(FragPos frag_in) : TARGET
 	return rgb;
 }
 
+float3 compute_r10l_reverse(float2 pos, bool limited)
+{
+	float4 xyzw = image.Load(int3(pos, 0)).bgra;
+	uint4 xyzw255 = uint4(mad(xyzw, 255., 0.5));
+	uint r = ((xyzw255.z & 0xC0u) >> 6) | (xyzw255.w << 2);
+	uint g = ((xyzw255.y & 0xFu) >> 4) | ((xyzw255.z & 0x3Fu) << 4);
+	uint b = (xyzw255.x >> 2) | ((xyzw255.y & 0xFu) << 6);
+	float3 rgb = float3(uint3(r, g, b));
+	if (limited)
+	{
+		rgb = mad(rgb, 1. / 876., -16. / 219.);
+	}
+	else
+	{
+		rgb /= 1023.;
+	}
+
+	return rgb;
+}
+
+float4 PSR10L_SRGB_Full_Reverse(FragPos frag_in) : TARGET
+{
+	float3 rgb = compute_r10l_reverse(frag_in.pos.xy, false);
+	rgb = srgb_nonlinear_to_linear(rgb);
+	return float4(rgb, 1.);
+}
+
+float4 PSR10L_PQ_2020_709_Full_Reverse(FragPos frag_in) : TARGET
+{
+	float3 pq = compute_r10l_reverse(frag_in.pos.xy, false);
+	float3 hdr2020 = st2084_to_linear_eetf(pq, hdr_lw, hdr_lmax) * maximum_over_sdr_white_nits;
+	float3 rgb = rec2020_to_rec709(hdr2020);
+	return float4(rgb, 1.);
+}
+
+float4 PSR10L_HLG_2020_709_Full_Reverse(FragPos frag_in) : TARGET
+{
+	float3 hlg = compute_r10l_reverse(frag_in.pos.xy, false);
+	float3 hdr2020 = hlg_to_linear(hlg, hlg_exponent) * maximum_over_sdr_white_nits;
+	float3 rgb = rec2020_to_rec709(hdr2020);
+	return float4(rgb, 1.);
+}
+
+float4 PSR10L_SRGB_Limited_Reverse(FragPos frag_in) : TARGET
+{
+	float3 rgb = compute_r10l_reverse(frag_in.pos.xy, true);
+	rgb = srgb_nonlinear_to_linear(rgb);
+	return float4(rgb, 1.);
+}
+
+float4 PSR10L_PQ_2020_709_Limited_Reverse(FragPos frag_in) : TARGET
+{
+	float3 pq = compute_r10l_reverse(frag_in.pos.xy, true);
+	float3 hdr2020 = st2084_to_linear_eetf(pq, hdr_lw, hdr_lmax) * maximum_over_sdr_white_nits;
+	float3 rgb = rec2020_to_rec709(hdr2020);
+	return float4(rgb, 1.);
+}
+
+float4 PSR10L_HLG_2020_709_Limited_Reverse(FragPos frag_in) : TARGET
+{
+	float3 hlg = compute_r10l_reverse(frag_in.pos.xy, true);
+	float3 hdr2020 = hlg_to_linear(hlg, hlg_exponent) * maximum_over_sdr_white_nits;
+	float3 rgb = rec2020_to_rec709(hdr2020);
+	return float4(rgb, 1.);
+}
+
 technique Planar_Y
 {
 	pass
@@ -1701,3 +1767,57 @@ technique BGR3_Full
 		pixel_shader  = PSBGR3_Full(frag_in);
 	}
 }
+
+technique R10L_SRGB_Full_Reverse
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PSR10L_SRGB_Full_Reverse(frag_in);
+	}
+}
+
+technique R10L_PQ_2020_709_Full_Reverse
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PSR10L_PQ_2020_709_Full_Reverse(frag_in);
+	}
+}
+
+technique R10L_HLG_2020_709_Full_Reverse
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PSR10L_HLG_2020_709_Full_Reverse(frag_in);
+	}
+}
+
+technique R10L_SRGB_Limited_Reverse
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PSR10L_SRGB_Limited_Reverse(frag_in);
+	}
+}
+
+technique R10L_PQ_2020_709_Limited_Reverse
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PSR10L_PQ_2020_709_Limited_Reverse(frag_in);
+	}
+}
+
+technique R10L_HLG_2020_709_Limited_Reverse
+{
+	pass
+	{
+		vertex_shader = VSPos(id);
+		pixel_shader  = PSR10L_HLG_2020_709_Limited_Reverse(frag_in);
+	}
+}

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

@@ -339,6 +339,13 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
 		frame->linesize[0] = adjusted_width;
 		break;
 	}
+
+	case VIDEO_FORMAT_R10L:
+		size = width * height * 4;
+		ALIGN_SIZE(size, alignment);
+		frame->data[0] = bmalloc(size);
+		frame->linesize[0] = width * 4;
+		break;
 	}
 }
 
@@ -372,6 +379,7 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
 	case VIDEO_FORMAT_BGR3:
 	case VIDEO_FORMAT_AYUV:
 	case VIDEO_FORMAT_V210:
+	case VIDEO_FORMAT_R10L:
 		memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
 		break;
 

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

@@ -91,6 +91,9 @@ enum video_format {
 
 	/* packed 4:2:2 format, 10 bpp */
 	VIDEO_FORMAT_V210,
+
+	/* packed uncompressed 10-bit format */
+	VIDEO_FORMAT_R10L,
 };
 
 enum video_trc {
@@ -164,6 +167,7 @@ static inline bool format_is_yuv(enum video_format format)
 	case VIDEO_FORMAT_BGRX:
 	case VIDEO_FORMAT_Y800:
 	case VIDEO_FORMAT_BGR3:
+	case VIDEO_FORMAT_R10L:
 		return false;
 	}
 
@@ -221,6 +225,8 @@ static inline const char *get_video_format_name(enum video_format format)
 		return "P416";
 	case VIDEO_FORMAT_V210:
 		return "v210";
+	case VIDEO_FORMAT_R10L:
+		return "R10l";
 	case VIDEO_FORMAT_NONE:;
 	}
 

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

@@ -264,6 +264,7 @@ bool video_format_get_parameters_for_format(enum video_colorspace color_space,
 	case VIDEO_FORMAT_P010:
 	case VIDEO_FORMAT_I210:
 	case VIDEO_FORMAT_V210:
+	case VIDEO_FORMAT_R10L:
 		bpc = 10;
 		break;
 	case VIDEO_FORMAT_I412:

+ 1 - 0
libobs/obs-internal.h

@@ -963,6 +963,7 @@ convert_video_format(enum video_format format, enum video_trc trc)
 		case VIDEO_FORMAT_P216:
 		case VIDEO_FORMAT_P416:
 		case VIDEO_FORMAT_V210:
+		case VIDEO_FORMAT_R10L:
 			return GS_RGBA16F;
 		default:
 			return GS_BGRX;

+ 33 - 0
libobs/obs-source.c

@@ -1592,6 +1592,7 @@ enum convert_type {
 	CONVERT_I010,
 	CONVERT_P010,
 	CONVERT_V210,
+	CONVERT_R10L,
 };
 
 static inline enum convert_type get_convert_type(enum video_format format,
@@ -1652,6 +1653,9 @@ static inline enum convert_type get_convert_type(enum video_format format,
 	case VIDEO_FORMAT_V210:
 		return CONVERT_V210;
 
+	case VIDEO_FORMAT_R10L:
+		return CONVERT_R10L;
+
 	case VIDEO_FORMAT_P216:
 	case VIDEO_FORMAT_P416:
 		/* Unimplemented */
@@ -1959,6 +1963,16 @@ static inline bool set_v210_sizes(struct obs_source *source,
 	return true;
 }
 
+static inline bool set_r10l_sizes(struct obs_source *source,
+				  const struct obs_source_frame *frame)
+{
+	source->async_convert_width[0] = frame->width;
+	source->async_convert_height[0] = frame->height;
+	source->async_texture_formats[0] = GS_BGRA_UNORM;
+	source->async_channel_count = 1;
+	return true;
+}
+
 static inline bool init_gpu_conversion(struct obs_source *source,
 				       const struct obs_source_frame *frame)
 {
@@ -2019,6 +2033,9 @@ static inline bool init_gpu_conversion(struct obs_source *source,
 	case CONVERT_V210:
 		return set_v210_sizes(source, frame);
 
+	case CONVERT_R10L:
+		return set_r10l_sizes(source, frame);
+
 	case CONVERT_NONE:
 		assert(false && "No conversion requested");
 		break;
@@ -2112,6 +2129,7 @@ static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
 	case CONVERT_I010:
 	case CONVERT_P010:
 	case CONVERT_V210:
+	case CONVERT_R10L:
 		for (size_t c = 0; c < MAX_AV_PLANES; c++) {
 			if (tex[c])
 				gs_texture_set_image(tex[c], frame->data[c],
@@ -2245,6 +2263,20 @@ static const char *select_conversion_technique(enum video_format format,
 		}
 	}
 
+	case VIDEO_FORMAT_R10L: {
+		switch (trc) {
+		case VIDEO_TRC_PQ:
+			return full_range ? "R10L_PQ_2020_709_Full_Reverse"
+					  : "R10L_PQ_2020_709_Limited_Reverse";
+		case VIDEO_TRC_HLG:
+			return full_range ? "R10L_HLG_2020_709_Full_Reverse"
+					  : "R10L_HLG_2020_709_Limited_Reverse";
+		default:
+			return full_range ? "R10L_SRGB_Full_Reverse"
+					  : "R10L_SRGB_Limited_Reverse";
+		}
+	}
+
 	case VIDEO_FORMAT_BGRA:
 	case VIDEO_FORMAT_BGRX:
 	case VIDEO_FORMAT_RGBA:
@@ -3462,6 +3494,7 @@ static void copy_frame_data(struct obs_source_frame *dst,
 	case VIDEO_FORMAT_BGR3:
 	case VIDEO_FORMAT_AYUV:
 	case VIDEO_FORMAT_V210:
+	case VIDEO_FORMAT_R10L:
 		copy_frame_data_plane(dst, src, 0, dst->height);
 		break;
 

+ 1 - 0
libobs/obs-video.c

@@ -787,6 +787,7 @@ static void set_gpu_converted_data(struct video_frame *output,
 	case VIDEO_FORMAT_YA2L:
 	case VIDEO_FORMAT_AYUV:
 	case VIDEO_FORMAT_V210:
+	case VIDEO_FORMAT_R10L:
 		/* unimplemented */
 		;
 	}