ts-ebml-esm
Version:
ebml decoder and encoder
458 lines (457 loc) • 12.6 kB
JavaScript
import { Uint64BE as Z, Int64BE as x } from "int64-buffer";
import { tools as W } from "ebml";
import q from "ebml-block";
import G from "matroska-schema";
const { byEbmlID: K } = G;
class g {
constructor() {
this._schema = K, this._buffers = [], this._stack = [];
}
encode(e) {
return m(
e.reduce((t, r) => t.concat(this.encodeChunk(r)), [])
).buffer;
}
encodeChunk(e) {
return e.type === "m" ? e.isEnd ? this.endTag(e) : this.startTag(e) : (e.data = Buffer.from(e.data), this.writeTag(e)), this.flush();
}
flush() {
const e = this._buffers;
return this._buffers = [], e;
}
getSchemaInfo(e) {
for (const [t, r] of Object.entries(this._schema))
if (r.name === e)
return Buffer.from(Number(t).toString(16), "hex");
return null;
}
writeTag(e) {
const t = e.name, r = this.getSchemaInfo(t), s = e.data;
if (r == null)
throw new Error("No schema entry found for " + t);
const a = E(r, s);
if (this._stack.length > 0) {
this._stack[this._stack.length - 1].children.push({
tagId: r,
elm: e,
children: [],
data: a
});
return;
}
this._buffers = this._buffers.concat(a);
}
startTag(e) {
const t = e.name, r = this.getSchemaInfo(t);
if (r == null)
throw new Error("No schema entry found for " + t);
if (e.unknownSize) {
const a = E(r, Buffer.alloc(0), e.unknownSize);
this._buffers = this._buffers.concat(a);
return;
}
const s = {
tagId: r,
elm: e,
children: [],
data: null
};
this._stack.length > 0 && this._stack[this._stack.length - 1].children.push(s), this._stack.push(s);
}
endTag(e) {
const t = this._stack.pop();
if (t == null)
throw new Error("EBML structure is broken");
if (t.elm.name !== e.name)
throw new Error("EBML structure is broken");
const r = t.children.reduce((a, f) => {
if (f.data === null)
throw new Error("EBML structure is broken");
return a.concat(f.data);
}, []), s = m(r);
t.elm.type === "m" ? t.data = E(
t.tagId,
s,
t.elm.unknownSize
) : t.data = E(t.tagId, s), this._stack.length < 1 && (this._buffers = this._buffers.concat(t.data));
}
}
const Q = W.readVint, O = W.writeVint, z = q;
function X(n) {
return z(Buffer.from(n));
}
function E(n, e, t = !1) {
return m([
n,
t ? Buffer.from("01ffffffffffffff", "hex") : O(e.length),
e
]);
}
function Y(n) {
return R(n).reduce((e, t) => z(t.data).frames.reduce((s, a) => {
const f = j(a), c = new Blob([f], { type: "image/webp" });
return s.concat(c);
}, e), []);
}
function R(n) {
return n.reduce((e, t) => t.type !== "b" || t.name !== "SimpleBlock" || !z(t.data).frames.some((a) => a.subarray(3, 6).toString("hex") === "9d012a") ? e : e.concat(t), []);
}
function j(n) {
const e = A("VP8 ", n), t = m([Buffer.from("WEBP", "ascii"), e]);
return A("RIFF", t);
}
function A(n, e) {
const t = Buffer.alloc(4);
return t.writeUInt32LE(e.byteLength, 0), m([
Buffer.from(n.substring(0, 4), "ascii"),
t,
e,
// padding
Buffer.alloc(e.byteLength % 2 === 0 ? 0 : 1)
]);
}
function ee(n, e, t, r = 0, s = 0) {
const a = T("EBML", n), c = k(a) + 12, h = n[n.length - 1].dataEnd - c, l = T(
"Info",
n
);
H("Duration", l), l.splice(1, 0, {
name: "Duration",
type: "f",
data: w(e, 8)
});
const _ = k(l), S = T("Tracks", n), p = k(S);
let y = 47, o = [], d = 5 + t.length * 15, i = [], B = -1;
const b = 10;
for (let D = 0; D < b; D++) {
const v = y, I = v + _;
let P = 0, L = 0;
s ? (P = s - c, L = I + p) : (P = I + p, L = P + d);
const M = L - h;
o = [], o.push({ name: "SeekHead", type: "m", isEnd: !1 }), o.push({ name: "Seek", type: "m", isEnd: !1 }), o.push({
name: "SeekID",
type: "b",
data: Buffer.from([21, 73, 169, 102])
}), o.push({
name: "SeekPosition",
type: "u",
data: u(v)
}), o.push({ name: "Seek", type: "m", isEnd: !0 }), o.push({ name: "Seek", type: "m", isEnd: !1 }), o.push({
name: "SeekID",
type: "b",
data: Buffer.from([22, 84, 174, 107])
}), o.push({
name: "SeekPosition",
type: "u",
data: u(I)
}), o.push({ name: "Seek", type: "m", isEnd: !0 }), o.push({ name: "Seek", type: "m", isEnd: !1 }), o.push({
name: "SeekID",
type: "b",
data: Buffer.from([28, 83, 187, 107])
}), o.push({
name: "SeekPosition",
type: "u",
data: u(P)
}), o.push({ name: "Seek", type: "m", isEnd: !0 }), o.push({ name: "SeekHead", type: "m", isEnd: !0 }), y = k(o), i = [], i.push({ name: "Cues", type: "m", isEnd: !1 });
for (const { CueTrack: $, CueClusterPosition: N, CueTime: J } of t) {
i.push({ name: "CuePoint", type: "m", isEnd: !1 }), i.push({
name: "CueTime",
type: "u",
data: u(J)
}), i.push({ name: "CueTrackPositions", type: "m", isEnd: !1 }), i.push({
name: "CueTrack",
type: "u",
data: u($)
});
let F = N - c;
r ? F += r : F += M, i.push({
name: "CueClusterPosition",
type: "u",
data: u(F)
}), i.push({ name: "CueTrackPositions", type: "m", isEnd: !0 }), i.push({ name: "CuePoint", type: "m", isEnd: !0 });
}
if (i.push({ name: "Cues", type: "m", isEnd: !0 }), d = k(i), B !== M) {
if (B = M, D === b - 1)
throw new Error("Failed to converge to a stable metadata size");
} else
break;
}
const C = [].concat.apply([], [
a,
{ name: "Segment", type: "m", isEnd: !1, unknownSize: !0 },
o,
l,
S,
s ? [] : i
]);
return new g().encode(C);
}
function H(n, e) {
let t = -1;
for (let r = 0; r < e.length; r++) {
const s = e[r];
if (s.name === n)
if (s.type === "m")
if (!s.isEnd)
t = r;
else {
if (t === -1)
throw new Error(
`Detected ${n} closing element before finding the start`
);
e.splice(t, r - t + 1);
return;
}
else {
e.splice(r, 1);
return;
}
}
}
function T(n, e) {
let t = [], r = -1;
for (let s = 0; s < e.length; s++) {
const a = e[s];
if (a.name === n)
if (a.type === "m")
if (!a.isEnd)
r = s;
else {
if (r === -1)
throw new Error(
`Detected ${n} closing element before finding the start`
);
t = e.slice(r, s + 1);
break;
}
else {
t.push(e[s]);
break;
}
}
return t;
}
function te(n, e) {
Array.isArray(e.cueInfos) && !Array.isArray(e.cues) && (console.warn(
"putRefinedMetaData: info.cueInfos property is deprecated. please use info.cues"
), e.cues = e.cueInfos);
let t = [], r = [];
for (let o = 0; o < n.length; o++) {
const d = n[o];
if (d.type === "m" && d.name === "Segment") {
if (t = n.slice(0, o), r = n.slice(o), d.unknownSize) {
r.shift();
break;
}
throw new Error("this metadata is not streaming webm file");
}
}
if (!(r[r.length - 1].dataEnd > 0))
throw new Error("metadata dataEnd has wrong number");
const s = r[r.length - 1].dataEnd, a = t[t.length - 1].dataEnd, c = new g().encode(t).byteLength - a, h = s - r[0].tagStart, l = Buffer.from([24, 83, 128, 103]), _ = Buffer.from("01ffffffffffffff", "hex"), S = l.byteLength + _.byteLength;
let p = h;
const y = 20;
for (let o = 1; o < y; o++) {
const i = a + S + p - s, B = c + i, b = ne(r, B, e), C = new g().encode(b).byteLength;
if (C === p)
return new g().encode(
[].concat(
t,
[{ type: "m", name: "Segment", isEnd: !1, unknownSize: !0 }],
b
)
);
p = C;
}
throw new Error(
"unable to refine metadata, stable size could not be found in " + y + " iterations!"
);
}
function k(n) {
const e = new g();
return n.reduce((t, r) => t.concat(e.encode([r])), []).reduce((t, r) => t + r.byteLength, 0);
}
function ne(n, e, t) {
const { duration: r, clusterPtrs: s, cues: a } = t, f = n.slice(0);
if (typeof r == "number") {
let h = !1;
for (const l of f)
l.type === "f" && l.name === "Duration" && (h = !0, l.data = w(r, 8));
h || V(f, "Info", [
{ name: "Duration", type: "f", data: w(r, 8) }
]);
}
Array.isArray(a) && V(f, "Cues", se(a, e));
let c = [];
return Array.isArray(s) && (console.warn(
"append cluster pointers to seekhead is deprecated. please use cues"
), c = re(s, e)), V(f, "SeekHead", c, !0), f;
}
function re(n, e) {
const t = [];
for (const r of n)
t.push({ name: "Seek", type: "m", isEnd: !1 }), t.push({
name: "SeekID",
type: "b",
data: Buffer.from([31, 67, 182, 117])
}), t.push({
name: "SeekPosition",
type: "u",
data: u(r + e)
}), t.push({ name: "Seek", type: "m", isEnd: !0 });
return t;
}
function se(n, e) {
const t = [];
for (const { CueTrack: r, CueClusterPosition: s, CueTime: a } of n)
t.push({ name: "CuePoint", type: "m", isEnd: !1 }), t.push({ name: "CueTime", type: "u", data: u(a) }), t.push({ name: "CueTrackPositions", type: "m", isEnd: !1 }), t.push({
name: "CueTrack",
type: "u",
data: u(r)
}), t.push({
name: "CueClusterPosition",
type: "u",
data: u(s + e)
}), t.push({ name: "CueTrackPositions", type: "m", isEnd: !0 }), t.push({ name: "CuePoint", type: "m", isEnd: !0 });
return t;
}
function V(n, e, t, r = !1) {
let s = -1;
for (let a = 0; a < n.length; a++) {
const f = n[a];
if (f.type === "m" && f.name === e && !f.isEnd) {
s = a;
break;
}
}
if (s >= 0)
Array.prototype.splice.apply(
n,
[s + 1, 0].concat(t)
);
else if (r) {
const a = [].concat(
[{ name: e, type: "m", isEnd: !1 }],
t,
[{ name: e, type: "m", isEnd: !0 }]
);
a.reverse();
for (const f of a)
n.unshift(f);
} else {
n.push({ name: e, type: "m", isEnd: !1 });
for (const a of t)
n.push(a);
n.push({ name: e, type: "m", isEnd: !0 });
}
}
function m(n) {
return Buffer.concat(n);
}
function ae(n) {
let e = Buffer.alloc(0);
if (n.type === "m")
return n;
switch (n.type) {
case "u":
e = u(n.value);
break;
case "i":
e = U(n.value);
break;
case "f":
e = w(n.value);
break;
case "s":
e = Buffer.from(n.value, "ascii");
break;
case "8":
e = Buffer.from(n.value, "utf8");
break;
case "b":
e = n.value;
break;
case "d":
e = new x(n.value.getTime().toString()).toBuffer();
break;
}
return Object.assign({}, n, { data: e });
}
function u(n) {
let e = 1;
for (; n >= Math.pow(2, 8 * e); e++)
;
if (e >= 7)
return console.warn("7bit or more bigger uint not supported."), new Z(n).toBuffer();
const t = Buffer.alloc(e);
return t.writeUIntBE(n, 0, e), t;
}
function U(n) {
let e = 1;
for (; n >= Math.pow(2, 8 * e); e++)
;
if (e >= 7)
return console.warn("7bit or more bigger uint not supported."), new x(n).toBuffer();
const t = Buffer.alloc(e);
return t.writeIntBE(n, 0, e), t;
}
function w(n, e = 8) {
if (e === 8) {
const t = Buffer.alloc(8);
return t.writeDoubleBE(n, 0), t;
} else if (e === 4) {
const t = Buffer.alloc(4);
return t.writeFloatBE(n, 0), t;
} else
throw new Error("float type bits must 4bytes or 8bytes");
}
function oe(n) {
return n instanceof Date ? n : new Date(
(/* @__PURE__ */ new Date("2001-01-01T00:00:00.000Z")).getTime() + Number(n) / 1e3 / 1e3
);
}
const de = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
__proto__: null,
VP8BitStreamToRiffWebPBuffer: j,
WebPBlockFilter: R,
WebPFrameFilter: Y,
concat: m,
convertEBMLDateToJSDate: oe,
createFloatBuffer: w,
createIntBuffer: U,
createRIFFChunk: A,
createUIntBuffer: u,
ebmlBlock: z,
encodeTag: E,
encodeValueToBuffer: ae,
extractElement: T,
makeMetadataSeekable: ee,
putRefinedMetaData: te,
readBlock: X,
readVint: Q,
removeElement: H,
writeVint: O
}, Symbol.toStringTag, { value: "Module" }));
export {
g as E,
j as V,
Y as W,
oe as a,
X as b,
m as c,
E as d,
z as e,
R as f,
A as g,
H as h,
T as i,
ae as j,
u as k,
U as l,
ee as m,
w as n,
te as p,
Q as r,
de as t,
O as w
};