Added initialization of camera. This should prevent breaking of camera
authorRoman Moravcik <roman.moravcik@gmail.com>
Thu, 7 Jan 2010 11:31:19 +0000 (12:31 +0100)
committerRoman Moravcik <roman.moravcik@gmail.com>
Thu, 7 Jan 2010 11:31:19 +0000 (12:31 +0100)
application (bug 4949).

src/flashlight_lib.c

index 6f56ede..d7ce455 100644 (file)
 #include <errno.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 
 #include <asm/types.h>
 #include <linux/videodev2.h>
 
 #include "flashlight_lib.h"
 
+struct buffer {
+       void *start;
+       size_t length;
+};
+
+struct buffer *buffers = NULL;
+static unsigned int n_buffers = 0;
+
 int flashlight_get_status (FlashlightContext_t *flashlight, int *status)
 {
        struct v4l2_control ctrl;
@@ -104,6 +113,8 @@ int flashlight_get_status (FlashlightContext_t *flashlight, int *status)
 int flashlight_set_intensity (FlashlightContext_t *flashlight, int intensity)
 {
        struct v4l2_control ctrl;
+       enum v4l2_buf_type type;
+       unsigned int i;
 
        printf ("flashlight_set_intensity(%d)\n", intensity);
 
@@ -128,6 +139,35 @@ int flashlight_set_intensity (FlashlightContext_t *flashlight, int intensity)
                return EGENERROR;
        }
 
+       /*
+          WORKAROUND: start/stop i/o streaming to block camera application
+        */
+       if (intensity > 0) {
+               for (i = 0; i < n_buffers; ++i) {
+                       struct v4l2_buffer buf;
+
+                       buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+                       buf.memory      = V4L2_MEMORY_MMAP;
+                       buf.index       = i;
+                       if (ioctl (flashlight->fd, VIDIOC_QBUF, &buf) == -1) {
+                               printf ("flashlight_set_intensity: unable to exchange a buffer %d with driver (%s)\n", i, strerror (errno));
+                               return EGENERROR;
+                       }
+               }
+
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               if (ioctl (flashlight->fd, VIDIOC_STREAMON, &type)) {
+                       printf ("flashlight_set_intensity: unable to start i/o streaming (%s)\n", strerror (errno));
+                       return EGENERROR;
+               }
+       } else {
+               type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               if (ioctl (flashlight->fd, VIDIOC_STREAMOFF, &type) == -1) {
+                       printf ("flashlight_set_intensity: unable to stop i/o streaming (%s)\n", strerror (errno));
+                       return EGENERROR;
+               }
+       }
+
        return ENOERROR;
 }
 
@@ -161,6 +201,10 @@ int flashlight_get_intensity (FlashlightContext_t *flashlight, int *intensity)
 int flashlight_open (FlashlightContext_t *flashlight, const char *device_name)
 {
        struct v4l2_queryctrl ctrl;
+       struct v4l2_cropcap cropcap;
+       struct v4l2_crop crop;
+       struct v4l2_format fmt;
+       struct v4l2_requestbuffers req;
        struct stat st;
 
        printf ("flashlight_open(%s)\n", device_name);
@@ -205,11 +249,92 @@ int flashlight_open (FlashlightContext_t *flashlight, const char *device_name)
        flashlight->min_intensity = ctrl.minimum;
        flashlight->max_intensity = ctrl.maximum;
 
+       /*
+          WORKAROUND: Initialization of camera extracted from v4l2_example.
+          http://v4l2spec.bytesex.org/spec/capture-example.html
+
+          We need to initialize camera in other to block camera application.
+          (bug 4949: Applet breaks the camera application)
+        */
+       /* get crop capabilities */
+       cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       if (ioctl (flashlight->fd, VIDIOC_CROPCAP, &cropcap) == -1) {
+               printf ("flashlight_open: unable to get crop capabilities (%s)\n", strerror (errno));
+               return EGENERROR;
+       }
+
+       /* set crop capabilities */
+       crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       crop.c = cropcap.defrect; /* reset to default */
+       if (ioctl (flashlight->fd, VIDIOC_S_CROP, &crop) == -1) {
+               printf ("flashlight_open: unable to set cropping rectangle (%s)\n", strerror (errno));
+               return EGENERROR;
+       }
+
+       /* set data format */
+       fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       fmt.fmt.pix.width       = 640;
+       fmt.fmt.pix.height      = 480;
+       fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+       fmt.fmt.pix.field       = V4L2_FIELD_INTERLACED;
+       if (ioctl (flashlight->fd, VIDIOC_S_FMT, &fmt) == -1) {
+               printf ("flashlight_open: unable to set data format (%s)\n", strerror (errno));
+               return EGENERROR;
+       }
+
+       req.count       = 4;
+       req.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       req.memory      = V4L2_MEMORY_MMAP;
+       if (ioctl (flashlight->fd, VIDIOC_REQBUFS, &req) == -1) {
+               printf ("flashlight_open: unable to initiate memory mapping (%s)\n", strerror (errno));
+               return EGENERROR;
+       }
+
+       if (req.count < 2) {
+               printf ("flashlight_open: insufficient buffer memory on %s\n", device_name);
+               return EGENERROR;
+       }
+
+       buffers = calloc (req.count, sizeof (*buffers));
+       if (!buffers) {
+               printf ("flashlight_open: unable to allocate memory\n");
+               return EGENERROR;
+       }
+
+       for (n_buffers = 0; n_buffers < req.count; ++n_buffers) {
+               struct v4l2_buffer buf;
+
+               buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               buf.memory      = V4L2_MEMORY_MMAP;
+               buf.index       = n_buffers;
+
+               if (ioctl (flashlight->fd, VIDIOC_QUERYBUF, &buf) == -1) {
+                       printf ("flashlight_open: unable to query the status of a buffer %d (%s)\n",
+                               n_buffers, strerror (errno));
+                       return EGENERROR;
+               }
+
+               buffers[n_buffers].length = buf.length;
+               buffers[n_buffers].start = mmap (NULL /* start anywhere */,
+                                                buf.length,
+                                                PROT_READ | PROT_WRITE /* required */,
+                                                MAP_SHARED /* recommended */,
+                                                flashlight->fd,
+                                                buf.m.offset);
+
+               if (buffers[n_buffers].start == MAP_FAILED) {
+                       printf ("flashlight_open: unable to map memory (%s)\n", strerror (errno));
+                       return EGENERROR;
+               }
+       }
+
        return ENOERROR;
 }
 
 int flashlight_close (FlashlightContext_t *flashlight)
 {
+       unsigned int i;
+
        printf ("flashlight_close()\n");
 
        if (flashlight == NULL) {
@@ -217,6 +342,15 @@ int flashlight_close (FlashlightContext_t *flashlight)
                return ENOCONTEXT;
        }
 
+       /* unmap memory mapped buffers */
+       for (i = 0; i < n_buffers; ++i) {
+               if (munmap (buffers[i].start, buffers[i].length) == -1) {
+                       printf ("flashlight_close: unable to unmap memory (%s)\n", strerror (errno));
+                       return EGENERROR;
+               }
+       }
+       free (buffers);
+
        if (flashlight->fd != -1) {
                if (close (flashlight->fd) == -1) {
                        printf ("flashlight_close: cannot close device '%s' (%s)\n", flashlight->device_name, strerror (errno));