docs/manual/: Try to get autoplugging working, fix type detection. Fix text in hello-world image.

Original commit message from CVS:
* docs/manual/advanced-autoplugging.xml:
* docs/manual/mime-world.fig:
Try to get autoplugging working, fix type detection. Fix text
in hello-world image.
This commit is contained in:
Ronald S. Bultje 2005-06-29 11:46:16 +00:00
parent 06ab4b7831
commit 92865101cc
3 changed files with 145 additions and 72 deletions

View file

@ -1,3 +1,10 @@
2005-06-29 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* docs/manual/advanced-autoplugging.xml:
* docs/manual/mime-world.fig:
Try to get autoplugging working, fix type detection. Fix text
in hello-world image.
2005-06-29 Wim Taymans <wim@fluendo.com>
* gst/base/gstbasesink.c: (gst_base_sink_handle_object),

View file

@ -114,8 +114,51 @@
was not found. The next section will introduce more useful behaviours,
such as plugging together a decoding pipeline.
</para>
<programlisting><!-- example-begin typefind.c -->
<programlisting><!-- example-begin typefind.c a -->
#include &lt;gst/gst.h&gt;
<!-- example-end typefind.c a -->
<!-- example-begin typefind.c b --><!--
static gboolean
my_bus_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR: {
GError *err;
gchar *debug;
gst_message_parse_error (message, &amp;err, &amp;debug);
g_print ("Error: %s\n", err-&gt;message);
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
g_main_loop_quit (loop);
break;
default:
break;
}
/* remove from queue */
return TRUE;
}
--><!-- example-end typefind.c b -->
<!-- example-begin typefind.c c -->
static gboolean
idle_exit_loop (gpointer data)
{
g_main_loop_quit ((GMainLoop *) data);
/* once */
return FALSE;
}
static void
cb_typefound (GstElement *typefind,
@ -123,38 +166,29 @@ cb_typefound (GstElement *typefind,
GstCaps *caps,
gpointer data)
{
GMainLoop *loop = data;
gchar *type;
type = gst_caps_to_string (caps);
g_print ("Media type %s found, probability %d%%\n", type, probability);
g_free (type);
/* done */
(* (gboolean *) data) = TRUE;
}
static void
cb_error (GstElement *pipeline,
GstElement *source,
GError *error,
gchar *debug,
gpointer data)
{
g_print ("Error: %s\n", error->message);
/* done */
(* (gboolean *) data) = TRUE;
/* since we connect to a signal in the pipeline thread context, we need
* to set an idle handler to exit the main loop in the mainloop context.
* Normally, your app should not need to worry about such things. */
g_idle_add (idle_exit_loop, loop);
}
gint
main (gint argc,
gchar *argv[])
{
GMainLoop *loop;
GstElement *pipeline, *filesrc, *typefind;
gboolean done = FALSE;
/* init GStreamer */
gst_init (&amp;argc, &amp;argv);
loop = g_main_loop_new (NULL, FALSE);
/* check args */
if (argc != 2) {
@ -164,24 +198,20 @@ main (gint argc,
/* create a new pipeline to hold the elements */
pipeline = gst_pipeline_new ("pipe");
g_signal_connect (pipeline, "error", G_CALLBACK (cb_error), &amp;done);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
my_bus_callback, NULL);
/* create file source and typefind element */
filesrc = gst_element_factory_make ("filesrc", "source");
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
typefind = gst_element_factory_make ("typefind", "typefinder");
g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), &amp;done);
g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), loop);
/* setup */
gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, NULL);
gst_element_link (filesrc, typefind);
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
/* now iterate until the type is found */
do {
if (!gst_bin_iterate (GST_BIN (pipeline)))
break;
} while (!done);
g_main_loop_run (loop);
/* unset */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
@ -189,7 +219,7 @@ main (gint argc,
return 0;
}
<!-- example-end typefind.c --></programlisting>
<!-- example-end typefind.c c --></programlisting>
<para>
Once a media type has been detected, you can plug an element (e.g. a
demuxer or decoder) to the source pad of the typefind element, and
@ -305,7 +335,7 @@ cb_newpad (GstElement *element,
caps = gst_pad_get_caps (pad);
try_to_plug (pad, caps);
gst_caps_free (caps);
gst_caps_unref (caps);
}
static void
@ -314,6 +344,7 @@ close_link (GstPad *srcpad,
const gchar *padname,
const GList *templlist)
{
GstPad *pad;
gboolean has_dynamic_pads = FALSE;
g_print ("Plugging pad %s:%s to newly created %s:%s\n",
@ -322,15 +353,18 @@ close_link (GstPad *srcpad,
gst_object_get_name (GST_OBJECT (sinkelement)), padname);
/* add the element to the pipeline and set correct state */
if (sinkelement != audiosink) {
gst_element_set_state (sinkelement, GST_STATE_PAUSED);
gst_bin_add (GST_BIN (pipeline), sinkelement);
gst_pad_link (srcpad, gst_element_get_pad (sinkelement, padname));
gst_bin_sync_children_state (GST_BIN (pipeline));
}
pad = gst_element_get_pad (sinkelement, padname);
gst_pad_link (srcpad, pad);
gst_object_unref (GST_OBJECT (pad));
/* if we have static source pads, link those. If we have dynamic
* source pads, listen for new-pad signals on the element */
for ( ; templlist != NULL; templlist = templlist->next) {
GstPadTemplate *templ = GST_PAD_TEMPLATE (templlist->data);
GstStaticPadTemplate *templ = templlist->data;
/* only sourcepads, no request pads */
if (templ->direction != GST_PAD_SRC ||
@ -345,7 +379,8 @@ close_link (GstPad *srcpad,
/* link */
try_to_plug (pad, caps);
gst_caps_free (caps);
gst_object_unref (GST_OBJECT (pad));
gst_caps_unref (caps);
break;
}
case GST_PAD_SOMETIMES:
@ -366,15 +401,15 @@ static void
try_to_plug (GstPad *pad,
const GstCaps *caps)
{
GstObject *parent = GST_OBJECT (gst_pad_get_parent (pad));
GstObject *parent = GST_OBJECT (GST_OBJECT_PARENT (pad));
const gchar *mime;
const GList *item;
GstCaps *res, *audiocaps;
/* don't plug if we're already plugged */
/* don't plug if we're already plugged - FIXME: memleak for pad */
if (GST_PAD_IS_LINKED (gst_element_get_pad (audiosink, "sink"))) {
g_print ("Omitting link for pad %s:%s because we're already linked\n",
gst_object_get_name (parent), gst_pad_get_name (pad));
GST_OBJECT_NAME (parent), GST_OBJECT_NAME (pad));
return;
}
@ -382,7 +417,7 @@ try_to_plug (GstPad *pad,
mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
if (g_strrstr (mime, "video")) {
g_print ("Omitting link for pad %s:%s because mimetype %s is non-audio\n",
gst_object_get_name (parent), gst_pad_get_name (pad), mime);
GST_OBJECT_NAME (parent), GST_OBJECT_NAME (pad), mime);
return;
}
@ -392,21 +427,21 @@ try_to_plug (GstPad *pad,
if (res &amp;&amp; !gst_caps_is_empty (res)) {
g_print ("Found pad to link to audiosink - plugging is now done\n");
close_link (pad, audiosink, "sink", NULL);
gst_caps_free (audiocaps);
gst_caps_free (res);
gst_caps_unref (audiocaps);
gst_caps_unref (res);
return;
}
gst_caps_free (audiocaps);
gst_caps_free (res);
gst_caps_unref (audiocaps);
gst_caps_unref (res);
/* try to plug from our list */
for (item = factories; item != NULL; item = item->next) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (item->data);
const GList *pads;
for (pads = gst_element_factory_get_pad_templates (factory);
for (pads = gst_element_factory_get_static_pad_templates (factory);
pads != NULL; pads = pads->next) {
GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
GstStaticPadTemplate *templ = pads->data;
/* find the sink template - need an always pad*/
if (templ->direction != GST_PAD_SINK ||
@ -415,18 +450,21 @@ try_to_plug (GstPad *pad,
}
/* can it link? */
res = gst_caps_intersect (caps, templ->caps);
res = gst_caps_intersect (caps,
gst_static_caps_get (&amp;templ->static_caps));
if (res &amp;&amp; !gst_caps_is_empty (res)) {
GstElement *element;
gchar *name_template = g_strdup (templ->name_template);
/* close link and return */
gst_caps_free (res);
gst_caps_unref (res);
element = gst_element_factory_create (factory, NULL);
close_link (pad, element, templ->name_template,
gst_element_factory_get_pad_templates (factory));
close_link (pad, element, name_template,
gst_element_factory_get_static_pad_templates (factory));
g_free (name_template);
return;
}
gst_caps_free (res);
gst_caps_unref (res);
/* we only check one sink template per factory, so move on to the
* next factory now */
@ -436,7 +474,7 @@ try_to_plug (GstPad *pad,
/* if we get here, no item was found */
g_print ("No compatible pad found to decode %s on %s:%s\n",
mime, gst_object_get_name (parent), gst_pad_get_name (pad));
mime, GST_OBJECT_NAME (parent), GST_OBJECT_NAME (pad));
}
static void
@ -446,13 +484,16 @@ cb_typefound (GstElement *typefind,
gpointer data)
{
gchar *s;
GstPad *pad;
s = gst_caps_to_string (caps);
g_print ("Detected media type %s\n", s);
g_free (s);
/* actually plug now */
try_to_plug (gst_element_get_pad (typefind, "src"), caps);
pad = gst_element_get_pad (typefind, "src");
try_to_plug (pad, caps);
gst_object_unref (GST_OBJECT (pad));
}
<!-- example-end dynamic.c c --></programlisting>
<para>
@ -462,25 +503,49 @@ cb_typefound (GstElement *typefind,
for video to create a player that plays both audio and video.
</para>
<!-- example-begin dynamic.c d --><!--
static void
cb_error (GstElement *pipeline,
GstElement *source,
GError *error,
gchar *debug,
static gboolean
my_bus_callback (GstBus *bus,
GstMessage *message,
gpointer data)
{
g_print ("Error: %s\n", error->message);
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR: {
GError *err;
gchar *debug;
gst_message_parse_error (message, &amp;err, &amp;debug);
g_print ("Error: %s\n", err-&gt;message);
g_error_free (err);
g_free (debug);
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
/* end-of-stream */
g_main_loop_quit (loop);
break;
default:
break;
}
/* remove from queue */
return TRUE;
}
gint
main (gint argc,
gchar *argv[])
{
GMainLoop *loop;
GstElement *typefind;
gchar *p;
/* init GStreamer and ourselves */
gst_init (&amp;argc, &amp;argv);
loop = g_main_loop_new (NULL, FALSE);
init_factories ();
/* args */
@ -492,16 +557,18 @@ main (gint argc,
/* pipeline */
p = g_strdup_printf ("filesrc location=\"%s\" ! typefind name=tf", argv[1]);
pipeline = gst_parse_launch (p, NULL);
gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
my_bus_callback, NULL);
g_free (p);
typefind = gst_bin_get_by_name (GST_BIN (pipeline), "tf");
g_signal_connect (pipeline, "error", G_CALLBACK (cb_error), NULL);
g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), NULL);
gst_object_unref (GST_OBJECT (typefind));
audiosink = gst_element_factory_make ("alsasink", "audiosink");
gst_element_set_state (audiosink, GST_STATE_PAUSED);
gst_bin_add (GST_BIN (pipeline), audiosink);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
/* run */
while (gst_bin_iterate (GST_BIN (pipeline))) ;
g_main_loop_run (loop);
/* exit */
gst_element_set_state (pipeline, GST_STATE_NULL);
@ -521,8 +588,7 @@ main (gint argc,
shortest-path-finding to make sure the most optimal pipeline is chosen,
and so on. Basically, the features that you implement in an autoplugger
depend on what you want to use it for. For full-blown implementations,
see the <quote>playbin</quote>, <quote>decodebin</quote> and
<quote>spider</quote> elements.
see the <quote>playbin</quote> and <quote>decodebin</quote> elements.
</para>
</sect1>
</chapter>

View file

@ -143,20 +143,20 @@ Single
8775 4050 8775 5475
2 1 1 1 0 7 50 0 -1 5.000 0 0 -1 0 0 2
9975 4050 9975 5250
4 0 0 50 0 16 12 0.0000 4 135 255 2175 2250 bin\001
4 0 0 50 0 16 12 0.0000 4 135 255 2175 2250 pipeline\001
4 0 0 50 0 16 12 0.0000 4 105 255 3525 3975 src\001
4 0 0 50 0 16 12 0.0000 4 135 330 4725 3975 sink\001
4 0 0 50 0 16 12 0.0000 4 105 255 6075 3975 src\001
4 0 0 50 0 16 12 0.0000 4 135 330 7350 3975 sink\001
4 0 0 50 0 16 12 0.0000 4 105 255 8625 3975 src\001
4 0 0 50 0 16 12 0.0000 4 135 330 9750 3975 sink\001
4 0 0 50 0 16 12 0.0000 4 165 1005 2250 3075 disk_source\001
4 0 0 50 0 16 12 0.0000 4 150 465 4725 3075 parse\001
4 0 0 50 0 16 12 0.0000 4 135 690 7275 3075 decoder\001
4 0 0 50 0 16 12 0.0000 4 180 930 9750 3075 play_audio\001
4 0 0 50 0 16 12 0.0000 4 165 1005 2250 3075 file source\001
4 0 0 50 0 16 12 0.0000 4 150 465 4725 3075 ogg demuxer\001
4 0 0 50 0 16 12 0.0000 4 135 690 7275 3075 vorbis decoder\001
4 0 0 50 0 16 12 0.0000 4 180 930 9750 3075 audio output\001
4 0 0 50 0 0 12 0.0000 4 135 75 3675 5475 ?\001
4 0 0 50 0 0 12 0.0000 4 135 735 9825 5475 audio/raw\001
4 0 0 50 0 0 12 0.0000 4 180 855 4350 5325 audio/mpeg\001
4 0 0 50 0 0 12 0.0000 4 135 735 8700 5625 audio/raw\001
4 0 0 50 0 0 12 0.0000 4 180 855 5775 5625 audio/mpeg\001
4 0 0 50 0 0 12 0.0000 4 180 855 7125 5325 audio/mpeg\001
4 0 0 50 0 0 12 0.0000 4 135 735 9825 5475 audio/x-raw-int\001
4 0 0 50 0 0 12 0.0000 4 180 855 4350 5325 application/ogg\001
4 0 0 50 0 0 12 0.0000 4 135 735 8700 5625 audio/x-raw-int\001
4 0 0 50 0 0 12 0.0000 4 180 855 5775 5625 audio/x-vorbis\001
4 0 0 50 0 0 12 0.0000 4 180 855 7125 5325 audio/x-vorbis\001