news 2026/9/13 15:45:26

Arduino-ESP32 ESP_Video 库实战指南:基于 MIPI-CSI 与 DVP 接口的 V4L2 风格摄像头采集

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Arduino-ESP32 ESP_Video 库实战指南:基于 MIPI-CSI 与 DVP 接口的 V4L2 风格摄像头采集

Arduino-ESP32 ESP_Video 库实战指南:基于 MIPI-CSI 与 DVP 接口的 V4L2 风格摄像头采集

【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32

ESP_Video 是 arduino-esp32 核心中面向 ESP32-S3 与 ESP32-P4 的摄像头采集库,它封装了 ESP-IDF 的esp_video组件,以 V4L2 风格 API 屏蔽 MIPI-CSI(含 ISP)与 DVP 两种底层接口的差异。读完本文,你将掌握视频设备节点的选择、像素格式与分辨率的映射关系、MIPI-CSI / DVP 两套完整初始化与取帧流程,以及如何通过传感器控制接口调节增益、曝光与镜像翻转,可直接基于 示例工程 与 DVP 示例 快速搭建预览、抓帧或 JPEG 采集应用。

库定位与适用前提

该库封装 ESP-IDFesp_video组件,对外暴露 V4L2 风格的采集 API,用于受支持 SoC 上的摄像头传感器。它完成MIPI-CSI(带 ISP)DVP两种接口的底层初始化后,让应用可以打开视频设备节点、分配缓冲区并取出帧数据。典型用途包括预览流水线、面向计算机视觉的抓帧、JPEG 采集,以及传感器调参(增益、曝光、翻转等控制)。

使用该库有三个硬性前提(见 ESP_Video.h 头部的条件编译):

  • ESP-IDF 5.4.0 或更高版本,且目标芯片为ESP32-S3 或 ESP32-P4
  • IDF 配置中至少开启CONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICECONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE其中之一,否则ESP_Video.h不暴露任何公共 API;
  • 示例分别面向ESP32-P4(MIPI-CSI + DVP)ESP32-S3(DVP)

在草图中包含头文件即可:

#include "ESP_Video.h"

从源码结构看,ESP_Video.h在最外层用#if (CONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE || CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE)#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)双重条件包裹全部类定义,这正是文档所述"无配置则无 API"的代码级体现。库的元信息见 library.properties(当前版本 3.3.11,类别 Signal Input/Output)。

视频设备节点:用文件路径操作摄像头

硬件初始化完成后,采集通过esp_video_device.h中定义的标准设备路径进行:

设备路径宏实际节点含义
ESP_VIDEO_MIPI_CSI_DEVICE_NAME/dev/video0MIPI-CSI 摄像头
ESP_VIDEO_ISP_DVP_DEVICE_NAME/dev/video1ISP + DVP
ESP_VIDEO_DVP_DEVICE_NAME/dev/video2无 ISP 路径的 DVP
其他节点在 IDF 配置中启用 SPI、USB UVC、JPEG/H264 编解码、ISP 设备时追加

节点路径只是入口,真正的工作由ESPVideoCaptureDevClass完成:它以open()打开设备,经VIDIOC_G_FMT读取驱动当前格式、VIDIOC_S_FMT重新应用格式,再请求 MMAP 捕获缓冲区(对应源码 open()/applyFormat())。

API 总览:七层设计

Arduino-ESP32 的 ESP Video API 组织为七层,从像素格式到传感器控制逐层递进:

  1. 像素格式——esp_video_format_tESPVideoFormatClass
  2. 分辨率——ESPVideoSolutionClass(帧宽高)
  3. 硬件配置——ESPVideoCamConfigClassESPVideoCSIConfigClassESPVideoDVPPinsConfigClassESPVideoDVPConfigClass
  4. 硬件初始化——ESPVideoClass::begin()
  5. 采集设备——ESPVideoCaptureDevClass(继承格式与分辨率基类)
  6. 缓冲区——ESPVideoBufferClass(同样继承格式与分辨率基类)
  7. 传感器控制——ESPVideoCaptureDevClass::setSensor*()系列方法

