Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some webcams return green screen #370

Open
i-rinat opened this issue Dec 24, 2017 · 1 comment
Open

Some webcams return green screen #370

i-rinat opened this issue Dec 24, 2017 · 1 comment

Comments

@i-rinat
Copy link
Owner

i-rinat commented Dec 24, 2017

Currently, libv4lconvert from libv4l is used for image capture. It simplifies conversion from numerous formats various webcams support to the desired V4L2_PIX_FMT_YUV420. It turned out that some webcams have MJPG as a primary format, with resolution which is not multiple of 8, dct block size (960x540 for example). It turned out that libv4lconvert does not expect such resolution and refuses to work.

I can see two possible solutions. First is to read RGB24 from libv4lconvert, and then convert it back to YUV420. Second is to fix non-8-multiple heights in libv4lconvert.

@i-rinat
Copy link
Owner Author

i-rinat commented Dec 24, 2017

Here is an idea for a patch.

diff --git a/lib/libv4lconvert/jpeg.c b/lib/libv4lconvert/jpeg.c
index 15f8dec7..4f4af582 100644
--- a/lib/libv4lconvert/jpeg.c
+++ b/lib/libv4lconvert/jpeg.c
@@ -238,14 +238,30 @@ static int decode_libjpeg_h_samp2(struct v4lconvert_data *data,
 	struct jpeg_decompress_struct *cinfo = &data->cinfo;
 	int y;
 	unsigned int width = cinfo->image_width;
+	unsigned char *drain_buf;
 	JSAMPROW y_rows[16], u_rows[8], v_rows[8];
 	JSAMPARRAY rows[3] = { y_rows, u_rows, v_rows };
 
+	drain_buf = v4lconvert_alloc_buffer(width,
+					    &data->convert_pixfmt_buf,
+					    &data->convert_pixfmt_buf_size);
+	if (!drain_buf)
+		return v4lconvert_oom_error(data);
+
 	while (cinfo->output_scanline < cinfo->image_height) {
-		for (y = 0; y < 8 * v_samp; y++) {
+		int last_y = cinfo->image_height - cinfo->output_scanline;
+		int last_uv;
+
+		last_y = last_y < 8 * v_samp ? last_y : 8 * v_samp;
+		last_uv = last_y / v_samp;
+
+		for (y = 0; y < last_y; y++) {
 			y_rows[y] = ydest;
 			ydest += width;
 		}
+		for (; y < 8 * v_samp; y++)
+			y_rows[y] = drain_buf;
+
 		/*
 		 * For v_samp == 1 were going to get 1 set of uv values per
 		 * line, but we need only 1 set per 2 lines since our output
@@ -253,7 +269,7 @@ static int decode_libjpeg_h_samp2(struct v4lconvert_data *data,
 		 * effectively using the second set for each output line.
 		 */
 		if (v_samp == 1) {
-			for (y = 0; y < 8; y++) {
+			for (y = 0; y < last_uv; y++) {
 				u_rows[y] = udest;
 				v_rows[y] = vdest;
 				y++;
@@ -262,13 +278,18 @@ static int decode_libjpeg_h_samp2(struct v4lconvert_data *data,
 				udest += width / 2;
 				vdest += width / 2;
 			}
+			for (; y < 8; y++)
+				u_rows[y] = v_rows[y] = drain_buf;
+
 		} else { /* v_samp == 2 */
-			for (y = 0; y < 8; y++) {
+			for (y = 0; y < last_uv; y++) {
 				u_rows[y] = udest;
 				v_rows[y] = vdest;
 				udest += width / 2;
 				vdest += width / 2;
 			}
+			for (; y < 8; y++)
+				u_rows[y] = v_rows[y] = drain_buf;
 		}
 
 		y = jpeg_read_raw_data(cinfo, rows, 8 * v_samp);
@@ -390,12 +411,14 @@ int v4lconvert_decode_jpeg_libjpeg(struct v4lconvert_data *data,
 		}
 
 		/* We don't want any padding as that may overflow our dest */
+#if 0
 		if (width % (8 * h_samp) || height % (8 * v_samp)) {
 			V4LCONVERT_ERR(
 				"resolution is not a multiple of dctsize");
 			errno = EIO;
 			return -1;
 		}
+#endif
 
 		if (dest_pix_fmt == V4L2_PIX_FMT_YVU420) {
 			vdest = dest + width * height;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant