# 系统工具

[English]

GMF-Core 在框架主体之外提供两组通用模块：操作系统抽象层（OAL）和辅助工具（helpers）。前者把操作系统 / IDF 相关的系统调用收敛到统一接口，便于兼容不同版本；后者提供 URI 解析、EIGHTCC 能力标识等小工具，供处理单元与上层应用复用。

本篇覆盖这两组模块的使用接口。框架主要对象（处理链（pipeline）、处理单元（element）、数据载体（payload）、数据端口（port））见 GMF 处理链与任务调度、GMF 处理单元 与 数据流转。

## 操作系统抽象层

位于 `oal/` 目录。任何 GMF 代码涉及内存、互斥锁、线程等系统调用都通过 OAL 访问，而不是直接调用 FreeRTOS 或 IDF 的 API。OAL 内部按”目标平台 + 编译开关”路由到具体实现，因此同一份框架代码既可以运行在 ESP-IDF 上，也为后续迁移到其他 RTOS 留出抽象层。

### 内存分配

`esp_gmf_oal_malloc` / `esp_gmf_oal_calloc` / `esp_gmf_oal_realloc` 与标准 C 接口同名同义，区别在于：开启 PSRAM 时框架会按策略选择内部 RAM 或 PSRAM 分配，而不需要应用代码做判断。`esp_gmf_oal_calloc_inner()` 强制使用内部 RAM，用于对延迟敏感的场景。

    void *buf = esp_gmf_oal_calloc(1, size);
    if (!buf) {
        return ESP_GMF_ERR_MEMORY_LACK;
    }
    /* ... */
    esp_gmf_oal_free(buf);

带对齐的分配用 `esp_gmf_oal_malloc_align()`，`align` 必须是 2 的幂或 0。

### PSRAM 状态

三个查询接口让代码能感知 PSRAM 的可用性与对齐要求：

- `esp_gmf_oal_mem_spiram_is_enabled()`：当前固件是否启用了 PSRAM

- `esp_gmf_oal_mem_spiram_stack_is_enabled()`：是否允许把任务栈放在 PSRAM

- `esp_gmf_oal_get_spiram_cache_align()`：PSRAM cache 的对齐字节数

自定义处理单元需要跨 PSRAM 边界 DMA 时，用 `esp_gmf_oal_get_spiram_cache_align()` 取出对齐值，填入 `ESP_GMF_ELEMENT_*_PORT_ATTR_SET` 的 `buf_addr_aligned` / `buf_size_aligned` 字段，避免缓存一致性问题。

### 互斥锁与线程

OAL 把 FreeRTOS 的 mutex 与 task 接口包成更简洁的 API：

- `esp_gmf_oal_mutex_create` / `lock` / `unlock` / `destroy`：递归互斥锁

- `esp_gmf_oal_thread_create` / `delete`：任务创建（`delete` 接受 NULL 句柄）

线程接口接收一个 `esp_gmf_oal_thread_t` 配置（栈大小、优先级、CPU 核心、是否使用外部 SPI RAM 栈），与 `esp_gmf_task_cfg_t` 中嵌套使用的 `esp_gmf_task_config_t` 字段一致。执行线程与处理链集成时一般不直接调 OAL 线程接口，而是通过 `esp_gmf_task_init()` 间接使用。

### 调试辅助

`ESP_GMF_MEM_SHOW(tag)` 在当前位置打印堆内存状态。`esp_gmf_oal_sys_get_real_time_stats` 输出运行时任务统计，便于排查栈不足或 CPU 占用偏高。这两个接口都用宏或函数把”调用点信息”自动带进日志，调试时不需要手填行号。

## URI 解析

`esp_gmf_uri_parser` 将 `scheme://host[:port]/path?query` 格式的字符串解析为各个字段，外部接口（IO）处理单元据此判断需要选择的具体实现。典型调用：

    esp_gmf_uri_t info = { 0 };
    esp_gmf_uri_parse("http://server:8080/song.mp3?token=abc", &info);
    /* info.scheme = "http", info.host = "server", info.path = "/song.mp3" */
    esp_gmf_uri_free(&info);

