flv.js怎么用?全面解读flv.js代码

阿神

阿神

2017-06-02

9086人浏览

原创

    首先声明,我不太懂JavaScript,我只是熟悉音视频处理部分,有错误在所难免,欢迎指正。

flv.js项目的代码有一定规模,如果要研究的话,我建议从demux入手,理解了demux就掌握了媒体数据处理的关键步骤,前面的媒体数据下载和后面的媒体数据播放就变得容易理解了。

    先普及点背景知识,为什么HTML5视频播放要用 flv 格式?

    因为Flash。我标题图片用的是“flash RIP”,flash快死了,但是它的影响力还在,flash技术是过去10多年的互联网视频基础技术,大量相关基础设施都是围绕Flash构建的,比如 CDN 普遍支持的 RTMP 和 flv over http协议。做互联网直播的公司为了能兼容Web上的Flash播放,不约而同地选择了flv的媒体格式。在从Flash到 HTML5过渡的时期,如果HTML5能支持flash的协议是再好不过了,可以平滑过渡,然而HTML5并不原生支持flash协议。flv.js这个项目解决了HTML5支持flash协议的问题,这就是flv.js应运而生短期爆红的历史背景。

    flv.js 中的demux就是一套 FLV 媒体数据格式的解析器,如果要理解FLV格式,下面的文档是必须熟读的。
