前端FLV视频直播解决方案

打印 上一主题 下一主题

主题 537|帖子 537|积分 1613

项目背景:

1. 背景给出一个地点,持续不停的推送flv视频流。
2.前端需要接收视频流,并探求合适的播放插件。
一开始:

着实用的是xgplayer(西瓜视频)。
官网地点:西瓜播放器
使用的是直播,flv的插件:西瓜播放器 | xgplayer-flv。
但是无法播放,现象就是一直loading
厥后,查了很多多少资料,发现一个issue:
流数据正常下载,xgplayer-flv无法播放 · Issue #604 · bytedance/xgplayer · GitHub。

和我环境一模一样,但是暂时没有什么解决方案。说明,此路不通
柳暗花明:

找了很久,找到一个全能播放插件 —— Jessibuca
官网地点:Jessibuca

如何使用:

前端如何使用?建议直接下载相关资源,静态引入。
需要下载三个资源,如下图:

怎么找到这三个资源?去官网的network里找找吧,不在多说。

vue中使用详情:

起首,上边的三个文件引入public。在index.html文件中只需要引入jessibuca.js。
  1. <!--
  2. public下的index.html 直接引入js文件
  3. -->
  4. ....
  5. <script src="<%= BASE_URL %>jessibuca.js"></script>
  6. .....
复制代码
然后,创建视频播放组件 LiveVideoPlay.vue:
  1. <script>
  2. export default {
  3.   name: "LiveVideoPlay",
  4.   props: {
  5.     // 播放地址
  6.     playUrl: {
  7.       type: String,
  8.       required: true,
  9.     },
  10.     // 目标domid
  11.     id: {
  12.       type: String,
  13.       required: true,
  14.     },
  15.   },
  16.   data() {
  17.     return {
  18.       player: null,
  19.     };
  20.   },
  21.   methods: {
  22.     // 初始化视频组件
  23.     initPlayer() {
  24.       if (Jessibuca) {
  25.         this.player = new Jessibuca({
  26.           container: document.getElementById(this.id), //jessibuca需要容器
  27.           videoBuffer: 0.2, // 缓存时长
  28.           isResize: false,
  29.           loadingText: "疯狂加载中...",
  30.           useMSE: true,
  31.           useWCS: true,
  32.           debug: true,
  33.           background: "@/assets/icons/svg/no-video.svg",
  34.           supportDblclickFullscreen: true,
  35.           showBandwidth: true, // 显示网速
  36.           operateBtns: {
  37.             fullscreen: true,
  38.             screenshot: true,
  39.             play: true,
  40.             audio: true,
  41.           },
  42.           forceNoOffscreen: true,
  43.           isNotMute: false,
  44.           timeout: 10,
  45.         });
  46.         //console.log("this.player ----- ", this.player, this.playUrl);
  47.         this.player.play(this.playUrl);
  48.       }
  49.     },
  50.   },
  51.   beforeDestroy() {
  52.     // 销毁视频
  53.     if (this.player) {
  54.       this.player.destroy();
  55.       this.player = null;
  56.     }
  57.   },
  58.   mounted() {
  59.     this.initPlayer();
  60.   },
  61. };
  62. </script>
  63. <template>
  64.   <div class="video-player-outer" :id="id"></div>
  65. </template>
  66. <style>
  67. .video-player-outer {
  68.   width: 100%;
  69.   height: 100%;
  70. }
  71. </style>
复制代码
最后,父组件中直接引用:
  1. // 父组件中直接使用该组件
  2. <script>
  3. import LiveVideoPlay from "./LiveVideoPlay.vue";
  4. export default {
  5.     name: '',
  6.     components: {
  7.         LiveVideoPlay
  8.     },
  9.     data () {
  10.         return {
  11.             playUrl1: null,
  12.             playUrl2: null,
  13.             showV1: false,
  14.             showV2: false,
  15.         }
  16.     },
  17.     methods: {
  18.         handlePlayVideo(v) {
  19.       if (v == 1) {
  20.         this.playUrl1 =
  21.           "https://xxxxxx/live/02.live.flv";
  22.         this.showV1 = true;
  23.       } else if (v == 2) {
  24.         this.playUrl2 =
  25.           "https://xxxxxx/live/02.live.flv";
  26.         this.showV2 = true;
  27.       }
  28.     },
  29.     StopPlayVideo(v) {
  30.       if (v == 1) {
  31.         this.showV1 = false;
  32.       } else if (v == 2) {
  33.         this.showV2 = false;
  34.       }
  35.     },
  36.     },
  37. }
  38. </script>
  39. <template>
  40.     <div class="box">
  41.           <div class="video-box-item">
  42.             <el-button @click="handlePlayVideo(1)">播放视频1</el-button>
  43.             <el-button @click="StopPlayVideo(1)">停止视频1</el-button>
  44.             <LiveVideoPlay v-if="showV1" :playUrl="playUrl1" id="v1" />
  45.           </div>
  46.           <div class="video-box-item">
  47.             <el-button @click="handlePlayVideo(2)">播放视频2</el-button>
  48.             <el-button @click="StopPlayVideo(2)">停止视频2</el-button>
  49.             <LiveVideoPlay v-if="showV2" :playUrl="playUrl2" id="v2" />
  50.           </div>
  51.     </div>
  52. </template>
