gst/playback/: Updated README.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 9 Nov 2004 12:10:28 +0000 (12:10 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 9 Nov 2004 12:10:28 +0000 (12:10 +0000)
Original commit message from CVS:
* gst/playback/README:
* gst/playback/gstplaybasebin.c: (group_destroy), (group_is_muted),
(add_stream), (unknown_type), (add_element_stream), (no_more_pads),
(probe_triggered), (preroll_unlinked), (new_decoded_pad),
(gst_play_base_bin_change_state), (gst_play_base_bin_found_tag):
* gst/playback/gstplaybin.c: (gen_vis_element), (remove_sinks),
(setup_sinks):
* gst/playback/gststreaminfo.c: (gst_stream_info_set_mute),
(gst_stream_info_is_mute), (gst_stream_info_set_property):
* gst/playback/gststreaminfo.h:
Updated README.
Only switch groups if all streams have muted (EOSed).
Send Tags in sync with the stream playback instead of in
the playback/preroll phase.
Some cleanups, free the fakesrc elements.

ChangeLog
gst/playback/README
gst/playback/gstplaybasebin.c
gst/playback/gstplaybin.c
gst/playback/gststreaminfo.c
gst/playback/gststreaminfo.h

index 1ee38ee..dc16941 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2004-11-09  Wim Taymans  <wim@fluendo.com>
+
+       * gst/playback/README:
+       * gst/playback/gstplaybasebin.c: (group_destroy), (group_is_muted),
+       (add_stream), (unknown_type), (add_element_stream), (no_more_pads),
+       (probe_triggered), (preroll_unlinked), (new_decoded_pad),
+       (gst_play_base_bin_change_state), (gst_play_base_bin_found_tag):
+       * gst/playback/gstplaybin.c: (gen_vis_element), (remove_sinks),
+       (setup_sinks):
+       * gst/playback/gststreaminfo.c: (gst_stream_info_set_mute),
+       (gst_stream_info_is_mute), (gst_stream_info_set_property):
+       * gst/playback/gststreaminfo.h:
+       Updated README.
+       Only switch groups if all streams have muted (EOSed).
+       Send Tags in sync with the stream playback instead of in
+       the playback/preroll phase.
+       Some cleanups, free the fakesrc elements.
+
 2004-11-09  Benjamin Otte  <in7y118@public.uni-hamburg.de>
 
        * ext/alsa/gstalsa.c: (gst_alsa_get_caps_internal):
index 7a00a9a..22a3037 100644 (file)
@@ -43,7 +43,6 @@ baseplaybin:
   - reuse, cleanup in ready state
   - when the first pad is closed, it's possible that another dynamic element is
     added somewhere so that we need a queue for the first pad as well.
-  - make sure we get EOS on all pads in a group before commiting the next group.
 
 playbin:
   
@@ -59,7 +58,6 @@ playbin:
    - be smarter about replugging the sinks instead of removing them and readding them.
    - Do not crap out when the audio device is in use.
 
-
 general
 
    TODO
index f8e1bb2..300e393 100644 (file)
@@ -262,6 +262,7 @@ group_destroy (GstPlayBaseGroup * group)
     GstElement *element = GST_ELEMENT (prerolls->data);
     GstPad *pad;
     guint sig_id;
+    GstElement *fakesrc;
 
     /* have to unlink the unlink handler first because else we
      * are going to link an element in the finalize handler */
@@ -275,10 +276,20 @@ group_destroy (GstPlayBaseGroup * group)
       g_object_set_data (G_OBJECT (pad), "unlinked_id", GINT_TO_POINTER (0));
     }
 
