gst/playback/gstplay-marshal.list: Added marshal for streamselector Tags.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 8 Feb 2008 17:47:37 +0000 (17:47 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 8 Feb 2008 17:47:37 +0000 (17:47 +0000)
Original commit message from CVS:
* gst/playback/gstplay-marshal.list:
Added marshal for streamselector Tags.
* gst/playback/gstplaybasebin.c: (set_active_source):
Streamselector now selects pads based on the pad object instead of its
name.
* gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
(init_group), (gst_play_bin_init), (get_group), (get_tags),
(gst_play_bin_get_video_tags), (gst_play_bin_get_audio_tags),
(gst_play_bin_get_text_tags),
(gst_play_bin_set_current_video_stream),
(gst_play_bin_set_current_audio_stream),
(gst_play_bin_set_current_text_stream),
(gst_play_bin_set_property), (gst_play_bin_get_property),
(pad_added_cb), (pad_removed_cb), (autoplug_select_cb):
Remove option to mute streams with the current-a/v/t property, we have
this functionality in the flags.
Add signals to notify when the number of A/V/T channels changed.
Add action signals to get tags for the A/V/T streams.
Implement setting the current A/V/T stream.
Rearrange some things to simplify stream selection.
Implement volume.
* gst/playback/gstplaysink.c: (gst_play_sink_set_volume),
(gst_play_sink_get_volume), (gst_play_sink_set_property),
(gst_play_sink_get_property), (gen_video_chain), (gen_audio_chain),
(activate_vis), (gst_play_sink_reconfigure):
* gst/playback/gstplaysink.h:
Add and implement volume setting methods.
* gst/playback/gststreamselector.c: (gst_selector_pad_class_init),
(gst_selector_pad_finalize), (gst_selector_pad_get_property),
(gst_selector_pad_event), (gst_stream_selector_class_init),
(gst_stream_selector_init), (gst_stream_selector_finalize),
(gst_stream_selector_set_property),
(gst_stream_selector_get_property),
(gst_stream_selector_get_linked_pad),
(gst_stream_selector_request_new_pad):
* gst/playback/gststreamselector.h:
Add pad properties for tags and status of pads.
Keep tags on pads.
Make active pad selection based on pad object instead of name.

ChangeLog
common
gst/playback/gstplay-marshal.list
gst/playback/gstplaybasebin.c
gst/playback/gstplaybin2.c
gst/playback/gstplaysink.c
gst/playback/gstplaysink.h
gst/playback/gststreamselector.c
gst/playback/gststreamselector.h

index 07e832b..0a9cffe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,49 @@
+2008-02-08  Wim Taymans  <wim.taymans@collabora.co.uk>
+
+       * gst/playback/gstplay-marshal.list:
+       Added marshal for streamselector Tags.
+
+       * gst/playback/gstplaybasebin.c: (set_active_source):
+       Streamselector now selects pads based on the pad object instead of its
+       name.
+
+       * gst/playback/gstplaybin2.c: (gst_play_bin_class_init),
+       (init_group), (gst_play_bin_init), (get_group), (get_tags),
+       (gst_play_bin_get_video_tags), (gst_play_bin_get_audio_tags),
+       (gst_play_bin_get_text_tags),
+       (gst_play_bin_set_current_video_stream),
+       (gst_play_bin_set_current_audio_stream),
+       (gst_play_bin_set_current_text_stream),
+       (gst_play_bin_set_property), (gst_play_bin_get_property),
+       (pad_added_cb), (pad_removed_cb), (autoplug_select_cb):
+       Remove option to mute streams with the current-a/v/t property, we have
+       this functionality in the flags.
+       Add signals to notify when the number of A/V/T channels changed.
+       Add action signals to get tags for the A/V/T streams.
+       Implement setting the current A/V/T stream.
+       Rearrange some things to simplify stream selection.
+       Implement volume.
+
+       * gst/playback/gstplaysink.c: (gst_play_sink_set_volume),
+       (gst_play_sink_get_volume), (gst_play_sink_set_property),
+       (gst_play_sink_get_property), (gen_video_chain), (gen_audio_chain),
+       (activate_vis), (gst_play_sink_reconfigure):
+       * gst/playback/gstplaysink.h:
+       Add and implement volume setting methods.
+
+       * gst/playback/gststreamselector.c: (gst_selector_pad_class_init),
+       (gst_selector_pad_finalize), (gst_selector_pad_get_property),
+       (gst_selector_pad_event), (gst_stream_selector_class_init),
+       (gst_stream_selector_init), (gst_stream_selector_finalize),
+       (gst_stream_selector_set_property),
+       (gst_stream_selector_get_property),
+       (gst_stream_selector_get_linked_pad),
+       (gst_stream_selector_request_new_pad):
+       * gst/playback/gststreamselector.h:
+       Add pad properties for tags and status of pads.
+       Keep tags on pads.
+       Make active pad selection based on pad object instead of name.
+
 2008-02-08  Stefan Kost  <ensonic@users.sf.net>
 
        * configure.ac:
diff --git a/common b/common
index aa24bcc..961bb6b 160000 (submodule)
--- a/common
+++ b/common
@@ -1 +1 @@
-Subproject commit aa24bcc28323422b29ba41874a4a98b6b6ddf63a
+Subproject commit 961bb6bd997d7c8da6058534e86b4a1361c0fcea
index 300a5b4..c26a918 100644 (file)
@@ -5,3 +5,4 @@ VOID:OBJECT,BOOLEAN
 ENUM:OBJECT,OBJECT,BOXED
 ENUM:OBJECT,OBJECT,OBJECT
 BOXED:OBJECT,OBJECT,BOXED
+BOXED:INT
index 150c0c4..4620feb 100644 (file)
@@ -2443,8 +2443,7 @@ set_active_source (GstPlayBaseBin * play_base_bin,
                 "pb_sel_pad"));
 
         if (sel && sel_pad != NULL) {
-          g_object_set (G_OBJECT (sel), "active-pad", GST_PAD_NAME (sel_pad),
-              NULL);
+          g_object_set (G_OBJECT (sel), "active-pad", sel_pad, NULL);
         }
 
         have_active = TRUE;
