• Main Page
  • Related Pages
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

src/N900/V4L2Sensor.cpp

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         // Request format
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         // set the starting parameters
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         // grab the histogram data for this frame
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         // For now we assume acquire_frame is being called quickly
00242         // enough that only the newest frame is relevant
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             if (errno != EBUSY)
00251                 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_REQ: %s", strerror(errno));
00252             return Histogram();
00253         }          
00254         
00255         // TODO: Deal with timestamps that are too early or too late
00256         
00257         Time h(hist_data.ts);        
00258 
00259         if ((t - h) > 4000) {
00260             warning(Event::DriverError, "Missing histogram (%d)\n", t-h);
00261             return Histogram();
00262         } 
00263         
00264         while ((t-h) < -4000) {
00265             // we got the wrong histogram!
00266             if (hist_data.frame_number == 0) hist_data.frame_number = 4095;
00267             else hist_data.frame_number--;
00268 
00269             if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_REQ, &hist_data)) {
00270                 if (errno != EBUSY)
00271                     error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_REQ: %s", 
00272                           strerror(errno));
00273                 return Histogram();
00274             }          
00275 
00276             h = Time(hist_data.ts);
00277         }
00278 
00279         Histogram hist(64, 3, conf.region);
00280         for (int i = 0; i < 64; i++) {
00281             hist(i, 0) = buf[64 + i];  // r
00282             hist(i, 1) = buf[i];       // g
00283             hist(i, 2) = buf[128 + i]; // b
00284         }
00285         return hist;
00286     }
00287 
00288     SharpnessMap V4L2Sensor::getSharpnessMap(Time t, const SharpnessMapConfig &conf) {
00289         if (!conf.enabled) {
00290             return SharpnessMap();
00291         }
00292 
00293         // grab the sharpness map for this frame        
00294         struct isp_af_data af_data;
00295         af_data.frame_number = NEWEST_FRAME;
00296         af_data.update = REQUEST_STATISTICS;
00297         af_data.curr_frame = 0;
00298         af_data.config_counter = 0;
00299         af_data.xtrastats.ts.tv_sec = 0;
00300         af_data.xtrastats.ts.tv_usec = 0;
00301         unsigned buf[16*12*12];
00302         af_data.af_statistics_buf = buf;
00303         
00304         if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_REQ, &af_data)) {
00305             if (errno != EBUSY)
00306                 error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_REQ: %s", strerror(errno));
00307             return SharpnessMap();
00308         }          
00309 
00310         Time s(af_data.xtrastats.ts);        
00311         if ((t - s) > 4000) {
00312             warning(Event::DriverError, "Missing sharpness (%d)\n", t-s);
00313         }
00314 
00315         while ((t-s) < -4000) {
00316             // we got the wrong sharpness map
00317             if (af_data.frame_number == 0) af_data.frame_number = 4095;
00318             else af_data.frame_number--;
00319 
00320             if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_REQ, &af_data)) {
00321                 if (errno != EBUSY)
00322                     error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_REQ: %s", strerror(errno));
00323                 return SharpnessMap();
00324             }          
00325             s = Time(af_data.xtrastats.ts);
00326         }
00327 
00328         SharpnessMap m(Size(16, 12), 3);
00329         unsigned *bufPtr = &buf[0];
00330         for (int y = 0; y < m.size().height; y++) {
00331             for (int x = 0; x < m.size().width; x++) {
00332                 m(x, y, 0) = bufPtr[1];
00333                 m(x, y, 1) = bufPtr[5];
00334                 m(x, y, 2) = bufPtr[9];
00335                 bufPtr += 12;
00336             }
00337         }
00338 
00339         return m;
00340     }
00341 
00342     void V4L2Sensor::setHistogramConfig(const HistogramConfig &histogram) {       
00343         if (!histogram.enabled) return;
00344 
00345         // get the output size from the ccdc
00346         isp_pipeline_stats pstats;
00347         if (ioctl(fd, VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ, &pstats) < 0) {
00348             error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ: %s", strerror(errno));
00349             return;
00350         }
00351         
00352         
00353         dprintf(4, "CCDC output: %d x %d\n", pstats.ccdc_out_w, pstats.ccdc_out_h);
00354         dprintf(4, "PRV  output: %d x %d\n", pstats.prv_out_w, pstats.prv_out_h);
00355         dprintf(4, "RSZ  input:  %d x %d + %d, %d\n",
00356                 pstats.rsz_in_w, pstats.rsz_in_h,
00357                 pstats.rsz_in_x, pstats.rsz_in_y);
00358         dprintf(4, "RSZ  output: %d x %d\n", pstats.rsz_out_w, pstats.rsz_out_h);
00359         
00360         struct isp_hist_config hist_cfg;                       
00361         hist_cfg.enable = 1;
00362         hist_cfg.source = HIST_SOURCE_CCDC;
00363         hist_cfg.input_bit_width = 10;
00364         hist_cfg.num_acc_frames = 1;
00365         hist_cfg.hist_bins = HIST_BINS_64;
00366         hist_cfg.cfa = HIST_CFA_BAYER;
00367         // set the gains to slightly above 1 in 3Q5 format, in
00368         // order to use the full range in the histogram. Without
00369         // this, bucket #60 is saturated pixels, and 61-64 are
00370         // unused.
00371         hist_cfg.wg[0] = 35;
00372         hist_cfg.wg[1] = 35;
00373         hist_cfg.wg[2] = 35;
00374         hist_cfg.wg[3] = 35;
00375         hist_cfg.num_regions = 1;
00376         
00377         // set up its width and height
00378         unsigned x = ((unsigned)histogram.region.x * pstats.ccdc_out_w) / currentMode.width;
00379         unsigned y = ((unsigned)histogram.region.y * pstats.ccdc_out_h) / currentMode.height;
00380         unsigned w = ((unsigned)histogram.region.width * pstats.ccdc_out_w) / currentMode.width;
00381         unsigned h = ((unsigned)histogram.region.height * pstats.ccdc_out_h) / currentMode.height;
00382         if (x > pstats.ccdc_out_w) x = pstats.ccdc_out_w-1;
00383         if (y > pstats.ccdc_out_h) y = pstats.ccdc_out_h-1;
00384         if (w > pstats.ccdc_out_w) w = pstats.ccdc_out_w-x;
00385         if (h > pstats.ccdc_out_h) h = pstats.ccdc_out_h-y;
00386         hist_cfg.reg_hor[0] = (x << 16) | w;
00387         hist_cfg.reg_ver[0] = (y << 16) | h;
00388         dprintf(4, "Histogram size: %d x %d + %d, %d\n", w, h, x, y);
00389         
00390         dprintf(3, "Enabling histogram generator\n");
00391         // enable the histogram generator
00392         if (ioctl(fd, VIDIOC_PRIVATE_ISP_HIST_CFG, &hist_cfg)) {
00393             error(Event::DriverError, "VIDIOC_PRIVATE_ISP_HIST_CFG: %s", strerror(errno));
00394             return;
00395         }
00396 
00397         currentHistogram = histogram;
00398         currentHistogram.buckets = 64;
00399     }
00400 
00401     void V4L2Sensor::setSharpnessMapConfig(const SharpnessMapConfig &sharpness) {       
00402         if (!sharpness.enabled) return;
00403 
00404         // Ignore the requested size and use 16x12
00405         Size size = Size(16, 12);
00406 
00407         // get the output size from the ccdc
00408         isp_pipeline_stats pstats;
00409         if (ioctl(fd, VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ, &pstats) < 0) {
00410             error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PIPELINE_STATS_REQ: %s", strerror(errno));
00411             return;
00412         }
00413 
00414         struct af_configuration af_config;
00415         
00416         af_config.alaw_enable = H3A_AF_ALAW_DISABLE;
00417         af_config.hmf_config.enable = H3A_AF_HMF_ENABLE;
00418         af_config.hmf_config.threshold = 10;
00419         af_config.rgb_pos = RG_GB_BAYER;
00420         af_config.iir_config.hz_start_pos = 0;
00421         
00422         // The IIR coefficients are as follows (yay reverse-engineering!)
00423         
00424         // The format is S6Q5 fixed point. A positive value of x
00425         // should be written as 32*x. A negatives value of x
00426         // should be written as 4096 - 32*x
00427         
00428         // 0: global gain? not sure.
00429         // 1-2: IIR taps on the first biquad
00430         // 3-5: FIR taps on the first biquad
00431         // 6-7: IIR taps on the second biquad
00432         // 8-10: FIR taps on the second biquad            
00433         
00434         // A high pass filter aimed at ~8 pixel frequencies and above
00435         af_config.iir_config.coeff_set0[0] = 32; // gain of 1
00436         
00437         af_config.iir_config.coeff_set0[1] = 0; //4096-27;
00438         af_config.iir_config.coeff_set0[2] = 0; //6;
00439         
00440         af_config.iir_config.coeff_set0[3] = 16;
00441         af_config.iir_config.coeff_set0[4] = 4096-32;
00442         af_config.iir_config.coeff_set0[5] = 16;
00443         
00444         af_config.iir_config.coeff_set0[6] = 0;
00445         af_config.iir_config.coeff_set0[7] = 0;
00446         
00447         af_config.iir_config.coeff_set0[8] = 32;
00448         af_config.iir_config.coeff_set0[9] = 0;
00449         af_config.iir_config.coeff_set0[10] = 0;
00450         
00451         
00452         // A high pass filter aimed at ~4 pixel frequencies and above
00453         af_config.iir_config.coeff_set1[0] = 32; // gain of 1
00454         
00455         af_config.iir_config.coeff_set1[1] = 0;
00456         af_config.iir_config.coeff_set1[2] = 0;
00457         
00458         af_config.iir_config.coeff_set1[3] = 16;
00459         af_config.iir_config.coeff_set1[4] = 4096-32;
00460         af_config.iir_config.coeff_set1[5] = 16;
00461         
00462         af_config.iir_config.coeff_set1[6] = 0;
00463         af_config.iir_config.coeff_set1[7] = 0;
00464         
00465         af_config.iir_config.coeff_set1[8] = 32;
00466         af_config.iir_config.coeff_set1[9] = 0;
00467         af_config.iir_config.coeff_set1[10] = 0;
00468         
00469         af_config.mode = ACCUMULATOR_SUMMED;
00470         af_config.af_config = H3A_AF_CFG_ENABLE;
00471         int paxWidth = ((pstats.ccdc_out_w-4) / (2*size.width))*2;
00472         int paxHeight = ((pstats.ccdc_out_h-4) / (2*size.height))*2;
00473 
00474         // These are internal errors because they should have been
00475         // caught and fixed earlier in the daemon class
00476 
00477         if (paxWidth > 256) {
00478             error(Event::InternalError, "AF paxels are too wide. Use a higher resolution sharpness map\n");
00479             return;
00480         }
00481         if (paxHeight > 256) {
00482             error(Event::InternalError, "AF paxels are too tall. Use a higher resolution sharpness map\n");
00483             return;
00484         }
00485         if (paxWidth < 16) {            
00486             error(Event::InternalError, "AF paxels are too narrow. Use a lower resolution sharpness map\n");
00487             return;
00488         }
00489         if (paxHeight < 2) {
00490             error(Event::InternalError, "AF paxels are too short. Use a lower resolution sharpness map\n");
00491             return;
00492         }
00493         
00494         dprintf(4, "Using %d x %d paxels for af\n", paxWidth, paxHeight);
00495         af_config.paxel_config.width = (paxWidth-2)/2;
00496         af_config.paxel_config.height = (paxHeight-2)/2;
00497         af_config.paxel_config.hz_start = (pstats.ccdc_out_w - size.width * paxWidth)/2;
00498         af_config.paxel_config.vt_start = (pstats.ccdc_out_h - size.height * paxHeight)/2;
00499         af_config.paxel_config.hz_cnt = size.width-1;
00500         af_config.paxel_config.vt_cnt = size.height-1;
00501         af_config.paxel_config.line_incr = 0;            
00502         
00503         dprintf(3, "Enabling sharpness detector\n");
00504         if (ioctl(fd, VIDIOC_PRIVATE_ISP_AF_CFG, &af_config)) {
00505             error(Event::DriverError, "VIDIOC_PRIVATE_ISP_AF_CFG: %s", strerror(errno));
00506             return;
00507         }
00508 
00509         currentSharpness = sharpness;
00510     }
00511 
00512     void V4L2Sensor::releaseFrame(V4L2Frame *frame) {
00513         // requeue the buffer
00514         v4l2_buffer buf;
00515         memset(&buf, 0, sizeof(v4l2_buffer));
00516         buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
00517         buf.memory = V4L2_MEMORY_MMAP;
00518         buf.index = frame->index;
00519         
00520         if (ioctl(fd, VIDIOC_QBUF, &buf) < 0) {
00521             error(Event::DriverError, "VIDIOC_QBUF: %s", strerror(errno));
00522             return;
00523         }
00524     }
00525    
00526     void V4L2Sensor::setControl(unsigned int id, int value) {
00527         if (state == CLOSED) return;
00528         v4l2_control ctrl;
00529         ctrl.id = id;
00530         ctrl.value = value;
00531         if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00532             // TODO: Better error reporting for all the get/set
00533             error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00534             return;
00535         }
00536     }
00537 
00538     int V4L2Sensor::getControl(unsigned int id) {
00539         if (state == CLOSED) return -1;
00540         v4l2_control ctrl;
00541         ctrl.id = id;
00542         if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00543             error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00544             return -1;
00545         }
00546 
00547         return ctrl.value;
00548     }
00549 
00550     void V4L2Sensor::setExposure(int e) {
00551         if (state == CLOSED) return;
00552 
00553         struct v4l2_control ctrl;
00554         ctrl.id = V4L2_CID_EXPOSURE;
00555         ctrl.value = e;
00556         if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00557             error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00558             return;
00559         }       
00560         
00561     }
00562 
00563     int V4L2Sensor::getExposure() {
00564         if (state == CLOSED) return -1;        
00565 
00566         struct v4l2_control ctrl;
00567         ctrl.id = V4L2_CID_EXPOSURE;
00568         
00569         if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00570             error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00571             return -1;
00572         }       
00573         
00574         return ctrl.value;
00575     }
00576 
00577 #define V4L2_CID_FRAME_TIME (V4L2_CTRL_CLASS_CAMERA | 0x10ff)
00578 
00579     void V4L2Sensor::setFrameTime(int e) {
00580         if (state == CLOSED) return;
00581         
00582         struct v4l2_control ctrl;
00583         ctrl.id = V4L2_CID_FRAME_TIME;
00584         ctrl.value = e;
00585         if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00586             error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00587             return;
00588         }       
00589     }
00590 
00591     int V4L2Sensor::getFrameTime() {
00592         if (state == CLOSED) return -1;        
00593 
00594         struct v4l2_control ctrl;
00595         ctrl.id = V4L2_CID_FRAME_TIME;
00596         
00597         if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00598             error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00599             return -1;
00600         }       
00601         
00602         return ctrl.value;
00603     }
00604 
00605     void V4L2Sensor::setGain(float g) {
00606         if (state == CLOSED) return;
00607 
00608         unsigned int gain;
00609         struct v4l2_control ctrl;
00610         
00611         gain = (int)(g * 32.0 + 0.5);
00612          
00613         ctrl.id = V4L2_CID_GAIN_EXACT;
00614         ctrl.value = gain;
00615         if (ioctl(fd, VIDIOC_S_CTRL, &ctrl) < 0) {
00616             error(Event::DriverError, "VIDIOC_S_CTRL: %s", strerror(errno));
00617             return;
00618         }              
00619     }
00620 
00621     float V4L2Sensor::getGain() {
00622         if (state == CLOSED) return -1.0f;
00623 
00624         struct v4l2_control ctrl;
00625         
00626         ctrl.id = V4L2_CID_GAIN_EXACT;
00627         if (ioctl(fd, VIDIOC_G_CTRL, &ctrl) < 0) {
00628             error(Event::DriverError, "VIDIOC_G_CTRL: %s", strerror(errno));
00629             return -1.0f;
00630         }       
00631         
00632         return ctrl.value / 32.0f;    
00633     }
00634 
00635     void V4L2Sensor::setWhiteBalance(const float *matrix) {
00636         if (state == CLOSED) return;
00637         
00638         struct ispprv_update_config prvcfg;      
00639         prvcfg.update = ISP_ABS_PREV_RGB2RGB | ISP_ABS_PREV_WB | ISP_ABS_PREV_BLKADJ;
00640 
00641         ispprev_rgbtorgb rgb2rgb;        
00642         for (int i = 0; i < 3; i++) {
00643             rgb2rgb.matrix[i][0] = (signed short)(matrix[i*4+0]*256);
00644             rgb2rgb.matrix[i][1] = (signed short)(matrix[i*4+1]*256);
00645             rgb2rgb.matrix[i][2] = (signed short)(matrix[i*4+2]*256);
00646         }
00647         rgb2rgb.offset[0] = (signed short)(matrix[3]);
00648         rgb2rgb.offset[1] = (signed short)(matrix[7]);
00649         rgb2rgb.offset[2] = (signed short)(matrix[11]);
00650         prvcfg.rgb2rgb = &rgb2rgb;
00651 
00652         // Set the pre-demosiacing gains to one (in case the Nokia
00653         // daemon has messed with them)
00654         struct ispprev_wbal wbal;
00655         wbal.dgain = 256;
00656         wbal.coef0 = 32;
00657         wbal.coef1 = 32;
00658         wbal.coef2 = 32;
00659         wbal.coef3 = 32;
00660         prvcfg.prev_wbal = &wbal;
00661 
00662         // Similarly set the black level to zero
00663         struct ispprev_blkadj blkadj;        
00664         blkadj.red = blkadj.green = blkadj.blue = 0;
00665         prvcfg.prev_blkadj = &blkadj;
00666 
00667         if (ioctl(fd, VIDIOC_PRIVATE_ISP_PRV_CFG, &prvcfg) < 0) {
00668             error(Event::DriverError, "VIDIOC_PRIVATE_ISP_PRV_CFG: %s", strerror(errno));
00669         }        
00670         
00671     }
00672 }}
00673 
00674 

Generated on Thu Jul 22 2010 17:50:33 for FCam by  doxygen 1.7.1