Open i-rinat opened 6 years ago
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;
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.