// {{{ includes
#include <stdio.h>
#include <gst/gst.h>
#include <gst/controller/gstinterpolationcontrolsource.h>
#include <gst/controller/gstlfocontrolsource.h>
#include <gst/controller/gstargbcontrolbinding.h>
#include <gst/controller/gstdirectcontrolbinding.h>
// }}}

GMainLoop *loop;
gboolean on_message (GstBus *bus, GstMessage * message, gpointer user_data);

gint main (gint argc, gchar ** argv)
{
    // {{{ define and create
    gint res = 1;
    GstElement *src, *overlay, *encoder, *muxer, *sink;
    GstElement *bin;
    GstControlSource *cs;
    GstControlBinding * cb;
    GstBus *bus;

    gst_init (&argc, &argv);

    loop    = g_main_loop_new (NULL, FALSE);
    bin	    = gst_pipeline_new ("pipeline");
    src	    = gst_element_factory_make ("videotestsrc", NULL);
    overlay = gst_element_factory_make ("gdkpixbufoverlay", NULL);
    encoder = gst_element_factory_make ("x264enc", NULL);
    muxer   = gst_element_factory_make ("mp4mux", NULL);
    sink    = gst_element_factory_make ("filesink", NULL);

    g_object_set (src, "num-buffers", 100, NULL);
    g_object_set (overlay, "location", "overlay.png", NULL);
    g_object_set (sink, "location", "out.mp4", NULL);

    if (!src || !overlay || !encoder || !muxer || !sink) {
	GST_WARNING ("problem creating");
	goto Error;
    }

    gst_bin_add_many (GST_BIN (bin), src, overlay, encoder, muxer, sink, NULL);
    if (!gst_element_link_many (src, overlay, encoder, muxer, sink, NULL)) {
	GST_WARNING ("can't link elements");
	goto Error;
    }
    // }}}

    cs = gst_interpolation_control_source_new ();
    cb = gst_direct_control_binding_new (GST_OBJECT_CAST (overlay), "offset-x", cs);
    g_object_set (cb, "absolute", TRUE, NULL);

    gst_object_add_control_binding (GST_OBJECT_CAST (overlay), cb);

    g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);

    gst_timed_value_control_source_set ((GstTimedValueControlSource *)cs, 0, -120);
    gst_timed_value_control_source_set ((GstTimedValueControlSource *)cs, GST_SECOND * 3, 320);

    gst_object_unref (cs);

    // {{{ Run

    bus = gst_pipeline_get_bus (GST_PIPELINE (bin));
    gst_bus_add_signal_watch (bus);
    g_signal_connect (G_OBJECT (bus), "message", G_CALLBACK (on_message), loop);
    gst_object_unref (GST_OBJECT (bus));

    gst_element_set_state (bin, GST_STATE_PLAYING);
    g_main_loop_run (loop);

    gst_element_set_state (bin, GST_STATE_NULL);
    gst_object_unref (bin);
    // }}}

    res = 0;
Error:
    return (res);
}

gboolean on_message (GstBus *bus, GstMessage * message, gpointer user_data) // {{{
{
    switch (GST_MESSAGE_TYPE (message)) {
	case GST_MESSAGE_ERROR:{
				   GError *err = NULL;
				   gchar *debug;

				   gst_message_parse_error (message, &err, &debug);
				   g_critical ("Got ERROR: %s (%s)", err->message, GST_STR_NULL (debug));
				   g_main_loop_quit (loop);
				   break;
			       }
	case GST_MESSAGE_WARNING:{
				     GError *err = NULL;
				     gchar *debug;

				     gst_message_parse_warning (message, &err, &debug);
				     g_warning ("Got WARNING: %s (%s)", err->message, GST_STR_NULL (debug));
				     g_main_loop_quit (loop);
				     break;
				 }
	case GST_MESSAGE_EOS:
				 g_print ("Got EOS, quitting main loop\n");
				 g_main_loop_quit (loop);
				 break;
	default:
				 break;
    }

    return TRUE;
} // }}}
