FFmpeg开发笔记(三十七)分析SRS对HLS协议里TS包的插帧操作
《FFmpeg开发实战:从零基础到短视频上线》一书的“2.1.2 音视频文件的封装格式”介绍了视频流的PS格式和TS格式。由于TS包的长度固定,从TS流的任一片段开始都能独立解码,因此可以把TS当成音视频文件的封装格式。
鉴于TS包的独立解码特性,HLS协议引入了TS格式作为传输单元。HLS协议的实现原理是对一个大的媒体分片,并将分片后的文件路径记录于m3u8文件,客户端依据该m3u8文件即可获取对应的分片列表,再依次播放分片内容。每个TS分片都以SPS与PPS等配置帧开头,其中指定了视频的规格信息及其编码参数,因此每个TS片段都能正常解析播放。关于SPS与PPS的详细说明参见之前的文章《解析H.264码流中的SPS帧和PPS帧》。
上述的分片文件便是一个个以TS格式封装的视频资源,那么当直播源来自一个MP4文件的时候,流媒体服务器又是怎么把MP4文件转化为一个个TS分片的呢?
以SRS为例,它在组装TS包时做了特殊处理,在每个TS包的开头位置,就自动插入SPS与PPS等配置帧。具体代码在SRS框架的trunk/src/main/srs_main_ingest_hls.cpp,查看该源码的SrsIngestHlsOutput::on_ts_video函数,找到以下的代码片段,可见程序在写入H.264流时,先写入SPS帧和PPS帧,再写入I帧、P帧和B帧。
if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) {
return ret;
}
if ((ret = write_h264_ipb_frame(ibps, frame_type, dts, pts)) != ERROR_SUCCESS) {
// drop the ts message.
if (ret == ERROR_H264_DROP_BEFORE_SPS_PPS) {
return ERROR_SUCCESS;
}
return ret;
}
找到write_h264_sps_pps函数的定义代码如下,发现函数内部在封装序列头时依次输入了SPS帧和PPS帧:
// h264 raw to h264 packet.
std::string sh;
if ((err = avc->mux_sequence_header(h264_sps, h264_pps, sh)) != srs_success) {
// TODO: FIXME: Use error
ret = srs_error_code(err);
srs_freep(err);
return ret;
}
进一步跟踪mux_sequence_header的定义来源,详细的定义代码在SRS框架的trunk/src/protocol/srs_protocol_raw_avc.cpp,查看该源码的SrsRawH264Stream::mux_sequence_header函数,找到以下的代码片段,可见程序依据ISO_IEC_14496-15的文档规范,先后写入了sequenceParameterSet的NAL单元(即SPS帧),以及pictureParameterSet的NAL单元(即PPS帧)。
// sps
if (true) {
// 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
// numOfSequenceParameterSets, always 1
stream.write_1bytes(uint8_t(0xe0 | 0x01));
// sequenceParameterSetLength
stream.write_2bytes((int16_t)sps.length());
// sequenceParameterSetNALUnit
stream.write_string(sps);
}
// pps
if (true) {
// 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
// numOfPictureParameterSets, always 1
stream.write_1bytes(0x01);
// pictureParameterSetLength
stream.write_2bytes((int16_t)pps.length());
// pictureParameterSetNALUnit
stream.write_string(pps);
}
由此可见,SRS在每个TS包头都写入了SPS帧和PPS帧,确保TS包是拥有SPS和PPS的完整H.264分片。只有加上SPS与PPS,客户端才能正常拉流解析数据,才能正常渲染视频画面。
更多详细的FFmpeg开发知识参见《FFmpeg开发实战:从零基础到短视频上线》一书。
FFmpeg开发笔记(三十七)分析SRS对HLS协议里TS包的插帧操作的更多相关文章
- FFmpeg开发笔记(三):ffmpeg介绍、windows编译以及开发环境搭建
前言 本篇章是对之前windows环境的补充,之前windows的是无需进行编译的,此篇使用源码进行编译,版本就使用3.4.8. FFmpeg简介 FFmpeg是领先的多媒体框架,能够解码 ...
- FFmpeg开发笔记(四):ffmpeg解码的基本流程详解
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- FFmpeg开发笔记(五):ffmpeg解码的基本流程详解(ffmpeg3新解码api)
若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...
- FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放
前言 ffmpeg播放rtsp网络流和摄像头流. Demo 使用ffmpeg播放局域网rtsp1080p海康摄像头:延迟0.2s,存在马赛克 使用ffmpeg播放网络rtsp文件流 ...
- FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台
FFmpeg和SDL开发专栏(点击传送门) 上一篇:<FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放>下一篇:敬请期待 前言 将ffmpeg移植到海思H ...
- Django开发笔记三
Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.基于类的方式重写登录:views.py: from ...
- 第三百三十七节,web爬虫讲解2—PhantomJS虚拟浏览器+selenium模块操作PhantomJS
第三百三十七节,web爬虫讲解2—PhantomJS虚拟浏览器+selenium模块操作PhantomJS PhantomJS虚拟浏览器 phantomjs 是一个基于js的webkit内核无头浏览器 ...
- FFmpeg开发笔记(一)搭建Linux系统的开发环境
对于初学者来说,如何搭建FFmpeg的开发环境是个不小的拦路虎,因为FFmpeg用到了许多第三方开发包,所以要先编译这些第三方源码,之后才能给FFmpeg集成编译好的第三方库.不过考虑到刚开始仅仅调用 ...
- Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类
一.多环境配置 在工作中,对于开发环境.测试环境.生产环境的配置肯定都不相同,比如我们开发阶段会在自己的电脑上安装 mysql ,连接自己电脑上的 mysql 即可,但是项目开发完毕后要上线就需要该配 ...
- FFmpeg开发笔记(二)搭建Windows系统的开发环境
由于Linux系统比较专业,个人电脑很少安装Linux,反而大都安装Windows系统,因此提高了FFmpeg的学习门槛,毕竟在Windows系统搭建FFmpeg的开发环境还是比较麻烦的.不过若有已经 ...
随机推荐
- 使用IIS部署WebDAV
服务器开启WebDAV 在服务器安装IIS的同时 要启用Windows身份验证与WebDAV发布 如果不是服务器版本,参照下图 在IIS中新建WebDAV网站 配置好本地目录与端口 启用Windows ...
- linux源码编译安装软件原理
目录 一.关于软件包 二.软件编译过程 三.编译安装常用参数 四.源码编译出错的解决思路 五.各种软件安装方法的特点 一.关于软件包 在linux中安装软件是需要安装包的,软件的安装包有各种类型: ...
- mysql,左连接 ,查询右表为null的写法,删除,带join条件的写法
select * from sale_guest sg left join sale_bill sbon sg.bill_id=sb.id where sg.gmt_create>'2023-1 ...
- 在唯一密钥属性“name”设置为“XXX”时,无法添加类型为“add”的重复集合项
我是在调试时,更改了项目url出现的问题,没有改端口号,只是改了"/"后面的地址 这个是我是改哈端口号就好了,改了端口号就重新建立虚拟目录了. 感觉是因为端口号没变,但项目url变 ...
- .NET Core 中使用GBK GB2312编码报错的问题
错误描述 环境 dotnet core 2.1 2.2 dotnet core 3.1 dotnet core 5.0 现象 当代码中使用 System.Text.Encoding.GetEnco ...
- mysql binlog查看指定数据库
1.mysql binlog查看指定数据库的方法 MySQL 的 binlog(二进制日志)主要记录了数据库上执行的所有更改数据的 SQL 语句,包括数据的插入.更新和删除等操作.但直接查看 binl ...
- itest(爱测试) 紧急 BUG 修复版(4.5.6)发布,,开源BUG 跟踪管理 & 敏捷测试管理&极简项目管理软件
itest 简介 itest 开源敏捷测试管理,testOps 践行者,极简的任务管理,测试管理,缺陷管理,测试环境管理4合1,又有丰富的统计分析.可按测试包分配测试用例执行,也可建测试迭代(含任务, ...
- Qt初始化代码基本说明
参考视频:黑马程序员https://www.bilibili.com/video/BV1XW411x7NU?p=4 1 工程基本介绍 按照这个基本步骤(https://www.cnblogs.com ...
- LeetCode 460. LFU Cache LFU缓存 (C++/Java)
题目: Design and implement a data structure for Least Frequently Used (LFU)cache. It should support th ...
- 太卷了,史上最简单的监控系统 catpaw 简介
指标监控的痛点 当下比较流行的监控系统,比如 Prometheus.Nightingale.VictoriaMetrics,都是基于数值型指标的监控系统,这类监控系统的痛点在于:告警的时候只能拿到异常 ...