【分享】Html5 Video 实现方案

前言: 最近项目中需要用到html5 视频播放功能,于是稍微研究了解了下,遇到了很多坑,特此记录下.

一、 Html5 Video
参考来源: http://www.xuanfengge.com/html5-video-play.html
(这篇博文确实帮助很大)

1.1、 目的
将Html5 Video功能应用到实际项目中,针对不同的平台和环境,进行个性化处理。
基本只考虑webkit浏览器兼容问题

1.2、 Html5 Video支持格式
只支持: .mp4后缀(.h264编码格式),和.webm后缀(专用web视频格式),以及.ogg后缀(音频文件)
注意: Html5 Video 可以添加多个source源来进行兼容适配,这样,当第一个源读取出问题时会自动读取下一个源. 比如可以同时在前面加上.webm和.mp4源,这样一个出错时会自动读取另一个可用源(因为不同浏览器,支持的格式是不一样的)
但是,Hybird模式的 Android 下,有些机型只能读取第一个source来源(测试华为和联想都是),所以也就是说在这种情况下,要确保第一个source源是正确的
各大浏览器兼容如图所示:
见图1

1.3、 不同平台环境和对应实现方案
说明: 这里分为两大块,普通浏览器环境(pc和手机,主要是移动端,pc不做特别处理)和Hybird模式的APP环境(Android和iOS).
注: Html5 video可以播放本地视频或者网络视频
1.3.1、 普通浏览器环境
*用Html5 Video 自带的播放栏控件
*用 Video 视频统一处理方法处理后,点击图片手动隐藏图片,设置视频大小,手动播放视频.
注: 播放效果则由各大浏览器自行实现

手机端浏览器实现的不同效果,比如:
QQ浏览器(包括QQ客户端内置的浏览器):播放时会自动进入全屏
华为自带浏览器: 正常小窗口播放

1.3.2、 Hybird App环境
说明: 内联播放是指直接在video标签中播放视频,没有必要进入全屏

1.3.2.1、 Android内联播放
*用Html5 Video 自带的播放栏控件
*用 Video 视频统一处理方法处理后,点击图片手动隐藏图片,设置视频大小,手动播放视频.
*Android内联播放需要注意,必须开启硬件加速,由于有些Android手机 webview是默认关闭硬件加速的,所以必须在创建这个带视频播放的webview时手动添加 硬件加速属性才行.(详情见plus创建webview的style)


style.hardwareAccelerated = true;

\n

1.3.2.2、 iOS内联播放
*用Html5 Video 自带的播放栏控件
*用 Video 视频统一处理方法处理后,点击图片手动隐藏图片,设置视频大小,手动播放视频.
*内联播放注意要点,由于iOS下默认是全屏播放的,所以需要经过设置才能正常内联播放
第一步:在项目的manifest里面配置允许webview内联播放


