diff options
author | Jean-François Moine <moinejf@free.fr> | 2011-02-10 05:15:24 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:32:06 -0400 |
commit | a4a3076ffcdbcf40358edc2068aa4d9103fe0a28 (patch) | |
tree | 81becbbf199822d1f3aee28de4731be0ea3948b7 /drivers | |
parent | 0f77f40c300c18c15e7aeb2f9eee510aa96d58fd (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.c | 119 |
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 */ | ||
2858 | marker_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 | ||
2825 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, | 2892 | static int sd_set_jcomp(struct gspca_dev *gspca_dev, |