Библиотека ESP_Video в Arduino: камера на ESP32-P4 и ESP32-S3

Перевод статьи Using ESP_Video in Arduino — Dong Heng, Espressif.
В этой статье — знакомство с библиотекой ESP_Video в Arduino-ядре для ESP32. Разберёмся, как устроен API захвата в стиле V4L2 для камер с интерфейсами MIPI-CSI и DVP, пройдём по настройке оборудования и получению кадров, а также запустим официальные примеры на платах с ESP32-P4 и ESP32-S3.

Введение#
Запуск камеры на микроконтроллере обычно начинается с таблиц выводов, регистров сенсора и учёта буферов. Библиотека ESP_Video в Arduino-ядре для ESP32 оборачивает компонент esp_video из ESP-IDF и сводит всю эту работу к небольшому набору классов C++: настроить шину камеры, открыть видеоустройство, запустить поток и забирать кадры.
API захвата построен по модели V4L2 из Linux. После инициализации железа приложение работает с узлами устройств вроде /dev/video0, запрашивает MMAP-буферы и в цикле вытаскивает кадры. Типичные применения — живой предпросмотр, захват кадров для компьютерного зрения, JPEG-снимки и настройка сенсора (усиление, экспозиция, отражение и т. п.).
ESP_Video доступна, если Arduino-ядро собрано с ESP-IDF 5.4.0 или новее, а целевой чип — ESP32-S3 или ESP32-P4:
| SoC | MIPI-CSI (с ISP) | DVP |
|---|---|---|
| ESP32-P4 | да | да |
| ESP32-S3 | — | да |
Официальные примеры рассчитаны на ESP32-P4-Function-EV-Board (MIPI-CSI и DVP) и ESP32-S3-EYE (DVP).
Если вы раньше пользовались классическим esp_camera и примером CameraWebServer, считайте ESP_Video следующим уровнем: скетч того же вида, но с полноценной поддержкой MIPI-CSI, встроенным ISP (процессором обработки изображения) на ESP32-P4, моделью устройств V4L2 и более широким набором форматов пикселей.
В статье разобрано:
- интерфейсы камер — MIPI-CSI против DVP и как они представлены видеоустройствами;
- API ESP_Video — классы конфигурации, захвата и буферов;
- начало работы в Arduino IDE — открыть пример, выбрать плату, прошить и смотреть кадры в мониторе порта;
- примеры захвата — как внутри этих скетчей реализован захват по MIPI-CSI (ESP32-P4) и DVP (ESP32-S3 или ESP32-P4);
- форматы пикселей и управление сенсором — где в документации Arduino ESP32 искать значения для
setFormat()и методыsetSensor*().
Интерфейсы камер#
Сенсору камеры от SoC нужны две вещи: шина управления и шина пикселей.
SCCB (Serial Camera Control Bus) — это, по сути, I2C под другим названием. Через неё хост определяет сенсор, загружает настройки регистров и на лету меняет усиление, экспозицию, отражение и качество JPEG.
Шина пикселей — то, по чему на самом деле приходит изображение. Сейчас ESP_Video поддерживает DVP и MIPI-CSI.
DVP#
DVP (Digital Video Port) — параллельный интерфейс камеры. Сенсор управляет восемью линиями данных (D0–D7), а также VSYNC, DE (HREF), PCLK; внешний тактовый сигнал (XCLK) генерирует SoC.
Это тот самый интерфейс, который вы знаете по платам ESP32-CAM и ESP32-S3-EYE. Разводка простая, пропускная способность ограничена параллельной шиной и трассировкой GPIO; хорошо подходит для сенсоров класса VGA и вывода в JPEG.
В ESP_Video DVP-камера без тракта ISP видна как ESP_VIDEO_DVP_DEVICE_NAME (/dev/video2).
MIPI-CSI#
MIPI-CSI — высокоскоростной последовательный интерфейс камеры. Пиксельные данные идут по дифференциальным линиям (lanes), а не по восьми GPIO. Поэтому ESP32-P4 может работать с RAW-сенсорами более высокого разрешения и пропускать изображение через встроенный ISP до того, как приложение получит RGB, YUV или JPEG.
В ESP_Video камера MIPI-CSI видна как ESP_VIDEO_MIPI_CSI_DEVICE_NAME (/dev/video0).
ESP32-P4 может работать с CSI и DVP одновременно. Каждый интерфейс инициализируется независимо и освобождается в ESPVideoClass::end() или при уничтожении объекта.
Схема потоков данных:
- SCCB (I2C) сенсора → блок MIPI-CSI + ISP (
/dev/video0) и блок DVP (/dev/video2); - пиксельные данные → по последовательным линиям в MIPI-CSI либо по D0–D7 + синхросигналам в DVP;
- оба видеоустройства → ваш скетч.
Примечание. В ESP-IDF есть и другие узлы V4L2 — для SPI-камер, USB UVC, кодеков JPEG/H.264 и устройств ISP, если включены соответствующие опции Kconfig. Примеры для Arduino в этой статье используют узлы захвата MIPI-CSI и DVP.
API ESP_Video#
Подключите заголовок библиотеки в скетче:
#include <ESP_Video.h>
API разбит на семь слоёв:
- формат пикселей —
esp_video_format_tиESPVideoFormatClass; - разрешение —
ESPVideoSolutionClass(ширина и высота кадра); - конфигурация железа —
ESPVideoCamConfigClass,ESPVideoCSIConfigClass,ESPVideoDVPPinsConfigClass,ESPVideoDVPConfigClass; - инициализация железа —
ESPVideoClass::begin(); - устройство захвата —
ESPVideoCaptureDevClass; - буфер —
ESPVideoBufferClass; - управление сенсором — методы
ESPVideoCaptureDevClass::setSensor*().
Полный сеанс захвата выглядит так:
- Скетч вызывает
ESPVideoClass::begin(csi_config или dvp_config). - Скетч вызывает
ESPVideoCaptureDevClass::begin(путь к устройству, число буферов). setFormat(RGB565).startCapture().- В цикле для каждого кадра:
captureBuffer()возвращает извлечённый из очереди MMAP-буфер (ESPVideoBufferClass); скетч обрабатываетdata()и уничтожает объект, а деструктор возвращает буфер драйверу черезVIDIOC_QBUF.
Прежде чем смотреть код, полезно запомнить несколько принципов устройства библиотеки:
- Объекты конфигурации — это типы-значения. Они хранят только настройки выводов и шины. Резервирование выводов через
perimanпроисходит вESPVideoClass::begin(), а освобождение — вend()или деструкторе. - Открытие захвата унифицировано.
ESPVideoCaptureDevClass::begin()открывает устройство, считывает и заново применяет текущий формат V4L2, запоминает ширину и высоту и запрашивает буферы захвата. - Формат и разрешение путешествуют вместе с кадром. И устройство захвата, и каждый извлечённый буфер наследуют метаданные формата и разрешения, так что
buffer.formatName(),getWidth()иgetHeight()описывают именно тот кадр, который вы только что получили. - Классы, владеющие ресурсами, нельзя копировать. Используйте один
ESPVideoClassи одинESPVideoCaptureDevClassна всё время работы скетча.ESPVideoBufferClassможно только перемещать.
Дальше пройдём по объектам, которые вы на самом деле создаёте в setup().
Конфигурация камеры (SCCB)#
ESPVideoCamConfigClass хранит общие для CSI и DVP настройки SCCB/I2C. Вызовите begin(), затем передайте объект в конфигурацию CSI или DVP.
ESPVideoCamConfigClass cam_config;
cam_config.begin(port, scl_pin, sda_pin);
Аргументы:
port— порт I2C, используемый для SCCB, если шину инициализирует библиотека;scl_pin/sda_pin— выводы тактирования и данных SCCB;i2c_freq— необязательный, по умолчанию 100 кГц;reset_pin/pwdn_pin— необязательные GPIO сброса и отключения питания сенсора; если не используются, передайте-1.
Если ваш скетч уже владеет шиной I2C master, используйте перегрузку, принимающую i2c_master_bus_handle_t. В этом случае библиотека не будет создавать второй драйвер I2C для SCCB.
Конфигурация MIPI-CSI#
ESPVideoCSIConfigClass расширяет конфигурацию камеры для связки MIPI-CSI + ISP на ESP32-P4.
ESPVideoCSIConfigClass csi_config;
csi_config.begin(cam_config);
Передайте вторым аргументом dont_init_ldo = true, если питание MIPI PHY подаётся извне и вы не хотите, чтобы драйвер CSI инициализировал LDO.
Конфигурация DVP#
DVP нужны ещё две вещи: карта параллельных выводов и частота XCLK сенсора.
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);
begin() у объекта выводов всегда настраивает 8-битную шину данных (D0–D7). xclk_freq_hz — внешняя тактовая частота, которую SoC генерирует для сенсора: 10 МГц на ESP32-S3-EYE и 20 МГц для DVP-камеры на ESP32-P4-Function-EV-Board.
Инициализация железа#
Создайте один экземпляр ESPVideoClass (глобальный или статический) и вызовите перегрузку begin(), соответствующую интерфейсу:
ESPVideoClass video;
if (!video.begin(csi_config)) { // or dvp_config
Serial.println("failed to init camera");
return;
}
Этот вызов резервирует GPIO, инициализирует esp_video с флагами CSI+ISP или DVP и сохраняет конфигурацию для последующего освобождения. Он возвращает true, если инициализация прошла успешно или уже была выполнена. При ошибке зарезервированные выводы освобождаются, и функция возвращает false.
Устройство захвата и кадры#
ESPVideoCaptureDevClass открывает узел захвата V4L2, управляет MMAP-буферами и извлекает кадры из очереди.
ESPVideoCaptureDevClass capture;
if (!capture.begin(ESP_VIDEO_MIPI_CSI_DEVICE_NAME, 2)) {
Serial.println("failed to open capture device");
return;
}
if (!capture.setFormat(ESP_VIDEO_FORMAT_RGB565)) {
Serial.println("failed to set format");
return;
}
if (!capture.startCapture()) {
Serial.println("failed to start capture");
return;
}
begin(path, buf_count)открывает устройство, применяет текущий формат и запрашиваетbuf_countMMAP-буферов. Берите не меньше 2 — тогда захват работает с двойной буферизацией и теряет меньше кадров.setFormat()переводит значениеesp_video_format_tв fourcc V4L2 и выполняетVIDIOC_S_FMT. Вызывайте послеbegin()и доstartCapture(). Если буферы уже были выделены, а формат изменился, они будут запрошены заново автоматически.startCapture()ставит все буферы в очередь и запускает поток (VIDIOC_STREAMON).
В loop() извлеките один кадр, используйте его и дайте объекту выйти из области видимости:
ESPVideoBufferClass frame = capture.captureBuffer();
if (frame.valid()) {
uint8_t *pixels = frame.data();
size_t nbytes = frame.size();
// process the frame
}
// destructor re-queues the buffer
ESPVideoBufferClass — RAII-обёртка над одним извлечённым буфером. Когда объект уничтожается, из него делают move или вызывают end(), буфер возвращается драйверу через VIDIOC_QBUF. Не храните указатель data() дольше, чем живёт объект. Если удерживать буферы и не отпускать их, captureBuffer() зависнет.
Начало работы в Arduino IDE#
Понадобится:
- Arduino IDE 2.x;
- Arduino Core for ESP32 с библиотекой ESP_Video (ядро 3.3.10 или новее);
- поддерживаемая плата с камерой: ESP32-P4-Function-EV-Board (MIPI-CSI или DVP) или ESP32-S3-EYE (DVP);
- USB-кабель с линиями данных.
Если пакет плат ESP32 ещё не установлен, следуйте руководству Getting Started with ESP32 Arduino. Если нужно самое свежее ядро с ESP_Video ещё до того, как оно попадёт в стабильный пакет, используйте development-адрес для Board Manager:
https://espressif.github.io/arduino-esp32/package_esp32_dev_index.json
Выбор платы#
- Подключите плату по USB.
- В Arduino IDE откройте Tools > Board > esp32 и выберите подходящую плату, например ESP32P4 Core Board.
- В меню Tools включите PSRAM, если такой пункт есть. Кадры камеры большие, и без PSRAM выделение буферов, скорее всего, не удастся.
- Выберите последовательный Port.

