ESP Media Service
简介
ESP Media Service 为 ESP-ADF 中的音视频服务定义了一套通用媒体接口,以 ESP Service 为基类。应用程序创建服务、配置媒体流,再把源流链接到接收端流。链接并启动后,媒体帧通过读取接口与写入接口自动流动,应用程序不必手动转发帧数据。音视频采集与播放见 ESP-GMF 通用多媒体框架。
功能清单
统一的音视频服务模型,源、接收端、源接收一体三种角色(
ESP_MEDIA_ROLE_SRC/SINK/SRC_SINK)基于 stream ID(
esp_media_stream_id_t)的多媒体端点,一个服务可以同时暴露多个 stream链接时的请求协商:接收端可以通过
esp_media_service_request_t向源提出诉求(如是否需要 global cache)Provider 读取接口(
esp_media_provider_t)与 track manager 写入接口相互解耦内置默认的内存 track manager(
esp_media_track_mngr_t),支持按 track 独立缓存或全局到达顺序缓存统一通过 ESP Service 管理服务生命周期,媒体相关操作作为独立的 vtable(
esp_media_service_ops_t)叠加在基类之上
技术拆解
服务角色与链接
ESP Media Service 通过 esp_media_service_ops_t 中的 get_role 声明自己是源、接收端还是二者兼具;esp_media_service_link() 在链接时校验所选源和接收端的角色是否兼容,再把源的 provider 传给接收端。
flowchart TD
Create["创建服务"] --> Config["配置服务"]
Config --> Link["链接源/接收端 stream"]
Link --> Start["启动服务"]
Start --> Flow["媒体帧流动"]
Flow --> Stop["停止服务"]
Stop --> Unlink["取消链接并销毁"]
esp_media_stream_id_t stream = ESP_MEDIA_DEFAULT_STREAM;
esp_media_service_link(src_service, stream, sink_service, stream);
esp_service_start(sink_service);
esp_service_start(src_service);
链接建立后,媒体数据通过源服务导出的 provider 流向接收端;取消链接需要调用 esp_media_service_unlink(),会清除接收端 stream 上当前设置的 provider。
Provider 与 Track Manager
媒体数据的传递依赖两个互相解耦的接口:接收端在链接时从源服务获取只读的 esp_media_provider_t,通过 esp_media_provider_acquire_frame() / esp_media_provider_release_frame() 获取和释放帧;源服务侧则持有一个 esp_media_track_mngr_t,通过写入 API 产生帧,并把它导出的 provider 句柄暴露给下游。
/* 源服务侧:创建 track manager,注册 track,导出 provider */
esp_media_track_mngr_cfg_t cfg = { .max_track_num = 2 };
esp_media_track_mngr_create(&cfg, &svc->mngr);
esp_media_track_mngr_add_track(svc->mngr, &audio_track);
esp_media_track_mngr_get_provider(svc->mngr, &svc->provider);
/* 接收端侧:读取并释放帧 */
esp_media_frame_t frame = {0};
if (esp_media_provider_acquire_frame(&sink->provider, &frame, timeout_ms) == ESP_OK) {
process_frame(&frame);
esp_media_provider_release_frame(&sink->provider, &frame);
}
警告
通过 esp_media_provider_acquire_frame() 获取的帧必须调用 esp_media_provider_release_frame() 释放,释放之后不能再访问 frame.data。
Track Manager 的缓存模式
默认的 esp_media_track_mngr_t 支持两种 payload 所有权模式:ESP_MEDIA_TRACK_CACHE_INTERNAL 由 manager 复制并持有帧数据;ESP_MEDIA_TRACK_CACHE_USER 只缓存帧元数据,payload 仍由用户持有,消费后通过 frame_release 回调归还。此外还支持 global cache,让多个 track 共用一个按到达顺序排列的队列,适合 RTMP 等音视频交错传输场景;启用 global cache 需要在添加 track 之前完成配置。
停止与中止顺序
媒体接口对停止顺序做了容错设计:源服务停止时应调用 esp_media_track_write_abort(),通过 ESP_MEDIA_PROVIDER_EVENT_TRACKS_ABORT 事件通知下游;接收端停止时应先置本地停止标志,再调用 esp_media_provider_abort() 唤醒阻塞的读取,等待任务退出、释放已获取的帧,最后才取消链接。若 track manager 被多个服务通过链接共享,需要先取消链接,再对它执行 reset 或 destroy;只要还有任务持有已获取的帧或阻塞在队列上,就不能对 track manager 执行 reset 或 destroy。
应用示例
源/接收端的完整示例见 esp_media_service 组件仓库 的 examples 目录。服务基类用法见 ESP Service。
FAQ
Q1:一个服务只能实现 ``get_provider`` 或 ``set_provider`` 中的一个吗?
不是必须的。角色为 ESP_MEDIA_ROLE_SRC_SINK 的服务可以同时实现两者,既作为下游的源,也作为上游的接收端;esp_media_service_link() 只按角色位校验所选的一对源/接收端服务是否兼容。
API 参考
Header File
Functions
-
esp_err_t esp_media_service_init(esp_media_service_t *service, const esp_media_service_config_t *config)
Initialize a media service base object.
Derived services call this after allocating or embedding esp_media_service_t, before exposing the base esp_service_t
- 参数:
service – [inout] Media service object to initialize
config – [in] Media service configuration
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG service or config is NULL
Others Error returned by esp_service_init()
-
esp_err_t esp_media_service_deinit(esp_service_t *service)
Deinitialize a media service base object.
- 参数:
service – [in] Base service pointer returned by ESP_SERVICE_BASE()
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG service is NULL
Others Error returned by esp_service_deinit()
-
esp_err_t esp_media_service_get_role(esp_service_t *service, esp_media_role_t *out_role)
Query the media role of a service.
- 参数:
service – [in] Base media service handle
out_role – [out] Output media role
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG service or out_role is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the service
Others Error returned by the service implementation
-
esp_err_t esp_media_service_get_provider(esp_service_t *service, esp_media_stream_id_t stream, esp_media_provider_t *out_provider)
Get a provider from a source stream.
- 参数:
service – [in] Base media service handle
stream – [in] Source stream ID
out_provider – [out] Output provider
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Service or provider is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the service
Others Error returned by the service implementation
-
esp_err_t esp_media_service_set_provider(esp_service_t *service, esp_media_stream_id_t stream, const esp_media_provider_t *provider)
Set a provider on a sink stream.
Pass NULL provider to disconnect the sink stream
- 参数:
service – [in] Base media service handle
stream – [in] Sink stream ID
provider – [in] Provider handle to consume, or NULL to clear
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG service is NULL, or provider has no ops
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the service
Others Error returned by the service implementation
-
esp_err_t esp_media_service_get_request(esp_service_t *service, esp_media_stream_id_t stream, esp_media_service_request_t *out_request)
Get link request hints for a media stream.
- 参数:
service – [in] Base media service handle
stream – [in] Stream ID
out_request – [out] Output request hints
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG service or out_request is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the service
Others Error returned by the service implementation
-
esp_err_t esp_media_service_set_request(esp_service_t *service, esp_media_stream_id_t stream, const esp_media_service_request_t *request)
Set link request hints for a media stream.
- 参数:
service – [in] Base media service handle
stream – [in] Stream ID
request – [in] Request hints to apply
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG service or request is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the service
Others Error returned by the service implementation
-
esp_err_t esp_media_service_link(esp_service_t *src_service, esp_media_stream_id_t src_stream, esp_service_t *sink_service, esp_media_stream_id_t sink_stream)
Link a source stream to a sink stream.
The sink request hints are applied to the source when supported, then the source provider is passed to the sink
- 参数:
src_service – [in] Source media service handle
src_stream – [in] Source stream ID
sink_service – [in] Sink media service handle
sink_stream – [in] Sink stream ID
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG src_service or sink_service is NULL
ESP_ERR_NOT_SUPPORTED Role check failed or required operation is missing
Others Error returned by source or sink implementation
-
esp_err_t esp_media_service_unlink(esp_service_t *src_service, esp_media_stream_id_t src_stream, esp_service_t *sink_service, esp_media_stream_id_t sink_stream)
Unlink a source stream from a sink stream.
Clears the provider currently set on the sink stream
- 参数:
src_service – [in] Source media service handle
src_stream – [in] Source stream ID
sink_service – [in] Sink media service handle
sink_stream – [in] Sink stream ID
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG src_service or sink_service is NULL
ESP_ERR_NOT_SUPPORTED Role check failed or sink operation is missing
Others Error returned by source or sink implementation
Structures
-
struct esp_media_service_request_t
Media-service link request/capability hints.
The structure is intentionally extensible so future services can add link-time requests without changing the media op shape
Public Members
-
bool need_global_cache
Sink requests source frames in one arrival-order cache
-
bool need_global_cache
-
struct esp_media_service_ops_t
Media-service virtual operations.
Public Members
-
esp_err_t (*get_role)(esp_service_t *service, esp_media_role_t *out_role)
Query source/sink role
-
esp_err_t (*get_provider)(esp_service_t *service, esp_media_stream_id_t stream, esp_media_provider_t *out_provider)
Get provider exported by a source stream
-
esp_err_t (*set_provider)(esp_service_t *service, esp_media_stream_id_t stream, const esp_media_provider_t *provider)
Set provider consumed by a sink stream
-
esp_err_t (*get_request)(esp_service_t *service, esp_media_stream_id_t stream, esp_media_service_request_t *request)
Get sink link requests
-
esp_err_t (*set_request)(esp_service_t *service, esp_media_stream_id_t stream, const esp_media_service_request_t *request)
Apply sink requests to a source
-
esp_err_t (*get_role)(esp_service_t *service, esp_media_role_t *out_role)
-
struct esp_media_service_config_t
Media service configuration.
Public Members
-
const char *name
Service instance name
-
void *user_data
User data passed to esp_service
-
const esp_service_ops_t *service_ops
Optional esp_service lifecycle ops
-
const esp_media_service_ops_t *media_ops
Optional media ops
-
const char *name
-
struct esp_media_service
Base media service structure Derived services embed this as the first member.
Public Members
-
esp_service_t base
Base service, must stay first
-
const esp_media_service_ops_t *media_ops
Media virtual operations
-
esp_service_t base
Macros
-
ESP_MEDIA_SERVICE_CONFIG_DEFAULT()
SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO., LTD SPDX-License-Identifier: LicenseRef-Espressif-Modified-MIT
See LICENSE file for details. Default media service configuration
-
ESP_MEDIA_DEFAULT_STREAM
Default media stream ID
Type Definitions
-
typedef uint16_t esp_media_stream_id_t
Instance-aware media stream address.
-
typedef struct esp_media_service esp_media_service_t
Base media service structure Derived services embed this as the first member.
Enumerations
Header File
Functions
-
esp_err_t esp_media_provider_get_track_num(const esp_media_provider_t *provider, uint16_t *out_num)
Get the number of tracks exposed by a provider.
SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO., LTD SPDX-License-Identifier: LicenseRef-Espressif-Modified-MIT
See LICENSE file for details.
- 参数:
provider – [in] Provider handle
out_num – [out] Output track count
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider or out_num is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
-
esp_err_t esp_media_provider_get_track_info(const esp_media_provider_t *provider, uint16_t index, esp_media_track_info_t *out_info)
Get track metadata by provider track index.
- 参数:
provider – [in] Provider handle
index – [in] Track index in the provider
out_info – [out] Output track metadata
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider or out_info is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
-
esp_err_t esp_media_provider_set_event_cb(const esp_media_provider_t *provider, esp_media_provider_event_cb_t cb, void *event_ctx)
Register a provider event callback.
- 参数:
provider – [in] Provider handle
cb – [in] Event callback, or NULL to clear it
event_ctx – [in] User context passed to cb
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
-
esp_err_t esp_media_provider_abort(const esp_media_provider_t *provider)
Abort provider-side blocking read operations.
- 参数:
provider – [in] Provider handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
-
esp_err_t esp_media_provider_acquire_frame(const esp_media_provider_t *provider, esp_media_frame_t *out_frame, uint32_t timeout_ms)
Acquire the next frame from a provider.
The returned frame must be released with esp_media_provider_release_frame(). Set fields such as type or track_id in out_frame before the call to select a specific track when the provider supports it
- 参数:
provider – [in] Provider handle
out_frame – [inout] Input track selector, output acquired frame
timeout_ms – [in] Timeout in milliseconds; 0 means no wait, UINT32_MAX means wait forever
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider or out_frame is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
-
esp_err_t esp_media_provider_read_frame(const esp_media_provider_t *provider, esp_media_frame_t *out_frame, uint32_t timeout_ms)
Read the next frame into caller-provided storage.
Set out_frame->data and out_frame->size before calling. On success, out_frame->size is updated to the actual payload size
- 参数:
provider – [in] Provider handle
out_frame – [inout] Input buffer descriptor, output frame descriptor
timeout_ms – [in] Timeout in milliseconds; 0 means no wait, UINT32_MAX means wait forever
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider or out_frame is NULL
ESP_ERR_INVALID_SIZE Provided buffer is too small
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
-
esp_err_t esp_media_provider_release_frame(const esp_media_provider_t *provider, esp_media_frame_t *frame)
Release a frame acquired from a provider.
- 参数:
provider – [in] Provider handle
frame – [in] Frame returned by esp_media_provider_acquire_frame()
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG provider or frame is NULL
ESP_ERR_NOT_SUPPORTED Operation is not implemented by the provider
Others Error returned by the provider implementation
Header File
Functions
-
esp_err_t esp_media_track_mngr_create(const esp_media_track_mngr_cfg_t *cfg, esp_media_track_mngr_t **out_mngr)
Create a media track manager.
- 参数:
cfg – [in] Provider configuration
out_mngr – [out] Output track manager handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG cfg is NULL, max_track_num is 0, or out_provider is NULL
ESP_ERR_NO_MEM Allocation failed
-
esp_err_t esp_media_track_mngr_destroy(esp_media_track_mngr_t *mngr)
Destroy a media track manager.
Wakes and destroys internal queues, releases pending user-owned frames through their release callbacks, and frees the track manager
- 参数:
mngr – [in] Track manager handle returned by esp_media_track_mngr_create()
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager is NULL
-
esp_err_t esp_media_track_mngr_reset(esp_media_track_mngr_t *mngr)
Reset tracks and queued data.
Removes all tracks and clears abort state. Global-cache mode is kept. User must re-add tracks after reset
- 参数:
mngr – [in] Track manager handle
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager is NULL
-
esp_err_t esp_media_track_mngr_set_global_cache(esp_media_track_mngr_t *mngr, bool enable, size_t cache_size)
Configure global cache mode before tracks are added.
- 参数:
mngr – [in] Track manager handle
enable – [in] true to use one arrival-order cache shared by all tracks
cache_size – [in] Shared queue byte size, 0 uses default
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager is NULL
ESP_ERR_INVALID_STATE Tracks have already been added
ESP_ERR_NO_MEM Allocation failed
-
esp_err_t esp_media_track_mngr_add_track(esp_media_track_mngr_t *mngr, const esp_media_track_mngr_track_cfg_t *cfg)
Add a track to a track manager.
- 参数:
mngr – [in] Track manager handle
cfg – [in] Track configuration
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager or cfg is NULL
ESP_ERR_NO_MEM Track limit reached or queue allocation failed
-
esp_err_t esp_media_track_mngr_update_track(esp_media_track_mngr_t *mngr, uint16_t index, const esp_media_track_info_t *info)
Queue a track metadata update.
The update is committed when provider acquire/read reaches the queued zero-size frame with ESP_MEDIA_FRAME_FLAG_TRACK_CHANGED. The provider event callback is invoked synchronously at that point
- 参数:
mngr – [in] Track manager handle
index – [in] Track index to update
info – [in] New track metadata
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager or info is NULL
ESP_ERR_NOT_FOUND index is out of range
ESP_ERR_NO_MEM Track queue is unavailable
ESP_ERR_TIMEOUT Failed to queue update frame
ESP_FAIL Failed to commit update frame
-
esp_err_t esp_media_track_mngr_remove_track(esp_media_track_mngr_t *mngr, uint16_t index)
Queue a track removal notification.
The removal is committed when provider acquire/read reaches the queued zero-size frame with ESP_MEDIA_FRAME_FLAG_TRACK_REMOVED. The provider event callback is invoked synchronously at that point
- 参数:
mngr – [in] Track manager handle
index – [in] Track index to remove
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager is NULL
ESP_ERR_NOT_FOUND index is out of range
ESP_ERR_NO_MEM Track queue is unavailable
ESP_ERR_TIMEOUT Failed to queue removal frame
ESP_FAIL Failed to commit removal frame
-
esp_err_t esp_media_track_mngr_get_provider(esp_media_track_mngr_t *mngr, esp_media_provider_t *provider)
Get the media provider handle exported by a track manager.
- 参数:
mngr – [in] Track manager handle
provider – [out] Output media provider
- 返回:
ESP_OK On success
ESP_ERR_INVALID_ARG Track manager or provider is NULL
Structures
-
struct esp_media_track_mngr_cfg_t
Media track manager configuration.
备注
The global cache used or not can be reconfigured by API
esp_media_track_mngr_set_global_cache
-
struct esp_media_track_mngr_cache_cfg_t
Media provider track buffer configuration.
Public Members
-
esp_media_track_cache_type_t cache_type
Track cache type
-
size_t cache_size
Queue byte size for track manager-owned payload mode
-
uint16_t addr_align
Track manager-owned frame data alignment, 0 uses pointer size
-
uint16_t size_align
Cached frame size alignment, 0 no special request
-
uint16_t queue_num
Metadata queue depth
-
esp_media_frame_release_cb_t frame_release
Release callback for user-owned frames
-
void *release_ctx
Context for frame_release
-
esp_media_track_cache_type_t cache_type
-
struct esp_media_track_mngr_track_cfg_t
Media track manager track configuration.
Public Members
-
esp_media_track_info_t info
Track metadata
-
esp_media_track_mngr_cache_cfg_t cache_cfg
Track buffer/cache settings
-
esp_media_track_info_t info
Type Definitions
-
typedef struct esp_media_track_mngr esp_media_track_mngr_t
Definition of media track manager.
SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO., LTD SPDX-License-Identifier: LicenseRef-Espressif-Modified-MIT
See LICENSE file for details.
-
typedef void (*esp_media_frame_release_cb_t)(const esp_media_frame_t *frame, void *ctx)
Release callback for user-owned frames after consumed.
- Param frame:
[in] Frame whose payload can be released by the owner
- Param ctx:
[in] User context from esp_media_track_mngr_cache_cfg_t