mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-31 11:17:20 +02:00
Merge branch 'feat/add_h264_encoder_decoder_demo' into 'master'
feat(esp_h264): Add esp_h264 enocder and decoder example Closes AUD-6406 See merge request espressif/esp-idf!39676
This commit is contained in:
@ -87,6 +87,13 @@ examples/peripherals/gpio/matrix_keyboard:
|
||||
enable:
|
||||
- if: IDF_TARGET == "esp32s2"
|
||||
|
||||
examples/peripherals/h264:
|
||||
enable:
|
||||
- if: IDF_TARGET in ["esp32p4", "esp32s3"]
|
||||
reason: only supports esp32p4 and esp32s3
|
||||
depends_components:
|
||||
- esp_h264
|
||||
|
||||
examples/peripherals/i2c/i2c_basic:
|
||||
disable:
|
||||
- if: SOC_I2C_SUPPORTED != 1
|
||||
|
7
examples/peripherals/h264/CMakeLists.txt
Normal file
7
examples/peripherals/h264/CMakeLists.txt
Normal file
@ -0,0 +1,7 @@
|
||||
# The following lines of boilerplate have to be in your project's
|
||||
# CMakeLists.txt file.
|
||||
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
|
||||
project(esp_h264_example)
|
153
examples/peripherals/h264/README.md
Normal file
153
examples/peripherals/h264/README.md
Normal file
@ -0,0 +1,153 @@
|
||||
| Supported Targets | ESP32-P4 | ESP32-S3 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
# H.264 Encoder-Decoder Example
|
||||
|
||||
## Overview
|
||||
|
||||
This example demonstrates how to use H.264 hardware/software encoder and decoder with visual pattern generation:
|
||||
|
||||
- Generate colorful test patterns for video processing
|
||||
- Encode video frames using H.264 codec (hardware on ESP32-P4, software on ESP32-S3)
|
||||
- Decode the encoded frames back to original format using software decoder
|
||||
- Display visual comparison between source and decoded images
|
||||
|
||||
The example supports multiple YUV formats and provides side-by-side colorized display in the console. All encoding parameters are configurable through the ESP-IDF menuconfig system.
|
||||
|
||||
## Configuration
|
||||
|
||||
This example provides comprehensive configuration options through `idf.py menuconfig`:
|
||||
|
||||
### H.264 Encoder Type Selection
|
||||
- **Hardware Encoder**: Available only on ESP32-P4, provides better performance and lower power consumption
|
||||
- **Software Encoder**: Available on all targets (ESP32-S3, ESP32-P4), uses more CPU resources
|
||||
|
||||
### Configurable Parameters
|
||||
All parameters can be adjusted in "H.264 Example Configuration" menu:
|
||||
|
||||
- **Video Width**: 64-1920 pixels (default: 320)
|
||||
- **Video Height**: 64-1080 pixels (default: 240)
|
||||
- **Frame Rate**: 1-60 fps (default: 30 for hardware, 15 for software)
|
||||
- **Bitrate**: 64K-10M bps (default: 512K for hardware, 256K for software)
|
||||
- **GOP Size**: 1-255 frames (default: 30)
|
||||
- **QP Value**: 10-51 (default: 26 for hardware, 28 for software)
|
||||
|
||||
### Target-Specific Defaults
|
||||
- **ESP32-P4**: Optimized for hardware encoding with higher performance settings
|
||||
- **ESP32-S3**: Optimized for software encoding with conservative settings
|
||||
|
||||
## How to use example
|
||||
|
||||
### Prerequisites Required
|
||||
|
||||
This example requires:
|
||||
- ESP32-P4 development board (for hardware encoding) or ESP32-S3 development board (for software encoding)
|
||||
- USB cable for programming and power supply
|
||||
- Terminal that supports ANSI color codes for proper visual output
|
||||
|
||||
### Configure the Example
|
||||
|
||||
Before building, configure the example parameters:
|
||||
|
||||
```bash
|
||||
idf.py menuconfig
|
||||
```
|
||||
|
||||
Navigate to: `Component config` → `H.264 Example Configuration`
|
||||
|
||||
1. **Select Encoder Type**: Choose between Hardware (ESP32-P4 only) or Software encoder
|
||||
2. **Adjust Parameters**: Configure video resolution, frame rate, bitrate, etc.
|
||||
3. **Save and Exit**: Press 'S' to save configuration
|
||||
|
||||
### Build and Flash
|
||||
|
||||
For ESP32-P4 (with hardware encoding support):
|
||||
```bash
|
||||
idf.py set-target esp32p4
|
||||
idf.py menuconfig # Configure as needed
|
||||
idf.py build
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
For ESP32-S3 (software encoding only):
|
||||
```bash
|
||||
idf.py set-target esp32s3
|
||||
idf.py menuconfig # Software encoder will be automatically selected
|
||||
idf.py build
|
||||
idf.py -p PORT flash monitor
|
||||
```
|
||||
|
||||
(To exit the serial monitor, type ``Ctrl-]``.)
|
||||
|
||||
See the [Getting Started Guide](https://docs.espressif.com/projects/esp-idf/en/latest/get-started/index.html) for full steps to configure and use ESP-IDF to build projects.
|
||||
|
||||
## Example Output
|
||||
|
||||
```bash
|
||||
I (1555) H264_ENC_DEC: H264 Example starting: 320x240 @ 30fps
|
||||
I (1565) H264_ENC_DEC: Encoder: Hardware, Decoder: Software
|
||||
I (1575) H264_ENC_DEC: Config: GOP=30, Bitrate=512000 bps, QP=26
|
||||
I (1585) H264_DEC.SW: tinyh264 version: 1c7f584
|
||||
I (1585) H264_ENC_DEC: H264 encode-decode loop started (320x240 @ 30fps)
|
||||
|
||||
Frame 0: source image | decoded image
|
||||
[Colorized bar patterns displayed side by side using ANSI colors]
|
||||
|
||||
Frame 1: source image | decoded image
|
||||
[Colorized bar patterns displayed side by side using ANSI colors]
|
||||
|
||||
Frame 2: source image | decoded image
|
||||
[Colorized bar patterns displayed side by side using ANSI colors]
|
||||
...
|
||||
|
||||
I (21465) H264_ENC_DEC: H264 process Completed successfully
|
||||
I (21475) main_task: Returned from app_main()
|
||||
```
|
||||
|
||||
*Note: The exact values shown will depend on your menuconfig settings.*
|
||||
|
||||
## Video Format Support
|
||||
|
||||
- **ESP_H264_RAW_FMT_I420**: Planar YUV 4:2:0 format (decoder output, software encoder input)
|
||||
- **ESP_H264_RAW_FMT_O_UYY_E_VYY**: Interlaced YUV format (hardware encoder input on ESP32-P4)
|
||||
|
||||
## Performance Recommendations
|
||||
|
||||
### For ESP32-P4 (Hardware Encoding):
|
||||
- Resolution: Up to 1920x1080 supported
|
||||
- Frame Rate: 30-60 fps achievable
|
||||
- Bitrate: 512K-5M bps recommended
|
||||
- QP: 20-30 for optimal quality/performance balance
|
||||
|
||||
### For ESP32-S3 (Software Encoding):
|
||||
- Resolution: 320x240 or smaller recommended
|
||||
- Frame Rate: 10-15 fps for stable performance
|
||||
- Bitrate: 256K-1M bps recommended
|
||||
- QP: 28-35 for better performance
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Configuration Issues:**
|
||||
- Use `idf.py menuconfig` to verify H.264 settings before building
|
||||
- Ensure hardware encoder is only selected for ESP32-P4 target
|
||||
|
||||
**Memory allocation failures:**
|
||||
- Reduce resolution or frame rate in menuconfig
|
||||
- Ensure sufficient SPIRAM is available
|
||||
- Check ESP-IDF memory configuration
|
||||
|
||||
**Encoding/decoding errors:**
|
||||
- Verify the correct target is selected (ESP32-P4 for hardware)
|
||||
- Check that H.264 component is properly configured in menuconfig
|
||||
- Adjust bitrate settings for your resolution/frame rate combination
|
||||
|
||||
**Performance Issues:**
|
||||
- Lower resolution, frame rate, or bitrate for software encoding
|
||||
- Use hardware encoder on ESP32-P4 for better performance
|
||||
- Increase QP value to reduce computational load
|
||||
|
||||
**Visual output issues:**
|
||||
- Ensure your terminal supports ANSI color codes
|
||||
- Try different terminal applications if colors don't display properly
|
||||
|
||||
(For any technical queries, please open an [issue](https://github.com/espressif/esp-idf/issues) on GitHub. We will get back to you as soon as possible.)
|
2
examples/peripherals/h264/main/CMakeLists.txt
Normal file
2
examples/peripherals/h264/main/CMakeLists.txt
Normal file
@ -0,0 +1,2 @@
|
||||
idf_component_register(SRC_DIRS "./"
|
||||
INCLUDE_DIRS "./")
|
96
examples/peripherals/h264/main/Kconfig.projbuild
Normal file
96
examples/peripherals/h264/main/Kconfig.projbuild
Normal file
@ -0,0 +1,96 @@
|
||||
menu "H.264 Example Configuration"
|
||||
|
||||
choice H264_ENCODER_TYPE
|
||||
prompt "H.264 Encoder Type"
|
||||
default H264_ENCODER_HARDWARE if IDF_TARGET_ESP32P4
|
||||
default H264_ENCODER_SOFTWARE
|
||||
help
|
||||
Select the H.264 encoder type to use.
|
||||
Hardware encoder is only available on ESP32P4 and provides
|
||||
better performance and lower power consumption.
|
||||
Software encoder is available on all targets but requires
|
||||
more CPU resources.
|
||||
|
||||
config H264_ENCODER_HARDWARE
|
||||
bool "Hardware Encoder (ESP32P4 only)"
|
||||
depends on IDF_TARGET_ESP32P4
|
||||
help
|
||||
Use hardware H.264 encoder.
|
||||
This option is only available on ESP32P4 which has
|
||||
dedicated H.264 hardware encoding capabilities.
|
||||
Provides better performance and lower power consumption
|
||||
compared to software encoding.
|
||||
|
||||
config H264_ENCODER_SOFTWARE
|
||||
bool "Software Encoder"
|
||||
help
|
||||
Use software H.264 encoder using OpenH264 library.
|
||||
Available on all supported targets (ESP32S3, ESP32P4)
|
||||
but requires more CPU resources and power consumption
|
||||
compared to hardware encoding.
|
||||
endchoice
|
||||
|
||||
menu "H.264 Encoder Parameters"
|
||||
|
||||
config H264_ENCODER_WIDTH
|
||||
int "Video Width"
|
||||
range 64 1920
|
||||
default 320
|
||||
help
|
||||
Video frame width in pixels.
|
||||
Must be multiple of 16 for optimal performance.
|
||||
Recommended values: 128, 160, 320, 640, 1280.
|
||||
|
||||
config H264_ENCODER_HEIGHT
|
||||
int "Video Height"
|
||||
range 64 1080
|
||||
default 240
|
||||
help
|
||||
Video frame height in pixels.
|
||||
Must be multiple of 16 for optimal performance.
|
||||
Recommended values: 96, 120, 240, 480, 720.
|
||||
|
||||
config H264_ENCODER_FPS
|
||||
int "Frame Rate (FPS)"
|
||||
range 1 60
|
||||
default 30 if H264_ENCODER_HARDWARE
|
||||
default 15 if H264_ENCODER_SOFTWARE
|
||||
help
|
||||
Video frame rate in frames per second.
|
||||
Hardware encoder can support higher frame rates.
|
||||
Software encoder performance depends on CPU capability.
|
||||
|
||||
config H264_ENCODER_BITRATE
|
||||
int "Bitrate (bps)"
|
||||
range 64000 10000000
|
||||
default 512000 if H264_ENCODER_HARDWARE
|
||||
default 256000 if H264_ENCODER_SOFTWARE
|
||||
help
|
||||
Video bitrate in bits per second.
|
||||
Higher bitrate provides better quality but larger file size.
|
||||
Hardware encoder can handle higher bitrates more efficiently.
|
||||
Typical values: 256K-1M for low quality, 1M-5M for high quality.
|
||||
|
||||
config H264_ENCODER_GOP_SIZE
|
||||
int "GOP Size"
|
||||
range 1 255
|
||||
default 30
|
||||
help
|
||||
Group of Pictures size. Determines the frequency
|
||||
of I-frames in the video stream.
|
||||
Larger GOP size = better compression, higher latency.
|
||||
Smaller GOP size = lower compression, lower latency.
|
||||
|
||||
config H264_ENCODER_QP_VALUE
|
||||
int "Quantization Parameter (QP)"
|
||||
range 10 51
|
||||
default 26 if H264_ENCODER_HARDWARE
|
||||
default 28 if H264_ENCODER_SOFTWARE
|
||||
help
|
||||
Quantization parameter that controls video quality.
|
||||
Lower values = higher quality, larger file size.
|
||||
Higher values = lower quality, smaller file size.
|
||||
Hardware encoder can handle lower QP values more efficiently.
|
||||
|
||||
endmenu
|
||||
endmenu
|
233
examples/peripherals/h264/main/esp_h264_enc_dec.c
Normal file
233
examples/peripherals/h264/main/esp_h264_enc_dec.c
Normal file
@ -0,0 +1,233 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <inttypes.h>
|
||||
#include "sdkconfig.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_h264_alloc.h"
|
||||
#include "esp_h264_dec_sw.h"
|
||||
#if CONFIG_H264_ENCODER_HARDWARE
|
||||
#include "esp_h264_enc_single_hw.h"
|
||||
#else
|
||||
#include "esp_h264_enc_single_sw.h"
|
||||
#endif /* CONFIG_H264_ENCODER_HARDWARE */
|
||||
#include "video_pattern.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
static const char *TAG = "H264_ENC_DEC";
|
||||
|
||||
#define FRAME_MAX_NUM 10
|
||||
|
||||
// Helper function to allocate aligned memory with error checking
|
||||
static void *allocate_frame_buffer(size_t size, uint32_t *actual_size, const char *buffer_name)
|
||||
{
|
||||
void *buffer = esp_h264_aligned_calloc(16, 1, size, actual_size, ESP_H264_MEM_SPIRAM);
|
||||
if (!buffer) {
|
||||
ESP_LOGE(TAG, "Failed to allocate %s buffer memory (%zu bytes)", buffer_name, size);
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// Helper function to initialize pattern info
|
||||
static void init_pattern_info(pattern_info_t *pattern, uint32_t width, uint32_t height, uint32_t format_id)
|
||||
{
|
||||
pattern->res.width = width;
|
||||
pattern->res.height = height;
|
||||
pattern->format_id = format_id;
|
||||
pattern->vertical = false;
|
||||
pattern->bar_count = 16;
|
||||
pattern->data_size = width * height * 3 / 2;
|
||||
}
|
||||
|
||||
/*
|
||||
This function is used to encode and decode a single frame.
|
||||
src_frame --> encoder --> enc_frame(dec_input) --> decoder --> dest_frame(out_pattern)
|
||||
*/
|
||||
|
||||
#if CONFIG_H264_ENCODER_HARDWARE
|
||||
esp_h264_err_t single_enc_dec_process(esp_h264_enc_cfg_hw_t enc_cfg, esp_h264_dec_cfg_sw_t dec_cfg)
|
||||
#else
|
||||
esp_h264_err_t single_enc_dec_process(esp_h264_enc_cfg_sw_t enc_cfg, esp_h264_dec_cfg_sw_t dec_cfg)
|
||||
#endif /* CONFIG_H264_ENCODER_HARDWARE */
|
||||
{
|
||||
int frame_num = 0;
|
||||
// Frame buffers - Fixed types to match decoder expectations
|
||||
esp_h264_enc_in_frame_t src_frame = {0}; // Original input frame
|
||||
esp_h264_enc_out_frame_t enc_frame = {0}; // Encoded frame output
|
||||
esp_h264_dec_in_frame_t dec_input = {0}; // Decoder input frame (fixed type)
|
||||
esp_h264_dec_out_frame_t dest_frame = {0}; // Decoded frame output (fixed type)
|
||||
|
||||
// Handles and variables
|
||||
esp_h264_err_t ret = ESP_H264_ERR_OK;
|
||||
esp_h264_enc_handle_t enc = NULL;
|
||||
esp_h264_dec_handle_t dec = NULL;
|
||||
|
||||
// Pattern info structures
|
||||
pattern_info_t in_pattern = {};
|
||||
pattern_info_t out_pattern = {};
|
||||
|
||||
size_t frame_size = enc_cfg.res.width * enc_cfg.res.height;
|
||||
size_t pixel_bits = 12; // 12 bits per pixel for YUV420
|
||||
if (enc_cfg.pic_type == ESP_H264_RAW_FMT_YUYV) {
|
||||
// Calculate frame size
|
||||
pixel_bits = 16; // 16 bits per pixel for YUYV
|
||||
}
|
||||
frame_size *= pixel_bits;
|
||||
|
||||
// Initialize pattern configurations
|
||||
init_pattern_info(&in_pattern, enc_cfg.res.width, enc_cfg.res.height, enc_cfg.pic_type);
|
||||
init_pattern_info(&out_pattern, enc_cfg.res.width, enc_cfg.res.height, dec_cfg.pic_type);
|
||||
|
||||
// Allocate frame buffers
|
||||
src_frame.raw_data.buffer = allocate_frame_buffer(frame_size, &src_frame.raw_data.len, "source frame");
|
||||
if (!src_frame.raw_data.buffer) {
|
||||
goto cleanup;
|
||||
}
|
||||
// Because of the different bitrate, the encoded frame buffer size is different.
|
||||
// It uses the same buffer size as the source frame to avoid not enough buffer error.
|
||||
enc_frame.raw_data.buffer = allocate_frame_buffer(frame_size, &enc_frame.raw_data.len, "encoded frame");
|
||||
if (!enc_frame.raw_data.buffer) {
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Setup decoder input frame (correct structure for decoder)
|
||||
dec_input.raw_data.buffer = enc_frame.raw_data.buffer;
|
||||
|
||||
// Assign pattern pixel buffers
|
||||
in_pattern.pixel = src_frame.raw_data.buffer;
|
||||
|
||||
// Initialize H264 encoder
|
||||
#if CONFIG_H264_ENCODER_HARDWARE
|
||||
ret = esp_h264_enc_hw_new(&enc_cfg, &enc);
|
||||
#else
|
||||
ret = esp_h264_enc_sw_new(&enc_cfg, &enc);
|
||||
#endif /* CONFIG_H264_ENCODER_HARDWARE */
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create H264 encoder (error: %d)", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = esp_h264_enc_open(enc);
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open H264 encoder (error: %d)", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Initialize H264 decoder
|
||||
ret = esp_h264_dec_sw_new(&dec_cfg, &dec);
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "Failed to create H264 decoder (error: %d)", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ret = esp_h264_dec_open(dec);
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "Failed to open H264 decoder (error: %d)", ret);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "H264 encode-decode loop started (%dx%d @ %dfps)",
|
||||
enc_cfg.res.width, enc_cfg.res.height, enc_cfg.fps);
|
||||
|
||||
while (1) {
|
||||
// Generate input pattern
|
||||
gen_pattern_color_bar(&in_pattern);
|
||||
// Encode frame
|
||||
ret = esp_h264_enc_process(enc, &src_frame, &enc_frame);
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "H264 encoding failed (error: %d)", ret);
|
||||
break;
|
||||
}
|
||||
//update decoder input
|
||||
dec_input.raw_data.len = enc_frame.length;
|
||||
// Decode frame
|
||||
ret = esp_h264_dec_process(dec, &dec_input, &dest_frame);
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "H264 decoding failed (error: %d)", ret);
|
||||
break;
|
||||
}
|
||||
out_pattern.pixel = dest_frame.outbuf;
|
||||
// Display conversion result
|
||||
draw_convert_result(&in_pattern, &out_pattern);
|
||||
printf("\nFrame %d: source image | decoded image\n", frame_num);
|
||||
frame_num++;
|
||||
if (frame_num >= FRAME_MAX_NUM) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
cleanup:
|
||||
// Cleanup encoder
|
||||
esp_h264_enc_close(enc);
|
||||
esp_h264_enc_del(enc);
|
||||
// Cleanup decoder
|
||||
esp_h264_dec_close(dec);
|
||||
esp_h264_dec_del(dec);
|
||||
// Free memory buffers
|
||||
if (src_frame.raw_data.buffer) {
|
||||
esp_h264_free(src_frame.raw_data.buffer);
|
||||
}
|
||||
if (enc_frame.raw_data.buffer) {
|
||||
esp_h264_free(enc_frame.raw_data.buffer);
|
||||
}
|
||||
ESP_LOGI(TAG, "H264 process %s", (ret == ESP_H264_ERR_OK) ? "Completed successfully" : "Failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
void app_main(void)
|
||||
{
|
||||
|
||||
#if CONFIG_H264_ENCODER_HARDWARE
|
||||
esp_h264_enc_cfg_hw_t enc_cfg = {
|
||||
.gop = CONFIG_H264_ENCODER_GOP_SIZE,
|
||||
.fps = CONFIG_H264_ENCODER_FPS,
|
||||
.res = {.width = CONFIG_H264_ENCODER_WIDTH, .height = CONFIG_H264_ENCODER_HEIGHT},
|
||||
.rc = {
|
||||
.bitrate = CONFIG_H264_ENCODER_BITRATE,
|
||||
.qp_min = CONFIG_H264_ENCODER_QP_VALUE,
|
||||
.qp_max = CONFIG_H264_ENCODER_QP_VALUE
|
||||
},
|
||||
.pic_type = ESP_H264_RAW_FMT_O_UYY_E_VYY,
|
||||
};
|
||||
#else
|
||||
esp_h264_enc_cfg_sw_t enc_cfg = {
|
||||
.gop = CONFIG_H264_ENCODER_GOP_SIZE,
|
||||
.fps = CONFIG_H264_ENCODER_FPS,
|
||||
.res = {.width = CONFIG_H264_ENCODER_WIDTH, .height = CONFIG_H264_ENCODER_HEIGHT},
|
||||
.rc = {
|
||||
.bitrate = CONFIG_H264_ENCODER_BITRATE,
|
||||
.qp_min = CONFIG_H264_ENCODER_QP_VALUE,
|
||||
.qp_max = CONFIG_H264_ENCODER_QP_VALUE
|
||||
},
|
||||
.pic_type = ESP_H264_RAW_FMT_I420,
|
||||
};
|
||||
#endif /* CONFIG_H264_ENCODER_HARDWARE */
|
||||
|
||||
// Always use software decoder since decoder choice was removed
|
||||
esp_h264_dec_cfg_sw_t dec_cfg = {
|
||||
.pic_type = ESP_H264_RAW_FMT_I420,
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "H264 Example starting: %dx%d @ %dfps",
|
||||
CONFIG_H264_ENCODER_WIDTH, CONFIG_H264_ENCODER_HEIGHT, CONFIG_H264_ENCODER_FPS);
|
||||
ESP_LOGI(TAG, "Encoder: %s, Decoder: Software",
|
||||
#if CONFIG_H264_ENCODER_HARDWARE
|
||||
"Hardware"
|
||||
#else
|
||||
"Software"
|
||||
#endif
|
||||
);
|
||||
// Fixed format specifiers to use PRIu32 for uint32_t values
|
||||
ESP_LOGI(TAG, "Config: GOP=%d, Bitrate=%" PRIu32 " bps, QP=%d",
|
||||
CONFIG_H264_ENCODER_GOP_SIZE, CONFIG_H264_ENCODER_BITRATE, CONFIG_H264_ENCODER_QP_VALUE);
|
||||
|
||||
// Start encode-decode process
|
||||
esp_h264_err_t ret = single_enc_dec_process(enc_cfg, dec_cfg);
|
||||
if (ret != ESP_H264_ERR_OK) {
|
||||
ESP_LOGE(TAG, "H264 example failed with error: %d", ret);
|
||||
}
|
||||
}
|
4
examples/peripherals/h264/main/idf_component.yml
Normal file
4
examples/peripherals/h264/main/idf_component.yml
Normal file
@ -0,0 +1,4 @@
|
||||
dependencies:
|
||||
espressif/esp_h264: "^1.0.4"
|
||||
idf:
|
||||
version: ">=5.3.0"
|
358
examples/peripherals/h264/main/video_pattern.c
Normal file
358
examples/peripherals/h264/main/video_pattern.c
Normal file
@ -0,0 +1,358 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file video_pattern.c
|
||||
* @brief Video pattern generation and processing implementation
|
||||
*
|
||||
* This file implements functions for generating test video patterns
|
||||
* and displaying conversion results for H264 codec testing.
|
||||
*/
|
||||
|
||||
#include "video_pattern.h"
|
||||
|
||||
#define GET_RGB565_R(x) (((((x) >> 11) & 0x1F) << 3) | (((x) >> 8) & 0x07))
|
||||
#define GET_RGB565_G(x) (((((x) >> 5) & 0x3F) << 2) | (((x) >> 3) & 0x03))
|
||||
#define GET_RGB565_B(x) ((((x) & 0x1F) << 3) | (((x) & 0x1C) >> 2))
|
||||
#define SWAP_EDIAN(x) (((x) << 8) | ((x) >> 8))
|
||||
#define CLAMP(x) ((x) < 0 ? 0 : ((x) > 255 ? 255 : (x)))
|
||||
|
||||
/**
|
||||
* @brief YUV pixel structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t y; /*!< Y (luma) component */
|
||||
uint8_t u; /*!< U (chroma) component */
|
||||
uint8_t v; /*!< V (chroma) component */
|
||||
} yuv_pixel_t;
|
||||
|
||||
/**
|
||||
* @brief RGB888 pixel structure
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t r; /*!< Red component */
|
||||
uint8_t g; /*!< Green component */
|
||||
uint8_t b; /*!< Blue component */
|
||||
} rgb888_pixel_t;
|
||||
|
||||
static void yuv_to_rgb(uint8_t y, uint8_t u, uint8_t v, rgb888_pixel_t *pixel)
|
||||
{
|
||||
int c = y - 16;
|
||||
int d = u - 128;
|
||||
int e = v - 128;
|
||||
int r_temp = (298 * c + 409 * e + 128) >> 8; // R = Y + 1.403 * (V-128)
|
||||
int g_temp = (298 * c - 100 * d - 208 * e + 128) >> 8; // G = Y - 0.344 * (U-128) - 0.714 * (V-128)
|
||||
int b_temp = (298 * c + 516 * d + 128) >> 8; // B = Y + 1.770 * (U-128)
|
||||
pixel->r = CLAMP(r_temp);
|
||||
pixel->g = CLAMP(g_temp);
|
||||
pixel->b = CLAMP(b_temp);
|
||||
}
|
||||
|
||||
static void get_pixel(pattern_info_t *info, rgb888_pixel_t *pixel, int x, int y)
|
||||
{
|
||||
uint8_t *data = info->pixel;
|
||||
switch (info->format_id) {
|
||||
case ESP_H264_RAW_FMT_YUYV: {
|
||||
x = (x >> 1 << 1);
|
||||
uint8_t *yuyv = data + y * info->res.width * 2 + x * 2;
|
||||
yuv_to_rgb(yuyv[0], yuyv[1], yuyv[3], pixel);
|
||||
break;
|
||||
}
|
||||
case ESP_H264_RAW_FMT_I420: {
|
||||
uint8_t *py = data + y * info->res.width + x;
|
||||
y >>= 1;
|
||||
x >>= 1;
|
||||
uint8_t *pu = data + info->res.height * info->res.width + y * info->res.width / 2 + x;
|
||||
uint8_t *pv = data + info->res.height * info->res.width * 5 / 4 + y * info->res.width / 2 + x;
|
||||
yuv_to_rgb(py[0], pu[0], pv[0], pixel);
|
||||
break;
|
||||
}
|
||||
case ESP_H264_RAW_FMT_O_UYY_E_VYY: {
|
||||
uint8_t *uyy = data + (y >> 1) * info->res.width * 3 + (x >> 1) * 3;
|
||||
uint8_t *vyy = uyy + info->res.width * 3 / 2;
|
||||
uint8_t y_pixel = (y & 1) ? vyy[1 + (x & 1)] : uyy[1 + (x & 1)];
|
||||
yuv_to_rgb(y_pixel, uyy[0], vyy[0], pixel);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
esp_err_t gen_pattern_color_bar(pattern_info_t *info)
|
||||
{
|
||||
uint8_t *pixel = info->pixel;
|
||||
bool vertical = info->vertical;
|
||||
uint8_t n = info->bar_count;
|
||||
|
||||
switch (info->format_id) {
|
||||
case ESP_H264_RAW_FMT_I420: {
|
||||
yuv_pixel_t *color = (yuv_pixel_t *)malloc(n * sizeof(yuv_pixel_t));
|
||||
if (color == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
color[i].y = (uint8_t)(rand() & 0xFF);
|
||||
color[i].u = (uint8_t)(rand() & 0xFF);
|
||||
color[i].v = (uint8_t)(rand() & 0xFF);
|
||||
}
|
||||
if (vertical) {
|
||||
uint32_t bar_w = (info->res.width / n) >> 1 << 1;
|
||||
uint32_t last_bar_w = info->res.width - bar_w * (n - 1);
|
||||
// Fill Y firstly
|
||||
for (int y = 0; y < info->res.height; y++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_w : bar_w);
|
||||
memset(pixel, color[i].y, bytes);
|
||||
pixel += bytes;
|
||||
}
|
||||
}
|
||||
// Fill U
|
||||
for (int y = 0; y < info->res.height >> 1; y++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_w : bar_w) >> 1;
|
||||
memset(pixel, color[i].u, bytes);
|
||||
pixel += bytes;
|
||||
}
|
||||
}
|
||||
// Fill V
|
||||
for (int y = 0; y < info->res.height >> 1; y++) {
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_w : bar_w) >> 1;
|
||||
memset(pixel, color[i].v, bytes);
|
||||
pixel += bytes;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t bar_h = (info->res.height / n) >> 1 << 1;
|
||||
uint32_t last_bar_h = info->res.height - bar_h * (n - 1);
|
||||
// Fill Y firstly
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_h : bar_h) * info->res.width;
|
||||
memset(pixel, color[i].y, bytes);
|
||||
pixel += bytes;
|
||||
}
|
||||
// Fill U
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_h : bar_h) * info->res.width >> 2;
|
||||
memset(pixel, color[i].u, bytes);
|
||||
pixel += bytes;
|
||||
}
|
||||
// Fill V
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_h : bar_h) * info->res.width >> 2;
|
||||
memset(pixel, color[i].v, bytes);
|
||||
pixel += bytes;
|
||||
}
|
||||
}
|
||||
free(color);
|
||||
} break;
|
||||
case ESP_H264_RAW_FMT_YUYV: {
|
||||
yuv_pixel_t *color = (yuv_pixel_t *)malloc(n * sizeof(yuv_pixel_t));
|
||||
if (color == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
color[i].y = (uint8_t)(rand() & 0xFF);
|
||||
color[i].u = (uint8_t)(rand() & 0xFF);
|
||||
color[i].v = (uint8_t)(rand() & 0xFF);
|
||||
}
|
||||
if (vertical) {
|
||||
uint32_t bar_w = (info->res.width / n) >> 1 << 1;
|
||||
// Fill Y firstly
|
||||
for (int y = 0; y < info->res.height; y++) {
|
||||
int bar_filled = 0;
|
||||
int i = 0;
|
||||
for (int x = 0; x < (info->res.width >> 1); x++) {
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].u;
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].v;
|
||||
bar_filled += 2;
|
||||
if (bar_filled >= bar_w) {
|
||||
bar_filled = 0;
|
||||
if (i < n - 1) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t bar_h = (info->res.height / n) >> 1 << 1;
|
||||
uint32_t last_bar_h = info->res.height - bar_h * (n - 1);
|
||||
// Fill Y firstly
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t bytes = (i == n - 1 ? last_bar_h : bar_h) * info->res.width * 3 / 2;
|
||||
while (bytes > 0) {
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].u;
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].v;
|
||||
bytes -= 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(color);
|
||||
} break;
|
||||
case ESP_H264_RAW_FMT_O_UYY_E_VYY: {
|
||||
yuv_pixel_t *color = (yuv_pixel_t *)malloc(n * sizeof(yuv_pixel_t));
|
||||
if (color == NULL) {
|
||||
return ESP_FAIL;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
color[i].y = (uint8_t)(rand() & 0xFF);
|
||||
color[i].u = (uint8_t)(rand() & 0xFF);
|
||||
color[i].v = (uint8_t)(rand() & 0xFF);
|
||||
}
|
||||
if (vertical) {
|
||||
uint32_t bar_w = (info->res.width / n) >> 1 << 1;
|
||||
// Fill Y firstly
|
||||
for (int y = 0; y < (info->res.height >> 1); y++) {
|
||||
int bar_filled = 0;
|
||||
int i = 0;
|
||||
for (int x = 0; x < (info->res.width >> 1); x++) {
|
||||
*pixel++ = color[i].u;
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].y;
|
||||
bar_filled += 2;
|
||||
if (bar_filled >= bar_w) {
|
||||
bar_filled = 0;
|
||||
if (i < n - 1) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
bar_filled = 0;
|
||||
i = 0;
|
||||
for (int x = 0; x < (info->res.width >> 1); x++) {
|
||||
*pixel++ = color[i].v;
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].y;
|
||||
bar_filled += 2;
|
||||
if (bar_filled >= bar_w) {
|
||||
bar_filled = 0;
|
||||
if (i < n - 1) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
uint32_t bar_h = (info->res.height / n) >> 1 << 1;
|
||||
uint32_t last_bar_h = info->res.height - bar_h * (n - 1);
|
||||
// Fill Y firstly
|
||||
for (int i = 0; i < n; i++) {
|
||||
uint32_t height = (i == n - 1 ? last_bar_h : bar_h);
|
||||
uint32_t width = info->res.width >> 1;
|
||||
for (int y = 0; y < (height >> 1); y++) {
|
||||
for (int x = 0; x < width; x++) {
|
||||
*pixel++ = color[i].u;
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].y;
|
||||
}
|
||||
for (int x = 0; x < width; x++) {
|
||||
*pixel++ = color[i].v;
|
||||
*pixel++ = color[i].y;
|
||||
*pixel++ = color[i].y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free(color);
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void draw_convert_result(pattern_info_t *a, pattern_info_t *b)
|
||||
{
|
||||
if (a->bar_count == 0) {
|
||||
return;
|
||||
}
|
||||
printf("\n");
|
||||
int y = 0;
|
||||
rgb888_pixel_t block_start = {};
|
||||
rgb888_pixel_t block_end = {};
|
||||
|
||||
if (a->bar_count == b->bar_count) {
|
||||
int n = a->bar_count;
|
||||
uint32_t bar_w = (a->res.width / n) >> 1 << 1;
|
||||
uint32_t last_bar_w = a->res.width - bar_w * (n - 1);
|
||||
uint32_t bar_h = a->res.height / n;
|
||||
|
||||
uint32_t bar_w_b = (b->res.width / n) >> 1 << 1;
|
||||
uint32_t last_bar_w_b = b->res.width - bar_w_b * (n - 1);
|
||||
uint32_t bar_h_b = b->res.height / n;
|
||||
int y_b = 0;
|
||||
|
||||
for (int col = 0; col < n; col++) {
|
||||
int x = 0;
|
||||
for (int row = 0; row < n; row++) {
|
||||
get_pixel(a, &block_start, x, y);
|
||||
x += (row == n - 1 ? last_bar_w : bar_w);
|
||||
get_pixel(a, &block_end, x - 1, y);
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_start.r, block_start.g, block_start.b, ' ');
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_end.r, block_end.g, block_end.b, ' ');
|
||||
}
|
||||
if (b->pixel) {
|
||||
printf(" | ");
|
||||
x = 0;
|
||||
for (int row = 0; row < n; row++) {
|
||||
get_pixel(b, &block_start, x, y_b);
|
||||
x += (row == n - 1 ? last_bar_w_b : bar_w_b);
|
||||
get_pixel(b, &block_end, x - 1, y_b);
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_start.r, block_start.g, block_start.b, ' ');
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_end.r, block_end.g, block_end.b, ' ');
|
||||
}
|
||||
y_b += bar_h_b;
|
||||
}
|
||||
y += bar_h;
|
||||
printf("\n");
|
||||
}
|
||||
} else {
|
||||
// Draw image
|
||||
int n = a->bar_count;
|
||||
uint32_t bar_w = (a->res.width / n) >> 1 << 1;
|
||||
uint32_t last_bar_w = a->res.width - bar_w * (n - 1);
|
||||
uint32_t bar_h = a->res.height / n;
|
||||
|
||||
printf("A:\n");
|
||||
for (int col = 0, y = 0; col < n; col++, y += bar_h) {
|
||||
int x = 0;
|
||||
printf("║ ");
|
||||
for (int row = 0; row < n; row++) {
|
||||
get_pixel(a, &block_start, x, y);
|
||||
x += (row == n - 1 ? last_bar_w : bar_w);
|
||||
get_pixel(a, &block_end, x - 1, y);
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_start.r, block_start.g, block_start.b, ' ');
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_end.r, block_end.g, block_end.b, ' ');
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
if (b->pixel) {
|
||||
uint32_t bar_w = (b->res.width / n) >> 1 << 1;
|
||||
uint32_t last_bar_w = b->res.width - bar_w * (n - 1);
|
||||
uint32_t bar_h = b->res.height / n;
|
||||
|
||||
printf("B:\n");
|
||||
for (int col = 0, y = 0; col < n; col++, y += bar_h) {
|
||||
int x = 0;
|
||||
printf("║ ");
|
||||
for (int row = 0; row < n; row++) {
|
||||
get_pixel(b, &block_start, x, y);
|
||||
x += (row == n - 1 ? last_bar_w : bar_w);
|
||||
get_pixel(b, &block_end, x - 1, y);
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_start.r, block_start.g, block_start.b, ' ');
|
||||
printf("\033[48;2;%d;%d;%dm%c\033[0m", block_end.r, block_end.g, block_end.b, ' ');
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
64
examples/peripherals/h264/main/video_pattern.h
Normal file
64
examples/peripherals/h264/main/video_pattern.h
Normal file
@ -0,0 +1,64 @@
|
||||
/**
|
||||
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file video_pattern.h
|
||||
* @brief Video pattern generation and processing utilities for H264 encoding/decoding examples
|
||||
*
|
||||
* This header provides structures and functions for generating test video patterns
|
||||
* and displaying conversion results for H264 codec testing.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "esp_err.h"
|
||||
#include "esp_h264_types.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/**
|
||||
* @brief Video resolution definition
|
||||
*/
|
||||
typedef struct {
|
||||
uint16_t width; /*!< Width of the video in pixels */
|
||||
uint16_t height; /*!< Height of the video in pixels */
|
||||
} video_resolution_t;
|
||||
|
||||
/**
|
||||
* @brief Pattern information structure for video pattern generation
|
||||
*/
|
||||
typedef struct {
|
||||
esp_h264_raw_format_t format_id; /*!< Video format identifier */
|
||||
video_resolution_t res; /*!< Video resolution */
|
||||
uint8_t *pixel; /*!< Pixel data buffer */
|
||||
uint32_t data_size; /*!< Size of pixel data in bytes */
|
||||
bool vertical; /*!< Vertical orientation flag */
|
||||
uint8_t bar_count; /*!< Number of color bars */
|
||||
} pattern_info_t;
|
||||
|
||||
/**
|
||||
* @brief Generate color bar pattern for video testing
|
||||
* @param info Pointer to pattern information structure
|
||||
* @return
|
||||
* - ESP_OK on success
|
||||
* - ESP_FAIL on error
|
||||
*/
|
||||
esp_err_t gen_pattern_color_bar(pattern_info_t *info);
|
||||
|
||||
/**
|
||||
* @brief Draw and display conversion result comparison
|
||||
* @param a Pointer to source pattern information
|
||||
* @param b Pointer to destination pattern information
|
||||
*/
|
||||
void draw_convert_result(pattern_info_t *a, pattern_info_t *b);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
17
examples/peripherals/h264/pytest_esp_h264.py
Normal file
17
examples/peripherals/h264/pytest_esp_h264.py
Normal file
@ -0,0 +1,17 @@
|
||||
# SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
import pytest
|
||||
from pytest_embedded import Dut
|
||||
from pytest_embedded_idf.utils import idf_parametrize
|
||||
|
||||
|
||||
@pytest.mark.octal_psram
|
||||
@idf_parametrize('target', ['esp32s3'], indirect=['target'])
|
||||
def test_esp_h264_esp32s3(dut: Dut) -> None:
|
||||
dut.expect_exact('H264 process Completed successfully')
|
||||
|
||||
|
||||
@pytest.mark.generic
|
||||
@idf_parametrize('target', ['esp32p4'], indirect=['target'])
|
||||
def test_esp_h264_esp32p4(dut: Dut) -> None:
|
||||
dut.expect_exact('H264 process Completed successfully')
|
17
examples/peripherals/h264/sdkconfig.defaults
Normal file
17
examples/peripherals/h264/sdkconfig.defaults
Normal file
@ -0,0 +1,17 @@
|
||||
CONFIG_SPIRAM=y
|
||||
|
||||
CONFIG_ESP_MAIN_TASK_STACK_SIZE=10240
|
||||
|
||||
# FreeRTOS configurations
|
||||
CONFIG_FREERTOS_HZ=1000
|
||||
|
||||
# H264 IRAM Configuration Notes:
|
||||
# When LDGEN_CHECK_MAPPING="1" strict memory mapping check is enabled, linking errors may occur
|
||||
# Cause: Prebuilt libtinyh264.a library doesn't support forced IRAM placement
|
||||
# Solutions:
|
||||
# Disable IRAM optimization: CONFIG_ESP_H264_DECODER_IRAM=n
|
||||
CONFIG_ESP_H264_DECODER_IRAM=n
|
||||
|
||||
# This case uses the terminal to print the brief diagrams before encoding and after decoding.
|
||||
# Turn off the watchdog to ensure the integrity of the picture printing
|
||||
CONFIG_ESP_TASK_WDT_EN=n
|
7
examples/peripherals/h264/sdkconfig.defaults.esp32p4
Normal file
7
examples/peripherals/h264/sdkconfig.defaults.esp32p4
Normal file
@ -0,0 +1,7 @@
|
||||
# SPIRAM configurations for ESP32P4
|
||||
CONFIG_IDF_EXPERIMENTAL_FEATURES=y
|
||||
CONFIG_SPIRAM_MODE_HEX=y
|
||||
CONFIG_SPIRAM_SPEED_200M=y
|
||||
|
||||
# CPU configuration
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_360=y
|
6
examples/peripherals/h264/sdkconfig.defaults.esp32s3
Normal file
6
examples/peripherals/h264/sdkconfig.defaults.esp32s3
Normal file
@ -0,0 +1,6 @@
|
||||
# SPIRAM configurations for ESP32S3
|
||||
CONFIG_SPIRAM_MODE_OCT=y
|
||||
CONFIG_SPIRAM_SPEED_80M=y
|
||||
|
||||
# CPU configuration
|
||||
CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ_240=y
|
Reference in New Issue
Block a user