这篇文章主要为大家详细介绍了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();
}

注:时间有限,暂时先写这么多。

GitHub 加速计划 / vu / vue
207.54 K
33.66 K
下载
vuejs/vue: 是一个用于构建用户界面的 JavaScript 框架,具有简洁的语法和丰富的组件库,可以用于开发单页面应用程序和多页面应用程序。
最近提交(Master分支:2 个月前 )
73486cb5 * chore: fix link broken Signed-off-by: snoppy <michaleli@foxmail.com> * Update packages/template-compiler/README.md [skip ci] --------- Signed-off-by: snoppy <michaleli@foxmail.com> Co-authored-by: Eduardo San Martin Morote <posva@users.noreply.github.com> 4 个月前
e428d891 Updated Browser Compatibility reference. The previous currently returns HTTP 404. 5 个月前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