资讯专栏INFORMATION COLUMN

关于 video 播放的新探索

Shihira / 2991人阅读

摘要:使用标签这是关于给出的基本用例。其实我们也是在这种背景下研究出来新的技术问题解决清晰度无缝切换的。这样之前说的所有成本问题都不存在,还能做到相同体验的无缝切换。所有代码来自带解析器能节省流量的西瓜播放器

前端同学要使用 HTML5 播放器视频,必然会使用 video 标签,不过大多数同学只是使用了较简单的功能,其实它本身拥有不凡之力有待我们发现。

首先,我们先来看下 video 最基础的用法:

使用 src 属性

使用 source 标签

这是 MDN 关于 video 给出的基本用例。在这里我们简单介绍下两种方法的不同,src 只能赋予 video 一个播放地址,当浏览器不支持这种视频格式的解码时就会出现错误,导致视频播放失败。为了解决这个问题才有了 source 标签,利用多个 source 标签引入不同格式的视频,从上到下解析直到遇到看上述代码当浏览器不支持 ogg 格式时,浏览器会自动播放 foo.mp4。

实用技巧

我们会发现使用 video:src 属性播放视频的时候会经常出现播放失败,我们该怎么做能提升视频播放的质量?

这种情况一般都使用 cdn,为了更保险一般还会将不同的 cdn 厂商分为主用 cdn 和备用 cdn。那么问题来了,我们怎么利用 video 本身的特性并结合 cdn 保证我们的视频播放质量?

不难看出,source 标签不仅支持不同视频格式的自动切换,也适用于相同视频格式的失败切换,即 main.mp4 因网络问题无法获取时浏览器会自动切换到 backup.mp4 。

高阶技能

如果大家浏览视频的时候,可以发现很多网站的 video 是这个样子的:

如果直接访问 blob 这个地址发现并不存在。

这个地址就是映射 Blob 对象的 DOMString,其实 video 属性 src 支持 Blob 的,不过新的标准是使用 srcObject 属性来替代这一个功能,目前代码可以这样写:

const mediaSource = new MediaSource();
const video = document.createElement("video");
try {
  video.srcObject = mediaSource;
} catch (error) {
  video.src = URL.createObjectURL(mediaSource);
}

在这段代码中除了 Blob 对象,还有 MediaSource 对象,让 video 拥有不凡之力的主要因素是浏览器对 MediaSource 对象的支持,才让 JavaScript 对 video 有了更大的操纵空间。关于如何使用 MediaSource 不在本文讲述,大家可以自行查阅,我们要说的是 video 结合 MediaSource 可以做哪些事情?

清晰度无缝切换

点播领域里 mp4 是最普遍、兼容性最好的视频容器,不过 mp4 也有它的局限性,比如常见的清晰度切换,我们是无法像youtube那样做到无缝切换的。我们可以看下普通的mp4播放的网络请求和youtube视频播放的网络请求的区别。

图1.1 普通mp4的下载请求过程

图1.2 Youtube视频下载请求过程

这两张图不难看出,在默认情况下 mp4 使用一次 http 请求所有的视频数据,Youtube 则分次请求。当然这个描述很不专业,但确实形象。造成这种差异的是 video 不支持流式的视频数据,Youtube 采用的是流式的视频容器 webm,而 mp4 是非流式的。那如何解释清楚流式的视频数据呢,从专业的角度三言两语很难说清楚,但用大白话翻译过来就是流式的视频数据支持分段独立播放,非流式的不可以。换句话说一个10M的视频文件,流式的视频可以把0~1M的数据请求回来多带带播放,但是非流式的不可以。

上面我们描述了视频格式的不同,接下来我们要说的是第一张图中的视频加载是浏览器来控制的,通过给 video 的 src 属性配置视频地址,触发播放之后浏览器就会开始下载了,JS干涉不了。而 Youtube 的视频加载是通过JS来控制的,各位可以再次看下第二张图的网络请求类型:xhr,足以证明这一点。

上面两点搞清楚之后我们就该说下清晰度切换的事情了。这个需求大家都不陌生,但是直接使用 mp4 格式做无缝清晰度切换,难度还挺大的。先解释下“无缝清晰度切换”的概念:从播放一个分辨率的视频到另一个分辨率且保证画面、声音不停顿的平滑切换过程。了解了这个概念,大家应该知道了用 video 无缝切换 mp4 有多难。一方面,video 是不支持流式的视频格式的,一方面,video 的加载是不受JS控制的。通过切换 video 的 src 属性,必然会导致画面中断、重新请求视频数据等。有的同学想到说利用两个 video 再结合 z-index 来搞,但是当你生成另一个video去加载视频的时候,无法保证两个画面是严格一致的,即使将原来的画面暂停到一个时刻,用另一个视频通过 currentTime 属性与之同步,切换仍然看到画面闪烁,基本无法和 Youtube 无缝切换的体验匹敌。而且还会造成更多流量的浪费,背后的原因大家可以研究下 mp4 容器和 webm 容器的异同,也可以看下视频解码相关的文章。