值得注意的设计细节(均有源码佐证):

  • 配置对象是值类型,只保存引脚与总线设置,可复制、可赋值;引脚通过periman的占用/释放由ESPVideoClass::begin()完成,在end()或析构函数中释放。
  • CSI 与 DVP 可共存(例如 ESP32-P4),每种接口由内部标志位独立跟踪,并在end()或析构时释放。
  • 采集设备打开是统一的begin()打开设备、读取并重放当前 V4L2 格式(VIDIOC_G_FMT/VIDIOC_S_FMT)、保存宽高并请求捕获缓冲区。
  • 格式与分辨率是共享基类,采集设备和每一帧缓冲区都携带元数据。
  • 像素格式是 Arduino 枚举setFormat()startCapture()前调用;若缓冲区分配后格式改变,驱动缓冲区会被自动重新请求(见setFormat()requestBuffer(buf_count_)的回调逻辑)。
  • 资源持有类不可复制ESPVideoClassESPVideoCaptureDevClass),ESPVideoBufferClass仅可移动。

像素格式与 V4L2 fourcc 映射

esp_video_format_t是 Arduino 侧的像素格式标识符,ESPVideoCaptureDevClass::setFormat()在发出VIDIOC_S_FMT前将每个枚举值映射为 V4L2 fourcc;格式元数据存放在ESPVideoFormatClass中,被采集设备与每个缓冲区继承。枚举定义(见 ESP_Video.h):

typedef enum { ESP_VIDEO_FORMAT_UNKNOWN = 0, ESP_VIDEO_FORMAT_RAW8, ESP_VIDEO_FORMAT_RAW10, ESP_VIDEO_FORMAT_RAW12, ESP_VIDEO_FORMAT_RGB565, ESP_VIDEO_FORMAT_RGB888, ESP_VIDEO_FORMAT_YUV420, ESP_VIDEO_FORMAT_YUV422_YUYV, ESP_VIDEO_FORMAT_YUV422_UYVY, ESP_VIDEO_FORMAT_GRAY8, ESP_VIDEO_FORMAT_JPEG, ESP_VIDEO_FORMAT_MAX } esp_video_format_t;

支持的格式及其 V4L2 映射(映射函数video_format_to_v4l2_format()见 ESP_Video.cpp):

esp_video_format_t名称字符串V4L2 fourcc
ESP_VIDEO_FORMAT_RAW8RAW8V4L2_PIX_FMT_SRGGB8
ESP_VIDEO_FORMAT_RAW10RAW10V4L2_PIX_FMT_SGRBG10
ESP_VIDEO_FORMAT_RAW12RAW12V4L2_PIX_FMT_SGRBG12
ESP_VIDEO_FORMAT_RGB565RGB565V4L2_PIX_FMT_RGB565
ESP_VIDEO_FORMAT_RGB888RGB888V4L2_PIX_FMT_RGB24
ESP_VIDEO_FORMAT_YUV420YUV420V4L2_PIX_FMT_YUV420
ESP_VIDEO_FORMAT_YUV422_YUYVYUV422_YUYVV4L2_PIX_FMT_YUYV
ESP_VIDEO_FORMAT_YUV422_UYVYYUV422_UYVYV4L2_PIX_FMT_UYVY
ESP_VIDEO_FORMAT_GRAY8GRAY8V4L2_PIX_FMT_GREY
ESP_VIDEO_FORMAT_JPEGJPEGV4L2_PIX_FMT_JPEG

ESP_VIDEO_FORMAT_UNKNOWNESP_VIDEO_FORMAT_MAX是哨兵值,不能传给setFormat()。实际可用格式取决于传感器驱动与当前视频设备;若驱动在begin()时报告无法识别的 fourcc,getFormat()会返回ESP_VIDEO_FORMAT_UNKNOWN(对应源码v4l2_format_to_video_format()的 default 分支)。

分辨率与格式元数据基类