Выберите плату, соответствующую вашему железу, в Tools > Board
Открываем официальный пример#
Примеры библиотеки сразу выдают поток корректных кадров, так что «голый» запуск драйвера можно пропустить. В Arduino IDE откройте File > Examples > ESP_Video и выберите скетч под свой интерфейс камеры:
- mipi_csi_camera — MIPI-CSI на ESP32-P4-Function-EV-Board V1.5;
- dvp_camera — DVP на ESP32-S3-EYE или ESP32-P4-Function-EV-Board V1.5.

Откройте File > Examples > ESP_Video и выберите скетч под свой интерфейс камеры
Определения выводов в начале каждого скетча соответствуют этим платам. Если камера подключена иначе, перед загрузкой поменяйте макросы EXAMPLE_*.
Для ESP32-P4 конфигурация CI примера MIPI-CSI использует флеш объёмом 16 МБ и увеличенную схему разделов. Если раздела по умолчанию не хватает для приложения вместе с буферами кадров, выберите схему побольше в Tools > Partition Scheme.
Загружаем и смотрим на кадры#
- Нажмите Upload.
- Откройте Tools > Serial Monitor на скорости 115200 бод.
- После строки
Arduino camera example startedна каждый кадр должна выводиться одна строка: указатель на буфер, размер, название формата, ширина и высота.

