Skip to content

Instantly share code, notes, and snippets.

@SanchayanMaity
Last active June 10, 2026 09:49
Show Gist options
  • Select an option

  • Save SanchayanMaity/d7a7e2ec1de2ef43b4fccb3cb4461c93 to your computer and use it in GitHub Desktop.

Select an option

Save SanchayanMaity/d7a7e2ec1de2ef43b4fccb3cb4461c93 to your computer and use it in GitHub Desktop.
qtdemux per stream pad query
#include <gst/gst.h>
#include <stdio.h>
static gboolean
bus_callback (GstBus * bus, GstMessage * message, gpointer data)
{
GMainLoop *loop = data;
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
{
g_main_loop_quit (loop);
break;
}
case GST_MESSAGE_EOS:
g_main_loop_quit (loop);
break;
default:
break;
}
return TRUE;
}
static gboolean query_position_timeout(gpointer user_data) {
GstElement *pipeline = (GstElement *)user_data;
GstElement *qtdemux;
gint64 duration, position;
GstIterator *iterator;
GValue value = G_VALUE_INIT;
gboolean done = FALSE;
qtdemux = gst_bin_get_by_name(GST_BIN(pipeline), "qtdemux");
if (!qtdemux) {
g_printerr("Failed to find qtdemux element\n");
return G_SOURCE_CONTINUE;
}
if (gst_element_query_position(qtdemux, GST_FORMAT_TIME, &position)) {
g_print("Element position (qtdemux): %" GST_TIME_FORMAT "\n",
GST_TIME_ARGS(position));
} else {
g_print("Failed to query element position\n");
}
iterator = gst_element_iterate_src_pads(qtdemux);
while (!done) {
switch (gst_iterator_next(iterator, &value)) {
case GST_ITERATOR_OK: {
GstPad *pad = g_value_get_object(&value);
if (gst_pad_query_position(pad, GST_FORMAT_TIME, &position)) {
g_print("Pad position - Name: %s, Position: %" GST_TIME_FORMAT "\n",
GST_PAD_NAME(pad), GST_TIME_ARGS(position));
} else {
g_print("Failed to query position for pad: %s\n", GST_PAD_NAME(pad));
}
if (gst_pad_query_duration(pad, GST_FORMAT_TIME, &duration)) {
g_print("Pad duration - Name: %s, Duration: %" GST_TIME_FORMAT "\n",
GST_PAD_NAME(pad), GST_TIME_ARGS(duration));
} else {
g_print("Failed to query duration for pad: %s\n", GST_PAD_NAME(pad));
}
g_value_unset(&value);
break;
}
case GST_ITERATOR_RESYNC:
gst_iterator_resync(iterator);
break;
case GST_ITERATOR_ERROR:
g_printerr("Error iterating source pads\n");
done = TRUE;
break;
case GST_ITERATOR_DONE:
done = TRUE;
break;
}
}
gst_iterator_free(iterator);
gst_object_unref(qtdemux);
g_print("---\n");
return G_SOURCE_CONTINUE;
}
static void on_pad_added(GstElement *qtdemux, GstPad *pad, gpointer user_data) {
GstElement *pipeline = (GstElement *)user_data;
GstPadLinkReturn ret;
GstCaps *caps;
GstStructure *str;
const gchar *mime_type;
gchar queue_name[32];
gchar fakesink_name[32];
gint64 duration;
caps = gst_pad_get_current_caps(pad);
if (!caps) {
caps = gst_pad_query_caps(pad, NULL);
}
str = gst_caps_get_structure(caps, 0);
mime_type = gst_structure_get_name(str);
g_print("Pad added: %s, MIME type: %s\n", GST_PAD_NAME(pad), mime_type);
g_snprintf(queue_name, sizeof(queue_name), "queue_%s", GST_PAD_NAME(pad));
g_snprintf(fakesink_name, sizeof(fakesink_name), "fakesink_%s", GST_PAD_NAME(pad));
GstElement *queue = gst_element_factory_make("queue", queue_name);
GstElement *fakesink = gst_element_factory_make("fakesink", fakesink_name);
g_object_set (fakesink, "sync", TRUE, NULL);
if (!queue || !fakesink) {
g_printerr("Failed to create queue or fakesink element\n");
gst_caps_unref(caps);
return;
}
gst_bin_add_many(GST_BIN(pipeline), queue, fakesink, NULL);
if (gst_element_link(queue, fakesink) != TRUE) {
g_printerr("Failed to link queue to fakesink\n");
gst_caps_unref(caps);
return;
}
gst_element_sync_state_with_parent(queue);
gst_element_sync_state_with_parent(fakesink);
GstPad *queue_sink_pad = gst_element_get_static_pad(queue, "sink");
ret = gst_pad_link(pad, queue_sink_pad);
gst_object_unref(queue_sink_pad);
if (ret != GST_PAD_LINK_OK) {
g_printerr("Failed to link qtdemux pad to queue: %d\n", ret);
gst_caps_unref(caps);
return;
}
gst_caps_unref(caps);
if (gst_element_query_duration (qtdemux, GST_FORMAT_TIME, &duration)) {
g_print("Element duration (qtdemux): %" GST_TIME_FORMAT "\n", GST_TIME_ARGS(duration));
}
}
static void on_no_more_pads(GstElement *qtdemux, gpointer user_data) {
g_print("No more pads will be added\n\n");
}
int main(int argc, char *argv[]) {
GstElement *pipeline, *filesrc, *qtdemux;
GstBus *bus;
const gchar *filename;
guint timeout_id;
GMainLoop *mainloop;
gst_init(&argc, &argv);
if (argc < 2) {
g_printerr("Usage: %s <input_file.mov|mp4|m4a|3gp>\n", argv[0]);
return -1;
}
filename = argv[1];
pipeline = gst_pipeline_new("qtdemux_pipeline");
filesrc = gst_element_factory_make("filesrc", "filesrc");
qtdemux = gst_element_factory_make("qtdemux", "qtdemux");
if (!pipeline || !filesrc || !qtdemux) {
g_printerr("Failed to create elements\n");
return -1;
}
g_object_set(G_OBJECT(filesrc), "location", filename, NULL);
gst_bin_add_many(GST_BIN(pipeline), filesrc, qtdemux, NULL);
if (!gst_element_link(filesrc, qtdemux)) {
g_printerr("Failed to link filesrc to qtdemux\n");
gst_object_unref(pipeline);
return -1;
}
g_signal_connect(qtdemux, "pad-added", G_CALLBACK(on_pad_added), pipeline);
g_signal_connect(qtdemux, "no-more-pads", G_CALLBACK(on_no_more_pads), NULL);
GstStateChangeReturn ret = gst_element_set_state(pipeline, GST_STATE_PLAYING);
if (ret == GST_STATE_CHANGE_FAILURE) {
g_printerr("Failed to set pipeline to PLAYING state\n");
gst_object_unref(pipeline);
return -1;
}
timeout_id = g_timeout_add(5000, query_position_timeout, pipeline);
mainloop = g_main_loop_new (NULL, FALSE);
bus = gst_element_get_bus(pipeline);
gst_bus_add_signal_watch (bus);
g_signal_connect (bus, "message", (GCallback) bus_callback, mainloop);
g_main_loop_run (mainloop);
if (timeout_id > 0) {
g_source_remove(timeout_id);
}
gst_element_set_state(pipeline, GST_STATE_NULL);
gst_object_unref(bus);
gst_object_unref(pipeline);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment