本文作者:IMWeb 张颖 原文出处:IMWeb社区 未经同意,禁止转载
为了文章的完整性,首先还是列举一下video标签的属性:
Video 对象属性:
Video 对象方法:
然后列出可以用于视频状态监控的Media 事件(由媒介(比如视频、图像和音频)触发的事件,适用于所有html元素,但常用于 audio、embed、img、object 以及 video中):
属性 | 值 | 描述 |
---|---|---|
onabort | script | 在退出时运行的脚本 |
oncanplay | script | 当文件就绪可以开始播放时运行的脚本(缓冲已足够开始时) |
oncanplaythrough | script | 当媒介能够无需因缓冲而停止即可播放至结尾时运行的脚本 |
ondurationchange | script | 当媒介长度改变时运行的脚本 |
onemptied | script | 当发生故障并且文件突然不可用时运行的脚本(比如连接意外断开时) |
onended | script | 当媒介已到达结尾时运行的脚本(可发送类似“感谢观看”之类的消息) |
onerror | script | 当在文件加载期间发生错误时运行的脚本 |
onloadeddata | script | 当媒介数据已加载时运行的脚本 |
onloadedmetadata | script | 当元数据(比如分辨率和时长)被加载时运行的脚本 |
onloadstart | script | 在文件开始加载且未实际加载任何数据前运行的脚本 |
onpause | script | 当媒介被用户或程序暂停时运行的脚本 |
onplay | script | 当媒介已就绪可以开始播放时运行的脚本 |
onplaying | script | 当媒介已开始播放时运行的脚本 |
onprogress | script | 当浏览器正在获取媒介数据时运行的脚本 |
onratechange | script | 每当回放速率改变时运行的脚本(比如当用户切换到慢动作或快进模式) |
onreadystatechange | script | 每当就绪状态改变时运行的脚本(就绪状态监测媒介数据的状态) |
onseeked | script | 当 seeking 属性设置为 false(指示定位已结束)时运行的脚本 |
onseeking | script | 当 seeking 属性设置为 true(指示定位是活动的)时运行的脚本 |
onstalled | script | 在浏览器不论何种原因未能取回媒介数据时运行的脚本 |
onsuspend | script | 在媒介数据完全加载之前不论何种原因终止取回媒介数据时运行的脚本 |
ontimeupdate | script | 当播放位置改变时(比如当用户快进到媒介中一个不同的位置时)运行的脚本 |
onvolumechange | script | 每当音量改变时(包括将音量设置为静音)时运行的脚本 |
onwaiting | script | 当媒介已停止播放但打算继续播放时(比如当媒介暂停已缓冲更多数据)运行脚本 |
这些Media 事件在不同平台下表现各异,事件触发的场景有差异,事件触发后Video对象属性的返回值也不尽相同,下面重点归纳其差异点,首先我们会给出结论,然后附上测试数据。 测试直接使用最简单的方式,在页面上添加video标签播放视频,视频设置循环播放属性loop。
event | pc侧 | iOS | android |
---|---|---|---|
loadstart | 文件加载,video初始化,未加载任何数据 | 与PC侧一致 | 一致 |
stalled | 视频没有播放,没有取回任何媒介数据:一般是由于网络状况不佳,导致视频下载中断 | 一致 | 可能在play()事件触发前 |
play | play()事件触发,状态是开始播放,但视频并未真正开始播放 | 一致 | 一致 |
waiting | play()事件触发后,等待数据 | 一致 | 一致 |
durationchange | 获取到视频长度,duration属性能获得真实视频长度 | 一致 | 可能在play()事件触发前,可能没有获取到真实的视频长度:可能触发多次, 只有最后一次才能获取到真实的duration,之前的值有可能为0或者1 |
loadedmetadata | play()事件触发后,获取到元数据 | 一致 | play()事件触发前,没有获取到真实的元数据 |
loadeddata | play()事件触发后,获取到媒介数据 | 一致 | play()事件触发前,没有获取到真实的媒介数据 |
canplay | 可以播放,但视频可能还未真正开始播放,并且中途可能因为加载而暂停 | 一致 | 一致 |
playing | 视频开始播放 | 一致 | 可能还未真正开始播放,并且可能还未获取到视频长度 |
canplaythrough | 视频开始播放后,可以流畅播放 | 一致 | 数据可能还没有开始加载,视频可能还未开始播放, 视频仍然会卡住 |
timeupdate | 视频播放后,更新播放进度, 会有明确的进度变化,可以获取到currentTime | 一致 | 第一次可能会有误差,如果 timeupdate事件的currentTime发生变化,代表视频一定开始播放 |
progress | 视频播放后,持续下载, 可以获取到当前的缓存buffer,并且全部下载完毕后不再触发 | 一致 | 第一次可能会有误差, 全部下载完毕后依然继续触发 |
suspend | 缓冲中,视频可能卡顿也可能在流畅播放中,全部缓存完毕后不再触发。视频还未真实播放前,pause()事件会触发suspend | 一致 | 一致 |
pause | 可能是响应pause()事件暂停,或者是切出页面自动暂停 | 一致 | 一致 |
seeking | 拖动进度条时,寻找播放位置。或者播放完毕,寻找下一个视频 | 一致 | 一致 |
seeked | 拖动进度条时,定位到播放位置。或者开始播放下一个视频,或者是从头开始循环播放 | 一致 | 一致 |
error | 错误,无法定位错误原因,无法通过paly()事件继续播放 | 一致 | 一致 |
buffered返回 TimeRanges 对象,TimeRanges 对象表示用户已缓冲音视频的时间范围,如果用户在音视频中跳跃播放,会得到多个缓冲范围。这里要强调的是如果跳跃播放,得到的多个缓冲范围是按照大小顺序排列,无重复覆盖的。
|
1、 视频加载时间
play事件触发时间 至 timeupdate事件第一次currentTime 属性值发生变化时,在加载过程中可用suspend判断是否有手动暂停。
2、 视频缓冲次数
video对象的buffered属性返回表示视频已缓冲部分的 TimeRanges 对象,currentTime属性设置或返回视频中的当前播放位置(以秒计),利用缓冲区的变化可以记录视频缓冲次数。 目前尝试的缓冲判断为: timeupdate事件中,currentTime 超出 buffered的记录范围。
3、 视频流中断
引起视频停止播放的原因有:手动暂停、视频流中断、视频播放完毕,切换程序,所以用视频停止播放来判断断流不准确。 要尽可能的实时监控视频流是否中断,目前还是尝试使用video对象的buffered属性, 因为视频断流意味着buffered缓冲区不会再发生变化。 视频流中断判断可表述为: timeupdate事件中,currentTime所在的缓冲buffered段的尾部时间,不等于视频的总长度duration, 且连续多次没有变化。具体使用连续多少次作为阈值,需要反复测试,目前所得结论是20次。
event | readyState | currentTime (s) | buffered (s) | duration (s) | 视频状态 | |
---|---|---|---|---|---|---|
1 | loadstart | NOTHING | 0 | null | NaN | 准备请求数据(初始化完毕) |
2 | stalled | NOTHING | 0 | null | NaN | |
3 | play | NOTHING | 0 | null | NaN | play()事件触发,状态是开始播放,但视频并未真正开始播放 |
4 | waiting | NOTHING | 0 | null | NaN | 等待数据 |
5 | durationchange | METADATA | 0 | 0.6 | 44.2 | 获取到视频长度 |
6 | loadedmetadata | METADATA | 0 | 0.6 | 44.2 | 获取到元数据 |
7 | loadeddata | ENOUGH_DATA | 0 | 1.06 | 44.2 | |
8 | canplay | ENOUGH_DATA | 0 | 1.06 | 44.2 | 可以播放,但中途可能因为加载而暂停 |
9 | playing | ENOUGH_DATA | 0 | 1.06 | 44.2 | 开始播放 |
10 | canplaythrough | ENOUGH_DATA | 0 | 1.06 | 44.2 | 可以流畅播放 |
11 | timeupdate | ENOUGH_DATA | 0 | 1.06 | 44.2 | 播放进度变化 |
12 | progress | ENOUGH_DATA | 0.1 | 2.92 | 44.2 | 持续下载 |
13 | timeupdate | ENOUGH_DATA | 0.21 | 4.67 | 44.2 | 播放进度变化 |
... | | | | | | |
38 | suspend | ENOUGH_DATA | 3.29 | 14.08 | 44.2 | 缓冲中,视频可能卡顿也可能在流畅播放中 |
39 | timeupdate | ENOUGH_DATA | 3.48 | 14.08 | 44.2 | |
... | | | | | | |
490 | timeupdate | ENOUGH_DATA | 39.7 | 44.2 | 44.2 | |
491 | pause | ENOUGH_DATA | 39.87 | 44.2 | 44.2 | 手动暂停 |
492 | play | ENOUGH_DATA | 39.87 | 44.2 | 44.2 | play()事件触发 |
493 | playing | ENOUGH_DATA | 40.06 | 44.2 | 44.2 | |
494 | timeupdate | ENOUGH_DATA | 40.24 | 44.2 | 44.2 | |
... | | | | | | |
509 | timeupdate | ENOUGH_DATA | 43.99 | 44.2 | 44.2 | |
510 | timeupdate | METADATA | 0 | 44.2 | 44.2 | 播放完毕 |
511 | seeking | METADATA | 0 | 44.2 | 44.2 | 寻找中 |
512 | waiting | METADATA | 0 | 44.2 | 44.2 | |
513 | progress | METADATA | 0 | 44.2 | 44.2 | |
514 | timeupdate | ENOUGH_DATA | 0 | 44.2 | 44.2 | |
515 | seeked | ENOUGH_DATA | 0.05 | 44.2 | 44.2 | 播放完毕进度回到起点循环播放 |
516 | canplay | ENOUGH_DATA | 0.25 | 44.2 | 44.2 | |
... | | | | | | |
802 | timeupdate | ENOUGH_DATA | 23.46 | 44.2 | 44.2 | |
803 | error | ENOUGH_DATA | 0 | 44.2 | 44.2 | 网络断开错误 |
804 | timeupdate | ENOUGH_DATA | 0 | 44.2 | 44.2 | 无法继续播放 |
event | readyState | currentTime (s) | buffered (s) | duration (s) | 视频状态 | |
---|---|---|---|---|---|---|
1 | loadstart | NOTHING | 0 | null | NaN | 准备请求数据(初始化完毕) |
2 | play | NOTHING | 0 | null | NaN | 状态是开始播放,但视频并未真正开始播放 |
3 | waiting | NOTHING | 0 | null | NaN | 等待数据 |
4 | durationchange | METADATA | 0 | 7.63 | 44.2 | 获取到视频长度 |
5 | loadedmetadata | METADATA | 0 | 7.63 | 44.2 | 获取到元数据 |
6 | loadeddata | ENOUGH_DATA | 0 | 7.63 | 44.2 | |
7 | canplay | ENOUGH_DATA | 0 | 7.63 | 44.2 | 可以播放,但中途可能因为加载而暂停 |
8 | canplaythrough | ENOUGH_DATA | 0 | 7.63 | 44.2 | 可以流畅播放 |
9 | playing | ENOUGH_DATA | 0 | 7.63 | 44.2 | 开始播放 |
10 | timeupdate | ENOUGH_DATA | 0 | 7.63 | 44.2 | 播放进度变化 |
11 | timeupdate | ENOUGH_DATA | 0.25 | 7.63 | 44.2 | |
... | | | | | | |
22 | timeupdate | ENOUGH_DATA | 3.01 | 36.24 | 44.2 | |
23 | progress | ENOUGH_DATA | 3.15 | 44.2 | 44.2 | 持续下载 |
24 | suspend | ENOUGH_DATA | 3.16 | 44.2 | 44.2 | |
25 | timeupdate | ENOUGH_DATA | 3.26 | 44.2 | 44.2 | |
... | | | | | | |
39 | pause | ENOUGH_DATA | 6.47 | 44.2 | 44.2 | 手动暂停 |
40 | play | ENOUGH_DATA | 6.51 | 44.2 | 44.2 | |
41 | playing | ENOUGH_DATA | 6.5 | 44.2 | 44.2 | |
42 | timeupdate | ENOUGH_DATA | 6.72 | 44.2 | 44.2 | |
... | | | | | | |
61 | timeupdate | ENOUGH_DATA | 11.4 | 44.2 | 44.2 | |
62 | pause | ENOUGH_DATA | 11.4 | 44.2 | 44.2 | 网络环境切换,自动触发 |
63 | play | ENOUGH_DATA | 11.38 | 44.2 | 44.2 | |
64 | playing | ENOUGH_DATA | 11.41 | 44.2 | 44.2 | |
65 | timeupdate | ENOUGH_DATA | 11.6 | 44.2 | 44.2 | |
... | | | | | | |
198 | timeupdate | ENOUGH_DATA | 44.15 | 44.2 | 44.2 | |
199 | timeupdate | ENOUGH_DATA | 0 | 44.2 | 44.2 | 播放完毕 |
200 | seeking | ENOUGH_DATA | 0 | 44.2 | 44.2 | 寻找中 |
201 | timeupdate | ENOUGH_DATA | 0.1 | 44.2 | 44.2 | |
202 | seeked | ENOUGH_DATA | 0.2 | 44.2 | 44.2 | 播放完毕进度回到起点循环播放 |
203 | timeupdate | ENOUGH_DATA | 0.37 | 44.2 | 44.2 | |
与微信无明显差异
与微信无明显差异
event | readyState | currentTime (s) | buffered (s) | duration (s) | 视频状态 | |
---|---|---|---|---|---|---|
1 | loadstart | NOTHING | 0 | null | NaN | 准备请求数据(初始化完毕) |
2 | progress | METADATA | 0 | null | 44.2 | |
3 | suspend | METADATA | 0 | null | 44.2 | |
4 | durationchange | METADATA | 0 | null | 44.2 | |
5 | loadedmetadata | METADATA | 0 | null | 44.2 | 未触发play()事件之前,自动触发以上事件 |
6 | timeupdate | METADATA | 0 | null | 44.2 | 触发play()事件,开始播放 |
7 | timeupdate | METADATA | 0 | null | 44.2 | |
8 | timeupdate | METADATA | 0 | null | 44.2 | |
在QQ浏览器中除了可以获取视频长度,其他属性均无法获取。鉴于其表现比较诡异,我们的对比中除开此特例。
<
event | readyState | currentTime (s) | buffered (s) | duration (s) | 视频状态 | |
---|---|---|---|---|---|---|
1 | loadstart | CURRENT_DATA | 0 | null | 1 | 准备请求数据(初始化完毕) |
2 | durationchange | CURRENT_DATA | 0 | null | 1 | |
3 | loadedmetadata | CURRENT_DATA | 0 | null | 1 | |
4 | loadeddata | CURRENT_DATA | 0 | null | 1 | |
5 | stalled | CURRENT_DATA | 0 | null | 1 |