play: Add stream-id based selection of streams to match better playbin3's API
authorSebastian Dröge <sebastian@centricular.com>
Thu, 10 Oct 2024 19:08:33 +0000 (15:08 -0400)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 27 Dec 2024 19:00:18 +0000 (19:00 +0000)
As part of this

  - Add accessors for the stream ID and selection API based on the
    stream ID
  - Deprecate the old index-based APIs
  - Remove playbin support
  - Implement the track enable API based on stream selection

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

girs/GstPlay-1.0.gir
subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info-private.h
subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c
subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.h
subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c
subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h

index 796b6640ce05dddd73cc5c0e35bb37894dc1b514..40bb287587fc85024d7817fc63f7da58eaf7a8e4 100644 (file)
@@ -981,7 +981,8 @@ in nanoseconds.</doc>
           </parameter>
         </parameters>
       </method>
-      <method name="set_audio_track" c:identifier="gst_play_set_audio_track" version="1.20">
+      <method name="set_audio_track" c:identifier="gst_play_set_audio_track" version="1.20" deprecated="1" deprecated-version="1.26">
+        <doc-deprecated xml:space="preserve">Use gst_play_set_audio_track_id() instead.</doc-deprecated>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
         <return-value transfer-ownership="none">
           <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
@@ -1017,6 +1018,25 @@ Sets the audio track @stream_index.</doc>
           </parameter>
         </parameters>
       </method>
+      <method name="set_audio_track_id" c:identifier="gst_play_set_audio_track_id" version="1.26">
+        <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
+        <return-value transfer-ownership="none">
+          <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
+
+Sets the audio track @stream_id.</doc>
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="play" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">#GstPlay instance</doc>
+            <type name="Play" c:type="GstPlay*"/>
+          </instance-parameter>
+          <parameter name="stream_id" transfer-ownership="none" nullable="1" allow-none="1">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">stream id</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
       <method name="set_audio_video_offset" c:identifier="gst_play_set_audio_video_offset" glib:set-property="audio-video-offset" version="1.20">
         <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Sets audio-video-offset property by value of @offset</doc>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
@@ -1152,7 +1172,8 @@ value.</doc>
           </parameter>
         </parameters>
       </method>
-      <method name="set_subtitle_track" c:identifier="gst_play_set_subtitle_track" version="1.20">
+      <method name="set_subtitle_track" c:identifier="gst_play_set_subtitle_track" version="1.20" deprecated="1" deprecated-version="1.26">
+        <doc-deprecated xml:space="preserve">Use gst_play_set_subtitle_track_id() instead.</doc-deprecated>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
         <return-value transfer-ownership="none">
           <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
@@ -1188,6 +1209,25 @@ Sets the subtitle stack @stream_index.</doc>
           </parameter>
         </parameters>
       </method>
+      <method name="set_subtitle_track_id" c:identifier="gst_play_set_subtitle_track_id" version="1.26">
+        <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
+        <return-value transfer-ownership="none">
+          <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
+
+Sets the subtitle track @stream_id.</doc>
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="play" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">#GstPlay instance</doc>
+            <type name="Play" c:type="GstPlay*"/>
+          </instance-parameter>
+          <parameter name="stream_id" transfer-ownership="none" nullable="1" allow-none="1">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">stream id</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
       <method name="set_subtitle_uri" c:identifier="gst_play_set_subtitle_uri" version="1.20">
         <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Sets the external subtitle URI. This should be combined with a call to
 gst_play_set_subtitle_track_enabled(@play, TRUE) so the subtitles are actually
@@ -1224,6 +1264,34 @@ rendered.</doc>
           </parameter>
         </parameters>
       </method>
+      <method name="set_track_ids" c:identifier="gst_play_set_track_ids" version="1.26">
+        <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
+        <return-value transfer-ownership="none">
+          <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
+
+Sets the selected track stream ids. Setting %NULL as stream id disables the
+corresponding track.</doc>
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="play" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">#GstPlay instance</doc>
+            <type name="Play" c:type="GstPlay*"/>
+          </instance-parameter>
+          <parameter name="audio_stream_id" transfer-ownership="none" nullable="1" allow-none="1">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">audio stream id</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+          <parameter name="video_stream_id" transfer-ownership="none" nullable="1" allow-none="1">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">video stream id</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+          <parameter name="subtitle_stream_id" transfer-ownership="none" nullable="1" allow-none="1">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">subtitle stream id</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
       <method name="set_uri" c:identifier="gst_play_set_uri" glib:set-property="uri" version="1.20">
         <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Sets the next URI to play.</doc>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
@@ -1241,7 +1309,8 @@ rendered.</doc>
           </parameter>
         </parameters>
       </method>
-      <method name="set_video_track" c:identifier="gst_play_set_video_track" version="1.20">
+      <method name="set_video_track" c:identifier="gst_play_set_video_track" version="1.20" deprecated="1" deprecated-version="1.26">
+        <doc-deprecated xml:space="preserve">Use gst_play_set_video_track_id() instead.</doc-deprecated>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
         <return-value transfer-ownership="none">
           <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
@@ -1277,6 +1346,25 @@ Sets the video track @stream_index.</doc>
           </parameter>
         </parameters>
       </method>
+      <method name="set_video_track_id" c:identifier="gst_play_set_video_track_id" version="1.26">
+        <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
+        <return-value transfer-ownership="none">
+          <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">%TRUE or %FALSE
+
+Sets the video track @stream_id.</doc>
+          <type name="gboolean" c:type="gboolean"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="play" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">#GstPlay instance</doc>
+            <type name="Play" c:type="GstPlay*"/>
+          </instance-parameter>
+          <parameter name="stream_id" transfer-ownership="none" nullable="1" allow-none="1">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">stream id</doc>
+            <type name="utf8" c:type="const gchar*"/>
+          </parameter>
+        </parameters>
+      </method>
       <method name="set_visualization" c:identifier="gst_play_set_visualization" version="1.20">
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
         <return-value transfer-ownership="none">
@@ -1883,7 +1971,7 @@ See also #gst_play_get_message_bus()</doc-version>
         </parameters>
       </function>
       <function name="parse_error" c:identifier="gst_play_message_parse_error" version="1.20">
-        <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Parse the given error @msg and extract the corresponding #GError</doc>
+        <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Parse the given error @msg and extract the corresponding #GError.</doc>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
         <return-value transfer-ownership="none">
           <type name="none" c:type="void"/>
@@ -2377,9 +2465,10 @@ unknown.</doc>
           </instance-parameter>
         </parameters>
       </method>
-      <method name="get_index" c:identifier="gst_play_stream_info_get_index" version="1.20">
+      <method name="get_index" c:identifier="gst_play_stream_info_get_index" version="1.20" deprecated="1" deprecated-version="1.26">
         <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c">Function to get stream index from #GstPlayStreamInfo instance or -1 if
 unknown.</doc>
+        <doc-deprecated xml:space="preserve">Use gst_play_stream_info_get_stream_id().</doc-deprecated>
         <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.h"/>
         <return-value transfer-ownership="none">
           <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c">the stream index of this stream.</doc>
