Your second application
FIXME: delete this section, talk more about the spider. In a previous chapter we created a first
version of the helloworld application. We then explained a better way of creating the elements
using factories identified by MIME types and the autoplugger.
Autoplugging helloworld
We will create a second version of the helloworld application using
autoplugging. Its source code is a bit more complicated but
it can handle many more data types. It can even play the audio track
of a video file.
Here is the full program listing. Start by looking at the main ()
function.
/* example-begin helloworld2.c */
#include <gst/gst.h>
static void gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline);
static void gst_play_cache_empty (GstElement *element, GstElement *pipeline);
static void
gst_play_have_type (GstElement *typefind, GstCaps *caps, GstElement *pipeline)
{
GstElement *osssink;
GstElement *new_element;
GstAutoplug *autoplug;
GstElement *autobin;
GstElement *filesrc;
GstElement *cache;
g_print ("GstPipeline: play have type\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
/* unlink the typefind from the pipeline and remove it */
gst_element_unlink (cache, typefind);
gst_bin_remove (GST_BIN (autobin), typefind);
/* and an audio sink */
osssink = gst_element_factory_make ("osssink", "play_audio");
g_assert (osssink != NULL);
autoplug = gst_autoplug_factory_make ("staticrender");
g_assert (autoplug != NULL);
new_element = gst_autoplug_to_renderers (autoplug, caps, osssink, NULL);
if (!new_element) {
g_print ("could not autoplug, no suitable codecs found...\n");
exit (-1);
}
gst_element_set_name (new_element, "new_element");
gst_bin_add (GST_BIN (autobin), new_element);
g_object_set (G_OBJECT (cache), "reset", TRUE, NULL);
gst_element_link (cache, new_element);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
}
static void
gst_play_cache_empty (GstElement *element, GstElement *pipeline)
{
GstElement *autobin;
GstElement *filesrc;
GstElement *cache;
GstElement *new_element;
g_print ("have cache empty\n");
gst_element_set_state (pipeline, GST_STATE_PAUSED);
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
new_element = gst_bin_get_by_name (GST_BIN (autobin), "new_element");
gst_element_unlink (filesrc, cache);
gst_element_unlink (cache, new_element);
gst_bin_remove (GST_BIN (autobin), cache);
gst_element_link (filesrc, new_element);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
g_print ("done with cache_empty\n");
}
int
main (int argc, char *argv[])
{
GstElement *filesrc;
GstElement *pipeline;
GstElement *autobin;
GstElement *typefind;
GstElement *cache;
gst_init (&argc, &argv);
if (argc != 2) {
g_print ("usage: %s <filename with audio>\n", argv[0]);
exit (-1);
}
/* create a new pipeline to hold the elements */
pipeline = gst_pipeline_new ("pipeline");
g_assert (pipeline != NULL);
/* create a disk reader */
filesrc = gst_element_factory_make ("filesrc", "disk_source");
g_assert (filesrc != NULL);
g_object_set (G_OBJECT (filesrc), "location", argv[1], NULL);
gst_bin_add (GST_BIN (pipeline), filesrc);
autobin = gst_bin_new ("autobin");
cache = gst_element_factory_make ("autoplugcache", "cache");
g_signal_connect (G_OBJECT (cache), "cache_empty",
G_CALLBACK (gst_play_cache_empty), pipeline);
typefind = gst_element_factory_make ("typefind", "typefind");
g_signal_connect (G_OBJECT (typefind), "have_type",
G_CALLBACK (gst_play_have_type), pipeline);
gst_bin_add (GST_BIN (autobin), cache);
gst_bin_add (GST_BIN (autobin), typefind);
gst_element_link (cache, typefind);
gst_element_add_ghost_pad (autobin,
gst_element_get_pad (cache, "sink"), "sink");
gst_bin_add (GST_BIN( pipeline), autobin);
gst_element_link (filesrc, autobin);
/* start playing */
gst_element_set_state( GST_ELEMENT (pipeline), GST_STATE_PLAYING);
while (gst_bin_iterate (GST_BIN (pipeline)));
/* stop the pipeline */
gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
gst_object_unref (GST_OBJECT (pipeline));
exit(0);
}
/* example-end helloworld2.c */
We start by constructing a 'filesrc' element and an 'autobin' element that
holds the autoplugcache and the typefind element.
We attach the "cache_empty" signal to gst_play_cache_empty and the
"have_type" to our gst_play_have_type function.
The _have_type function first sets the pipeline to the PAUSED state
so that it can safely modify the pipeline. It then finds the elements
it is going to manipulate in the pipeline with:
filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "disk_source");
autobin = gst_bin_get_by_name (GST_BIN (pipeline), "autobin");
cache = gst_bin_get_by_name (GST_BIN (autobin), "cache");
Now we have a handle to the elements we are going to manipulate in
the next step.
We don't need the typefind element anymore so we remove it from
the pipeline:
/* unlink the typefind from the pipeline and remove it */
gst_element_unlink (cache, "src", typefind, "sink");
gst_bin_remove (GST_BIN (autobin), typefind);
Our next step is to construct an element that can play the type we just
detected. We are going to use the autoplugger to create an element that
links the type to an osssink. We add the new element to our
autobin.
/* and an audio sink */
osssink = gst_element_factory_make("osssink", "play_audio");
g_assert(osssink != NULL);
autoplug = gst_autoplug_factory_make ("staticrender");
g_assert (autoplug != NULL);
new_element = gst_autoplug_to_renderers (autoplug,
caps,
osssink,
NULL);
if (!new_element) {
g_print ("could not autoplug, no suitable codecs found...\n");
exit (-1);
}
gst_element_set_name (new_element, "new_element");
gst_bin_add (GST_BIN (autobin), new_element);
Our next step is to reset the cache so that the buffers used by the
typefind element are fed into the new element we just created. We reset
the cache by setting the "reset" property of the cache element to TRUE.
g_object_set (G_OBJECT (cache), "reset", TRUE, NULL);
gst_element_link (cache, "src", new_element, "sink");
Finally we set the pipeline back to the playing state. At this point the
cache will replay the buffers. We will be notified when the cache is empty
by the gst_play_cache_empty callback function.
The cache empty function simply removes the autoplugcache element from
the pipeline and relinks the filesrc to the autoplugged element.
To compile the helloworld2 example, use:
gcc -Wall `pkg-config gstreamer --cflags --libs` helloworld2.c \
-o helloworld2
You can run the example with
(substitute helloworld.mp3 with you favorite audio file):
./helloworld2 helloworld.mp3
You can also try to use an AVI or MPEG file as its input.
Using autoplugging,
GStreamer
will automatically figure out how to
handle the stream.
Remember that only the audio part will be played because
we have only added an osssink to the pipeline.
./helloworld2 mymovie.mpeg