Issuu on Google+

GStreamer Multimedia Framework Part 5


Contents

Description

Part 1

Introduction to GStreamer

Part 2

GStreamer Plugin Internals

Part 3

Advanced GStreamer Concepts

Part 4

Concepts of GStreamer Application

Part 5

An Example Application Code

2


An Example Application Code 

static gboolean gst_initialized = FALSE;

This variable will be set to TRUE if the gst is initialized properly.

gst_init (int *argc, char **argv[])

Initializes the GStreamer library, setting up internal path lists,

registering built-in elements, and loading standard plugins.

the registry will be loaded. By default this will also check if the registry cache needs to be

updated and rescan all plugins if needed.

This function should be called before calling any other GLib functions.

gst_is_initialized (void){

return gst_initialized;

}

Use this function to check if GStreamer has been initialized.

GstElement *

gst_pipeline_new (const gchar * name){

return gst_element_factory_make ("pipeline", name);

}

Create a new pipeline with the given name.

gst_element_factory_make uses gst_element_factory_find() and gst_element_factory_create() functions internally to create the gst_element of the given type.

3


An Example Application Code

now it's time to get the decoder

decoder = gst_element_factory_make ("mad", "decode");

if (!decoder) {

g_print ("could not find plugin \"mad\"");

return -1;

}

also, we need to add some converters to make sure the audio stream

from the decoder is converted into a format the audio sink can understand (if necessary)

conv = gst_element_factory_make ("audioconvert", "audioconvert");

if (!conv) {

g_print ("could not create \"audioconvert\" element!");

return -1;

}

resample = gst_element_factory_make ("audioresample", "audioresample");

if (!resample) {

g_print ("could not create \"audioresample\" element!");

return -1;

}

4


An Example Application Code 

add an audio sink

audiosink = gst_element_factory_make ("alsasink", "play_audio");

g_assert (audiosink);

add objects to the main pipeline

gst_bin_add_many (GST_BIN (bin), filesrc, decoder, conv,

resample, audiosink, NULL);

Adds a NULL-terminated list of elements to a bin. This function is

equivalent to calling gst_bin_add() for each member of the list. The return

value of each gst_bin_add() is ignored.

void

gst_bin_add_many (GstBin * bin, GstElement * element_1, ...)

{

va_list args;

g_return_if_fail (GST_IS_BIN (bin));

g_return_if_fail (GST_IS_ELEMENT (element_1));

va_start (args, element_1);

5


An Example Application Code 

while (element_1) {

gst_bin_add (bin, element_1);

element_1 = va_arg (args, GstElement *);

}

va_end (args);

}

gboolean

gst_bin_add (GstBin * bin, GstElement * element)

{

GstBinClass *bclass;

gboolean result;

g_return_val_if_fail (GST_IS_BIN (bin), FALSE);

g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);

bclass = GST_BIN_GET_CLASS (bin);

6


An Example Application Code 

if (G_UNLIKELY (bclass->add_element == NULL))

goto no_function;

GST_CAT_DEBUG (GST_CAT_PARENTAGE, "adding element %s to bin %s",

GST_STR_NULL (GST_ELEMENT_NAME (element)),

GST_STR_NULL (GST_ELEMENT_NAME (bin)));

result = bclass->add_element (bin, element);

return result;

ERROR handling

no_function:

{

g_warning ("adding elements to bin %s is not supported",

GST_ELEMENT_NAME (bin));

return FALSE;

 

} }

Adds the given element to the bin. Sets the element's parent, and thus

takes ownership of the element. An element can only be added to one bin.

7


An Example Application Code 

If the element's pads are linked to other pads, the pads will be unlinked

before the element is added to the bin.

void

gst_bin_remove_many (GstBin * bin, GstElement * element_1, ...)