还有一种方法就是将 mp4 格式统统转码到流式的视频格式比如 hls、webm 等。不过这种看上去可行的方式实际上会带来很大的成本开销,如将大量视频做转码会消耗高昂的机器资源、双倍存储的费用、CDN的双倍费用等等。其实我们也是在这种背景下研究出来新的技术问题解决清晰度无缝切换的。

首先,我们改变对 mp4 视频的播放流程,不再直接使用 video 的 src 来播放,因为我们没有任何可以操作的空间。video不仅支持 src 属性还支持 Blob 对象,我们就是利用后者。播放的流程如下:


图1.3 mp4 视频新播放流程

来请求 mp4 视频数据,这样可以结合视频 Range 服务,做到精确加载。

编写解析器将加载回来的部分 mp4 视频数据进行解复用

将解复用的视频数据转成 fmp4 格式并传递给 MediaSource

使用 video 进行解码完成播放

然后在做清晰度切换的时候流程如下:


图1.4 mp4视频清晰度切换原理示意图

来请求 mp4 视频数据,这样可以结合视频 Range 服务,做到精确加载。

编写解析器将加载回来的部分 mp4 视频数据进行解复用

将解复用的视频数据转成 fmp4 格式并传递给 MediaSource

使用 video 进行解码完成播放

然后在做清晰度切换的时候流程如下:


图1.5 mp4视频清晰度切换流程示意图

这个过程看上去比较繁琐,但是所有的操作都是在浏览器端完成,也就是说都是JS来实现的。这样之前说的所有成本问题都不存在,还能做到youtube相同体验的无缝切换。如果大家也想使用这个功能不需要自己再去实现一遍上述流程,可以使用如下代码:

import Player from "xgplayer";
import "xgplayer-mp4";

let player = new Player({
      el:document.querySelector("#mse"),
      url: [{src:"/mp4/",type:"video/mp4"},{src:"/mp5/",type:"video/mp4"}]
});

player.emit("resourceReady", [{name: "高清", url: "/mp4/",cname:"高清"}, {name: "超清", url: "/mp5/",cname:"超清"}]);

如果对这段代码有什么疑惑或者想深入了解下它背后是如何实现的可以参考 文档 或者 Github。

节省视频流量

我们平时直接使用video加载视频,大概是这样的:


图2.1 video默认下载截图

我随便找了个视频,大家看下视频总长度是 02:08,在播放到 00:05 的时候,浏览器已经下载到 01:30 了,如果用户终止观看,下载的视频就这样被浪费掉了。当然,如果不断的 seek 也会造成较多的流量浪费。按照我们之前的统计在短视频领域,用户 seek 的频率在 80%,所以这部分流量是可以节省掉的。具体原理如下:


图2.2 播放器加载视频原理

设置每次加载的数据包大小

设置预加载时长

开启加载队列,完成第一次数据包下载,判断缓冲时间和预加载时长是否满足,不满足请求下一个数据包

具体实现代码如下:

  import Player from "xgplayer";
  import "xgplayer-mp4";
  const player = new Player({
    id:"vs",
    url:"//abc.com/a/mp4",
    preloadTime:10
  });

这样就实现了视频在播放过程中永远只预加载10秒的数据,进而保证节省流量。

所有代码来自带解析器、能节省流量的西瓜播放器,Github

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96055.html

相关文章

  • 代码自动生成在重构中的一次探索

    摘要:事件只能携带一个的。例如在上述代码示例中的将所有使用发布事件的地方,全部修改为使用的方法。是否能够编写脚本或者自动化工具,自动化的完成重构工作。实施方案使用注解解析自动生成文件我们都知道,是通过注解来实现的。 欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:吴涛 导语:EventBus 已经火了很长一段时间了。最近我们项目决定引入EventBus,替换我们播放器现在的事...

    ztyzz 评论0 收藏0
  • 探索支付宝账单的技术实现

    摘要:年度的支付宝账单果然不负众望,再一次刷屏了。于是乎,我决定探究一下支付宝账单背后的技术实现。三后端数据整合这部分内容将重点介绍支付宝账单数据的形成,纯属个人对支付宝技术架构的了解进行猜想的,并不代表是真实的运作情况。 2017年度的支付宝账单果然不负众望,再一次刷屏了。 回顾一下这个年关,现象级的刷屏活动就有三起: 秀18岁;秀网易音乐歌单;秀支付宝账单。 一位网友调侃道:2018年大...

    JiaXinYi 评论0 收藏0
  • 【小案例】基于色键技术的纯客户端实时蒙版弹幕

    摘要:组件提供了一系列的操作接口以方便用户对弹幕的相关特性进行定制。对于这种类型的图像,我们可以使用色键的方式进行抠图生成蒙版。其中,用于更新蒙版的接口为。 导读:本文内容是笔者最近实现的 web 端弹幕组件—— Barrage UI 的一个延伸。在阅读本文的实例和相关代码之前,不妨先浏览项目文档,对组件的使用方式和相关接口进行了解。 各位童鞋如果经常上 B 站(bilibili.com) ...

    muzhuyu 评论0 收藏0

发表评论

0条评论

Shihira

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<