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开发实战:从零基础到短视频上线》一书。

相关推荐
EasyDSS1 小时前
讲座视频资源散存易丢失?视频直播点播EasyDSS校园/视频融媒体平台高效管理视频
音视频·媒体·easydss
2601_965619693 小时前
AI视频制作:做历史战争视频,兵力部署的老地图难找,AI怎么自动配战争地图?
人工智能·音视频
2601_965449086 小时前
AI视频制作:做系列考古视频音色不统一,AI 音色克隆的完整流程
人工智能·机器学习·音视频
2601_965449087 小时前
AI视频制作:做系列历史地图视频想固定音色,AI 音色克隆的流程实测
人工智能·音视频
智塑未来8 小时前
AI视频翻译配音工具怎么选?5款工具的链路覆盖对比
人工智能·音视频
做萤石二次开发的哈哈10 小时前
商场分区广播怎么开发?商用音频主机四大技能与音频文件管理实践
音视频·蓝海aiot一站式工作台·公共广播·智慧广播·萤石云开放平台·商用音频主机·矩阵路由
音视频牛哥11 小时前
大牛直播SDK(SmartMediaKit)iOS平台Unity3D RTSP/RTMP播放器集成实践
音视频·unity3d·ios rtmp播放器·ios rtsp播放器·ios unity3d播放器·ios unity rtsp·ios unity rtmp
美狐美颜SDK开放平台12 小时前
视频美颜SDK如何应对快速转头与大幅度面部动作?
android·人工智能·ios·音视频·直播美颜sdk·视频美颜sdk
甜到心里的蛋糕14 小时前
AI 生成 MV 音频异响排查:频谱定位、片段替换与 Nginx 缓存
人工智能·python·nginx·ffmpeg·音视频·音频处理
镭封1 天前
从视频文案提取到 AI 配音,短视频制作需要哪些工具?
人工智能·智能手机·音视频·语音识别·媒体