{

va_list args;

g_return_if_fail (GST_IS_BIN (bin));

g_return_if_fail (GST_IS_ELEMENT (element_1));

va_start (args, element_1);

while (element_1) {

gst_bin_remove (bin, element_1);

element_1 = va_arg (args, GstElement *);

}

va_end (args);

}

8


An Example Application Code 

Chain together a series of elements. Uses gst_element_link().

Make sure you have added your elements to a bin or pipeline with

gst_bin_add() before trying to link them.

link the elements

gst_element_link_many (filesrc, decoder, conv, resample, audiosink, NULL);

gboolean

gst_element_link_many (GstElement * element_1, GstElement * element_2, ...)

{

gboolean res = TRUE;

va_list args;

g_return_val_if_fail (GST_IS_ELEMENT (element_1), FALSE);

g_return_val_if_fail (GST_IS_ELEMENT (element_2), FALSE);

va_start (args, element_2);

while (element_2) {

if (!gst_element_link (element_1, element_2)) {

res = FALSE;

break;

}

element_1 = element_2;

element_2 = va_arg (args, GstElement *);

}

9


An Example Application Code

va_end (args);

return res;

}

Make sure you have added your elements to a bin or pipeline with

gst_bin_add() before trying to link them.

gboolean

gst_element_link (GstElement * src, GstElement * dest)

{

return gst_element_link_pads (src, NULL, dest, NULL);

}

gst_element_link_pads_full (GstElement * src, const gchar * srcpadname,

 

GstElement * dest, const gchar * destpadname, GstPadLinkCheck flags) {

const GList *srcpads, *destpads, *srctempls, *desttempls, *l;

GstPad *srcpad, *destpad;

GstPadTemplate *srctempl, *desttempl;

GstElementClass *srcclass, *destclass;

checks

g_return_val_if_fail (GST_IS_ELEMENT (src), FALSE);

g_return_val_if_fail (GST_IS_ELEMENT (dest), FALSE);

10


An Example Application Code 

GST_CAT_INFO (GST_CAT_ELEMENT_PADS,

"trying to link element %s:%s to element %s:%s", GST_ELEMENT_NAME (src),

srcpadname ? srcpadname : "(any)", GST_ELEMENT_NAME (dest),

destpadname ? destpadname : "(any)");

get a src pad

if (srcpadname) {

name specified, look it up

if (!(srcpad = gst_element_get_static_pad (src, srcpadname)))

srcpad = gst_element_get_request_pad (src, srcpadname);

if (!srcpad) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",

GST_ELEMENT_NAME (src), srcpadname);

 

return FALSE; } else {

if (!(GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC)) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no src pad",

GST_DEBUG_PAD_NAME (srcpad));

gst_object_unref (srcpad);

return FALSE;

}

if (GST_PAD_PEER (srcpad) != NULL) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked",

GST_DEBUG_PAD_NAME (srcpad));

gst_object_unref (srcpad);

return FALSE;

   

} } srcpads = NULL; } else { 11


An Example Application Code 

no name given, get the first available pad

GST_OBJECT_LOCK (src);

srcpads = GST_ELEMENT_PADS (src);

srcpad = srcpads ? GST_PAD_CAST (srcpads->data) : NULL;

if (srcpad)

gst_object_ref (srcpad);

GST_OBJECT_UNLOCK (src);

}

get a destination pad

if (destpadname) {

    

name specified, look it up if (!(destpad = gst_element_get_static_pad (dest, destpadname))) destpad = gst_element_get_request_pad (dest, destpadname); if (!destpad) { GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no pad %s:%s",

   

GST_ELEMENT_NAME (dest), destpadname); return FALSE; } else { if (!(GST_PAD_DIRECTION (destpad) == GST_PAD_SINK)) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is no sink pad",

GST_DEBUG_PAD_NAME (destpad));

gst_object_unref (destpad);

return FALSE;

}

if (GST_PAD_PEER (destpad) != NULL) {

 

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "pad %s:%s is already linked", GST_DEBUG_PAD_NAME (destpad));

