欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

总结手机视频播放的误区(不时更新)

最编程 2024-03-08 08:33:17
...

以下为自己亲身踩过的坑,希望对你有帮助~

1、x5同层播放器

移动端浏览器中的video元素是比较特别的,早期无论是在iOS还是Android的浏览器中,它都位于页面的最顶层,无法被遮盖。后来这个问题在iOS下得到了解决,但是Android的浏览器则问题依旧。X5是腾讯基于Webkit开发的渲染引擎,它提供了一种名叫「同层播放器」的特殊video元素以解决遮盖问题。

只要给普通的video元素加上X5的自定义属性 x5-video-player-type,就可以调用同层播放器。

<div class="player">
    <video id="video" class="video" controls="controls" playsinline x5-video-player-type="h5">
        <source src="video.mp4" />
    </video>
</div>

同层播放器的视频样式和ios的视频播放器是一样的。安卓的原生播放器(非同层播放器)无法控制是否自动播放、点击播放时是否自动全屏。

如果你需要安卓的视频样式和ios表现为一样,可以使用腾讯的H5同层播放器接入规范

同层页面内播放是标准的视频播放形态,在video标签中添加x5-video-player-type:h5-page属性来控制网页内部同层播放,可以在视频上方显示html元素。

坑点注意:

使用x5的tbs同层播放器,在tbs版本4.5.2以下(这个是经过测试了10几台安卓手机得出来的),视频的右上方会出现一个无法去除的全屏按钮,如图:

想要去掉这个按钮,要通过css把视频区域挤出屏幕外,在通过object-opsition把视频定位回正常的位置,以下video-player__main__tech为video元素:

        &.x5-android {
            overflow: hidden;
            & {
                .video-player__main {
                    padding-left: 200px;
                    width: calc(100% + 200px);
                    .video-player__main__tech {
                        position: absolute;
                        width: calc(100% - 200px) !important;
                        right: 0;
                         object-position: calc(50% - 200px) 50% !important;
                    }
                }
            }
            }

必须注意的是,x5下tbs版本在4.5.2以上是不需要做样式适配的,否则会造成视频画面缺失,因此使用前要先做判断:

isAndroidX5SupportInlinePlayer() {
        const ua = window.navigator.userAgent;
        const tbs = ua.match(/TBS\/([\d.]+)/);

        const x5 = {
            tbsWx: ua.match(/MicroMessenger/i) == 'micromessenger' && tbs && tbs[1] >= 36849,
            // tbsQQ: browser.versions.QQ && isTBS && (isTBS[1]>= 36855) && (isTBS[1] <= 45200), // qq 内置 webview
            MQQBrowser: ua.match(/MQQBrowser\/([\d.]+)/) && ua.match(/MQQBrowser\/([\d.]+)/)[1] >= 7.2, // qq 浏览器 或者  qq 内置 webview
            tbsX5: tbs && tbs[1] >= 36900 && (isTBS[1] <= 45200)// 第三方接入 TBS x5 内核,如孕管安卓。注意:安卓 QQ 浏览器的 UA 没有 TBS(安卓 QQ 内置 webview 的 UA 有 TBS)
        };
        return (
            (ua.indexOf('Android') > -1 || ua.indexOf('Linux') > -1) &&
            (x5.tbsWx || x5.tbsQQ || x5.MQQBrowser || x5.tbsX5)
        );
    },

2、autoplay自动播放

video标签可以设置自动播放,只需在标签设置autoplay即可。但是,设置自动播放是会有兼容性问题的,并不是所有机型都可以。

1.我所遇到的,设置了autoply ios基本可以实现自动播放,但是要设置静音,即:没音频轨道,或者设置了muted属性。

2.安卓的话,只有部分机型可以自动播放。而且不能模拟自动播放,一定要有用户行为才可以触发播放。

微信自动播放

微信自动播放实在是太多坑了T_T,具体表现为

