Your first application This chapter will summarize everything you've learned in the previous chapters. It describes all aspects of a simple &GStreamer; application, including initializing libraries, creating elements, packing elements together in a pipeline and playing this pipeline. By doing all this, you will be able to build a simple Ogg/Vorbis audio player. Hello world We're going to create a simple first application, a simple Ogg/Vorbis command-line audio player. For this, we will use only standard &GStreamer; components. The player will read a file specified on the command-line. Let's get started! We've learned, in , that the first thing to do in your application is to initialize &GStreamer; by calling gst_init (). Also, make sure that the application includes gst/gst.h so all function names and objects are properly defined. Use #include <gst/gst.h> to do that. Next, you'll want to create the different elements using gst_element_factory_make (). For an Ogg/Vorbis audio player, we'll need a source element that reads files from a disk. &GStreamer; includes this element under the name filesrc. Next, we'll need something to parse the file and decoder it into raw audio. &GStreamer; has two elements for this: the first parses Ogg streams into elementary streams (video, audio) and is called oggdemux. The second is a Vorbis audio decoder, it's conveniently called vorbisdec. Since oggdemux creates dynamic pads for each elementary stream, you'll need to set a new-pad event handler on the oggdemux element, like you've learned in , to link the Ogg parser and the Vorbis decoder elements together. At last, we'll also need an audio output element, we will use alsasink, which outputs sound to an ALSA audio device. The last thing left to do is to add all elements into a container element, a GstPipeline, and iterate this pipeline until we've played the whole song. We've previously learned how to add elements to a container bin in , and we've learned about element states in . We will use the function gst_bin_sync_children_state () to synchronize the state of a bin on all of its contained children. Let's now add all the code together to get our very first audio player: #include <gst/gst.h> /* * Global objects are usually a bad thing. For the purpose of this * example, we will use them, however. */ GstElement *pipeline, *source, *parser, *decoder, *conv, *scale, *sink; static void new_pad (GstElement *element, GstPad *pad, gpointer data) { /* We can now link this pad with the audio decoder and * add both decoder and audio output to the pipeline. */ gst_pad_link (pad, gst_element_get_pad (decoder, "sink")); gst_bin_add_many (GST_BIN (pipeline), decoder, conv, scale, sink, NULL); /* This function synchronizes a bins state on all of its * contained children. */ gst_bin_sync_children_state (GST_BIN (pipeline)); } int main (int argc, char *argv[]) { /* initialize GStreamer */ gst_init (&argc, &argv); /* check input arguments */ if (argc != 2) { g_print ("Usage: %s <Ogg/Vorbis filename>\n", argv[0]); return -1; } /* create elements */ pipeline = gst_pipeline_new ("audio-player"); source = gst_element_factory_make ("filesrc", "file-source"); parser = gst_element_factory_make ("oggdemux", "ogg-parser"); decoder = gst_element_factory_make ("vorbisdec", "vorbis-decoder"); conv = gst_element_factory_make ("audioconvert", "conv"); scale = gst_element_factory_make ("audioscale", "scale"); sink = gst_element_factory_make ("alsasink", "alsa-output"); /* set filename property on the file source */ g_object_set (G_OBJECT (source), "location", argv[1], NULL); /* link together - note that we cannot link the parser and * decoder yet, becuse the parser uses dynamic pads. For that, * we set a new-pad signal handler. */ gst_element_link (source, parser); gst_element_link_many (decoder, conv, scale, sink, NULL); g_signal_connect (parser, "new-pad", G_CALLBACK (new_pad), NULL); /* put all elements in a bin - or at least the ones we will use * instantly. */ gst_bin_add_many (GST_BIN (pipeline), source, parser, NULL); /* Now set to playing and iterate. We will set the decoder and * audio output to ready so they initialize their memory already. * This will decrease the amount of time spent on linking these * elements when the Ogg parser emits the new-pad signal. */ gst_element_set_state (decoder, GST_STATE_READY); gst_element_set_state (conv, GST_STATE_READY); gst_element_set_state (scale, GST_STATE_READY); gst_element_set_state (sink, GST_STATE_READY); gst_element_set_state (pipeline, GST_STATE_PLAYING); /* and now iterate - the rest will be automatic from here on. * When the file is finished, gst_bin_iterate () will return * FALSE, thereby terminating this loop. */ while (gst_bin_iterate (GST_BIN (pipeline))) ; /* clean up nicely */ gst_element_set_state (pipeline, GST_STATE_NULL); gst_object_unref (GST_OBJECT (pipeline)); return 0; } We now have created a complete pipeline. We can visualise the pipeline as follows:
The "hello world" pipeline
Compiling and Running helloworld.c To compile the helloworld example, use: gcc -Wall $(pkg-config --cflags --libs gstreamer-&GST_MAJORMINOR;) helloworld.c -o helloworld. &GStreamer; makes use of pkg-config to get compiler and linker flags needed to compile this application. If you're running a non-standard installation, make sure the PKG_CONFIG_PATH environment variable is set to the correct location ($libdir/pkgconfig). application against the uninstalled location. You can run this example application with ./helloworld file.ogg. Substitute file.ogg with your favourite Ogg/Vorbis file. Conclusion This concludes our first example. As you see, setting up a pipeline is very low-level but powerful. You will see later in this manual how you can create a more powerful media player with even less effort using higher-level interfaces. We will discuss all that in . We will first, however, go more in-depth into more advanced &GStreamer; internals. It should be clear from the example that we can very easily replace the filesrc element with some other element that reads data from a network, or some other data source element that is better integrated with your desktop environment. Also, you can use other decoders and parsers to support other media types. You can use another audio sink if you're not running Linux, but Mac OS X, Windows or FreeBSD, or you can instead use a filesink to write audio files to disk instead of playing them back. By using an audio card source, you can even do audio capture instead of playback. All this shows the reusability of &GStreamer; elements, which is its greatest advantage.