Files
JC-ESP32P4-M3-DEV/1-Demo/IDF-DEMO/withDisplay/test/main/app_camera.c
T
2025-09-05 18:58:05 +02:00

284 lines
8.8 KiB
C

/*
* 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 "driver/i2c_master.h"
#include "linux/videodev2.h"
#include "esp_video_init.h"
#include "esp_video_ioctl.h"
#include "app_camera.h"
#define MEMORY_TYPE V4L2_MEMORY_MMAP
#define BUFFER_COUNT 2
#define CAPTURE_SECONDS 3
static i2c_master_bus_handle_t i2c_handle = NULL;
static const char *TAG = "example";
#if CONFIG_EXAMPLE_ENABLE_MIPI_CSI_CAM_SENSOR
static 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_ENABLE_DVP_CAM_SENSOR
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 esp_err_t camera_capture_stream(void)
{
int fd;
esp_err_t ret;
int fmt_index = 0;
uint32_t frame_size;
uint32_t frame_count;
struct v4l2_buffer buf;
uint8_t *buffer[BUFFER_COUNT];
struct v4l2_format init_format;
struct v4l2_requestbuffers req;
struct v4l2_capability capability;
const int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fd = open("/dev/video0", O_RDONLY);
if (fd < 0) {
ESP_LOGE(TAG, "failed to open device");
return ESP_FAIL;
}
if (ioctl(fd, VIDIOC_QUERYCAP, &capability)) {
ESP_LOGE(TAG, "failed to get capability");
ret = ESP_FAIL;
goto exit_0;
}
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");
}
}
/* Set custom register configuration */
if (ioctl(fd, VIDIOC_S_SENSOR_FMT, &custom_format_info) != 0) {
ret = ESP_FAIL;
goto exit_0;
}
memset(&init_format, 0, sizeof(struct v4l2_format));
init_format.type = type;
if (ioctl(fd, VIDIOC_G_FMT, &init_format) != 0) {
ESP_LOGE(TAG, "failed to get format");
ret = ESP_FAIL;
goto exit_0;
}
struct v4l2_fmtdesc fmtdesc = {
.index = fmt_index++,
.type = type,
};
ESP_LOGI(TAG, "Capture %s format frames for %d seconds:", (char *)fmtdesc.description, CAPTURE_SECONDS);
memset(&req, 0, sizeof(req));
req.count = BUFFER_COUNT;
req.type = type;
req.memory = MEMORY_TYPE;
if (ioctl(fd, VIDIOC_REQBUFS, &req) != 0) {
ESP_LOGE(TAG, "failed to require buffer");
ret = ESP_FAIL;
goto exit_0;
}
for (int i = 0; i < BUFFER_COUNT; i++) {
struct v4l2_buffer buf;
memset(&buf, 0, sizeof(buf));
buf.type = type;
buf.memory = MEMORY_TYPE;
buf.index = i;
if (ioctl(fd, VIDIOC_QUERYBUF, &buf) != 0) {
ESP_LOGE(TAG, "failed to query buffer");
ret = ESP_FAIL;
goto exit_0;
}
buffer[i] = (uint8_t *)mmap(NULL, buf.length, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, buf.m.offset);
if (!buffer[i]) {
ESP_LOGE(TAG, "failed to map buffer");
ret = ESP_FAIL;
goto exit_0;
}
if (ioctl(fd, VIDIOC_QBUF, &buf) != 0) {
ESP_LOGE(TAG, "failed to queue video frame");
ret = ESP_FAIL;
goto exit_0;
}
}
if (ioctl(fd, VIDIOC_STREAMON, &type) != 0) {
ESP_LOGE(TAG, "failed to start stream");
ret = ESP_FAIL;
goto exit_0;
}
frame_count = 0;
frame_size = 0;
int64_t start_time_us = esp_timer_get_time();
while (esp_timer_get_time() - start_time_us < (CAPTURE_SECONDS * 1000 * 1000)) {
memset(&buf, 0, sizeof(buf));
buf.type = type;
buf.memory = MEMORY_TYPE;
if (ioctl(fd, VIDIOC_DQBUF, &buf) != 0) {
ESP_LOGE(TAG, "failed to receive video frame");
ret = ESP_FAIL;
goto exit_0;
}
frame_size += buf.bytesused;
if (ioctl(fd, VIDIOC_QBUF, &buf) != 0) {
ESP_LOGE(TAG, "failed to queue video frame");
ret = ESP_FAIL;
goto exit_0;
}
frame_count++;
}
if (ioctl(fd, VIDIOC_STREAMOFF, &type) != 0) {
ESP_LOGE(TAG, "failed to stop stream");
ret = ESP_FAIL;
goto exit_0;
}
ESP_LOGI(TAG, "\twidth: %" PRIu32, init_format.fmt.pix.width);
ESP_LOGI(TAG, "\theight: %" PRIu32, init_format.fmt.pix.height);
ESP_LOGI(TAG, "\tsize: %" PRIu32, frame_size / frame_count);
ESP_LOGI(TAG, "\tFPS: %" PRIu32, frame_count / CAPTURE_SECONDS);
// bsp_display_lock(0);
// lv_label_ins_text(label,LV_LABEL_POS_LAST,"Camera initial #00ff00 Success#\n");
// bsp_display_unlock();
ret = ESP_OK;
exit_0:
close(fd);
return ret;
}
void app_camera(void)
{
esp_err_t ret = ESP_OK;
i2c_master_get_bus_handle(1, &i2c_handle);
csi_config[0].sccb_config.init_sccb = false;
csi_config[0].sccb_config.i2c_handle = i2c_handle;
static const esp_video_init_config_t cam_config = {
.csi = csi_config,
};
ret = esp_video_init(&cam_config);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Camera init failed with error 0x%x", ret);
// bsp_display_lock(0);
// lv_label_ins_text(label,LV_LABEL_POS_LAST,"Camera initial #ff0000 Failed#\n");
// bsp_display_unlock();
return;
}
ret = camera_capture_stream();
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Camera capture stream failed with error 0x%x", ret);
return;
}
}