aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2010-12-12 06:55:04 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2010-12-29 05:17:01 -0500
commit2b3e284a89dfa53eb42b6470e4c03e5ddfdb24c5 (patch)
tree5a33c8a36c776bbdec281d4a8a2dbdb73c0134f7
parentd6746d55da0819edbe913a1447b1ab0e7b440241 (diff)
[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: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
-rw-r--r--drivers/media/video/gspca/sonixb.c160
1 files changed, 106 insertions, 54 deletions
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index bfbd8c17d28b..f47a82902fa3 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -56,6 +56,8 @@ struct sd {
56 int prev_avg_lum; 56 int prev_avg_lum;
57 int exp_too_low_cnt; 57 int exp_too_low_cnt;
58 int exp_too_high_cnt; 58 int exp_too_high_cnt;
59 int header_read;
60 u8 header[12]; /* Header without sof marker */
59 61
60 unsigned short exposure; 62 unsigned short exposure;
61 unsigned char gain; 63 unsigned char gain;
@@ -1177,13 +1179,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
1177 sd_init(gspca_dev); 1179 sd_init(gspca_dev);
1178} 1180}
1179 1181
1180static void sd_pkt_scan(struct gspca_dev *gspca_dev, 1182static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
1181 u8 *data, /* isoc packet */
1182 int len) /* iso packet length */
1183{ 1183{
1184 int i;
1185 struct sd *sd = (struct sd *) gspca_dev; 1184 struct sd *sd = (struct sd *) gspca_dev;
1186 struct cam *cam = &gspca_dev->cam; 1185 int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12;
1187 1186
1188 /* frames start with: 1187 /* frames start with:
1189 * ff ff 00 c4 c4 96 synchro 1188 * ff ff 00 c4 c4 96 synchro
@@ -1194,58 +1193,84 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1194 * ll mm brightness sum outside auto exposure 1193 * ll mm brightness sum outside auto exposure
1195 * (xx xx xx xx xx) audio values for snc103 1194 * (xx xx xx xx xx) audio values for snc103
1196 */ 1195 */
1197 if (len > 6 && len < 24) { 1196 for (i = 0; i < len; i++) {
1198 for (i = 0; i < len - 6; i++) { 1197 switch (sd->header_read) {
1199 if (data[0 + i] == 0xff 1198 case 0:
1200 && data[1 + i] == 0xff 1199 if (data[i] == 0xff)
1201 && data[2 + i] == 0x00 1200 sd->header_read++;
1202 && data[3 + i] == 0xc4 1201 break;
1203 && data[4 + i] == 0xc4 1202 case 1:
1204 && data[5 + i] == 0x96) { /* start of frame */ 1203 if (data[i] == 0xff)
1205 int lum = -1; 1204 sd->header_read++;
1206 int pkt_type = LAST_PACKET; 1205 else
1207 int fr_h_sz = (sd->bridge == BRIDGE_103) ? 1206 sd->header_read = 0;
1208 18 : 12; 1207 break;
1209 1208 case 2:
1210 if (len - i < fr_h_sz) { 1209 if (data[i] == 0x00)
1211 PDEBUG(D_STREAM, "packet too short to" 1210 sd->header_read++;
1212 " get avg brightness"); 1211 else if (data[i] != 0xff)
1213 } else if (sd->bridge == BRIDGE_103) { 1212 sd->header_read = 0;
1214 lum = data[i + 9] + 1213 break;
1215 (data[i + 10] << 8); 1214 case 3:
1216 } else { 1215 if (data[i] == 0xc4)
1217 lum = data[i + 8] + (data[i + 9] << 8); 1216 sd->header_read++;
1218 } 1217 else if (data[i] == 0xff)
1219 /* When exposure changes midway a frame we 1218 sd->header_read = 1;
1220 get a lum of 0 in this case drop 2 frames 1219 else
1221 as the frames directly after an exposure 1220 sd->header_read = 0;
1222 change have an unstable image. Sometimes lum 1221 break;
1223 *really* is 0 (cam used in low light with 1222 case 4:
1224 low exposure setting), so do not drop frames 1223 if (data[i] == 0xc4)
1225 if the previous lum was 0 too. */ 1224 sd->header_read++;
1226 if (lum == 0 && sd->prev_avg_lum != 0) { 1225 else if (data[i] == 0xff)
1227 lum = -1; 1226 sd->header_read = 1;
1228 sd->frames_to_drop = 2; 1227 else
1229 sd->prev_avg_lum = 0; 1228 sd->header_read = 0;
1230 } else 1229 break;
1231 sd->prev_avg_lum = lum; 1230 case 5:
1232 atomic_set(&sd->avg_lum, lum); 1231 if (data[i] == 0x96)
1233 1232 sd->header_read++;
1234 if (sd->frames_to_drop) { 1233 else if (data[i] == 0xff)
1235 sd->frames_to_drop--; 1234 sd->header_read = 1;
1236 pkt_type = DISCARD_PACKET; 1235 else
1237 } 1236 sd->header_read = 0;
1238 1237 break;
1239 gspca_frame_add(gspca_dev, pkt_type, 1238 default:
1240 NULL, 0); 1239 sd->header[sd->header_read - 6] = data[i];
1241 data += i + fr_h_sz; 1240 sd->header_read++;
1242 len -= i + fr_h_sz; 1241 if (sd->header_read == header_size) {
1243 gspca_frame_add(gspca_dev, FIRST_PACKET, 1242 sd->header_read = 0;
1244 data, len); 1243 return data + i + 1;
1245 return;
1246 } 1244 }
1247 } 1245 }
1248 } 1246 }
1247 return NULL;
1248}
1249
1250static void sd_pkt_scan(struct gspca_dev *gspca_dev,
1251 u8 *data, /* isoc packet */
1252 int len) /* iso packet length */
1253{
1254 int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0;
1255 struct sd *sd = (struct sd *) gspca_dev;
1256 struct cam *cam = &gspca_dev->cam;
1257 u8 *sof;
1258
1259 sof = find_sof(gspca_dev, data, len);
1260 if (sof) {
1261 if (sd->bridge == BRIDGE_103) {
1262 fr_h_sz = 18;
1263 lum_offset = 3;
1264 } else {
1265 fr_h_sz = 12;
1266 lum_offset = 2;
1267 }
1268
1269 len_after_sof = len - (sof - data);
1270 len = (sof - data) - fr_h_sz;
1271 if (len < 0)
1272 len = 0;
1273 }
1249 1274
1250 if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) { 1275 if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
1251 /* In raw mode we sometimes get some garbage after the frame 1276 /* 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 } 1284 }
1260 1285
1261 gspca_frame_add(gspca_dev, INTER_PACKET, data, len); 1286 gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
1287
1288 if (sof) {
1289 int lum = sd->header[lum_offset] +
1290 (sd->header[lum_offset + 1] << 8);
1291
1292 /* When exposure changes midway a frame we
1293 get a lum of 0 in this case drop 2 frames
1294 as the frames directly after an exposure
1295 change have an unstable image. Sometimes lum
1296 *really* is 0 (cam used in low light with
1297 low exposure setting), so do not drop frames
1298 if the previous lum was 0 too. */
1299 if (lum == 0 && sd->prev_avg_lum != 0) {
1300 lum = -1;
1301 sd->frames_to_drop = 2;
1302 sd->prev_avg_lum = 0;
1303 } else
1304 sd->prev_avg_lum = lum;
1305 atomic_set(&sd->avg_lum, lum);
1306
1307 if (sd->frames_to_drop)
1308 sd->frames_to_drop--;
1309 else
1310 gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
1311
1312 gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof);
1313 }
1262} 1314}
1263 1315
1264static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val) 1316static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)