#include "Vision.h"  // 必须放在最前面以避免类型冲突
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/videodev2.h>

// 全局变量定义
static int v4l2_fd = -1;

/**
 * 初始化V4L2虚拟设备
 */
bool init_v4l2_device(int width, int height) {
    v4l2_fd = open("/dev/video0", O_RDWR);
    if (v4l2_fd < 0) {
        fprintf(stderr, "Failed to open V4L2 device\n");
        return false;
    }

    struct v4l2_format v4l2_fmt;
    memset(&v4l2_fmt, 0, sizeof(v4l2_fmt));
    v4l2_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
    v4l2_fmt.fmt.pix.width = width;
    v4l2_fmt.fmt.pix.height = height;
    v4l2_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    v4l2_fmt.fmt.pix.field = V4L2_FIELD_NONE;
    
    if (ioctl(v4l2_fd, VIDIOC_S_FMT, &v4l2_fmt) < 0) {
        fprintf(stderr, "Failed to set V4L2 format\n");
        close(v4l2_fd);
        v4l2_fd = -1;
        return false;
    }

    fprintf(stderr, "V4L2 device initialized: %dx%d\n", width, height);
    return true;
}

void close_v4l2_device() {
    if (v4l2_fd >= 0) {
        close(v4l2_fd);
        v4l2_fd = -1;
    }
}

/**
 * 使用VisionSDK定义的类型替代stdint.h中的类型
 */
typedef unsigned char uchar;
typedef unsigned short ushort;

bool FrameProcCb(ushort* pFrameInShort, ushort iFrameID,
                int iFrameWidth, int iFrameHeight,
                unsigned int iTimeCount, void* pParam)
{
    if (pFrameInShort) {
        if (v4l2_fd < 0 && !init_v4l2_device(iFrameWidth, iFrameHeight)) {
            return false;
        }
        
        size_t yuyv_size = iFrameWidth * iFrameHeight * 2;
        uchar* yuyv_buffer = (uchar*)malloc(yuyv_size);
        if (!yuyv_buffer) {
            fprintf(stderr, "Failed to allocate YUYV buffer\n");
            return false;
        }

        for (int i = 0, j = 0; i < iFrameWidth * iFrameHeight; i++) {
            uchar y = (pFrameInShort[i] >> 4) & 0xFF;
            yuyv_buffer[j++] = y;
            yuyv_buffer[j++] = (i % 2) ? 0x80 : 0x80; // U/V值
        }

        if (write(v4l2_fd, yuyv_buffer, yuyv_size) < 0) {
            perror("V4L2 write failed");
            free(yuyv_buffer);
            return false;
        }

        free(yuyv_buffer);
        return true;
    }
    return false;
}

void FirmwareDownloadCb(char* pPartName, unsigned int iProgress, void* pParam)
{
    fprintf(stderr, "Part:%s Progress: %u\n", pPartName, iProgress);
}

int main(void)
{
    unsigned int iDeviceNum = 0;
    const char* pDeviceID = NULL;
    SDeviceInfo sDeviceInfo;
    int iKey = 0;

    Init();
    fprintf(stderr, "SDK Version: %s\n", GetVersionText());

    if (!SetCallLogEnable(true)) {
        fprintf(stderr, "SetCallLogEnable=Error:%s\n", GetLastErrorText());
        return 0;
    }

    iDeviceNum = SearchforDevice();
    if (iDeviceNum < 0) {
        Uninit();
        fprintf(stderr, "Press Enter key to exit\n");
        scanf("%c", &iKey);
        return 0;
    }

    for (unsigned int i = 0; i < iDeviceNum; i++) {
        pDeviceID = GetDeviceID(i);
        fprintf(stderr, "***************************************************************\n");
        GetDeviceInfo(pDeviceID, &sDeviceInfo);
        fprintf(stderr, "    MAC=%s\n", sDeviceInfo.pMac);
        fprintf(stderr, "    IP=%s\n", sDeviceInfo.pIP);

        if (!OpenDevice(pDeviceID)) {
            fprintf(stderr, "  OpenDevice=Error:%s\n", GetLastErrorText());
            continue;
        }

        Stream pStream = CreateStream(pDeviceID);
        if (!pStream) {
            fprintf(stderr, "++++CreateStream=ERROR:%s\n", GetLastErrorText());
            continue;
        }

        if (!SetStreamLogEnable(pStream, "StreamLog.txt")) {
            fprintf(stderr, "++++SetStreamLogEnable=ERROR:%s\n", GetLastErrorText());
        }

        if (StartStream(pStream, true, FrameProcCb, NULL)) {
            fprintf(stderr, "Press Enter key to stop streaming\n");
            getchar();
            StopStream(pStream);
        } else {
            fprintf(stderr, "++++StartStream=ERROR:%s\n", GetLastErrorText());
        }

        DestroyStream(pStream);
        CloseDevice(pDeviceID);
    }

    close_v4l2_device();
    Uninit();
    fprintf(stderr, "Press Enter key to exit\n");
    scanf("%c", &iKey);
    return 0;
}