​《FFmpeg开发实战:从零基础到短视频上线》一书的“3.4.3  把原始的H264文件封装为MP4格式”介绍了如何把H.264裸流封装为MP4文件。那么在网络上传输的H.264裸流是怎样被接收端获取视频格式的呢?前文指出H.264流必定以“SPS帧→PPS帧→IDR帧”开头,接下来就来验证是否确实如此。

这里用到了雷霄骅雷神写的H264分析器,在此向雷神致敬,雷神10年前写的小程序至今仍然好用。打开H264分析器,该软件的初始界面如下图所示:

单击文件路径栏右边的打开按钮,在弹出的文件对话框中选择某个H.264裸流文件,再单击界面右下角的开始按钮,分析器便开始分析H264文件的内容格式,分析后的结果界面如下图所示:

从分析结果可见,H.264裸流的开头三帧果然是“SPS帧→PPS帧→IDR帧”。单击列表中的某个帧,界面右侧会显示该帧的详细字段信息。

当然,分析器只能读取H.264裸流文件。倘若让分析器读取MP4文件,就无法正常读出各帧信息。那么流媒体服务器又是怎么把MP4文件转化为H.264裸流的呢?

以ZLMediaKit为例,它在向推流序列插入I帧时做了特殊处理,一旦出现I帧,就自动插入SPS与PPS等配置帧。具体代码在ZLMediaKit框架的ext-codec/H264.cpp,查看该源码的H264Track::inputFrame_l函数,找到以下的代码片段,可见程序在判断关键帧之后调用了insertConfigFrame函数。

// 判断是否是I帧, 并且如果是,那判断前面是否插入过config帧, 如果插入过就不插入了
if (frame->keyFrame() && !_latest_is_config_frame) {
    insertConfigFrame(frame); // 插入SPS帧和PPS帧
}
if(!frame->dropAble()){
    _latest_is_config_frame = false;
}
ret = VideoTrack::inputFrame(frame);

找到insertConfigFrame函数的定义代码如下,果然函数内容依次插入了SPS帧和PPS帧:

// 插入SPS帧和PPS帧
void H264Track::insertConfigFrame(const Frame::Ptr &frame) {
    if (!_sps.empty()) { // 插入SPS帧
        auto spsFrame = FrameImp::create<H264Frame>();
        spsFrame->_prefix_size = 4;
        spsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
        spsFrame->_buffer.append(_sps);
        spsFrame->_dts = frame->dts();
        spsFrame->setIndex(frame->getIndex());
        VideoTrack::inputFrame(spsFrame);
    }
    if (!_pps.empty()) { // 插入PPS帧
        auto ppsFrame = FrameImp::create<H264Frame>();
        ppsFrame->_prefix_size = 4;
        ppsFrame->_buffer.assign("\x00\x00\x00\x01", 4);
        ppsFrame->_buffer.append(_pps);
        ppsFrame->_dts = frame->dts();
        ppsFrame->setIndex(frame->getIndex());
        VideoTrack::inputFrame(ppsFrame);
    }
}

由此可见,ZLMediaKit在每个关键帧前面都额外插入了SPS帧和PPS帧,确保H.264裸流维持着形如“SPS帧→PPS帧→IDR帧”的队形。如果不添加SPS和PPS,客户端在拉流时会报错如下:

[NULL @ 0000022ed7782540] non-existing PPS 0 referenced

只有加上SPS与PPS,客户端才能正常拉流解析数据,才能正常渲染视频画面。 

更多详细的FFmpeg开发知识参见《FFmpeg开发实战:从零基础到短视频上线》一书。