@@ -2463,7 +2462,7 @@ set_active_source (GstPlayBaseBin * play_base_bin,
 
   if (!have_active) {
     GST_LOG ("Muting group type: %d", type);
-    g_object_set (sel, "active-pad", "", NULL);
+    g_object_set (sel, "active-pad", NULL, NULL);
   } else {
     GST_LOG ("Unmuting group type: %d", type);
   }
index edc8d4e..51d3fa8 100644 (file)
 #include <gst/pbutils/pbutils.h>
 
 #include "gstplay-enum.h"
+#include "gstplay-marshal.h"
 #include "gstplaysink.h"
 #include "gstfactorylists.h"
 #include "gststreaminfo.h"
@@ -277,7 +278,7 @@ struct _GstSourceSelect
   GstPlaySinkType type;         /* the sink pad type of the selector */
 
   GstElement *selector;         /* the selector */
-  gint current;                 /* the currently selected stream */
+  GPtrArray *channels;
   GstPad *srcpad;               /* the source pad of the selector */
   GstPad *sinkpad;              /* the sinkpad of the sink when the selector is linked */
 };
@@ -298,6 +299,10 @@ struct _GstSourceGroup
   GstElement *source;
   gchar *subencoding;           /* encoding to propagate to the subtitle elements */
 
+  GPtrArray *video_channels;    /* links to selector pads */
+  GPtrArray *audio_channels;    /* links to selector pads */
+  GPtrArray *text_channels;     /* links to selector pads */
+
   /* uridecodebins for uri and subtitle uri */
   GstElement *uridecodebin;
   GstElement *suburidecodebin;
@@ -319,6 +324,9 @@ struct _GstPlayBin
 
   /* properties */
   guint connection_speed;       /* connection speed in bits/sec (0 = unknown) */
+  gint current_video;           /* the currently selected stream */
+  gint current_audio;           /* the currently selected stream */
+  gint current_text;            /* the currently selected stream */
 
   /* our play sink */
   GstPlaySink *playsink;
@@ -330,7 +338,15 @@ struct _GstPlayBinClass
 {
   GstPipelineClass parent_class;
 
-  void (*about_to_finish) (void);
+  void (*about_to_finish) (GstPlayBin * playbin);
+
+  void (*video_changed) (GstPlayBin * playbin);
+  void (*audio_changed) (GstPlayBin * playbin);
+  void (*text_changed) (GstPlayBin * playbin);
+
+  GstTagList *(*get_video_tags) (GstPlayBin * playbin, gint stream);
+  GstTagList *(*get_audio_tags) (GstPlayBin * playbin, gint stream);
+  GstTagList *(*get_text_tags) (GstPlayBin * playbin, gint stream);
 };
 
 /* props */
@@ -381,6 +397,12 @@ enum
 enum
 {
   SIGNAL_ABOUT_TO_FINISH,
+  SIGNAL_VIDEO_CHANGED,
+  SIGNAL_AUDIO_CHANGED,
+  SIGNAL_TEXT_CHANGED,
+  SIGNAL_GET_VIDEO_TAGS,
+  SIGNAL_GET_AUDIO_TAGS,
+  SIGNAL_GET_TEXT_TAGS,
   LAST_SIGNAL
 };
 