@@ -2392,6 +2481,20 @@ unknown.</doc>
           </instance-parameter>
         </parameters>
       </method>
+      <method name="get_stream_id" c:identifier="gst_play_stream_info_get_stream_id" version="1.26">
+        <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c">A string stream id identifying this #GstPlayStreamInfo.</doc>
+        <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.h"/>
+        <return-value transfer-ownership="none">
+          <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c">stream id string.</doc>
+          <type name="utf8" c:type="const gchar*"/>
+        </return-value>
+        <parameters>
+          <instance-parameter name="info" transfer-ownership="none">
+            <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c">a #GstPlayStreamInfo</doc>
+            <type name="PlayStreamInfo" c:type="const GstPlayStreamInfo*"/>
+          </instance-parameter>
+        </parameters>
+      </method>
       <method name="get_stream_type" c:identifier="gst_play_stream_info_get_stream_type" version="1.20">
         <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay-media-info.c">Function to return human readable name for the stream type
 of the given @info (ex: "audio", "video", "subtitle")</doc>
@@ -2896,7 +2999,7 @@ freed using gst_play_visualization_free().</doc>
       </parameters>
     </function>
     <function name="play_message_parse_error" c:identifier="gst_play_message_parse_error" moved-to="PlayMessage.parse_error" version="1.20">
-      <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Parse the given error @msg and extract the corresponding #GError</doc>
+      <doc xml:space="preserve" filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.c">Parse the given error @msg and extract the corresponding #GError.</doc>
       <source-position filename="../subprojects/gst-plugins-bad/gst-libs/gst/play/gstplay.h"/>
       <return-value transfer-ownership="none">
         <type name="none" c:type="void"/>
index a6ec7ee76ec7107f79dc7acd63b4d5165bec34d8..c93374fb00b2dd4c6ab1a7d53c25ab8e96c3d36c 100644 (file)
@@ -119,7 +119,7 @@ G_GNUC_INTERNAL GstPlayMediaInfo*   gst_play_media_info_new
 G_GNUC_INTERNAL GstPlayMediaInfo*   gst_play_media_info_copy
                                       (GstPlayMediaInfo *ref);
 G_GNUC_INTERNAL GstPlayStreamInfo*  gst_play_stream_info_new
-                                      (gint stream_index, GType type);
+                                      (gint stream_index, const gchar *stream_id, GType type);
 G_GNUC_INTERNAL GstPlayStreamInfo*  gst_play_stream_info_copy
                                       (GstPlayStreamInfo *ref);
 
index 65c73336640fa13e629570951953bfcd73487ee3..8b28d67171bb8345133d621cca7b5a76d53a8f3c 100644 (file)
@@ -74,6 +74,9 @@ gst_play_stream_info_class_init (GstPlayStreamInfoClass * klass)
  * unknown.
  *
  * Returns: the stream index of this stream.
+ *
+ * Deprecated: 1.26: Use gst_play_stream_info_get_stream_id().
+ *
  * Since: 1.20
  */
 gint
@@ -103,8 +106,11 @@ gst_play_stream_info_get_stream_type (const GstPlayStreamInfo * info)
     return "video";
   else if (GST_IS_PLAY_AUDIO_INFO (info))
     return "audio";
-  else
+  else if (GST_IS_PLAY_SUBTITLE_INFO (info))
     return "subtitle";
+  else
+    g_assert_not_reached ();
+  return NULL;
 }
 
 /**
@@ -139,6 +145,24 @@ gst_play_stream_info_get_codec (const GstPlayStreamInfo * info)
   return info->codec;
 }
 
+/**
+ * gst_play_stream_info_get_stream_id:
+ * @info: a #GstPlayStreamInfo
+ *
+ * A string stream id identifying this #GstPlayStreamInfo.
+ *
+ * Returns: stream id string.
+ *
+ * Since: 1.26
+ */
+const gchar *
+gst_play_stream_info_get_stream_id (const GstPlayStreamInfo * info)
+{
+  g_return_val_if_fail (GST_IS_PLAY_STREAM_INFO (info), NULL);
+
+  return info->stream_id;
+}
+
 /**
  * gst_play_stream_info_get_caps:
  * @info: a #GstPlayStreamInfo
@@ -610,7 +634,8 @@ gst_play_media_info_copy (GstPlayMediaInfo * ref)
 }
 
 GstPlayStreamInfo *
-gst_play_stream_info_new (gint stream_index, GType type)
+gst_play_stream_info_new (gint stream_index, const gchar * stream_id,
+    GType type)
 {
   GstPlayStreamInfo *info = NULL;
 
@@ -618,10 +643,13 @@ gst_play_stream_info_new (gint stream_index, GType type)
     info = (GstPlayStreamInfo *) gst_play_audio_info_new ();
   else if (type == GST_TYPE_PLAY_VIDEO_INFO)
     info = (GstPlayStreamInfo *) gst_play_video_info_new ();
-  else
+  else if (type == GST_TYPE_PLAY_SUBTITLE_INFO)
     info = (GstPlayStreamInfo *) gst_play_subtitle_info_new ();
+  else
+    g_assert_not_reached ();
 
   info->stream_index = stream_index;
+  info->stream_id = g_strdup (stream_id);
 
   return info;
 }
index b78698a0b2c879a48b5887b06f45389c683a64c8..4bcecc0919d366f812f85069c0e3e09494ba9472 100644 (file)
@@ -55,7 +55,7 @@ typedef struct _GstPlayStreamInfoClass GstPlayStreamInfoClass;
 GST_PLAY_API
 GType         gst_play_stream_info_get_type (void);
 
-GST_PLAY_API
+GST_PLAY_DEPRECATED_FOR(gst_play_stream_info_get_stream_id)
 gint          gst_play_stream_info_get_index (const GstPlayStreamInfo *info);
 
 GST_PLAY_API
@@ -70,6 +70,9 @@ GstCaps*      gst_play_stream_info_get_caps  (const GstPlayStreamInfo *info);
 GST_PLAY_API
 const gchar*  gst_play_stream_info_get_codec (const GstPlayStreamInfo *info);
 
+GST_PLAY_API
+const gchar*  gst_play_stream_info_get_stream_id (const GstPlayStreamInfo *info);
+
 /**
  * GST_TYPE_PLAY_VIDEO_INFO:
  * Since: 1.20
index 09227788f969d49b5f3a7909eaef5f392f54e8a3..5cd9170a9fe9d39b29f6ea459a3d5e028bfed43c 100644 (file)
@@ -89,9 +89,8 @@
 
 #include <gst/gst.h>
 #include <gst/video/video.h>
-#include <gst/video/colorbalance.h>
 #include <gst/tag/tag.h>
-#include <gst/pbutils/descriptions.h>
+#include <gst/pbutils/pbutils.h>
 
 #include <string.h>
 
@@ -195,12 +194,13 @@ struct _GstPlay
   GSource *seek_source;
   GstClockTime seek_position;
 
-  /* For playbin3 */
-  gboolean use_playbin3;
   GstStreamCollection *collection;
   gchar *video_sid;
+  gboolean video_enabled;
   gchar *audio_sid;
+  gboolean audio_enabled;
   gchar *subtitle_sid;
