jason--liu / Blog

MyBlog

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

使用FFmpeg提取mp4文件中的H264码流

jason--liu opened this issue · comments

MP4的视频H264封装有2种格式:h264和avc1,对于这个细节,很容易被忽略(是的,我是新手,不知道MP4里面是AVC1,走了很多弯路)。其次,通过ffprobe也可以看到我测试的mp4文件里面H264是AVC1格式的。
image

AVCC与Annex-B

H264码流分为AVCC与Annex-B两种组织格式。

  • AVCC格式 也叫AVC1格式,MPEG-4格式,字节对齐,因此也叫Byte-Stream Format。用于mp4/flv/mkv等封装中。
  • Annex-B格式 也叫MPEG-2 transport stream format格式(ts格式), ElementaryStream格式。用于TS流中(以及使用TS作为切片的hls格式中)。

这两种格式的区别有两点: 1. NALU的分割方式不同; 2. SPS/PPS的数据结构不同。

  •  AVCC格式使用NALU长度(固定字节,字节数由extradata中的信息给定)进行分割,在封装文件或者直播流的头部包含extradata信息(非NALU),extradata中包含NALU长度的字节数以及SPS/PPS信息。
  • Annex-B格式使用start code进行分割,start code为0x000001或0x00000001,SPS/PPS作为一般NALU单元以start code作为分隔符的方式放在文件或者直播流的头部。

我们知道H264是由多个NALU组成,每个NALU之间都使用start code(起始码)分隔。
00 00 00 01为SPS或PPS的起始码
00 00 01是其他NALU的起始码

读取数据

ffmpeg读取mp4中的H264数据,并不能直接得到NALU,文件中也没有储存0x00000001的分隔符。

格式规定

MPEG-4 Part 15 "Advanced Video Coding (AVC) file format" section 5.2.4.1 的规定如下:

bits
8 version ( always 0x01 )
8 avc profile ( sps[0][1] )
8 avc compatibility ( sps[0][2] )
8 avc level ( sps[0][3] )
6 reserved ( all bits on ) // 即 0xFC | current byte
2 NALULengthSizeMinusOne // 前缀长度-1
3 reserved ( all bits on ) // 即 0xE0 | currrent byte
5 number of SPS NALUs (usually 1)
-- repeated once per SPS --
16 SPS size
N variable SPS NALU data
8 number of PPS NALUs (usually 1)
-- repeated once per PPS --
16 PPS size
N variable PPS NALU data

提取流程

1、打开MP4文件,循环读取
2、从AVPacket获取IDR(nalu type==5),从AVFormatContext->streams[video_index]->codec->extradata获取SPS与PPS。
3、添加start code,给SPS与PPS前加上00 00 00 01,IDR加上00 00 01
4、按照上图的数据结构写入文件中
5、继续提取NALU,添加start code(00 00 01),写入文件中

主要事项

1、SPS与PPS存在于AVFormatContext->streams[video_index]->codec->extradata
2、其他的NALU存在于读取出来的AVPacket中
3、AVPacket->data前四个字节表示当前NALU的大小,根据这一条件可以获取NALU
4、AVFormatContext->streams[video_index]->codec->extradata + 5,之后两个字节表示SPS的个数,SPS的数据结束后的两个字节表示PPS的个数

具体代码请看这里

参考资料

码流格式: Annex-B, AVCC(H.264)与HVCC(H.265), extradata详解
视频码流格式解析
从MP4抽取H.264视频数据
h264-extradata-partially-explained