gst_object_unref (destpad);

return FALSE; 12


An Example Application Code 

}

}

destpads = NULL;

} else {

no name given, get the first available pad

GST_OBJECT_LOCK (dest);

destpads = GST_ELEMENT_PADS (dest);

destpad = destpads ? GST_PAD_CAST (destpads->data) : NULL;

if (destpad)

gst_object_ref (destpad);

GST_OBJECT_UNLOCK (dest);

}

if (srcpad) {

        

loop through the allowed pads in the source, trying to find a compatible destination pad GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "looping through allowed src and dest pads"); do { GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "trying src pad %s:%s", GST_DEBUG_PAD_NAME (srcpad)); if ((GST_PAD_DIRECTION (srcpad) == GST_PAD_SRC) && (GST_PAD_PEER (srcpad) == NULL)) {

GstPad *temp;

if (destpadname) {

temp = destpad;

gst_object_ref (temp);

13


An Example Application Code 

} else {

temp = gst_element_get_compatible_pad (dest, srcpad, NULL);

}

if (temp && pad_link_maybe_ghosting (srcpad, temp, flags)) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "linked pad %s:%s to pad %s:%s",

GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (temp));

if (destpad)

gst_object_unref (destpad);

gst_object_unref (srcpad);

gst_object_unref (temp);

return TRUE;

}

if (temp) {

gst_object_unref (temp);

}

}

 

if (srcpads) {

srcpads = g_list_next (srcpads);

if (srcpads) {

gst_object_unref (srcpad);

srcpad = GST_PAD_CAST (srcpads->data);

gst_object_ref (srcpad);

}

}

 

} while (srcpads); } 14


An Example Application Code 

if (srcpadname) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS, "no link possible from %s:%s to %s",

GST_DEBUG_PAD_NAME (srcpad), GST_ELEMENT_NAME (dest));

if (destpad)

gst_object_unref (destpad);

destpad = NULL;

}

if (srcpad)

  

gst_object_unref (srcpad); srcpad = NULL; gst_element_get_compatible_pad function implementation

srcclass = GST_ELEMENT_GET_CLASS (src);

destclass = GST_ELEMENT_GET_CLASS (dest);

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,

srctempls = gst_element_class_get_pad_template_list (srcclass);

desttempls = gst_element_class_get_pad_template_list (destclass);

if (srctempls && desttempls) {

while (srctempls) {

srctempl = (GstPadTemplate *) srctempls->data;

if (srctempl->presence == GST_PAD_REQUEST) {

for (l = desttempls; l; l = l->next) {

desttempl = (GstPadTemplate *) l->data;

if (desttempl->presence == GST_PAD_REQUEST &&

 

desttempl->direction != srctempl->direction) { if (gst_caps_is_always_compatible (gst_pad_template_get_caps

15


An Example Application Code 

(srctempl), gst_pad_template_get_caps (desttempl))) {

srcpad =

gst_element_get_request_pad (src, srctempl->name_template);

destpad =

gst_element_get_request_pad (dest, desttempl->name_template);

if (srcpad && destpad

&& pad_link_maybe_ghosting (srcpad, destpad, flags)) {

GST_CAT_DEBUG (GST_CAT_ELEMENT_PADS,

"linked pad %s:%s to pad %s:%s",

GST_DEBUG_PAD_NAME (srcpad), GST_DEBUG_PAD_NAME (destpad));

gst_object_unref (srcpad);

gst_object_unref (destpad);

return TRUE;

}

it failed, so we release the request pads

if (srcpad)

gst_element_release_request_pad (src, srcpad);

if (destpad)

gst_element_release_request_pad (dest, destpad);

}

}

}

}

srctempls = srctempls->next;

}

}

return TRUE;

} 16


An Example Application Code 

start playing

gst_element_set_state (bin, GST_STATE_PLAYING);

Sets the state of the element. This function will try to set the