ESPVideoSolutionClass:分辨率

存储当前帧宽高,被ESPVideoCaptureDevClassbegin()期间经VIDIOC_G_FMT填充)与ESPVideoBufferClass(取帧时从采集设备复制)继承:

ESPVideoSolutionClass(); // 空对象,宽高为 0 ESPVideoSolutionClass(const ESPVideoSolutionClass &config); // 复制宽高 ESPVideoSolutionClass &operator=(const ESPVideoSolutionClass &config); void begin(uint32_t width, uint32_t height); // 存储帧尺寸 uint32_t getWidth() const; uint32_t getHeight() const;

ESPVideoFormatClass:格式元数据

存储当前像素格式类型及其可读名称,同样被采集设备与缓冲区继承:

ESPVideoFormatClass(); // 空对象,格式为 UNKNOWN ESPVideoFormatClass(const ESPVideoFormatClass &config); ESPVideoFormatClass &operator=(const ESPVideoFormatClass &config); void begin(esp_video_format_t format_type, const std::string &format_name = ""); esp_video_format_t getFormat() const; const char *getFormatName() const;

begin()传入空format_name时,getFormatName()会根据format_type推导名称并在首次访问时缓存(源码中format_name_被声明为mutable以支持惰性填充)。

摄像头配置(SCCB / I2C)

ESPVideoCamConfigClass保存 CSI 与 DVP 共用的 SCCB(I2C)设置。创建实例后调用begin()填充设置,再传给ESPVideoCSIConfigClassESPVideoDVPConfigClass。默认构造创建空对象,复制构造/赋值复制 SCCB 端口或句柄、引脚号与 I2C 频率,但不保留 GPIO,引脚所有权归ESPVideoClass::begin()

begin(Arduino 引脚号版本)

bool begin(i2c_port_num_t port, int8_t scl_pin, int8_t sda_pin, uint32_t i2c_freq = i2c_freq_hz, int8_t reset_pin = -1, int8_t pwdn_pin = -1);
  • port—— 库初始化总线时用于 SCCB 的 I2C 端口;
  • scl_pin/sda_pin—— SCCB 时钟与数据引脚;
  • i2c_freq—— SCCB 频率(Hz),默认 100 kHz(源码中i2c_freq_hz = 100 * 1000);
  • reset_pin/pwdn_pin—— 可选的传感器复位与掉电 GPIO,不用时传-1

begin(复用已有 I2C 主总线)

bool begin(i2c_master_bus_handle_t i2c_handle, uint32_t i2c_freq = i2c_freq_hz, int8_t reset_pin = -1, int8_t pwdn_pin = -1);

当 SCCB 复用应用已创建的 I2C 总线时使用此重载,此时库不会为 SCCB 初始化新的 I2C 驱动(源码通过needInitI2C()判断i2c_handle == nullptr来决定是否自建总线,并在getSccbConfig()中相应设置init_sccb标志)。

其他成员

  • esp_video_init_sccb_config_t getSccbConfig() const—— 返回供 ESP-IDFesp_video初始化结构使用的 SCCB 段;
  • gpio_num_t getResetPin() const/gpio_num_t getPwdnPin() const—— 可选传感器控制 GPIO 的只读访问;
  • bool acquirePins(void *bus)/bool releasePins()—— 通过periman保留或释放 SCCB 及复位/掉电 GPIO,由ESPVideoClass::begin()/end()自动调用,应用通常无需直接调用。DVP 场景下periman的占用类型包括ESP32_BUS_TYPE_VIDEO_CAM_RESETESP32_BUS_TYPE_VIDEO_SCCB_SCL/SDA以及ESP32_BUS_TYPE_LCDCAM_CAM_*系列(见 setPinsBus/clearPinsBus 实现)。

MIPI-CSI 配置

ESPVideoCSIConfigClass继承ESPVideoCamConfigClass,用于 MIPI-CSI + ISP 初始化,仅在启用CONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE时可用。复制构造会同时复制基类摄像头配置与 LDO 初始化标志。

