flv格式详解+实例剖析
简介
FLV(Flash Video)是现在非常流行的流媒体格式,由于其视频文件体积轻巧、封装播放简单等特点,使其很适合在网络上进行应用,目前主流的视频网站无一例外地使用了FLV格式。另外由于当前浏览器与Flash Player紧密的结合,使得网页播放FLV视频轻而易举,也是FLV流行的原因之一。
FLV是流媒体封装格式,我们可以将其数据看为二进制字节流。总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag及Tag Size对组成。
FLV格式解析
先来一张图,这是《东风破》——周杰伦(下载)的一个MV视频。我使用的是Binary Viewer的二进制查看工具。
header
头部分由一下几部分组成
Signature(3 Byte)+Version(1 Byte)+Flags(1 Bypte)+DataOffset(4 Byte)
- signature 占3个字节
固定FLV三个字符作为标示。一般发现前三个字符为FLV时就认为他是flv文件。 - Version 占1个字节
标示FLV的版本号。这里我们看到是1 - Flags 占1个字节
内容标示。第0位和第2位,分别表示 video 与 audio 存在的情况.(1表示存在,0表示不存在)。截图看到是0x05
,也就是00000101
,代表既有视频,也有音频。 - DataOffset 4个字节
表示FLV的header长度。这里可以看到固定是9
body
FLV的body部分是由一系列的back-pointers + tag构成
- back-pointers 固定4个字节,表示前一个tag的size。
- tag 分三种类型,video、audio、scripts。
tag组成
tag type
+tag data size
+Timestamp
+TimestampExtended
+stream id
+ tag data
- type 1个字节。8为Audio,9为Video,18为scripts
- tag data size 3个字节。表示tag data的长度。从streamd id 后算起。
- Timestreamp 3个字节。时间戳
- TimestampExtended 1个字节。时间戳扩展字段
- stream id 3个字节。总是0
- tag data 数据部分
我们根据实例来分析:
看到第一个TAG
type=0x12
=18。这里应该是一个scripts。
size=0x000125
=293。长度为293。
timestreamp=0x000000
。这里是scripts,所以为0
TimestampExtended =0x00
。
stream id =0x000000
我们看一下TAG的data部分:
tag的划分
图中红色部分是我标出的两个back-pointers,都是4个字节。而中间就是第一个TAG。那是怎么计算的呢?我们就以这个做个示例。
- 首先第一个back-pointers是
0x00000000
,那是因为后面是第一个TAG。所以他为0。 - 然后根据我们我们前面格式获取到size是
0x000125
。也就是说从stream id后面再加上293个字节就到了第一个TAG的末尾,我们数一下一下。stream id以前总共有24个字节。那么到第一个TAG结束,总共有293+24=137=0x13D
。 - 接下来我们找到
0x13D
的地址,从工具上很容易找到,正好就是红色下划线的前面。红色部分是0x00000130
=304,这代表的是上一个TAG的大小。 - 最后我们计算一下,上一个TAG数据部分是293个字节,前面type、stream id等字段占了11个字节。正好是匹配的。
上面我们已经知道了怎么取划分每个TAG。接下来我们就看TAG的具体内容
tag的内容
前面已经提到tag分3种。我们一个个看
script
脚本Tag一般只有一个,是flv的第一个Tag,用于存放flv的信息,比如duration、audiodatarate、creator、width等。
首先介绍下脚本的数据类型。所有数据都是以数据类型+(数据长度)+数据的格式出现的,数据类型占1byte,数据长度看数据类型是否存在,后面才是数据。
一般来说,该Tag Data结构包含两个AMF包。AMF(Action Message Format)是Adobe设计的一种通用数据封装格式,在Adobe的很多产品中应用,简单来说,AMF将不同类型的数据用统一的格式来描述。第一个AMF包封装字符串类型数据,用来装入一个“onMetaData”标志,这个标志与Adobe的一些API调用有,在此不细述。第二个AMF包封装一个数组类型,这个数组中包含了音视频信息项的名称和值。具体说明如下,大家可以参照图片上的数据进行理解。
值 | 类型 | 说明 |
---|---|---|
0 | Number type | 8 Bypte Double |
1 | Boolean type | 1 Bypte bool |
2 | String type | 后面2个字节为长度 |
3 | Object type | |
4 | MovieClip type | |
5 | Null type | |
6 | Undefined type | |
7 | Reference type | |
8 | ECMA array type | 数组,类似Map |
10 | Strict array type | |
11 | Date type | |
12 | Long string type | 后面4个字节为长度 |
上图为第一个AMF包
- type=
0x02
对应String - size=
0A
=10 value=onMetaData 正好是10个字节。
5.png上图为第二个AMF
- type=
0x08
对应ECMA array type。
表示数组,类似Map。后面4个字节为数组的个数。然后是键值对,第一个为键,2个字节为长度。后面跟具体的内容。接着3个字节表示值的类型,然后根据类型判断长度。
上图我们可以判断,总共有13个键值对。
第一个长度为8个字节是duration。值类型是0x004073
,第一个字节是00,所以是double,8个字节。
第二个长度5个字节是width。值也是double类型,8个字节。
依次解析下去...
到处,我们已经知道了如何解析FLV中Tag为script的数据。
video
type=0x09
=9。这里应该是一个video。
size=0x000030
=48。长度为48。
timestreamp=0x000000
。
TimestampExtended =0x00
。
stream id =0x000000
我们看到数据部分:
视频信息+数据
视频信息,1个字节。
前4位为帧类型Frame Type
值 | 类型 |
---|---|
1 | keyframe (for AVC, a seekable frame) 关键帧 |
2 | inter frame (for AVC, a non-seekable frame) |
3 | disposable inter frame (H.263 only) |
4 | generated keyframe (reserved for server use only) |
5 | video info/command frame |
后4位为编码ID (CodecID)
值 | 类型 |
---|---|
1 | JPEG (currently unused) |
2 | Sorenson H.263 |
3 | Screen video |
4 | On2 VP6 |
5 | On2 VP6 with alpha channel |
6 | Screen video version 2 |
7 | AVC |
特殊情况
视频的格式(CodecID)是AVC(H.264)的话,VideoTagHeader会多出4个字节的信息,AVCPacketType 和CompositionTime。
- AVCPacketType 占1个字节
值 | 类型 |
---|---|
0 | AVCDecoderConfigurationRecord(AVC sequence header) |
1 | AVC NALU |
2 | AVC end of sequence (lower level NALU sequence ender is not required or supported) |
AVCDecoderConfigurationRecord.包含着是H.264解码相关比较重要的sps和pps信息,再给AVC解码器送数据流之前一定要把sps和pps信息送出,否则的话解码器不能正常解码。而且在解码器stop之后再次start之前,如seek、快进快退状态切换等,都需要重新送一遍sps和pps的信息.AVCDecoderConfigurationRecord在FLV文件中一般情况也是出现1次,也就是第一个video tag.
- CompositionTime 占3个字节
条件 | 值 |
---|---|
AVCPacketType ==1 | Composition time offset |
AVCPacketType !=1 | 0 |
我们看第一个video tag,也就是前面那张图。我们看到AVCPacketType =0。而后面三个字节也是0。说明这个tag记录的是AVCDecoderConfigurationRecord。包含sps和pps数据。
再看到第二个video tag
我们看到 AVCPacketType =1,而后面三个字节为000043
。这是一个视频帧数据。
解析到的数据完全符合上面的理论。
sps pps
前面我们提到第一个video 一般存放的是sps和pps。这里我们具体解析下sps和pps内容。先看下存储的格式(图6):
0x01
+sps[1]
+sps[2]
+sps[3]
+0xFF
+0xE1
+sps size
+sps
+01
+pps size
+pps
我们看到图7 。
sps[1]=0x64
sps[2]=00
sps[3]=0D
sps size=0x001B
=27
跳过27个字节后,是0x01
pps size=0x0005
=118
跳过5个字节,就到了back-pointers。
视频帧数据
解析出sps和pps tag后,后面的video tag就是真正的视频数据内容了
这是第二个video tag其实和图8一样,只是我圈出来关键信息。先看下格式
frametype=0x17
=00010111
AVCPacketType =1
Composition Time=0x000043
后面就是NALU DATA
Audio
与视频格式类似
前4位为音频格式
值 | 类型 |
---|---|
0 | Linear PCM, platform endian |
1 | ADPCM |
2 | MP3 |
3 | Linear PCM, little endian |
4 | Nellymoser 16-kHz mono |
5 | Nellymoser 8-kHz mono |
6 | Nellymoser |
7 | G.711 A-law logarithmic PCM |
8 | G.711 mu-law logarithmic PCM |
9 | reserved |
10 | AAC |
11 | Speex |
14 | MP3 8-Khz |
15 | Device-specific sound |
接着2位为采样率
值 | 类型 |
---|---|
0 | 5.5-kHz |
1 | 11-kHz |
2 | 22-kHz |
3 | 44-kHz |
对于AAC总是3
接着1位为采样的长度
值 | 类型 |
---|---|
0 | snd8Bit |
1 | snd16Bit |
压缩过的音频都是16bit
接着1位为音频类型
值 | 类型 |
---|---|
0 | sndMono |
1 | sndStereo |
对于AAC总是1
我们看到第三个TAG
这个留给大家自己来解析吧。
from:https://www.jianshu.com/p/7ffaec7b3be6
flv格式详解+实例剖析的更多相关文章
- 通过RTMP play分析FLV格式详解
最近做了一个rtmp中转服务程序,通过实践,熟悉rtmp play和push中各类格式,这里总结一下. 程序github地址: https://github.com/runner365/rtmp_re ...
- FLV格式详解
Overview Flash Video(简称FLV),是一种流行的网络格式.目前国内外大部分视频分享网站都是采用的这种格式. File Structure 从整个文件上开看,FLV是由The FLV ...
- FLV视频封装格式详解
FLV视频封装格式详解 分类: FFMpeg编解码 2012-04-04 21:13 1378人阅读 评论(2) 收藏 举报 flvheaderaudiovideocodecfile 目录(?)[-] ...
- [转帖]ECC公钥格式详解
ECC公钥格式详解 https://www.cnblogs.com/xinzhao/p/8963724.html 本文首先介绍公钥格式相关的若干概念/技术,随后以示例的方式剖析DER格式的ECC公钥, ...
- php 序列化(serialize)格式详解
1.前言 PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对序列 ...
- Java字节码(.class文件)格式详解(一)
原文链接:http://www.blogjava.net/DLevin/archive/2011/09/05/358033.html 小介:去年在读<深入解析JVM>的时候写的,记得当时还 ...
- 常用经典SQL语句大全完整版--详解+实例 (存)
常用经典SQL语句大全完整版--详解+实例 转 傻豆儿的博客 http://blog.sina.com.cn/shadou2012 http://blog.sina.com.cn/s/blog_84 ...
- BMP格式详解
BMP格式详解 BMP文件格式详解(BMP file format) BMP文件格式,又称为Bitmap(位图)或是DIB(Device-Independent Device,设备无关位图),是Win ...
- C# XML序列化与反序列化与XML格式详解
1.https://www.cnblogs.com/sandyliu1999/p/4844664.html XML是有层次结构的,序列化实际就是内存化,用连续的结构化的内存来存储表示一个对象,那么这两 ...
随机推荐
- hdu 3032 Nim or not Nim? sg函数 难度:0
Nim or not Nim? Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- Win10 怎么给php文件设置默认打开应用
一,首先以管理员身份打开命令提示符 二,assoc .php=phpfile 创建一个文件关联 三,ftype phpfile="E:\Program Files\Sublime Text ...
- 平衡二叉树(AVL)的实现,附可运行C语言代码
最近几月一直在自学C语言和数据结构,先是写了排序二叉树,觉得平衡二叉树作为一个经典数据结构,有必要实现一下. 网上看了些资料,在AVL和红黑树之间考虑,最后个人还是倾向于AVL. 不同于标准AVL的是 ...
- 第8课:异常处理、面向对象编程、发送邮件、url编码
1. 异常处理 import traceback import pymysql import requests def calc(a, b): res = a / b return res def m ...
- eclipsec常用快捷键
Eclipse常用快捷键 1几个最重要的快捷键 代码助手:Ctrl+Space(简体中文操作系统是Alt+/)快速修正:Ctrl+1单词补全:Alt+/打开外部Java文档:Shift+F2 显示搜索 ...
- 在头文件中声明class 类 与 include类所在的头文件区别---理解
在头文件中声明class 类 与 include类所在的头文件的理解: 在头文件中,声明类 它告诉编译器:存在这样的类.而实际的类则可以位于同一个编译单元中,也可以放在其他编译单元中.没有这个类原型, ...
- postgresql与Oracle:空字符串与null
空字符串:两个单引号,中间无空格等任何内容 在postgresql中,空字符串与null是不同的:而oracle中,空字符串与null等同.测试如下: postgresql中: postgres=# ...
- HDU 2268
http://acm.hdu.edu.cn/showproblem.php?pid=2268 小学四年级应用题,让我找回了儿时的快乐... #include <iostream> #inc ...
- 基本SQL命令
1.SQL命令的使用规则 1.每条命令必须以 ; 结尾 2.SQL命令不区分字母大小写 3.使用 \c 来终止当前命令的执行 2.库的管理 1.库的基本操作 1.查看已有库 show database ...
- Jsp邮件找回密码全攻略
[来源网络 http://www.2cto.com/kf/201502/376374.html] 一般大型网站我们登录的时候,密码忘了都有个功能可以找回密码. 细数下大致的方法: 1.直接把密码发送 ...