Feature/add usb camera example
This commit is contained in:
+54
-147
@@ -1,8 +1,8 @@
|
||||
.build_template: &build_template
|
||||
stage: build
|
||||
image: espressif/idf:release-v5.0
|
||||
tags:
|
||||
- build
|
||||
image: ${IMAGE}
|
||||
variables:
|
||||
# Enable ccache for all build jobs. See configure_ci_environment.sh for more ccache related settings.
|
||||
IDF_CCACHE_ENABLE: "1"
|
||||
@@ -31,20 +31,13 @@
|
||||
expire_in: 1 week
|
||||
variables:
|
||||
IDF_CI_BUILD: "1"
|
||||
# By configuring this macro, you can append the compiled configuration file.
|
||||
# For example, using "sdkconf.etc=default" specifies the default sdkconfig file.
|
||||
EXAMPLE_CONFIG: "="
|
||||
script:
|
||||
- pip install --upgrade idf-component-manager
|
||||
- pip install idf_build_apps
|
||||
- python -m idf_build_apps build -vv
|
||||
-p $EXAMPLE_DIR
|
||||
-t all
|
||||
--config "sdkconfig.ci.*="
|
||||
--build-dir build_@t_@w
|
||||
--build-log build_log.txt
|
||||
--size-file size.json
|
||||
--check-warnings
|
||||
--ignore-warning-str "$WARNING_STR"
|
||||
--collect-size-info size_info.txt
|
||||
--default-build-targets $IDF_TARGET
|
||||
- python tools/build_apps.py ${EXAMPLE_DIR} --config ${EXAMPLE_CONFIG} -t esp32s3 -vv
|
||||
|
||||
.build_matter_examples: &build_matter_examples
|
||||
<<: *build_template
|
||||
@@ -87,183 +80,97 @@ build_example_matter_switch_v5.1:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/matter_switch
|
||||
|
||||
build_example_chatgpt_demo_v5.0:
|
||||
build_example_chatgpt_demo:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_chatgpt_demo
|
||||
image: espressif/idf:release-v5.0
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/chatgpt_demo
|
||||
|
||||
build_example_chatgpt_demo_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_chatgpt_demo
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/chatgpt_demo
|
||||
|
||||
build_example_factory_demo_v5.0:
|
||||
build_example_factory_demo:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_factory_demo
|
||||
#image: espressif/idf:release-v5.0 don't support release-v5.0 now.
|
||||
image: espressif/idf:release-v5.1
|
||||
parallel:
|
||||
matrix:
|
||||
#- IMAGE: espressif/idf:release-v5.0 don't support release-v5.0 now.
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/factory_demo
|
||||
|
||||
build_example_factory_demo_v5.1:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_factory_demo
|
||||
image: espressif/idf:release-v5.1
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/factory_demo
|
||||
|
||||
build_example_factory_demo_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_factory_demo
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/factory_demo
|
||||
|
||||
build_example_image_display_v5.0:
|
||||
build_example_image_display:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_image_display
|
||||
image: espressif/idf:release-v5.0
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/image_display
|
||||
|
||||
build_example_image_display_v5.1:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_image_display
|
||||
image: espressif/idf:release-v5.1
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/image_display
|
||||
|
||||
build_example_image_display_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_image_display
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/image_display
|
||||
|
||||
build_example_lv_demos_v5.0:
|
||||
build_example_lv_demos:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_lv_demos
|
||||
image: espressif/idf:release-v5.0
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/lv_demos
|
||||
|
||||
build_example_lv_demos_v5.1:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_lv_demos
|
||||
image: espressif/idf:release-v5.1
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/lv_demos
|
||||
|
||||
build_example_lv_demos_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_lv_demos
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/lv_demos
|
||||
|
||||
build_example_mp3_demo_v5.0:
|
||||
build_example_mp3_demo:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_mp3_demo
|
||||
image: espressif/idf:release-v5.0
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/mp3_demo
|
||||
|
||||
build_example_mp3_demo_v5.1:
|
||||
build_example_usb_camera_lcd_display:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_mp3_demo
|
||||
image: espressif/idf:release-v5.1
|
||||
- .rules:build:example_usb_camera_lcd_display
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/mp3_demo
|
||||
EXAMPLE_DIR: examples/usb_camera_lcd_display
|
||||
|
||||
build_example_mp3_demo_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_mp3_demo
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/mp3_demo
|
||||
|
||||
build_example_usb_headset_v5.0:
|
||||
build_example_usb_headset:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_usb_headset
|
||||
image: espressif/idf:release-v5.0
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/usb_headset
|
||||
|
||||
build_example_usb_headset_v5.1:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_usb_headset
|
||||
image: espressif/idf:release-v5.1
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/usb_headset
|
||||
|
||||
build_example_usb_headset_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_usb_headset
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/usb_headset
|
||||
|
||||
build_example_watering_demo_v5.0:
|
||||
build_example_watering_demo:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_watering_demo
|
||||
image: espressif/idf:release-v5.0
|
||||
parallel:
|
||||
matrix:
|
||||
- IMAGE: espressif/idf:release-v5.0
|
||||
- IMAGE: espressif/idf:release-v5.1
|
||||
- IMAGE: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/watering_demo
|
||||
|
||||
build_example_watering_demo_v5.1:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_watering_demo
|
||||
image: espressif/idf:release-v5.1
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/watering_demo
|
||||
|
||||
build_example_watering_demo_latest:
|
||||
extends:
|
||||
- .build_examples_template
|
||||
- .rules:build:example_watering_demo
|
||||
image: espressif/idf:latest
|
||||
variables:
|
||||
IDF_TARGET: esp32s3
|
||||
EXAMPLE_DIR: examples/watering_demo
|
||||
@@ -25,6 +25,9 @@
|
||||
.patterns-example_mp3_demo: &patterns-example_mp3_demo
|
||||
- "examples/mp3_demo/**/*"
|
||||
|
||||
.patterns-example_usb_camera_lcd_display: &patterns-example_usb_camera_lcd_display
|
||||
- "examples/usb_camera_lcd_display/**/*"
|
||||
|
||||
.patterns-example_usb_headset: &patterns-example_usb_headset
|
||||
- "examples/usb_headset/**/*"
|
||||
|
||||
@@ -101,6 +104,15 @@
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_mp3_demo
|
||||
|
||||
.rules:build:example_usb_camera_lcd_display:
|
||||
rules:
|
||||
- <<: *if-protected
|
||||
- <<: *if-label-build
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-components_bsp
|
||||
- <<: *if-dev-push
|
||||
changes: *patterns-example_usb_camera_lcd_display
|
||||
|
||||
.rules:build:example_usb_headset:
|
||||
rules:
|
||||
- <<: *if-protected
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
# 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.5)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(usb_camera_lcd_display)
|
||||
@@ -0,0 +1,54 @@
|
||||
## USB Stream LCD Display Example
|
||||
|
||||
| Board | Support Status |
|
||||
| ----------------- | -------------- |
|
||||
| ESP32-S3-BOX | NO |
|
||||
| ESP32-S3-BOX-Lite | NO |
|
||||
| ESP32-S3-BOX-3 | YES |
|
||||
|
||||
This routine demonstrates how to use the [usb_stream](https://components.espressif.com/components/espressif/usb_stream) component to acquire a USB camera image and display it adaptively on the LCD screen.
|
||||
|
||||
* Pressing the boot button can switch the display resolution.
|
||||
* For better performance, please use ESP-IDF release/v5.0 or above versions.
|
||||
* Currently only images with a resolution smaller than the screen resolution are displayed
|
||||
* When the image width is equal to the screen width, the refresh rate is at its highest.
|
||||
|
||||
## Hardware
|
||||
|
||||
* An ESP32-S3-BOX-3 development board with 320*240 LCD.
|
||||
* A [USB camera](https://docs.espressif.com/projects/espressif-esp-iot-solution/zh_CN/latest/usb/usb_stream.html#id1) (Can be connected to USB port or Expansion Connector).
|
||||
* An USB Type-C cable for Power supply and programming (Please connect to UART port instead of USB port)
|
||||
|
||||
Note:
|
||||
Error message with `A fatal error occurred: Could not open /dev/ttyACM0, the port doesn't exist`: Please first make sure development board connected, then make board into "Download Boot" mode to upload by following steps:
|
||||
1. keep pressing "BOOT(SW2)" button
|
||||
2. short press "RST(SW1)" button
|
||||
3. release "BOOT(SW2)".
|
||||
4. upload program and reset
|
||||
|
||||
## PSRAM 120M DDR
|
||||
|
||||
The PSRAM 120M DDR feature is intended to achieve the best performance of RGB LCD. It is only available with ESP-IDF **release/v5.1** and above. It can be used by enabling the `IDF_EXPERIMENTAL_FEATURES`, `SPIRAM_SPEED_120M`, `SPIRAM_MODE_OCT` options. see [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/flash_psram_config.html#all-supported-modes-and-speeds) for more details.
|
||||
|
||||
**Note: The PSRAM 120 MHz DDR is an experimental feature and it has temperature risks as below.**
|
||||
* Cannot guarantee normal functioning with a temperature higher than 65 degrees Celsius.
|
||||
* Temperature changes can also cause the crash of accessing to PSRAM/Flash, see [here](https://docs.espressif.com/projects/esp-idf/en/latest/esp32s3/api-guides/flash_psram_config.html#all-supported-modes-and-speeds) for more details.
|
||||
|
||||
### How To Use
|
||||
|
||||
Note:
|
||||
|
||||
1. First delete existing `build`, `sdkconfig` , `sdkconfig.old`
|
||||
```
|
||||
rm -rf build sdkconfig sdkconfig.old
|
||||
```
|
||||
|
||||
2. Use the command line to enable the relevant configuration
|
||||
```
|
||||
idf.py -D SDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.psram_octal_120m" reconfigure
|
||||
```
|
||||
|
||||
3. Compile and burn
|
||||
```
|
||||
idf.py build flash monitor
|
||||
```
|
||||
@@ -0,0 +1,7 @@
|
||||
idf_component_register(
|
||||
SRCS "src/audio_malloc.c"
|
||||
INCLUDE_DIRS "include"
|
||||
)
|
||||
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/libs/${CONFIG_IDF_TARGET}/libesp_codec.a")
|
||||
target_link_libraries(${COMPONENT_LIB} INTERFACE "-u audio_free -u audio_calloc_inner -u audio_calloc")
|
||||
@@ -0,0 +1,120 @@
|
||||
// Copyright 2022 Espressif Systems (Shanghai) CO., LTD
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "stdint.h"
|
||||
|
||||
/* Error code */
|
||||
typedef enum {
|
||||
JPEG_ERR_OK = 0, /* Succeeded */
|
||||
JPEG_ERR_FAIL = -1, /* Device error or wrong termination of input stream */
|
||||
JPEG_ERR_MEM = -2, /* Insufficient memory pool for the image */
|
||||
JPEG_ERR_NO_MORE_DATA = -3, /* Input data is not enough */
|
||||
JPEG_ERR_PAR = -4, /* Parameter error */
|
||||
JPEG_ERR_FMT1 = -5, /* Data format error (may be damaged data) */
|
||||
JPEG_ERR_FMT2 = -6, /* Right format but not supported */
|
||||
JPEG_ERR_FMT3 = -7 /* Not supported JPEG standard */
|
||||
} jpeg_error_t;
|
||||
|
||||
/* Jpeg raw data type.
|
||||
* raw data ---> encoder ---> encoded data ---> transmit ---> decoder ---> raw data
|
||||
*/
|
||||
typedef enum {
|
||||
JPEG_RAW_TYPE_GRAY = 0, /*!< Grayscale. encoder supported. decoder un-supported.*/
|
||||
JPEG_RAW_TYPE_RGB888 = 1, /*!< RGB888. encoder supported. decoder supported. */
|
||||
JPEG_RAW_TYPE_RGBA = 2, /*!< RGBA. encoder supported. decoder un-supported.*/
|
||||
JPEG_RAW_TYPE_YCbYCr = 3, /*!< Y422. encoder supported. decoder un-supported.*/
|
||||
JPEG_RAW_TYPE_YCbY2YCrY2 = 4, /*!< Y420. encoder supported. decoder un-supported.*/
|
||||
JPEG_RAW_TYPE_RGB565_BE = 5, /*!< RGB565. The data is big end. encoder un-supported. decoder supported. */
|
||||
JPEG_RAW_TYPE_RGB565_LE = 6, /*!< RGB565. The data is little end. encoder un-supported. decoder supported.*/
|
||||
} jpeg_raw_type_t;
|
||||
|
||||
/* JPEG chroma subsampling factors */
|
||||
typedef enum {
|
||||
JPEG_SUB_SAMPLE_Y = 0, /*!< Grayscale */
|
||||
JPEG_SUB_SAMPLE_YUV444 = 1, /*!< data order:YUV 1x1x1 3 pixel per MCU Y444*/
|
||||
JPEG_SUB_SAMPLE_YUV422 = 2, /*!< data order:YUYV 2x1x1 2 pixel per MCU Y422*/
|
||||
JPEG_SUB_SAMPLE_YUV420 = 3 /*!< data order:YUY2YVY2 4x1x1 1.25 pixel per MCU Y420)*/
|
||||
} jpeg_subsampling_t;
|
||||
|
||||
typedef enum {
|
||||
JPEG_ROTATE_0D = 0, /*!< Source image rotates clockwise 0 degree before encoding */
|
||||
JPEG_ROTATE_90D = 1, /*!< Source image rotates clockwise 90 degree before encoding */
|
||||
JPEG_ROTATE_180D = 2, /*!< Source image rotates clockwise 180 degree before encoding */
|
||||
JPEG_ROTATE_270D = 3, /*!< Source image rotates clockwise 270 degree before encoding */
|
||||
} jpeg_rotate_t;
|
||||
|
||||
/**
|
||||
* @brief Convert YUV to RGB
|
||||
*
|
||||
* @param[in] sub_sample chroma subsampling factors. Grayscale is un-supported. The others are supported.
|
||||
* @param[in] raw_type raw data type. RGB888 and RGB565 are supported. The others are un-supported.
|
||||
* @param[in] yuv_image input YUV image data. The buffer must be aligned 16 byte.
|
||||
* @param[in] width image width
|
||||
* @param[in] height image height
|
||||
* @param[out] rgb_image output RGB image data
|
||||
*
|
||||
* @return jpeg_error_t
|
||||
* - JPEG_ERR_OK: on success
|
||||
* - Others: error occurs
|
||||
*/
|
||||
jpeg_error_t jpeg_yuv2rgb(jpeg_subsampling_t sub_sample, jpeg_raw_type_t raw_type, uint8_t *yuv_image, int width, int height, uint8_t *rgb_image);
|
||||
|
||||
/**
|
||||
* @brief Allocated buffer. And the buffer address will be aligned.
|
||||
*
|
||||
* @param[in] size Allocate buffer size.
|
||||
* @param[in] aligned Aligned byte
|
||||
*
|
||||
* @return positive: Allocate buffer address
|
||||
* NULL: failed
|
||||
*/
|
||||
void *jpeg_malloc_align(int size, int aligned);
|
||||
|
||||
/**
|
||||
* @brief Free buffer. The buffer address come from `jpeg_malloc_align`
|
||||
*
|
||||
* @param[in] data The buffer address.
|
||||
*
|
||||
*/
|
||||
void jpeg_free_align(void *data);
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
* @code{c}
|
||||
*
|
||||
* void* yu2_rgb_demo()
|
||||
* {
|
||||
* // allocate memory
|
||||
* int width = 320;
|
||||
* int height = 240;
|
||||
* int yuv_pixel = 3; //JPEG_SUB_SAMPLE_YUV444:3 JPEG_SUB_SAMPLE_YUV422:2 JPEG_SUB_SAMPLE_YUV420:1.5
|
||||
* int yuv_image_size = width * height * yuv_pixel;
|
||||
* uint8_t* yuv_image = (uint8_t*)calloc(1, yuv_image_size);
|
||||
* if(yuv_image == NULL) {
|
||||
* return;
|
||||
* }
|
||||
* int rgb_pixel = 3; // JPEG_RAW_TYPE_RGB888:3 JPEG_RAW_TYPE_RGB565_LE/JPEG_RAW_TYPE_RGB565_BE:2
|
||||
* int rgb_image_size = width * height * rgb_pixel;
|
||||
* uint8_t* rgb_image = (uint8_t*)jpeg_malloc_align(rgb_image_size, 16);
|
||||
* if(rgb_image == NULL) {
|
||||
* return;
|
||||
* }
|
||||
* // read yuv data
|
||||
* memset(yuv_image, 128, yuv_image_size)
|
||||
* for (int i= 0; i< yuv_image_size; i+=3) {
|
||||
* yuv_image[i] = i / 3;
|
||||
* }
|
||||
* // convert
|
||||
* jpeg_error_t ret = jpeg_yuv2rgb(JPEG_SUB_SAMPLE_YUV444, JPEG_RAW_TYPE_RGB888, yuv_image, width, height, rgb_image);
|
||||
* // print rgb data
|
||||
* for (int i= 0; i< rgb_image_size; i++) {
|
||||
* printf("%x ", rgb_image[i]&0xff);
|
||||
* }
|
||||
* jpeg_free_align(rgb_image);
|
||||
* free(yuv_image);
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*/
|
||||
@@ -0,0 +1,195 @@
|
||||
// Copyright 2021 Espressif Systems (Shanghai) CO., LTD
|
||||
// All rights reserved.
|
||||
|
||||
#ifndef ESP_JPEG_DEC_H
|
||||
#define ESP_JPEG_DEC_H
|
||||
|
||||
/**
|
||||
* @file esp_jpeg_dec.h
|
||||
* @brief Create an JPEG decoder.
|
||||
* Currently, support functions as follows:
|
||||
* - Support variety of width and height to decoder
|
||||
* - Support RGB888 RGB565(big end) RGB565(little end) raw data to output
|
||||
* - Support 0, 90 180 270 degree clockwise rotation, under width and height are multiply of 8.
|
||||
* The encoder do ASM optimization in ESP32S3. The encoder frame rate performs better than the others chips.
|
||||
* @version 1.0.0
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "esp_jpeg_common.h"
|
||||
|
||||
#define DEFAULT_JPEG_DEC_CONFIG() { \
|
||||
.output_type = JPEG_RAW_TYPE_RGB565_LE, \
|
||||
.rotate = JPEG_ROTATE_0D, \
|
||||
}
|
||||
|
||||
#define JPEG_DEC_MAX_MARKER_CHECK_LEN (1024)
|
||||
|
||||
typedef void* jpeg_dec_handle_t;
|
||||
|
||||
/* Jpeg dec user need to config */
|
||||
typedef struct {
|
||||
jpeg_raw_type_t output_type; /*!< jpeg_dec_out_type 1:rgb888 0:rgb565 */
|
||||
jpeg_rotate_t rotate; /*!< Supports 0, 90 180 270 degree clockwise rotation.
|
||||
Under width % 8 == 0. height % 8 = 0 conditions, rotation enabled. Otherwise unsupported */
|
||||
} jpeg_dec_config_t;
|
||||
|
||||
/* Jpeg dec out info */
|
||||
typedef struct {
|
||||
int width; /* Number of pixels in the horizontal direction */
|
||||
int height; /* Number of pixels in the vertical direction */
|
||||
int component_num; /* Number of color component*/
|
||||
uint8_t component_id[3]; /* ID of color component*/
|
||||
uint8_t x_factory[3]; /* Size factory in the x direction*/
|
||||
uint8_t y_factory[3]; /* Size factory in the y direction*/
|
||||
uint8_t huffbits[2][2][16]; /* Huffman bit distribution tables [id][dcac] */
|
||||
uint16_t huffdata[2][2][256]; /* Huffman decoded data tables [id][dcac] */
|
||||
uint8_t qtid[3]; /* Quantization table ID of each component */
|
||||
int16_t qt_tbl[4][64]; /* De-quantizer tables [id] */
|
||||
} jpeg_dec_header_info_t;
|
||||
|
||||
/* Jpeg dec io control */
|
||||
typedef struct {
|
||||
unsigned char *inbuf; /* The input buffer pointer */
|
||||
int inbuf_len; /* The number of the input buffer */
|
||||
int inbuf_remain; /* Not used number of the in buffer */
|
||||
unsigned char *outbuf; /* The decoded data is placed.The buffer must be aligned 16 byte. */
|
||||
} jpeg_dec_io_t;
|
||||
|
||||
/**
|
||||
* @brief Create a Jpeg decode handle, set user config info to decode handle
|
||||
*
|
||||
* @param[in] config The configuration information
|
||||
*
|
||||
* @return other values: The JPEG decoder handle
|
||||
* NULL: failed
|
||||
*/
|
||||
jpeg_dec_handle_t *jpeg_dec_open(jpeg_dec_config_t *config);
|
||||
|
||||
/**
|
||||
* @brief Parse picture data header, and out put info to user
|
||||
*
|
||||
* @param[in] jpeg_dec jpeg decoder handle
|
||||
*
|
||||
* @param[in] io struct of jpeg_dec_io_t
|
||||
*
|
||||
* @param[out] out_info output info struct to user
|
||||
*
|
||||
* @return jpeg_error_t
|
||||
* - JPEG_ERR_OK: on success
|
||||
* - Others: error occurs
|
||||
*/
|
||||
jpeg_error_t jpeg_dec_parse_header(jpeg_dec_handle_t *jpeg_dec, jpeg_dec_io_t *io, jpeg_dec_header_info_t *out_info);
|
||||
|
||||
/**
|
||||
* @brief Decode one Jpeg picture
|
||||
*
|
||||
* @param[in] jpeg_dec jpeg decoder handle
|
||||
*
|
||||
* @param[in] io struct of jpeg_dec_io_t
|
||||
*
|
||||
* @return jpeg_error_t
|
||||
* - JPEG_ERR_OK: on success
|
||||
* - Others: error occurs
|
||||
*/
|
||||
jpeg_error_t jpeg_dec_process(jpeg_dec_handle_t *jpeg_dec, jpeg_dec_io_t *io);
|
||||
|
||||
/**
|
||||
* @brief Deinitialize Jpeg decode handle
|
||||
*
|
||||
* @param[in] jpeg_dec jpeg decoder handle
|
||||
*
|
||||
* @return jpeg_error_t
|
||||
* - JPEG_ERR_OK: on success
|
||||
* - Others: error occurs
|
||||
*/
|
||||
jpeg_error_t jpeg_dec_close(jpeg_dec_handle_t *jpeg_dec);
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
* @code{c}
|
||||
*
|
||||
* // Function for decode one jpeg picture
|
||||
* // input_buf input picture data
|
||||
* // len input picture data length
|
||||
* int esp_jpeg_decoder_one_picture(unsigned char *input_buf, int len, unsigned char **output_buf)
|
||||
* {
|
||||
* // Generate default configuration
|
||||
* jpeg_dec_config_t config = DEFAULT_JPEG_DEC_CONFIG();
|
||||
*
|
||||
* // Empty handle to jpeg_decoder
|
||||
* jpeg_dec_handle_t jpeg_dec = NULL;
|
||||
*
|
||||
* // Create jpeg_dec
|
||||
* jpeg_dec = jpeg_dec_open(&config);
|
||||
*
|
||||
* // Create io_callback handle
|
||||
* jpeg_dec_io_t *jpeg_io = calloc(1, sizeof(jpeg_dec_io_t));
|
||||
* if (jpeg_io == NULL) {
|
||||
* return ESP_FAIL;
|
||||
* }
|
||||
*
|
||||
* // Create out_info handle
|
||||
* jpeg_dec_header_info_t *out_info = calloc(1, sizeof(jpeg_dec_header_info_t));
|
||||
* if (out_info == NULL) {
|
||||
* return ESP_FAIL;
|
||||
* }
|
||||
*
|
||||
* // Set input buffer and buffer len to io_callback
|
||||
* jpeg_io->inbuf = input_buf;
|
||||
* jpeg_io->inbuf_len = len;
|
||||
*
|
||||
* int ret = 0;
|
||||
* // Parse jpeg picture header and get picture for user and decoder
|
||||
* ret = jpeg_dec_parse_header(jpeg_dec, jpeg_io, out_info);
|
||||
* if (ret < 0) {
|
||||
* return ret;
|
||||
* }
|
||||
*
|
||||
* // Calloc out_put data buffer and update inbuf ptr and inbuf_len
|
||||
* int outbuf_len;
|
||||
* if (config.output_type == JPEG_RAW_TYPE_RGB565_LE
|
||||
* || config.output_type == JPEG_RAW_TYPE_RGB565_BE) {
|
||||
* outbuf_len = out_info->width * out_info->height * 2;
|
||||
* } else if (config.output_type == JPEG_RAW_TYPE_RGB888) {
|
||||
* outbuf_len = out_info->width * out_info->height * 3;
|
||||
* } else {
|
||||
* return ESP_FAIL;
|
||||
* }
|
||||
* unsigned char *out_buf = jpeg_malloc_align(outbuf_len, 16);
|
||||
* if (out_buf == NULL) {
|
||||
* return ESP_FAIL;
|
||||
* }
|
||||
* jpeg_io->outbuf = out_buf;
|
||||
* *output_buf = out_buf;
|
||||
* int inbuf_consumed = jpeg_io->inbuf_len - jpeg_io->inbuf_remain;
|
||||
* jpeg_io->inbuf = input_buf + inbuf_consumed;
|
||||
* jpeg_io->inbuf_len = jpeg_io->inbuf_remain;
|
||||
*
|
||||
* // Start decode jpeg raw data
|
||||
* ret = jpeg_dec_process(jpeg_dec, jpeg_io);
|
||||
* if (ret < 0) {
|
||||
* return ret;
|
||||
* }
|
||||
*
|
||||
* // Decoder deinitialize
|
||||
* jpeg_free_align(out_buf);
|
||||
* jpeg_dec_close(jpeg_dec);
|
||||
* free(out_info);
|
||||
* free(jpeg_io);
|
||||
* return ESP_OK;
|
||||
* }
|
||||
*
|
||||
* @endcode
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,244 @@
|
||||
// Copyright 2022 Espressif Systems (Shanghai) CO., LTD
|
||||
// All rights reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* @file esp_jpeg_enc.h
|
||||
* @brief Create an JPEG encoder.
|
||||
* Currently, support functions as follows:
|
||||
* - Support variety of width and height to encoder
|
||||
* - Support RGB888 RGBA YCbYCr YCbY2YCrY2 GRAY raw data to encode
|
||||
* - Support sub-sample(YUV444 YUV422 Yuv420)
|
||||
* - Support quality(1-100)
|
||||
* - Support 0, 90 180 270 degree clockwise rotation, under src_type = JPEG_RAW_TYPE_YCbYCr,
|
||||
* subsampling = JPEG_SUB_SAMPLE_YUV420, width and height are multiply of 16 and
|
||||
* src_type = JPEG_RAW_TYPE_YCbYCr, subsampling = JPEG_SUB_SAMPLE_Y, width and height are multiply of 8.
|
||||
* - Support dual-task
|
||||
* - Support two mode encoder, respectively block encoder and one image encoder
|
||||
* The encoder does ASM optimization in ESP32S3. The encoder frame rate performs better than the others chips.
|
||||
* Under src_type = JPEG_RAW_TYPE_YCbYCr, subsampling = JPEG_SUB_SAMPLE_YUV420, width % 16 == 0. height % 16 = 0 conditions,
|
||||
* memory consumption is about 9K.Others, with wider the image and larger `subsampling`, the greater memory consumption will be.
|
||||
*
|
||||
* @version 1.0.0
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "stdint.h"
|
||||
#include "esp_jpeg_common.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define DEFAULT_JPEG_ENC_CONFIG() \
|
||||
{ \
|
||||
.width = 320, \
|
||||
.height = 240, \
|
||||
.src_type = JPEG_RAW_TYPE_YCbYCr, \
|
||||
.subsampling = JPEG_SUB_SAMPLE_YUV420, \
|
||||
.quality = 40, \
|
||||
.task_enable = false, \
|
||||
.hfm_task_priority = 13, \
|
||||
.hfm_task_core = 1, \
|
||||
.rotate = JPEG_ROTATE_0D, \
|
||||
}
|
||||
|
||||
/* JPEG configure information*/
|
||||
typedef struct jpeg_info {
|
||||
int width; /*!< Image width */
|
||||
int height; /*!< Image height */
|
||||
jpeg_raw_type_t src_type; /*!< Input image type */
|
||||
jpeg_subsampling_t subsampling; /*!< JPEG chroma subsampling factors. If `src_type` is JPEG_RAW_TYPE_YCbY2YCrY2, this must be `JPEG_SUB_SAMPLE_Y` or `JPEG_SUB_SAMPLE_YUV420`. Others is un-support */
|
||||
uint8_t quality; /*!< Quality: 1-100, higher is better. Typical values are around 40 - 100. */
|
||||
bool task_enable; /*!< True: `jpeg_enc_open` would create task to finish part of encoding work. false: no task help the encoder encode */
|
||||
uint8_t hfm_task_priority; /*!< Task priority.If task_enable is true, this must be set */
|
||||
uint8_t hfm_task_core; /*!< Task core.If task_enable is true, this must be set */
|
||||
jpeg_rotate_t rotate; /*!< Supports 0, 90 180 270 degree clockwise rotation.
|
||||
Under src_type = JPEG_RAW_TYPE_YCbYCr, subsampling = JPEG_SUB_SAMPLE_YUV420, width % 16 == 0. height % 16 = 0 conditions, rotation enabled.
|
||||
Otherwise unsupported */
|
||||
} jpeg_enc_info_t;
|
||||
|
||||
/**
|
||||
* @brief Create an JPEG handle to encode
|
||||
*
|
||||
* @param info The configuration information
|
||||
*
|
||||
* @return >0: The JPEG encoder handle
|
||||
* NULL: refer to `jpeg_error_t`
|
||||
*/
|
||||
void *jpeg_enc_open(jpeg_enc_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Encode one image
|
||||
*
|
||||
* @param handle The JPEG encoder handle. It gained from `jpeg_enc_open`
|
||||
* @param in_buf The input buffer, It needs a completed image. The buffer must be aligned 16 byte.
|
||||
* @param inbuf_size The size of `in_buf`. The value must be size of a completed image.
|
||||
* @param out_buf The output buffer, it saves a completed JPEG image. The size must be gather than 700 bytes.
|
||||
* @param outbuf_size The size of output buffer
|
||||
* @param out_size The size of JPEG image
|
||||
*
|
||||
* @return `JPEG_ERR_OK`: It has finished to encode one image.
|
||||
* other values refer to `jpeg_error_t`
|
||||
*/
|
||||
jpeg_error_t jpeg_enc_process(const void *handle, const uint8_t *in_buf, int inbuf_size, uint8_t *out_buf, int outbuf_size, int *out_size);
|
||||
|
||||
/**
|
||||
* @brief Get block size. Block size is minimum process unit.
|
||||
*
|
||||
* @param handle The JPEG encoder handle. It gained from `jpeg_enc_open`
|
||||
*
|
||||
* @return positive value block size
|
||||
*/
|
||||
int jpeg_enc_get_block_size(const void *handle);
|
||||
|
||||
/**
|
||||
* @brief Encode block size image. Get block size from `jpeg_enc_get_block_size`
|
||||
*
|
||||
* @param handle The JPEG encoder handle. It gained from `jpeg_enc_open`
|
||||
* @param in_buf The input buffer, It needs a completed image.
|
||||
* @param inbuf_size The size of `in_buf`. Get block size from `jpeg_enc_get_block_size`
|
||||
* @param out_buf The output buffer, it saves a completed JPEG image. The size must be gather than 700 bytes.
|
||||
* @param outbuf_size The size of output buffer
|
||||
* @param out_size The size of JPEG image
|
||||
*
|
||||
* @return block size: It has finished to encode current block size image.
|
||||
* `JPEG_ERR_OK`: It has finished to encode one image.
|
||||
* `JPEG_ERR_FAIL`: Encoder failed
|
||||
*/
|
||||
int jpeg_enc_process_with_block(const void *handle, const uint8_t *in_buf, int inbuf_size, uint8_t *out_buf, int outbuf_size, int *out_size);
|
||||
|
||||
/**
|
||||
* @brief Deinit JPEG handle
|
||||
*
|
||||
* @param handle The JPEG encoder handle. It gained from `jpeg_enc_open`
|
||||
*
|
||||
* @return `JPEG_ERR_OK` It has finished to deinit.
|
||||
*/
|
||||
jpeg_error_t jpeg_enc_close(void *handle);
|
||||
|
||||
/**
|
||||
* @brief Reset quality.
|
||||
*
|
||||
* @param handle The JPEG encoder handle. It gained from `jpeg_enc_open`
|
||||
* @param q Quality: 1-100, higher is better. Typical values are around 40 - 100.
|
||||
*
|
||||
* @return JPEG_ERR_Ok succeed
|
||||
* others failed
|
||||
*/
|
||||
jpeg_error_t jpeg_enc_set_quality(const void *handle, uint8_t q);
|
||||
|
||||
/**
|
||||
* Example usage:
|
||||
* demo1: It is to encode one image using `jpeg_enc_process`
|
||||
* @code{c}
|
||||
*
|
||||
* int esp_jpeg_enc_demo1 () {
|
||||
* /// configure encoder
|
||||
* jpeg_enc_info_t info = DEFAULT_JPEG_ENC_CONFIG();
|
||||
*
|
||||
* /// allocate input buffer to fill original image stream.
|
||||
* int in_len = info.width *info.height * 2;
|
||||
* char *inbuf = jpeg_malloc_align(in_len);
|
||||
* if(inbuf == NULL) {
|
||||
* goto exit;
|
||||
* }
|
||||
* /// allocate output buffer to fill encoded image stream.
|
||||
* int out_len = info.width * info.height * 2;
|
||||
* char *outbuf = malloc(out_len);
|
||||
* if (inbuf == NULL) {
|
||||
* goto exit;
|
||||
* }
|
||||
* int out_size = 0;
|
||||
* void* el = jpeg_enc_open(&info);
|
||||
* if (el == NULL) {
|
||||
* goto exit;
|
||||
* }
|
||||
* char in_name[100] = "test.yuv";
|
||||
* char out_name[100] = "test.jpg";
|
||||
* FILE *in = fopen(in_name, "rb");
|
||||
* if (el == NULL){
|
||||
* goto exit;
|
||||
* }
|
||||
* FILE *out = fopen(out_name, "wb");
|
||||
* if (el == NULL) {
|
||||
* fclose(in);
|
||||
* goto exit;
|
||||
* }
|
||||
* int ret = fread(inbuf, 1, in_len, in);
|
||||
* if(ret <= 0) {
|
||||
* fclose(in);
|
||||
* fclose(out);
|
||||
* goto exit;
|
||||
* }
|
||||
* jpeg_enc_process(el, inbuf, in_len, outbuf, out_len, &out_size);
|
||||
* ret = fwrite(outbuf, 1, out_size, out);
|
||||
* if (ret <= 0){
|
||||
* fclose(in);
|
||||
* fclose(out);
|
||||
* goto exit;
|
||||
* }
|
||||
* fclose(in);
|
||||
* fclose(out);
|
||||
* exit:
|
||||
* jpeg_enc_close(el);
|
||||
* free(inbuf);
|
||||
* free(outbuf);
|
||||
* }
|
||||
|
||||
* demo2: It is to encode one image using `jpeg_enc_process_with_block`
|
||||
* int esp_jpeg_enc_demo2 () {
|
||||
* jpeg_enc_info_t info = DEFAULT_JPEG_ENC_CONFIG();
|
||||
* int in_len = jpeg_enc_get_block_size(el);
|
||||
* char *inbuf = jpeg_malloc_align(in_len);
|
||||
* if(inbuf == NULL) {
|
||||
* goto exit;
|
||||
* }
|
||||
* int num_times = info.width * info.height * 3 / in_len;
|
||||
* int out_len = info.width * info.height * 2;
|
||||
* char *outbuf = malloc(out_len);
|
||||
* if (inbuf == NULL){
|
||||
* goto exit;
|
||||
* }
|
||||
* int out_size = 0;
|
||||
* void* el = jpeg_enc_open(&info);
|
||||
* if (el == NULL){
|
||||
* goto exit;
|
||||
* }
|
||||
*
|
||||
* char in_name[100] = "test.yuv";
|
||||
* char out_name[100] = "test.jpg";
|
||||
* FILE *in = fopen(in_name, "rb") if (el == NULL)
|
||||
* {
|
||||
* goto exit;
|
||||
* }
|
||||
* FILE *out = fopen(out_name, "wb") if (el == NULL)
|
||||
* {
|
||||
* fclose(in);
|
||||
* goto exit;
|
||||
* }
|
||||
* for (size_t j = 0; j < num_times; j++) {
|
||||
* int ret = fread(inbuf, 1, in_len, in);
|
||||
* if(ret <= 0) {
|
||||
* ret = fwrite(outbuf, 1, out_size, out);
|
||||
* fclose(in);
|
||||
* fclose(out);
|
||||
* goto exit;
|
||||
* }
|
||||
* jpeg_enc_process_with_block(el, inbuf, in_len, outbuf, out_len, &out_size);
|
||||
* }
|
||||
* fclose(in);
|
||||
* fclose(out);
|
||||
* exit:
|
||||
* jpeg_enc_close(el);
|
||||
* free(inbuf);
|
||||
* free(outbuf);
|
||||
* }
|
||||
* @endcode
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
Binary file not shown.
@@ -0,0 +1,40 @@
|
||||
#include <stdlib.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
// #define audio_malloc malloc
|
||||
// #define audio_free free
|
||||
// #define audio_strdup strdup
|
||||
// #define audio_calloc calloc
|
||||
// #define audio_realloc realloc
|
||||
|
||||
void *audio_calloc_inner(size_t n, size_t size)
|
||||
{
|
||||
void *data = NULL;
|
||||
#if CONFIG_SPIRAM_BOOT_INIT
|
||||
data = heap_caps_calloc_prefer(n, size, 2, MALLOC_CAP_DEFAULT | MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT, MALLOC_CAP_DEFAULT | MALLOC_CAP_SPIRAM);
|
||||
#else
|
||||
data = heap_caps_calloc(n, size, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLE_AUDIO_MEM_TRACE
|
||||
ESP_LOGI("AUIDO_MEM", "calloc_inner:%p, size:%d, called:0x%08x", data, size, (intptr_t)__builtin_return_address(0) - 2);
|
||||
#endif
|
||||
return data;
|
||||
}
|
||||
|
||||
void *audio_calloc(size_t n, size_t size)
|
||||
{
|
||||
return calloc(n, size);
|
||||
}
|
||||
|
||||
// void* realloc(void* ptr, size_t size)
|
||||
// {
|
||||
// return heap_caps_realloc_default(ptr, size);
|
||||
// }
|
||||
|
||||
void audio_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
idf_component_register(SRCS main.c)
|
||||
@@ -0,0 +1,5 @@
|
||||
dependencies:
|
||||
espressif/esp-box-3: "^1.0.0"
|
||||
idf: ">=5.0"
|
||||
usb_stream:
|
||||
version: "~1.1.0"
|
||||
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "freertos/task.h"
|
||||
#include "bsp/esp-bsp.h"
|
||||
#include "bsp/display.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_jpeg_dec.h"
|
||||
#include "esp_timer.h"
|
||||
#include "nvs.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "usb_stream.h"
|
||||
#include "iot_button.h"
|
||||
|
||||
static const char *TAG = "uvc_camera_lcd_demo";
|
||||
/****************** configure the example working mode *******************************/
|
||||
|
||||
#define DEMO_UVC_XFER_BUFFER_SIZE (35 * 1024) // Double buffer
|
||||
#define DEMO_KEY_RESOLUTION "resolution" // The key of the resolution stored in nvs
|
||||
#define DEMO_SWITCH_BUTTON_IO 0 // The button to switch resolution
|
||||
#define DEMO_MAX_H 680 // The max width of the camera
|
||||
#define DEMO_MAX_V 480 // The max height of the camera
|
||||
|
||||
#define BIT0_FRAME_START (0x01 << 0)
|
||||
static EventGroupHandle_t s_evt_handle;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
} camera_frame_size_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
camera_frame_size_t camera_frame_size;
|
||||
uvc_frame_size_t *camera_frame_list;
|
||||
size_t camera_frame_list_num;
|
||||
size_t camera_currect_frame_index;
|
||||
} camera_resolution_info_t;
|
||||
|
||||
static camera_resolution_info_t camera_resolution_info = {0};
|
||||
static uint8_t *jpg_frame_buf = NULL;
|
||||
static uint8_t *xfer_buffer_a = NULL;
|
||||
static uint8_t *xfer_buffer_b = NULL;
|
||||
static uint8_t *frame_buffer = NULL;
|
||||
static uint16_t current_width = 0;
|
||||
static uint16_t current_height = 0;
|
||||
static lv_obj_t *camera_canvas = NULL;
|
||||
static lv_obj_t *label = NULL;
|
||||
|
||||
static jpeg_error_t esp_jpeg_decoder_one_picture(uint8_t *input_buf, int len, uint8_t *output_buf)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
// Generate default configuration
|
||||
jpeg_dec_config_t config = DEFAULT_JPEG_DEC_CONFIG();
|
||||
config.output_type = JPEG_RAW_TYPE_RGB565_BE;
|
||||
// Empty handle to jpeg_decoder
|
||||
jpeg_dec_handle_t jpeg_dec = NULL;
|
||||
|
||||
// Create jpeg_dec
|
||||
jpeg_dec = jpeg_dec_open(&config);
|
||||
|
||||
// Create io_callback handle
|
||||
jpeg_dec_io_t *jpeg_io = calloc(1, sizeof(jpeg_dec_io_t));
|
||||
if (jpeg_io == NULL)
|
||||
{
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
// Create out_info handle
|
||||
jpeg_dec_header_info_t *out_info = calloc(1, sizeof(jpeg_dec_header_info_t));
|
||||
if (out_info == NULL)
|
||||
{
|
||||
return ESP_FAIL;
|
||||
}
|
||||
// Set input buffer and buffer len to io_callback
|
||||
jpeg_io->inbuf = input_buf;
|
||||
jpeg_io->inbuf_len = len;
|
||||
|
||||
// Parse jpeg picture header and get picture for user and decoder
|
||||
ret = jpeg_dec_parse_header(jpeg_dec, jpeg_io, out_info);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
jpeg_io->outbuf = output_buf;
|
||||
int inbuf_consumed = jpeg_io->inbuf_len - jpeg_io->inbuf_remain;
|
||||
jpeg_io->inbuf = input_buf + inbuf_consumed;
|
||||
jpeg_io->inbuf_len = jpeg_io->inbuf_remain;
|
||||
|
||||
// Start decode jpeg raw data
|
||||
ret = jpeg_dec_process(jpeg_dec, jpeg_io);
|
||||
if (ret < 0)
|
||||
{
|
||||
goto _exit;
|
||||
}
|
||||
|
||||
_exit:
|
||||
// Decoder deinitialize
|
||||
jpeg_dec_close(jpeg_dec);
|
||||
free(out_info);
|
||||
free(jpeg_io);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void adaptive_jpg_frame_buffer(size_t length)
|
||||
{
|
||||
if (jpg_frame_buf != NULL)
|
||||
{
|
||||
free(jpg_frame_buf);
|
||||
}
|
||||
|
||||
jpg_frame_buf = (uint8_t *)heap_caps_aligned_alloc(16, length, MALLOC_CAP_SPIRAM);
|
||||
assert(jpg_frame_buf != NULL);
|
||||
}
|
||||
|
||||
static void _camera_display(uint8_t *lcd_buffer)
|
||||
{
|
||||
bsp_display_lock(0);
|
||||
lv_canvas_set_buffer(camera_canvas, lcd_buffer, current_width, current_height, LV_IMG_CF_TRUE_COLOR);
|
||||
lv_label_set_text_fmt(label, "#FF0000 %d*%d#", current_width, current_height);
|
||||
bsp_display_unlock();
|
||||
}
|
||||
|
||||
static void camera_frame_cb(uvc_frame_t *frame, void *ptr)
|
||||
{
|
||||
ESP_LOGI(TAG, "uvc callback! frame_format = %d, seq = %" PRIu32 ", width = %" PRIu32 ", height = %" PRIu32 ", length = %u, ptr = %d",
|
||||
frame->frame_format, frame->sequence, frame->width, frame->height, frame->data_bytes, (int)ptr);
|
||||
if (current_width != frame->width || current_height != frame->height)
|
||||
{
|
||||
current_width = frame->width;
|
||||
current_height = frame->height;
|
||||
adaptive_jpg_frame_buffer(current_width * current_height * 2);
|
||||
}
|
||||
|
||||
esp_jpeg_decoder_one_picture((uint8_t *)frame->data, frame->data_bytes, jpg_frame_buf);
|
||||
_camera_display(jpg_frame_buf);
|
||||
vTaskDelay(pdMS_TO_TICKS(1));
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t _display_init(void)
|
||||
{
|
||||
bsp_display_start();
|
||||
bsp_display_backlight_on(); // Set display brightness to 100%
|
||||
bsp_display_lock(0);
|
||||
camera_canvas = lv_canvas_create(lv_scr_act());
|
||||
assert(camera_canvas);
|
||||
lv_obj_center(camera_canvas);
|
||||
label = lv_label_create(lv_scr_act());
|
||||
lv_label_set_recolor(label, true);
|
||||
lv_obj_set_pos(label, 0, 0);
|
||||
lv_label_set_text(label, "Insert a camera, press boot for resolution.");
|
||||
bsp_display_unlock();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static void _get_value_from_nvs(char *key, void *value, size_t *size)
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("memory", NVS_READWRITE, &my_handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
|
||||
}
|
||||
else
|
||||
{
|
||||
err = nvs_get_blob(my_handle, key, value, size);
|
||||
switch (err)
|
||||
{
|
||||
case ESP_OK:
|
||||
break;
|
||||
case ESP_ERR_NVS_NOT_FOUND:
|
||||
ESP_LOGI(TAG, "%s is not initialized yet!", key);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Error (%s) reading!\n", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
nvs_close(my_handle);
|
||||
}
|
||||
}
|
||||
|
||||
static esp_err_t _set_value_to_nvs(char *key, void *value, size_t size)
|
||||
{
|
||||
nvs_handle_t my_handle;
|
||||
esp_err_t err = nvs_open("memory", NVS_READWRITE, &my_handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "Error (%s) opening NVS handle!\n", esp_err_to_name(err));
|
||||
return ESP_FAIL;
|
||||
}
|
||||
else
|
||||
{
|
||||
err = nvs_set_blob(my_handle, key, value, size);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "NVS set failed %s", esp_err_to_name(err));
|
||||
}
|
||||
|
||||
err = nvs_commit(my_handle);
|
||||
if (err != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "NVS commit failed");
|
||||
}
|
||||
|
||||
nvs_close(my_handle);
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static esp_err_t _usb_stream_init(void)
|
||||
{
|
||||
uvc_config_t uvc_config = {
|
||||
.frame_interval = FRAME_INTERVAL_FPS_30,
|
||||
.xfer_buffer_size = DEMO_UVC_XFER_BUFFER_SIZE,
|
||||
.xfer_buffer_a = xfer_buffer_a,
|
||||
.xfer_buffer_b = xfer_buffer_b,
|
||||
.frame_buffer_size = DEMO_UVC_XFER_BUFFER_SIZE,
|
||||
.frame_buffer = frame_buffer,
|
||||
.frame_cb = &camera_frame_cb,
|
||||
.frame_cb_arg = NULL,
|
||||
.frame_width = FRAME_RESOLUTION_ANY,
|
||||
.frame_height = FRAME_RESOLUTION_ANY,
|
||||
.flags = FLAG_UVC_SUSPEND_AFTER_START,
|
||||
};
|
||||
|
||||
esp_err_t ret = uvc_streaming_config(&uvc_config);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "uvc streaming config failed");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static size_t _find_current_resolution(camera_frame_size_t *camera_frame_size)
|
||||
{
|
||||
if (camera_resolution_info.camera_frame_list == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
while (i < camera_resolution_info.camera_frame_list_num)
|
||||
{
|
||||
if (camera_frame_size->width >= camera_resolution_info.camera_frame_list[i].width && camera_frame_size->height >= camera_resolution_info.camera_frame_list[i].height)
|
||||
{
|
||||
/* Find next resolution
|
||||
If current resolution is the min resolution, switch to the max resolution*/
|
||||
camera_frame_size->width = camera_resolution_info.camera_frame_list[i].width;
|
||||
camera_frame_size->height = camera_resolution_info.camera_frame_list[i].height;
|
||||
break;
|
||||
}
|
||||
else if (i == camera_resolution_info.camera_frame_list_num - 1)
|
||||
{
|
||||
camera_frame_size->width = camera_resolution_info.camera_frame_list[i].width;
|
||||
camera_frame_size->height = camera_resolution_info.camera_frame_list[i].height;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
ESP_LOGI(TAG, "Current resolution is %dx%d", camera_frame_size->width, camera_frame_size->height);
|
||||
return i;
|
||||
}
|
||||
|
||||
static void switch_button_press_down_cb(void *arg, void *data)
|
||||
{
|
||||
if (camera_resolution_info.camera_frame_list == NULL || xEventGroupWaitBits(s_evt_handle, BIT0_FRAME_START, false, false, pdMS_TO_TICKS(10)) != pdTRUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "old resolution is %d*%d", camera_resolution_info.camera_frame_size.width, camera_resolution_info.camera_frame_size.height);
|
||||
if (++camera_resolution_info.camera_currect_frame_index >= camera_resolution_info.camera_frame_list_num)
|
||||
{
|
||||
camera_resolution_info.camera_currect_frame_index = 0;
|
||||
}
|
||||
camera_resolution_info.camera_frame_size.width = camera_resolution_info.camera_frame_list[camera_resolution_info.camera_currect_frame_index].width;
|
||||
camera_resolution_info.camera_frame_size.height = camera_resolution_info.camera_frame_list[camera_resolution_info.camera_currect_frame_index].height;
|
||||
ESP_LOGI(TAG, "currect resolution is %d*%d", camera_resolution_info.camera_frame_size.width, camera_resolution_info.camera_frame_size.height);
|
||||
|
||||
/* Save the new camera resolution to nsv */
|
||||
usb_streaming_control(STREAM_UVC, CTRL_SUSPEND, NULL);
|
||||
ESP_ERROR_CHECK(uvc_frame_size_reset(camera_resolution_info.camera_frame_size.width,
|
||||
camera_resolution_info.camera_frame_size.height,
|
||||
FPS2INTERVAL(30)));
|
||||
ESP_ERROR_CHECK(_set_value_to_nvs(DEMO_KEY_RESOLUTION, &camera_resolution_info.camera_frame_size, sizeof(camera_frame_size_t)));
|
||||
usb_streaming_control(STREAM_UVC, CTRL_RESUME, NULL);
|
||||
}
|
||||
|
||||
static esp_err_t _switch_button_init(void)
|
||||
{
|
||||
button_config_t button_config = {
|
||||
.type = BUTTON_TYPE_GPIO,
|
||||
.gpio_button_config = {
|
||||
.gpio_num = DEMO_SWITCH_BUTTON_IO,
|
||||
.active_level = 0,
|
||||
},
|
||||
};
|
||||
|
||||
button_handle_t button_handle = iot_button_create(&button_config);
|
||||
assert(button_handle != NULL);
|
||||
esp_err_t ret = iot_button_register_cb(button_handle, BUTTON_PRESS_DOWN, switch_button_press_down_cb, NULL);
|
||||
if (ret != ESP_OK)
|
||||
{
|
||||
ESP_LOGE(TAG, "button register callback fail");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void _stream_state_changed_cb(usb_stream_state_t event, void *arg)
|
||||
{
|
||||
switch (event)
|
||||
{
|
||||
case STREAM_CONNECTED:
|
||||
{
|
||||
/* Get camera resolution in nvs*/
|
||||
size_t size = sizeof(camera_frame_size_t);
|
||||
_get_value_from_nvs(DEMO_KEY_RESOLUTION, &camera_resolution_info.camera_frame_size, &size);
|
||||
size_t frame_index = 0;
|
||||
uvc_frame_size_list_get(NULL, &camera_resolution_info.camera_frame_list_num, NULL);
|
||||
if (camera_resolution_info.camera_frame_list_num)
|
||||
{
|
||||
ESP_LOGI(TAG, "UVC: get frame list size = %u, current = %u", camera_resolution_info.camera_frame_list_num, frame_index);
|
||||
uvc_frame_size_t *_frame_list = (uvc_frame_size_t *)malloc(camera_resolution_info.camera_frame_list_num * sizeof(uvc_frame_size_t));
|
||||
|
||||
camera_resolution_info.camera_frame_list = (uvc_frame_size_t *)realloc(camera_resolution_info.camera_frame_list, camera_resolution_info.camera_frame_list_num * sizeof(uvc_frame_size_t));
|
||||
if (NULL == camera_resolution_info.camera_frame_list)
|
||||
{
|
||||
ESP_LOGE(TAG, "camera_resolution_info.camera_frame_list");
|
||||
}
|
||||
uvc_frame_size_list_get(_frame_list, NULL, NULL);
|
||||
for (size_t i = 0; i < camera_resolution_info.camera_frame_list_num; i++)
|
||||
{
|
||||
if (_frame_list[i].width <= DEMO_MAX_H && _frame_list[i].height <= DEMO_MAX_V)
|
||||
{
|
||||
camera_resolution_info.camera_frame_list[frame_index++] = _frame_list[i];
|
||||
ESP_LOGI(TAG, "\tpick frame[%u] = %ux%u", i, _frame_list[i].width, _frame_list[i].height);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGI(TAG, "\tdrop frame[%u] = %ux%u", i, _frame_list[i].width, _frame_list[i].height);
|
||||
}
|
||||
}
|
||||
camera_resolution_info.camera_frame_list_num = frame_index;
|
||||
if (camera_resolution_info.camera_frame_size.width != 0 && camera_resolution_info.camera_frame_size.height != 0)
|
||||
{
|
||||
camera_resolution_info.camera_currect_frame_index = _find_current_resolution(&camera_resolution_info.camera_frame_size);
|
||||
}
|
||||
else
|
||||
{
|
||||
camera_resolution_info.camera_currect_frame_index = 0;
|
||||
}
|
||||
|
||||
if (-1 == camera_resolution_info.camera_currect_frame_index)
|
||||
{
|
||||
ESP_LOGE(TAG, "fine current resolution fail");
|
||||
break;
|
||||
}
|
||||
ESP_ERROR_CHECK(uvc_frame_size_reset(camera_resolution_info.camera_frame_list[camera_resolution_info.camera_currect_frame_index].width,
|
||||
camera_resolution_info.camera_frame_list[camera_resolution_info.camera_currect_frame_index].height, FPS2INTERVAL(30)));
|
||||
camera_frame_size_t camera_frame_size = {
|
||||
.width = camera_resolution_info.camera_frame_list[camera_resolution_info.camera_currect_frame_index].width,
|
||||
.height = camera_resolution_info.camera_frame_list[camera_resolution_info.camera_currect_frame_index].height,
|
||||
};
|
||||
ESP_ERROR_CHECK(_set_value_to_nvs(DEMO_KEY_RESOLUTION, &camera_frame_size, sizeof(camera_frame_size_t)));
|
||||
|
||||
if (_frame_list != NULL)
|
||||
{
|
||||
free(_frame_list);
|
||||
}
|
||||
/* Wait USB Camera connected */
|
||||
usb_streaming_control(STREAM_UVC, CTRL_RESUME, NULL);
|
||||
xEventGroupSetBits(s_evt_handle, BIT0_FRAME_START);
|
||||
}
|
||||
else
|
||||
{
|
||||
ESP_LOGW(TAG, "UVC: get frame list size = %u", camera_resolution_info.camera_frame_list_num);
|
||||
}
|
||||
ESP_LOGI(TAG, "Device connected");
|
||||
break;
|
||||
}
|
||||
case STREAM_DISCONNECTED:
|
||||
xEventGroupClearBits(s_evt_handle, BIT0_FRAME_START);
|
||||
ESP_LOGI(TAG, "Device disconnected");
|
||||
break;
|
||||
default:
|
||||
ESP_LOGE(TAG, "Unknown event");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
esp_log_level_set("*", ESP_LOG_INFO);
|
||||
/* Initialize NVS */
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND)
|
||||
{
|
||||
/* NVS partition was truncated and needs to be erased */
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
/* Retry nvs_flash_init */
|
||||
ret = nvs_flash_init();
|
||||
}
|
||||
ESP_ERROR_CHECK(ret);
|
||||
|
||||
/* Create event group */
|
||||
s_evt_handle = xEventGroupCreate();
|
||||
if (s_evt_handle == NULL)
|
||||
{
|
||||
ESP_LOGE(TAG, "line-%u event group create failed", __LINE__);
|
||||
assert(0);
|
||||
}
|
||||
|
||||
/* malloc double buffer for usb payload, xfer_buffer_size >= frame_buffer_size*/
|
||||
// xfer_buffer_a = (uint8_t *)heap_caps_calloc(1, DEMO_UVC_XFER_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||
xfer_buffer_a = (uint8_t *)heap_caps_malloc(DEMO_UVC_XFER_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||
assert(xfer_buffer_a != NULL);
|
||||
xfer_buffer_b = (uint8_t *)heap_caps_malloc(DEMO_UVC_XFER_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||
assert(xfer_buffer_b != NULL);
|
||||
|
||||
/* malloc frame buffer for a jpeg frame*/
|
||||
frame_buffer = (uint8_t *)heap_caps_malloc(DEMO_UVC_XFER_BUFFER_SIZE, MALLOC_CAP_SPIRAM);
|
||||
assert(frame_buffer != NULL);
|
||||
|
||||
/* Initialize the screen */
|
||||
ESP_ERROR_CHECK(_display_init());
|
||||
|
||||
/* Initialize the button to switch resolution */
|
||||
ESP_ERROR_CHECK(_switch_button_init());
|
||||
|
||||
/* Initialize the screen according to the resolution stored in nvs */
|
||||
ESP_ERROR_CHECK(_usb_stream_init());
|
||||
|
||||
/* Register a callback to control uvc frame size */
|
||||
ESP_ERROR_CHECK(usb_streaming_state_register(&_stream_state_changed_cb, NULL));
|
||||
|
||||
/* Start stream with pre-configs, usb stream driver will create multi-tasks internal
|
||||
to handle usb data from different pipes, and user's callback will be called after new frame ready. */
|
||||
ESP_ERROR_CHECK(usb_streaming_start());
|
||||
ESP_ERROR_CHECK(usb_streaming_connect_wait(portMAX_DELAY));
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
CONFIG_IDF_TARGET="esp32s3"
|
||||
CONFIG_IDF_TARGET_ESP32S3=y
|
||||
|
||||
#
|
||||
# ESP System Settings
|
||||
#
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
||||
|
||||
#
|
||||
# FreeRTOS
|
||||
#
|
||||
|
||||
#
|
||||
# Kernel
|
||||
#
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
#
|
||||
# Compiler options
|
||||
#
|
||||
CONFIG_COMPILER_OPTIMIZATION_PERF=y
|
||||
|
||||
#
|
||||
# ESP PSRAM
|
||||
#
|
||||
CONFIG_SPIRAM=y
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
CONFIG_SPIRAM_FETCH_INSTRUCTIONS=y
|
||||
CONFIG_SPIRAM_RODATA=y
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
|
||||
|
||||
#
|
||||
# SPI RAM config
|
||||
#
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_FLASHMODE_QIO=y
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_80M=y
|
||||
|
||||
#
|
||||
# LCD
|
||||
#
|
||||
CONFIG_BSP_LCD_RGB_BUFFER_NUMS=2
|
||||
|
||||
CONFIG_BSP_LCD_DRAW_BUF_HEIGHT=150
|
||||
CONFIG_BSP_LCD_DRAW_BUF_DOUBLE=y
|
||||
CONFIG_LV_COLOR_16_SWAP=y
|
||||
@@ -0,0 +1,16 @@
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
|
||||
#
|
||||
# Serial flasher config
|
||||
#
|
||||
CONFIG_ESPTOOLPY_FLASHFREQ_120M=y
|
||||
|
||||
#
|
||||
# SPI RAM config
|
||||
#
|
||||
CONFIG_SPIRAM_SPEED_120M=y
|
||||
|
||||
#
|
||||
# Cache config
|
||||
#
|
||||
CONFIG_ESP32S3_DATA_CACHE_LINE_64B=y
|
||||
@@ -0,0 +1,145 @@
|
||||
# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
"""
|
||||
This file is used in CI generate binary files for different kinds of apps
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
from pathlib import Path
|
||||
from typing import List
|
||||
|
||||
from idf_build_apps import LOGGER, App, build_apps, find_apps, setup_logging
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent.absolute()
|
||||
APPS_BUILD_PER_JOB = 30
|
||||
IGNORE_WARNINGS = [
|
||||
|
||||
]
|
||||
|
||||
def _get_idf_version():
|
||||
if os.environ.get('IDF_VERSION'):
|
||||
return os.environ.get('IDF_VERSION')
|
||||
version_path = os.path.join(os.environ['IDF_PATH'], 'tools/cmake/version.cmake')
|
||||
regex = re.compile(r'^\s*set\s*\(\s*IDF_VERSION_([A-Z]{5})\s+(\d+)')
|
||||
ver = {}
|
||||
with open(version_path) as f:
|
||||
for line in f:
|
||||
m = regex.match(line)
|
||||
if m:
|
||||
ver[m.group(1)] = m.group(2)
|
||||
return '{}.{}'.format(int(ver['MAJOR']), int(ver['MINOR']))
|
||||
|
||||
def get_cmake_apps(
|
||||
paths,
|
||||
target,
|
||||
config_rules_str,
|
||||
default_build_targets,
|
||||
): # type: (List[str], str, List[str]) -> List[App]
|
||||
idf_ver = _get_idf_version()
|
||||
apps = find_apps(
|
||||
paths,
|
||||
recursive=True,
|
||||
target=target,
|
||||
build_dir=f'{idf_ver}/build_@t_@w',
|
||||
config_rules_str=config_rules_str,
|
||||
build_log_path='build_log.txt',
|
||||
size_json_path='size.json',
|
||||
check_warnings=True,
|
||||
preserve=True,
|
||||
default_build_targets=default_build_targets,
|
||||
manifest_files=[
|
||||
],
|
||||
)
|
||||
return apps
|
||||
|
||||
|
||||
def main(args): # type: (argparse.Namespace) -> None
|
||||
default_build_targets = args.default_build_targets.split(',') if args.default_build_targets else None
|
||||
apps = get_cmake_apps(args.paths, args.target, args.config, default_build_targets)
|
||||
if args.exclude_apps:
|
||||
apps_to_build = [app for app in apps if app.name not in args.exclude_apps]
|
||||
else:
|
||||
apps_to_build = apps[:]
|
||||
|
||||
LOGGER.info('Found %d apps after filtering', len(apps_to_build))
|
||||
LOGGER.info(
|
||||
'Suggest setting the parallel count to %d for this build job',
|
||||
len(apps_to_build) // APPS_BUILD_PER_JOB + 1,
|
||||
)
|
||||
|
||||
ret_code = build_apps(
|
||||
apps_to_build,
|
||||
parallel_count=args.parallel_count,
|
||||
parallel_index=args.parallel_index,
|
||||
dry_run=False,
|
||||
collect_size_info=args.collect_size_info,
|
||||
keep_going=True,
|
||||
ignore_warning_strs=IGNORE_WARNINGS,
|
||||
copy_sdkconfig=True,
|
||||
)
|
||||
|
||||
sys.exit(ret_code)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Build all the apps for different test types. Will auto remove those non-test apps binaries',
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
||||
)
|
||||
parser.add_argument('paths', nargs='*', help='Paths to the apps to build.')
|
||||
parser.add_argument(
|
||||
'-t', '--target',
|
||||
default='all',
|
||||
help='Build apps for given target. could pass "all" to get apps for all targets',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--config',
|
||||
default=['sdkconfig.ci=default', 'sdkconfig.ci.*=', '=default'],
|
||||
action='append',
|
||||
help='Adds configurations (sdkconfig file names) to build. This can either be '
|
||||
'FILENAME[=NAME] or FILEPATTERN. FILENAME is the name of the sdkconfig file, '
|
||||
'relative to the project directory, to be used. Optional NAME can be specified, '
|
||||
'which can be used as a name of this configuration. FILEPATTERN is the name of '
|
||||
'the sdkconfig file, relative to the project directory, with at most one wildcard. '
|
||||
'The part captured by the wildcard is used as the name of the configuration.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--parallel-count', default=1, type=int, help='Number of parallel build jobs.'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--parallel-index',
|
||||
default=1,
|
||||
type=int,
|
||||
help='Index (1-based) of the job, out of the number specified by --parallel-count.',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--collect-size-info',
|
||||
type=argparse.FileType('w'),
|
||||
help='If specified, the test case name and size info json will be written to this file',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--exclude-apps',
|
||||
nargs='*',
|
||||
help='Exclude build apps',
|
||||
)
|
||||
parser.add_argument(
|
||||
'--default-build-targets',
|
||||
default=None,
|
||||
help='default build targets used in manifest files',
|
||||
)
|
||||
parser.add_argument(
|
||||
'-v', '--verbose',
|
||||
action='count', default=0,
|
||||
help='Show verbose log message',
|
||||
)
|
||||
|
||||
arguments = parser.parse_args()
|
||||
if not arguments.paths:
|
||||
arguments.paths = [PROJECT_ROOT]
|
||||
setup_logging(verbose=arguments.verbose) # Info
|
||||
main(arguments)
|
||||
Reference in New Issue
Block a user