FLV格式详解

FLV格式概述:

FLV(Flash Video)是Adobe公司设计开发的一种流行的流媒体格式,由于其视频文件体积轻巧、封装简单等特点,使其很适合在互联网上进行应用。此外,FLV可以使用Flash Player进行播放,而Flash Player插件已经安装在全世界绝大部分浏览器上,这使得通过网页播放FLV视频十分容易。

Flv文件格式

Flv由文件头(File Header)和 文件体(File Body)组成。

Flv Body由一系列的Tag组成,每个Tag又有一个preTagSize字段,标记着前面一个Tag的大小。
在这里插入图片描述

Flv 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长度。

下图是Flv Header的内容,(UI8表示无符号8位,也就是一个字节;UB[5]表示一个字节中的5位)
在这里插入图片描述

Flv Body

Flv Body由一个一个Tag组成,每个Tag都有一个preTagSize字段,标记着前面一个Tag的大小。
在这里插入图片描述
Tag有三种类型,Audio Tag(音频Tag),Video Tag(视频Tag),script Tag(又称Metadata Tag)

每个Tag由“Tag Header”和“Tag Data”组成,对于不同类型的Tag,“Tag Header”的格式都是相同的,“Tag Body”的格式就不一样了。
在这里插入图片描述
下面这张图归纳一下上面讲的内容,看完后对flv应该有个总体的了解了。
在这里插入图片描述
一般一个flv文件由一个头部信息,一个script Tag,以及若干个video Tag和audio Tag组成。
在这里插入图片描述
下面来详细讲解每种类型的Tag Data
在这里插入图片描述

Tag Data

Flv有三种tag:“Audio Tag Data”、“Video Tag Data”、“Script Tag Data”
在这里插入图片描述

Aideo tag是由tag Header + Tag Data组成:

tag Header:
TagType: 8 (1 byte)
TagType 代表含义如下:

  • 8: audio

  • 9 : video

  • 18 : script data

DataSize: 7 (3 bytes)
tag Data大小
tag Header大小 = Previous Tag Size - DataSize
TimeStamp: 0 (3 bytes) 时间戳
TimestampExtended: 0 (1 byte) 扩展时间戳
StreamId: 0 (3 bytes) 流ID

Audio Tag Data:
在这里插入图片描述

Video tag 解析:

video tag是由tag Header + Tag Data组成:
在这里插入图片描述
tag Header:

TagType: 9 (1 byte)
TagType 代表含义如下:

  • 8: audio
  • 9 : video
  • 18 : script data

DataSize: 50 (3 bytes)

  • tag Data大小

  • tag Header大小 = Previous Tag Size - DataSize

TimeStamp: 0 (3 bytes) 时间戳
TimestampExtended: 0 (1 byte) 扩展时间戳
StreamId: 0 (3 bytes) 流ID

Video Tag Data
在这里插入图片描述

scripts tag 解析:

该类型Tag又通常被称为MetadataTag,会放一些关于FLV视频和音频的元数据信息如:duration、width、height等。通常该类型Tag会跟在FileHeader后面作为第一个Tag出现,而且只有一个。
在这里插入图片描述
tag Header:

TagType: 18 (1 byte)
TagType 代表含义如下:

  • 8: audio

  • 9 : video

  • 18 : script data

DataSize: 293 (3 bytes)

  • tag Data大小

  • tag Header大小 = Previous Tag Size - DataSize

TimeStamp: 0 (3 bytes) 时间戳
TimestampExtended: 0 (1 byte) 扩展时间戳
StreamId: 0 (3 bytes) 流ID

tag Data:

AMF包:第一个字节表示AMF包的类型
在这里插入图片描述
第一个AMF包:
第一个字节一般为0x02,表示字符串,第2-3个字节表示字符串的长度,一般为0x000A,后面跟的就是字符串,一般为"onMetaData"。

第二AMF包:
第一个字节为0x08,表示数组,第2-5个字节表示数组元素个数,后面跟着就是数组的元素,格式为:元素名长度(UI16) + 元素名(UI8[n]) + 元素的值(double),最后以“009”结尾。
在这里插入图片描述

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 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
发出的红包

打赏作者

狗蛋儿l

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值