OpenCVとV4L2 その2


やっぱりバッファの管理だった。
画像のサイズが変わっても、バッファの拡張がされていないことを確認。
MJPEGの場合はそれでもバッファサイズ内に収まっていたので問題がなかった様子。

いろいろいじって、とりあえずバッファの拡張というか再マップに対応。
暇があればOpenCVのMLにでも投げたいところだね。

--- opencv-cvs.orig/otherlibs/highgui/cvcap_v4l.cpp	2007-10-13 21:24:34.000000000 +0900
+++ opencv-cvs/otherlibs/highgui/cvcap_v4l.cpp	2007-10-18 18:08:40.000000000 +0900
@@ -276,7 +276,7 @@
 #ifdef HAVE_CAMV4L2
 
    /* V4L2 variables */
-   buffer buffers[10];
+   buffer* buffers;
    struct v4l2_capability cap;
    struct v4l2_input inp;
    struct v4l2_format form;
@@ -530,6 +530,11 @@
     PALETTE_YUV411P = 1;
   }
   else
+  if (try_palette_v4l2(capture, V4L2_PIX_FMT_YUYV) == 0)
+  {
+    PALETTE_YUYV = 1;
+  }
+  else
 
 #ifdef HAVE_JPEG
 #ifdef __USE_GNU
@@ -544,11 +549,6 @@
 #endif
 #endif
 
-  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;
@@ -777,6 +777,93 @@
 
 }
 
+static int _free_buffers_V4L2 (CvCaptureCAM_V4L *capture){
+  for (unsigned int n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
+  {
+    if (-1 == munmap (capture->buffers[n_buffers].start, capture->buffers[n_buffers].length)) {
+      perror ("munmap");
+    }
+  }
+  cvFree(&capture->buffers);
+  return 1;
+}
+
+
+static int _init_buffers_V4L2 (CvCaptureCAM_V4L *capture){
+   if(capture->buffers != NULL){
+     _free_buffers_V4L2(capture);
+   }
+  
+   CLEAR (capture->req);
+
+   capture->req.count               = 256;
+   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);
+         fprintf (stderr, "It does not support memory mapping\n");
+       } else {
+         perror ("VIDIOC_REQBUFS");
+       }
+       /* free capture, and returns an error code */
+       icvCloseCAM_V4L (capture);
+       return -1;
+   }
+
+   if (capture->req.count < 4)
+   {
+//       fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
+       fprintf (stderr, "Insufficient buffer memory\n");
+
+       /* free capture, and returns an error code */
+       icvCloseCAM_V4L (capture);
+       return -1;
+   }
+  
+   capture->buffers = (buffer*) cvAlloc(capture->req.count*sizeof(buffer));
+     
+
+   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 */
+           icvCloseCAM_V4L (capture);
+           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 */
+           icvCloseCAM_V4L (capture);
+           return -1;
+       }
+   }
+   return 1;
+}
+
 static int _capture_V4L2 (CvCaptureCAM_V4L *capture, char *deviceName)
 {
    int detect_v4l2 = 0;
@@ -872,68 +959,8 @@
    if (capture->form.fmt.pix.sizeimage < min)
        capture->form.fmt.pix.sizeimage = min;
 
-   CLEAR (capture->req);
-
-   capture->req.count               = 4;
-   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 */
-       icvCloseCAM_V4L (capture);
-       return -1;
-   }
-
-   if (capture->req.count < 4)
-   {
-       fprintf (stderr, "Insufficient buffer memory on %s\n", deviceName);
-
-       /* free capture, and returns an error code */
-       icvCloseCAM_V4L (capture);
-       return -1;
-   }
-
-   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 */
-           icvCloseCAM_V4L (capture);
-           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 */
-           icvCloseCAM_V4L (capture);
-           return -1;
-       }
-   }
+   if(_init_buffers_V4L2(capture) == -1)
+     return -1;
 
    /* Set up Image data */
    cvInitImageHeader( &capture->frame,
@@ -1219,6 +1246,8 @@
 
       if (V4L2_SUPPORT == 1)
       {
+        if(_init_buffers_V4L2(capture) == -1)
+            return -1;
 
         for (capture->bufferIndex = 0;
              capture->bufferIndex < ((int)capture->req.count);
@@ -2664,13 +2693,7 @@
      }
 #ifdef HAVE_CAMV4L2
      else {
-
-       for (unsigned int n_buffers = 0; n_buffers < capture->req.count; ++n_buffers)
-       {
-           if (-1 == munmap (capture->buffers[n_buffers].start, capture->buffers[n_buffers].length)) {
-               perror ("munmap");
-           }
-       }
+       _free_buffers_V4L2(capture);
 
      }
 #endif /* HAVE_CAMV4L2 */