Browse Source

win-dshow: Add support for YUY2 in virtualcam

jp9000 5 years ago
parent
commit
18a73c9a45

+ 1 - 1
plugins/win-dshow/libdshowcapture

@@ -1 +1 @@
-Subproject commit 1d9685530922617778ae99f7d45ca427f67d7370
+Subproject commit 46c9b12f27f70d19c3eac45069ae0e4b37846676

+ 77 - 4
plugins/win-dshow/tiny-nv12-scale.c

@@ -6,10 +6,10 @@
  * it's nearest neighbor so not really a huge deal.  at the very least it
  * should be sse2 at some point. */
 
-void nv12_scale_init(nv12_scale_t *s, bool convert_to_i420, int dst_cx,
+void nv12_scale_init(nv12_scale_t *s, enum target_format format, int dst_cx,
 		     int dst_cy, int src_cx, int src_cy)
 {
-	s->convert_to_i420 = convert_to_i420;
+	s->format = format;
 
 	s->src_cx = src_cx;
 	s->src_cy = src_cy;
@@ -118,16 +118,89 @@ static void nv12_convert_to_i420(nv12_scale_t *s, uint8_t *dst_start,
 	}
 }
 
+static void nv12_scale_nearest_to_yuy2(nv12_scale_t *s, uint8_t *dst_start,
+				       const uint8_t *src)
+{
+	register uint8_t *dst = dst_start;
+	const int src_cx = s->src_cx;
+	const int src_cy = s->src_cy;
+	const int dst_cx = s->dst_cx;
+	const int dst_cy = s->dst_cy;
+	const int src_cx_d2 = src_cx / 2;
+	const int src_cy_d2 = src_cy / 2;
+	const int dst_cx_d2 = dst_cx / 2;
+	const int dst_cy_d2 = dst_cy / 2;
+	const int size = src_cx * src_cy;
+
+	const uint8_t *src_uv = src + size;
+
+	register int uv_flip = 0;
+
+	for (int y = 0; y < dst_cy; y++) {
+		const int src_line = y * src_cy / dst_cy * s->src_cx;
+		const int src_line_d2 =
+			y / 2 * src_cy_d2 / dst_cy_d2 * s->src_cx;
+
+		for (int x = 0; x < dst_cx; x++) {
+			const int src_x = x * src_cx / dst_cx;
+			const int src_x_d2 = x / 2 * src_cx_d2 / dst_cx_d2;
+			const int pos = src_line + src_x;
+			const int pos_uv = src_line_d2 + src_x_d2 * 2 + uv_flip;
+
+			*(dst++) = src[pos];
+			*(dst++) = src_uv[pos_uv];
+
+			uv_flip ^= 1;
+		}
+	}
+}
+
+static void nv12_convert_to_yuy2(nv12_scale_t *s, uint8_t *dst_start,
+				 const uint8_t *src_start)
+{
+	const int size = s->src_cx * s->src_cy;
+	const int size_dst_line = s->src_cx * 4;
+
+	register const uint8_t *src_y = src_start;
+	register const uint8_t *src_uv = src_y + size;
+	register uint8_t *dst = dst_start;
+	register uint8_t *dst_end = dst + size * 2;
+
+	while (dst < dst_end) {
+		register uint8_t *dst_line_end = dst + size_dst_line;
+		const uint8_t *src_uv_start = src_uv;
+		while (dst < dst_line_end) {
+			*(dst++) = *(src_y++);
+			*(dst++) = *(src_uv++);
+			*(dst++) = *(src_y++);
+			*(dst++) = *(src_uv++);
+		}
+
+		dst_line_end = dst + size_dst_line;
+		src_uv = src_uv_start;
+		while (dst < dst_line_end) {
+			*(dst++) = *(src_y++);
+			*(dst++) = *(src_uv++);
+			*(dst++) = *(src_y++);
+			*(dst++) = *(src_uv++);
+		}
+	}
+}
+
 void nv12_do_scale(nv12_scale_t *s, uint8_t *dst, const uint8_t *src)
 {
 	if (s->src_cx == s->dst_cx && s->src_cy == s->dst_cy) {
-		if (s->convert_to_i420)
+		if (s->format == TARGET_FORMAT_I420)
 			nv12_convert_to_i420(s, dst, src);
+		else if (s->format == TARGET_FORMAT_YUY2)
+			nv12_convert_to_yuy2(s, dst, src);
 		else
 			memcpy(dst, src, s->src_cx * s->src_cy * 3 / 2);
 	} else {
-		if (s->convert_to_i420)
+		if (s->format == TARGET_FORMAT_I420)
 			nv12_scale_nearest_to_i420(s, dst, src);
+		else if (s->format == TARGET_FORMAT_YUY2)
+			nv12_scale_nearest_to_yuy2(s, dst, src);
 		else
 			nv12_scale_nearest(s, dst, src);
 	}

+ 9 - 3
plugins/win-dshow/tiny-nv12-scale.h

@@ -7,8 +7,14 @@
 extern "C" {
 #endif
 
+enum target_format {
+	TARGET_FORMAT_NV12,
+	TARGET_FORMAT_I420,
+	TARGET_FORMAT_YUY2,
+};
+
 struct nv12_scale {
-	bool convert_to_i420;
+	enum target_format format;
 
 	int src_cx;
 	int src_cy;
@@ -19,8 +25,8 @@ struct nv12_scale {
 
 typedef struct nv12_scale nv12_scale_t;
 
-extern void nv12_scale_init(nv12_scale_t *s, bool convert_to_i420, int dst_cx,
-			    int dst_cy, int src_cx, int src_cy);
+extern void nv12_scale_init(nv12_scale_t *s, enum target_format format,
+			    int dst_cx, int dst_cy, int src_cx, int src_cy);
 extern void nv12_do_scale(nv12_scale_t *s, uint8_t *dst, const uint8_t *src);
 
 #ifdef __cplusplus

+ 13 - 5
plugins/win-dshow/virtualcam-module/virtualcam-filter.cpp

@@ -20,6 +20,8 @@ VCamFilter::VCamFilter()
 
 	AddVideoFormat(VideoFormat::I420, DEFAULT_CX, DEFAULT_CY,
 		       DEFAULT_INTERVAL);
+	AddVideoFormat(VideoFormat::YUY2, DEFAULT_CX, DEFAULT_CY,
+		       DEFAULT_INTERVAL);
 
 	/* ---------------------------------------- */
 	/* load placeholder image                   */
@@ -90,13 +92,14 @@ VCamFilter::VCamFilter()
 	if (new_cx != cx || new_cy != cy || new_interval != interval) {
 		AddVideoFormat(VideoFormat::NV12, new_cx, new_cy, new_interval);
 		AddVideoFormat(VideoFormat::I420, new_cx, new_cy, new_interval);
+		AddVideoFormat(VideoFormat::YUY2, new_cx, new_cy, new_interval);
 		SetVideoFormat(VideoFormat::NV12, new_cx, new_cy, new_interval);
 		cx = new_cx;
 		cy = new_cy;
 		interval = new_interval;
 	}
 
-	nv12_scale_init(&scaler, false, cx, cy, cx, cy);
+	nv12_scale_init(&scaler, TARGET_FORMAT_NV12, cx, cy, cx, cy);
 
 	/* ---------------------------------------- */
 
@@ -157,7 +160,7 @@ void VCamFilter::Thread()
 	cy = GetCY();
 	interval = GetInterval();
 
-	nv12_scale_init(&scaler, false, GetCX(), GetCY(), cx, cy);
+	nv12_scale_init(&scaler, TARGET_FORMAT_NV12, GetCX(), GetCY(), cx, cy);
 
 	while (!stopped()) {
 		Frame(filter_time);
@@ -201,15 +204,20 @@ void VCamFilter::Frame(uint64_t ts)
 				       new_interval);
 		}
 
-		nv12_scale_init(&scaler, false, GetCX(), GetCY(), new_cx,
-				new_cy);
+		nv12_scale_init(&scaler, TARGET_FORMAT_NV12, GetCX(), GetCY(),
+				new_cx, new_cy);
 
 		cx = new_cx;
 		cy = new_cy;
 		interval = new_interval;
 	}
 
-	scaler.convert_to_i420 = GetVideoFormat() == VideoFormat::I420;
+	if (GetVideoFormat() == VideoFormat::I420)
+		scaler.format = TARGET_FORMAT_I420;
+	else if (GetVideoFormat() == VideoFormat::YUY2)
+		scaler.format = TARGET_FORMAT_YUY2;
+	else
+		scaler.format = TARGET_FORMAT_NV12;
 
 	uint8_t *ptr;
 	if (LockSampleData(&ptr)) {