mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-03 05:59:10 +00:00
gst/playback/: Make playbin async, it'll commit state to paused when all streams are detected.
Original commit message from CVS: * gst/playback/Makefile.am: * gst/playback/gstdecodebin.c: (gst_decode_bin_init), (gst_decode_bin_dispose), (dynamic_create), (dynamic_free), (free_dynamics), (pad_unblocked), (pad_blocked), (close_pad_link), (try_to_link_1), (new_pad), (no_more_pads), (type_found), (gst_decode_bin_change_state): * gst/playback/gstplaybin.c: (gst_play_bin_class_init), (gst_play_bin_send_event_to_sink): * gst/playback/test5.c: (new_pad), (no_more_pads), (start_finding), (dump_element_stats), (main): * gst/playback/test6.c: (main): Make playbin async, it'll commit state to paused when all streams are detected. Remove ugly hack. Added test6.c to show async behaviour.
This commit is contained in:
parent
ceaa930f24
commit
cffa20bf51
5 changed files with 230 additions and 46 deletions
18
ChangeLog
18
ChangeLog
|
@ -1,3 +1,21 @@
|
|||
2005-10-18 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/playback/Makefile.am:
|
||||
* gst/playback/gstdecodebin.c: (gst_decode_bin_init),
|
||||
(gst_decode_bin_dispose), (dynamic_create), (dynamic_free),
|
||||
(free_dynamics), (pad_unblocked), (pad_blocked), (close_pad_link),
|
||||
(try_to_link_1), (new_pad), (no_more_pads), (type_found),
|
||||
(gst_decode_bin_change_state):
|
||||
* gst/playback/gstplaybin.c: (gst_play_bin_class_init),
|
||||
(gst_play_bin_send_event_to_sink):
|
||||
* gst/playback/test5.c: (new_pad), (no_more_pads), (start_finding),
|
||||
(dump_element_stats), (main):
|
||||
* gst/playback/test6.c: (main):
|
||||
Make playbin async, it'll commit state to paused when all streams
|
||||
are detected.
|
||||
Remove ugly hack.
|
||||
Added test6.c to show async behaviour.
|
||||
|
||||
2005-10-18 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* ext/ogg/gstoggdemux.c: (gst_ogg_demux_chain_peer),
|
||||
|
|
|
@ -31,7 +31,7 @@ noinst_HEADERS = \
|
|||
gststreaminfo.h \
|
||||
gststreamselector.h
|
||||
|
||||
noinst_PROGRAMS = test decodetest test2 test3 test4 test5
|
||||
noinst_PROGRAMS = test decodetest test2 test3 test4 test5 test6
|
||||
|
||||
test_LDADD = $(GST_LIBS)
|
||||
test_CFLAGS = $(GST_CFLAGS)
|
||||
|
@ -48,6 +48,9 @@ test4_CFLAGS = $(GST_CFLAGS)
|
|||
test5_LDADD = $(GST_LIBS)
|
||||
test5_CFLAGS = $(GST_CFLAGS)
|
||||
|
||||
test6_LDADD = $(GST_LIBS)
|
||||
test6_CFLAGS = $(GST_CFLAGS)
|
||||
|
||||
decodetest_LDADD = $(GST_LIBS)
|
||||
decodetest_CFLAGS = $(GST_CFLAGS)
|
||||
|
||||
|
|
|
@ -56,16 +56,20 @@ struct _GstDecodeBin
|
|||
GstBin bin; /* we extend GstBin */
|
||||
|
||||
GstElement *typefind; /* this holds the typefind object */
|
||||
GstElement *fakesink;
|
||||
|
||||
gboolean threaded; /* indicating threaded execution is desired */
|
||||
GList *dynamics; /* list of dynamic connections */
|
||||
|
||||
GList *factories; /* factories we can use for selecting elements */
|
||||
gint numpads;
|
||||
gint numwaiting;
|
||||
|
||||
GList *elements; /* elements we added in autoplugging */
|
||||
|
||||
guint have_type_id; /* signal id for the typefind element */
|
||||
|
||||
gboolean shutting_down; /* stop pluggin if we're shutting down */
|
||||
};
|
||||
|
||||
struct _GstDecodeBinClass
|
||||
|
@ -122,6 +126,7 @@ static void gst_decode_bin_get_property (GObject * object, guint prop_id,
|
|||
static GstStateChangeReturn gst_decode_bin_change_state (GstElement * element,
|
||||
GstStateChange transition);
|
||||
|
||||
static void free_dynamics (GstDecodeBin * decode_bin);
|
||||
static void type_found (GstElement * typefind, guint probability,
|
||||
GstCaps * caps, GstDecodeBin * decode_bin);
|
||||
static GstElement *try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad,
|
||||
|
@ -334,6 +339,16 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
|
|||
g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
|
||||
G_CALLBACK (type_found), decode_bin);
|
||||
}
|
||||
decode_bin->fakesink = gst_element_factory_make ("fakesink", "fakesink");
|
||||
if (!decode_bin->fakesink) {
|
||||
g_warning ("can't find fakesink element, decodebin will not work");
|
||||
} else {
|
||||
if (!gst_bin_add (GST_BIN (decode_bin), decode_bin->fakesink)) {
|
||||
g_warning ("Could not add fakesink element, decodebin will not work");
|
||||
gst_object_unref (decode_bin->fakesink);
|
||||
decode_bin->fakesink = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
decode_bin->threaded = DEFAULT_THREADED;
|
||||
decode_bin->dynamics = NULL;
|
||||
|
@ -353,6 +368,11 @@ gst_decode_bin_dispose (GObject * object)
|
|||
decode_bin->factories = NULL;
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
|
||||
/* our parent dispose might trigger new signals when pads are unlinked
|
||||
* etc. clean up the mess here. */
|
||||
/* FIXME do proper cleanup when going to NULL */
|
||||
free_dynamics (decode_bin);
|
||||
}
|
||||
|
||||
static GstDynamic *
|
||||
|
@ -360,6 +380,8 @@ dynamic_create (GstElement * element, GstDecodeBin * decode_bin)
|
|||
{
|
||||
GstDynamic *dyn;
|
||||
|
||||
GST_DEBUG_OBJECT (element, "dynamic create");
|
||||
|
||||
/* take refs */
|
||||
gst_object_ref (element);
|
||||
gst_object_ref (decode_bin);
|
||||
|
@ -378,6 +400,8 @@ dynamic_create (GstElement * element, GstDecodeBin * decode_bin)
|
|||
static void
|
||||
dynamic_free (GstDynamic * dyn)
|
||||
{
|
||||
GST_DEBUG_OBJECT (dyn->decode_bin, "dynamic free");
|
||||
|
||||
/* disconnect signals */
|
||||
g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->np_sig_id);
|
||||
g_signal_handler_disconnect (G_OBJECT (dyn->element), dyn->nmp_sig_id);
|
||||
|
@ -389,6 +413,20 @@ dynamic_free (GstDynamic * dyn)
|
|||
g_free (dyn);
|
||||
}
|
||||
|
||||
static void
|
||||
free_dynamics (GstDecodeBin * decode_bin)
|
||||
{
|
||||
GList *dyns;
|
||||
|
||||
for (dyns = decode_bin->dynamics; dyns; dyns = g_list_next (dyns)) {
|
||||
GstDynamic *dynamic = (GstDynamic *) dyns->data;
|
||||
|
||||
dynamic_free (dynamic);
|
||||
}
|
||||
g_list_free (decode_bin->dynamics);
|
||||
decode_bin->dynamics = NULL;
|
||||
}
|
||||
|
||||
/* this function runs through the element factories and returns a list
|
||||
* of all elements that are able to sink the given caps
|
||||
*/
|
||||
|
@ -441,6 +479,33 @@ mimetype_is_raw (const gchar * mimetype)
|
|||
g_str_has_prefix (mimetype, "text/plain");
|
||||
}
|
||||
|
||||
static void
|
||||
pad_unblocked (GstPad * pad, gboolean blocked, GstDecodeBin * decode_bin)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
pad_blocked (GstPad * pad, gboolean blocked, GstDecodeBin * decode_bin)
|
||||
{
|
||||
decode_bin->numwaiting--;
|
||||
if (decode_bin->numwaiting == 0) {
|
||||
gst_object_ref (decode_bin->fakesink);
|
||||
gst_bin_remove (GST_BIN (decode_bin), decode_bin->fakesink);
|
||||
|
||||
gst_element_set_state (decode_bin->fakesink, GST_STATE_NULL);
|
||||
gst_element_get_state (decode_bin->fakesink, NULL, NULL,
|
||||
GST_CLOCK_TIME_NONE);
|
||||
|
||||
gst_object_unref (decode_bin->fakesink);
|
||||
decode_bin->fakesink = NULL;
|
||||
|
||||
gst_element_post_message (GST_ELEMENT_CAST (decode_bin),
|
||||
gst_message_new_state_dirty (GST_OBJECT_CAST (decode_bin)));
|
||||
}
|
||||
gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback) pad_unblocked,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* given a pad and a caps from an element, find the list of elements
|
||||
* that could connect to the pad
|
||||
*
|
||||
|
@ -494,11 +559,15 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
|
|||
/* make a unique name for this new pad */
|
||||
padname = g_strdup_printf ("src%d", decode_bin->numpads);
|
||||
decode_bin->numpads++;
|
||||
decode_bin->numwaiting++;
|
||||
|
||||
/* make it a ghostpad */
|
||||
ghost = gst_ghost_pad_new (padname, pad);
|
||||
gst_element_add_pad (GST_ELEMENT (decode_bin), ghost);
|
||||
|
||||
gst_pad_set_blocked_async (pad, TRUE, (GstPadBlockCallback) pad_blocked,
|
||||
decode_bin);
|
||||
|
||||
GST_LOG_OBJECT (element, "closed pad %s", padname);
|
||||
|
||||
/* our own signal with an extra flag that this is the only pad */
|
||||
|
@ -546,37 +615,6 @@ many_types:
|
|||
}
|
||||
}
|
||||
|
||||
/* crude crude crude crude hack to avoid deadlocks in core while wim figures out
|
||||
* what's going on */
|
||||
/* not mt-safe */
|
||||
static GstStateChangeReturn
|
||||
gst_element_set_state_like_a_crazy_man (GstElement * element, GstState state)
|
||||
{
|
||||
GstElement *e;
|
||||
GList *chain = NULL, *walk;
|
||||
GstStateChangeReturn ret;
|
||||
|
||||
for (e = gst_object_ref (element); e;
|
||||
e = (GstElement *) gst_element_get_parent (e))
|
||||
chain = g_list_prepend (chain, e);
|
||||
|
||||
for (walk = chain; walk; walk = walk->next)
|
||||
GST_STATE_LOCK (walk->data);
|
||||
|
||||
ret = gst_element_set_state (element, state);
|
||||
|
||||
chain = g_list_reverse (chain);
|
||||
|
||||
for (walk = chain; walk; walk = walk->next) {
|
||||
GST_STATE_UNLOCK (walk->data);
|
||||
gst_object_unref (walk->data);
|
||||
}
|
||||
|
||||
g_list_free (chain);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* given a list of element factories, try to link one of the factories
|
||||
* to the given pad.
|
||||
|
@ -622,7 +660,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
gst_bin_add (GST_BIN (decode_bin), element);
|
||||
|
||||
/* set to ready first so it is ready */
|
||||
gst_element_set_state_like_a_crazy_man (element, GST_STATE_READY);
|
||||
gst_element_set_state (element, GST_STATE_READY);
|
||||
|
||||
/* keep our own list of elements */
|
||||
decode_bin->elements = g_list_prepend (decode_bin->elements, element);
|
||||
|
@ -634,7 +672,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
gst_object_unref (sinkpad);
|
||||
/* this element did not work, remove it again and continue trying
|
||||
* other elements, the element will be disposed. */
|
||||
gst_element_set_state_like_a_crazy_man (element, GST_STATE_NULL);
|
||||
gst_element_set_state (element, GST_STATE_NULL);
|
||||
gst_bin_remove (GST_BIN (decode_bin), element);
|
||||
} else {
|
||||
const gchar *klass;
|
||||
|
@ -669,7 +707,7 @@ try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
|
|||
* on it until we have a raw type */
|
||||
close_link (element, decode_bin);
|
||||
/* change the state of the element to that of the parent */
|
||||
gst_element_set_state_like_a_crazy_man (element, GST_STATE_PAUSED);
|
||||
gst_element_set_state (element, GST_STATE_PAUSED);
|
||||
|
||||
result = element;
|
||||
|
||||
|
@ -811,6 +849,15 @@ new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
|
|||
GstDecodeBin *decode_bin = dynamic->decode_bin;
|
||||
GstCaps *caps;
|
||||
|
||||
GST_LOCK (decode_bin);
|
||||
if (decode_bin->shutting_down)
|
||||
goto shutting_down1;
|
||||
GST_UNLOCK (decode_bin);
|
||||
|
||||
GST_STATE_LOCK (decode_bin);
|
||||
if (decode_bin->shutting_down)
|
||||
goto shutting_down2;
|
||||
|
||||
/* see if any more pending dynamic connections exist */
|
||||
gboolean more = gst_decode_bin_is_dynamic (decode_bin);
|
||||
|
||||
|
@ -818,6 +865,17 @@ new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
|
|||
close_pad_link (element, pad, caps, decode_bin, more);
|
||||
if (caps)
|
||||
gst_caps_unref (caps);
|
||||
GST_STATE_UNLOCK (decode_bin);
|
||||
|
||||
return;
|
||||
|
||||
shutting_down1:
|
||||
GST_UNLOCK (decode_bin);
|
||||
return;
|
||||
|
||||
shutting_down2:
|
||||
GST_STATE_UNLOCK (decode_bin);
|
||||
return;
|
||||
}
|
||||
|
||||
/* this signal is fired when an element signals the no_more_pads signal.
|
||||
|
@ -843,6 +901,7 @@ no_more_pads (GstElement * element, GstDynamic * dynamic)
|
|||
GST_DEBUG_OBJECT (decode_bin,
|
||||
"no more dynamic elements, signaling no_more_pads");
|
||||
gst_element_no_more_pads (GST_ELEMENT (decode_bin));
|
||||
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (decode_bin, "we have more dynamic elements");
|
||||
}
|
||||
|
@ -1021,6 +1080,10 @@ type_found (GstElement * typefind, guint probability, GstCaps * caps,
|
|||
gboolean dynamic;
|
||||
GstPad *pad;
|
||||
|
||||
GST_STATE_LOCK (decode_bin);
|
||||
if (decode_bin->shutting_down)
|
||||
goto shutting_down;
|
||||
|
||||
GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
|
||||
|
||||
/* autoplug the new pad with the caps that the signal gave us. */
|
||||
|
@ -1038,6 +1101,10 @@ type_found (GstElement * typefind, guint probability, GstCaps * caps,
|
|||
/* more dynamic elements exist that could create new pads */
|
||||
GST_DEBUG_OBJECT (decode_bin, "we have more dynamic elements");
|
||||
}
|
||||
|
||||
shutting_down:
|
||||
GST_STATE_UNLOCK (decode_bin);
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1085,18 +1152,28 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
|
|||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstDecodeBin *decode_bin;
|
||||
GList *dyns;
|
||||
|
||||
decode_bin = GST_DECODE_BIN (element);
|
||||
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_NULL_TO_READY:
|
||||
decode_bin->numpads = 0;
|
||||
decode_bin->numwaiting = 0;
|
||||
decode_bin->dynamics = NULL;
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_PAUSED:
|
||||
GST_LOCK (decode_bin);
|
||||
decode_bin->shutting_down = FALSE;
|
||||
GST_UNLOCK (decode_bin);
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
|
||||
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
GST_LOCK (decode_bin);
|
||||
decode_bin->shutting_down = TRUE;
|
||||
GST_UNLOCK (decode_bin);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -1108,13 +1185,7 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
|
|||
case GST_STATE_CHANGE_PAUSED_TO_READY:
|
||||
break;
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
for (dyns = decode_bin->dynamics; dyns; dyns = g_list_next (dyns)) {
|
||||
GstDynamic *dynamic = (GstDynamic *) dyns->data;
|
||||
|
||||
dynamic_free (dynamic);
|
||||
}
|
||||
g_list_free (decode_bin->dynamics);
|
||||
decode_bin->dynamics = NULL;
|
||||
free_dynamics (decode_bin);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -24,13 +24,13 @@ static GMainLoop *loop;
|
|||
static void
|
||||
new_pad (GstElement * element, GstPad * pad, gboolean last, GstElement * sink)
|
||||
{
|
||||
g_print ("New pad...");
|
||||
g_print ("New pad...\n");
|
||||
}
|
||||
|
||||
static void
|
||||
no_more_pads (GstElement * element)
|
||||
{
|
||||
g_print ("No more pads...");
|
||||
g_print ("No more pads...\n");
|
||||
g_main_loop_quit (loop);
|
||||
}
|
||||
|
||||
|
|
92
gst/playback/test6.c
Normal file
92
gst/playback/test6.c
Normal file
|
@ -0,0 +1,92 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#include <unistd.h>
|
||||
#include <gst/gst.h>
|
||||
|
||||
gint
|
||||
main (gint argc, gchar * argv[])
|
||||
{
|
||||
GstElement *pipeline, *filesrc, *decodebin;
|
||||
GstStateChangeReturn res;
|
||||
GstIterator *it;
|
||||
gpointer data;
|
||||
|
||||
gst_init (&argc, &argv);
|
||||
|
||||
pipeline = gst_pipeline_new ("pipeline");
|
||||
|
||||
filesrc = gst_element_factory_make ("filesrc", "filesrc");
|
||||
g_assert (filesrc);
|
||||
|
||||
decodebin = gst_element_factory_make ("decodebin", "decodebin");
|
||||
g_assert (decodebin);
|
||||
|
||||
gst_bin_add_many (GST_BIN (pipeline), filesrc, decodebin, NULL);
|
||||
gst_element_link (filesrc, decodebin);
|
||||
|
||||
if (argc < 2) {
|
||||
g_print ("usage: %s <uri>\n", argv[0]);
|
||||
exit (-1);
|
||||
}
|
||||
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
|
||||
|
||||
g_print ("pause..\n");
|
||||
res = gst_element_set_state (pipeline, GST_STATE_PAUSED);
|
||||
if (res == GST_STATE_CHANGE_FAILURE) {
|
||||
g_print ("could not pause\n");
|
||||
exit (-1);
|
||||
}
|
||||
g_print ("waiting..\n");
|
||||
res = gst_element_get_state (pipeline, NULL, NULL, GST_CLOCK_TIME_NONE);
|
||||
if (res != GST_STATE_CHANGE_SUCCESS) {
|
||||
g_print ("could not complete pause\n");
|
||||
exit (-1);
|
||||
}
|
||||
g_print ("stats..\n");
|
||||
|
||||
it = gst_element_iterate_src_pads (decodebin);
|
||||
while (gst_iterator_next (it, &data) == GST_ITERATOR_OK) {
|
||||
GstPad *pad = GST_PAD (data);
|
||||
GstCaps *caps;
|
||||
gchar *str;
|
||||
GstQuery *query;
|
||||
|
||||
g_print ("stream %s:\n", GST_OBJECT_NAME (pad));
|
||||
|
||||
caps = gst_pad_get_caps (pad);
|
||||
str = gst_caps_to_string (caps);
|
||||
g_print (" caps: %s\n", str);
|
||||
g_free (str);
|
||||
|
||||
query = gst_query_new_position (GST_FORMAT_TIME);
|
||||
if (gst_pad_query (pad, query)) {
|
||||
gint64 duration;
|
||||
|
||||
gst_query_parse_position (query, NULL, NULL, &duration);
|
||||
|
||||
g_print (" duration: %" GST_TIME_FORMAT "\n", GST_TIME_ARGS (duration));
|
||||
}
|
||||
gst_query_unref (query);
|
||||
|
||||
gst_object_unref (pad);
|
||||
}
|
||||
gst_iterator_free (it);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue