位置: IT常识 - 正文

flv.js的追帧、断流重连及实时更新的直播优化方案(逐帧flash动画)

发布时间:2024-01-21
1. 前言 最近在处理前端直播的业务,根据业务需要,使用 flv.js 的方案播放实时的flv视频流。不得不承认,flv.js 是一个伟大的库。 在使用flv.js开发的过程中,遇到了一些问题,也无外乎是视频延迟,视频卡顿等问题,经过在github issues里摸爬滚打,加上长时间的试错,将这些问 ... 目录1. 前言2. 前端直播

2.1 常见直播协议2.2 flv.js 的原理2.3 flv.js 的简单使用3. flv.js 的优化方案

3.1 追帧-解决延迟累积问题3.2 断流重连3.3 实时更新3.4 解决 stuck 问题4. 封装插件 flvExtend.js5. 其他问题参考1. 前言

推荐整理分享flv.js的追帧、断流重连及实时更新的直播优化方案(逐帧flash动画),希望有所帮助,仅作参考,欢迎阅读内容。

文章相关热门搜索词:flv延迟,fl逐帧动画,逐帧flash动画,js逐帧动画,flash逐帧素材,flv延迟,flv延迟,fl逐帧动画,内容如对您有帮助,希望把文章链接给更多的朋友!

最近在处理前端直播的业务,根据业务需要,使用 flv.js 的方案播放实时的flv视频流。不得不承认,flv.js 是一个伟大的库。

在使用flv.js开发的过程中,遇到了一些问题,也无外乎是视频延迟,视频卡顿等问题,经过在github issues里摸爬滚打,加上长时间的试错,将这些问题归纳出了对应的解决方案,也自己封装了一个扩展插件 flvExtend。

于是写这篇文章来对我遇到的一些问题进行总结,我提出的解决方案不一定适合所有场景,如果有更好的解决方案,欢迎讨论,这也是我写这篇文章的目的,也是我写文章的初心。

2. 前端直播

在讲解 flv.js 的优化方案之前,我想先简单的介绍一下前端直播的方案,为什么要使用 flv.js,方便大家理解以及作为一项技术来储备。

2.1 常见直播协议RTMP: 底层基于 TCP,在浏览器端依赖 Flash。HTTP-FLV: 基于 HTTP 流式 IO 传输 FLV,依赖浏览器支持播放 FLV。WebSocket-FLV: 基于 WebSocket 传输 FLV,依赖浏览器支持播放 FLV。WebSocket 建立在 HTTP 之上,建立 WebSocket 连接前还要先建立 HTTP 连接。HLS: Http Live Streaming,苹果提出基于 HTTP 的流媒体传输协议。HTML5 可以直接打开播放。RTP: 基于 UDP,延迟 1 秒,浏览器不支持。

可以看到,在浏览器端,可以考虑的方案有:HTTP-FLV、WebSocket-FLV 以及 HLS, 我们可以对比一下这几个直播协议之间的性能:(以下数据来源于网络,只做对比参考)

传输协议播放器延迟内存CPURTMPFlash1s430M11%HTTP-FLVVideo1s310M4.4%HLSVideo20s205M3%

可以看出在浏览器里做直播,使用 HTTP-FLV 协议是不错的,性能优于 RTMP+Flash,延迟可以做到和 RTMP+Flash 一样甚至更好。

2.2 flv.js 的原理

flv.js 的主要工作就是,在获取到 FLV 格式的音视频数据后通过原生的 JS 去解码 FLV 数据,再通过 Media Source Extensions API 喂给原生 HTML5 Video 标签。(HTML5 原生仅支持播放 mp4/webm 格式,不支持 FLV)

flv.js 为什么要绕一圈,从服务器获取 FLV 再解码转换后再喂给 Video 标签呢?原因如下:

兼容目前的直播方案:目前大多数直播方案的音视频服务都是采用 FLV 容器格式传输音视频数据。FLV 容器格式相比于 MP4 格式更加简单,解析起来更快更方便。2.3 flv.js 的简单使用<script src="https://www.cnblogs.com/xiahj/p/flv.min.js"></script><video id="videoElement"></video><script> if (flvjs.isSupported()) { var videoElement = document.getElementById("videoElement"); var flvPlayer = flvjs.createPlayer({ type: "flv", isLive: true, url: "http://example.com/flv/video.flv", }); flvPlayer.attachMediaElement(videoElement); flvPlayer.load(); flvPlayer.play(); }</script>

主要流程就是:

创建flvjs.Player对象,可以传递两个参数:MediaDataSource,以及 Config,具体的可以看下官方文档挂载元素加载视频流播放视频流

