惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
U
Unit 42
IT之家
IT之家
Y
Y Combinator Blog
T
Tailwind CSS Blog
B
Blog
大猫的无限游戏
大猫的无限游戏
博客园 - 叶小钗
Jina AI
Jina AI
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
InfoQ
J
Java Code Geeks
F
Fortinet All Blogs
T
The Blog of Author Tim Ferriss
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Hackread – Cybersecurity News, Data Breaches, AI and More
人人都是产品经理
人人都是产品经理
腾讯CDC
Hugging Face - Blog
Hugging Face - Blog
GbyAI
GbyAI
博客园 - 司徒正美
The GitHub Blog
The GitHub Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
L
LangChain Blog

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12)
Android 实时音视频接入教程:媒体补充增强信息(SEI)
RTC实战笔记 · 2026-06-18 · via 博客园_首页

笔者简介

长期关注 RTC 实时音视频领域的技术演进,参与过音视频算法工程化、接入实现与效果评估等相关工作。
在实际项目中,持续关注包括腾讯 TRTC、即构 ZEGO、声网 Agora 在内的多家 RTC 厂商在实时通信能力与工程落地层面的实践,重点关注 SDK 接入、通话链路实现与场景化应用。
本系列文章将围绕 RTC SDK 接入与实时互动能力实现,持续输出工程实践与场景分析。
本文将以 ZEGO 官方 SDK 文档为基础,围绕「媒体补充增强信息(SEI)」梳理完整接入流程,帮助开发者理解环境准备、初始化、核心 API 调用、媒体处理和常见问题排查。

功能简介

在音视频流媒体应用中,除了可以流媒体通道推拉音视频内容外,还可以使用流 SEI(Supplemental Enhancement Information,媒体补充增强信息)通过流媒体通道将文本信息与音视频内容打包在一起,从主播端(推流端)推出,并从观众端(拉流端)接收,以此实现文本数据与音视频内容的精准同步的目的。
一般可用于视频画面的精准布局、远端歌词同步、直播答题等应用场景。

示例源码下载

请参考 下载示例源码 获取源码。
相关源码请查看 “/ZegoExpressExample/Others/src/main/java/im/zego/others/sei” 目录下的文件。

前提条件

在实现 SEI 功能之前,请确保:

使用步骤

发送与接收 SEI 信息功能,需要在推流端发送 SEI 信息,在拉流端接收 SEI 信息,如下图所示:
推流端:

  1. 调用 createEngine 接口创建 engine 对象。
  2. 调用 loginRoom 接口登录房间。
  3. 调用 startPublishingStream 接口推流。
  4. 在推流成功后,调用 sendSEI 接口发送 SEI 信息。
    拉流端:
  5. 调用 createEngine 接口创建 engine 对象。
  6. 创建 IZegoEventHandler 对象,并重写接收 SEI 信息的 onPlayerRecvSEI 方法,调用 setEventHandler 接口传入创建的 IZegoEventHandler 监听 onPlayerRecvSEI 的回调。
  7. 调用 loginRoom 接口登录房间。
  8. 调用 startPlayingStream 接口拉流。
  9. 在拉流成功后,接收到推流端发送的 SEI 信息之后触发 onPlayerRecvSEI 回调。说明拉流时,如果开发者通过调用 mutePlayStreamVideomuteAllPlayStreamVideo 接口,设置了只拉音频流时,将无法接收 SEI 信息。

1(可选)设置 SEI 类型

设置 SEI 类型
由于 SDK 默认使用 ZEGO 自行定义的 SEI(nalu type = 6, payload type = 243)类型打包,且此类型是 SEI 标准未规定的类型,因此跟视频编码器或者视频文件中的 SEI 不存在冲突。但当开发者需要使用第三方解码器解码时(如 FFmpeg),会导致解不出正确的 SEI,此时需要在推流前调用
setSEIConfig
接口更换 SDK 发送 SEI 的类型,使用 UserUnregister 的 SEI(nalu type = 6, payload type = 5)类型打包。

说明

仅当开发者使用第三方解码器解码 SEI 时需要执行该步骤。

