FLV.js系列之三:FLV格式分析
承接最后两篇文章
flv.js源代码知识点(一)
flv.js源代码的知识点(中)
这是最后一篇文章。FLV.js中的音视频分隔符是FLVDemuxer。在理解这里的代码之前,首先要理解flv文件的数据格式,以及如何读取JS中指定的二进制数据。
1 FLV文件格式
FLV是Flash Video的缩写,是Adobe推出的一种流媒体文件格式。我们下面的数据操作是基于FLV标准文件。整体结构如下图所示,由FLVHeader和FLVBody组成。
1.1首字母
FLVHeader是固定的9个字节,其定义如下:
为了解释上图,Type列定义了这个字段的长度,UI8代表8位无符号整数,一个字节。UI32代表32位无符号整数,四个字节。UB[5]表示一个字节的5位,UB[1]表示一个字节的1位。
第一个字节固定是 0x46 表示 F第二个字节固定是 0x4c 表示 L第三个字节固定是 0x56 表示 V第四个字节 指定FLV格式版本第五个字节中 TypeFlagsAudio 表示是否有音频,TypeFlagsVideo 表示是否有视频最后四个字节表示 FLVHeader的长度 固定是数字 9
1.2 FLVBody和标签
FLVBody由多个previous tag size和tag组成,其中Previous TagSize占4个字节,第一个Previous TagSize的值为0。接下来我们来看一下Tag的结构,Tag由Tag头和Tag数据组成,其定义如下:
可以看到标签头的长度是11个字节。
C++音视频开发学习地址:[免费]FFMPEG/WebRTC/RTMP/NDK/Android音视频流媒体高级开发-学习视频教程-腾讯课堂
C++音视频开发学习资料:点击接收→音视频开发(资料和文档+视频教程+面试问题)(FFMPEG+WebRTC+RTMP+RTSP+HLS+RTP)。
2 二进制数据读取API
我们需要按照上面的FLV格式解析ArrayBuffer类型的数据,需要借助DateView视图类读写二进制数据。让我们看看我们将遇到的API。
2.1建造商
来自MDN:
新数据视图(缓冲区[,字节偏移量[,字节长度]]).参数描述:buffer现有对象ArrayBuffer或SharedArrayBuffer作为存储支持新的Datiew对象。ByteOffset到上述缓冲区中第一个字节的可选偏移量(以字节为单位),供新视图引用。如果没有指定,缓冲区视图从第一个字节开始。ByteLength可选字节数组中的元素个数。如果没有指定,视图的长度将匹配缓冲区的长度。
演示:
//创建一个大小为in bytes const buffer = new array buffer(16)的array buffer;//创建一对视图const view 1 = new Datiew(buffer);const view2 = new Datiew(buffer,12,4);//从第12字节开始,为后4个字节view1.setInt8(12,42);//将42放入slot 12 console . log(view 2 . getint 8(0));//expectedout: 422.2用于获取数据的API
Datiew.getUint8(byteOffset)参数byteOffset,从视图开始读取数据的偏移量(以字节为单位)。返回值,一个无符号8位整数。数据视图。getuint32 (byteOffset [,little endian])参数byteOffset,从视图开始读取数据的偏移量(以字节为单位)。LittleEndian,可选地指示32位int是以小字节顺序还是大字节顺序格式存储。默认值为false。返回值,一个无符号的32位整数。这里只使用了两个API。当然,Dateview还有一个API,用于设置和读取有符号或无符号的8位/16位/32位。
2.3端字节顺序
内存中的每个字节是一个单元,对应一个内存地址。八位最多能代表0-255。如果你想表示数字258,你需要两个字节。字节顺序的作用是指定这两个字节哪个代表高位,哪个代表低位。如果内存地址为低位,则意味着littleEndian,反之亦然。如258所示:
代码验证如下:
var buf = new array buffer(2);var view = new Datiew(buf);view.setInt16(0,258,true);//little-endian write let little = view . get uint 8(0);let big = view . getuint 8(1);console . log(little)//Print 2 cons console . log(big)//打印13位二进制数据的位运算,包括按位NOT (~)、按位AND (&)、按位OR (|)、按位XOR()和左移(& gt),无符号右移(> & gt& gt)。js的API只提供8、16、32等固定位数的数据。,其他位的数据需要按位操作读取。
3.1读取字节中的一位为0或1。
您可以将字节数与目标位的值进行AND运算,以便只保留字节中目标位的值。例如,读取第6位和第8位的值。
let data = new uint 8 array(buffer)[0];设hasAudio =(data & 4)= = = 4;设has video =(data & 1)= = = 1;3.2读取字节中几个连续位代表的数值。
首先,和这些数字所代表的值,然后向右下方移动。例如,读取一个字节中前5位表示的数,前5位的值为248。
let data = new uint 8 array(buffer)[0];let target = (data & 248)>& gt3;读取字节中其他位置的值也是如此。
3.3多字节拼接大数据
虽然有API可以获取多字节数据,但是在需求得不到满足时,可以通过位移和按位或运算拼接大数据。比如在FLV标签中,有一个时间戳拼接的地方,二进制的后8位要拼接在24位前面,形成一个32位的数。
设v =新数据视图(块,偏移量);设ts2 = v . getuint 8(0);设ts1 = v . getuint 8(1);设ts0 = v . getuint 8(2);设ts3 = v . getuint 8(3);//获取时间戳字段ts3是高8位,假设时间戳= TS0 | (TS1
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。