解析结果中的字符串是从源字符串复制出的副本，使用结束后必须调用 `esp_gmf_uri_free()` 释放。注册池（pool）的 `esp_gmf_pool_get_io_tag_by_url()` 内部使用同一解析器；自定义外部接口实现 `get_score` 回调评估 URL 时，也建议复用此模块。

## EIGHTCC 能力标识

EIGHTCC（Eight Character Code，八字符代码）用 8 个 ASCII 字符标识处理单元能力类别。能力描述（capability）通过 `cap_eightcc` 声明处理单元属于哪一类能力，例如音频解码、音频混音、视频缩放或视频叠加。EIGHTCC 描述”能做什么”，FourCC 描述”处理什么媒体格式”；FourCC 的定义见 GMF FourCC。

`esp_gmf_caps_def.h` 按音频与视频两类定义常见 EIGHTCC。

音频能力

- `ESP_GMF_CAPS_AUDIO_DECODER` / `ESP_GMF_CAPS_AUDIO_ENCODER`：音频解码 / 编码

- `ESP_GMF_CAPS_AUDIO_RATE_CONVERT` / `ESP_GMF_CAPS_AUDIO_CHANNEL_CONVERT` / `ESP_GMF_CAPS_AUDIO_BIT_CONVERT`：采样率、声道数、位深转换

- `ESP_GMF_CAPS_AUDIO_EQUALIZER` / `ESP_GMF_CAPS_AUDIO_MIXER` / `ESP_GMF_CAPS_AUDIO_SONIC` / `ESP_GMF_CAPS_AUDIO_FADE`：常规音频效果

- `ESP_GMF_CAPS_AUDIO_AEC` / `ESP_GMF_CAPS_AUDIO_NS` / `ESP_GMF_CAPS_AUDIO_AGC` / `ESP_GMF_CAPS_AUDIO_VAD` / `ESP_GMF_CAPS_AUDIO_WWE` / `ESP_GMF_CAPS_AUDIO_VCMD`：AI 语音前端能力

- `ESP_GMF_CAPS_AUDIO_DRC` / `ESP_GMF_CAPS_AUDIO_MBC`：动态范围处理

视频能力

- `ESP_GMF_CAPS_VIDEO_DECODER` / `ESP_GMF_CAPS_VIDEO_ENCODER`：视频解码 / 编码

- `ESP_GMF_CAPS_VIDEO_COLOR_CONVERT`：颜色格式转换

- `ESP_GMF_CAPS_VIDEO_CROP` / `ESP_GMF_CAPS_VIDEO_ROTATE` / `ESP_GMF_CAPS_VIDEO_SCALE`：裁剪、旋转、缩放

- `ESP_GMF_CAPS_VIDEO_OVERLAY` / `ESP_GMF_CAPS_VIDEO_FPS_CVT`：叠加与帧率转换

字符串与数值的相互转换通过 `STR_2_EIGHTCC` / `EIGHTCC_2_STR` 宏完成；新增自定义能力标识时复用这两个宏，避免直接拼接字节。

## API 参考

本篇涉及的头文件：

- `esp_gmf_oal_mem.h`：内存分配与 PSRAM 状态查询

- `esp_gmf_oal_mutex.h`：互斥锁

- `esp_gmf_oal_thread.h`：线程封装

- `esp_gmf_oal_sys.h`：运行时统计与系统辅助

- `esp_gmf_uri_parser.h`：URI 解析

- `esp_gmf_caps_def.h`：EIGHTCC 能力标识

### Header File

- gmf_core/oal/include/esp_gmf_oal_mem.h

### Functions

void *esp_gmf_oal_malloc(size_t size)

  Allocate memory of a specified size.

  参数:

    size – [in] Size of memory to allocate, in bytes

  返回:

    - Pointer to allocated memory on success

    - NULL if an error occurs

