#include <gst/gst.h>
#include <linux/dvb/frontend.h>
#include <unistd.h>

const gchar *adapter_prefix = "/dev/dvb/adapter0";

static const char* adapter_type_str[] = {"DVB-S", "DVB-C", "DVB-T"};
gint adapter_type = -1;

    GstElement *audio_thread, *audio_queue, *audio_decoder, *audio_sink;
    GstElement *video_thread, *video_queue, *video_decoder, *video_deinterlacer, *video_sink;

static void dvbsrc_adapter_type (GstElement *dvbsrc, gint type) {
    printf("Using %s adapter on %s\n", adapter_type_str[type], adapter_prefix);
    adapter_type = type;
}

static void dvbsrc_signal_quality(GstElement *dvbsrc, gint strength, gint snr) {
//    printf("Strength: %d, SNR: %d\n", strength, snr);
}

static void mpegdemux_new_pad(GstElement *parse, GstPad *pad, GstElement *pipeline) {
    gst_element_set_state(pipeline, GST_STATE_PAUSED);

    printf("New Pad: %s\n", gst_pad_get_name(pad));

    if (g_str_equal(gst_pad_get_name(pad), "audio_00")) {
        gst_pad_link(pad, gst_element_get_pad(audio_queue, "sink"));
        gst_element_set_state(audio_thread, GST_STATE_PLAYING);
        printf("Audio connected\n");
    }
    
    if (g_str_equal(gst_pad_get_name(pad), "video_00")) {
        gst_pad_link(pad, gst_element_get_pad(video_queue, "sink"));
        gst_element_set_state(video_thread, GST_STATE_PLAYING);
        printf("Video connected\n");
    }
    
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
}

static gboolean idle_func(gpointer pipeline)
{
    gboolean busy;
    busy = gst_bin_iterate(GST_BIN(pipeline));
    return busy;
}

int main(int argc, char *argv[]) {
    GstElement *pipeline, *dvbsrc, *ts2ps, *mpegdemux;

    gst_init(&argc, &argv);

    audio_thread = gst_thread_new("audio_thread");
    audio_queue = gst_element_factory_make("queue", "audio_queue");
    audio_decoder = gst_element_factory_make("mad", "audio_decoder");
    audio_sink = gst_element_factory_make("gconfaudiosink", "audio_sink");
    
    gst_bin_add_many(GST_BIN(audio_thread), audio_queue, audio_decoder, audio_sink, NULL);
    gst_element_link_many(audio_queue, audio_decoder, audio_sink, NULL);

    video_thread = gst_thread_new("video_thread");
    video_sink = gst_element_factory_make("gconfvideosink", "video_sink");
    video_deinterlacer = gst_element_factory_make("deinterlace", "video_deinterlacer");
    video_decoder = gst_element_factory_make("ffdec_mpeg2video", "video_decoder");
    video_queue = gst_element_factory_make("queue", "video_queue");

    gst_bin_add_many(GST_BIN(video_thread), video_queue, video_decoder, video_deinterlacer, video_sink, NULL);
    gst_element_link_many(video_queue, video_decoder, video_deinterlacer, video_sink, NULL);

    pipeline = gst_pipeline_new("pipeline");
    dvbsrc = gst_element_factory_make("dvbsrc", "dvbsrc");
    ts2ps = gst_element_factory_make("ts2ps", "ts2ps");
    mpegdemux = gst_element_factory_make("mpegdemux", "mpegdemux");

    g_assert(pipeline);
    g_assert(dvbsrc);
    g_assert(ts2ps);
    g_assert(mpegdemux);
    
    gst_bin_add_many(GST_BIN(pipeline), dvbsrc, ts2ps, mpegdemux, NULL);
    gst_element_link_many(dvbsrc, ts2ps, mpegdemux, NULL);

    g_signal_connect(G_OBJECT(dvbsrc), "adapter-type", G_CALLBACK(dvbsrc_adapter_type), NULL);
    g_signal_connect(G_OBJECT(dvbsrc), "signal-quality", G_CALLBACK(dvbsrc_signal_quality), NULL);
    g_signal_connect(G_OBJECT(mpegdemux), "new-pad", G_CALLBACK(mpegdemux_new_pad), pipeline);

    g_object_set(
        G_OBJECT(dvbsrc),
        "adapter-prefix", adapter_prefix,
        NULL);

    g_idle_add(idle_func, pipeline);
    gst_element_set_state(pipeline, GST_STATE_READY);

    while (-1 == adapter_type)
        sleep(1);

    g_object_set(
        G_OBJECT(dvbsrc),
        "freq", 658000,
        "bandwidth", BANDWIDTH_8_MHZ,
        "code-rate-hp", FEC_2_3,
        "code-rate-lp", FEC_1_2,
        "modulation", QAM_16, 
        "trans-mode", TRANSMISSION_MODE_8K, 
        "guard", GUARD_INTERVAL_1_8, 
        "hierarchy", HIERARCHY_NONE,
        "pids", "305:306", 
        NULL);
    g_object_set(
        G_OBJECT(ts2ps),
        "vpid", 305, 
        "apid", 306, 
        NULL);
    g_object_set(
        G_OBJECT(dvbsrc),
        "tune", -1,
        NULL);

    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    gst_main();

    return 0;
}

// vim: sw=4 sta et