"plus": {
"splashscreen": {
"autoclose": true,/*是否自动关闭程序启动界面,true表示应用加载应用入口页面后自动关闭;false则需调plus.navigator.closeSplashscreen()关闭*/
"waiting": true/*是否在程序启动界面显示等待雪花,true表示显示,false表示不显示。*/
},
"allowsInlineMediaPlayback": true,/*设置ios下允许内联播放*/
"popGesture": "close"

\n

第二步: 创建video标签时,手动加上内联播放的属性(iOS不支持preload)

<!--
让ios支持内联播放,必须添加 webkit-playsinline 标签
-->
<video webkit-playsinline id="videoMedia" controls="controls" preload>
\n

这样iOS手机在播放的时候才会采用内联播放

1.3.2.3、 Android非内联播放
*通过NJS使用原生播放器来播放视频,传入的url可以是本地的或网络的地址
*用 Video 视频统一处理方法处理后,点击图片之后,图片保持不变(所以没有必要隐藏图片),直接获取视频的资源地址,传给原生播放器播放
注: 这种模式下,性能要比直接html5自带播放器播放高

1.3.2.4、 iOS非内联播放
*用Html5 Video 自带的播放栏控件(非内联播放需要去除特定内联属性”webkit-playsinline”,这样才能全屏播放)

if(!isInlinePlay){
//如果是非内敛,ios需要去除内联样式
mediaTarget.removeAttribute('webkit-playsinline');
}
\n

*用 Video 视频统一处理方法处理后,点击图片之后,图片保持不变(所以没有必要隐藏图片),直接调用video.play()播放视频(这时候会用一个全屏播放器来播放视频)

1.3.3、 注意要点
如果采用NJS通过Android原生播放器播放视频,目前无法监听到视频的一些自定义事件.(如下载中,播放完毕,暂停,播放时间等)
而如果采用Html5 Video自带播放,这些是可以通过脚本控制的.
所以选定方案时需要进行衡量
*另外,在Html5 Video播放时,无法监听到规定的结束事件seeked,只能在timeUpdate里面判断,如果ended为true就代表结束了.
*在NJS通过Android原生播放器播放时,可以通过document监听resume和pause事件判断是否进入播放和退出播放

1.4、 Tips

1.4.1、 关于Video 视频统一处理的方案
说明: 由于将一个<Video>直接显示在页面中,会有各种五花八门的播放器效果,如图:
(这里引用了参考来源的图)
见图2


显然,体验效果并不好,所以现在的做法是用一张模拟播放的图片来替代<Video>所在的地方,而将Video元素设置为1*1像素大小.然后给图片设置点击监听,监听到点击时,播放视频.
注意:
*这里不要用{display: none}或者{width:0;height:0;}的方式,因为这样视频元素会处于未激活的状态,给后续的处理带来麻烦.
*这里没有考虑ios<6和一些低版本的Android的兼容性问题了(这些版本里,无法直接通过video.play()来播放),因为项目环境基本上要求Android>4.0 iOS 7.0以上的.
*关于点击图片播放视频后,如果是内联播放模式下(或者是普通浏览器),就应该将图片隐藏,然后将视频大小设置为本来的大小(一般为图片大小);如果是非内联播放模式(全屏模式),就没有必要隐藏图片了,因为iOS下会自动打开一个全屏播放器来播放视频,Android下考虑到Html5 video较卡,所以也会通过NJS使用原生播放器来全屏播放视频.

1.4.2、 Android NJS播放视屏的实现代码
说明: 这个是Dcloud论坛中有人分享的

 //非内联模式下的plus下的android才用到
var Intent = plus.android.importClass("android.content.Intent");
var Uri = plus.android.importClass("android.net.Uri");
var main = plus.android.runtimeMainActivity();
var intent = new Intent(Intent.ACTION_VIEW);
var uri = Uri.parse(url);
intent.setDataAndType(uri, "video/*");
main.startActivity(intent);
\n

1.4.3、 如何读取元素的宽高
*在获取视频的宽度时,发现用 video.style.width无法获取到宽度.
后来查了资料,发现dom.style.width(height)只能获取在stye直接赋予的值.而如果是通过css样式表赋予的值是无法直接获取的,只能通过dom.offsetWidth(offsetHeight)获取.
*设置元素宽和高是不要直接在style里设置,而是最好通过css样式表赋予
*读取元素宽和高时,用offsetWidth(offsetHeight)

1.4.4、 关于全屏播放的问题
在PC端webkit浏览器下,全屏代码如下:
进入全屏: videoContainer(对应的dom).webkitRequestFullscreen();
退出全屏: document.webkitCancelFullScreen();
*但是经测试,在手机浏览器和Hybird模式下的手机环境中都无法使用,
应该是手机浏览器中video 播放器的全屏模式和pc端的有区别,已经脱离了webkit的全屏组件,而是用原生自己实现的.

1.5、 遇到问题及解决方法

1.5.1、 Video.currentTime 设置值时设置无效,或者变为0
原因分析:
与测试的服务器和端口有关,测试环境是放在hbuild本地浏览器的,没有处理好视频快进问题,所以会导致每次快进后,视频都会重置-在某些测试服务器上,则出现快进无效,但不会重置
解决方法:
将网页用其它正式服务器打开均可正常,如tomcat,wampserver,甚至直接在本地打开也行.

1.5.2、 无法通过代码Video.src获取资源路径
原因分析:
本实例中,Video是通过source添加src的,无法直接读取video的src
解决方法:
可以通过读取到第一个source的标签,再获取source的src
注:本来这个方法有一个缺点就是有可能第一个source的src不可用.但是由于Android中第一个source必须有用才行.否则无法正常播放.所以在确保第一个source正确的情况下能这样用.

1.5.3、 部分Android机型无法退出全屏
描述:
在使用Html5 Video自带播放器播放时,部分Android机型(如联想K860点击全屏按钮进入全屏后,无法退出全屏-因为进入全屏后,全屏按钮不见了)
原因分析: 可能是手机厂商擅自劫持了浏览器或者篡改了浏览器实现方式
解决方法:
目前无法解决,在这类机型中,建议直接采用非内联模式播放或者是尽量不要手动进入全屏

1.6、 示例Demo
注: 示例视频也可自己更改为自己的网络视频或者本地视频,由于视频文件太大,所以上传时就删掉了

见源码附件


32 分享 关注
wenju DCloud_MUI_FXY mingtianfu fengerous shwanYu DCloud_heavensoft LFZ Bruin 小云菜 qiuxiaojun DCloud_客服_Trust 赵梦欢 lhyh NewsNing 雷小达 jiujiu3178@163.com Android_XR 1048064873@qq.com huaguojun123@163.com For艾尔 beisong 菜鸟V5 wx_1214@126.com 450767949@qq.com bughunter fwrong 1060548792@qq.com MooGu mlm8368 251378520 786131690@qq.com 1184034925@qq.com
1184034925@qq.com

1184034925@qq.com

好帖 MARK
0 赞 2018-08-13 15:49
15515806372@163.com

15515806372@163.com 回复 mystyle@sina.com

解决了没?我也遇到这个问题
0 赞 2018-07-09 09:21
mystyle@sina.com

mystyle@sina.com

DEMO中 如果是动态获取的 视频的 url ,就无法正常播放了,有没相应的解决方案
0 赞 2018-06-03 20:23
itxiaoxiao

itxiaoxiao

Zepto('#videoMedia').on('tap', function() {
play();
});
应该加个延迟
var aa = '';
Zepto('#videoMedia').on('tap', function() {
clearTimeout(aa);
aa = setTimeout(function() {
play();
}, 20); //这里给个延迟不然播放视频时点击videoMedia这一块控制栏一直闪烁
});
0 赞 2018-05-02 17:49
上官萧晨

上官萧晨 回复 NewsNing

你好,后面你做进度条拖动改变视频进度的功能没,有没有demo
0 赞 2018-04-15 17:16
讯实

讯实

学习了很多。你们也可以到这看看。有一些作品。!http://www.3g-edu.org?wxdc
0 赞 2017-11-20 10:50
古古怪怪

古古怪怪

博主很细心,我这也有一个参考网址,你们可以看看http://www.3g-edu.org?wwxkiter
1 赞 2017-11-16 15:19
zjaton@sohu.com

zjaton@sohu.com

mark
0 赞 2017-08-21 14:41
king110

king110

在iphone上测试了一下 还是不行啊,下载的你们测试文件,还是全屏播放
1 赞 2017-07-30 12:35
云钦

云钦

看到一,没看到二
0 赞 2017-07-03 21:45
1019422167@qq.com

1019422167@qq.com

mark
0 赞 2017-05-22 10:05
wx_1214@126.com

wx_1214@126.com 回复 DCloud_heavensoft

如果下载视频到本地,理论上播放的始终是下载到本地的视频吧?没下载完,可以边下载边播放吗?
0 赞 2017-05-02 14:26
mafx

mafx

mark
0 赞 2017-03-20 10:39
DCloud_heavensoft

DCloud_heavensoft 回复 362673301@qq.com

调用plus.download下载视频到本地,然后video控件指向本地文件路径
0 赞 2017-03-14 04:33
362673301@qq.com

362673301@qq.com

如何app缓存网络视频?这个很实用而且很常见,没这个功能,基本是废物一个。
0 赞 2017-03-13 21:14
阿德

阿德 回复 294061991@qq.com

我想也做这个功能,有解决思路没
0 赞 2016-12-29 17:27
1019422167@qq.com

1019422167@qq.com

mark
0 赞 2016-12-19 09:51
294061991@qq.com

294061991@qq.com

如何实现视频离线缓存到本地,不是实现就把视频打包到APP中的办法,实现把视频打包进APP,APP会很大;希望实现视频可以选择性下载,下载观看就不用远程视频了
1 赞 2016-10-04 16:56
31682066@qq.com

31682066@qq.com

mark
0 赞 2016-09-19 22:48
雷小达

雷小达

mark
0 赞 2016-09-17 20:11
NewsNing

NewsNing

https://segmentfault.com/a/1190000006604046 大家可以看一下,全屏播放的另类解决方案,兼容ios android
3 赞 2016-08-26 21:37
NewsNing

NewsNing 回复 陈晓猛

请看我的文章https://segmentfault.com/a/1190000006604046
0 赞 2016-08-26 21:37
陈晓猛

陈晓猛

请问一下内联样式,在android机上运行的时候,点击全屏没办法横屏全屏播放,这个有什么解决的方法吗?
0 赞 2016-08-18 15:15
toogu

toogu

学习了
0 赞 2016-07-11 12:34
撒网要见鱼

撒网要见鱼 回复 LFZ

我这边用chrome浏览器调试监听ended是没问题的。
另外,测试快进等功能是别用hbuild自带的server(有buug),可以改用其它server.
或者干脆用本地文件方式打开。
0 赞 2016-05-27 16:49
LFZ

LFZ 回复 LFZ

用eclipse就只能监听seeked,用HBuilder就只能监听到ended,什么情况
0 赞 2016-05-25 11:40
LFZ

LFZ

监听结束是监听ended才正确而不是监听seeked
0 赞 2016-04-29 10:22
小刀

小刀

android 先使用内联模式播放,然后非内联模式下调用内置播放器播放,关闭内置播放器,返回到原页面后,再使用内联模式播放,只有声音没有图像了,你的例子也是这样。如何解决?
0 赞 2016-04-22 01:59
撒网要见鱼

撒网要见鱼 回复 smith

你在创建webview的时候再加上style.hardwareAccelerated = true; 试试!
0 赞 2016-04-15 08:12
smith

smith

为什么在manifest.json文件中添加了"hardwareAccelerated": true,视频仍然只有声音没有图像vivo手机Android5.0版本
0 赞 2016-04-14 14:46
ztingjian

ztingjian

mark
0 赞 2016-04-11 14:19
马脸老男人

马脸老男人

mark
0 赞 2016-04-09 17:07
DCloud_heavensoft

DCloud_heavensoft

好文!
漏了一个注意事项,Android上使用video标签播放视频时,务必强制打开硬件加速,否则只有声音没有画面。
因为在Android5的部分rom上是默认关闭硬件加速的,此时需强制打开硬件加速。创建webview时style里有个hardwareAccelerated参数,设置为true。
参考文档[http://ask.dcloud.net.cn/article/55](http://ask.dcloud.net.cn/article/55)
0 赞 2016-04-03 04:10
Raining

Raining

学习了
0 赞 2016-03-24 15:18
mingtianfu

mingtianfu

好帖
0 赞 2016-03-15 11:23
wenju

wenju

mark
0 赞 2016-03-11 16:42

要回复文章请先登录注册