videojs-contrib-dash-s1
Version:
A Video.js source-handler providing MPEG-DASH playback.
203 lines (163 loc) • 7.09 kB
JavaScript
'use strict';
Object.defineProperty(exports, '__esModule', {
value: true
});
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _videoJs = require('video.js');
var _videoJs2 = _interopRequireDefault(_videoJs);
require('dashjs/dist/dash.all.debug');
/**
* Use Dash.js to playback DASH content inside of Video.js via a SourceHandler
*/
var Html5DashJS = (function () {
function Html5DashJS(source, tech) {
_classCallCheck(this, Html5DashJS);
var manifestSource = source.src;
this.tech_ = tech;
this.el_ = tech.el();
this.elParent_ = this.el_.parentNode;
// Do nothing if the src is falsey
if (!source.src) {
return;
}
// While the manifest is loading and Dash.js has not finished initializing
// we must defer events and functions calls with isReady_ and then `triggerReady`
// again later once everything is setup
tech.isReady_ = false;
this.keySystemOptions_ = Html5DashJS.buildDashJSProtData(source.keySystemOptions);
// We have to hide errors since SRC_UNSUPPORTED is thrown by the video element when
// we set src = '' in order to clear the mediaKeys
this.hideErrors();
// Must be before anything is initialized since we are overridding a global object
// injection
if (Html5DashJS.useVideoJSDebug) {
Html5DashJS.useVideoJSDebug(_videoJs2['default']);
}
// Save the context after the first initialization for subsequent instances
Html5DashJS.context_ = Html5DashJS.context_ || {};
// But make a fresh MediaPlayer each time the sourceHandler is used
this.mediaPlayer_ = window.dashjs.MediaPlayer(Html5DashJS.context_).create();
// Initialize the media player with the element and autoplay settings
this.mediaPlayer_.initialize();
this.mediaPlayer_.setLimitBitrateByPortal(true);
this.mediaPlayer_.attachView(this.el_);
// Dash.js autoplays by default
if (!tech.options_.autoplay) {
this.mediaPlayer_.setAutoPlay(false);
}
// Fetches and parses the manifest - WARNING the callback is non-standard
// "error-last" style
this.mediaPlayer_.retrieveManifest(manifestSource, _videoJs2['default'].bind(this, this.initializeDashJS));
}
_createClass(Html5DashJS, [{
key: 'initializeDashJS',
value: function initializeDashJS(manifest, err) {
var _this = this;
var manifestProtectionData = {};
if (err) {
this.showErrors();
this.tech_.triggerReady();
this.dispose();
return;
}
// If we haven't received protection data from the outside world try to get it from
// the manifest, We merge the two allowing the manifest to override any
// keySystemOptions provided via src()
if (Html5DashJS.getWidevineProtectionData) {
manifestProtectionData = Html5DashJS.getWidevineProtectionData(manifest);
this.keySystemOptions_ = _videoJs2['default'].mergeOptions(this.keySystemOptions_, manifestProtectionData);
}
// We have to reset any mediaKeys before the attachSource call below
this.resetSrc_(function () {
_this.showErrors();
// Attach the source with any protection data
_this.mediaPlayer_.attachSource(manifest, null, _this.keySystemOptions_);
_this.tech_.triggerReady();
});
}
/**
* Add a css-class that is used to temporarily hide the error dialog while so that
* we don't see a flash of the dialog box when we remove the video element's src
* to reset MediaKeys in resetSrc_
*/
}, {
key: 'hideErrors',
value: function hideErrors() {
this.elParent_.className += ' vjs-dashjs-hide-errors';
}
/**
* Remove the css-class above to enable the error dialog to be shown once again
*/
}, {
key: 'showErrors',
value: function showErrors() {
var _this2 = this;
// The video element's src is set asynchronously so we have to wait a while
// before we unhide any errors
// 250ms is arbitrary but I haven't seen dash.js take longer than that to initialize
// in my testing
setTimeout(function () {
_this2.elParent_.className = _this2.elParent_.className.replace(' vjs-dashjs-hide-errors', '');
}, 250);
}
/**
* Iterate over the `keySystemOptions` array and convert each object into
* the type of object Dash.js expects in the `protData` argument.
*
* Also rename 'licenseUrl' property in the options to an 'serverURL' property
*/
}, {
key: 'resetSrc_',
/**
* Helper function to clear any EME keys that may have been set on the video element
*
* The MediaKeys has to be explicitly set to null before any DRM content can be loaded
* into a video element that already contained DRM content.
*/
value: function resetSrc_(callback) {
// In Chrome, MediaKeys can NOT be changed when a src is loaded in the video element
// Dash.js has a bug where it doesn't correctly reset the data so we do it manually
// The order of these two lines is important. The video element's src must be reset
// to allow `mediaKeys` to changed otherwise a DOMException is thrown.
if (this.el_) {
this.el_.src = '';
if (this.el_.setMediaKeys) {
this.el_.setMediaKeys(null).then(callback, callback);
} else {
callback();
}
}
}
}, {
key: 'dispose',
value: function dispose() {
if (this.mediaPlayer_) {
this.mediaPlayer_.reset();
}
this.resetSrc_(function () {});
}
}], [{
key: 'buildDashJSProtData',
value: function buildDashJSProtData(keySystemOptions) {
var output = {};
if (!keySystemOptions || !Array.isArray(keySystemOptions)) {
return output;
}
for (var i = 0; i < keySystemOptions.length; i++) {
var keySystem = keySystemOptions[i];
var options = _videoJs2['default'].mergeOptions({}, keySystem.options);
if (options.licenseUrl) {
options.serverURL = options.licenseUrl;
delete options.licenseUrl;
}
output[keySystem.name] = options;
}
return output;
}
}]);
return Html5DashJS;
})();
exports['default'] = Html5DashJS;
module.exports = exports['default'];