#include <stdio.h>
#include <gst/gst.h>


void new_pad_callback(G_GNUC_UNUSED GstElement *p_uridecodebin, GstPad *p_pad, gpointer p_data)
{
	GstElement *identity = GST_ELEMENT_CAST(p_data);

	fprintf(stderr, "linking new decodebin pad\n");

	/* only link once */
	if (GST_PAD_IS_LINKED(p_pad))
		return;

	/* check media type */
	{
		GstCaps *caps = gst_pad_query_caps(p_pad, NULL);
		GstStructure *s = gst_caps_get_structure(caps, 0);
		gboolean match = g_strrstr(gst_structure_get_name(s), "audio") != NULL;
		gst_caps_unref(caps);
		if (!match)
			return;
	}

	/* link this pad to the identity element */
	{
		GstPad *identity_sinkpad = gst_element_get_static_pad(identity, "sink");
		gst_pad_link(p_pad, identity_sinkpad);
		gst_object_unref(GST_OBJECT(identity_sinkpad));
	}

	fprintf(stderr, "linking new decodebin pad done\n");
}


int main(int argc, char **argv)
{
	if (!gst_init_check(&argc, &argv, NULL))
		return -1;

	if (argc < 2)
		return -1;

	while (TRUE)
	{
		GstPad *sinkpad1, *srcpad1, *sinkpad2, *srcpad2;
		GstPadTemplate *templ;
		GstElement *pipeline, *concat, *sink, *uridecodebin1, *uridecodebin2, *identity1, *identity2;

		fprintf(stderr, "========================================\n");

		pipeline = gst_pipeline_new(NULL);
		concat = gst_element_factory_make("concat", NULL);
		sink = gst_element_factory_make("fakesink", NULL);
		uridecodebin1 = gst_element_factory_make("uridecodebin", NULL);
		uridecodebin2 = gst_element_factory_make("uridecodebin", NULL);
		identity1 = gst_element_factory_make("identity", NULL);
		identity2 = gst_element_factory_make("identity", NULL);
		gst_bin_add_many(GST_BIN(pipeline), concat, sink, uridecodebin1, uridecodebin2, identity1, identity2, NULL);

		gst_element_link(concat, sink);

		templ = gst_element_class_get_pad_template(GST_ELEMENT_GET_CLASS(concat), "sink_%u");

		sinkpad1 = gst_element_request_pad(concat, templ, NULL, NULL);
		srcpad1 = gst_element_get_static_pad(identity1, "src");
		gst_pad_link(srcpad1, sinkpad1);

		sinkpad2 = gst_element_request_pad(concat, templ, NULL, NULL);
		srcpad2 = gst_element_get_static_pad(identity2, "src");
		gst_pad_link(srcpad2, sinkpad2);

		g_object_set(G_OBJECT(sink), "sync", (gboolean)TRUE, NULL);
		g_object_set(G_OBJECT(uridecodebin1), "uri", argv[1], "async-handling", (gboolean)TRUE, NULL);
		g_object_set(G_OBJECT(uridecodebin2), "uri", argv[1], "async-handling", (gboolean)TRUE, NULL);
		g_signal_connect(G_OBJECT(uridecodebin1), "pad-added", G_CALLBACK(new_pad_callback), identity1);
		g_signal_connect(G_OBJECT(uridecodebin2), "pad-added", G_CALLBACK(new_pad_callback), identity2);

		GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "pipeline");

		fprintf(stderr, "setting to playing\n");
		gst_element_set_state(pipeline, GST_STATE_PLAYING);

#if 0
		g_usleep(1000000);
#endif

		fprintf(stderr, "setting to null\n");
		gst_element_set_state(pipeline, GST_STATE_NULL);

		gst_pad_unlink(srcpad1, sinkpad1);
		gst_object_unref(GST_OBJECT(srcpad1));
		gst_element_release_request_pad(concat, sinkpad1);
		gst_object_unref(GST_OBJECT(sinkpad1));

		gst_pad_unlink(srcpad2, sinkpad2);
		gst_object_unref(GST_OBJECT(srcpad2));
		gst_element_release_request_pad(concat, sinkpad2);
		gst_object_unref(GST_OBJECT(sinkpad2));

		gst_object_unref(GST_OBJECT(pipeline));
	}

	gst_deinit();

	return -1;
}
