欢迎关注公众号:冒泡的肥皂
1.flv简介
FLV 是FLASH VIDEO的简称。 FLV是一种文件封装格式,它可以封装H264和AAC,其他常见的文件封装格式还有MP4、TS、MKV等等。不同的文件封装格式可以相互转换,只要把一种文件封装格式拆包,解出“裸”的视频流和音频流,再按另一种文件封装格式打包,就可以完成转换,不需要重新编码,因此速度非常快。
2.flv文件格式
2.1头文件
FLV头文件:(9字节)
1-3: 前3个字节是文件格式标识(FLV 0x46 0x4C 0x56).
4-4: 第4个字节是版本(0x01)
5-5: 第5个字节
has_video = (b & 0x01)==1 视频
has_audio = (b & 0x04)==4 音频
0x05既有视频也有音频
6-9: 第6-9的四个字节长度.其数据为 00000009 .
整个文件头的长度,一般是9(3+1+1+4)
2.2 tag格式
除了9 字节的公共文件头外,body 部分就是一个个 tag 组成的。每一个 tag 都有 15 字节的 tag 头。字段说明如下:
script格式
PreviousTagSize,是 4 字节长度,表面之前的 Tag 的长度,包含了 tag 头和 tag 数据。第一个 tag ,此值是 0。
TagType,是 1 字节长度。音频:8, 视频:9,scriptTag = 0x12
DataSize , 是 3 字节长。flv tag 的数据长度,其实如图里 audio tag 头及其数据长度。
Timestamp,是 3 字节长。时间戳,貌似 flv 播放需要。
TimestampExtended, 是对 Timestamp 长度的扩展,当时间长度 3 字节不能表示的时候,启用扩展字段。
StreamID ,3 字节长,都填 0
头文件和tag脚本写入
private byte[] encodeFlvHeaderAndMetadata() {
ByteBuf encodeMetaData = encodeMetaData();
ByteBuf buf = Unpooled.buffer();
RtmpMediaMessage msg = content.get(0);
int timestamp = msg.getTimestamp() & 0xffffff;
int timestampExtended = ((msg.getTimestamp() & 0xff000000) >> 24);
flvHeader = new byte[] { 0x46, 0x4C, 0x56, 0x01, 0x05, 00, 00, 00, 0x09 };
buf.writeBytes(flvHeader);
buf.writeInt(0); // previousTagSize0
int readableBytes = encodeMetaData.readableBytes();
buf.writeByte(0x12); // script
buf.writeMedium(readableBytes);
// make the first script tag timestamp same as the keyframe
buf.writeMedium(timestamp);
buf.writeByte(timestampExtended);
buf.writeMedium(0);// streamid
buf.writeBytes(encodeMetaData);
buf.writeInt(readableBytes + 11);
byte[] result = new byte[buf.readableBytes()];
buf.readBytes(result);
return result;
}
tag写入
private byte[] encodeMediaAsFlvTagAndPrevTagSize(RtmpMediaMessage msg) {
int tagType = msg.getMsgType();
byte[] data = msg.raw();
int dataSize = data.length;
int timestamp = msg.getTimestamp() & 0xffffff;
int timestampExtended = ((msg.getTimestamp() & 0xff000000) >> 24);
ByteBuf buffer = Unpooled.buffer();
buffer.writeByte(tagType);//类型
buffer.writeMedium(dataSize);//长度
buffer.writeMedium(timestamp);//时间戳
buffer.writeByte(timestampExtended);// timestampExtended
buffer.writeMedium(0);// streamid
buffer.writeBytes(data);
buffer.writeInt(data.length + 11); // 长度
byte[] r = new byte[buffer.readableBytes()];
buffer.readBytes(r);
return r;
}