From b398d11af9c4dd45be7da9857574a4b8eed6944f Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 9 Nov 2004 12:10:28 +0000 Subject: [PATCH] gst/playback/: Updated README. 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 | 18 +++++ gst/playback/README | 2 - gst/playback/gstplaybasebin.c | 141 +++++++++++++++++++++++++++------- gst/playback/gstplaybin.c | 2 - gst/playback/gststreaminfo.c | 40 ++++++---- gst/playback/gststreaminfo.h | 35 +++++---- 6 files changed, 177 insertions(+), 61 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1ee38ee863..dc16941930 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2004-11-09 Wim Taymans + + * 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 * ext/alsa/gstalsa.c: (gst_alsa_get_caps_internal): diff --git a/gst/playback/README b/gst/playback/README index 7a00a9a86c..22a3037ea8 100644 --- a/gst/playback/README +++ b/gst/playback/README @@ -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 diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c index f8e1bb2277..300e393995 100644 --- a/gst/playback/gstplaybasebin.c +++ b/gst/playback/gstplaybasebin.c @@ -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 diff --git a/gst/playback/gstplaybin.c b/gst/playback/gstplaybin.c index b8faa2f5c5..2ab0d564b0 100644 --- a/gst/playback/gstplaybin.c +++ b/gst/playback/gstplaybin.c @@ -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; } diff --git a/gst/playback/gststreaminfo.c b/gst/playback/gststreaminfo.c index 4716f5cd83..62cdfccccb 100644 --- a/gst/playback/gststreaminfo.c +++ b/gst/playback/gststreaminfo.c @@ -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; diff --git a/gst/playback/gststreaminfo.h b/gst/playback/gststreaminfo.h index b5381ed0e3..b6a72169b5 100644 --- a/gst/playback/gststreaminfo.h +++ b/gst/playback/gststreaminfo.h @@ -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