Commit 2b3e284a authored by Hans de Goede's avatar Hans de Goede Committed by Mauro Carvalho Chehab

[media] gspca_sonixb: Rewrite start of frame detection

Our old start of frame detection code wrongly assumes that the sof
marker always lives at the beginning of the frame. At least for the
0c45:602a camera this is not the case. This patch also improves
the framerate from 28 fps to 30 fps with the 0c45:6005 and 0c45:6007
Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent d6746d55
...@@ -56,6 +56,8 @@ struct sd { ...@@ -56,6 +56,8 @@ struct sd {
int prev_avg_lum; int prev_avg_lum;
int exp_too_low_cnt; int exp_too_low_cnt;
int exp_too_high_cnt; int exp_too_high_cnt;
int header_read;
u8 header[12]; /* Header without sof marker */
unsigned short exposure; unsigned short exposure;
unsigned char gain; unsigned char gain;
...@@ -1177,13 +1179,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev) ...@@ -1177,13 +1179,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
sd_init(gspca_dev); sd_init(gspca_dev);
} }
static void sd_pkt_scan(struct gspca_dev *gspca_dev, static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
u8 *data, /* isoc packet */
int len) /* iso packet length */
{ {
int i;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam; int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12;
/* frames start with: /* frames start with:
* ff ff 00 c4 c4 96 synchro * ff ff 00 c4 c4 96 synchro
...@@ -1194,58 +1193,84 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, ...@@ -1194,58 +1193,84 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
* ll mm brightness sum outside auto exposure * ll mm brightness sum outside auto exposure
* (xx xx xx xx xx) audio values for snc103 * (xx xx xx xx xx) audio values for snc103
*/ */
if (len > 6 && len < 24) { for (i = 0; i < len; i++) {
for (i = 0; i < len - 6; i++) { switch (sd->header_read) {
if (data[0 + i] == 0xff case 0:
&& data[1 + i] == 0xff if (data[i] == 0xff)
&& data[2 + i] == 0x00 sd->header_read++;
&& data[3 + i] == 0xc4 break;
&& data[4 + i] == 0xc4 case 1:
&& data[5 + i] == 0x96) { /* start of frame */ if (data[i] == 0xff)
int lum = -1; sd->header_read++;
int pkt_type = LAST_PACKET; else
int fr_h_sz = (sd->bridge == BRIDGE_103) ? sd->header_read = 0;
18 : 12; break;
case 2:
if (len - i < fr_h_sz) { if (data[i] == 0x00)
PDEBUG(D_STREAM, "packet too short to" sd->header_read++;
" get avg brightness"); else if (data[i] != 0xff)
} else if (sd->bridge == BRIDGE_103) { sd->header_read = 0;
lum = data[i + 9] + break;
(data[i + 10] << 8); case 3:
} else { if (data[i] == 0xc4)
lum = data[i + 8] + (data[i + 9] << 8); sd->header_read++;
} else if (data[i] == 0xff)
/* When exposure changes midway a frame we sd->header_read = 1;
get a lum of 0 in this case drop 2 frames else
as the frames directly after an exposure sd->header_read = 0;
change have an unstable image. Sometimes lum break;
*really* is 0 (cam used in low light with case 4:
low exposure setting), so do not drop frames if (data[i] == 0xc4)
if the previous lum was 0 too. */ sd->header_read++;
if (lum == 0 && sd->prev_avg_lum != 0) { else if (data[i] == 0xff)
lum = -1; sd->header_read = 1;
sd->frames_to_drop = 2; else
sd->prev_avg_lum = 0; sd->header_read = 0;
} else break;
sd->prev_avg_lum = lum; case 5:
atomic_set(&sd->avg_lum, lum); if (data[i] == 0x96)
sd->header_read++;
if (sd->frames_to_drop) { else if (data[i] == 0xff)
sd->frames_to_drop--; sd->header_read = 1;
pkt_type = DISCARD_PACKET; else
} sd->header_read = 0;
break;
gspca_frame_add(gspca_dev, pkt_type, default:
NULL, 0); sd->header[sd->header_read - 6] = data[i];
data += i + fr_h_sz; sd->header_read++;
len -= i + fr_h_sz; if (sd->header_read == header_size) {
gspca_frame_add(gspca_dev, FIRST_PACKET, sd->header_read = 0;
data, len); return data + i + 1;
return;
} }
} }
} }
return NULL;
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0;
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
u8 *sof;
sof = find_sof(gspca_dev, data, len);
if (sof) {
if (sd->bridge == BRIDGE_103) {
fr_h_sz = 18;
lum_offset = 3;
} else {
fr_h_sz = 12;
lum_offset = 2;
}
len_after_sof = len - (sof - data);
len = (sof - data) - fr_h_sz;
if (len < 0)
len = 0;
}
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
/* In raw mode we sometimes get some garbage after the frame /* In raw mode we sometimes get some garbage after the frame
...@@ -1259,6 +1284,33 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev, ...@@ -1259,6 +1284,33 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
} }
gspca_frame_add(gspca_dev, INTER_PACKET, data, len); gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
if (sof) {
int lum = sd->header[lum_offset] +
(sd->header[lum_offset + 1] << 8);
/* 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)
sd->frames_to_drop--;
else
gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof);
}
} }
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment