H264码流分两种组织方式,一种是AnnexB格式,一种是AVCC格式。

作者:码农小明

来源:https://blog.csdn.net/shaosunrise/article/details/121548065

首先要了解的是H.264编码规范只是规定了如何编码,并没有规定以何种方式来排列编码后的数据

就如同AES算法只是规定如何加密一组数据,并没有强制规定如果分组。H.264规范没有规定如何组织数据,但是在附录B中提供了一种可选方案,即Annex B格式。

H.264 NALU 概念

H.264视频编码后的数据叫 NALU(Network Abstraction Layer Units)

NALU有多种类型,分为两大类:VCL(Video Coding Layer) 和 非VCL。VCL是图像编码数据,非VCL为编码参数信息。

NALU结构头部指明类型,类型字段如下。

SPS:序列参数集,包含解码配置,比如profile level 分辨率和帧率等。

PPS:图像参数集,包含有关熵编码模式、分片组、运动预测和去块滤波器等信息。

IDR: 立即解码刷新单元,这种NALU包含一个完整的图像序列,不依赖其他NALU就可以独立解码和显示,即一种特殊的I帧。

值得注意的是,一个NALU即使是VCL NALU 也并不一定表示一个视频帧。因为一个帧的数据可能比较多,可以分片为多个NALU来储存。一个或者多个NALU组成一个访问单元AU,一个AU包含一个完整的帧。

H.264 码流格式

H264码流分两种组织方式,一种是AnnexB格式,一种是AVCC格式。

AnnexB格式

[start code]NALU | [start code] NALU |...

这种格式比较常见,也就是我们熟悉的每个帧前面都有0x00 00 00 01或者0x00 00 01作为起始码。

h264文件就是采用的这种格式,每个帧前面都要有个起始码。

SPS PPS等也作为一类NALU存储在这个码流中,一般在码流最前面。也就是说这种格式包含VCL 和 非VCL 类型的NALU。

AVCC格式

([extradata]) | ([length] NALU) | ([length] NALU) | ...

这种模式也叫AVC1格式,没有起始码,每个帧最前面几个字节(通常4字节)是帧长度。

这里的NALU一般没有SPS PPS等参数信息,参数信息属于额外数据extradata存在其他地方。

比如ffmpeg中解析mp4文件后sps pps存在streams[index]->codecpar->extradata;中。

也就是说这种码流通常只包含VCL类型NALU。

这些extradata通常有如下格式(可以根据这个规则ffmpeg解析mp4文件的SPS和PPS)

第1字节:version (通常0x01)
第2字节:avc profile (值同第1个sps的第2字节)
第3字节:avc compatibility (值同第1个sps的第3字节)
第4字节:avc level (值同第1个sps的第3字节)
第5字节前6位:保留全1
第5字节后2位:NALU Length 字段大小减1,通常这个值为3,即NAL码流中使用3+1=4字节表示NALU的长度
第6字节前3位:保留,全1
第6字节后5位:SPS NALU的个数,通常为1
第7字节开始后接1个或者多个SPS数据SPS结构 [16位 SPS长度][SPS NALU data]SPS数据后
第1字节:PPS的个数,通常为1
第2字节开始接1个或多个PPS数据PPS结构 [16位 PPS长度][SPS NALU data]

FFmpeg解析mp4中H.264 码流

MP4文件中编码信息是存储在文件开始或者文件末尾的,详细结构这里不详述了。就知道不是和图像数据放在一起的就可以了。FFmpeg使用av_read_frame(AVFormatContext *s, AVPacket *pkt)函数读mp4文件,读到packet里面仅仅是VCL编码数据NAL,并且这个编码数据是AVCC格式组织的码流,直接保存成.264文件没法播放。

先说一下思路:

1 .从avFmtCtx->streams[_videoStreamIndex]->codecpar->extradata中解析SPS和PPS数据,数据格式上一节已经描述了。解析出SPS PPS数据加上4字节的0001的起始码拼装成nnexB格式的NALU,先写入文件。

  1. 通过av_read_frame(AVFormatContext *s, AVPacket *pkt)读取到数据存放在pkt->data中,长度为pkt->size。

注意:这1个pkt->data中的数据可能是多个NALU的数据!!!这些数据按([length] NALU) | ([length] NALU) | ...规则排列。先取前4字节作为长度,读取指定长度的数据加上起始码拼NALU。然后同样的方式读取后面的数据,直到总长度等于pkt->size。

FFmpeg 解析mp4中H264码流 代码示例

这里就只贴关键部分代码。省略前面打开文件和查询流信息等操作。

//...AVPacket spsPacket, ppsPacket, tmpPacket;uint8_t startCode[4] = {0x00, 0x00, 0x00, 0x01};bool sendSpsPps = false;while (av_read_frame(_avFmtCtx, _avPacket) == 0) { // 能读到数据返回0,循环读取// 根据pkt->stream_index判断是不是视频流if (_avPacket->stream_index == _videoStreamIndex) {// 仅1次处理sps pps,也可以拿在while外面if (!sendSpsPps) { int spsLength = 0;int ppsLength = 0;// extradata 数据指针,方便操作取其指针uint8_t *ex = _avFmtCtx->streams[_videoStreamIndex]->codecpar->extradata;// extradata;第6字节后5位表示SPS个数,通常为1,这里就省略判断处理,严谨期间还是要判断// 直接 取第7 8 俩字节作为SPS长度spsLength = (ex[6] << 8) | ex[7];// x[8+spsLength]表示PPS个数,通常为1,这里就省略判断处理// 取接下来两位作为PPS长度ppsLength = (ex[8 + spsLength + 1] << 8) | ex[8 + spsLength + 2];// 为spsPacket ppsPacket的data分配内存,类似malloc// 如果只是为了保存文件,可以不使用pkt结构,直接malloc就行// 分配的空间为sps或pps长度加上4字节的起始码av_new_packet(&spsPacket, spsLength + 4);av_new_packet(&ppsPacket, ppsLength + 4);// 给SPS拼前4字节起始码memcpy(spsPacket.data, startCode, 4);// 把SPS数据拼在起始码后面memcpy(spsPacket.data + 4, ex + 8, spsLength);// TODO: 这里可以把spsPacket.data数据写入文件 // 给PPS拼前4字节起始码memcpy(ppsPacket.data, startCode, 4);// 把PPS数据拼在起始码后面memcpy(ppsPacket.data + 4, ex + 8 + spsLength + 2 + 1, ppsLength);// TODO: 这里可以把ppsPacket.data数据写入文件 sendSpsPps = true;}// 下面处理读到pkt中的数据int nalLength = 0;uint8_t *data = _avPacket->data;// _avPacket->data中可能有多个NALU,循环处理while (data < _avPacket->data + _avPacket->size) {// 取前4字节作为nal的长度nalLength = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];if (nalLength > 0) {memcpy(data, startCode, 4);  // 拼起始码tmpPacket = *_avPacket;      // 仅为了复制packet的其他信息,保存文件可忽略tmpPacket.data = data;   // 把tmpPkt指针偏移到实际数据位置tmpPacket.size = nalLength + 4; // 长度为nal长度+起始码4//TODO: 处理这个NALU的数据,可以直接把tmpPacket.data写入文件}data = data + 4 + nalLength; // 处理data中下一个NALU数据}}av_packet_unref(_avPacket);}

上述代码FFmpeg 4.4使用正常。

此外,FFmpeg也提供了h264_mp4toannexb_filter相关的过滤器进行相应转换的操作,这里不示例怎么用了。

最后欢迎大家加入 音视频开发进阶 知识星球 ,这里有知识干货、编程答疑、开发教程,还有很多精彩分享。

更多内容可以在星球菜单中找到,随着时间推移,干货也会越来越多!!!

给出 10元 优惠券,涨价在即,目前还是白菜价,基本上提几个问题就回本,投资自己就是最好的投资!!!

加我微信 ezglumes ,拉你进技术交流群

推荐阅读:

音视频开发工作经验分享 || 视频版

OpenGL ES 学习资源分享

开通专辑 | 细数那些年写过的技术文章专辑

Android NDK 免费视频在线学习!!!

你想要的音视频开发资料库来了

推荐几个堪称教科书级别的 Android 音视频入门项目

觉得不错,点个在看呗~

