Flvjs

flv.js

中文文档

实用的文档

解决跳帧、断流问题文档

一个可以在HTML5视频中播放.flv视频格式的JavaScript库

API

使用

  1. 安装依赖

npm i –save flv.js

  1. 在文件中引入依赖

import flvjs from ‘flv.js’

  1. 初始化播放器实例,并播放
1
<video id='video' controls></video>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

const videoDom = document.getElementById('video')

if (flvjs.isSupported()) { // 判断浏览器是否支持flvjs
const flvPlayer = flvjs.createPlayer({
type: 'flv',
url: '',
isLive: true,
hasAudio: false,
hasVideo: true,
duration: 0,
},
{
enableWorker: false,
autoCleanupSourceBuffer: true, // 对SourceBuffer进行自动清理
autoCleanupMaxBackwardDuration: 12, // 当向后缓冲区持续时间超过此值(以秒为单位)时,请对SourceBuffer进行自动清理
autoCleanupMinBackwardDuration: 8, // 指示进行自动清除时为反向缓冲区保留的持续时间(以秒为单位)。
enableStashBuffer: false, // 关闭IO隐藏缓冲区
isLive: true,
lazyLoad: false,
reuseRedirectedURL: true
})
flvPlayer.attachMediaElement(videoDom)
flvPlayer.load()
flvPlayer.play()

// 监听数据源是否加载完成
flvPlayer.on(flvjs.Events.LOADING_COMPLETE, (res) => {
if (!flvPlayer._receivedCanPlay) {
// 不能播放 销毁
flvPlayer.pause()
flvPlayer.unload()
flvPlayer.detachMediaElement();
flvPlayer.destroy();
// message.error('视频资源获取失败')
}
})

// 所有异常捕获(播放途中断流、网络错误等)
flvPlayer.on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
flvPlayer.pause()
flvPlayer.unload()
flvPlayer.detachMediaElement();
flvPlayer.destroy();
})

// 关闭异常
flvPlayer.off(flvjs.Events.ERROR, err => {
console.log('--off异常', err)
})

// 监听数据流请求 只要流在请求就一直监听 (追针应该就是通过定时器写在这里实现的)
flvPlayer.on(flvjs.Events.STATISTICS_INFO, (res) => {
console.log('请求数据信息')
})
}

  1. 跳帧处理

通过改变视频的当前时间来实现
buffered 属性返回 TimeRanges 对象,表示音频/视频的已缓冲部分

TimeRanges 对象的属性:

  • length - 获得音频/视频中已缓冲范围的数量
  • start(index) - 获得某个已缓冲范围的开始位置
  • end(index) - 获得某个已缓冲范围的结束位置
  • 注释:第一个缓冲范围的下标是 0
1
2
3
4
5
6
7
8
9
10
const clearBufferToPlay = () => {
if (flvPlayer && flvPlayer.buffered && flvPlayer.buffered.length) {
const end = flvPlayer.buffered.end(0)
const diff = end - flvPlayer.currentTime;
if (diff > 0) {
flvPlayer.currentTime = end - 0.00001 // 直接等于end会加载不出来
}
}
}

  1. 追针处理

改变视频播放的速率来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
const changeSpeadToPlay = () => {
if (flvPlayer && flvPlayer.buffered && flvPlayer.buffered.length) {
const end = flvPlayer.buffered.end(0)
const diff = end - flvPlayer.currentTime;
if (diff > 1) {
// 大于一秒开始倍速播放
videoElement.playbackRate = 1.1
}

if (diff <= 0.5) {
videoElement.playbackRate = 1
}
}
}
  1. 异常处理

后端转流后会出现第一帧卡帧的情况、追针和跳帧在流不稳定的情况下容易出问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
try {
flvPlayerList[index].on(flvjs.Events.STATISTICS_INFO, (res) => {
if (res.decodedFrames === 0) {
// TODO 画面卡顿重连
stuckCount.value[index] = stuckCount.value[index] ? stuckCount.value[index] + 1 : 1
if (stuckCount.value[index] >= 30) {
setAllPlayFlag(false)
// TODO 是否需要重连
setTimeout(() => {
stuckCount.value[index] = 0
handleVideoStatusChange(index, true)
playerList[index].addEventListener('loadedmetadata', () => {
setAllPlayFlag(isAllPlayStatus(currentPage, defaultSize))
})
console.log('---画面卡顿重连')
}, 1000);
}
console.log(`%c STATISTICS_INFO loading ${index} , count:${stuckCount.value[index]} ${playerList[index]?.paused}`, 'color:red')
} else {
stuckCount.value[index] = 0
}
})
} catch (err) {
console.log('拉流异常捕获', err)
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const handleProgress = (index: number) => {
// 数据在请求但是画面不动
if (playSt.value[index]) {
if (currentTimeCount.value[index] && currentTimeCount.value[index].key == playerList[index].currentTime) {
currentTimeCount.value[index].count++
if (currentTimeCount.value[index].count >= 10) {

currentTimeCount.value[index] = null
handleVideoStatusChange(index, true)

playerList[index].addEventListener('loadedmetadata', () => {
setAllPlayFlag(isAllPlayStatus(currentPage, defaultSize))
})

console.log('%c 画面卡顿重连', 'color:red')
}
} else {
currentTimeCount.value[index] = { key: playerList[index].currentTime ? playerList[index].currentTime : 0 + '', count: 1 }
}
}
}

内存泄漏

文档提供的配置项设置了之后还是会内存泄漏,目前解决方法是 reload() 可以清除缓存、但是切换标签的时候会清空所有状态,只有在路由跳转的时候用一下

扫一扫,分享到微信

微信分享二维码
  • Copyrights © 2019-2023 John Doe
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信