H5视频化调研浅析

1,759 阅读9分钟

目前图文形式向视频化转型已经成为一种风向,其中H5视频化能做到一次开发,多端通用。

这里简单调研下H5播放视频的一些问题和解决方案。主要分为三部分:

  1. H5视频化所遇到的问题
  2. 对视频的一些基础操作
  3. 调研大厂,小红书,B站,抖音的H5页面在各浏览器的播放情况

相信一定有所收获~

0.视频加载基本介绍

在视频/音频(audio/video)加载过程中,事件的触发顺序如下:

  1. onloadstart (浏览器开始寻找指定资源)
  2. ondurationchange (视频/音频 的时长发生变化时触发)
  3. onloadedmetadata (指定视频/音频 的元数据加载后触发)
  4. onloadeddata (当前帧的数据加载完成且还没有足够的数据播放)
  5. onprogress (下载指定的视频/音频 时触发)
  6. oncanplay (用户可以开始播放视频/音频 时触发)
  7. oncanplaythrough (可以正常播放且无需停顿和缓冲时触发)

一.H5视频化所遇到的问题

1.初始化样式不统一

由于各家浏览器播放视频时展示的视频控件样式并不一致,所以建议隐藏默认的视频播放控件,自己开发统一。

const video = document.createElement('video');
const source = document.createElement('source');
source.setAttribute('src', src);
video.textContent = '您的浏览器不支持 video 标签。';
video.appendChild(source);
video.setAttribute('controls', false);
video.controls = false;

2.自动播放的问题

这是由Chrome的官方策略导致:developers.google.com/web/updates… 并且在IOS10后的safari和微信也均不能自动播放

解决方式有以下几种:

(1).视频静音状态自动播放

const video = document.createElement('video');
const source = document.createElement('source');
source.setAttribute('src', src);
video.textContent = '您的浏览器不支持 video 标签。';
video.appendChild(source);
video.muted = true;
video.setAttribute('autoplay', true);
video.setAttribute('controls', false);
video.controls = false;

(2).引导用户点击播放

考验产品的交互设计能力,可以参考B站的页面,截图见B站视频化测试一章

(3).媒体参与指数(MEI) 达到一定的值时可以自动播放

MEI是衡量个人在网站上消费媒体的倾向。

Chrome的策略可以看这个文档: 官方文档 规则大概如下:

  • 媒体(音频/视频)的播放大于7秒
  • 音频存在且未取消静音。
  • 带视频的标签处于活跃状态
  • 视频大小(以px为单位)必须大于200x140

