V4L/DVB (8870): gspca: Fix dark room problem with sonixb.
Hans de Goede [Thu, 4 Sep 2008 19:22:56 +0000 (16:22 -0300)]
When using the sonixb driver in a dark room and given that the autoexposure
algorithm starts with a setting most suitable for daylight, the picture
produced by the cam may actually be 100% black leading to a avg_lum value of 0,
so an avg_lum value of 0 does not always signal an exposure settings change
(which it normally does). This patch adds a check for the really black image
case and stops dropping all frames as invalid in this case.

Signed-off-by: Hans de Goede <j.w.r.degoede@hhs.nl>
Signed-off-by: Jean-Francois Moine <moinejf@free.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>

drivers/media/video/gspca/sonixb.c

index bde9ea9..64bc758 100644 (file)
@@ -52,6 +52,7 @@ MODULE_LICENSE("GPL");
 struct sd {
        struct gspca_dev gspca_dev;     /* !! must be the first item */
        atomic_t avg_lum;
+       int prev_avg_lum;
 
        unsigned char gain;
        unsigned char exposure;
@@ -1022,10 +1023,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
                                } else {
                                        lum = data[i + 8] + (data[i + 9] << 8);
                                }
-                               if (lum == 0) {
+                               /* When exposure changes midway a frame we
+                                  get a lum of 0 in this case drop 2 frames
+                                  as the frames directly after an exposure
+                                  change have an unstable image. Sometimes lum
+                                  *really* is 0 (cam used in low light with
+                                  low exposure setting), so do not drop frames
+                                  if the previous lum was 0 too. */
+                               if (lum == 0 && sd->prev_avg_lum != 0) {
                                        lum = -1;
                                        sd->frames_to_drop = 2;
-                               }
+                                       sd->prev_avg_lum = 0;
+                               } else
+                                       sd->prev_avg_lum = lum;
                                atomic_set(&sd->avg_lum, lum);
 
                                if (sd->frames_to_drop) {