Your second application 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. We start by creating the main() of our program: #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); 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>\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_elementfactory_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_elementfactory_make ("autoplugcache", "cache"); g_signal_connect (G_OBJECT (cache), "cache_empty", G_CALLBACK (gst_play_cache_empty), pipeline); typefind = gst_elementfactory_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_connect (cache, "src", typefind, "sink"); gst_element_add_ghost_pad (autobin, gst_element_get_pad (cache, "sink"), "sink"); gst_bin_add (GST_BIN( pipeline), autobin); gst_element_connect (filesrc, "src", autobin, "sink"); /* 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); } 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 (defined below). 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; GST_DEBUG (0,"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"); // disconnect the typefind from the pipeline and remove it gst_element_disconnect (cache, "src", typefind, "sink"); gst_bin_remove (GST_BIN (autobin), typefind); /* and an audio sink */ osssink = gst_elementfactory_make("osssink", "play_audio"); g_assert(osssink != NULL); autoplug = gst_autoplugfactory_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_connect (cache, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); } 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: // disconnect the typefind from the pipeline and remove it gst_element_disconnect (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 connects the type to an osssink. We add the new element to our autobin. /* and an audio sink */ osssink = gst_elementfactory_make("osssink", "play_audio"); g_assert(osssink != NULL); autoplug = gst_autoplugfactory_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_connect (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 with the gst_play_cache_empty callback function: static void gst_play_cache_empty (GstElement *element, GstElement *pipeline) { GstElement *autobin; GstElement *filesrc; GstElement *cache; GstElement *new_element; fprintf (stderr, "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_disconnect (filesrc, "src", cache, "sink"); gst_element_disconnect (cache, "src", new_element, "sink"); gst_bin_remove (GST_BIN (autobin), cache); gst_element_connect (filesrc, "src", new_element, "sink"); gst_element_set_state (pipeline, GST_STATE_PLAYING); fprintf (stderr, "done with cache_empty\n"); } The cache empty function simply removes the autoplugcache element from the pipeline and reconnects the filesrc to the autoplugged element. To compile the helloworld2 example, use: gcc -Wall `gstreamer-config --cflags --libs` helloworld2.c \ -o helloworld2 You can run the example with (substitute helloworld.mp3 with you favorite MP3 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