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

/* 宏定义：分辨率、批处理超时等参数 */
#define MUXER_OUTPUT_WIDTH 1280
#define MUXER_OUTPUT_HEIGHT 720
#define MUXER_BATCH_TIMEOUT_USEC 4000000

/* 消息处理函数：处理管道错误和EOS事件 */
static gboolean bus_call(GstBus *bus, GstMessage *msg, gpointer data) {
    GMainLoop *loop = (GMainLoop *)data;
    switch (GST_MESSAGE_TYPE(msg)) {
        case GST_MESSAGE_EOS:
            g_print("End of stream\n");
            g_main_loop_quit(loop);
            break;
        case GST_MESSAGE_ERROR: {
            gchar *debug;
            GError *err;
            gst_message_parse_error(msg, &err, &debug);
            g_print("Error: %s\n", (gchar *)err);
            g_free(err);
            g_free(debug);
            g_main_loop_quit(loop);
            break;
        }
        default:
            break;
    }
    return TRUE;
}

int main(int argc, char *argv[]) {
    GMainLoop *loop = NULL;
    GstElement *pipeline = NULL, *streammux = NULL, *pgie = NULL;
    GstElement *sink = NULL, *osd = NULL, *tracker = NULL;
    GstBus *bus = NULL;
    guint bus_watch_id;
    gint i;

    /* 检查输入参数（需提供2个视频文件路径） */
    if (argc != 3) {
        g_printerr("Usage: %s <video1.h264> <video2.h264>\n", argv[0]);
        return -1;
    }

    /* 初始化GStreamer */
    gst_init(&argc, &argv);
    loop = g_main_loop_new(NULL, FALSE);

    /* 创建主管道 */
    pipeline = gst_pipeline_new("multi-decode-inference-pipeline");

    /* 创建nvstreammux（流合并器） */
    streammux = gst_element_factory_make("nvstreammux", "streammux");
    if (!streammux) {
        g_printerr("Failed to create streammux\n");
        return -1;
    }
    /* 配置streammux：批处理分辨率、超时时间 */
    // g_object_set(G_OBJECT(streammux), 
    //             "batched-width", MUXER_OUTPUT_WIDTH,
    //             "batched-height", MUXER_OUTPUT_HEIGHT,
    //             "batched-push-timeout", MUXER_BATCH_TIMEOUT_USEC,
    //             "live-source", FALSE,  // 非实时源（文件）
    //             NULL);
    g_object_set (G_OBJECT (streammux), "batch-size", 2, NULL);

    /* 创建nvinferserver（推理插件） */
    pgie = gst_element_factory_make("nvinferserver", "primary-inference");
    if (!pgie) {
        g_printerr("Failed to create nvinferserver\n");
        return -1;
    }
    g_object_set(G_OBJECT(pgie), "config-file-path", "dstest1_pgie_nvinferserver_config.txt", NULL);

    /* 创建其他辅助插件：跟踪器、OSD、渲染器 */
    // tracker = gst_element_factory_make("nvtracker", "tracker");
    // osd = gst_element_factory_make("nvdsosd", "onscreendisplay");
    sink = gst_element_factory_make("fakesink", "fakesink");  // 3D渲染sink（或用nveglglessink）

    if (!sink) {
        g_printerr("Failed to create auxiliary elements\n");
        return -1;
    }

    /* 将所有元素添加到管道 */
    gst_bin_add_many(GST_BIN(pipeline), streammux, pgie, sink, NULL);

    /* 链接推理部分：streammux → pgie → tracker → osd → sink */
    if (!gst_element_link_many(streammux, pgie, sink, NULL)) {
        g_printerr("Failed to link inference elements\n");
        return -1;
    }

    /* 为每路视频流创建解码分支，并连接到streammux的sink端口 */
    for (i = 0; i < 2; i++) {
        GstElement *src, *h264parser, *decoder;
        gchar *src_name, *parser_name, *decoder_name, *sink_pad_name;
        GstPad *sinkpad, *srcpad;

        /* 创建元素名称（区分多路流） */
        src_name = g_strdup_printf("file-source-%d", i);
        parser_name = g_strdup_printf("h264-parser-%d", i);
        decoder_name = g_strdup_printf("hy-decoder-%d", i);

        /* 创建解码分支元素 */
        src = gst_element_factory_make("filesrc", src_name);
        h264parser = gst_element_factory_make("h264parse", parser_name);
        decoder = gst_element_factory_make("hyh264dec", decoder_name);  // NVIDIA硬件解码器

        if (!src || !h264parser || !decoder) {
            g_printerr("Failed to create elements for stream %d\n", i);
            return -1;
        }

        /* 配置文件源路径 */
        g_object_set(G_OBJECT(src), "location", argv[i+1], NULL);

        /* 将解码分支元素添加到管道 */
        gst_bin_add_many(GST_BIN(pipeline), src, h264parser, decoder,NULL);

        /* 链接解码分支：src → parser → decoder */
        if (!gst_element_link_many(src, h264parser, decoder,NULL)) {
            g_printerr("Failed to link elements for stream %d\n", i);
            return -1;
        }

        /* 将解码分支的输出连接到streammux的sink端口（sink_0, sink_1...） */
        srcpad = gst_element_get_static_pad(decoder, "src");
        sink_pad_name = g_strdup_printf("sink_%d", i);
        sinkpad = gst_element_request_pad_simple(streammux, sink_pad_name);

        if (gst_pad_link(srcpad, sinkpad) != GST_PAD_LINK_OK) {
            g_printerr("Failed to link stream %d to streammux\n", i);
            return -1;
        }

        /* 释放资源 */
        gst_object_unref(srcpad);
        gst_object_unref(sinkpad);
        g_free(src_name);
        g_free(parser_name);
        g_free(decoder_name);
        g_free(sink_pad_name);
    }

    /* 启动管道消息循环 */
    bus = gst_pipeline_get_bus(GST_PIPELINE(pipeline));
    bus_watch_id = gst_bus_add_watch(bus, bus_call, loop);
    gst_object_unref(bus);

    /* 启动管道 */
    gst_element_set_state(pipeline, GST_STATE_PLAYING);
    g_print("Running pipeline...\n");
    g_main_loop_run(loop);

    /* 清理资源 */
    gst_element_set_state(pipeline, GST_STATE_NULL);
    gst_object_unref(GST_OBJECT(pipeline));
    g_source_remove(bus_watch_id);
    g_main_loop_unref(loop);
    return 0;
}