@@ -398,6 +420,13 @@ static GstStateChangeReturn gst_play_bin_change_state (GstElement * element,
 
 static void gst_play_bin_handle_message (GstBin * bin, GstMessage * message);
 
+static GstStructure *gst_play_bin_get_video_tags (GstPlayBin * playbin,
+    gint stream);
+static GstStructure *gst_play_bin_get_audio_tags (GstPlayBin * playbin,
+    gint stream);
+static GstStructure *gst_play_bin_get_text_tags (GstPlayBin * playbin,
+    gint stream);
+
 static gboolean setup_next_source (GstPlayBin * playbin);
 
 static GstElementClass *parent_class;
@@ -495,13 +524,11 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
    *
    * Get or set the currently playing video stream. By default the first video
    * stream with data is played.
-   *
-   * Setting this property to -2 will disable the video stream.
    */
   g_object_class_install_property (gobject_klass, PROP_CURRENT_VIDEO,
       g_param_spec_int ("current-video", "Current Video",
-          "Currently playing video stream (-1 = auto, -2 = none)",
-          -2, G_MAXINT, -1, G_PARAM_READWRITE));
+          "Currently playing video stream (-1 = auto)",
+          -1, G_MAXINT, -1, G_PARAM_READWRITE));
   /**
    * GstPlayBin:n-audio
    *
@@ -515,13 +542,11 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
    *
    * Get or set the currently playing audio stream. By default the first audio
    * stream with data is played.
-   *
-   * Setting this property to -2 will disable the audio stream.
    */
   g_object_class_install_property (gobject_klass, PROP_CURRENT_AUDIO,
       g_param_spec_int ("current-audio", "Current audio",
-          "Currently playing audio stream (-1 = none, -2 = none)",
-          -2, G_MAXINT, -1, G_PARAM_READWRITE));
+          "Currently playing audio stream (-1 = auto)",
+          -1, G_MAXINT, -1, G_PARAM_READWRITE));
   /**
    * GstPlayBin:n-text
    *
@@ -533,15 +558,13 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
   /**
    * GstPlayBin:current-text
    *
-   * Get or set the currently playing subtitle stream. By default the first audio
-   * stream with data is played.
-   *
-   * Setting this property to -2 will disable the text stream.
+   * Get or set the currently playing subtitle stream. By default the first
+   * subtitle stream with data is played.
    */
   g_object_class_install_property (gobject_klass, PROP_CURRENT_TEXT,
       g_param_spec_int ("current-text", "Current Text",
-          "Currently playing text stream (-1 = none, -2 = none)",
-          -2, G_MAXINT, -1, G_PARAM_READWRITE));
+          "Currently playing text stream (-1 = auto)",
+          -1, G_MAXINT, -1, G_PARAM_READWRITE));
 
   g_object_class_install_property (gobject_klass, PROP_SUBTITLE_ENCODING,
       g_param_spec_string ("subtitle-encoding", "subtitle encoding",
@@ -582,6 +605,7 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
           0, G_MAXUINT, DEFAULT_CONNECTION_SPEED, G_PARAM_READWRITE));
   /**
    * GstPlayBin::about-to-finish:
+   * @playbin: a #GstPlayBin
    *
    * This signal is emitted when the current uri is about to finish. You can
    * set the next-uri and next-suburi to make sure that playback continues.
@@ -592,6 +616,99 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
       G_STRUCT_OFFSET (GstPlayBinClass, about_to_finish), NULL, NULL,
       gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
 
+  /**
+   * GstPlayBin::video-changed
+   * @playbin: a #GstPlayBin
+   *
+   * This signal is emited whenever the number or order of the video
+   * streams has changed. The application will most likely want to select
+   * a new video stream.
+   */
+  gst_play_bin_signals[SIGNAL_VIDEO_CHANGED] =
+      g_signal_new ("video-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstPlayBinClass, video_changed), NULL, NULL,
+      gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+  /**
+   * GstPlayBin::audio-changed
+   * @playbin: a #GstPlayBin
+   *
+   * This signal is emited whenever the number or order of the audio
+   * streams has changed. The application will most likely want to select
+   * a new audio stream.
+   */
+  gst_play_bin_signals[SIGNAL_AUDIO_CHANGED] =
+      g_signal_new ("audio-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstPlayBinClass, audio_changed), NULL, NULL,
+      gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+  /**
+   * GstPlayBin::text-changed
+   * @playbin: a #GstPlayBin
+   *
+   * This signal is emited whenever the number or order of the text
+   * streams has changed. The application will most likely want to select
+   * a new text stream.
+   */
+  gst_play_bin_signals[SIGNAL_TEXT_CHANGED] =
+      g_signal_new ("text-changed", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstPlayBinClass, text_changed), NULL, NULL,
+      gst_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  /**
+   * GstPlayBin::get-video-tags
+   * @playbin: a #GstPlayBin
+   * @stream: a video stream number
+   *
+   * Action signal to retrieve the tags of a specific video stream number.
+   * This information can be used to select a stream.
+   *
+   * Returns: a GstTagList with tags or NULL when the stream number does not
+   * exist.
+   */
+  gst_play_bin_signals[SIGNAL_GET_VIDEO_TAGS] =
+      g_signal_new ("get-video-tags", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstPlayBinClass, get_video_tags), NULL, NULL,
+      gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
+  /**
+   * GstPlayBin::get-audio-tags
+   * @playbin: a #GstPlayBin
+   * @stream: an audio stream number
+   *
+   * Action signal to retrieve the tags of a specific audio stream number.
+   * This information can be used to select a stream.
+   *
+   * Returns: a GstTagList with tags or NULL when the stream number does not
+   * exist.
+   */
+  gst_play_bin_signals[SIGNAL_GET_AUDIO_TAGS] =
+      g_signal_new ("get-audio-tags", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstPlayBinClass, get_audio_tags), NULL, NULL,
+      gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
+  /**
+   * GstPlayBin::get-text-tags
+   * @playbin: a #GstPlayBin
+   * @stream: a text stream number
+   *
+   * Action signal to retrieve the tags of a specific text stream number.
+   * This information can be used to select a stream.
+   *
+   * Returns: a GstTagList with tags or NULL when the stream number does not
+   * exist.
+   */
+  gst_play_bin_signals[SIGNAL_GET_TEXT_TAGS] =
+      g_signal_new ("get-text-tags", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+      G_STRUCT_OFFSET (GstPlayBinClass, get_text_tags), NULL, NULL,
+      gst_play_marshal_BOXED__INT, GST_TYPE_TAG_LIST, 1, G_TYPE_INT);
+
+  klass->get_video_tags = gst_play_bin_get_video_tags;
+  klass->get_audio_tags = gst_play_bin_get_audio_tags;
+  klass->get_text_tags = gst_play_bin_get_text_tags;
+
   gst_element_class_set_details (gstelement_klass, &gst_play_bin_details);
 
   gstelement_klass->change_state =
@@ -604,18 +721,27 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
 static void
 init_group (GstPlayBin * playbin, GstSourceGroup * group)
 {
+  /* store the array for the different channels */
+  group->video_channels = g_ptr_array_new ();
+  group->audio_channels = g_ptr_array_new ();
+  group->text_channels = g_ptr_array_new ();
   /* init selectors */
   group->playbin = playbin;
   group->selector[0].media = "audio/x-raw-";
   group->selector[0].type = GST_PLAY_SINK_TYPE_AUDIO_RAW;
+  group->selector[0].channels = group->audio_channels;
   group->selector[1].media = "audio/";
   group->selector[1].type = GST_PLAY_SINK_TYPE_AUDIO;
+  group->selector[1].channels = group->audio_channels;
   group->selector[2].media = "video/x-raw-";
   group->selector[2].type = GST_PLAY_SINK_TYPE_VIDEO_RAW;
+  group->selector[2].channels = group->video_channels;
   group->selector[3].media = "video/";
   group->selector[3].type = GST_PLAY_SINK_TYPE_VIDEO;
+  group->selector[3].channels = group->video_channels;
   group->selector[4].media = "text/";
   group->selector[4].type = GST_PLAY_SINK_TYPE_TEXT;
+  group->selector[4].channels = group->text_channels;
 }
 
 static void
@@ -639,7 +765,9 @@ gst_play_bin_init (GstPlayBin * playbin)
   gst_bin_add (GST_BIN_CAST (playbin), GST_ELEMENT_CAST (playbin->playsink));
   gst_play_sink_set_flags (playbin->playsink, DEFAULT_FLAGS);
 
-  /* get the caps */
+  playbin->current_video = DEFAULT_CURRENT_VIDEO;
+  playbin->current_audio = DEFAULT_CURRENT_AUDIO;
+  playbin->current_text = DEFAULT_CURRENT_TEXT;
 }
 
 static void
@@ -698,6 +826,202 @@ done:
   GST_OBJECT_UNLOCK (playbin);
 }
 
