本文记录一下最近在直播组关于在移动端视频播放器的笔记。
分别使用了原生video标签,video.js,flv.js, TC player几个来实现在移动端各设备间和PC端 视频、直播播放的兼容适配。
原生video标签
原生的video标签中,事件等各个方面属性在不同设备、不同浏览器下会出现不兼容情况。
使用原生video标签,在安卓和I0S11以下机型中,autoplay不支持;解决办法:
- 使用静音【muted】播放
- 引导用户点击后播放<–>推荐
在微信内核和一些移动端浏览器中,播放视频会默认全屏;需添加以下属性阻止全屏:
x5-video-orientation="portraint"
webkit-playsinline='true'
playsinline='true'
x-webkit-airplay='true'
x5-video-player-type='h5'
x5-video-player-fullscreen='true'
x5-video-ignore-metadata='true'
以上属性,经测试后在微信内是如期的;但在小米浏览器上视频还是全屏播放。
关于更多各个设备下video标签属性的差异,非常推荐这位前辈的文章: 移动端HTML video视频播放优化实践
以下为原生video标签示例,支持暂停播放,是否缓冲到可播放状态
step1: 在组件中声明video
<template>
<div>
<div class="video">
<video :src="infoData.imagesUrls[0].url" :poster="infoData.imagesUrls[0].thumbUrl" ref="video"
x5-video-orientation="portraint" @timeupdate="handleTimeupdate"
webkit-playsinline='true' playsinline='true' x-webkit-airplay='true'
x5-video-player-type='h5' x5-video-player-fullscreen='true' x5-video-ignore-metadata='true'
id="video" loop preload="auto" :playOrPause="playOrPause">
您的设备不支持!
</video>
</div>
<div class="playOrPause">
<img class="video_play" @click="pauseVideo()" v-show="!playOrPause" src="http://lztimg.oss-cn-qingdao.aliyuncs.com/images/20210203/share03.png"/>
</div>
</div>
</template>
step2:设置播放器和一些事件处理
<script>
mounted() {
this.$video = this.$refs.video;
/**
* 定时获取当前视频长度,获取到后获取当前视频已经下载多少了
* 当当前视频下载量大于等于当前视频长度时去除加载动画;待用户点击播放
* 以下定时器中,在非IOS中使用
* */
this.$video.setAttribute('autoplay', true)
let getVideoLengthTimer = setInterval(()=>{
let duration = this.$video.duration;
if(!isNaN(duration)){
let end = this.getVideoEnd();
if(end <= duration) {
return
}
// 去除加载动画和遮罩
clearInterval(getVideoLengthTimer)
}else{
// 去除加载动画和遮罩
clearInterval(getVideoLengthTimer)
}
},1000)
}
methods: {
// 暂停/开始视频
pauseVideo(){
try {
let video = document.getElementById('video');
if (this.playOrPause) {
video.pause();
} else {
video.play();
video.pause();
setTimeout(() => {
video.play();
}, 100);
}
this.playOrPause = !this.playOrPause;
// this.getVideoDuration();
} catch (e) {
alert(e);
}
},
// 获取当前视频已经加载多少了
getVideoEnd(){ // video:video标签对象
let end = 0
try {
if(this.$video.buffered.length>0){
end = this.$video.buffered.end(0) || 0
end = parseInt(end * 1000 + 1) / 1000
}
} catch(e) {
console.log(e)
}
return end
},
// IOS下会自动播放,在自动播放后清除遮罩
handleTimeupdate(){
if(!this.$video.paused){
this.playOrPause = true
}
let mask = document.getElementById('mask');
mask.style.opacity = 0;
mask.style.zIndex = -99;
},
}
</script>
TCplayer Lite 在vue中使用笔记
腾讯出品:TCPlayerLite 文档
首先先说明 此播放器不支持在移动端播放.FLV格式视频。
listener
可以监听到video各个时间段的事件;并针对特别事件做处理
step1:引入
// 在index.html头文件引入
<script src="https://imgcache.qq.com/open/qcloud/video/vcplayer/TcPlayer-2.3.3.js" charset="utf-8"></script>
step2: 在组件中创建容器
<template>
<div class="video" >
<div id="id_test_video" style="width:100%; height:100vh;"></div>
</div>
</template>
step3: 设置播放器
<script>
export default {
mounted() {
var self = this;
var player = new TcPlayer('id_test_video', {
"mp4": "//vjs.zencdn.net/v/oceans.mp4", //请替换成实际可用的播放地址
"autoplay" : true, //iOS 下 safari 浏览器,以及大部分移动端浏览器是不开放视频自动播放这个能力的
"poster" : "http://www.test.com/myimage.jpg",
"width" : '100vw',//视频的显示宽度,请尽量使用视频分辨率宽度
"height" : '100vh', //视频的显示高度,请尽量使用视频分辨率高度
"live": false, // 是否直播
// "controls": "none" // 是否显示控制条
listener: (msg) => { // 监听播放器事件
console.log(msg.type)
// progress timeupdate
if(msg.type === 'progress'){
self.loading = true
}
if(msg.type === 'timeupdate'){
self.loading = false;
}
}
});
// 给video标签添加,在各个设备下不自动全屏显示
let video = document.getElementsByTagName('video')[0];
video.setAttribute("x5-video-orientation", "portraint")
video.setAttribute("webkit-playsinline", "true")
video.setAttribute("playsinline", "true")
video.setAttribute("x-webkit-airplay", "true")
video.setAttribute("x5-video-ignore-metadata", "true")
video.setAttribute("x5-video-player-fullscreen", "true")
video.setAttribute("x5-video-player-type", "h5")
}
}
</script>
此时,播放器可以使用了
step4: 修改默认样式
// 视频播放区域
.vcp-player video{
width: 100vw;
height: auto;
min-height: 100vh;
}
#id_test_video{
display: flex;
align-items: center;
}
// 视频封面
.vcp-poster img{
width: 100%;
//height: 100%;
}
.vcp-bigplay{
height: 100%;
}
// 加载动画
.vcp-loading{
border: none;
background: url("https://lztimg.oss-cn-qingdao.aliyuncs.com/ips/images/20210201/loading.gif") center no-repeat;
width: 1.6rem;
height: 1rem;
background-size: 60%;
margin-left: -0.8rem;
}
.vcp-loading:before{
content: "";
display: inline;
}
// 全屏
.vcp-fullscreen-toggle{
display: none;
}
// 播放/暂停 按钮
.vcp-playtoggle{
position: absolute;
top: -50vh;
left: 50%;
background: url("http://lztimg.oss-cn-qingdao.aliyuncs.com/images/20210203/share03.png") center no-repeat;
width: 1.6rem;
height: 1.6rem;
margin-left: -0.8rem;
}
// 进度条
.vcp-slider{
background-color: rgba(89,83,84,1);
}
.vcp-slider .vcp-slider-track{
background-color: #fff;
}
// 控制条背景
.vcp-panel-bg{
background: none;
}
// 时间显示
.vcp-timelabel{
// display: none;
text-align: center;
width: 100%;
font-size: 0.28rem;
line-height: 1.8;
padding: 0;
}
video.js + flv.js 播放.flv直播数据
因为IOS不支持MSE,所以,FLV视频不能在IOS下播放
参考:
给video绑定ended
事件,当直播流结束时会触发(不要循环播放:loop:false);
step1:引入
// 在index.html头文件引入
<link href="https://unpkg.com/video.js/dist/video-js.css" rel="stylesheet">
<script src="https://unpkg.com/video.js/dist/video.min.js"></script>
<script src="https://unpkg.com/flv.js/dist/flv.min.js"></script>
<script src="https://unpkg.com/videojs-flvjs/dist/videojs-flvjs.min.js"></script>
step2: 在组件中创建容器
<template>
<div class="video">
<video id="videojs-flvjs-player" class="video-js liveVideo vjs-default-skin vjs-big-play-centered" width="100vw" height="100vh"
x5-video-orientation="portraint" ref="videojs"
webkit-playsinline='true' playsinline='true' x-webkit-airplay='true'
x5-video-player-type='h5' x5-video-player-fullscreen='true' x5-video-ignore-metadata='true'>
</video>
</div>
</template>
step3: 设置播放器
<script>
export default {
mounted() {
var flvUrl = this.infoData.room.mixedPlayURL;
var player = videojs('videojs-flvjs-player', {
techOrder: ['html5', 'flvjs'],
flvjs: {
mediaDataSource: {
isLive: true,
cors: true,
withCredentials: false,
},
},
sources: [{
src: flvUrl,
type: 'video/mp4'
}],
autoplay: true,
loop: false, // 需要捕获直播结束事件,一定要禁止循环播放
controls: true,
preload: "auto",
poster: this.infoData.room.liveCover
}, function onPlayerReady() {
console.log('player ready')
player.on('error', (err) => {
console.log('first source load fail')
player.src({
src: flvUrl,
type: 'video/x-flv'
});
player.ready(function () {
console.log('player ready')
player.load();
player.play();
});
})
// 绑定直播结束事件
player.on('ended', () => {
console.log("直播结束")
})
// 绑定加载到可以播放的事件
player.on("canplaythrough", function () {
console.log("视频源数据加载完成")
})
});
},
}
</script>
此时,播放器可以使用了
step4: 修改默认样式
<style>
/*播放按钮*/
.liveVideo .vjs-big-play-button {
background: url("http://lztimg.oss-cn-qingdao.aliyuncs.com/images/20210203/share03.png") center no-repeat;
height: 2.2em;
border: none;
}
/*去掉自带的播放按钮样式*/
.liveVideo .vjs-big-play-button .vjs-icon-placeholder:before {
content: "";
}
/*隐藏控制条*/
.liveVideo .vjs-control-bar {
display: none !important;
}
/*更改加载动画*/
.liveVideo .vjs-loading-spinner {
border: none;
background: url("https://lztimg.oss-cn-qingdao.aliyuncs.com/ips/images/20210201/loading.gif") center no-repeat;
width: 1.6rem;
height: 1rem;
background-size: 60%;
margin-left: -0.8rem;
}
/*去除原生加载动画*/
.liveVideo .vjs-loading-spinner:before,
.liveVideo .vjs-loading-spinner:after {
border: none;
animation: none !important;
}
</style>
vue中使用flv.js播放直播数据(pc)
在移动端直播等视频播放需求完成后,产品又让在后台管理系统中播放当前所有的直播画面,故记录下:不涉及兼容性,只用
flv.js
来实现
下载依赖
npm i flv.js S
引入依赖
在需要的组件内引入即可,无需全局引入
import flvjs from 'flv.js'
定义
video
标签位置在
<template>
中定义video标签<video id="videoElement" ref="videoElement" width="100%" height="100%"></video>
创建加载播放直播
在script事件中创建并播放直播
let url="http://xxx.com/live/room_123.flv"; if (flvjs.isSupported()) { let videoElement = document.getElementById("videoElement"); this.flvPlayer = flvjs.createPlayer({ type: "flv", isLive: true, hasAudio: true, url }) this.flvPlayer.attachMediaElement(videoElement) this.flvPlayer.load() }
销毁直播组件
关闭页面时,或切换画面的话建议先销毁播放组件
if (this.flvPlayer) { this.flvPlayer.pause(); this.flvPlayer.unload(); this.flvPlayer.detachMediaElement(); this.flvPlayer.destroy(); this.flvPlayer = null; }
附:自定义弹窗
自定义弹窗组件代码:
<template>
<div id='customDialog'>
<div class="warrp"></div>
<div class="main">
<slot></slot>
</div>
</div>
</template>
<script>
export default {
name: 'customDialog',
created() {
let body = document.getElementsByTagName('body')[0]
body.style.height = '100vh'
body.style.overflow = 'hidden'
},
destroyed() {
let body = document.getElementsByTagName('body')[0]
body.style.height = 'auto'
body.style.overflow = 'auto'
}
}
</script>
<style scoped lang="scss">
#customDialog{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
z-index: 3000;
.warrp{
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
background-color: rgba(0,0,0,.6);
z-index: 3001;
}
.main{
z-index: 3002;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100vw;
height: 100vh;
transition: all 1s ease-out;
}
}
</style>
使用:
<custonDialog v-if="showLive">
<div class="view">
<button @click="showLive = false" class="closeBtn">点我关闭弹窗</button>
</div>
</custonDialog>
前端苦设备适配久矣!
参考文章:
很多未尽之处,在日后想起便会更新~
撒花,散会~