cap_libv4l.cpp v4l2_buffer-> timestamp始终为0

时间:2016-05-04 10:37:36

标签: c++ opencv webcam capture v4l2

我在Linux上使用OpenCv 2.4.8,并获取USB网络摄像头(logitech C200)捕获以进行进一步处理。我已经确定捕获使用cap_libv4.cpp(存在于modlules / highgui中)来捕获图像。我不得不修改所述文件以添加对时间戳的支持。

我已尝试使用多个网络摄像头,并注意到如果结构v4l2_buffer中的flags字段为0,它只给出正确的时间戳。如果它等于2,对应于V4L2_BUF_FLAG_TIMESTAMP MONOTONIC,则它给出0.我是想知道我的代码修改或libv4l驱动程序是否有问题。

函数read_frame_v4l2读取缓冲区,并更新时间戳。可以使用icvGetPropertyCAM_V4L函数读取时间戳。这两个函数的修改代码如下:

icvGetPropertyCAM_V4L:

static double icvGetPropertyCAM_V4L (CvCaptureCAM_V4L* capture,
                                     int property_id ) {
  char name[32];
  int is_v4l2_device = 0;
      /* initialize the control structure */
  switch (property_id) {
    case CV_CAP_PROP_FRAME_WIDTH:
    case CV_CAP_PROP_FRAME_HEIGHT:
      CLEAR (capture->form);
      capture->form.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
      if (-1 == xioctl (capture->deviceHandle, VIDIOC_G_FMT, &capture->form)) {
          /* display an error message, and return an error code */
          perror ("VIDIOC_G_FMT");
        if (v4l1_ioctl (capture->deviceHandle, VIDIOCGWIN, &capture->captureWindow) < 0) {
          fprintf (stderr, "HIGHGUI ERROR: V4L: Unable to determine size of incoming image\n");
          icvCloseCAM_V4L(capture);
          return -1;
        } else {
          int retval = (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->captureWindow.width:capture->captureWindow.height;
          return retval / 0xFFFF;
        }
      }
      return (property_id == CV_CAP_PROP_FRAME_WIDTH)?capture->form.fmt.pix.width:capture->form.fmt.pix.height;
    case CV_CAP_PROP_BRIGHTNESS:
      sprintf(name, "Brightness");
      capture->control.id = V4L2_CID_BRIGHTNESS;
      break;
    case CV_CAP_PROP_CONTRAST:
      sprintf(name, "Contrast");
      capture->control.id = V4L2_CID_CONTRAST;
      break;
    case CV_CAP_PROP_SATURATION:
      sprintf(name, "Saturation");
      capture->control.id = V4L2_CID_SATURATION;
      break;
    case CV_CAP_PROP_HUE:
      sprintf(name, "Hue");
      capture->control.id = V4L2_CID_HUE;
      break;
    case CV_CAP_PROP_GAIN:
      sprintf(name, "Gain");
      capture->control.id = V4L2_CID_GAIN;
      break;
    case CV_CAP_PROP_EXPOSURE:
      sprintf(name, "Exposure");
      capture->control.id = V4L2_CID_EXPOSURE;
      break;
    case CV_CAP_PROP_POS_MSEC:
          if (capture->FirstCapture) {
            return 0;
          } else {
            return 1000 * capture->timestamp.tv_sec + ((double) capture->timestamp.tv_usec) / 1000;
          }
          break;
    default:
      sprintf(name, "<unknown property string>");
      capture->control.id = property_id;
  }

  if(v4l2_ioctl(capture->deviceHandle, VIDIOC_G_CTRL, &capture->control) == 0) {
    /* all went well */
    is_v4l2_device = 1;
  } else {
    fprintf(stderr, "HIGHGUI ERROR: V4L2: Unable to get property %s(%u) - %s\n", name, capture->control.id, strerror(errno));
  }

  if (is_v4l2_device == 1) {
      /* get the min/max values */
      int v4l2_min = v4l2_get_ctrl_min(capture, capture->control.id);
      int v4l2_max = v4l2_get_ctrl_max(capture, capture->control.id);

      if ((v4l2_min == -1) && (v4l2_max == -1)) {
        fprintf(stderr, "HIGHGUI ERROR: V4L2: Property %s(%u) not supported by device\n", name, property_id);
        return -1;
      }

      /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
      return ((float)capture->control.value - v4l2_min) / (v4l2_max - v4l2_min);

  } else {
    /* TODO: review this section */
    int retval = -1;

    switch (property_id) {
      case CV_CAP_PROP_BRIGHTNESS:
        retval = capture->imageProperties.brightness;
        break;
      case CV_CAP_PROP_CONTRAST:
        retval = capture->imageProperties.contrast;
        break;
      case CV_CAP_PROP_SATURATION:
        retval = capture->imageProperties.colour;
        break;
      case CV_CAP_PROP_HUE:
        retval = capture->imageProperties.hue;
        break;
      case CV_CAP_PROP_GAIN:
        fprintf(stderr, "HIGHGUI ERROR: V4L: Gain control in V4L is not supported\n");
        return -1;
        break;
      case CV_CAP_PROP_EXPOSURE:
        fprintf(stderr, "HIGHGUI ERROR: V4L: Exposure control in V4L is not supported\n");
        return -1;
        break;
    }

    if (retval == -1) {
      /* there was a problem */
      return -1;
    }
    /* all was OK, so convert to 0.0 - 1.0 range, and return the value */
    return float (retval) / 0xFFFF;
  }
}

read_frame_v4l2:

static CvCaptureCAM_V4L * icvCaptureFromCAM_V4L (int index)
{
   static int autoindex;
   autoindex = 0;

   char deviceName[MAX_DEVICE_DRIVER_NAME];

   if (!numCameras)
      icvInitCapture_V4L(); /* Havent called icvInitCapture yet - do it now! */
   if (!numCameras)
     return NULL; /* Are there any /dev/video input sources? */

   //search index in indexList
   if ( (index>-1) && ! ((1 << index) & indexList) )
   {
     fprintf( stderr, "HIGHGUI ERROR: V4L: index %d is not correct!\n",index);
     return NULL; /* Did someone ask for not correct video source number? */
   }
   /* Allocate memory for this humongus CvCaptureCAM_V4L structure that contains ALL
      the handles for V4L processing */
   CvCaptureCAM_V4L * capture = (CvCaptureCAM_V4L*)cvAlloc(sizeof(CvCaptureCAM_V4L));
   if (!capture) {
      fprintf( stderr, "HIGHGUI ERROR: V4L: Could not allocate memory for capture process.\n");
      return NULL;
   }

#ifdef USE_TEMP_BUFFER
   capture->buffers[MAX_V4L_BUFFERS].start = NULL;
#endif

   /* Select camera, or rather, V4L video source */
   if (index<0) { // Asking for the first device available
     for (; autoindex<MAX_CAMERAS;autoindex++)
    if (indexList & (1<<autoindex))
        break;
     if (autoindex==MAX_CAMERAS)
    return NULL;
     index=autoindex;
     autoindex++;// i can recall icvOpenCAM_V4l with index=-1 for next camera
   }
   /* Print the CameraNumber at the end of the string with a width of one character */
   sprintf(deviceName, "/dev/video%1d", index);

   /* 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;

   /* set the default size */
   capture->width  = DEFAULT_V4L_WIDTH;
   capture->height = DEFAULT_V4L_HEIGHT;

   if (_capture_V4L2 (capture, deviceName) == -1) {
       icvCloseCAM_V4L(capture);
       capture->is_v4l2_device = 0;
       if (_capture_V4L (capture, deviceName) == -1) {
           icvCloseCAM_V4L(capture);
           return NULL;
       }
   } else {
       capture->is_v4l2_device = 1;
   }

   return capture;
}; /* End icvOpenCAM_V4L */

#ifdef HAVE_CAMV4L2

static int 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;
        }
   }

   assert(buf.index < capture->req.count);

