libv4l: handle some ioctls changing the format as a side effect
authorHans de Goede <hdegoede@redhat.com>
Fri, 7 Oct 2011 07:54:24 +0000 (09:54 +0200)
committerHans de Goede <hdegoede@redhat.com>
Sun, 16 Oct 2011 14:31:32 +0000 (16:31 +0200)
Some ioctls may change the devices fmt as a side effect, handle this properly.

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
lib/libv4l2/libv4l2-priv.h
lib/libv4l2/libv4l2.c
lib/libv4l2/log.c

index 2e99200..730f193 100644 (file)
@@ -100,6 +100,7 @@ void v4l2_plugin_cleanup(void *plugin_lib, void *plugin_priv,
                         const struct libv4l2_dev_ops *dev_ops);
 
 /* From log.c */
+extern const char *v4l2_ioctls[];
 void v4l2_log_ioctl(unsigned long int request, void *arg, int result);
 
 #endif
index f7ec85d..0db7230 100644 (file)
@@ -1059,6 +1059,13 @@ int v4l2_ioctl(int fd, unsigned long int request, ...)
                                stream_needs_locking = 1;
                }
                break;
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_DV_PRESET:
+       case VIDIOC_S_DV_TIMINGS:
+               is_capture_request = 1;
+               stream_needs_locking = 1;
+               break;          
        }
 
        if (!is_capture_request) {
@@ -1150,6 +1157,53 @@ no_capture_request:
                break;
        }
 
+       case VIDIOC_S_STD:
+       case VIDIOC_S_INPUT:
+       case VIDIOC_S_DV_PRESET:
+       case VIDIOC_S_DV_TIMINGS: {
+               struct v4l2_format src_fmt;
+
+               result = devices[index].dev_ops->ioctl(
+                               devices[index].dev_ops_priv,
+                               fd, request, arg);
+               if (result)
+                       break;
+
+               /* These ioctls may have changed the device's fmt */
+               src_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+               result = devices[index].dev_ops->ioctl(
+                               devices[index].dev_ops_priv,
+                               fd, VIDIOC_G_FMT, &src_fmt);
+               if (result) {
+                       V4L2_LOG_ERR("getting pixformat after %s: %s\n",
+                                    v4l2_ioctls[_IOC_NR(request)],
+                                    strerror(errno));
+                       result = 0; /* The original command did succeed */
+                       break;
+               }
+
+               if (v4l2_pix_fmt_compat(&devices[index].src_fmt, &src_fmt)) {
+                       v4l2_set_src_and_dest_format(index, &src_fmt,
+                                                    &devices[index].dest_fmt);
+                       break;
+               }
+
+               /* The fmt has been changed, remember the new format ... */
+               devices[index].src_fmt  = src_fmt;
+               devices[index].dest_fmt = src_fmt;
+               /* and try to restore the last set destination pixelformat. */
+               src_fmt.fmt.pix.pixelformat =
+                       devices[index].dest_fmt.fmt.pix.pixelformat;
+               result = v4l2_s_fmt(index, &src_fmt);
+               if (result) {
+                       V4L2_LOG_WARN("restoring destination pixelformat after %s failed\n",
+                                     v4l2_ioctls[_IOC_NR(request)]);
+                       result = 0; /* The original command did succeed */
+               }
+
+               break;
+       }
+
        case VIDIOC_REQBUFS: {
                struct v4l2_requestbuffers *req = arg;
 
index 37d2e1f..f7ce06f 100644 (file)
@@ -31,7 +31,7 @@
 
 FILE *v4l2_log_file = NULL;
 
-static const char *v4l2_ioctls[] = {
+const char *v4l2_ioctls[] = {
        /* start v4l2 ioctls */
        [_IOC_NR(VIDIOC_QUERYCAP)]         = "VIDIOC_QUERYCAP",
        [_IOC_NR(VIDIOC_RESERVED)]         = "VIDIOC_RESERVED",