mirror of
https://github.com/zhw2590582/ArtPlayer.git
synced 2026-10-12 23:36:15 -08:00
21 files changed
+1340
-137
No files matched your search
@@ -19,20 +19,16 @@ body,
|
||||
|
||||
.part-top .config {
|
||||
width: 500px;
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.part-top .config .urlInput {
|
||||
flex: 1;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.part-top .config .playBtn {
|
||||
width: 50px;
|
||||
width: 100%;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.part-top .artplayer {
|
||||
opacity: 0;
|
||||
width: 500px;
|
||||
height: 300px;
|
||||
background: #fff;
|
||||
|
||||
+13
-9
@@ -19,8 +19,12 @@
|
||||
<div class="container">
|
||||
<div class="part-top">
|
||||
<div class="config">
|
||||
<input class="urlInput" type="text" value="https://blog.zhw-island.com/assets-cdn/video/one-more-time-one-more-chance-480p.flv">
|
||||
<input class="playBtn" type="button" value="play">
|
||||
<input class="urlInput" type="text" value="./video/again.flv">
|
||||
<!-- <input class="urlInput" type="text" value="https://blog.zhw-island.com/assets-cdn/video/one-more-time-one-more-chance-480p.flv"> -->
|
||||
<div class="btns">
|
||||
<input class="playBtn" type="button" value="Play">
|
||||
<input class="fileBtn" type="file">
|
||||
</div>
|
||||
</div>
|
||||
<div class="artplayer"></div>
|
||||
</div>
|
||||
@@ -31,13 +35,13 @@
|
||||
<script src="../uncompiled/artplayer-plugin-flv.js"></script>
|
||||
<script src="./js/common.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?b6c9b8bafbf5fe7225160101dafbbc7d";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
// var _hmt = _hmt || [];
|
||||
// (function() {
|
||||
// var hm = document.createElement("script");
|
||||
// hm.src = "https://hm.baidu.com/hm.js?b6c9b8bafbf5fe7225160101dafbbc7d";
|
||||
// var s = document.getElementsByTagName("script")[0];
|
||||
// s.parentNode.insertBefore(hm, s);
|
||||
// })();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
+20
-8
@@ -1,11 +1,11 @@
|
||||
'use strict';
|
||||
|
||||
(function() {
|
||||
consola.creat({
|
||||
target: '.part-bottom',
|
||||
size: '100%',
|
||||
zIndex: 99,
|
||||
});
|
||||
// consola.creat({
|
||||
// target: '.part-bottom',
|
||||
// size: '100%',
|
||||
// zIndex: 99,
|
||||
// });
|
||||
|
||||
console.info('Welcome, if you like it, consider star it, thank you.');
|
||||
console.info('https://github.com/zhw2590582/ArtPlayer');
|
||||
@@ -16,8 +16,9 @@
|
||||
|
||||
var $urlInput = document.querySelector('.urlInput');
|
||||
var $playBtn = document.querySelector('.playBtn');
|
||||
var $fileBtn = document.querySelector('.fileBtn');
|
||||
|
||||
function creatPlayer() {
|
||||
function creatPlayer(file) {
|
||||
Artplayer.instances.forEach(function(art) {
|
||||
art.destroy(true);
|
||||
});
|
||||
@@ -28,13 +29,24 @@
|
||||
type: 'flv',
|
||||
customType: {
|
||||
flv: function(video, url) {
|
||||
this.plugins.artplayerPluginFlv.init(video, url);
|
||||
var flv = new Flv({
|
||||
mediaElement: video,
|
||||
url: file instanceof File ? file : url,
|
||||
debug: true,
|
||||
});
|
||||
|
||||
this.on('destroy', () => {
|
||||
flv.destroy();
|
||||
});
|
||||
},
|
||||
},
|
||||
plugins: [artplayerPluginFlv]
|
||||
});
|
||||
}
|
||||
|
||||
creatPlayer();
|
||||
$playBtn.addEventListener('click', creatPlayer);
|
||||
$fileBtn.addEventListener('change', () => {
|
||||
const file = $fileBtn.files[0];
|
||||
creatPlayer(file);
|
||||
});
|
||||
})();
|
||||
Binary file not shown.
@@ -170,6 +170,36 @@
|
||||
};
|
||||
var tinyEmitter = E;
|
||||
|
||||
function _arrayWithoutHoles(arr) {
|
||||
if (Array.isArray(arr)) {
|
||||
for (var i = 0, arr2 = new Array(arr.length); i < arr.length; i++) {
|
||||
arr2[i] = arr[i];
|
||||
}
|
||||
|
||||
return arr2;
|
||||
}
|
||||
}
|
||||
|
||||
var arrayWithoutHoles = _arrayWithoutHoles;
|
||||
|
||||
function _iterableToArray(iter) {
|
||||
if (Symbol.iterator in Object(iter) || Object.prototype.toString.call(iter) === "[object Arguments]") return Array.from(iter);
|
||||
}
|
||||
|
||||
var iterableToArray = _iterableToArray;
|
||||
|
||||
function _nonIterableSpread() {
|
||||
throw new TypeError("Invalid attempt to spread non-iterable instance");
|
||||
}
|
||||
|
||||
var nonIterableSpread = _nonIterableSpread;
|
||||
|
||||
function _toConsumableArray(arr) {
|
||||
return arrayWithoutHoles(arr) || iterableToArray(arr) || nonIterableSpread();
|
||||
}
|
||||
|
||||
var toConsumableArray = _toConsumableArray;
|
||||
|
||||
function _isNativeFunction(fn) {
|
||||
return Function.toString.call(fn).indexOf("[native code]") !== -1;
|
||||
}
|
||||
@@ -270,85 +300,727 @@
|
||||
|
||||
return FlvError;
|
||||
}(wrapNativeSuper(Error));
|
||||
|
||||
function errorHandle(condition, msg) {
|
||||
if (!condition) {
|
||||
throw new FlvError(msg);
|
||||
}
|
||||
}
|
||||
function mergeTypedArrays(a, b) {
|
||||
var c = new a.constructor(a.length + b.length);
|
||||
c.set(a);
|
||||
c.set(b, a.length);
|
||||
return c;
|
||||
}
|
||||
function sleep() {
|
||||
var ms = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
|
||||
return new Promise(function (resolve) {
|
||||
return setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
function getUint8Sum(arr) {
|
||||
return arr.reduce(function (totle, num, index) {
|
||||
return totle + num * Math.pow(256, arr.length - index - 1);
|
||||
}, 0);
|
||||
}
|
||||
function string2Bin(str) {
|
||||
var result = [];
|
||||
|
||||
var CheckSupport = function CheckSupport() {
|
||||
classCallCheck(this, CheckSupport);
|
||||
for (var i = 0; i < str.length; i += 1) {
|
||||
result.push(Number(str.charCodeAt(i).toString(10)));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
function bin2String(array) {
|
||||
var _String$fromCharCode;
|
||||
|
||||
return (_String$fromCharCode = String.fromCharCode).call.apply(_String$fromCharCode, [String].concat(toConsumableArray(array)));
|
||||
}
|
||||
function bin2Float(array) {
|
||||
var view = new DataView(new ArrayBuffer(array.length));
|
||||
array.forEach(function (b, i) {
|
||||
view.setUint8(i, b);
|
||||
});
|
||||
return view.getFloat64(0);
|
||||
}
|
||||
function bin2Boolean(bin) {
|
||||
return bin === 1;
|
||||
}
|
||||
function log(name) {
|
||||
var msg = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : '';
|
||||
console.log("[".concat(name, "] ").concat(msg));
|
||||
}
|
||||
function readUint8(uint8) {
|
||||
var index = 0;
|
||||
return function read(length) {
|
||||
var tempUint8 = new Uint8Array(length);
|
||||
|
||||
for (var i = 0; i < length; i += 1) {
|
||||
tempUint8[i] = uint8[index];
|
||||
index += 1;
|
||||
}
|
||||
|
||||
read.index = index;
|
||||
return tempUint8;
|
||||
};
|
||||
}
|
||||
|
||||
var utils = /*#__PURE__*/Object.freeze({
|
||||
errorHandle: errorHandle,
|
||||
mergeTypedArrays: mergeTypedArrays,
|
||||
sleep: sleep,
|
||||
getUint8Sum: getUint8Sum,
|
||||
string2Bin: string2Bin,
|
||||
bin2String: bin2String,
|
||||
bin2Float: bin2Float,
|
||||
bin2Boolean: bin2Boolean,
|
||||
log: log,
|
||||
readUint8: readUint8
|
||||
});
|
||||
|
||||
function checkSupport(options) {
|
||||
var mediaElement = options.mediaElement,
|
||||
url = options.url;
|
||||
errorHandle(mediaElement instanceof HTMLVideoElement, 'The first parameter is not a video tag element');
|
||||
errorHandle(typeof url === 'string' || url instanceof File && url.type === 'video/x-flv', 'The second parameter is not a string type or flv file');
|
||||
var MP4H264MimeCodec = 'video/mp4; codecs="avc1.42001E, mp4a.40.2"';
|
||||
var videoElement = window.document.createElement('video');
|
||||
var canPlay = videoElement.canPlayType(MP4H264MimeCodec);
|
||||
var canPlay = mediaElement.canPlayType(MP4H264MimeCodec);
|
||||
errorHandle(window.MediaSource && window.MediaSource.isTypeSupported(MP4H264MimeCodec) && (canPlay === 'probably' || canPlay === 'maybe'), "Unsupported MIME type or codec: ".concat(MP4H264MimeCodec));
|
||||
errorHandle(typeof window.Promise === 'function', "Unsupported 'Promise' method");
|
||||
errorHandle(typeof window.fetch === 'function', "Unsupported 'fetch' method");
|
||||
errorHandle(typeof window.Worker === 'function', "Unsupported 'Worker' method");
|
||||
errorHandle(typeof window.ReadableStream === 'function', "Unsupported 'ReadableStream' method");
|
||||
}
|
||||
|
||||
var EventProxy =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
function EventProxy() {
|
||||
classCallCheck(this, EventProxy);
|
||||
|
||||
this.destroyEvents = [];
|
||||
this.proxy = this.proxy.bind(this);
|
||||
}
|
||||
|
||||
createClass(EventProxy, [{
|
||||
key: "proxy",
|
||||
value: function proxy(target, name, callback) {
|
||||
var option = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
||||
target.addEventListener(name, callback, option);
|
||||
this.destroyEvents.push(function () {
|
||||
target.removeEventListener(name, callback, option);
|
||||
});
|
||||
}
|
||||
}, {
|
||||
key: "destroy",
|
||||
value: function destroy() {
|
||||
this.destroyEvents.forEach(function (event) {
|
||||
return event();
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
return EventProxy;
|
||||
}();
|
||||
|
||||
var CreatWorker =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
function CreatWorker() {
|
||||
classCallCheck(this, CreatWorker);
|
||||
|
||||
this.workers = new Map();
|
||||
}
|
||||
|
||||
createClass(CreatWorker, [{
|
||||
key: "add",
|
||||
value: function add(name, fn) {
|
||||
if (!this.workers.has(name)) {
|
||||
this.workers.set(name, CreatWorker.create(fn));
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "run",
|
||||
value: function run(name) {
|
||||
var worker = this.workers.get(name);
|
||||
|
||||
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
|
||||
args[_key - 1] = arguments[_key];
|
||||
}
|
||||
|
||||
return worker.post(args);
|
||||
}
|
||||
}, {
|
||||
key: "kill",
|
||||
value: function kill(name) {
|
||||
var worker = this.workers.get(name);
|
||||
worker.kill();
|
||||
}
|
||||
}, {
|
||||
key: "killAll",
|
||||
value: function killAll() {
|
||||
this.workers.forEach(function (worker) {
|
||||
worker.kill();
|
||||
});
|
||||
}
|
||||
}], [{
|
||||
key: "fnToStr",
|
||||
value: function fnToStr(fn) {
|
||||
return "\n self.onmessage = event => {\n return self.postMessage((".concat(fn, ").apply(null, event.data));\n }\n ");
|
||||
}
|
||||
}, {
|
||||
key: "create",
|
||||
value: function create(fn) {
|
||||
var blob = new Blob([CreatWorker.fnToStr(fn)], {
|
||||
type: 'application/javascript'
|
||||
});
|
||||
var objectURL = window.URL.createObjectURL(blob);
|
||||
var worker = new Worker(objectURL);
|
||||
|
||||
worker.kill = function () {
|
||||
URL.revokeObjectURL(objectURL);
|
||||
worker.terminate();
|
||||
};
|
||||
|
||||
worker.post = function (args) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
worker.onmessage = function (event) {
|
||||
resolve(event.data);
|
||||
};
|
||||
|
||||
worker.onerror = function (error) {
|
||||
reject(error);
|
||||
};
|
||||
|
||||
worker.postMessage(args);
|
||||
});
|
||||
};
|
||||
|
||||
return worker;
|
||||
}
|
||||
}]);
|
||||
|
||||
return CreatWorker;
|
||||
}();
|
||||
|
||||
var config = {
|
||||
mediaSource: {
|
||||
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 CreatMediaSource = function CreatMediaSource(flv) {
|
||||
classCallCheck(this, CreatMediaSource);
|
||||
var CreatMediaSource =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
function CreatMediaSource(flv) {
|
||||
classCallCheck(this, CreatMediaSource);
|
||||
|
||||
this.mediaSource = new MediaSource();
|
||||
this.url = URL.createObjectURL(this.mediaSource);
|
||||
flv.mediaElement.src = this.url;
|
||||
};
|
||||
this.flv = flv;
|
||||
this.creatUrl();
|
||||
this.eventBind();
|
||||
}
|
||||
|
||||
createClass(CreatMediaSource, [{
|
||||
key: "creatUrl",
|
||||
value: function creatUrl() {
|
||||
var _this$flv = this.flv,
|
||||
mediaElement = _this$flv.options.mediaElement,
|
||||
destroyEvents = _this$flv.events.destroyEvents;
|
||||
this.mediaSource = new MediaSource();
|
||||
var url = URL.createObjectURL(this.mediaSource);
|
||||
destroyEvents.push(function () {
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
mediaElement.src = url;
|
||||
}
|
||||
}, {
|
||||
key: "eventBind",
|
||||
value: function eventBind() {
|
||||
var _this = this;
|
||||
|
||||
var proxy = this.flv.events.proxy;
|
||||
config.mediaSource.events.forEach(function (eventName) {
|
||||
proxy(_this.mediaSource, eventName, function (event) {
|
||||
_this.flv.emit("mediaSource:".concat(event.type), event);
|
||||
});
|
||||
});
|
||||
config.sourceBufferList.events.forEach(function (eventName) {
|
||||
proxy(_this.mediaSource.sourceBuffers, eventName, function (event) {
|
||||
_this.flv.emit("sourceBuffers:".concat(event.type), event);
|
||||
});
|
||||
proxy(_this.mediaSource.activeSourceBuffers, eventName, function (event) {
|
||||
_this.flv.emit("activeSourceBuffers:".concat(event.type), event);
|
||||
});
|
||||
});
|
||||
}
|
||||
}]);
|
||||
|
||||
return CreatMediaSource;
|
||||
}();
|
||||
|
||||
function _arrayWithHoles(arr) {
|
||||
if (Array.isArray(arr)) return arr;
|
||||
}
|
||||
|
||||
var arrayWithHoles = _arrayWithHoles;
|
||||
|
||||
function _iterableToArrayLimit(arr, i) {
|
||||
var _arr = [];
|
||||
var _n = true;
|
||||
var _d = false;
|
||||
var _e = undefined;
|
||||
|
||||
try {
|
||||
for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) {
|
||||
_arr.push(_s.value);
|
||||
|
||||
if (i && _arr.length === i) break;
|
||||
}
|
||||
} catch (err) {
|
||||
_d = true;
|
||||
_e = err;
|
||||
} finally {
|
||||
try {
|
||||
if (!_n && _i["return"] != null) _i["return"]();
|
||||
} finally {
|
||||
if (_d) throw _e;
|
||||
}
|
||||
}
|
||||
|
||||
return _arr;
|
||||
}
|
||||
|
||||
var iterableToArrayLimit = _iterableToArrayLimit;
|
||||
|
||||
function _nonIterableRest() {
|
||||
throw new TypeError("Invalid attempt to destructure non-iterable instance");
|
||||
}
|
||||
|
||||
var nonIterableRest = _nonIterableRest;
|
||||
|
||||
function _slicedToArray(arr, i) {
|
||||
return arrayWithHoles(arr) || iterableToArrayLimit(arr, i) || nonIterableRest();
|
||||
}
|
||||
|
||||
var slicedToArray = _slicedToArray;
|
||||
|
||||
function fetchStream(flv, url) {
|
||||
flv.emit('flvFetchStart');
|
||||
fetch(url).then(function (response) {
|
||||
errorHandle(response.ok && response.status >= 200 && response.status <= 299, "".concat(response.status, " ").concat(response.statusText));
|
||||
var contentType = response.headers.get('content-type');
|
||||
errorHandle(contentType.includes('x-flv'), 'The resource does not seem to be a flv file');
|
||||
return new Response(new ReadableStream({
|
||||
start: function start(controller) {
|
||||
var reader = response.body.getReader();
|
||||
flv.on('destroy', function () {
|
||||
reader.cancel();
|
||||
});
|
||||
flv.on('readerCancel', function () {
|
||||
reader.cancel();
|
||||
});
|
||||
|
||||
(function read() {
|
||||
reader.read().then(function (_ref) {
|
||||
var done = _ref.done,
|
||||
value = _ref.value;
|
||||
|
||||
if (done) {
|
||||
flv.emit('flvFetchEnd');
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
|
||||
flv.emit('flvFetching', new Uint8Array(value));
|
||||
controller.enqueue(value);
|
||||
read();
|
||||
}).catch(function (error) {
|
||||
throw error;
|
||||
});
|
||||
})();
|
||||
},
|
||||
cancel: function cancel() {
|
||||
flv.emit('flvFetchCancel');
|
||||
}
|
||||
}));
|
||||
});
|
||||
}
|
||||
|
||||
function readFile(flv, file) {
|
||||
flv.emit('flvFetchStart');
|
||||
var proxy = flv.events.proxy;
|
||||
var reader = new FileReader();
|
||||
proxy(reader, 'load', function (e) {
|
||||
var buffer = e.target.result;
|
||||
var uint8 = new Uint8Array(buffer);
|
||||
flv.emit('flvFetchEnd', uint8);
|
||||
});
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
|
||||
function parseScripTag(scripTagBody) {
|
||||
var readScripTag = readUint8(scripTagBody);
|
||||
var metadata = Object.create(null);
|
||||
var amf1 = Object.create(null);
|
||||
var amf2 = Object.create(null);
|
||||
|
||||
var _readScripTag = readScripTag(1);
|
||||
|
||||
var _readScripTag2 = slicedToArray(_readScripTag, 1);
|
||||
|
||||
amf1.type = _readScripTag2[0];
|
||||
errorHandle(amf1.type === 2, "AMF: [amf1] type expect 2, but got ".concat(amf1.type));
|
||||
amf1.size = getUint8Sum(readScripTag(2));
|
||||
amf1.string = bin2String(readScripTag(amf1.size));
|
||||
|
||||
var _readScripTag3 = readScripTag(1);
|
||||
|
||||
var _readScripTag4 = slicedToArray(_readScripTag3, 1);
|
||||
|
||||
amf2.type = _readScripTag4[0];
|
||||
errorHandle(amf2.type === 8, "AMF: [amf1] type expect 8, but got ".concat(amf2.type));
|
||||
amf2.size = getUint8Sum(readScripTag(4));
|
||||
amf2.metaData = Object.create(null);
|
||||
|
||||
function getValue(type) {
|
||||
var value = null;
|
||||
|
||||
if (type !== undefined) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
value = bin2Float(readScripTag(8));
|
||||
break;
|
||||
|
||||
case 1:
|
||||
value = bin2Boolean(readScripTag(1)[0]);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
var valueLength = getUint8Sum(readScripTag(2));
|
||||
value = bin2String(readScripTag(valueLength));
|
||||
break;
|
||||
}
|
||||
|
||||
case 3:
|
||||
{
|
||||
value = Object.create(null);
|
||||
var endObject = false;
|
||||
|
||||
while (!endObject && readScripTag.index < scripTagBody.length) {
|
||||
var nameLength = getUint8Sum(readScripTag(2));
|
||||
var name = bin2String(readScripTag(nameLength));
|
||||
var _type = readScripTag(1)[0];
|
||||
|
||||
if (name) {
|
||||
value[name] = getValue(_type);
|
||||
}
|
||||
|
||||
if (_type === 9) {
|
||||
endObject = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 8:
|
||||
{
|
||||
value = Object.create(null);
|
||||
var endArray = false;
|
||||
|
||||
while (!endArray && readScripTag.index < scripTagBody.length) {
|
||||
var _nameLength = getUint8Sum(readScripTag(2));
|
||||
|
||||
var _name = bin2String(readScripTag(_nameLength));
|
||||
|
||||
var _type2 = readScripTag(1)[0];
|
||||
|
||||
if (_name) {
|
||||
value[_name] = getValue(_type2);
|
||||
}
|
||||
|
||||
if (_type2 === 9) {
|
||||
endArray = true;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 10:
|
||||
{
|
||||
var _valueLength = getUint8Sum(readScripTag(4));
|
||||
|
||||
value = [];
|
||||
|
||||
for (var index = 0; index < _valueLength; index += 1) {
|
||||
var itemType = readScripTag(1)[0];
|
||||
value.push(getValue(itemType));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case 12:
|
||||
{
|
||||
var _valueLength2 = getUint8Sum(readScripTag(4));
|
||||
|
||||
value = bin2String(readScripTag(_valueLength2));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
console.log(readScripTag(scripTagBody.length - readScripTag.index - 1));
|
||||
errorHandle(false, "AMF: Unknown metaData type: ".concat(type));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
while (readScripTag.index < scripTagBody.length) {
|
||||
var nameLength = getUint8Sum(readScripTag(2));
|
||||
var name = bin2String(readScripTag(nameLength));
|
||||
var type = readScripTag(1)[0];
|
||||
|
||||
if (name) {
|
||||
amf2.metaData[name] = getValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
errorHandle(readScripTag.index === scripTagBody.length, 'AMF: Seems to be incompletely parsed');
|
||||
errorHandle(amf2.size === Object.keys(amf2.metaData).length, 'AMF: [amf2] length does not match');
|
||||
metadata.amf1 = amf1;
|
||||
metadata.amf2 = amf2;
|
||||
return metadata;
|
||||
}
|
||||
|
||||
var FlvParse =
|
||||
/*#__PURE__*/
|
||||
function () {
|
||||
function FlvParse(flv) {
|
||||
var _this = this;
|
||||
|
||||
classCallCheck(this, FlvParse);
|
||||
|
||||
this.flv = flv;
|
||||
var _flv$options = flv.options,
|
||||
url = _flv$options.url,
|
||||
debug = _flv$options.debug;
|
||||
this.uint8 = new Uint8Array(0);
|
||||
this.index = 0;
|
||||
this.header = null;
|
||||
this.scripTag = null;
|
||||
this.tags = [];
|
||||
this.done = false;
|
||||
flv.on('flvFetchStart', function () {
|
||||
if (debug) {
|
||||
console.log('[flv-fetch-start]', url);
|
||||
}
|
||||
});
|
||||
flv.on('flvFetchCancel', function () {
|
||||
if (debug) {
|
||||
console.log('[flv-fetch-cancel]');
|
||||
}
|
||||
});
|
||||
flv.on('flvFetching', function (uint8) {
|
||||
_this.uint8 = mergeTypedArrays(_this.uint8, uint8);
|
||||
|
||||
_this.parse();
|
||||
});
|
||||
flv.on('flvFetchEnd', function (uint8) {
|
||||
if (debug) {
|
||||
console.log('[flv-fetch-end]');
|
||||
}
|
||||
|
||||
_this.done = true;
|
||||
|
||||
if (uint8) {
|
||||
_this.uint8 = uint8;
|
||||
_this.index = 0;
|
||||
_this.header = null;
|
||||
_this.scripTag = null;
|
||||
_this.tags = [];
|
||||
|
||||
_this.parse();
|
||||
}
|
||||
|
||||
flv.emit('flvParseDone');
|
||||
|
||||
if (debug) {
|
||||
console.log('[flv-parse-done]');
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof url === 'string') {
|
||||
fetchStream(flv, url);
|
||||
} else {
|
||||
readFile(flv, url);
|
||||
}
|
||||
}
|
||||
|
||||
createClass(FlvParse, [{
|
||||
key: "parse",
|
||||
value: function parse() {
|
||||
var debug = this.flv.options.debug;
|
||||
|
||||
if (this.uint8.length >= 13 && !this.header) {
|
||||
var header = Object.create(null);
|
||||
header.signature = bin2String(this.read(3));
|
||||
|
||||
var _this$read = this.read(1);
|
||||
|
||||
var _this$read2 = slicedToArray(_this$read, 1);
|
||||
|
||||
header.version = _this$read2[0];
|
||||
|
||||
var _this$read3 = this.read(1);
|
||||
|
||||
var _this$read4 = slicedToArray(_this$read3, 1);
|
||||
|
||||
header.flags = _this$read4[0];
|
||||
header.headersize = getUint8Sum(this.read(4));
|
||||
this.header = header;
|
||||
this.read(4);
|
||||
this.flv.emit('flvParseHeader', this.header);
|
||||
|
||||
if (debug) {
|
||||
console.log('[flv-parse-header]', this.header);
|
||||
}
|
||||
}
|
||||
|
||||
while (this.index < this.uint8.length) {
|
||||
var tag = Object.create(null);
|
||||
|
||||
var _this$read5 = this.read(1);
|
||||
|
||||
var _this$read6 = slicedToArray(_this$read5, 1);
|
||||
|
||||
tag.tagType = _this$read6[0];
|
||||
tag.dataSize = getUint8Sum(this.read(3));
|
||||
tag.timestamp = this.read(4);
|
||||
tag.streamID = this.read(3);
|
||||
tag.body = this.read(tag.dataSize);
|
||||
this.tags.push(tag);
|
||||
this.read(4);
|
||||
|
||||
switch (tag.tagType) {
|
||||
case 18:
|
||||
this.scripTag = parseScripTag(tag.body);
|
||||
this.flv.emit('parseScripTag', this.scripTag);
|
||||
|
||||
if (debug) {
|
||||
console.log('[flv-parse-scrip-tag]', this.scripTag);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.flv.emit('flvParseTag', tag);
|
||||
}
|
||||
}
|
||||
}, {
|
||||
key: "read",
|
||||
value: function read(length) {
|
||||
var tempUint8 = new Uint8Array(length);
|
||||
|
||||
for (var i = 0; i < length; i += 1) {
|
||||
tempUint8[i] = this.uint8[this.index];
|
||||
this.index += 1;
|
||||
}
|
||||
|
||||
return tempUint8;
|
||||
}
|
||||
}]);
|
||||
|
||||
return FlvParse;
|
||||
}();
|
||||
|
||||
var id = 0;
|
||||
|
||||
var Flv =
|
||||
/*#__PURE__*/
|
||||
function (_Emitter) {
|
||||
inherits(Flv, _Emitter);
|
||||
|
||||
function Flv(mediaElement, url) {
|
||||
function Flv(options) {
|
||||
var _this;
|
||||
|
||||
classCallCheck(this, Flv);
|
||||
|
||||
_this = possibleConstructorReturn(this, getPrototypeOf(Flv).call(this));
|
||||
_this.mediaElement = mediaElement;
|
||||
_this.url = url;
|
||||
_this.support = new CheckSupport(assertThisInitialized(assertThisInitialized(_this)));
|
||||
_this.options = Object.assign({}, Flv.DEFAULTS, options);
|
||||
checkSupport(_this.options);
|
||||
_this.events = new EventProxy(assertThisInitialized(assertThisInitialized(_this)));
|
||||
_this.workers = new CreatWorker(assertThisInitialized(assertThisInitialized(_this)));
|
||||
_this.mediaSource = new CreatMediaSource(assertThisInitialized(assertThisInitialized(_this)));
|
||||
_this.flvData = new FlvParse(assertThisInitialized(assertThisInitialized(_this)));
|
||||
id += 1;
|
||||
_this.id = id;
|
||||
Flv.instances.push(assertThisInitialized(assertThisInitialized(_this)));
|
||||
return _this;
|
||||
}
|
||||
|
||||
createClass(Flv, [{
|
||||
key: "load",
|
||||
value: function load() {
|
||||
console.log(this);
|
||||
}
|
||||
}, {
|
||||
key: "destroy",
|
||||
value: function destroy() {
|
||||
console.log(this);
|
||||
this.events.destroy();
|
||||
this.workers.killAll();
|
||||
Flv.instances.splice(Flv.instances.indexOf(this), 1);
|
||||
this.emit('destroy');
|
||||
}
|
||||
}], [{
|
||||
key: "DEFAULTS",
|
||||
get: function get() {
|
||||
return {
|
||||
mediaElement: '',
|
||||
url: '',
|
||||
debug: false
|
||||
};
|
||||
}
|
||||
}, {
|
||||
key: "version",
|
||||
get: function get() {
|
||||
return '1.0.6';
|
||||
}
|
||||
}, {
|
||||
key: "config",
|
||||
get: function get() {
|
||||
return config;
|
||||
}
|
||||
}, {
|
||||
key: "utils",
|
||||
get: function get() {
|
||||
return utils;
|
||||
}
|
||||
}]);
|
||||
|
||||
return Flv;
|
||||
}(tinyEmitter);
|
||||
|
||||
Object.defineProperty(Flv, 'instances', {
|
||||
value: []
|
||||
});
|
||||
window.Flv = Flv;
|
||||
|
||||
function artplayerPluginFlv(art) {
|
||||
var flv = null;
|
||||
art.on('destroy', function () {
|
||||
if (flv) {
|
||||
flv.destroy();
|
||||
}
|
||||
});
|
||||
return {
|
||||
flv: flv,
|
||||
init: function init(mediaElement, url) {
|
||||
flv = new Flv(mediaElement, url);
|
||||
flv.load();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
window.artplayerPluginFlv = artplayerPluginFlv;
|
||||
|
||||
exports.default = artplayerPluginFlv;
|
||||
exports.default = Flv;
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
{"version":3,"file":"artplayer-plugin-flv.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","../../packages/artplayer-plugin-flv/node_modules/tiny-emitter/index.js","../../node_modules/@babel/runtime/helpers/isNativeFunction.js","../../node_modules/@babel/runtime/helpers/construct.js","../../node_modules/@babel/runtime/helpers/wrapNativeSuper.js","../../packages/artplayer-plugin-flv/src/flv/utils.js","../../packages/artplayer-plugin-flv/src/flv/checkSupport.js","../../packages/artplayer-plugin-flv/src/flv/creatMediaSource.js","../../packages/artplayer-plugin-flv/src/flv/index.js","../../packages/artplayer-plugin-flv/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 E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\nLine truncated
|
||||
{"version":3,"file":"artplayer-plugin-flv.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","../../packages/artplayer-plugin-flv/node_modules/tiny-emitter/index.js","../../node_modules/@babel/runtime/helpers/arrayWithoutHoles.js","../../node_modules/@babel/runtime/helpers/iterableToArray.js","../../node_modules/@babel/runtime/helpers/nonIterableSpread.js","../../node_modules/@babel/runtime/helpers/toConsumableArray.js","../../node_modules/@babel/runtime/helpers/isNativeFunction.js","../../node_modules/@babel/runtime/helpers/construct.js","../../node_modules/@babel/runtime/helpers/wrapNativeSuper.js","../../packages/artplayer-plugin-flv/src/utils/flvError.js","../../packages/artplayer-plugin-flv/src/utils/index.js","../../packages/artplayer-plugin-flv/src/utils/checkSupport.js","../../packages/artplayer-plugin-flv/src/eventProxy.js","../../packages/artplayer-plugin-flv/src/creatWorker.js","../../packages/artplayer-plugin-flv/src/config.js","../../packages/artplayer-plugin-flv/src/creatMediaSource.js","../../node_modules/@babel/runtime/helpers/arrayWithHoles.js","../../node_modules/@babel/runtime/helpers/iterableToArrayLimit.js","../../node_modules/@babel/runtime/helpers/nonIterableRest.js","../../node_modules/@babel/runtime/helpers/slicedToArray.js","../../packages/artplayer-plugin-flv/src/flvParse/fetchStream.js","../../packages/artplayer-plugin-flv/src/flvParse/readFile.js","../../packages/artplayer-plugin-flv/src/flvParse/parseScripTag.js","../../packages/artplayer-plugin-flv/src/flvParse/index.js","../../packages/artplayer-plugin-flv/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\" Line truncated
|
||||
@@ -0,0 +1,58 @@
|
||||
export default {
|
||||
mediaSource: {
|
||||
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',
|
||||
],
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,43 @@
|
||||
import config from './config';
|
||||
|
||||
export default class CreatMediaSource {
|
||||
constructor(flv) {
|
||||
this.flv = flv;
|
||||
this.creatUrl();
|
||||
this.eventBind();
|
||||
}
|
||||
|
||||
creatUrl() {
|
||||
const {
|
||||
options: { mediaElement },
|
||||
events: { destroyEvents },
|
||||
} = this.flv;
|
||||
this.mediaSource = new MediaSource();
|
||||
const url = URL.createObjectURL(this.mediaSource);
|
||||
destroyEvents.push(() => {
|
||||
URL.revokeObjectURL(url);
|
||||
});
|
||||
mediaElement.src = url;
|
||||
}
|
||||
|
||||
eventBind() {
|
||||
const {
|
||||
events: { proxy },
|
||||
} = this.flv;
|
||||
|
||||
config.mediaSource.events.forEach(eventName => {
|
||||
proxy(this.mediaSource, eventName, event => {
|
||||
this.flv.emit(`mediaSource:${event.type}`, event);
|
||||
});
|
||||
});
|
||||
|
||||
config.sourceBufferList.events.forEach(eventName => {
|
||||
proxy(this.mediaSource.sourceBuffers, eventName, event => {
|
||||
this.flv.emit(`sourceBuffers:${event.type}`, event);
|
||||
});
|
||||
proxy(this.mediaSource.activeSourceBuffers, eventName, event => {
|
||||
this.flv.emit(`activeSourceBuffers:${event.type}`, event);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
export default class CreatWorker {
|
||||
constructor() {
|
||||
this.workers = new Map();
|
||||
}
|
||||
|
||||
static fnToStr(fn) {
|
||||
return `
|
||||
self.onmessage = event => {
|
||||
return self.postMessage((${fn}).apply(null, event.data));
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
static create(fn) {
|
||||
const blob = new Blob([CreatWorker.fnToStr(fn)], {
|
||||
type: 'application/javascript',
|
||||
});
|
||||
const objectURL = window.URL.createObjectURL(blob);
|
||||
const worker = new Worker(objectURL);
|
||||
worker.kill = () => {
|
||||
URL.revokeObjectURL(objectURL);
|
||||
worker.terminate();
|
||||
};
|
||||
worker.post = args =>
|
||||
new Promise((resolve, reject) => {
|
||||
worker.onmessage = event => {
|
||||
resolve(event.data);
|
||||
};
|
||||
worker.onerror = error => {
|
||||
reject(error);
|
||||
};
|
||||
worker.postMessage(args);
|
||||
});
|
||||
return worker;
|
||||
}
|
||||
|
||||
add(name, fn) {
|
||||
if (!this.workers.has(name)) {
|
||||
this.workers.set(name, CreatWorker.create(fn));
|
||||
}
|
||||
}
|
||||
|
||||
run(name, ...args) {
|
||||
const worker = this.workers.get(name);
|
||||
return worker.post(args);
|
||||
}
|
||||
|
||||
kill(name) {
|
||||
const worker = this.workers.get(name);
|
||||
worker.kill();
|
||||
}
|
||||
|
||||
killAll() {
|
||||
this.workers.forEach(worker => {
|
||||
worker.kill();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
export default class EventProxy {
|
||||
constructor() {
|
||||
this.destroyEvents = [];
|
||||
this.proxy = this.proxy.bind(this);
|
||||
}
|
||||
|
||||
proxy(target, name, callback, option = {}) {
|
||||
target.addEventListener(name, callback, option);
|
||||
this.destroyEvents.push(() => {
|
||||
target.removeEventListener(name, callback, option);
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.destroyEvents.forEach(event => event());
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import { errorHandle } from './utils';
|
||||
|
||||
export default class CheckSupport {
|
||||
constructor() {
|
||||
const MP4H264MimeCodec = 'video/mp4; codecs="avc1.42001E, mp4a.40.2"';
|
||||
const videoElement = window.document.createElement('video');
|
||||
const canPlay = videoElement.canPlayType(MP4H264MimeCodec);
|
||||
errorHandle(
|
||||
window.MediaSource &&
|
||||
window.MediaSource.isTypeSupported(MP4H264MimeCodec) &&
|
||||
(canPlay === 'probably' || canPlay === 'maybe'),
|
||||
`Unsupported MIME type or codec: ${MP4H264MimeCodec}`,
|
||||
);
|
||||
errorHandle(typeof window.Promise === 'function', "Unsupported 'Promise' method");
|
||||
errorHandle(typeof window.fetch === 'function', "Unsupported 'fetch' method");
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
export default class CreatMediaSource {
|
||||
constructor(flv) {
|
||||
this.mediaSource = new MediaSource();
|
||||
this.url = URL.createObjectURL(this.mediaSource);
|
||||
flv.mediaElement.src = this.url;
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import Emitter from 'tiny-emitter';
|
||||
import CheckSupport from './checkSupport';
|
||||
import CreatMediaSource from './creatMediaSource';
|
||||
|
||||
class Flv extends Emitter {
|
||||
constructor(mediaElement, url) {
|
||||
super();
|
||||
this.mediaElement = mediaElement;
|
||||
this.url = url;
|
||||
this.support = new CheckSupport(this);
|
||||
this.mediaSource = new CreatMediaSource(this);
|
||||
}
|
||||
|
||||
load() {
|
||||
console.log(this);
|
||||
}
|
||||
|
||||
destroy() {
|
||||
console.log(this);
|
||||
}
|
||||
}
|
||||
|
||||
window.Flv = Flv;
|
||||
export default Flv;
|
||||
@@ -0,0 +1,49 @@
|
||||
import { errorHandle } from '../utils';
|
||||
|
||||
export default function fetchStream(flv, url) {
|
||||
flv.emit('flvFetchStart');
|
||||
fetch(url).then(response => {
|
||||
errorHandle(
|
||||
response.ok && response.status >= 200 && response.status <= 299,
|
||||
`${response.status} ${response.statusText}`,
|
||||
);
|
||||
const contentType = response.headers.get('content-type');
|
||||
errorHandle(contentType.includes('x-flv'), 'The resource does not seem to be a flv file');
|
||||
return new Response(
|
||||
new ReadableStream({
|
||||
start(controller) {
|
||||
const reader = response.body.getReader();
|
||||
|
||||
flv.on('destroy', () => {
|
||||
reader.cancel();
|
||||
});
|
||||
|
||||
flv.on('readerCancel', () => {
|
||||
reader.cancel();
|
||||
});
|
||||
|
||||
(function read() {
|
||||
reader
|
||||
.read()
|
||||
.then(({ done, value }) => {
|
||||
if (done) {
|
||||
flv.emit('flvFetchEnd');
|
||||
controller.close();
|
||||
return;
|
||||
}
|
||||
flv.emit('flvFetching', new Uint8Array(value));
|
||||
controller.enqueue(value);
|
||||
read();
|
||||
})
|
||||
.catch(error => {
|
||||
throw error;
|
||||
});
|
||||
})();
|
||||
},
|
||||
cancel() {
|
||||
flv.emit('flvFetchCancel');
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
import fetchStream from './fetchStream';
|
||||
import readFile from './readFile';
|
||||
import parseScripTag from './parseScripTag';
|
||||
import { mergeTypedArrays, getUint8Sum, bin2String } from '../utils';
|
||||
|
||||
export default class FlvParse {
|
||||
constructor(flv) {
|
||||
this.flv = flv;
|
||||
const { url, debug } = flv.options;
|
||||
this.uint8 = new Uint8Array(0);
|
||||
this.index = 0;
|
||||
this.header = null;
|
||||
this.scripTag = null;
|
||||
this.tags = [];
|
||||
this.done = false;
|
||||
|
||||
flv.on('flvFetchStart', () => {
|
||||
if (debug) {
|
||||
console.log('[flv-fetch-start]', url);
|
||||
}
|
||||
});
|
||||
|
||||
flv.on('flvFetchCancel', () => {
|
||||
if (debug) {
|
||||
console.log('[flv-fetch-cancel]');
|
||||
}
|
||||
});
|
||||
|
||||
flv.on('flvFetching', uint8 => {
|
||||
this.uint8 = mergeTypedArrays(this.uint8, uint8);
|
||||
this.parse();
|
||||
});
|
||||
|
||||
flv.on('flvFetchEnd', uint8 => {
|
||||
if (debug) {
|
||||
console.log('[flv-fetch-end]');
|
||||
}
|
||||
this.done = true;
|
||||
if (uint8) {
|
||||
this.uint8 = uint8;
|
||||
this.index = 0;
|
||||
this.header = null;
|
||||
this.scripTag = null;
|
||||
this.tags = [];
|
||||
this.parse();
|
||||
}
|
||||
flv.emit('flvParseDone');
|
||||
if (debug) {
|
||||
console.log('[flv-parse-done]');
|
||||
}
|
||||
});
|
||||
|
||||
if (typeof url === 'string') {
|
||||
fetchStream(flv, url);
|
||||
} else {
|
||||
readFile(flv, url);
|
||||
}
|
||||
}
|
||||
|
||||
parse() {
|
||||
const { debug } = this.flv.options;
|
||||
if (this.uint8.length >= 13 && !this.header) {
|
||||
const header = Object.create(null);
|
||||
header.signature = bin2String(this.read(3));
|
||||
[header.version] = this.read(1);
|
||||
[header.flags] = this.read(1);
|
||||
header.headersize = getUint8Sum(this.read(4));
|
||||
this.header = header;
|
||||
this.read(4);
|
||||
this.flv.emit('flvParseHeader', this.header);
|
||||
if (debug) {
|
||||
console.log('[flv-parse-header]', this.header);
|
||||
}
|
||||
}
|
||||
|
||||
while (this.index < this.uint8.length) {
|
||||
const tag = Object.create(null);
|
||||
[tag.tagType] = this.read(1);
|
||||
tag.dataSize = getUint8Sum(this.read(3));
|
||||
tag.timestamp = this.read(4);
|
||||
tag.streamID = this.read(3);
|
||||
tag.body = this.read(tag.dataSize);
|
||||
this.tags.push(tag);
|
||||
this.read(4);
|
||||
|
||||
switch (tag.tagType) {
|
||||
case 18:
|
||||
this.scripTag = parseScripTag(tag.body);
|
||||
this.flv.emit('parseScripTag', this.scripTag);
|
||||
if (debug) {
|
||||
console.log('[flv-parse-scrip-tag]', this.scripTag);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
this.flv.emit('flvParseTag', tag);
|
||||
}
|
||||
}
|
||||
|
||||
read(length) {
|
||||
const tempUint8 = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
tempUint8[i] = this.uint8[this.index];
|
||||
this.index += 1;
|
||||
}
|
||||
return tempUint8;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
import { getUint8Sum, readUint8, bin2String, bin2Boolean, bin2Float, errorHandle } from '../utils';
|
||||
|
||||
export default function parseScripTag(scripTagBody) {
|
||||
const readScripTag = readUint8(scripTagBody);
|
||||
const metadata = Object.create(null);
|
||||
const amf1 = Object.create(null);
|
||||
const amf2 = Object.create(null);
|
||||
|
||||
[amf1.type] = readScripTag(1);
|
||||
errorHandle(amf1.type === 2, `AMF: [amf1] type expect 2, but got ${amf1.type}`);
|
||||
amf1.size = getUint8Sum(readScripTag(2));
|
||||
amf1.string = bin2String(readScripTag(amf1.size));
|
||||
|
||||
[amf2.type] = readScripTag(1);
|
||||
errorHandle(amf2.type === 8, `AMF: [amf1] type expect 8, but got ${amf2.type}`);
|
||||
amf2.size = getUint8Sum(readScripTag(4));
|
||||
amf2.metaData = Object.create(null);
|
||||
|
||||
function getValue(type) {
|
||||
let value = null;
|
||||
if (type !== undefined) {
|
||||
switch (type) {
|
||||
case 0:
|
||||
value = bin2Float(readScripTag(8));
|
||||
break;
|
||||
case 1:
|
||||
value = bin2Boolean(readScripTag(1)[0]);
|
||||
break;
|
||||
case 2: {
|
||||
const valueLength = getUint8Sum(readScripTag(2));
|
||||
value = bin2String(readScripTag(valueLength));
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
value = Object.create(null);
|
||||
let endObject = false;
|
||||
while (!endObject && readScripTag.index < scripTagBody.length) {
|
||||
const nameLength = getUint8Sum(readScripTag(2));
|
||||
const name = bin2String(readScripTag(nameLength));
|
||||
const type = readScripTag(1)[0];
|
||||
if (name) {
|
||||
value[name] = getValue(type);
|
||||
}
|
||||
if (type === 9) {
|
||||
endObject = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 8: {
|
||||
value = Object.create(null);
|
||||
let endArray = false;
|
||||
while (!endArray && readScripTag.index < scripTagBody.length) {
|
||||
const nameLength = getUint8Sum(readScripTag(2));
|
||||
const name = bin2String(readScripTag(nameLength));
|
||||
const type = readScripTag(1)[0];
|
||||
if (name) {
|
||||
value[name] = getValue(type);
|
||||
}
|
||||
if (type === 9) {
|
||||
endArray = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 10: {
|
||||
const valueLength = getUint8Sum(readScripTag(4));
|
||||
value = [];
|
||||
for (let index = 0; index < valueLength; index += 1) {
|
||||
const itemType = readScripTag(1)[0];
|
||||
value.push(getValue(itemType));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 12: {
|
||||
const valueLength = getUint8Sum(readScripTag(4));
|
||||
value = bin2String(readScripTag(valueLength));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
console.log(readScripTag(scripTagBody.length - readScripTag.index - 1));
|
||||
errorHandle(false, `AMF: Unknown metaData type: ${type}`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
while (readScripTag.index < scripTagBody.length) {
|
||||
const nameLength = getUint8Sum(readScripTag(2));
|
||||
const name = bin2String(readScripTag(nameLength));
|
||||
const type = readScripTag(1)[0];
|
||||
if (name) {
|
||||
amf2.metaData[name] = getValue(type);
|
||||
}
|
||||
}
|
||||
|
||||
errorHandle(readScripTag.index === scripTagBody.length, 'AMF: Seems to be incompletely parsed');
|
||||
errorHandle(amf2.size === Object.keys(amf2.metaData).length, 'AMF: [amf2] length does not match');
|
||||
|
||||
metadata.amf1 = amf1;
|
||||
metadata.amf2 = amf2;
|
||||
return metadata;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
export default function readFile(flv, file) {
|
||||
flv.emit('flvFetchStart');
|
||||
const { proxy } = flv.events;
|
||||
const reader = new FileReader();
|
||||
proxy(reader, 'load', e => {
|
||||
const buffer = e.target.result;
|
||||
const uint8 = new Uint8Array(buffer);
|
||||
flv.emit('flvFetchEnd', uint8);
|
||||
});
|
||||
reader.readAsArrayBuffer(file);
|
||||
}
|
||||
@@ -1,22 +1,58 @@
|
||||
import Flv from './flv';
|
||||
import Emitter from 'tiny-emitter';
|
||||
import checkSupport from './utils/checkSupport';
|
||||
import EventProxy from './eventProxy';
|
||||
import CreatWorker from './creatWorker';
|
||||
import CreatMediaSource from './creatMediaSource';
|
||||
import FlvParse from './flvParse';
|
||||
import * as utils from './utils';
|
||||
import config from './config';
|
||||
|
||||
function artplayerPluginFlv(art) {
|
||||
let flv = null;
|
||||
let id = 0;
|
||||
class Flv extends Emitter {
|
||||
constructor(options) {
|
||||
super();
|
||||
this.options = Object.assign({}, Flv.DEFAULTS, options);
|
||||
checkSupport(this.options);
|
||||
this.events = new EventProxy(this);
|
||||
this.workers = new CreatWorker(this);
|
||||
this.mediaSource = new CreatMediaSource(this);
|
||||
this.flvData = new FlvParse(this);
|
||||
id += 1;
|
||||
this.id = id;
|
||||
Flv.instances.push(this);
|
||||
}
|
||||
|
||||
art.on('destroy', () => {
|
||||
if (flv) {
|
||||
flv.destroy();
|
||||
}
|
||||
});
|
||||
static get DEFAULTS() {
|
||||
return {
|
||||
mediaElement: '',
|
||||
url: '',
|
||||
debug: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
flv,
|
||||
init: (mediaElement, url) => {
|
||||
flv = new Flv(mediaElement, url);
|
||||
flv.load();
|
||||
},
|
||||
};
|
||||
static get version() {
|
||||
return '__VERSION__';
|
||||
}
|
||||
|
||||
static get config() {
|
||||
return config;
|
||||
}
|
||||
|
||||
static get utils() {
|
||||
return utils;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.events.destroy();
|
||||
this.workers.killAll();
|
||||
Flv.instances.splice(Flv.instances.indexOf(this), 1);
|
||||
this.emit('destroy');
|
||||
}
|
||||
}
|
||||
|
||||
window.artplayerPluginFlv = artplayerPluginFlv;
|
||||
export default artplayerPluginFlv;
|
||||
Object.defineProperty(Flv, 'instances', {
|
||||
value: [],
|
||||
});
|
||||
|
||||
window.Flv = Flv;
|
||||
export default Flv;
|
||||
@@ -0,0 +1,24 @@
|
||||
import { errorHandle } from '.';
|
||||
|
||||
export default function checkSupport(options) {
|
||||
const { mediaElement, url } = options;
|
||||
errorHandle(mediaElement instanceof HTMLVideoElement, 'The first parameter is not a video tag element');
|
||||
errorHandle(
|
||||
typeof url === 'string' || (url instanceof File && url.type === 'video/x-flv'),
|
||||
'The second parameter is not a string type or flv file',
|
||||
);
|
||||
|
||||
const MP4H264MimeCodec = 'video/mp4; codecs="avc1.42001E, mp4a.40.2"';
|
||||
const canPlay = mediaElement.canPlayType(MP4H264MimeCodec);
|
||||
errorHandle(
|
||||
window.MediaSource &&
|
||||
window.MediaSource.isTypeSupported(MP4H264MimeCodec) &&
|
||||
(canPlay === 'probably' || canPlay === 'maybe'),
|
||||
`Unsupported MIME type or codec: ${MP4H264MimeCodec}`,
|
||||
);
|
||||
|
||||
errorHandle(typeof window.Promise === 'function', "Unsupported 'Promise' method");
|
||||
errorHandle(typeof window.fetch === 'function', "Unsupported 'fetch' method");
|
||||
errorHandle(typeof window.Worker === 'function', "Unsupported 'Worker' method");
|
||||
errorHandle(typeof window.ReadableStream === 'function', "Unsupported 'ReadableStream' method");
|
||||
}
|
||||
+2
-8
@@ -1,4 +1,4 @@
|
||||
export class FlvError extends Error {
|
||||
export default class FlvError extends Error {
|
||||
constructor(message, context) {
|
||||
super(message);
|
||||
if (typeof Error.captureStackTrace === 'function') {
|
||||
@@ -6,10 +6,4 @@ export class FlvError extends Error {
|
||||
}
|
||||
this.name = 'FlvError';
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandle(condition, msg) {
|
||||
if (!condition) {
|
||||
throw new FlvError(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
import FlvError from './flvError';
|
||||
|
||||
export function errorHandle(condition, msg) {
|
||||
if (!condition) {
|
||||
throw new FlvError(msg);
|
||||
}
|
||||
}
|
||||
|
||||
export function mergeTypedArrays(a, b) {
|
||||
const c = new a.constructor(a.length + b.length);
|
||||
c.set(a);
|
||||
c.set(b, a.length);
|
||||
return c;
|
||||
}
|
||||
|
||||
export function sleep(ms = 0) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export function getUint8Sum(arr) {
|
||||
return arr.reduce((totle, num, index) => totle + num * 256 ** (arr.length - index - 1), 0);
|
||||
}
|
||||
|
||||
export function string2Bin(str) {
|
||||
const result = [];
|
||||
for (let i = 0; i < str.length; i += 1) {
|
||||
result.push(Number(str.charCodeAt(i).toString(10)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function bin2String(array) {
|
||||
return String.fromCharCode.call(String, ...array);
|
||||
}
|
||||
|
||||
export function bin2Float(array) {
|
||||
const view = new DataView(new ArrayBuffer(array.length));
|
||||
array.forEach((b, i) => {
|
||||
view.setUint8(i, b);
|
||||
});
|
||||
return view.getFloat64(0);
|
||||
}
|
||||
|
||||
export function bin2Boolean(bin) {
|
||||
return bin === 1;
|
||||
}
|
||||
|
||||
export function log(name, msg = '') {
|
||||
console.log(`[${name}] ${msg}`);
|
||||
}
|
||||
|
||||
export function readUint8(uint8) {
|
||||
let index = 0;
|
||||
return function read(length) {
|
||||
const tempUint8 = new Uint8Array(length);
|
||||
for (let i = 0; i < length; i += 1) {
|
||||
tempUint8[i] = uint8[index];
|
||||
index += 1;
|
||||
}
|
||||
read.index = index;
|
||||
return tempUint8;
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user