+    /* remove any fakesrc elements for this preroll element */
+    fakesrc = (GstElement *) g_object_get_data (G_OBJECT (element), "fakesrc");
+    if (fakesrc != NULL) {
+      GST_LOG ("removing fakesrc");
+      gst_bin_remove (GST_BIN (play_base_bin->thread), fakesrc);
+    }
+
+    /* if the group is currently being played, we have to remove the element 
+     * from the thread */
     if (get_active_group (play_base_bin) == group) {
       GST_LOG ("removing preroll element %s", gst_element_get_name (element));
       gst_bin_remove (GST_BIN (play_base_bin->thread), element);
     } else {
+      /* else we can just unref it */
       gst_object_unref (GST_OBJECT (element));
     }
   }
@@ -336,6 +347,22 @@ group_commit (GstPlayBaseBin * play_base_bin)
   g_mutex_unlock (play_base_bin->group_lock);
 }
 
+/* check if there are streams in the group that are not muted */
+static gboolean
+group_is_muted (GstPlayBaseGroup * group)
+{
+  GList *infos;
+
+  for (infos = group->streaminfo; infos; infos = g_list_next (infos)) {
+    GstStreamInfo *info = GST_STREAM_INFO (infos->data);
+
+    /* if we find a non muded group we can return FALSE */
+    if (!info->mute)
+      return FALSE;
+  }
+  return TRUE;
+}
+
 /* this signal will be fired when one of the queues with raw
  * data is filled. This means that the group building stage is over 
  * and playback of the new queued group should start */
@@ -400,11 +427,13 @@ remove_groups (GstPlayBaseBin * play_base_bin)
 /* Add/remove a single stream to current  building group.
  */
 static void
