Overview
A GStreamer application is built around a pipeline — a runtime container that organizes elements into a coherent data path and manages their execution as a single unit. Elements are linked in data-flow order to form a complete processing chain, and execution is governed by a state model that propagates lifecycle transitions across all elements simultaneously.
Application Lifecycle
A minimal GStreamer application follows a well-defined sequence of stages:Concepts
The following steps and concepts are required to build a complete GStreamer application:- GStreamer Initialization — Preparing the library for use before any pipeline operations are performed.
- Pipeline and Element Instantiation — Creating the pipeline container, instantiating individual elements, adding them to the pipeline, and linking them in the intended data-flow order.
- Pipeline Configuration — Setting element properties programmatically or through pipeline strings to control runtime behavior.
- Pipeline Execution States — Understanding the GStreamer state machine (
NULL,READY,PAUSED,PLAYING), how state transitions are applied, and how they propagate to all contained elements. - Caps Negotiation — How GStreamer automatically negotiates compatible data formats between linked elements, and how caps filters are used to constrain or enforce specific formats.
- Main Loop — Keeping the application alive during pipeline execution and serving as the event dispatcher for signals, callbacks, and bus messages.
- Interaction with Pipeline during Runtime via Bus — The asynchronous communication channel through which the pipeline delivers runtime notifications — including errors, state changes, and end-of-stream conditions — to the application.
- Dynamic Pads — Handling elements such as demuxers that expose output pads only at runtime, requiring deferred linking via the
pad-addedsignal. - Tee and Queue — Splitting a stream into multiple parallel branches using
tee, and decoupling branch execution usingqueueelements to prevent blocking and enable independent threading. - Error Handling — Responding to pipeline errors delivered through the bus and performing a controlled shutdown.
- Application Shutdown and Teardown — Handling external interrupt signals cleanly using
g_unix_signal_add(), with support for both immediate and graceful EOS-based shutdown strategies, followed by safely transitioning the pipeline toNULLand releasing all allocated resources. - Application Interaction via appsink — Accessing pipeline data directly from application code using the
appsinkelement for custom processing, integration with external systems, or frame export.
1. GStreamer Initialization
Simple Initialization
Includegst/gst.h to access GStreamer library functions, and call gst_init(&argc, &argv) at the start of the application to initialize the library and parse GStreamer-specific command-line options.
The GOption Interface
GOption-based initialization can be used if the application needs to parse custom-defined input parameters.A
GOptionTable can be used to define application-specific command-line options and passed to the GLib initialization function along with the option group returned from gst_init_get_option_group(). This ensures that application options are parsed alongside the standard GStreamer options.2. Pipeline and Element Instantiation
Constructing a pipeline follows three sequential steps:- 2.1 Creating elements as independent
GstElementobjects - 2.2 Adding them to the pipeline container
- 2.3 Linking them in the intended data-flow order
GstBin, elements are added using gst_bin_add() or gst_bin_add_many(), which transfers ownership to the pipeline and enables lifecycle and state management across all contained elements.
2.1 Creating Elements
Elements areGstElement objects that form the functional building blocks of a GStreamer pipeline, each responsible for a specific role in the data flow:
- Source — producing data
- Transform — processing data
- Sink — consuming data
gst_element_factory_make("factory-name", "instance-name").
2.2 Adding Elements to the Pipeline
appctx->pipelineis aGstPipeline(a subclass ofGstBin)gst_bin_add_manytransfers ownership of the elements to the pipeline- After this call, the pipeline manages their lifecycle and propagates state changes
2.3 Linking Elements
v4l2src— produces video data (from a camera)qtivtransform— processes or converts the datafilesink— consumes and writes data to a file
Constructing the Pipeline from a String
The entire process of creating, adding, and linking elements can also be done implicitly using a pipeline string:3. Pipeline and Element Configuration
Once elements are created and placed in the pipeline, they must be configured to define their runtime behavior.Programmatic Configuration
Configuring the Source
Configuring the Sink
Configuration via Pipeline String
When usinggst_parse_launch(), element configuration is embedded directly in the pipeline string using key=value syntax:
Comparison: Programmatic vs. String Configuration
In practice, many applications combine both approaches — using a pipeline string to define the overall structure while retrieving specific elements by name for further programmatic configuration.
4. Pipeline Execution States
Once the pipeline is constructed and configured, its execution is governed by a well-defined state model.4.1 The State Model
GStreamer defines a small set of states that represent different stages in the lifecycle of a pipeline:
4.2 State Transitions
Pipeline execution is controlled through state transitions:Transitioning from
NULL to PLAYING implicitly passes through READY and PAUSED. The pipeline manages state propagation to all child elements automatically.5. Caps Negotiation
Beyond configuring element properties, building a functional pipeline requires that linked elements agree on the format of the data they exchange. GStreamer handles this automatically through caps negotiation.Role of Caps
Caps (short for capabilities) describe the structure of the data flowing between elements. They typically include:- Media type (e.g.,
video,audio) - Encoding format
- Resolution or sample rate
- Pixel format or layout
Negotiation Process
When the pipeline transitions toPAUSED or PLAYING, GStreamer initiates the negotiation process:
- Upstream elements propose their supported output formats.
- Downstream elements select formats they can accept.
- A final format agreement is established for each pad link.
Influencing Negotiation with Caps Filters
Caps filters are used in the following scenarios:Setting Caps Programmatically
Setting Caps via Pipeline String
6. Main Loop
Once the pipeline is transitioned toPLAYING, the application must remain active for the duration of execution using g_main_loop_run():
- Thread synchronization — blocks the main thread, keeping the application alive.
- Event dispatching — processes and routes events including signals, callbacks, and pipeline notifications.
Exiting the Main Loop
7. Interaction During Runtime
While the pipeline is running, the application interacts through:- State change requests
- Bus messages
- Callbacks
Bus
The GStreamer bus provides an asynchronous communication channel from the pipeline to the application.Accessing the Bus
Types of Messages
Integration with the Main Loop
When a signal watch is registered, incoming bus messages are dispatched as callbacks through the main loop, allowing the application to react to pipeline events as part of the same event-driven model.8. Dynamic Pads
Some elements do not expose all their pads at creation time — their pads appear dynamically during runtime. The most common example is a demuxer (e.g.,qtdemux).
Static vs. Dynamic Pads
Linking Strategy
- Create and add all relevant elements to the pipeline.
- Link all statically available elements.
- Register a callback for the
pad-addedsignal on the dynamic element. - Perform the remaining links inside the callback when the pad becomes available.
Behavior in Pipeline Strings
Higher-level elements likedecodebin handle dynamic pads internally:
When working with lower-level or specialized elements such as explicit demuxers, manual pad handling is required.
Care must be taken to avoid linking the same pad more than once, particularly in callbacks that may be invoked multiple times.
9. Tee and Queue — Branching the Pipeline
Many real-world applications require the same data to be processed in multiple ways simultaneously. GStreamer supports this throughtee and queue.
Tee — Splitting the Stream
Thetee element duplicates an incoming stream and forwards it to multiple output branches:
Queue — Decoupling Branch Execution
Aqueue element must be inserted at the start of each branch:
queue element introduces two key behaviors:
- Buffering — holds incoming buffers in internal storage, decoupling production and consumption rates.
- Thread boundary — data is pushed and consumed on separate threads, allowing each branch to execute independently.
Queue Usage Beyond Branching
Thequeue element also benefits linear pipelines:
10. Error Handling
Errors are delivered via the GStreamer bus asGST_MESSAGE_ERROR messages. Typical causes include:
Handling Error Messages
Recommended Error Response Sequence
1
Log the Error
Record both the error message and debug information for troubleshooting.
2
Stop the Main Loop
Terminate the event loop to halt further message processing.
3
Set Pipeline to GST_STATE_NULL
Stops all elements, terminates internal threads, and releases all allocated resources.
4
Perform Application Cleanup
Free application-level resources, destroy pipeline objects, and exit gracefully.
Errors are asynchronous and can arrive at any time. They are typically fatal — in most cases, a current pipeline instance cannot continue execution. Recovery requires explicit design at the application level.
11. Application Shutdown and Teardown
Properly shutting down a GStreamer application involves two coordinated steps: handling the signal that initiates shutdown and stopping the pipeline in a controlled manner.Shutdown Strategies
- Immediate Shutdown
- Graceful Shutdown (Recommended)
Quit the main loop directly — fast but does not guarantee all in-flight buffers are processed.Use case: Live previews or non-persistent data streams.
Comparison
Typical Signal Handler
Teardown
Once the main loop exits, transition the pipeline toNULL and release all resources:
Handling Ctrl+C
Complete Graceful Shutdown Sequence
1
User presses Ctrl+C
SIGINT is triggered.
2
Signal routed to handler
g_unix_signal_add() routes SIGINT to the signal handler via the main loop.3
Application sends EOS
gst_event_new_eos() is sent to the pipeline.4
Pipeline finishes processing
All remaining in-flight data is processed.
5
Pipeline posts EOS message on bus
The pipeline notifies the application via the bus.
6
EOS callback quits the main loop
g_main_loop_quit() is called.7
Application transitions pipeline to NULL
All resources are released and the application exits gracefully.
12. Application Interaction via appsink
Theappsink element acts as a bridge between the pipeline’s internal data flow and application-level code, enabling direct access to individual buffers as they are produced.
How appsink Works
Register a callback for incoming samples:Use Cases
Resource management: Always unmap buffers with
gst_buffer_unmap() and unreference samples with gst_sample_unref() after processing. Failing to do so causes memory leaks or buffer pool exhaustion.Callback efficiency: The new-sample callback is invoked from within the pipeline’s streaming thread. Avoid heavy or blocking operations inside the callback — offload long-running tasks to a separate thread.Pipeline independence: If the application cannot consume samples fast enough, the appsink queue may fill up. Control this behavior via appsink properties such as max-buffers and drop.
