目录
- 背景
- EasyPlayer.js H5播放器简单介绍
- EasyPlayer.js 简介
- EasyPlayer.js 功能说明:
- 配置属性
- 事件回调
- 方法
- 下载 EasyPlayer.js
- 引入使用
- 重写webpack
- 问题处理
- 证清白
- 最后
背景
项目中要使用 easyplayer-pro.js
播放视频,查了下资料,网上基本都是 在 Vue
项目中的使用,很少有在 React
项目中使用,即使找到一篇在 React
项目中使用的记录,那也是牛头不对马嘴,前面写的是 React
,后面就是 Vue
的写法,这不扯淡嘛。
所以在经过一番努力学习验证后,写上一篇日记来记录一下,便于自己也方便大家。
EasyPlayer.js H5播放器简单介绍
不愿意看这部分的可以跳过,直接从 【下载 EasyPlayer.js】 查看。
EasyPlayer.js 简介
EasyPlayer.js H5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方式,支持Windows、Linux、Android、iOS全平台终端的H5播放器,使用简单, 功能强大。
EasyPlayer.js 功能说明:
- 支持 MSE H264和H265硬解码;
- 支持 WebCodec H264和H265硬解码;
- 支持 WASM H264和H265硬解码/软解码;
- 支持 m3u8/HLS (H265/H265)播放;
- 支持 Mpeg4格式(H264)播放;
- 支持 HTTP-FLV/WS-FLV (H265/H265)播放;
- 支持 HTTP-FMP4/WS-FMP4 (H265/H265)播放;
- <支持 WEBRTC(easy支持H264/H265、其他流媒体支持H264)播放;
- 支持 裸流(H264/H265) 播放;
- 支持 直播和点播播放;
- 支持 点播多清晰度播放;
- 支持 全屏或比例显示;
- 支持 电子放大;
- 支持 水印(动态水印、幽灵水印);
- 支持 显示上一个视频最后一帧;
- 支持 播放器快照截图;
- 支持 视频录制(WebM格式(音频+视频)、Mp4格式(视频),Flv格式(音频+视频));
- 支持 超时、断网重连、异常暂停播放等
额外介绍:这个仅支持 Vue 和 普通引入使用。
配置属性
参数 | 说明 | 类型 | 默认值 |
---|---|---|---|
container | 播放器容器 | - | - |
decoder | wasm解码地址 | String | - |
isResize | 是否拉伸 | Boolean | true |
loadingText | 加载显示的文字 | String | 加载中 |
videoBuffer | 加载显设置最小缓冲时长,单位秒,播放器会自动消除延迟。示的文字 | Number | 1 |
hasAudio | 是否解析音频 | Boolean | true |
useMSE | MSE模式 | Boolean | fasle |
useWCS | WCS模式 | Boolean | fasle |
useSIMD | 强制使用wasm模式 | Boolean | false |
background | 视频封面图片 | String | - |
qualityConfig | 配置清晰 | Array | [‘普清’, ‘高清’, ‘超清’, ‘4K’, ‘8K’] |
defaultStreamQuality | 默认显示的清晰度,如果不设置,会显示第一个清晰度 | String | - |
isNotMute | 是否渲染音频 | Boolean | false |
recordType | 视频录制默认mp4格式 | String | mp4,flv |
playbackForwardMaxRateDecodeIFrame | 录像倍数 | Number | - |
debug | 控制台日志打印 | Boolean false | |
debugLevel | 打印日志级别默认warn | String | debug,warn |
事件回调
事件名 | 说明 |
---|---|
play | 播放事件 |
pause | 暂时事件 |
videoInfo | 视频信息 |
audioInfo | 音频信息 |
mute | 音频 |
error | 播放异常 |
kBps | 当前网速, 单位KB 每秒1次, |
recordEnd | 录制结束的事件 |
recordStart | 录制开始的事件 |
fullscreen | 当前是否全屏 |
streamQualityChange | 清晰度回调 |
playbackSeek | 录像时间轴跳转回调 |
playbackPreRateChange | 录像倍数的回调 |
currentPts | 监听当前渲染帧的时间戳(流里面的) |
方法
方法名 | 说明 | 参数 |
---|---|---|
play | 播放 | ‘url’ |
playback | 播放录像 | |
pause | 暂停播放 | |
isPause | 返回是否暂停中状态 | |
setBufferTime | 设置最大缓冲时长 1 | |
setVolume | 设置音量 | |
getVolume | 获取音量 | |
exitFullscreen | 退出全屏 | |
mute | 静音 | |
cancelMute | 取消静音 | |
isMute | 返回是否静音 | |
screenshot | 获取快照 | |
setFullscreen | 全屏(取消全屏)播放视频 | |
setStreamQuality | 设置分辨率必须是qualityConfig里面的数据 | |
forward | 设置录像倍数 | |
setPlaybackStartTime | 设置录像跳转时间/s | |
getVideoInfo | 获取视频信息 | |
getAudioInfo | 获取音频信息 | |
destroy | 关闭视频,释放底层资源 |
下载 EasyPlayer.js
按照下面的地址去下载下来,简单。
EasyPlayer.js 访问地址
引入使用
-
将下载的文件拷贝到 React 项目的 public 目录下
注意:不能拷贝到其他文件,只能在这里,有兴趣的同学也可以尝试一下其他地址
-
然后在
index.html
文件中引入easyplayer-pro.js
<!DOCTYPE html> <html lang="en"> <head> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"/> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=Edge" /> <title>你的爱豆</title> </head> <body> <!-- easyplayer-pro.js 文件 --> <script type="text/javascript" src="./js/easyplayer-pro.js"></script> <!-- react 挂载根节点 --> <div id="root"></div> </body> <script> // 将 EasyPlayerPro 挂载到 window 上,便于全局使用 window.EasyPlayerPro = EasyPlayerPro; </script> </html>
-
将下载的文件再次拷贝一份到需要使用的组件下
-
创建视频播放组件,并在组件中添加播放内容
import React, { useEffect, useImperativeHandle, useRef } from "react";
import { Button, Icon, Modal } from "antd";
import { useState } from "react";
// 根据自己的需要定义样式
import './index.less';
// 调用接口
import { getVideoManagerPlay } from "server/video.api";
const _myWindow:any = window;
const EasyPlayerVideoDialog = ({onRef}:any) => {
const easyPlayerRef:any = useRef(null);
const [open, setOpen] = useState<boolean>(false);
const [videoUrl, setVideoUrl] = useState<string>('');
useImperativeHandle(onRef, () => ({
showModal: (record:any) => {
const {deviceId} = record;
getVideoUrlFn(deviceId);
setOpen(true);
}
}));
// 获取播放视频地址
const getVideoUrlFn = async (deviceId:string|undefined) => {
if (!deviceId) return;
try {
const params = {
deviceId,
};
const res = await getVideoManagerPlay(params);
const {code, data}:any = res;
if (code === 200 && data && typeof data === 'string' && data.length > 0) {
setVideoUrl(data);
} else {
setVideoUrl('');
}
} catch (error) {
setVideoUrl('');
}
};
useEffect(() => {
if (!videoUrl) return;
playCreate();
}, [videoUrl])
const playCreate = () => {
const EasyPlayerPro = _myWindow?.['EasyPlayerPro'];
if (EasyPlayerPro) {
// 可以根据自己的需要自行配置
const easyplayer = new EasyPlayerPro({
container: document.getElementById('player_box1'),
// 这里需要注意,根据自己打包需求设定
decoder: process.env.NODE_ENV === 'development' ? './js/decoder-pro.js' : './static/js/easyPlayerPro/decoder-pro.js', // wasm解码地址
videoBuffer: 2, // 加载显设置最小缓冲时长,单位秒,播放器会自动消除延迟。
isResize: false, // 是否拉伸
text: "",
loadingText: "加载中",
// debug: true,
// debugLevel: 'debug',
useMSE: true, // MSE模式
useWCS: true, // WCS模式
isMulti: true,
useSIMD: false, // 强制使用wasm模式
hasAudio: true, // 是否解析音频
showBandwidth: false, // 显示网速
showPerformance: false,
operateBtns: {
fullscreen: true,
screenshot: true,
play: true,
audio: true,
record: true,
quality: true,
performance: true,
},
watermarkConfig: {
text: {
content: ''
},
right: 10,
top: 10
},
playbackForwardMaxRateDecodeIFrame: 1,
isWebrtcForOthers:true,
demuxUseWorker: true,
supportHls265:true,
});
// 一些监听事件
easyplayer.on("fullscreen", function (flag:any) {
console.log('is fullscreen', flag)
})
easyplayer.on('playbackPreRateChange', (rate:any) => {
easyplayer.forward(rate);
})
easyplayer.on('playbackSeek', (data:any) => {
easyplayer.setPlaybackStartTime(data.ts);
})
if (easyPlayerRef.current) easyPlayerRef.current = null;
easyPlayerRef.current = easyplayer;
// 开启自动播放
easyplayer.play(videoUrl);
}
}
// 隐藏弹框重置数据
const onCancelFn = () => {
easyPlayerRef.current?.pause();
easyPlayerRef.current?.destroy();
easyPlayerRef.current = null;
setVideoUrl('');
setOpen(false);
};
return (
<Modal
className="easyPlayerModal"
// title="视频监控"
getContainer={false}
visible={open}
footer={null}
width={1200}
centered={true}
maskClosable={true}
onCancel={onCancelFn}
>
<div className="easy-player-wrp">
<div className="easy-player-box" id="player_box1"/>
</div>
</Modal>
)
};
export default EasyPlayerVideoDialog;
重写webpack
因为我项目中使用 customize-cra
插件,根据插件要求,在项目根目录创建 config-overrides.js
文件重写 webpack
配置。
点击此处可以查看 customize-cra 插件 的所有api及相关解释。
// 引入插件 customize-cra
const {
override,
fixBabelImports,
addLessLoader,
addWebpackPlugin,
addWebpackAlias,
disableEsLint,
setWebpackOptimizationSplitChunks,
useBabelRc,
addBundleVisualizer,
adjustWorkbox,
overrideDevServer,
} = require('customize-cra');
// 引入css分离插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 下载拷贝文件插件
const CopyWebpackPlugin = require('copy-webpack-plugin');
// 输出文件配置
const appBuildOutput = () => (config) => {
// 可以根据环境自定义配置输出文件
switch(process.env.NODE_ENV){
case 'development':
break;
case 'product':
// 关闭sourceMap
config.devtool = false;
// 更改生产模式输出的文件名
// main.js 不带hash
// 按需引入的文件带有hash
config.output = {
...config.output,
path: paths.appBuild,
filename: 'static/js/[name].js',
chunkFilename: 'static/js/[name].[contenthash:8].chunk.js',
};
config.optimization.runtimeChunk = false;
// 针对 css 拆包
config.plugins.forEach((item, index, self) => {
if (item instanceof MiniCssExtractPlugin) {
self[index] = new MiniCssExtractPlugin({
filename: 'static/css/[name].css',
chunkFilename: 'static/css/[name].[contenthash:4].chunk.css',
ignoreOrder: true,
});
}
});
// 拷贝 easyPlayer-pro.js到指定目录
config.plugins.push(
new CopyWebpackPlugin(
[
{
from: 'public/js/*.js', // 指定public目录下js文件夹中的所有.js文件
to: 'static/js/easyPlayerPro/[name].[ext]', // 指定目标路径,[name]和[ext]是文件名和扩展名的占位符
},
]
)
);
break;
// 其他...
}
}
module.exports = {
webpack: override(
// 其他配置...
appBuildOutput(),
),
devServer: overrideDevServer((config) => {
return {
...config
// 其他配置...
}
})
}
到这里就结束了吗,就能够正常运行了吗,不一定,请接着往下看。
问题处理
将打包好的文件放到线上测试环境部署,一运行就报如下错误,这是个啥呀,点击进去一看,都到人家的插件里面去了,那铁定不能去改啊,对吧,那就是我们自身的代码出了问题,继续排查排查。
经过不断地努力排除,最终定位到 easyPlayer-pro.js
解码视频还需要一个二进制的文件,这个文件没有拷贝进去,所以继续如下操作即可。
经过查找,缺失的这个二进制文件就是以 *.wasm
结尾的文件,问题找到了,那么只要将这个文件在打包的时候拷贝进去就好,所以继续修改我们的 config-overrides.js
文件。
// 其他...
// 拷贝 easyPlayer-pro.js到指定目录
config.plugins.push(
new CopyWebpackPlugin(
[
// ********** 原来的 **********
{
from: 'public/js/*.js', // 指定public目录下js文件夹中的所有.js文件
to: 'static/js/easyPlayerPro/[name].[ext]', // 指定目标路径,[name]和[ext]是文件名和扩展名的占位符
},
// ********** 重要 **********
// 新增:一定要拷贝这里的 *.wasm 格式的文件,否则播放视频一定报错
{
from: 'public/js/*.wasm', // 指定public目录下js文件夹中的所有.wasm文件
to: 'static/js/easyPlayerPro/[name].[ext]', // 指定目标路径,[name]和[ext]是文件名和扩展名的占位符
}
]
)
);
// 其他...
证清白
因项目保密,就只展示这么一部分。
最后
关于在 React
项目中引用 EasyPlayer.js
到这里就结束了,希望能够对有需要的朋友一些帮助。
如果这篇文章对你还有点儿作用,麻烦点赞,搜藏,如果有哪里不对,可以评论,私信。