requested state by going through all the intermediary states and calling

the class's state change function for each.

 

This function can return #GST_STATE_CHANGE_ASYNC, in which case the

element will perform the remainder of the state change asynchronously in

another thread.

An application can use gst_element_get_state() to wait for the completion

of the state change or it can wait for a state change message on the bus.

GstStateChangeReturn

gst_element_set_state (GstElement * element, GstState state)

{

GstElementClass *oclass;

GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;

g_return_val_if_fail (GST_IS_ELEMENT (element), GST_STATE_CHANGE_FAILURE);

17


An Example Application Code 

oclass = GST_ELEMENT_GET_CLASS (element);

if (oclass->set_state)

result = (oclass->set_state) (element, state);

 

return result; }

Run event loop listening for bus messages until EOS or ERROR

event_loop (bin);

A Model software loop to explain the functionality of a loop

static void

event_loop (GstElement * pipe)

{

GstBus *bus;

GstMessage *message = NULL;

gboolean running = TRUE;

bus = gst_element_get_bus (GST_ELEMENT (pipe));

18


An Example Application Code 

while (running) {

message = gst_bus_poll (bus, GST_MESSAGE_ANY, -1);

g_assert (message != NULL);

switch (message->type) {

case GST_MESSAGE_EOS:

running = FALSE;

break;

case GST_MESSAGE_WARNING:{

GError *gerror;

gchar *debug;

gst_message_parse_warning (message, &gerror, &debug);

gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);

g_error_free (gerror);

g_free (debug);

break;

}

case GST_MESSAGE_ERROR:{

GError *gerror;

19


An Example Application Code 

gchar *debug;

gst_message_parse_error (message, &gerror, &debug);

gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);

g_error_free (gerror);

g_free (debug);

running = FALSE;

break;

}

default:

break;

}

gst_message_unref (message);

}

gst_object_unref (bus);

}

stop the bin

gst_element_set_state (bin, GST_STATE_NULL);

exit(0);

20


An Example Application Code 

GMainLoop *loop;

loop = g_main_loop_new (NULL, FALSE);

Create gstreamer elements

pipeline = gst_pipeline_new ("audio-player");

source = gst_element_factory_make ("filesrc",

demuxer = gst_element_factory_make ("oggdemux",

decoder = gst_element_factory_make ("vorbisdec",

conv

sink

if (!pipeline || !source || !demuxer || !decoder || !conv || !sink) {

"file-source"); "ogg-demuxer"); "vorbis-decoder");

= gst_element_factory_make ("audioconvert", "converter"); = gst_element_factory_make ("autoaudiosink", "audio-output");

g_printerr ("One element could not be created. Exiting.\n");

return -1;

}

Set up the pipeline

we set the input filename to the source element

g_object_set (G_OBJECT (source), "location", argv[1], NULL);

we add a message handler

bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));

GstBus *

gst_pipeline_get_bus (GstPipeline * pipeline)

21


An Example Application Code 

{

return gst_element_get_bus (GST_ELEMENT_CAST (pipeline));

}

GstBus *

gst_element_get_bus (GstElement * element)

{

GstBus *result = NULL;

g_return_val_if_fail (GST_IS_ELEMENT (element), result);

GST_OBJECT_LOCK (element);

if ((result = GST_ELEMENT_BUS (element)))

gst_object_ref (result);

GST_OBJECT_UNLOCK (element);

GST_CAT_DEBUG_OBJECT (GST_CAT_BUS, element, "got bus %" GST_PTR_FORMAT,

result);

return result;

}

gst_bus_add_watch (bus, bus_call, loop);

guint

gst_bus_add_watch (GstBus * bus, GstBusFunc func, gpointer user_data)

{

return gst_bus_add_watch_full (bus, G_PRIORITY_DEFAULT, func,

22


An Example Application Code 

user_data, NULL);

}

guint