复制代码
如上,可以试一试本身的播放地点是否可以成功播放视频.如果你的需求不那么高,不考虑延迟,到这里基本就够了,不需要卷下去.
但是,如果你的要求比较高,又不想买jecibuca的收费版本,那么请继续往下看, 有更好的解决方案.

优中选优:

现在这个功能是做出来了,但是视频延迟的问题比较突出.比如,我控制摄像头旋转一下位置,在上述解决方案中,会明显发现摄像头触发旋转进而回传视频明显延迟.那怎么办? 如果你要求不高,那么上边的解决方案足够使用,但是如果要求低延迟,那么就不得不祭出另个大杀器了 - LiveQing.
官网地点: LivePlayer H5播放器 | 青柿视频流媒体服务解决方案
如何使用? vue2中大概分为这几步调(vue3+vite的可以参考官网):
1. 安装 Liveplayer:
  1. npm install @liveqing/liveplayer
复制代码
2. 安装 webpack 插件 copy-webpack-plugin
  1. npm install copy-webpack-plugin@4.6.0
复制代码
注意: 如果你的版本是vuecli4.0+, 那么以上这个版本就够用了.但是 如果你的vuecli5.0+, 你需要升级这个copywebpack-plugins的版本,比如 copy-webpack-plugin@11.0.0 .亲测有效,一定要注意!!!
3. 配置vue.config.js
  1. /**  vue.config.js   */
  2. // *****  注意 还是vuecli版本的问题
  3. // *****  如果你的vuelci4.0+  就用下边这个配置
  4. const CopyWebpackPlugin = require("copy-webpack-plugin");
  5. module.exports = {
  6.     ...
  7.     configureWebpack: (config) => {
  8.         config.devtool = "source-map";
  9.         config.output.libraryExport =
  10.                       "default"; /* 解决import UMD打包文件时, 组件install方法执行报错的问题!! */
  11.         // 增加配置如下  主要是 plugins
  12.         const plugins = [
  13.           new CopyWebpackPlugin([
  14.             {
  15.               from: "node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml",
  16.             },
  17.             {
  18.               from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf",
  19.             },
  20.             {
  21.               from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js",
  22.               to: "livePlayer/",
  23.             },
  24.       ]),
  25.     ];
  26.         config.plugins.push(...plugins);
  27.       
  28.     }
  29.   },
  30.     ...
  31. }
  32. // *****  如果你的vuelci5.0+  就用下边这个配置
  33. const CopyWebpackPlugin = require("copy-webpack-plugin");
  34. module.exports = {
  35.     .....
  36.     chainWebpack(config) {
  37.         
  38.         // 增加插件
  39.         
  40.         config.plugin('copy').use(CopyWebpackPlugin, [
  41.            {
  42.                  patterns: [
  43.             {
  44.               from: "node_modules/@liveqing/liveplayer/dist/component/crossdomain.xml",
  45.             },
  46.             {
  47.               from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer.swf",
  48.             },
  49.             {
  50.               from: "node_modules/@liveqing/liveplayer/dist/component/liveplayer-lib.min.js",
  51.               to: "livePlayer/",
  52.             },
  53.       ]
  54.             }
  55.         ])
  56.         
  57.     }
  58.    
  59. }
复制代码
4. public中的index.html中引入js文件

