最近要做一个判断flv文件信息的程序,使用php对flv文件进行解析判断,百度了半天也没有对应的信息,后来又去csdn发帖子,得到的答复是目前还没有直接可以对flv文件进行处理的方法,于是决定放弃这个功能。不过后来终于让我在google上搜出一个牛人的blog,这哥们对flv的格式相当有研究。于是盯着看了好久,终于让我找到了一些的思路。尽管这个功能已经不做了,但是把思路写下来,总还是有用处的。
不过我是第一次搞关于flv视频相关的东西,因此如果有说的不对的地方,希望有看到的同人不要骂我。年轻人嘛,总要有犯错误的机会。我犯了再改,改了再犯…………千锤百炼嘛。
废话少说,对于flv文件,相信许多前辈已经研究了很多了。flv文件除了头只外,是由连续的tag组成的。每一个tag代表一个视频祯或一个音频祯或metadata,这些都不细说了。既然是要获取视频的尺寸,那么我们对视频进行下研究就ok了。
首先第一个问题是如何定位一个视频tag,我们假定各个祯的尺寸都是一样的,那么只要找到第一个tag就ok了。
flv tags有下面的格式:
tag类型 1个字节:
8 音频
9 视频
18(0x12) 脚本数据
其它 保留
先粘一个图,这个图是对一个flv文件进行二进制转换后的片段。
从第一行开始看,前12个字节是flv文件的头,具体的东西有人讲过我就不细说了。可以参考http://www.roading.net/blog/article.asp?id=104这个blog就可以了。
文件头之后,是以12开头的一段,这一段就是一个初始tag了。这个tag主要包含了一些基本的信息具体也可以参考上面的blog。我们要关心的是我选定的那部分。这部分就是一个视频的tag。视频的tag是以09开头的,且09前面的三个字节表示了前一个祯的大小。那么我们看一下09前的三个字节是000101,也就是257个字节。数一下就知道从第一行12开始到这三个字节之前,恰好是257个字节,因此可以断定000101之后就是一个视频tag了。
一个视频tag包含的信息如下:
//—————————————————————————
tag类型 0x09
tag数据大小 3个字节的视频数据大小
tag时间戳 3个字节tag数据应用的时间(毫秒)
tag时间戳扩展 1个字节的时间戳扩展,让时间戳变成4字节,本字节作为时间戳的高位.
streamID 3个字节的类id,总是0
视频tags的数据
//———————————————————————————————————–
视频tags的数据:
视频tags数据和swf文件格式中的VideoFrame是相似的.他们的数据是一样的
视频格式的数据的组成如下:
帧类型 4bit
1: 关键帧keyframe(视频中的关键帧,数据存储的是整个画面完整的数据,可以提取它来生成图片)
2: 中间帧inter frame(关键帧之间的状态,不完整的画面数据,需要依靠前面帧的数据生成)
3: 可任意使用的中间帧disposable inter frame(H.263 only)
视频编码id 4bit
2: Sorenson H.263(mencoder转换所使用的视频编码)
3: Screen video
4: On2 VP6
5: On2 VP6 with alpha channel
6: Screen video version 2
//—————
视频数据
If CodecID = 2
H263VIDEOPACKET
If CodecID = 3
SCREENVIDEOPACKET
If CodecID = 4
VP6FLVVIDEOPACKET
If CodecID = 5
VP6FLVALPHAVIDEOPAC
KET
If CodecID = 6
SCREENV2VIDEOPACKET
tag类型 0x09
tag数据大小 3个字节的视频数据大小
tag时间戳 3个字节tag数据应用的时间(毫秒)
tag时间戳扩展 1个字节的时间戳扩展,让时间戳变成4字节,本字节作为时间戳的高位.
streamID 3个字节的类id,总是0
视频tags的数据
//———————————————————————————————————–
视频tags的数据:
视频tags数据和swf文件格式中的VideoFrame是相似的.他们的数据是一样的
视频格式的数据的组成如下:
帧类型 4bit
1: 关键帧keyframe(视频中的关键帧,数据存储的是整个画面完整的数据,可以提取它来生成图片)
2: 中间帧inter frame(关键帧之间的状态,不完整的画面数据,需要依靠前面帧的数据生成)
3: 可任意使用的中间帧disposable inter frame(H.263 only)
视频编码id 4bit
2: Sorenson H.263(mencoder转换所使用的视频编码)
3: Screen video
4: On2 VP6
5: On2 VP6 with alpha channel
6: Screen video version 2
//—————
视频数据
If CodecID = 2
H263VIDEOPACKET
If CodecID = 3
SCREENVIDEOPACKET
If CodecID = 4
VP6FLVVIDEOPACKET
If CodecID = 5
VP6FLVALPHAVIDEOPAC
KET
If CodecID = 6
SCREENV2VIDEOPACKET
接下来的内容是关于视频编码的。也是我们需要关注的内容,因为我们需要获取的视频文件信息就在其中!!!
通过分析我们可以获取到CodecID为2,也就是说使用的是H263VIDEOPACKET的数据结构下面讲一下
H263VIDEOPACKET数据结构(其中UB代表usebit):
PictureStartCode UB[17] 和H.263 5.1.1相似
0000 0000 0000 0000 1
Version UB[5] 视频格式版本
Flash Player 6 supports 0 and 1
TemporalReference UB[8] 察看 H.263 5.1.2
PictureSize UB[3] 图像尺寸:
000: custom, 1 byte
001: custom, 2 bytes
010: CIF (352×288)
011: QCIF (176×144)
100: SQCIF (128×96)
101: 320×240
110: 160×120
111: 保留
CustomWidth If PictureSize = 000 UB[8]
If PictureSize = 001 UB[16]
否则不存在
注意:UB[16]不一样UI16,这里不是字节交换的
单位是像素
CustomHeight If PictureSize = 000 UB[8]
If PictureSize = 001 UB[16]
否则不存在
注意:UB[16]不一样UI16,这里不是字节交换的
单位是像素
如果你仔细观察,就会发现,我选中的那段数据,恰好是与这个视频tag完全对应上的。因此通过php使用一定的位运算,就可以获取到flv文件的播放尺寸了。
PictureStartCode UB[17] 和H.263 5.1.1相似
0000 0000 0000 0000 1
Version UB[5] 视频格式版本
Flash Player 6 supports 0 and 1
TemporalReference UB[8] 察看 H.263 5.1.2
PictureSize UB[3] 图像尺寸:
000: custom, 1 byte
001: custom, 2 bytes
010: CIF (352×288)
011: QCIF (176×144)
100: SQCIF (128×96)
101: 320×240
110: 160×120
111: 保留
CustomWidth If PictureSize = 000 UB[8]
If PictureSize = 001 UB[16]
否则不存在
注意:UB[16]不一样UI16,这里不是字节交换的
单位是像素
CustomHeight If PictureSize = 000 UB[8]
If PictureSize = 001 UB[16]
否则不存在
注意:UB[16]不一样UI16,这里不是字节交换的
单位是像素
如果你仔细观察,就会发现,我选中的那段数据,恰好是与这个视频tag完全对应上的。因此通过php使用一定的位运算,就可以获取到flv文件的播放尺寸了。
第一次发这样的技术文章加上时间比较紧迫,只能先简单的写这么多。有兴趣的朋友可以参考我上面给出的那个blog地址,那位老兄才是真正的牛
原文:http://hi.baidu.com/pejaq/blog/item/0d17e9503bc9e25d1138c210.html