Skip to content

Commit c2eda35

Browse files
ijgs02mchehab
authored andcommitted
media: uvcvideo: Implement dual stream quirk to fix loss of usb packets
Some cameras, such as the Sonix Technology Co. 292A, exhibit issues when running two parallel streams, causing USB packets to be dropped when an H.264 stream posts a keyframe while an MJPEG stream is running simultaneously. This occasionally causes the driver to erroneously output two consecutive JPEG images as a single frame. To fix this, we inspect the buffer, and trigger a new frame when we find an SOI. Signed-off-by: Isaac Scott <[email protected]> Reviewed-by: Ricardo Ribalda <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Laurent Pinchart <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
1 parent 40ed9e9 commit c2eda35

File tree

2 files changed

+27
-1
lines changed

2 files changed

+27
-1
lines changed

drivers/media/usb/uvc/uvc_video.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include <linux/atomic.h>
2121
#include <linux/unaligned.h>
2222

23+
#include <media/jpeg.h>
2324
#include <media/v4l2-common.h>
2425

2526
#include "uvcvideo.h"
@@ -1142,6 +1143,7 @@ static void uvc_video_stats_stop(struct uvc_streaming *stream)
11421143
static int uvc_video_decode_start(struct uvc_streaming *stream,
11431144
struct uvc_buffer *buf, const u8 *data, int len)
11441145
{
1146+
u8 header_len;
11451147
u8 fid;
11461148

11471149
/*
@@ -1155,6 +1157,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
11551157
return -EINVAL;
11561158
}
11571159

1160+
header_len = data[0];
11581161
fid = data[1] & UVC_STREAM_FID;
11591162

11601163
/*
@@ -1236,9 +1239,31 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
12361239
return -EAGAIN;
12371240
}
12381241

1242+
/*
1243+
* Some cameras, when running two parallel streams (one MJPEG alongside
1244+
* another non-MJPEG stream), are known to lose the EOF packet for a frame.
1245+
* We can detect the end of a frame by checking for a new SOI marker, as
1246+
* the SOI always lies on the packet boundary between two frames for
1247+
* these devices.
1248+
*/
1249+
if (stream->dev->quirks & UVC_QUIRK_MJPEG_NO_EOF &&
1250+
(stream->cur_format->fcc == V4L2_PIX_FMT_MJPEG ||
1251+
stream->cur_format->fcc == V4L2_PIX_FMT_JPEG)) {
1252+
const u8 *packet = data + header_len;
1253+
1254+
if (len >= header_len + 2 &&
1255+
packet[0] == 0xff && packet[1] == JPEG_MARKER_SOI &&
1256+
buf->bytesused != 0) {
1257+
buf->state = UVC_BUF_STATE_READY;
1258+
buf->error = 1;
1259+
stream->last_fid ^= UVC_STREAM_FID;
1260+
return -EAGAIN;
1261+
}
1262+
}
1263+
12391264
stream->last_fid = fid;
12401265

1241-
return data[0];
1266+
return header_len;
12421267
}
12431268

12441269
static inline enum dma_data_direction uvc_stream_dir(

drivers/media/usb/uvc/uvcvideo.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#define UVC_QUIRK_NO_RESET_RESUME 0x00004000
7777
#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000
7878
#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000
79+
#define UVC_QUIRK_MJPEG_NO_EOF 0x00020000
7980

8081
/* Format flags */
8182
#define UVC_FMT_FLAG_COMPRESSED 0x00000001

0 commit comments

Comments
 (0)