#ifdef USE_TEMP_BUFFER
   memcpy(capture->buffers[MAX_V4L_BUFFERS].start,
    capture->buffers[buf.index].start,
    capture->buffers[MAX_V4L_BUFFERS].length );
   capture->bufferIndex = MAX_V4L_BUFFERS;
   //printf("got data in buff %d, len=%d, flags=0x%X, seq=%d, used=%d)\n",
   //   buf.index, buf.length, buf.flags, buf.sequence, buf.bytesused);
#else
   capture->bufferIndex = buf.index;
#endif

   if (-1 == xioctl (capture->deviceHandle, VIDIOC_QBUF, &buf))
       perror ("VIDIOC_QBUF");

   //set timestamp in capture struct to be timestamp of most recent frame
   /** where timestamps refer to the instant the field or frame was received by the driver, not the capture time*/
   capture->timestamp = buf.timestamp;   //
   printf("Flags %0x.X, timestamp = %ld, %ld", buf.flags, buf.timestamp.tv_sec, buf.timestamp.tv_usec);
   //prints 0 if the flags is of the 4th nibble from LSB is 2 i.e. of the form .....2xxx H   
   return 1;
}

我需要时间戳以确定我在图像中检测到的物体的速度。我搜索了很多,但没有找到任何解决方案。

0 个答案:

没有答案