ZegoSEIConfig seiConfig = new ZegoSEIConfig();
// 采用 H.264 的 SEI (nalu type = 6,payload type = 5) 类型打包,因为视频编码器自身会产生 payload type 为 5 的 SEI,或者使用视频文件推流时,视频文件中也可能存在这样的 SEI,所以使用此类型时,用户需要把 uuid + content 当作 buffer 塞给 SEI 发送接口;此时为了区别视频编码器自身产生的 SEI, App 在发送此类型 SEI 时,可以填写业务特定的 uuid(uuid 长度为 16 字节),接收方使用 SDK 解析 payload type 为 5 的 SEI 时,会根据设置的过滤字符串过滤出 uuid 相符的 SEI 抛给业务,如果没有设置过滤字符串,SDK 会把所有收到的 SEI 都抛给开发者。
seiConfig.type = ZegoSEIType.USER_UNREGISTER;

engine.setSEIConfig(seiConfig);

// 通过 advancedConfig 设置 uuid 过滤字段,设置之后 SDK 只会抛出前 12 个字节为开发者所设置 uuid 的 SEI。
ZegoEngineConfig engineConfig = new ZegoEngineConfig();
// 其他用户通过 [onPlayerRecvSEI] 收到的 SEI 信息前 12 个字节一定是 zegozegozego,其他会被过滤。
engineConfig.advancedConfig.put("unregister_sei_filter", "zegozegozego");
ZegoExpressEngine.setEngineConfig(engineConfig);

// 开始推流。
engine.startPublishingStream("STREAM_ID");

2 推流方

发送 SEI 信息的接口需要在推流成功之后调用,接口原型如下:

  • 接口原型
/**
 * 发送媒体增强补充信息。
 *
 * 此接口可在开发者推流传输音视频流数据同时,发送流媒体增强补充信息来同步一些其他附加信息。
 * 一般如同步音乐歌词或视频画面精准布局等场景,可选择使用发送 SEI。
 * 当推流方发送 SEI 后,拉流方可通过监听 [onPlayerRecvSEI] 的回调获取 SEI 内容。
 * 由于 SEI 信息跟随视频帧或音频帧,由于网络问题有可能丢帧,因此 SEI 信息也有可能丢,为解决这种情况,应该在限制频率内多发几次。
 * 限制频率:1 秒钟不要超过 30 次。
 * SEI 数据长度限制为 4096 字节。
 * @param data SEI 内容。
 */
public void sendSEI(byte[] data)

  • 调用示例
// 定义 SDK 引擎对象。
ZegoExpressEngine engine;

ZegoEngineProfile profile = new ZegoEngineProfile();
// 请通过官网注册获取,格式为 123456789L。
profile.appID = appID;
// 请通过官网注册获取,格式为:@"0123456789012345678901234567890123456789012345678901234567890123"(共 64 个字符)。
profile.appSign = appSign;
// 通用场景接入。
profile.scenario = ZegoScenario.DEFAULT;
// 设置app的application 对象。
profile.application = getApplication();
// 创建引擎。
engine = ZegoExpressEngine.createEngine(profile, null);
// 登录房间。
engine.loginRoom("roomid", new ZegoUser("userid_1"));
// 推流。
engine.startPublishingStream("streamid");
// 开发者的其他业务逻辑。
...;
// 在业务场景需要的时机发送 SEI 信息。
engine.sendSEI("12345".getBytes());

3 拉流方

接收 SEI 信息的回调接口需要在拉流成功之后触发,接口原型如下:

  • 接口原型
/**
 * 收到远端流的 SEI 内容。
 *
 * 拉流成功后,当远端流调用 sendSEI 后,本端会收到此回调。
 * 若只拉纯音频流,将收不到推流端发送的 SEI 信息。
 * @param streamID 拉流的流 ID。
 * @param data SEI 内容。
 */
public void onPlayerRecvSEI(String streamID, byte[] data){

}

  • 调用示例
// 定义 SDK 引擎对象。
ZegoExpressEngine engine;

ZegoEngineProfile profile = new ZegoEngineProfile();
// 请通过官网注册获取,格式为 123456789L。
profile.appID = appID;
// 请通过官网注册获取,格式为:@"0123456789012345678901234567890123456789012345678901234567890123"(共 64 个字符)。
profile.appSign = appSign;
// 通用场景接入。
profile.scenario = ZegoScenario.DEFAULT;
// 设置 app 的 application 对象。
profile.application = getApplication();
// 创建引擎。
engine = ZegoExpressEngine.createEngine(profile, null);