gst_bus_add_watch_full (GstBus * bus, gint priority,

 

GstBusFunc func, gpointer user_data, GDestroyNotify notify) {

guint id;

g_return_val_if_fail (GST_IS_BUS (bus), 0);

GST_OBJECT_LOCK (bus);

id = gst_bus_add_watch_full_unlocked (bus, priority, func, user_data, notify);

GST_OBJECT_UNLOCK (bus);

 

return id; }

must be called with the bus OBJECT LOCK

static guint

gst_bus_add_watch_full_unlocked (GstBus * bus, gint priority,

 

GstBusFunc func, gpointer user_data, GDestroyNotify notify) {

guint id;

GSource *source;

if (bus->priv->watch_id) {

GST_ERROR_OBJECT (bus,

23


An Example Application Code 

"Tried to add new watch while one was already there");

return 0;

}

source = gst_bus_create_watch (bus);

if (priority != G_PRIORITY_DEFAULT)

g_source_set_priority (source, priority);

g_source_set_callback (source, (GSourceFunc) func, user_data, notify);

Attach the source (bus watch) to the main context and returns a bus watch id

id = g_source_attach (source, NULL);

g_source_unref (source);

GST_DEBUG_OBJECT (bus, "New source %p with id %u", source, id);

return id;

}

GSource for the bus

 

typedef struct

{

GSource source;

GstBus *bus;

gboolean inited;

} GstBusSource;

24


An Example Application Code 

GSource *

gst_bus_create_watch (GstBus * bus)

{

GstBusSource *source;

g_return_val_if_fail (GST_IS_BUS (bus), NULL);

source = (GstBusSource *) g_source_new (&gst_bus_source_funcs,

sizeof (GstBusSource));

source->bus = gst_object_ref (bus);

source->inited = FALSE;

return (GSource *) source;

}

we add all elements into the pipeline

file-source | ogg-demuxer | vorbis-decoder | converter | alsa-output

gst_bin_add_many (GST_BIN (pipeline),

source, demuxer, decoder, conv, sink, NULL);

we link the elements together

file-source -> ogg-demuxer ~> vorbis-decoder -> converter -> alsa-output

gst_element_link (source, demuxer);

gst_element_link_many (decoder, conv, sink, NULL);

note that the demuxer will be linked to the decoder dynamically.

The reason is that Ogg may contain various streams (for example

audio and video). The source pad(s) will be created at run time,

25


An Example Application Code 

by the demuxer when it detects the amount and nature of streams.

Therefore we connect a callback function which will be executed

when the "pad-added" is emitted.

g_signal_connect (demuxer, "pad-added", G_CALLBACK (on_pad_added), decoder);

Set the pipeline to "playing" state

gst_element_set_state (pipeline, GST_STATE_PLAYING);

Iterate

g_main_loop_run (loop);

Out of the main loop, clean up nicely

gst_element_set_state (pipeline, GST_STATE_NULL);

gst_object_unref (GST_OBJECT (pipeline));

return 0;

26


An Example Application Code

 

static void

on_pad_added (GstElement *element,

GstPad

gpointer

*pad, data)

{

GstPad *sinkpad;

GstElement *decoder = (GstElement *) data;

We can now link this pad with the vorbis-decoder sink pad

g_print ("Dynamic pad created, linking demuxer/decoder\n");

sinkpad = gst_element_get_static_pad (decoder, "sink");

gst_pad_link (pad, sinkpad);

gst_object_unref (sinkpad);

}

static gboolean

bus_call (GstBus

*bus,

GstMessage *msg,

gpointer

 

data)

{ GMainLoop *loop = (GMainLoop *) data;

27


An Example Application Code

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 *error;

gst_message_parse_error (msg, &error, &debug);

g_free (debug);

g_printerr ("Error: %s\n", error->message);

g_error_free (error);

g_main_loop_quit (loop);

break;

}

default:

break;

}

return TRUE;

}

 28


Thank You


GStreamer - Part 5