This article shows how to use GStreamer to read and process multimedia content. It starts by explaining how to perform GStreamer operations from the command line, and then presents the central data structures of the GStreamer API. The article ends by presenting two example applications that demonstrate how GStreamer can be used.
As multimedia devices become more popular, it becomes more necessary to build applications that can read and process their content. There are many programming libraries available, but GStreamer is one of the few open-source toolsets that can process all kinds of audio and video data. It's freely available, runs on multiple operating systems, and provides impressive performance and extensive documentation.
As I see it, there are two only drawbacks of using GStreamer. First, its data structures (pads, caps, buses, elements) are unlike anything I've encountered before. Second, it's written in C, so you have to deal with lengthy function names like gst_bus_timed_pop_filtered
.
The goal of this article is to present GStreamer's usage and capabilities. It starts by explaining how to install the package and then shows how to perform operations from the command line. The last part presents the fundamental data structures of GStreamer and demonstrates how they can be used.
1. Installation
The main site for GStreamer is gstreamer.freedesktop.org. The installation process depends on your operating system, and you can find instructions by by visiting the GStreamer site and performing four steps:
- Click the Documentation button on the left.
- Click the Get Started button in the center.
- Open the Installing GStreamer option in the upper left.
- Click the link corresponding to your operating system.
Once you've installed GStreamer, you'll have several new libraries, header files, and executables. A large part of this article is concerned with the libraries and header files, but for newcomers, I recommend starting with the executables.
2. GStreamer from the Command Line
If you've never worked with GStreamer, I recommend using its command-line tools before writing code. They're easy to use, and once you're familiar with them, you'll have a much better idea of what GStreamer is all about.
On my Linux system, GStreamer installs its executables in /usr/bin. On my Windows system, they're in C:\gstreamer\1.0\msvc_x86_64\bin. Before proceeding further, it's a good idea to make sure you can access these utilities (particularly gst-launch-1.0
) from a command prompt, which may require updating your PATH environment variable.
To get started, open a command prompt and execute the following command:
gst-launch-1.0 audiotestsrc freq=200 ! audioconvert ! lamemp3enc ! filesink location=audio.mp3
This can take a long time, so press Ctrl-c after a few seconds. When the command is finished, you'll find a file named audio.mp3 in the current directory. If you play it, you'll hear a low-pitched tone corresponding to a 200 Hz sine wave.
This isn't exciting, but once you see how the command is structured, you'll be well on your way to understanding GStreamer. The text following gst-launch-1.0
is called a pipeline description because it describes how media (audio data in this case) should be processed. When you execute gst-launch-1.0
with a pipeline description, it creates a pipeline and executes it.
In essence, the goal of a GStreamer application is to create and execute pipelines. When it comes to pipeline descriptions, there are four points to be aware of:
- A pipeline description consists of elements that identify how media should be generated, processed, and consumed.
- Elements are separated by exclamation points (!), which represent links between elements.
- An element's properties can be set by following its name with
name=value
pairs, where name
is a property's name and value
is the desired value. - In nearly all cases, elements are identified with names of GStreamer plugins.
With this in mind, let's look at the preceding command. The pipeline description contains four elements named audiotestsrc
, audioconvert
, lamemp3enc
, and filesink
. The audiotestsrc
element has a property named freq
and the filesink
element has a property named location
.
A GStreamer plugin is a library that performs an operation in a pipeline. Each of the four elements identifies a plugin, and when gst-launch-1.0
executes, it calls on each plugin to perform its operation.
Most plugins process streaming data in some way, but some read data from a source or generate new data. These are source plugins, and in the example command, audiotestsrc
is a source plugin that generates audio data. Similarly, a sink plugin consumes or stores streaming data. In this preceding example, the filesink plugin stores the audio data to a file named audio.mp3.
The filesink
plugin is one of the many plugins that come packaged with GStreamer. These are the core plugins, and Table 1 lists filesink
and several other core plugins.
Table 1: Core Plugins (Abridged) Plugin Name | Classification | Description |
filesrc | Source/File | Read data from a file |
filesink | Sink/File | Write data to a file |
dataurisrc | Source | Provides data from a URI |
fdsrc | Source/File | Read data from a file descriptor |
fdsink | Sink/File | Write data to a file descriptor |
fakesrc | Source | False source for data |
fakesink | Sink | False sink for data |
funnel | Generic | N-to-1 stream connection |
identity | Generic | Pass data without modification |
input-selector | Generic | N-to-1 input stream selector |
output-selector | Generic | N-to-1 output stream selector |
queue | Generic | Simple data queue |
queue2 | Generic | Simple data queue |
tee | Generic | 1-to-N stream tee |
typefind | Generic | Prints the stream's media type |
In addition to the core plugins, you can install four open-source collections of GStreamer plugins:
- gst-plugins-base - reliable, high-quality, well-documented and maintained
- gst-plugins-good - good quality and well-maintained
- gst-plugins-bad - deficiencies exist with quality and/or maintenance
- gst-plugins-ugly - may have concerns with distribution due to licensing
The gst-plugins-base package provides a vast number of plugins in several categories, including audioconvert, encoding, and playback. The plugins in the playback category are particularly helpful, and Table 2 lists many of them.
Table 2: Playback Plugins (Abridged) Plugin Name | Classification | Description |
decodebin | Generic/Bin/Decoder | Decode data to raw media |
decodebin3 | Generic/Bin/Decoder | Decode data to raw media |
playbin | Generic/Bin/Player | Play media from a URI |
playbin3 | Generic/Bin/Player | Play media from a URI |
playsink | Generic/Bin/Sink | Convenience sink for multiple streams |
subtitleoverlay | Video/Overlay | Overlays subtitles on video |
uridecodebin | Generic/Bin/Decoder | Decode URI to raw media |
uridecodebin3 | Generic/Bin/Decoder | Decode URI to raw media |
urisourcebin | Generic/Bin/Source | Download and buffer data from a URI |
Of these, playbin
is popular because of its ability to play streaming media from a URI. To demonstrate, the following command plays a WebM video file from a free GStreamer site:
gst-launch-1.0 playbin uri=https:
When you run this command, keep in mind that it may take time for the pipeline to load, buffer, and play the video. Also, pay attention to the different states that the pipeline goes through, such as PAUSED
and PLAYING
.
At this point, you should understand that GStreamer's purpose is to execute pipelines composed of elements. The gst-launch-1.0
utility is great for simple operations, but it's not suitable for sophisticated media processing. To create pipelines programmatically, you'll need to grapple with the GStreamer API and its data structures.
3. The GStreamer API
GStreamer is written in C, which is not an object-oriented language. Despite this, the official documentation refers to GStreamer's data structures as classes. The documentation also describes an inheritance hierarchy beginning with GObject
. For example, the documentation states that GstElement
is a subclass of GstObject
, which is a subclass of GInitiallyOwned
, which is a subclass of GObject
.
In GStreamer, inheritance is based on aggregation. If Structure X is a subclass of Structure Y, then the first field of Structure X is an instance of Structure Y. For example, the first field of GstElement
is an instance of GstObject
and the first field of GstObject
is an instance of GInitiallyOwned
.
If you're familiar with traditional object-oriented programming, this will seem bizarre and unnatural. But if you want to understand GStreamer's API, it's crucial to accept this. Figure 1 presents the inheritance hierarchy of GStreamer's most important classes.
Figure 1: Important Classes in the Inheritance Hierarchy
In this illustration, the two structures on top start with G
and the structures below it start with Gst
. This is because GObject
and GInitiallyUnowned
are provided by GLib and the other structures are provided by GStreamer. Similarly, functions that start with g_
perform GLib operations and functions that start with gst_
perform GStreamer operations.
This section looks at the shaded structures in this diagram: GObject
, GstObject
, GstElement
, GstBin
, GstPipeline
, GstBus
, and GstPad
. Once you understand what these structures accomplish, you'll have no trouble using them to create and execute pipelines.
3.1 GObject
The GObject
structure is the base structure in the GLib/GStreamer hierarchy. For this article, you only need to know two things about them:
- A
GObject
stores name-value pairs called properties. - A
GObject
can emit signals that can be received by handlers.
Regarding properties, GLib provides two functions that read and modify the properties of a GObject
:
g_object_get(GObject* obj, const gchar* name, void* val, NULL)
- Copies the property of obj
named name
into the memory referenced by val
g_object_set(GObject* obj, const gchar* name, any val, NULL)
- sets one or more properties of the object
In these signatures, each function only accepts one name/value pair. Additional pairs can be appended, but the last argument must be set to the NULL
terminator. To demonstrate, the following code sets the name
and color
properties of the GObject*
named gobj
:
g_object_set(gobj, "name", "RedObject", "color", "red", NULL);
GStreamer applications generally access information about a structure by calling the following function:
g_signal_emit_by_name(GObject* obj, const gchar* signal, gint index, void* data)
In addition to storing regular properties, many GStreamer structures store metadata called tags in structures called GstTagList
s. When an application calls g_signal_emit_by_name
with the name of a structure's tag list, the last argument will point to the returned GstTagList
.
3.2 GstObject
The GstObject
structure is the base structure of the GStreamer hierarchy. Applications usually don't access GstObject
s directly, but there are four functions worth knowing:
gst_init(int argc, char** argv)
- initializes the GStreamer environment gst_object_unref(GstObject* obj)
- deallocates a GstObject
gst_object_set_name(GstObject* obj, const gchar* name)
- assigns a name to the object gst_object_get_name(GstObject* obj)
- returns the object's name
Applications need to call gst_init
before any other GStreamer function. This can accept the command-line arguments (argc
and argv
) passed into the application.
Many applications will declare a GstObject
pointer variable and initialize the variable by calling a function. To free memory, the application should call gst_object_unref
for each initialized variable.
3.3 GstElement
Each stage in a media-processing pipeline is represented by a GstElement
. This section discusses three aspects of this important data structure:
- Fields of the
GstElement
- Functions that create
GstElement
s - Functions that access
GstElement
properties
As you read this section, you don't need to remember every field and function. But you should learn enough to be comfortable with how GstElement
s are used.
3.3.1 GstElement Fields
To see what GstElement
accomplishes, it's a good idea to become familiar with its fields. Table 3 lists many of these fields along with their data types.
Table 3: GstElement Fields Field | Data Type | Description |
object | GstObject | The element's "superclass" |
contexts | GList* | The element's processing task |
current_state | GstState | The element's current state |
next_state | GstState | The element's following state |
target_state | GstState | The element's goal state |
srcpads | GList* | The element's source pads |
numsrcpads | guint16 | Number of source pads |
sinkpads | GList* | The element's sink pads |
numsinkpads | guint16 | Number of sink pads |
bus | GstBus* | The connected bus |
clock | GstClock* | The element's clock |
start_time | GstClockTime | Time since the last PAUSE state |
base_time | GstClockTimeDiff | Time just before the PLAY state |
The first field is a GstObject
, which is the superclass of GstElement
. The next field, contexts
, stores the operation(s) to be performed by the element. The third field, current_state
, identifies the element's processing state, which can take one of five values:
GST_STATE_NULL
- the element's initial state GST_STATE_READY
- the element is ready to enter the paused state GST_STATE_PAUSE
- the element is ready to accept and process data GST_STATE_PLAYING
- the element is playing data GST_STATE_VOID_PENDING
- the element has no pending state
Elements always enter the PAUSE
state before the PLAYING
state. This makes it straightforward to measure the playing time.
An application can access information about an element through its GstBus
. This is particularly useful for responding to errors, and I'll discuss GstBus
structures shortly.
3.3.2 Creating Elements
GStreamer's element factories make it easy to create different types of elements. The gst_element_factory_find
function accepts a name and returns the corresponding element factory. For example, the following code accesses the GstElementFactory
named videotestsrc
:
factory = gst_element_factory_find("videotestsrc");
An application can create a new GstElement
from an element factory by calling gst_element_factory_make
, which accepts the factory's ID and a name to be assigned to the GstElement
. To demonstrate, the following code creates an element named elem
from the factory named videotestsrc
. Because its name is set to NULL
, GStreamer will assign a unique name to it.
elem = gst_element_factory_make("videotestsrc", NULL);
In these functions, the argument is commonly the name of a plugin, which means the new element is an instance of a GStreamer plugin. This will be made clear in the example code toward the end of the article.
3.3.3 Accessing Fields
GStreamer applications usually don't access the fields of a GstElement
directly. Instead, they call functions that read and modify these fields. Table 4 lists many of the available functions and provides a description of each.
Table 4: GstElement Field Functions Function | Description |
gst_element_get_state(GstElement*,
GstState*, GstState*, GstClockTime) | Reads the element's current/pending states |
gst_element_set_state(GstElement*,
GstState) | Sets the element's current state |
gst_element_get_static_pad(GstElement*,
const gchar*) | Returns the pad with the given name |
gst_element_iterate_pads(GstElement*) | Returns an iterator for the element's pads |
gst_element_add_pad(GstElement*,
GstPad*) | Adds the given pad to the element |
gst_element_remove_pad(GstElement*,
GstPad*) | Removes the given pad from the element |
gst_element_get_bus(GstElement*) | Returns the element's bus |
gst_element_get_clock(GstElement*) | Returns the element's clock |
gst_element_set_clock(GstElement*,
GstClock*) | Sets the element's clock |
gst_element_get_start_time(GstElement*) | Returns the time since the last pause state |
gst_element_get_current_clock_time(
GstElement*, GstClockTime) | Returns the current clock time |
Most of these functions are easy to understand. Keep in mind that an element can have any number of pads, but always starts with none. It always has one bus for transferring data, but the bus may not be used.
3.4 GstPad and Capabilities
In a pipeline description, an exclamation point is used to connect one element to another. This is fine for simple topologies, but GStreamer makes it possible to create multiple connections between elements, and at a low level, these connections are established using pads. An element can have zero or more pads that provide data (source pads) and zero or more pads that receive data (sink pads).
Each pad has a set of capabilities (caps) that identify the nature of the data that it can transfer. One pad might have the capability to transfer video streams of a specific format while another has the capability to transfer a specific format of audio data.
In code, pads are represented by GstPad
instances and a pad's set of capabilities is contained in a GstCaps
instance. Table 5 lists many functions related to pads and their properties.
Table 5: GstPad Functions Function | Description |
gst_pad_new(const gchar*, GstPadDirection) | Creates a new pad |
gst_pad_new_from_template(GstPadTemplate*,
const gchar*) | Creates a new pad from a template |
gst_pad_get_name(GstPad*) | Returns the pad's name |
gst_pad_get_direction(GstPad*) | Returns the pad's direction |
gst_pad_get_parent(GstPad*) | Returns the element containing the pad |
gst_pad_set_active(GstPad*, gboolean) | Sets the pad as active or inactive |
gst_pad_get_current_caps(GstPad*) | Returns the pad's capabilities |
gst_pad_link(GstPad*, GstPad*) | Creates a link between two pads |
gst_pad_unlink(GstPad*, GstPad*) | Removes the link between two pads |
gst_pad_is_linked(GstPad*) | Identifies if the pad is linked or not |
The first function, gst_pad_new
, creates a new GstPad
with a given name and direction. The second argument is a GstPadDirection
, which can take one of three values:
GST_PAD_UNKNOWN
- the pad's direction is unknown GST_PAD_SRC
- the pad sends data GST_PAD_SINK
- the pad receives data
Before a pad can transfer data, it needs to be made active. This is accomplished by calling the gst_pad_set_active
function. Most applications activate an element's pads by setting the element's state to RUNNING
.
The gst_pad_get_current_caps
function returns a GstCaps
instance containing the pad's capabilities. If pads in different elements have one or more capabilities in common, an application can create a link between them by calling gst_pad_link
.
Another way to create a link between two elements is to call gst_element_link
with pointers to the elements to be linked. When this is called, GStreamer will look for unlinked pads with similar capabilities and create a link between them. Another function for linking elements is given as follows:
gst_element_link_filtered(GstElement* src, GstElement* dest, GstCaps* filter)
This creates a link between two elements if they have unlinked pads with similar capabilities given in the filter
argument. This returns true
if the link was established and false
otherwise.
An application can create links between multiple elements by calling gst_element_link_many
. This accepts a series of elements followed by the NULL
terminator. As an example, the following code establishes a connection from elemA
to elemB
and from elemB
to elemC
.
gst_element_link_many(elemA, elemB, elemC, NULL);
In addition to pad functions, GStreamer also provides functions related to pad capabilities. Their names start with gst_caps_
and Table 6 lists eight of them.
Table 6: GstCaps Functions Function | Description |
gst_caps_new_empty() | Create a new empty GstCaps |
gst_caps_new_empty_simple(const char*) | Create a new GstCaps with the given media type |
gst_caps_new_simple(const char*,
const char*, ...) | Create a new GstCaps with a given GstStructure |
gst_caps_get_size(const GstCaps*) | Returns the number of structures in the GstCaps |
gst_caps_get_structure(const GstCaps*,
guint index) | Returns the GstStructure at the given index |
gst_caps_remove_structure(GstCaps*,
guint index) | Removes the GstStructure at the given index |
gst_caps_append(GstCaps*, GstCaps*) | Appends one GstCaps to another |
gst_caps_unref(GstCaps*) | Frees the GstCaps memory |
Each element of a GstCaps
is a GstStructure
, which is a general container of name/value pairs. When an application creates a new GstCaps
with a function like gst_caps_new_simple
, it needs to provide the name/value pairs in the GstStructure
. As an example, the following code creates a GstCaps
with a capability for processing video:
GstCaps *caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "I420",
"framerate", GST_TYPE_FRACTION, 25, 1,
"pixel-aspect-ratio", GST_TYPE_FRACTION, 1, 1,
"width", G_TYPE_INT, 320,
"height", G_TYPE_INT, 240,
NULL);
As a result of this code, the GstCaps
contains a GStructure
representing the capability of displaying raw video with a pixel aspect ratio of 1:1, a width of 320, and a height of 240.
In addition to defining structures, applications can also access structures with gst_caps_get_structure
and remove structures with gst_caps_remove_structure
. When an application is done processing a GstCaps
, it should call gst_caps_unref
to free its memory.
3.5 GstBus and Messages
Every GstElement
has a GstBus
that enables the application to extract information from the element. It's important to understand the difference between pads and buses—a pad transfers multimedia data between elements and a bus transfers status messages from an element to the application.
A GstBus
stores its messages in a queue and each is message is an instance of the GstMessage
structure. Table 7 lists functions related to the GstBus
structure and its message queue.
Table 7: GstBus Functions Function | Description |
gst_bus_post(GstBus*, GstMessage*) | Places a message on the bus's queue |
gst_bus_peek(GstBus*) | Retrieve the first message without changing the queue |
gst_bus_pop(GstBus*) | Retrieve the first message, remove from queue |
gst_bus_timed_pop(GstBus*,
GstClockTime) | Retrieve/remove the first message with timeout |
gst_bus_pop_filtered(GstBus*,
GstMessageType) | Retrieve and remove the first message based on type |
gst_bus_timed_pop_filtered(GstBus*,
GstClockTime, GstMessageType) | Retrieve/remove the first message based on type with timeout |
gst_bus_post
places a message on the queue, but this is rarely used. Instead, applications wait for error messages by calling one of the pop functions. gst_bus_pop
returns immediately, returning the first message if the queue isn't empty and NULL
if the queue is empty. In contrast, gst_bus_timed_pop
returns after the amount of time given by the second argument.
gst_bus_pop_filtered
will only return a message if it belongs to the type or types identified by the second argument. This can be set to one of the values of the GstMessageType
enumerated type or an OR'ed combination thereof. Table 8 lists the first ten values of this type.
Table 8: Message Types (Abridged) Message Type | Value | Description |
GST_MESSAGE_UNKNOWN | 0 | Undefined message |
GST_MESSAGE_EOS | 1 | The pipeline has reached the end of the stream |
GST_MESSAGE_ERROR | 2 | An error message |
GST_MESSAGE_WARNING | 4 | A warning message |
GST_MESSAGE_INFO | 8 | An information message |
GST_MESSAGE_TAG | 16 | A tag message |
GST_MESSAGE_BUFFERING | 32 | The pipeline is buffering |
GST_MESSAGE_STATE_CHANGED | 64 | The state has changed |
GST_MESSAGE_STATE_DIRTY | 128 | An element changed state |
GST_MESSAGE_STEP_DONE | 256 | A stepping operation finished |
It's common for applications to wait for an error condition (GST_MESSAGE_ERROR
) or the end of the stream (GST_MESSAGE_EOS
). This can be accomplished by calling the gst_bus_timed_pop_filtered
function in the following way:
GstMessage* msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
The second argument, GST_CLOCK_TIME_NONE
, represents an indefinite amount of time. Because of this argument, the function waits indefinitely for an error message or an end-of-stream message. This combination of the two types is given as GST_MESSAGE_ERROR | GST_MESSAGE_EOS
.
3.6 GstBin and GstPipeline
As illustrated in Figure 1, GstBin
is a sub-structure of GstElement
and GstPipeline
is a sub-structure of GstBin
. A GstBin
is an element that can contain other elements and a GstPipeline
represents an entire pipeline. The functions for both structures are fairly simple.
An application can create an empty bin by calling gst_bin_new
with a name for the new structure. Then it can add an element by calling gst_bin_add
or add multiple elements by calling gst_bin_add_many
. An application can remove an element from a bin by calling gst_bin_remove
. An element in a bin can be retrieved by name by calling gst_bin_get_by_name
.
An application can create an empty pipeline structure by calling gst_pipeline_new
with a name for the pipeline. But it's more common to call gst_parse_launch
, which accepts a pipeline description and a pointer to memory to store errors (GError**
). It returns a GstPipeline
with the characteristics given in the description.
For example, the following code creates a pipeline by using the filesrc
plugin to access a file named image.svg:
pipeline = gst_parse_launch("filesrc location=image.svg", NULL);
Once an application creates a GstPipeline
, it can access the pipeline's fields by calling one of the functions in Table 9.
Table 9: GstPipeline Functions Function | Description |
gst_pipeline_get_bus(GstPipeline*) | Returns the bus of the pipeline |
gst_pipeline_get_clock(GstPipeline*) | Returns the pipeline's clock |
gst_pipeline_set_clock(GstPipeline*, GstClock*) | Set the clock associated with the pipeline |
gst_pipeline_get_delay(GstPipeline*) | Retrieve the pipeline's delay |
gst_pipeline_set_delay(GstPipeline*, GstClockTime) | Set the delay of the pipeline |
gst_pipeline_get_latency(GstPipeline*) | Retrieve the pipeline's latency |
gst_pipeline_set_latency(GstPipeline*,
GstClockTime) | Set the latency for pipeline processing |
To add elements to a GstPipeline
, an application can convert it to a GstBin
using the GST_BIN
macro. Then it call gst_bin_add
or gst_bin_add_many
. To demonstrate, the following code creates a GstBin
from pipeline
and adds three elements: elemA
, elemB
, and elemC
:
gst_bin_add_many(GST_BIN(pipeline), elemA, elemB, elemC, NULL);
As with many GStreamer functions, the last parameter of gst_bin_add_many
is set to NULL
. This terminates the list of elements added to the pipeline.
4. Writing Applications
Now that you're familiar with GStreamer's main data structures of GStreamer, it's time to look at code. This article provides two example source files:
- simple_playback.c - Creates a pipeline that plays video from the GStreamer site
- audio_file.c - Creates a new MP3 file by connecting elements
To compile these files, you need to have GStreamer installed. If you have GCC available, you can compile the first source file with the following command:
gcc simple_playback.c -o simple_playback `pkg-config --cflags --libs gstreamer-1.0`
In this command, pkg-config
is a helper tool that produces the appropriate flags needed to compile with GStreamer. This type of command can be used with all of three of the example source files.
4.1 The Simple Playback Example
The code in the first source file, simple_playback.c, creates and executes a pipeline that displays a video (sintel_trailer-480p.webm) from the GStreamer site. Its code is given as follows:
int main(int argc, char *argv[]) {
GstElement *pipeline;
GstBus *bus;
GstMessage *msg;
gst_init(&argc, &argv);
pipeline =
gst_parse_launch("playbin uri=https://gstreamer.freedesktop.org/data/media/sintel_trailer-480p.webm", NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
bus = gst_element_get_bus(pipeline);
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
if (msg != NULL) {
GError *err;
gchar *dbg;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg, &err, &dbg);
g_printerr("Error from element %s: %s\n",
GST_OBJECT_NAME(msg->src), err->message);
g_printerr("Debug: %s\n", dbg ? dbg : "none");
g_clear_error(&err);
g_free(dbg);
break;
case GST_MESSAGE_EOS:
g_print("End-Of-Stream\n");
break;
default:
g_printerr("Unexpected message\n");
break;
}
gst_message_unref(msg);
}
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
After initializing GStreamer's operation with gst_init
, this code creates a pipeline by calling gst_parse_launch
with a pipeline description. Then it plays the pipeline's media by calling gst_element_set_state
with GST_STATE_PLAYING
.
Most of the code configures the pipeline to provide messages if any errors occur. This requires three steps:
- Access the pipeline's bus with
gst_element_get_bus
. - Configure the bus to provide messages if an error condition or the end-of-stream (EOS) conditions occur.
- Print appropriate text if either condition occurs.
After the error handling is set, the application deallocates the pipeline's bus. Then it sets the pipeline's state to GST_STATE_NULL
and deallocates the pipeline with gst_object_unref
.
4.2 The Audio File Example
Toward the start of the article, I presented a basic pipeline description that creates an MP3 file containing a 200 Hz tone. The text for the pipeline was given as follows:
audiotestsrc freq=200 ! audioconvert ! lamemp3enc ! filesink location=audio.mp3
The audio_file.c example accomplishes the same result by creating and connecting elements. The code in this file is given as follows:
int main(int argc, char *argv[]) {
GstElement *pipeline, *src, *convert, *encode, *sink;
GstBus *bus;
GstMessage *msg;
gst_init(&argc, &argv);
src = gst_element_factory_make("audiotestsrc", NULL);
convert = gst_element_factory_make("audioconvert", NULL);
encode = gst_element_factory_make("lamemp3enc", NULL);
sink = gst_element_factory_make("filesink", NULL);
pipeline = gst_pipeline_new("pipeline");
gst_bin_add_many(GST_BIN(pipeline), src, convert, encode, sink, NULL);
gst_element_link_many(src, convert, encode, sink, NULL);
g_object_set(G_OBJECT(src), "freq", 200.0f, NULL);
g_object_set(G_OBJECT(sink), "location", "audio.mp3", NULL);
gst_element_set_state(pipeline, GST_STATE_PLAYING);
bus = gst_element_get_bus(pipeline);
msg = gst_bus_timed_pop_filtered(bus, GST_CLOCK_TIME_NONE,
GST_MESSAGE_ERROR | GST_MESSAGE_EOS);
if (msg != NULL) {
GError *err;
gchar *dbg;
switch (GST_MESSAGE_TYPE(msg)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error(msg, &err, &dbg);
g_printerr("Error from element %s: %s\n",
GST_OBJECT_NAME(msg->src), err->message);
g_printerr("Debug: %s\n", dbg ? dbg : "none");
g_clear_error(&err);
g_free(dbg);
break;
case GST_MESSAGE_EOS:
g_print("End-Of-Stream\n");
break;
default:
g_printerr("Unexpected message\n");
break;
}
gst_message_unref(msg);
}
gst_object_unref(bus);
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(pipeline);
return 0;
}
After initializing GStreamer, the code calls gst_element_factory_make
to create a GstElement
for each element in the pipeline. Then it creates an empty pipeline with gst_pipeline_new
and adds the elements to the pipeline with gst_bin_add_many
. After the elements are added, the code creates connections between them by calling gst_element_link_many
.
The code calls g_object_set
twice to set element properties. The first call sets the frequency (freq
) of the source element (src
) to 200 Hz. The second call sets the file name (location
) of the sink element (sink
) to audio.mp3
.
After the pipeline has been populated with connected elements, the source code executes the pipeline by calling gst_element_set_state
with GST_STATE_PLAYING
. Then it configures error handling using the same code discussed earlier.
When you run the executable, it will create the audio.mp3 file and continue writing data to it. Press Ctrl-c to halt the process.
History
This article was initially submitted on September 1, 2024.