// 创建 IZegoEventHandler 对象, 并重写 onPlayerRecvSEI 方法。
IZegoEventHandler handler = new IZegoEventHandler(){
// 监听其他回调。
    ...;

    // 监听接收 SEI 信息的回调, 当发送端调用 sendSEI 发送信息时会触发此回调。
    public void onPlayerRecvSEI(String streamID, byte[] data) {
    // 在这里实现业务场景相关的逻辑, 例如展现相关的 UI 等。
        ...;
    }

}
// 添加监听的回调对象。
engine.setEventHandler(handler);
// 登录房间。
engine.loginRoom("roomid", new ZegoUser("userid_2"));
// 拉流, canvas 为 ZegoCanvas 类型的索引 UI 渲染控件的对象。
engine.startPlayingStream("streamid", canvas);
// 开发者的其他业务逻辑。
...;

相关文档

如何理解和使用 SEI(媒体补充增强信息)?

结语

本文主要介绍了「媒体补充增强信息(SEI)」的基础接入流程,并结合官方文档梳理了环境准备、核心 API 调用、媒体处理和结果验证等关键环节。
通过这类能力,开发者可以更快搭建实时音视频、在线互动、远程协作、直播连麦、视频通话等典型场景,并在后续根据业务需要扩展更多互动能力。
围绕实时音视频能力,后续还可以继续关注:

  • RTC SDK 完整接入流程与关键参数配置
  • 推流、拉流、房间与回调机制解析
  • 权限、Token、设备兼容和网络异常排查
  • 多人通话、语聊房、互动直播等进阶场景
  • 跨端场景下的实时互动能力对比
    本系列将围绕「RTC SDK 接入与实时互动能力实现」持续更新,适合需要构建实时音视频、在线互动、AI 实时通信等能力的开发者参考。

常见问题

1. SEI 适合解决什么业务问题?

SEI 适合把文本类附加信息与音视频流同步传输,例如视频画面精准布局、远端歌词同步、直播答题等。它通过流媒体通道随音视频内容发送,适合对音视频画面和业务数据同步性要求较高的场景。

2. sendSEI 应该在什么时候调用?

文档中说明,发送 SEI 信息的接口需要在推流成功之后调用。典型流程是先创建 engine、登录房间、调用 startPublishingStream 推流,再在业务需要的时机调用 sendSEI 发送数据。

3. 为什么只拉音频流时收不到 SEI?

SEI 信息跟随音视频流中的视频相关数据传递。文档特别说明,如果拉流端通过 mutePlayStreamVideo 或 muteAllPlayStreamVideo 设置只拉音频流,将无法接收推流端发送的 SEI 信息。

4. SEI 发送频率和数据大小有什么限制?

sendSEI 的限制频率是 1 秒钟不要超过 30 次,SEI 数据长度限制为 4096 字节。由于 SEI 跟随音视频帧传输,网络问题可能导致丢帧,因此业务上可以在限制频率内重复发送关键 SEI 信息。

5. 默认 SEI 类型和 USER_UNREGISTER 类型有什么区别?

SDK 默认使用 ZEGO 自定义 SEI 类型打包,通常不会与视频编码器或视频文件中的 SEI 冲突。如果需要使用第三方解码器如 FFmpeg 解码 SEI,可以在推流前调用 setSEIConfig,改用 UserUnregister 类型。

6. 使用 FFmpeg 等第三方解码器时为什么要配置 setSEIConfig?

默认 ZEGO 自定义 SEI 类型属于标准未规定的类型,第三方解码器可能无法解析出正确 SEI。此时可通过 setSEIConfig 将 SDK 发送 SEI 的类型更换为 UserUnregister,以便第三方解码器按 H.264 SEI 方式处理。

7. unregister_sei_filter 的作用是什么?

unregister_sei_filter 用于设置 uuid 过滤字段。配置后,SDK 只会抛出前 12 个字节与过滤字段匹配的 SEI,避免业务收到视频编码器自身或视频文件中其他不相关的 SEI 数据。