这里主要介绍下H264和H265存储和传输格式的基本知识介绍,如果知识想了解如何fmp4封装,本节可以跳过。
H265和H265标准中指定了视频如何编码成独立的包,但如何存储和传输这些包却未作规范,虽然标准中包含了一个Annex附件,里面描述了一种可能的格式Annex B,但这并不是一个必须要求的格式,为了针对不同的存储传输需求,出现了两种打包方法:一种即Annex B格式,另一种称为AVCC/HVCC格式。
Annex B格式及我们厂家的HECVC或者H264码流封装格式,其格式如下:
[StartCode][NALU Header][NALU PAYLOAD]
起始码一般为00000001或者000001开头,通过定位起始码,解码器就可以识别NALU的边界,为了防止编码数据中存在与起始码相同的数据,在构建NALU时,需要将数据中的0x000000,0x000001,0x000002,0x000003中插入防竞争字节(Emulation Prevention Bytes)0x03,使其变为:
0x000000 = 0x0000 03 00
0x000001 = 0x0000 03 01
0x000002 = 0x0000 03 02
0x000003 = 0x0000 03 03
因此,解码器在检测到0x000003时,将0x03抛弃,恢复原始数据。
AVCC格式不使用StartCode作为NALU的分界,而是在每个NALU前都加上一个指定NALU长度的大端格式表示的前缀,这个前缀可以是1、2或4个字节,所以在解析AVCC格式的时候需要将指定的前缀字节数的值保存在一个头部对象中,通常称为extradata或者sequence header,其中SPS和PPS数据也需要保存在extradata中。这里需要注意SPS和PPS都是去掉起始头的
H.264 extradata语法如下:
其中第5字节的后2位NALULengthSizeMinusOne表示的就是NALU size的字节数,NALU前缀长度减1,假设前缀长度为4,那么这个值应该为3。如果此之为3表示此码流所有nalu前需要加上四字节size,去掉起始码。
在fmp4打包H264详解文章中我们已经使用过此种封装方式来打包程avcc的box,详见此文章中的avcC box解释:moov->trak->media->minf->stbl->stsd->avc1->avcC,需要trak带有此box表示mp4封装的H264码流,此trackID的流中mdat的box中封装的是去除起00000001始码的码流,解码时需要注意这里虽然去掉了起始码,但是但防竞争字节还是有的,需要转换一下。
与H.264类似,H.265(HEVC)码流也有两种封装格式,一种是用起始码作为分界的Annex B格式,另一种则是在NALU头添加NALU长度前缀的格式称为HVCC,与AVCC类似,需要通过extradata来保存视频流的编解码参数,其格式定义如下:
表示extradata后半段是一段格式重复的数组数据,其中numOfArrays表示数组的个数,一般为0x03,表示包含VPS/SPS/PPS,
封装方式示意如下(《ISO-14496-15 AVC file format》中有详细说明):
// The CodecPrivate syntax shall follow the
// syntax of HEVCDecoderConfigurationRecord
// defined in ISO/IEC 14496-15.
//
// The number zero (0) shall be written to
// the configurationVersion variable until
// official finalization of 14496-15, 3rd ed.
//
// After its finalization, this field and the
// following CodecPrivate structure shall
// follow the definition of the
// HEVCDecoderConfigurationRecord in 14496-15.
unsigned int(8) configurationVersion;
unsigned int(2) general_profile_space;
unsigned int(1) general_tier_flag;
unsigned int(5) general_profile_idc;
unsigned int(32) general_profile_compatibility_flags;
unsigned int(48) general_constraint_indicator_flags;
unsigned int(8) general_level_idc;
bit(4) reserved = ‘1111’b;
unsigned int(12) min_spatial_segmentation_idc;
bit(6) reserved = ‘111111’b;
unsigned int(2) parallelismType;
bit(6) reserved = ‘111111’b;
unsigned int(2) chromaFormat;
bit(5) reserved = ‘11111’b;
unsigned int(3) bitDepthLumaMinus8;
bit(5) reserved = ‘11111’b;
unsigned int(3) bitDepthChromaMinus8;
bit(16) avgFrameRate;
bit(2) constantFrameRate;
bit(3) numTemporalLayers;
bit(1) temporalIdNested;
unsigned int(2) lengthSizeMinusOne;
unsigned int(8) numOfArrays;
for (j=0; j < numOfArrays; j++) {
bit(1) array_completeness;
unsigned int(1) reserved = 0;
unsigned int(6) NAL_unit_type;
unsigned int(16) numNalus;
for (i=0; i< numNalus; i++) {
unsigned int(16) nalUnitLength;
bit(8*nalUnitLength) nalUnit;
}
}
bits | 描述 | 备注 |
---|---|---|
1 | array_completeness | 默认0 |
1 | reserved | 默认0 |
6 | NAL_unit_type | 帧类型 |
16 | numNalus | 此种类型的帧个数,一般为1,如果大于1,下面进入循环 |
16 | nalUnitLength | 2字节表示附加帧的长度 |
N | NALU data | 附加帧的数据 |
一般在fmp4封装时,hvcC box的box负载采用此种方式封装,其中相关的编码参数获取是从HEVC的SPS帧中分析出来的,附加帧数据VPS/SPS/PPS。
fmp4封装H265,仅有两个box需要修改ftyp box和stsd box
ftyp box格式与H264封装一样,其中compatible brands赋值为isom、iso2、mp41,HEVC ftype示例如下:
0x00,0x00,0x00,0x1C,//box size
0x66,0x74,0x79,0x70,//ftyp的ascii
0x69, 0x73, 0x6f, 0x6d, // major_brand: isom
0x0, 0x0, 0x02, 0x0, // minor_version: 0x01
0x69, 0x73, 0x6F, 0x6D, // isom
0x69, 0x73, 0x6F, 0x32, // iso2
0x6d, 0x70, 0x34, 0x31, // mp41
经过验证,这里直接用isom也能够正常播放,所以此box可与H264保持一致。
有关H265的fmp4打包,此box需要把avc1 box替换成hvc1 box,hvc1 box的封装格式与avc1类似,只是把avcC子box替换程hvcC,其格式如下:
[4字节size][4字节type][6字节预留][2字节data_reference_index][2字节pre_defined][2字节预留][12字节pre_defined][2字节宽][2字节高][4字节horizresolution][四字节 vertresolution][4字节预留][2字节视频帧数量][Compression name长度][Compression name][Compression name预留位(32-Compression name长度-1)][2字节深度][2字节pre_defined][hvcC box][btrt box]
这里主要对与H264不同的hvcC box进行说明,其结构如下:
[4字节size][4字节type][hevc extradata]
其中hevc extradata格式见1.1.2 HVCC封装格式,其后半段附加了VPS、SPS、PPS帧数据,HVCC附加的解码信息字段可从SPS中解析得到,具体解析方式参照文章:
https://www.cnblogs.com/sddai/p/14366110.html
示例及详解如下:
00 00 00 6E 68 76 63 43 01 01 60 00 00 00 B0 00 00 00 00 00 7B F0 00 FC FD F8 F8 00 00 03 03 20 00 01 00 17 40 01 0C 01 FF FF 01 60 00 00 03 00 B0 00 00 03 00 00 03 00 7B AC 09 21 00 01 00 22 42 01 01 01 60 00 00 03 00 B0 00 00 03 00 00 03 00 7B A0 03 C0 80 10 E5 8D AE 49 32 F4 DC 04 04 04 02 22 00 01 00 07 44 01 C0 F2 F0 3C 90
以下是用mp4reader解析的结果,有关fmp4示例文件及mp4reader安装包获取,请关注微信公众号壹零仓,发送fmp4,获取: