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 @@
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));
}