mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-23 18:21:04 +00:00
gst/playback/: Add support for chained ogg files. Prepare for playlist support. This patch introduces the concept of ...
Original commit message from CVS: * gst/playback/gstdecodebin.c: (unlinked): * gst/playback/gstplay-marshal.list: * gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init), (gst_play_base_bin_init), (group_create), (get_active_group), (get_building_group), (group_destroy), (group_commit), (queue_overrun), (remove_groups), (add_stream), (unknown_type), (add_element_stream), (no_more_pads), (probe_triggered), (preroll_unlinked), (new_decoded_pad), (removed_decoded_pad), (state_change), (setup_source), (gst_play_base_bin_get_property), (gst_play_base_bin_change_state), (gst_play_base_bin_add_element), (gst_play_base_bin_link_stream), (gst_play_base_bin_get_streaminfo): * gst/playback/gstplaybasebin.h: * gst/playback/gstplaybin.c: (gst_play_bin_class_init), (remove_sinks), (setup_sinks), (gst_play_bin_change_state): Add support for chained ogg files. Prepare for playlist support. This patch introduces the concept of pad groups, which together compose one playable media file.
This commit is contained in:
parent
4b8c8d5469
commit
ac515f710f
6 changed files with 468 additions and 150 deletions
21
ChangeLog
21
ChangeLog
|
@ -1,3 +1,24 @@
|
|||
2004-11-08 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/playback/gstdecodebin.c: (unlinked):
|
||||
* gst/playback/gstplay-marshal.list:
|
||||
* gst/playback/gstplaybasebin.c: (gst_play_base_bin_class_init),
|
||||
(gst_play_base_bin_init), (group_create), (get_active_group),
|
||||
(get_building_group), (group_destroy), (group_commit),
|
||||
(queue_overrun), (remove_groups), (add_stream), (unknown_type),
|
||||
(add_element_stream), (no_more_pads), (probe_triggered),
|
||||
(preroll_unlinked), (new_decoded_pad), (removed_decoded_pad),
|
||||
(state_change), (setup_source), (gst_play_base_bin_get_property),
|
||||
(gst_play_base_bin_change_state), (gst_play_base_bin_add_element),
|
||||
(gst_play_base_bin_link_stream),
|
||||
(gst_play_base_bin_get_streaminfo):
|
||||
* gst/playback/gstplaybasebin.h:
|
||||
* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
|
||||
(remove_sinks), (setup_sinks), (gst_play_bin_change_state):
|
||||
Add support for chained ogg files. Prepare for playlist
|
||||
support. This patch introduces the concept of pad groups, which
|
||||
together compose one playable media file.
|
||||
|
||||
2004-11-07 David Schleef <ds@schleef.org>
|
||||
|
||||
* testsuite/gst-lint: Check for pad templates that aren't statically
|
||||
|
|
|
@ -625,17 +625,6 @@ remove_element_chain (GstDecodeBin * decode_bin, GstPad * pad)
|
|||
gst_bin_remove (GST_BIN (decode_bin), elem);
|
||||
}
|
||||
|
||||
/* This function will be called when a pad is disconnected for some reason */
|
||||
static void
|
||||
unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
|
||||
{
|
||||
/* inactivate pad */
|
||||
gst_pad_set_active (pad, FALSE);
|
||||
|
||||
/* remove all elements linked to the peerpad */
|
||||
remove_element_chain (decode_bin, peerpad);
|
||||
}
|
||||
|
||||
/* This function will be called when a dynamic pad is created on an element.
|
||||
* We try to continue autoplugging on this new pad. */
|
||||
static void
|
||||
|
@ -682,6 +671,43 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
|
|||
}
|
||||
}
|
||||
|
||||
/* This function will be called when a pad is disconnected for some reason */
|
||||
static void
|
||||
unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
|
||||
{
|
||||
GList *walk;
|
||||
GstDynamic *dyn;
|
||||
GstElement *element;
|
||||
|
||||
/* inactivate pad */
|
||||
gst_pad_set_active (pad, FALSE);
|
||||
|
||||
/* remove all elements linked to the peerpad */
|
||||
remove_element_chain (decode_bin, peerpad);
|
||||
|
||||
/* if an element removes two pads, then we don't want this twice */
|
||||
element = gst_pad_get_parent (pad);
|
||||
for (walk = decode_bin->dynamics; walk != NULL; walk = walk->next) {
|
||||
dyn = walk->data;
|
||||
if (dyn->element == element)
|
||||
return;
|
||||
}
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "pad removal while alive - chained?");
|
||||
|
||||
/* re-setup dynamic plugging */
|
||||
dyn = g_new0 (GstDynamic, 1);
|
||||
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
|
||||
G_CALLBACK (new_pad), dyn);
|
||||
dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
|
||||
G_CALLBACK (no_more_pads), dyn);
|
||||
dyn->element = element;
|
||||
dyn->decode_bin = decode_bin;
|
||||
|
||||
/* and add this element to the dynamic elements */
|
||||
decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
|
||||
}
|
||||
|
||||
/* this function inspects the given element and tries to connect something
|
||||
* on the srcpads. If there are dynamic pads, it sets up a signal handler to
|
||||
* continue autoplugging when they become available */
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
VOID:OBJECT,OBJECT
|
||||
BOOLEAN:OBJECT,OBJECT
|
||||
VOID:OBJECT,BOOLEAN
|
||||
|
|
|
@ -44,7 +44,8 @@ enum
|
|||
/* signals */
|
||||
enum
|
||||
{
|
||||
MUTE_STREAM_SIGNAL,
|
||||
SETUP_OUTPUT_PADS_SIGNAL,
|
||||
REMOVED_OUTPUT_PAD_SIGNAL,
|
||||
LINK_STREAM_SIGNAL,
|
||||
UNLINK_STREAM_SIGNAL,
|
||||
LAST_SIGNAL
|
||||
|
@ -129,7 +130,7 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
|
|||
g_object_class_install_property (gobject_klass, ARG_QUEUE_SIZE,
|
||||
g_param_spec_uint64 ("queue-size", "Queue size",
|
||||
"Size of internal queues in nanoseconds", 0, G_MAXINT64,
|
||||
DEFAULT_QUEUE_SIZE, G_PARAM_READABLE));
|
||||
DEFAULT_QUEUE_SIZE, G_PARAM_READWRITE));
|
||||
g_object_class_install_property (gobject_klass, ARG_STREAMINFO,
|
||||
g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo",
|
||||
G_PARAM_READABLE));
|
||||
|
@ -137,14 +138,29 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
|
|||
GST_DEBUG_CATEGORY_INIT (gst_play_base_bin_debug, "playbasebin", 0,
|
||||
"playbasebin");
|
||||
|
||||
/* signals */
|
||||
gst_play_base_bin_signals[SETUP_OUTPUT_PADS_SIGNAL] =
|
||||
g_signal_new ("setup-output-pads", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstPlayBaseBinClass, setup_output_pads),
|
||||
NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
|
||||
gst_play_base_bin_signals[REMOVED_OUTPUT_PAD_SIGNAL] =
|
||||
g_signal_new ("removed-output-pad", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (GstPlayBaseBinClass, removed_output_pad),
|
||||
NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
||||
|
||||
/* action signals */
|
||||
gst_play_base_bin_signals[LINK_STREAM_SIGNAL] =
|
||||
g_signal_new ("link-stream", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
|
||||
g_signal_new ("link-stream", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (GstPlayBaseBinClass, link_stream),
|
||||
NULL, NULL, gst_play_marshal_VOID__OBJECT_OBJECT, G_TYPE_NONE, 2,
|
||||
NULL, NULL, gst_play_marshal_BOOLEAN__OBJECT_OBJECT, G_TYPE_BOOLEAN, 2,
|
||||
G_TYPE_OBJECT, GST_TYPE_PAD);
|
||||
gst_play_base_bin_signals[UNLINK_STREAM_SIGNAL] =
|
||||
g_signal_new ("unlink-stream", G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstPlayBaseBinClass, unlink_stream),
|
||||
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
||||
G_STRUCT_OFFSET (GstPlayBaseBinClass, unlink_stream),
|
||||
NULL, NULL, gst_marshal_VOID__OBJECT, G_TYPE_NONE, 1, G_TYPE_OBJECT);
|
||||
|
||||
gobject_klass->dispose = GST_DEBUG_FUNCPTR (gst_play_base_bin_dispose);
|
||||
|
@ -170,9 +186,12 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
|
|||
play_base_bin->source = NULL;
|
||||
play_base_bin->decoder = NULL;
|
||||
|
||||
play_base_bin->preroll_lock = g_mutex_new ();
|
||||
play_base_bin->preroll_cond = g_cond_new ();
|
||||
play_base_bin->preroll_elems = NULL;
|
||||
play_base_bin->group_lock = g_mutex_new ();
|
||||
play_base_bin->group_cond = g_cond_new ();
|
||||
|
||||
play_base_bin->building_group = NULL;
|
||||
play_base_bin->queued_groups = NULL;
|
||||
|
||||
play_base_bin->queue_size = DEFAULT_QUEUE_SIZE;
|
||||
|
||||
GST_FLAG_SET (play_base_bin, GST_BIN_SELF_SCHEDULABLE);
|
||||
|
@ -192,18 +211,139 @@ gst_play_base_bin_dispose (GObject * object)
|
|||
}
|
||||
}
|
||||
|
||||
static GstPlayBaseGroup *
|
||||
group_create (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstPlayBaseGroup *group;
|
||||
|
||||
group = g_new0 (GstPlayBaseGroup, 1);
|
||||
group->bin = play_base_bin;
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
static GstPlayBaseGroup *
|
||||
get_active_group (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
if (play_base_bin->queued_groups) {
|
||||
return (GstPlayBaseGroup *) play_base_bin->queued_groups->data;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* get the group used for discovering the different streams.
|
||||
* This function creates a group is there is none.
|
||||
*/
|
||||
static GstPlayBaseGroup *
|
||||
get_building_group (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstPlayBaseGroup *group;
|
||||
|
||||
group = play_base_bin->building_group;
|
||||
|
||||
if (group == NULL) {
|
||||
group = group_create (play_base_bin);
|
||||
play_base_bin->building_group = group;
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
static void
|
||||
group_destroy (GstPlayBaseGroup * group)
|
||||
{
|
||||
GstPlayBaseBin *play_base_bin = group->bin;
|
||||
GList *prerolls, *infos;
|
||||
|
||||
GST_LOG ("removing group %p", group);
|
||||
|
||||
/* remove the preroll queues */
|
||||
for (prerolls = group->preroll_elems; prerolls;
|
||||
prerolls = g_list_next (prerolls)) {
|
||||
GstElement *element = GST_ELEMENT (prerolls->data);
|
||||
GstPad *pad;
|
||||
guint sig_id;
|
||||
|
||||
/* have to unlink the unlink handler first because else we
|
||||
* are going to link an element in the finalize handler */
|
||||
pad = gst_element_get_pad (element, "sink");
|
||||
sig_id =
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (pad), "unlinked_id"));
|
||||
|
||||
if (sig_id != 0) {
|
||||
GST_LOG ("removing unlink signal %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
g_signal_handler_disconnect (G_OBJECT (pad), sig_id);
|
||||
g_object_set_data (G_OBJECT (pad), "unlinked_id", GINT_TO_POINTER (0));
|
||||
}
|
||||
|
||||
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 {
|
||||
gst_object_unref (GST_OBJECT (element));
|
||||
}
|
||||
}
|
||||
g_list_free (group->preroll_elems);
|
||||
|
||||
/* free the streaminfo too */
|
||||
for (infos = group->streaminfo; infos; infos = g_list_next (infos)) {
|
||||
GstStreamInfo *info = GST_STREAM_INFO (infos->data);
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
g_list_free (group->streaminfo);
|
||||
g_free (group);
|
||||
}
|
||||
|
||||
/* is called when the current building group is completely finished
|
||||
* and ready for playback
|
||||
*/
|
||||
static void
|
||||
group_commit (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstPlayBaseGroup *group = play_base_bin->building_group;
|
||||
GList *prerolls;
|
||||
|
||||
/* if an element signalled a no-more-pads after we stopped due
|
||||
* to preroll, the group is NULL. This is not an error */
|
||||
if (group == NULL)
|
||||
return;
|
||||
|
||||
GST_DEBUG ("group %p done", group);
|
||||
|
||||
play_base_bin->queued_groups = g_list_append (play_base_bin->queued_groups,
|
||||
group);
|
||||
|
||||
play_base_bin->building_group = NULL;
|
||||
|
||||
/* remove signals. We don't want anymore signals from the preroll
|
||||
* elements at this stage. */
|
||||
for (prerolls = group->preroll_elems; prerolls;
|
||||
prerolls = g_list_next (prerolls)) {
|
||||
GstElement *element = GST_ELEMENT (prerolls->data);
|
||||
guint sig_id;
|
||||
|
||||
sig_id =
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (element), "signal_id"));
|
||||
|
||||
GST_LOG ("removing preroll signal %s", gst_element_get_name (element));
|
||||
g_signal_handler_disconnect (G_OBJECT (element), sig_id);
|
||||
}
|
||||
|
||||
g_mutex_lock (play_base_bin->group_lock);
|
||||
GST_DEBUG ("signal group done");
|
||||
g_cond_signal (play_base_bin->group_cond);
|
||||
GST_DEBUG ("signaled group done");
|
||||
g_mutex_unlock (play_base_bin->group_lock);
|
||||
}
|
||||
|
||||
/* this signal will be fired when one of the queues with raw
|
||||
* data is filled. This means that the preroll stage is over and
|
||||
* playback should start */
|
||||
* data is filled. This means that the group building stage is over
|
||||
* and playback of the new queued group should start */
|
||||
static void
|
||||
queue_overrun (GstElement * element, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GST_DEBUG ("queue %s overrun", gst_element_get_name (element));
|
||||
g_mutex_lock (play_base_bin->preroll_lock);
|
||||
GST_DEBUG ("signal preroll done");
|
||||
g_cond_signal (play_base_bin->preroll_cond);
|
||||
GST_DEBUG ("signaled preroll done");
|
||||
g_mutex_unlock (play_base_bin->preroll_lock);
|
||||
group_commit (play_base_bin);
|
||||
}
|
||||
|
||||
/* generate a preroll element which is simply a queue. While there
|
||||
|
@ -236,33 +376,47 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin, GstPad * pad)
|
|||
}
|
||||
|
||||
static void
|
||||
remove_prerolls (GstPlayBaseBin * play_base_bin)
|
||||
remove_groups (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GList *prerolls, *infos;
|
||||
GList *groups;
|
||||
|
||||
/* remove the preroll queues */
|
||||
for (prerolls = play_base_bin->preroll_elems; prerolls;
|
||||
prerolls = g_list_next (prerolls)) {
|
||||
GstElement *element = GST_ELEMENT (prerolls->data);
|
||||
|
||||
GST_LOG ("removing preroll element %s", gst_element_get_name (element));
|
||||
gst_bin_remove (GST_BIN (play_base_bin->thread), element);
|
||||
/* first destroy the group we were building if any */
|
||||
if (play_base_bin->building_group) {
|
||||
group_destroy (play_base_bin->building_group);
|
||||
play_base_bin->building_group = NULL;
|
||||
}
|
||||
g_list_free (play_base_bin->preroll_elems);
|
||||
play_base_bin->preroll_elems = NULL;
|
||||
|
||||
/* free the streaminfo too */
|
||||
for (infos = play_base_bin->streaminfo; infos; infos = g_list_next (infos)) {
|
||||
GstStreamInfo *info = GST_STREAM_INFO (infos->data);
|
||||
/* remove the queued groups */
|
||||
for (groups = play_base_bin->queued_groups; groups;
|
||||
groups = g_list_next (groups)) {
|
||||
GstPlayBaseGroup *group = (GstPlayBaseGroup *) groups->data;
|
||||
|
||||
g_object_unref (info);
|
||||
group_destroy (group);
|
||||
}
|
||||
g_list_free (play_base_bin->queued_groups);
|
||||
play_base_bin->queued_groups = NULL;
|
||||
}
|
||||
|
||||
/* Add/remove a single stream to current building group.
|
||||
*/
|
||||
static void
|
||||
add_stream (GstPlayBaseBin * play_base_bin, GstStreamInfo * info)
|
||||
{
|
||||
GstPlayBaseGroup *group = get_building_group (play_base_bin);
|
||||
|
||||
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:
|
||||
group->naudiopads++;
|
||||
break;
|
||||
case GST_STREAM_TYPE_VIDEO:
|
||||
group->nvideopads++;
|
||||
break;
|
||||
default:
|
||||
group->nunknownpads++;
|
||||
break;
|
||||
}
|
||||
g_list_free (play_base_bin->streaminfo);
|
||||
play_base_bin->streaminfo = NULL;
|
||||
play_base_bin->nstreams = 0;
|
||||
play_base_bin->naudiopads = 0;
|
||||
play_base_bin->nvideopads = 0;
|
||||
play_base_bin->nunknownpads = 0;
|
||||
}
|
||||
|
||||
/* signal fired when an unknown stream is found. We create a new
|
||||
|
@ -282,7 +436,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);
|
||||
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
|
||||
add_stream (play_base_bin, info);
|
||||
|
||||
g_free (capsstr);
|
||||
}
|
||||
|
@ -302,23 +456,90 @@ add_element_stream (GstElement * element, GstPlayBaseBin * play_base_bin)
|
|||
gst_stream_info_new (GST_OBJECT (element), GST_STREAM_TYPE_ELEMENT,
|
||||
NULL, NULL);
|
||||
info->origin = GST_OBJECT (element);
|
||||
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
|
||||
add_stream (play_base_bin, info);
|
||||
}
|
||||
|
||||
/* when the decoder element signals that no more pads will be generated, we
|
||||
* can stop the preroll
|
||||
* can commit the current group.
|
||||
*/
|
||||
static void
|
||||
no_more_pads (GstElement * element, GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
/* setup phase */
|
||||
GST_DEBUG ("no more pads");
|
||||
g_mutex_lock (play_base_bin->preroll_lock);
|
||||
GST_DEBUG ("signal preroll done");
|
||||
g_cond_signal (play_base_bin->preroll_cond);
|
||||
GST_DEBUG ("signaled preroll done");
|
||||
g_mutex_unlock (play_base_bin->preroll_lock);
|
||||
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;
|
||||
|
||||
if (GST_IS_EVENT (*data)) {
|
||||
GstEvent *event = GST_EVENT (*data);
|
||||
|
||||
if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
|
||||
gint queued;
|
||||
|
||||
GST_DEBUG ("probe got EOS in group %p", group);
|
||||
|
||||
/* see if we have some more groups left to play */
|
||||
queued = g_list_length (play_base_bin->queued_groups);
|
||||
if (queued > 1) {
|
||||
gst_element_set_state (play_base_bin->thread, GST_STATE_PAUSED);
|
||||
/* ok, get rid of the current group then */
|
||||
group_destroy (group);
|
||||
/* removing the current group brings the next group
|
||||
* active */
|
||||
play_base_bin->queued_groups =
|
||||
g_list_delete_link (play_base_bin->queued_groups,
|
||||
play_base_bin->queued_groups);
|
||||
GST_DEBUG ("switching to next group %p",
|
||||
play_base_bin->queued_groups->data);
|
||||
/* and signal the new group */
|
||||
GST_DEBUG ("emit signal");
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[SETUP_OUTPUT_PADS_SIGNAL], 0);
|
||||
|
||||
gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING);
|
||||
|
||||
/* get rid of the EOS event */
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* This function will be called when the sinkpad of the preroll element
|
||||
* is unlinked, we have to connect something to the sinkpad or else the
|
||||
* state change will fail..
|
||||
*/
|
||||
static void
|
||||
preroll_unlinked (GstPad * pad, GstPad * peerpad,
|
||||
GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstElement *fakesrc;
|
||||
guint sig_id;
|
||||
|
||||
fakesrc = gst_element_factory_make ("fakesrc", NULL);
|
||||
g_object_set (G_OBJECT (fakesrc), "num_buffers", 0, NULL);
|
||||
|
||||
GST_DEBUG ("patching unlinked pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
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"));
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* signal fired when decodebin has found a new raw pad. We create
|
||||
* a preroll element if needed and the appropriate streaminfo.
|
||||
*/
|
||||
|
@ -334,6 +555,8 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
|||
GstStreamType type;
|
||||
GstPad *srcpad;
|
||||
gboolean need_preroll;
|
||||
GstPlayBaseGroup *group;
|
||||
GstProbe *probe;
|
||||
|
||||
GST_DEBUG ("play base: new decoded pad %d", last);
|
||||
|
||||
|
@ -348,33 +571,35 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
|||
structure = gst_caps_get_structure (caps, 0);
|
||||
mimetype = gst_structure_get_name (structure);
|
||||
|
||||
play_base_bin->nstreams++;
|
||||
group = get_building_group (play_base_bin);
|
||||
|
||||
group->nstreams++;
|
||||
|
||||
need_preroll = FALSE;
|
||||
|
||||
if (g_str_has_prefix (mimetype, "audio/")) {
|
||||
type = GST_STREAM_TYPE_AUDIO;
|
||||
play_base_bin->naudiopads++;
|
||||
/* first audio pad gets a preroll element */
|
||||
if (play_base_bin->naudiopads == 1) {
|
||||
if (group->naudiopads == 0) {
|
||||
need_preroll = TRUE;
|
||||
}
|
||||
} else if (g_str_has_prefix (mimetype, "video/")) {
|
||||
type = GST_STREAM_TYPE_VIDEO;
|
||||
play_base_bin->nvideopads++;
|
||||
/* first video pad gets a preroll element */
|
||||
if (play_base_bin->nvideopads == 1) {
|
||||
if (group->nvideopads == 0) {
|
||||
need_preroll = TRUE;
|
||||
}
|
||||
} else {
|
||||
type = GST_STREAM_TYPE_UNKNOWN;
|
||||
play_base_bin->nunknownpads++;
|
||||
}
|
||||
|
||||
if (last || !need_preroll) {
|
||||
GST_DEBUG ("play base: pad does not need preroll");
|
||||
srcpad = pad;
|
||||
} else {
|
||||
guint sig;
|
||||
GstPad *sinkpad;
|
||||
|
||||
GST_DEBUG ("play base: pad needs preroll");
|
||||
|
||||
new_element = gen_preroll_element (play_base_bin, pad);
|
||||
|
@ -382,59 +607,49 @@ new_decoded_pad (GstElement * element, GstPad * pad, gboolean last,
|
|||
gst_bin_add (GST_BIN (play_base_bin->thread), new_element);
|
||||
play_base_bin->threaded = TRUE;
|
||||
|
||||
play_base_bin->preroll_elems =
|
||||
g_list_prepend (play_base_bin->preroll_elems, new_element);
|
||||
group->preroll_elems = g_list_prepend (group->preroll_elems, new_element);
|
||||
|
||||
gst_element_set_state (new_element, GST_STATE_READY);
|
||||
|
||||
gst_pad_link (pad, gst_element_get_pad (new_element, "sink"));
|
||||
sinkpad = gst_element_get_pad (new_element, "sink");
|
||||
gst_pad_link (pad, sinkpad);
|
||||
/* make sure we catch unlink signals */
|
||||
sig = g_signal_connect (G_OBJECT (sinkpad), "unlinked",
|
||||
G_CALLBACK (preroll_unlinked), play_base_bin);
|
||||
/* keep a ref to the signal id so that we can disconnect the signal callback */
|
||||
g_object_set_data (G_OBJECT (sinkpad), "unlinked_id",
|
||||
GINT_TO_POINTER (sig));
|
||||
|
||||
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);
|
||||
play_base_bin->streaminfo = g_list_append (play_base_bin->streaminfo, info);
|
||||
add_stream (play_base_bin, info);
|
||||
|
||||
/* signal the no more pads after adding the stream */
|
||||
if (last)
|
||||
no_more_pads (NULL, play_base_bin);
|
||||
}
|
||||
|
||||
/* signal fired when decodebin has removed a raw pad. We remove
|
||||
* the preroll element if needed and the appropriate streaminfo.
|
||||
*/
|
||||
|
||||
/* nothing, really... We have already dealt with this because
|
||||
* we have the EOS padprobe installed on each pad */
|
||||
static void
|
||||
removed_decoded_pad (GstElement * element, GstPad * pad,
|
||||
GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GList *streams;
|
||||
|
||||
GST_DEBUG ("removing decoded pad %s:%s", GST_DEBUG_PAD_NAME (pad));
|
||||
|
||||
/* first find the stream to decode this pad */
|
||||
streams = play_base_bin->streaminfo;
|
||||
while (streams) {
|
||||
GstStreamInfo *info = GST_STREAM_INFO (streams->data);
|
||||
|
||||
if (info->origin == GST_OBJECT (pad)) {
|
||||
GST_DEBUG ("removing stream %p", info);
|
||||
play_base_bin->streaminfo =
|
||||
g_list_remove (play_base_bin->streaminfo, info);
|
||||
g_object_unref (info);
|
||||
return;
|
||||
} else {
|
||||
GST_DEBUG ("skipping stream %p", info);
|
||||
}
|
||||
streams = g_list_next (streams);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Cache errors...
|
||||
*/
|
||||
|
||||
static void
|
||||
thread_error (GstElement * element,
|
||||
GstElement * orig, GError * error, const gchar * debug, gpointer data)
|
||||
|
@ -456,13 +671,9 @@ state_change (GstElement * element,
|
|||
GstPlayBaseBin *play_base_bin = GST_PLAY_BASE_BIN (data);
|
||||
|
||||
if (old_state > new_state) {
|
||||
/* EOS or error occurred */
|
||||
/* EOS or error occurred, we have to commit the current group */
|
||||
GST_DEBUG ("state changed downwards");
|
||||
g_mutex_lock (play_base_bin->preroll_lock);
|
||||
GST_DEBUG ("signal preroll done");
|
||||
g_cond_signal (play_base_bin->preroll_cond);
|
||||
GST_DEBUG ("signaled preroll done");
|
||||
g_mutex_unlock (play_base_bin->preroll_lock);
|
||||
group_commit (play_base_bin);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,15 +721,18 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
|
|||
old_dec = play_base_bin->decoder;
|
||||
if (old_dec) {
|
||||
GST_LOG ("removing old decoder element %s", gst_element_get_name (old_dec));
|
||||
/* keep a ref to the old decoder as we might need to add it again
|
||||
* to the bin if we can't find a new decoder */
|
||||
gst_object_ref (GST_OBJECT (old_dec));
|
||||
gst_bin_remove (GST_BIN (play_base_bin->thread), old_dec);
|
||||
}
|
||||
|
||||
/* remove our previous preroll queues */
|
||||
remove_prerolls (play_base_bin);
|
||||
remove_groups (play_base_bin);
|
||||
|
||||
/* now see if the source element emits raw audio/video all by itself,
|
||||
* if so, we can create streams for the pads and be done with it.
|
||||
* Also check that is has source pads, if now, we assume it will
|
||||
* Also check that is has source pads, if not, we assume it will
|
||||
* do everything itself.
|
||||
*/
|
||||
{
|
||||
|
@ -558,12 +772,14 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
|
|||
}
|
||||
}
|
||||
if (is_raw) {
|
||||
no_more_pads (play_base_bin->source, play_base_bin);
|
||||
return TRUE;
|
||||
}
|
||||
if (no_out) {
|
||||
/* create a stream to indicate that this uri is handled by a self
|
||||
* contained element */
|
||||
add_element_stream (play_base_bin->source, play_base_bin);
|
||||
no_more_pads (play_base_bin->source, play_base_bin);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
@ -582,6 +798,9 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
|
|||
/* ref decoder so that the bin does not take ownership */
|
||||
gst_object_ref (GST_OBJECT (play_base_bin->decoder));
|
||||
gst_bin_add (GST_BIN (play_base_bin->thread), play_base_bin->decoder);
|
||||
/* now we can really get rid of the old decoder */
|
||||
if (old_dec)
|
||||
gst_object_unref (GST_OBJECT (old_dec));
|
||||
}
|
||||
|
||||
res = gst_pad_link (srcpad,
|
||||
|
@ -604,44 +823,25 @@ setup_source (GstPlayBaseBin * play_base_bin, GError ** error)
|
|||
/* either when the queues are filled or when the decoder element has no more
|
||||
* dynamic streams, the cond is unlocked. We can remove the signal handlers then
|
||||
*/
|
||||
g_mutex_lock (play_base_bin->preroll_lock);
|
||||
g_mutex_lock (play_base_bin->group_lock);
|
||||
if (gst_element_set_state (play_base_bin->thread, GST_STATE_PLAYING) ==
|
||||
GST_STATE_SUCCESS) {
|
||||
GList *prerolls;
|
||||
|
||||
GST_DEBUG ("waiting for preroll...");
|
||||
GST_DEBUG ("waiting for first group...");
|
||||
sig6 = g_signal_connect (G_OBJECT (play_base_bin->thread),
|
||||
"state-change", G_CALLBACK (state_change), play_base_bin);
|
||||
g_cond_wait (play_base_bin->preroll_cond, play_base_bin->preroll_lock);
|
||||
GST_DEBUG ("preroll done !");
|
||||
|
||||
/* remove signals */
|
||||
for (prerolls = play_base_bin->preroll_elems; prerolls;
|
||||
prerolls = g_list_next (prerolls)) {
|
||||
GstElement *element = GST_ELEMENT (prerolls->data);
|
||||
guint sig_id;
|
||||
|
||||
sig_id =
|
||||
GPOINTER_TO_INT (g_object_get_data (G_OBJECT (element),
|
||||
"signal_id"));
|
||||
|
||||
GST_LOG ("removing preroll signal %s", gst_element_get_name (element));
|
||||
g_signal_handler_disconnect (G_OBJECT (element), sig_id);
|
||||
}
|
||||
g_cond_wait (play_base_bin->group_cond, play_base_bin->group_lock);
|
||||
GST_DEBUG ("group done !");
|
||||
} else {
|
||||
GST_DEBUG ("state change failed, media cannot be loaded");
|
||||
sig6 = 0;
|
||||
}
|
||||
g_mutex_unlock (play_base_bin->preroll_lock);
|
||||
g_mutex_unlock (play_base_bin->group_lock);
|
||||
|
||||
if (sig6 != 0)
|
||||
g_signal_handler_disconnect (G_OBJECT (play_base_bin->thread), sig6);
|
||||
|
||||
g_signal_handler_disconnect (G_OBJECT (play_base_bin->thread), sig5);
|
||||
g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig4);
|
||||
g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig3);
|
||||
//g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig2);
|
||||
//g_signal_handler_disconnect (G_OBJECT (play_base_bin->decoder), sig1);
|
||||
|
||||
play_base_bin->need_rebuild = FALSE;
|
||||
}
|
||||
|
@ -704,13 +904,22 @@ gst_play_base_bin_get_property (GObject * object, guint prop_id, GValue * value,
|
|||
g_value_set_string (value, play_base_bin->uri);
|
||||
break;
|
||||
case ARG_NSTREAMS:
|
||||
g_value_set_int (value, play_base_bin->nstreams);
|
||||
{
|
||||
GstPlayBaseGroup *group = get_active_group (play_base_bin);
|
||||
|
||||
if (group) {
|
||||
g_value_set_int (value, group->nstreams);
|
||||
} else {
|
||||
g_value_set_int (value, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ARG_QUEUE_SIZE:
|
||||
g_value_set_uint64 (value, play_base_bin->queue_size);
|
||||
break;
|
||||
case ARG_STREAMINFO:
|
||||
g_value_set_pointer (value, play_base_bin->streaminfo);
|
||||
g_value_set_pointer (value,
|
||||
(gpointer) gst_play_base_bin_get_streaminfo (play_base_bin));
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
@ -744,8 +953,6 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
if (sched) {
|
||||
gst_element_set_scheduler (play_base_bin->thread, sched);
|
||||
|
||||
//gst_object_set_parent (GST_OBJECT (play_base_bin->thread), GST_OBJECT (play_base_bin));
|
||||
|
||||
gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
|
||||
|
||||
g_signal_connect (G_OBJECT (play_base_bin->thread), "eos",
|
||||
|
@ -781,11 +988,17 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
} else {
|
||||
const GList *item;
|
||||
gboolean stream_found = FALSE, no_media = FALSE;
|
||||
GstPlayBaseGroup *group;
|
||||
|
||||
group = get_active_group (play_base_bin);
|
||||
|
||||
/* FIXME for now... */
|
||||
g_assert (group);
|
||||
|
||||
/* check if we found any supported stream... if not, then
|
||||
* we detected stream type (or the above would've failed),
|
||||
* but linking/decoding failed - plugin probably missing. */
|
||||
for (item = play_base_bin->streaminfo; item != NULL; item = item->next) {
|
||||
for (item = group->streaminfo; item != NULL; item = item->next) {
|
||||
GstStreamInfo *info = GST_STREAM_INFO (item->data);
|
||||
|
||||
if (info->type != GST_STREAM_TYPE_UNKNOWN) {
|
||||
|
@ -834,12 +1047,12 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
* because one stream was unrecognized. */
|
||||
g_signal_connect (play_base_bin->thread, "error",
|
||||
G_CALLBACK (gst_play_base_bin_error), play_base_bin);
|
||||
GST_DEBUG ("emit signal");
|
||||
g_signal_emit (play_base_bin,
|
||||
gst_play_base_bin_signals[SETUP_OUTPUT_PADS_SIGNAL], 0);
|
||||
} else {
|
||||
/* in case of no preroll, we might have streaminfo already... */
|
||||
g_list_foreach (play_base_bin->streaminfo,
|
||||
(GFunc) g_object_unref, NULL);
|
||||
g_list_free (play_base_bin->streaminfo);
|
||||
play_base_bin->streaminfo = NULL;
|
||||
/* clean up leftover groups */
|
||||
remove_groups (play_base_bin);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -854,6 +1067,7 @@ gst_play_base_bin_change_state (GstElement * element)
|
|||
G_CALLBACK (gst_play_base_bin_error), play_base_bin);
|
||||
ret = gst_element_set_state (play_base_bin->thread, GST_STATE_READY);
|
||||
play_base_bin->need_rebuild = TRUE;
|
||||
remove_groups (play_base_bin);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
gst_object_unref (GST_OBJECT (play_base_bin->thread));
|
||||
|
@ -903,7 +1117,7 @@ gst_play_base_bin_add_element (GstBin * bin, GstElement * element)
|
|||
|
||||
/* FIXME set element to READY so that negotiation can happen. This
|
||||
* currently fails because of weird negotiation problems. */
|
||||
/* gst_element_set_state (element, GST_STATE_READY); */
|
||||
//gst_element_set_state (element, GST_STATE_PLAYING);
|
||||
|
||||
} else {
|
||||
g_warning ("adding elements is not allowed in NULL");
|
||||
|
@ -996,7 +1210,7 @@ gst_play_base_bin_found_tag (GstElement * element,
|
|||
gst_object_unref (parent);
|
||||
}
|
||||
|
||||
void
|
||||
gboolean
|
||||
gst_play_base_bin_link_stream (GstPlayBaseBin * play_base_bin,
|
||||
GstStreamInfo * info, GstPad * pad)
|
||||
{
|
||||
|
@ -1004,9 +1218,14 @@ gst_play_base_bin_link_stream (GstPlayBaseBin * play_base_bin,
|
|||
|
||||
if (info == NULL) {
|
||||
GList *streams;
|
||||
GstPlayBaseGroup *group = get_active_group (play_base_bin);
|
||||
|
||||
for (streams = play_base_bin->streaminfo; streams;
|
||||
streams = g_list_next (streams)) {
|
||||
if (group == NULL) {
|
||||
GST_DEBUG ("no current group");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (streams = group->streaminfo; streams; streams = g_list_next (streams)) {
|
||||
GstStreamInfo *sinfo = (GstStreamInfo *) streams->data;
|
||||
|
||||
if (sinfo->type == GST_STREAM_TYPE_ELEMENT)
|
||||
|
@ -1025,10 +1244,13 @@ gst_play_base_bin_link_stream (GstPlayBaseBin * play_base_bin,
|
|||
if (!gst_pad_link (GST_PAD (info->object), pad)) {
|
||||
GST_DEBUG ("could not link");
|
||||
g_object_set (G_OBJECT (info), "mute", TRUE, NULL);
|
||||
return FALSE;
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG ("could not find pad to link");
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1041,5 +1263,11 @@ gst_play_base_bin_unlink_stream (GstPlayBaseBin * play_base_bin,
|
|||
const GList *
|
||||
gst_play_base_bin_get_streaminfo (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
return play_base_bin->streaminfo;
|
||||
GstPlayBaseGroup *group = get_active_group (play_base_bin);
|
||||
GList *info = NULL;
|
||||
|
||||
if (group) {
|
||||
info = group->streaminfo;
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
|
|
@ -35,14 +35,35 @@ G_BEGIN_DECLS
|
|||
typedef struct _GstPlayBaseBin GstPlayBaseBin;
|
||||
typedef struct _GstPlayBaseBinClass GstPlayBaseBinClass;
|
||||
|
||||
/* a GstPlayBaseGroup is a group of pads and streaminfo that together
|
||||
* make up a playable stream. A new group is created from the current
|
||||
* set of pads that are alive when the preroll elements are filled or
|
||||
* when the no-more-pads signal is fired.
|
||||
*
|
||||
* We have to queue the groups as they can be created while the preroll
|
||||
* queues are still playing the old group. We monitor the EOS signals
|
||||
* on the preroll queues and when all the streams in the current group
|
||||
* have EOSed, we switch to the next queued group.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
GstPlayBaseBin *bin; /* ref to the owner */
|
||||
|
||||
gint nstreams;
|
||||
GList *streaminfo;
|
||||
|
||||
gint naudiopads;
|
||||
gint nvideopads;
|
||||
gint nunknownpads;
|
||||
|
||||
GList *preroll_elems;
|
||||
} GstPlayBaseGroup;
|
||||
|
||||
struct _GstPlayBaseBin {
|
||||
GstBin bin;
|
||||
|
||||
/* properties */
|
||||
gboolean threaded;
|
||||
GMutex *preroll_lock;
|
||||
GCond *preroll_cond;
|
||||
GList *preroll_elems;
|
||||
guint64 queue_size;
|
||||
|
||||
/* internal thread */
|
||||
|
@ -52,12 +73,11 @@ struct _GstPlayBaseBin {
|
|||
GstElement *decoder;
|
||||
gboolean need_rebuild;
|
||||
|
||||
gint nstreams;
|
||||
GList *streaminfo;
|
||||
|
||||
gint naudiopads;
|
||||
gint nvideopads;
|
||||
gint nunknownpads;
|
||||
/* group management */
|
||||
GMutex *group_lock; /* lock and mutex to signal availability of new group */
|
||||
GCond *group_cond;
|
||||
GstPlayBaseGroup *building_group; /* the group that we are constructing */
|
||||
GList *queued_groups; /* the constructed groups, head is the active one */
|
||||
|
||||
/* list of usable factories */
|
||||
GList *factories;
|
||||
|
@ -66,7 +86,13 @@ struct _GstPlayBaseBin {
|
|||
struct _GstPlayBaseBinClass {
|
||||
GstBinClass parent_class;
|
||||
|
||||
void (*link_stream) (GstPlayBaseBin *play_base_bin,
|
||||
/* signals */
|
||||
void (*setup_output_pads) (GstPlayBaseBin *play_base_bin);
|
||||
void (*removed_output_pad) (GstPlayBaseBin *play_base_bin,
|
||||
GstStreamInfo *info);
|
||||
|
||||
/* action signals */
|
||||
gboolean (*link_stream) (GstPlayBaseBin *play_base_bin,
|
||||
GstStreamInfo *info,
|
||||
GstPad *pad);
|
||||
void (*unlink_stream) (GstPlayBaseBin *play_base_bin,
|
||||
|
@ -80,7 +106,7 @@ const GList* gst_play_base_bin_get_streaminfo (GstPlayBaseBin *play_base_bin);
|
|||
gint gst_play_base_bin_get_nstreams_of_type (GstPlayBaseBin *play_base_bin,
|
||||
GstStreamType type);
|
||||
|
||||
void gst_play_base_bin_link_stream (GstPlayBaseBin *play_base_bin,
|
||||
gboolean gst_play_base_bin_link_stream (GstPlayBaseBin *play_base_bin,
|
||||
GstStreamInfo *info,
|
||||
GstPad *pad);
|
||||
void gst_play_base_bin_unlink_stream (GstPlayBaseBin *play_base_bin,
|
||||
|
|
|
@ -85,6 +85,8 @@ static void gst_play_bin_class_init (GstPlayBinClass * klass);
|
|||
static void gst_play_bin_init (GstPlayBin * play_bin);
|
||||
static void gst_play_bin_dispose (GObject * object);
|
||||
|
||||
static void setup_sinks (GstPlayBaseBin * play_base_bin);
|
||||
|
||||
static void gst_play_bin_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * spec);
|
||||
static void gst_play_bin_get_property (GObject * object, guint prop_id,
|
||||
|
@ -147,10 +149,12 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
|
|||
GObjectClass *gobject_klass;
|
||||
GstElementClass *gstelement_klass;
|
||||
GstBinClass *gstbin_klass;
|
||||
GstPlayBaseBinClass *playbasebin_klass;
|
||||
|
||||
gobject_klass = (GObjectClass *) klass;
|
||||
gstelement_klass = (GstElementClass *) klass;
|
||||
gstbin_klass = (GstBinClass *) klass;
|
||||
playbasebin_klass = (GstPlayBaseBinClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (gst_play_base_bin_get_type ());
|
||||
|
||||
|
@ -191,6 +195,8 @@ gst_play_bin_class_init (GstPlayBinClass * klass)
|
|||
gstelement_klass->get_query_types =
|
||||
GST_DEBUG_FUNCPTR (gst_play_bin_get_query_types);
|
||||
gstelement_klass->query = GST_DEBUG_FUNCPTR (gst_play_bin_query);
|
||||
|
||||
playbasebin_klass->setup_output_pads = setup_sinks;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -497,6 +503,7 @@ remove_sinks (GstPlayBin * play_bin)
|
|||
GstObject *parent;
|
||||
GstElement *element;
|
||||
|
||||
GST_DEBUG ("removesinks");
|
||||
element = g_hash_table_lookup (play_bin->cache, "abin");
|
||||
if (element != NULL) {
|
||||
parent = gst_element_get_parent (element);
|
||||
|
@ -536,14 +543,20 @@ remove_sinks (GstPlayBin * play_bin)
|
|||
* media file
|
||||
*/
|
||||
static void
|
||||
setup_sinks (GstPlayBin * play_bin)
|
||||
setup_sinks (GstPlayBaseBin * play_base_bin)
|
||||
{
|
||||
GstPlayBin *play_bin = GST_PLAY_BIN (play_base_bin);
|
||||
GList *streaminfo;
|
||||
GList *s;
|
||||
gint num_audio = 0;
|
||||
gint num_video = 0;
|
||||
gboolean need_vis = FALSE;
|
||||
|
||||
/* FIXME: do this nicer */
|
||||
if (GST_STATE (play_base_bin) == GST_STATE_PLAYING) {
|
||||
remove_sinks (play_bin);
|
||||
}
|
||||
GST_DEBUG ("setupsinks");
|
||||
/* get info about the stream */
|
||||
g_object_get (G_OBJECT (play_bin), "stream-info", &streaminfo, NULL);
|
||||
|
||||
|
@ -631,7 +644,11 @@ setup_sinks (GstPlayBin * play_bin)
|
|||
}
|
||||
|
||||
if (sink != NULL) {
|
||||
gst_object_ref (GST_OBJECT (sink));
|
||||
gst_bin_add (GST_BIN (play_bin), sink);
|
||||
GST_DEBUG ("Adding sink with state %d (parent: %d, peer: %d)\n",
|
||||
GST_STATE (sink), GST_STATE (play_bin),
|
||||
GST_STATE (gst_pad_get_parent (srcpad)));
|
||||
sinkpad = gst_element_get_pad (sink, "sink");
|
||||
res = gst_pad_link (srcpad, sinkpad);
|
||||
if (!res) {
|
||||
|
@ -672,7 +689,7 @@ gst_play_bin_change_state (GstElement * element)
|
|||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
setup_sinks (play_bin);
|
||||
//setup_sinks (play_bin);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
|
|
Loading…
Reference in a new issue