更新日期:2019-09-12
实现
全景视频原理
原理:球模型贴图+鼠标(手势)事件
官方示例代码:https://github.com/mrdoob/three.js/blob/master/examples/webgl_video_panorama_equirectangular.html
示例地址:webgl_video_panorama_equirectangular
测试视频:http://cache.utovr.com/9049b27016264739a2126dd073830492/L2_em34n10gj9tdzeks.mp4
动态获取视频链接
问题:将video标签的src赋一个空字符传作为初值,然后通过请求或其他方式获取到视频链接,再替换video标签的src,这样做视频不能正常播放。
方案:获取到视频链接后,再生成video,插入到页面中
function createdVideo(src) {
var videoPlayer = $("#my-video").get(0)
if (typeof (videoPlayer) != "undefined") {
var myPlayer = videojs('my-video')
myPlayer.dispose()
}
var id = 'my-video'
var videoDom = ''
videoDom = $('<video id="' + id + '" class="video-js" controls preload="auto" loop data-setup="{}" crossorigin="anonymous" webkit-playsinline="true" x-webkit-airplay="true" playsinline="true" x5-video-player-type="h5" x5-video-player-fullscreen="true"><source src="' + src + '"></video>')
$('#wrapper').html(videoDom)
return videojs(id, {}, function() {
var myPlayer = videojs(id);
videojs(id).ready(function () {
var myPlayer = this;
startRender(myPlayer)
});
})
}
渲染全景视频
问题:视频能都播放,但无法渲染
方案:可能的原因是视频动态获取,还没有加载就进行渲染,导致渲染失败。因此在加载成功后再进行渲染
function startRender() {
var geometry = new THREE.SphereBufferGeometry(500, 60, 40)
// invert the geometry on the x-axis so that all of the faces point inward
geometry.scale(-1, 1, 1)
var texture = new THREE.VideoTexture(document.querySelector('#my-video video'))
texture.wrapS = texture.wrapT = THREE.ClampToEdgeWrapping;
texture.minFilter = THREE.LinearFilter;
texture.needsUpdate = true;
var material = new THREE.MeshBasicMaterial({ map: texture })
mesh = new THREE.Mesh(geometry, material)
scene.add(mesh)
}
自动播放
新版的chrome已经禁止了自动播放,autoplay属性无效。但是可以通过video标签的muted属性进行静音,保证自动播放。网上流传的静音播放然后再打开声音的方法是无效的。自动播放什么的就别想了
移动端播放
webkit-playsinline="true"
x-webkit-airplay="true"
playsinline="true"
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
注意:在退出全屏时候会暂停视频,触发pause事件
播放m3u8格式视频
使用video.js还要加一个插件才能播放m3u8,video标签上还需要加一个type="application/x-mpegURL"
属性
<script src="https://cdnjs.cloudflare.com/ajax/libs/video.js/7.3.0/video.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/videojs-contrib-hls/5.15.0/videojs-contrib-hls.min.js"></script>
<video
src="xxx"
class="video-js"
controls preload="auto"
autoplay
loop
data-setup="{}"
crossorigin="anonymous"
webkit-playsinline="true"
x-webkit-airplay="true"
playsinline="true"
x5-video-player-type="h5"
x5-video-player-fullscreen="true"
type="application/x-mpegURL">
</video>
在IOS上出现的问题
网络原因
一开始播放不了以为是代码或是视频问题,其实网络问题也是一个重要的因素。
ios不支持视频格式
ios支持播放的视频编码其实很少,渲染出场景的前提是视频能够播放。
ios视频请求
ios无法播放视频,在网上看到这样一种解释:
ios在请求视频时,会先请求0-1个字节,写在请求头的
range
字段中:range:'bytes=0-1'
。如果是想要传输视频,必须要解析range字段,然后按照range字段的要求返回对应的数据,同时response header至少要包含三个字段:Content-Type
,Content-Range
,Content-Length
。Content-Type
必需明确指定视频格式,有video/mp4
,video/ogg
,video/mov
等等
这个需要后端处理,由于公司没有视频服务,只能作罢。
参考链接:
https://www.zhihu.com/question/41818719
https://segmentfault.com/q/1010000012524886/a-1020000012526858
loadedmetadata事件:ios的微信浏览器上视频只有在点击播放时才会开始加载,在ios上可以通过loadedmetadata事件判断视频是否开始加载,再进行渲染。因此,当要获取视频时长(duration)时,ios的微信浏览器要开始播放才能获取得到。
this.on('loadedmetadata',function(){
var u = navigator.userAgent
var isIOS = !!u.match(/\(i[^;]+;( U;)? CPU.+Mac OS X/);
if(isIOS){
startRender(myPlayer)
}
})
window.resize事件
问题:在ios上横屏播放时,获取到的window宽高是之前的宽高
方案:setTimeout延时获取,不知有没有更好的方法
function onWindowResize() {
var width, height
setTimeout(function() {
width = window.innerWidth
height = window.innerHeight
camera.aspect = width / height
camera.updateProjectionMatrix()
renderer.setSize(width, height)
}, 200)
}
注意:全屏时也需要重新设置renderer的大小,全屏时会触发resize事件,所以最好不用orientationchange事件判断横竖屏,否则全屏时可能会有问题。
总结
这次主要的问题还是视频在ios上无法播放。要锻炼的还是自己排查问题的能力。这次排查问题的主要思路:
- 通过测试视频判断问题是出在播放器上还是视频上,或者是视频服务上
- 视频在ios上是否能够直接播放
- 网络问题
- 是否因动态获取视频连接导致无法播放
- ios是否支持视频格式
- 视频能否成功渲染成全景场景
- 是否在视频加载后才开始渲染
- three.js各个参数设置是否正确