1、ios在用户无交互时触发play()方法会报错,导致视频无法加载。 解决方法:

                document.addEventListener(
                    "WeixinJSBridgeReady",
                    () => {
                            this.video.play();
                    },
                    false
                ); // 兼容微信自动播放

但是这个方法也有一个问题,关乎于WeixinJSBridge的注入时机,有时候快有时候慢。因此如果项目是像vue这种单页应用,需要额外加载js生成dom元素,才能定义以上方法,会导致定义的WeixinJSBridgeReady不一定每次都可以触发,所以不一定每次自动播放都能成功。

2、安卓里面,如果设置了自动播放,视频会先播放(但是currentTime没有变,视频在加载,因此并没有播放进度),视频加载完会,就会自动暂停。如果封面图是自己实现的,不是使用video的,就会给用户一种不正常的表现(因为用户的体验是,视频并没有进行播放,封面图却消失了)。我的解决方法:

  • 监听视频的pause事件
  • 如果视频的currentTime为false(0或者NaN),是安卓并且是微信,则恢复封面图的显示。
                onPause: function() {
                    self.status = "暂停";
                    self.isPlaying = false;
                    if(!self.currentTime && !util.isIOS() && util.isWeixin()) {
                        // 微信下安卓设置了自动播放,还没播放就会自动暂停,然后封面图就会消失了,会给人一种不正常的感觉,
                        // 因此用这种方法恢复封面图
                        self.isPlayed = false;  
                    }else{
                        self._fixShowControl();
                    }
                },

3、视频行内播放

默认情况下,点击video播放会全屏播放,如果想要视频在局部内可以播放的话,可以设置:x5-playsinline

坑点注意:

如果想播放时默认全屏播放,在设置了x5-video-player-type=h5这个属性,即使存在x5-video-player-fullscree=true,安卓也是是不能默认全屏播放的。解决方法:在点击播放视频的事件那里添加视频全屏的操作

4、视频全屏播放后的大小

这个情况只针对安卓的同层播放器播放时全屏播放的情况。在同层播放器全屏播放后,视频底色会变成黑色,然后视频只是在中间居中,大小是原来视频设置的大小,并不是会全屏铺满。

效果如图。
1、我第一次采用的方案是,当视频全屏时,会触发onresize方法,在该方法里面强制把视频的大小设置为屏幕的宽高:

let video = this.$refs.video;
            // 以下代码是为了解决安卓播放无办法自动全屏
            this.myPlayer.on('play',() => {
                console.log('play')
                    window.onresize = function () {
                    document.querySelector('.video-container').style.width = window.innerWidth + "px";
                    document.querySelector('.video-container').style.height = document.documentElement.clientHeight + "px";         
                    }
            })
            this.myPlayer.on('pause',() => {
                console.log('pause')
                window.onresize = function () {
                    document.querySelector('.video-container').style.width = "270px";
                    document.querySelector('.video-container').style.height = "170px";
                }
            })

但是这种方法,由于是整个视频的尺寸直接设置为当前屏幕的宽高,因此测试反映说视频被拉伸变形了,因为尺寸不是按照比例的。

2、因此,采取以下方案。videoHeight()和videoWidth()分别获取原视频的高和宽,然后与屏幕的宽高计算出比例。

            if (MJSSDK.UA.android) {
                this.myPlayer.on('play', () => {
                    // console.log('play');
                    window.onresize = () => {
                        // console.log('onresize-play');
                        this.isfull = true;
                        let vheight = this.myPlayer.videoHeight();
                        let vweight = this.myPlayer.videoWidth();
                        let clientHeight = document.documentElement.clientHeight;
                        document.querySelector('.video-container').style.width = (clientHeight * vweight) / vheight + 'px';
                        document.querySelector('.video-container').style.height = clientHeight + 'px';
                        document.querySelector('#my-video').style.backgroundColor = 'black';
                    };
                });
                this.myPlayer.on('pause', () => {
                    // console.log('pause');
                    window.onresize = () => {
                        // console.log('onresize-pause');
                        this.isfull = false;
                        // 全屏后,华为等部分机型会有白边,是页面的颜色,用该值控制背景色
                        document.querySelector('.video-container').style.width = '270px';
                        document.querySelector('.video-container').style.height = '170px';
                    };
                });
            }
        },