Chrome会计算媒体互动分数,当它足够高时,允许媒体 仅在桌面上 自动播放。(比如B站,youtube

用户的MEI可在chrome://media-engagement/内部页面上找到。

(4).同源地址第二次进入时可以自动播放,刷新页面也可以

这点建议自己试试,依赖浏览器的兼容性,不是很稳定

3.视频全屏播放问题

ios端播放视频会弹出全屏的效果,而且视频会 “浮” 在页面上,页面上的所有元素都只能在视频元素下面,设置z-index也没有任何的效果。ios环境的微信浏览器也是如此。

解决方式:

设置webkit-playsinlineplaysinline属性,基本就可以将视频内敛到webview里面了

video.setAttribute('webkit-playsinline', true);
video.setAttribute('playsinline', true);

4.poster封面问题

android下,多数设备是不显示视频封面的,即使加上poster属性

微信浏览器不自动播放的时候,封面背景为黑色,且微信浏览器无法截取第一帧作为封面。

posterandroid兼容性不好,更建议在视频上层加个div图片。

由于android不允许视频上层有东西(层级问题,可以采用下面的一种方式方式),所以首先将视频设为的width:1px,当播放后,上层的封面remove掉,同时width:100%或者你想要的宽度。

5.video层级问题

X5浏览器里默认video播放时的层级是最高的,无论你调多大的z-index参数都不能改变,所幸的是微信在2017年9月提供了支持,只要我们在video中加上x5-video-player-type='h5' 就可以实现在video上再加DOM

video.setAttribute('x5-video-player-type', 'h5');
video.setAttribute('x5-video-orientation', 'portrait');

二.对H5视频的简单操作

1.初始化video

    const awareness = ({ src }) => {
       const video = document.createElement('video');
       const source = document.createElement('source');
       source.setAttribute('src', src);
       video.textContent = '您的浏览器不支持 video 标签。';
       video.appendChild(source);
       video.setAttribute('loop', true);
       video.setAttribute('width', '100%');
       video.setAttribute('preload', 'auto');
           // 解决视频层级过高的问题,视频播放不会进入全屏状态,启用X5内核同层渲染
       video.setAttribute('x5-video-player-type', 'h5-page');
           // 播放器支付的方向, landscape横屏,portraint竖屏,默认值为竖屏
       video.setAttribute('x5-video-orientation', 'andscape|portrait');
           // ios 10中设置可以让视频在小窗内播放,也就是不是全屏播放
       video.setAttribute('webkit-playsinline', true);
           // IOS微信浏览器支持小窗内播放
       video.setAttribute('playsinline', true);
       // 更改视频资源,并重新载入视频
      // video.load();
       return video;
   };

2.获取视频的第一帧

通过创建canvas标签,利用其drawImage() 方法在画布上绘制该视频,然后运用toDataURL方法转换canvas上的图片为base64格式,并将base64格式的图片作为video标签的poster属性。

需要注意的是,由于canvas无法对跨域的图片进行操作,需要提前处理好跨域问题。

function getVideoBase64(url) {
    return new Promise(function (resolve, reject) {
        let dataURL = ''
        let video = document.createElement("video");
        video.setAttribute('crossOrigin', 'anonymous');//处理跨域
        video.setAttribute('src', url);
        video.setAttribute('width', 400);
        video.setAttribute('height', 240);
        video.addEventListener('loadeddata', function () {
            let canvas = document.createElement("canvas")
            let width = video.width //canvas的尺寸和图片一样
            let height = video.height
            canvas.width = width
            canvas.height = height
            canvas.getContext("2d").drawImage(video, 0, 0, width, height); //绘制canvas
            dataURL = canvas.toDataURL('image/jpeg'); //转换为base64
            resolve(dataURL)
        })
    })
}

3. 获取视频尺寸

video.onloadedmetadata = () => {
    const height = video.videoHeight
    const width = video.videoWidth
}

4.给视频加封面,让视频上下居中

// 等到元数据加载完成
const loadedmetadata = () => {
    const video = videoRef.current;
    // 获取视频的宽和高
    const height = video.videoHeight;
    const width = video.videoWidth;
    video.height = width / 750 * height;
    // 根据设计稿尺寸设置高度
    video.setAttribute('height', width / 750 * height);
    video.setAttribute('poster', cover);
    const { offsetHeight } = document.body;
    const { offsetWidth } = document.body;
    // 设置距离顶部的高度,让视频上下居中
    const topHeight = `${(offsetHeight - video.offsetHeight) / 750 * offsetWidth - state.navBarHeight}px`;
    video.style.top = `${(offsetHeight - video.offsetHeight) / 750 * offsetWidth - 15}px`;
    // 获取视频的时长并设置
    if (video.duration) {
        setDuration(video.duration);
    }
};

5.video事件监听

/**
 * @description: video上需要监听的事件
 */
const videoMountEvent = () => {
  const video = videoRef.current;
  video.addEventListener("loadedmetadata", loadedmetadata);
  video.addEventListener("play", play);
  video.addEventListener("playing", playing);
  video.addEventListener("waiting", waiting);
  video.addEventListener("pause", pause);
  video.addEventListener("ended", ended);
};
/**
 * @description: video上需要卸载的事件
 */
const videoUnmountEvent = () => {
  const video = videoRef.current;
  video.removeEventListener("loadedmetadata", loadedmetadata);
  video.removeEventListener("play", play);
  video.removeEventListener("playing", playing);
  video.removeEventListener("waiting", waiting);
  video.removeEventListener("pause", pause);
  video.removeEventListener("ended", ended);
};

6.设置进度条

/**
     * @description: 设置进度条
     */
const setProgress = () => {
    const video = videoRef.current;
    timeID.current = requestAnimationFrame(() => {
        setCurrentTime(video.currentTime);
        setProgress();
    });
};
/**
 * @description: 视频暂停中
 * @return {*}
 */
const pause = () => {
  // 取消进度条更新
    cancelAnimationFrame(timeID.current);
    setVideoStatus('pause');
};
/**
 * @description: 视频播放完成
 * @return {*}
 */
const ended = () => {
   // 取消进度条更新
    cancelAnimationFrame(timeID.current);
    setVideoStatus('ended');
};
const Progress = ({ duration, currentTime }) => {
return (
    <>
        {!!duration && (
            <div className={cx('video-controll_progress')}>
                <div
                    className={cx('video-controll_progress__line')}
                    style={{ width: `${(currentTime / duration) * 100}%` }}
                >
                </div>
            </div>
        )}
    </>
);
};

三.测试各家大厂的H5播放情况

1.小红书

(1).设备信息

手机型号

(2). H5页面播放情况

使用的地址:www.xiaohongshu.com/discovery/i…

浏览器图标版本展示情况说明
360浏览器v10.0.5.3001.进页面就会被浏览器的控件接管2.可以播放和暂停
UC浏览器image.pngv15.1.2.1202image.pngimage.png1.能播放,能暂停2.会展示浏览器自带的视频控件3.会提示下载app
搜狗浏览器image.png11.9.7.7100image.pngimage.pngimage.png1.可以播放,第一次播放时会黑屏一会2.可以暂停3.会提示下载app
百度浏览器image.png135010image.pngimage.pngimage.png1.点击能播放2.播放后会展示出浏览器默认的控件3.播放能暂停4.会提示下载app
chromeimage.png78.0.3904.96image.pngimage.pngimage.png1.点击能播放2.播放时能暂停3.暂停后会提示有可能危险文件,是否保留
火狐浏览器image.png68.12.0image.png没有播放按钮,点击不能播放,点啥都不行,没有任何反应
自带浏览器image.png48.8.4.1_f00a28eimage.pngimage.pngimage.png1.不能自动播放2.点击能播放,再点击能暂停3.点击暂停后,会有弹窗
微信浏览器image.png8.0.33image.pngimage.pngimage.png1.不能自动播放2.点播放按钮能播放3.播放状态下,点视频会跳转到下载页面

2. 抖音

(1).设备信息

手机型号

(2).H5页面播放情况

使用的地址:m.ixigua.com/douyin/shar…

浏览器图标版本展示情况说明
夸克浏览器image.png6.2.0.245image.pngimage.png1.可以播放和暂停2.但会出现浏览器自带的控件
360浏览器image.pngv10.0.5.300image.pngimage.png1.不能自动播放2.点击能播放,能暂停
UC浏览器image.pngv15.1.2.1202image.png image.png1.不能自动播放2.点击能播放,能暂停3.播放后会展示浏览器自带的控件,且控件会占满页面,看不到其他操作按钮,甚至没办法缩小
搜狗浏览器image.png11.9.7.7100image.pngimage.png1.不能自动播放2.点击能播放,能暂停
百度浏览器image.png135010image.png image.png1.不能自动播放2.点击能播放,能暂停
chromeimage.png78.0.3904.96image.pngimage.png1.不能自动播放2.点击能播放,能暂停
火狐浏览器image.png68.12.0image.pngimage.png1.不能自动播放2.点击能播放,能暂停
自带浏览器image.png48.8.4.1_f00a28eimage.pngimage.png1.不能自动播放2.点击能播放,能暂停
微信浏览器image.png8.0.33image.png image.png1.不能自动播放2.点击能播放,能暂停

3. B站h5播放情况

(1).设备信息

手机型号
image.png

(2).H5页面播放情况

使用的地址:www.bilibili.com/video/BV1FM…

浏览器图标版本展示情况说明
浏览器图标版本展示情况说明
360浏览器image.pngv10.0.5.300image.pngimage.png1.进入页面后会先提示跳转app页面2.点击立即播放能播放3.有自定义控件
UC浏览器image.pngv15.1.2.1202image.pngimage.pngimage.png1.进入页面后会先弹出一个蒙层,推荐去app观看2.点几立即观看后,出现弹窗3.点击继续网页观看,能播放4.能自定义控件
搜狗浏览器image.png11.9.7.7100image.pngimage.png1.进入页面后会先提示跳转app页面2.能自定义控件
百度浏览器image.png135010image.pngimage.pngimage.png1.进入页面后会推荐去app观看2.点几立即观看后,出现弹窗3.点击继续网页观看,能播放4.能自定义控件
chromeimage.png78.0.3904.96image.pngimage.pngimage.png1.进入页面后会推荐去app观看2.点几立即观看后,出现弹窗3.点击继续网页观看,能播放4.能自定义控件
火狐浏览器image.png68.12.0image.pngimage.png1.先进入跳转app的页面2.之后会进入到无法理解该地址的情况
自带浏览器image.png48.8.4.1_f00a28eimage.pngimage.pngimage.png1.有自带的缓冲2.点击后有自带的控件3.能自动播放
微信浏览器image.png8.0.33image.pngimage.png1.不能自动播放2.点击后能播放,能自定义控件

总结

虽然会遇到各种各样的问题,甚至各大厂也没有完美的解决方案,但H5视频化已成互联网用户习惯,必须要做。

需要调研清楚,哪些是可以解决的问题,哪些是无法解决的feature,更考验与产品和测试的沟通(忽悠)能力。