@poe-platform/safe-bash 0.1.839 → 0.1.841
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audio-ast/binary.d.ts +19 -0
- package/dist/audio-ast/index.d.ts +1 -0
- package/dist/audio-ast/index.js +92 -91
- package/dist/audio-ast/mpeg.d.ts +23 -0
- package/dist/mp4-ast/containers/adapters.d.ts +1 -0
- package/dist/mp4-ast/types.d.ts +8 -2
- package/dist/pdf-ast/cos/security.d.ts +10 -0
- package/dist/pdf-ast/edit/retained-attachment-edits.d.ts +4 -0
- package/dist/pdf-ast/edit/retained-graph.d.ts +1 -1
- package/dist/pdf-ast/image.js +1 -1
- package/dist/pdf-ast/index.d.ts +2 -1
- package/dist/pdf-ast/index.js +7 -1
- package/dist/pdf-ast/vendor/pdfjs-fonts.d.mts +8 -0
- package/dist/pdf-ast/vendor/pdfjs-fonts.mjs +28 -0
- package/dist/safe-bash/audio-ast.browser.js +2 -1
- package/dist/safe-bash/audio-ast.js +1 -1
- package/dist/safe-bash/command-chunks/{chunk-SG2KOOD4.js → chunk-3SAYZFMD.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-T6OXG7QQ.js → chunk-AAOPVEPF.js} +66 -1
- package/dist/safe-bash/command-chunks/{chunk-FH5VMAPS.js → chunk-BZW25LNV.js} +420 -131
- package/dist/safe-bash/command-chunks/{chunk-DQVOBGI2.js → chunk-CIV3GER2.js} +6770 -6523
- package/dist/safe-bash/command-chunks/{chunk-46GA576V.js → chunk-CPKVUB7S.js} +2 -2
- package/dist/safe-bash/command-chunks/{chunk-MBXNG6C3.js → chunk-DLLN3C3Q.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-ZSQCROFE.js → chunk-DM5T5D2K.js} +5 -1
- package/dist/safe-bash/command-chunks/{chunk-3EAZRKI4.js → chunk-G7HQYFIU.js} +10 -1
- package/dist/safe-bash/command-chunks/{chunk-GYKQ3IOV.js → chunk-LMYQMJYY.js} +94 -18
- package/dist/safe-bash/command-chunks/{chunk-DX7KU6YU.js → chunk-N52AHO6S.js} +1 -1
- package/dist/safe-bash/command-chunks/{chunk-4BSD2RGK.js → chunk-QPKL5GWH.js} +102 -42
- package/dist/safe-bash/command-chunks/{chunk-Z2T7E4ID.js → chunk-R7QLP5RH.js} +1212 -1119
- package/dist/safe-bash/command-chunks/{chunk-77ROD2TR.js → chunk-X3WNWRVT.js} +11 -5
- package/dist/safe-bash/command-chunks/{chunk-RSFKQE2U.js → chunk-YAXP4EHP.js} +19 -10
- package/dist/safe-bash/command-chunks/{chunk-TCXM7BSZ.js → chunk-YFMNXPLP.js} +4 -4
- package/dist/safe-bash-command-exiftool/index.js +25 -1
- package/dist/safe-bash-command-ffmpeg/index.js +191 -49
- package/dist/safe-bash-command-ffprobe/index.js +2 -2
- package/dist/safe-bash-command-ffprobe/media.js +2 -2
- package/dist/safe-bash-command-imagemagick/index.js +498 -101
- package/dist/safe-bash-command-mdq/index.js +2 -0
- package/dist/safe-bash-command-pandoc/citeproc-filters.js +7 -7
- package/dist/safe-bash-command-pandoc/command.js +8 -8
- package/dist/safe-bash-command-pandoc/index.js +52 -52
- package/dist/safe-bash-command-qpdf/index.js +1037 -654
- package/dist/safe-bash-command-qpdf/page-range.d.ts +2 -0
- package/dist/safe-bash-command-soffice/index.js +28 -8
- package/dist/safe-bash-command-sqlite3/btree.d.ts +2 -1
- package/dist/safe-bash-command-sqlite3/engine.d.ts +15 -1
- package/dist/safe-bash-command-sqlite3/index.js +294 -68
- package/dist/safe-bash-command-tar/create.js +2 -2
- package/dist/safe-bash-command-tar/extract.js +2 -2
- package/dist/safe-bash-command-tar/format.js +1 -1
- package/dist/safe-bash-command-tar/index.js +4 -4
- package/dist/safe-bash-command-tar/modes.js +4 -4
- package/dist/safe-bash-command-unzip/index.js +1 -1
- package/dist/safe-bash-command-unzip/unzip.js +1 -1
- package/dist/safe-bash-markdown-engine/commonmark-blocks.d.ts +17 -1
- package/dist/safe-bash-markdown-engine/commonmark-blocks.js +3 -3
- package/dist/safe-bash-markdown-engine/commonmark-inlines.d.ts +1 -1
- package/dist/safe-bash-markdown-engine/commonmark-inlines.js +3 -3
- package/dist/safe-bash-markdown-engine/commonmark-syntax.d.ts +5 -0
- package/dist/safe-bash-markdown-engine/commonmark-syntax.js +5 -1
- package/dist/safe-bash-markdown-engine/gfm-syntax.js +2 -2
- package/dist/safe-bash-markdown-engine/index.js +4 -4
- package/dist/safe-bash-zip-engine/index.js +1 -1
- package/dist/safe-bash-zip-engine/zip/repair.js +1 -1
- package/dist/safe-bash-zip-engine/zip/sfx.js +1 -1
- package/dist/safe-bash-zip-engine/zip-format.d.ts +2 -0
- package/dist/safe-bash-zip-engine/zip-format.js +1 -1
- package/package.json +2 -2
- package/third-party/pdf-ast/THIRD_PARTY_NOTICES.md +2 -0
|
@@ -381276,7 +381276,7 @@ function buildProbeStream(track, desc, stats, idx, containerFormat) {
|
|
|
381276
381276
|
duration_ts: track.duration,
|
|
381277
381277
|
duration: durationSec.toFixed(6),
|
|
381278
381278
|
bit_rate: bitRate,
|
|
381279
|
-
nb_frames: String(nbFrames),
|
|
381279
|
+
nb_frames: containerFormat === "wav" ? void 0 : String(nbFrames),
|
|
381280
381280
|
disposition: {
|
|
381281
381281
|
default: track.enabled ? 1 : 0,
|
|
381282
381282
|
dub: 0,
|
|
@@ -381979,7 +381979,7 @@ function parseMp4(bytes, options = {}) {
|
|
|
381979
381979
|
else if (step.kind === "sync-has") answer = syncSamples.has(step.sample);
|
|
381980
381980
|
else {
|
|
381981
381981
|
const { offset, ...sample } = step.sample;
|
|
381982
|
-
samples.push({ ...sample, data: bytes.subarray(offset, offset + sample.size) });
|
|
381982
|
+
samples.push({ ...sample, offset, data: bytes.subarray(offset, offset + sample.size) });
|
|
381983
381983
|
}
|
|
381984
381984
|
}
|
|
381985
381985
|
if (moofBoxes.length > 0) {
|
|
@@ -382019,7 +382019,7 @@ function parseMp4(bytes, options = {}) {
|
|
|
382019
382019
|
if (step.kind === "read") answer2 = bytes.subarray(step.offset, step.offset + step.length);
|
|
382020
382020
|
else if (step.kind === "sample") {
|
|
382021
382021
|
const { offset, ...sample } = step.sample;
|
|
382022
|
-
samples.push({ ...sample, data: bytes.subarray(offset, offset + sample.size) });
|
|
382022
|
+
samples.push({ ...sample, offset, data: bytes.subarray(offset, offset + sample.size) });
|
|
382023
382023
|
}
|
|
382024
382024
|
}
|
|
382025
382025
|
}
|
|
@@ -383203,8 +383203,8 @@ function buildProbeResultFromDoc(doc, byteLength, filename = "input.mp4", option
|
|
|
383203
383203
|
duration: s.duration,
|
|
383204
383204
|
duration_time: durTime,
|
|
383205
383205
|
size: String(s.size),
|
|
383206
|
-
pos: String(bytePos),
|
|
383207
|
-
flags: s.isKeyframe ? "
|
|
383206
|
+
pos: String(s.offset ?? (doc.containerFormat === "mp4" || doc.containerFormat === "mov" ? -1 : bytePos)),
|
|
383207
|
+
flags: s.isKeyframe ? "K__" : "___"
|
|
383208
383208
|
});
|
|
383209
383209
|
}
|
|
383210
383210
|
if (options.showFrames) {
|
|
@@ -383218,13 +383218,12 @@ function buildProbeResultFromDoc(doc, byteLength, filename = "input.mp4", option
|
|
|
383218
383218
|
pkt_dts_time: dtsTime,
|
|
383219
383219
|
best_effort_timestamp: s.pts,
|
|
383220
383220
|
best_effort_timestamp_time: ptsTime,
|
|
383221
|
-
pkt_duration: s.duration,
|
|
383222
|
-
pkt_duration_time: durTime,
|
|
383221
|
+
...doc.containerFormat === "gif" ? { duration: s.duration, duration_time: durTime } : { pkt_duration: s.duration, pkt_duration_time: durTime },
|
|
383223
383222
|
pkt_size: String(s.size),
|
|
383224
383223
|
width: w,
|
|
383225
383224
|
height: h,
|
|
383226
383225
|
pix_fmt: track.type === "video" ? desc?.pixFmt ?? "yuv420p" : void 0,
|
|
383227
|
-
pict_type:
|
|
383226
|
+
pict_type: void 0,
|
|
383228
383227
|
sample_fmt: sampleFormat,
|
|
383229
383228
|
nb_samples: track.type === "audio" ? s.duration : void 0,
|
|
383230
383229
|
channels: track.type === "audio" ? desc?.channels ?? 2 : void 0
|
|
@@ -384267,6 +384266,132 @@ function serializeDashDocument(doc, options = {}) {
|
|
|
384267
384266
|
return { manifest, resources };
|
|
384268
384267
|
}
|
|
384269
384268
|
|
|
384269
|
+
// packages/mp4-ast/src/containers/mp3-frames.ts
|
|
384270
|
+
import { mpegFrame } from "../../audio-ast/index.js";
|
|
384271
|
+
function* scanMp3Frames() {
|
|
384272
|
+
const frames = [];
|
|
384273
|
+
let offset = 0, first = true, skipSamples = 0, discardPadding = 0;
|
|
384274
|
+
while (true) {
|
|
384275
|
+
const bytes = yield { offset, length: 4 };
|
|
384276
|
+
if (!bytes.length) break;
|
|
384277
|
+
if (bytes.length < 4) throw new Error("Truncated MPEG frame");
|
|
384278
|
+
const marker = String.fromCharCode(...bytes.subarray(0, 3));
|
|
384279
|
+
if (marker === "ID3") {
|
|
384280
|
+
const tag = yield { offset: offset + 4, length: 6 };
|
|
384281
|
+
if (tag.length !== 6 || tag.subarray(2).some((b) => b > 127)) throw new Error("Invalid ID3 header");
|
|
384282
|
+
const size = tag[2] * 2097152 + tag[3] * 16384 + tag[4] * 128 + tag[5];
|
|
384283
|
+
offset += 10 + size + (bytes[3] === 4 && tag[1] & 16 ? 10 : 0);
|
|
384284
|
+
continue;
|
|
384285
|
+
}
|
|
384286
|
+
if (marker === "TAG") {
|
|
384287
|
+
const tag = yield { offset: offset + 4, length: 124 };
|
|
384288
|
+
if (tag.length !== 124) throw new Error("Truncated ID3v1 tag");
|
|
384289
|
+
offset += 128;
|
|
384290
|
+
continue;
|
|
384291
|
+
}
|
|
384292
|
+
const header = new DataView(bytes.buffer, bytes.byteOffset, 4).getUint32(0);
|
|
384293
|
+
const frame = mpegFrame(header, offset, Infinity);
|
|
384294
|
+
const payload = yield { offset: offset + 4, length: frame.frameSize - 4 };
|
|
384295
|
+
if (payload.length !== frame.frameSize - 4) throw new Error("Truncated MPEG frame");
|
|
384296
|
+
const side = frame.version === 1 ? frame.channels === 1 ? 17 : 32 : frame.channels === 1 ? 9 : 17;
|
|
384297
|
+
const xing = side + (header & 65536 ? 0 : 2);
|
|
384298
|
+
const text = (pos) => String.fromCharCode(...payload.subarray(pos, pos + 4));
|
|
384299
|
+
const metadata = first && (["Xing", "Info"].includes(text(xing)) || text(32) === "VBRI");
|
|
384300
|
+
if (metadata && ["Xing", "Info"].includes(text(xing)) && xing + 8 <= payload.length) {
|
|
384301
|
+
const flags = new DataView(payload.buffer, payload.byteOffset, payload.length).getUint32(xing + 4);
|
|
384302
|
+
const encoder = xing + 8 + (flags & 1 ? 4 : 0) + (flags & 2 ? 4 : 0) + (flags & 4 ? 100 : 0) + (flags & 8 ? 4 : 0);
|
|
384303
|
+
if (encoder + 24 <= payload.length && ["LAME", "Lavc", "Lavf"].includes(text(encoder))) {
|
|
384304
|
+
const delay = payload[encoder + 21] * 16 + (payload[encoder + 22] >>> 4);
|
|
384305
|
+
const padding = (payload[encoder + 22] & 15) * 256 + payload[encoder + 23];
|
|
384306
|
+
skipSamples = delay + 529;
|
|
384307
|
+
discardPadding = Math.max(0, padding - 529);
|
|
384308
|
+
}
|
|
384309
|
+
}
|
|
384310
|
+
first = false;
|
|
384311
|
+
if (!metadata) frames.push({ offset, size: frame.frameSize, sampleRate: frame.rate, channels: frame.channels, samples: frame.count, skipSamples: 0, discardPadding: 0 });
|
|
384312
|
+
offset += frame.frameSize;
|
|
384313
|
+
}
|
|
384314
|
+
if (!frames.length) throw new Error("MP3 contains no MPEG frames");
|
|
384315
|
+
for (const frame of frames) {
|
|
384316
|
+
frame.skipSamples = Math.min(skipSamples, frame.samples);
|
|
384317
|
+
skipSamples -= frame.skipSamples;
|
|
384318
|
+
}
|
|
384319
|
+
for (let i = frames.length - 1; i >= 0 && discardPadding; i--) {
|
|
384320
|
+
const frame = frames[i];
|
|
384321
|
+
frame.discardPadding = Math.min(discardPadding, frame.samples - frame.skipSamples);
|
|
384322
|
+
discardPadding -= frame.discardPadding;
|
|
384323
|
+
}
|
|
384324
|
+
return frames;
|
|
384325
|
+
}
|
|
384326
|
+
function readMp3Frames(bytes) {
|
|
384327
|
+
const scan = scanMp3Frames();
|
|
384328
|
+
let step = scan.next();
|
|
384329
|
+
while (!step.done) {
|
|
384330
|
+
const { offset, length } = step.value;
|
|
384331
|
+
step = scan.next(bytes.subarray(offset, offset + length));
|
|
384332
|
+
}
|
|
384333
|
+
return step.value;
|
|
384334
|
+
}
|
|
384335
|
+
async function readMp3SourceFrames(source, signal) {
|
|
384336
|
+
signal?.throwIfAborted();
|
|
384337
|
+
if (!Number.isSafeInteger(source.size) || source.size < 0) throw new RangeError("Invalid MP3 source size");
|
|
384338
|
+
const scan = scanMp3Frames();
|
|
384339
|
+
let step = scan.next();
|
|
384340
|
+
while (!step.done) {
|
|
384341
|
+
const { offset, length } = step.value;
|
|
384342
|
+
const bytes = new Uint8Array(Math.max(0, Math.min(length, source.size - offset)));
|
|
384343
|
+
let filled = 0;
|
|
384344
|
+
while (filled < bytes.length) {
|
|
384345
|
+
signal?.throwIfAborted();
|
|
384346
|
+
const chunk = await source.read(offset + filled, bytes.length - filled);
|
|
384347
|
+
signal?.throwIfAborted();
|
|
384348
|
+
if (!chunk.length || chunk.length > bytes.length - filled) throw new Error("Invalid MP3 source read");
|
|
384349
|
+
bytes.set(chunk, filled);
|
|
384350
|
+
filled += chunk.length;
|
|
384351
|
+
}
|
|
384352
|
+
step = scan.next(bytes);
|
|
384353
|
+
}
|
|
384354
|
+
signal?.throwIfAborted();
|
|
384355
|
+
return step.value;
|
|
384356
|
+
}
|
|
384357
|
+
async function readMp3StreamFrames(source, signal) {
|
|
384358
|
+
signal?.throwIfAborted();
|
|
384359
|
+
const scan = scanMp3Frames();
|
|
384360
|
+
let step = scan.next(), bytes = new Uint8Array(step.done ? 0 : step.value.length);
|
|
384361
|
+
let size = 0, filled = 0;
|
|
384362
|
+
let failure;
|
|
384363
|
+
for await (const chunk of source) {
|
|
384364
|
+
signal?.throwIfAborted();
|
|
384365
|
+
const start = size;
|
|
384366
|
+
size += chunk.byteLength;
|
|
384367
|
+
if (!Number.isSafeInteger(size)) throw new RangeError("Invalid MP3 source size");
|
|
384368
|
+
if (failure) continue;
|
|
384369
|
+
try {
|
|
384370
|
+
while (!step.done && step.value.offset < size) {
|
|
384371
|
+
signal?.throwIfAborted();
|
|
384372
|
+
const request = step.value;
|
|
384373
|
+
const from = Math.max(start, request.offset + filled), end = Math.min(size, request.offset + request.length);
|
|
384374
|
+
if (end > from) {
|
|
384375
|
+
bytes.set(chunk.subarray(from - start, end - start), filled);
|
|
384376
|
+
filled += end - from;
|
|
384377
|
+
}
|
|
384378
|
+
if (filled < request.length) break;
|
|
384379
|
+
step = scan.next(bytes);
|
|
384380
|
+
bytes = new Uint8Array(step.done ? 0 : step.value.length);
|
|
384381
|
+
filled = 0;
|
|
384382
|
+
}
|
|
384383
|
+
} catch (error) {
|
|
384384
|
+
signal?.throwIfAborted();
|
|
384385
|
+
failure = { error };
|
|
384386
|
+
}
|
|
384387
|
+
}
|
|
384388
|
+
signal?.throwIfAborted();
|
|
384389
|
+
if (failure) throw failure.error;
|
|
384390
|
+
if (!step.done) step = scan.next(bytes.subarray(0, filled));
|
|
384391
|
+
if (!step.done) throw new Error("Truncated MP3 source");
|
|
384392
|
+
return { frames: step.value, size };
|
|
384393
|
+
}
|
|
384394
|
+
|
|
384270
384395
|
// packages/mp4-ast/src/aac.ts
|
|
384271
384396
|
function decodeAacTrack(doc, track) {
|
|
384272
384397
|
const description = track.codecDescriptions[0];
|
|
@@ -384514,6 +384639,101 @@ function encodeFlacPackets(doc) {
|
|
|
384514
384639
|
return frames;
|
|
384515
384640
|
}
|
|
384516
384641
|
|
|
384642
|
+
// packages/mp4-ast/src/containers/flac-probe.ts
|
|
384643
|
+
function checksum(value, byte, width, polynomial) {
|
|
384644
|
+
value ^= byte << width - 8;
|
|
384645
|
+
for (let bit = 0; bit < 8; bit++) value = value << 1 ^ (value & 1 << width - 1 ? polynomial : 0);
|
|
384646
|
+
return value & (1 << width) - 1;
|
|
384647
|
+
}
|
|
384648
|
+
function frameHeader(bytes, start) {
|
|
384649
|
+
if (bytes[start] !== 255 || (bytes[start + 1] & 254) !== 248 || bytes[start + 3] & 1) return;
|
|
384650
|
+
const block = bytes[start + 2] >>> 4, rate = bytes[start + 2] & 15;
|
|
384651
|
+
if (!block || rate === 15 || bytes[start + 3] >>> 4 > 10) return;
|
|
384652
|
+
let pos = start + 4, number = bytes[pos++];
|
|
384653
|
+
if (number >= 128) {
|
|
384654
|
+
let tails = 0, mask = 128;
|
|
384655
|
+
while (number & mask) {
|
|
384656
|
+
tails++;
|
|
384657
|
+
mask >>>= 1;
|
|
384658
|
+
}
|
|
384659
|
+
if (tails < 2 || tails > 7) return;
|
|
384660
|
+
number &= mask - 1;
|
|
384661
|
+
for (let i = 1; i < tails; i++) {
|
|
384662
|
+
const byte = bytes[pos++];
|
|
384663
|
+
if ((byte & 192) !== 128) return;
|
|
384664
|
+
number = number * 64 + (byte & 63);
|
|
384665
|
+
}
|
|
384666
|
+
}
|
|
384667
|
+
let duration = block === 1 ? 192 : block < 6 ? 576 * 2 ** (block - 2) : 256 * 2 ** (block - 8);
|
|
384668
|
+
if (block === 6) duration = bytes[pos++] + 1;
|
|
384669
|
+
if (block === 7) {
|
|
384670
|
+
duration = bytes[pos] * 256 + bytes[pos + 1] + 1;
|
|
384671
|
+
pos += 2;
|
|
384672
|
+
}
|
|
384673
|
+
pos += rate === 12 ? 1 : rate >= 13 ? 2 : 0;
|
|
384674
|
+
if (pos >= bytes.length) return;
|
|
384675
|
+
let crc2 = 0;
|
|
384676
|
+
for (let i = start; i <= pos; i++) crc2 = checksum(crc2, bytes[i], 8, 7);
|
|
384677
|
+
if (crc2) return;
|
|
384678
|
+
return { duration, number, variable: !!(bytes[start + 1] & 1) };
|
|
384679
|
+
}
|
|
384680
|
+
var FlacFrameScanner = class {
|
|
384681
|
+
header = new Uint8Array(42);
|
|
384682
|
+
packets = [];
|
|
384683
|
+
size = 0;
|
|
384684
|
+
pending = new Uint8Array();
|
|
384685
|
+
offset = 0;
|
|
384686
|
+
metadataEnd = 4;
|
|
384687
|
+
audio = false;
|
|
384688
|
+
lastMetadata = false;
|
|
384689
|
+
crc = 0;
|
|
384690
|
+
frame;
|
|
384691
|
+
fixedBlockSize = 0;
|
|
384692
|
+
push(chunk, final = false) {
|
|
384693
|
+
if (this.size < 42) this.header.set(chunk.subarray(0, 42 - this.size), this.size);
|
|
384694
|
+
this.size += chunk.length;
|
|
384695
|
+
let bytes = chunk;
|
|
384696
|
+
if (this.pending.length) {
|
|
384697
|
+
bytes = new Uint8Array(this.pending.length + chunk.length);
|
|
384698
|
+
bytes.set(this.pending);
|
|
384699
|
+
bytes.set(chunk, this.pending.length);
|
|
384700
|
+
}
|
|
384701
|
+
let pos = 0;
|
|
384702
|
+
const end = final ? bytes.length : Math.max(0, bytes.length - 16);
|
|
384703
|
+
for (; pos < end; pos++, this.offset++) {
|
|
384704
|
+
if (!this.audio) {
|
|
384705
|
+
if (this.offset < this.metadataEnd) continue;
|
|
384706
|
+
if (!this.lastMetadata) {
|
|
384707
|
+
if (pos + 4 > bytes.length) break;
|
|
384708
|
+
this.lastMetadata = !!(bytes[pos] & 128);
|
|
384709
|
+
this.metadataEnd = this.offset + 4 + bytes[pos + 1] * 65536 + bytes[pos + 2] * 256 + bytes[pos + 3];
|
|
384710
|
+
continue;
|
|
384711
|
+
}
|
|
384712
|
+
this.audio = true;
|
|
384713
|
+
}
|
|
384714
|
+
if (!this.frame || this.crc === 0) {
|
|
384715
|
+
const header = frameHeader(bytes, pos);
|
|
384716
|
+
if (header) {
|
|
384717
|
+
if (this.frame) this.packets.push({ ...this.frame, size: this.offset - this.frame.pos });
|
|
384718
|
+
this.fixedBlockSize ||= header.duration;
|
|
384719
|
+
this.frame = {
|
|
384720
|
+
pts: header.variable ? header.number : header.number * this.fixedBlockSize,
|
|
384721
|
+
duration: header.duration,
|
|
384722
|
+
pos: this.offset
|
|
384723
|
+
};
|
|
384724
|
+
this.crc = 0;
|
|
384725
|
+
}
|
|
384726
|
+
}
|
|
384727
|
+
if (this.frame) this.crc = checksum(this.crc, bytes[pos], 16, 32773);
|
|
384728
|
+
}
|
|
384729
|
+
this.pending = bytes.slice(pos);
|
|
384730
|
+
if (final && this.frame && this.crc === 0) {
|
|
384731
|
+
this.packets.push({ ...this.frame, size: this.offset - this.frame.pos });
|
|
384732
|
+
this.frame = void 0;
|
|
384733
|
+
}
|
|
384734
|
+
}
|
|
384735
|
+
};
|
|
384736
|
+
|
|
384517
384737
|
// packages/mp4-ast/src/containers/ogg.ts
|
|
384518
384738
|
function page(packet, sequence, flags, granule) {
|
|
384519
384739
|
const segments = Math.floor(packet.length / 255) + 1;
|
|
@@ -384634,7 +384854,7 @@ async function readOggFlacHeader(source, options = {}) {
|
|
|
384634
384854
|
const start = offset, header = await read(27);
|
|
384635
384855
|
if (header[0] !== 79 || header[1] !== 103 || header[2] !== 103 || header[3] !== 83) throw new Error("Invalid Ogg page");
|
|
384636
384856
|
const lacing = await read(header[26]);
|
|
384637
|
-
let
|
|
384857
|
+
let checksum2 = oggCrc(lacing, oggCrc(header), 27);
|
|
384638
384858
|
const continuation = Boolean(header[5] & 1) !== packetSize > 0;
|
|
384639
384859
|
let remaining = 0, chunk = new Uint8Array(), used = 0;
|
|
384640
384860
|
for (const length of lacing) remaining += length;
|
|
@@ -384643,7 +384863,7 @@ async function readOggFlacHeader(source, options = {}) {
|
|
|
384643
384863
|
if (used === chunk.length) {
|
|
384644
384864
|
chunk = await read(Math.min(16384, remaining));
|
|
384645
384865
|
used = 0;
|
|
384646
|
-
|
|
384866
|
+
checksum2 = oggCrc(chunk, checksum2, offset - start - chunk.length);
|
|
384647
384867
|
remaining -= chunk.length;
|
|
384648
384868
|
}
|
|
384649
384869
|
const take = Math.min(pending, chunk.length - used);
|
|
@@ -384661,7 +384881,7 @@ async function readOggFlacHeader(source, options = {}) {
|
|
|
384661
384881
|
packetSize = 0;
|
|
384662
384882
|
}
|
|
384663
384883
|
}
|
|
384664
|
-
if (
|
|
384884
|
+
if (checksum2 !== new DataView(header.buffer).getUint32(22, true)) throw new Error("Ogg CRC mismatch");
|
|
384665
384885
|
if (continuation) throw new Error("Invalid Ogg packet continuation");
|
|
384666
384886
|
if (firstSize >= 0 && !mapped) return void 0;
|
|
384667
384887
|
}
|
|
@@ -386509,7 +386729,10 @@ function aacAst() {
|
|
|
386509
386729
|
function isWavSignature(bytes) {
|
|
386510
386730
|
return bytes.byteLength >= 12 && decodeFourCC(bytes, 0) === "RIFF" && decodeFourCC(bytes, 8) === "WAVE";
|
|
386511
386731
|
}
|
|
386512
|
-
|
|
386732
|
+
function wavPacketFrames(sampleRate, block) {
|
|
386733
|
+
const samples = Math.max(1, Math.min(Math.floor(sampleRate / 10), Math.floor(2147483647 / block)));
|
|
386734
|
+
return 2 ** Math.floor(Math.log2(samples));
|
|
386735
|
+
}
|
|
386513
386736
|
function parseWav(bytes, options = {}) {
|
|
386514
386737
|
const header = readWavHeader(bytes);
|
|
386515
386738
|
const { formatTag, channels, sampleRate, bitsPerSample } = header;
|
|
@@ -386540,7 +386763,7 @@ function parseWav(bytes, options = {}) {
|
|
|
386540
386763
|
decodedAudio = { sampleRate, channels, channelData };
|
|
386541
386764
|
}
|
|
386542
386765
|
const samples = [];
|
|
386543
|
-
const chunkFrames = wavPacketFrames;
|
|
386766
|
+
const chunkFrames = wavPacketFrames(header.sampleRate, bytesPerFrame);
|
|
386544
386767
|
for (let offsetSample = 0; offsetSample < totalPcmSamples; offsetSample += chunkFrames) {
|
|
386545
386768
|
const count = Math.min(chunkFrames, totalPcmSamples - offsetSample);
|
|
386546
386769
|
const byteStart = offsetSample * bytesPerFrame;
|
|
@@ -386643,7 +386866,6 @@ function wavMetadata(header, filename = "input.wav") {
|
|
|
386643
386866
|
const bytesPerFrame = Math.max(1, header.channels * (header.bitsPerSample >>> 3));
|
|
386644
386867
|
return { ...result, streams: [{
|
|
386645
386868
|
...result.streams[0],
|
|
386646
|
-
nb_frames: String(Math.ceil(samples / wavPacketFrames)),
|
|
386647
386869
|
bit_rate: doc.durationSeconds > 0 ? String(Math.round(samples * bytesPerFrame * 8 / doc.durationSeconds)) : "0"
|
|
386648
386870
|
}] };
|
|
386649
386871
|
}
|
|
@@ -386651,10 +386873,11 @@ function wavRecords(header, options) {
|
|
|
386651
386873
|
const metadata = wavMetadata(header, options.filename), stream = metadata.streams[0];
|
|
386652
386874
|
const bytesPerFrame = Math.max(1, header.channels * (header.bitsPerSample >>> 3));
|
|
386653
386875
|
const samples = Math.floor(header.dataSize / bytesPerFrame), rate = Math.max(1, header.sampleRate);
|
|
386876
|
+
const chunkFrames = wavPacketFrames(header.sampleRate, bytesPerFrame);
|
|
386654
386877
|
function* spans() {
|
|
386655
|
-
for (let pts = 0; pts < samples; pts +=
|
|
386878
|
+
for (let pts = 0; pts < samples; pts += chunkFrames) {
|
|
386656
386879
|
options.signal?.throwIfAborted();
|
|
386657
|
-
const count = Math.min(
|
|
386880
|
+
const count = Math.min(chunkFrames, samples - pts);
|
|
386658
386881
|
yield { pts, count, size: String(count * bytesPerFrame), time: (pts / rate).toFixed(6), duration: (count / rate).toFixed(6) };
|
|
386659
386882
|
}
|
|
386660
386883
|
options.signal?.throwIfAborted();
|
|
@@ -386673,7 +386896,7 @@ function wavRecords(header, options) {
|
|
|
386673
386896
|
duration_time: s.duration,
|
|
386674
386897
|
size: s.size,
|
|
386675
386898
|
pos: String(s.pts * bytesPerFrame),
|
|
386676
|
-
flags: "
|
|
386899
|
+
flags: "K__"
|
|
386677
386900
|
};
|
|
386678
386901
|
} } : void 0,
|
|
386679
386902
|
frames: options.showFrames ? { *[Symbol.iterator]() {
|
|
@@ -386753,20 +386976,21 @@ function isMp3Signature(bytes) {
|
|
|
386753
386976
|
if (bytes[0] === 73 && bytes[1] === 68 && bytes[2] === 51) return true;
|
|
386754
386977
|
return bytes[0] === 255 && (bytes[1] & 224) === 224 && (bytes[1] & 6) !== 0;
|
|
386755
386978
|
}
|
|
386756
|
-
function mp3Document(byteLength, samples) {
|
|
386757
|
-
const sampleRate
|
|
386979
|
+
function mp3Document(byteLength, frames, samples) {
|
|
386980
|
+
const { sampleRate, channels } = frames[0];
|
|
386981
|
+
const duration = frames.reduce((sum, frame) => sum + frame.samples * 14112e3 / frame.sampleRate, 0);
|
|
386758
386982
|
return {
|
|
386759
386983
|
containerFormat: "mp3",
|
|
386760
|
-
timescale:
|
|
386761
|
-
duration
|
|
386762
|
-
durationSeconds:
|
|
386984
|
+
timescale: 14112e3,
|
|
386985
|
+
duration,
|
|
386986
|
+
durationSeconds: duration / 14112e3,
|
|
386763
386987
|
tracks: [
|
|
386764
386988
|
{
|
|
386765
386989
|
id: 1,
|
|
386766
386990
|
type: "audio",
|
|
386767
386991
|
handlerType: "soun",
|
|
386768
|
-
timescale:
|
|
386769
|
-
duration
|
|
386992
|
+
timescale: 14112e3,
|
|
386993
|
+
duration,
|
|
386770
386994
|
language: "und",
|
|
386771
386995
|
enabled: true,
|
|
386772
386996
|
codecDescriptions: [
|
|
@@ -386785,24 +387009,27 @@ function mp3Document(byteLength, samples) {
|
|
|
386785
387009
|
byteLength
|
|
386786
387010
|
};
|
|
386787
387011
|
}
|
|
386788
|
-
function mp3Records(size, options) {
|
|
387012
|
+
function mp3Records(size, frames, options) {
|
|
386789
387013
|
options.signal?.throwIfAborted();
|
|
386790
|
-
|
|
386791
|
-
const count = Math.max(1, Math.floor(size / 417)), doc = mp3Document(size, []);
|
|
387014
|
+
const doc = mp3Document(size, frames, []);
|
|
386792
387015
|
const metadata = buildProbeResultFromDoc(doc, size, options.filename ?? "input.mp3", {
|
|
386793
387016
|
formatName: "mp3",
|
|
386794
387017
|
formatLongName: "MP2/3 (MPEG audio layer 2/3)"
|
|
386795
387018
|
});
|
|
386796
387019
|
const stream = {
|
|
386797
387020
|
...metadata.streams[0],
|
|
386798
|
-
nb_frames:
|
|
386799
|
-
|
|
387021
|
+
nb_frames: void 0,
|
|
387022
|
+
nb_read_packets: String(frames.length),
|
|
387023
|
+
nb_read_frames: String(frames.filter((f) => f.samples > f.skipSamples + f.discardPadding).length),
|
|
387024
|
+
bit_rate: String(Math.round(frames.reduce((sum, f) => sum + f.size, 0) * 8 / doc.durationSeconds))
|
|
386800
387025
|
};
|
|
386801
387026
|
function* spans() {
|
|
386802
|
-
|
|
387027
|
+
let pts = 0;
|
|
387028
|
+
for (const frame of frames) {
|
|
386803
387029
|
options.signal?.throwIfAborted();
|
|
386804
|
-
const
|
|
386805
|
-
yield { pts, time: (pts /
|
|
387030
|
+
const duration = frame.samples * 14112e3 / frame.sampleRate;
|
|
387031
|
+
yield { ...frame, pts, duration, time: (pts / 14112e3).toFixed(6), durationTime: (duration / 14112e3).toFixed(6) };
|
|
387032
|
+
pts += duration;
|
|
386806
387033
|
}
|
|
386807
387034
|
options.signal?.throwIfAborted();
|
|
386808
387035
|
}
|
|
@@ -386817,52 +387044,48 @@ function mp3Records(size, options) {
|
|
|
386817
387044
|
pts_time: s.time,
|
|
386818
387045
|
dts: s.pts,
|
|
386819
387046
|
dts_time: s.time,
|
|
386820
|
-
duration:
|
|
386821
|
-
duration_time:
|
|
386822
|
-
size: s.size,
|
|
386823
|
-
pos: s.
|
|
386824
|
-
flags: "
|
|
387047
|
+
duration: s.duration,
|
|
387048
|
+
duration_time: s.durationTime,
|
|
387049
|
+
size: String(s.size),
|
|
387050
|
+
pos: String(s.offset),
|
|
387051
|
+
flags: "K__"
|
|
386825
387052
|
};
|
|
386826
387053
|
} } : void 0,
|
|
386827
387054
|
frames: options.showFrames ? { *[Symbol.iterator]() {
|
|
386828
|
-
for (const s of spans())
|
|
386829
|
-
|
|
386830
|
-
|
|
386831
|
-
|
|
386832
|
-
|
|
386833
|
-
|
|
386834
|
-
|
|
386835
|
-
|
|
386836
|
-
|
|
386837
|
-
|
|
386838
|
-
|
|
386839
|
-
|
|
386840
|
-
|
|
386841
|
-
|
|
386842
|
-
|
|
386843
|
-
|
|
386844
|
-
|
|
386845
|
-
|
|
386846
|
-
|
|
386847
|
-
|
|
386848
|
-
|
|
387055
|
+
for (const s of spans()) {
|
|
387056
|
+
const samples = s.samples - s.skipSamples - s.discardPadding;
|
|
387057
|
+
if (!samples) continue;
|
|
387058
|
+
const pts = s.pts + s.skipSamples * 14112e3 / s.sampleRate, time = (pts / 14112e3).toFixed(6);
|
|
387059
|
+
const duration = samples * 14112e3 / s.sampleRate;
|
|
387060
|
+
yield {
|
|
387061
|
+
media_type: "audio",
|
|
387062
|
+
stream_index: 0,
|
|
387063
|
+
key_frame: 1,
|
|
387064
|
+
pts,
|
|
387065
|
+
pts_time: time,
|
|
387066
|
+
pkt_dts: pts,
|
|
387067
|
+
pkt_dts_time: time,
|
|
387068
|
+
best_effort_timestamp: pts,
|
|
387069
|
+
best_effort_timestamp_time: time,
|
|
387070
|
+
duration,
|
|
387071
|
+
duration_time: (duration / 14112e3).toFixed(6),
|
|
387072
|
+
pkt_size: String(s.size),
|
|
387073
|
+
sample_fmt: stream.sample_fmt,
|
|
387074
|
+
nb_samples: samples,
|
|
387075
|
+
channels: s.channels
|
|
387076
|
+
};
|
|
387077
|
+
}
|
|
386849
387078
|
} } : void 0
|
|
386850
387079
|
};
|
|
386851
387080
|
}
|
|
386852
387081
|
function mp3Ast() {
|
|
386853
387082
|
return {
|
|
386854
387083
|
async probeMetadata(source, options = {}) {
|
|
386855
|
-
return mp3Records(source.size, options);
|
|
387084
|
+
return mp3Records(source.size, await readMp3SourceFrames(source, options.signal), options);
|
|
386856
387085
|
},
|
|
386857
387086
|
async probeMetadataStream(source, options = {}) {
|
|
386858
|
-
options.signal
|
|
386859
|
-
|
|
386860
|
-
for await (const chunk of source) {
|
|
386861
|
-
options.signal?.throwIfAborted();
|
|
386862
|
-
size += chunk.byteLength;
|
|
386863
|
-
if (!Number.isSafeInteger(size)) throw new RangeError("Invalid MP3 source size");
|
|
386864
|
-
}
|
|
386865
|
-
return mp3Records(size, options);
|
|
387087
|
+
const { frames, size } = await readMp3StreamFrames(source, options.signal);
|
|
387088
|
+
return mp3Records(size, frames, options);
|
|
386866
387089
|
},
|
|
386867
387090
|
id: "mp3",
|
|
386868
387091
|
formatName: "mp3",
|
|
@@ -386879,23 +387102,24 @@ function mp3Ast() {
|
|
|
386879
387102
|
return false;
|
|
386880
387103
|
},
|
|
386881
387104
|
parse(bytes) {
|
|
386882
|
-
const
|
|
386883
|
-
|
|
386884
|
-
|
|
386885
|
-
const
|
|
386886
|
-
const
|
|
386887
|
-
|
|
386888
|
-
|
|
386889
|
-
|
|
386890
|
-
pts: i * 1152,
|
|
387105
|
+
const frames = readMp3Frames(bytes);
|
|
387106
|
+
let pts = 0;
|
|
387107
|
+
const samples = frames.map((frame) => {
|
|
387108
|
+
const duration = frame.samples * 14112e3 / frame.sampleRate;
|
|
387109
|
+
const sample = {
|
|
387110
|
+
data: bytes.subarray(frame.offset, frame.offset + frame.size),
|
|
387111
|
+
dts: pts,
|
|
387112
|
+
pts,
|
|
386891
387113
|
cts: 0,
|
|
386892
|
-
duration
|
|
386893
|
-
size:
|
|
387114
|
+
duration,
|
|
387115
|
+
size: frame.size,
|
|
386894
387116
|
isKeyframe: true,
|
|
386895
387117
|
sampleDescriptionIndex: 1
|
|
386896
|
-
}
|
|
386897
|
-
|
|
386898
|
-
|
|
387118
|
+
};
|
|
387119
|
+
pts += duration;
|
|
387120
|
+
return sample;
|
|
387121
|
+
});
|
|
387122
|
+
return mp3Document(bytes.byteLength, frames, samples);
|
|
386899
387123
|
},
|
|
386900
387124
|
serialize(doc) {
|
|
386901
387125
|
const numFrames = Math.max(1, Math.ceil((doc.durationSeconds || 1) * 44100 / 1152));
|
|
@@ -386906,13 +387130,13 @@ function mp3Ast() {
|
|
|
386906
387130
|
frame[3] = 0;
|
|
386907
387131
|
return concatBytes(Array.from({ length: numFrames }, () => frame));
|
|
386908
387132
|
},
|
|
386909
|
-
probe(bytes, options) {
|
|
386910
|
-
const
|
|
386911
|
-
return
|
|
386912
|
-
...
|
|
386913
|
-
|
|
386914
|
-
|
|
386915
|
-
}
|
|
387133
|
+
probe(bytes, options = {}) {
|
|
387134
|
+
const result = mp3Records(bytes.length, readMp3Frames(bytes), options);
|
|
387135
|
+
return {
|
|
387136
|
+
...result,
|
|
387137
|
+
packets: result.packets ? Array.from(result.packets) : void 0,
|
|
387138
|
+
frames: result.frames ? Array.from(result.frames) : void 0
|
|
387139
|
+
};
|
|
386916
387140
|
},
|
|
386917
387141
|
concat(docs, options) {
|
|
386918
387142
|
return concatMp4(docs, options);
|
|
@@ -386977,42 +387201,61 @@ function flacDocument(bytes, byteLength, data = new Uint8Array()) {
|
|
|
386977
387201
|
byteLength
|
|
386978
387202
|
};
|
|
386979
387203
|
}
|
|
387204
|
+
function flacProbe(scanner, options = {}) {
|
|
387205
|
+
const doc = flacDocument(scanner.header.subarray(0, Math.min(42, scanner.size)), scanner.size);
|
|
387206
|
+
const samples = scanner.packets.map((packet) => ({
|
|
387207
|
+
...packet,
|
|
387208
|
+
dts: packet.pts,
|
|
387209
|
+
cts: 0,
|
|
387210
|
+
data: new Uint8Array(),
|
|
387211
|
+
isKeyframe: true,
|
|
387212
|
+
sampleDescriptionIndex: 1
|
|
387213
|
+
}));
|
|
387214
|
+
const result = buildProbeResultFromDoc(
|
|
387215
|
+
{ ...doc, tracks: [{ ...doc.tracks[0], samples }] },
|
|
387216
|
+
scanner.size,
|
|
387217
|
+
options.filename ?? "input.flac",
|
|
387218
|
+
{ ...options, formatName: "flac", formatLongName: "raw FLAC" }
|
|
387219
|
+
);
|
|
387220
|
+
return {
|
|
387221
|
+
...result,
|
|
387222
|
+
streams: result.streams.map((stream) => ({
|
|
387223
|
+
...stream,
|
|
387224
|
+
nb_frames: void 0,
|
|
387225
|
+
nb_read_packets: String(samples.length),
|
|
387226
|
+
nb_read_frames: String(samples.length)
|
|
387227
|
+
})),
|
|
387228
|
+
packets: result.packets?.map((packet, index) => ({ ...packet, pos: String(scanner.packets[index].pos) }))
|
|
387229
|
+
};
|
|
387230
|
+
}
|
|
386980
387231
|
function flacAst() {
|
|
386981
387232
|
return {
|
|
386982
387233
|
async probeMetadata(source, options = {}) {
|
|
386983
387234
|
options.signal?.throwIfAborted();
|
|
386984
387235
|
if (!Number.isSafeInteger(source.size) || source.size < 0) throw new RangeError("Invalid FLAC source size");
|
|
386985
|
-
const
|
|
386986
|
-
|
|
386987
|
-
const
|
|
387236
|
+
const scanner = new FlacFrameScanner();
|
|
387237
|
+
while (scanner.size < source.size) {
|
|
387238
|
+
const length = Math.min(16384, source.size - scanner.size);
|
|
387239
|
+
const chunk = await source.read(scanner.size, length);
|
|
386988
387240
|
options.signal?.throwIfAborted();
|
|
386989
387241
|
if (!chunk.length) throw new Error("Unexpected end of FLAC source");
|
|
386990
|
-
if (chunk.length >
|
|
386991
|
-
|
|
386992
|
-
offset += chunk.length;
|
|
387242
|
+
if (chunk.length > length) throw new Error("FLAC source returned more bytes than requested");
|
|
387243
|
+
scanner.push(chunk);
|
|
386993
387244
|
}
|
|
386994
|
-
|
|
386995
|
-
|
|
386996
|
-
formatName: "flac",
|
|
386997
|
-
formatLongName: "raw FLAC"
|
|
386998
|
-
});
|
|
387245
|
+
scanner.push(new Uint8Array(), true);
|
|
387246
|
+
return flacProbe(scanner, options);
|
|
386999
387247
|
},
|
|
387000
387248
|
async probeMetadataStream(source, options = {}) {
|
|
387001
387249
|
options.signal?.throwIfAborted();
|
|
387002
|
-
const
|
|
387003
|
-
let size = 0;
|
|
387250
|
+
const scanner = new FlacFrameScanner();
|
|
387004
387251
|
for await (const chunk of source) {
|
|
387005
387252
|
options.signal?.throwIfAborted();
|
|
387006
|
-
|
|
387007
|
-
size
|
|
387008
|
-
if (!Number.isSafeInteger(size)) throw new RangeError("Invalid FLAC source size");
|
|
387253
|
+
scanner.push(chunk);
|
|
387254
|
+
if (!Number.isSafeInteger(scanner.size)) throw new RangeError("Invalid FLAC source size");
|
|
387009
387255
|
}
|
|
387010
387256
|
options.signal?.throwIfAborted();
|
|
387011
|
-
|
|
387012
|
-
|
|
387013
|
-
formatName: "flac",
|
|
387014
|
-
formatLongName: "raw FLAC"
|
|
387015
|
-
});
|
|
387257
|
+
scanner.push(new Uint8Array(), true);
|
|
387258
|
+
return flacProbe(scanner, options);
|
|
387016
387259
|
},
|
|
387017
387260
|
id: "flac",
|
|
387018
387261
|
formatName: "flac",
|
|
@@ -387037,12 +387280,9 @@ function flacAst() {
|
|
|
387037
387280
|
return concatBytes(encodeFlacPackets(doc));
|
|
387038
387281
|
},
|
|
387039
387282
|
probe(bytes, options) {
|
|
387040
|
-
const
|
|
387041
|
-
|
|
387042
|
-
|
|
387043
|
-
formatName: "flac",
|
|
387044
|
-
formatLongName: "raw FLAC"
|
|
387045
|
-
});
|
|
387283
|
+
const scanner = new FlacFrameScanner();
|
|
387284
|
+
scanner.push(bytes, true);
|
|
387285
|
+
return flacProbe(scanner, options);
|
|
387046
387286
|
},
|
|
387047
387287
|
concat(docs, options) {
|
|
387048
387288
|
return concatMp4(docs, options);
|
|
@@ -387269,7 +387509,7 @@ function gifAst() {
|
|
|
387269
387509
|
enabled: true,
|
|
387270
387510
|
width,
|
|
387271
387511
|
height,
|
|
387272
|
-
codecDescriptions: [{ formatFourCC: "gif ", codecName: "gif", width, height, pixFmt: "
|
|
387512
|
+
codecDescriptions: [{ formatFourCC: "gif ", codecName: "gif", width, height, pixFmt: "bgra" }],
|
|
387273
387513
|
samples,
|
|
387274
387514
|
decodedVideoFrames: frames
|
|
387275
387515
|
}],
|
|
@@ -387299,11 +387539,28 @@ function gifAst() {
|
|
|
387299
387539
|
},
|
|
387300
387540
|
probe(bytes, options) {
|
|
387301
387541
|
const doc = this.parse(bytes, options);
|
|
387302
|
-
|
|
387542
|
+
const result = buildProbeResultFromDoc(doc, bytes.byteLength, options?.filename ?? "input.gif", {
|
|
387303
387543
|
...options,
|
|
387304
387544
|
formatName: "gif",
|
|
387305
387545
|
formatLongName: "CompuServe Graphics Interchange Format (GIF)"
|
|
387306
387546
|
});
|
|
387547
|
+
const track = doc.tracks[0];
|
|
387548
|
+
const stream = result.streams[0];
|
|
387549
|
+
if (track.samples.length > 1) {
|
|
387550
|
+
const averageDelay = Math.floor(track.duration / track.samples.length);
|
|
387551
|
+
const averageDivisor = gcd(track.timescale, averageDelay);
|
|
387552
|
+
let interval = 0;
|
|
387553
|
+
for (let index = 1; index < track.samples.length; index++) {
|
|
387554
|
+
interval = gcd(interval, track.samples[index].dts - track.samples[index - 1].dts);
|
|
387555
|
+
}
|
|
387556
|
+
const nominalDivisor = gcd(track.timescale, interval);
|
|
387557
|
+
return { ...result, streams: [{
|
|
387558
|
+
...stream,
|
|
387559
|
+
avg_frame_rate: `${track.timescale / averageDivisor}/${averageDelay / averageDivisor}`,
|
|
387560
|
+
r_frame_rate: `${track.timescale / nominalDivisor}/${interval / nominalDivisor}`
|
|
387561
|
+
}] };
|
|
387562
|
+
}
|
|
387563
|
+
return result;
|
|
387307
387564
|
},
|
|
387308
387565
|
concat(docs, options) {
|
|
387309
387566
|
return concatMp4(docs, options);
|
|
@@ -388114,9 +388371,9 @@ async function* scanMp4CodecDescriptions(source, range, options = {}) {
|
|
|
388114
388371
|
async function* scanMp4Packets(source, options = {}) {
|
|
388115
388372
|
for await (const record of scanProbeRecords(source, options, "packets")) {
|
|
388116
388373
|
if (!("sample" in record)) continue;
|
|
388117
|
-
const { sample, track
|
|
388374
|
+
const { sample, track } = record;
|
|
388118
388375
|
const scale = Math.max(1, track.timescale);
|
|
388119
|
-
yield { codec_type: track.type, stream_index: track.index, pts: sample.pts, pts_time: (sample.pts / scale).toFixed(6), dts: sample.dts, dts_time: (sample.dts / scale).toFixed(6), duration: sample.duration, duration_time: (sample.duration / scale).toFixed(6), size: String(sample.size), pos: String(
|
|
388376
|
+
yield { codec_type: track.type, stream_index: track.index, pts: sample.pts, pts_time: (sample.pts / scale).toFixed(6), dts: sample.dts, dts_time: (sample.dts / scale).toFixed(6), duration: sample.duration, duration_time: (sample.duration / scale).toFixed(6), size: String(sample.size), pos: String(sample.offset), flags: sample.isKeyframe ? "K__" : "___" };
|
|
388120
388377
|
}
|
|
388121
388378
|
}
|
|
388122
388379
|
async function* scanMp4Frames(source, options = {}) {
|
|
@@ -388140,7 +388397,7 @@ async function* scanMp4Frames(source, options = {}) {
|
|
|
388140
388397
|
width: track.width,
|
|
388141
388398
|
height: track.height,
|
|
388142
388399
|
pix_fmt: track.type === "video" ? track.codec?.pixFmt ?? "yuv420p" : void 0,
|
|
388143
|
-
pict_type:
|
|
388400
|
+
pict_type: void 0,
|
|
388144
388401
|
sample_fmt: probeSampleFormat(track.type, track.codec?.codecName ?? (track.type === "video" ? "h264" : "aac")),
|
|
388145
388402
|
nb_samples: track.type === "audio" ? sample.duration : void 0,
|
|
388146
388403
|
channels: track.type === "audio" ? track.codec?.channels ?? 2 : void 0
|
|
@@ -388266,11 +388523,16 @@ async function* scanProbeRecords(source, options, mode) {
|
|
|
388266
388523
|
}
|
|
388267
388524
|
}
|
|
388268
388525
|
let duration = 0, mediaEnd = 0, allPacked = true, count = 0, firstPts = 0;
|
|
388526
|
+
let highestPts = -Infinity, reorderSpan = 0;
|
|
388269
388527
|
for await (const sample of samples()) {
|
|
388270
388528
|
if (!count) firstPts = sample.pts;
|
|
388271
388529
|
count++;
|
|
388272
388530
|
duration += sample.duration;
|
|
388273
388531
|
mediaEnd = Math.max(mediaEnd, sample.pts + sample.duration);
|
|
388532
|
+
if (mode === "frames" && type === "video") {
|
|
388533
|
+
highestPts = Math.max(highestPts, sample.pts);
|
|
388534
|
+
reorderSpan = Math.max(reorderSpan, highestPts - sample.pts);
|
|
388535
|
+
}
|
|
388274
388536
|
if (type === "subtitle" && allPacked) {
|
|
388275
388537
|
if (sample.size < 2) allPacked = false;
|
|
388276
388538
|
else allPacked = new BinaryReader(await readMp4SampleRange(source, sample.offset, 2, work)).readU16BE() === sample.size - 2;
|
|
@@ -388283,18 +388545,20 @@ async function* scanProbeRecords(source, options, mode) {
|
|
|
388283
388545
|
const version = header2.readU8();
|
|
388284
388546
|
header2.skip(3);
|
|
388285
388547
|
const count2 = header2.readU32BE(), width2 = version === 1 ? 20 : 12;
|
|
388286
|
-
let total = 0, entries = 0, delay = 0, foundMedia = false;
|
|
388548
|
+
let total = 0, entries = 0, delay = 0, mediaStart = 0, foundMedia = false;
|
|
388287
388549
|
for (let i = 0; i < count2 && 8 + i * width2 < elst.payloadSize; i++) {
|
|
388288
388550
|
const row = new BinaryReader(yield { kind: "read", table: elst, offset: elst.payloadOffset + 8 + i * width2, length: Math.min(width2, elst.payloadSize - 8 - i * width2) });
|
|
388289
388551
|
let segment = version === 1 ? row.readU64BE() : row.readU32BE();
|
|
388290
388552
|
const mediaTime = version === 1 ? row.readI64BE() : row.readI32BE();
|
|
388291
388553
|
if (fragmented && segment === 0 && mediaTime >= 0) segment = Math.round(Math.max(0, mediaEnd - mediaTime) * movieTimescale / timescale);
|
|
388292
|
-
if (mediaTime >= 0
|
|
388293
|
-
|
|
388554
|
+
if (mediaTime >= 0 && !foundMedia) {
|
|
388555
|
+
mediaStart = mediaTime;
|
|
388556
|
+
foundMedia = true;
|
|
388557
|
+
} else if (!foundMedia) delay += segment;
|
|
388294
388558
|
total += segment;
|
|
388295
388559
|
entries++;
|
|
388296
388560
|
}
|
|
388297
|
-
return entries ? { duration: Math.round(total * timescale / movieTimescale), start: Math.round(delay * timescale / movieTimescale) } : void 0;
|
|
388561
|
+
return entries ? { duration: Math.round(total * timescale / movieTimescale), start: Math.round(delay * timescale / movieTimescale), mediaStart } : void 0;
|
|
388298
388562
|
}
|
|
388299
388563
|
const edits = consumeMp4SampleSteps(source, editDuration(), sampleOptions), result = await edits.next();
|
|
388300
388564
|
if (!result.done) throw new Error("Unexpected MP4 edit sample");
|
|
@@ -388307,7 +388571,8 @@ async function* scanProbeRecords(source, options, mode) {
|
|
|
388307
388571
|
formatStart = Math.min(formatStart, start);
|
|
388308
388572
|
formatEnd = Math.max(formatEnd, start + probeDuration / Math.max(1, timescale));
|
|
388309
388573
|
if (mode === "summary") continue;
|
|
388310
|
-
|
|
388574
|
+
const timestampOffset = result.value ? result.value.start - result.value.mediaStart : 0;
|
|
388575
|
+
let cursor = 0, previousPts = -Infinity;
|
|
388311
388576
|
const stats = { totalBytes: 0, count: 0, ticks: 0, firstPts: startPts, hasReorderedSamples: false };
|
|
388312
388577
|
const packet = (sample) => {
|
|
388313
388578
|
if (mode === "streams") {
|
|
@@ -388317,11 +388582,34 @@ async function* scanProbeRecords(source, options, mode) {
|
|
|
388317
388582
|
stats.hasReorderedSamples ||= sample.pts < previousPts;
|
|
388318
388583
|
previousPts = sample.pts;
|
|
388319
388584
|
}
|
|
388320
|
-
|
|
388321
|
-
bytePos += sample.size;
|
|
388322
|
-
return record;
|
|
388585
|
+
return { sample, track };
|
|
388323
388586
|
};
|
|
388324
|
-
|
|
388587
|
+
async function* frameSamples() {
|
|
388588
|
+
const pending = [];
|
|
388589
|
+
let highest = -Infinity;
|
|
388590
|
+
try {
|
|
388591
|
+
for await (const sample of samples()) {
|
|
388592
|
+
highest = Math.max(highest, sample.pts);
|
|
388593
|
+
const index2 = pending.findIndex((row) => row.pts <= sample.pts);
|
|
388594
|
+
pending.splice(index2 < 0 ? pending.length : index2, 0, sample);
|
|
388595
|
+
budget.allocateMemory(128);
|
|
388596
|
+
while (pending.length && pending[pending.length - 1].pts <= highest - reorderSpan) {
|
|
388597
|
+
const next = pending.pop();
|
|
388598
|
+
budget.releaseMemory(128);
|
|
388599
|
+
yield next;
|
|
388600
|
+
}
|
|
388601
|
+
}
|
|
388602
|
+
while (pending.length) {
|
|
388603
|
+
const next = pending.pop();
|
|
388604
|
+
budget.releaseMemory(128);
|
|
388605
|
+
yield next;
|
|
388606
|
+
}
|
|
388607
|
+
} finally {
|
|
388608
|
+
budget.releaseMemory(pending.length * 128);
|
|
388609
|
+
}
|
|
388610
|
+
}
|
|
388611
|
+
for await (const rawSample of reorderSpan > 0 ? frameSamples() : samples()) {
|
|
388612
|
+
const sample = { ...rawSample, pts: rawSample.pts + timestampOffset, dts: rawSample.dts + timestampOffset };
|
|
388325
388613
|
if (type !== "subtitle" || !count || allPacked) {
|
|
388326
388614
|
const row2 = packet(sample);
|
|
388327
388615
|
if (mode !== "streams") yield row2;
|
|
@@ -388329,12 +388617,12 @@ async function* scanProbeRecords(source, options, mode) {
|
|
|
388329
388617
|
}
|
|
388330
388618
|
const start2 = Math.max(cursor, Math.round(sample.pts));
|
|
388331
388619
|
if (start2 > cursor) {
|
|
388332
|
-
const row2 = packet({ pts: cursor, dts: cursor, duration: start2 - cursor, size: 2, isKeyframe: true });
|
|
388620
|
+
const row2 = packet({ offset: -1, pts: cursor, dts: cursor, duration: start2 - cursor, size: 2, isKeyframe: true });
|
|
388333
388621
|
if (mode !== "streams") yield row2;
|
|
388334
388622
|
cursor = start2;
|
|
388335
388623
|
}
|
|
388336
388624
|
const duration2 = Math.max(1, Math.round(sample.duration));
|
|
388337
|
-
const row = packet({ pts: cursor, dts: cursor, duration: duration2, size: sample.size + 2, isKeyframe: true });
|
|
388625
|
+
const row = packet({ offset: sample.offset, pts: cursor, dts: cursor, duration: duration2, size: sample.size + 2, isKeyframe: true });
|
|
388338
388626
|
if (mode !== "streams") yield row;
|
|
388339
388627
|
cursor += duration2;
|
|
388340
388628
|
}
|
|
@@ -388387,6 +388675,7 @@ export {
|
|
|
388387
388675
|
createSyntheticMp4,
|
|
388388
388676
|
parseStreamingManifest,
|
|
388389
388677
|
serializeDashDocument,
|
|
388678
|
+
wavPacketFrames,
|
|
388390
388679
|
probeOggStreamMetadata,
|
|
388391
388680
|
probeOggFlacSource,
|
|
388392
388681
|
parseSubtitleDocument,
|