void *esp_gmf_oal_malloc_align(uint8_t align, size_t size)

  Allocate memory with specified alignment.

  参数:

    - align – [in] Memory alignment in bytes (must be a power of 2 or 0)

    - size – [in] Size of memory to allocate, in bytes

  返回:

    - Pointer to aligned memory on success

    - NULL if an error occurs

void esp_gmf_oal_free(void *ptr)

  Free allocated memory.

  参数:

    ptr – [in] Pointer to the memory to free

void *esp_gmf_oal_calloc(size_t nmemb, size_t size)

  Allocate zero-initialized memory, if SPI RAM is enabled, memory may be allocated there.

  参数:

    - nmemb – [in] Number of elements to allocate

    - size – [in] Size of each element, in bytes

  返回:

    - Pointer to allocated and zero-initialized memory on success

    - NULL if an error occurs

void *esp_gmf_oal_calloc_inner(size_t nmemb, size_t size)

  Allocate zero-initialized memory in internal memory.

  参数:

    - nmemb – [in] Number of elements to allocate

    - size – [in] Size of each element, in bytes

  返回:

    - Pointer to allocated and zero-initialized memory on success

    - NULL if an error occurs

void esp_gmf_oal_mem_print(const char *tag, int line, const char *func)

  Print the current heap memory status.

  参数:

    - tag – [in] Log tag identifier

    - line – [in] Line number where the function is called

    - func – [in] Name of the function making the call

void *esp_gmf_oal_realloc(void *ptr, size_t size)

  Reallocate memory to a new size, if SPI RAM is enabled, the memory may be allocated there.

  参数:

    - ptr – [in] Pointer to previously allocated memory

    - size – [in] New size of memory block, in bytes

  返回:

    - Pointer to the reallocated memory block on success

    - NULL if an error occurs

char *esp_gmf_oal_strdup(const char *str)

  Duplicate a string in newly allocated memory.

  参数:

    str – [in] String to duplicate

  返回:

    - Pointer to the duplicated string in allocated memory

    - NULL if an error occurs

bool esp_gmf_oal_mem_spiram_is_enabled(void)

  Check if SPI RAM is enabled.

  返回:

    - true if SPI RAM is enabled

    - false if SPI RAM is not enabled

bool esp_gmf_oal_mem_spiram_stack_is_enabled(void)

  Check if stack allocation on external SPI RAM is enabled.

  返回:

    - true if stack allocation on SPI RAM is enabled

    - false if stack allocation on SPI RAM is not enabled

uint8_t esp_gmf_oal_get_spiram_cache_align(void)

  Get SPI RAM cache alignment.

  返回:

    - Alignment SPI RAM cache alignment

### Macros

ESP_GMF_OAL_ALIGN_UP(num, align)

ESP_GMF_OAL_ALIGN_BYTES_VALID(align)

ESP_GMF_MEM_SHOW(x)

### Header File

- gmf_core/oal/include/esp_gmf_oal_mutex.h

### Functions

void *esp_gmf_oal_mutex_create(void)

  Allocates and initializes a new mutex object for synchronization.

  返回:

    - Pointer to the newly created mutex on success

    - NULL if the mutex creation fails

int esp_gmf_oal_mutex_destroy(void *mutex)

  Destroy a mutex.

  参数:

    mutex – [in] Pointer to the mutex to destroy

  返回:

    - 0 on success

    - Negative value if an error occurs

int esp_gmf_oal_mutex_lock(void *mutex)

  Acquires a lock on the specified mutex, blocking if necessary until the lock becomes available.

  参数:

    mutex – [in] Pointer to the mutex to lock

  返回:

    - 0 on success

    - Negative value if an error occurs

int esp_gmf_oal_mutex_unlock(void *mutex)

  Releases the lock held on the specified mutex, allowing other threads to acquire the lock.

  参数:

    mutex – [in] Pointer to the mutex to unlock

  返回:

    - 0 on success

    - Negative value if an error occurs

### Header File

