/* * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: ESPRESSIF MIT */ #include #include #include #include #include #include #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; } }