FFmpeg SPS/PPS剖析

简介:

场景说明
            在解码过程中,需要设置SPS/PPS等解码信息,才能够初始化解码器。有两种方式可以设置SPS/PPS,一种是手动指定SPS/PPS内容,指定AVCodecContext
结构体中extradata的值;一种是让FFmpeg通过读取传输数据来分析SPS/PPS信息,一般情况下在每一个I帧之前都会发送一个SPS帧和PPS帧


方法1)一般的摄像机都会在RTSP指令中SDP携带的SPS/PPS内容,例如海康IPC发送的RTSP指令中携带信息如下:sprop-parameter-sets=Z0IAKpY1QPAET8s3AQEBQAABwgAAV+QB,aM48gA==
分号前面是SPS,后面是PPS,这是base64编码的结果,需要解码,才能够传递给extradata,并且还需要在SPS/PPS字符串前面添加起始码(0x00 0x00 0x00 0x01)。补充一点SPS的类型是
0x67, PPS的类型是0x68

char szBase64SPSBuffer[] = { "Z0IAKpY1QPAET8s3AQEBQAABwgAAV+QB" };
uint8_t szDecodedSPS[128] = { 0 };
int nSPSLen = av_base64_decode(szDecodedSPS, szBase64SPSBuffer, sizeof(szBase64SPSBuffer));//nSPSLen=24

char szBase64PPSBuffer[] = { "aM48gA==" };
uint8_t szDecodedPPS[128] = { 0 };
int nPPSLen = av_base64_decode(szDecodedPPS, szBase64PPSBuffer, sizeof(szBase64PPSBuffer));//nPPSLen=4

将SPS/PPS拼凑的结果如下:
unsigned char szSPSPPS[] = { 0x00 ,0x00 ,0x01,0x67,0x42,0x00 ,0x2a ,0x96 ,0x35 ,0x40 ,0xf0 ,0x04 ,0x4f ,0xcb ,0x37 ,0x01 ,0x01 ,0x01 ,0x40 ,0x00 ,0x01 ,0xc2 ,0x00 ,0x00 ,0x57 ,0xe4 ,0x01 ,0x00 ,0x00 ,0x00 ,0x01 ,0x68 ,0xce ,0x3c ,0x80, 0x00};


然后拷贝SPS/PPS数据到AVFormatContext的extradata
unsigned char szSPSPPS[] = { 0x00 ,0x00 ,0x01,0x67,0x42,0x00 ,0x2a ,0x96 ,0x35 ,0x40 ,0xf0 ,0x04 ,0x4f ,0xcb ,0x37 ,0x01 ,0x01 ,0x01 ,0x40 ,0x00 ,0x01 ,0xc2 ,0x00 ,0x00 ,0x57 ,0xe4 ,0x01 ,0x00 ,0x00 ,0x00 ,0x01 ,0x68 ,0xce ,0x3c ,0x80, 0x00};
pFormatContext->streams[0]->codecpar->extradata_size = sizeof(szSPSPPS);
pFormatContext->streams[0]->codecpar->extradata = (uint8_t*)av_mallocz(pFormatContext->streams[0]->codecpar->extradata_size + AV_INPUT_BUFFER_PADDING_SIZE);
memcpy(pFormatContext->streams[0]->codecpar->extradata, szSPSPPS, sizeof(szSPSPPS));

通过avcodec_parameters_to_context将信息从pFormatContext->streams[0]->codecpar拷贝到m_pAVCodecContext
avcodec_open2函数在调用的时候,会解析extradata数据的内容


出错异常

