Merge the tizen patch and fix build err based on 1.12.2
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / v4l2_calls.c
index 4ccbbf5..758a079 100644 (file)
@@ -1,7 +1,7 @@
 /* GStreamer
  *
  * Copyright (C) 2002 Ronald Bultje <rbultje@ronald.bitfreak.net>
- *               2006 Edgard Lima <edgard.lima@indt.org.br>
+ *               2006 Edgard Lima <edgard.lima@gmail.com>
  *
  * v4l2_calls.c - generic V4L2 calls handling
  *
@@ -33,6 +33,9 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+#include <glob.h>
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 #ifdef __sun
 /* Needed on older Solaris Nevada builds (72 at least) */
 #include <stropts.h>
 
 #include "gst/gst-i18n-plugin.h"
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+enum {
+  V4L2_OPEN_ERROR = 0,
+  V4L2_OPEN_ERROR_STAT_FAILED,
+  V4L2_OPEN_ERROR_NO_DEVICE,
+  V4L2_OPEN_ERROR_NOT_OPEN,
+  V4L2_OPEN_ERROR_NOT_CAPTURE,
+  V4L2_OPEN_ERROR_NOT_OUTPUT
+};
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
+
 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
 #define GST_CAT_DEFAULT v4l2_debug
 
@@ -74,11 +88,16 @@ gst_v4l2_get_capabilities (GstV4l2Object * v4l2object)
   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_QUERYCAP, &v4l2object->vcap) < 0)
     goto cap_failed;
 
+  if (v4l2object->vcap.capabilities & V4L2_CAP_DEVICE_CAPS)
+    v4l2object->device_caps = v4l2object->vcap.device_caps;
+  else
+    v4l2object->device_caps = v4l2object->vcap.capabilities;
+
   GST_LOG_OBJECT (e, "driver:      '%s'", v4l2object->vcap.driver);
   GST_LOG_OBJECT (e, "card:        '%s'", v4l2object->vcap.card);
   GST_LOG_OBJECT (e, "bus_info:    '%s'", v4l2object->vcap.bus_info);
   GST_LOG_OBJECT (e, "version:     %08x", v4l2object->vcap.version);
-  GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->vcap.capabilities);
+  GST_LOG_OBJECT (e, "capabilites: %08x", v4l2object->device_caps);
 
   return TRUE;
 
@@ -216,8 +235,8 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
     GstTunerNorm *norm;
 
     /* fill in defaults */
-    standard.frameperiod.numerator = 0;
-    standard.frameperiod.denominator = 1;
+    standard.frameperiod.numerator = 1;
+    standard.frameperiod.denominator = 0;
     standard.index = n;
 
     if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_ENUMSTD, &standard) < 0) {
@@ -238,14 +257,14 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
     }
 
     GST_DEBUG_OBJECT (e, "    '%s', fps: %d / %d",
-        standard.name, standard.frameperiod.numerator,
-        standard.frameperiod.denominator);
+        standard.name, standard.frameperiod.denominator,
+        standard.frameperiod.numerator);
 
     v4l2norm = g_object_new (GST_TYPE_V4L2_TUNER_NORM, NULL);
     norm = GST_TUNER_NORM (v4l2norm);
     norm->label = g_strdup ((const gchar *) standard.name);
     gst_value_set_fraction (&norm->framerate,
-        standard.frameperiod.numerator, standard.frameperiod.denominator);
+        standard.frameperiod.denominator, standard.frameperiod.numerator);
     v4l2norm->index = standard.id;
 
     GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s",
@@ -484,16 +503,17 @@ gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object)
    * in a contiguous manner. In this case the first v4l2 plane
    * contains all the gst planes.
    */