5. 封装播放视频组件
  1. <template>
  2.   <LivePlayer
  3.     class="component-wrapper video-panel"
  4.     :class="{ fullscreen: flag }"
  5.     :videoUrl="options.url"
  6.     :videoTitle="options.title"
  7.     :poster="options.poster"
  8.     :controls="options.controls"
  9.     :autoplay="options.autoplay"
  10.     :live="options.live"
  11.     :hide-snapshot-button="options.hideSnapshot"
  12.     :muted="options.muted"
  13.     :fluent="options.fluent"
  14.     :stretch="options.stretch"
  15.     :aspect="options.aspect"
  16.     :loading="options.loading"
  17.     :hide-big-play-button="options.hideBigPlay"
  18.     @fullscreen="onFullscreen"
  19.   >
  20.     <slot></slot>
  21.   </LivePlayer>
  22. </template>
  23. <script>
  24. import LivePlayer from "@liveqing/liveplayer";
  25. export default {
  26.   name: "LiveVideoRtcPlayer",
  27.   components: {
  28.     LivePlayer,
  29.   },
  30.   props: {
  31.     params: {
  32.       type: String,
  33.     },
  34.   },
  35.   data() {
  36.     return {
  37.       flag: false,
  38.     };
  39.   },
  40.   computed: {
  41.     options() {
  42.       return {
  43.         // 播放地址
  44.         url: this.params,
  45.         // 视频标题
  46.         title: "",
  47.         // 视频封面图片
  48.         poster: "",
  49.         // 播放器控制栏
  50.         controls: true,
  51.         // 隐藏截图
  52.         hideSnapshot: true,
  53.         // 是否直播
  54.         live: true,
  55.         // 是否自动播放
  56.         autoplay: true,
  57.         // 是否静音
  58.         muted: true,
  59.         // 流畅模式
  60.         fluent: true,
  61.         // 是否拉伸
  62.         stretch: true,
  63.         // 全屏 - 适应div
  64.         aspect: "fullscreen",
  65.         // 指示加载状态
  66.         loading: true,
  67.         // 隐藏起播状态下的大播放按钮
  68.         hideBigPlay: true,
  69.       };
  70.     },
  71.   },
  72.   created() {
  73.     console.log("配置 ----- ", this.options);
  74.   },
  75.   beforeDestroy() {
  76.     if (this.options) {
  77.       this.options.url = "";
  78.     }
  79.     this.onExitFullscreen();
  80.   },
  81.   methods: {
  82.     onExitFullscreen() {
  83.       this.flag = false;
  84.     },
  85.     onFullscreen(status) {
  86.       this.flag = status;
  87.       if (!status) {
  88.         this.onExitFullscreen();
  89.         return;
  90.       }
  91.     },
  92.   },
  93. };
  94. </script>
  95. <style lang="scss" scoped>
  96. .component-wrapper.video-panel {
  97.   position: relative;
  98.   width: 100%;
  99.   height: 100%;
  100.   .video-wrapper .video-js {
  101.     background-color: rgba(32, 46, 71, 0.6);
  102.     .video-title {
  103.       top: 4px;
  104.       right: unset;
  105.       left: 4px;
  106.       padding: 4px 6px;
  107.       max-width: 80%;
  108.       font-size: 16px;
  109.     }
  110.     .video-control {
  111.       position: absolute;
  112.       top: 100%;
  113.       left: 50%;
  114.       transform: translate(-50%, -140%);
  115.       margin-top: 0;
  116.     }
  117.   }
  118.   &.fullscreen .video-wrapper .video-js {
  119.     .video-title {
  120.       top: 60px;
  121.       right: unset;
  122.       left: 20px;
  123.       padding: 5px 8px 6px;
  124.       background: rgba(4, 16, 37, 0.6);
  125.       border-radius: 4px;
  126.     }
  127.   }
  128. }
  129. </style>
复制代码
6. 父组件中引用播放组件
  1. <template>
  2.   <div id="app">
  3.     <!-- 视频 -->
  4.     <div class="video-box">
  5.       <el-button @click="handlePlayVideo(1)">播放视频1</el-button>
  6.       <el-button @click="StopPlayVideo(1)">停止视频1</el-button>
  7.       <div class="video-box-item">
  8.         <LiveVideoRtcPlayer v-if="showV1" :params="playUrl1" id="v1" />
  9.       </div>
  10.       <el-button @click="handlePlayVideo(2)">播放视频2</el-button>
  11.       <el-button @click="StopPlayVideo(2)">停止视频2</el-button>
  12.       <div class="video-box-item">
  13.         <LiveVideoRtcPlayer v-if="showV2" :params="playUrl2" id="v2" />
  14.       </div>
  15.     </div>
  16.   </div>
  17. </template>
  18. <script>
  19. //import Child from "./Child.vue";
  20. //import LiveVideoPlay from "./LiveVideoPlay.vue";
  21. import LiveVideoRtcPlayer from "./LiveVideoRtcPlayer.vue";
  22. export default {
  23.   name: "App",
  24.   components: {
  25.     //LiveVideoPlay,
  26.     LiveVideoRtcPlayer,
  27.   },
  28.   data() {
  29.     return {
  30.       playUrl1: null,
  31.       playUrl2: null,
  32.       showV1: false,
  33.       showV2: false,
  34.     };
  35.   },
  36.   methods: {
  37.     handlePlayVideo(v) {
  38.       if (v == 1) {
  39.         // this.playUrl1 =
  40.         //   "https://xxxxxxxxxxxx/live/02.live.flv";
  41.         this.playUrl1 =
  42.           "webrtcs://xxxxxxxxxxxxx/live/index/api";
  43.         this.showV1 = true;
  44.       } else if (v == 2) {
  45.         this.playUrl2 = 'xxxxx 播放地址';
  46.         this.showV2 = true;
  47.       }
  48.     },
  49.     StopPlayVideo(v) {
  50.       if (v == 1) {
  51.         this.showV1 = false;
  52.       } else if (v == 2) {
  53.         this.showV2 = false;
  54.       }
  55.     },
  56.   },
  57. };
  58. </script>
  59. <style lang="scss" scoped>
  60. #app {
  61.   height: 100%;
  62. }
  63. #app ::v-deep .box {
  64.   font-size: 30px;
  65. }
  66. .video-box {
  67.   width: 100%;
  68.   height: 600px;
  69.   overflow: hidden;
  70.   &-item {
  71.     width: 300px;
  72.     height: 400px;
  73.     float: left;
  74.     overflow: hidden;
  75.     background-color: #f1f2f3;
  76.     margin-left: 50px;
  77.     position: relative;
  78.   }
  79. }
  80. </style>
  81. <style lang="scss"></style>
复制代码
测试一下,nice.
累了,就这样吧.

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南七星之家

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表