00001 #include <linux/videodev2.h>
00002 #include <asm/types.h>
00003 #include <sys/types.h>
00004 #include <sys/syscall.h>
00005 #include <sys/prctl.h>
00006 #include <linux/capability.h>
00007
00008 #include <pthread.h>
00009 #include <poll.h>
00010
00011 #include <stdio.h>
00012 #include <stdlib.h>
00013 #include <string.h>
00014 #include <unistd.h>
00015 #include <math.h>
00016
00017 #include <sys/fcntl.h>
00018 #include <sys/ioctl.h>
00019 #include <sys/mman.h>
00020 #include <sys/time.h>
00021 #include <time.h>
00022
00023 #include <errno.h>
00024 #include <malloc.h>
00025
00026 #include "../Debug.h"
00027 #include "V4L2Sensor.h"
00028 #include "linux/isp_user.h"
00029 #include "linux/omap34xxcam-fcam.h"
00030 #include "FCam/Event.h"
00031
00032 namespace FCam {
00033 namespace N900 {
00034
00035 V4L2Sensor *V4L2Sensor::instance(std::string fname) {
00036 std::map<std::string, V4L2Sensor *>::iterator i;
00037 i = instances_.find(fname);
00038 if (i == instances_.end()) {
00039 instances_[fname] = new V4L2Sensor(fname);
00040 }
00041
00042 return instances_[fname];
00043 };
00044
00045 V4L2Sensor::V4L2Sensor(std::string fname) : state(CLOSED), filename(fname) {
00046
00047 }
00048
00049 std::map<std::string, V4L2Sensor *> V4L2Sensor::instances_;
00050
00051 void V4L2Sensor::open() {
00052 if (state != CLOSED) {
00053 return;
00054 }
00055
00056 fd = ::open(filename.c_str(), O_RDWR | O_NONBLOCK, 0);
00057
00058 if (fd < 0) {
00059 error(Event::DriverError, "V4L2Sensor: Error opening %s: %s", filename.c_str(), strerror(errno));
00060 return;
00061 }
00062
00063 state = IDLE;
00064 }
00065
00066 void V4L2Sensor::close() {
00067 if (state != CLOSED) {
00068 ::close(fd);
00069 }
00070 state = CLOSED;
00071 }
00072
00073 int V4L2Sensor::getFD() {
00074 if (state == CLOSED) {
00075 return -1;
00076 }
00077 return fd;
00078 }
00079
00080 void V4L2Sensor::startStreaming(Mode m,
00081 const HistogramConfig &histogram,
00082 const SharpnessMapConfig &sharpness) {
00083
00084 if (state != IDLE) {
00085 error(Event::InternalError, "V4L2Sensor: Can only initiate streaming if sensor is idle");
00086 return;
00087 }
00088
00089 struct v4l2_format fmt;
00090
00091 memset(&fmt, 0, sizeof(struct v4l2_format));
00092
00093 fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00094 fmt.fmt.pix.width = m.width;
00095 fmt.fmt.pix.height = m.height;
00096 if (m.type == UYVY) {
00097 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
00098 } else if (m.type == RAW) {
00099 fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
00100 } else {
00101 error(Event::InternalError, "V4L2Sensor: Unknown image format requested");
00102 return;
00103 }
00104 fmt.fmt.pix.field = V4L2_FIELD_NONE;
00105
00106
00107 if (ioctl(fd, VIDIOC_S_FMT, &fmt) < 0) {
00108 error(Event::DriverError, "VIDIOC_S_FMT");
00109 return;
00110 }
00111
00112
00113 struct v4l2_streamparm parm;
00114 memset(&parm, 0, sizeof(struct v4l2_streamparm));
00115 parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00116 parm.parm.capture.timeperframe.numerator = 0;
00117 parm.parm.capture.timeperframe.denominator = 1000000;
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127 if (ioctl(fd, VIDIOC_S_PARM, &parm) < 0) {
00128 error(Event::DriverError, "VIDIOC_S_PARM");
00129 return;
00130 }
00131
00132 currentMode.width = fmt.fmt.pix.width;
00133 currentMode.height = fmt.fmt.pix.height;
00134 currentMode.type = (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_UYVY) ? UYVY : RAW;
00135
00136 struct v4l2_requestbuffers req;
00137 memset(&req, 0, sizeof(req));
00138 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00139 req.memory = V4L2_MEMORY_MMAP;
00140 req.count = 8;
00141
00142 if (ioctl(fd, VIDIOC_REQBUFS, &req) < 0) {
00143 error(Event::DriverError, "VIDIOC_REQBUFS: %s", strerror(errno));
00144 return;
00145 }
00146
00147 buffers.resize(req.count);
00148
00149 for (size_t i = 0; i < buffers.size(); i++) {
00150 v4l2_buffer buf;
00151 memset(&buf, 0, sizeof(v4l2_buffer));
00152 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00153 buf.memory = V4L2_MEMORY_MMAP;
00154 buf.index = i;
00155
00156 if (ioctl(fd, VIDIOC_QUERYBUF, &buf) < 0) {
00157 error(Event::DriverError, "VIDIOC_QUERYBUF: %s", strerror(errno));
00158 return;
00159 }
00160
00161 buffers[i].index = i;
00162 buffers[i].length = buf.length;
00163 buffers[i].data =
00164 (unsigned char *)mmap(NULL, buffers[i].length, PROT_READ | PROT_WRITE,
00165 MAP_SHARED, fd, buf.m.offset);
00166
00167 if (buffers[i].data == MAP_FAILED) {
00168 error(Event::InternalError, "V4L2Sensor: mmap failed: %s", strerror(errno));
00169 return;
00170 }
00171 }
00172
00173 for (size_t i = 0; i < buffers.size(); i++) {
00174 releaseFrame(&buffers[i]);
00175 }
00176
00177
00178 setHistogramConfig(histogram);
00179 setSharpnessMapConfig(sharpness);
00180
00181 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00182 if (ioctl(fd, VIDIOC_STREAMON, &type) < 0) {
00183 error(Event::DriverError, "VIDIOC_STREAMON: %s", strerror(errno));
00184 return;
00185 }
00186
00187 dprintf(2, "Sensor now streaming\n");
00188 state = STREAMING;
00189 }
00190
00191
00192 void V4L2Sensor::stopStreaming() {
00193 if (state != STREAMING) {
00194 return;
00195 }
00196
00197 enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00198 if (ioctl(fd, VIDIOC_STREAMOFF, &type) < 0) {
00199 error(Event::DriverError, "VIDIOC_STREAMOFF: %s", strerror(errno));
00200 return;
00201 }
00202
00203 for (size_t i = 0; i < buffers.size(); i++) {
00204 if (munmap(buffers[i].data, buffers[i].length)) {
00205 error(Event::InternalError, "munmap failed: %s", strerror(errno));
00206 }
00207 }
00208
00209 state = IDLE;
00210 }
00211
00212
00213
00214 V4L2Sensor::V4L2Frame *V4L2Sensor::acquireFrame(bool blocking) {
00215 if (state != STREAMING) {
00216 error(Event::InternalError, "V4L2Sensor: Can't acquire a frame when not streaming");
00217 return NULL;
00218 }
00219
00220 v4l2_buffer buf;
00221 memset(&buf, 0, sizeof(v4l2_buffer));
00222 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00223 buf.memory = V4L2_MEMORY_MMAP;
00224
00225 if (blocking) {
00226 struct pollfd p = {fd, POLLIN, 0};
00227 poll(&p, 1, -1);
00228 if (!(p.revents & POLLIN)) {
00229 error(Event::DriverError, "Poll returned without data being available: %s", strerror(errno));
00230 return NULL;
00231 }
00232 }
00233
00234 if (ioctl(fd, VIDIOC_DQBUF, &buf) < 0) {
00235 if (errno == EAGAIN && !blocking) {
00236 return NULL;
00237 }
00238
00239 error(Event::DriverError, "VIDIOC_DQBUF: %s", strerror(errno));
00240 return NULL;
00241 }
00242
00243 buffers[buf.index].processingDoneTime = Time(buf.timestamp);
00244 return &(buffers[buf.index]);
00245 }
00246
00247
00248
00249 Histogram V4L2Sensor::getHistogram(Time t, const HistogramConfig &conf) {
00250
00251 if (!conf.enabled) {
00252 return Histogram();
00253 }
00254
00255
00256
00257 struct isp_hist_data hist_data;
00258 unsigned buf[64 * 4];
00259 hist_data.hist_statistics_buf = buf;
00260 hist_data.update = REQUEST_STATISTICS;
00261
00262
00263
00264 hist_data.frame_number = NEWEST_FRAME;
00265 hist_data.curr_frame = 0;
00266 hist_data.config_counter = 0;
00267 hist_data.ts.tv_sec = 0;
00268 hist_data.ts.tv_usec = 0;
00269
00270 if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_REQ, &hist_data)) {
00271 if (errno != EBUSY) {
00272 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_REQ: %s", strerror(errno));
00273 }
00274 return Histogram();
00275 }
00276
00277
00278
00279 Time h(hist_data.ts);
00280
00281 if ((t - h) > 4000) {
00282 warning(Event::DriverError, "Missing histogram (%d)\n", t-h);
00283 return Histogram();
00284 }
00285
00286 while ((t-h) < -4000) {
00287
00288 if (hist_data.frame_number == 0) { hist_data.frame_number = 4095; }
00289 else { hist_data.frame_number--; }
00290
00291 if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_REQ, &hist_data)) {
00292 if (errno != EBUSY)
00293 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_REQ: %s",
00294 strerror(errno));
00295 return Histogram();
00296 }
00297
00298 h = Time(hist_data.ts);
00299 }
00300
00301 Histogram hist(64, 3, conf.region);
00302 for (int i = 0; i < 64; i++) {
00303 hist(i, 0) = buf[64 + i];
00304 hist(i, 1) = buf[i];
00305 hist(i, 2) = buf[128 + i];
00306 }
00307 return hist;
00308 }
00309
00310 SharpnessMap V4L2Sensor::getSharpnessMap(Time t, const SharpnessMapConfig &conf) {
00311 if (!conf.enabled) {
00312 return SharpnessMap();
00313 }
00314
00315
00316 struct isp_af_data af_data;
00317 af_data.frame_number = NEWEST_FRAME;
00318 af_data.update = REQUEST_STATISTICS;
00319 af_data.curr_frame = 0;
00320 af_data.config_counter = 0;
00321 af_data.xtrastats.ts.tv_sec = 0;
00322 af_data.xtrastats.ts.tv_usec = 0;
00323 unsigned buf[16*12*12];
00324 af_data.af_statistics_buf = buf;
00325
00326 if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_REQ, &af_data)) {
00327 if (errno != EBUSY) {
00328 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_REQ: %s", strerror(errno));
00329 }
00330 return SharpnessMap();
00331 }
00332
00333 Time s(af_data.xtrastats.ts);
00334 if ((t - s) > 4000) {
00335 warning(Event::DriverError, "Missing sharpness (%d)\n", t-s);
00336 }
00337
00338 while ((t-s) < -4000) {
00339
00340 if (af_data.frame_number == 0) { af_data.frame_number = 4095; }
00341 else { af_data.frame_number--; }
00342
00343 if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_REQ, &af_data)) {
00344 if (errno != EBUSY) {
00345 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_REQ: %s", strerror(errno));
00346 }
00347 return SharpnessMap();
00348 }
00349 s = Time(af_data.xtrastats.ts);
00350 }
00351
00352 SharpnessMap m(Size(16, 12), 3);
00353 unsigned *bufPtr = &buf[0];
00354 for (int y = 0; y < m.size().height; y++) {
00355 for (int x = 0; x < m.size().width; x++) {
00356 m(x, y, 0) = bufPtr[1];
00357 m(x, y, 1) = bufPtr[5];
00358 m(x, y, 2) = bufPtr[9];
00359 bufPtr += 12;
00360 }
00361 }
00362
00363 return m;
00364 }
00365
00366 void V4L2Sensor::setHistogramConfig(const HistogramConfig &histogram) {
00367 if (!histogram.enabled) { return; }
00368
00369
00370 isp_pipeline_stats pstats;
00371 if (ioctl(fd, VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ, &pstats) < 0) {
00372 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ: %s", strerror(errno));
00373 return;
00374 }
00375
00376
00377 dprintf(4, "CCDC output: %d x %d\n", pstats.ccdc_out_w, pstats.ccdc_out_h);
00378 dprintf(4, "PRV output: %d x %d\n", pstats.prv_out_w, pstats.prv_out_h);
00379 dprintf(4, "RSZ input: %d x %d + %d, %d\n",
00380 pstats.rsz_in_w, pstats.rsz_in_h,
00381 pstats.rsz_in_x, pstats.rsz_in_y);
00382 dprintf(4, "RSZ output: %d x %d\n", pstats.rsz_out_w, pstats.rsz_out_h);
00383
00384 struct isp_hist_config hist_cfg;
00385 hist_cfg.enable = 1;
00386 hist_cfg.source = HIST_SOURCE_CCDC;
00387 hist_cfg.input_bit_width = 10;
00388 hist_cfg.num_acc_frames = 1;
00389 hist_cfg.hist_bins = HIST_BINS_64;
00390 hist_cfg.cfa = HIST_CFA_BAYER;
00391
00392
00393
00394
00395 hist_cfg.wg[0] = 35;
00396 hist_cfg.wg[1] = 35;
00397 hist_cfg.wg[2] = 35;
00398 hist_cfg.wg[3] = 35;
00399 hist_cfg.num_regions = 1;
00400
00401
00402 unsigned x = ((unsigned)histogram.region.x * pstats.ccdc_out_w) / currentMode.width;
00403 unsigned y = ((unsigned)histogram.region.y * pstats.ccdc_out_h) / currentMode.height;
00404 unsigned w = ((unsigned)histogram.region.width * pstats.ccdc_out_w) / currentMode.width;
00405 unsigned h = ((unsigned)histogram.region.height * pstats.ccdc_out_h) / currentMode.height;
00406 if (x > pstats.ccdc_out_w) { x = pstats.ccdc_out_w-1; }
00407 if (y > pstats.ccdc_out_h) { y = pstats.ccdc_out_h-1; }
00408 if (w > pstats.ccdc_out_w) { w = pstats.ccdc_out_w-x; }
00409 if (h > pstats.ccdc_out_h) { h = pstats.ccdc_out_h-y; }
00410 hist_cfg.reg_hor[0] = (x << 16) | w;
00411 hist_cfg.reg_ver[0] = (y << 16) | h;
00412 dprintf(4, "Histogram size: %d x %d + %d, %d\n", w, h, x, y);
00413
00414 dprintf(3, "Enabling histogram generator\n");
00415
00416 if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_CFG, &hist_cfg)) {
00417 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_CFG: %s", strerror(errno));
00418 return;
00419 }
00420
00421 currentHistogram = histogram;
00422 currentHistogram.buckets = 64;
00423 }
00424
00425 void V4L2Sensor::setSharpnessMapConfig(const SharpnessMapConfig &sharpness) {
00426 if (!sharpness.enabled) { return; }
00427
00428
00429 Size size = Size(16, 12);
00430
00431
00432 isp_pipeline_stats pstats;
00433 if (ioctl(fd, VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ, &pstats) < 0) {
00434 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ: %s", strerror(errno));
00435 return;
00436 }
00437
00438 struct af_configuration af_config;
00439
00440 af_config.alaw_enable = H3A_AF_ALAW_DISABLE;
00441 af_config.hmf_config.enable = H3A_AF_HMF_ENABLE;
00442 af_config.hmf_config.threshold = 10;
00443 af_config.rgb_pos = RG_GB_BAYER;
00444 af_config.iir_config.hz_start_pos = 0;
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459 af_config.iir_config.coeff_set0[0] = 32;
00460
00461 af_config.iir_config.coeff_set0[1] = 0;
00462 af_config.iir_config.coeff_set0[2] = 0;
00463
00464 af_config.iir_config.coeff_set0[3] = 16;
00465 af_config.iir_config.coeff_set0[4] = 4096-32;
00466 af_config.iir_config.coeff_set0[5] = 16;
00467
00468 af_config.iir_config.coeff_set0[6] = 0;
00469 af_config.iir_config.coeff_set0[7] = 0;
00470
00471 af_config.iir_config.coeff_set0[8] = 32;
00472 af_config.iir_config.coeff_set0[9] = 0;
00473 af_config.iir_config.coeff_set0[10] = 0;
00474
00475
00476
00477 af_config.iir_config.coeff_set1[0] = 32;
00478
00479 af_config.iir_config.coeff_set1[1] = 0;
00480 af_config.iir_config.coeff_set1[2] = 0;
00481
00482 af_config.iir_config.coeff_set1[3] = 16;
00483 af_config.iir_config.coeff_set1[4] = 4096-32;
00484 af_config.iir_config.coeff_set1[5] = 16;
00485
00486 af_config.iir_config.coeff_set1[6] = 0;
00487 af_config.iir_config.coeff_set1[7] = 0;
00488
00489 af_config.iir_config.coeff_set1[8] = 32;
00490 af_config.iir_config.coeff_set1[9] = 0;
00491 af_config.iir_config.coeff_set1[10] = 0;
00492
00493 af_config.mode = ACCUMULATOR_SUMMED;
00494 af_config.af_config = H3A_AF_CFG_ENABLE;
00495 int paxWidth = ((pstats.ccdc_out_w-4) / (2*size.width))*2;
00496 int paxHeight = ((pstats.ccdc_out_h-4) / (2*size.height))*2;
00497
00498
00499
00500
00501 if (paxWidth > 256) {
00502 error(Event::InternalError, "AF paxels are too wide. Use a higher resolution sharpness map\n");
00503 return;
00504 }
00505 if (paxHeight > 256) {
00506 error(Event::InternalError, "AF paxels are too tall. Use a higher resolution sharpness map\n");
00507 return;
00508 }
00509 if (paxWidth < 16) {
00510 error(Event::InternalError, "AF paxels are too narrow. Use a lower resolution sharpness map\n");
00511 return;
00512 }
00513 if (paxHeight < 2) {
00514 error(Event::InternalError, "AF paxels are too short. Use a lower resolution sharpness map\n");
00515 return;
00516 }
00517
00518 dprintf(4, "Using %d x %d paxels for af\n", paxWidth, paxHeight);
00519 af_config.paxel_config.width = (paxWidth-2)/2;
00520 af_config.paxel_config.height = (paxHeight-2)/2;
00521 af_config.paxel_config.hz_start = (pstats.ccdc_out_w - size.width * paxWidth)/2;
00522 af_config.paxel_config.vt_start = (pstats.ccdc_out_h - size.height * paxHeight)/2;
00523 af_config.paxel_config.hz_cnt = size.width-1;
00524 af_config.paxel_config.vt_cnt = size.height-1;
00525 af_config.paxel_config.line_incr = 0;
00526
00527 dprintf(3, "Enabling sharpness detector\n");
00528 if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_CFG, &af_config)) {
00529 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_CFG: %s", strerror(errno));
00530 return;
00531 }
00532
00533 currentSharpness = sharpness;
00534 }
00535
00536 void V4L2Sensor::releaseFrame(V4L2Frame *frame) {
00537
00538 v4l2_buffer buf;
00539 memset(&buf, 0, sizeof(v4l2_buffer));
00540 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00541 buf.memory = V4L2_MEMORY_MMAP;
00542 buf.index = frame->index;
00543
00544 if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
00545 error(Event::DriverError, "VIDIOC_QBUF: %s", strerror(errno));
00546 return;
00547 }
00548 }
00549
00550 void V4L2Sensor::setControl(unsigned int id, int value) {
00551 if (state == CLOSED) { return; }
00552 v4l2_control ctrl;
00553 ctrl.id = id;
00554 ctrl.value = value;
00555 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00556
00557 error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00558 return;
00559 }
00560 }
00561
00562 int V4L2Sensor::getControl(unsigned int id) {
00563 if (state == CLOSED) { return -1; }
00564 v4l2_control ctrl;
00565 ctrl.id = id;
00566 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00567 error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00568 return -1;
00569 }
00570
00571 return ctrl.value;
00572 }
00573
00574 void V4L2Sensor::setExposure(int e) {
00575 if (state == CLOSED) { return; }
00576
00577 dprintf(3, "Setting exposure to %d\n", e);
00578
00579 struct v4l2_control ctrl;
00580 ctrl.id = V4L2_CID_EXPOSURE;
00581 ctrl.value = e;
00582 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00583 error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00584 return;
00585 }
00586
00587 }
00588
00589 int V4L2Sensor::getExposure() {
00590 if (state == CLOSED) { return -1; }
00591
00592 struct v4l2_control ctrl;
00593 ctrl.id = V4L2_CID_EXPOSURE;
00594
00595 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00596 error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00597 return -1;
00598 }
00599
00600 dprintf(3, "Getting exposure: %d\n", ctrl.value);
00601
00602 return ctrl.value;
00603 }
00604
00605 #define V4L2_CID_FRAME_TIME (V4L2_CTRL_CLASS_CAMERA | 0x10ff)
00606
00607 void V4L2Sensor::setFrameTime(int e) {
00608 if (state == CLOSED) { return; }
00609
00610 struct v4l2_control ctrl;
00611 ctrl.id = V4L2_CID_FRAME_TIME;
00612 ctrl.value = e;
00613 dprintf(3, "Setting frame time to %d\n", e);
00614 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00615 error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00616 return;
00617 }
00618 }
00619
00620 int V4L2Sensor::getFrameTime() {
00621 if (state == CLOSED) { return -1; }
00622
00623 struct v4l2_control ctrl;
00624 ctrl.id = V4L2_CID_FRAME_TIME;
00625
00626 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00627 error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00628 return -1;
00629 }
00630
00631 dprintf(3, "Getting frame time: %d\n", ctrl.value);
00632
00633 return ctrl.value;
00634 }
00635
00636 void V4L2Sensor::setGain(float g) {
00637 if (state == CLOSED) { return; }
00638
00639 unsigned int gain;
00640 struct v4l2_control ctrl;
00641
00642 dprintf(3, "Setting gain to %f\n", g);
00643
00644 gain = (int)(g * 32.0 + 0.5);
00645
00646 ctrl.id = V4L2_CID_GAIN_EXACT;
00647 ctrl.value = gain;
00648 if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00649 error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00650 return;
00651 }
00652 }
00653
00654 float V4L2Sensor::getGain() {
00655 if (state == CLOSED) { return -1.0f; }
00656
00657 struct v4l2_control ctrl;
00658
00659 ctrl.id = V4L2_CID_GAIN_EXACT;
00660 if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00661 error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00662 return -1.0f;
00663 }
00664
00665 return ctrl.value / 32.0f;
00666 }
00667
00668 float max3(float a, float b, float c) {
00669 if (a > b && a > c) { return a; }
00670 else if (b > c) { return b; }
00671 return c;
00672 }
00673
00674 void V4L2Sensor::setWhiteBalance(const float *matrix) {
00675 if (state == CLOSED) { return; }
00676
00677
00678 struct ispprv_update_config prvcfg;
00679 prvcfg.update = ISP_ABS_PREV_RGB2RGB | ISP_ABS_PREV_WB | ISP_ABS_PREV_BLKADJ;
00680 struct ispprev_wbal wbal;
00681 wbal.dgain = 256;
00682 wbal.coef0 = 32;
00683 wbal.coef1 = 32;
00684 wbal.coef2 = 32;
00685 wbal.coef3 = 32;
00686 prvcfg.prev_wbal = &wbal;
00687
00688
00689 float rs = 1.0, gs = 1.0, bs = 1.0;
00690 float maxC = max3(fabs(matrix[0]), fabs(matrix[4]), fabs(matrix[8]));
00691 while (maxC > 8) {
00692 wbal.coef1 *= 2;
00693 maxC /= 2;
00694 rs *= 0.5;
00695 }
00696
00697 maxC = max3(fabs(matrix[1]), fabs(matrix[5]), fabs(matrix[9]));
00698 while (maxC > 8) {
00699 wbal.coef0 *= 2;
00700 wbal.coef3 *= 2;
00701 maxC /= 2;
00702 gs *= 0.5;
00703 }
00704
00705 maxC = max3(fabs(matrix[2]), fabs(matrix[6]), fabs(matrix[10]));
00706 while (maxC > 8) {
00707 wbal.coef2 *= 2;
00708 maxC /= 2;
00709 bs *= 0.5;
00710 }
00711
00712 ispprev_rgbtorgb rgb2rgb;
00713 for (int i = 0; i < 3; i++) {
00714 rgb2rgb.matrix[i][0] = (signed short)(matrix[i*4+0]*rs*256);
00715 rgb2rgb.matrix[i][1] = (signed short)(matrix[i*4+1]*gs*256);
00716 rgb2rgb.matrix[i][2] = (signed short)(matrix[i*4+2]*bs*256);
00717 }
00718 rgb2rgb.offset[0] = (signed short)(matrix[3]);
00719 rgb2rgb.offset[1] = (signed short)(matrix[7]);
00720 rgb2rgb.offset[2] = (signed short)(matrix[11]);
00721 prvcfg.rgb2rgb = &rgb2rgb;
00722
00723
00724 struct ispprev_blkadj blkadj;
00725 blkadj.red = blkadj.green = blkadj.blue = 0;
00726 prvcfg.prev_blkadj = &blkadj;
00727
00728 if (ioctl(fd, VIDIOC_PRIVATE_ISP_PRV_CFG, &prvcfg) < 0) {
00729 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PRV_CFG: %s", strerror(errno));
00730 }
00731
00732 }
00733 }
00734 }
00735
00736