v4l2src: Add new property for auto scan device feature
[platform/upstream/gst-plugins-good.git] / sys / v4l2 / v4l2_calls.c
index f52bd99..137f399 100644 (file)
@@ -33,6 +33,9 @@
 #include <string.h>
 #include <errno.h>
 #include <unistd.h>
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+#include <glob.h>
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
 #ifdef __sun
 /* Needed on older Solaris Nevada builds (72 at least) */
 #include <stropts.h>
 
 #include "gst/gst-i18n-plugin.h"
 
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+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_AUTO_SCAN_DEVICE_NODE */
+
 GST_DEBUG_CATEGORY_EXTERN (v4l2_debug);
 #define GST_CAT_DEFAULT v4l2_debug
 
@@ -251,7 +265,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
         standard.frameperiod.denominator, standard.frameperiod.numerator);
     v4l2norm->index = standard.id;
 
-    GST_DEBUG_OBJECT (v4l2object->element, "index=%08x, label=%s",
+    GST_DEBUG_OBJECT (v4l2object->dbg_obj, "index=%08x, label=%s",
         (unsigned int) v4l2norm->index, norm->label);
 
     v4l2object->norms = g_list_prepend (v4l2object->norms, (gpointer) norm);
@@ -340,7 +354,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
       }
       default:
         GST_DEBUG_OBJECT (e,
-            "Control type for '%s' not suppored for extra controls.",
+            "Control type for '%s' not supported for extra controls.",
             control.name);
         break;
     }
@@ -461,7 +475,7 @@ gst_v4l2_fill_lists (GstV4l2Object * v4l2object)
 static void
 gst_v4l2_empty_lists (GstV4l2Object * v4l2object)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "deleting enumerations");
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "deleting enumerations");
 
   g_list_foreach (v4l2object->channels, (GFunc) g_object_unref, NULL);
   g_list_free (v4l2object->channels);