bool begin(const ESPVideoCamConfigClass &config, bool dont_init_ldo = false);
  • config—— 基础摄像头 / SCCB 配置;
  • dont_init_ldo—— 为true时跳过 CSI 驱动内的 LDO 初始化(外部供电时使用)。

getCsiInitConfig()从存储的配置构建 ESP-IDF CSI 初始化结构;getDontInitLdo()返回 LDO 跳过标志。

DVP 引脚配置与 DVP 配置

ESPVideoDVPPinsConfigClass:并行引脚

描述 DVP 并行数据与同步引脚,仅在启用CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE时可用;begin()固定配置 8 位数据宽度(D0–D7)。

bool begin(int8_t vsync_pin, int8_t de_pin, int8_t pclk_pin, int8_t xclk_pin, int8_t data0_pin, int8_t data1_pin, int8_t data2_pin, int8_t data3_pin, int8_t data4_pin, int8_t data5_pin, int8_t data6_pin, int8_t data7_pin);
  • vsync_pin/de_pin/pclk_pin/xclk_pin—— 同步与时钟引脚;
  • data0_pindata7_pin—— 8 条并行数据线。

源码中该begin()会将dvp_pin.data_width固定为CAM_CTLR_DATA_WIDTH_8,并把各引脚填入esp_cam_ctlr_dvp_pin_config_tgetDvpPin()返回原生 ESP-IDF DVP 引脚结构。

ESPVideoDVPConfigClass:组合配置

同时继承ESPVideoCamConfigClassESPVideoDVPPinsConfigClass,单个实例携带完整 DVP 设置(SCCB + 引脚 + XCLK 频率):

bool begin(const ESPVideoCamConfigClass &config, const ESPVideoDVPPinsConfigClass &dvp_pin, uint32_t xclk_freq);
  • config—— 基础摄像头 / SCCB 配置;
  • dvp_pin—— DVP 数据、同步与时钟引脚映射(参见 ESP-IDF camera controller 文档);
  • xclk_freq—— 传感器外部时钟(XCLK)频率(Hz)。

getDvpInitConfig()构建 ESP-IDF DVP 初始化结构,getXclkFreq()返回 XCLK 频率。其acquirePins()/releasePins()依次调用基类实现,同时管理 SCCB、复位/掉电与 DVP 并行引脚。

ESPVideoClass:硬件初始化与清理

ESPVideoClass初始化 CSI 或 DVP 的esp_video栈,每个应用创建一个实例(或使用静态/全局实例)。析构函数调用end()停止已初始化的子系统并释放保留的引脚。

void end();

通过esp_video_deinit_with_flags()停止子系统、释放begin()期间保留的引脚并清空存储的配置。

begin(MIPI-CSI)

bool begin(const ESPVideoCSIConfigClass &config);

初始化 MIPI-CSI 与 ISP(ESP_VIDEO_INIT_FLAGS_MIPI_CSI | ESP_VIDEO_INIT_FLAGS_ISP)。流程为:通过periman保留引脚 → 调用esp_video_init_with_flags()→ 保存配置供清理。初始化成功或已完成时返回true;失败时在返回false前释放已保留引脚(源码中的回滚逻辑见 begin(CSI))。isCSIInitialized()返回 CSI 与 ISP 标志是否生效。

begin(DVP)

bool begin(const ESPVideoDVPConfigClass &config);

初始化 DVP 视频设备(ESP_VIDEO_INIT_FLAGS_DVP),遵循与 CSI 相同的引脚保留与回滚规则。isDVPInitialized()返回 DVP 子系统是否已初始化。isActive()则返回是否有任何子系统标志处于活动状态。

ESPVideoCaptureDevClass:采集设备与帧循环

该类打开 V4L2 采集设备、管理缓冲区并取出帧,继承ESPVideoSolutionClassESPVideoFormatClass提供分辨率与格式元数据。类本身不可复制、不可移动,请使用单一长生命周期实例或显式管理生命周期。析构函数调用end()停止采集、解除 MMAP 映射、释放驱动缓冲区并关闭文件描述符。