H.264 媒体流 AnnexB 和 AVCC 格式分析 及 FFmpeg 解析mp4的H.264码流方法相关推荐

  1. python 读取文件读出来是什么格式-深入学习python解析并读取PDF文件内容的方法...

    这篇文章主要学习了python解析并读取PDF文件内容的方法,包括对学习库的应用,python2.7和python3.6中python解析PDF文件内容库的更新,包括对pdfminer库的详细解释和应 ...

  2. 用于MPEG-4视听流的RTP负载格式

    MPEG-4的rtp协议封装 英文原版 RFC 3016:http://www.rfc-editor.org/rfc/rfc3016.txt 中文翻译: 组织:中国互动出版网(http://www.c ...

  3. 码流格式: Annex-B, AVCC(H.264)与HVCC(H.265), extradata详解

    1.前言 介绍H.264结构的文章铺天盖地,无责任翻译.无责任转载以及部分经验之谈(目前搜索最靠前的一篇实际是对stackoverflow上答案的翻译..链接后面给出了),所以缺的不是资料,是叙述准确 ...

  4. 五. H.264的码流封装格式

    H.264的语法元素进行编码后,生成的输出数据都封装为NAL Unit进行传递,多个NAL Unit的数据组合在一起形成总的输出码流.对于不同的应用场景,NAL规定了一种通用的格式适应不同的传输封装类 ...

  5. nalu格式annex-B和avcc

    一 annexb和avcc Annexb 视频编码成的包叫做Network Abstraction Layer Units, 也简称为NALU.NAL,每个NALU包都可以被单独的解析和处理,每个NA ...

  6. H.264基础知识及视频码流解析

    H.264基础知识及视频码流解析 目录 H.264概述 H264相关概念 H264压缩方式 H264分层结构 H264码流结构 H264的NAL单元 H.264视频码流解析及代码实现 1. H.264 ...

  7. 原始 H.264 码流播放

    我们平时遇到的视频文件各式各样,五花八门.通常它们会根据格式的不同,而有着不同的扩展名,比如 avi,rmvb,mkv,mp4 等等等.这些格式代表的都是 封装格式. 这些文件通常产生的过程是这样的: ...

  8. 视音频数据处理入门:H.264视频码流解析

    ===================================================== 视音频数据处理入门系列文章:视音频数据处理入门:RGB.YUV像素数据处理视音频数据处理入门 ...

  9. 【数据压缩】H.264文件解析和码流分析

    一.实验课要求 选择一个.mp4或者.264文件. 在码流分析仪软件中打开该文件,从几个层次进行分析: 分析SPS和PPS里都包含哪些主要的信息,给出参数值.(例如分辨率.帧率.GOP结构等等) 以一 ...

最新文章

  1. IntelliJ 发布 2020 RoadMap,中文版终于要来了?
  2. Weblogic配置故障转移
  3. Python内置函数zip map filter的使用
  4. ESB学习笔记(Spring Integration实战)
  5. Photoshop的基本操作
  6. Python3 爬虫学习笔记 C11【数据储存系列 — MongoDB】
  7. Linux内核网络数据包处理流程
  8. Qt实践录:一些界面设计的记录示例
  9. thinkphp系统常量与自定义常量
  10. [Telink][TLSR8251] [泰凌微][SDK3.4] 上手第二步 框架介绍
  11. TscanCode代码扫描工具
  12. IE浏览器验证码不刷新
  13. 基于captcha的图形验证码实现
  14. 银光团队项目正式启动,欢迎您的参与!
  15. 【无标题】求X的n次方函数
  16. 根据ip查询地理位置
  17. 【2G模组Air202开发】Lua脚本编程实现MQTT协议连接Tlink平台(三)
  18. 没有足够的内存继续执行程序.(mscorlib)
  19. 专家观点:Facebook的衰落
  20. 在10Gbps网络下开启Huawei CE6850交换机的ECN功能并实验DCTCP协议

热门文章

  1. Java API思维导图
  2. PIC 单片机的振荡器及程序烧写
  3. 【案例25】配置https之后 IE打不开登陆页面
  4. 成为杰出人物的路线图_如何成为杰出的初级开发人员
  5. 快速入门百度Ai(java向)
  6. CPLEX出现‘q1‘ is not convex?
  7. C# WinForm 借助Windows API 实现进程间通信
  8. python——读取docx文档wordcloud生成词云并进行词频统计
  9. 新手爬虫——网易云音乐分析
  10. VulnHub-Raven