#include <gst/gst.h>
#include <glib.h>
#include <unistd.h>
#include <string.h>

static GstElement *pipeline;

/* Handler for the pad-added signal */
static void pad_added_handler (GstElement *src, GstPad *pad, GstElement *data);

/* it returns the current running_time */
static GstClockTime get_running_time()
{
	GstClock *clock = gst_element_get_clock(pipeline);
	GstClockTime running_time = gst_clock_get_time(clock) - gst_element_get_base_time(pipeline);
	gst_object_unref(clock);

	return running_time;
}

static GstElement * get_mixer_input()
/* Returns a custom bin to be used as a mixer's input */
{
	GstElement *src =gst_element_factory_make("filesrc", NULL);
	g_object_set(G_OBJECT(src), "location", "video.mkv",NULL);

	GstElement *demuxer = gst_element_factory_make("matroskademux", NULL);
	GstElement *decoder = gst_element_factory_make("theoradec", NULL);
	g_signal_connect (demuxer, "pad-added", G_CALLBACK (pad_added_handler), decoder);

	GstElement *input_bin = gst_bin_new("input_bin");
	gst_bin_add_many(GST_BIN(input_bin), src, demuxer, decoder, NULL);
	gst_element_link_many(src, demuxer, NULL);

	GstPad *srcpad = gst_element_get_static_pad(decoder, "src");
	gst_element_add_pad(input_bin, gst_ghost_pad_new("src", srcpad));
	gst_object_unref(srcpad);

	return input_bin;
}

static gpointer thread_1(GstElement *mixer)
/* It waits 5 seconds and add a new mixer's input */
{
  sleep(5);

  gst_element_set_state(pipeline, GST_STATE_PAUSED);

  GstPad *mpad = gst_element_get_request_pad(mixer, "sink_1");
  gst_pad_set_offset(mpad, get_running_time()); // sets the offset on the new mixer's pad

  GstElement *mixer_input = get_mixer_input();
  gst_bin_add_many(GST_BIN(pipeline), mixer_input, NULL);
  GstPad *spad = gst_element_get_static_pad(mixer_input, "src");
  gst_pad_link(spad, mpad);

  gst_element_sync_state_with_parent(mixer_input);
  gst_element_set_state(pipeline, GST_STATE_PLAYING);

  gst_object_unref(mpad);
  gst_object_unref(spad);
  return NULL;
}

int main(int argc, char *argv[]) {
  /* Initialize GStreamer */
  gst_init (&argc, &argv);
    
  /* Create the elements */
  GstElement * source = gst_element_factory_make("videotestsrc", NULL);
  GstElement * filter = gst_element_factory_make("capsfilter", NULL);
  GstCaps * fcaps = gst_caps_from_string("video/x-raw, width=720, height=576");
  g_object_set(G_OBJECT(filter), "caps", fcaps, NULL);
  gst_caps_unref(fcaps);
  GstElement *mixer = gst_element_factory_make("videomixer", NULL);
  GstElement *sink = gst_element_factory_make("autovideosink", NULL);
   
  pipeline = gst_pipeline_new ("pipeline");

  /* Add and link the elements */
  gst_bin_add_many (GST_BIN (pipeline), source, filter, mixer, sink, NULL);
  gst_element_link_many(source, filter, NULL);
  GstPad *mpad = gst_element_get_request_pad(mixer, "sink_0");
  GstPad *fpad = gst_element_get_static_pad(filter, "src");
  gst_pad_link(fpad, mpad);
  gst_object_unref(mpad);
  gst_object_unref(fpad);
  gst_element_link_many(mixer, sink,  NULL);
    
  /* Start playing */
  GMainLoop *loop = g_main_loop_new(NULL, FALSE);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);
  GThread *thread = g_thread_new("thread_1", (GThreadFunc)thread_1, mixer);
  g_main_loop_run(loop);
   
  /* Free resources */
  g_thread_unref(thread);
  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  return 0;
}


static void pad_added_handler (GstElement *src, GstPad *new_pad, GstElement *data) {
  GstPad *sink_pad = gst_element_get_static_pad (data, "sink");

  if (GST_PAD_LINK_FAILED (gst_pad_link (new_pad, sink_pad))) {
      g_print ("Link failed.\n");
  } else {
	  g_print ("Link succeeded.\n");
  }

  /* Unreference the sink pad */
  gst_object_unref (sink_pad);
}