+/* get the currently playing group or if nothing is playing, the next
+ * group. Must be called with the LOCK. */
+static GstSourceGroup *
+get_group (GstPlayBin * playbin)
+{
+  GstSourceGroup *result;
+
+  if (!(result = playbin->curr_group))
+    result = playbin->next_group;
+
+  return result;
+}
+
+static GstTagList *
+get_tags (GstPlayBin * playbin, GPtrArray * channels, gint stream)
+{
+  GstTagList *result;
+  GstPad *sinkpad;
+
+  if (!channels || channels->len < stream)
+    return NULL;
+
+  sinkpad = g_ptr_array_index (channels, stream);
+  g_object_get (sinkpad, "tags", &result, NULL);
+
+  return result;
+}
+
+static GstTagList *
+gst_play_bin_get_video_tags (GstPlayBin * playbin, gint stream)
+{
+  GstTagList *result;
+  GstSourceGroup *group;
+
+  GST_OBJECT_LOCK (playbin);
+  group = get_group (playbin);
+  result = get_tags (playbin, group->video_channels, stream);
+  GST_OBJECT_UNLOCK (playbin);
+
+  return result;
+}
+
+static GstTagList *
+gst_play_bin_get_audio_tags (GstPlayBin * playbin, gint stream)
+{
+  GstTagList *result;
+  GstSourceGroup *group;
+
+  GST_OBJECT_LOCK (playbin);
+  group = get_group (playbin);
+  result = get_tags (playbin, group->audio_channels, stream);
+  GST_OBJECT_UNLOCK (playbin);
+
+  return result;
+}
+
+static GstTagList *
+gst_play_bin_get_text_tags (GstPlayBin * playbin, gint stream)
+{
+  GstTagList *result;
+  GstSourceGroup *group;
+
+  GST_OBJECT_LOCK (playbin);
+  group = get_group (playbin);
+  result = get_tags (playbin, group->text_channels, stream);
+  GST_OBJECT_UNLOCK (playbin);
+
+  return result;
+}
+
+static gboolean
+gst_play_bin_set_current_video_stream (GstPlayBin * playbin, gint stream)
+{
+  GstSourceGroup *group;
+  GPtrArray *channels;
+  GstPad *sinkpad;
+
+  GST_OBJECT_LOCK (playbin);
+  group = get_group (playbin);
+  if (!(channels = group->video_channels))
+    goto no_channels;
+
+  if (stream == -1 || channels->len < stream) {
+    sinkpad = NULL;
+  } else {
+    /* take channel from selected stream */
+    sinkpad = g_ptr_array_index (channels, stream);
+  }
+
+  if (sinkpad)
+    gst_object_ref (sinkpad);
+  GST_OBJECT_UNLOCK (playbin);
+
+  if (sinkpad) {
+    GstObject *selector;
+
+    if ((selector = gst_pad_get_parent (sinkpad))) {
+      /* activate the selected pad */
+      g_object_set (selector, "active-pad", sinkpad, NULL);
+      gst_object_unref (selector);
+    }
+    gst_object_unref (sinkpad);
+  }
+  return TRUE;
+
+no_channels:
+  {
+    GST_OBJECT_UNLOCK (playbin);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_play_bin_set_current_audio_stream (GstPlayBin * playbin, gint stream)
+{
+  GstSourceGroup *group;
+  GPtrArray *channels;
+  GstPad *sinkpad;
+
+  GST_OBJECT_LOCK (playbin);
+  group = get_group (playbin);
+  if (!(channels = group->audio_channels))
+    goto no_channels;
+
+  if (stream == -1 || channels->len < stream) {
+    sinkpad = NULL;
+  } else {
+    /* take channel from selected stream */
+    sinkpad = g_ptr_array_index (channels, stream);
+  }
+
+  if (sinkpad)
+    gst_object_ref (sinkpad);
+  GST_OBJECT_UNLOCK (playbin);
+
+  if (sinkpad) {
+    GstObject *selector;
+
+    if ((selector = gst_pad_get_parent (sinkpad))) {
+      /* activate the selected pad */
+      g_object_set (selector, "active-pad", sinkpad, NULL);
+      gst_object_unref (selector);
+    }
+    gst_object_unref (sinkpad);
+  }
+  return TRUE;
+
+no_channels:
+  {
+    GST_OBJECT_UNLOCK (playbin);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_play_bin_set_current_text_stream (GstPlayBin * playbin, gint stream)
+{
+  GstSourceGroup *group;
+  GPtrArray *channels;
+  GstPad *sinkpad;
+
+  GST_OBJECT_LOCK (playbin);
+  group = get_group (playbin);
+  if (!(channels = group->text_channels))
+    goto no_channels;
+
+  if (stream == -1 || channels->len < stream) {
+    sinkpad = NULL;
+  } else {
+    /* take channel from selected stream */
+    sinkpad = g_ptr_array_index (channels, stream);
+  }
+
+  if (sinkpad)
+    gst_object_ref (sinkpad);
+  GST_OBJECT_UNLOCK (playbin);
+
+  if (sinkpad) {
+    GstObject *selector;
+
+    if ((selector = gst_pad_get_parent (sinkpad))) {
+      /* activate the selected pad */
+      g_object_set (selector, "active-pad", sinkpad, NULL);
+      gst_object_unref (selector);
+    }
+    gst_object_unref (sinkpad);
+  }
+  return TRUE;
+
+no_channels:
+  {
+    GST_OBJECT_UNLOCK (playbin);
+    return FALSE;
+  }
+}
+
 static void
 gst_play_bin_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
@@ -717,10 +1041,13 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
       gst_play_sink_set_flags (playbin->playsink, g_value_get_flags (value));
       break;
     case PROP_CURRENT_VIDEO:
+      gst_play_bin_set_current_video_stream (playbin, g_value_get_int (value));
       break;
     case PROP_CURRENT_AUDIO:
+      gst_play_bin_set_current_audio_stream (playbin, g_value_get_int (value));
       break;
     case PROP_CURRENT_TEXT:
+      gst_play_bin_set_current_text_stream (playbin, g_value_get_int (value));
       break;
     case PROP_SUBTITLE_ENCODING:
       break;
@@ -731,6 +1058,7 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
     case PROP_VIS_PLUGIN:
       break;
     case PROP_VOLUME:
+      gst_play_sink_set_volume (playbin->playsink, g_value_get_double (value));
       break;
     case PROP_FONT_DESC:
       break;
@@ -745,32 +1073,6 @@ gst_play_bin_set_property (GObject * object, guint prop_id,
   }
 }
 
-/* get the currently playing group or if nothing is playing, the next
- * group. Must be called with the LOCK. */
-static GstSourceGroup *
-get_group (GstPlayBin * playbin)
-{
-  GstSourceGroup *result;
-
-  if (!(result = playbin->curr_group))
-    result = playbin->next_group;
-
-  return result;
-}
-
-static gint
-get_n_pads (GstSourceSelect * select)
-{
-  gint res;
-
-  if (select->selector == NULL)
-    return 0;
-
-  g_object_get (select->selector, "n-pads", &res, NULL);
-
-  return res;
-}
-
 static void
 gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
     GParamSpec * pspec)
@@ -808,37 +1110,53 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_N_VIDEO:
     {
       GstSourceGroup *group;
-      gint n_rawvideo, n_video;
+      gint n_video;
 
       GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
-      n_rawvideo = get_n_pads (&group->selector[2]);
-      n_video = get_n_pads (&group->selector[3]);
-      g_value_set_int (value, n_rawvideo + n_video);
+      n_video = (group->video_channels ? group->video_channels->len : 0);
+      g_value_set_int (value, n_video);
       GST_OBJECT_UNLOCK (playbin);
       break;
     }
     case PROP_CURRENT_VIDEO:
+      GST_OBJECT_LOCK (playbin);
+      g_value_set_int (value, playbin->current_video);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     case PROP_N_AUDIO:
     {
       GstSourceGroup *group;
-      gint n_rawaudio, n_audio;
+      gint n_audio;
 
       GST_OBJECT_LOCK (playbin);
       group = get_group (playbin);
-      n_rawaudio = get_n_pads (&group->selector[0]);
-      n_audio = get_n_pads (&group->selector[1]);
-      g_value_set_int (value, n_rawaudio + n_audio);
+      n_audio = (group->audio_channels ? group->audio_channels->len : 0);
+      g_value_set_int (value, n_audio);
       GST_OBJECT_UNLOCK (playbin);
       break;
     }
-      break;
     case PROP_CURRENT_AUDIO:
+      GST_OBJECT_LOCK (playbin);
+      g_value_set_int (value, playbin->current_audio);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     case PROP_N_TEXT:
+    {
+      GstSourceGroup *group;
+      gint n_text;
+
+      GST_OBJECT_LOCK (playbin);
+      group = get_group (playbin);
+      n_text = (group->text_channels ? group->text_channels->len : 0);
+      g_value_set_int (value, n_text);
+      GST_OBJECT_UNLOCK (playbin);
       break;
+    }
     case PROP_CURRENT_TEXT:
+      GST_OBJECT_LOCK (playbin);
+      g_value_set_int (value, playbin->current_text);
+      GST_OBJECT_UNLOCK (playbin);
       break;
     case PROP_SUBTITLE_ENCODING:
       break;
@@ -849,6 +1167,7 @@ gst_play_bin_get_property (GObject * object, guint prop_id, GValue * value,
     case PROP_VIS_PLUGIN:
       break;
     case PROP_VOLUME:
+      g_value_set_double (value, gst_play_sink_get_volume (playbin->playsink));
       break;
     case PROP_FRAME:
       break;
@@ -929,6 +1248,9 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
   if (select == NULL)
     goto unknown_type;
 
+  /* store the selector for the pad */
+  g_object_set_data (G_OBJECT (pad), "playbin2.select", select);
+
   if (select->selector == NULL) {
     /* no selector, create one */
     GST_DEBUG_OBJECT (playbin, "creating new selector");
@@ -948,12 +1270,16 @@ pad_added_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
   if ((sinkpad = gst_element_get_request_pad (select->selector, "sink%d"))) {
     GST_DEBUG_OBJECT (playbin, "got pad %s:%s from selector",
         GST_DEBUG_PAD_NAME (sinkpad));
+
+    /* store the pad in the array */
+    g_ptr_array_add (select->channels, sinkpad);
+
     res = gst_pad_link (pad, sinkpad);
     if (GST_PAD_LINK_FAILED (res))
       goto link_failed;
 
     /* store selector pad so we can release it */
-    g_object_set_data (G_OBJECT (pad), "playbin2.selector", sinkpad);
+    g_object_set_data (G_OBJECT (pad), "playbin2.sinkpad", sinkpad);
   }
   GST_DEBUG_OBJECT (playbin, "linked pad %s:%s to selector %p",
       GST_DEBUG_PAD_NAME (pad), select->selector);
@@ -990,15 +1316,20 @@ pad_removed_cb (GstElement * decodebin, GstPad * pad, GstSourceGroup * group)
   GstPlayBin *playbin;
   GstPad *peer;
   GstElement *selector;
+  GstSourceSelect *select;
 
   playbin = group->playbin;
 
   GST_DEBUG_OBJECT (playbin,
       "pad %s:%s removed from group %p", GST_DEBUG_PAD_NAME (pad), group);
 
+  if ((select = g_object_get_data (G_OBJECT (pad), "playbin2.select"))) {
+    /* remove the pad from the array */
+    g_ptr_array_remove (select->channels, pad);
+  }
+
   /* get the selector sinkpad */
-  peer = g_object_get_data (G_OBJECT (pad), "playbin2.selector");
-  if (!peer)
+  if (!(peer = g_object_get_data (G_OBJECT (pad), "playbin2.sinkpad")))
     goto not_linked;
 
   /* unlink the pad now (can fail, the pad is unlinked before it's removed) */
index 105233f..8eedf00 100644 (file)
@@ -33,7 +33,6 @@ GST_DEBUG_CATEGORY_STATIC (gst_play_sink_debug);
 #define GST_CAT_DEFAULT gst_play_sink_debug
 
 #define VOLUME_MAX_DOUBLE 10.0
-#define CONNECTION_SPEED_DEFAULT 0
 
 /* holds the common data fields for the audio and video pipelines. We keep them
  * in a structure to more easily have all the info available. */
@@ -519,6 +518,39 @@ gst_play_sink_set_vis_plugin (GstPlaySink * playsink,
   }
 }
 
+void
+gst_play_sink_set_volume (GstPlaySink * playsink, gdouble volume)
+{
+  GstPlayAudioChain *chain;
+
+  GST_PLAY_SINK_LOCK (playsink);
+  playsink->volume = volume;
+  chain = (GstPlayAudioChain *) playsink->audiochain;
+  if (chain && chain->volume) {
+    g_object_set (chain->volume, "volume", volume, NULL);
+  }
+  GST_PLAY_SINK_UNLOCK (playsink);
+}
+
+gdouble
+gst_play_sink_get_volume (GstPlaySink * playsink)
+{
+  gdouble result;
+  GstPlayAudioChain *chain;
+
+  GST_PLAY_SINK_LOCK (playsink);
+  chain = (GstPlayAudioChain *) playsink->audiochain;
+  if (chain && chain->volume) {
+    g_object_get (chain->volume, "volume", &result, NULL);
+    playsink->volume = result;
+  } else {
+    result = playsink->volume;
+  }
+  GST_PLAY_SINK_UNLOCK (playsink);
+
+  return result;
+}
+
 static void
 gst_play_sink_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
@@ -538,9 +570,7 @@ gst_play_sink_set_property (GObject * object, guint prop_id,
       gst_play_sink_set_vis_plugin (playsink, g_value_get_object (value));
       break;
     case PROP_VOLUME:
-      GST_OBJECT_LOCK (playsink);
-      playsink->volume = g_value_get_double (value);
-      GST_OBJECT_UNLOCK (playsink);
+      gst_play_sink_set_volume (playsink, g_value_get_double (value));
       break;
     case PROP_FONT_DESC:
       GST_OBJECT_LOCK (playsink);
@@ -583,9 +613,7 @@ gst_play_sink_get_property (GObject * object, guint prop_id, GValue * value,
       GST_OBJECT_UNLOCK (playsink);
       break;
     case PROP_VOLUME:
-      GST_OBJECT_LOCK (playsink);
-      g_value_set_double (value, playsink->volume);
-      GST_OBJECT_UNLOCK (playsink);
+      g_value_set_double (value, gst_play_sink_get_volume (playsink));
       break;
     case PROP_FRAME:
     {
@@ -914,8 +942,11 @@ gen_audio_chain (GstPlaySink * playsink, gboolean raw)
 
     res = gst_element_link_pads (chain->conv, "src", chain->resample, "sink");
 
+    /* FIXME check if the sink has the volume property */
+
     if (playsink->flags & GST_PLAY_FLAG_SOFT_VOLUME) {
       chain->volume = gst_element_factory_make ("volume", "volume");
+      /* configure with the latest volume */
       g_object_set (G_OBJECT (chain->volume), "volume", playsink->volume, NULL);
       gst_bin_add (bin, chain->volume);
 
index 6373edd..ec89f41 100644 (file)
@@ -69,6 +69,9 @@ void             gst_play_sink_set_video_sink (GstPlaySink * playsink, GstElemen
 void             gst_play_sink_set_audio_sink (GstPlaySink * playsink, GstElement * sink);
 void             gst_play_sink_set_vis_plugin (GstPlaySink * playsink, GstElement * vis);
 
+void             gst_play_sink_set_volume     (GstPlaySink *playsink, gdouble volume);
+gdouble          gst_play_sink_get_volume     (GstPlaySink *playsink);
+
 gboolean         gst_play_sink_set_flags      (GstPlaySink * playsink, GstPlayFlags flags);
 GstPlayFlags     gst_play_sink_get_flags      (GstPlaySink * playsink);
 
index 9681f01..87604b9 100644 (file)
@@ -91,6 +91,7 @@ struct _GstSelectorPad
   gboolean eos;
   gboolean segment_pending;
   GstSegment segment;
+  GstTagList *tags;
 };
 
 struct _GstSelectorPadClass
@@ -102,6 +103,9 @@ static void gst_selector_pad_class_init (GstSelectorPadClass * klass);
 static void gst_selector_pad_init (GstSelectorPad * pad);
 static void gst_selector_pad_finalize (GObject * object);
 
+static void gst_selector_pad_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
 static GstPadClass *selector_pad_parent_class = NULL;
 
 static void gst_selector_pad_reset (GstSelectorPad * pad);
@@ -112,6 +116,14 @@ static GstFlowReturn gst_selector_pad_chain (GstPad * pad, GstBuffer * buf);
 static GstFlowReturn gst_selector_pad_bufferalloc (GstPad * pad,
     guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
 
+enum
+{
+  PROP_PAD_0,
+  PROP_PAD_TAGS,
+  PROP_PAD_ACTIVE,
+  PROP_PAD_LAST
+};
+
 static GType
 gst_selector_pad_get_type (void)
 {
@@ -147,6 +159,17 @@ gst_selector_pad_class_init (GstSelectorPadClass * klass)
   selector_pad_parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->finalize = gst_selector_pad_finalize;
+  gobject_class->get_property =
+      GST_DEBUG_FUNCPTR (gst_selector_pad_get_property);
+
+  g_object_class_install_property (gobject_class, PROP_PAD_TAGS,
+      g_param_spec_boxed ("tags", "Tags",
+          "The currently active tags on the pad", GST_TYPE_TAG_LIST,
+          G_PARAM_READABLE));
+
+  g_object_class_install_property (gobject_class, PROP_PAD_ACTIVE,
+      g_param_spec_boolean ("active", "Active",
+          "If the pad is currently active", FALSE, G_PARAM_READABLE));
 }
 
 static void
@@ -162,10 +185,43 @@ gst_selector_pad_finalize (GObject * object)
 
   pad = GST_SELECTOR_PAD_CAST (object);
 
+  if (pad->tags)
+    gst_tag_list_free (pad->tags);
+
   G_OBJECT_CLASS (selector_pad_parent_class)->finalize (object);
 }
 
 static void
+gst_selector_pad_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstSelectorPad *pad;
+
+  pad = GST_SELECTOR_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_TAGS:
+      GST_OBJECT_LOCK (object);
+      g_value_set_boxed (value, pad->tags);
+      GST_OBJECT_UNLOCK (object);
+      break;
+    case PROP_PAD_ACTIVE:
+    {
+      GstStreamSelector *sel;
+
+      sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
+      g_value_set_boolean (value, gst_stream_selector_is_active_sinkpad (sel,
+              GST_PAD_CAST (pad)));
+      gst_object_unref (sel);
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
 gst_selector_pad_reset (GstSelectorPad * pad)
 {
   pad->active = FALSE;
@@ -232,6 +288,21 @@ gst_selector_pad_event (GstPad * pad, GstEvent * event)
         selpad->segment_pending = TRUE;
       break;
     }
+    case GST_EVENT_TAG:
+    {
+      GstTagList *tags;
+
+      GST_OBJECT_LOCK (selpad);
+      if (selpad->tags)
+        gst_tag_list_free (selpad->tags);
+      gst_event_parse_tag (event, &tags);
+      if (tags)
+        tags = gst_tag_list_copy (tags);
+      selpad->tags = tags;
+      GST_DEBUG_OBJECT (sel, "received tags %" GST_PTR_FORMAT, selpad->tags);
+      GST_OBJECT_UNLOCK (selpad);
+      break;
+    }
     case GST_EVENT_EOS:
       selpad->eos = TRUE;
       break;
@@ -364,19 +435,24 @@ ignore:
 }
 
 static void gst_stream_selector_dispose (GObject * object);
+static void gst_stream_selector_finalize (GObject * object);
+
 static void gst_stream_selector_init (GstStreamSelector * sel);
 static void gst_stream_selector_base_init (GstStreamSelectorClass * klass);
 static void gst_stream_selector_class_init (GstStreamSelectorClass * klass);
+
 static void gst_stream_selector_set_property (GObject * object,
     guint prop_id, const GValue * value, GParamSpec * pspec);
 static void gst_stream_selector_get_property (GObject * object,
     guint prop_id, GValue * value, GParamSpec * pspec);
+
 static GstPad *gst_stream_selector_request_new_pad (GstElement * element,
     GstPadTemplate * templ, const gchar * unused);
 static void gst_stream_selector_release_pad (GstElement * element,
     GstPad * pad);
 static GList *gst_stream_selector_get_linked_pads (GstPad * pad);
 static GstCaps *gst_stream_selector_getcaps (GstPad * pad);
+
 static GstElementClass *parent_class = NULL;
 
 GType
@@ -427,17 +503,19 @@ gst_stream_selector_class_init (GstStreamSelectorClass * klass)
   parent_class = g_type_class_peek_parent (klass);
 
   gobject_class->dispose = gst_stream_selector_dispose;
+  gobject_class->finalize = gst_stream_selector_finalize;
+
   gobject_class->set_property =
       GST_DEBUG_FUNCPTR (gst_stream_selector_set_property);
   gobject_class->get_property =
       GST_DEBUG_FUNCPTR (gst_stream_selector_get_property);
 
   g_object_class_install_property (gobject_class, PROP_N_PADS,
-      g_param_spec_int ("n-pads", "Number of Pads",
-          "The number of sink pads", 0, G_MAXINT, 0, G_PARAM_READABLE));
+      g_param_spec_uint ("n-pads", "Number of Pads",
+          "The number of sink pads", 0, G_MAXUINT, 0, G_PARAM_READABLE));
   g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
-      g_param_spec_string ("active-pad", "Active pad",
-          "Name of the currently" " active sink pad", NULL, G_PARAM_READWRITE));
+      g_param_spec_object ("active-pad", "Active Pad",
+          "The currently active sink pad", GST_TYPE_PAD, G_PARAM_READWRITE));
 
   gstelement_class->request_new_pad = gst_stream_selector_request_new_pad;
   gstelement_class->release_pad = gst_stream_selector_release_pad;
@@ -453,9 +531,8 @@ gst_stream_selector_init (GstStreamSelector * sel)
       GST_DEBUG_FUNCPTR (gst_stream_selector_getcaps));
   gst_element_add_pad (GST_ELEMENT (sel), sel->srcpad);
   /* sinkpad management */
-  sel->active_sinkpad = NULL;
   sel->padcount = 0;
-  sel->n_pads = 0;
+  sel->active_sinkpad = NULL;
   gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
 }
 
@@ -473,19 +550,29 @@ gst_stream_selector_dispose (GObject * object)
 }
 
 static void
+gst_stream_selector_finalize (GObject * object)
+{
+  GstStreamSelector *sel;
+
+  sel = GST_STREAM_SELECTOR (object);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
 gst_stream_selector_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
   GstStreamSelector *sel = GST_STREAM_SELECTOR (object);
 
   switch (prop_id) {
-    case PROP_ACTIVE_PAD:{
-      const gchar *pad_name = g_value_get_string (value);
+    case PROP_ACTIVE_PAD:
+    {
       GstPad *pad = NULL;
       GstPad **active_pad_p;
 
-      if (strcmp (pad_name, "") != 0)
-        pad = gst_element_get_pad (GST_ELEMENT (object), pad_name);
+      pad = g_value_get_object (value);
+
       GST_OBJECT_LOCK (object);
       if (pad != sel->active_sinkpad) {
         GstSelectorPad *selpad;
@@ -504,8 +591,6 @@ gst_stream_selector_set_property (GObject * object, guint prop_id,
         }
       }
       GST_OBJECT_UNLOCK (object);
-      if (pad)
-        gst_object_unref (pad);
       break;
     }
     default:
@@ -523,16 +608,12 @@ gst_stream_selector_get_property (GObject * object, guint prop_id,
   switch (prop_id) {
     case PROP_N_PADS:
       GST_OBJECT_LOCK (object);
-      g_value_set_int (value, sel->n_pads);
+      g_value_set_uint (value, sel->n_pads);
       GST_OBJECT_UNLOCK (object);
       break;
     case PROP_ACTIVE_PAD:{
       GST_OBJECT_LOCK (object);
-      if (sel->active_sinkpad != NULL) {
-        g_value_take_string (value, gst_pad_get_name (sel->active_sinkpad));
-      } else {
-        g_value_set_string (value, "");
-      }
+      g_value_set_object (value, sel->active_sinkpad);
       GST_OBJECT_UNLOCK (object);
       break;
     }
@@ -549,6 +630,7 @@ gst_stream_selector_get_linked_pad (GstPad * pad, gboolean strict)
   GstPad *otherpad = NULL;
 
   sel = GST_STREAM_SELECTOR (gst_pad_get_parent (pad));
+
   GST_OBJECT_LOCK (sel);
   if (pad == sel->srcpad)
     otherpad = sel->active_sinkpad;
@@ -653,10 +735,10 @@ gst_stream_selector_request_new_pad (GstElement * element,
   GST_LOG_OBJECT (sel, "Creating new pad %d", sel->padcount);
   GST_OBJECT_LOCK (sel);
   name = g_strdup_printf ("sink%d", sel->padcount++);
-  sel->n_pads++;
   sinkpad = g_object_new (GST_TYPE_SELECTOR_PAD,
       "name", name, "direction", templ->direction, "template", templ, NULL);
   g_free (name);
+  sel->n_pads++;
   GST_OBJECT_UNLOCK (sel);
 
   gst_pad_set_event_function (sinkpad,
index d64da77..5200a0b 100644 (file)
@@ -44,10 +44,9 @@ struct _GstStreamSelector {
 
   GstPad *srcpad;
 
-  guint padcount;
-
   GstPad *active_sinkpad;
   guint n_pads;
+  guint padcount;
 
   GstSegment segment;
 };