+  gboolean subtitle_enabled;
   gulong stream_notify_id;
 };
 
@@ -236,15 +236,9 @@ static void change_state (GstPlay * self, GstPlayState state);
 
 static GstPlayMediaInfo *gst_play_media_info_create (GstPlay * self);
 
-static void gst_play_streams_info_create (GstPlay * self,
-    GstPlayMediaInfo * media_info, const gchar * prop, GType type);
 static void gst_play_stream_info_update (GstPlay * self, GstPlayStreamInfo * s);
-static void gst_play_stream_info_update_tags_and_caps (GstPlay * self,
-    GstPlayStreamInfo * s);
 static GstPlayStreamInfo *gst_play_stream_info_find (GstPlayMediaInfo *
     media_info, GType type, gint stream_index);
-static GstPlayStreamInfo *gst_play_stream_info_get_current (GstPlay *
-    self, const gchar * prop, GType type);
 
 static void gst_play_video_info_update (GstPlay * self,
     GstPlayStreamInfo * stream_info);
@@ -253,6 +247,8 @@ static void gst_play_audio_info_update (GstPlay * self,
 static void gst_play_subtitle_info_update (GstPlay * self,
     GstPlayStreamInfo * stream_info);
 
+static gboolean gst_play_select_streams (GstPlay * self);
+
 /* For playbin3 */
 static void gst_play_streams_info_create_from_collection (GstPlay * self,
     GstPlayMediaInfo * media_info, GstStreamCollection * collection);
@@ -307,6 +303,10 @@ gst_play_init (GstPlay * self)
   self->cached_position = 0;
   self->cached_duration = GST_CLOCK_TIME_NONE;
 
+  self->audio_enabled = TRUE;
+  self->video_enabled = TRUE;
+  self->subtitle_enabled = TRUE;
+
   GST_TRACE_OBJECT (self, "Initialized");
 }
 
@@ -1630,7 +1630,7 @@ update_stream_collection (GstPlay * self, GstStreamCollection * collection)
       g_signal_connect (self->collection, "stream-notify",
       G_CALLBACK (stream_notify_cb), self);
 
-  return TRUE;
+  return self->media_info != NULL;
 }
 
 static void
@@ -1640,6 +1640,7 @@ stream_collection_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
   GstPlay *self = GST_PLAY (user_data);
   GstStreamCollection *collection = NULL;
   gboolean updated = FALSE;
+  gboolean do_default_selection;
 
   gst_message_parse_stream_collection (msg, &collection);
 
@@ -1647,8 +1648,39 @@ stream_collection_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
     return;
 
   g_mutex_lock (&self->lock);
+  do_default_selection = self->collection != NULL;
   updated = update_stream_collection (self, collection);
   gst_object_unref (collection);
+
+  if (do_default_selection) {
+    gboolean select_audio = self->audio_enabled;
+    gboolean select_video = self->video_enabled;
+    gboolean select_subtitle = self->subtitle_enabled;
+    guint i, len;
+
+    GST_DEBUG_OBJECT (self, "Do initial default selection");
+    len = gst_stream_collection_get_size (collection);
+
+    for (i = 0; i < len; i++) {
+      GstStream *stream = gst_stream_collection_get_stream (collection, i);
+      GstStreamType stream_type = gst_stream_get_stream_type (stream);
+      const gchar *stream_id = gst_stream_get_stream_id (stream);
+
+      if ((stream_type & GST_STREAM_TYPE_AUDIO) && select_audio) {
+        self->audio_sid = g_strdup (stream_id);
+        select_audio = FALSE;
+      } else if ((stream_type & GST_STREAM_TYPE_VIDEO) && select_video) {
+        self->video_sid = g_strdup (stream_id);
+        select_video = FALSE;
+      } else if ((stream_type & GST_STREAM_TYPE_TEXT) && select_subtitle) {
+        self->subtitle_sid = g_strdup (stream_id);
+        select_subtitle = FALSE;
+      }
+    }
+
+    gst_play_select_streams (self);
+  }
+
   g_mutex_unlock (&self->lock);
 
   if (self->media_info && updated)
@@ -1761,30 +1793,6 @@ on_media_info_updated (GstPlay * self)
   g_object_unref (media_info_copy);
 }
 
