Vue3使用mpegts.js播放FLV视频的配置和遇到的坑
这篇文章主要为大家详细介绍了vue3如何使用mpegts.js实现播放flv的直播视频流
1.安装
npm install --save mpegts.js
2.使用(vue组件方法)
<script setup lang="ts">
import {watch} from "vue";
import Mpegts from "mpegts.js";
const props = defineProps<{
url: string,
}>()
let MPEGTSPlayer: Mpegts.Player; // 播放器实例
watch(props, ()=>{
initPlayer()
})
/**
* @description 初始化
* */
const initPlayer = async () => {
destroyVideo();
const videoElement: HTMLMediaElement = document.getElementById('videoEle') as HTMLMediaElement;
if (props.url && videoElement) {
Mpegts.isSupported() ? createPlayer(videoElement) : console.log("播放器不可以在您的设备上运行");
}
}
/**
* @description 创建播放器
* @param videoElement 播放器媒体标签
* */
const createPlayer = (videoElement: HTMLMediaElement) => {
const mediaDataSource = {
type: "flv",
isLive: true,
cors: true,
url: props.url
}
MPEGTSPlayer = Mpegts.createPlayer(mediaDataSource, {
enableWorker: false,
enableStashBuffer: false,
liveBufferLatencyChasing: true,
reuseRedirectedURL: true,
lazyLoad: false,
deferLoadAfterSourceOpen: false,
stashInitialSize: 384,
autoCleanupSourceBuffer: true,
autoCleanupMinBackwardDuration: 30,
autoCleanupMaxBackwardDuration: 60,
})
MPEGTSPlayer.attachMediaElement(videoElement);
loadPlay(MPEGTSPlayer);
}
/**
* @description 加载视频并且播放
* @param video 需要加载的视频
* */
const loadPlay = (video: any) => {
if (video && video['e'] !== null) {
// 添加媒体监听 1.监听视频错误 2.监听视频加载
video.on(Mpegts.Events.ERROR, listenerError);
video.on(Mpegts.Events.LOADING_COMPLETE, listenerLoading);
// 加载视频
video.load();
// 播放视频
video.play().then(() => {
// 视频播放之后的一些操作
}).catch((error: Error) => {
// 视频播放错误的一些操作
})
}
}
/**
* @description 实时监听播放异常
* @param Error 错误信息
* */
const listenerError = (Error: any) => {
switch (Error) {
case Mpegts.ErrorTypes.NETWORK_ERROR:
// 网络异常
break;
case Mpegts.ErrorTypes.MEDIA_ERROR:
// 媒体错误
break;
case Mpegts.ErrorTypes.OTHER_ERROR:
// 其他错误
break;
}
}
/**
* @description 监听加载事件(直播流可能会导致视频播放暂停,此时会触发此方法)
* */
const listenerLoading = () => {
}
/**
* @description 关闭监听、停止播放、断流、销毁
* */
const destroyVideo = () => {
if (MPEGTSPlayer && MPEGTSPlayer['e'] != null) {
MPEGTSPlayer.off(Mpegts.Events.ERROR, listenerError);
MPEGTSPlayer.off(Mpegts.Events.LOADING_COMPLETE, listenerLoading);
MPEGTSPlayer.pause();
MPEGTSPlayer.unload();
MPEGTSPlayer.detachMediaElement();
MPEGTSPlayer.destroy();
MPEGTSPlayer = null;
}
}
</script>
3.vue(html部分)
<template>
<video autoplay muted controls
class="video"
id="videoEle"
:data-src="videoURL"
></video>
</template>
4.样式自定义,此处省略
style:略。
5.可能出现的异常
问题1:[FLVDemuxer] > Unsupported tag type 0, skipped
解决方法:
出现此提示,视频可以正常播放,但会重复出现。可能的问题:流不干净,用FlvBugger或ffmpeg检查下
问题2:[FlvPlayer] > Playback seems stuck at 0,seek to 1.32
解决方法:
出现这个问题,可能是音画不同步出现的提示信息,可以添加一个“追帧”的方法
const end = MPEGTSPlayer.buffered.length > 0 ? MPEGTSPlayer.buffered.end(0) : 0;
const differTime = end - MPEGTSPlayer.currentTime;
if (differTime >= 2) {
MPEGTSPlayer.currentTime = end - .5;
}
问题3:Error while initialize transmuxing worker,fallback to inline transmuxing
解决方法:
添加以下配置:
enableWorker:false
提示:此方法还可以解决直播过程导致浏览器奔溃的问题,如果配置的是"enableWorker:true",在直播到一定时长的时候会导致浏览器奔溃。
问题4:The Play() request was interrupted by a call to payse().
play()请求被pause()调用中断
解决方法:
给播放器数据流的地方添加一个定时器,如下:
setTimeout(()=>{
flvPlayer.play()
},300)
此方法在一些理想情况下是可以解决的,但是如果因为频繁切换的话还是不能彻底解决该问题,此时需要在播放(参考前面 loadPlay 方法)的时候添加对应的处理
video.play().then(() => {
// 正常播放的一些操作
failedMessage.value = ''; // 错误信息用于显示在播放器界面,提示提示用户
}).catch((error: Error) => {
// 播放错误的一些处理
console.log('摄像头名称---: ' + cameraName.value + '---', error.message);
// 可能出现的播放错误信息:“source”
const source = 'Failed to load because no supported source was found.';
if (source == error.message) {
failedMessage.value = ' _ 未找到播放源';
}
// 可能出现的播放错误信息:“pause”
const pause = 'The play() request was interrupted by a call to pause(). https://goo.gl/LdLk22';
if (pause == error.message) {
console.log(cameraName.value + ' play() 请求被 pause() 调用中断');
}
})
此时会把错误抛出,因为频繁切换,是避免不了 'The Play() request was interrupted by a call to payse(). '。所以只能这样处理。保证切换后的播放不受影响就可以了。
问题5:[MseController] > Failed to execute 'appendBuffer' on 'SourceBuffer':The HTMLMediaElement.error attribute is not null.
解决方法:
一般是发生在切换播放重新拉流之前调用了 destroyVideo 方法,
/**
* @description 关闭监听、停止播放、断流、销毁
* */
const destroyVideo = () => {
if (MPEGTSPlayer && MPEGTSPlayer['e'] != null) {
MPEGTSPlayer.off(Mpegts.Events.ERROR, listenerError);
MPEGTSPlayer.off(Mpegts.Events.LOADING_COMPLETE, listenerLoading);
MPEGTSPlayer.pause();
MPEGTSPlayer.unload();
MPEGTSPlayer.detachMediaElement();
MPEGTSPlayer.destroy();
MPEGTSPlayer = null;
}
}
为了所谓的节省内存,没有重新创建播放器,直接调用 以下loadPlay 方法
/**
* @description 加载视频并且播放
* @param video 需要加载的视频
* */
const loadPlay = (video: any) => {
if (video && video['e'] !== null) {
// 添加媒体监听 1.监听视频错误 2.监听视频加载
video.on(Mpegts.Events.ERROR, listenerError);
video.on(Mpegts.Events.LOADING_COMPLETE, listenerLoading);
// 加载视频
video.load();
// 播放视频
video.play().then(() => {
// 视频播放之后的一些操作
}).catch((error: Error) => {
// 视频播放错误的一些操作
})
}
}
所以,只要执行了 destroyVideo 方法,一定要重新 createPlayer 播放器
/**
* @description 创建播放器
* @param videoElement 播放器媒体标签
* */
const createPlayer = (videoElement: HTMLMediaElement) => {
const mediaDataSource = {
type: "flv",
isLive: true,
cors: true,
url: props.url
}
MPEGTSPlayer = Mpegts.createPlayer(mediaDataSource, {
enableWorker: false,
enableStashBuffer: false,
liveBufferLatencyChasing: true,
reuseRedirectedURL: true,
lazyLoad: false,
deferLoadAfterSourceOpen: false,
stashInitialSize: 384,
autoCleanupSourceBuffer: true,
autoCleanupMinBackwardDuration: 30,
autoCleanupMaxBackwardDuration: 60,
})
MPEGTSPlayer.attachMediaElement(videoElement);
loadPlay(MPEGTSPlayer);
}
问题6:Failed to read the 'buffered' property from 'SourceBuffer':This SourceBuffer has been removed from the parent media source.
解决方法:
在打开新页面和切换播放的时候前面的视频已经加载过一次,切换的时候视频资源会二次加载,在每次切换播放新的视频流之前调用 destroyVideo() 方法,销毁前面播放过的视频,
问题7:直播流播放时长到一定长度(一般20分钟以上),监控画面可能会卡住。
解决方法:
此时是因为播放器视频加载结束了,具体问题还有待验证,但是有解决方法,就是在创建播放器播放的时候,添加一个监听 video.on(Mpegts.Events.LOADING_COMPLETE, listenerLoading);
/**
* @description 实时监听加载播放事件
* 1. 在窗口激活情况下播放结束 且没有网络错误 重新initPlayer
* */
const listenerLoading = () => {
initPlayer();
}
浏览器控制台出现'The input MediaDataSource has been completely buffered to end'提示,就会触发这个方法,然后在该方法里面调用'initPlayer()',重新创建播放器播放就可以解决了。
以上就是我在项目里面遇到的坑,如果还有没有提到的问题,也可以提出来一起学习参考解决。
问题8:[MSEController] > MediaSource onSourceEnded(和问题7类似)
onSourceBuffer 结束后视频卡住,但流式传输仍在进行。
解决方法:
在下面的方法里里面重新调用 initPlayer()方法,也可以调用createPlayer ()方法重新创建播放器,具体看你的业务
/**
* @description 实时监听加载播放事件
* 1. onSourceBuffer 结束后视频卡住,但流式传输仍在进行。
* */
const listenerLoading = () => {
initPlayer();
// or
createPlayer();
}
注:时间有限,暂时先写这么多。
更多推荐
所有评论(0)