begin / end

bool begin(const char *path, size_t buf_count = 2); void end();

begin()打开path指定的设备(若未打开),读取驱动格式(VIDIOC_G_FMT)、重新应用(VIDIOC_S_FMT)、保存宽高与像素格式,并请求buf_count个 MMAP 捕获缓冲区;检测到的格式与分辨率可通过getFormat()getFormatName()getWidth()getHeight()获取。设备已打开时直接返回true而不改变路径;任何失败都会关闭设备并使实例保持未打开状态(源码 begin())。

requestBuffer / startCapture / stopCapture

bool requestBuffer(size_t buf_count); bool startCapture(); bool stopCapture();
  • requestBuffer(buf_count)—— 释放既有缓冲区,向驱动请求新的 MMAP 缓冲区并映射到用户空间,buf_count通常取 2 以实现双缓冲;失败时回滚部分已分配缓冲区。源码中会依次执行VIDIOC_REQBUFS→ 逐个VIDIOC_QUERYBUF+mmap()(见 requestBuffer())。
  • startCapture()—— 将所有缓冲区入队并启动视频流(VIDIOC_STREAMON),要求先完成缓冲区设置。
  • stopCapture()—— 若采集已启动则停止流(VIDIOC_STREAMOFF);未启动或已停止时返回false

captureBuffer 与状态查询

ESPVideoBufferClass captureBuffer(); bool isOpened() const; bool isCaptureStarted() const;

captureBuffer()取出一个已填充缓冲区(VIDIOC_DQBUF);采集未运行或取帧失败时返回无效缓冲区。isOpened()判断设备文件描述符是否有效,isCaptureStarted()判断startCapture()是否成功且流未停止。

setFormat

bool setFormat(esp_video_format_t format);

在采集开始前选择像素格式,或在设备打开后更改格式。内部以format对应的 V4L2 fourcc 执行VIDIOC_G_FMT/VIDIOC_S_FMT;若格式改变且已分配捕获缓冲区,会释放既有 MMAP 缓冲区并按上次begin()/requestBuffer()的缓冲区数量重新请求。对不支持的枚举值、I/O 错误或缓冲区重分配失败返回false。典型应用在begin()之后、startCapture()之前调用。注意源码中若采集已启动(capture_started_),setFormat()会直接拒绝执行。

传感器控制

以下方法映射到 V4L2 扩展控制(VIDIOC_S_EXT_CTRLS),可用性取决于传感器驱动与当前格式,每个控制方法在驱动接受值时才返回true

方法对应的 V4L2 控制
bool setSensorGain(int32_t gain)V4L2_CID_GAIN
bool setSensorExposure(int32_t exposure)V4L2_CID_EXPOSURE
bool setSensorExposureTime(int32_t exposure_time)V4L2_CID_EXPOSURE_ABSOLUTE
bool setSensorAETargetLevel(int32_t target_level)V4L2_CID_CAMERA_AE_LEVEL
bool setSensorJPEGQuality(int32_t quality)V4L2_CID_JPEG_COMPRESSION_QUALITY
bool setSensorVFlip(bool vflip)V4L2_CID_VFLIP
bool setSensorHFlip(bool hflip)V4L2_CID_HFLIP
bool setSensorTestPattern(bool test_pattern)V4L2_CID_TEST_PATTERN

所有方法统一经setExtCtrlValue()构造v4l2_ext_control/v4l2_ext_controls并下发ioctl(fd, VIDIOC_S_EXT_CTRLS, ...)(见 ESP_Video.cpp)。

ESPVideoBufferClass:RAII 帧缓冲

一帧已取出数据的 RAII 包装。继承ESPVideoSolutionClassESPVideoFormatClass,因此每帧自带格式与分辨率元数据。对象被销毁、被移动,或调用end()时,缓冲区会被重新入队(VIDIOC_QBUF)以便采集继续。该类仅可移动(复制已删除)。

