- vue-video-player github地址:https://github.com/surmon-china/vue-video-player
- 官方案例:https://github.surmon.me/vue-video-player/
- 官方案例对应代码地址:https://github.com/surmon-china/vue-video-player/tree/master/examples
最近接触了流媒体播放的问题,以往做的视频播放都是基于mp4格式文件播放,用的是vue-video-player插件,这次研究了下像直播流媒体等的播放设置,碰见了不少坑,下面来总结一下
1、普通视频播放
- npm install vue-video-player --save // 安装依赖
- 一般在PC端设置了autoplay属性都可以自动播放
<template>
<div class="item physical-video">
<div class="player">
<video-player class="vjs-custom-skin"
ref="videoPlayer"
:options="playerOptions"
:playsinline="true"
>
</video-player>
</div>
</div>
</template>
<script>
export default {
data() {
return {
playerOptions: {
height: '360',
autoplay: true,
muted: true,
language: 'en',
playbackRates: [0.7, 1.0, 1.5, 2.0],
sources: [{
type: "video/mp4",
src: "http://vjs.zencdn.net/v/oceans.mp4",
}],
poster: "https://surmon-china.github.io/vue-quill-editor/static/images/surmon-1.jpg",
}
}
}
}
</script>
<style scoped>
.physical-video{
width: 100%;
height: 100vh;
}
</style>
<style>
.physical-video .video-js.vjs-custom-skin {
height: 100vh;
}
.physical-video .video-js.vjs-custom-skin .vjs-control-bar {
height: 90px;
}
.physical-video .video-js.vjs-custom-skin .vjs-control {
width: 4em!important;
}
.physical-video .video-js .vjs-time-control,.physical-video .video-js.vjs-custom-skin .vjs-control-bar .vjs-playback-rate .vjs-playback-rate-value {
font-size: 2em!important;
line-height: 3em!important;
}
.physical-video .video-js .vjs-control:before {
height: 50px;
font-size: 4em;
}
</style>
- 设置了自动播放,Chrome和Safari的PC端浏览器播放都可以自动播放
- iphone 手机上在微信端及Safari浏览器访问,无法自动播放
- 至于iphone上无法自动播放视频的原因,也查了很多材料,iOS Safari 不允许自动播放视频,只能通过用户主动触发的交互才能播放,就好比H5页面中的按钮不能主动触发事件一样,只能是用户主动操作才可以,这大概也是出于一种安全策略考虑,但是为什么别人的 iPhone 使用微信打开一个 H5 却能自动播放音频?
- 关于这一点参考了这篇文章的说法
这里说到一个被腾讯和谐掉的接口 WeixinJSBridge,这里就不讲为什么 WeixinJSBridge 接口会被和谐掉,反正都被和谐掉了,以后也不建议在项目中使用.但是腾讯又没把 WeixinJSBridge 这个 API 所有功能都和谐掉,相反,有好几个功能还是相当有用的,可以正常使用.有兴趣的可以看看<<微信JSAPI>>.接下来我们就需要用到尚未被腾讯和谐掉的 WeixinJSBridge 接口来实现在 iPhone 手机微信端 <audio>
自动播放.
在微信内置浏览器中有一个内置的 JS 对象,这个内置的 JS 对象就是 WeixinJSBridge. WeixinJSBridge 并不是 WebView 一打开就有了,客户端需要初始化这个对象,当这个对象准备好的时候,客户端会抛出事件 "WeixinJSBridgeReady"。因此,在调用 WeixinJSBridge 相关 api 时,需要做好 WeixinJSBridge 存在与否的判断,修改后代码如下
<template>
<div class="item physical-video">
<div class="player">
<video-player class="vjs-custom-skin"
ref="videoPlayer"
:options="playerOptions"
:playsinline="true"
>
</video-player>
</div>
</div>
</template>
<script>
export default {
data() {
return {
// videojs options
playerOptions: {
height: '360',
autoplay: true,
muted: true,
language: 'en',
playbackRates: [0.7, 1.0, 1.5, 2.0],
sources: [{
type: "video/mp4",
src: "http://vjs.zencdn.net/v/oceans.mp4",
}],
poster: "https://surmon-china.github.io/vue-quill-editor/static/images/surmon-1.jpg",
}
}
},
mounted() {
let self = this
//调用 <audio> 元素提供的方法 play()
this.$refs.videoPlayer.player.play()
//判斷 WeixinJSBridge 是否存在
if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
self.$refs.videoPlayer.player.play()
} else {
//監聽客户端抛出事件"WeixinJSBridgeReady"
if (document.addEventListener) {
document.addEventListener("WeixinJSBridgeReady", function(){
self.$refs.videoPlayer.player.play()
}, false);
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady", function(){
self.$refs.videoPlayer.player.play()
});
document.attachEvent("onWeixinJSBridgeReady", function(){
self.$refs.videoPlayer.player.play()
});
}
}
//voiceStatu用來記録狀態,使 touchstart 事件只能觸發一次有效,避免與 click 事件衝突
var voiceStatu = true;
//监听 touchstart 事件进而调用 <audio> 元素提供的 play() 方法播放音频
document.addEventListener("touchstart",function(e){
if(voiceStatu){
self.$refs.videoPlayer.player.play()
voiceStatu = false;
}
}, false);
},
computed: {
player() {
return this.$refs.videoPlayer.player
}
}
}
</script>
<style scoped>
.physical-video{
width: 100%;
height: 100vh;
}
</style>
<style>
.physical-video .video-js.vjs-custom-skin {
height: 100vh;
}
.physical-video .video-js.vjs-custom-skin .vjs-control-bar {
height: 90px;
}
.physical-video .video-js.vjs-custom-skin .vjs-control {
width: 4em!important;
}
.physical-video .video-js .vjs-time-control,.physical-video .video-js.vjs-custom-skin .vjs-control-bar .vjs-playback-rate .vjs-playback-rate-value {
font-size: 2em!important;
line-height: 3em!important;
}
.physical-video .video-js .vjs-control:before {
height: 50px;
font-size: 4em;
}
</style>
- 再次使用微信打开链接就可以自动播放了
2、流媒体自动播放设置
- 自动播放设置和上方普通视频一样,在微信中也能自动播放
<template>
<div class="item physical-video">
<div class="player">
<video-player
class="vjs-custom-skin"
ref="videoPlayer"
:options="playerOptions"
@ready="playerReadied">
</video-player>
</div>
</div>
</template>
<script>
require('videojs-contrib-hls/dist/videojs-contrib-hls.js')
export default {
data() {
return {
playerOptions: {
// videojs and plugin options
height: '360',
autoplay: true,
muted: true,
sources: [{
withCredentials: false,
type: "application/x-mpegURL",
src: "https://logos-channel.scaleengine.net/logos-channel/live/biblescreen-ad-free/playlist.m3u8"
}],
controlBar: {
timeDivider: false,
durationDisplay: false
},
flash: { hls: { withCredentials: false }},
html5: { hls: { withCredentials: false }},
poster: "https://surmon-china.github.io/vue-quill-editor/static/images/surmon-5.jpg"
}
}
},
mounted() {
let self = this
//调用 <audio> 元素提供的方法 play()
this.$refs.videoPlayer.player.play()
//判斷 WeixinJSBridge 是否存在
if (typeof WeixinJSBridge == "object" && typeof WeixinJSBridge.invoke == "function") {
self.$refs.videoPlayer.player.play()
} else {
//監聽客户端抛出事件"WeixinJSBridgeReady"
if (document.addEventListener) {
document.addEventListener("WeixinJSBridgeReady", function(){
self.$refs.videoPlayer.player.play()
}, false);
} else if (document.attachEvent) {
document.attachEvent("WeixinJSBridgeReady", function(){
self.$refs.videoPlayer.player.play()
});
document.attachEvent("onWeixinJSBridgeReady", function(){
self.$refs.videoPlayer.player.play()
});
}
}
//voiceStatu用來記録狀態,使 touchstart 事件只能觸發一次有效,避免與 click 事件衝突
var voiceStatu = true;
//监听 touchstart 事件进而调用 <audio> 元素提供的 play() 方法播放音频
document.addEventListener("touchstart",function(e){
if(voiceStatu){
self.$refs.videoPlayer.player.play()
voiceStatu = false;
}
}, false);
},
computed: {
player() {
return this.$refs.videoPlayer.player
}
},
methods: {
playerReadied(player) {
var hls = player.tech({ IWillNotUseThisInPlugins: true }).hls
player.tech_.hls.xhr.beforeRequest = function(options) {
// console.log(options)
return options
}
}
}
}
</script>
<style scoped>
.physical-video{
width: 100%;
height: 100vh;
}
</style>
<style>
.physical-video .video-js.vjs-custom-skin {
height: 100vh;
}
.physical-video .video-js.vjs-custom-skin .vjs-control-bar {
height: 90px;
}
.physical-video .video-js.vjs-custom-skin .vjs-control {
width: 4em!important;
}
.physical-video .video-js .vjs-time-control,.physical-video .video-js.vjs-custom-skin .vjs-control-bar .vjs-playback-rate .vjs-playback-rate-value {
font-size: 2em!important;
line-height: 3em!important;
}
.physical-video .video-js .vjs-control:before {
height: 50px;
font-size: 4em;
}
</style>