Tech 扩展
Tech 是 videojs 中处理视频播放的技术,在【videojs 系列02】videojs 中四种扩展性设计 中我们知道,videojs 核心源码中提供了 Html5 作为默认 Tech,用于播放浏览器默认支持的视频类型。同时支持扩展 Tech,用于支持浏览器无法直接播放的视频类型,例如 flv、hls、dash 等。
在 videojs 源码中,定义了 Tech 基类和 Tech.registerTech
静态方法。所有的扩展 Tech 都直接或间接地继承自 Tech 并使用 Tech.registerTech
注册到全局。
videojs 官方提供了许多扩展 Tech,例如 videojs-youtube 和 videojs-vimeo
registerSourceHandler
除了实现 Tech 的派生类并 registerTech 之外,还有另一种方式扩展 Tech,即 registerSourceHandler
。
以 videojs 官方提供的 videojs-dash 为例,关键代码如下,完整代码见 videojs-dash.js。
定义一个 SourceHandler 并通过 registerSourceHandler
注册到 Html5 Tech 中,使得 Html5 Tech 可以支持更多视频类型。
videojs.DashSourceHandler = function() {
return {
canHandleSource(source) {
const dashExtRE = /\.mpd/i;
if (!canHandleKeySystems(source)) {
return '';
}
if (videojs.DashSourceHandler.canPlayType(source.type)) {
return 'probably';
} else if (dashExtRE.test(source.src)) {
return 'maybe';
}
return '';
},
handleSource(source, tech, options) {
return new Html5DashJS(source, tech, options);
},
canPlayType(type) {
return videojs.DashSourceHandler.canPlayType(type);
}
};
};
videojs.DashSourceHandler.canPlayType = function(type) {
const dashTypeRE = /^application\/dash\+xml/i;
if (dashTypeRE.test(type)) {
return 'probably';
}
return '';
};
// Only add the SourceHandler if the browser supports MediaSourceExtensions
if (window.MediaSource) {
videojs.getTech('Html5').registerSourceHandler(videojs.DashSourceHandler(), 0);
}
选择什么方案来播放 hls 直播流
关于 Hls 的支持,videojs 官方目前提供的最新支持是 videojs-http-streaming,简称 VHS,替代过去的 videojs-contrib-hls。
Github 上也有一些第三方实现,基于 hls.js 的扩展,例如基于 Tech.registerTech
实现的 videojs-hlsjs,和基于 registerSourceHandler
实现的 videojs-hlsjs-plugin。
对比这两个第三方库,可以发现使用 Tech.registerTech
会比使用 registerSourceHandler
代码更简单。
videojs 较新的版本已经默认内置了 VHS,只有 videojs.core.js 才是剔除了 VHS 的核心代码。但是对比 VHS 和 hls.js 源码之后,我们还是决定使用 hls.js。
因为 hls.js 代码结构更好,与 flv.js 结构类似,更容易理解。而且 hls.js 更加纯粹,没有和 videojs 绑定,可以单独使用或结合其他的播放器 UI 使用。
所以,最终方案是基于 hls.js 通过 Tech.registerTech
来实现扩展,但是 videojs-hlsjs 已经是 4 年前的代码,比较落后。鉴于继承 Tech 自己重写也比较简单,这里就自己写了一个 Hls Tech。
自己实现的 hls tech
基于 hls.js 实现 Tech 的简单代码如下,注意此处使用了 script 标签加载 hls.min.js,所以是从 window 中获取 Hls 对象。
import videojs from 'video.js';
const Html5 = videojs.getTech('Html5');
const Hls = window['Hls'];
class Hlsjs extends Html5 {
hls_;
static canPlaySource: (techId: any, source: any) => any;
static isSupported: () => any;
setSrc(src) {
if (this.hls_) {
this.hls_.stopLoad();
this.hls_.detachMedia();
this.hls_ = null;
}
this.hls_ = new Hls();
this.hls_.attachMedia(this.el_);
this.hls_.loadSource(src);
}
/**
* @override {HTML5.currentSrc}
*/
currentSrc() {
if (this.hls_) {
return this.hls_.url;
}
return this.el_.currentSrc;
}
/**
* @override {Html5.dispose}
*/
dispose() {
if (this.hls_) {
this.hls_.detachMedia();
this.hls_.destroy();
}
super.dispose();
}
}
Hlsjs.isSupported = function () {
return Hls && Hls.isSupported();
};
Hlsjs.canPlaySource = function (source, options) {
if(source.type === 'application/x-mpegURL'){
return 'maybe';
}
return '';
};
videojs.registerTech('Hlsjs', Hlsjs);
export default Hlsjs;
注册了 Hlsjs 之后,在 videojs 的初始化参数中,将 techOrder 由 ['html5', 'flvjs'] 改为 ['html5', 'hlsjs', 'flvjs'] 即可。
video.js 和 hls.js 都用 script 标签在顶部引入,video.js 使用 video.core.min.js 避免引入 VHS。