-static GstCaps *
-get_caps (GstPlay * self, gint stream_index, GType type)
-{
-  GstPad *pad = NULL;
-  GstCaps *caps = NULL;
-
-  if (type == GST_TYPE_PLAY_VIDEO_INFO)
-    g_signal_emit_by_name (G_OBJECT (self->playbin),
-        "get-video-pad", stream_index, &pad);
-  else if (type == GST_TYPE_PLAY_AUDIO_INFO)
-    g_signal_emit_by_name (G_OBJECT (self->playbin),
-        "get-audio-pad", stream_index, &pad);
-  else
-    g_signal_emit_by_name (G_OBJECT (self->playbin),
-        "get-text-pad", stream_index, &pad);
-
-  if (pad) {
-    caps = gst_pad_get_current_caps (pad);
-    gst_object_unref (pad);
-  }
-
-  return caps;
-}
-
 static void
 gst_play_subtitle_info_update (GstPlay * self, GstPlayStreamInfo * stream_info)
 {
@@ -1819,21 +1827,13 @@ gst_play_subtitle_info_update (GstPlay * self, GstPlayStreamInfo * stream_info)
      * external subtitle and use the filename.
      */
     if (!info->language) {
-      gint text_index = -1;
       gchar *suburi = NULL;
 
       g_object_get (G_OBJECT (self->playbin), "current-suburi", &suburi, NULL);
       if (suburi) {
-        if (self->use_playbin3) {
-          if (self->subtitle_sid &&
-              g_str_equal (self->subtitle_sid, stream_info->stream_id)) {
-            info->language = g_path_get_basename (suburi);
-          }
-        } else {
-          g_object_get (G_OBJECT (self->playbin), "current-text", &text_index,
-              NULL);
-          if (text_index == gst_play_stream_info_get_index (stream_info))
-            info->language = g_path_get_basename (suburi);
+        if (self->subtitle_sid &&
+            g_str_equal (self->subtitle_sid, stream_info->stream_id)) {
+          info->language = g_path_get_basename (suburi);
         }
         g_free (suburi);
       }
@@ -2006,7 +2006,7 @@ gst_play_stream_info_find (GstPlayMediaInfo * media_info,
   for (l = list; l != NULL; l = l->next) {
     info = (GstPlayStreamInfo *) l->data;
     if ((G_OBJECT_TYPE (info) == type) && (info->stream_index == stream_index)) {
-      return info;
+      return g_object_ref (info);
     }
   }
 
@@ -2047,26 +2047,6 @@ is_track_enabled (GstPlay * self, gint pos)
   return FALSE;
 }
 
-static GstPlayStreamInfo *
-gst_play_stream_info_get_current (GstPlay * self, const gchar * prop,
-    GType type)
-{
-  gint current;
-  GstPlayStreamInfo *info;
-
-  if (!self->media_info)
-    return NULL;
-
-  g_object_get (G_OBJECT (self->playbin), prop, &current, NULL);
-  g_mutex_lock (&self->lock);
-  info = gst_play_stream_info_find (self->media_info, type, current);
-  if (info)
-    info = gst_play_stream_info_copy (info);
-  g_mutex_unlock (&self->lock);
-
-  return info;
-}
-
 static GstPlayStreamInfo *
 gst_play_stream_info_get_current_from_stream_id (GstPlay * self,
     const gchar * stream_id, GType type)
@@ -2158,86 +2138,6 @@ stream_info_get_codec (GstPlayStreamInfo * s)
   return codec;
 }
 
-static void
-gst_play_stream_info_update_tags_and_caps (GstPlay * self,
-    GstPlayStreamInfo * s)
-{
-  GstTagList *tags;
-  gint stream_index;
-
-  stream_index = gst_play_stream_info_get_index (s);
-
-  if (GST_IS_PLAY_VIDEO_INFO (s))
-    g_signal_emit_by_name (self->playbin, "get-video-tags",
-        stream_index, &tags);
-  else if (GST_IS_PLAY_AUDIO_INFO (s))
-    g_signal_emit_by_name (self->playbin, "get-audio-tags",
-        stream_index, &tags);
-  else
-    g_signal_emit_by_name (self->playbin, "get-text-tags", stream_index, &tags);
-
-  if (s->tags)
-    gst_tag_list_unref (s->tags);
-  s->tags = tags;
-
-  if (s->caps)
-    gst_caps_unref (s->caps);
-  s->caps = get_caps (self, stream_index, G_OBJECT_TYPE (s));
-
-  g_free (s->codec);
-  s->codec = stream_info_get_codec (s);
-
-  GST_DEBUG_OBJECT (self, "%s index: %d tags: %p caps: %p",
-      gst_play_stream_info_get_stream_type (s), stream_index, s->tags, s->caps);
-
-  gst_play_stream_info_update (self, s);
-}
-
-static void
-gst_play_streams_info_create (GstPlay * self,
-    GstPlayMediaInfo * media_info, const gchar * prop, GType type)
-{
-  gint i;
-  gint total = -1;
-  GstPlayStreamInfo *s;
-
-  if (!media_info)
-    return;
-
-  g_object_get (G_OBJECT (self->playbin), prop, &total, NULL);
-
-  GST_DEBUG_OBJECT (self, "%s: %d", prop, total);
-
-  for (i = 0; i < total; i++) {
-    /* check if stream already exist in the list */
-    s = gst_play_stream_info_find (media_info, type, i);
-
-    if (!s) {
-      /* create a new stream info instance */
-      s = gst_play_stream_info_new (i, type);
-
-      /* add the object in stream list */
-      media_info->stream_list = g_list_append (media_info->stream_list, s);
-
-      /* based on type, add the object in its corresponding stream_ list */
-      if (GST_IS_PLAY_AUDIO_INFO (s))
-        media_info->audio_stream_list = g_list_append
-            (media_info->audio_stream_list, s);
-      else if (GST_IS_PLAY_VIDEO_INFO (s))
-        media_info->video_stream_list = g_list_append
-            (media_info->video_stream_list, s);
-      else
-        media_info->subtitle_stream_list = g_list_append
-            (media_info->subtitle_stream_list, s);
-
-      GST_DEBUG_OBJECT (self, "create %s stream stream_index: %d",
-          gst_play_stream_info_get_stream_type (s), i);
-    }
-
-    gst_play_stream_info_update_tags_and_caps (self, s);
-  }
-}
-
 static void
 gst_play_stream_info_update_from_stream (GstPlay * self,
     GstPlayStreamInfo * s, GstStream * stream)
@@ -2253,9 +2153,8 @@ gst_play_stream_info_update_from_stream (GstPlay * self,
   g_free (s->codec);
   s->codec = stream_info_get_codec (s);
 
-  GST_DEBUG_OBJECT (self, "%s index: %d tags: %p caps: %p",
-      gst_play_stream_info_get_stream_type (s), s->stream_index,
-      s->tags, s->caps);
+  GST_DEBUG_OBJECT (self, "%s stream id: %s tags: %p caps: %p",
+      gst_play_stream_info_get_stream_type (s), s->stream_id, s->tags, s->caps);
 
   gst_play_stream_info_update (self, s);
 }
@@ -2282,21 +2181,22 @@ gst_play_streams_info_create_from_collection (GstPlay * self,
     const gchar *stream_id = gst_stream_get_stream_id (stream);
 
     if (stream_type & GST_STREAM_TYPE_AUDIO) {
-      s = gst_play_stream_info_new (n_audio, GST_TYPE_PLAY_AUDIO_INFO);
+      s = gst_play_stream_info_new (n_audio, stream_id,
+          GST_TYPE_PLAY_AUDIO_INFO);
       n_audio++;
     } else if (stream_type & GST_STREAM_TYPE_VIDEO) {
-      s = gst_play_stream_info_new (n_video, GST_TYPE_PLAY_VIDEO_INFO);
+      s = gst_play_stream_info_new (n_video, stream_id,
+          GST_TYPE_PLAY_VIDEO_INFO);
       n_video++;
     } else if (stream_type & GST_STREAM_TYPE_TEXT) {
-      s = gst_play_stream_info_new (n_text, GST_TYPE_PLAY_SUBTITLE_INFO);
+      s = gst_play_stream_info_new (n_text, stream_id,
+          GST_TYPE_PLAY_SUBTITLE_INFO);
       n_text++;
     } else {
       GST_DEBUG_OBJECT (self, "Unknown type stream %d", i);
       continue;
     }
 
-    s->stream_id = g_strdup (stream_id);
-
     /* add the object in stream list */
     media_info->stream_list = g_list_append (media_info->stream_list, s);
 
@@ -2311,46 +2211,13 @@ gst_play_streams_info_create_from_collection (GstPlay * self,
       media_info->subtitle_stream_list = g_list_append
           (media_info->subtitle_stream_list, s);
 
-    GST_DEBUG_OBJECT (self, "create %s stream stream_index: %d",
-        gst_play_stream_info_get_stream_type (s), s->stream_index);
+    GST_DEBUG_OBJECT (self, "create %s stream id %s",
+        gst_play_stream_info_get_stream_type (s), s->stream_id);
 
     gst_play_stream_info_update_from_stream (self, s, stream);
   }
 }
 
-static void
-video_changed_cb (G_GNUC_UNUSED GObject * object, gpointer user_data)
-{
-  GstPlay *self = GST_PLAY (user_data);
-
-  g_mutex_lock (&self->lock);
-  gst_play_streams_info_create (self, self->media_info,
-      "n-video", GST_TYPE_PLAY_VIDEO_INFO);
-  g_mutex_unlock (&self->lock);
-}
-
-static void
-audio_changed_cb (G_GNUC_UNUSED GObject * object, gpointer user_data)
-{
-  GstPlay *self = GST_PLAY (user_data);
-
-  g_mutex_lock (&self->lock);
-  gst_play_streams_info_create (self, self->media_info,
-      "n-audio", GST_TYPE_PLAY_AUDIO_INFO);
-  g_mutex_unlock (&self->lock);
-}
-
-static void
-subtitle_changed_cb (G_GNUC_UNUSED GObject * object, gpointer user_data)
-{
-  GstPlay *self = GST_PLAY (user_data);
-
-  g_mutex_lock (&self->lock);
-  gst_play_streams_info_create (self, self->media_info,
-      "n-text", GST_TYPE_PLAY_SUBTITLE_INFO);
-  g_mutex_unlock (&self->lock);
-}
-
 static void *
 get_title (GstTagList * tags)
 {
@@ -2451,18 +2318,8 @@ gst_play_media_info_create (GstPlay * self)
     gst_query_parse_seeking (query, NULL, &media_info->seekable, NULL, NULL);
   gst_query_unref (query);
 
-  if (self->use_playbin3) {
-    gst_play_streams_info_create_from_collection (self, media_info,
-        self->collection);
-  } else {
-    /* create audio/video/sub streams */
-    gst_play_streams_info_create (self, media_info, "n-video",
-        GST_TYPE_PLAY_VIDEO_INFO);
-    gst_play_streams_info_create (self, media_info, "n-audio",
-        GST_TYPE_PLAY_AUDIO_INFO);
-    gst_play_streams_info_create (self, media_info, "n-text",
-        GST_TYPE_PLAY_SUBTITLE_INFO);
-  }
+  gst_play_streams_info_create_from_collection (self, media_info,
+      self->collection);
 
   media_info->title = get_from_tags (self, media_info, get_title);
   media_info->container =
@@ -2479,47 +2336,6 @@ gst_play_media_info_create (GstPlay * self)
   return media_info;
 }
 
-static void
-tags_changed_cb (GstPlay * self, gint stream_index, GType type)
-{
-  GstPlayStreamInfo *s;
-
-  if (!self->media_info)
-    return;
-
-  /* update the stream information */
-  g_mutex_lock (&self->lock);
-  s = gst_play_stream_info_find (self->media_info, type, stream_index);
-  gst_play_stream_info_update_tags_and_caps (self, s);
-  g_mutex_unlock (&self->lock);
-
-  on_media_info_updated (self);
-}
-
-static void
-video_tags_changed_cb (G_GNUC_UNUSED GstElement * playbin, gint stream_index,
-    gpointer user_data)
-{
-  tags_changed_cb (GST_PLAY (user_data), stream_index,
-      GST_TYPE_PLAY_VIDEO_INFO);
-}
-
-static void
-audio_tags_changed_cb (G_GNUC_UNUSED GstElement * playbin, gint stream_index,
-    gpointer user_data)
-{
-  tags_changed_cb (GST_PLAY (user_data), stream_index,
-      GST_TYPE_PLAY_AUDIO_INFO);
-}
-
-static void
-subtitle_tags_changed_cb (G_GNUC_UNUSED GstElement * playbin, gint stream_index,
-    gpointer user_data)
-{
-  tags_changed_cb (GST_PLAY (user_data), stream_index,
-      GST_TYPE_PLAY_SUBTITLE_INFO);
-}
-
 static void
 volume_notify_cb (G_GNUC_UNUSED GObject * obj, G_GNUC_UNUSED GParamSpec * pspec,
     GstPlay * self)
@@ -2566,7 +2382,6 @@ gst_play_main (gpointer data)
   GstBus *bus;
   GSource *source;
   GstElement *scaletempo;
-  const gchar *env;
 
   GST_TRACE_OBJECT (self, "Starting main thread");
 
@@ -2578,21 +2393,9 @@ gst_play_main (gpointer data)
   g_source_attach (source, self->context);
   g_source_unref (source);
 
-  env = g_getenv ("GST_PLAY_USE_PLAYBIN3");
-  if (env && g_str_has_prefix (env, "0"))
-    self->use_playbin3 = FALSE;
-  else
-    self->use_playbin3 = TRUE;
-
-  if (self->use_playbin3) {
-    GST_DEBUG_OBJECT (self, "playbin3 enabled");
-    self->playbin = gst_element_factory_make ("playbin3", "playbin3");
-  } else {
-    self->playbin = gst_element_factory_make ("playbin", "playbin");
-  }
-
+  self->playbin = gst_element_factory_make ("playbin3", "playbin3");
   if (!self->playbin) {
-    g_error ("GstPlay: 'playbin' element not found, please check your setup");
+    g_error ("GstPlay: 'playbin3' element not found, please check your setup");
     g_assert_not_reached ();
   }
 
@@ -2613,6 +2416,7 @@ gst_play_main (gpointer data)
   self->bus = bus = gst_element_get_bus (self->playbin);
   gst_object_set_name (GST_OBJECT (self->bus), "playbin_bus");
   gst_bus_add_signal_watch (bus);
+  gst_bus_enable_sync_message_emission (bus);
 
   g_signal_connect (G_OBJECT (bus), "message::error", G_CALLBACK (error_cb),
       self);
@@ -2634,28 +2438,10 @@ gst_play_main (gpointer data)
   g_signal_connect (G_OBJECT (bus), "message::element",
       G_CALLBACK (element_cb), self);
   g_signal_connect (G_OBJECT (bus), "message::tag", G_CALLBACK (tags_cb), self);
-
-  if (self->use_playbin3) {
-    g_signal_connect (G_OBJECT (bus), "message::stream-collection",
-        G_CALLBACK (stream_collection_cb), self);
-    g_signal_connect (G_OBJECT (bus), "message::streams-selected",
-        G_CALLBACK (streams_selected_cb), self);
-  } else {
-    g_signal_connect (self->playbin, "video-changed",
-        G_CALLBACK (video_changed_cb), self);
-    g_signal_connect (self->playbin, "audio-changed",
-        G_CALLBACK (audio_changed_cb), self);
-    g_signal_connect (self->playbin, "text-changed",
-        G_CALLBACK (subtitle_changed_cb), self);
-
-    g_signal_connect (self->playbin, "video-tags-changed",
-        G_CALLBACK (video_tags_changed_cb), self);
-    g_signal_connect (self->playbin, "audio-tags-changed",
-        G_CALLBACK (audio_tags_changed_cb), self);
-    g_signal_connect (self->playbin, "text-tags-changed",
-        G_CALLBACK (subtitle_tags_changed_cb), self);
-  }
-
+  g_signal_connect (G_OBJECT (bus), "sync-message::stream-collection",
+      G_CALLBACK (stream_collection_cb), self);
+  g_signal_connect (G_OBJECT (bus), "sync-message::streams-selected",
+      G_CALLBACK (streams_selected_cb), self);
   g_signal_connect (self->playbin, "notify::volume",
       G_CALLBACK (volume_notify_cb), self);
   g_signal_connect (self->playbin, "notify::mute",
@@ -3453,14 +3239,9 @@ gst_play_get_current_audio_track (GstPlay * self)
   if (!is_track_enabled (self, GST_PLAY_FLAG_AUDIO))
     return NULL;
 
-  if (self->use_playbin3) {
-    info = (GstPlayAudioInfo *)
-        gst_play_stream_info_get_current_from_stream_id (self,
-        self->audio_sid, GST_TYPE_PLAY_AUDIO_INFO);
-  } else {
-    info = (GstPlayAudioInfo *) gst_play_stream_info_get_current (self,
-        "current-audio", GST_TYPE_PLAY_AUDIO_INFO);
-  }
+  info = (GstPlayAudioInfo *)
+      gst_play_stream_info_get_current_from_stream_id (self,
+      self->audio_sid, GST_TYPE_PLAY_AUDIO_INFO);
 
   return info;
 }
@@ -3486,14 +3267,9 @@ gst_play_get_current_video_track (GstPlay * self)
   if (!is_track_enabled (self, GST_PLAY_FLAG_VIDEO))
     return NULL;
 
-  if (self->use_playbin3) {
-    info = (GstPlayVideoInfo *)
-        gst_play_stream_info_get_current_from_stream_id (self,
-        self->video_sid, GST_TYPE_PLAY_VIDEO_INFO);
-  } else {
-    info = (GstPlayVideoInfo *) gst_play_stream_info_get_current (self,
-        "current-video", GST_TYPE_PLAY_VIDEO_INFO);
-  }
+  info = (GstPlayVideoInfo *)
+      gst_play_stream_info_get_current_from_stream_id (self,
+      self->video_sid, GST_TYPE_PLAY_VIDEO_INFO);
 
   return info;
 }
@@ -3519,14 +3295,9 @@ gst_play_get_current_subtitle_track (GstPlay * self)
   if (!is_track_enabled (self, GST_PLAY_FLAG_SUBTITLE))
     return NULL;
 
-  if (self->use_playbin3) {
-    info = (GstPlaySubtitleInfo *)
-        gst_play_stream_info_get_current_from_stream_id (self,
-        self->subtitle_sid, GST_TYPE_PLAY_SUBTITLE_INFO);
-  } else {
-    info = (GstPlaySubtitleInfo *) gst_play_stream_info_get_current (self,
-        "current-text", GST_TYPE_PLAY_SUBTITLE_INFO);
-  }
+  info = (GstPlaySubtitleInfo *)
+      gst_play_stream_info_get_current_from_stream_id (self,
+      self->subtitle_sid, GST_TYPE_PLAY_SUBTITLE_INFO);
 
   return info;
 }
