网络摄像机首次播放音视频延时出图像踩坑记录
ZLMediaKit / RTSP / H.264 播放音视频踩坑记录 - SDP、SPS、PPS 完整详解适用场景RTSP 信令交互、addStreamProxy 拉流、WebRTC、H264 裸流、花屏、首帧黑屏、无法解码绝大多数问题根源就是 SDP / SPS/PPS。1、SDP 是什么SDPSession Description Protocol会话描述协议文本格式。RTSP 中客户端发送DESCRIBE请求服务端返回 SDPSDP 告诉播放器这个流有什么轨道视频 / 音频、编码格式、分辨率、采样率、RTP 端口、传输协议、SPS/PPS 等信息。SDP 只是描述元数据不携带音视频帧数据纯文本。RTSP 交互片段VLC/ZLM(PlayerProxy) →DESCRIBE rtsp://xxx/vs0 RTSP/1.0设备 RTSP 服务端回复Body 就是SDP 文本。SDP 典型片段 (H.264 视频)v0 o- 1600000001 1600000001 IN IP4 127.0.0.1 sMediaServer t0 0 mvideo 0 RTP/AVP 96 artpmap:96 H264/90000 afmtp:96 packetization-mode1;profile-level-id42001E;sprop‑parameter‑setsZ0IAKeKQFAe2AtwEBAaQeJEA8AAIBBA1KGA,g48IAA重点字段mvideo视频媒体轨道rtpmap:96 H264/90000PT96H264 编码时间戳频率 90000fmtp:96H264 私有参数packetization-mode1模式 1FU‑A 分片模式RTSP/RTP 最常用profile‑level‑idH264 profile levelsprop‑parameter‑setsbase64(SPS),base64(PPS)→SPS、PPS 做 base64 编码写在这里关键点sprop‑parameter‑sets就是把 SPS、PPS 放到 SDP 里面播放器拿到 SDP 就提前拿到解码参数不需要等 I 帧。2、SPS / PPS 是什么H.264H.264 码流由 NALUNAL 单元组成。SPS、PPS 属于参数集 NALU不是图像帧是解码器初始化必须的元数据。名称全称作用NALU 类型SPSSequence Parameter Set 序列参数集序列全局信息分辨率、profile、level、帧率、参考帧数量NALU type7PPSPicture Parameter Set 图像参数集图像相关熵编码模式、片组参数依附 SPSNALU type8⚠️解码器没有 SPS/PPS绝对不能解码 I 帧 (IDR 帧)。现象收到 I 帧但是画面黑屏、花屏、绿屏没有报错但是出不来图像。NALU 类型简单记忆7SPS8PPS5IDR‑I 帧关键帧1普通 P 帧、非 I 帧两种携带 SPS/PPS 的方式RTSP/RTP 场景方式 1SDP 内携带 sprop‑parameter‑sets最理想RTSP 标准SDP 的fmtp字段把 SPS、PPS 做 base64 编码写入。播放器收到 DESCRIBE 应答解析 SDP 就拿到 SPS/PPS解码器直接初始化。ZLMediaKit addStreamProxy 拉流RTSP 服务端输出 SDP 带 sprop体验最好首帧秒出。方式 2SDP 不带 sprop‑parameter‑setsSPS/PPS 随码流在 IDR 前面发送SDP 里没有 sprop‑parameter‑setsSPSPPS NALU 放在每一个 IDR (I 帧) 前面作为码流一部分随 RTP 包传输。播放器必须等到第一个 IDR 帧到来解析前面 SPS/PPS才能开始解码。现象VLC 打开流要等 1~2 秒才出画面seek、断流重连容易黑屏。很多嵌入式设备 RTSP 服务端容易踩坑SDP 不填 sprop‑parameter‑sets只在码流里面输出 SPS/PPS。裸 H264 AnnexB 格式文件 / 本地码流起始码0x00 00 01分割 NALU00 00 01 67 ... (SPS NALU) 00 00 01 68 ... (PPS NALU) 00 00 01 65 ... (IDR I帧)RTP 传输 RTSP 时AnnexB 起始码会被去掉用 RTP 封装SPS/PPS 可以放到 SDP (sprop) 或者穿插在 RTP 负载中。3、sprop‑parameter‑sets 解析示例sprop‑parameter‑setsZ0IAKeKQFAe2AtwEBAaQeJEA8AAIBBA1KGA,g48IAA逗号分隔逗号前 base64 串 →SPS 原始二进制逗号后 base64 串 →PPS 原始二进制解码流程base64 解码 → 得到 SPS NALU 原始字节带 NALU 头 0x67、PPS NALU 字节0x68。注意sprop 里面的 SPS/PPS不带 AnnexB 起始码 00 00 01只是纯 NALU 负载。常见故障现象与 SPS/PPS 关系现象根因VLC 打开 RTSP 流音频正常视频黑屏过 1‑2 秒出图SDP 没有 sprop‑parameter‑sets要等码流中 SPS/PPSIDR 到来首帧花屏、马赛克后面正常拿到 SPS/PPS 之前收到 I 帧解码器参数错误ZLMediaKit WebRTC 播放失败报错 no sps/ppsWebRTC 强制要求 SDP 携带 sprop‑parameter‑sets仅码流携带 SPS/PPS 不行网络抖动断流恢复后黑屏断流丢失 SPS/PPS后续 I 帧没有配套参数集WebRTC 硬性要求SDP 必须携带 sprop‑parameter‑sets只在 RTP 流里送 SPS/PPS 是无法播放 WebRTC。这是 ZLM 非常高频坑。4、RTSP 完整交互看 SDP/SPS/PPS 时序摄像机设备 A - ZLMediaKit addStreamProxyZLM PlayerProxyRTSP 客户端发送 DESCRIBEA 设备 RTSP 服务端回复 SDP。✅理想SDP fmtp 携带sprop‑parameter‑setsZLM 直接解析 SPS/PPS。❌缺陷SDP 无 spropZLM 只能等待 RTP 码流中出现 SPS/PPS NALU。ZLM 发送 SETUP建立 RTP 通道rtsp_type0 TCP interleavedZLM 发送 PLAYA 设备输出 RTP 包SPS/PPS IDR‑I P 帧如果 SDP 不带 spropZLM 内部会缓存等待码流中 SPS/PPS 到来才生成完整 MediaSource 对外分发。此时 VLC 连接 ZLM也要等待 IDR 帧。5、A 端设备 RTSP 服务端输出建议方法A 端设备端RTSP 服务端SDP 的 fmtp 必须填充sprop‑parameter‑setsSPS,PPS base64不要只放在码流里。packetization‑mode1FU‑A 分片大 I 帧分片传输RTSP over TCP 标准。IDR 帧前面码流中依然重复输出 SPSPPS双重保险网络丢包容错。ZLMediaKit addStreamProxy 相关参数影响 SDP 处理directProxy1默认透传源 SDP源 SDP 不带 sprop则 ZLM 对外 SDP 也不带 spropWebRTC 无法播放。directProxy0ZLM 解封装从 RTP 码流提取 SPS/PPS重新生成 SDP补全 sprop‑parameter‑sets兼容性提升消耗少量 CPU。curl 可以追加参数directProxy0curlhttp://127.0.0.1:80/index/api/addStreamProxy?secret$SECRETvhost__defaultVhost__applivestreamak3918urlrtsp%3A%2F%2F127.0.0.1%3A8554%2Fvs0rtsp_type0directProxy06、快速排错手段tcpdump/wireshark 抓 RTSP 报文查看 DESCRIBE 应答 SDP看sprop‑parameter‑sets是否存在。ZLMediaKit 日志搜索sps、pps、h264观察是否成功解析到参数集。如果 SDP 没有 sprop打开 directProxy0ZLM 会从 RTP 码流自动提取 SPS/PPS 重建 SDP。7、C 代码原始 SPS/PPS NALU 生成 sprop‑parameter‑sets 字符串说明输入去掉 AnnexB 起始码 (0x000001) 的纯 NALU 二进制SPS NAL、PPS NAL包含 NALU 头字节 0x67 / 0x68输出sprop‑parameter‑setsxxxx,yyyy字符串可直接填入 SDP 的 fmtp 字段依赖需要实现 base64 编码函数嵌入式可使用开源 base64 实现。注意不要带入 00 00 01 起始码sprop 标准只接受 NALU 净荷。#includestdio.h#includestring.h#includestdlib.h/** * brief base64编码函数输入二进制输出base64字符串(外部释放内存) */char*base64_encode(constunsignedchar*data,size_tlen);/** * brief 生成SDP fmtp中的 sprop‑parameter‑sets 字段字符串 * param sps_buf SPS NALU(无000001起始码含nal头0x67) * param sps_len SPS字节长度 * param pps_buf PPS NALU(无000001起始码含nal头0x68) * param pps_len PPS字节长度 * return 动态分配字符串示例sprop‑parameter‑setsZ0IA...,g48IAA; 返回NULL失败调用者free释放 */char*h264_gen_sprop_parameter_sets(constuint8_t*sps_buf,size_tsps_len,constuint8_t*pps_buf,size_tpps_len){if(!sps_buf||sps_len0||!pps_buf||pps_len0){returnNULL;}// SPS base64char*sps_b64base64_encode(sps_buf,sps_len);if(!sps_b64)returnNULL;// PPS base64char*pps_b64base64_encode(pps_buf,pps_len);if(!pps_b64){free(sps_b64);returnNULL;}// sprop‑parameter‑setssps_b64,pps_b64size_tout_lenstrlen(sprop‑parameter‑sets)strlen(sps_b64)1strlen(pps_b64)1;char*out_str(char*)malloc(out_len);if(!out_str){free(sps_b64);free(pps_b64);returnNULL;}snprintf(out_str,out_len,sprop‑parameter‑sets%s,%s,sps_b64,pps_b64);free(sps_b64);free(pps_b64);returnout_str;}/* --------------使用示例-------------- */voiddemo_usage(void){// 示例sps_nal、pps_nal 为去除00 00 01起始码的NALU原始数据uint8_tsps_nal[]{0x67,0x42,0x00,0x1E,0x8D,0x8D,0x40,0xA0};uint8_tpps_nal[]{0x68,0xCE,0x3C,0x80};char*sprop_strh264_gen_sprop_parameter_sets(sps_nal,sizeof(sps_nal),pps_nal,sizeof(pps_nal));if(sprop_str){printf(%sn,sprop_str);/* * 拼接进SDP fmtp行 * afmtp:96 packetization-mode1;profile-level-id42001E;%srn */free(sprop_str);}}配套从 AnnexB 码流提取 SPS/PPS NALU去除起始码从 H264 AnnexB 流 (带00 00 01) 中剥离起始码拿到纯 NALU作为上面函数输入。重点传给h264_gen_sprop_parameter_sets的不能包含 0x000001 起始码。/** * brief 简单查找AnnexB起始码 0x00 00 01 */intfind_annexb_startcode(constuint8_t*buf,size_tlen,size_t*pos){for(size_ti0;i3len;i){if(buf[i]0buf[i1]0buf[i2]1){*posi3;// 跳过3字节起始码返回NALU有效载荷起始偏移return1;}}return0;}profile‑level‑id 生成补充SDP fmtp 还需要profile‑level‑idXXYYZZ取自 SPS NALU 的第 1、2、3 字节byte0profile_idcbyte1constraint_set_flagsbyte2level_idc拼接为十六进制 6 位字符串例如42001E。集成进 RTSP SDP 输出示例片段afmtp:96 packetization-mode1;profile-level-id42001E;sprop‑parameter‑setsZ0IA...,g48IAA重要注意事项sprop‑parameter‑sets 格式sps_base64,pps_base64逗号分隔无空格。输入必须是 NALU 本体剔除 AnnexB 起始码 00 00 01否则 base64 之后参数集错误解码器无法初始化。编码输出的字符串直接填入 SDP不要额外 urlencodeSDP 本身不需要 URL 编码URL 编码只用于 HTTP API。H.265 HEVC需要同时处理 VPSSPSPPS对应字段sprop‑vps‑sets;sprop‑sps‑sets;sprop‑pps‑sets。补充 H.265 (HEVC)H265 对应SPS (type33), PPS (type34), VPS (type32)SDP 字段为sprop‑vps‑sets,sprop‑sps‑sets,sprop‑pps‑sets。wireshark 常用过滤表达式# 过滤RTSP DESCRIBE应答查看SDP rtsp rtsp.method DESCRIBE # 过滤H264 SPS NALU h264.nal_unit_type 7 # 过滤H264 PPS NALU h264.nal_unit_type 8