FFmpeg开发笔记(三十三)分析ZLMediaKit对H.264流的插帧操作的更多相关文章

  1. FFmpeg开发笔记(三):ffmpeg介绍、windows编译以及开发环境搭建

    前言   本篇章是对之前windows环境的补充,之前windows的是无需进行编译的,此篇使用源码进行编译,版本就使用3.4.8.   FFmpeg简介   FFmpeg是领先的多媒体框架,能够解码 ...

  2. FFmpeg开发笔记(四):ffmpeg解码的基本流程详解

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  3. FFmpeg开发笔记(五):ffmpeg解码的基本流程详解(ffmpeg3新解码api)

    若该文为原创文章,未经允许不得转载原博主博客地址:https://blog.csdn.net/qq21497936原博主博客导航:https://blog.csdn.net/qq21497936/ar ...

  4. FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放

    前言   ffmpeg播放rtsp网络流和摄像头流.   Demo   使用ffmpeg播放局域网rtsp1080p海康摄像头:延迟0.2s,存在马赛克     使用ffmpeg播放网络rtsp文件流 ...

  5. FFmpeg开发笔记(十):ffmpeg在ubuntu上的交叉编译移植到海思HI35xx平台

    FFmpeg和SDL开发专栏(点击传送门) 上一篇:<FFmpeg开发笔记(九):ffmpeg解码rtsp流并使用SDL同步播放>下一篇:敬请期待   前言   将ffmpeg移植到海思H ...

  6. Django开发笔记三

    Django开发笔记一 Django开发笔记二 Django开发笔记三 Django开发笔记四 Django开发笔记五 Django开发笔记六 1.基于类的方式重写登录:views.py: from ...

  7. Django笔记三十三之缓存操作

    本文首发于公众号:Hunter后端 原文链接:Django笔记三十三之缓存操作 这一节介绍一下如何在 Django 中使用 redis 做缓存操作. 在 Django 中可以有很多种方式做缓存,比如数 ...

  8. 《手把手教你》系列技巧篇(三十三)-java+ selenium自动化测试-单选和多选按钮操作-上篇(详解教程)

    1.简介 在实际自动化测试过程中,我们同样也避免不了会遇到单选和多选的测试,特别是调查问卷或者是答题系统中会经常碰到.因此宏哥在这里直接分享和介绍一下,希望小伙伴或者童鞋们在以后工作中遇到可以有所帮助 ...

  9. FFmpeg开发笔记(一)搭建Linux系统的开发环境

    对于初学者来说,如何搭建FFmpeg的开发环境是个不小的拦路虎,因为FFmpeg用到了许多第三方开发包,所以要先编译这些第三方源码,之后才能给FFmpeg集成编译好的第三方库.不过考虑到刚开始仅仅调用 ...

  10. Java开发笔记(十三)利用关系运算符比较大小

    前面在<Java开发笔记(九)赋值运算符及其演化>中提到,Java编程中的等号“=”表示赋值操作,并非数学上的等式涵义.Java通过等式符号“==”表示左右两边相等,对应数学的等号“=”: ...

随机推荐

  1. Tomcat+web测试环境配置

    一.JDK安装完成 二.Tomcat安装配置 1:官网下载tomact,地址为:https://tomcat.apache.org/download-80.cgi 2:将下载后的文件解压 3:进入To ...

  2. Pr 的导出视频

    导出视频 https://www.bilibili.com/video/BV1Vt411n7Bb?p=7

  3. vscode插件安装和配置支持vue3

    一.常用插件介绍 1.插件Vue 3 Snippets 作用:用于vue3的智能代码提示,语法高亮.智能感知.Emmet等.替代Vetur插件,Vetur在vue2时期比较流行. 常用命令:vuein ...

  4. windows server2012 挂载linux的nfs共享目录

    1.安装NFS客户端 首先win-server上添加角色-----选择文件服务-----网络文件系统(或者NFS客户端)-安装 2.挂载nfs目录 先cmd检查服务端的共享目录 然后执行:showmo ...

  5. web3.js:使用eth包

    原文在这里 简介 web3-eth包提供了一套强大的功能,可以与以太坊区块链和智能合约进行交互.在本教程中,我们将指导您如何使用web3.js版本4的web3-eth包的基础知识.我们将在整个示例中使 ...

  6. prometheus使用3

    不错链接 60.Prometheus-alertmanager.邮件告警配置   https://www.cnblogs.com/ygbh/p/17306539.html 服务发现 基于文件的服务发现 ...

  7. uniapp android端和ios端铃声静音,但是还是会震动

    uniapp 使用了html5plus的api,可以实现调用原生的api功能,htm5plus官方api文档: https://www.html5plus.org/doc/zh_cn/ios.html ...

  8. 一文搞懂 Spring Bean 的生命周期

    一. 前言 在学习Spring框架的IOC.AOP两大功能之前,首先需要了解这两个技术的基础--Bean.在Spring框架中,Bean无处不在,IOC容器管理的对象就是各种各样的Bean.理解Bea ...

  9. CSS操作——文本属性

    1.font-style(字体样式风格) /* 属性值: normal:设置字体样式为正体.默认值. italic:设置字体样式为斜体.这是选择字体库中的斜体字. oblique:设置字体样式为斜体. ...

  10. aardio桌面软件开发 简单,打包后文件小,支持 .net python 和 众多插件

    aardio 编程语言 - 官网 aardio  专注于桌面软件开发,17年一直保持非常活跃地更新( 更新日志 ),aardio 被多年用于生产项目实践,久经测试和锤炼.aardio 在诞生之初就设计 ...