// {{{ 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;
GstControlSource *left_cs, *right_cs, *top_cs, *bottom_cs;

GstControlSource* create_cs (GstElement *element, char *prop_name) // {{{
{
    GstControlSource *cs = gst_interpolation_control_source_new ();
    gst_object_add_control_binding (GST_OBJECT_CAST (element),
	    gst_direct_control_binding_new_absolute (GST_OBJECT_CAST (element), prop_name, cs));
    g_object_set (cs, "mode", GST_INTERPOLATION_MODE_LINEAR, NULL);

    return cs;
}
// }}}

#define SRC_W 1280
#define SRC_H 720
#define DST_W 854
#define DST_H 480

void add_cp (int x, int y, gint64 time, int width, int height) // {{{
{
    int lv, rv, tv, bv;

    if (width == 0)
        width = DST_W;
    if (height == 0)
        height = DST_H;

    CLAMP (x, 0, SRC_W - width);
    CLAMP (y, 0, SRC_H - height);

    lv = x; rv = SRC_W - (x + width);
    tv = y; bv = SRC_H - (y + height);

    g_print ("l=%d, r=%d, t=%d, b=%d\n", lv, rv, tv, bv);

    gst_timed_value_control_source_set ((GstTimedValueControlSource *)left_cs, GST_MSECOND * time, lv);
    gst_timed_value_control_source_set ((GstTimedValueControlSource *)right_cs, GST_MSECOND * time, rv);
    gst_timed_value_control_source_set ((GstTimedValueControlSource *)top_cs, GST_MSECOND * time, tv);
    gst_timed_value_control_source_set ((GstTimedValueControlSource *)bottom_cs, GST_MSECOND * time, bv);
} 
// }}}

gint main (gint argc, gchar ** argv)
{
    // {{{ define and create
    gint res = 1;
    GstElement *src, *crop, *scaler, *src_filter, *scale_filter, *sink;
    GstElement *bin;
    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);
    crop    = gst_element_factory_make ("videocrop", NULL);
    scaler  = gst_element_factory_make ("videoscale", NULL);
    sink    = gst_element_factory_make ("ximagesink", NULL);
    src_filter   = gst_element_factory_make ("capsfilter", NULL);
    scale_filter = gst_element_factory_make ("capsfilter", NULL);

    g_object_set (src, "num-buffers", 1500, NULL);
    // Don't go into passthrough 
    g_object_set (crop, "left", 1, "right", 1, "top", 1, "bottom", 1, NULL);
    g_object_set (scaler, "add-borders", 0, NULL);
    g_object_set (scale_filter, "caps", gst_caps_from_string ("video/x-raw,width=852,height=480"), NULL);
    g_object_set (src_filter, "caps", gst_caps_from_string ("video/x-raw,width=1280,height=720"), NULL);

    if (!src || !crop || !scaler || !scale_filter || !sink) {
	g_print ("Failed to create one or more elements\n");
	goto Error;
    }

    gst_bin_add_many (GST_BIN (bin), src, src_filter, crop, scaler, scale_filter, sink, NULL);

    if (!gst_element_link_many (src, src_filter, crop, scaler, scale_filter, sink, NULL)) {
	g_print ("Failed to link elements\n");
	goto Error;
    }
    // }}}

    left_cs   = create_cs (crop, "left");
    right_cs  = create_cs (crop, "right");
    top_cs    = create_cs (crop, "top") ;
    bottom_cs = create_cs (crop, "bottom");

    add_cp (0  , 0, 0, 100, 100);
    add_cp (200, 200, 4000, 0, 0);
    add_cp (0, 0, 8000, 100, 100);
    add_cp (200, 200, 12000, 0, 0);

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

    gst_element_set_state (bin, GST_STATE_NULL);

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