aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJean-François Moine <moinejf@free.fr>2011-02-10 05:38:58 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 19:32:06 -0400
commitb96cfc33e74f5ee5a206b2d43bf0bc3898c5a572 (patch)
treefbd665d1a56c497de0effc449aef7c0ccfea59b8
parentdccdcccdd36bf7570967ff53411c7401b8e645d6 (diff)
[media] gspca - sonixj: Update the JPEG quality for best image transfer
During image capture, the filling rate of the isoc packets is computed. It is then used by a work queue to update the current JPEG quality. Tested-by: Franck Bourdonnec <fbourdonnec@chez.com> Signed-off-by: Jean-François Moine <moinejf@free.fr> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/gspca/sonixj.c109
1 files changed, 86 insertions, 23 deletions
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index d465022b8022..2bfb8df9168b 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -57,12 +57,18 @@ struct sd {
57 atomic_t avg_lum; 57 atomic_t avg_lum;
58 u32 exposure; 58 u32 exposure;
59 59
60 struct work_struct work;
61 struct workqueue_struct *work_thread;
62
63 u32 pktsz; /* (used by pkt_scan) */
64 u16 npkt;
65 u8 nchg;
60 s8 short_mark; 66 s8 short_mark;
61 67
62 u8 quality; /* image quality */ 68 u8 quality; /* image quality */
63#define QUALITY_MIN 60 69#define QUALITY_MIN 25
64#define QUALITY_MAX 95 70#define QUALITY_MAX 90
65#define QUALITY_DEF 80 71#define QUALITY_DEF 70
66 72
67 u8 reg01; 73 u8 reg01;
68 u8 reg17; 74 u8 reg17;
@@ -100,6 +106,8 @@ enum sensors {
100 SENSOR_SP80708, 106 SENSOR_SP80708,
101}; 107};
102 108
109static void qual_upd(struct work_struct *work);
110
103/* device flags */ 111/* device flags */
104#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */ 112#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */
105#define F_ILLUM 0x02 /* presence of illuminator */ 113#define F_ILLUM 0x02 /* presence of illuminator */
@@ -1786,6 +1794,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
1786 sd->ag_cnt = -1; 1794 sd->ag_cnt = -1;
1787 sd->quality = QUALITY_DEF; 1795 sd->quality = QUALITY_DEF;
1788 1796
1797 INIT_WORK(&sd->work, qual_upd);
1798
1789 return 0; 1799 return 0;
1790} 1800}
1791 1801
@@ -2297,6 +2307,19 @@ static void setjpegqual(struct gspca_dev *gspca_dev)
2297 reg_w1(gspca_dev, 0x18, sd->reg18); 2307 reg_w1(gspca_dev, 0x18, sd->reg18);
2298} 2308}
2299 2309
2310/* JPEG quality update */
2311/* This function is executed from a work queue. */
2312static void qual_upd(struct work_struct *work)
2313{
2314 struct sd *sd = container_of(work, struct sd, work);
2315 struct gspca_dev *gspca_dev = &sd->gspca_dev;
2316
2317 mutex_lock(&gspca_dev->usb_lock);
2318 PDEBUG(D_STREAM, "qual_upd %d%%", sd->quality);
2319 setjpegqual(gspca_dev);
2320 mutex_unlock(&gspca_dev->usb_lock);
2321}
2322
2300/* -- start the camera -- */ 2323/* -- start the camera -- */
2301static int sd_start(struct gspca_dev *gspca_dev) 2324static int sd_start(struct gspca_dev *gspca_dev)
2302{ 2325{
@@ -2610,6 +2633,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
2610 setcolors(gspca_dev); 2633 setcolors(gspca_dev);
2611 setautogain(gspca_dev); 2634 setautogain(gspca_dev);
2612 setfreq(gspca_dev); 2635 setfreq(gspca_dev);
2636
2637 sd->pktsz = sd->npkt = 0;
2638 sd->nchg = sd->short_mark = 0;
2639 sd->work_thread = create_singlethread_workqueue(MODULE_NAME);
2640
2613 return gspca_dev->usb_err; 2641 return gspca_dev->usb_err;
2614} 2642}
2615 2643
@@ -2686,6 +2714,20 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
2686 /* reg_w1(gspca_dev, 0xf1, 0x01); */ 2714 /* reg_w1(gspca_dev, 0xf1, 0x01); */
2687} 2715}
2688 2716
2717/* called on streamoff with alt==0 and on disconnect */
2718/* the usb_lock is held at entry - restore on exit */
2719static void sd_stop0(struct gspca_dev *gspca_dev)
2720{
2721 struct sd *sd = (struct sd *) gspca_dev;
2722
2723 if (sd->work_thread != NULL) {
2724 mutex_unlock(&gspca_dev->usb_lock);
2725 destroy_workqueue(sd->work_thread);
2726 mutex_lock(&gspca_dev->usb_lock);
2727 sd->work_thread = NULL;
2728 }
2729}
2730
2689static void do_autogain(struct gspca_dev *gspca_dev) 2731static void do_autogain(struct gspca_dev *gspca_dev)
2690{ 2732{
2691 struct sd *sd = (struct sd *) gspca_dev; 2733 struct sd *sd = (struct sd *) gspca_dev;
@@ -2778,7 +2820,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
2778 int len) /* iso packet length */ 2820 int len) /* iso packet length */
2779{ 2821{
2780 struct sd *sd = (struct sd *) gspca_dev; 2822 struct sd *sd = (struct sd *) gspca_dev;
2781 int i; 2823 int i, new_qual;
2782 2824
2783 /* 2825 /*
2784 * A frame ends on the marker 2826 * A frame ends on the marker
@@ -2818,6 +2860,10 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
2818 data += i; 2860 data += i;
2819 } 2861 }
2820 2862
2863 /* count the packets and their size */
2864 sd->npkt++;
2865 sd->pktsz += len;
2866
2821 /* search backwards if there is a marker in the packet */ 2867 /* search backwards if there is a marker in the packet */
2822 for (i = len - 1; --i >= 0; ) { 2868 for (i = len - 1; --i >= 0; ) {
2823 if (data[i] != 0xff) { 2869 if (data[i] != 0xff) {
@@ -2843,27 +2889,60 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
2843 return; 2889 return;
2844 2890
2845 /* marker found */ 2891 /* marker found */
2846 /* if some error, discard the frame */ 2892 /* if some error, discard the frame and decrease the quality */
2847marker_found: 2893marker_found:
2894 new_qual = 0;
2848 if (i > 2) { 2895 if (i > 2) {
2849 if (data[i - 2] != 0xff || data[i - 1] != 0xd9) { 2896 if (data[i - 2] != 0xff || data[i - 1] != 0xd9) {
2850 gspca_dev->last_packet_type = DISCARD_PACKET; 2897 gspca_dev->last_packet_type = DISCARD_PACKET;
2898 new_qual = -3;
2851 } 2899 }
2852 } else if (i + 6 < len) { 2900 } else if (i + 6 < len) {
2853 if (data[i + 6] & 0x08) { 2901 if (data[i + 6] & 0x08) {
2854 gspca_dev->last_packet_type = DISCARD_PACKET; 2902 gspca_dev->last_packet_type = DISCARD_PACKET;
2903 new_qual = -5;
2855 } 2904 }
2856 } 2905 }
2857 2906
2858 gspca_frame_add(gspca_dev, LAST_PACKET, data, i); 2907 gspca_frame_add(gspca_dev, LAST_PACKET, data, i);
2859 2908
2909 /* compute the filling rate and a new JPEG quality */
2910 if (new_qual == 0) {
2911 int r;
2912
2913 r = (sd->pktsz * 100) /
2914 (sd->npkt *
2915 gspca_dev->urb[0]->iso_frame_desc[0].length);
2916 if (r >= 85)
2917 new_qual = -3;
2918 else if (r < 75)
2919 new_qual = 2;
2920 }
2921 if (new_qual != 0) {
2922 sd->nchg += new_qual;
2923 if (sd->nchg < -6 || sd->nchg >= 12) {
2924 sd->nchg = 0;
2925 new_qual += sd->quality;
2926 if (new_qual < QUALITY_MIN)
2927 new_qual = QUALITY_MIN;
2928 else if (new_qual > QUALITY_MAX)
2929 new_qual = QUALITY_MAX;
2930 if (new_qual != sd->quality) {
2931 sd->quality = new_qual;
2932 queue_work(sd->work_thread, &sd->work);
2933 }
2934 }
2935 } else {
2936 sd->nchg = 0;
2937 }
2938 sd->pktsz = sd->npkt = 0;
2939
2860 /* if the marker is smaller than 62 bytes, 2940 /* if the marker is smaller than 62 bytes,
2861 * memorize the number of bytes to skip in the next packet */ 2941 * memorize the number of bytes to skip in the next packet */
2862 if (i + 62 > len) { /* no more usable data */ 2942 if (i + 62 > len) { /* no more usable data */
2863 sd->short_mark = i + 62 - len; 2943 sd->short_mark = i + 62 - len;
2864 return; 2944 return;
2865 } 2945 }
2866
2867 if (sd->ag_cnt >= 0) 2946 if (sd->ag_cnt >= 0)
2868 set_lum(sd, data + i); 2947 set_lum(sd, data + i);
2869 2948
@@ -2878,22 +2957,6 @@ marker_found:
2878 } 2957 }
2879} 2958}
2880 2959
2881static int sd_set_jcomp(struct gspca_dev *gspca_dev,
2882 struct v4l2_jpegcompression *jcomp)
2883{
2884 struct sd *sd = (struct sd *) gspca_dev;
2885
2886 if (jcomp->quality < QUALITY_MIN)
2887 sd->quality = QUALITY_MIN;
2888 else if (jcomp->quality > QUALITY_MAX)
2889 sd->quality = QUALITY_MAX;
2890 else
2891 sd->quality = jcomp->quality;
2892 if (gspca_dev->streaming)
2893 setjpegqual(gspca_dev);
2894 return 0;
2895}
2896
2897static int sd_get_jcomp(struct gspca_dev *gspca_dev, 2960static int sd_get_jcomp(struct gspca_dev *gspca_dev,
2898 struct v4l2_jpegcompression *jcomp) 2961 struct v4l2_jpegcompression *jcomp)
2899{ 2962{
@@ -2955,10 +3018,10 @@ static const struct sd_desc sd_desc = {
2955 .init = sd_init, 3018 .init = sd_init,
2956 .start = sd_start, 3019 .start = sd_start,
2957 .stopN = sd_stopN, 3020 .stopN = sd_stopN,
3021 .stop0 = sd_stop0,
2958 .pkt_scan = sd_pkt_scan, 3022 .pkt_scan = sd_pkt_scan,
2959 .dq_callback = do_autogain, 3023 .dq_callback = do_autogain,
2960 .get_jcomp = sd_get_jcomp, 3024 .get_jcomp = sd_get_jcomp,
2961 .set_jcomp = sd_set_jcomp,
2962 .querymenu = sd_querymenu, 3025 .querymenu = sd_querymenu,
2963#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE) 3026#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
2964 .int_pkt_scan = sd_int_pkt_scan, 3027 .int_pkt_scan = sd_int_pkt_scan,