// %flair:license{ // This file is part of the Flair framework distributed under the // CECILL-C License, Version 1.0. // %flair:license} // created: 2014/07/17 // filename: V4LCamera.cpp // // author: Guillaume Sanahuja // Copyright Heudiasyc UMR UTC/CNRS 7253 // // version: $Id: $ // // purpose: base class for V4l camera // // /*********************************************************************/ #include "V4LCamera.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define DEFAULT_V4L_BUFFERS 4 #define CHANNEL_NUMBER 1 #define CLEAR(x) memset (&(x), 0, sizeof (x)) #define DEFAULT_V4L_WIDTH 640 #define DEFAULT_V4L_HEIGHT 480 #define CV_CAP_PROP_POS_MSEC 0 #define CV_CAP_PROP_POS_FRAMES 1 #define CV_CAP_PROP_POS_AVI_RATIO 2 #define CV_CAP_PROP_FRAME_WIDTH 3 #define CV_CAP_PROP_FRAME_HEIGHT 4 #define CV_CAP_PROP_FPS 5 #define CV_CAP_PROP_FOURCC 6 #define CV_CAP_PROP_FRAME_COUNT 7 #define CV_CAP_PROP_FORMAT 8 #define CV_CAP_PROP_MODE 9 #define CV_CAP_PROP_BRIGHTNESS 10 #define CV_CAP_PROP_CONTRAST 11 #define CV_CAP_PROP_SATURATION 12 #define CV_CAP_PROP_HUE 13 #define CV_CAP_PROP_GAIN 14 #define CV_CAP_PROP_CONVERT_RGB 15 #define CV_CAP_PROP_SHARPNESS 16 #define CV_CAP_PROP_EXPOSURE 17 #define CV_CAP_PROP_AUTOGAIN 18 #define CV_CAP_PROP_AWB 19 #define HAVE_CAMV4L2 using std::string; using namespace flair::core; using namespace flair::gui; namespace flair { namespace sensor { V4LCamera::V4LCamera(string name, uint8_t camera_index, uint16_t width, uint16_t height, Image::Type::Format format, uint8_t priority) : Thread(getFrameworkManager(), name, priority), Camera(name, width, height, format) { string deviceName="/dev/video"+std::to_string(camera_index); device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK); if (device == -1) { Thread::Err("Cannot open %s\n",deviceName.c_str()); } else { Printf("V4LCamera %s, opened %s\n",name.c_str(),deviceName.c_str()); } /* w/o memset some parts arent initialized - AKA: Fill it with zeros so it is clean */ memset(&capture,0,sizeof(CvCaptureCAM_V4L)); /* Present the routines needed for V4L funtionality. They are inserted as part of the standard set of cv calls promoting transparency. "Vector Table" insertion. */ capture.FirstCapture = 1; capture.deviceHandle = device; PALETTE_YUYV = 0; PALETTE_UYVY= 0; n_buffers = 0; if (_capture_V4L2 (&capture) == -1) { Thread::Err("_capture_V4L2 failed\n"); } if (icvSetPropertyCAM_V4L(&capture, CV_CAP_PROP_FRAME_WIDTH, width)<0) Thread::Err("cvSetCaptureProperty error\n"); if (icvSetPropertyCAM_V4L(&capture, CV_CAP_PROP_FRAME_HEIGHT, height)<0) Thread::Err("cvSetCaptureProperty error\n"); if (format == Image::Type::Format::UYVY) { if (icvSetPropertyCAM_V4L(&capture, CV_CAP_PROP_FORMAT, V4L2_PIX_FMT_UYVY)<0) Thread::Err("cvSetCaptureProperty error\n"); } else if (format == Image::Type::Format::YUYV) { if (icvSetPropertyCAM_V4L(&capture, CV_CAP_PROP_FORMAT, V4L2_PIX_FMT_YUYV) < 0) Thread::Err("cvSetCaptureProperty error\n"); } else { Thread::Err("format not supported\n"); } // ground station gain = new DoubleSpinBox(GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1); exposure = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "exposure:", 0,1, 0.1); bright = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1); contrast = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "contrast:", 0,1, 0.1); hue = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1); sharpness = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "sharpness:", 0, 1, 0.1); sat = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1,0.1); autogain = new CheckBox(GetGroupBox()->NewRow(), "autogain:"); autoexposure = new CheckBox(GetGroupBox()->LastRowLastCol(), "autoexposure:"); awb = new CheckBox(GetGroupBox()->LastRowLastCol(), "awb:"); fps = new Label(GetGroupBox()->NewRow(), "fps"); hasProblems=false; } V4LCamera::~V4LCamera() { for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) { //FreeFunction((char*)buffers[n_buffers].start); } SafeStop(); Join(); } int V4LCamera::icvSetPropertyCAM_V4L( CvCaptureCAM_V4L* capture, int property_id, double value ){ static int width = 0, height = 0; int retval; /* initialization */ retval = 0; /* two subsequent calls setting WIDTH and HEIGHT will change the video size */ /* the first one will return an error, though. */ switch (property_id) { case CV_CAP_PROP_FRAME_WIDTH: width = value; if(width !=0 && height != 0) { retval = icvSetVideoSize( capture, width, height); width = height = 0; } break; case CV_CAP_PROP_FRAME_HEIGHT: height = value; if(width !=0 && height != 0) { retval = icvSetVideoSize( capture, width, height); width = height = 0; } break; case CV_CAP_PROP_FORMAT: capture->form.fmt.pix.pixelformat = (unsigned long)value; retval == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form); if ((unsigned long)value != capture->form.fmt.pix.pixelformat) retval=-1; PALETTE_YUYV = 0; PALETTE_UYVY= 0; if ((unsigned long)value== V4L2_PIX_FMT_YUYV) { PALETTE_YUYV = 1; } if ((unsigned long)value== V4L2_PIX_FMT_UYVY) { PALETTE_UYVY = 1; } break; case CV_CAP_PROP_BRIGHTNESS: case CV_CAP_PROP_CONTRAST: case CV_CAP_PROP_SATURATION: case CV_CAP_PROP_HUE: case CV_CAP_PROP_GAIN: case CV_CAP_PROP_SHARPNESS: case CV_CAP_PROP_EXPOSURE: case CV_CAP_PROP_AUTOGAIN: case CV_CAP_PROP_AWB: retval = icvSetControl(capture, property_id, value); break; default: fprintf(stderr, "HIGHGUI ERROR: V4L: setting property #%d is not supported\n", property_id); } /* return the the status */ return retval; } int V4LCamera::icvSetControl (CvCaptureCAM_V4L* capture, int property_id, double value) { /* limitation of the input value */ if (value < 0.0) { value = 0.0; } else if (value > 1.0) { value = 1.0; } /* default value for min and max */ int v4l2_min = 0; int v4l2_max = 255; /* initialisations */ CLEAR (capture->control); /* set which control we want to set */ switch (property_id) { case CV_CAP_PROP_BRIGHTNESS: capture->control.id = V4L2_CID_BRIGHTNESS; break; case CV_CAP_PROP_CONTRAST: capture->control.id = V4L2_CID_CONTRAST; break; case CV_CAP_PROP_SATURATION: capture->control.id = V4L2_CID_SATURATION; break; case CV_CAP_PROP_HUE: capture->control.id = V4L2_CID_HUE; break; case CV_CAP_PROP_GAIN: capture->control.id = V4L2_CID_GAIN; break; case CV_CAP_PROP_SHARPNESS: capture->control.id = V4L2_CID_SHARPNESS; break; case CV_CAP_PROP_EXPOSURE: capture->control.id = V4L2_CID_EXPOSURE; break; case CV_CAP_PROP_AUTOGAIN: capture->control.id = V4L2_CID_AUTOGAIN; break; case CV_CAP_PROP_AWB: capture->control.id = V4L2_CID_AUTO_WHITE_BALANCE; break; default: fprintf(stderr, "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n", property_id); return -1; } /* get the min and max values */ if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_CTRL, &capture->control)) { // perror ("VIDIOC_G_CTRL for getting min/max values"); return -1; } /* get the min/max values */ switch (property_id) { case CV_CAP_PROP_BRIGHTNESS: v4l2_min = capture->v4l2_brightness_min; v4l2_max = capture->v4l2_brightness_max; break; case CV_CAP_PROP_CONTRAST: v4l2_min = capture->v4l2_contrast_min; v4l2_max = capture->v4l2_contrast_max; break; case CV_CAP_PROP_SATURATION: v4l2_min = capture->v4l2_saturation_min; v4l2_max = capture->v4l2_saturation_max; break; case CV_CAP_PROP_HUE: v4l2_min = capture->v4l2_hue_min; v4l2_max = capture->v4l2_hue_max; break; case CV_CAP_PROP_GAIN: v4l2_min = capture->v4l2_gain_min; v4l2_max = capture->v4l2_gain_max; break; case CV_CAP_PROP_SHARPNESS: v4l2_min = capture->v4l2_sharpness_min; v4l2_max = capture->v4l2_sharpness_max; break; case CV_CAP_PROP_EXPOSURE: v4l2_min = capture->v4l2_exposure_min; v4l2_max = capture->v4l2_exposure_max; break; case CV_CAP_PROP_AUTOGAIN: v4l2_min = capture->v4l2_autogain_min; v4l2_max = capture->v4l2_autogain_max; break; case CV_CAP_PROP_AWB: v4l2_min = capture->v4l2_awb_min; v4l2_max = capture->v4l2_awb_max; break; } /* initialisations */ CLEAR (capture->control); /* set which control we want to set */ switch (property_id) { case CV_CAP_PROP_BRIGHTNESS: capture->control.id = V4L2_CID_BRIGHTNESS; break; case CV_CAP_PROP_CONTRAST: capture->control.id = V4L2_CID_CONTRAST; break; case CV_CAP_PROP_SATURATION: capture->control.id = V4L2_CID_SATURATION; break; case CV_CAP_PROP_HUE: capture->control.id = V4L2_CID_HUE; break; case CV_CAP_PROP_GAIN: capture->control.id = V4L2_CID_GAIN; break; case CV_CAP_PROP_SHARPNESS: capture->control.id = V4L2_CID_SHARPNESS; break; case CV_CAP_PROP_EXPOSURE: capture->control.id = V4L2_CID_EXPOSURE; break; case CV_CAP_PROP_AUTOGAIN: capture->control.id = V4L2_CID_AUTOGAIN; break; case CV_CAP_PROP_AWB: capture->control.id = V4L2_CID_AUTO_WHITE_BALANCE; break; default: fprintf(stderr, "HIGHGUI ERROR: V4L2: setting property #%d is not supported\n", property_id); return -1; } /* set the value we want to set to the scaled the value */ capture->control.value = (int)(value * (v4l2_max - v4l2_min) + v4l2_min); /* The driver may clamp the value or return ERANGE, ignored here */ if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_CTRL, &capture->control) && errno != ERANGE) { perror ("VIDIOC_S_CTRL"); return -1; } /* all was OK */ return 0; } int V4LCamera::_capture_V4L2 (CvCaptureCAM_V4L *capture) { int detect_v4l2 = 0; detect_v4l2 = try_init_v4l2(capture); if (detect_v4l2 != 1) { /* init of the v4l2 device is not OK */ return -1; } /* Init V4L2 control variables */ capture->v4l2_brightness = 0; capture->v4l2_contrast = 0; capture->v4l2_saturation = 0; capture->v4l2_hue = 0; capture->v4l2_gain = 0; capture->v4l2_sharpness = 0; capture->v4l2_exposure = 0; capture->v4l2_autogain = 0; capture->v4l2_awb = 0; capture->v4l2_brightness_min = 0; capture->v4l2_contrast_min = 0; capture->v4l2_saturation_min = 0; capture->v4l2_hue_min = 0; capture->v4l2_gain_min = 0; capture->v4l2_sharpness_min = 0; capture->v4l2_exposure_min = 0; capture->v4l2_autogain_min = 0; capture->v4l2_awb_min = 0; capture->v4l2_brightness_max = 0; capture->v4l2_contrast_max = 0; capture->v4l2_saturation_max = 0; capture->v4l2_hue_max = 0; capture->v4l2_gain_max = 0; capture->v4l2_sharpness_max = 0; capture->v4l2_exposure_max = 0; capture->v4l2_autogain_max = 0; capture->v4l2_awb_max = 0; if ((capture->cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { /* Nope. */ fprintf( stderr, "HIGHGUI ERROR: V4L2: device is unable to capture video memory.\n"); return -1; } /* Find Window info */ CLEAR (capture->form); capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) { fprintf( stderr, "HIGHGUI ERROR: V4L2: Could not obtain specifics of capture window.\n\n"); return -1; } if (autosetup_capture_mode_v4l2(capture) == -1) return -1; icvSetVideoSize(capture, DEFAULT_V4L_WIDTH, DEFAULT_V4L_HEIGHT); unsigned int min; /* Buggy driver paranoia. */ min = capture->form.fmt.pix.width * 2; if (capture->form.fmt.pix.bytesperline < min) capture->form.fmt.pix.bytesperline = min; min = capture->form.fmt.pix.bytesperline * capture->form.fmt.pix.height; if (capture->form.fmt.pix.sizeimage < min) capture->form.fmt.pix.sizeimage = min; return 1; } int V4LCamera::icvSetVideoSize( CvCaptureCAM_V4L* capture, int w, int h) { CLEAR (capture->crop); capture->crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; capture->crop.c.left = 0; capture->crop.c.top = 0; capture->crop.c.height = h*24; capture->crop.c.width = w*24; /* set the crop area, but don't exit if the device don't support croping */ xioctl (capture->deviceHandle, VIDIOC_S_CROP, &capture->crop); CLEAR (capture->form); capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; /* read the current setting, mainly to retreive the pixelformat information */ xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form); /* set the values we want to change */ capture->form.fmt.pix.width = w; capture->form.fmt.pix.height = h; capture->form.fmt.win.chromakey = 0; capture->form.fmt.win.field = V4L2_FIELD_ANY; capture->form.fmt.win.clips = 0; capture->form.fmt.win.clipcount = 0; capture->form.fmt.pix.field = V4L2_FIELD_ANY; /* ask the device to change the size * don't test if the set of the size is ok, because some device * don't allow changing the size, and we will get the real size * later */ xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form); /* try to set framerate to 30 fps */ struct v4l2_streamparm setfps; memset (&setfps, 0, sizeof(struct v4l2_streamparm)); setfps.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; setfps.parm.capture.timeperframe.numerator = 1; setfps.parm.capture.timeperframe.denominator = 30; xioctl (capture->deviceHandle, VIDIOC_S_PARM, &setfps); /* we need to re-initialize some things, like buffers, because the size has * changed */ capture->FirstCapture = 1; /* Get window info again, to get the real value */ if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) { fprintf(stderr, "HIGHGUI ERROR: V4L/V4L2: Could not obtain specifics of capture window.\n\n"); return 0; } return 0; return 0; } int V4LCamera::try_palette_v4l2(CvCaptureCAM_V4L* capture, unsigned long colorspace) { CLEAR (capture->form); capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; capture->form.fmt.pix.pixelformat = colorspace; capture->form.fmt.pix.field = V4L2_FIELD_ANY; capture->form.fmt.pix.width = DEFAULT_V4L_WIDTH; capture->form.fmt.pix.height = DEFAULT_V4L_HEIGHT; if (-1 == xioctl (capture->deviceHandle, VIDIOC_S_FMT, &capture->form)) return -1; if (colorspace != capture->form.fmt.pix.pixelformat) return -1; else return 0; } int V4LCamera::autosetup_capture_mode_v4l2(CvCaptureCAM_V4L* capture) { if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUYV) == 0) { PALETTE_YUYV = 1; } else if (try_palette_v4l2(capture, V4L2_PIX_FMT_UYVY) == 0) { PALETTE_UYVY = 1; } else { fprintf(stderr, "HIGHGUI ERROR: V4L2: Pixel format of incoming image is unsupported by OpenCV\n"); return -1; } return 0; } int V4LCamera::try_init_v4l2(CvCaptureCAM_V4L* capture) { // if detect = -1 then unable to open device // if detect = 0 then detected nothing // if detect = 1 then V4L2 device int detect = 0; if (detect == 0) { CLEAR (capture->cap); if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYCAP, &capture->cap)) { detect = 0; } else { CLEAR (capture->capability); capture->capability.type = capture->cap.capabilities; /* Query channels number */ if (-1 != xioctl (capture->deviceHandle, VIDIOC_G_INPUT, &capture->capability.channels)) { detect = 1; } } } return detect; } /* V4LCamera::V4LCamera(string name, uint8_t camera_index, uint16_t width, uint16_t height, Image::Type::Format format, uint8_t priority) : Thread(getFrameworkManager(), name, priority), Camera(name, width, height, format) { string deviceName="/dev/video"+std::to_string(camera_index); device = open(deviceName.c_str(), O_RDWR | O_NONBLOCK); if (device == -1) { Thread::Err("Cannot open %s\n",deviceName.c_str()); } else { Printf("V4LCamera %s, opened %s\n",name.c_str(),deviceName.c_str()); } struct v4l2_capability cap; memset(&cap, 0, sizeof (v4l2_capability)); if (xioctl (device, VIDIOC_QUERYCAP, &cap)==-1) { Thread::Err("VIDIOC_QUERYCAP xioctl\n"); } if ((cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) == 0) { Thread::Err("device is unable to capture video memory.\n"); } //get v4l2_format struct v4l2_format form; form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if(xioctl (device, VIDIOC_G_FMT,&form)==-1) { Thread::Err("VIDIOC_G_FMT xioctl\n"); } //set width, height and format if (format == Image::Type::Format::UYVY) { form.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY; } else if (format == Image::Type::Format::YUYV) { form.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; } else { Thread::Err("format not supported\n"); } form.fmt.pix.width = width; form.fmt.pix.height = height; form.fmt.win.chromakey = 0; form.fmt.win.field = V4L2_FIELD_ANY; form.fmt.win.clips = 0; form.fmt.win.clipcount = 0; form.fmt.pix.field = V4L2_FIELD_ANY; if(xioctl (device, VIDIOC_S_FMT,&form)==-1) { Thread::Err("VIDIOC_S_FMT xioctl\n"); } //alloc and queue bufs AllocBuffers(); for (int bufferIndex = 0; bufferIndex < nbBuffers;++bufferIndex) { QueueBuffer(bufferIndex); } // enable the streaming v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (xioctl (device, VIDIOC_STREAMON,&type)==-1) { Thread::Err("VIDIOC_STREAMON xioctl\n"); } // skip first frame. it is often bad -- this is unnotied in traditional apps, // but could be fatal if bad jpeg is enabled bufferIndex=-1; GrabFrame(); // ground station gain = new DoubleSpinBox(GetGroupBox()->NewRow(), "gain:", 0, 1, 0.1); exposure = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "exposure:", 0,1, 0.1); bright = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "bright:", 0, 1, 0.1); contrast = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "contrast:", 0,1, 0.1); hue = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "hue:", 0, 1, 0.1); sharpness = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "sharpness:", 0, 1, 0.1); sat = new DoubleSpinBox(GetGroupBox()->LastRowLastCol(), "saturation:", 0, 1,0.1); autogain = new CheckBox(GetGroupBox()->NewRow(), "autogain:"); autoexposure = new CheckBox(GetGroupBox()->LastRowLastCol(), "autoexposure:"); awb = new CheckBox(GetGroupBox()->LastRowLastCol(), "awb:"); fps = new Label(GetGroupBox()->NewRow(), "fps"); hasProblems=false; } V4LCamera::~V4LCamera() { for (int n_buffers = 0; n_buffers < nbBuffers; n_buffers++) { FreeFunction((char*)buffers[n_buffers].start); } SafeStop(); Join(); } void V4LCamera::Run(void) { Time cam_time, new_time, fpsNow, fpsPrev; int fpsCounter = 0; // init image old GrabFrame(); cam_time = GetTime(); fpsPrev = cam_time; while (!ToBeStopped()) { //check for ps3eye deconnection in hds uav if(hasProblems==false) { struct v4l2_format form; form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; xioctl(device, VIDIOC_G_FMT,&form); if(xioctl (device, VIDIOC_G_FMT,&form)<0) { Thread::Warn("camera disconnected\n"); hasProblems=true; } } // fps counter fpsCounter++; if (GetTime() > (fpsPrev + 5 * (Time)1000000000)) { // every 5 secondes fpsNow = GetTime(); fps->SetText("fps: %.1f", fpsCounter / ((float)(fpsNow - fpsPrev) / 1000000000.)); fpsCounter = 0; fpsPrev = fpsNow; } // cam properties if (gain->ValueChanged() == true && autogain->Value() == false) SetGain(gain->Value()); if (exposure->ValueChanged() == true && autoexposure->Value() == false) SetExposure(exposure->Value()); if (bright->ValueChanged() == true) SetBrightness(bright->Value()); if (sat->ValueChanged() == true) SetSaturation(sat->Value()); if (contrast->ValueChanged() == true) SetContrast(contrast->Value()); if (hue->ValueChanged() == true) SetHue(hue->Value()); if (sharpness->ValueChanged() == true) SetProperty(V4L2_CID_SHARPNESS, sharpness->Value()); if (autogain->ValueChanged() == true) { if (autogain->Value() == true) { gain->setEnabled(false); } else { gain->setEnabled(true); SetGain(gain->Value()); } SetAutoGain(autogain->Value()); } if (autoexposure->ValueChanged() == true) { if (autoexposure->Value() == true) { exposure->setEnabled(false); } else { exposure->setEnabled(true); SetExposure(exposure->Value()); } SetAutoExposure(autoexposure->Value()); } if (awb->ValueChanged() == true) SetProperty(V4L2_CID_AUTO_WHITE_BALANCE, awb->Value()); // get picture GrabFrame(); new_time = GetTime(); //check for ps3eye deconnection in hds uav if(new_time-cam_time>100*1000*1000) { Thread::Warn("delta trop grand\n"); hasProblems=true; } output->GetMutex(); output->buffer=(char*)buffers[bufferIndex].start; output->ReleaseMutex(); output->SetDataTime(cam_time); ProcessUpdate(output); cam_time = new_time; } close(device); } */ int V4LCamera::v4l2_alloc_buffers (CvCaptureCAM_V4L *capture, char *deviceName) { CLEAR (capture->req); unsigned int buffer_number = DEFAULT_V4L_BUFFERS; try_again: capture->req.count = buffer_number; capture->req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; capture->req.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl (capture->deviceHandle, VIDIOC_REQBUFS, &capture->req)) { if (EINVAL == errno) { fprintf (stderr, "%s does not support memory mapping\n", deviceName); } else { perror ("VIDIOC_REQBUFS"); } /* free capture, and returns an error code */ return -1; } if (capture->req.count < buffer_number) { if (buffer_number == 1) { fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName); /* free capture, and returns an error code */ return -1; } else { buffer_number--; fprintf (stderr, "Insufficient buffer memory on %s -- decreaseing buffers\n", deviceName); goto try_again; } } for (n_buffers = 0; n_buffers < capture->req.count; ++n_buffers) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = n_buffers; if (-1 == xioctl (capture->deviceHandle, VIDIOC_QUERYBUF, &buf)) { perror ("VIDIOC_QUERYBUF"); /* free capture, and returns an error code */ return -1; } capture->buffers[n_buffers].length = buf.length; capture->buffers[n_buffers].start = mmap (NULL /* start anywhere */, buf.length, PROT_READ | PROT_WRITE /* required */, MAP_SHARED /* recommended */, capture->deviceHandle, buf.m.offset); if (MAP_FAILED == capture->buffers[n_buffers].start) { perror ("mmap"); /* free capture, and returns an error code */ return -1; } } /* Set up Image data */ /* cvInitImageHeader( &capture->frame, cvSize( capture->captureWindow.width, capture->captureWindow.height ), IPL_DEPTH_8U, 3, IPL_ORIGIN_TL, 4 );*/ /* Allocate space for RGBA data */ capture->imageSize=capture->form.fmt.pix.width*capture->form.fmt.pix.height*2; capture->imageData = AllocFunction(capture->imageSize); Printf("cmem allocated %i at %x\n",capture->imageSize,capture->imageData); return 1; }; int V4LCamera::cvGrabFrame(CvCaptureCAM_V4L* capture) { if (capture->FirstCapture) { /* Some general initialization must take place the first time through */ /* This is just a technicality, but all buffers must be filled up before any staggered SYNC is applied. SO, filler up. (see V4L HowTo) */ v4l2_alloc_buffers (capture, NULL); for (capture->bufferIndex = 0; capture->bufferIndex < ((int)capture->req.count); ++capture->bufferIndex) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = (unsigned long)capture->bufferIndex; if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) { perror ("VIDIOC_QBUF"); return 0; } } /* enable the streaming */ capture->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (-1 == xioctl (capture->deviceHandle, VIDIOC_STREAMON, &capture->type)) { /* error enabling the stream */ perror ("VIDIOC_STREAMON"); return 0; } /* preparation is ok */ capture->FirstCapture = 0; } mainloop_v4l2(capture); return(1); } void V4LCamera::mainloop_v4l2(CvCaptureCAM_V4L* capture) { unsigned int count; count = 1; while (count-- > 0) { for (;;) { fd_set fds; struct timeval tv; int r; FD_ZERO (&fds); FD_SET (capture->deviceHandle, &fds); /* Timeout. */ tv.tv_sec = 2; tv.tv_usec = 0; r = select (capture->deviceHandle+1, &fds, NULL, NULL, &tv); if (-1 == r) { if (EINTR == errno) continue; perror ("select"); } if (0 == r) { fprintf (stderr, "select timeout\n"); /* end the infinite loop */ break; } if (read_frame_v4l2 (capture)) break; } } } int V4LCamera::read_frame_v4l2(CvCaptureCAM_V4L* capture) { struct v4l2_buffer buf; CLEAR (buf); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (-1 == xioctl (capture->deviceHandle, VIDIOC_DQBUF, &buf)) { switch (errno) { case EAGAIN: return 0; case EIO: /* Could ignore EIO, see spec. */ /* fall through */ default: /* display the error and stop processing */ perror ("VIDIOC_DQBUF"); return 1; } } if(buf.index >= capture->req.count) { Thread::Err("buf.index >= capture->req.count\n"); } capture->bufferIndex = buf.index; if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf)) perror ("VIDIOC_QBUF"); return 1; } void V4LCamera::Run(void) { Time cam_time, new_time, fpsNow, fpsPrev; //IplImage *img; // raw image int fpsCounter = 0; // init image old if (!cvGrabFrame(&capture)) { Printf("Could not grab a frame\n"); } cam_time = GetTime(); fpsPrev = cam_time; while (!ToBeStopped()) { // fps counter fpsCounter++; if (fpsCounter == 100) { fpsNow = GetTime(); fps->SetText("fps: %.1f", fpsCounter / ((float)(fpsNow - fpsPrev) / 1000000000.)); fpsCounter = 0; fpsPrev = fpsNow; } // cam properties if (gain->ValueChanged() == true && autogain->Value() == false) SetGain(gain->Value()); if (exposure->ValueChanged() == true && autoexposure->Value() == false) SetExposure(exposure->Value()); if (bright->ValueChanged() == true) SetBrightness(bright->Value()); if (sat->ValueChanged() == true) SetSaturation(sat->Value()); if (contrast->ValueChanged() == true) SetContrast(contrast->Value()); if (hue->ValueChanged() == true) SetHue(hue->Value()); //if (sharpness->ValueChanged() == true) // cvSetCaptureProperty(capture, CV_CAP_PROP_SHARPNESS, sharpness->Value()); if (autogain->ValueChanged() == true) { if (autogain->Value() == true) { gain->setEnabled(false); } else { gain->setEnabled(true); SetGain(gain->Value()); } SetAutoGain(autogain->Value()); } if (autoexposure->ValueChanged() == true) { if (autoexposure->Value() == true) { exposure->setEnabled(false); } else { exposure->setEnabled(true); SetExposure(exposure->Value()); } SetAutoExposure(autoexposure->Value()); } //if (awb->ValueChanged() == true) // cvSetCaptureProperty(capture, CV_CAP_PROP_AWB, awb->Value()); // cam pictures cvRetrieveRawFrame(&capture); if (!cvGrabFrame(&capture)) { Printf("Could not grab a frame\n"); } new_time = GetTime(); //check for ps3eye deconnection in hds uav if(new_time-cam_time>100*1000*1000) { Thread::Warn("delta trop grand\n"); hasProblems=true; } output->GetMutex(); output->buffer=capture.imageData; output->ReleaseMutex(); output->SetDataTime(cam_time); ProcessUpdate(output); cam_time = new_time; } //cvReleaseCapture(&capture); } void V4LCamera::cvRetrieveRawFrame( CvCaptureCAM_V4L* capture) { /* Now get what has already been captured as a IplImage return */ /* First, reallocate imageData if the frame size changed */ /* if(((unsigned long)capture->frame.width != capture->form.fmt.pix.width) || ((unsigned long)capture->frame.height != capture->form.fmt.pix.height)) { if (PALETTE_YUYV == 1 || PALETTE_UYVY == 1) { cvFree(&capture->frame.imageData); cvInitImageHeader( &capture->frame, cvSize( capture->form.fmt.pix.width, capture->form.fmt.pix.height ), IPL_DEPTH_8U,2, IPL_ORIGIN_TL, 4 ); capture->frame.imageData = (char *)cvAlloc(capture->frame.imageSize); }else { fprintf( stderr, "HIGHGUI ERROR: V4L: raw output not supported for this palette\n"); } } */ if (PALETTE_YUYV == 1){ memcpy((char *)capture->imageData, (char *)capture->buffers[capture->bufferIndex].start, capture->imageSize); } if (PALETTE_UYVY == 1){ memcpy((char *)capture->imageData, (char *)capture->buffers[capture->bufferIndex].start, capture->imageSize); } } int V4LCamera::QueueBuffer(int index) { struct v4l2_buffer buf; if(index>=0 && indexGetDataType().GetSize(); buffers[n_buffers].start =AllocFunction(output->GetDataType().GetSize()); } return 1; }; bool V4LCamera::HasProblems(void) { return hasProblems; } void V4LCamera::SetAutoGain(bool value) { SetProperty(V4L2_CID_AUTOGAIN, value); } void V4LCamera::SetAutoExposure(bool value) { Thread::Warn("not implemented\n"); } void V4LCamera::SetGain(float value) { SetProperty(V4L2_CID_GAIN, value); } void V4LCamera::SetExposure(float value) { SetProperty(V4L2_CID_EXPOSURE, value); } void V4LCamera::SetBrightness(float value) { SetProperty(V4L2_CID_BRIGHTNESS, value); } void V4LCamera::SetSaturation(float value) { SetProperty(V4L2_CID_SATURATION, value); } void V4LCamera::SetHue(float value) { SetProperty(V4L2_CID_HUE, value); } void V4LCamera::SetContrast(float value) { SetProperty(V4L2_CID_CONTRAST, value); } float V4LCamera::GetProperty(int property) { //get min and max value struct v4l2_queryctrl queryctrl; queryctrl.id = property; if(xioctl (device, VIDIOC_QUERYCTRL,&queryctrl)==-1) return -1; int min = queryctrl.minimum; int max = queryctrl.maximum; //set value struct v4l2_control control; memset (&control, 0, sizeof (v4l2_control)); control.id = property; if(xioctl (device,VIDIOC_G_CTRL, &control)==-1) return -1; return ((float)control.value - min + 1) / (max - min); } void V4LCamera::SetProperty(int property,float value) { //get min and max value struct v4l2_queryctrl queryctrl; queryctrl.id = property; xioctl (device, VIDIOC_QUERYCTRL,&queryctrl); int min = queryctrl.minimum; int max = queryctrl.maximum; //set value struct v4l2_control control; memset (&control, 0, sizeof (v4l2_control)); control.id = property; control.value = (int)(value * (max - min) + min); xioctl (device,VIDIOC_S_CTRL, &control); } int V4LCamera::xioctl( int fd, int request, void *arg) { int r; do r = ioctl (fd, request, arg); while (-1 == r && EINTR == errno); return r; } } // end namespace sensor } // end namespace flair