php获取视频文件属性,使用php获取flv视频文件的信息

最近要做一个判断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文件进行二进制转换后的片段。

0c8ea4d856f148af4979b26b1eab3029.png

从第一行开始看,前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

接下来的内容是关于视频编码的。也是我们需要关注的内容,因为我们需要获取的视频文件信息就在其中!!!

通过分析我们可以获取到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文件的播放尺寸了。

第一次发这样的技术文章加上时间比较紧迫,只能先简单的写这么多。有兴趣的朋友可以参考我上面给出的那个blog地址,那位老兄才是真正的牛

原文:http://hi.baidu.com/pejaq/blog/item/0d17e9503bc9e25d1138c210.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
获取ws推送的flv格式视频帧,您可以使用以下步骤: 1. 建立WebSocket连接并接收数据流。 2. 处理数据流并解析FLV视频信息。 3. 从FLV视频中提取视频帧。 下面是一些示例代码,演示如何获取FLV视频帧: ``` import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; public class FlvParser { private static final int FLV_HEADER_SIZE = 9; private static final int PREVIOUS_TAG_SIZE_FIELD_SIZE = 4; private static final int TAG_HEADER_SIZE = 11; private static final int TAG_TYPE_VIDEO = 0x09; private static final int AVC_PACKET_TYPE_SEQUENCE_HEADER = 0x00; private static final int AVC_PACKET_TYPE_NALU = 0x01; private static final int TAG_HEADER_TOTAL_SIZE = PREVIOUS_TAG_SIZE_FIELD_SIZE + TAG_HEADER_SIZE; private static final int NAL_HEADER_SIZE = 4; private static final byte[] NAL_HEADER = new byte[]{0x00, 0x00, 0x00, 0x01}; private ByteBuffer mByteBuffer = ByteBuffer.allocate(1024 * 1024); // 1MB private List<byte[]> mNaluList = new ArrayList<>(); public void parse(byte[] data, int length) { mByteBuffer.put(data, 0, length); mByteBuffer.flip(); while (mByteBuffer.remaining() > TAG_HEADER_TOTAL_SIZE) { int previousTagSize = mByteBuffer.getInt(); int tagType = mByteBuffer.get() & 0xff; int dataSize = ((mByteBuffer.get() & 0xff) << 16) | ((mByteBuffer.get() & 0xff) << 8) | (mByteBuffer.get() & 0xff); int timestamp = ((mByteBuffer.get() & 0xff) << 16) | ((mByteBuffer.get() & 0xff) << 8) | (mByteBuffer.get() & 0xff) | ((mByteBuffer.get() & 0xff) << 24); int streamId = ((mByteBuffer.get() & 0xff) << 16) | ((mByteBuffer.get() & 0xff) << 8) | (mByteBuffer.get() & 0xff); if (tagType == TAG_TYPE_VIDEO) { int frameType = (mByteBuffer.get() & 0xff) >> 4; int codecId = mByteBuffer.get() & 0x0f; if (codecId == 7) { // AVC handleAvcPacket(dataSize); } } mByteBuffer.position(mByteBuffer.position() + dataSize + PREVIOUS_TAG_SIZE_FIELD_SIZE); if (mByteBuffer.remaining() < TAG_HEADER_TOTAL_SIZE) { mByteBuffer.compact(); break; } } mByteBuffer.compact(); } private void handleAvcPacket(int dataSize) { int avcPacketType = mByteBuffer.get() & 0xff; if (avcPacketType == AVC_PACKET_TYPE_SEQUENCE_HEADER) { // TODO: parse SPS and PPS } else if (avcPacketType == AVC_PACKET_TYPE_NALU) { byte[] naluData = new byte[dataSize - 1]; mByteBuffer.get(naluData); mNaluList.add(naluData); } while (mNaluList.size() > 0) { byte[] naluData = mNaluList.get(0); int naluLength = naluData.length + NAL_HEADER_SIZE; byte[] frameData = new byte[naluLength]; System.arraycopy(NAL_HEADER, 0, frameData, 0, NAL_HEADER_SIZE); System.arraycopy(naluData, 0, frameData, NAL_HEADER_SIZE, naluData.length); // TODO: handle frameData mNaluList.remove(0); } } } ``` 在上面的示例代码中,`parse()`方法处理FLV视频流,`handleAvcPacket()`方法解析AVC数据包并提取NAL单元,`NAL_HEADER`是NAL单元的头部。 当您成功解析NAL单元后,可以将它们组合成完整的视频帧,并对其进行处理。 希望这可以帮助您获取ws推送的flv格式视频帧。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值