[media] gspca - sonixj: Better scanning of isochronous packets
A marker 'ff ff 00 c4 c4 96' indicates an end of frame. It is 62 bytes long and may be splitted on 2 packets. It contains a flag 'USB full' which indicates that the frame is truncated. Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
0f77f40c30
commit
a4a3076ffc
|
@ -57,6 +57,8 @@ struct sd {
|
||||||
atomic_t avg_lum;
|
atomic_t avg_lum;
|
||||||
u32 exposure;
|
u32 exposure;
|
||||||
|
|
||||||
|
s8 short_mark;
|
||||||
|
|
||||||
u8 quality; /* image quality */
|
u8 quality; /* image quality */
|
||||||
#define QUALITY_MIN 60
|
#define QUALITY_MIN 60
|
||||||
#define QUALITY_MAX 95
|
#define QUALITY_MAX 95
|
||||||
|
@ -2787,39 +2789,104 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
|
||||||
int len) /* iso packet length */
|
int len) /* iso packet length */
|
||||||
{
|
{
|
||||||
struct sd *sd = (struct sd *) gspca_dev;
|
struct sd *sd = (struct sd *) gspca_dev;
|
||||||
int sof;
|
int i;
|
||||||
|
|
||||||
/* the image ends on a 64 bytes block starting with
|
/*
|
||||||
* ff d9 ff ff 00 c4 c4 96
|
* A frame ends on the marker
|
||||||
* and followed by various information including luminosity */
|
* ff ff 00 c4 c4 96 ..
|
||||||
/* this block may be splitted between two packets */
|
* which is 62 bytes long and is followed by various information
|
||||||
/* a new image always starts in a new packet */
|
* including statuses and luminosity.
|
||||||
switch (gspca_dev->last_packet_type) {
|
*
|
||||||
case DISCARD_PACKET: /* restart image building */
|
* A marker may be splitted on two packets.
|
||||||
sof = len - 64;
|
*
|
||||||
if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9)
|
* The 6th byte of a marker contains the bits:
|
||||||
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
|
* 0x08: USB full
|
||||||
return;
|
* 0xc0: frame sequence
|
||||||
case LAST_PACKET: /* put the JPEG 422 header */
|
* When the bit 'USB full' is set, the frame must be discarded;
|
||||||
|
* this is also the case when the 2 bytes before the marker are
|
||||||
|
* not the JPEG end of frame ('ff d9').
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*fixme: assumption about the following code:
|
||||||
|
* - there can be only one marker in a packet
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* skip the remaining bytes of a short marker */
|
||||||
|
i = sd->short_mark;
|
||||||
|
if (i != 0) {
|
||||||
|
sd->short_mark = 0;
|
||||||
|
if (i < 0 /* if 'ff' at end of previous packet */
|
||||||
|
&& data[0] == 0xff
|
||||||
|
&& data[1] == 0x00)
|
||||||
|
goto marker_found;
|
||||||
|
if (data[0] == 0xff && data[1] == 0xff) {
|
||||||
|
i = 0;
|
||||||
|
goto marker_found;
|
||||||
|
}
|
||||||
|
len -= i;
|
||||||
|
if (len <= 0)
|
||||||
|
return;
|
||||||
|
data += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* search backwards if there is a marker in the packet */
|
||||||
|
for (i = len - 1; --i >= 0; ) {
|
||||||
|
if (data[i] != 0xff) {
|
||||||
|
i--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (data[i + 1] == 0xff) {
|
||||||
|
|
||||||
|
/* (there may be 'ff ff' inside a marker) */
|
||||||
|
if (i + 2 >= len || data[i + 2] == 0x00)
|
||||||
|
goto marker_found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* no marker found */
|
||||||
|
/* add the JPEG header if first fragment */
|
||||||
|
if (data[len - 1] == 0xff)
|
||||||
|
sd->short_mark = -1;
|
||||||
|
if (gspca_dev->last_packet_type == LAST_PACKET)
|
||||||
gspca_frame_add(gspca_dev, FIRST_PACKET,
|
gspca_frame_add(gspca_dev, FIRST_PACKET,
|
||||||
sd->jpeg_hdr, JPEG_HDR_SZ);
|
sd->jpeg_hdr, JPEG_HDR_SZ);
|
||||||
break;
|
|
||||||
}
|
|
||||||
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
|
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
|
||||||
|
return;
|
||||||
|
|
||||||
data = gspca_dev->image;
|
/* marker found */
|
||||||
if (data == NULL)
|
/* if some error, discard the frame */
|
||||||
return;
|
marker_found:
|
||||||
sof = gspca_dev->image_len - 64;
|
if (i > 2) {
|
||||||
if (data[sof] != 0xff
|
if (data[i - 2] != 0xff || data[i - 1] != 0xd9) {
|
||||||
|| data[sof + 1] != 0xd9)
|
gspca_dev->last_packet_type = DISCARD_PACKET;
|
||||||
return;
|
}
|
||||||
|
} else if (i + 6 < len) {
|
||||||
|
if (data[i + 6] & 0x08) {
|
||||||
|
gspca_dev->last_packet_type = DISCARD_PACKET;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gspca_frame_add(gspca_dev, LAST_PACKET, data, i);
|
||||||
|
|
||||||
|
/* if the marker is smaller than 62 bytes,
|
||||||
|
* memorize the number of bytes to skip in the next packet */
|
||||||
|
if (i + 62 > len) { /* no more usable data */
|
||||||
|
sd->short_mark = i + 62 - len;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* end of image found - remove the trailing data */
|
|
||||||
gspca_dev->image_len = sof + 2;
|
|
||||||
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
|
|
||||||
if (sd->ag_cnt >= 0)
|
if (sd->ag_cnt >= 0)
|
||||||
set_lum(sd, data + sof + 2);
|
set_lum(sd, data + i);
|
||||||
|
|
||||||
|
/* if more data, start a new frame */
|
||||||
|
i += 62;
|
||||||
|
if (i < len) {
|
||||||
|
data += i;
|
||||||
|
len -= i;
|
||||||
|
gspca_frame_add(gspca_dev, FIRST_PACKET,
|
||||||
|
sd->jpeg_hdr, JPEG_HDR_SZ);
|
||||||
|
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
|
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
|
||||||
|
|
Loading…
Reference in New Issue