mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-08 10:56:15 -08:00
add mse
This commit is contained in:
1 parent
b74ff6052c
commit
495782f5c6
11 files changed
+504
-7
No files matched your search
@@ -31,6 +31,22 @@
|
||||
poster: 'http://s2.pstatp.com/cdn/expire-1-M/byted-player-videos/1.0.0/poster.jpg'
|
||||
});
|
||||
|
||||
player.on('video:canplay', event => {
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
player.on('video:play', event => {
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
player.on('video:progress', event => {
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
player.on('video:pause', event => {
|
||||
console.log(event);
|
||||
});
|
||||
|
||||
console.log(player);
|
||||
</script>
|
||||
</body>
|
||||
|
||||
+196
-3
@@ -220,6 +220,13 @@
|
||||
function clamp(num, a, b) {
|
||||
return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
|
||||
}
|
||||
function request(url) {
|
||||
return fetch(url).then(function (response) {
|
||||
return response.arrayBuffer();
|
||||
}).catch(function (err) {
|
||||
throw new ArtPlayerError(err.message);
|
||||
});
|
||||
}
|
||||
|
||||
function verification(option) {
|
||||
errorHandle(option.container, '\'container\' option is required.');
|
||||
@@ -231,6 +238,8 @@
|
||||
errorHandle(typeof option.autoplay === 'boolean', "'autoplay' option require 'boolean' type, but got '".concat(_typeof_1(option.autoplay), "'."));
|
||||
errorHandle(['none', 'metadata', 'auto'].indexOf(option.preload) > -1, '\'preload\' option require one of \'none、metadata、auto\'.');
|
||||
errorHandle(typeof option.lang === 'string', "'lang' option require 'string' type, but got '".concat(_typeof_1(option.lang), "'."));
|
||||
errorHandle(typeof option.type === 'string', "'type' option require 'string' type, but got '".concat(_typeof_1(option.type), "'."));
|
||||
errorHandle(typeof option.mimeCodec === 'string', "'mimeCodec' option require 'string' type, but got '".concat(_typeof_1(option.mimeCodec), "'."));
|
||||
}
|
||||
|
||||
function E () {
|
||||
@@ -362,6 +371,12 @@
|
||||
return I18n;
|
||||
}();
|
||||
|
||||
var mediaElement = {
|
||||
propertys: ['audioTracks', 'autoplay', 'buffered', 'controller', 'controls', 'crossOrigin', 'currentSrc', 'currentTime', 'defaultMuted', 'defaultPlaybackRate', 'duration', 'ended', 'error', 'loop', 'mediaGroup', 'muted', 'networkState', 'paused', 'playbackRate', 'played', 'preload', 'readyState', 'seekable', 'seeking', 'src', 'startDate', 'textTracks', 'videoTracks', 'volume'],
|
||||
methods: ['addTextTrack', 'canPlayType', 'load', 'play', 'pause'],
|
||||
events: ['abort', 'canplay', 'canplaythrough', 'durationchange', 'emptied', 'ended', 'error', 'loadeddata', 'loadedmetadata', 'loadstart', 'pause', 'play', 'playing', 'progress', 'ratechange', 'seeked', 'seeking', 'stalled', 'suspend', 'timeupdate', 'volumechange', 'waiting']
|
||||
};
|
||||
|
||||
var Player =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
@@ -369,7 +384,9 @@
|
||||
classCallCheck(this, Player);
|
||||
|
||||
this.art = art;
|
||||
this.eventFn = this.eventFn.bind(this);
|
||||
this.init();
|
||||
this.eventBind();
|
||||
}
|
||||
|
||||
createClass(Player, [{
|
||||
@@ -377,18 +394,191 @@
|
||||
value: function init() {
|
||||
var option = this.art.option;
|
||||
var $video = this.art.refs.$video;
|
||||
$video.controls = false;
|
||||
$video.controls = true;
|
||||
$video.poster = option.poster;
|
||||
$video.volume = clamp(option.volume, 0, 1);
|
||||
$video.autoplay = option.autoplay;
|
||||
$video.preload = option.preload;
|
||||
$video.src = option.url;
|
||||
}
|
||||
}, {
|
||||
key: "eventBind",
|
||||
value: function eventBind() {
|
||||
var _this = this;
|
||||
|
||||
var $video = this.art.refs.$video;
|
||||
var events = mediaElement.events;
|
||||
|
||||
var _loop = function _loop(index) {
|
||||
var eventName = events[index];
|
||||
$video.addEventListener(eventName, _this.eventFn);
|
||||
|
||||
_this.art.destroyEvents.push(function () {
|
||||
$video.removeEventListener(eventName, _this.eventFn);
|
||||
});
|
||||
};
|
||||
|
||||
for (var index = 0; index < events.length; index++) {
|
||||
_loop(index);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "eventFn",
|
||||
value: function eventFn(event) {
|
||||
this.art.emit("video:".concat(event.type), event);
|
||||
}
|
||||
}]);
|
||||
|
||||
return Player;
|
||||
}();
|
||||
|
||||
var mimeCodeces = {
|
||||
mp4: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
|
||||
webm: 'video/webm; codecs="vorbis, vp8"',
|
||||
ts: 'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"'
|
||||
};
|
||||
|
||||
var mseConfig = {
|
||||
instance: {
|
||||
propertys: ['activeSourceBuffers', 'duration', 'readyState', 'sourceBuffers'],
|
||||
methods: ['addSourceBuffer', 'endOfStream', 'removeSourceBuffer', 'clearLiveSeekableRange', 'setLiveSeekableRange'],
|
||||
events: ['sourceclose', 'sourceended', 'sourceopen']
|
||||
},
|
||||
sourceBuffer: {
|
||||
propertys: ['mode', 'updating', 'buffered', 'timestampOffset', 'audioTracks', 'videoTracks', 'textTracks', 'appendWindowStart', 'appendWindowEnd', 'trackDefaults'],
|
||||
methods: ['appendBuffer', 'appendStream', 'abort', 'remove'],
|
||||
events: ['abort', 'error', 'update', 'updateend', 'updatestart']
|
||||
},
|
||||
sourceBufferList: {
|
||||
propertys: ['length'],
|
||||
events: ['addsourcebuffer', 'removesourcebuffer']
|
||||
}
|
||||
};
|
||||
|
||||
var Mse =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
function Mse(art) {
|
||||
classCallCheck(this, Mse);
|
||||
|
||||
this.art = art;
|
||||
this.setMimeCodec();
|
||||
this.mediaSourceEventFn = this.mediaSourceEventFn.bind(this);
|
||||
this.sourceBufferEventFn = this.sourceBufferEventFn.bind(this);
|
||||
this.sourceBuffersEventFn = this.sourceBuffersEventFn.bind(this);
|
||||
this.activeSourceBuffersEventFn = this.activeSourceBuffersEventFn.bind(this);
|
||||
this.init();
|
||||
this.eventBind();
|
||||
this.eventStart();
|
||||
}
|
||||
|
||||
createClass(Mse, [{
|
||||
key: "setMimeCodec",
|
||||
value: function setMimeCodec() {
|
||||
var option = this.art.option;
|
||||
|
||||
if (!option.type) {
|
||||
var urlArr = option.url.trim().toLowerCase().split('.');
|
||||
var type = urlArr[urlArr.length - 1];
|
||||
errorHandle(Object.keys(mimeCodeces).includes(type), "Can't find video's type from ".concat(option.url));
|
||||
option.type = type;
|
||||
}
|
||||
|
||||
if (!option.mimeCodec) {
|
||||
var mimeCodec = mimeCodeces[option.type];
|
||||
errorHandle(mimeCodec, "Can't find video's mimeCodec from ".concat(option.type));
|
||||
option.mimeCodec = mimeCodec;
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "init",
|
||||
value: function init() {
|
||||
var _this$art = this.art,
|
||||
option = _this$art.option,
|
||||
$video = _this$art.refs.$video;
|
||||
errorHandle(MediaSource.isTypeSupported(option.mimeCodec), "Unsupported MIME type or codec: ".concat(option.mimeCodec));
|
||||
this.mediaSource = new MediaSource();
|
||||
$video.src = URL.createObjectURL(this.mediaSource);
|
||||
this.art.destroyEvents.push(function () {
|
||||
URL.revokeObjectURL($video.src);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "eventBind",
|
||||
value: function eventBind() {
|
||||
var _this = this;
|
||||
|
||||
var instance = mseConfig.instance,
|
||||
sourceBufferList = mseConfig.sourceBufferList;
|
||||
instance.events.forEach(function (eventName) {
|
||||
_this.mediaSource.addEventListener(eventName, _this.mediaSourceEventFn);
|
||||
|
||||
_this.art.destroyEvents.push(function () {
|
||||
_this.mediaSource.removeEventListener(eventName, _this.mediaSourceEventFn);
|
||||
});
|
||||
});
|
||||
sourceBufferList.events.forEach(function (eventName) {
|
||||
_this.mediaSource.sourceBuffers.addEventListener(eventName, _this.sourceBuffersEventFn);
|
||||
|
||||
_this.art.destroyEvents.push(function () {
|
||||
_this.mediaSource.sourceBuffers.removeEventListener(eventName, _this.sourceBuffersEventFn);
|
||||
});
|
||||
|
||||
_this.mediaSource.activeSourceBuffers.addEventListener(eventName, _this.activeSourceBuffersEventFn);
|
||||
|
||||
_this.art.destroyEvents.push(function () {
|
||||
_this.mediaSource.activeSourceBuffers.removeEventListener(eventName, _this.activeSourceBuffersEventFn);
|
||||
});
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "eventStart",
|
||||
value: function eventStart() {
|
||||
var _this2 = this;
|
||||
|
||||
var option = this.art.option;
|
||||
var sourceBuffer = mseConfig.sourceBuffer;
|
||||
this.art.on('mediaSource:sourceopen', function () {
|
||||
_this2.sourceBuffer = _this2.mediaSource.addSourceBuffer(option.mimeCodec);
|
||||
sourceBuffer.events.forEach(function (eventName) {
|
||||
_this2.sourceBuffer.addEventListener(eventName, _this2.sourceBufferEventFn);
|
||||
|
||||
_this2.art.destroyEvents.push(function () {
|
||||
_this2.sourceBuffer.removeEventListener(eventName, _this2.sourceBufferEventFn);
|
||||
});
|
||||
});
|
||||
});
|
||||
this.art.on('sourceBuffer:updateend', function () {
|
||||
_this2.mediaSource.endOfStream();
|
||||
});
|
||||
request(option.url).then(function (response) {
|
||||
_this2.sourceBuffer.appendBuffer(response);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "mediaSourceEventFn",
|
||||
value: function mediaSourceEventFn(event) {
|
||||
this.art.emit("mediaSource:".concat(event.type), event);
|
||||
}
|
||||
}, {
|
||||
key: "sourceBufferEventFn",
|
||||
value: function sourceBufferEventFn(event) {
|
||||
this.art.emit("sourceBuffer:".concat(event.type), event);
|
||||
}
|
||||
}, {
|
||||
key: "sourceBuffersEventFn",
|
||||
value: function sourceBuffersEventFn(event) {
|
||||
this.art.emit("sourceBuffers:".concat(event.type), event);
|
||||
}
|
||||
}, {
|
||||
key: "activeSourceBuffersEventFn",
|
||||
value: function activeSourceBuffersEventFn(event) {
|
||||
this.art.emit("activeSourceBuffers:".concat(event.type), event);
|
||||
}
|
||||
}]);
|
||||
|
||||
return Mse;
|
||||
}();
|
||||
|
||||
var Controls = function Controls(_ref) {//
|
||||
|
||||
var option = _ref.option;
|
||||
@@ -470,6 +660,7 @@
|
||||
this.template = new Template(this);
|
||||
this.i18n = new I18n(this);
|
||||
this.player = new Player(this);
|
||||
this.mse = new Mse(this);
|
||||
this.controls = new Controls(this);
|
||||
this.contextmenu = new Contextmenu(this);
|
||||
this.danmaku = new Danmu(this);
|
||||
@@ -484,7 +675,7 @@
|
||||
key: "destroy",
|
||||
value: function destroy() {
|
||||
this.destroyEvents.forEach(function (event) {
|
||||
return event.destroy();
|
||||
return event();
|
||||
});
|
||||
this.refs.container.innerHTML = '';
|
||||
instances.splice(instances.indexOf(this), 1);
|
||||
@@ -525,6 +716,8 @@
|
||||
volume: 0.7,
|
||||
autoplay: false,
|
||||
preload: 'auto',
|
||||
type: '',
|
||||
mimeCodec: '',
|
||||
lang: navigator.language.toLowerCase()
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"artplayer.js","sources":["../../node_modules/@babel/runtime/helpers/classCallCheck.js","../../node_modules/@babel/runtime/helpers/createClass.js","../../node_modules/@babel/runtime/helpers/typeof.js","../../node_modules/@babel/runtime/helpers/assertThisInitialized.js","../../node_modules/@babel/runtime/helpers/possibleConstructorReturn.js","../../node_modules/@babel/runtime/helpers/getPrototypeOf.js","../../node_modules/@babel/runtime/helpers/setPrototypeOf.js","../../node_modules/@babel/runtime/helpers/inherits.js","../../node_modules/@babel/runtime/helpers/isNativeFunction.js","../../node_modules/@babel/runtime/helpers/construct.js","../../node_modules/@babel/runtime/helpers/wrapNativeSuper.js","../../src/utils/ArtPlayerError.js","../../src/utils/index.js","../../src/utils/verification.js","../../node_modules/tiny-emitter/index.js","../../src/template.js","../../src/i18n/zh-CN.js","../../src/i18n/zh-TW.js","../../src/i18n/en.js","../../src/i18n/jp.js","../../src/i18n/index.js","../../src/player.js","../../src/controls/index.js","../../src/contextmenu.js","../../src/danmaku.js","../../src/info.js","../../src/subtitle.js","../../src/events.js","../../src/hotkey.js","../../src/index.js"],"sourcesContent":["function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\nmodule.exports = _classCallCheck;","function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\n\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n}\n\nmodule.exports = _createClass;","function _typeof2(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof2(obj); }\n\nfunction _typeof(obj) {\n if (typeof Symbol === \"function\" && _typeof2(Symbol.iterator) === \"symbol\") {\n module.exports = _typeof = function _typeof(obj) {\n return _typeof2(obj);\n };\n } else {\n module.exports = _typeof = function _typeof(obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : _typeof2(obj);\n };\n }\n\n return _typeof(obj);\n}\n\nmodule.exports = _typeof;","function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}\n\nmodule.exports = _assertThisInitialized;","var _typeof = require(\"../helpers/typeof\");\n\nvar assertThisInitialized = require(\"./assertThisInitialized\");\n\nfunction _possibleConstructorReturn(self, call) {\n if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) {\n return call;\n }\n\n return assertThisInitialized(self);\n}\n\nmodule.exports = _possibleConstructorReturn;","function _getPrototypeOf(o) {\n module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {\n return o.__proto__ || Object.getPrototypeOf(o);\n };\n return _getPrototypeOf(o);\n}\n\nmodule.exports = _getPrototypeOf;","function _setPrototypeOf(o, p) {\n module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n}\n\nmodule.exports = _setPrototypeOf;","var setPrototypeOf = require(\"./setPrototypeOf\");\n\nfunction _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n writable: true,\n configurable: true\n }\n });\n if (superClass) setPrototypeOf(subClass, superClass);\n}\n\nmodule.exports = _inherits;","function _isNativeFunction(fn) {\n return Function.toString.call(fn).indexOf(\"[native code]\") !== -1;\n}\n\nmodule.exports = _isNativeFunction;","var setPrototypeOf = require(\"./setPrototypeOf\");\n\nfunction isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) return false;\n if (Reflect.construct.sham) return false;\n if (typeof Proxy === \"function\") return true;\n\n trLine truncated
|
||||
{"version":3,"file":"artplayer.js","sources":["../../node_modules/@babel/runtime/helpers/classCallCheck.js","../../node_modules/@babel/runtime/helpers/createClass.js","../../node_modules/@babel/runtime/helpers/typeof.js","../../node_modules/@babel/runtime/helpers/assertThisInitialized.js","../../node_modules/@babel/runtime/helpers/possibleConstructorReturn.js","../../node_modules/@babel/runtime/helpers/getPrototypeOf.js","../../node_modules/@babel/runtime/helpers/setPrototypeOf.js","../../node_modules/@babel/runtime/helpers/inherits.js","../../node_modules/@babel/runtime/helpers/isNativeFunction.js","../../node_modules/@babel/runtime/helpers/construct.js","../../node_modules/@babel/runtime/helpers/wrapNativeSuper.js","../../src/utils/ArtPlayerError.js","../../src/utils/index.js","../../src/utils/verification.js","../../node_modules/tiny-emitter/index.js","../../src/template.js","../../src/i18n/zh-CN.js","../../src/i18n/zh-TW.js","../../src/i18n/en.js","../../src/i18n/jp.js","../../src/i18n/index.js","../../src/utils/mediaElement.js","../../src/player.js","../../src/utils/mimeCodeces.js","../../src/utils/mseConfig.js","../../src/mse.js","../../src/controls/index.js","../../src/contextmenu.js","../../src/danmaku.js","../../src/info.js","../../src/subtitle.js","../../src/events.js","../../src/hotkey.js","../../src/index.js"],"sourcesContent":["function _classCallCheck(instance, Constructor) {\n if (!(instance instanceof Constructor)) {\n throw new TypeError(\"Cannot call a class as a function\");\n }\n}\n\nmodule.exports = _classCallCheck;","function _defineProperties(target, props) {\n for (var i = 0; i < props.length; i++) {\n var descriptor = props[i];\n descriptor.enumerable = descriptor.enumerable || false;\n descriptor.configurable = true;\n if (\"value\" in descriptor) descriptor.writable = true;\n Object.defineProperty(target, descriptor.key, descriptor);\n }\n}\n\nfunction _createClass(Constructor, protoProps, staticProps) {\n if (protoProps) _defineProperties(Constructor.prototype, protoProps);\n if (staticProps) _defineProperties(Constructor, staticProps);\n return Constructor;\n}\n\nmodule.exports = _createClass;","function _typeof2(obj) { if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof2 = function _typeof2(obj) { return typeof obj; }; } else { _typeof2 = function _typeof2(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof2(obj); }\n\nfunction _typeof(obj) {\n if (typeof Symbol === \"function\" && _typeof2(Symbol.iterator) === \"symbol\") {\n module.exports = _typeof = function _typeof(obj) {\n return _typeof2(obj);\n };\n } else {\n module.exports = _typeof = function _typeof(obj) {\n return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : _typeof2(obj);\n };\n }\n\n return _typeof(obj);\n}\n\nmodule.exports = _typeof;","function _assertThisInitialized(self) {\n if (self === void 0) {\n throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\");\n }\n\n return self;\n}\n\nmodule.exports = _assertThisInitialized;","var _typeof = require(\"../helpers/typeof\");\n\nvar assertThisInitialized = require(\"./assertThisInitialized\");\n\nfunction _possibleConstructorReturn(self, call) {\n if (call && (_typeof(call) === \"object\" || typeof call === \"function\")) {\n return call;\n }\n\n return assertThisInitialized(self);\n}\n\nmodule.exports = _possibleConstructorReturn;","function _getPrototypeOf(o) {\n module.exports = _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) {\n return o.__proto__ || Object.getPrototypeOf(o);\n };\n return _getPrototypeOf(o);\n}\n\nmodule.exports = _getPrototypeOf;","function _setPrototypeOf(o, p) {\n module.exports = _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) {\n o.__proto__ = p;\n return o;\n };\n\n return _setPrototypeOf(o, p);\n}\n\nmodule.exports = _setPrototypeOf;","var setPrototypeOf = require(\"./setPrototypeOf\");\n\nfunction _inherits(subClass, superClass) {\n if (typeof superClass !== \"function\" && superClass !== null) {\n throw new TypeError(\"Super expression must either be null or a function\");\n }\n\n subClass.prototype = Object.create(superClass && superClass.prototype, {\n constructor: {\n value: subClass,\n writable: true,\n configurable: true\n }\n });\n if (superClass) setPrototypeOf(subClass, superClass);\n}\n\nmodule.exports = _inherits;","function _isNativeFunction(fn) {\n return Function.toString.call(fn).indexOf(\"[native code]\") !== -1;\n}\n\nmodule.exports = _isNativeFunction;","var setPrototypeOf = require(\"./setPrototypeOf\");\n\nfunction isNativeReflectConstruct() {\n if (typeof Reflect === \"undefined\" || !Reflect.construct) Line truncated
|
||||
+5
-1
@@ -4,6 +4,7 @@ import Emitter from 'tiny-emitter';
|
||||
import Template from './template';
|
||||
import I18n from './i18n';
|
||||
import Player from './player';
|
||||
import Mse from './mse';
|
||||
import Controls from './controls';
|
||||
import Contextmenu from './contextmenu';
|
||||
import Danmaku from './danmaku';
|
||||
@@ -35,6 +36,8 @@ class Artplayer extends Emitter {
|
||||
volume: 0.7,
|
||||
autoplay: false,
|
||||
preload: 'auto',
|
||||
type: '',
|
||||
mimeCodec: '',
|
||||
lang: navigator.language.toLowerCase()
|
||||
};
|
||||
}
|
||||
@@ -66,6 +69,7 @@ class Artplayer extends Emitter {
|
||||
this.template = new Template(this);
|
||||
this.i18n = new I18n(this);
|
||||
this.player = new Player(this);
|
||||
this.mse = new Mse(this);
|
||||
this.controls = new Controls(this);
|
||||
this.contextmenu = new Contextmenu(this);
|
||||
this.danmaku = new Danmaku(this);
|
||||
@@ -79,7 +83,7 @@ class Artplayer extends Emitter {
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.destroyEvents.forEach(event => event.destroy());
|
||||
this.destroyEvents.forEach(event => event());
|
||||
this.refs.container.innerHTML = '';
|
||||
instances.splice(instances.indexOf(this), 1);
|
||||
}
|
||||
|
||||
+121
@@ -0,0 +1,121 @@
|
||||
import { errorHandle, request } from './utils';
|
||||
import mimeCodeces from './utils/mimeCodeces';
|
||||
import mseConfig from './utils/mseConfig';
|
||||
|
||||
export default class Mse {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.setMimeCodec();
|
||||
this.mediaSourceEventFn = this.mediaSourceEventFn.bind(this);
|
||||
this.sourceBufferEventFn = this.sourceBufferEventFn.bind(this);
|
||||
this.sourceBuffersEventFn = this.sourceBuffersEventFn.bind(this);
|
||||
this.activeSourceBuffersEventFn = this.activeSourceBuffersEventFn.bind(this);
|
||||
this.init();
|
||||
this.eventBind();
|
||||
this.eventStart();
|
||||
}
|
||||
|
||||
setMimeCodec() {
|
||||
const { option } = this.art;
|
||||
if (!option.type) {
|
||||
const urlArr = option.url
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
.split('.');
|
||||
const type = urlArr[urlArr.length - 1];
|
||||
errorHandle(
|
||||
Object.keys(mimeCodeces).includes(type),
|
||||
`Can't find video's type from ${option.url}`
|
||||
);
|
||||
option.type = type;
|
||||
}
|
||||
|
||||
if (!option.mimeCodec) {
|
||||
const mimeCodec = mimeCodeces[option.type];
|
||||
errorHandle(
|
||||
mimeCodec,
|
||||
`Can't find video's mimeCodec from ${option.type}`
|
||||
);
|
||||
option.mimeCodec = mimeCodec;
|
||||
}
|
||||
}
|
||||
|
||||
init() {
|
||||
const {
|
||||
option,
|
||||
refs: { $video }
|
||||
} = this.art;
|
||||
errorHandle(
|
||||
MediaSource.isTypeSupported(option.mimeCodec),
|
||||
`Unsupported MIME type or codec: ${option.mimeCodec}`
|
||||
);
|
||||
this.mediaSource = new MediaSource();
|
||||
$video.src = URL.createObjectURL(this.mediaSource);
|
||||
this.art.destroyEvents.push(() => {
|
||||
URL.revokeObjectURL($video.src);
|
||||
});
|
||||
}
|
||||
|
||||
eventBind() {
|
||||
const { instance, sourceBufferList } = mseConfig;
|
||||
|
||||
instance.events.forEach(eventName => {
|
||||
this.mediaSource.addEventListener(eventName, this.mediaSourceEventFn);
|
||||
this.art.destroyEvents.push(() => {
|
||||
this.mediaSource.removeEventListener(eventName, this.mediaSourceEventFn);
|
||||
});
|
||||
});
|
||||
|
||||
sourceBufferList.events.forEach(eventName => {
|
||||
this.mediaSource.sourceBuffers.addEventListener(eventName, this.sourceBuffersEventFn);
|
||||
this.art.destroyEvents.push(() => {
|
||||
this.mediaSource.sourceBuffers.removeEventListener(eventName, this.sourceBuffersEventFn);
|
||||
});
|
||||
|
||||
this.mediaSource.activeSourceBuffers.addEventListener(eventName, this.activeSourceBuffersEventFn);
|
||||
this.art.destroyEvents.push(() => {
|
||||
this.mediaSource.activeSourceBuffers.removeEventListener(eventName, this.activeSourceBuffersEventFn);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
eventStart() {
|
||||
const { option } = this.art;
|
||||
const { sourceBuffer } = mseConfig;
|
||||
|
||||
this.art.on('mediaSource:sourceopen', () => {
|
||||
this.sourceBuffer = this.mediaSource.addSourceBuffer(option.mimeCodec);
|
||||
|
||||
sourceBuffer.events.forEach(eventName => {
|
||||
this.sourceBuffer.addEventListener(eventName, this.sourceBufferEventFn);
|
||||
this.art.destroyEvents.push(() => {
|
||||
this.sourceBuffer.removeEventListener(eventName, this.sourceBufferEventFn);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this.art.on('sourceBuffer:updateend', () => {
|
||||
this.mediaSource.endOfStream();
|
||||
});
|
||||
|
||||
request(option.url).then(response => {
|
||||
this.sourceBuffer.appendBuffer(response);
|
||||
});
|
||||
}
|
||||
|
||||
mediaSourceEventFn(event) {
|
||||
this.art.emit(`mediaSource:${event.type}`, event);
|
||||
}
|
||||
|
||||
sourceBufferEventFn(event) {
|
||||
this.art.emit(`sourceBuffer:${event.type}`, event);
|
||||
}
|
||||
|
||||
sourceBuffersEventFn(event) {
|
||||
this.art.emit(`sourceBuffers:${event.type}`, event);
|
||||
}
|
||||
|
||||
activeSourceBuffersEventFn(event) {
|
||||
this.art.emit(`activeSourceBuffers:${event.type}`, event);
|
||||
}
|
||||
}
|
||||
+20
-2
@@ -1,19 +1,37 @@
|
||||
import { clamp } from './utils';
|
||||
import mediaElement from './utils/mediaElement';
|
||||
|
||||
export default class Player {
|
||||
constructor(art) {
|
||||
this.art = art;
|
||||
this.eventFn = this.eventFn.bind(this);
|
||||
this.init();
|
||||
this.eventBind();
|
||||
}
|
||||
|
||||
init() {
|
||||
const { option } = this.art;
|
||||
const { $video } = this.art.refs;
|
||||
$video.controls = false;
|
||||
$video.controls = true;
|
||||
$video.poster = option.poster;
|
||||
$video.volume = clamp(option.volume, 0, 1);
|
||||
$video.autoplay = option.autoplay;
|
||||
$video.preload = option.preload;
|
||||
$video.src = option.url;
|
||||
}
|
||||
|
||||
eventBind() {
|
||||
const { $video } = this.art.refs;
|
||||
const { events } = mediaElement;
|
||||
for (let index = 0; index < events.length; index++) {
|
||||
const eventName = events[index];
|
||||
$video.addEventListener(eventName, this.eventFn);
|
||||
this.art.destroyEvents.push(() => {
|
||||
$video.removeEventListener(eventName, this.eventFn);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
eventFn(event) {
|
||||
this.art.emit(`video:${event.type}`, event);
|
||||
}
|
||||
}
|
||||
@@ -9,3 +9,11 @@ export function errorHandle(condition, msg) {
|
||||
export function clamp(num, a, b) {
|
||||
return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b));
|
||||
}
|
||||
|
||||
export function request(url) {
|
||||
return fetch(url)
|
||||
.then(response => response.arrayBuffer())
|
||||
.catch(err => {
|
||||
throw new ArtPlayerError(err.message);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
export default {
|
||||
propertys: [
|
||||
'audioTracks',
|
||||
'autoplay',
|
||||
'buffered',
|
||||
'controller',
|
||||
'controls',
|
||||
'crossOrigin',
|
||||
'currentSrc',
|
||||
'currentTime',
|
||||
'defaultMuted',
|
||||
'defaultPlaybackRate',
|
||||
'duration',
|
||||
'ended',
|
||||
'error',
|
||||
'loop',
|
||||
'mediaGroup',
|
||||
'muted',
|
||||
'networkState',
|
||||
'paused',
|
||||
'playbackRate',
|
||||
'played',
|
||||
'preload',
|
||||
'readyState',
|
||||
'seekable',
|
||||
'seeking',
|
||||
'src',
|
||||
'startDate',
|
||||
'textTracks',
|
||||
'videoTracks',
|
||||
'volume'
|
||||
],
|
||||
methods: [
|
||||
'addTextTrack',
|
||||
'canPlayType',
|
||||
'load',
|
||||
'play',
|
||||
'pause'
|
||||
],
|
||||
events: [
|
||||
'abort',
|
||||
'canplay',
|
||||
'canplaythrough',
|
||||
'durationchange',
|
||||
'emptied',
|
||||
'ended',
|
||||
'error',
|
||||
'loadeddata',
|
||||
'loadedmetadata',
|
||||
'loadstart',
|
||||
'pause',
|
||||
'play',
|
||||
'playing',
|
||||
'progress',
|
||||
'ratechange',
|
||||
'seeked',
|
||||
'seeking',
|
||||
'stalled',
|
||||
'suspend',
|
||||
'timeupdate',
|
||||
'volumechange',
|
||||
'waiting'
|
||||
]
|
||||
};
|
||||
@@ -0,0 +1,5 @@
|
||||
export default {
|
||||
mp4: 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"',
|
||||
webm: 'video/webm; codecs="vorbis, vp8"',
|
||||
ts: 'video/mp2t; codecs="avc1.42E01E, mp4a.40.2"'
|
||||
};
|
||||
@@ -0,0 +1,58 @@
|
||||
export default {
|
||||
instance: {
|
||||
propertys: [
|
||||
'activeSourceBuffers',
|
||||
'duration',
|
||||
'readyState',
|
||||
'sourceBuffers'
|
||||
],
|
||||
methods: [
|
||||
'addSourceBuffer',
|
||||
'endOfStream',
|
||||
'removeSourceBuffer',
|
||||
'clearLiveSeekableRange',
|
||||
'setLiveSeekableRange'
|
||||
],
|
||||
events: [
|
||||
'sourceclose',
|
||||
'sourceended',
|
||||
'sourceopen'
|
||||
]
|
||||
},
|
||||
sourceBuffer: {
|
||||
propertys: [
|
||||
'mode',
|
||||
'updating',
|
||||
'buffered',
|
||||
'timestampOffset',
|
||||
'audioTracks',
|
||||
'videoTracks',
|
||||
'textTracks',
|
||||
'appendWindowStart',
|
||||
'appendWindowEnd',
|
||||
'trackDefaults'
|
||||
],
|
||||
methods: [
|
||||
'appendBuffer',
|
||||
'appendStream',
|
||||
'abort',
|
||||
'remove'
|
||||
],
|
||||
events: [
|
||||
'abort',
|
||||
'error',
|
||||
'update',
|
||||
'updateend',
|
||||
'updatestart'
|
||||
]
|
||||
},
|
||||
sourceBufferList: {
|
||||
propertys: [
|
||||
'length'
|
||||
],
|
||||
events: [
|
||||
'addsourcebuffer',
|
||||
'removesourcebuffer'
|
||||
]
|
||||
}
|
||||
};
|
||||
@@ -46,4 +46,14 @@ export default function verification(option) {
|
||||
`'lang' option require 'string' type, but got '${typeof option.lang}'.`
|
||||
);
|
||||
|
||||
errorHandle(
|
||||
typeof option.type === 'string',
|
||||
`'type' option require 'string' type, but got '${typeof option.type}'.`
|
||||
);
|
||||
|
||||
errorHandle(
|
||||
typeof option.mimeCodec === 'string',
|
||||
`'mimeCodec' option require 'string' type, but got '${typeof option.mimeCodec}'.`
|
||||
);
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user