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.
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 Chapter 4, 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 "pad-added" event handler
on the "oggdemux" element, like you've learned in
Section 8.1.1, 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 Chapter 6, and we've learned about element states
in Section 5.6. We will also attach
a message handler to the pipeline bus so we can retrieve errors
and detect the end-of-stream.
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, *sink; static gboolean bus_call (GstBus *bus, GstMessage *msg, gpointer data) { GMainLoop *loop = data; switch (GST_MESSAGE_TYPE (msg)) { case GST_MESSAGE_EOS: g_print ("End-of-stream\n"); g_main_loop_quit (loop); break; case GST_MESSAGE_ERROR: { gchar *debug; GError *err; gst_message_parse_error (msg, &err, &debug); g_free (debug); g_print ("Error: %s\n", err->message); g_error_free (err); g_main_loop_quit (loop); break; } default: break; } return TRUE; } static void new_pad (GstElement *element, GstPad *pad, gpointer data) { GstPad *sinkpad; /* We can now link this pad with the audio decoder */ g_print ("Dynamic pad created, linking parser/decoder\n"); sinkpad = gst_element_get_pad (decoder, "sink"); gst_pad_link (pad, sinkpad); gst_object_unref (sinkpad); } int main (int argc, char *argv[]) { GMainLoop *loop; GstBus *bus; /* initialize GStreamer */ gst_init (&argc, &argv); loop = g_main_loop_new (NULL, FALSE); /* 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", "converter"); sink = gst_element_factory_make ("alsasink", "alsa-output"); if (!pipeline || !source || !parser || !decoder || !conv || !sink) { g_print ("One element could not be created\n"); return -1; } /* set filename property on the file source. Also add a message * handler. */ g_object_set (G_OBJECT (source), "location", argv[1], NULL); bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline)); gst_bus_add_watch (bus, bus_call, loop); gst_object_unref (bus); /* put all elements in a bin */ gst_bin_add_many (GST_BIN (pipeline), source, parser, decoder, conv, sink, NULL); /* link together - note that we cannot link the parser and * decoder yet, becuse the parser uses dynamic pads. For that, * we set a pad-added signal handler. */ gst_element_link (source, parser); gst_element_link_many (decoder, conv, sink, NULL); g_signal_connect (parser, "pad-added", G_CALLBACK (new_pad), NULL); /* Now set to playing and iterate. */ g_print ("Setting to PLAYING\n"); gst_element_set_state (pipeline, GST_STATE_PLAYING); g_print ("Running\n"); g_main_loop_run (loop); /* clean up nicely */ g_print ("Returned, stopping playback\n"); gst_element_set_state (pipeline, GST_STATE_NULL); g_print ("Deleting pipeline\n"); gst_object_unref (GST_OBJECT (pipeline)); return 0; }
We now have created a complete pipeline. We can visualise the pipeline as follows: