Gstreamer C/C++
A brief introduction to developing a gstreamer application in C/C++ to run on the F-11.
For more complicated streaming setups, we often resort to a more robust gstreamer solution. To do this, we use the gstreamer C library, where we have full control over the streaming pipeline. The current gstreamer version we support is 1.16.3, which is the version that is shipped with Nvidia JetPack 5.1.2 by default. Upgrading gstreamer is possible, though we will only support the version that Nvidia supports.
Building With CMake
The easiest way to build gstreamer applications on the F-11 is to use cmake, which we heavily rely on in our own development. To do this, you can add the following few lines in your CMakeLists.txt
file to find the required gstreamer libraries:
Then linking against the gstreamer libraries is simple:
Sample Pipeline
A gstreamer application is responsible for data manipulation, which may represent audio or video data, through the use of a pipeline. A good, though often inadequate, analogy of a gstreamer pipeline is a water pipe. A gstreamer pipeline should be free of leaks, and data flows from sources to sinks.
While this may be sufficient for some applications, we often run into situations where error handling must be handled gracefully so that the service is not halted. We can accomplish this in C with just a few steps. At a high level, we will do the following:
Initialize gstreamer
Create the pipeline elements and configure their settings
Link elements that can be statically linked
Set up handlers to dynamically link the rest
Play the pipeline
Listen to the message bus for any messages, warnings, or errors
Cleanup
Initialization
Every gstreamer application has to initialize the library, usually passing in command line arguments if they are present (or NULL
otherwise).
Creating the pipeline elements
As we will see shortly, there are many callbacks involved with gstreamer. In these callbacks, it is useful to have access to our pipeline elements and any other data we may need. We therefore often organize everything we need into some data struct. In this example, the data struct will only consist of the pipeline elements, as well as the pipeline itself. In general, it may include more information such as certain logical states or references to hidden elements.
Should an element creation fail, the factory will return NULL
. Each element should be checked to be non-NULL upon creation.
These properties directly reflect the properties specified in the second sample pipeline.
Static Linking
In general, gstreamer elements have pads that can be connected to each other. Just like real pipes, the end of one can be connected to the start of another. The source pad of an element, which can be thought of as its output, can be connected to the sink of another element, which can be considered its input. Elements may have zero or more source pads and zero or more sink pads. When these pads are always present, we can use static linking to connect them to each other. We can think of linking as gluing together two pipes at a specific point. Just like pipes can only be connected if their interface matches up, pipeline elements can only be linked if their source and sink pads can agree on the connection type.
To check the pad availability of an element, we can use gst-inspect-1.0
. For example, running gst-inspect-1.0 rtph264depay
shows us the following:
Doing the same for the rtspclientsink gives us:
which should return TRUE
on success (this is a gboolean
, not to be confused with the standard true
).
Dynamic Linking
When checking the pads of rtspsrc with gst-inspect-1.0
, we get the following:
This is different than the previous section. This element connects to an RTSP server and starts streaming from it, but it will not create any stream pads (we can think of these as the source pads for now) until data actually flows through this element. No data will flow through this element until the pipeline is actually playing, which will not happen until we finish setting up the pipeline and setting its state to playing. Therefore, this stream pad will not exist until later on in our execution. Situations like these require dynamic pad linking, which can be done by setting up a new callback to handle this event.
This line says that when our rtspsrc element finally adds a new stream pad, we will call our pad_added_handler. This handler will be responsible for linking this pad to the pipeline, and can be done as follows:
Playing the Pipeline
Now that we have a pipeline that is built, linked, and ready for dynamic linking, we can actually play the pipeline. This will kickstart all our processes and should start pulling the stream from the endpoint.
Message Bus
Cleaning Up
Lastly, we have to clean up the resources we used. In our case, we have the bus and the pipeline to clean up. Before cleaning up a pipeline element, we have to set its state to GST_STATE_NULL
, as failing to do so will not allow us to clean up our resources.
Last updated
Was this helpful?