-add_stream (GstPlayBaseBin * play_base_bin, GstStreamInfo * info)
+add_stream (GstPlayBaseGroup * group, GstStreamInfo * info)
 {
-  GstPlayBaseGroup *group = get_building_group (play_base_bin);
+  GST_DEBUG ("add stream to group %p", group);
+
+  /* keep ref to the group */
+  g_object_set_data (G_OBJECT (info), "group", group);
 
-  GST_DEBUG ("add stream to building group %p", group);
   group->streaminfo = g_list_append (group->streaminfo, info);
   switch (info->type) {
     case GST_STREAM_TYPE_AUDIO:
@@ -428,6 +457,7 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
 {
   gchar *capsstr;
   GstStreamInfo *info;
+  GstPlayBaseGroup *group = get_building_group (play_base_bin);
 
   capsstr = gst_caps_to_string (caps);
   g_warning ("don't know how to handle %s", capsstr);
@@ -436,7 +466,7 @@ unknown_type (GstElement * element, GstPad * pad, GstCaps * caps,
   info = gst_stream_info_new (GST_OBJECT (pad), GST_STREAM_TYPE_UNKNOWN,
       NULL, caps);
   info->origin = GST_OBJECT (pad);
-  add_stream (play_base_bin, info);
+  add_stream (group, info);
 
   g_free (capsstr);
 }
@@ -450,13 +480,14 @@ static void
 add_element_stream (GstElement * element, GstPlayBaseBin * play_base_bin)
 {
   GstStreamInfo *info;
+  GstPlayBaseGroup *group = get_building_group (play_base_bin);
 
   /* add the stream to the list */
   info =
       gst_stream_info_new (GST_OBJECT (element), GST_STREAM_TYPE_ELEMENT,
       NULL, NULL);
   info->origin = GST_OBJECT (element);
-  add_stream (play_base_bin, info);
+  add_stream (group, info);
 }
 
 /* when the decoder element signals that no more pads will be generated, we
@@ -467,31 +498,45 @@ no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
 {
   /* setup phase */
   GST_DEBUG ("no more pads");
+  /* we can commit this group for playback now */
   group_commit (play_base_bin);
 }
 
 static gboolean
 probe_triggered (GstProbe * probe, GstData ** data, gpointer user_data)
 {
-  GstPlayBaseGroup *group = (GstPlayBaseGroup *) user_data;
-  GstPlayBaseBin *play_base_bin = group->bin;
+  GstPlayBaseGroup *group;
+  GstPlayBaseBin *play_base_bin;
+  GstStreamInfo *info = GST_STREAM_INFO (user_data);
+
+  group = (GstPlayBaseGroup *) g_object_get_data (G_OBJECT (info), "group");
+  play_base_bin = group->bin;
 
   if (GST_IS_EVENT (*data)) {
     GstEvent *event = GST_EVENT (*data);
 
     if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
-      gint queued;
+      gboolean have_left;
 
       GST_DEBUG ("probe got EOS in group %p", group);
 
-      /* FIXME there might be more streams in this group that need
-       * to go to EOS before we can switch to the next group. So
-       * here we should mark the stream as EOSed and decide if all
-       * streams have EOSed before continuing. */
+      /* mute this stream */
+      g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
 
       /* see if we have some more groups left to play */
-      queued = g_list_length (play_base_bin->queued_groups);
-      if (queued > 1) {
+      have_left = (g_list_length (play_base_bin->queued_groups) > 1);
+
+      /* see if the complete group is muted */
+      if (!group_is_muted (group)) {
+        /* group is not completely muted, we remove the EOS event
+         * and continue, eventually the other streams will be EOSed and
+         * we can switch out this group. */
+        GST_DEBUG ("group %p not completely muted", group);
+        /* remove the EOS if we have something left */
+        return !have_left;
+      }
+
+      if (have_left) {
         gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
         /* ok, get rid of the current group then */
         group_destroy (group);
@@ -512,6 +557,27 @@ probe_triggered (GstProbe * probe, GstData ** data, gpointer user_data)
         /* get rid of the EOS event */
         return FALSE;
       }
+    } else if (GST_EVENT_TYPE (event) == GST_EVENT_TAG) {
+      GstTagList *taglist;
+      GstObject *source;
+
+      /* ref some to be sure.. */
+      gst_event_ref (event);
+      gst_object_ref (GST_OBJECT (play_base_bin));
+      taglist = gst_event_tag_get_list (event);
+      /* now try to find the source of this tag */
+      source = event->src;
+      if (source == NULL || !GST_IS_ELEMENT (source)) {
+        /* no source, just use playbasebin then. This happens almost
+         * all the time, it seems the source is never filled in... */
+        source = GST_OBJECT (play_base_bin);
+      }
+      /* emit the signal now */
+      g_signal_emit_by_name (G_OBJECT (play_base_bin),
+          "found-tag", source, taglist);
+      /* and unref */
+      gst_object_unref (GST_OBJECT (play_base_bin));
+      gst_event_unref (event);
     }
   }
   return TRUE;
@@ -525,9 +591,10 @@ static void
 preroll_unlinked (GstPad * pad, GstPad * peerpad,
     GstPlayBaseBin * play_base_bin)
 {
-  GstElement *fakesrc;
+  GstElement *fakesrc, *queue;
   guint sig_id;
 
+  /* make a fakesrc that will just emit one EOS */
   fakesrc = gst_element_factory_make ("fakesrc", NULL);
   g_object_set (G_OBJECT (fakesrc), "num_buffers", 0, NULL);
 
@@ -536,8 +603,13 @@ preroll_unlinked (GstPad * pad, GstPad * peerpad,
   gst_pad_link (gst_element_get_pad (fakesrc, "src"), pad);
   gst_bin_add (GST_BIN (play_base_bin->thread), fakesrc);
 
-  sig_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "unlinked_id"));
+  /* keep track of these patch elements */
+  queue = GST_ELEMENT (gst_object_get_parent (GST_OBJECT (pad)));
+  g_object_set_data (G_OBJECT (queue), "fakesrc", fakesrc);
 
+  /* now unlink the unlinked signal so that it is not called again when
+   * we destroy the queue */
+  sig_id = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "unlinked_id"));
   if (sig_id != 0) {
     g_signal_handler_disconnect (G_OBJECT (pad), sig_id);
     g_object_set_data (G_OBJECT (pad), "unlinked_id", GINT_TO_POINTER (0));
@@ -627,15 +699,15 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
 
     gst_element_set_state (new_element, GST_STATE_PAUSED);
   }
-  /* install a probe so that we know when this group has ended */
-  probe = gst_probe_new (FALSE, probe_triggered, group);
-
-  gst_pad_add_probe (GST_PAD_REALIZE (srcpad), probe);
-
   /* add the stream to the list */
   info = gst_stream_info_new (GST_OBJECT (srcpad), type, NULL, caps);
   info->origin = GST_OBJECT (pad);
-  add_stream (play_base_bin, info);
+  add_stream (group, info);
+
+  /* install a probe so that we know when this group has ended */
+  probe = gst_probe_new (FALSE, probe_triggered, info);
+  /* have to REALIZE the pad as we cannot attach a padprobe to a ghostpad */
+  gst_pad_add_probe (GST_PAD_REALIZE (srcpad), probe);
 
   /* signal the no more pads after adding the stream */
   if (last)
@@ -1181,27 +1253,38 @@ gst_play_base_bin_error (GstElement * element,
   gst_object_unref (parent);
 }
 
+/* this code does not do anything usefull as it catches the tags
+ * in the preroll and playback stage so that it is very difficult
+ * to link them to the actual playback point. 
+ *
+ * An alternative codepath can be found in the probe_triggered function
+ * where the tag is signaled when it is found inside the stream. The
+ * drawback is that we don't know the source anymore at that point because
+ * the event->src field appears to be left empty most of the time...
+ */
 static void
 gst_play_base_bin_found_tag (GstElement * element,
     GstElement * _source, const GstTagList * taglist, gpointer data)
 {
-  GstObject *source, *parent;
+  GstObject *source;
+  GstPlayBaseBin *play_base_bin;
 
   source = GST_OBJECT (_source);
-  parent = GST_OBJECT (data);
+  play_base_bin = GST_PLAY_BASE_BIN (data);
 
   /* tell ourselves */
   gst_object_ref (source);
-  gst_object_ref (parent);
+  gst_object_ref (GST_OBJECT (play_base_bin));
   GST_DEBUG ("forwarding taglist %p from %s to %s", taglist,
-      GST_ELEMENT_NAME (source), GST_OBJECT_NAME (parent));
+      GST_ELEMENT_NAME (source), GST_OBJECT_NAME (play_base_bin));
 
-  g_signal_emit_by_name (G_OBJECT (parent), "found-tag", source, taglist);
+  /* this would signal completely out-of-band */
+  //g_signal_emit_by_name (G_OBJECT (play_base_bin), "found-tag", source, taglist);
 
   GST_DEBUG ("forwarded taglist %p from %s to %s", taglist,
-      GST_ELEMENT_NAME (source), GST_OBJECT_NAME (parent));
+      GST_ELEMENT_NAME (source), GST_OBJECT_NAME (play_base_bin));
   gst_object_unref (source);