-#define CHECK_CAPS (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)
   switch (v4l2object->type) {
     case V4L2_BUF_TYPE_VIDEO_OUTPUT:
-      if (v4l2object->vcap.capabilities & CHECK_CAPS) {
+      if (v4l2object->device_caps &
+          (V4L2_CAP_VIDEO_OUTPUT_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)) {
         GST_DEBUG ("adjust type to multi-planar output");
         v4l2object->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
       }
       break;
     case V4L2_BUF_TYPE_VIDEO_CAPTURE:
-      if (v4l2object->vcap.capabilities & CHECK_CAPS) {
+      if (v4l2object->device_caps &
+          (V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_VIDEO_M2M_MPLANE)) {
         GST_DEBUG ("adjust type to multi-planar capture");
         v4l2object->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
       }
@@ -501,7 +521,6 @@ gst_v4l2_adjust_buf_type (GstV4l2Object * v4l2object)
     default:
       break;
   }
-#undef CHECK_CAPS
 }
 
 /******************************************************
@@ -514,6 +533,18 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
 {
   struct stat st;
   int libv4l2_fd;
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  int error_type = V4L2_OPEN_ERROR_STAT_FAILED;
+  int device_index = 0;
+  glob_t glob_buf;
+
+  memset(&glob_buf, 0x0, sizeof(glob_t));
+
+  if (!v4l2object) {
+    GST_ERROR("v4l2object is NULL");
+    return FALSE;
+  }
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
   GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
       v4l2object->videodev);
@@ -525,19 +556,48 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
   if (!v4l2object->videodev)
     v4l2object->videodev = g_strdup ("/dev/video");
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  if (!v4l2object->videodev) {
+    GST_ERROR_OBJECT(v4l2object->element, "videodev is NULL");
+    return FALSE;
+  }
+
+CHECK_AGAIN:
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   /* check if it is a device */
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  if (stat (v4l2object->videodev, &st) == -1) {
+    error_type = V4L2_OPEN_ERROR_STAT_FAILED;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   if (stat (v4l2object->videodev, &st) == -1)
     goto stat_failed;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  if (!S_ISCHR (st.st_mode)) {
+    error_type = V4L2_OPEN_ERROR_NO_DEVICE;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   if (!S_ISCHR (st.st_mode))
     goto no_device;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
   /* open the device */
   v4l2object->video_fd =
       open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  if (!GST_V4L2_IS_OPEN (v4l2object)) {
+    error_type = V4L2_OPEN_ERROR_NOT_OPEN;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   if (!GST_V4L2_IS_OPEN (v4l2object))
     goto not_open;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
   libv4l2_fd = v4l2_fd_open (v4l2object->video_fd,
       V4L2_ENABLE_ENUM_FMT_EMULATION);
@@ -551,36 +611,69 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
     v4l2object->video_fd = libv4l2_fd;
 
   /* get capabilities, error will be posted */
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  if (!gst_v4l2_get_capabilities (v4l2object)) {
+    error_type = V4L2_OPEN_ERROR;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   if (!gst_v4l2_get_capabilities (v4l2object))
     goto error;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
   /* do we need to be a capture device? */
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  GST_INFO_OBJECT(v4l2object->element, "device_caps 0x%x", v4l2object->device_caps);
+  if (GST_IS_V4L2SRC (v4l2object->element) &&
+      (!(v4l2object->device_caps & (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) ||
+       (v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))) {
+    error_type = V4L2_OPEN_ERROR_NOT_CAPTURE;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   if (GST_IS_V4L2SRC (v4l2object->element) &&
-      !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_CAPTURE |
+      !(v4l2object->device_caps & (V4L2_CAP_VIDEO_CAPTURE |
               V4L2_CAP_VIDEO_CAPTURE_MPLANE)))
     goto not_capture;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
   if (GST_IS_V4L2SINK (v4l2object->element) &&
-      !(v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_OUTPUT |
+      !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
+              V4L2_CAP_VIDEO_OUTPUT_MPLANE))) {
+    error_type = V4L2_OPEN_ERROR_NOT_OUTPUT;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
+  if (GST_IS_V4L2SINK (v4l2object->element) &&
+      !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
               V4L2_CAP_VIDEO_OUTPUT_MPLANE)))
     goto not_output;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
   if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) &&
       /* Today's M2M device only expose M2M */
-      !((v4l2object->vcap.capabilities & (V4L2_CAP_VIDEO_M2M |
+      !((v4l2object->device_caps & (V4L2_CAP_VIDEO_M2M |
                   V4L2_CAP_VIDEO_M2M_MPLANE)) ||
           /* But legacy driver may expose both CAPTURE and OUTPUT */
-          ((v4l2object->vcap.capabilities &
+          ((v4l2object->device_caps &
                   (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
-              (v4l2object->vcap.capabilities &
+              (v4l2object->device_caps &
                   (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
     goto not_m2m;
 
   gst_v4l2_adjust_buf_type (v4l2object);
 
   /* create enumerations, posts errors. */
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  if (!gst_v4l2_fill_lists (v4l2object)) {
+    error_type = V4L2_OPEN_ERROR;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
   if (!gst_v4l2_fill_lists (v4l2object))
     goto error;
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
 
   GST_INFO_OBJECT (v4l2object->element,
       "Opened device '%s' (%s) successfully",
@@ -589,6 +682,10 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
   if (v4l2object->extra_controls)
     gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+  globfree(&glob_buf);
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
+
   /* UVC devices are never interlaced, and doing VIDIOC_TRY_FMT on them
    * causes expensive and slow USB IO, so don't probe them for interlaced
    */
@@ -598,6 +695,60 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
 
   return TRUE;
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+pre_error_check:
+  {
+    if (GST_IS_V4L2SRC(v4l2object->element) && glob_buf.gl_pathc == 0) {
+      if (glob("/dev/video*", 0, 0, &glob_buf) != 0) {
+        GST_WARNING_OBJECT(v4l2object->element, "glob failed");
+      }
+    }
+
+    if (glob_buf.gl_pathc > 0 && device_index < glob_buf.gl_pathc) {
+      if (v4l2object->videodev) {
+        g_free(v4l2object->videodev);
+        v4l2object->videodev = NULL;
+      }
+      v4l2object->videodev = g_strdup(glob_buf.gl_pathv[device_index]);
+      if (v4l2object->videodev) {
+        device_index++;
+        GST_INFO_OBJECT(v4l2object->element, "check device [%s]",
+                        v4l2object->videodev);
+
+        if (GST_V4L2_IS_OPEN (v4l2object)) {
+          /* close device */
+          v4l2_close (v4l2object->video_fd);
+          v4l2object->video_fd = -1;
+        }
+        /* empty lists */
+        gst_v4l2_empty_lists (v4l2object);
+
+        goto CHECK_AGAIN;
+      } else {
+        GST_WARNING_OBJECT(v4l2object->element, "g_strdup failed [%s]",
+                           glob_buf.gl_pathv[device_index]);
+      }
+    }
+
+    GST_WARNING_OBJECT(v4l2object->element, "error type : %d", error_type);
+
+    switch (error_type) {
+    case V4L2_OPEN_ERROR_STAT_FAILED:
+      goto stat_failed;
+    case V4L2_OPEN_ERROR_NO_DEVICE:
+      goto no_device;
+    case V4L2_OPEN_ERROR_NOT_OPEN:
+      goto not_open;
+    case V4L2_OPEN_ERROR_NOT_CAPTURE:
+      goto not_capture;
+    case V4L2_OPEN_ERROR_NOT_OUTPUT:
+      goto not_output;
+    default:
+      goto error;
+    }
+  }
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
+
   /* ERRORS */
 stat_failed:
   {
@@ -625,7 +776,7 @@ not_capture:
     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
         (_("Device '%s' is not a capture device."),
             v4l2object->videodev),
-        ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
+        ("Capabilities: 0x%x", v4l2object->device_caps));
     goto error;
   }
 not_output:
@@ -633,7 +784,7 @@ not_output:
     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
         (_("Device '%s' is not a output device."),
             v4l2object->videodev),
-        ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
+        ("Capabilities: 0x%x", v4l2object->device_caps));
     goto error;
   }
 not_m2m:
@@ -641,7 +792,7 @@ not_m2m:
     GST_ELEMENT_ERROR (v4l2object->element, RESOURCE, NOT_FOUND,
         (_("Device '%s' is not a M2M device."),
             v4l2object->videodev),
-        ("Capabilities: 0x%x", v4l2object->vcap.capabilities));
+        ("Capabilities: 0x%x", v4l2object->device_caps));
     goto error;
   }
 error:
@@ -654,6 +805,10 @@ error:
     /* empty lists */
     gst_v4l2_empty_lists (v4l2object);
 
+#ifdef TIZEN_FEATURE_V4L2SRC_MODIFICATION
+    globfree(&glob_buf);
+#endif /* TIZEN_FEATURE_V4L2SRC_MODIFICATION */
+
     return FALSE;
   }
 }
@@ -670,6 +825,7 @@ gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
   GST_V4L2_CHECK_NOT_ACTIVE (v4l2object);
 
   v4l2object->vcap = other->vcap;
+  v4l2object->device_caps = other->device_caps;
   gst_v4l2_adjust_buf_type (v4l2object);
 
   v4l2object->video_fd = v4l2_dup (other->video_fd);
@@ -842,7 +998,7 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
 
   freq.tuner = tunernum;
   /* fill in type - ignore error */
-  v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
+  (void) v4l2_ioctl (v4l2object->video_fd, VIDIOC_G_FREQUENCY, &freq);
   freq.frequency = frequency / channel->freq_multiplicator;
 
   if (v4l2_ioctl (v4l2object->video_fd, VIDIOC_S_FREQUENCY, &freq) < 0)
@@ -923,9 +1079,9 @@ gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
   /* ERRORS */
 ctrl_failed:
   {
-    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
-        (_("Failed to get value for control %d on device '%s'."),
-            attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
+    GST_WARNING_OBJECT (v4l2object,
+        _("Failed to get value for control %d on device '%s'."),
+        attribute_num, v4l2object->videodev);
     return FALSE;
   }
 }
@@ -958,9 +1114,9 @@ gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
   /* ERRORS */
 ctrl_failed:
   {
-    GST_ELEMENT_WARNING (v4l2object->element, RESOURCE, SETTINGS,
-        (_("Failed to set value %d for control %d on device '%s'."),
-            value, attribute_num, v4l2object->videodev), GST_ERROR_SYSTEM);
+    GST_WARNING_OBJECT (v4l2object,
+        _("Failed to set value %d for control %d on device '%s'."),
+        value, attribute_num, v4l2object->videodev);
     return FALSE;
   }
 }
@@ -1034,7 +1190,7 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
 
   /* ERRORS */
 input_failed:
-  if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
     /* only give a warning message if driver actually claims to have tuner
      * support
      */
@@ -1059,7 +1215,7 @@ gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
 
   /* ERRORS */
 input_failed:
-  if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
     /* only give a warning message if driver actually claims to have tuner
      * support
      */
@@ -1091,7 +1247,7 @@ gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
 
   /* ERRORS */
 output_failed:
-  if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
     /* only give a warning message if driver actually claims to have tuner
      * support
      */
@@ -1116,7 +1272,7 @@ gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
 
   /* ERRORS */
 output_failed:
-  if (v4l2object->vcap.capabilities & V4L2_CAP_TUNER) {
+  if (v4l2object->device_caps & V4L2_CAP_TUNER) {
     /* only give a warning message if driver actually claims to have tuner
      * support
      */