相关新闻

Java主流框架与源码:MyBatis / Hibernate

Java主流框架与源码:MyBatis / Hibernate

1. 引言 在 Java 企业级开发中,ORM(对象关系映射)框架是连接面向对象世界与关系型数据库的桥梁。MyBatis 与 Hibernate 作为两大主流持久层框架,各有千秋,其底层源码实现更是蕴含着无数精妙的设计思想。 本文将深入剖析…

2026/9/15 3:03:26 阅读更多 →
Java数据库与数据存储:分库分表实战

Java数据库与数据存储:分库分表实战

1. 引言 在互联网业务高速发展的今天,单库单表往往成为系统性能的瓶颈。当数据量达到千万级甚至亿级时,数据库的读写性能会急剧下降,索引膨胀、锁竞争、连接数耗尽等问题接踵而至。此时,分库分表便成为Java后端架构中不可或缺的优…

2026/9/23 9:34:50 阅读更多 →
Java数据库与数据存储:Redis

Java数据库与数据存储:Redis

1. 引言 在当今互联网高并发场景下,数据库的性能瓶颈往往成为系统扩展的最大障碍。Redis 作为一款高性能的内存数据库,凭借其丰富的数据结构、极快的读写速度和灵活的持久化机制,已经成为 Java 后端开发中不可或缺的组件。 本文将系统性地介绍…