附:官方 API 文档

3. flv.js 的优化方案

我们根据官方的例子,可以很容易地把 flv 直播流播起来,但是在实际项目中使用时,还会遇到一些问题,我们需要手动对这些问题进行优化处理

3.1 追帧-解决延迟累积问题

flv.js 有一个最大的问题,就是延迟问题,一方面是直播端的延迟,一方面是浏览器的延迟,而且浏览器的延迟如果不做特殊处理,会造成延时累积的问题,对直播的实时性影响很大。

解决方案需要从以下两部分入手:

3.1.1 修改 config 配置

{ enableWorker: true, // 启用分离的线程进行转换 enableStashBuffer: false, // 关闭IO隐藏缓冲区 stashInitialSize: 128, // 减少首帧显示等待时长}开启 flv.js 的 Worker,多线程运行 flv.js 提升解析速度可以优化延迟关闭 buffer 缓存,这个选项可以明显地降低延迟,缺点就是由于关闭了 buffer 缓存,网络不好的时候可能会出现 loading 加载调低 IO 缓冲区的初始尺寸,减少首帧显示的等待时长

3.1.2 追帧设置

flv.js的追帧、断流重连及实时更新的直播优化方案(逐帧flash动画)

解决延时累加最有效的方式就是进行追帧设置

追帧,就是去判断缓冲区末尾的 buffer 值与当前播放时间的差值,如果大于某个值,就进行追帧设置,具体的思路如下:

首先,在 progress 事件,或者定时器中进行追帧逻辑判断 buffer 的差值 deltalet end = this.player.buffered.end(0); //获取当前buffered值(缓冲区末尾)let delta = end - this.player.currentTime; //获取buffered与当前播放位置的差值如果 delta 值大于某个设定的值,则进行追帧操作追帧有两种方式1)一种是直接更新当前的时间:this.player.currentTime = this.player.buffered.end(0) - 1,缺点是如果频繁触发会导致跳帧,观感差;2)一种是调快播放速度的方式来慢慢追帧: this.videoElement.playbackRate = 1.1,优点是稳定,缺点是如果 delta 值过大,通过这种方式追得太慢在实际使用中两种方式可以结合起来。

代码实现:

videoElement.addEventListener("progress", () => { let end = player.buffered.end(0); //获取当前buffered值(缓冲区末尾) let delta = end - player.currentTime; //获取buffered与当前播放位置的差值 // 延迟过大,通过跳帧的方式更新视频 if (delta > 10 || delta < 0) { this.player.currentTime = this.player.buffered.end(0) - 1; return; } // 追帧 if (delta > 1) { videoElement.playbackRate = 1.1; } else { videoElement.playbackRate = 1; }});3.2 断流重连

断流重连即在flvjs播放失败的回调中,进行重建视频的操作

代码实现:

this.player.on(flvjs.Events.ERROR, (e) => { // destroy this.player.pause(); this.player.unload(); this.player.detachMediaElement(); this.player.destroy(); this.player = null; // 进行重建的逻辑,这里不再展开 this.init();});3.3 实时更新

直播需要保证视频的实时性,以下两种操作都会导致视频的实时性得不到保证:

用户点击了暂停,过一段时间后再点播放,这时候的直播视频不是最新的网页切到后台,再重新切换回前台,视频不是最新的

所以需要根据这两种情况来实时更新视频

代码实现:

// 点击播放按钮后,更新视频videoElement.addEventListener("play", () => { let end = player.buffered.end(0) - 1; this.player.currentTime = end;});// 网页重新激活后,更新视频window.onfocus = () => { let end = player.buffered.end(0) - 1; this.player.currentTime = end;};3.4 解决 stuck 问题

有的时候,视频在播放的过程中会突然卡住,或者控制台有时会报错 “Playback seems stuck at 0, seek to 1.1”。

我们需要判断视频是否卡住了,然后重建视频实例

思路就是判断 decodedFrames 是否产生变化,如果视频是播放状态并且该值没有产生变化,则可以判断视频卡住了。

代码实现:

function handleStuck() { let lastDecodedFrames = 0; let stuckTime = 0; this.interval && clearInterval(this.interval); this.interval = setInterval(() => { const decodedFrames = this.player.statisticsInfo.decodedFrames; if (!decodedFrames) return; if (lastDecodedFrames === decodedFrames && !this.videoElement.paused) { // 可能卡住了,重载 stuckTime++; if (stuckTime > 1) { console.log(`%c 卡住,重建视频`, "background:red;color:#fff"); // 先destroy,再重建视频实例 this.rebuild(); } } else { lastDecodedFrames = decodedFrames; stuckTime = 0; } }, 800);}4. 封装插件 flvExtend.js

我将这些优化方案封装成了一个插件 flvExtend.js,它相当于是 flv.js 的一个功能扩展

插件地址:https://github.com/shady-xia/flvExtend

使用起来是这个样子:

import FlvExtend from "flv-extend";// 配置需要的功能const flv = new FlvExtend({ element: videoElement, // *必传 frameTracking: true, // 开启追帧设置 updateOnStart: true, // 点击播放后更新视频 updateOnFocus: true, // 获得焦点后更新视频 reconnect: true, // 开启断流重连 reconnectInterval: 2000, // 断流重连间隔});// 调用 init 方法初始化视频// init 方法的参数与 flvjs.createPlayer 相同,并返回 flvjs.player 实例const player = flv.init( { type: "flv", url: "http://192.168.0.11/stream", isLive: true, }, { enableStashBuffer: false, // 如果您需要实时(最小延迟)来进行实时流播放,则设置为false stashInitialSize: 128, // 减少首帧显示等待时长 });// 直接调用play即可播放player.play();5. 其他问题

这里打算长期记录一下遇到的问题以及解决思路,欢迎大家讨论,我会更新补充

1)多路视频同时直播

由于浏览器对 http 1.0 的限制,以Chrome为例,同一个浏览器下,最多只能播6路同源地址下的视频(包括多个标签页也会被合算在内)

目前的解决方案有:

使用http 2.0,由于http 2.0的多路复用,可以同屏播放多个视频流使用 websocket通过为流分配不同的服务端地址参考github issues使用 flv.js 做直播
本文链接地址:https://www.jiuchutong.com/zhishi/303781.html 转载请保留说明!

上一篇:帝国cms模板文件存在哪个文件目录里(帝国cms模板文件在哪)

下一篇:ps怎么把人p掉背景不变(ps怎么把人p掉背景还原)

  • 天猫精灵TGC1是什么型号

    天猫精灵TGC1是什么型号

  • 小米屏幕使用时间在哪里找呢(小米屏幕使用时长怎么设置)

    小米屏幕使用时间在哪里找呢(小米屏幕使用时长怎么设置)

  • 怎么删除朋友圈的内容(怎么删除朋友圈发过来的信息)

    怎么删除朋友圈的内容(怎么删除朋友圈发过来的信息)

  • 手机怎样滴滴打车(手机上怎样打滴)

    手机怎样滴滴打车(手机上怎样打滴)

  • 银行能否查到充值的微信账号(在银行能查到充值的游戏吗)

    银行能否查到充值的微信账号(在银行能查到充值的游戏吗)

  • md514zp/a是ipad几代(md514ll/a是ipad什么型号)

    md514zp/a是ipad几代(md514ll/a是ipad什么型号)

  • qq消息声音突然不响了(为什么qq消息声音小)

    qq消息声音突然不响了(为什么qq消息声音小)

  • wifi已连接但是无法访问互联网是什么意思(wifi已连接但是没有网络是什么原因)

    wifi已连接但是无法访问互联网是什么意思(wifi已连接但是没有网络是什么原因)

  • 华为nova6后摄像头旁边的黑条是什么(华为nova6后摄像头玻璃更换教程)

    华为nova6后摄像头旁边的黑条是什么(华为nova6后摄像头玻璃更换教程)

  • 微信视频群聊人数限制(微信群里视频聊天其他人能看得到吗)

    微信视频群聊人数限制(微信群里视频聊天其他人能看得到吗)

  • bios保存是哪个键(bios保存设置)

    bios保存是哪个键(bios保存设置)

  • 甲类功放和乙类功放有什么区别(甲类功放和乙类功放音质区别)

    甲类功放和乙类功放有什么区别(甲类功放和乙类功放音质区别)

  • qq扩列老是匹配失败(qq扩列一直显示匹配失败2021)

    qq扩列老是匹配失败(qq扩列一直显示匹配失败2021)

  • 微信新设备登录没有好友验证(微信新设备登录限制怎么解除)

    微信新设备登录没有好友验证(微信新设备登录限制怎么解除)

  • 华为mate30pro四个摄像头的作用

    华为mate30pro四个摄像头的作用

  • 钉钉静音算时长吗(钉钉静音对方知道吗)

    钉钉静音算时长吗(钉钉静音对方知道吗)

  • b365和z390区别有哪些(z390i和b360i)

    b365和z390区别有哪些(z390i和b360i)

  • 计算机指令由两部分组成它们是(计算机指令由两部组成)

    计算机指令由两部分组成它们是(计算机指令由两部组成)

  • 苹果怎么发炫彩短信(苹果怎么发炫彩照片)

    苹果怎么发炫彩短信(苹果怎么发炫彩照片)

  • 苹果xr待机时间多久(苹果xr待机时间是多久)

    苹果xr待机时间多久(苹果xr待机时间是多久)

  • tp-link路由器app(tp-link路由器APP)

    tp-link路由器app(tp-link路由器APP)

  • 手机和相机拍照区别(手机和相机拍照像素一样吗)

    手机和相机拍照区别(手机和相机拍照像素一样吗)

  • 使用UEFI模式安装Win10系统以获得更快的启动速度(uefi模式怎么装机)

    使用UEFI模式安装Win10系统以获得更快的启动速度(uefi模式怎么装机)

  • 语音处理/语音识别基础(六)- 语音的端点检测(EPD/VAD)(语音语言)

    语音处理/语音识别基础(六)- 语音的端点检测(EPD/VAD)(语音语言)

  • 购买免税产品的app
  • 小规模季度不超30万需要交什么税
  • 企业实收资本与股本区别
  • 生产企业退税计算方法怎么选择
  • 会计忘记申报税款会有什么影响
  • 发票二维码只有一半可以收吗
  • 发出商品是用进货吗
  • 建筑企业增值税怎么算
  • 虚开增值税发票的涉税风险如何防范
  • 可以抵扣的凭证
  • 折价购入股权
  • 个人独资所得税税率表最新
  • 应交印花税会计分录
  • 增值税优惠政策有哪些
  • 甲公司采用租赁方式租入一台大型设备
  • 三证合一对纳税有影响吗
  • 开发转产品好转吗
  • 作废已开具的普通发票
  • 公司集体活动的目的与意义
  • 营业执照办下来多久能在网上查到
  • 电子税务局财报怎么报
  • 收到车险理赔款会计分录
  • 签发支票怎么做账务处理
  • 投资者与被投资者的名人
  • 存货跌价准备借贷方表示的含义
  • 一般纳税人购进农产品如何抵扣进项税额
  • 空调应该计入什么科目
  • 支付给其他公司的工程项目管理费
  • transit code
  • 税务局开出来的发票没问题吧?
  • 前端打包后生成文件
  • elipse左侧菜单栏显示
  • php自定义函数的关键字是什么
  • 这年头不好混图片
  • 第十届蓝桥杯大赛个人赛省赛结果
  • php怎么获取post数据
  • php取字符串
  • 企业管理咨询合作协议
  • 总公司签协议,分公司开票,报账怎样写说明
  • 如何去掉或修改文件夹
  • mongodb如何删除
  • dedecms怎么改图片
  • 附有销售退回条件的商品销售
  • 一般纳税人零申报怎么报税步骤
  • 认缴制和实缴制的区别公司破产
  • 产品检测费计入成本吗
  • 个体户电子申报税流程
  • 企业为员工承担个人部分的五险 一金可以税前扣除?
  • 企业营业税怎么征收
  • 更正申报失败,维持原申报?
  • 加盟费收入如何入账
  • 报销差旅费大于预借差旅费会计分录
  • 2、开办费用计入哪个账户?
  • 哪些支出可以在出国公杂费中扣除
  • 营改增后增值税增加了什么征收范围
  • 快递公司成本分析
  • 物业公司劳务外包
  • 空调购买攻略
  • 银行期初余额录少了怎么办
  • 减免的税金怎样做会计分录
  • 事业单位开办费与注册资本的关系
  • 工程项目立项前包括哪几个过程
  • 关于投资收益纳税的说法
  • 支付个人运费没有发票怎么办
  • 挂靠工程项目预交税金的会计分录如何做?
  • win8怎么让我的电脑显示在桌面上
  • windows10预览版是什么
  • sdis.exe
  • linux服务器dns配置安装
  • 简单总结译码器和数据选择器的作用
  • 批处理书
  • js移动到指定位置
  • linux如何一次性删除多个文件
  • dos批处理文件的扩展名
  • 简略说明本岗位最高风险的防范措施和现场处置方案
  • unity shader可视化编辑
  • python simpy
  • 农产品进项税额核定扣除办法2019
  • 成都市武侯区税务局官网
  • 西藏景区门票优惠政策最新
  • 免责声明:网站部分图片文字素材来源于网络,如有侵权,请及时告知,我们会第一时间删除,谢谢! 邮箱:opceo@qq.com

    鄂ICP备2023003026号