前言:
由于自己的项目中使用了基于 video.js 的 vue-video-player 插件;所以研究了不仅限于 vue-video-player 的行为;还包括视频基础, 插件 video.js 以及 原生 标签在移动端(android及ios)的表现;
1.视频基础:
2.项目中应用:
两种方式:
2.1 在HTML中用 data-setup
<video data-setup='{ "autoplay": false, "preload": "auto" }'...>
2.2 video.js 中用 options 传参
// videojs options
options: {
// muted: true, // 是否静音播放
autoplay: false, // 播放器准备好之后是否自动播放
loop: false, // 循环播放
liveui: true,
preload: 'metautoadata',
language: 'en',
playbackRates: [0.5, 1.0, 1.5, 2.0], // 播放速度
aspectRatio: '16:9', // 视频适应比率
fluid: true, // 播放器缩放以适合其容器
bigPlayButton: true, // 视频中央大播放按钮
// flash: {
// swf: 'video-js-fixed.swf'
// },
controlBar:{ //设置是否显示该组件
'currentTimeDisplay': true, // 当前时间
'timeDivider':true, // 时分器
'durationDisplay':true, // 持续时间显示
'remainingTimeDisplay':true, // 剩余时间显示
'volumeMenuButton': {
inline: true,//设置音量bar为水平
vertical: false//设置音量bar为竖直
}
},
// 视频流资源集
sources: [{
type: "video/mp4",
src: 'https://xxx.com/video/工伤保险广告.mp4'
}],
notSupportedMessage: '此视频暂无法播放,请稍后再试' // 允许覆盖Video.js无法播放媒体源时显示的默认信息
// 播放之前的视频画面
poster: 'https://xxx.com/upload/82.png',
// 控制按钮显示顺序(组件顺序)
// children: ['playToggle', 'volumeMenuButton', 'currentTimeDisplay', 'timeDivider', 'durationDisplay', 'progressControl', 'liveDisplay', 'remainingTimeDisplay', 'customControlSpacer', 'playbackRateMenuButton', 'chaptersButton', 'subtitlesButton', 'captionsButton', 'fullscreenToggle']
},
2.3 vue 中的支持:
vue中引用基于 video.js 的 vue-video-player 插件
// 局部注册使用的方式
<template>
<video-player class="video-player-box"
ref="videoPlayer"
:options="playerOptions"
:playsinline="true"
customEventName="customstatechangedeventname"
@play="onPlayerPlay($event)"
@pause="onPlayerPause($event)"
@ended="onPlayerEnded($event)"
@waiting="onPlayerWaiting($event)"
@playing="onPlayerPlaying($event)"
@loadeddata="onPlayerLoadeddata($event)"
@timeupdate="onPlayerTimeupdate($event)"
@canplay="onPlayerCanplay($event)"
@canplaythrough="onPlayerCanplaythrough($event)"
@statechanged="playerStateChanged($event)"
@ready="playerReadied">
</video-player>
</template>
<script>
import 'video.js/dist/video-js.css'
import { videoPlayer } from 'vue-video-player'
export default {
components: { videoPlayer },
data() {
return {
playerOptions: {
// videojs options
muted: true,
language: 'en',
playbackRates: [0.5, 1.0, 1.5, 2.0],
sources: [{
type: "video/mp4",
src: "http://cdn.moji.com/websrc/video/spring20200311.mp4"
}],
poster: "/static/images/author.jpg",
}
}
},
mounted() {
console.log('this is current player instance object', this.player)
},
computed: {
player() {
return this.$refs.videoPlayer.player
}
},
methods: {
// listen event
onPlayerPlay(player) {
// console.log('player play!', player)
this.$refs.videoPlayer.player.play()
},
onPlayerPause(player) {
// console.log('player pause!', player)
},
// ...player event
// or listen state event
playerStateChanged(playerCurrentState) {
// console.log('player current update state', playerCurrentState)
},
// player is ready
playerReadied(player) {
console.log('the player is readied', player)
player.play()
// you can use it to do something...
// player.[methods]
}
}
}
</script>
2.4 vue-video-player 的插件
Player
PosterImage //默认封面
TextTrackDisplay
LoadingSpinner
BigPlayButton //大播放按钮
ControlBar // 控制条
PlayToggle //播放暂停
FullscreenToggle //全屏
CurrentTimeDisplay //当前播放时间
TimeDivider
DurationDisplay
RemainingTimeDisplay //剩余播放时间
ProgressControl //时间轴
SeekBar
LoadProgressBar
PlayProgressBar
SeekHandle
VolumeControl //音量控制
VolumeBar
VolumeLevel
VolumeHandle
PlaybackRateMenuButton //播放速率
》》》更详细的介绍可以查看文末的4.0参考文档中给出的官方资料;
3. 开始各种踩坑:
3.1 The play() request was interrupted by a call to pause()
播放器在执行了play()方法后立即执行pause()所导致;
解决方法:在执行play()的时候加定时器;
setTimeout(() => {
$video.play();
}, 10 );
// 此方法本人亲测了没有啥效果,但还是记录在此吧....
// 最后我是改变了调用play()的时机,采用了 在 @ready 回调中去调用已经实例化了的 player 实例来执行 player.play() 就不报错了。
3.2 autoPlay 自动播放
方案:
要解决iOS上的自动播放问题,请不要使用videojs 选项自动播放视频。
不起作用的方式:
(1)
<video id="my-video-id" autoplay></video>
(2)
videojs('my-video-id', {
"autoplay": true
});
而是等待视频对象加载,然后触发播放操作:
videojs('my-video-id').ready(function() {
this.play();
});
或者:
SPA中设置
// player is ready 初始化
playerReadied(player) {
// 主动调用视频播放 API
console.log('---readied----')
player.play() // 主动调用播放api
console.log('---执行播放----')
},
A、video 视频播放触发条件:
1、touch自chromeM55版本之后从手势事件中移除;视频首次播放无法在touch start中触发;
2、touch end跟click手势事件存在一定的时间重叠,视频的首次播放可能被触发,但不可靠;
3、视频的首次播放可以在click中触发;
videoBtn3.addEventListener('click', function (evt) {
video.play();
})
4、视频的首次播放无法在timer响应中触发;
videoBtn4.addEventListener('touchstart', function (evt) {
setTimeout(function(){
video.play();
},1000);
})
5、视频的首次播放无法在promise回调中触发;
videoBtn5.addEventListener('touchstart', function (evt) {
fetch('./video_gesture.html')
.then(function(response) {
video.play();
})
.catch(function(myBlob) {
video.play();
});
})
B、其他导致的因素:
1、chrome6以及更高的版本不允许媒体自动播放;
2、safari 阻止自动播放视频。opera 阻止autoplay;
3、出于用户体验,节省流量的考虑,移动端禁止自动播放;
4、视频文件太大,加载时间过长或错误;
C、总结:
1.经过以上所有策略的调整之后,IOS 基本可以实现自动播放,但是要设置静音,即:没音频轨道,或者设置了muted=true属性。
2.安卓的话,只有部分机型可以自动播放。而且不能模拟自动播放,一定要有用户行为(点击播放按钮)才可以触发播放,也就有用户的主动行为才是稳定的。
3.3 多端播放行为一致性处理
<video id="theVideo"
class="video-player"
preload="auto"
src="http://xxx"
type="video/mp4"
width="100%"
webkit-playsinline="true"
playsinline="true"
x5-video-player-type="h5"
x5-video-player-fullscreen="portraint"
x-webkit-airplay="true"
x5-playsinline=""></video>
为了适配 iOS 与安卓系统,最后四个属性起到关键作用;
webkit-playsinline="true";playsinline="true" 作用与 iOS 系统,使用 playsinline 让用户无法全屏播放视频,不带 control 属性,去掉了系统自带的控件,方便为用户提供自己编写的播放器控件,使得不同系统表现一致。
x5- 开头的两个属性,作用于安卓系统,因为安卓系统的微信浏览器内核为 X5,
x5-playsinline="";x5-video-player-type="h5";x5-video-player-fullscreen="landspace" 是两个比较通用的配置,让视频以横屏的同层方式播放。
3.4 视频编码(不是格式)导致的部分浏览器播放有声音无画面的问题
问题描述:
进度条能移动有声音但是没有图像。百度了下,了解相关知识点;
原理:
目前video标签只支持MP4,WebMail,Ogg格式的视频;
各大浏览器对三种视频格式的兼容性:
格式 | IE | Firefox | Opera | Chrome | Safari |
---|---|---|---|---|---|
MPEG 4 | 9.0+ | No | No | 5.0+ | 3.0+ |
WebM | No | 4.0+ | 10.6+ | 6.0+ | No |
Ogg | No | 3.5+ | 10.5+ | 5.0+ | No |
MP4 = MPEG4 文件使用 H264 视频编解码器和AAC音频编解码器
WebM = WebM 文件使用 VP8 视频编解码器和 Vorbis 音频编解码器
Ogg = Ogg 文件使用 Theora 视频编解码器和 Vorbis音频编解码器
其中 MP4 有3种编码,MPEG4(DivX)、MPEG4(Xvid)、AVC(H264);但只有H264才是公认的MP4标准编码。
解决方案:
下载 “格式工厂”,将输出配置里面的编码改为 AVC(H264) ,导出视频,重新上传服务端,搞定!!!;
3.5 视频资源无法正常加载
问题:
The media could not be loaded, either because the server or network failed or because the format is not supported
排查:
在排查这个问题的时候可以按照以下步骤依次排除原因:
1、核实video的url地址是否有误;
2、核实用户上网地区(有部分地区可能有限制,比如新疆、西藏);
3、核实用户的上网环境,是家庭网络还是公司网络,如果是家庭网络,让用户重启路由器试试。如果是公司网络,让用户问下公司网管是否禁掉相关协议;
4、如无法确定所连网络是否禁止相关协议,可以建议用户用电脑连接手机热点后再尝试播放,如果连接手机热点后能播放,那一定是相关视频协议被禁掉了;
5、MP4视频格式编码问题导致的,见 2.4。
3.6 minio中的视频无法在ios Safari 中播放
场景:
前端上传 MP4(H264(AVC编码)视频文件,服务端采用分布式存储 minio,并用 Nginx 代理转发服务接口,iOS客户端通过 URL 无法播放该视频文件,安卓端、PC端各浏览器均播放正常;
原因分析:
- safari 不支持整个文件流,服务器请求必须支持分段请求(也就是断点续传);
- safari 对于文件流的请求需要包含一个请求头(Request) Range, 和一个响应头(Response)Content-Range,通过我们的 Nginx 代理后没有返回 Range 的相关信息。
解决方案:
(1)首先配置 Nginx 支持 Range 标签返回,添加 add_header Accept-Ranges bytes这一行即可:
server {
listen 80;
location ~xxx{
add_header Accept-Ranges bytes;
}
(2)再将请求的 Response 里设置 Content-Range 返回。
4.参考文档:
vue-video-player文档: https://github.com/surmon-china/vue-video-player
video.js 文档: docs.videojs.com/tutorial-op…
腾讯X5内核视频行为官方解释: x5.tencent.com/tbs/guide/v…
video.js中遇到的问题: www.cnblogs.com/loveamyfore…
关于 MediaSource: https://developer.mozilla.org/zh-CN/docs/Web/API/MediaSource