1 <chapter id="chapter-autoplugging">
2 <title>Autoplugging</title>
4 In <xref linkend="chapter-helloworld"/>, you've learned to build a
5 simple media player for Ogg/Vorbis files. By using alternative elements,
6 you are able to build media players for other media types, such as
7 Ogg/Speex, MP3 or even video formats. However, you would rather want
8 to build an application that can automatically detect the media type
9 of a stream and automatically generate the best possible pipeline
10 by looking at all available elements in a system. This process is called
11 autoplugging, and &GStreamer; contains high-quality autopluggers. If
12 you're looking for an autoplugger, don't read any further and go to
13 <xref linkend="chapter-components"/>. This chapter will explain the
14 <emphasis>concept</emphasis> of autoplugging and typefinding. It will
15 explain what systems &GStreamer; includes to dynamically detect the
16 type of a media stream, and how to generate a pipeline of decoder
17 elements to playback this media. The same principles can also be used
18 for transcoding. Because of the full dynamicity of this concept,
19 &GStreamer; can be automatically extended to support new media types
20 without needing any adaptations to its autopluggers.
23 We will first introduce the concept of MIME types as a dynamic and
24 extendible way of identifying media streams. After that, we will introduce
25 the concept of typefinding to find the type of a media stream. Lastly,
26 we will explain how autoplugging and the &GStreamer; registry can be
27 used to setup a pipeline that will convert media from one mimetype to
28 another, for example for media decoding.
31 <sect1 id="section-mime">
32 <title>MIME-types as a way to identity streams</title>
34 We have previously introduced the concept of capabilities as a way
35 for elements (or, rather, pads) to agree on a media type when
36 streaming data from one element to the next (see <xref
37 linkend="section-caps"/>). We have explained that a capability is
38 a combination of a mimetype and a set of properties. For most
39 container formats (those are the files that you will find on your
40 hard disk; Ogg, for example, is a container format), no properties
41 are needed to describe the stream. Only a MIME-type is needed. A
42 full list of MIME-types and accompanying properties can be found
44 url="http://gstreamer.freedesktop.org/data/doc/gstreamer/head/pwg/html/section-types-definitions.html">the
45 Plugin Writer's Guide</ulink>.
48 An element must associate a MIME-type to its source and sink pads
49 when it is loaded into the system. &GStreamer; knows about the
50 different elements and what type of data they expect and emit through
51 the &GStreamer; registry. This allows for very dynamic and extensible
52 element creation as we will see.
56 In <xref linkend="chapter-helloworld"/>, we've learned to build a
57 music player for Ogg/Vorbis files. Let's look at the MIME-types
58 associated with each pad in this pipeline. <xref
59 linkend="section-mime-img"/> shows what MIME-type belongs to each
62 <!-- FIXME: update for ogg/vorbis rather than mp3 -->
63 <figure float="1" id="section-mime-img">
64 <title>The Hello world pipeline with MIME types</title>
67 <imagedata fileref="images/mime-world.ℑ" format="&IMAGE;"/>
72 Now that we have an idea how &GStreamer; identifies known media
73 streams, we can look at methods &GStreamer; uses to setup pipelines
74 for media handling and for media type detection.
78 <sect1 id="section-typefinding">
79 <title>Media stream type detection</title>
81 Usually, when loading a media stream, the type of the stream is not
82 known. This means that before we can choose a pipeline to decode the
83 stream, we first need to detect the stream type. &GStreamer; uses the
84 concept of typefinding for this. Typefinding is a normal part of a
85 pipeline, it will read data for as long as the type of a stream is
86 unknown. During this period, it will provide data to all plugins
87 that implement a typefinder. when one of the typefinders recognizes
88 the stream, the typefind element will emit a signal and act as a
89 passthrough module from that point on. If no type was found, it will
90 emit an error and further media processing will stop.
93 Once the typefind element has found a type, the application can
94 use this to plug together a pipeline to decode the media stream.
95 This will be discussed in the next section.
98 Plugins in &GStreamer; can, as mentioned before, implement typefinder
99 functionality. A plugin implementing this functionality will submit
100 a mimetype, optionally a set of file extensions commonly used for this
101 media type, and a typefind function. Once this typefind function inside
102 the plugin is called, the plugin will see if the data in this media
103 stream matches a specific pattern that marks the media type identified
104 by that mimetype. If it does, it will notify the typefind element of
105 this fact, telling which mediatype was recognized and how certain we
106 are that this stream is indeed that mediatype. Once this run has been
107 completed for all plugins implementing a typefind functionality, the
108 typefind element will tell the application what kind of media stream
109 it thinks to have recognized.
112 The following code should explain how to use the typefind element.
113 It will print the detected media type, or tell that the media type
114 was not found. The next section will introduce more useful behaviours,
115 such as plugging together a decoding pipeline.
117 <programlisting><!-- example-begin typefind.c a -->
118 #include <gst/gst.h>
119 <!-- example-end typefind.c a -->
120 <!-- example-begin typefind.c b --><!--
122 my_bus_callback (GstBus *bus,
126 GMainLoop *loop = data;
128 switch (GST_MESSAGE_TYPE (message)) {
129 case GST_MESSAGE_ERROR: {
133 gst_message_parse_error (message, &err, &debug);
134 g_print ("Error: %s\n", err->message);
138 g_main_loop_quit (loop);
141 case GST_MESSAGE_EOS:
143 g_main_loop_quit (loop);
149 /* remove from queue */
152 --><!-- example-end typefind.c b -->
153 <!-- example-begin typefind.c c -->
155 idle_exit_loop (gpointer data)
157 g_main_loop_quit ((GMainLoop *) data);
164 cb_typefound (GstElement *typefind,
169 GMainLoop *loop = data;
172 type = gst_caps_to_string (caps);
173 g_print ("Media type %s found, probability %d%%\n", type, probability);
176 /* since we connect to a signal in the pipeline thread context, we need
177 * to set an idle handler to exit the main loop in the mainloop context.
178 * Normally, your app should not need to worry about such things. */
179 g_idle_add (idle_exit_loop, loop);
187 GstElement *pipeline, *filesrc, *typefind;
190 gst_init (&argc, &argv);
191 loop = g_main_loop_new (NULL, FALSE);
195 g_print ("Usage: %s <filename>\n", argv[0]);
199 /* create a new pipeline to hold the elements */
200 pipeline = gst_pipeline_new ("pipe");
201 gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
202 my_bus_callback, NULL);
204 /* create file source and typefind element */
205 filesrc = gst_element_factory_make ("filesrc", "source");
206 g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
207 typefind = gst_element_factory_make ("typefind", "typefinder");
208 g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), loop);
211 gst_bin_add_many (GST_BIN (pipeline), filesrc, typefind, NULL);
212 gst_element_link (filesrc, typefind);
213 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
214 g_main_loop_run (loop);
217 gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
218 gst_object_unref (GST_OBJECT (pipeline));
222 <!-- example-end typefind.c c --></programlisting>
224 Once a media type has been detected, you can plug an element (e.g. a
225 demuxer or decoder) to the source pad of the typefind element, and
226 decoding of the media stream will start right after.
230 <sect1 id="section-dynamic">
231 <title>Plugging together dynamic pipelines</title>
233 In this chapter we will see how you can create a dynamic pipeline. A
234 dynamic pipeline is a pipeline that is updated or created while data
235 is flowing through it. We will create a partial pipeline first and add
236 more elements while the pipeline is playing. The basis of this player
237 will be the application that we wrote in the previous section (<xref
238 linkend="section-typefinding"/>) to identify unknown media streams.
240 <!-- example-begin dynamic.c a --><!--
241 #include <gst/gst.h>
243 GstElement *pipeline;
244 --><!-- example-end dynamic.c a -->
246 Once the type of the media has been found, we will find elements in
247 the registry that can decode this streamtype. For this, we will get
248 all element factories (which we've seen before in <xref
249 linkend="section-elements-create"/>) and find the ones with the
250 given MIME-type and capabilities on their sinkpad. Note that we will
251 only use parsers, demuxers and decoders. We will not use factories for
252 any other element types, or we might get into a loop of encoders and
253 decoders. For this, we will want to build a list of <quote>allowed</quote>
254 factories right after initializing &GStreamer;.
256 <programlisting><!-- example-begin dynamic.c b -->
257 static GList *factories;
260 * This function is called by the registry loader. Its return value
261 * (TRUE or FALSE) decides whether the given feature will be included
262 * in the list that we're generating further down.
266 cb_feature_filter (GstPluginFeature *feature,
272 /* we only care about element factories */
273 if (!GST_IS_ELEMENT_FACTORY (feature))
276 /* only parsers, demuxers and decoders */
277 klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
278 if (g_strrstr (klass, "Demux") == NULL &&
279 g_strrstr (klass, "Decoder") == NULL &&
280 g_strrstr (klass, "Parse") == NULL)
283 /* only select elements with autoplugging rank */
284 rank = gst_plugin_feature_get_rank (feature);
285 if (rank < GST_RANK_MARGINAL)
292 * This function is called to sort features by rank.
296 cb_compare_ranks (GstPluginFeature *f1,
297 GstPluginFeature *f2)
299 return gst_plugin_feature_get_rank (f2) - gst_plugin_feature_get_rank (f1);
303 init_factories (void)
305 /* first filter out the interesting element factories */
306 factories = gst_registry_pool_feature_filter (
307 (GstPluginFeatureFilter) cb_feature_filter, FALSE, NULL);
309 /* sort them according to their ranks */
310 factories = g_list_sort (factories, (GCompareFunc) cb_compare_ranks);
312 <!-- example-end dynamic.c b --></programlisting>
314 From this list of element factories, we will select the one that most
315 likely will help us decoding a media stream to a given output type.
316 For each newly created element, we will again try to autoplug new
317 elements to its source pad(s). Also, if the element has dynamic pads
318 (which we've seen before in <xref linkend="section-pads-dynamic"/>),
319 we will listen for newly created source pads and handle those, too.
320 The following code replaces the <function>cb_type_found</function>
321 from the previous section with a function to initiate autoplugging,
322 which will continue with the above approach.
324 <programlisting><!-- example-begin dynamic.c c -->
325 static void try_to_plug (GstPad *pad, const GstCaps *caps);
327 static GstElement *audiosink;
330 cb_newpad (GstElement *element,
336 caps = gst_pad_get_caps (pad);
337 try_to_plug (pad, caps);
338 gst_caps_unref (caps);
342 close_link (GstPad *srcpad,
343 GstElement *sinkelement,
344 const gchar *padname,
345 const GList *templlist)
348 gboolean has_dynamic_pads = FALSE;
350 g_print ("Plugging pad %s:%s to newly created %s:%s\n",
351 gst_object_get_name (GST_OBJECT (gst_pad_get_parent (srcpad))),
352 gst_pad_get_name (srcpad),
353 gst_object_get_name (GST_OBJECT (sinkelement)), padname);
355 /* add the element to the pipeline and set correct state */
356 if (sinkelement != audiosink) {
357 gst_bin_add (GST_BIN (pipeline), sinkelement);
358 gst_element_set_state (sinkelement, GST_STATE_READY);
360 pad = gst_element_get_pad (sinkelement, padname);
361 gst_pad_link (srcpad, pad);
362 if (sinkelement != audiosink) {
363 gst_element_set_state (sinkelement, GST_STATE_PAUSED);
365 gst_object_unref (GST_OBJECT (pad));
367 /* if we have static source pads, link those. If we have dynamic
368 * source pads, listen for new-pad signals on the element */
369 for ( ; templlist != NULL; templlist = templlist->next) {
370 GstStaticPadTemplate *templ = templlist->data;
372 /* only sourcepads, no request pads */
373 if (templ->direction != GST_PAD_SRC ||
374 templ->presence == GST_PAD_REQUEST) {
378 switch (templ->presence) {
379 case GST_PAD_ALWAYS: {
380 GstPad *pad = gst_element_get_pad (sinkelement, templ->name_template);
381 GstCaps *caps = gst_pad_get_caps (pad);
384 try_to_plug (pad, caps);
385 gst_object_unref (GST_OBJECT (pad));
386 gst_caps_unref (caps);
389 case GST_PAD_SOMETIMES:
390 has_dynamic_pads = TRUE;
397 /* listen for newly created pads if this element supports that */
398 if (has_dynamic_pads) {
399 g_signal_connect (sinkelement, "new-pad", G_CALLBACK (cb_newpad), NULL);
404 try_to_plug (GstPad *pad,
407 GstObject *parent = GST_OBJECT (GST_OBJECT_PARENT (pad));
410 GstCaps *res, *audiocaps;
412 /* don't plug if we're already plugged - FIXME: memleak for pad */
413 if (GST_PAD_IS_LINKED (gst_element_get_pad (audiosink, "sink"))) {
414 g_print ("Omitting link for pad %s:%s because we're already linked\n",
415 GST_OBJECT_NAME (parent), GST_OBJECT_NAME (pad));
419 /* as said above, we only try to plug audio... Omit video */
420 mime = gst_structure_get_name (gst_caps_get_structure (caps, 0));
421 if (g_strrstr (mime, "video")) {
422 g_print ("Omitting link for pad %s:%s because mimetype %s is non-audio\n",
423 GST_OBJECT_NAME (parent), GST_OBJECT_NAME (pad), mime);
427 /* can it link to the audiopad? */
428 audiocaps = gst_pad_get_caps (gst_element_get_pad (audiosink, "sink"));
429 res = gst_caps_intersect (caps, audiocaps);
430 if (res && !gst_caps_is_empty (res)) {
431 g_print ("Found pad to link to audiosink - plugging is now done\n");
432 close_link (pad, audiosink, "sink", NULL);
433 gst_caps_unref (audiocaps);
434 gst_caps_unref (res);
437 gst_caps_unref (audiocaps);
438 gst_caps_unref (res);
440 /* try to plug from our list */
441 for (item = factories; item != NULL; item = item->next) {
442 GstElementFactory *factory = GST_ELEMENT_FACTORY (item->data);
445 for (pads = gst_element_factory_get_static_pad_templates (factory);
446 pads != NULL; pads = pads->next) {
447 GstStaticPadTemplate *templ = pads->data;
449 /* find the sink template - need an always pad*/
450 if (templ->direction != GST_PAD_SINK ||
451 templ->presence != GST_PAD_ALWAYS) {
456 res = gst_caps_intersect (caps,
457 gst_static_caps_get (&templ->static_caps));
458 if (res && !gst_caps_is_empty (res)) {
460 gchar *name_template = g_strdup (templ->name_template);
462 /* close link and return */
463 gst_caps_unref (res);
464 element = gst_element_factory_create (factory, NULL);
465 close_link (pad, element, name_template,
466 gst_element_factory_get_static_pad_templates (factory));
467 g_free (name_template);
470 gst_caps_unref (res);
472 /* we only check one sink template per factory, so move on to the
473 * next factory now */
478 /* if we get here, no item was found */
479 g_print ("No compatible pad found to decode %s on %s:%s\n",
480 mime, GST_OBJECT_NAME (parent), GST_OBJECT_NAME (pad));
484 cb_typefound (GstElement *typefind,
492 s = gst_caps_to_string (caps);
493 g_print ("Detected media type %s\n", s);
496 /* actually plug now */
497 pad = gst_element_get_pad (typefind, "src");
498 try_to_plug (pad, caps);
499 gst_object_unref (GST_OBJECT (pad));
501 <!-- example-end dynamic.c c --></programlisting>
503 By doing all this, we will be able to make a simple autoplugger that
504 can automatically setup a pipeline for any media type. In the example
505 below, we will do this for audio only. However, we can also do this
506 for video to create a player that plays both audio and video.
508 <!-- example-begin dynamic.c d --><!--
510 my_bus_callback (GstBus *bus,
514 GMainLoop *loop = data;
516 switch (GST_MESSAGE_TYPE (message)) {
517 case GST_MESSAGE_ERROR: {
521 gst_message_parse_error (message, &err, &debug);
522 g_print ("Error: %s\n", err->message);
526 g_main_loop_quit (loop);
529 case GST_MESSAGE_EOS:
531 g_main_loop_quit (loop);
537 /* remove from queue */
546 GstElement *typefind, *realsink;
549 /* init GStreamer and ourselves */
550 gst_init (&argc, &argv);
551 loop = g_main_loop_new (NULL, FALSE);
556 g_print ("Usage: %s <filename>\n", argv[0]);
561 p = g_strdup_printf ("filesrc location=\"%s\" ! typefind name=tf", argv[1]);
562 pipeline = gst_parse_launch (p, NULL);
563 gst_bus_add_watch (gst_pipeline_get_bus (GST_PIPELINE (pipeline)),
564 my_bus_callback, NULL);
566 typefind = gst_bin_get_by_name (GST_BIN (pipeline), "tf");
567 g_signal_connect (typefind, "have-type", G_CALLBACK (cb_typefound), NULL);
568 gst_object_unref (GST_OBJECT (typefind));
569 audiosink = gst_element_factory_make ("audioconvert", "aconv");
570 realsink = gst_element_factory_make ("alsasink", "audiosink");
571 gst_bin_add_many (GST_BIN (pipeline), audiosink, realsink, NULL);
572 gst_element_link (audiosink, realsink);
573 gst_element_set_state (pipeline, GST_STATE_PLAYING);
576 g_main_loop_run (loop);
579 gst_element_set_state (pipeline, GST_STATE_NULL);
580 gst_object_unref (GST_OBJECT (pipeline));
584 --><!-- example-end dynamic.c d -->
586 The example above is a good first try for an autoplugger. Next steps
587 would be to listen for <quote>pad-removed</quote> signals, so we
588 can dynamically change the plugged pipeline if the stream changes
589 (this happens for DVB or Ogg radio). Also, you might want special-case
590 code for input with known content (such as a DVD or an audio-CD),
591 and much, much more. Moreover, you'll want many checks to prevent
592 infinite loops during autoplugging, maybe you'll want to implement
593 shortest-path-finding to make sure the most optimal pipeline is chosen,
594 and so on. Basically, the features that you implement in an autoplugger
595 depend on what you want to use it for. For full-blown implementations,
596 see the <quote>playbin</quote> and <quote>decodebin</quote> elements.