Монитор порта на 115200 бод: по строке на каждый извлечённый кадр
Успешный запуск выглядит так (значения зависят от сенсора и формата):
Arduino camera example started
captured buffer: 0x3c0a0000 size: 614400 format: RGB565 width: 640 height: 480
captured buffer: 0x3c110000 size: 614400 format: RGB565 width: 640 height: 480
Конкретные адреса зависят от раскладки PSRAM. Если инициализация не удалась, скетч выведет failed to init CSI camera / failed to init DVP camera или failed to open capture device и дальше будет просто ждать в loop(). Проверьте выбор платы, PSRAM, выводы SCCB и то, что подключён поддерживаемый сенсор.
Важно. Публичный API в
ESP_Video.hкомпилируется, только если включена хотя бы одна из опцийCONFIG_ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICEилиCONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE. Arduino-ядро включает их для ESP32-P4 и ESP32-S3 в стандартной конфигурации SDK, на которой собираются примеры. Если вы собираете Arduino как компонент ESP-IDF со своимsdkconfig, включите нужную опцию сами.
Захват по MIPI-CSI на ESP32-P4#
В этом разделе разберём mipi_csi_camera.ino. Разводка по умолчанию — MIPI-CSI-камера на ESP32-P4-Function-EV-Board V1.5: SCCB на порту I2C 0, SCL — GPIO 8, SDA — GPIO 7.
Настраиваем SCCB и CSI#
ESPVideoCamConfigClass cam_config;
cam_config.begin(EXAMPLE_MIPI_CSI_SCCB_I2C_PORT,
EXAMPLE_MIPI_CSI_SCCB_I2C_SCL_PIN,
EXAMPLE_MIPI_CSI_SCCB_I2C_SDA_PIN);
ESPVideoCSIConfigClass csi_config;
csi_config.begin(cam_config);
if (!video.begin(csi_config)) {
Serial.println("failed to init CSI camera");
return;
}
video.begin(csi_config) инициализирует MIPI-CSI и ISP (ESP_VIDEO_INIT_FLAGS_MIPI_CSI | ESP_VIDEO_INIT_FLAGS_ISP). После возврата из функции появляется /dev/video0, а драйвер сенсора уже нашёл камеру на шине SCCB.
Открываем устройство, ставим RGB565, запускаем поток#
const size_t kCaptureBufferCount = 2;
if (!capture_dev.begin(ESP_VIDEO_MIPI_CSI_DEVICE_NAME, kCaptureBufferCount)) {
Serial.println("failed to open capture device");
return;
}
if (!capture_dev.setFormat(ESP_VIDEO_FORMAT_RGB565)) {
Serial.println("failed to set format");
return;
}
if (!capture_dev.startCapture()) {
Serial.println("failed to start capture");
return;
}
RGB565 — удобный формат для предпросмотра: два байта на пиксель, легко выводить на RGB565-дисплей. Если сенсор или ISP не умеют его выдавать, setFormat() вернёт false — попробуйте ESP_VIDEO_FORMAT_YUV422_YUYV, ESP_VIDEO_FORMAT_JPEG или оставьте формат драйвера по умолчанию, пропустив setFormat().
Извлекаем кадры в loop()#
void loop() {
if (!capture_dev.isOpened() || !capture_dev.isCaptureStarted()) {
delay(1000);
return;
}
ESPVideoBufferClass buffer = capture_dev.captureBuffer();
if (!buffer.valid()) {
Serial.println("failed to capture buffer");
delay(10);
return;
}
Serial.printf(
"captured buffer: %p size: %lu format: %s width: %lu height: %lu\n",
buffer.data(), (unsigned long)buffer.size(), buffer.formatName(),
(unsigned long)buffer.getWidth(), (unsigned long)buffer.getHeight());
}
Вот и весь путь захвата на стороне приложения. Замените Serial.printf на свой предпросмотр, кодировщик или подачу на вход нейросети. Держите объект ESPVideoBufferClass только пока обрабатываете этот один кадр.
Полный пример для MIPI-CSI — mipi_csi_camera.ino:
#include "Arduino.h"
#include <ESP_Video.h>
#define EXAMPLE_MIPI_CSI_SCCB_I2C_PORT 0
#define EXAMPLE_MIPI_CSI_SCCB_I2C_SCL_PIN 8
#define EXAMPLE_MIPI_CSI_SCCB_I2C_SDA_PIN 7
ESPVideoClass video;
ESPVideoCaptureDevClass capture_dev;
const size_t kCaptureBufferCount = 2;
void setup() {
Serial.begin(115200);
ESPVideoCamConfigClass cam_config;
cam_config.begin(EXAMPLE_MIPI_CSI_SCCB_I2C_PORT,
EXAMPLE_MIPI_CSI_SCCB_I2C_SCL_PIN,
EXAMPLE_MIPI_CSI_SCCB_I2C_SDA_PIN);
ESPVideoCSIConfigClass csi_config;
csi_config.begin(cam_config);
if (!video.begin(csi_config)) {
Serial.println("failed to init CSI camera");
return;
}
if (!capture_dev.begin(ESP_VIDEO_MIPI_CSI_DEVICE_NAME, kCaptureBufferCount)) {
Serial.println("failed to open capture device");
return;
}
if (!capture_dev.setFormat(ESP_VIDEO_FORMAT_RGB565)) {
Serial.println("failed to set format");
return;
}
if (!capture_dev.startCapture()) {
Serial.println("failed to start capture");
return;
}
Serial.println("Arduino camera example started");
}
void loop() {
if (!capture_dev.isOpened() || !capture_dev.isCaptureStarted()) {
delay(1000);
return;
}
ESPVideoBufferClass buffer = capture_dev.captureBuffer();
if (!buffer.valid()) {
Serial.println("failed to capture buffer");
delay(10);
return;
}
Serial.printf(
"captured buffer: %p size: %lu format: %s width: %lu height: %lu\n",
buffer.data(), (unsigned long)buffer.size(), buffer.formatName(),
(unsigned long)buffer.getWidth(), (unsigned long)buffer.getHeight());
}
Захват по DVP на ESP32-S3 или ESP32-P4#
dvp_camera.ino устроен так же. Дополнительный шаг — заполнить ESPVideoDVPPinsConfigClass перед ESPVideoDVPConfigClass.
Карты выводов по умолчанию.
ESP32-S3-EYE:
| Сигнал | GPIO |
|---|---|
| SCCB SCL / SDA | 5 / 4 |
| XCLK / PCLK | 15 / 13 |
| VSYNC / DE | 6 / 7 |
| D0–D7 | 11, 9, 8, 10, 12, 18, 17, 16 |
| Частота XCLK | 10 МГц |
ESP32-P4-Function-EV-Board V1.5:
| Сигнал | GPIO |
|---|---|
| SCCB SCL / SDA | 8 / 7 |
| XCLK / PCLK | 20 / 4 |
| VSYNC / DE | 37 / 22 |
| D0–D7 | 2, 32, 33, 23, 3, 6, 5, 21 |
| Частота XCLK | 20 МГц |
Настраиваем SCCB, выводы и DVP#
ESPVideoCamConfigClass cam_config;
cam_config.begin(EXAMPLE_DVP_SCCB_I2C_PORT,
EXAMPLE_DVP_SCCB_I2C_SCL_PIN,
EXAMPLE_DVP_SCCB_I2C_SDA_PIN);
ESPVideoDVPPinsConfigClass dvp_pins;
dvp_pins.begin(
EXAMPLE_DVP_VSYNC_PIN, EXAMPLE_DVP_DE_PIN,
EXAMPLE_DVP_PCLK_PIN, EXAMPLE_DVP_XCLK_PIN,
EXAMPLE_DVP_D0_PIN, EXAMPLE_DVP_D1_PIN, EXAMPLE_DVP_D2_PIN, EXAMPLE_DVP_D3_PIN,
EXAMPLE_DVP_D4_PIN, EXAMPLE_DVP_D5_PIN, EXAMPLE_DVP_D6_PIN, EXAMPLE_DVP_D7_PIN);
ESPVideoDVPConfigClass dvp_config;
dvp_config.begin(cam_config, dvp_pins, EXAMPLE_DVP_XCLK_FREQ);
if (!video.begin(dvp_config)) {
Serial.println("failed to init DVP camera");
return;
}
Открываем /dev/video2 и захватываем#
if (!capture_dev.begin(ESP_VIDEO_DVP_DEVICE_NAME, kCaptureBufferCount)) {
Serial.println("failed to open capture device");
return;
}
if (!capture_dev.startCapture()) {
Serial.println("failed to start capture");
return;
}
Пример для DVP не вызывает setFormat() и оставляет формат драйвера по умолчанию. Если нужен конкретный fourcc, setFormat() всё равно можно вызвать после begin(). loop() полностью совпадает со скетчем MIPI-CSI: извлечь кадр, вывести метаданные, отпустить.
Форматы пикселей#
Вызывайте setFormat() со значением esp_video_format_t после begin(). Какие форматы реально поддерживает сенсор, зависит от драйвера и активного видеоустройства. Перечисление, соответствие fourcc V4L2 и строковые названия форматов описаны в разделе Pixel format документации Arduino ESP32.
Управление сенсором#
Когда устройство захвата открыто, можно подстраивать усиление, экспозицию, отражение, качество JPEG и другие параметры. Каждый метод возвращает true, если драйвер принял значение. Поддержка зависит от сенсора и текущего формата. Полный список методов setSensor*() и их соответствие элементам управления V4L2 — в разделе Sensor controls документации Arduino ESP32.
capture.setSensorGain(16);
capture.setSensorExposure(800);
capture.setSensorVFlip(true);
capture.setSensorHFlip(false);
capture.setSensorJPEGQuality(12);
При запуске новой платы пригодится тестовый шаблон: если setSensorTestPattern(true) выдаёт известную картинку, значит, шина пикселей жива, и отлаживать SCCB или настройки ISP можно отдельно.
Что дальше#
Примеры из статьи ограничиваются выводом метаданных кадра. Отсюда можно:
- выводить кадры RGB565 на LCD для локального предпросмотра;
- подавать буферы YUV или RGB в ESP-WHO или ESP-DL для обнаружения и распознавания;
- снимать JPEG-кадры и раздавать их по HTTP — в духе CameraWebServer;
- сделать Matter-камеру на ESP32-P4, как описано в статье Introducing Matter Cameras.
Полный справочник по классам и методам:
- ESP Video API (документация Arduino ESP32);
- исходники и примеры библиотеки ESP_Video;
- ESP-Video-Components — архитектура на стороне IDF, поддерживаемые сенсоры и настройка ISP.
Заключение#
Мы познакомились с ESP_Video — стеком для работы с камерой из Arduino на ESP32-P4 и ESP32-S3: MIPI-CSI со встроенным ISP, DVP и цикл захвата в стиле V4L2, который умещается в setup() и loop(). Мы запустили официальный пример из Arduino IDE, убедились, что поток корректных кадров идёт, а затем разобрали, как эти скетчи настраивают SCCB и шину пикселей, открывают узел устройства и извлекают RAII-буферы. Форматы пикселей и управление сенсором описаны в API Arduino ESP32, поэтому статья сосредоточилась на пути от работающего захвата к приложению.
Этот путь начинается в loop(). Примеры печатают указатель, размер, формат и разрешение; всё остальное — просто другое использование того же объекта ESPVideoBufferClass, пока он находится в области видимости.
Самый очевидный следующий шаг — локальный предпросмотр. RGB565 — это два байта на пиксель, и он хорошо ложится на многие LCD: выведите data() как изображение размером getWidth() на getHeight(), а затем позвольте деструктору буфера вернуть слот драйверу. Если дисплей ожидает другой формат или ориентацию, помогут те же setFormat() и setSensorVFlip() / setSensorHFlip(), что уже показаны для захвата.
Компьютерное зрение устроено так же. Кадры YUV или RGB можно передавать в ESP-WHO или ESP-DL для обнаружения и распознавания прямо на устройстве, без ПК в цепочке. JPEG-снимки идут в обратную сторону: кодируйте их на сенсоре или в ISP и раздавайте по HTTP в духе CameraWebServer. На ESP32-P4 тот же стек камеры служит основой для продукта — Matter-камеры, как описано в Introducing Matter Cameras.
Когда кадры пошли, самое интересное — уже не запуск драйвера. Это выбор формата, короткое время жизни буферов и передача пикселей в предпросмотр, инференс, веб-интерфейс или конвейер умного дома.