ESPVideoBufferClass(ESPVideoBufferClass &&other) noexcept; // 转移所有权,源对象清空 ESPVideoBufferClass &operator=(ESPVideoBufferClass &&other) noexcept; bool valid() const; // data() 非空且 size() > 0 uint8_t *data() const; // MMAP 模式下的像素数据指针 size_t size() const; // V4L2 的 bytesused,有效字节数 int index() const; // 驱动缓冲区索引,重新入队后为 -1 uint32_t getWidth() const; uint32_t getHeight() const; // 取帧时从采集设备复制的宽高 const char *formatName() const; // getFormatName() 的别名 esp_video_format_t formatType() const; // getFormat() 的别名 void end(); // 立即将缓冲区归还驱动

重要提示:只在处理一帧期间持有ESPVideoBufferClass。销毁、移动或调用end()都会把缓冲区归还驱动;不及时释放缓冲区会导致captureBuffer()停滞(缓冲区耗尽)。同时,data()返回的指针不可超过ESPVideoBufferClass对象的生命周期保存。

端到端示例:MIPI-CSI 采集(ESP32-P4)

完整示例见 mipi_csi_camera.ino,核心流程如下:

#include "esp_video_device.h" ESPVideoClass video; ESPVideoCamConfigClass cam_config; cam_config.begin(port, scl, sda); ESPVideoCSIConfigClass csi_config; csi_config.begin(cam_config); if (!video.begin(csi_config)) { // handle error } ESPVideoCaptureDevClass capture; if (!capture.begin(ESP_VIDEO_MIPI_CSI_DEVICE_NAME, 2)) { // handle error } if (!capture.setFormat(ESP_VIDEO_FORMAT_RGB565)) { // handle error } if (!capture.startCapture()) { // handle error } ESPVideoBufferClass frame = capture.captureBuffer(); if (frame.valid()) { uint8_t *pixels = frame.data(); size_t nbytes = frame.size(); const char *format_name = frame.formatName(); // e.g. "JPEG", "RGB565" uint32_t width = frame.getWidth(); uint32_t height = frame.getHeight(); // use frame; buffer is returned to the driver when `frame` is destroyed }

示例工程的引脚定义以 ESP32-P4-Function-EV-Board V1.5 为默认(SCCB I2C 端口 0、SCL GPIO 8、SDA GPIO 7),并保护性地用#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 4, 0)#if CONFIG_IDF_TARGET_ESP32P4包裹,版本或芯片不符时给出明确编译错误或运行提示。示例 CI 配置(ci.yml)还要求PartitionScheme=esp_sr_16, FlashSize=16MCONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE=y,可作为你配置开发环境时的参考。

端到端示例:DVP 采集(ESP32-S3 / ESP32-P4)

完整示例见 dvp_camera.ino,核心流程如下:

#include "esp_video_device.h" ESPVideoClass video; ESPVideoCamConfigClass cam_config; cam_config.begin(port, scl, sda); ESPVideoDVPPinsConfigClass dvp_pins; dvp_pins.begin(vsync, de, pclk, xclk, d0, d1, d2, d3, d4, d5, d6, d7); ESPVideoDVPConfigClass dvp_config; dvp_config.begin(cam_config, dvp_pins, xclk_freq_hz); if (!video.begin(dvp_config)) { // handle error } ESPVideoCaptureDevClass capture; if (!capture.begin(ESP_VIDEO_DVP_DEVICE_NAME, 2)) { // handle error } if (!capture.startCapture()) { // handle error } ESPVideoBufferClass frame = capture.captureBuffer(); if (frame.valid()) { uint8_t *pixels = frame.data(); size_t nbytes = frame.size(); const char *format_name = frame.formatName(); uint32_t width = frame.getWidth(); uint32_t height = frame.getHeight(); // use frame; buffer is returned to the driver when `frame` is destroyed }

