#ifndef V4L2_CAPTURE_H #define V4L2_CAPTURE_H #include #include #include #include // V4L2 流式(MMAP)取图封装 // 参考 quick_bring_up_64g.sh 中 v4l2src 的行为: // - 打开 /dev/videoN // - 协商 UYVY 像素格式与分辨率 // - 设置相机控制(sensor_mode / trig_pin 等, 等价于 v4l2-ctl -c ...) // - MMAP 方式申请内核缓冲区并流式采集 class V4l2Capture { public: // 单帧采集结果 struct Frame { void *data = nullptr; // 指向 MMAP 缓冲区, 释放前有效 size_t size = 0; // 实际帧字节数(bytesused) uint32_t width = 0; uint32_t height = 0; uint32_t pixelformat = 0; // V4L2_PIX_FMT_* (如 V4L2_PIX_FMT_UYVY) uint32_t bytes_per_line = 0; uint32_t sequence = 0; // 驱动序号 uint64_t timestamp_us = 0; // 单调时钟时间戳(us) int index = -1; // 内部缓冲区索引 }; V4l2Capture() = default; ~V4l2Capture(); V4l2Capture(const V4l2Capture &) = delete; V4l2Capture &operator=(const V4l2Capture &) = delete; // 打开设备节点, 例如 /dev/video5 bool open(const std::string &device); // 关闭设备并释放所有资源 void close(); bool isOpen() const { return fd_ >= 0; } // 协商像素格式与分辨率. pixelformat 使用 V4L2_PIX_FMT_* 四字符码 bool setFormat(uint32_t width, uint32_t height, uint32_t pixelformat); // 设置帧率(通过 VIDIOC_S_PARM). fps 分子/分母均为 fps/1 bool setFps(uint32_t fps); // 设置 V4L2 控制, 等价 v4l2-ctl -c =. id 为 V4L2_CID_* 之四字符码 // 例如 sensor_mode=0x009a2008, trig_pin=0x009a2084 bool setControl(uint32_t id, int32_t value); // 申请 MMAP 缓冲区, 默认 4 个 bool initMmap(uint32_t buffer_count = 4); // 开始 / 停止采集 bool startStreaming(); bool stopStreaming(); // 阻塞取一帧, 超时 timeout_ms 毫秒. 成功返回 true, 需配对调用 releaseFrame() bool getFrame(Frame &frame, int timeout_ms = 1000); // 归还缓冲区给驱动队列, 必须在下次 getFrame 前调用 void releaseFrame(const Frame &frame); uint32_t width() const { return width_; } uint32_t height() const { return height_; } uint32_t pixelformat() const { return pixelformat_; } private: struct MmapBuffer { void *start = nullptr; size_t length = 0; bool queued = false; // 是否在驱动队列中 }; // 归还指定索引的缓冲区 (内部使用) void releaseFrameByIndex(int idx); int fd_ = -1; uint32_t width_ = 0; uint32_t height_ = 0; uint32_t pixelformat_ = 0; uint32_t bytes_per_line_ = 0; bool streaming_ = false; std::vector buffers_; int last_dequeued_ = -1; // 当前已出队但未归还的缓冲区索引 }; #endif // V4L2_CAPTURE_H