-  gst_object_unref (parent);
+  gst_object_unref (GST_OBJECT (play_base_bin));
 }
 
 gboolean
index b8faa2f..2ab0d56 100644 (file)
@@ -491,8 +491,6 @@ gen_vis_element (GstPlayBin * play_bin)
   gst_element_add_ghost_pad (element,
       gst_element_get_pad (tee, "sink"), "sink");
 
-  //gst_element_set_state (element, GST_STATE_READY);
-
   return element;
 }
 
index 4716f5c..62cdfcc 100644 (file)
@@ -231,12 +231,36 @@ stream_info_mute_pad (GstStreamInfo * stream_info, GstPad * pad, gboolean mute)
   }
 }
 
+gboolean
+gst_stream_info_set_mute (GstStreamInfo * stream_info, gboolean mute)
+{
+  g_return_val_if_fail (GST_IS_STREAM_INFO (stream_info), FALSE);
+
+  if (stream_info->type == GST_STREAM_TYPE_ELEMENT) {
+    g_warning ("cannot mute element stream");
+    return FALSE;
+  }
+
+  if (mute != stream_info->mute) {
+    stream_info->mute = mute;
+    stream_info_mute_pad (stream_info, GST_PAD (stream_info->object), mute);
+  }
+  return TRUE;
+}
+
+gboolean
+gst_stream_info_is_mute (GstStreamInfo * stream_info)
+{
+  g_return_val_if_fail (GST_IS_STREAM_INFO (stream_info), TRUE);
+
+  return stream_info->mute;
+}
+
 static void
 gst_stream_info_set_property (GObject * object, guint prop_id,
     const GValue * value, GParamSpec * pspec)
 {
   GstStreamInfo *stream_info;
-  gboolean new_mute;
 
   g_return_if_fail (GST_IS_STREAM_INFO (object));
 
@@ -244,20 +268,8 @@ gst_stream_info_set_property (GObject * object, guint prop_id,
 
   switch (prop_id) {
     case ARG_MUTE:
-    {
-      if (stream_info->type == GST_STREAM_TYPE_ELEMENT) {
-        g_warning ("cannot mute element stream");
-        break;
-      }
-      new_mute = g_value_get_boolean (value);
-
-      if (new_mute != stream_info->mute) {
-        stream_info->mute = new_mute;
-        stream_info_mute_pad (stream_info, GST_PAD (stream_info->object),
-            new_mute);
-      }
+      gst_stream_info_set_mute (stream_info, g_value_get_boolean (value));
       break;
-    }
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
index b5381ed..b6a7216 100644 (file)
@@ -36,21 +36,23 @@ typedef struct _GstStreamInfoClass GstStreamInfoClass;
 
 typedef enum {
   GST_STREAM_TYPE_UNKNOWN = 0,
-  GST_STREAM_TYPE_AUDIO   = 1,
-  GST_STREAM_TYPE_VIDEO   = 2,
-  GST_STREAM_TYPE_TEXT    = 3,
-  GST_STREAM_TYPE_ELEMENT = 4,
+  GST_STREAM_TYPE_AUDIO   = 1, /* an audio stream */
+  GST_STREAM_TYPE_VIDEO   = 2, /* a video stream */
+  GST_STREAM_TYPE_TEXT    = 3, /* a subtitle/text stream */
+  GST_STREAM_TYPE_ELEMENT = 4, /* stream handled by an element */
 } GstStreamType;
 
 struct _GstStreamInfo {
   GObject       parent;
 
-  GstObject    *object;
-  GstStreamType         type;
-  gchar        *decoder;
-  gboolean      mute;
-  GstObject    *origin;
-  GstCaps      *caps;
+  GstObject    *object;        /* pad/element providing/handling this stream */
+  GstStreamType         type;          /* the type of the provided stream */
+  gchar        *decoder;       /* string describing the decoder */
+  gboolean      mute;          /* is the stream muted or not */
+  GstObject    *origin;        /* the real object providing this stream, this can
+                                  be different from the object as the object can be
+                                  a queue pad, inserted for preroll. */
+  GstCaps      *caps;          /* the caps of the stream */
 };
 
 struct _GstStreamInfoClass {
@@ -62,10 +64,15 @@ struct _GstStreamInfoClass {
 
 GType gst_stream_info_get_type (void);
 
-GstStreamInfo* gst_stream_info_new (GstObject     *object,
-                                   GstStreamType  type,
-                                   const gchar   *decoder,
-                                   const GstCaps *caps);
+GstStreamInfo*         gst_stream_info_new             (GstObject     *object,
+                                                GstStreamType  type,
+                                                const gchar   *decoder,
+                                                const GstCaps *caps);
+
+gboolean       gst_stream_info_set_mute        (GstStreamInfo *stream_info, 
+                                                gboolean mute);
+gboolean       gst_stream_info_is_mute         (GstStreamInfo *stream_info);
+
 
 G_END_DECLS