I:2018-01-08 14:23:00 ms:221:nal_unit_type: 7, nal_ref_idc: 3
I:2018-01-08 14:23:00 ms:221:nal_unit_type: 8, nal_ref_idc: 3
I:2018-01-08 14:23:00 ms:221:sps:0 profile:66/42 poc:0 ref:1 120x68 FRM 8B8 crop:0/0/0/8 VUI 420 1800/90000 b8 reo:-1
I:2018-01-08 14:23:00 ms:221:pps:0 sps:0 CAVLC slice_groups:1 ref:1/1  qp:26/26/0/0 LPAR   
I:2018-01-08 14:23:00 ms:222:deprecated pixel format used, make sure you did set range correctly
I:2018-01-08 14:23:00 ms:250:non-existing PPS 0 referenced

错误分析
        从av_log日志可以看出已经正确的解析出来PPS,但是在进行avcodec_read_frame的时候 还是打印出错non-existing PPS 0 referenced,这是什么问题?
这主要是没有在缓冲区中读取到包含SPS/PPS信息的帧,而不是说解码器没有正确初始化SPS/PPS参数,这一点需要注意

展望

        从这里就可以看出,实际上并没有多大的必要手动设置SPS/PPS,因为FFmpeg会从缓冲中分析出SPS/PPS,然后解析出码流参数,估计唯一的一种极端情况是I帧之前没有任何的SPS/PPS信息,或者需要很长时间才会发送一帧包含SPS/PPS的信息


相关代码定义
/**
 * This struct describes the properties of an encoded stream.
 
*
 * sizeof(AVCodecParameters) is not a part of the public ABI, this struct must
 
* be allocated with avcodec_parameters_alloc() and freed with
 
* avcodec_parameters_free().
 
*/
typedef struct AVCodecParameters {
/**
     * Extra binary data needed for initializing the decoder, codec-dependent.
     *
     
* Must be allocated with av_malloc() and will be freed by
     
* avcodec_parameters_free(). The allocated size of extradata must be at
     
* least extradata_size + AV_INPUT_BUFFER_PADDING_SIZE, with the padding
     * bytes zeroed.
     */

    uint8_t *extradata;
    
/**
     * Size of the extradata content in bytes.  
*/
    int      extradata_size;
}

描述说明
额外的二进制数据用来初始化解码器,主要是初始化SPS/PPS,必须通过av_malloc进行内存分配,然后通过avcodec_parameters_free进行释放。内存分配的大小必须是extradata_size的大小加上AV_INPUT_BUFFER_PADDING_SIZE二进制数据的真实长度大小保存在extradata_size


     本文转自fengyuzaitu 51CTO博客,原文链接:http://blog.51cto.com/fengyuzaitu/2058138,如需转载请自行联系原作者





