Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a4a3076f authored by Jean-François Moine's avatar Jean-François Moine Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarJean-François Moine <moinejf@free.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 0f77f40c
Loading
Loading
Loading
Loading
+93 −26
Original line number Diff line number Diff line
@@ -57,6 +57,8 @@ struct sd {
	atomic_t avg_lum;
	u32 exposure;

	s8 short_mark;

	u8 quality;			/* image quality */
#define QUALITY_MIN 60
#define QUALITY_MAX 95
@@ -2787,39 +2789,104 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
			int len)			/* iso packet length */
{
	struct sd *sd = (struct sd *) gspca_dev;
	int sof;

	/* the image ends on a 64 bytes block starting with
	 *	ff d9 ff ff 00 c4 c4 96
	 * and followed by various information including luminosity */
	/* this block may be splitted between two packets */
	/* a new image always starts in a new packet */
	switch (gspca_dev->last_packet_type) {
	case DISCARD_PACKET:		/* restart image building */
		sof = len - 64;
		if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9)
			gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
	int i;

	/*
	 * A frame ends on the marker
	 *		ff ff 00 c4 c4 96 ..
	 * which is 62 bytes long and is followed by various information
	 * including statuses and luminosity.
	 *
	 * A marker may be splitted on two packets.
	 *
	 * The 6th byte of a marker contains the bits:
	 *	0x08: USB full
	 *	0xc0: frame sequence
	 * 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;
	case LAST_PACKET:		/* put the JPEG 422 header */
		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,
				sd->jpeg_hdr, JPEG_HDR_SZ);
		break;
	}
	gspca_frame_add(gspca_dev, INTER_PACKET, data, len);

	data = gspca_dev->image;
	if (data == NULL)
	return;
	sof = gspca_dev->image_len - 64;
	if (data[sof] != 0xff
	 || data[sof + 1] != 0xd9)

	/* marker found */
	/* if some error, discard the frame */
marker_found:
	if (i > 2) {
		if (data[i - 2] != 0xff || data[i - 1] != 0xd9) {
			gspca_dev->last_packet_type = DISCARD_PACKET;
		}
	} 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)
		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,