示例为两种芯片提供了可直接套用的默认引脚与 XCLK 频率:

  • ESP32-S3(ESP32-S3-EYE):SCCB I2C 端口 0、SCL GPIO 5、SDA GPIO 4;XCLK GPIO 15、PCLK GPIO 13、VSYNC GPIO 6、DE GPIO 7、D0–D7 为 GPIO 11/9/8/10/12/18/17/16;XCLK 频率10 MHz
  • ESP32-P4(ESP32-P4-Function-EV-Board V1.5):SCCB I2C 端口 0、SCL GPIO 8、SDA GPIO 7;XCLK GPIO 20、PCLK GPIO 4、VSYNC GPIO 37、DE GPIO 22、D0–D7 为 GPIO 2/32/33/23/3/6/5/21;XCLK 频率20 MHz

两个示例的loop()都采用"取帧 → 校验 → 打印指针/大小/格式/宽高 → 帧对象析构归还缓冲区"的循环模式,Serial 波特率 115200;kCaptureBufferCount = 2即双缓冲,可避免帧丢失。示例同样要求CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE=y

配置 Kconfig 与开发环境要点

  • 库整体在 library.properties 中声明为architectures=esp32的标准 Arduino 库,安装后通过#include <ESP_Video.h>使用。
  • 必须按接口类型开启对应 Kconfig:MIPI-CSI 用CONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE=y,DVP 用CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE=y;两者可同时开启(ESP32-P4 支持 CSI 与 DVP 共存)。
  • 示例 CI 额外使用PartitionScheme=esp_sr_16, FlashSize=16M,在资源紧张的工程中可作为分区间隔的参考。
  • 若板级引脚与示例不同,只需改写EXAMPLE_*引脚宏;引脚冲突会在periman保留阶段被检测并打印日志(源码中videoDetachBus会提示先调用video.end()再复用摄像头引脚)。

【免费下载链接】arduino-esp32Arduino core for the ESP32 family of SoCs项目地址: https://gitcode.com/GitHub_Trending/ar/arduino-esp32

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/13 15:45:01

国产高端蓝牙音箱如何打破价格桎梏,以声学实力挺进国际市场

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 15:44:46

基于Django的旅游信息管理系统:从源码到部署的完整实战

简介&#xff1a;基于Django的旅游信息管理系统源码是一份面向毕业设计及Python Web初学者的完整项目。系统覆盖用户注册登录与权限管理、景点信息维护、线路规划、预订服务、评论评分及后台管理等典型模块&#xff0c;贯穿Django的MVT架构、ORM数据库操作、表单处理与安全防护…

作者头像 李华
网站建设 2026/9/13 15:44:36

高职大数据与财务管理专业的数据分析教学实践

1. 为什么这个专业必须直面数据分析1.1 先看清行业变化&#xff1a;财务管理正在被数据重构这几年我跟不少高职院校的老师交流&#xff0c;大家普遍反映一个问题&#xff1a;大数据与财务管理专业每年招进来几百号学生&#xff0c;但很多学校实际教学还是老会计那套——基础会计…

作者头像 李华
网站建设 2026/9/13 15:44:30

Redis key数量失控?Shell脚本组合拳实现高效清理与长效治理

去年秋天我接到一单线上求助&#xff1a;某个 Redis 集群的内存其实还在可控范围&#xff0c;但是INFO keyspace里单节点 key 数量已经超过 1.2 亿。业务方一开始想扩容&#xff0c;我去看了一眼接入方式&#xff0c;发现问题的核心根本不在于内存&#xff0c;而在于 key 数量失…

作者头像 李华
网站建设 2026/9/13 15:43:19

Python实现地铁ACC数据分钟级客流预测系统

简介&#xff1a;本资源是一套基于Python开发的地铁客流预测系统完整实现&#xff0c;面向城市轨道交通数据分析初学者、交通工程专业学生及Python Web开发学习者&#xff0c;聚焦于利用ACC系统用户行程与站点数据开展线路级与站点级客流建模、预测与可视化预警。系统采用B/S架…

作者头像 李华
网站建设 2026/9/13 15:41:52

AR硬件交互原型系统:从光学标定到失效兜底的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华