Преглед изворни кода

libobs: Add support for YUV422P10LE, YUV444P12LE, YUVA444P12LE

mvji пре 3 година
родитељ
комит
d3a8ef7128

+ 67 - 0
libobs/data/format_conversion.effect

@@ -501,6 +501,19 @@ float3 PSPlanar422_Reverse(FragPosWide frag_in) : TARGET
 	return rgb;
 }
 
+float4 PSPlanar422_10LE_Reverse(FragPosWide frag_in) : TARGET
+{
+    float y = image.Load(int3(frag_in.pos_wide.xz, 0)).x;
+    int3 xy0_chroma = int3(frag_in.pos_wide.yz, 0);
+    float cb = image1.Load(xy0_chroma).x;
+    float cr = image2.Load(xy0_chroma).x;
+    float3 yuv = float3(y, cb, cr);
+    yuv *= 65535. / 1023.;
+    float3 rgb = YUV_to_RGB(yuv);
+    rgb = srgb_nonlinear_to_linear(rgb);
+    return float4(rgb, 1.0);
+}
+
 float4 PSPlanar422A_Reverse(FragPosWide frag_in) : TARGET
 {
 	int3 xy0_luma = int3(frag_in.pos_wide.xz, 0);
@@ -525,6 +538,19 @@ float3 PSPlanar444_Reverse(FragPos frag_in) : TARGET
 	return rgb;
 }
 
+float4 PSPlanar444_12LE_Reverse(FragPos frag_in) : TARGET
+{
+    int3 xy0 = int3(frag_in.pos.xy, 0);
+    float y = image.Load(xy0).x;
+    float cb = image1.Load(xy0).x;
+    float cr = image2.Load(xy0).x;
+    float3 yuv = float3(y, cb, cr);
+    yuv *= 65535. / 4095.;
+    float3 rgb = YUV_to_RGB(yuv);
+    rgb = srgb_nonlinear_to_linear(rgb);
+    return float4(rgb, 1.0);
+}
+
 float4 PSPlanar444A_Reverse(FragPos frag_in) : TARGET
 {
 	int3 xy0 = int3(frag_in.pos.xy, 0);
@@ -537,6 +563,20 @@ float4 PSPlanar444A_Reverse(FragPos frag_in) : TARGET
 	return rgba;
 }
 
+float4 PSPlanar444A_12LE_Reverse(FragPos frag_in) : TARGET
+{
+    int3 xy0 = int3(frag_in.pos.xy, 0);
+    float y = image.Load(xy0).x;
+    float cb = image1.Load(xy0).x;
+    float cr = image2.Load(xy0).x;
+    float alpha = image3.Load(xy0).x * 16.;
+    float3 yuv = float3(y, cb, cr);
+    yuv *= 65535. / 4095.;
+    float3 rgb = YUV_to_RGB(yuv);
+    rgb = srgb_nonlinear_to_linear(rgb);
+    return float4(rgb, alpha);
+}
+
 float4 PSAYUV_Reverse(FragPos frag_in) : TARGET
 {
 	float4 yuva = image.Load(int3(frag_in.pos.xy, 0));
@@ -921,6 +961,15 @@ technique I422_Reverse
 	}
 }
 
+technique I210_Reverse
+{
+    pass
+    {
+        vertex_shader = VSPosWide_Reverse(id);
+        pixel_shader  = PSPlanar422_10LE_Reverse(frag_in);
+    }
+}
+
 technique I42A_Reverse
 {
 	pass
@@ -939,6 +988,15 @@ technique I444_Reverse
 	}
 }
 
+technique I412_Reverse
+{
+    pass
+    {
+        vertex_shader = VSPos(id);
+        pixel_shader  = PSPlanar444_12LE_Reverse(frag_in);
+    }
+}
+
 technique YUVA_Reverse
 {
 	pass
@@ -948,6 +1006,15 @@ technique YUVA_Reverse
 	}
 }
 
+technique YA2L_Reverse
+{
+    pass
+    {
+        vertex_shader = VSPos(id);
+        pixel_shader  = PSPlanar444A_12LE_Reverse(frag_in);
+    }
+}
+
 technique AYUV_Reverse
 {
 	pass

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

@@ -112,6 +112,17 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
 		frame->linesize[2] = width;
 		break;
 
+	case VIDEO_FORMAT_I412:
+		size = width * height * 2;
+		ALIGN_SIZE(size, alignment);
+		frame->data[0] = bmalloc(size * 3);
+		frame->data[1] = (uint8_t *)frame->data[0] + size;
+		frame->data[2] = (uint8_t *)frame->data[1] + size;
+		frame->linesize[0] = width * 2;
+		frame->linesize[1] = width * 2;
+		frame->linesize[2] = width * 2;
+		break;
+
 	case VIDEO_FORMAT_BGR3:
 		size = width * height * 3;
 		ALIGN_SIZE(size, alignment);
@@ -139,6 +150,27 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
 		break;
 	}
 
