v4l2src: Try to avoid TRY_FMT when camera is streaming

Some camera firmware crash is TRY_FMT is called during streaming. As a
side effect. This try and detect that the same format as currently
running is about to be tried, and skip renegotiation.

https://bugzilla.gnome.org/show_bug.cgi?id=796789
diff --git a/sys/v4l2/gstv4l2object.c b/sys/v4l2/gstv4l2object.c
index ee6ebdb..11c81ff 100644
--- a/sys/v4l2/gstv4l2object.c
+++ b/sys/v4l2/gstv4l2object.c
@@ -4020,6 +4020,46 @@
 }
 
 gboolean
+gst_v4l2_object_caps_is_subset (GstV4l2Object * v4l2object, GstCaps * caps)
+{
+  GstStructure *config;
+  GstCaps *oldcaps;
+  gboolean ret;
+
+  if (!v4l2object->pool)
+    return FALSE;
+
+  config = gst_buffer_pool_get_config (v4l2object->pool);
+  gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
+
+  ret = oldcaps && gst_caps_is_subset (oldcaps, caps);
+
+  gst_structure_free (config);
+
+  return ret;
+}
+
+GstCaps *
+gst_v4l2_object_get_current_caps (GstV4l2Object * v4l2object)
+{
+  GstStructure *config;
+  GstCaps *oldcaps;
+
+  if (!v4l2object->pool)
+    return NULL;
+
+  config = gst_buffer_pool_get_config (v4l2object->pool);
+  gst_buffer_pool_config_get_params (config, &oldcaps, NULL, NULL, NULL);
+
+  if (oldcaps)
+    gst_caps_ref (oldcaps);
+
+  gst_structure_free (config);
+
+  return oldcaps;
+}
+
+gboolean
 gst_v4l2_object_unlock (GstV4l2Object * v4l2object)
 {
   gboolean ret = TRUE;
diff --git a/sys/v4l2/gstv4l2object.h b/sys/v4l2/gstv4l2object.h
index 9097a48..7871eaf 100644
--- a/sys/v4l2/gstv4l2object.h
+++ b/sys/v4l2/gstv4l2object.h
@@ -278,7 +278,9 @@
 gboolean     gst_v4l2_object_set_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
 gboolean     gst_v4l2_object_try_format  (GstV4l2Object * v4l2object, GstCaps * caps, GstV4l2Error * error);
 
-gboolean     gst_v4l2_object_caps_equal  (GstV4l2Object * v4l2object, GstCaps * caps);
+gboolean     gst_v4l2_object_caps_equal       (GstV4l2Object * v4l2object, GstCaps * caps);
+gboolean     gst_v4l2_object_caps_is_subset   (GstV4l2Object * v4l2object, GstCaps * caps);
+GstCaps *    gst_v4l2_object_get_current_caps (GstV4l2Object * v4l2object);
 
 gboolean     gst_v4l2_object_unlock      (GstV4l2Object * v4l2object);
 gboolean     gst_v4l2_object_unlock_stop (GstV4l2Object * v4l2object);
diff --git a/sys/v4l2/gstv4l2src.c b/sys/v4l2/gstv4l2src.c
index aba4496..88c813f 100644
--- a/sys/v4l2/gstv4l2src.c
+++ b/sys/v4l2/gstv4l2src.c
@@ -447,6 +447,14 @@
     fcaps = gst_caps_copy_nth (caps, i);
 
     if (GST_V4L2_IS_ACTIVE (obj)) {
+      /* try hard to avoid TRY_FMT since some UVC camera just crash when this
+       * is called at run-time. */
+      if (gst_v4l2_object_caps_is_subset (obj, fcaps)) {
+        gst_caps_unref (fcaps);
+        fcaps = gst_v4l2_object_get_current_caps (obj);
+        break;
+      }
+
       /* Just check if the format is acceptable, once we know
        * no buffers should be outstanding we try S_FMT.
        *