- gmf_core/oal/include/esp_gmf_oal_thread.h

### Functions

esp_gmf_err_t esp_gmf_oal_thread_create(esp_gmf_oal_thread_t *p_handle, const char *name, void (*main_func)(void *arg), void *arg, uint32_t stack, int prio, bool stack_in_ext, int core_id)

  This function creates a new thread, specifying its properties like name, priority, stack size, and the core to which it should be pinned.

  备注

  - Please apply the ./idf_patches/idf_v3.3/4.x_freertos.patch first

  - Please enable support for external RAM and `Allow external memory as an argument to xTaskCreateStatic` to be able to use external memory for task stack, namely `CONFIG_SPIRAM_BOOT_INIT=y` and `CONFIG_SPIRAM_ALLOW_STACK_EXTERNAL_MEMORY=y`

  参数:

    - p_handle – [out] Pointer to the thread handle that will be created

    - name – [in] The name of the thread

    - main_func – [in] The main function that the thread will execute

    - arg – [in] Argument to pass to the thread’s main function

    - stack – [in] The size of the stack (in bytes) to allocate for the thread

    - prio – [in] The priority of the thread

    - stack_in_ext – [in] If true, the stack will be allocated in external memory

    - core_id – [in] The core to pin the thread to (-1 for no pinning)

  返回:

    - ESP_GMF_ERR_OK Operation successful

    - ESP_GMF_ERR_FAIL Operation failed, usually due to insufficient memory for creating a new thread

esp_gmf_err_t esp_gmf_oal_thread_delete(esp_gmf_oal_thread_t p_handle)

  Delete an existing GMF OAL thread.

  参数:

    p_handle – [in] Pointer to the thread handle to be deleted

  返回:

    - ESP_GMR_ERR_OK Operation successful

### Type Definitions

typedef void *esp_gmf_oal_thread_t

### Header File

- gmf_core/oal/include/esp_gmf_oal_sys.h

### Functions

int esp_gmf_oal_sys_get_tick_by_time_ms(int ms)

  Get system ticks based on the given millisecond value.

  参数:

    ms – [in] Time in milliseconds

  返回:

    - The corresponding system ticks

int64_t esp_gmf_oal_sys_get_time_ms(void)

  Retrieve the current system time in milliseconds.

  返回:

    - The system time in milliseconds

esp_gmf_err_t esp_gmf_oal_sys_get_real_time_stats(int elapsed_time_ms, bool markdown)

  Print CPU usage statistics of tasks over a specified time period.

          This function measures and prints the CPU usage of tasks over a given
          period (in milliseconds) by calling `uxTaskGetSystemState()` twice,
          with a delay in between. The CPU usage is then calculated based on the
          difference in task run times before and after the delay.

  备注

  - If tasks are added or removed during the delay, their statistics will not be included in the final report

  - To minimize inaccuracies caused by delays, this function should be called from a high-priority task

  - In dual-core mode, each core will account for up to 50% of the total runtime

  参数:

    - elapsed_time_ms – [in] Time period for the CPU usage measurement in milliseconds

    - markdown – [in] Whether print use markdown format

  返回:

    - ESP_GMF_ERR_OK On success

    - ESP_GMF_ERR_MEMORY_LACK No memory for operation

    - ESP_GMF_ERR_NOT_ENOUGH More memory is needed for uxTaskGetSystemState

    - ESP_GMF_ERR_FAIL On failure

### Macros

FALL_THROUGH

### Header File

- gmf_core/helpers/include/esp_gmf_uri_parser.h

### Functions

int esp_gmf_uri_parse(const char *uri_str, esp_gmf_uri_t **uri_out)

  Parses a URI string and populates a esp_gmf_uri_t structure with its components.

          This function takes a URI string as input, parses it, and allocates and populates a
          `esp_gmf_uri_t` structure with the parsed components. The caller is responsible for
          freeing the allocated memory using `esp_gmf_uri_free()`.

  参数:

    - uri_str – [in] The URI string to be parsed

    - uri_out – [out] Pointer to the `esp_gmf_uri_t` structure where the parsed URI components will be stored

  返回:

    - 0 On success

    - Non-zero Error code on failure