Adobe官方的flv格式说明
http://www.adobe.com/content/dam/Adobe/en/devnet/flv/pdfs/video_file_format_spec_v10.pdf

   flv.js怎么用? 下面进入正题,flv.js代码解读:demux部分

    打开代码 https://github.com/Bilibili/flv.js/blob/master/src/demux/flv-demuxer.js

 static probe(buffer) {
        let data = new Uint8Array(buffer);
        let mismatch = {match: false};

        if (data[0] !== 0x46 || data[1] !== 0x4C || data[2] !== 0x56 || data[3] !== 0x01) {
            return mismatch;
        }

    0x46 0x4c 0x56 这几个数字其实就是 'F' 'L' 'V' 的ascii码,表示flv文件头,后面的0x01是flv格式的版本号,用这来检测数据是不是 flv 格式。

let hasAudio = ((data[4] & 4) >>> 2) !== 0;
let hasVideo = (data[4] & 1) !== 0;

    取出第五个字节,它的第六 和 第八 bit 分别表示是否存在 音频和视频数据,其它位是保留位可以忽略。

    这个probe是被 parseChunks 调用的,当读取了至少13个字节后,就判断下是否是一个flv数据,然后再继续后面的分析。为什么是13,因为flv的文件头就是13个字节,参考 上面 PDF里的 “The FLV header”,这13个字节包括了后面的一个四字节的size,这个size表示前一个tag的大小,但是由于第一个tag是不存在前一个的,所以第一个size总是 0。

    parseChunks 后面的代码就是在不断解析 tag,flv把一段媒体数据称为 TAG,每个tag有不同的type,实际上真正用到的只有三种type,8、9、18 分别对应,音频、视频和Script Data。

 if (tagType !== 8 && tagType !== 9 && tagType !== 18) {
                Log.w(this.TAG, `Unsupported tag type ${tagType}, skipped`);
                // consume the whole tag (skip it)
                offset += 11 + dataSize + 4;
                continue;
            }

    这段代码就在判断tag type,注意看 那个 数字 11,因为tag header是11个字节,后面就是tag body了,所以offset加上这些偏移是为了跳到下一个tag的位置。

    tag header的格式为:UI 表示 unsigned int,后面的是bit数。

UI8 tag type
UI24 data size
UI24 timestamp
UI8 TimestampExtended
UI24 StreamID

    你看是不是正好 11 个字节,adobe为了节约流量,能用24bit表示的绝不用32bit,但是还是给timestamp设置了一个 扩展位存放最高位的字节,这个设计很蛋疼,于是导致了下面这段奇葩代码,先取三个字节按照Big-Endian转换成整数再在高位放上第四个字节。

let ts2 = v.getUint8(4);
let ts1 = v.getUint8(5);
let ts0 = v.getUint8(6);
let ts3 = v.getUint8(7);
let timestamp = ts0 | (ts1 <p>   
	解析完了 tag header后面分别按照不同的 tag type调用不同的解析函数。</p><pre class="brush:js;toolbar:false">switch (tagType) {
    case 8:  // Audio
        this._parseAudioData(chunk, dataOffset, dataSize, timestamp);
        break;
    case 9:  // Video
        this._parseVideoData(chunk, dataOffset, dataSize, timestamp, byteStart + offset);
        break;
    case 18:  // ScriptDataObject
        this._parseScriptData(chunk, dataOffset, dataSize);
        break;
}

TAG type:8 音频

    音频结构比较简单,AUDIODATA的第一个字节表示音频格式,其实基本都是 ACC 16bit 立体声 44.1kHz采样,所以最常见的数字就是 0xAF,后面一般就是 AACAUDIODATA了

TAG type : 9 视频

    重点看的是视频,

let frameType = (spec & 240) >>> 4;
let codecId = spec & 15;

    这里取两个重要的值,frameType表示帧类型 1 是关键帧 2 是非关键帧,codeId是编码类型。虽然flv支持 六种视频格式,但是实际上互联网点播直播真正在用的基本只有H.264一种。所以codecId基本都是7。这里作者用了十进制的数,其实就是按位取值,用16进制的数会更好理解。

    _parseAVCVideoPacket 用来解析 AVCVIDEOPACKET 结构,就是H.264的视频包

let packetType = v.getUint8(0);
let cts = v.getUint32(0, !le) & 0x00FFFFFF;

    解释下 CTS的概念,CompositionTime,我们前面在tag header里拿到过一个 timestamp,这个在视频里对应于DTS,就是解码时间戳,而CTS实际上是一个offset,表示 PTS相对于DTS的偏移量,就是 PTS和DTS的差值。

    这里有个坑,参考adobe的文档,这是CTS是个有符号的24位整数,SI24,就是说它有可能是个负数,所以我怀疑flv.js解析cts的代码有bug,没有处理负数情况。因为负数的24位整型到32位负数转换的时候要手工处理高位的符号位和补码问题。(我只是怀疑,没有调试确认过,但是我在处理YY直播数据的时候是踩过这个坑的,个别包含 B frame的视频是会出现CTS为负数的情况的)

2.png

Flowstep
Flowstep

AI界面设计工具,通过对话几秒内创建UI设计图、线框图和流程图

下载

    packetType有两种,0 表示 AVCDecoderConfigurationRecord,这个是H.264的视频信息头,包含了 sps 和 pps,AVCDecoderConfigurationRecord的格式不是flv定义的,而是264标准定义的,如果用ffmpeg去解码,这个结构可以直接放到 codec的extradata里送给ffmpeg去解释。

    flv.js作者选择了自己来解析这个数据结构,也是迫不得已,因为JS环境下没有ffmpeg,解析这个结构主要是为了提取 sps和pps。虽然理论上sps允许有多个,但其实一般就一个。

let config = SPSParser.parseSPS(sps);

    pps的信息没什么用,所以作者只实现了sps的分析器,说明作者下了很大功夫去学习264的标准,其中的Golomb解码还是挺复杂的,能解对不容易,我在PC和手机平台都是用ffmpeg去解析的。SPS里面包括了视频分辨率,帧率,profile level等视频重要信息。

    packetTtype 为 1 表示 NALU,NALU= network abstract layer unit,这是H.264的概念,网络抽象层数据单元,其实简单理解就是一帧视频数据。

    NALU的头有两种标准,一种是用 00 00 00 01四个字节开头这叫 start code,另一个叫mp4风格以Big-endian的四字节size开头,flv用了后一种,而我们在H.264的裸流里常见的是前一种。

TAG type : 18 Script Data

    除了音视频数据外还有 ScriptData,这是一种类似二进制json的对象描述数据格式,JavaScript比较惨只能自己写实现,其它平台可以用 librtmp的代码去做。

    我觉得作者处理解决flv播放问题外,也为前端贡献了 amf 解析,sps解析,Golomb解码等基础代码,这些是可以用在其他项目里的。

    在用传输协议获取了flv数据流后,用demux分离出音视频数据的属性和数据包,这为后面的播放打下了基础,从demux入手去读代码是个不错的切入点,而且一定要配合 flv file format spec一起看,反复多看几遍争取熟记在心。我现在已经可以从wireshark的抓包数据里人肉分析flv数据包了,对于debug相当有帮助。

相关文章:

如何看待B站 (bilibili) 开源 HTML5 播放器内核 flv.js?

开源代码flv.js的使用说明

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
墨刀AI提示词教学
墨刀AI提示词教学

本合集由PHP中文网精心整理,为您提供全面的墨刀AI提示词教学。内容涵盖高质量原型撰写公式与实操窍门,助您轻松掌握AI设计工具。无论是零基础入门还是进阶技巧,都能让您快速上手,大幅提升产品设计与协作效率。

2026.08.04

10

21

墨刀AI完整入门
墨刀AI完整入门

PHP中文网为您倾力打造墨刀AI保姆级入门指南完整版!本合集从零基础讲起,涵盖AI生成原型、提示词优化、图片转原型及多轮对话等核心功能。无论您是新手还是进阶用户,都能轻松掌握产品设计全流程。快来PHP中文网,一键解锁高效设计技巧,让想法即刻成型!

2026.08.04

8

20

墨刀AI进阶技巧
墨刀AI进阶技巧

本合集由PHP中文网精心整理,为您提供墨刀AI核心进阶策略指南。内容涵盖高效提示词写作、原型智能生成与微调、结构化导图制作及行业分析报告输出等实战技巧。助您轻松掌握AI设计工具,大幅提升产品设计与团队协作效率。

2026.08.04

10

14

火山引擎实名认证失败怎么办
火山引擎实名认证失败怎么办

火山引擎实名认证失败可能与证件信息填写错误、姓名或企业信息不一致、证件照片不清晰、营业执照状态异常、手机号验证失败或审核资料不完整有关。本专题整理个人认证、企业认证、资料上传、审核退回、重新提交和认证不通过的常见处理方法。

2026.08.04

5

10

火山引擎域名备案流程详解
火山引擎域名备案流程详解

火山引擎域名备案适合需要在火山引擎云服务器、对象存储、CDN或网站服务上绑定域名的用户参考。本专题整理备案入口、账号实名认证、备案类型选择、主体信息填写、网站信息提交、资料上传、初审核验、管局审核和备案失败排查,帮助用户完成网站上线前的备案流程。

2026.08.04

1

10

火山引擎DNS解析配置步骤
火山引擎DNS解析配置步骤

使用火山引擎DNS解析网站域名时,需要确认域名已完成管理接入,并正确配置服务器IP、CNAME地址或验证记录。本专题整理域名添加、记录类型选择、TTL设置、解析状态检查、备案和访问测试等流程,适合新手搭建网站时参考。

2026.08.04

3

10

火山引擎对象存储使用教程
火山引擎对象存储使用教程

火山引擎对象存储适合用于网站图片、视频文件、备份数据、静态资源和应用附件管理。本专题整理TOS控制台入口、存储桶创建、地域选择、权限设置、文件上传、访问链接生成、CDN加速、费用查看和常见上传或访问失败问题,帮助用户快速掌握对象存储基础操作。

2026.08.04

1

10

火山引擎云服务器使用教程
火山引擎云服务器使用教程

火山引擎云服务器使用教程适合第一次购买、部署和管理云服务器的用户参考。本专题整理控制台入口、实例创建、地域和配置选择、系统镜像设置、安全组放行、远程连接、网站部署、续费计费和常见连接失败问题,帮助用户快速完成云服务器基础使用流程。

2026.08.04

5

10

火山引擎API Key绑定大模型教程
火山引擎API Key绑定大模型教程

火山引擎API Key怎么绑定大模型适合需要在火山方舟、应用后台、脚本工具或AI编程软件中调用模型的开发者参考。本专题整理控制台服务开通、API Key创建、模型权限检查、模型ID选择、Base URL填写、调用测试和鉴权失败排查,帮助用户完成从密钥到模型调用的配置流程。

2026.08.04

2

10

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
DuMate-DeepResearch PDF 文档
DuMate-DeepResearch PDF 文档

共0课时 | 0人学习

阶跃Al官方手册
阶跃Al官方手册

共0课时 | 0人学习

Apache Subversion 官方手册
Apache Subversion 官方手册

共0课时 | 0人学习