一、flv 格式
本文转自:http://blog.csdn.net/yeyumin89/article/details/7932368 对其文章的格式稍做调整,并修改了部分 type error.
flv 文件的格式其实网上资料还是不少,但是怎么封装成 flv 却不多。看了不少资料,找到了一个觉得还比较靠谱的:
其实 flv 还是挺简单的一个视频格式,下面就来先谈一谈 FLV 的格式吧。
FLV 是一个二进制文件,简单来说,其是由一个文件头(FLV header)和很多 tag 组成(FLV body)。tag 又可以分成三类: audio, video, script,分别代表音频流,视频流,脚本流,而每个 tag 又由 tag header 和 tag data 组成。
文件头由 9 bytes 组成
前3个 bytes 是文件类型,总是“FLV”,也就是(0x46 0x4C 0x56)。第4 btye 是版本号,目前一般是 0x01。第5 byte 是流的信息,倒数第一 bit 是1表示有视频(0x01),倒数第三 bit 是1表示有音频(0x4),有视频又有音频就是 0x01 | 0x04(0x05),其他都应该是 0。最后 4 bytes 表示 FLV 头的长度,3+1+1+4 = 9。
FLV header 后面就是 FLV body,FLV body 由若干个 tag 组成。每一个 tag 第一部分是 tag header,tag header 长度为 11 bytes,但是每个 tag header 前面有 4 bytes 记录着上一个 tag 的长度,此待会儿再说。tag header 的第1个 byte 为记录着 tag 的类型,音频(0x8),视频(0x9),脚本(0x12);第2到4 bytes 是数据区的长度,也就是 tag data 的长度;再后面3个 bytes 是时间戳,单位是毫秒,类型为0x12则时间戳为0,时间戳控制着文件播放的速度,可以根据音视频的帧率类设置;时间戳后面一个 byte 是扩展时间戳,时间戳不够长的时候用;最后3 bytes 是 streamID,但是总为0,再后面就是数据区了(tag data),也即是h264的裸流,tag header 长度为1+3+3+1+3=11。
0x12 前面的 00 00 00 00 就是刚刚说的记录着上一个 tag 的长度的4 bytes,这里因为前面没有tag,所以为0。
tag data 如果是音频数据,第一个 byte 记录 audio 信息:
前 4 bits 表示音频格式(全部格式请看官方文档):
·0 -- 未压缩
·1 -- ADPCM
·2 -- MP3
·4 -- Nellymoser 16-kHz mono
·5 -- Nellymoser 8-kHz mono
·10 -- AAC
下面两个 bits 表示 samplerate:
·0 -- 5.5KHz
·1 -- 11kHz
·2 -- 22kHz
·3 -- 44kHz
下面1 bit 表示采样长度:
·0 -- snd8Bit
·1 -- snd16Bit
下面1 bit 表示类型:
·0 -- sndMomo
·1 -- sndStereo
之后是数据。
如果是视频数据,第一个 byte 记录 video 信息:
前4 bits 表示类型:
·1-- keyframe
·2 -- inner frame
·3 -- disposable inner frame (h.263 only)
·4 -- generated keyframe
后4 bits 表示解码器 ID:
·2 -- seronson h.263
·3 -- screen video
·4 -- On2 VP6
·5 -- On2 VP6 with alpha channel
·6 -- Screen video version 2
·7 -- AVC (h.264)
之后是数据。
如果是 AAC 和 AVC 的音视频,则在放入数据前有一个音频和视频的配置信息需要写入前两个 tag,等会再说。之前说每个 tag 前面会有一个记录上个 tag 长度的4个bytes(previous tag size),整个的 flv 文件其实是:FLV header + previous tag size0 + tag1 + previous tag size1 + tag2 + previous tag size2 + ... +tagN + previous tag sizeN。第一个 previous tag size 因为前面没有 tag,所以为0,其他的总是记录着前面一个 tag 长度(tag data size + tag header size)。
如果 tag data 是脚本数据,Script Tag Data,该类型 Tag 又通常被称为Metadata(元数据) Tag,会放一些关于 FLV 视频和音频的参数信息,如duration、width、height等。通常该类型 Tag 会跟在 File Header 后面作为第一个 Tag 出现,而且只有一个。一般来说,该 Tag Data 结构包含两个 AMF 包。AMF(Action Message Format)是 Adobe 设计的一种通用数据封装格式,在Adobe 的很多产品中应用,简单来说,AMF 将不同类型的数据用统一的格式来描述。第一个 AMF 包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与 Adobe 的一些 API 调用有,在此不细述。第二个 AMF 包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。具体说明如下,大家可以参照图片上的数据进行理解。
第一个 AMF 包:
第1个字节表示 AMF 包类型,一般总是0x02,表示字符串,其他值表示意义请查阅文档。
第2-3个字节为 UI16 类型值,表示字符串的长度,一般总是 0x000A(“onMetaData”长度)。
后面字节为字符串数据,一般总为“onMetaData”。
第二个AMF包:
第1个字节表示 AMF 包类型,一般总是 0x08,表示数组。
第2-5个字节为 UI32 类型值,表示数组元素的个数。
后面即为各数组元素的封装,数组元素为元素名称和值组成的对。表示方法如下:
第1-2个字节表示元素名称的长度,假设为L。
后面跟着为长度为L的字符串。
第L+3个字节表示元素值的类型。
后面跟着为对应值,占用字节数取决于值的类型。
到此flv格式的解析就差不多了,如有写错的地方请指出。
附上一个网友写的flv的查看工具:
二、开始动手
前面写了 flv 文件的解析,有 h264 裸流的话就开始封装吧。网上大多数都是用ffmeg 库来做这个工作的,哎,学习资料少学不会,还是自己动手吧。
#define NALU_TYPE_EOSEQ 10 #define NALU_TYPE_EOSTREAM 11
#define NALU_TYPE_FILL 12
这个例子是对应我第一个截图来的,一般 h264 数据最开始的两个 NALU 就是 SPS 和 PPS,但是我现在还没有明白为什么我的那个 h264 裸流在开始的时候会有两个 SPS、PPS,而且之后数据还会不时的出现,但是我没有管这个,依然只各弄了一个进去,其他的忽略掉了,反正多余的我都忽略了,也没发现有什么错。反正首先把音视频的配置信息封进 metadata 之后的 tag,然后就可以封数据了。再说下元数据,flv header 之后就是它了,再之后就是音视频配置信息,再后面就是音视频数据,元数据前一章说了是 AMF 格式的,按格式封就行了,测试其实没有元数据视频也可以正常播放,等会再简单说下 AMF吧。
现在开始封装 h264 数据吧,前一章提到了 flv 关于 AVC 的格式,除开元数据,其他数据是:一个 byte 的 video 信息 + 一个 byte 的 AVCPacket type + 3 个 bytes 的无用数据(composition time,当 AVC 时无用,全是 0)+ 4 个bytes 的 NALU 单元长度 + N 个bytes 的 NALU 数据,所以包头数据长度信息是刚才提到的信息的总和长度。要强调下,当音视频配置信息 tag 的时候,是没有 4 个 bytes 的 NALU 单元长度的。
17 -- 高4 bits:1,keyframe。 低4 bits:7,代表 AVC。 后面一个 byte 0x00,AVCPacket type,代表 AVC sequence header。后 3 个 bytes 无意义,之后就是 decoder configuration record 的内容了。 图中绿色后面 00 00 00 28 就是前面 tag 的总长度。
- tag1 是 metadata,记录视频的一些信息;
- tag2 是视频配置信息(AVC decoder configuration record),
- tag3 是音频配置信息(如果没有音频则去掉此项),
- tag4以及之后的tag就是音视频数据了。
封包的时候要特别注意一下包头里面的时间戳,因为这个控制着播放的速度,如果不填,全是 0 的话,播放会相当快,一般按视频帧率来设置。我这个 h264 流是 8 帧的,所以我每个 tag 的时间间隔是 125ms 左右。