@@ -3538,11 +3309,11 @@ gst_play_select_streams (GstPlay * self)
   GList *stream_list = NULL;
   gboolean ret = FALSE;
 
-  if (self->audio_sid)
+  if (self->audio_sid && self->audio_enabled)
     stream_list = g_list_append (stream_list, g_strdup (self->audio_sid));
-  if (self->video_sid)
+  if (self->video_sid && self->video_enabled)
     stream_list = g_list_append (stream_list, g_strdup (self->video_sid));
-  if (self->subtitle_sid)
+  if (self->subtitle_sid && self->subtitle_enabled)
     stream_list = g_list_append (stream_list, g_strdup (self->subtitle_sid));
 
   g_mutex_unlock (&self->lock);
@@ -3566,6 +3337,9 @@ gst_play_select_streams (GstPlay * self)
  * Returns: %TRUE or %FALSE
  *
  * Sets the audio track @stream_index.
+ *
+ * Deprecated: 1.26: Use gst_play_set_audio_track_id() instead.
+ *
  * Since: 1.20
  */
 gboolean
@@ -3574,29 +3348,24 @@ gst_play_set_audio_track (GstPlay * self, gint stream_index)
   GstPlayStreamInfo *info;
   gboolean ret = TRUE;
 
-  g_return_val_if_fail (GST_IS_PLAY (self), 0);
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
 
   g_mutex_lock (&self->lock);
   info = gst_play_stream_info_find (self->media_info,
       GST_TYPE_PLAY_AUDIO_INFO, stream_index);
