mirror of
https://github.com/espressif/esp-idf.git
synced 2026-10-01 10:40:47 +03:00
fix(jpeg): JPEG can encode and decode in encryption situation
This commit is contained in:
@@ -17,15 +17,18 @@ Functional Overview
|
||||
|
||||
This document covers the following sections:
|
||||
|
||||
- `Resource Allocation <#resource-allocation>`__ - covers how to allocate JPEG resources with properly set of configurations. It also covers how to recycle the resources when they finished working.
|
||||
- `Finite State Machine <#finite-state-machine>`__ - covers JPEG workflow. Introduce how jpeg driver uses internal resources and its software process.
|
||||
- `JPEG Decoder Engine <#jpeg-decoder-engine>`__ - covers behavior of JPEG decoder engine. Introduce how to use decoder engine functions to decode an image (from jpg format to raw format).
|
||||
- `JPEG Encoder Engine <#jpeg-encoder-engine>`__ - covers behavior of JPEG encoder engine. Introduce how to use encoder engine functions to encode an image (from raw format to jpg format).
|
||||
- `Performance Overview <#performance-overview>`__ - covers encoder and decoder performance.
|
||||
- `Pixel Storage Layout for Different Color Formats <#pixel-storage-layout-for-different-color-formats>`__ - covers color space order overview required in this JPEG decoder and encoder.
|
||||
- `Thread Safety <#thread-safety>`__ - lists which APIs are guaranteed to be thread safe by the driver.
|
||||
- `Power Management <#power-management>`__ - describes how JPEG driver would be affected by power consumption.
|
||||
- `Kconfig Options <#kconfig-options>`__ - lists the supported Kconfig options that can bring different effects to the driver.
|
||||
- :ref:`jpeg-resource-allocation` - covers how to allocate JPEG resources with properly set of configurations. It also covers how to recycle the resources when they finished working.
|
||||
- :ref:`jpeg-finite-state-machine` - covers JPEG workflow. Introduce how jpeg driver uses internal resources and its software process.
|
||||
- :ref:`jpeg-decoder-engine` - covers behavior of JPEG decoder engine. Introduce how to use decoder engine functions to decode an image (from jpg format to raw format).
|
||||
- :ref:`jpeg-encoder-engine` - covers behavior of JPEG encoder engine. Introduce how to use encoder engine functions to encode an image (from raw format to jpg format).
|
||||
- :ref:`jpeg-performance-overview` - covers encoder and decoder performance.
|
||||
- :ref:`jpeg-pixel-storage-layout` - covers color space order overview required in this JPEG decoder and encoder.
|
||||
- :ref:`jpeg-thread-safety` - lists which APIs are guaranteed to be thread safe by the driver.
|
||||
- :ref:`jpeg-power-management` - describes how JPEG driver would be affected by power consumption.
|
||||
- :ref:`jpeg-flash-encryption` - describes how to use the JPEG codec correctly when flash/PSRAM encryption is enabled.
|
||||
- :ref:`jpeg-kconfig-options` - lists the supported Kconfig options that can bring different effects to the driver.
|
||||
|
||||
.. _jpeg-resource-allocation:
|
||||
|
||||
Resource Allocation
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
@@ -85,6 +88,8 @@ If a previously installed JPEG engine is no longer needed, it's recommended to r
|
||||
|
||||
ESP_ERROR_CHECK(jpeg_del_encoder_engine(encoder_engine));
|
||||
|
||||
.. _jpeg-finite-state-machine:
|
||||
|
||||
Finite State Machine
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -96,6 +101,8 @@ The JPEG driver usage of hardware resources and its process workflow are shown i
|
||||
|
||||
JPEG finite state machine
|
||||
|
||||
.. _jpeg-decoder-engine:
|
||||
|
||||
JPEG Decoder Engine
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -153,6 +160,8 @@ There are some tips that can help you use this driver more accurately:
|
||||
|
||||
3. If the source JPEG uses YUV420 or YUV422 sampling, the decoded output dimensions can be padded up to 16-pixel boundaries. For example, if the visible image size is 1080*1920, the decoder may require an output buffer sized for 1088*1920 pixels. This comes from the JPEG block layout, so please provide enough output buffer memory for the padded image, not only for the visible width and height.
|
||||
|
||||
.. _jpeg-encoder-engine:
|
||||
|
||||
JPEG Encoder Engine
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -173,40 +182,46 @@ The format conversions supported by this driver are listed in the table below:
|
||||
- GRAY
|
||||
|
||||
|
||||
Below is the example of code that encodes a 1080*1920 picture:
|
||||
Below is the example of code that encodes a 1280x720 picture from an embedded raw buffer:
|
||||
|
||||
.. code:: c
|
||||
|
||||
int raw_size_1080p = 0;/* Your raw image size */
|
||||
size_t raw_size_720p = EXAMPLE_WIDTH * EXAMPLE_HEIGHT * 3; /* 1280x720 bgr24 frame */
|
||||
jpeg_encode_cfg_t enc_config = {
|
||||
.src_type = JPEG_ENCODE_IN_FORMAT_RGB888,
|
||||
.sub_sample = JPEG_DOWN_SAMPLING_YUV422,
|
||||
.image_quality = 80,
|
||||
.width = 1920,
|
||||
.height = 1080,
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.pixel_reverse = false, // Whether to reverse the pixel order of the input image, or pixel order detail please refer to technical reference manual
|
||||
};
|
||||
|
||||
uint8_t *raw_buf_1080p = (uint8_t*)jpeg_alloc_encoder_mem(raw_size_1080p);
|
||||
if (raw_buf_1080p == NULL) {
|
||||
ESP_LOGE(TAG, "alloc 1080p tx buffer error");
|
||||
return;
|
||||
}
|
||||
uint8_t *jpg_buf_1080p = (uint8_t*)jpeg_alloc_encoder_mem(raw_size_1080p / 10); // Assume that compression ratio of 10 to 1
|
||||
if (jpg_buf_1080p == NULL) {
|
||||
ESP_LOGE(TAG, "alloc jpg_buf_1080p error");
|
||||
jpeg_encode_memory_alloc_cfg_t rx_mem_cfg = {
|
||||
.buffer_direction = JPEG_ENC_ALLOC_OUTPUT_BUFFER,
|
||||
};
|
||||
size_t jpg_buffer_size = 0;
|
||||
uint8_t *jpg_buf_720p = (uint8_t*)jpeg_alloc_encoder_mem(raw_size_720p / 10, &rx_mem_cfg, &jpg_buffer_size);
|
||||
if (jpg_buf_720p == NULL) {
|
||||
ESP_LOGE(TAG, "alloc jpg_buf_720p error");
|
||||
return;
|
||||
}
|
||||
|
||||
ESP_ERROR_CHECK(jpeg_encoder_process(jpeg_handle, &enc_config, raw_buf_1080p, raw_size_1080p, jpg_buf_1080p, &jpg_size_1080p););
|
||||
/* The current JPEG encoder input path expects BGR24-style raw bytes for
|
||||
* JPEG_ENCODE_IN_FORMAT_RGB888. The embedded asset can be read directly
|
||||
* from flash as long as it remains valid until this call returns. */
|
||||
ESP_ERROR_CHECK(jpeg_encoder_process(jpeg_handle, &enc_config, embedded_bgr24_start, raw_size_720p, jpg_buf_720p, jpg_buffer_size, &jpg_size_720p));
|
||||
|
||||
There are some tips that can help you use this driver more accurately:
|
||||
|
||||
1. In above code, you should make sure the `raw_buf_1080p` and `jpg_buf_1080p` should aligned by calling :cpp:func:`jpeg_alloc_encoder_mem`.
|
||||
1. In the above code, the output buffer `jpg_buf_720p` should be allocated by calling :cpp:func:`jpeg_alloc_encoder_mem`, because the JPEG bitstream buffer must satisfy the driver's alignment requirements.
|
||||
|
||||
2. The content of `raw_buf_1080p` buffer should not be changed until :cpp:func:`jpeg_encoder_process` returns.
|
||||
2. The content pointed to by `embedded_bgr24_start` should not be changed until :cpp:func:`jpeg_encoder_process` returns. This input buffer can come from flash-mapped embedded data or another memory region that stays readable for the full call.
|
||||
|
||||
3. The compression ratio depends on the chosen `image_quality` and the content of the image itself. Generally, a higher `image_quality` value obviously results in better image quality but a smaller compression ratio. As for the image content, it is hard to give any specific guidelines, so this question is out of the scope of this document. Generally, the baseline JPEG compression ratio can vary from 40:1 to 10:1. Please take the actual situation into account.
|
||||
3. For :cpp:enumerator:`JPEG_ENCODE_IN_FORMAT_RGB888`, the current driver expects the raw input bytes in a BGR24-style layout. Supplying RGB24 raw data would swap the red and blue channels in the encoded JPEG.
|
||||
|
||||
4. The compression ratio depends on the chosen `image_quality` and the content of the image itself. Generally, a higher `image_quality` value obviously results in better image quality but a smaller compression ratio. As for the image content, it is hard to give any specific guidelines, so this question is out of the scope of this document. Generally, the baseline JPEG compression ratio can vary from 40:1 to 10:1. Please take the actual situation into account.
|
||||
|
||||
.. _jpeg-performance-overview:
|
||||
|
||||
Performance Overview
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
@@ -339,6 +354,8 @@ JPEG encoder performance
|
||||
.. [#] Format of Original Image
|
||||
.. [#] Down sampling method
|
||||
|
||||
.. _jpeg-pixel-storage-layout:
|
||||
|
||||
Pixel Storage Layout for Different Color Formats
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -415,11 +432,15 @@ In the following picture, each small block means one byte.
|
||||
|
||||
YUV420 pixel order
|
||||
|
||||
.. _jpeg-thread-safety:
|
||||
|
||||
Thread Safety
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The factory function :cpp:func:`jpeg_new_decoder_engine`, :cpp:func:`jpeg_decoder_get_info`, :cpp:func:`jpeg_decoder_process`, and :cpp:func:`jpeg_del_decoder_engine` are guaranteed to be thread safe by the driver, which means, user can call them from different RTOS tasks without protection by extra locks.
|
||||
|
||||
.. _jpeg-power-management:
|
||||
|
||||
Power Management
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -427,6 +448,26 @@ When power management is enabled (i.e., :ref:`CONFIG_PM_ENABLE` is set), the sys
|
||||
|
||||
Whenever the user is decoding or encoding via JPEG (i.e., calling :cpp:func:`jpeg_encoder_process` or :cpp:func:`jpeg_decoder_process`), the driver guarantees that the power management lock is acquired by setting it to :cpp:enumerator:`esp_pm_lock_type_t::ESP_PM_CPU_FREQ_MAX`. Once the encoding or decoding is finished, the driver releases the lock and the system can enter Light-sleep.
|
||||
|
||||
.. _jpeg-flash-encryption:
|
||||
|
||||
Usage Under Encryption
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The JPEG codec moves data via the 2D-DMA, and the JPEG codec **cannot process encrypted data**. Therefore, when PSRAM encryption is enabled, the JPEG input/output buffers must reside in an unencrypted memory region, otherwise encoding/decoding fails.
|
||||
|
||||
To support the encrypted scenario, the driver does the following:
|
||||
|
||||
- When ``CONFIG_SPIRAM_ENC_EXEMPT`` is enabled, :cpp:func:`jpeg_alloc_decoder_mem` and :cpp:func:`jpeg_alloc_encoder_mem` allocate buffers from the unencrypted PSRAM region (``MALLOC_CAP_SPIRAM_NO_ENC``) automatically.
|
||||
- The allocated buffers satisfy both the cache line alignment and the byte alignment required by the 2D-DMA.
|
||||
|
||||
Please note the following when using it:
|
||||
|
||||
1. It is recommended to always allocate buffers via :cpp:func:`jpeg_alloc_encoder_mem` / :cpp:func:`jpeg_alloc_decoder_mem` to ensure correct alignment and memory region.
|
||||
|
||||
2. The size of the unencrypted region is determined by ``CONFIG_SPIRAM_ENC_EXEMPT_SIZE``. Since the JPEG buffer size depends on the image resolution and cannot be predicted automatically, configure it according to the largest image you actually process. If the region is insufficient, the allocation fails and an error log is printed, suggesting to enlarge ``CONFIG_SPIRAM_ENC_EXEMPT_SIZE``. Also note that this value must not be greater than or equal to the actual PSRAM size, otherwise the unencrypted region is disabled.
|
||||
|
||||
.. _jpeg-kconfig-options:
|
||||
|
||||
Kconfig Options
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
@@ -448,7 +489,7 @@ Application Examples
|
||||
|
||||
- :example:`peripherals/jpeg/jpeg_decode` demonstrates how to use the JPEG hardware decoder to parse one embedded JPEG, decode it into RGB888, stream the raw output as base64 over UART, and validate the result with pytest.
|
||||
|
||||
- :example:`peripherals/jpeg/jpeg_encode` demonstrates how to use the JPEG hardware encoder to encode a 1080p picture, specifically converting `*.rgb` files to `*.jpg` files.
|
||||
- :example:`peripherals/jpeg/jpeg_encode` demonstrates how to use the JPEG hardware encoder to encode an embedded 720p raw picture, stream the JPEG as base64 over UART, and validate the result with pytest.
|
||||
|
||||
|
||||
API Reference
|
||||
|
||||
Reference in New Issue
Block a user