@@ -519,8 +533,19 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
 {
   struct stat st;
   int libv4l2_fd = -1;
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+  int error_type = V4L2_OPEN_ERROR_STAT_FAILED;
+  int device_index = 0;
+  glob_t glob_buf;
+
+  memset (&glob_buf, 0x0, sizeof(glob_t));
 
-  GST_DEBUG_OBJECT (v4l2object->element, "Trying to open device %s",
+  if (!v4l2object) {
+    GST_ERROR ("v4l2object is NULL");
+    return FALSE;
+  }
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying to open device %s",
       v4l2object->videodev);
 
   GST_V4L2_CHECK_NOT_OPEN (v4l2object);
@@ -530,19 +555,45 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
   if (!v4l2object->videodev)
     v4l2object->videodev = g_strdup ("/dev/video");
 
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+  if (!v4l2object->videodev) {
+    GST_ERROR_OBJECT (v4l2object->element, "videodev is NULL");
+    return FALSE;
+  }
+
+CHECK_AGAIN:
+  /* check if it is a device */
+  if (stat (v4l2object->videodev, &st) == -1) {
+    error_type = V4L2_OPEN_ERROR_STAT_FAILED;
+    goto pre_error_check;
+  }
+
+  if (!S_ISCHR (st.st_mode)) {
+    error_type = V4L2_OPEN_ERROR_NO_DEVICE;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
   /* check if it is a device */
   if (stat (v4l2object->videodev, &st) == -1)
     goto stat_failed;
 
   if (!S_ISCHR (st.st_mode))
     goto no_device;
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
 
   /* open the device */
   v4l2object->video_fd =
       open (v4l2object->videodev, O_RDWR /* | O_NONBLOCK */ );
 
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+  if (!GST_V4L2_IS_OPEN (v4l2object)) {
+    error_type = V4L2_OPEN_ERROR_NOT_OPEN;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
   if (!GST_V4L2_IS_OPEN (v4l2object))
     goto not_open;
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
 
 #ifdef HAVE_LIBV4L2
   if (v4l2object->fd_open)
@@ -560,6 +611,28 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
     v4l2object->video_fd = libv4l2_fd;
 
   /* get capabilities, error will be posted */
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+  if (!gst_v4l2_get_capabilities (v4l2object)) {
+    error_type = V4L2_OPEN_ERROR;
+    goto pre_error_check;
+  }
+
+  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;
+  }
+
+  if (GST_IS_V4L2SINK (v4l2object->element) &&
+      !(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_AUTO_SCAN_DEVICE_NODE */
   if (!gst_v4l2_get_capabilities (v4l2object))
     goto error;
 
@@ -573,31 +646,36 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
       !(v4l2object->device_caps & (V4L2_CAP_VIDEO_OUTPUT |
               V4L2_CAP_VIDEO_OUTPUT_MPLANE)))
     goto not_output;
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
 
   if (GST_IS_V4L2_VIDEO_DEC (v4l2object->element) &&
-      /* Today's M2M device only expose M2M */
-      !((v4l2object->device_caps & (V4L2_CAP_VIDEO_M2M |
-                  V4L2_CAP_VIDEO_M2M_MPLANE)) ||
-          /* But legacy driver may expose both CAPTURE and OUTPUT */
-          ((v4l2object->device_caps &
-                  (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_CAPTURE_MPLANE)) &&
-              (v4l2object->device_caps &
-                  (V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OUTPUT_MPLANE)))))
+      !GST_V4L2_IS_M2M (v4l2object->device_caps))
     goto not_m2m;
 
   gst_v4l2_adjust_buf_type (v4l2object);
 
   /* create enumerations, posts errors. */
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+  if (!gst_v4l2_fill_lists (v4l2object)) {
+    error_type = V4L2_OPEN_ERROR;
+    goto pre_error_check;
+  }
+#else /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
   if (!gst_v4l2_fill_lists (v4l2object))
     goto error;
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
 
-  GST_INFO_OBJECT (v4l2object->element,
+  GST_INFO_OBJECT (v4l2object->dbg_obj,
       "Opened device '%s' (%s) successfully",
       v4l2object->vcap.card, v4l2object->videodev);
 
   if (v4l2object->extra_controls)
     gst_v4l2_set_controls (v4l2object, v4l2object->extra_controls);
 
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+  globfree (&glob_buf);
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
+
   /* 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
    */
@@ -608,6 +686,65 @@ gst_v4l2_open (GstV4l2Object * v4l2object)
 
   return TRUE;
 
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+pre_error_check:
+  {
+    if (v4l2object->auto_scan_device == FALSE) {
+      GST_WARNING_OBJECT (v4l2object->element, "auto scan device disabled");
+      goto error;
+    }
+
+    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 = 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_AUTO_SCAN_DEVICE_NODE */
+
   /* ERRORS */
 stat_failed:
   {
@@ -664,6 +801,10 @@ error:
     /* empty lists */
     gst_v4l2_empty_lists (v4l2object);
 
+#ifdef TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE
+    globfree (&glob_buf);
+#endif /* TIZEN_FEATURE_V4L2SRC_AUTO_SCAN_DEVICE_NODE */
+
     return FALSE;
   }
 }
@@ -671,7 +812,7 @@ error:
 gboolean
 gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "Trying to dup device %s",
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying to dup device %s",
       other->videodev);
 
   GST_V4L2_CHECK_OPEN (other);
@@ -690,11 +831,12 @@ gst_v4l2_dup (GstV4l2Object * v4l2object, GstV4l2Object * other)
   g_free (v4l2object->videodev);
   v4l2object->videodev = g_strdup (other->videodev);
 
-  GST_INFO_OBJECT (v4l2object->element,
+  GST_INFO_OBJECT (v4l2object->dbg_obj,
       "Cloned device '%s' (%s) successfully",
       v4l2object->vcap.card, v4l2object->videodev);
 
   v4l2object->never_interlaced = other->never_interlaced;
+  v4l2object->no_initial_format = other->no_initial_format;
 
   return TRUE;
 
@@ -717,7 +859,7 @@ not_open:
 gboolean
 gst_v4l2_close (GstV4l2Object * v4l2object)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "Trying to close %s",
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "Trying to close %s",
       v4l2object->videodev);
 
   GST_V4L2_CHECK_OPEN (v4l2object);
@@ -742,7 +884,7 @@ gst_v4l2_close (GstV4l2Object * v4l2object)
 gboolean
 gst_v4l2_get_norm (GstV4l2Object * v4l2object, v4l2_std_id * norm)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "getting norm");
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting norm");
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
@@ -770,7 +912,7 @@ std_failed:
 gboolean
 gst_v4l2_set_norm (GstV4l2Object * v4l2object, v4l2_std_id norm)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "trying to set norm to "
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to set norm to "
       "%" G_GINT64_MODIFIER "x", (guint64) norm);
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
@@ -804,7 +946,7 @@ gst_v4l2_get_frequency (GstV4l2Object * v4l2object,
 
   GstTunerChannel *channel;
 
-  GST_DEBUG_OBJECT (v4l2object->element, "getting current tuner frequency");
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting current tuner frequency");
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
@@ -843,7 +985,7 @@ gst_v4l2_set_frequency (GstV4l2Object * v4l2object,
 
   GstTunerChannel *channel;
 
-  GST_DEBUG_OBJECT (v4l2object->element,
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj,
       "setting current tuner frequency to %lu", frequency);
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
@@ -882,7 +1024,7 @@ gst_v4l2_signal_strength (GstV4l2Object * v4l2object,
 {
   struct v4l2_tuner tuner = { 0, };
 
-  GST_DEBUG_OBJECT (v4l2object->element, "trying to get signal strength");
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to get signal strength");
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
@@ -916,7 +1058,7 @@ gst_v4l2_get_attribute (GstV4l2Object * v4l2object,
 {
   struct v4l2_control control = { 0, };
 
-  GST_DEBUG_OBJECT (v4l2object->element, "getting value of attribute %d",
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "getting value of attribute %d",
       attribute_num);
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
@@ -953,7 +1095,7 @@ gst_v4l2_set_attribute (GstV4l2Object * v4l2object,
 {
   struct v4l2_control control = { 0, };
 
-  GST_DEBUG_OBJECT (v4l2object->element, "setting value of attribute %d to %d",
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "setting value of attribute %d to %d",
       attribute_num, value);
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
@@ -1029,7 +1171,7 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
 {
   gint n;
 
-  GST_DEBUG_OBJECT (v4l2object->element, "trying to get input");
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to get input");
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
@@ -1039,7 +1181,7 @@ gst_v4l2_get_input (GstV4l2Object * v4l2object, gint * input)
 
   *input = n;
 
-  GST_DEBUG_OBJECT (v4l2object->element, "input: %d", n);
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "input: %d", n);
 
   return TRUE;
 
@@ -1058,7 +1200,7 @@ input_failed:
 gboolean
 gst_v4l2_set_input (GstV4l2Object * v4l2object, gint input)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "trying to set input to %d", input);
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to set input to %d", input);
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
@@ -1086,7 +1228,7 @@ gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
 {
   gint n;
 
-  GST_DEBUG_OBJECT (v4l2object->element, "trying to get output");
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to get output");
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;
@@ -1096,7 +1238,7 @@ gst_v4l2_get_output (GstV4l2Object * v4l2object, gint * output)
 
   *output = n;
 
-  GST_DEBUG_OBJECT (v4l2object->element, "output: %d", n);
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "output: %d", n);
 
   return TRUE;
 
@@ -1115,7 +1257,7 @@ output_failed:
 gboolean
 gst_v4l2_set_output (GstV4l2Object * v4l2object, gint output)
 {
-  GST_DEBUG_OBJECT (v4l2object->element, "trying to set output to %d", output);
+  GST_DEBUG_OBJECT (v4l2object->dbg_obj, "trying to set output to %d", output);
 
   if (!GST_V4L2_IS_OPEN (v4l2object))
     return FALSE;