aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorJean-François Moine <moinejf@free.fr>2011-02-10 05:15:24 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 19:32:06 -0400
commita4a3076ffcdbcf40358edc2068aa4d9103fe0a28 (patch)
tree81becbbf199822d1f3aee28de4731be0ea3948b7 /drivers
parent0f77f40c300c18c15e7aeb2f9eee510aa96d58fd (diff)
[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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/media/video/gspca/sonixj.c119
1 files changed, 93 insertions, 26 deletions
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index c4147072b73e..21f0330885dd 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -57,6 +57,8 @@ struct sd {
57 atomic_t avg_lum; 57 atomic_t avg_lum;
58 u32 exposure; 58 u32 exposure;
59 59
60 s8 short_mark;
61
60 u8 quality; /* image quality */ 62 u8 quality; /* image quality */
61#define QUALITY_MIN 60 63#define QUALITY_MIN 60
62#define QUALITY_MAX 95 64#define QUALITY_MAX 95
@@ -2787,39 +2789,104 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
2787 int len) /* iso packet length */ 2789 int len) /* iso packet length */
2788{ 2790{
2789 struct sd *sd = (struct sd *) gspca_dev; 2791 struct sd *sd = (struct sd *) gspca_dev;
2790 int sof; 2792 int i;
2791 2793
2792 /* the image ends on a 64 bytes block starting with 2794 /*
2793 * ff d9 ff ff 00 c4 c4 96 2795 * A frame ends on the marker
2794 * and followed by various information including luminosity */ 2796 * ff ff 00 c4 c4 96 ..
2795 /* this block may be splitted between two packets */ 2797 * which is 62 bytes long and is followed by various information
2796 /* a new image always starts in a new packet */ 2798 * including statuses and luminosity.
2797 switch (gspca_dev->last_packet_type) { 2799 *
2798 case DISCARD_PACKET: /* restart image building */ 2800 * A marker may be splitted on two packets.
2799 sof = len - 64; 2801 *
2800 if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) 2802 * The 6th byte of a marker contains the bits:
2801 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0); 2803 * 0x08: USB full
2802 return; 2804 * 0xc0: frame sequence
2803 case LAST_PACKET: /* put the JPEG 422 header */ 2805 * When the bit 'USB full' is set, the frame must be discarded;
2806 * this is also the case when the 2 bytes before the marker are
2807 * not the JPEG end of frame ('ff d9').
2808 */
2809
2810/*fixme: assumption about the following code:
2811 * - there can be only one marker in a packet
2812 */
2813
2814 /* skip the remaining bytes of a short marker */
2815 i = sd->short_mark;
2816 if (i != 0) {
2817 sd->short_mark = 0;
2818 if (i < 0 /* if 'ff' at end of previous packet */
2819 && data[0] == 0xff
2820 && data[1] == 0x00)
2821 goto marker_found;
2822 if (data[0] == 0xff && data[1] == 0xff) {
2823 i = 0;
2824 goto marker_found;
2825 }
2826 len -= i;
2827 if (len <= 0)
2828 return;
2829 data += i;
2830 }
2831
2832 /* search backwards if there is a marker in the packet */
2833 for (i = len - 1; --i >= 0; ) {
2834 if (data[i] != 0xff) {
2835 i--;
2836 continue;
2837 }
2838 if (data[i + 1] == 0xff) {
2839
2840 /* (there may be 'ff ff' inside a marker) */
2841 if (i + 2 >= len || data[i + 2] == 0x00)
2842 goto marker_found;
2843 }
2844 }
2845
2846 /* no marker found */
2847 /* add the JPEG header if first fragment */
2848 if (data[len - 1] == 0xff)
2849 sd->short_mark = -1;
2850 if (gspca_dev->last_packet_type == LAST_PACKET)
2804 gspca_frame_add(gspca_dev, FIRST_PACKET, 2851 gspca_frame_add(gspca_dev, FIRST_PACKET,
2805 sd->jpeg_hdr, JPEG_HDR_SZ); 2852 sd->jpeg_hdr, JPEG_HDR_SZ);
2806 break;
2807 }
2808 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 2853 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
2854 return;
2855
2856 /* marker found */
2857 /* if some error, discard the frame */
2858marker_found:
2859 if (i > 2) {
2860 if (data[i - 2] != 0xff || data[i - 1] != 0xd9) {
2861 gspca_dev->last_packet_type = DISCARD_PACKET;
2862 }
2863 } else if (i + 6 < len) {
2864 if (data[i + 6] & 0x08) {
2865 gspca_dev->last_packet_type = DISCARD_PACKET;
2866 }
2867 }
2809 2868
2810 data = gspca_dev->image; 2869 gspca_frame_add(gspca_dev, LAST_PACKET, data, i);
2811 if (data == NULL) 2870
2812 return; 2871 /* if the marker is smaller than 62 bytes,
2813 sof = gspca_dev->image_len - 64; 2872 * memorize the number of bytes to skip in the next packet */
2814 if (data[sof] != 0xff 2873 if (i + 62 > len) { /* no more usable data */
2815 || data[sof + 1] != 0xd9) 2874 sd->short_mark = i + 62 - len;
2816 return; 2875 return;
2876 }
2817 2877
2818 /* end of image found - remove the trailing data */
2819 gspca_dev->image_len = sof + 2;
2820 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
2821 if (sd->ag_cnt >= 0) 2878 if (sd->ag_cnt >= 0)
2822 set_lum(sd, data + sof + 2); 2879 set_lum(sd, data + i);
2880
2881 /* if more data, start a new frame */
2882 i += 62;
2883 if (i < len) {
2884 data += i;
2885 len -= i;
2886 gspca_frame_add(gspca_dev, FIRST_PACKET,
2887 sd->jpeg_hdr, JPEG_HDR_SZ);
2888 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
2889 }
2823} 2890}
2824 2891
2825static int sd_set_jcomp(struct gspca_dev *gspca_dev, 2892static int sd_set_jcomp(struct gspca_dev *gspca_dev,