2026/9/14 13:23:36 阅读更多 →

最新新闻

Mockery 参数验证(Argument Validation)指南:掌握 with() 匹配器与 Hamcrest 对照用法

Mockery 参数验证(Argument Validation)指南:掌握 with() 匹配器与 Hamcrest 对照用法

示例工程数据库教程后端 【免费下载链接】sql-server-samples Azure Data SQL Samples - Official Microsoft GitHub Repository containing code samples for SQL Server, Azure SQL, Azure Synapse, and Azure SQL Edge 项目地址: https://gitcode.com/gh_mirrors…

2026/9/23 23:39:59 阅读更多 →
TCP长连接选择响应:从粘包半包到可靠按需回包实战

TCP长连接选择响应:从粘包半包到可靠按需回包实战

简介:TCP选择响应是计算机网络传输层可靠传输机制的经典实验课题。这份资源面向正在学习计算机网络、需要完成TCP大实验或深入理解选择重传协议的高校学生与研究者,围绕“选择响应版本”提供了完整的实验工程。压缩包共24个文件,体积仅1.05MB…

2026/9/23 23:39:59 阅读更多 →
Presto 0.259 版本解析:Weibull 分布函数、内存错误增强与资源组查询限制

Presto 0.259 版本解析:Weibull 分布函数、内存错误增强与资源组查询限制

