资讯详情

资讯详情

flvjs、videojs、cyberplayer.js 播放器选型与 FLV 直播实战

1. 三款播放器到底该怎么选先搞清楚它们各自在解决什么问题视频播放这件事看起来只是页面上放一个video标签那么简单但真正做过点播、直播、监控回放这类项目的人都知道坑几乎全在“格式兼容”和“协议适配”上。浏览器原生video只认 MP4、WebM、Ogg 这几种容器编码上基本就是 H.264、VP8/VP9、AV1 这一套。可现实里服务端吐出来的流往往是 HTTP-FLV、HLSm3u8ts、甚至 RTMP 转出来的东西原生标签根本吃不下。这时候就需要一层 JS 播放库来做“翻译”和“调度”。flvjs、videojs、cyberplayer.js 这三个名字经常被放在一起讨论但它们其实不在同一个抽象层级上很多人一开始就搞混了。我先把定位讲清楚不然后面选型全是错的。flvjs是一个专注做 FLV 格式解码播放的库核心能力是把 HTTP-FLV 或 WebSocket-FLV 流通过 MSEMedia Source Extensions喂给video标签。它本质上是一个“格式适配层”只干一件事让浏览器能播 FLV。它不管 UI不管皮肤不管播放按钮长什么样就是一个纯粹的播放内核。videojs是一个完整的播放器框架它有自己的 UI、插件体系、事件模型、皮肤系统。它本身不直接解 FLV但它可以通过插件比如配合 flvjs 做 tech 层来支持 FLV。它的价值在于“生态”和“可扩展性”你要做一套带完整控制条、清晰度切换、字幕、广告插播的播放器videojs 是更省事的选择。cyberplayer.js是国内某云厂商推出的一套播放器 SDK它把 FLV、HLS、RTMP通过 Flash 或 H5 降级等多种协议封装在一起主打“开箱即用”尤其是配合自家云服务的直播、点播场景。它的特点是集成度高、文档偏业务向但灵活性和社区生态不如前两者。所以这三者的关系用一句话概括flvjs 是零件videojs 是组装平台cyberplayer.js 是成品套装。你选哪个取决于你是想自己造轮子、还是想快速上线、还是想深度定制。我做过一个监控回放项目最初用 cyberplayer.js因为接入快但后来要做多路同屏、自定义时间轴拖拽、倍速和逐帧发现它的扩展点不够最后换成了 videojs flvjs 的组合。这个切换过程踩了不少坑后面会细讲。2. flvjs 核心机制拆解MSE 是怎么把 FLV 喂给浏览器的要理解 flvjs 为什么能播 FLV得先搞明白 MSE 这套机制。浏览器原生不支持 FLV但支持 MSEMSE 允许你用 JavaScript 往video里“塞”数据。具体做法是创建一个MediaSource对象挂到 video 的 src 上然后通过SourceBuffer不断 append 解码后的媒体分片。flvjs 干的事就是把 FLV 的 tag 解析出来转成 MSE 能接受的 fMP4碎片化 MP4分片再 append 进去。2.1 FLV 封装格式的解析逻辑FLV 文件结构是 Header Tag 序列。Header 9 字节标记版本和是否有音视频。每个 Tag 由 TagHeader11 字节和 TagData 组成TagHeader 里有个 TagType8 是音频9 是视频18 是脚本数据onMetaData。flvjs 的解析器就是按这个结构逐字节读遇到音频 tag 提取 AAC 帧遇到视频 tag 提取 H.264 NALU然后重新封装成 fMP4 的 moofmdat 结构。这里有个关键点FLV 里的 H.264 是 Annex B 格式带 0x00000001 起始码而 MSE 要的是 AVCC 格式长度前缀。flvjs 内部会做这个转换把起始码替换成 4 字节的长度字段。这个转换如果出错表现就是画面花屏或者直接黑屏。我遇到过服务端推流时 NALU 分隔符不规范导致 flvjs 解析出来的帧长度对不上画面每隔几秒就卡一下后来在服务端加了强制转封装才解决。2.2 MSE 的 SourceBuffer 管理策略flvjs 在拿到 MediaSource 后会创建两个 SourceBuffer一个视频一个音频如果音视频分离。SourceBuffer 有配额限制不能无限 append否则会触发QuotaExceededError。flvjs 的策略是维护一个缓冲区当buffered范围超过阈值时调用remove()清理旧数据。这个阈值默认是 60 秒左右但在低内存设备上需要调小。注意如果你在移动端或者电视盒子上跑 flvjs一定要把autoCleanupSourceBuffer打开并且把autoCleanupMaxBackwardDuration设成 30 秒以内否则播久了必崩。2.3 直播与点播的配置差异flvjs 的配置项里isLive这个参数很关键。直播场景下要设成 true这样它不会去 seek也不会等待缓冲区填满才播而是尽量追最新帧。点播场景设 false它会做更积极的缓冲。另外lazyLoad和lazyLoadMaxDuration控制懒加载点播时打开能减少首屏流量。我实测下来直播场景下enableStashBuffer设成 false 能降低延迟但会牺牲一点流畅度网络抖动时容易卡。如果对延迟不敏感保持默认 true 更稳。3. videojs 的插件体系与 FLV 集成实战videojs 本身不认 FLV但它有一个 tech 抽象层。默认的 Html5 tech 就是原生 video你要播 FLV得注册一个新的 tech或者用现成的videojs-flvjs插件。这个插件的原理就是继承 videojs 的 Tech 类在createEl时初始化 flvjs 实例把 flvjs 的事件桥接到 videojs 的事件系统上。3.1 注册 flvjs tech 的完整代码import videojs from video.js; import flvjs from flv.js; import videojs-flvjs; const player videojs(my-video, { techOrder: [flvjs, html5], sources: [{ src: https://example.com/live/stream.flv, type: video/x-flv }], flvjs: { mediaDataSource: { isLive: true, cors: true, withCredentials: false }, config: { enableWorker: true, enableStashBuffer: false, stashInitialSize: 128 } } });这段代码里techOrder决定了优先用哪个 techflvjs必须排在html5前面。enableWorker打开后flvjs 会在 Web Worker 里做解码主线程不卡这个在低端机上效果很明显。stashInitialSize是初始缓冲大小单位 KB设太小首屏快但容易卡设太大首屏慢128 是个比较平衡的值。3.2 事件桥接与错误处理videojs 的事件系统和 flvjs 不一样插件会做一层映射。比如 flvjs 的ERROR事件会转成 videojs 的errorSTATISTICS_INFO会转成自定义事件。但有些事件映射不全比如 flvjs 的MEDIA_INFO包含视频宽高、帧率在 videojs 里拿不到需要直接监听 flvjs 实例。player.on(error, () { const err player.error(); console.error(播放错误:, err.code, err.message); }); // 直接拿 flvjs 实例监听底层事件 const tech player.tech({ IWillNotUseThisInPlugins: true }); if (tech tech.flv) { tech.flv.on(flvjs.Events.STATISTICS_INFO, (info) { console.log(当前网速:, info.speed, KB/s); }); }注意player.tech()这个方法在 videojs 7 以后需要传{ IWillNotUseThisInPlugins: true }才能拿到真实 tech否则返回的是代理对象拿不到 flv 实例。这个坑我踩过文档里没写清楚。3.3 多实例与内存泄漏防范一个页面放多个 videojs 实例时每个实例都会创建一个 flvjs 对象和 Worker。如果不手动销毁切路由后内存会一直涨。正确做法是在组件卸载时调用player.dispose()并且确保 flvjs 的destroy()被触发。videojs-flvjs 插件在 dispose 时会自动调但如果你手动创建了 flvjs 实例就得自己管。我做过一个 4 路同屏的页面一开始没管销毁切了十几次路由后浏览器直接卡死。后来加了beforeDestroy钩子每路都 dispose内存才稳定下来。4. cyberplayer.js 的适用边界与迁移成本cyberplayer.js 的优势是集成度高一个 script 标签引入初始化时传个 ak授权码就能播。它内部把 FLV、HLS、RTMP 都封装好了甚至做了 Flash 降级虽然现在 Flash 已经淘汰。对于只想快速上线、不打算深度定制 UI 的项目它确实省事。但它的边界也很明显。第一UI 定制能力弱控制条、按钮、弹幕层这些它提供的配置项有限想改得深入源码或者用 CSS 硬覆盖。第二事件模型不透明很多底层事件拿不到比如你想做精确的卡顿统计它只给一个模糊的onStatistics回调。第三绑定云服务虽然理论上可以播任意地址但部分高级功能如加密播放、时移需要配合特定服务端。我那个监控项目从 cyberplayer.js 迁到 videojs flvjs主要工作量在三块一是重写 UI 控制条二是把原来依赖 cyberplayer 回调的逻辑改成监听 videojs 事件三是处理 FLV 地址的鉴权参数拼接。迁移花了两周但之后做多路同屏、逐帧、倍速这些功能就顺畅多了。对比维度flvjsvideojscyberplayer.js定位FLV 解码内核播放器框架成品 SDKUI 定制无 UI高度可定制有限定制协议支持FLV依赖插件FLV/HLS/RTMP社区生态活跃非常活跃封闭上手成本中中高低深度定制高高低适合场景自研播放器复杂业务播放器快速上线5. 实操中的典型问题与排查手册5.1 首屏黑屏或长时间 loading这个问题的原因通常有三个一是流地址跨域CORS 没配好flvjs 拿不到数据二是服务端返回的 FLV header 不对比如缺少 onMetaData三是 MSE 的 codec 字符串不匹配比如服务端是 H.265 但浏览器只支持 H.264。排查顺序先看 Network 面板有没有数据返回再看 Console 有没有MediaSource相关报错最后用 flvjs 的MEDIA_INFO事件看解析出来的 codec 是什么。如果是 H.265那 flvjs 也救不了得换支持 H.265 的方案或者服务端转码。5.2 播放几分钟后卡死大概率是 SourceBuffer 配额满了。打开autoCleanupSourceBuffer把autoCleanupMaxBackwardDuration和autoCleanupMinBackwardDuration设合理。另外检查是不是enableWorker没开主线程被解码阻塞了。5.3 音视频不同步FLV 里音视频时间戳是分开的如果服务端推流时时间戳基准不一致就会出现不同步。flvjs 有个fixAudioTimestampGap配置设成 true 能缓解。但根治还得服务端对齐时间戳。5.4 移动端兼容性iOS Safari 对 MSE 支持有限尤其是低版本flvjs 在 iOS 上基本跑不起来。Android 的 WebView 也要看内核版本Chrome 内核 60 以上才比较稳。如果必须覆盖 iOS得用 HLSvideojs 配合videojs-contrib-hls或者原生 HLS 播放。提示做移动端项目前先用flvjs.isSupported()检测不支持就直接降级到 HLS 地址别硬上。5.5 常见问题速查表现象可能原因解决方向首屏黑屏CORS/header/codec查 Network、Console、MEDIA_INFO播几分钟卡死SourceBuffer 配额满开 autoCleanup调小缓冲音视频不同步时间戳基准不一致fixAudioTimestampGap服务端对齐画面花屏NALU 格式转换错误检查服务端 Annex B/AVCC内存持续上涨实例未销毁dispose player 和 flv 实例iOS 无法播放MSE 不支持降级 HLS延迟高缓冲策略太保守关 stashBuffer调小 stashInitialSize6. 我个人的选型建议与踩坑体会如果你只是要播一个 FLV 直播流页面简单不想引入大框架直接用 flvjs自己写个 video 标签和几个按钮就够了体积小、可控。如果你要做一套完整的点播/直播播放器有清晰度切换、字幕、广告、弹幕、多路同屏这些需求videojs flvjs 是更合适的组合前期搭架子花点时间后期扩展省心。如果你赶工期、预算够、不打算深度定制cyberplayer.js 能让你一天上线但要做好后期被绑定的心理准备。我踩过最大的坑是在 videojs 里直接改techOrder但没引入videojs-flvjs插件结果一直走 html5 techFLV 地址直接报错。还有一个坑是 flvjs 的enableWorker在部分 Android WebView 里反而导致播放失败因为 Worker 里没法访问某些 API后来加了环境判断只在桌面端开 Worker。另外提醒一点flvjs 已经进入维护模式新项目可以考虑它的继任者或者直接用 MSE 自己封装但存量项目里 flvjs 依然是最稳的 FLV 方案。videojs 的版本迭代要注意7.x 和 8.x 的 API 有差异升级前先看 changelog。cyberplayer.js 的授权码机制要留意过期时间别等到线上挂了才发现 ak 失效。最后分享一个小技巧调试 FLV 流的时候可以先用 flvjs 的flvjs.getFeatureList()看当前浏览器支持哪些特性再决定开哪些配置。这个 API 很多人不知道但能省不少排查时间。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →