#include <gst/gst.h>

/* Functions below print the Capabilities in a human-friendly format */

static gboolean print_field (GQuark field, const GValue * value, gpointer pfx) {

gchar *str = gst_value_serialize (value);

g_print ("%s %15s: %s\n", (gchar *) pfx, g_quark_to_string (field), str);

g_free (str);

return TRUE;

}

static void print_caps (const GstCaps * caps, const gchar * pfx) {

guint i;

g_return_if_fail (caps != NULL);

if (gst_caps_is_any (caps)) {

g_print ("%sANY\n", pfx);

return;

}

if (gst_caps_is_empty (caps)) {

g_print ("%sEMPTY\n", pfx);

return;

}

for (i = 0; i < gst_caps_get_size (caps); i++) {

GstStructure *structure = gst_caps_get_structure (caps, i);

g_print ("%s%s\n", pfx, gst_structure_get_name (structure));

gst_structure_foreach (structure, print_field, (gpointer) pfx);

}

}

/* Prints information about a Pad Template, including its Capabilities */

static void print_pad_templates_information (GstElementFactory * factory) {

const GList *pads;

GstStaticPadTemplate *padtemplate;

g_print ("Pad Templates for %s:\n", gst_element_factory_get_longname (factory));

if (!gst_element_factory_get_num_pad_templates (factory)) {

g_print (" none\n");

return;

}

pads = gst_element_factory_get_static_pad_templates (factory);

while (pads) {

padtemplate = pads->data;

pads = g_list_next (pads);

if (padtemplate->direction == GST_PAD_SRC)

g_print (" SRC template: '%s'\n", padtemplate->name_template);

else if (padtemplate->direction == GST_PAD_SINK)

g_print (" SINK template: '%s'\n", padtemplate->name_template);

else

g_print (" UNKNOWN!!! template: '%s'\n", padtemplate->name_template);

if (padtemplate->presence == GST_PAD_ALWAYS)

g_print (" Availability: Always\n");

else if (padtemplate->presence == GST_PAD_SOMETIMES)

g_print (" Availability: Sometimes\n");

else if (padtemplate->presence == GST_PAD_REQUEST) {

g_print (" Availability: On request\n");

} else

g_print (" Availability: UNKNOWN!!!\n");

if (padtemplate->static_caps.string) {

GstCaps *caps;

g_print (" Capabilities:\n");

caps = gst_static_caps_get (&padtemplate->static_caps);

print_caps (caps, " ");

gst_caps_unref (caps);

}

g_print ("\n");

}

}

/* Shows the CURRENT capabilities of the requested pad in the given element */

static void print_pad_capabilities (GstElement *element, gchar *pad_name) {

GstPad *pad = NULL;

GstCaps *caps = NULL;

/* Retrieve pad */

pad = gst_element_get_static_pad (element, pad_name);

if (!pad) {

g_printerr ("Could not retrieve pad '%s'\n", pad_name);

return;

}

/* Retrieve negotiated caps (or acceptable caps if negotiation is not finished yet) */

caps = gst_pad_get_current_caps (pad);

if (!caps)

caps = gst_pad_query_caps (pad, NULL);

/* Print and free */

g_print ("Caps for the %s pad:\n", pad_name);

print_caps (caps, " ");

gst_caps_unref (caps);

gst_object_unref (pad);

}

int main(int argc, char *argv[]) {

GstElement *pipeline, *source, *sink;

GstElementFactory *source_factory, *sink_factory;

GstBus *bus;

GstMessage *msg;

GstStateChangeReturn ret;

gboolean terminate = FALSE;

/* Initialize GStreamer */

gst_init (&argc, &argv);

/* Create the element factories */

source_factory = gst_element_factory_find ("audiotestsrc");

sink_factory = gst_element_factory_find ("autoaudiosink");

if (!source_factory || !sink_factory) {

g_printerr ("Not all element factories could be created.\n");

return -1;

}

/* Print information about the pad templates of these factories */

print_pad_templates_information (source_factory);

print_pad_templates_information (sink_factory);

/* Ask the factories to instantiate actual elements */

source = gst_element_factory_create (source_factory, "source");

sink = gst_element_factory_create (sink_factory, "sink");

/* Create the empty pipeline */

pipeline = gst_pipeline_new ("test-pipeline");

if (!pipeline || !source || !sink) {

g_printerr ("Not all elements could be created.\n");

return -1;

}

/* Build the pipeline */

gst_bin_add_many (GST_BIN (pipeline), source, sink, NULL);

if (gst_element_link (source, sink) != TRUE) {

g_printerr ("Elements could not be linked.\n");

gst_object_unref (pipeline);

return -1;

}

/* Print initial negotiated caps (in NULL state) */

g_print ("In NULL state:\n");

print_pad_capabilities (sink, "sink");

/* Start playing */

ret = gst_element_set_state (pipeline, GST_STATE_PLAYING);

if (ret == GST_STATE_CHANGE_FAILURE) {

g_printerr ("Unable to set the pipeline to the playing state (check the bus for error messages).\n");

}

/* Wait until error, EOS or State Change */

bus = gst_element_get_bus (pipeline);

do {

msg = gst_bus_timed_pop_filtered (bus, GST_CLOCK_TIME_NONE, GST_MESSAGE_ERROR | GST_MESSAGE_EOS |

GST_MESSAGE_STATE_CHANGED);

/* Parse message */

if (msg != NULL) {

GError *err;

gchar *debug_info;

switch (GST_MESSAGE_TYPE (msg)) {

case GST_MESSAGE_ERROR:

gst_message_parse_error (msg, &err, &debug_info);

g_printerr ("Error received from element %s: %s\n", GST_OBJECT_NAME (msg->src), err->message);

g_printerr ("Debugging information: %s\n", debug_info ? debug_info : "none");

g_clear_error (&err);

g_free (debug_info);

terminate = TRUE;

break;

case GST_MESSAGE_EOS:

g_print ("End-Of-Stream reached.\n");

terminate = TRUE;

break;

case GST_MESSAGE_STATE_CHANGED:

/* We are only interested in state-changed messages from the pipeline */

if (GST_MESSAGE_SRC (msg) == GST_OBJECT (pipeline)) {

GstState old_state, new_state, pending_state;

gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);

g_print ("\nPipeline state changed from %s to %s:\n",

gst_element_state_get_name (old_state), gst_element_state_get_name (new_state));

/* Print the current capabilities of the sink element */

print_pad_capabilities (sink, "sink");

}

break;

default:

/* We should not reach here because we only asked for ERRORs, EOS and STATE_CHANGED */

g_printerr ("Unexpected message received.\n");

break;

}

gst_message_unref (msg);

}

} while (!terminate);

/* Free resources */

gst_object_unref (bus);

gst_element_set_state (pipeline, GST_STATE_NULL);

gst_object_unref (pipeline);

gst_object_unref (source_factory);

gst_object_unref (sink_factory);

return 0;

}