大数据数据库后端 【免费下载链接】presto The official home of the Presto distributed SQL query engine for big data 项目地址: https://gitcode.com/gh_mirrors/pre/presto 点击查看 免费下载 导读 Presto 0.259 是 PrestoDB(GitHub 加速计划 / …

2026/9/23 23:39:59 阅读更多 →
Terminal.Gui 导航系统深入解析:焦点管理、Tab 遍历与键盘/鼠标导航实战指南

Terminal.Gui 导航系统深入解析:焦点管理、Tab 遍历与键盘/鼠标导航实战指南

UI组件跨平台桌面应用 【免费下载链接】Terminal.Gui Cross Platform Terminal UI toolkit for .NET 项目地址: https://gitcode.com/gh_mirrors/te/Terminal.Gui 点击查看 免费下载 导读 本文全面剖析 Terminal.Gui(跨平台 .NET 终端 UI 工具包&#…

2026/9/23 23:39:59 阅读更多 →
CNN风格迁移原理与PyTorch实现:从Gram矩阵到VGG特征优化

CNN风格迁移原理与PyTorch实现:从Gram矩阵到VGG特征优化

简介:一份基于CNN卷积神经网络实现图像风格迁移的Python项目完整源码,主要面向计算机相关专业正在准备毕业设计、课程设计或期末大作业的学生,也适合需要项目实战练习的初中级开发者。项目经过导师指导并获高分评价,代码结构完整、…

2026/9/23 23:39:59 阅读更多 →
信号分析与处理实验全链路:从采样到滤波器设计的MATLAB实现

信号分析与处理实验全链路:从采样到滤波器设计的MATLAB实现

简介:这份资源是南京邮电大学「信号分析与处理实验」课程的完整实验报告,面向正在修读数字信号处理、信号与系统相关课程的高校学生,以及需要借助 MATLAB 完成实验与课程设计的自学者。报告覆盖信号的产生和运算、连续时间信号的频域分析、信…

2026/9/23 23:38:58 阅读更多 →

日新闻

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析

3招搞定手机怎么下载微信面试难题实战项目解析 面试被问“手机怎么下载微信”背后的原理,90%的人答不上来。别笑,这看似弱智的问题,实则是考察你对移动应用分发机制、安全校验及网络协议理解的试金石。我带过不少校招新人,他们背了八股文,却连一个A…

2026/9/23 0:00:23 阅读更多 →
2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我

2k显示屏性能优化踩坑:版本升级后API全变了,这份源码解析救了我 刚把开发环境的显示器从1080P换到2K,跑老项目直接报错,版本升级后 API…

2026/9/23 0:01:25 阅读更多 →
3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点

3步搞定美眉图实战项目,告别官方文档抓不住重点 官方文档翻了三遍还是云里雾里?别急,美眉图在实战项目中常被用来做数据可视化,但它的原理比你想的简单。今天咱们直接上手,用一个完整的小项目把美眉图跑通,不再死磕那些冗长的理论说明。…

2026/9/23 0:01:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/23 4:55:02 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/23 4:49:06 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/23 9:53:41 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/23 9:53:40 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/23 9:53:40 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/23 9:53:40 阅读更多 →