相关文章
|
8月前
|
存储 编解码
FFmpeg开发笔记(三十)解析H.264码流中的SPS帧和PPS帧
《FFmpeg开发实战》书中介绍了音视频编码历史,重点讲述H.264的成功在于其分为视频编码层和网络抽象层。H.264帧类型包括SPS(序列参数集,含视频规格参数),PPS(图像参数集,含编码参数)和IDR帧(立即解码刷新,关键帧)。SPS用于计算视频宽高和帧率,PPS存储编码设置,IDR帧则标志新的解码序列。书中还配以图片展示各帧结构详情,完整内容可参考相关书籍。
318 7
FFmpeg开发笔记(三十)解析H.264码流中的SPS帧和PPS帧
|
4月前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
ijkplayer是由Bilibili基于FFmpeg3.4研发并开源的播放器,适用于Android和iOS,支持本地视频及网络流媒体播放。本文详细介绍如何在新版Android Studio中导入并使用ijkplayer库,包括Gradle版本及配置更新、导入编译好的so文件以及添加直播链接播放代码等步骤,帮助开发者顺利进行App调试与开发。更多FFmpeg开发知识可参考《FFmpeg开发实战:从零基础到短视频上线》。
421 2
FFmpeg开发笔记(六十)使用国产的ijkplayer播放器观看网络视频
|
4月前
|
编解码 语音技术 内存技术
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
《FFmpeg开发实战:从零基础到短视频上线》一书中的“5.1.2 把音频流保存为PCM文件”章节介绍了将媒体文件中的音频流转换为原始PCM音频的方法。示例代码直接保存解码后的PCM数据,保留了原始音频的采样频率、声道数量和采样位数。但在实际应用中,有时需要特定规格的PCM音频。例如,某些语音识别引擎仅接受16位PCM数据,而标准MP3音频通常采用32位采样,因此需将32位MP3音频转换为16位PCM音频。
126 0
FFmpeg开发笔记(五十八)把32位采样的MP3转换为16位的PCM音频
|
4月前
|
XML 开发工具 Android开发
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
ExoPlayer最初是为了解决Android早期MediaPlayer控件对网络视频兼容性差的问题而推出的。现在,Android官方已将其升级并纳入Jetpack的Media3库,使其成为音视频操作的统一引擎。新版ExoPlayer支持多种协议,解决了设备和系统碎片化问题,可在整个Android生态中一致运行。通过修改`build.gradle`文件、布局文件及Activity代码,并添加必要的权限,即可集成并使用ExoPlayer进行网络视频播放。具体步骤包括引入依赖库、配置播放界面、编写播放逻辑以及添加互联网访问权限。
280 1
FFmpeg开发笔记(五十六)使用Media3的Exoplayer播放网络视频
|
4月前
|
Web App开发 安全 程序员
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
多年的互联网寒冬在今年尤为凛冽,坚守安卓开发愈发不易。面对是否转行或学习新技术的迷茫,安卓程序员可从三个方向进阶:1)钻研谷歌新技术,如Kotlin、Flutter、Jetpack等;2)拓展新功能应用,掌握Socket、OpenGL、WebRTC等专业领域技能;3)结合其他行业,如汽车、游戏、安全等,拓宽职业道路。这三个方向各有学习难度和保饭碗指数,助你在安卓开发领域持续成长。
114 1
FFmpeg开发笔记(五十五)寒冬里的安卓程序员可进阶修炼的几种姿势
|
5月前
|
XML Java Android开发
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
GSYVideoPlayer是一款国产移动端视频播放器,支持弹幕、滤镜、广告等功能,采用IJKPlayer、Media3(EXOPlayer)、MediaPlayer及AliPlayer多种内核。截至2024年8月,其GitHub星标数达2万。集成时需使用新版Android Studio,并按特定步骤配置依赖与权限。提供了NormalGSYVideoPlayer、GSYADVideoPlayer及ListGSYVideoPlayer三种控件,支持HLS、RTMP等多种直播链接。
215 18
FFmpeg开发笔记(五十二)移动端的国产视频播放器GSYVideoPlayer
|
4月前
|
Linux API 开发工具
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
ijkplayer是由B站研发的移动端播放器,基于FFmpeg 3.4,支持Android和iOS。其源码托管于GitHub,截至2024年9月15日,获得了3.24万星标和0.81万分支,尽管已停止更新6年。本文档介绍了如何在Linux环境下编译ijkplayer的so库,以便在较新的开发环境中使用。首先需安装编译工具并调整/tmp分区大小,接着下载并安装Android SDK和NDK,最后下载ijkplayer源码并编译。详细步骤包括环境准备、工具安装及库编译等。更多FFmpeg开发知识可参考相关书籍。
142 0
FFmpeg开发笔记(五十九)Linux编译ijkplayer的Android平台so库
|
5月前
|
Linux 开发工具 Android开发
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher
EasyPusher是一款国产RTSP直播录制推流客户端工具,支持Windows、Linux、Android及iOS等系统。尽管其GitHub仓库(安卓版:https://github.com/EasyDarwin/EasyPusher-Android)已多年未更新,但通过一系列改造,如升级SDK版本、迁移到AndroidX、指定本地NDK版本及更新Gradle版本等,仍可在最新Android Studio上运行。以下是针对Android Studio Dolphin版本的具体改造步骤。
98 3
FFmpeg开发笔记(五十三)移动端的国产直播录制工具EasyPusher