视频播放器(watermelon Player)vue2使用体验(教程版)
作为一名前端开发者,我曾参与过一个视频播放相关的项目,当时的主要任务是实现一个支持多种视频格式的播放器。在项目中,我们遇到了不少挑战,比如不同视频格式的兼容性问题、H.265 和 H.264 编码的支持,以及播放性能的优化等。虽然最终项目顺利完成,但我也意识到,如果能有一个通用的视频播放组件,可以轻松兼容多种格式和编码,那将会大大提升开发效率。
最近,我了解到西瓜视频播放器,它不仅支持 H.265 和 H.264 编码,还能兼容 FLV、M3U8 和 MP4 等常见视频格式。这让我眼前一亮,于是决定基于西瓜视频播放器,封装一个通用的 Vue 组件。这个组件只需要传入视频流地址和视频格式,就能自动适配 H.265 和 H.264 编码,并支持多种视频格式的播放。话不多数开整。
目录
前言
一、首先需要在项目中安装西瓜播放器的插件(用哪个装哪个)
二、实现支持flv的使用
1.下载对应的库并引入组件(此时间点的最新版本)
2.组件结构使用(注意组件中标识的id一定要唯一)
3.组件方法使用(配置很多,需要啥配置啥就行)
三、实现支持m3u8的使用
1.下载对应的库并引入组件(此时间点的最新版本)
2.组件结构使用(注意组件中标识的id一定要唯一)
3.组件方法使用(配置很多,需要啥配置啥就行)
四、实现支持mp4的使用(默认支持mp4格式,不用单独下载)
1.下载对应的库并引入组件(此时间点的最新版本)
2.组件结构使用(注意组件中标识的id一定要唯一)
3.组件方法使用(配置很多,需要啥配置啥就行)
五.对以上三种格式进行兼容封装
六.简单的父组件使用
七.此处是根据视频地址后缀识别视频格式的方法
总结:
前言
整体项目内容太多不过分介绍(之前文章有大致提及),其中一块内容是不同格式分屏直播窗口功能,因此一款能支持多种视频流格式的视频播放器组件显得尤为重要,实现了这个那么就相当于打好了地基高楼就可以有条不紊的搭建了。
一、首先需要在项目中安装西瓜播放器的插件(用哪个装哪个)
必不可少的是xgplayer,适配flv就需要装xgplayer-flv,适配m3u8就需要装xgplayer-hls,适配mp4的可以安装xgplayer-mp4(当然也可以不装,西瓜默认支持mp4格式),看好版本下载对应的插件,当然也需要参考对应版本的文档哈。
二、实现支持flv的使用
1.下载对应的库并引入组件(此时间点的最新版本)
npm install xgplayer@3.0.20 xgplayer-flv@3.0.20
import Player from "xgplayer";
import FlvPLugin from "xgplayer-flv";
import "xgplayer/dist/xgplayer.min.css"
2.组件结构使用(注意组件中标识的id一定要唯一)
<template>
<div class="flv-player-xg-king-container">
<!-- 屏幕 -->
<div id="myPlayerFLV" class="xg-style"></div>
</div>
</template>
3.组件方法使用(配置很多,需要啥配置啥就行)
export default {
name: "FlvPlayer",
data() {
return {
myPlayerFlv: null, // 视频实例
videoUrl: null, // 视频链接
height: "380px",
width: "600px",
};
},
mounted() {
this.init();
},
methods: {
// 初始化视频
init() {
if (FlvPLugin.isSupported()) {
// FlvPlayer继承于xgplayer
this.myPlayerFlv = new Player({
id: "myPlayerFLV", // 渲染的标签
isLive: true, // 直播开始与否
url: this.videoUrl, // 资源地址(视频流地址)
width: this.width, // 默认是600px
height: this.height, // 默认是337.5px
autoplay: true, // 自动播放
videoFillMode: "fill", // 画面填充模式
plugins: [FlvPLugin], // 引入插件
flv: {
retryCount: 3, // 重试 3 次,默认值
retryDelay: 1000, // 每次重试间隔 1 秒,默认值
loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
fetchOptions: {
// 该参数会透传给 fetch,默认值为 undefined
mode: "cors",
},
},
});
}
},
},
// 销毁组件时销毁视频
beforeDestroy() {
if (this.myPlayerFlv) {
this.myPlayerFlv.destroy();
}
this.myPlayerFlv= null;
},
};
三、实现支持m3u8的使用
1.下载对应的库并引入组件(此时间点的最新版本)
npm install xgplayer@3.0.20 xgplayer-hls@3.0.20
import Player from "xgplayer";
import HlsPLugin from "xgplayer-hls";
import "xgplayer/dist/xgplayer.min.css"
2.组件结构使用(注意组件中标识的id一定要唯一)
<template>
<div class="hls-player-xg-king-container">
<!-- 屏幕 -->
<div id="myPlayerHls" class="xg-style"></div>
</div>
</template>
3.组件方法使用(配置很多,需要啥配置啥就行)
export default {
name: "HlsPlayer",
data() {
return {
myPlayerHls: null, // 视频实例
videoUrl: null, // 视频链接
height: "380px",
width: "600px",
};
},
mounted() {
this.init();
},
methods: {
// 初始化视频
init() {
if (HlsPlugin.isSupported()) {
this.myPlayerHls = new Player({
id: "myPlayerHls", // 渲染的标签
isLive: true, // 直播开始与否
url: this.videoUrl, // 资源地址(视频流地址)
width: this.width, // 默认是600px
height: this.height, // 默认是337.5px
autoplay: true, // 自动播放
videoFillMode: "fill", // 画面填充模式
plugins: [HlsPlugin], // 引入插件
hls: {
retryCount: 3, // 重试 3 次,默认值
retryDelay: 1000, // 每次重试间隔 1 秒,默认值
loadTimeout: 10000, // 请求超时时间为 10 秒,默认值
fetchOptions: {
// 该参数会透传给 fetch,默认值为 undefined
mode: "cors",
},
},
});
},
}
},
// 销毁组件时销毁视频
beforeDestroy() {
if (this.myPlayerHls) {
this.myPlayerHls.destroy();
}
this.myPlayerHls= null;
},
};
四、实现支持mp4的使用(默认支持mp4格式,不用单独下载)
1.下载对应的库并引入组件(此时间点的最新版本)
npm install xgplayer@3.0.20 xgplayer-mp4@3.0.20
import Player from "xgplayer";
import Mp4Plugin from "xgplayer-mp4";
import "xgplayer/dist/xgplayer.min.css"
2.组件结构使用(注意组件中标识的id一定要唯一)
<template>
<div class="mp4-player-xg-king-container">
<!-- 屏幕 -->
<div id="myPlayerMp4" class="xg-style"></div>
</div>
</template>
3.组件方法使用(配置很多,需要啥配置啥就行)
export default {
name: "Mp4Player",
data() {
return {
myPlayerMp4: null, // 视频实例
videoUrl: null, // 视频链接
height: "380px",
width: "600px",
};
},
mounted() {
this.init();
},
methods: {
// 初始化视频
init() {
this.myPlayerMp4 = new Player({
id: "myPlayerMp4", // 渲染的标签
isLive: true, // 直播开始与否
url: this.videoUrl, // 资源地址(视频流地址)
width: this.width, // 默认是600px
height: this.height, // 默认是337.5px
autoplay: true, // 自动播放
videoFillMode: "fill", // 画面填充模式
plugins: [Mp4Plugin], // 引入插件
});
}
},
// 销毁组件时销毁视频
beforeDestroy() {
if (this.myPlayerMp4) {
this.myPlayerMp4.destroy();
}
this.myPlayerMp4= null;
},
};
五.对以上三种格式进行兼容封装
<!--
* @Description: 同时支持H265和H264协议的flv、m3u8、mp4视频播放组件
* @version: 0.0.2
* @Author: King
* @Date: 2025-03-18 09:49:11
* @LastEditors: xinShiCheng
* @LastEditTime: 2025-03-20 14:00:00
-->
<template>
<div class="video-player-xg-king-container">
<!-- 屏幕 -->
<div :id="`myPlayer${idIndex}`" class="xg-style"></div>
<!-- 错误提示 -->
<div v-if="errorMessage" class="error-message">{{ errorMessage }}</div>
</div>
</template>
<script>
// 西瓜插件
import Player from "xgplayer";
import FlvPLugin from "xgplayer-flv";
import HlsPlugin from "xgplayer-hls";
import "xgplayer/dist/index.min.css";
export default {
name: "VideoPlayer",
watch: {
// 监听播放源改变(一般用不上,可以在父组件直接控制销毁和初始化)
videoUrl: {
handler(newVal, oldVal) {
console.log("播放源改变", newVal, oldVal); // 添加调试信息
this.init();
},
},
},
props: {
// 这个是处理多个分屏窗口预留参数,父组件可以默认传一个9999(防止重复就行)
idIndex: {
type: Number,
required: true,
},
videoUrl: {
type: String,
required: true,
},
// 视频格式(由于没发现西瓜提供自动识别方法,所以需要传入)
streamType: {
type: String,
default: "m3u8",
},
// 默认公用配置
config: {
type: Object,
default: {
isLive: true,
autoplay: true,
videoFillMode: "fill",
controls: false, // 禁用控制条
closeVideoClick: true, // 禁止点击视频进行暂停和播放
screenShot: true, // 开启截图
// 开启截图功能务必为播放器提前配置好跨域 crossOrigin ,否则 canvas toDataURL 会触发错
videoAttributes: {
crossOrigin: "anonymous",
},
}
}
},
data() {
return {
myPlayerObj: null, // 视频实例
errorMessage: null, // 错误信息
};
},
mounted() {
this.init();
},
methods: {
// 初始化视频
init() {
// 极限处理预防报错
if (this.myPlayerObj) {
this.myPlayerObj.destroy();
}
let plugins = [];
let config = {
id: `myPlayer${this.idIndex}`,
url: this.videoUrl,
...this.config
};
switch (this.streamType) {
case "flv":
if (FlvPLugin.isSupported()) {
plugins = [FlvPLugin];
config.flv = {
retryCount: 3,
retryDelay: 1000,
loadTimeout: 10000,
fetchOptions: {
mode: "cors",
},
};
}
break;
case "m3u8":
plugins = [HlsPlugin];
break;
case "mp4":
break;
default:
console.error("不支持的视频类型");
this.errorMessage = "不支持的视频类型";
return;
}
config.plugins = plugins;
try {
this.myPlayerObj = new Player(config);
// 监听视频事件
this.myPlayerObj.on("play", () => {
this.$emit("videoPlay");
});
this.myPlayerObj.on("pause", () => {
this.$emit("videoPause");
});
this.myPlayerObj.on("ended", () => {
this.$emit("videoEnded");
});
this.myPlayerObj.on("error", (error) => {
console.error("视频播放出错", error);
this.errorMessage = "视频播放出错,请检查网络或视频源";
});
let queryFa = {
index: this.idIndex,
player: this.myPlayerObj,
};
this.$emit("playerCreated", queryFa);
} catch (error) {
console.error("播放器初始化出错", error);
this.errorMessage = "播放器初始化出错,请稍后重试";
}
},
},
// 销毁组件时销毁视频
beforeDestroy() {
if (this.myPlayerObj) {
this.myPlayerObj.destroy();
}
this.myPlayerObj = null;
},
};
</script>
<style scoped lang="scss">
.video-player-xg-king-container {
height: 100%;
width: 100%;
box-sizing: border-box;
background: #000000;
position: relative;
.xg-style {
width: 100% !important;
height: 100% !important;
}
.error-message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 18px;
background-color: rgba(0, 0, 0, 0.7);
padding: 10px 20px;
border-radius: 5px;
}
}
</style>
六.简单的父组件使用
<template>
<div class="parent-container">
<video-player
v-if="videoUrl"
:idIndex="9999"
:videoUrl="VideoUrl"
:streamType="streamType"
@playerCreated="handlePlayerCreated"
/>
</div>
</template>
<script>
// 识别视频流格式(只有视频流地址有后缀的才可以用哈,没有后缀的地址,格式可以让后端提供)
import { getType } from "@/utils/KingVideoType";
// 组件引入
import VideoPlayer from "@/components/WatermelonPlayer/VideoPlayer.vue";
export default {
name: "PlaybackVideoView",
components: { VideoPlayer },
data() {
return {
streamType: "m3u8",
videoUrl: null,
myPlayer: null,
}
},
methods: {
handlePlayerCreated(e) {
const { index, player } = e;
// 这是父组件拿到的子组件的实例对象(此时就可以想干啥干啥了), index多个分屏的时候用);
this.myPlayer = player;
},
}
}
</script>
七.此处是根据视频地址后缀识别视频格式的方法
// 文件位置在工程目录 src/utils/KingVideoType.js
export function getType(url) {
if (!url) {
return;
}
// 查找 URL 中最后一个点号之后的部分,即文件扩展名
const urlParts = url.split("/");
const fileName = urlParts.pop(); // 获取文件名(可能包含查询参数)
const fileExtension = fileName.split("?")[0].split(".").pop().toLowerCase(); // 去除查询参数并获取扩展名
let mimeType = "";
switch (fileExtension) {
case "flv":
mimeType = "flv";
break;
case "m3u8":
mimeType = "m3u8";
break;
case "mp4":
mimeType = "mp4";
break;
// default:
// mimeType = "flv";
// break;
// 可以在这里添加更多文件类型和对应的 MIME 类型
}
return mimeType;
}
总结:
在这次项目中,我尝试使用了**西瓜视频播放器插件**,整体体验非常出色。它不仅使用方便,而且功能强大,完美解决了之前项目中多格式视频兼容的痛点。通过支持 H.265 和 H.264 编码,以及 FLV、M3U8 和 MP4 等常见视频格式,西瓜视频播放器极大地简化了视频播放功能的开发流程,提升了项目的开发效率和用户体验。
在封装通用 Vue 组件的过程中,我深刻感受到西瓜视频播放器的灵活性和易用性。无论是直播流媒体还是点播视频,它都能轻松应对,为我的项目带来了诸多便利。当然,由于本人技术有限,代码实现中难免存在一些不足之处,欢迎大家留言或私信指正,共同探讨和改进。
最后,感谢大家的阅读和支持!看完觉得有点用的可以用您发财的小手帮忙点个赞,希望这篇文章能为大家在视频播放技术的探索中提供一些帮助和启发。未来,我也会继续学习和分享更多实用的技术内容,与大家共同进步!