void esp_gmf_uri_free(esp_gmf_uri_t *uri)

  Frees the memory allocated for a esp_gmf_uri_t object.

          This function releases all dynamically allocated memory associated with the URI components
          within the given `esp_gmf_uri_t` structure. After calling this function, the URI pointer will be invalid.

  参数:

    uri – [in] Pointer to the `esp_gmf_uri_t` object to be freed

### Structures

struct esp_gmf_uri_t

  Structure representing a parsed URI.

          This structure holds different components of a URI such as scheme, userinfo,
          host, port, path, query, etc. Each field corresponds to a specific part of the URI

  Public Members

  char *scheme

    The scheme of the URI (e.g., “http”, “https”)

  char *userinfo

    The userinfo component (optional, may include username and password)

  char *username

    The username part of the userinfo, if present

  char *password

    The password part of the userinfo, if present

  char *host

    The host (e.g., domain name or IP address)

  int port

    The port number (optional, if not specified, defaults to scheme’s standard port)

  char *path

    The path component of the URI

  char *query

    The query string of the URI (optional, starts after ‘?’ in URL)

  char *fragment

    The fragment identifier (optional, starts after ‘#’ in URL)

### Header File

- gmf_core/helpers/include/esp_gmf_caps_def.h

### Functions

static inline uint64_t gmf_str_to_cc(const char *str, int max_len)

static inline void gmf_eightcc_to_str(uint64_t eightcc, char out[9])

### Macros

STR_2_EIGHTCC(str)

STR_2_FOURTCC(str)

EIGHTCC_2_STR(eightcc)

ESP_GMF_CAPS_AUDIO_DECODER

ESP_GMF_CAPS_AUDIO_ENCODER

ESP_GMF_CAPS_AUDIO_ALC

ESP_GMF_CAPS_AUDIO_BIT_CONVERT

ESP_GMF_CAPS_AUDIO_CHANNEL_CONVERT

ESP_GMF_CAPS_AUDIO_RATE_CONVERT

ESP_GMF_CAPS_AUDIO_MIXER

ESP_GMF_CAPS_AUDIO_EQUALIZER

ESP_GMF_CAPS_AUDIO_SONIC

ESP_GMF_CAPS_AUDIO_FADE

ESP_GMF_CAPS_AUDIO_DEINTERLEAVE

ESP_GMF_CAPS_AUDIO_INTERLEAVE

ESP_GMF_CAPS_AUDIO_AEC

ESP_GMF_CAPS_AUDIO_NS

ESP_GMF_CAPS_AUDIO_AGC

ESP_GMF_CAPS_AUDIO_VAD

ESP_GMF_CAPS_AUDIO_DOA

ESP_GMF_CAPS_AUDIO_WWE

ESP_GMF_CAPS_AUDIO_VCMD

ESP_GMF_CAPS_AUDIO_DRC

ESP_GMF_CAPS_AUDIO_MBC

ESP_GMF_CAPS_AUDIO_MUXER

ESP_GMF_CAPS_AUDIO_HOWL

ESP_GMF_CAPS_VIDEO_DECODER

ESP_GMF_CAPS_VIDEO_ENCODER

ESP_GMF_CAPS_VIDEO_COLOR_CONVERT

ESP_GMF_CAPS_VIDEO_CROP

ESP_GMF_CAPS_VIDEO_ROTATE

ESP_GMF_CAPS_VIDEO_SCALE

ESP_GMF_CAPS_VIDEO_OVERLAY

ESP_GMF_CAPS_VIDEO_FPS_CVT

此文档对您有帮助吗？

- 反馈已收到，谢谢！
- 如果您有其他意见，欢迎填写乐鑫文档反馈表。

- 我们重视您的反馈。
- 您可以填写乐鑫文档反馈表告诉我们如何改进该文档。