-  g_mutex_unlock (&self->lock);
   if (!info) {
     GST_ERROR_OBJECT (self, "invalid audio stream index %d", stream_index);
+    g_mutex_unlock (&self->lock);
     return FALSE;
   }
 
-  if (self->use_playbin3) {
-    g_mutex_lock (&self->lock);
-    g_free (self->audio_sid);
-    self->audio_sid = g_strdup (info->stream_id);
-    ret = gst_play_select_streams (self);
-    g_mutex_unlock (&self->lock);
-  } else {
-    g_object_set (G_OBJECT (self->playbin), "current-audio", stream_index,
-        NULL);
-  }
+  g_free (self->audio_sid);
+  self->audio_sid = g_strdup (info->stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+  GST_DEBUG_OBJECT (self, "set stream id '%s'", info->stream_id);
+  g_object_unref (info);
 
-  GST_DEBUG_OBJECT (self, "set stream index '%d'", stream_index);
   return ret;
 }
 
@@ -3608,6 +3377,9 @@ gst_play_set_audio_track (GstPlay * self, gint stream_index)
  * Returns: %TRUE or %FALSE
  *
  * Sets the video track @stream_index.
+ *
+ * Deprecated: 1.26: Use gst_play_set_video_track_id() instead.
+ *
  * Since: 1.20
  */
 gboolean
@@ -3616,30 +3388,25 @@ gst_play_set_video_track (GstPlay * self, gint stream_index)
   GstPlayStreamInfo *info;
   gboolean ret = TRUE;
 
-  g_return_val_if_fail (GST_IS_PLAY (self), 0);
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
 
   /* check if stream_index exist in our internal media_info list */
   g_mutex_lock (&self->lock);
   info = gst_play_stream_info_find (self->media_info,
       GST_TYPE_PLAY_VIDEO_INFO, stream_index);
-  g_mutex_unlock (&self->lock);
   if (!info) {
     GST_ERROR_OBJECT (self, "invalid video stream index %d", stream_index);
+    g_mutex_unlock (&self->lock);
     return FALSE;
   }
 
-  if (self->use_playbin3) {
-    g_mutex_lock (&self->lock);
-    g_free (self->video_sid);
-    self->video_sid = g_strdup (info->stream_id);
-    ret = gst_play_select_streams (self);
-    g_mutex_unlock (&self->lock);
-  } else {
-    g_object_set (G_OBJECT (self->playbin), "current-video", stream_index,
-        NULL);
-  }
+  g_free (self->video_sid);
+  self->video_sid = g_strdup (info->stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+  GST_DEBUG_OBJECT (self, "set stream id '%s'", info->stream_id);
+  g_object_unref (info);
 
-  GST_DEBUG_OBJECT (self, "set stream index '%d'", stream_index);
   return ret;
 }
 
@@ -3651,6 +3418,9 @@ gst_play_set_video_track (GstPlay * self, gint stream_index)
  * Returns: %TRUE or %FALSE
  *
  * Sets the subtitle stack @stream_index.
+ *
+ * Deprecated: 1.26: Use gst_play_set_subtitle_track_id() instead.
+ *
  * Since: 1.20
  */
 gboolean
@@ -3659,28 +3429,269 @@ gst_play_set_subtitle_track (GstPlay * self, gint stream_index)
   GstPlayStreamInfo *info;
   gboolean ret = TRUE;
 
-  g_return_val_if_fail (GST_IS_PLAY (self), 0);
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
 
   g_mutex_lock (&self->lock);
   info = gst_play_stream_info_find (self->media_info,
       GST_TYPE_PLAY_SUBTITLE_INFO, stream_index);
