最近再封装H264文件,本来想想用ffmpeg,可惜设备端没有足够的空间放ffmpeg的库了,无奈只好开始撸协议自己封装了~
首先至少得了解以下知识点:
一 【音视频技术】AVC H264的一些基本概念和知识点
二 【音视频技术】FLV封装格式
三 【音视频技术】AMF实用协议解析说明
好了,开撸。
FLV的封装格式就不说了,这篇博客着重说一下 H264中的NALU如何封装成 FLV中的video tag ,关于FLVheader 及FLV其他结构有不清楚的可以上网查其他资料或者看我写的这篇【音视频技术】FLV封装格式博客。
-------------------------------------------------------------------------------------------------------------
H264 的NALU 封装成FLV有三种不同的形式:
(H264 NALU 不清楚的【音视频技术】AVC H264的一些基本概念和知识点)
(1)H264 NALU type SPS +PPS;
(2)H264 NALU type SEI;
(3)H264 NALU type Slice 也就是 type值为(1-5);
--------------------------------------------------------------------------------------------------------------
(1)H264 NALU type SPS +PPS 封装成 FLV video tag:
在H264的码流中 SPS 和 PPS是成对出现的,先是SPS然后是PPS,SPS对于H264来说就是编码后的第一帧、PPS是编码后的第二帧这两针携带的数据主要是编码器的一些属性,比如宽高 profile level deblock滤波器等等。
在封装FLV中这两帧数据被合并到一个video TAG中:
FLV tag header Bytes value
1)Tag type // 0 0x09
2)Data Size // 1-3 0x00 0x00 0x24
3)TimeStamp // 4-6 0x00 0x00 0x00 (First frame)
4)TimeStampExtend // 7 0x00
5)StreamID // 8-10 0x00 0x00 0x00 (always zero)
AVC Video tag header
1)FrameType | CodecID //11 0x17
2)AVCPacketType //12 0x00
3)Composition Time //13-15 0x00 0x00 0x00
AVCDecoderConfigurationRecord
1)Configuration VerSion //16 0x01
2)AVC Profile SPS[1] //17 0x42
3)profile_compatibility SPS[2] //18 0x00
4)AVC Level SPS[3] //19 0x2A
5)lengthSizeMinusOne //20 0xFF
6)numOfSequenceParameterSets //21 0xE1
SPS
1)SPS0 Length //22-23 0x0010
2)SPS0 Data
3)SPS(n) length /btyes 如果存在多个循环存放最多31个SPS
4)SPS(n) Data
PPS
PPS count //1byte 0x01
PPS0 Length //2bytes 0x00 0x04
PPS0 Data
PPS(n) Length
PPS(n) Data
+PreviousTag Size
--------------------------------------------------------------------------------------------------------
(2)H264 NALU type Sei 封装成 FLV video tag:
SEI NALU 是没有图像数据的,它的主要作用是对图像数据或者视频流的补充,有些内容可能对解码有帮助。在封装FLV文件中含义SEI的videoTAG其中包含色SEI数据还有SEI帧后紧跟着的一个IDR数据,其编码结构如下;
FLV tag header Bytes value
1)Tag type // 0 0x09
2)Data Size // 1-3 0x00 0x00 0x24
3)TimeStamp // 4-6 0x00 0x00 0x00 (First frame)
4)TimeStampExtend // 7 0x00
5)StreamID // 8-10 0x00 0x00 0x00 (always zero)
AVC Video tag header
1)FrameType | CodecID //11 0x27
2)AVCPacketType //12 0x01
3)Composition Time //13-15 0x00 0x00 0x00
SEI
1)SEI length //16-19 0x00 0x00 0x00 0x05
2)SEI Data // 20-N 0x06 E5 01 81 80
3)IDR NALU Length //4Bytes 0x00 0x00 0x1F 0xF4
4)IDR NALU Data
+PreviousTag Size
----------------------------------------------------------------------------------------------------
(3)H264 NALU type Slice 封装成 FLV video tag:
Slice Type NALU (1-5) 就是H264 中一片一片的数据了,在FLV video tag中封装 如下:
FLV tag header Bytes value
1)Tag type // 0 0x09
2)Data Size // 1-3 0x00 0x95 0xF6
3)TimeStamp // 4-6 0x00 0x00 0x00 (First frame)
4)TimeStampExtend // 7 0x00
5)StreamID // 8-10 0x00 0x00 0x00 (always zero)
AVC Video tag header
1)FrameType | CodecID //11 0x27 or 0x17
2)AVCPacketType //12 0x01
3)Composition Time //13-15 0x00 0x00 0x00
NALU
NALU Length // 4bytes 0x00 0x00 0x95 0xED
NALU data
+PreviousTag Size
OK,上述就是H264在封装成FLV文件时的3中video tag。再说点调试时的经验吧。封装FLV我总共花了3天,第一天了解FLV协议,AMF协议,结合着flv的媒体文件来对照协议,理解各个字段的意思。大家可以使用UEdit这个工具来看二进制文件,也可以使用这个flv解析工具来直接解析flv文件 (还算挺好用的吧)。封装过程中有些大端小端的一定要注意,还有扩展时间戳位(不知道搞协议的人怎么想的搞出这个东西来)。第二天,再网上搞了一套代码,看懂后改了改 ,可以封装H264了 但是 生产出来的flv文件播放有马赛克。后来用ffmpeg封装对比前后的文件慢慢找出的端倪。错在SEI type的nalu 我处理的不对又改了改,大功告成。源代码的话我就不放了,如果按照我这个按部就班的做应该没问题的,我就是这么搞出来的。
整个工作过程这篇博客给我的帮助是最大的,内容也是最正确的,其他看了好多感觉都有写的不对的地方(感谢感谢):
打包H264码流到FLV文件