#pragma once #include "sdkconfig.h" #ifndef CONFIG_IDF_TARGET_ESP32 #include #include #include #include #include #include #include #include "camera.h" #include "jpg/image_to_jpeg.h" #include "esp_video_init.h" struct JpegChunk { uint8_t* data; size_t len; }; class Esp32Camera : public Camera { public: // [T04] 人脸检测用帧引用:zero-copy 指向 mmap 缓冲区 // 使用者获得后必须在短时间内调用 ReleaseDetectionFrame 归还,否则 V4L2 流会卡死 struct FrameRef { const uint8_t* data = nullptr; size_t len = 0; uint16_t width = 0; uint16_t height = 0; v4l2_pix_fmt_t format = 0; uint32_t buf_index = 0; // 用于 VIDIOC_QBUF 归还 }; private: struct FrameBuffer { uint8_t *data = nullptr; size_t len = 0; uint16_t width = 0; uint16_t height = 0; v4l2_pix_fmt_t format = 0; } frame_; v4l2_pix_fmt_t sensor_format_ = 0; #ifdef CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE uint16_t sensor_width_ = 0; uint16_t sensor_height_ = 0; #endif // CONFIG_XIAOZHI_ENABLE_ROTATE_CAMERA_IMAGE int video_fd_ = -1; bool streaming_on_ = false; struct MmapBuffer { void *start = nullptr; size_t length = 0; }; std::vector mmap_buffers_; std::string explain_url_; std::string explain_token_; std::thread encoder_thread_; // [T04] 采集互斥锁:face_track 和 MCP 拍照共享 V4L2 DQBUF 单槽 // 使用 FreeRTOS 信号量(非 std::mutex)以获得 timeout 语义 SemaphoreHandle_t capture_mutex_ = nullptr; public: Esp32Camera(const esp_video_init_config_t& config); ~Esp32Camera(); virtual void SetExplainUrl(const std::string& url, const std::string& token); virtual bool Capture(); // 翻转控制函数 virtual bool SetHMirror(bool enabled) override; virtual bool SetVFlip(bool enabled) override; virtual std::string Explain(const std::string& question); // [T01] 最小化 V4L2 DQBUF/QBUF 探测方法 // 用途:验证 OV3660 + esp_video 底层采集链路是否正常工作 // 不做 JPEG 编码、不做 PSRAM 大分配、不触发 encoder_thread // 调用链路:VIDIOC_DQBUF → 立即 VIDIOC_QBUF 归还 // @param elapsed_us 输出参数,返回两次 ioctl 间的耗时(微秒) // @return 成功返回 true;streaming 未启动或 ioctl 失败返回 false bool ProbeFrameCapture(int64_t* elapsed_us); // [T04] 人脸检测用帧采集:超短 timeout(10ms)拿不到锁则跳帧 // 语义:人脸检测允许丢帧,拍照不允许丢 // 成功返回 true 后,out 指向的缓冲有效期到 ReleaseDetectionFrame 为止 // 必须配对调用:Capture 成功 → Release 归还(否则 V4L2 队列耗尽) bool CaptureForDetection(FrameRef* out); // [T04] 归还人脸检测帧:配对 CaptureForDetection // 内部执行 VIDIOC_QBUF 将缓冲归还给 V4L2 驱动,并释放 capture_mutex_ bool ReleaseDetectionFrame(const FrameRef& ref); }; #endif // ndef CONFIG_IDF_TARGET_ESP32