FFmpeg开辟条记(三十七)分析SRS对HLS协议里TS包的插帧操作 ...

打印 上一主题 下一主题

主题 919|帖子 919|积分 2757

​《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:n_ts_video函数,找到以下的代码片段,可见程序在写入H.264流时,先写入SPS帧和PPS帧,再写入I帧、P帧和B帧。
  1. if ((ret = write_h264_sps_pps(dts, pts)) != ERROR_SUCCESS) {
  2.     return ret;
  3. }
  4. if ((ret = write_h264_ipb_frame(ibps, frame_type, dts, pts)) != ERROR_SUCCESS) {
  5.     // drop the ts message.
  6.     if (ret == ERROR_H264_DROP_BEFORE_SPS_PPS) {
  7.         return ERROR_SUCCESS;
  8.     }
  9.     return ret;
  10. }
复制代码
找到write_h264_sps_pps函数的定义代码如下,发现函数内部在封装序列头时依次输入了SPS帧和PPS帧:
  1. // h264 raw to h264 packet.
  2. std::string sh;
  3. if ((err = avc->mux_sequence_header(h264_sps, h264_pps, sh)) != srs_success) {
  4.     // TODO: FIXME: Use error
  5.     ret = srs_error_code(err);
  6.     srs_freep(err);
  7.     return ret;
  8. }
复制代码
进一步跟踪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帧)。
  1. // sps
  2. if (true) {
  3.     // 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
  4.     // numOfSequenceParameterSets, always 1
  5.     stream.write_1bytes(uint8_t(0xe0 | 0x01));
  6.     // sequenceParameterSetLength
  7.     stream.write_2bytes((int16_t)sps.length());
  8.     // sequenceParameterSetNALUnit
  9.     stream.write_string(sps);
  10. }
  11. // pps
  12. if (true) {
  13.     // 5.3.4.2.1 Syntax, ISO_IEC_14496-15-AVC-format-2012.pdf, page 16
  14.     // numOfPictureParameterSets, always 1
  15.     stream.write_1bytes(0x01);
  16.     // pictureParameterSetLength
  17.     stream.write_2bytes((int16_t)pps.length());
  18.     // pictureParameterSetNALUnit
  19.     stream.write_string(pps);
  20. }
复制代码
由此可见,SRS在每个TS包头都写入了SPS帧和PPS帧,确保TS包是拥有SPS和PPS的完整H.264分片。只有加上SPS与PPS,客户端才能正常拉流解析数据,才能正常渲染视频画面。 
更多具体的FFmpeg开辟知识参见《FFmpeg开辟实战:从零基础到短视频上线》一书。
 



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

尚未崩坏

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表