first commit

This commit is contained in:
David R.
2025-09-05 18:58:05 +02:00
parent fc13e0779b
commit ed05c83ac6
3678 changed files with 832193 additions and 0 deletions
@@ -0,0 +1,8 @@
esp_video/examples/uvc:
enable:
- if: IDF_TARGET == "esp32p4"
reason: only support on esp32p4
depends_components:
- esp_video
- esp_cam_sensor
- esp_sccb_intf
@@ -0,0 +1,7 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(uvc)
@@ -0,0 +1,219 @@
# USB Video Class Example
(See the [README.md](../README.md) file in the upper level [examples](../) directory for more information about examples.)
This example demonstrates the following:
- How to initialize esp_video with specific parameters
- How to open camera interface video device and capture video stream from this device
- How to open H.264 or JPEG video device and encode video stream by this device
- How to initialize USB video class and see video on the PC
## How to use example
### Software Required
* `potplay` APP for PC on Windows OS
### Configure the Project
Configure camera hardware data interface based on development kit:
#### MIPI-CSI Development Kit
```
Example Configuration --->
Camera sensor interface (MIPI-CSI) --->
(X) MIPI-CSI
(0) MIPI CSI SCCB I2C Port Number
(8) MIPI CSI SCCB I2C SCL Pin
(7) MIPI CSI SCCB I2C SDA Pin
Component config --->
Espressif Camera Sensors Configurations --->
[*] SC2336 ---->
Default format select for MIPI (RAW8 1280x720 30fps, MIPI 2lane 24M input) --->
(X) RAW8 1280x720 30fps, MIPI 2lane 24M input
USB Device UVC --->
USB Cam1 Config --->
UVC Default Resolution (HD 1280x720) --->
(X) HD 1280x720
(30) Frame Rate (FPS)
(1280) Cam1 Frame Width
(720) Cam1 Frame Height
```
Note: For custom development boards, please update the I2C pins configuration in the `Example Configuration` menu.
#### DVP Development Kit
```
Example Configuration --->
Camera sensor interface (DVP) --->
(X) DVP
(1) DVP SCCB I2C Port Number (NEW)
(33) DVP SCCB I2C SCL Pin (NEW)
(32) DVP SCCB I2C SDA Pin (NEW)
Component config --->
Espressif Camera Sensors Configurations --->
[*] OV2640 --->
Default format select (RGB565 640x480 6fps, DVP 8bit 20M input) --->
(X) RGB565 640x480 6fps, DVP 8bit 20M input
USB Device UVC --->
USB Cam1 Config --->
Default Resolution (VGA 640x480) --->
(X) VGA 640x480
(6) Frame Rate (FPS)
(640) Cam1 Frame Width
(480) Cam1 Frame Height
```
#### Select USB video class output video format
##### JPEG
```
component config --->
USB Device UVC --->
USB Cam1 Config --->
Cam1 Format (MJPEG) --->
(X) MJPEG
```
##### H.264
```
component config --->
USB Device UVC --->
USB Cam1 Config --->
UVC Cam1 Format (H264) --->
(X) H264
```
***Please note that the OV2640 doesn't support H.264 format, it only supports the JPEG format***.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py set-target esp32p4
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the [ESP-IDF Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/esp32p4/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
## Example Output
Running this example, you will see the following log output on the serial monitor:
#### MIPI-CSI Development Kit
```
...
I (1641) main_task: Calling app_main()
I (1641) gpio: GPIO[22]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1651) gpio: GPIO[23]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1661) sc2336: Detected Camera sensor PID=0xcb3a
I (1741) example: version: 0.5.1
I (1741) example: driver: MIPI-CSI
I (1741) example: card: MIPI-CSI
I (1741) example: bus: esp32p4:MIPI-CSI
I (1741) example: capabilities:
I (1751) example: VIDEO_CAPTURE
I (1751) example: STREAMING
I (1761) example: device capabilities:
I (1761) example: VIDEO_CAPTURE
I (1761) example: STREAMING
I (1771) example: version: 0.5.1
I (1771) example: driver: H.264
I (1781) example: card: H.264
I (1781) example: bus: esp32p4:H.264
I (1781) example: capabilities:
I (1791) example: STREAMING
I (1791) example: device capabilities:
I (1801) example: STREAMING
I (1801) example: Format List
I (1801) example: Format(1) = H.264
I (1811) example: Frame List
I (1811) example: Frame(1) = 1280 * 720 @30fps
I (1821) usbd_uvc: UVC Device Start, Version: 1.1.0
I (1821) main_task: Returned from app_main()
I (2031) usbd_uvc: Mount
I (3281) usbd_uvc: Suspend
...
```
#### DVP Development Kit
```
...
I (1164) main_task: Calling app_main()
I (1164) gpio: GPIO[32]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1174) gpio: GPIO[33]| InputEn: 1| OutputEn: 1| OpenDrain: 1| Pullup: 1| Pulldown: 0| Intr:0
I (1194) ov2640: Detected Camera sensor PID=0x26
I (1274) example: version: 0.5.1
I (1274) example: driver: DVP
I (1274) example: card: DVP
I (1274) example: bus: esp32p4:DVP
I (1274) example: capabilities:
I (1284) example: VIDEO_CAPTURE
I (1284) example: STREAMING
I (1284) example: device capabilities:
I (1294) example: VIDEO_CAPTURE
I (1294) example: STREAMING
I (1304) example: version: 0.5.1
I (1304) example: driver: JPEG
I (1304) example: card: JPEG
I (1314) example: bus: esp32p4:JPEG
I (1314) example: capabilities:
I (1314) example: STREAMING
I (1324) example: device capabilities:
I (1324) example: STREAMING
I (1334) example: Format List
I (1334) example: Format(1) = MJPEG
I (1334) example: Frame List
I (1344) example: Frame(1) = 640 * 480 @6fps
I (1344) usbd_uvc: UVC Device Start, Version: 1.1.0
I (1354) main_task: Returned from app_main()
I (1564) usbd_uvc: Mount
I (2824) usbd_uvc: Suspend
...
```
Open potplay APP and select follow option in menu:
```
PotPlayer -->
Open -->
Camera/Other Device
```
You can see following log on the serial monitor and video in potlayer display window:
```
I (192121) usbd_uvc: Resume
I (192411) usbd_uvc: bFrameIndex: 1
I (192411) usbd_uvc: dwFrameInterval: 333333
```
## Troubleshooting
* If the console log shows as follows, it means your ESP32-P4 chip version is v0.0, and it is not supported by default configuration, please configure the right version by menuconfig:
```txt
A fatal error occurred: bootloader/bootloader.bin requires chip revision in range [v0.1 - v0.99] (this chip is revision v0.0). Use --force to flash anyway
```
menuconfig:
```
Component config --->
Hardware Settings --->
Chip revision --->
Minimum Supported ESP32-P4 Revision (Rev v0.1) --->
(X) Rev v0.0
```
@@ -0,0 +1,145 @@
dependencies:
espressif/cmake_utilities:
component_hash: 351350613ceafba240b761b4ea991e0f231ac7a9f59a9ee901f751bddc0bb18f
dependencies:
- name: idf
require: private
version: '>=4.1'
source:
registry_url: https://components.espressif.com
type: service
version: 0.5.3
espressif/esp_cam_sensor:
component_hash: 7b110b08542aeae833895dacd74425e926dd36eed68ae1a26f2b6109e04ea984
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_sccb_intf
registry_url: https://components.espressif.com
require: private
version: '>=0.0.2'
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com
type: service
targets:
- esp32p4
version: 0.9.0
espressif/esp_h264:
component_hash: 7599170f185871bfde69aa0213dfc7f12d45e7dedfd85247be08d6decd34e476
dependencies:
- name: idf
require: private
version: '>=4.4'
source:
registry_url: https://components.espressif.com
type: service
targets:
- esp32s3
- esp32p4
version: 1.1.2
espressif/esp_ipa:
component_hash: 7547b050a99351a85aaba8ba38211c36fd4769c2ae3e570fa330dc90dfd2704c
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: idf
require: private
version: '>=5.4'
source:
registry_url: https://components.espressif.com
type: service
targets:
- esp32p4
version: 0.2.0
espressif/esp_sccb_intf:
component_hash: 71e3def402f6193a23c599bdde4fa0b544ca2b1f63608b6d0ec2bee3cd9a1c33
dependencies:
- name: idf
require: private
version: '>=5.3'
source:
registry_url: https://components.espressif.com
type: service
version: 0.0.5
espressif/esp_video:
component_hash: 37f7a3b16aa842e612180d5a4698db1c3bc36142a0b78664eb4ffe67c8cd0510
dependencies:
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: 0.*
- name: espressif/esp_cam_sensor
registry_url: https://components.espressif.com
require: private
version: 0.9.*
- name: espressif/esp_h264
registry_url: https://components.espressif.com
require: private
version: '>=1.0.3'
- name: espressif/esp_ipa
registry_url: https://components.espressif.com
require: private
version: 0.2.*
- name: idf
require: private
version: '>=5.4'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32p4
version: 0.8.0~3
espressif/tinyusb:
component_hash: 214989d502fc168241a4a4f83b097d8ac44a93cd6f1787b4ac10069a8b3bebd3
dependencies:
- name: idf
require: private
version: '>=5.0'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32s2
- esp32s3
- esp32p4
version: 0.15.0~10
espressif/usb_device_uvc:
component_hash: c14907ba235d9c1292de13f64d465ee6ff9483b9509b4e01123ad0774161c0f5
dependencies:
- name: idf
require: private
version: '>=5.0'
- name: espressif/cmake_utilities
registry_url: https://components.espressif.com
require: private
version: '*'
- name: espressif/tinyusb
registry_url: https://components.espressif.com
require: private
version: '>=0.15.0~10'
source:
registry_url: https://components.espressif.com/
type: service
targets:
- esp32s2
- esp32s3
- esp32p4
version: 1.1.2
idf:
source:
type: idf
version: 5.5.0
direct_dependencies:
- espressif/esp_video
- espressif/tinyusb
- espressif/usb_device_uvc
manifest_hash: 9fb4947fc8d76b823256c2b1c4e3be1949536cea28581179f094368f47f66df8
target: esp32p4
version: 2.0.0
@@ -0,0 +1 @@
idf_component_register(SRCS "uvc_example.c")
@@ -0,0 +1,191 @@
menu "Example Configuration"
choice EXAMPLE_CAM_SENSOR_INTERFACE
prompt "Camera sensor interface"
default EXAMPLE_CAM_SENSOR_MIPI_CSI
help
Select camera sensor interface based on development board.
config EXAMPLE_CAM_SENSOR_MIPI_CSI
bool "MIPI-CSI"
depends on ESP_VIDEO_ENABLE_MIPI_CSI_VIDEO_DEVICE
config EXAMPLE_CAM_SENSOR_DVP
bool "DVP"
depends on ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE
endchoice
if EXAMPLE_CAM_SENSOR_MIPI_CSI
config EXAMPLE_MIPI_CSI_SCCB_I2C_PORT
int "MIPI CSI SCCB I2C Port Number"
default 0
range 0 1
config EXAMPLE_MIPI_CSI_SCCB_I2C_SCL_PIN
int "MIPI CSI SCCB I2C SCL Pin"
default 34
range -1 56
config EXAMPLE_MIPI_CSI_SCCB_I2C_SDA_PIN
int "MIPI CSI SCCB I2C SDA Pin"
default 31
range -1 56
config EXAMPLE_MIPI_CSI_SCCB_I2C_FREQ
int "MIPI CSI SCCB I2C Frequency"
default 100000
range 100000 400000
help
Increasing this value can reduce the initialization time of the camera sensor.
Please refer to the relevant instructions of the camera sensor to adjust the value.
config EXAMPLE_MIPI_CSI_CAM_SENSOR_RESET_PIN
int "MIPI CSI Camera Sensor Reset Pin"
default -1
range -1 56
config EXAMPLE_MIPI_CSI_CAM_SENSOR_PWDN_PIN
int "MIPI CSI Camera Sensor Power Down Pin"
default -1
range -1 56
endif
if EXAMPLE_CAM_SENSOR_DVP
config EXAMPLE_DVP_SCCB_I2C_PORT
int "DVP SCCB I2C Port Number"
default 1
range 0 1
config EXAMPLE_DVP_SCCB_I2C_SCL_PIN
int "DVP SCCB I2C SCL Pin"
default 33
range -1 56
config EXAMPLE_DVP_SCCB_I2C_SDA_PIN
int "DVP SCCB I2C SDA Pin"
default 32
range -1 56
config EXAMPLE_DVP_SCCB_I2C_FREQ
int "DVP SCCB I2C Frequency"
default 100000
range 100000 400000
help
Increasing this value can reduce the initialization time of the camera sensor.
Please refer to the relevant instructions of the camera sensor to adjust the value.
config EXAMPLE_DVP_CAM_SENSOR_RESET_PIN
int "DVP Camera Sensor Reset Pin"
default -1
range -1 56
config EXAMPLE_DVP_CAM_SENSOR_PWDN_PIN
int "DVP Camera Sensor Power Down Pin"
default -1
range -1 56
config EXAMPLE_DVP_XCLK_FREQ
int "DVP XCLK Frequency"
default 20000000
config EXAMPLE_DVP_XCLK_PIN
int "DVP XCLK Pin"
range 0 56
default 20
config EXAMPLE_DVP_PCLK_PIN
int "DVP PCLK Pin"
range 0 56
default 21
config EXAMPLE_DVP_VSYNC_PIN
int "DVP VSYNC Pin"
range 0 56
default 23
config EXAMPLE_DVP_DE_PIN
int "DVP DE Pin"
range 0 56
default 22
config EXAMPLE_DVP_D0_PIN
int "DVP D0 Pin"
range 0 56
default 53
config EXAMPLE_DVP_D1_PIN
int "DVP D1 Pin"
range 0 56
default 54
config EXAMPLE_DVP_D2_PIN
int "DVP D2 Pin"
range 0 56
default 52
config EXAMPLE_DVP_D3_PIN
int "DVP D3 Pin"
range 0 56
default 1
config EXAMPLE_DVP_D4_PIN
int "DVP D4 Pin"
range 0 56
default 0
config EXAMPLE_DVP_D5_PIN
int "DVP D5 Pin"
range 0 56
default 45
config EXAMPLE_DVP_D6_PIN
int "DVP D6 Pin"
range 0 56
default 46
config EXAMPLE_DVP_D7_PIN
int "DVP D7 Pin"
range 0 56
default 47
endif
if FORMAT_MJPEG_CAM1
config EXAMPLE_JPEG_COMPRESSION_QUALITY
int "JPEG Compression Quality"
default 80
range 1 100
help
JPEG compression quality, higher value means higher output
image quality.
endif
if FORMAT_H264_CAM1
config EXAMPLE_H264_I_PERIOD
int "H.264 Intra Frame period"
default 120
range 1 120
help
H.264 I-Frame period.
config EXAMPLE_H264_BITRATE
int "H.264 Bitrate"
default 1000000
range 25000 2500000
help
H.264 bitrate.
config EXAMPLE_H264_MIN_QP
int "H.264 Minimum Quality"
default 25
range 1 51
help
H.264 minimum quality, the value should be less than H.264 maximum quality.
config EXAMPLE_H264_MAX_QP
int "H.264 Maximum Quality"
default 26
range 1 51
help
H.264 maximum quality, the value should be larger than H.264 minimum quality.
endif
endmenu
@@ -0,0 +1,7 @@
dependencies:
esp_video:
version: "0.8.*"
usb_device_uvc:
version: "1.1.*"
espressif/tinyusb:
version: "0.15.0~10"
@@ -0,0 +1,481 @@
/*
* SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: ESPRESSIF MIT
*/
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/param.h>
#include <sys/errno.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_timer.h"
#include "linux/videodev2.h"
#include "esp_video_init.h"
#include "esp_video_device.h"
#include "usb_device_uvc.h"
#include "uvc_frame_config.h"
#if CONFIG_EXAMPLE_CAM_SENSOR_MIPI_CSI
#define CAM_DEV_PATH ESP_VIDEO_MIPI_CSI_DEVICE_NAME
#elif CONFIG_EXAMPLE_CAM_SENSOR_DVP
#define CAM_DEV_PATH ESP_VIDEO_DVP_DEVICE_NAME
#endif
#if CONFIG_FORMAT_MJPEG_CAM1
#define ENCODE_DEV_PATH ESP_VIDEO_JPEG_DEVICE_NAME
#define UVC_OUTPUT_FORMAT V4L2_PIX_FMT_JPEG
#elif CONFIG_FORMAT_H264_CAM1
#if CONFIG_EXAMPLE_H264_MAX_QP <= CONFIG_EXAMPLE_H264_MIN_QP
#error "CONFIG_EXAMPLE_H264_MAX_QP should larger than CONFIG_EXAMPLE_H264_MIN_QP"
#endif
#define ENCODE_DEV_PATH ESP_VIDEO_H264_DEVICE_NAME
#define UVC_OUTPUT_FORMAT V4L2_PIX_FMT_H264
#endif
#define BUFFER_COUNT 2
typedef struct uvc {
int cap_fd;
uint32_t format;
uint8_t *cap_buffer[BUFFER_COUNT];
int m2m_fd;
uint8_t *m2m_cap_buffer;
uvc_fb_t fb;
} uvc_t;
static const char *TAG = "example";
#if CONFIG_EXAMPLE_CAM_SENSOR_MIPI_CSI
static const esp_video_init_csi_config_t csi_config[] = {
{
.sccb_config = {
.init_sccb = true,
.i2c_config = {
.port = CONFIG_EXAMPLE_MIPI_CSI_SCCB_I2C_PORT,
.scl_pin = CONFIG_EXAMPLE_MIPI_CSI_SCCB_I2C_SCL_PIN,
.sda_pin = CONFIG_EXAMPLE_MIPI_CSI_SCCB_I2C_SDA_PIN,
},
.freq = CONFIG_EXAMPLE_MIPI_CSI_SCCB_I2C_FREQ,
},
.reset_pin = CONFIG_EXAMPLE_MIPI_CSI_CAM_SENSOR_RESET_PIN,
.pwdn_pin = CONFIG_EXAMPLE_MIPI_CSI_CAM_SENSOR_PWDN_PIN,
},
};
#endif
#if CONFIG_EXAMPLE_CAM_SENSOR_DVP
static const esp_video_init_dvp_config_t dvp_config[] = {
{
.sccb_config = {
.init_sccb = true,
.i2c_config = {
.port = CONFIG_EXAMPLE_DVP_SCCB_I2C_PORT,
.scl_pin = CONFIG_EXAMPLE_DVP_SCCB_I2C_SCL_PIN,
.sda_pin = CONFIG_EXAMPLE_DVP_SCCB_I2C_SDA_PIN,
},
.freq = CONFIG_EXAMPLE_DVP_SCCB_I2C_FREQ,
},
.reset_pin = CONFIG_EXAMPLE_DVP_CAM_SENSOR_RESET_PIN,
.pwdn_pin = CONFIG_EXAMPLE_DVP_CAM_SENSOR_PWDN_PIN,
.dvp_pin = {
.data_width = CAM_CTLR_DATA_WIDTH_8,
.data_io = {
CONFIG_EXAMPLE_DVP_D0_PIN, CONFIG_EXAMPLE_DVP_D1_PIN, CONFIG_EXAMPLE_DVP_D2_PIN, CONFIG_EXAMPLE_DVP_D3_PIN,
CONFIG_EXAMPLE_DVP_D4_PIN, CONFIG_EXAMPLE_DVP_D5_PIN, CONFIG_EXAMPLE_DVP_D6_PIN, CONFIG_EXAMPLE_DVP_D7_PIN,
},
.vsync_io = CONFIG_EXAMPLE_DVP_VSYNC_PIN,
.de_io = CONFIG_EXAMPLE_DVP_DE_PIN,
.pclk_io = CONFIG_EXAMPLE_DVP_PCLK_PIN,
.xclk_io = CONFIG_EXAMPLE_DVP_XCLK_PIN,
},
.xclk_freq = CONFIG_EXAMPLE_DVP_XCLK_FREQ,
},
};
#endif
static const esp_video_init_config_t cam_config = {
#if CONFIG_EXAMPLE_CAM_SENSOR_MIPI_CSI
.csi = csi_config,
#endif
#if CONFIG_EXAMPLE_CAM_SENSOR_DVP
.dvp = dvp_config,
#endif
};
static void print_video_device_info(const struct v4l2_capability *capability)
{
ESP_LOGI(TAG, "version: %d.%d.%d", (uint16_t)(capability->version >> 16),
(uint8_t)(capability->version >> 8),
(uint8_t)capability->version);
ESP_LOGI(TAG, "driver: %s", capability->driver);
ESP_LOGI(TAG, "card: %s", capability->card);
ESP_LOGI(TAG, "bus: %s", capability->bus_info);
ESP_LOGI(TAG, "capabilities:");
if (capability->capabilities & V4L2_CAP_VIDEO_CAPTURE) {
ESP_LOGI(TAG, "\tVIDEO_CAPTURE");
}
if (capability->capabilities & V4L2_CAP_READWRITE) {
ESP_LOGI(TAG, "\tREADWRITE");
}
if (capability->capabilities & V4L2_CAP_ASYNCIO) {
ESP_LOGI(TAG, "\tASYNCIO");
}
if (capability->capabilities & V4L2_CAP_STREAMING) {
ESP_LOGI(TAG, "\tSTREAMING");
}
if (capability->capabilities & V4L2_CAP_META_OUTPUT) {
ESP_LOGI(TAG, "\tMETA_OUTPUT");
}
if (capability->capabilities & V4L2_CAP_DEVICE_CAPS) {
ESP_LOGI(TAG, "device capabilities:");
if (capability->device_caps & V4L2_CAP_VIDEO_CAPTURE) {
ESP_LOGI(TAG, "\tVIDEO_CAPTURE");
}
if (capability->device_caps & V4L2_CAP_READWRITE) {
ESP_LOGI(TAG, "\tREADWRITE");
}
if (capability->device_caps & V4L2_CAP_ASYNCIO) {
ESP_LOGI(TAG, "\tASYNCIO");
}
if (capability->device_caps & V4L2_CAP_STREAMING) {
ESP_LOGI(TAG, "\tSTREAMING");
}
if (capability->device_caps & V4L2_CAP_META_OUTPUT) {
ESP_LOGI(TAG, "\tMETA_OUTPUT");
}
}
}
static esp_err_t init_capture_video(uvc_t *uvc)
{
int fd;
struct v4l2_capability capability;
fd = open(CAM_DEV_PATH, O_RDONLY);
assert(fd >= 0);
ESP_ERROR_CHECK(ioctl(fd, VIDIOC_QUERYCAP, &capability));
print_video_device_info(&capability);
uvc->cap_fd = fd;
return 0;
}
static esp_err_t init_codec_video(uvc_t *uvc)
{
int fd;
const char *devpath = ENCODE_DEV_PATH;
struct v4l2_capability capability;
struct v4l2_ext_controls controls;
struct v4l2_ext_control control[1];
fd = open(devpath, O_RDONLY);
assert(fd >= 0);
ESP_ERROR_CHECK(ioctl(fd, VIDIOC_QUERYCAP, &capability));
print_video_device_info(&capability);
#if CONFIG_FORMAT_MJPEG_CAM1
controls.ctrl_class = V4L2_CID_JPEG_CLASS;
controls.count = 1;
controls.controls = control;
control[0].id = V4L2_CID_JPEG_COMPRESSION_QUALITY;
control[0].value = CONFIG_EXAMPLE_JPEG_COMPRESSION_QUALITY;
if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &controls) != 0) {
ESP_LOGW(TAG, "failed to set JPEG compression quality");
}
#elif CONFIG_FORMAT_H264_CAM1
controls.ctrl_class = V4L2_CID_CODEC_CLASS;
controls.count = 1;
controls.controls = control;
control[0].id = V4L2_CID_MPEG_VIDEO_H264_I_PERIOD;
control[0].value = CONFIG_EXAMPLE_H264_I_PERIOD;
if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &controls) != 0) {
ESP_LOGW(TAG, "failed to set H.264 intra frame period");
}
controls.ctrl_class = V4L2_CID_CODEC_CLASS;
controls.count = 1;
controls.controls = control;
control[0].id = V4L2_CID_MPEG_VIDEO_BITRATE;
control[0].value = CONFIG_EXAMPLE_H264_BITRATE;
if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &controls) != 0) {
ESP_LOGW(TAG, "failed to set H.264 bitrate");
}
controls.ctrl_class = V4L2_CID_CODEC_CLASS;
controls.count = 1;
controls.controls = control;
control[0].id = V4L2_CID_MPEG_VIDEO_H264_MIN_QP;
control[0].value = CONFIG_EXAMPLE_H264_MIN_QP;
if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &controls) != 0) {
ESP_LOGW(TAG, "failed to set H.264 minimum quality");
}
controls.ctrl_class = V4L2_CID_CODEC_CLASS;
controls.count = 1;
controls.controls = control;
control[0].id = V4L2_CID_MPEG_VIDEO_H264_MAX_QP;
control[0].value = CONFIG_EXAMPLE_H264_MAX_QP;
if (ioctl(fd, VIDIOC_S_EXT_CTRLS, &controls) != 0) {
ESP_LOGW(TAG, "failed to set H.264 maximum quality");
}
#endif
uvc->format = UVC_OUTPUT_FORMAT;
uvc->m2m_fd = fd;
return 0;
}
static esp_err_t video_start_cb(uvc_format_t uvc_format, int width, int height, int rate, void *cb_ctx)
{
int type;
struct v4l2_buffer buf;
struct v4l2_format format;
struct v4l2_requestbuffers req;
uvc_t *uvc = (uvc_t *)cb_ctx;
uint32_t capture_fmt = 0;
ESP_LOGD(TAG, "UVC start");
if (uvc->format == V4L2_PIX_FMT_JPEG) {
int fmt_index = 0;
const uint32_t jpeg_input_formats[] = {
V4L2_PIX_FMT_RGB565,
V4L2_PIX_FMT_YUV422P,
V4L2_PIX_FMT_RGB24,
V4L2_PIX_FMT_GREY
};
int jpeg_input_formats_num = sizeof(jpeg_input_formats) / sizeof(jpeg_input_formats[0]);
while (!capture_fmt) {
struct v4l2_fmtdesc fmtdesc = {
.index = fmt_index++,
.type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
};
if (ioctl(uvc->cap_fd, VIDIOC_ENUM_FMT, &fmtdesc) != 0) {
break;
}
for (int i = 0; i < jpeg_input_formats_num; i++) {
if (jpeg_input_formats[i] == fmtdesc.pixelformat) {
capture_fmt = jpeg_input_formats[i];
break;
}
}
}
if (!capture_fmt) {
ESP_LOGI(TAG, "The camera sensor output pixel format is not supported by JPEG");
return ESP_ERR_NOT_SUPPORTED;
}
} else {
capture_fmt = V4L2_PIX_FMT_YUV420;
}
/* Configure camera interface capture stream */
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = capture_fmt;
ESP_ERROR_CHECK(ioctl(uvc->cap_fd, VIDIOC_S_FMT, &format));
memset(&req, 0, sizeof(req));
req.count = BUFFER_COUNT;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ESP_ERROR_CHECK(ioctl(uvc->cap_fd, VIDIOC_REQBUFS, &req));
for (int i = 0; i < BUFFER_COUNT; i++) {
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = i;
ESP_ERROR_CHECK (ioctl(uvc->cap_fd, VIDIOC_QUERYBUF, &buf));
uvc->cap_buffer[i] = (uint8_t *)mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, uvc->cap_fd, buf.m.offset);
assert(uvc->cap_buffer[i]);
ESP_ERROR_CHECK(ioctl(uvc->cap_fd, VIDIOC_QBUF, &buf));
}
/* Configure codec output stream */
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = capture_fmt;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_S_FMT, &format));
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
req.memory = V4L2_MEMORY_USERPTR;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_REQBUFS, &req));
/* Configure codec capture stream */
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = width;
format.fmt.pix.height = height;
format.fmt.pix.pixelformat = uvc->format;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_S_FMT, &format));
memset(&req, 0, sizeof(req));
req.count = 1;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_REQBUFS, &req));
memset(&buf, 0, sizeof(buf));
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
buf.index = 0;
ESP_ERROR_CHECK (ioctl(uvc->m2m_fd, VIDIOC_QUERYBUF, &buf));
uvc->m2m_cap_buffer = (uint8_t *)mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, uvc->m2m_fd, buf.m.offset);
assert(uvc->m2m_cap_buffer);
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_QBUF, &buf));
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_STREAMON, &type));
type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_STREAMON, &type));
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ESP_ERROR_CHECK(ioctl(uvc->cap_fd, VIDIOC_STREAMON, &type));
return ESP_OK;
}
static void video_stop_cb(void *cb_ctx)
{
int type;
uvc_t *uvc = (uvc_t *)cb_ctx;
ESP_LOGD(TAG, "UVC stop");
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(uvc->cap_fd, VIDIOC_STREAMOFF, &type);
type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
ioctl(uvc->m2m_fd, VIDIOC_STREAMOFF, &type);
type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ioctl(uvc->m2m_fd, VIDIOC_STREAMOFF, &type);
}
static uvc_fb_t *video_fb_get_cb(void *cb_ctx)
{
int64_t us;
uvc_t *uvc = (uvc_t *)cb_ctx;
struct v4l2_format format;
struct v4l2_buffer cap_buf;
struct v4l2_buffer m2m_out_buf;
struct v4l2_buffer m2m_cap_buf;
ESP_LOGD(TAG, "UVC get");
memset(&cap_buf, 0, sizeof(cap_buf));
cap_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
cap_buf.memory = V4L2_MEMORY_MMAP;
ESP_ERROR_CHECK(ioctl(uvc->cap_fd, VIDIOC_DQBUF, &cap_buf));
memset(&m2m_out_buf, 0, sizeof(m2m_out_buf));
m2m_out_buf.index = 0;
m2m_out_buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
m2m_out_buf.memory = V4L2_MEMORY_USERPTR;
m2m_out_buf.m.userptr = (unsigned long)uvc->cap_buffer[cap_buf.index];
m2m_out_buf.length = cap_buf.bytesused;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_QBUF, &m2m_out_buf));
memset(&m2m_cap_buf, 0, sizeof(m2m_cap_buf));
m2m_cap_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
m2m_cap_buf.memory = V4L2_MEMORY_MMAP;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_DQBUF, &m2m_cap_buf));
ESP_ERROR_CHECK(ioctl(uvc->cap_fd, VIDIOC_QBUF, &cap_buf));
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_DQBUF, &m2m_out_buf));
memset(&format, 0, sizeof(format));
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_G_FMT, &format));
uvc->fb.buf = uvc->m2m_cap_buffer;
uvc->fb.len = m2m_cap_buf.bytesused;
uvc->fb.width = format.fmt.pix.width;
uvc->fb.height = format.fmt.pix.height;
uvc->fb.format = format.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG ? UVC_FORMAT_JPEG : UVC_FORMAT_H264;
us = esp_timer_get_time();
uvc->fb.timestamp.tv_sec = us / 1000000UL;;
uvc->fb.timestamp.tv_usec = us % 1000000UL;
return &uvc->fb;
}
static void video_fb_return_cb(uvc_fb_t *fb, void *cb_ctx)
{
struct v4l2_buffer m2m_cap_buf;
uvc_t *uvc = (uvc_t *)cb_ctx;
ESP_LOGD(TAG, "UVC return");
m2m_cap_buf.index = 0;
m2m_cap_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
m2m_cap_buf.memory = V4L2_MEMORY_MMAP;
ESP_ERROR_CHECK(ioctl(uvc->m2m_fd, VIDIOC_QBUF, &m2m_cap_buf));
}
static esp_err_t init_uvc(uvc_t *uvc)
{
int index = 0;
uvc_device_config_t config = {
.start_cb = video_start_cb,
.fb_get_cb = video_fb_get_cb,
.fb_return_cb = video_fb_return_cb,
.stop_cb = video_stop_cb,
.cb_ctx = (void *)uvc,
};
config.uvc_buffer_size = UVC_FRAMES_INFO[index][0].width * UVC_FRAMES_INFO[index][0].height;
config.uvc_buffer = malloc(config.uvc_buffer_size);
assert(config.uvc_buffer);
ESP_LOGI(TAG, "Format List");
ESP_LOGI(TAG, "\tFormat(1) = %s", uvc->format == V4L2_PIX_FMT_JPEG ? "MJPEG" : "H.264");
ESP_LOGI(TAG, "Frame List");
ESP_LOGI(TAG, "\tFrame(1) = %d * %d @%dfps", UVC_FRAMES_INFO[index][0].width, UVC_FRAMES_INFO[index][0].height, UVC_FRAMES_INFO[index][0].rate);
ESP_ERROR_CHECK(uvc_device_config(index, &config));
ESP_ERROR_CHECK(uvc_device_init());
return ESP_OK;
}
void app_main(void)
{
uvc_t *uvc = calloc(1, sizeof(uvc_t));
assert(uvc);
ESP_ERROR_CHECK(esp_video_init(&cam_config));
ESP_ERROR_CHECK(init_capture_video(uvc));
ESP_ERROR_CHECK(init_codec_video(uvc));
ESP_ERROR_CHECK(init_uvc(uvc));
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,24 @@
# This file was generated using idf.py save-defconfig. It can be edited manually.
# Espressif IoT Development Framework (ESP-IDF) 5.5.0 Project Minimal Configuration
#
CONFIG_IDF_TARGET="esp32p4"
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
CONFIG_ESPTOOLPY_FLASHSIZE_16MB=y
CONFIG_EXAMPLE_MIPI_CSI_SCCB_I2C_SCL_PIN=8
CONFIG_EXAMPLE_MIPI_CSI_SCCB_I2C_SDA_PIN=7
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_200M=y
CONFIG_SPIRAM_XIP_FROM_PSRAM=y
CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=3584
CONFIG_ESP_MAIN_TASK_STACK_SIZE=4096
CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=3584
CONFIG_CAMERA_OV5647=y
CONFIG_CAMERA_OV5647_MIPI_RAW10_1920x1080_30FPS=y
CONFIG_ESP_VIDEO_ENABLE_DVP_VIDEO_DEVICE=n
CONFIG_ESP_VIDEO_ENABLE_HW_H264_VIDEO_DEVICE=y
CONFIG_ESP_VIDEO_ENABLE_HW_JPEG_VIDEO_DEVICE=y
CONFIG_FRAMESIZE_FHD=y
CONFIG_UVC_CAM1_FRAMERATE=30
CONFIG_UVC_MULTI_FRAME_WIDTH_1=1280
CONFIG_UVC_MULTI_FRAME_HEIGHT_1=720
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
@@ -0,0 +1,7 @@
CONFIG_CAMERA_SC2336=y
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
CONFIG_SPIRAM=y
CONFIG_SPIRAM_SPEED_200M=y
File diff suppressed because it is too large Load Diff