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