/*
 * screenshot_demo — 摄像头截图保存
 * ======================================
 * 每次运行截一张图, 保存到 ./screenshot/image_N.jpg
 * 用法:
 *   ./screenshot_demo              截一张图 + LCD 显示
 *   ./screenshot_demo --no-display 无 LCD
 */

#include <opencv2/opencv.hpp>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <linux/fb.h>

using namespace cv;
using namespace std;

static uint16_t rgb565(uint8_t r, uint8_t g, uint8_t b)
{
    return ((r & 0xF8) << 8) | ((g & 0xFC) << 3) | (b >> 3);
}

int main(int argc, char *argv[])
{
    bool no_display = false;
    for (int i = 1; i < argc; ++i)
        if (strcmp(argv[i], "--no-display") == 0)
            no_display = true;

    // ---- 创建目录 ----
    mkdir("./screenshot", 0755);

    // ---- 摄像头 ----
    VideoCapture cap;
    cap.open(0, CAP_V4L2);
    if (!cap.isOpened()) cap.open(0);
    if (!cap.isOpened()) { cerr << "无法打开摄像头" << endl; return 1; }
    cap.set(CAP_PROP_FRAME_WIDTH,  640);
    cap.set(CAP_PROP_FRAME_HEIGHT, 480);
    cap.set(CAP_PROP_FOURCC, VideoWriter::fourcc('M', 'J', 'P', 'G'));
    printf("摄像头: %dx%d\n",
           (int)cap.get(CAP_PROP_FRAME_WIDTH),
           (int)cap.get(CAP_PROP_FRAME_HEIGHT));

    // ---- 丢弃前几帧 (曝光稳定) ----
    Mat frame;
    for (int i = 0; i < 10; ++i)
        cap.read(frame);
    usleep(100000);

    // ---- 截图 ----
    if (!cap.read(frame) || frame.empty())
    {
        cerr << "截图失败" << endl;
        cap.release();
        return 1;
    }

    // 自增文件名
    int idx = 0;
    char fname[64];
    struct stat st;
    do {
        snprintf(fname, sizeof(fname),
                 "./screenshot/image_%05d.jpg", ++idx);
    } while (stat(fname, &st) == 0);

    imwrite(fname, frame);
    printf("截图: %s (%dx%d)\n", fname, frame.cols, frame.rows);

    // ---- LCD 显示 ----
    if (!no_display)
    {
        int fb_fd = open("/dev/fb0", O_RDWR);
        if (fb_fd >= 0)
        {
            struct fb_var_screeninfo vinfo;
            ioctl(fb_fd, FBIOGET_VSCREENINFO, &vinfo);
            int scr_w = vinfo.xres, scr_h = vinfo.yres;
            size_t fb_size = vinfo.yres_virtual * vinfo.xres_virtual * 2;
            uint16_t *fb_buf = (uint16_t *)mmap(nullptr, fb_size,
                                                 PROT_READ|PROT_WRITE,
                                                 MAP_SHARED, fb_fd, 0);

            Mat disp;
            resize(frame, disp, Size(scr_w, scr_h));
            rectangle(disp, Point(0, 0), Point(disp.cols, disp.rows),
                      Scalar(0, 255, 255), 3);

            for (int y = 0; y < scr_h; ++y)
                for (int x = 0; x < scr_w; ++x)
                {
                    Vec3b px = disp.at<Vec3b>(y, x);
                    fb_buf[y * scr_w + x] = rgb565(px[2], px[1], px[0]);
                }

            sleep(1);
            munmap(fb_buf, fb_size);
            close(fb_fd);
        }
    }

    cap.release();
    return 0;
}
