This piece of code below creates a pipeline that shows test video while saving encoded content to files with splitmuxsink.
#include <gst/gst.h>
GMainLoop* loop = NULL;
GstElement* pipeline = NULL;
GstElement* splitmuxsink = NULL;
#pragma warning(disable:4996)
gboolean split(gpointer data) {
GTimeVal timeval;
g_get_current_time(&timeval);
g_printerr("[%ld.%03ld] split-now\n", timeval.tv_sec, timeval.tv_usec / 1000);
g_signal_emit_by_name(splitmuxsink, "split-now");
return FALSE;
}
gchar* format_location_callback(GstElement* splitmux, guint fragment_id, gpointer data)
{
static int index = 0;
gchar* location = g_strdup_printf("output-%05d.mp4", index);
if (index++ == 1) {
GTimeVal timeval;
g_get_current_time(&timeval);
g_printerr("[%ld.%03ld] pause\n", timeval.tv_sec, timeval.tv_usec / 1000);
gst_element_set_state(pipeline, GST_STATE_PAUSED);
}
return location;
}
int main(int argc, char* argv[])
{
gst_init(NULL, NULL);
// create the pipeline
pipeline = gst_parse_launch(
"videotestsrc ! video/x-raw,width=800,height=600,framerate=30/1 ! timeoverlay time-mode=buffer-count ! tee name=t"
" t. ! queue ! autovideosink"
" t. ! queue ! videoconvert ! nvh264enc ! h264parse ! splitmuxsink name=sink max-size-time=30000000000", NULL);
if (!pipeline) exit(-1);
// splitmuxsink: pause the pipeline when the second file is to be created
splitmuxsink = gst_bin_get_by_name(GST_BIN(pipeline), "sink");
g_signal_connect(splitmuxsink, "format-location", G_CALLBACK(format_location_callback), NULL);
// create the main loop
loop = g_main_loop_new(NULL, FALSE);
// pause at 00:00:20
g_timeout_add_seconds(20, split, NULL);
// start playing
gst_element_set_state(pipeline, GST_STATE_PLAYING);
g_main_loop_run(loop);
// cleanup omitted: gst_element_set_state(pipeline, GST_STATE_NULL) ...
gst_deinit();
return 0;
}
The pipeline needs to be paused at certain points, which is triggerred dynamically by users.
The last video file is not finished and cannot be played, if I just simply pause the pipeline. To make the last video file playable, we have to send a split signal to splitmuxsink and wait until the split is finished.
When the pipeline is paused, I hope that video files created by splitmuxsink contains the latest visible frame (i.e., if the user opens the video file with a player and seeks to the end, he will see an image same as the one in autovideosink).
So I send a split-now signal to splitmuxsink, and wait until the file is splitted with splitmuxsink’s format_location_callback. This callback is used because it seems to be the only one relavant in splitmuxsink’s documentation.
The pause is triggerred at 00:00:20. I find that the video file indeed contains exactly 600 frames, but autovideosink bahaves unexpectedly. Most of the time, the location callback is triggerred 2.2 seconds after signaling split-now, and autovideosink stops at frame-670. Sometimes, the location callback is triggerred 0.2 seconds after split-now.
It’s weird that the video source is paused at frame-670, while the video file containing 600 frames. The delay is too high.
How can I make it behave consistently? How to split video more quickly when requested?
(tested under Windows & GStreamer 1.24.12)