昨天公司指派给我了一个任务, 是关于视频播放后展示页面的单页应用, 具体需求如下:
1)用户在进入页面后视频开始自动播放, 期间不得操作;
2)视频播放完成后顺滑切换到主体页.
看起来是不是特别简单粗暴, 乍一看好像也是就是不到一小时的工作量, 却让我足足熬到了深夜两点钟, 说起来都是泪~~. 这期间遇到了不少问题, 我都会在下面一一列举(以下所说的浏览器均为移动端浏览器, 不再一一标注).
一, video 的默认显示
在我开发完基本代码之后, push 到 githook 上在手机上展示时, 遇到了第一个问题: 众所周知, html 中 video 的 autoplay 在移动端浏览器上基本失效(其一, 移动端要有用户交互才能触发事件, 如 click,touch; 其二, iOS 协议蜂窝数据下不得开启音视频的自动播放), 所以我在加载后取巧的加了一个悬浮播放图标, 引导用户点击开始业务流程.
但可能因为内核不同, 在微信浏览器 / Safari/Chrome 上默认展示的 poster 各有不同, Chrome 应用了默认行为截取了视频第一帧作为显示, 微信浏览器和 Safari 却显示空白, 效果就是孤零零的播放图放在一张白纸上. 解决方案是: 通过 canvas 截取视频第一帧作为默认显示的图片:
- var cut = function() {
- let canvas = document.createElement("canvas");// 创建画布
- canvas.width = video.videoWidth * scale;
- canvas.height = video.videoHeight * scale;// 设定宽高比
- canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height);// 将视频此刻帧数画入画布
- let img = document.createElement("img");
- img.src = canvas.toDataURL("image/PNG");
- Dom.appendChild(img);// 写入到 Dom
- };
- video.addEventListener('loadeddata',cut);// 在视频帧数已加载时执行截取
二, video 控制栏的隐藏
HTML 文档里写有, 如果 controls 属性不出现, 则默认不显示, 但其实在实际应用中, 浏览器一般都是调用默认播放器进行播放, 再加上双端差异, 实际展示效果更是精彩纷呈. 说到这里, 要写一下目前各个浏览器的内核情况:
微信浏览器
安卓
微信 6.1 版本以上的 Android 用户, 都是使用的 QQ 浏览器的 X5 内核. 5.4-6.1 之间的版本, 若用户安装了 QQ 浏览器就是使用的 X5 内核, 若用户未安装浏览器, 使用的是系统内核.
iOS
webkit.
大部分手机浏览器
Webkit.(UC 的 U3 内核和 X5 内核一样, 是基于 webkit 修改的内核).
由上可知, 在移动端开发遇到的百分之九十的问题, 都是系统和机型问题.
我们回到问题本身, 在使用 htmlvideo 标签时, 我们会发现, 点击播放之后首先会进入播放器占用整个屏幕, 之后开始播放, 再次点击视频会出现控制栏.
好, 捋一捋思路. 第一步, 要解决脱离屏幕的播放问题.
- <video poster="img/test.jpg" webkit-playsinline="true" playsinline>
- <source src="img/movie.mp4" type="video/mp4">
- <source src="img/movie.ogg" type="video/ogg">
您的浏览器不支持该视频格式.
</video>
webkit-playsinline playsinline: 这个属性作用是让视频播放时局域播放(不全屏, 在原有位置上播放), 不脱离文档流 . 但这个属性需要嵌入网页的 App 比如 WeChat 中 UIwebview 的 allowsInlineMediaPlayback = YES webview.allowsInlineMediaPlayback = YES, 才能生效. 换句话说, 安卓不支持, 而 iOS 的 wechat 却支持, 因为 App 不支持 playsinline, 所以安卓是默认全屏播放的.
第二步, 隐藏掉控制栏.
- <video x5-video-player-type="h5" id="video">
- <source src="img/movie.mp4" type="video/mp4">
- <source src="img/movie.ogg" type="video/ogg">
您的浏览器不支持该视频格式.
</video>
x5-video-player-type='h5' 启用同层 H5 播放器, 学名叫沉浸式播放. 播放的时候除去了 control 和微信的导航栏, 只留下 "X" 和 "<" 两键.
一般来说, 这种已经足够'沉浸'了, 但项目对定制化要求比较高, 要求这种也不要出现. 我苦思冥想, 查了好多文档, 方法却都大同小异. 直到最后灵光一闪, 放弃了通过属性或方法来限制的思路, 决定用视觉遮挡来实现效果:
将 video 的控制栏挤出可视区域, 不就相当于隐藏了控制栏嘛.
- /* 这是 CSS*/
- HTML,body,.main{
- width: 100%;
- height: 100%;
- overflow: hidden;// 隐藏
- background: #FFF;
- box-sizing:border-box;
- }
- .videobox{
- z-index: 12;
- position: fixed;
- left: 0;
- top: 0;
- width: 100%;
- height: 100%;
- }
- #video{
- position: absolute;
- top: -2%;
- width: 100%;
- height: 110%;
- }
- <!-- 这是 HTML-->
- <div class="videobox" ontouchmove="return false;">
- <video poster="img/test.jpg" webkit-playsinline="true" playsinline x5-video-player-type="h5" x-webkit-airplay="true" id="video">
- <source src="img/movie.mp4" type="video/mp4">
- <source src="img/movie.ogg" type="video/ogg">
您的浏览器不支持该视频格式.
- </video>
- </div>
这样就实现了播放时不得操作的需求.
三, iOS 当视频被打开在 Safari 浏览器时播放白屏.
这就牵扯到两个个问题, 我们分开来说.
video 标签对视频格式以及编码的支持
MPEG4 = 带有 H.264 视频编码和 AAC 音频编码的 MPEG4 文件
WebM = 带有 VP8 视频编码和 Vorbis 音频编码的 WebM 文件
Ogg = 带有 Theora 视频编码和 Vorbis 音频编码的 Ogg 文件
如上所示, 只有 h264 编码的 MP4 视频 (MPEG-LA 公司),VP8 编码的 webm 格式的视频(Google 公司) 和 Theora 编码的 ogg 格式的视频 (iTouch 开发) 可以支持 html5 的 < video > 标签.
那么在实际代码上我们应该这么布置:
- <video poster="img/test.jpg" webkit-playsinline="true" playsinline x5-video-player-type="h5" x-webkit-airplay="true" id="video">
- <source src="img/movie.mp4" type="video/mp4">
- <source src="img/movie.ogg" type="video/ogg">
您的浏览器不支持该视频格式.
</video>
首先会判断是否支持 MP4, 如否, 判断是否支持 OGG, 如否, 展示文字. 这也是我最后选择的解决方式, 简单粗暴可以早睡觉 :).
备注: 网上有文章说, 用格式工厂将 mp4 编码转成 H264 即可, 但我实际应用中发现 H264 在 Safari 和 Chrome 中竟然无法打开, 具体原因究竟是我编码错误还是与文档冲突, 暂未知晓.
iOS 上播放视频, http 协议中应用 rang 请求头
引用了 CSDN 一位版主业余草的回复 https://bbs.csdn.NET/topics/392167856
视频格式 MP4 是正确的, 但是你的后台没有对 iOS 的视频播放器做适配. 如果想要在 iOS 上播放视频, 那么必须在 http 协议中应用 rang 请求头.
对于有的朋友还对 iOS 播放器 http 的 range 标记不是很懂. 我再讲解下.
视频文件总长度是 123456789
range 是播放器要求的区间也就是客户端发送请求的时候 http 会带有这个标记, 这个区间的值在 http.headers.range 中获取, 一般是 bytes=0-1 这样的.
我们需要做的处理是返回文件的指定区间(如上面的例子, 我们就应该返回 0 到 1 的字符), 并添加 Content-Range:btyes 0-1,Accept-Ranges:bytes,'Content-Length: 123456789','Content-Type: video/mp4'到 http.headers 中
具体效果因为时间关系并没有亲自测试, 有兴趣的朋友可以研究一下.
四, 关于其他属性的补充
让你的视频充满屏幕.
- #video{
- object-fit: fill;
- }
把当前的视频投放到其他支持此技术的设备上.
<video x-webkit-airplay="true"></video>
在视频结束时执行事件.
- $("#video").get(0).addEventListener("ended", function() {
- }, false);
微信浏览器下实现自动播放.
- document.addEventListener("WeixinJSBridgeReady", function() {
- video.play()
- }, false)
笔记到这里就结束了, 如果在文章里有哪些纰漏和错误, 望您不吝赐教
END
来源: https://juejin.im/post/5ba5abedf265da0aa664c0f6