+	case VIDEO_FORMAT_I210: {
+		size = width * height * 2;
+		ALIGN_SIZE(size, alignment);
+		offsets[0] = size;
+		const uint32_t half_width = (width + 1) / 2;
+		const uint32_t half_area = half_width * height;
+		const uint32_t half_area_size = 2 * half_area;
+		size += half_area_size;
+		ALIGN_SIZE(size, alignment);
+		offsets[1] = size;
+		size += half_area_size;
+		ALIGN_SIZE(size, alignment);
+		frame->data[0] = bmalloc(size);
+		frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
+		frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
+		frame->linesize[0] = width * 2;
+		frame->linesize[1] = half_width * 2;
+		frame->linesize[2] = half_width * 2;
+		break;
+	}
+
 	case VIDEO_FORMAT_I40A: {
 		size = width * height;
 		ALIGN_SIZE(size, alignment);
@@ -212,6 +244,31 @@ void video_frame_init(struct video_frame *frame, enum video_format format,
 		frame->linesize[3] = width;
 		break;
 
+	case VIDEO_FORMAT_YA2L: {
+		const uint32_t linesize = width * 2;
+		const uint32_t plane_size = linesize * height;
+		size = plane_size;
+		ALIGN_SIZE(size, alignment);
+		offsets[0] = size;
+		size += plane_size;
+		ALIGN_SIZE(size, alignment);
+		offsets[1] = size;
+		size += plane_size;
+		ALIGN_SIZE(size, alignment);
+		offsets[2] = size;
+		size += plane_size;
+		ALIGN_SIZE(size, alignment);
+		frame->data[0] = bmalloc(size);
+		frame->data[1] = (uint8_t *)frame->data[0] + offsets[0];
+		frame->data[2] = (uint8_t *)frame->data[0] + offsets[1];
+		frame->data[3] = (uint8_t *)frame->data[0] + offsets[2];
+		frame->linesize[0] = linesize;
+		frame->linesize[1] = linesize;
+		frame->linesize[2] = linesize;
+		frame->linesize[3] = linesize;
+		break;
+	}
+
 	case VIDEO_FORMAT_I010: {
 		size = width * height * 2;
 		ALIGN_SIZE(size, alignment);
@@ -283,6 +340,8 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
 
 	case VIDEO_FORMAT_I444:
 	case VIDEO_FORMAT_I422:
+	case VIDEO_FORMAT_I210:
+	case VIDEO_FORMAT_I412:
 		memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
 		memcpy(dst->data[1], src->data[1], src->linesize[1] * cy);
 		memcpy(dst->data[2], src->data[2], src->linesize[2] * cy);
@@ -297,6 +356,7 @@ void video_frame_copy(struct video_frame *dst, const struct video_frame *src,
 
 	case VIDEO_FORMAT_I42A:
 	case VIDEO_FORMAT_YUVA:
+	case VIDEO_FORMAT_YA2L:
 		memcpy(dst->data[0], src->data[0], src->linesize[0] * cy);
 		memcpy(dst->data[1], src->data[1], src->linesize[1] * cy);
 		memcpy(dst->data[2], src->data[2], src->linesize[2] * cy);

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

@@ -73,6 +73,15 @@ enum video_format {
 	/* 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 10 bits */
+	VIDEO_FORMAT_I210, // Little Endian
+
+	/* planar 4:4:4 12 bits */
+	VIDEO_FORMAT_I412, // Little Endian
+
+	/* planar 4:4:4 12 bits with alpha */
+	VIDEO_FORMAT_YA2L, // Little Endian
 };
 
 enum video_trc {
@@ -123,13 +132,16 @@ static inline bool format_is_yuv(enum video_format format)
 	case VIDEO_FORMAT_I420:
 	case VIDEO_FORMAT_NV12:
 	case VIDEO_FORMAT_I422:
+	case VIDEO_FORMAT_I210:
 	case VIDEO_FORMAT_YVYU:
 	case VIDEO_FORMAT_YUY2:
 	case VIDEO_FORMAT_UYVY:
 	case VIDEO_FORMAT_I444:
+	case VIDEO_FORMAT_I412:
 	case VIDEO_FORMAT_I40A:
 	case VIDEO_FORMAT_I42A:
 	case VIDEO_FORMAT_YUVA:
+	case VIDEO_FORMAT_YA2L:
 	case VIDEO_FORMAT_AYUV:
 	case VIDEO_FORMAT_I010:
 	case VIDEO_FORMAT_P010:
@@ -155,6 +167,8 @@ static inline const char *get_video_format_name(enum video_format format)
 		return "NV12";
 	case VIDEO_FORMAT_I422:
 		return "I422";
+	case VIDEO_FORMAT_I210:
+		return "I210";
 	case VIDEO_FORMAT_YVYU:
 		return "YVYU";
 	case VIDEO_FORMAT_YUY2:
@@ -169,6 +183,8 @@ static inline const char *get_video_format_name(enum video_format format)
 		return "BGRX";
 	case VIDEO_FORMAT_I444:
 		return "I444";
+	case VIDEO_FORMAT_I412:
+		return "I412";
 	case VIDEO_FORMAT_Y800:
 		return "Y800";
 	case VIDEO_FORMAT_BGR3:
@@ -179,6 +195,8 @@ static inline const char *get_video_format_name(enum video_format format)
 		return "I42A";
 	case VIDEO_FORMAT_YUVA:
 		return "YUVA";
+	case VIDEO_FORMAT_YA2L:
+		return "YA2L";
 	case VIDEO_FORMAT_AYUV:
 		return "AYUV";
 	case VIDEO_FORMAT_I010:

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

@@ -264,7 +264,13 @@ bool video_format_get_parameters_for_format(enum video_colorspace color_space,
 	switch (format) {
 	case VIDEO_FORMAT_I010:
 	case VIDEO_FORMAT_P010:
+	case VIDEO_FORMAT_I210:
 		bpc = 10;
+		break;
+	case VIDEO_FORMAT_I412:
+	case VIDEO_FORMAT_YA2L:
+		bpc = 12;
+		break;
 	}
 
 	return video_format_get_parameters_for_bpc(color_space, range, matrix,

+ 10 - 0
libobs/media-io/video-scaler-ffmpeg.c

@@ -51,16 +51,26 @@ get_ffmpeg_video_format(enum video_format format)
 		return AV_PIX_FMT_GRAY8;
 	case VIDEO_FORMAT_I444:
 		return AV_PIX_FMT_YUV444P;
+	case VIDEO_FORMAT_I412:
+		return AV_PIX_FMT_YUV444P12LE;
 	case VIDEO_FORMAT_BGR3:
 		return AV_PIX_FMT_BGR24;
 	case VIDEO_FORMAT_I422:
 		return AV_PIX_FMT_YUV422P;
+	case VIDEO_FORMAT_I210:
+		return AV_PIX_FMT_YUV422P10LE;
 	case VIDEO_FORMAT_I40A:
 		return AV_PIX_FMT_YUVA420P;
 	case VIDEO_FORMAT_I42A:
 		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)
+		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:

+ 3 - 0
libobs/obs-internal.h

@@ -890,6 +890,9 @@ convert_video_format(enum video_format format)
 		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;

+ 91 - 1
libobs/obs-source.c

@@ -1548,10 +1548,13 @@ enum convert_type {
 	CONVERT_420,
 	CONVERT_420_A,
 	CONVERT_422,
+	CONVERT_422P10LE,
 	CONVERT_422_A,
 	CONVERT_422_PACK,
 	CONVERT_444,
+	CONVERT_444P12LE,
 	CONVERT_444_A,
+	CONVERT_444P12LE_A,
 	CONVERT_444_A_PACK,
 	CONVERT_800,
 	CONVERT_RGB_LIMITED,
@@ -1574,8 +1577,12 @@ static inline enum convert_type get_convert_type(enum video_format format,
 		return CONVERT_NV12;
 	case VIDEO_FORMAT_I444:
 		return CONVERT_444;
+	case VIDEO_FORMAT_I412:
+		return CONVERT_444P12LE;
 	case VIDEO_FORMAT_I422:
 		return CONVERT_422;
+	case VIDEO_FORMAT_I210:
+		return CONVERT_422P10LE;
 
 	case VIDEO_FORMAT_YVYU:
 	case VIDEO_FORMAT_YUY2:
@@ -1603,6 +1610,9 @@ static inline enum convert_type get_convert_type(enum video_format format,
 	case VIDEO_FORMAT_YUVA:
 		return CONVERT_444_A;
 
+	case VIDEO_FORMAT_YA2L:
+		return CONVERT_444P12LE_A;
+
 	case VIDEO_FORMAT_AYUV:
 		return CONVERT_444_A_PACK;
 
@@ -1672,6 +1682,22 @@ static inline bool set_planar444_sizes(struct obs_source *source,
 	return true;
 }
 
+static inline bool set_planar444_16_sizes(struct obs_source *source,
+					  const struct obs_source_frame *frame)
+{
+	source->async_convert_width[0] = frame->width;
+	source->async_convert_width[1] = frame->width;
+	source->async_convert_width[2] = frame->width;
+	source->async_convert_height[0] = frame->height;
+	source->async_convert_height[1] = frame->height;
+	source->async_convert_height[2] = frame->height;
+	source->async_texture_formats[0] = GS_R16;
+	source->async_texture_formats[1] = GS_R16;
+	source->async_texture_formats[2] = GS_R16;
+	source->async_channel_count = 3;
+	return true;
+}
+
 static inline bool
 set_planar444_alpha_sizes(struct obs_source *source,
 			  const struct obs_source_frame *frame)
@@ -1692,6 +1718,26 @@ set_planar444_alpha_sizes(struct obs_source *source,
 	return true;
 }
 
+static inline bool
+set_planar444_16_alpha_sizes(struct obs_source *source,
+			     const struct obs_source_frame *frame)
+{
+	source->async_convert_width[0] = frame->width;
+	source->async_convert_width[1] = frame->width;
+	source->async_convert_width[2] = frame->width;
+	source->async_convert_width[3] = frame->width;
+	source->async_convert_height[0] = frame->height;
+	source->async_convert_height[1] = frame->height;
+	source->async_convert_height[2] = frame->height;
+	source->async_convert_height[3] = frame->height;
+	source->async_texture_formats[0] = GS_R16;
+	source->async_texture_formats[1] = GS_R16;
+	source->async_texture_formats[2] = GS_R16;
+	source->async_texture_formats[3] = GS_R16;
+	source->async_channel_count = 4;
+	return true;
+}
+
 static inline bool set_planar420_sizes(struct obs_source *source,
 				       const struct obs_source_frame *frame)
 {
@@ -1754,6 +1800,24 @@ static inline bool set_planar422_sizes(struct obs_source *source,
 	source->async_channel_count = 3;
 	return true;
 }
+static inline bool set_planar422_16_sizes(struct obs_source *source,
+					  const struct obs_source_frame *frame)
+{
+	const uint32_t width = frame->width;
+	const uint32_t height = frame->height;
+	const uint32_t half_width = (width + 1) / 2;
+	source->async_convert_width[0] = width;
+	source->async_convert_width[1] = half_width;
+	source->async_convert_width[2] = half_width;
+	source->async_convert_height[0] = height;
+	source->async_convert_height[1] = height;
+	source->async_convert_height[2] = height;
+	source->async_texture_formats[0] = GS_R16;
+	source->async_texture_formats[1] = GS_R16;
+	source->async_texture_formats[2] = GS_R16;
+	source->async_channel_count = 3;
+	return true;
+}
 
 static inline bool
 set_planar422_alpha_sizes(struct obs_source *source,
@@ -1876,12 +1940,18 @@ static inline bool init_gpu_conversion(struct obs_source *source,
 	case CONVERT_422:
 		return set_planar422_sizes(source, frame);
 
+	case CONVERT_422P10LE:
+		return set_planar422_16_sizes(source, frame);
+
 	case CONVERT_NV12:
 		return set_nv12_sizes(source, frame);
 
 	case CONVERT_444:
 		return set_planar444_sizes(source, frame);
 
+	case CONVERT_444P12LE:
+		return set_planar444_16_sizes(source, frame);
+
 	case CONVERT_800:
 		return set_y800_sizes(source, frame);
 
@@ -1900,6 +1970,9 @@ static inline bool init_gpu_conversion(struct obs_source *source,
 	case CONVERT_444_A:
 		return set_planar444_alpha_sizes(source, frame);
 
+	case CONVERT_444P12LE_A:
+		return set_planar444_16_alpha_sizes(source, frame);
+
 	case CONVERT_444_A_PACK:
 		return set_packed444_alpha_sizes(source, frame);
 
@@ -1992,11 +2065,14 @@ static void upload_raw_frame(gs_texture_t *tex[MAX_AV_PLANES],
 	case CONVERT_BGR3:
 	case CONVERT_420:
 	case CONVERT_422:
+	case CONVERT_422P10LE:
 	case CONVERT_NV12:
 	case CONVERT_444:
+	case CONVERT_444P12LE:
 	case CONVERT_420_A:
 	case CONVERT_422_A:
 	case CONVERT_444_A:
+	case CONVERT_444P12LE_A:
 	case CONVERT_444_A_PACK:
 	case CONVERT_I010_SRGB:
 	case CONVERT_I010_PQ_2020_709:
@@ -2039,6 +2115,9 @@ static const char *select_conversion_technique(enum video_format format,
 	case VIDEO_FORMAT_I444:
 		return "I444_Reverse";
 
+	case VIDEO_FORMAT_I412:
+		return "I412_Reverse";
+
 	case VIDEO_FORMAT_Y800:
 		return full_range ? "Y800_Full" : "Y800_Limited";
 
@@ -2048,6 +2127,9 @@ static const char *select_conversion_technique(enum video_format format,
 	case VIDEO_FORMAT_I422:
 		return "I422_Reverse";
 
+	case VIDEO_FORMAT_I210:
+		return "I210_Reverse";
+
 	case VIDEO_FORMAT_I40A:
 		return "I40A_Reverse";
 
@@ -2057,6 +2139,9 @@ static const char *select_conversion_technique(enum video_format format,
 	case VIDEO_FORMAT_YUVA:
 		return "YUVA_Reverse";
 
+	case VIDEO_FORMAT_YA2L:
+		return "YA2L_Reverse";
+
 	case VIDEO_FORMAT_AYUV:
 		return "AYUV_Reverse";
 
@@ -2097,7 +2182,9 @@ static const char *select_conversion_technique(enum video_format format,
 
 static bool need_linear_output(enum video_format format)
 {
-	return (format == VIDEO_FORMAT_I010) || (format == VIDEO_FORMAT_P010);
+	return (format == VIDEO_FORMAT_I010) || (format == VIDEO_FORMAT_P010) ||
+	       (format == VIDEO_FORMAT_I210) || (format == VIDEO_FORMAT_I412) ||
+	       (format == VIDEO_FORMAT_YA2L);
 }
 
 static inline void set_eparam(gs_effect_t *effect, const char *name, float val)
@@ -3192,6 +3279,8 @@ static void copy_frame_data(struct obs_source_frame *dst,
 
 	case VIDEO_FORMAT_I444:
 	case VIDEO_FORMAT_I422:
+	case VIDEO_FORMAT_I210:
+	case VIDEO_FORMAT_I412:
 		copy_frame_data_plane(dst, src, 0, dst->height);
 		copy_frame_data_plane(dst, src, 1, dst->height);
 		copy_frame_data_plane(dst, src, 2, dst->height);
@@ -3222,6 +3311,7 @@ static void copy_frame_data(struct obs_source_frame *dst,
 
 	case VIDEO_FORMAT_I42A:
 	case VIDEO_FORMAT_YUVA:
+	case VIDEO_FORMAT_YA2L:
 		copy_frame_data_plane(dst, src, 0, dst->height);
 		copy_frame_data_plane(dst, src, 1, dst->height);
 		copy_frame_data_plane(dst, src, 2, dst->height);

+ 3 - 0
libobs/obs-video.c

@@ -727,10 +727,13 @@ static void set_gpu_converted_data(struct obs_core_video *video,
 	case VIDEO_FORMAT_BGRX:
 	case VIDEO_FORMAT_Y800:
 	case VIDEO_FORMAT_BGR3:
+	case VIDEO_FORMAT_I412:
 	case VIDEO_FORMAT_I422:
+	case VIDEO_FORMAT_I210:
 	case VIDEO_FORMAT_I40A:
 	case VIDEO_FORMAT_I42A:
 	case VIDEO_FORMAT_YUVA:
+	case VIDEO_FORMAT_YA2L:
 	case VIDEO_FORMAT_AYUV:
 		/* unimplemented */
 		;

+ 3 - 0
libobs/obs.c

@@ -379,6 +379,9 @@ static bool obs_init_textures(struct obs_video_info *ovi)
 	switch (ovi->output_format) {
 	case VIDEO_FORMAT_I010:
 	case VIDEO_FORMAT_P010:
+	case VIDEO_FORMAT_I210:
+	case VIDEO_FORMAT_I412:
+	case VIDEO_FORMAT_YA2L:
 		format = GS_RGBA16F;
 	}