@jxstjh/jhvideo
Version:
HTML5 jhvideo base on MPEG2-TS Stream Player
919 lines (917 loc) • 403 kB
JavaScript
(function (f) { if (typeof exports === "object" && typeof module !== "undefined") {
module.exports = f();
}
else if (typeof define === "function" && define.amd) {
define([], f);
}
else {
var g;
if (typeof window !== "undefined") {
g = window;
}
else if (typeof global !== "undefined") {
g = global;
}
else if (typeof self !== "undefined") {
g = self;
}
else {
g = this;
}
g.EBML = f();
} })(function () {
var define, module, exports;
return (function () { function r(e, n, t) { function o(i, f) { if (!n[i]) {
if (!e[i]) {
var c = "function" == typeof require && require;
if (!f && c)
return c(i, !0);
if (u)
return u(i, !0);
var a = new Error("Cannot find module '" + i + "'");
throw a.code = "MODULE_NOT_FOUND", a;
}
var p = n[i] = { exports: {} };
e[i][0].call(p.exports, function (r) { var n = e[i][1][r]; return o(n || r); }, p, p.exports, r, e, n, t);
} return n[i].exports; } for (var u = "function" == typeof require && require, i = 0; i < t.length; i++)
o(t[i]); return o; } return r; })()({
1: [function (require, module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tools_1 = require("./tools");
var int64_buffer_1 = require("int64-buffer");
var tools = require("./tools");
var schema = require("matroska/lib/schema");
var byEbmlID = schema.byEbmlID;
// https://www.matroska.org/technical/specs/index.html
var State;
(function (State) {
State[State["STATE_TAG"] = 1] = "STATE_TAG";
State[State["STATE_SIZE"] = 2] = "STATE_SIZE";
State[State["STATE_CONTENT"] = 3] = "STATE_CONTENT";
})(State || (State = {}));
var EBMLDecoder = /** @class */ (function () {
function EBMLDecoder() {
this._buffer = new tools_1.Buffer(0);
this._tag_stack = [];
this._state = State.STATE_TAG;
this._cursor = 0;
this._total = 0;
this._schema = byEbmlID;
this._result = [];
}
EBMLDecoder.prototype.decode = function (chunk) {
this.readChunk(chunk);
var diff = this._result;
this._result = [];
return diff;
};
EBMLDecoder.prototype.readChunk = function (chunk) {
// 読みかけの(読めなかった) this._buffer と 新しい chunk を合わせて読み直す
this._buffer = tools.concat([this._buffer, new tools_1.Buffer(chunk)]);
while (this._cursor < this._buffer.length) {
// console.log(this._cursor, this._total, this._tag_stack);
if (this._state === State.STATE_TAG && !this.readTag()) {
break;
}
if (this._state === State.STATE_SIZE && !this.readSize()) {
break;
}
if (this._state === State.STATE_CONTENT && !this.readContent()) {
break;
}
}
};
EBMLDecoder.prototype.getSchemaInfo = function (tagNum) {
return this._schema[tagNum] || {
name: "unknown",
level: -1,
type: "unknown",
description: "unknown"
};
};
/**
* vint された parsing tag
* @return - return false when waiting for more data
*/
EBMLDecoder.prototype.readTag = function () {
// tag.length が buffer の外にある
if (this._cursor >= this._buffer.length) {
return false;
}
// read ebml id vint without first byte
var tag = tools_1.readVint(this._buffer, this._cursor);
// tag が読めなかった
if (tag == null) {
return false;
}
// >>>>>>>>>
// tag 識別子
//const tagStr = this._buffer.toString("hex", this._cursor, this._cursor + tag.length);
//const tagNum = parseInt(tagStr, 16);
// 上と等価
var buf = this._buffer.slice(this._cursor, this._cursor + tag.length);
var tagNum = buf.reduce(function (o, v, i, arr) { return o + v * Math.pow(16, 2 * (arr.length - 1 - i)); }, 0);
var schema = this.getSchemaInfo(tagNum);
var tagObj = {
EBML_ID: tagNum.toString(16),
schema: schema,
type: schema.type,
name: schema.name,
level: schema.level,
tagStart: this._total,
tagEnd: this._total + tag.length,
sizeStart: this._total + tag.length,
sizeEnd: null,
dataStart: null,
dataEnd: null,
dataSize: null,
data: null
};
// | tag: vint | size: vint | data: Buffer(size) |
this._tag_stack.push(tagObj);
// <<<<<<<<
// ポインタを進める
this._cursor += tag.length;
this._total += tag.length;
// 読み込み状態変更
this._state = State.STATE_SIZE;
return true;
};
/**
* vint された現在のタグの内容の大きさを読み込む
* @return - return false when waiting for more data
*/
EBMLDecoder.prototype.readSize = function () {
// tag.length が buffer の外にある
if (this._cursor >= this._buffer.length) {
return false;
}
// read ebml datasize vint without first byte
var size = tools_1.readVint(this._buffer, this._cursor);
// まだ読めない
if (size == null) {
return false;
}
// >>>>>>>>>
// current tag の data size 決定
var tagObj = this._tag_stack[this._tag_stack.length - 1];
tagObj.sizeEnd = tagObj.sizeStart + size.length;
tagObj.dataStart = tagObj.sizeEnd;
tagObj.dataSize = size.value;
if (size.value === -1) {
// unknown size
tagObj.dataEnd = -1;
if (tagObj.type === "m") {
tagObj.unknownSize = true;
}
}
else {
tagObj.dataEnd = tagObj.sizeEnd + size.value;
}
// <<<<<<<<
// ポインタを進める
this._cursor += size.length;
this._total += size.length;
this._state = State.STATE_CONTENT;
return true;
};
/**
* データ読み込み
*/
EBMLDecoder.prototype.readContent = function () {
var tagObj = this._tag_stack[this._tag_stack.length - 1];
// master element は子要素を持つので生データはない
if (tagObj.type === 'm') {
// console.log('content should be tags');
tagObj.isEnd = false;
this._result.push(tagObj);
this._state = State.STATE_TAG;
// この Mastert Element は空要素か
if (tagObj.dataSize === 0) {
// 即座に終了タグを追加
var elm = Object.assign({}, tagObj, { isEnd: true });
this._result.push(elm);
this._tag_stack.pop(); // スタックからこのタグを捨てる
}
return true;
}
// waiting for more data
if (this._buffer.length < this._cursor + tagObj.dataSize) {
return false;
}
// タグの中身の生データ
var data = this._buffer.slice(this._cursor, this._cursor + tagObj.dataSize);
// 読み終わったバッファを捨てて読み込んでいる部分のバッファのみ残す
this._buffer = this._buffer.slice(this._cursor + tagObj.dataSize);
tagObj.data = data;
// >>>>>>>>>
switch (tagObj.type) {
//case "m": break;
// Master-Element - contains other EBML sub-elements of the next lower level
case "u":
tagObj.value = data.readUIntBE(0, data.length);
break;
// Unsigned Integer - Big-endian, any size from 1 to 8 octets
case "i":
tagObj.value = data.readIntBE(0, data.length);
break;
// Signed Integer - Big-endian, any size from 1 to 8 octets
case "f":
tagObj.value = tagObj.dataSize === 4 ? data.readFloatBE(0) :
tagObj.dataSize === 8 ? data.readDoubleBE(0) :
(console.warn("cannot read " + tagObj.dataSize + " octets float. failback to 0"), 0);
break;
// Float - Big-endian, defined for 4 and 8 octets (32, 64 bits)
case "s":
tagObj.value = data.toString("ascii");
break; // ascii
// Printable ASCII (0x20 to 0x7E), zero-padded when needed
case "8":
tagObj.value = data.toString("utf8");
break;
// Unicode string, zero padded when needed (RFC 2279)
case "b":
tagObj.value = data;
break;
// Binary - not interpreted by the parser
case "d":
tagObj.value = tools_1.convertEBMLDateToJSDate(new int64_buffer_1.Int64BE(data).toNumber());
break;
// nano second; Date.UTC(2001,1,1,0,0,0,0) === 980985600000
// Date - signed 8 octets integer in nanoseconds with 0 indicating
// the precise beginning of the millennium (at 2001-01-01T00:00:00,000000000 UTC)
}
if (tagObj.value === null) {
throw new Error("unknown tag type:" + tagObj.type);
}
this._result.push(tagObj);
// <<<<<<<<
// ポインタを進める
this._total += tagObj.dataSize;
// タグ待ちモードに変更
this._state = State.STATE_TAG;
this._cursor = 0;
this._tag_stack.pop(); // remove the object from the stack
while (this._tag_stack.length > 0) {
var topEle = this._tag_stack[this._tag_stack.length - 1];
// 親が不定長サイズなので閉じタグは期待できない
if (topEle.dataEnd < 0) {
this._tag_stack.pop(); // 親タグを捨てる
return true;
}
// 閉じタグの来るべき場所まで来たかどうか
if (this._total < topEle.dataEnd) {
break;
}
// 閉じタグを挿入すべきタイミングが来た
if (topEle.type !== "m") {
throw new Error("parent element is not master element");
}
var elm = Object.assign({}, topEle, { isEnd: true });
this._result.push(elm);
this._tag_stack.pop();
}
return true;
};
return EBMLDecoder;
}());
exports.default = EBMLDecoder;
}, { "./tools": 5, "int64-buffer": 15, "matroska/lib/schema": 17 }], 2: [function (require, module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tools = require("./tools");
var tools_1 = require("./tools");
var schema = require("matroska/lib/schema");
var byEbmlID = schema.byEbmlID;
var EBMLEncoder = /** @class */ (function () {
function EBMLEncoder() {
this._schema = byEbmlID;
this._buffers = [];
this._stack = [];
}
EBMLEncoder.prototype.encode = function (elms) {
var _this = this;
return tools.concat(elms.reduce(function (lst, elm) {
return lst.concat(_this.encodeChunk(elm));
}, [])).buffer;
};
EBMLEncoder.prototype.encodeChunk = function (elm) {
if (elm.type === "m") {
if (!elm.isEnd) {
this.startTag(elm);
}
else {
this.endTag(elm);
}
}
else {
this.writeTag(elm);
}
return this.flush();
};
EBMLEncoder.prototype.flush = function () {
var ret = this._buffers;
this._buffers = [];
return ret;
};
EBMLEncoder.prototype.getSchemaInfo = function (tagName) {
var tagNums = Object.keys(this._schema).map(Number);
for (var i = 0; i < tagNums.length; i++) {
var tagNum = tagNums[i];
if (this._schema[tagNum].name === tagName) {
return new tools_1.Buffer(tagNum.toString(16), 'hex');
}
}
return null;
};
EBMLEncoder.prototype.writeTag = function (elm) {
var tagName = elm.name;
var tagId = this.getSchemaInfo(tagName);
var tagData = elm.data;
if (tagId == null) {
throw new Error('No schema entry found for ' + tagName);
}
var data = tools.encodeTag(tagId, tagData);
/**
* 親要素が閉じタグあり(isEnd)なら閉じタグが来るまで待つ(children queに入る)
*/
if (this._stack.length > 0) {
var last = this._stack[this._stack.length - 1];
last.children.push({
tagId: tagId,
elm: elm,
children: [],
data: data
});
return;
}
this._buffers = this._buffers.concat(data);
return;
};
EBMLEncoder.prototype.startTag = function (elm) {
var tagName = elm.name;
var tagId = this.getSchemaInfo(tagName);
if (tagId == null) {
throw new Error('No schema entry found for ' + tagName);
}
/**
* 閉じタグ不定長の場合はスタックに積まずに即時バッファに書き込む
*/
if (elm.unknownSize) {
var data = tools.encodeTag(tagId, new tools_1.Buffer(0), elm.unknownSize);
this._buffers = this._buffers.concat(data);
return;
}
var tag = {
tagId: tagId,
elm: elm,
children: [],
data: null
};
if (this._stack.length > 0) {
this._stack[this._stack.length - 1].children.push(tag);
}
this._stack.push(tag);
};
EBMLEncoder.prototype.endTag = function (elm) {
var tagName = elm.name;
var tag = this._stack.pop();
if (tag == null) {
throw new Error("EBML structure is broken");
}
if (tag.elm.name !== elm.name) {
throw new Error("EBML structure is broken");
}
var childTagDataBuffers = tag.children.reduce(function (lst, child) {
if (child.data === null) {
throw new Error("EBML structure is broken");
}
return lst.concat(child.data);
}, []);
var childTagDataBuffer = tools.concat(childTagDataBuffers);
if (tag.elm.type === "m") {
tag.data = tools.encodeTag(tag.tagId, childTagDataBuffer, tag.elm.unknownSize);
}
else {
tag.data = tools.encodeTag(tag.tagId, childTagDataBuffer);
}
if (this._stack.length < 1) {
this._buffers = this._buffers.concat(tag.data);
}
};
return EBMLEncoder;
}());
exports.default = EBMLEncoder;
}, { "./tools": 5, "matroska/lib/schema": 17 }], 3: [function (require, module, exports) {
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b)
if (b.hasOwnProperty(p))
d[p] = b[p]; };
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = require("events");
var tools = require("./tools");
/**
* This is an informal code for reference.
* EBMLReader is a class for getting information to enable seeking Webm recorded by MediaRecorder.
* So please do not use for regular WebM files.
*/
var EBMLReader = /** @class */ (function (_super) {
__extends(EBMLReader, _super);
function EBMLReader() {
var _this = _super.call(this) || this;
_this.logGroup = "";
_this.hasLoggingStarted = false;
_this.metadataloaded = false;
_this.chunks = [];
_this.stack = [];
_this.segmentOffset = 0;
_this.last2SimpleBlockVideoTrackTimecode = [0, 0];
_this.last2SimpleBlockAudioTrackTimecode = [0, 0];
_this.lastClusterTimecode = 0;
_this.lastClusterPosition = 0;
_this.timecodeScale = 1000000; // webm default TimecodeScale is 1ms
_this.metadataSize = 0;
_this.metadatas = [];
_this.cues = [];
_this.firstVideoBlockRead = false;
_this.firstAudioBlockRead = false;
_this.currentTrack = { TrackNumber: -1, TrackType: -1, DefaultDuration: null, CodecDelay: null };
_this.trackTypes = [];
_this.trackDefaultDuration = [];
_this.trackCodecDelay = [];
_this.trackInfo = { type: "nothing" };
_this.ended = false;
_this.logging = false;
_this.use_duration_every_simpleblock = false;
_this.use_webp = false;
_this.use_segment_info = true;
_this.drop_default_duration = true;
return _this;
}
/**
* emit final state.
*/
EBMLReader.prototype.stop = function () {
this.ended = true;
this.emit_segment_info();
// clean up any unclosed Master Elements at the end of the stream.
while (this.stack.length) {
this.stack.pop();
if (this.logging) {
console.groupEnd();
}
}
// close main group if set, logging is enabled, and has actually logged anything.
if (this.logging && this.hasLoggingStarted && this.logGroup) {
console.groupEnd();
}
};
/**
* emit chunk info
*/
EBMLReader.prototype.emit_segment_info = function () {
var data = this.chunks;
this.chunks = [];
if (!this.metadataloaded) {
this.metadataloaded = true;
this.metadatas = data;
var videoTrackNum = this.trackTypes.indexOf(1); // find first video track
var audioTrackNum = this.trackTypes.indexOf(2); // find first audio track
this.trackInfo = videoTrackNum >= 0 && audioTrackNum >= 0 ? { type: "both", trackNumber: videoTrackNum }
: videoTrackNum >= 0 ? { type: "video", trackNumber: videoTrackNum }
: audioTrackNum >= 0 ? { type: "audio", trackNumber: audioTrackNum }
: { type: "nothing" };
if (!this.use_segment_info) {
return;
}
this.emit("metadata", { data: data, metadataSize: this.metadataSize });
}
else {
if (!this.use_segment_info) {
return;
}
var timecode = this.lastClusterTimecode;
var duration = this.duration;
var timecodeScale = this.timecodeScale;
this.emit("cluster", { timecode: timecode, data: data });
this.emit("duration", { timecodeScale: timecodeScale, duration: duration });
}
};
EBMLReader.prototype.read = function (elm) {
var _this = this;
var drop = false;
if (this.ended) {
// reader is finished
return;
}
if (elm.type === "m") {
// 閉じタグの自動挿入
if (elm.isEnd) {
this.stack.pop();
}
else {
var parent_1 = this.stack[this.stack.length - 1];
if (parent_1 != null && parent_1.level >= elm.level) {
// 閉じタグなしでレベルが下がったら閉じタグを挿入
this.stack.pop();
// From http://w3c.github.io/media-source/webm-byte-stream-format.html#webm-media-segments
// This fixes logging for webm streams with Cluster of unknown length and no Cluster closing elements.
if (this.logging) {
console.groupEnd();
}
parent_1.dataEnd = elm.dataEnd;
parent_1.dataSize = elm.dataEnd - parent_1.dataStart;
parent_1.unknownSize = false;
var o = Object.assign({}, parent_1, { name: parent_1.name, type: parent_1.type, isEnd: true });
this.chunks.push(o);
}
this.stack.push(elm);
}
}
if (elm.type === "m" && elm.name == "Segment") {
if (this.segmentOffset != 0) {
console.warn("Multiple segments detected!");
}
this.segmentOffset = elm.dataStart;
this.emit("segment_offset", this.segmentOffset);
}
else if (elm.type === "b" && elm.name === "SimpleBlock") {
var _a = tools.ebmlBlock(elm.data), timecode = _a.timecode, trackNumber = _a.trackNumber, frames_1 = _a.frames;
if (this.trackTypes[trackNumber] === 1) { // trackType === 1 => video track
if (!this.firstVideoBlockRead) {
this.firstVideoBlockRead = true;
if (this.trackInfo.type === "both" || this.trackInfo.type === "video") {
var CueTime = this.lastClusterTimecode + timecode;
this.cues.push({ CueTrack: trackNumber, CueClusterPosition: this.lastClusterPosition, CueTime: CueTime });
this.emit("cue_info", { CueTrack: trackNumber, CueClusterPosition: this.lastClusterPosition, CueTime: this.lastClusterTimecode });
this.emit("cue", { CueTrack: trackNumber, CueClusterPosition: this.lastClusterPosition, CueTime: CueTime });
}
}
this.last2SimpleBlockVideoTrackTimecode = [this.last2SimpleBlockVideoTrackTimecode[1], timecode];
}
else if (this.trackTypes[trackNumber] === 2) { // trackType === 2 => audio track
if (!this.firstAudioBlockRead) {
this.firstAudioBlockRead = true;
if (this.trackInfo.type === "audio") {
var CueTime = this.lastClusterTimecode + timecode;
this.cues.push({ CueTrack: trackNumber, CueClusterPosition: this.lastClusterPosition, CueTime: CueTime });
this.emit("cue_info", { CueTrack: trackNumber, CueClusterPosition: this.lastClusterPosition, CueTime: this.lastClusterTimecode });
this.emit("cue", { CueTrack: trackNumber, CueClusterPosition: this.lastClusterPosition, CueTime: CueTime });
}
}
this.last2SimpleBlockAudioTrackTimecode = [this.last2SimpleBlockAudioTrackTimecode[1], timecode];
}
if (this.use_duration_every_simpleblock) {
this.emit("duration", { timecodeScale: this.timecodeScale, duration: this.duration });
}
if (this.use_webp) {
frames_1.forEach(function (frame) {
var startcode = frame.slice(3, 6).toString("hex");
if (startcode !== "9d012a") {
return;
}
; // VP8 の場合
var webpBuf = tools.VP8BitStreamToRiffWebPBuffer(frame);
var webp = new Blob([webpBuf], { type: "image/webp" });
var currentTime = _this.duration;
_this.emit("webp", { currentTime: currentTime, webp: webp });
});
}
}
else if (elm.type === "m" && elm.name === "Cluster" && elm.isEnd === false) {
this.firstVideoBlockRead = false;
this.firstAudioBlockRead = false;
this.emit_segment_info();
this.emit("cluster_ptr", elm.tagStart);
this.lastClusterPosition = elm.tagStart;
}
else if (elm.type === "u" && elm.name === "Timecode") {
this.lastClusterTimecode = elm.value;
}
else if (elm.type === "u" && elm.name === "TimecodeScale") {
this.timecodeScale = elm.value;
}
else if (elm.type === "m" && elm.name === "TrackEntry") {
if (elm.isEnd) {
this.trackTypes[this.currentTrack.TrackNumber] = this.currentTrack.TrackType;
this.trackDefaultDuration[this.currentTrack.TrackNumber] = this.currentTrack.DefaultDuration;
this.trackCodecDelay[this.currentTrack.TrackNumber] = this.currentTrack.CodecDelay;
}
else {
this.currentTrack = { TrackNumber: -1, TrackType: -1, DefaultDuration: null, CodecDelay: null };
}
}
else if (elm.type === "u" && elm.name === "TrackType") {
this.currentTrack.TrackType = elm.value;
}
else if (elm.type === "u" && elm.name === "TrackNumber") {
this.currentTrack.TrackNumber = elm.value;
}
else if (elm.type === "u" && elm.name === "CodecDelay") {
this.currentTrack.CodecDelay = elm.value;
}
else if (elm.type === "u" && elm.name === "DefaultDuration") {
// media source api は DefaultDuration を計算するとバグる。
// https://bugs.chromium.org/p/chromium/issues/detail?id=606000#c22
// chrome 58 ではこれを回避するために DefaultDuration 要素を抜き取った。
// chrome 58 以前でもこのタグを抜き取ることで回避できる
if (this.drop_default_duration) {
console.warn("DefaultDuration detected!, remove it");
drop = true;
}
else {
this.currentTrack.DefaultDuration = elm.value;
}
}
else if (elm.name === "unknown") {
console.warn(elm);
}
if (!this.metadataloaded && elm.dataEnd > 0) {
this.metadataSize = elm.dataEnd;
}
if (!drop) {
this.chunks.push(elm);
}
if (this.logging) {
this.put(elm);
}
};
Object.defineProperty(EBMLReader.prototype, "duration", {
/**
* DefaultDuration が定義されている場合は最後のフレームのdurationも考慮する
* 単位 timecodeScale
*
* !!! if you need duration with seconds !!!
* ```js
* const nanosec = reader.duration * reader.timecodeScale;
* const sec = nanosec / 1000 / 1000 / 1000;
* ```
*/
get: function () {
if (this.trackInfo.type === "nothing") {
console.warn("no video, no audio track");
return 0;
}
// defaultDuration は 生の nano sec
var defaultDuration = 0;
// nanoseconds
var codecDelay = 0;
var lastTimecode = 0;
var _defaultDuration = this.trackDefaultDuration[this.trackInfo.trackNumber];
if (typeof _defaultDuration === "number") {
defaultDuration = _defaultDuration;
}
else {
// https://bugs.chromium.org/p/chromium/issues/detail?id=606000#c22
// default duration がないときに使う delta
if (this.trackInfo.type === "both") {
if (this.last2SimpleBlockAudioTrackTimecode[1] > this.last2SimpleBlockVideoTrackTimecode[1]) {
// audio diff
defaultDuration = (this.last2SimpleBlockAudioTrackTimecode[1] - this.last2SimpleBlockAudioTrackTimecode[0]) * this.timecodeScale;
// audio delay
var delay = this.trackCodecDelay[this.trackTypes.indexOf(2)]; // 2 => audio
if (typeof delay === "number") {
codecDelay = delay;
}
// audio timecode
lastTimecode = this.last2SimpleBlockAudioTrackTimecode[1];
}
else {
// video diff
defaultDuration = (this.last2SimpleBlockVideoTrackTimecode[1] - this.last2SimpleBlockVideoTrackTimecode[0]) * this.timecodeScale;
// video delay
var delay = this.trackCodecDelay[this.trackTypes.indexOf(1)]; // 1 => video
if (typeof delay === "number") {
codecDelay = delay;
}
// video timecode
lastTimecode = this.last2SimpleBlockVideoTrackTimecode[1];
}
}
else if (this.trackInfo.type === "video") {
defaultDuration = (this.last2SimpleBlockVideoTrackTimecode[1] - this.last2SimpleBlockVideoTrackTimecode[0]) * this.timecodeScale;
var delay = this.trackCodecDelay[this.trackInfo.trackNumber]; // 2 => audio
if (typeof delay === "number") {
codecDelay = delay;
}
lastTimecode = this.last2SimpleBlockVideoTrackTimecode[1];
}
else if (this.trackInfo.type === "audio") {
defaultDuration = (this.last2SimpleBlockAudioTrackTimecode[1] - this.last2SimpleBlockAudioTrackTimecode[0]) * this.timecodeScale;
var delay = this.trackCodecDelay[this.trackInfo.trackNumber]; // 1 => video
if (typeof delay === "number") {
codecDelay = delay;
}
lastTimecode = this.last2SimpleBlockAudioTrackTimecode[1];
} // else { not reached }
}
// convert to timecodescale
var duration_nanosec = ((this.lastClusterTimecode + lastTimecode) * this.timecodeScale) + defaultDuration - codecDelay;
var duration = duration_nanosec / this.timecodeScale;
return Math.floor(duration);
},
enumerable: true,
configurable: true
});
EBMLReader.prototype.addListener = function (event, listener) {
return _super.prototype.addListener.call(this, event, listener);
};
EBMLReader.prototype.put = function (elm) {
if (!this.hasLoggingStarted) {
this.hasLoggingStarted = true;
if (this.logging && this.logGroup) {
console.groupCollapsed(this.logGroup);
}
}
if (elm.type === "m") {
if (elm.isEnd) {
console.groupEnd();
}
else {
console.group(elm.name + ":" + elm.tagStart);
}
}
else if (elm.type === "b") {
// for debug
//if(elm.name === "SimpleBlock"){
//const o = EBML.tools.ebmlBlock(elm.value);
//console.log(elm.name, elm.type, o.trackNumber, o.timecode);
//}else{
console.log(elm.name, elm.type);
//}
}
else {
console.log(elm.name, elm.tagStart, elm.type, elm.value);
}
};
return EBMLReader;
}(events_1.EventEmitter));
exports.default = EBMLReader;
;
;
;
;
}, { "./tools": 5, "events": 13 }], 4: [function (require, module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var EBMLDecoder_1 = require("./EBMLDecoder");
exports.Decoder = EBMLDecoder_1.default;
var EBMLEncoder_1 = require("./EBMLEncoder");
exports.Encoder = EBMLEncoder_1.default;
var EBMLReader_1 = require("./EBMLReader");
exports.Reader = EBMLReader_1.default;
var tools = require("./tools");
exports.tools = tools;
var version = require("../package.json").version;
exports.version = version;
}, { "../package.json": 18, "./EBMLDecoder": 1, "./EBMLEncoder": 2, "./EBMLReader": 3, "./tools": 5 }], 5: [function (require, module, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/// <reference types="node"/>
var int64_buffer_1 = require("int64-buffer");
var EBMLEncoder_1 = require("./EBMLEncoder");
var _Buffer = require("buffer/");
var _tools = require("ebml/lib/ebml/tools");
var _block = require("ebml-block");
exports.Buffer = _Buffer.Buffer;
exports.readVint = _tools.readVint;
exports.writeVint = _tools.writeVint;
exports.ebmlBlock = _block;
function readBlock(buf) {
return exports.ebmlBlock(new exports.Buffer(buf));
}
exports.readBlock = readBlock;
/**
* @param end - if end === false then length is unknown
*/
function encodeTag(tagId, tagData, unknownSize) {
if (unknownSize === void 0) {
unknownSize = false;
}
return concat([
tagId,
unknownSize ?
new exports.Buffer('01ffffffffffffff', 'hex') :
exports.writeVint(tagData.length),
tagData
]);
}
exports.encodeTag = encodeTag;
/**
* @return - SimpleBlock to WebP Filter
*/
function WebPFrameFilter(elms) {
return WebPBlockFilter(elms).reduce(function (lst, elm) {
var o = exports.ebmlBlock(elm.data);
return o.frames.reduce(function (lst, frame) {
// https://developers.Blob.com/speed/webp/docs/riff_container
var webpBuf = VP8BitStreamToRiffWebPBuffer(frame);
var webp = new Blob([webpBuf], { type: "image/webp" });
return lst.concat(webp);
}, lst);
}, []);
}
exports.WebPFrameFilter = WebPFrameFilter;
/**
* WebP ファイルにできる SimpleBlock の パスフィルタ
*/
function WebPBlockFilter(elms) {
return elms.reduce(function (lst, elm) {
if (elm.type !== "b") {
return lst;
}
if (elm.name !== "SimpleBlock") {
return lst;
}
var o = exports.ebmlBlock(elm.data);
var hasWebP = o.frames.some(function (frame) {
// https://tools.ietf.org/html/rfc6386#section-19.1
var startcode = frame.slice(3, 6).toString("hex");
return startcode === "9d012a";
});
if (!hasWebP) {
return lst;
}
return lst.concat(elm);
}, []);
}
exports.WebPBlockFilter = WebPBlockFilter;
/**
* @param frame - VP8 BitStream のうち startcode をもつ frame
* @return - WebP ファイルの ArrayBuffer
*/
function VP8BitStreamToRiffWebPBuffer(frame) {
var VP8Chunk = createRIFFChunk("VP8 ", frame);
var WebPChunk = concat([
new exports.Buffer("WEBP", "ascii"),
VP8Chunk
]);
return createRIFFChunk("RIFF", WebPChunk);
}
exports.VP8BitStreamToRiffWebPBuffer = VP8BitStreamToRiffWebPBuffer;
/**
* RIFF データチャンクを作る
*/
function createRIFFChunk(FourCC, chunk) {
var chunkSize = new exports.Buffer(4);
chunkSize.writeUInt32LE(chunk.byteLength, 0);
return concat([
new exports.Buffer(FourCC.substr(0, 4), "ascii"),
chunkSize,
chunk,
new exports.Buffer(chunk.byteLength % 2 === 0 ? 0 : 1) // padding
]);
}
exports.createRIFFChunk = createRIFFChunk;
/* Original Metadata
m 0 EBML
u 1 EBMLVersion 1
u 1 EBMLReadVersion 1
u 1 EBMLMaxIDLength 4
u 1 EBMLMaxSizeLength 8
s 1 DocType webm
u 1 DocTypeVersion 4
u 1 DocTypeReadVersion 2
m 0 Segment
m 1 Info segmentContentStartPos, all CueClusterPositions provided in info.cues will be relative to here and will need adjusted
u 2 TimecodeScale 1000000
8 2 MuxingApp Chrome
8 2 WritingApp Chrome
m 1 Tracks tracksStartPos
m 2 TrackEntry
u 3 TrackNumber 1
u 3 TrackUID 31790271978391090
u 3 TrackType 2
s 3 CodecID A_OPUS
b 3 CodecPrivate <Buffer 19>
m 3 Audio
f 4 SamplingFrequency 48000
u 4 Channels 1
m 2 TrackEntry
u 3 TrackNumber 2
u 3 TrackUID 24051277436254136
u 3 TrackType 1
s 3 CodecID V_VP8
m 3 Video
u 4 PixelWidth 1024
u 4 PixelHeight 576
m 1 Cluster clusterStartPos
u 2 Timecode 0
b 2 SimpleBlock track:2 timecode:0 keyframe:true invisible:false discardable:false lacing:1
*/
/* Desired Metadata
m 0 EBML
u 1 EBMLVersion 1
u 1 EBMLReadVersion 1
u 1 EBMLMaxIDLength 4
u 1