urisourcebin: Set source element to READY before querying it
authorEdward Hervey <edward@centricular.com>
Tue, 31 Jan 2023 15:12:17 +0000 (16:12 +0100)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Tue, 18 Jul 2023 14:45:12 +0000 (14:45 +0000)
Generating the source element is done when urisourcebin is doing the READY to
PAUSED state change, so it is reasonable to set the new source element to that
state.

This also allows detecting early failures with backing libraries or
hardware (checks done in NULL->READY).

Finally it makes more sense to have an element in READY when attempting to query
information from it (such as SCHEDULING queries or probing live-ness).

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5058>

subprojects/gst-plugins-base/gst/playback/gsturisourcebin.c

index a37653030d1fb3dbbcd0c06808b663b9488591f7..55aaee36dc5b751557716f8644b9873410fa5585 100644 (file)
@@ -1465,8 +1465,6 @@ gen_source_element (GstURISourceBin * urisrc)
   GObjectClass *source_class;
   GstElement *source;
   GParamSpec *pspec;
-  GstQuery *query;
-  GstSchedulingFlags flags;
   GError *err = NULL;
 
   if (!urisrc->uri)
@@ -1486,31 +1484,9 @@ gen_source_element (GstURISourceBin * urisrc)
 
   GST_LOG_OBJECT (urisrc, "found source type %s", G_OBJECT_TYPE_NAME (source));
 
-  urisrc->is_stream = IS_STREAM_URI (urisrc->uri);
-
-  query = gst_query_new_scheduling ();
-  if (gst_element_query (source, query)) {
-    gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
-    if ((flags & GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED))
-      urisrc->is_stream = TRUE;
-  }
-  gst_query_unref (query);
-
   source_class = G_OBJECT_GET_CLASS (source);
 
-  if (urisrc->is_stream) {
-    /* Live sources are not streamable */
-    pspec = g_object_class_find_property (source_class, "is-live");
-    if (pspec && G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN) {
-      gboolean is_live;
-      g_object_get (G_OBJECT (source), "is-live", &is_live, NULL);
-      if (is_live)
-        urisrc->is_stream = FALSE;
-    }
-  }
-
-  GST_LOG_OBJECT (urisrc, "source is stream: %d", urisrc->is_stream);
-
+  /* Propagate connection speed */
   pspec = g_object_class_find_property (source_class, "connection-speed");
   if (pspec != NULL) {
     guint64 speed = urisrc->connection_speed / 1000;
@@ -1750,6 +1726,38 @@ analyse_source_and_expose_raw_pads (GstURISourceBin * urisrc,
   GstIterator *pads_iter;
   gboolean res = TRUE;
 
+  /* Collect generic information about the source */
+
+  urisrc->is_stream = IS_STREAM_URI (urisrc->uri);
+
+  if (!urisrc->is_stream) {
+    GstQuery *query;
+    GstSchedulingFlags flags;
+    /* do a final check to see if the source element is streamable */
+    query = gst_query_new_scheduling ();
+    if (gst_element_query (urisrc->source, query)) {
+      gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
+      if ((flags & GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED))
+        urisrc->is_stream = TRUE;
+    }
+    gst_query_unref (query);
+  }
+
+  if (urisrc->is_stream) {
+    GObjectClass *source_class = G_OBJECT_GET_CLASS (urisrc->source);
+    GParamSpec *pspec = g_object_class_find_property (source_class, "is-live");
+    /* Live sources are not streamable */
+    if (pspec && G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_BOOLEAN) {
+      gboolean is_live;
+      g_object_get (G_OBJECT (urisrc->source), "is-live", &is_live, NULL);
+      if (is_live)
+        urisrc->is_stream = FALSE;
+    }
+  }
+
+  GST_LOG_OBJECT (urisrc, "source is stream: %d", urisrc->is_stream);
+
+  /* Handle the existing source pads */
   pads_iter = gst_element_iterate_src_pads (urisrc->source);
 
 restart:
@@ -2285,12 +2293,16 @@ setup_source (GstURISourceBin * urisrc)
    * handled by the application right after. */
   gst_bin_add (GST_BIN_CAST (urisrc), urisrc->source);
 
-  /* notify of the new source used */
+  /* notify of the new source used and allow external users to do final
+   * modifications before activating the element */
   g_object_notify (G_OBJECT (urisrc), "source");
 
   g_signal_emit (urisrc, gst_uri_source_bin_signals[SIGNAL_SOURCE_SETUP],
       0, urisrc->source);
 
+  if (gst_element_set_state (urisrc->source,
+          GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS)
+    goto state_fail;
   /* see if the source element emits raw audio/video all by itself,
    * if so, we can create streams for the pads and be done with it.
    * Also check that is has source pads, if not, we assume it will
@@ -2323,6 +2335,12 @@ invalid_source:
         (_("Source element is invalid.")), (NULL));
     return FALSE;
   }
+state_fail:
+  {
+    GST_ELEMENT_ERROR (urisrc, CORE, FAILED,
+        (_("Source element can't be prepared")), (NULL));
+    return FALSE;
+  }
 no_pads:
   {
     GST_ELEMENT_ERROR (urisrc, CORE, FAILED,