5、视频全屏后出现白边

安卓启用同层播放器后全屏出现的,这是个很诡异的问题,仅在部分的安卓机型下出现。如图:

经过排查,该白边是页面的颜色,就是同层播放器的全屏是把这个页面旋转过来,然后区域放大这样。 解决方法:全屏时把页面背景色设置为黑色,取消全屏时改回来。

6、全屏方法调用问题

由于视频播放器的控制条是自己实现的,所以需要实现自己全屏方法。

1、原生全屏

原生全屏一般会使用这种方法:

        if (video.requestFullscreen) {
            video.requestFullscreen();
        } else if (video.mozRequestFullScreen) {
            video.mozRequestFullScreen();
        } else if (video.webkitRequestFullscreen) {
            video.webkitRequestFullscreen();
        } else if (video.webkitSupportsFullscreen) {
            video.webkitEnterFullscreen();
        } else if (video.msRequestFullscreen) {
            video.msRequestFullscreen();
        } else {
            this.addClass(el, "video-player--is-cssfullscreen");
        }

后来看了videojs的源码,发现可以用screenfull.js这个库直接实现全屏,非常方便。

import screenfull from "screenfull";
if (screenfull.isEnabled) {
    screenfull.request(video);
}

但是,在ios上面调试,发现screenfull.request(video)无法实现全屏,而且也无法监听得到全屏变化事件。只有webkitEnterFullscreen()才可以在ios实现全屏

因此,为了兼容ios:

                if (util.isIOS()) {
                    document.getElementById(this.vId).webkitEnterFullscreen();
                    return;
                }

2、伪全屏

这里的伪全屏是指通过css实现的样式全屏,可以实现自定义html元素覆盖在视频上。

1、竖版全屏

需要全屏时,给视频添加如下样式:

.video-player--is-cssfullscreen {
            position: fixed !important;
            left: 0 !important;
            top: 0 !important;
            width: 100% !important;
            height: 100% !important;
            z-index: $z-index-video !important;
    }

2、横版全屏

点击全屏时,先把video元素的最外层父容器旋转90度,并设置为fixed,固定窗口。为了使视频能够居中,left设置为50%,top为当前文档宽度的一半,我这里为-375px。

.cross-screen {
        position: fixed;
        top: -375px;
        left: 50%;
        background: #000;
        transform-origin: 0;
        transform: rotate(90deg) translate3d(0, 0, 0);
    }

video的上一层父元素的宽设置为窗口的高,高则设置为当前窗口的宽:

        this.crossScreenStyle = {
            width: window.innerHeight + "px",
            height: window.innerWidth + "px",
        };

坑点注意:

如果同时设置了position:fixed 以及transform属性,可能会导致z-index层级表现异常,层级高的元素被层级低的覆盖了。解决方法:层级高的元素额外添加属性transform: translateZ(100px),把元素提升上来

7、video 标签被浏览器劫持接管

现象:

强制出现controls控制条

强制全屏

强制画中画

强制浮动播放器且浮动有bug

等等。。。

这里是指即使使用了x5同层播放器,还是会出现以上现象。

我目前是在vivo的某台手机复现过。

解决方案

浏览器厂商添加域名白名单。如 uc ios 白名单的域名有 *.v.qq.com *.taobao.com

8、动态插入video标签的问题

为了提升页面渲染性能,会考虑动态插入插入video标签,例如点击了播放才把video标签插入到对应容器里面。

但是,如果启用了x5同层播放器,动态插入的video是会被浏览器劫持的。

解决方案

1、可以使用第7点的解决方案

2、判断是x5内核下,则不使用动态插入的方式