-  g_mutex_unlock (&self->lock);
   if (!info) {
     GST_ERROR_OBJECT (self, "invalid subtitle stream index %d", stream_index);
+    g_mutex_unlock (&self->lock);
     return FALSE;
   }
 
-  if (self->use_playbin3) {
-    g_mutex_lock (&self->lock);
-    g_free (self->subtitle_sid);
-    self->subtitle_sid = g_strdup (info->stream_id);
-    ret = gst_play_select_streams (self);
-    g_mutex_unlock (&self->lock);
-  } else {
-    g_object_set (G_OBJECT (self->playbin), "current-text", stream_index, NULL);
+  g_free (self->subtitle_sid);
+  self->subtitle_sid = g_strdup (info->stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+  GST_DEBUG_OBJECT (self, "set stream id '%s'", info->stream_id);
+  g_object_unref (info);
+
+  return ret;
+}
+
+/**
+ * gst_play_set_audio_track_id:
+ * @play: #GstPlay instance
+ * @stream_id: (nullable): stream id
+ *
+ * Returns: %TRUE or %FALSE
+ *
+ * Sets the audio track @stream_id.
+ *
+ * Since: 1.26
+ */
+gboolean
+gst_play_set_audio_track_id (GstPlay * self, const gchar * stream_id)
+{
+  gboolean ret = TRUE;
+
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
+
+  g_mutex_lock (&self->lock);
+  if (stream_id) {
+    GstPlayStreamInfo *info;
+
+    info = gst_play_stream_info_find_from_stream_id (self->media_info,
+        stream_id);
+    if (!info) {
+      GST_ERROR_OBJECT (self, "invalid audio stream id %s", stream_id);
+      g_mutex_unlock (&self->lock);
+      return FALSE;
+    }
+
+    if (!GST_IS_PLAY_AUDIO_INFO (info)) {
+      GST_ERROR_OBJECT (self, "invalid audio stream id %s", stream_id);
+      g_mutex_unlock (&self->lock);
+      g_object_unref (info);
+      return FALSE;
+    }
+    g_object_unref (info);
+  }
+
+  g_free (self->audio_sid);
+  self->audio_sid = g_strdup (stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+
+  GST_DEBUG_OBJECT (self, "set stream id '%s'", GST_STR_NULL (stream_id));
+  return ret;
+}
+
+/**
+ * gst_play_set_video_track_id:
+ * @play: #GstPlay instance
+ * @stream_id: (nullable): stream id
+ *
+ * Returns: %TRUE or %FALSE
+ *
+ * Sets the video track @stream_id.
+ *
+ * Since: 1.26
+ */
+gboolean
+gst_play_set_video_track_id (GstPlay * self, const gchar * stream_id)
+{
+  gboolean ret = TRUE;
+
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
+
+  g_mutex_lock (&self->lock);
+  if (stream_id) {
+    GstPlayStreamInfo *info;
+
+    info = gst_play_stream_info_find_from_stream_id (self->media_info,
+        stream_id);
+    if (!info) {
+      GST_ERROR_OBJECT (self, "invalid video stream index %s", stream_id);
+      g_mutex_unlock (&self->lock);
+      return FALSE;
+    }
+
+    if (!GST_IS_PLAY_VIDEO_INFO (info)) {
+      GST_ERROR_OBJECT (self, "invalid video stream id %s", stream_id);
+      g_mutex_unlock (&self->lock);
+      g_object_unref (info);
+      return FALSE;
+    }
+    g_object_unref (info);
   }
 
-  GST_DEBUG_OBJECT (self, "set stream index '%d'", stream_index);
+  g_free (self->video_sid);
+  self->video_sid = g_strdup (stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+
+  GST_DEBUG_OBJECT (self, "set stream id '%s'", GST_STR_NULL (stream_id));
+  return ret;
+}
+
+/**
+ * gst_play_set_subtitle_track_id:
+ * @play: #GstPlay instance
+ * @stream_id: (nullable): stream id
+ *
+ * Returns: %TRUE or %FALSE
+ *
+ * Sets the subtitle track @stream_id.
+ *
+ * Since: 1.26
+ */
+gboolean
+gst_play_set_subtitle_track_id (GstPlay * self, const gchar * stream_id)
+{
+  gboolean ret = TRUE;
+
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
+
+  g_mutex_lock (&self->lock);
+  if (stream_id) {
+    GstPlayStreamInfo *info;
+
+    info = gst_play_stream_info_find_from_stream_id (self->media_info,
+        stream_id);
+    if (!info) {
+      GST_ERROR_OBJECT (self, "invalid subtitle stream index %s", stream_id);
+      g_mutex_unlock (&self->lock);
+      return FALSE;
+    }
+
+    if (!GST_IS_PLAY_SUBTITLE_INFO (info)) {
+      GST_ERROR_OBJECT (self, "invalid subtile stream id %s", stream_id);
+      g_mutex_unlock (&self->lock);
+      g_object_unref (info);
+      return FALSE;
+    }
+    g_object_unref (info);
+  }
+
+  g_free (self->subtitle_sid);
+  self->subtitle_sid = g_strdup (stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+
+  GST_DEBUG_OBJECT (self, "set stream id '%s'", GST_STR_NULL (stream_id));
+  return ret;
+}
+
+/**
+ * gst_play_set_track_ids:
+ * @play: #GstPlay instance
+ * @audio_stream_id: (nullable): audio stream id
+ * @video_stream_id: (nullable): video stream id
+ * @subtitle_stream_id: (nullable): subtitle stream id
+ *
+ * Returns: %TRUE or %FALSE
+ *
+ * Sets the selected track stream ids. Setting %NULL as stream id disables the
+ * corresponding track.
+ *
+ * Since: 1.26
+ */
+gboolean
+gst_play_set_track_ids (GstPlay * self, const gchar * audio_stream_id,
+    const gchar * video_stream_id, const gchar * subtitle_stream_id)
+{
+  gboolean ret = TRUE;
+
+  g_return_val_if_fail (GST_IS_PLAY (self), FALSE);
+
+  g_mutex_lock (&self->lock);
+  if (audio_stream_id) {
+    GstPlayStreamInfo *info;
+
+    info = gst_play_stream_info_find_from_stream_id (self->media_info,
+        audio_stream_id);
+    if (!info) {
+      GST_ERROR_OBJECT (self, "invalid audio stream id %s", audio_stream_id);
+      g_mutex_unlock (&self->lock);
+      return FALSE;
+    }
+
+    if (!GST_IS_PLAY_AUDIO_INFO (info)) {
+      GST_ERROR_OBJECT (self, "invalid audio stream id %s", audio_stream_id);
+      g_mutex_unlock (&self->lock);
+      g_object_unref (info);
+      return FALSE;
+    }
+    g_object_unref (info);
+  }
+
+  if (video_stream_id) {
+    GstPlayStreamInfo *info;
+
+    info = gst_play_stream_info_find_from_stream_id (self->media_info,
+        video_stream_id);
+    if (!info) {
+      GST_ERROR_OBJECT (self, "invalid video stream index %s", video_stream_id);
+      g_mutex_unlock (&self->lock);
+      return FALSE;
+    }
+
+    if (!GST_IS_PLAY_VIDEO_INFO (info)) {
+      GST_ERROR_OBJECT (self, "invalid video stream id %s", video_stream_id);
+      g_mutex_unlock (&self->lock);
+      g_object_unref (info);
+      return FALSE;
+    }
+    g_object_unref (info);
+  }
+
+  if (subtitle_stream_id) {
+    GstPlayStreamInfo *info;
+
+    info = gst_play_stream_info_find_from_stream_id (self->media_info,
+        subtitle_stream_id);
+    if (!info) {
+      GST_ERROR_OBJECT (self, "invalid subtitle stream index %s",
+          subtitle_stream_id);
+      g_mutex_unlock (&self->lock);
+      return FALSE;
+    }
+
+    if (!GST_IS_PLAY_SUBTITLE_INFO (info)) {
+      GST_ERROR_OBJECT (self, "invalid subtile stream id %s",
+          subtitle_stream_id);
+      g_mutex_unlock (&self->lock);
+      g_object_unref (info);
+      return FALSE;
+    }
+    g_object_unref (info);
+  }
+
+  g_free (self->audio_sid);
+  self->audio_sid = g_strdup (audio_stream_id);
+  g_free (self->video_sid);
+  self->video_sid = g_strdup (video_stream_id);
+  g_free (self->subtitle_sid);
+  self->subtitle_sid = g_strdup (subtitle_stream_id);
+  ret = gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
+
+  GST_DEBUG_OBJECT (self, "set stream ids audio '%s' video '%s' subtitle '%s'",
+      GST_STR_NULL (audio_stream_id), GST_STR_NULL (video_stream_id),
+      GST_STR_NULL (subtitle_stream_id));
+
   return ret;
 }
 
@@ -3697,10 +3708,10 @@ gst_play_set_audio_track_enabled (GstPlay * self, gboolean enabled)
 {
   g_return_if_fail (GST_IS_PLAY (self));
 
-  if (enabled)
-    play_set_flag (self, GST_PLAY_FLAG_AUDIO);
-  else
-    play_clear_flag (self, GST_PLAY_FLAG_AUDIO);
+  g_mutex_lock (&self->lock);
+  self->audio_enabled = enabled;
+  gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
 
   GST_DEBUG_OBJECT (self, "track is '%s'", enabled ? "Enabled" : "Disabled");
 }
@@ -3718,10 +3729,10 @@ gst_play_set_video_track_enabled (GstPlay * self, gboolean enabled)
 {
   g_return_if_fail (GST_IS_PLAY (self));
 
-  if (enabled)
-    play_set_flag (self, GST_PLAY_FLAG_VIDEO);
-  else
-    play_clear_flag (self, GST_PLAY_FLAG_VIDEO);
+  g_mutex_lock (&self->lock);
+  self->video_enabled = enabled;
+  gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
 
   GST_DEBUG_OBJECT (self, "track is '%s'", enabled ? "Enabled" : "Disabled");
 }
@@ -3739,10 +3750,10 @@ gst_play_set_subtitle_track_enabled (GstPlay * self, gboolean enabled)
 {
   g_return_if_fail (GST_IS_PLAY (self));
 
-  if (enabled)
-    play_set_flag (self, GST_PLAY_FLAG_SUBTITLE);
-  else
-    play_clear_flag (self, GST_PLAY_FLAG_SUBTITLE);
+  g_mutex_lock (&self->lock);
+  self->subtitle_enabled = enabled;
+  gst_play_select_streams (self);
+  g_mutex_unlock (&self->lock);
 
   GST_DEBUG_OBJECT (self, "track is '%s'", enabled ? "Enabled" : "Disabled");
 }
@@ -4589,7 +4600,6 @@ GstSample *
 gst_play_get_video_snapshot (GstPlay * self,
     GstPlaySnapshotFormat format, const GstStructure * config)
 {
-  gint video_tracks = 0;
   GstPlayVideoInfo *video_info = NULL;
   GstSample *sample = NULL;
   GstCaps *caps = NULL;
@@ -4599,20 +4609,12 @@ gst_play_get_video_snapshot (GstPlay * self,
   gint par_d = 1;
   g_return_val_if_fail (GST_IS_PLAY (self), NULL);
 
-  if (self->use_playbin3) {
-    video_info = gst_play_get_current_video_track (self);
-    if (video_info == NULL) {
-      GST_DEBUG_OBJECT (self, "no current video track");
-      return NULL;
-    } else {
-      g_object_unref (video_info);
-    }
+  video_info = gst_play_get_current_video_track (self);
+  if (video_info == NULL) {
+    GST_DEBUG_OBJECT (self, "no current video track");
+    return NULL;
   } else {
-    g_object_get (self->playbin, "n-video", &video_tracks, NULL);
-    if (video_tracks == 0) {
-      GST_DEBUG_OBJECT (self, "total video track num is 0");
-      return NULL;
-    }
+    g_object_unref (video_info);
   }
 
   switch (format) {
@@ -4848,7 +4850,7 @@ gst_play_message_parse_buffering_percent (GstMessage * msg, guint * percent)
  * @error: (out) (optional) (transfer full): the resulting error
  * @details: (out) (optional) (nullable) (transfer full): A #GstStructure containing additional details about the error
  *
- * Parse the given error @msg and extract the corresponding #GError
+ * Parse the given error @msg and extract the corresponding #GError.
  *
  * Since: 1.20
  */
index e6d839f03f7fae7549718d83102cf2de711a717f..9157414cf451751f31392ff36ca5b9c36aeede98 100644 (file)
@@ -273,17 +273,34 @@ GST_PLAY_API
 void         gst_play_set_subtitle_track_enabled    (GstPlay    * play,
                                                      gboolean enabled);
 
-GST_PLAY_API
+GST_PLAY_DEPRECATED_FOR(gst_play_set_audio_track_id)
 gboolean     gst_play_set_audio_track               (GstPlay    *play,
                                                      gint stream_index);
 
-GST_PLAY_API
+GST_PLAY_DEPRECATED_FOR(gst_play_set_video_track_id)
 gboolean     gst_play_set_video_track               (GstPlay    *play,
                                                      gint stream_index);
 
-GST_PLAY_API
+GST_PLAY_DEPRECATED_FOR(gst_play_set_subtitle_track_id)
 gboolean     gst_play_set_subtitle_track            (GstPlay    *play,
                                                      gint stream_index);
+GST_PLAY_API
+gboolean     gst_play_set_audio_track_id            (GstPlay     *play,
+                                                     const gchar *stream_id);
+
+GST_PLAY_API
+gboolean     gst_play_set_video_track_id            (GstPlay     *play,
+                                                     const gchar *stream_id);
+
+GST_PLAY_API
+gboolean     gst_play_set_subtitle_track_id         (GstPlay     *play,
+                                                     const gchar *stream_id);
+
+GST_PLAY_API
+gboolean     gst_play_set_track_ids                 (GstPlay     *play,
+                                                     const gchar *audio_stream_id,
+                                                     const gchar *video_stream_id,
+                                                     const gchar *subtitle_stream_id);
 
 GST_PLAY_API
 GstPlayMediaInfo *    gst_play_get_media_info     (GstPlay * play);