@poe-platform/safe-bash 0.1.840 → 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.
@@ -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 ? "K_" : "__"
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) {
@@ -383223,7 +383223,7 @@ function buildProbeResultFromDoc(doc, byteLength, filename = "input.mp4", option
383223
383223
  width: w,
383224
383224
  height: h,
383225
383225
  pix_fmt: track.type === "video" ? desc?.pixFmt ?? "yuv420p" : void 0,
383226
- pict_type: track.type === "video" ? s.isKeyframe ? "I" : "P" : void 0,
383226
+ pict_type: void 0,
383227
383227
  sample_fmt: sampleFormat,
383228
383228
  nb_samples: track.type === "audio" ? s.duration : void 0,
383229
383229
  channels: track.type === "audio" ? desc?.channels ?? 2 : void 0
@@ -384266,6 +384266,132 @@ function serializeDashDocument(doc, options = {}) {
384266
384266
  return { manifest, resources };
384267
384267
  }
384268
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
+
384269
384395
  // packages/mp4-ast/src/aac.ts
384270
384396
  function decodeAacTrack(doc, track) {
384271
384397
  const description = track.codecDescriptions[0];
@@ -384513,6 +384639,101 @@ function encodeFlacPackets(doc) {
384513
384639
  return frames;
384514
384640
  }
384515
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
+
384516
384737
  // packages/mp4-ast/src/containers/ogg.ts
384517
384738
  function page(packet, sequence, flags, granule) {
384518
384739
  const segments = Math.floor(packet.length / 255) + 1;
@@ -384633,7 +384854,7 @@ async function readOggFlacHeader(source, options = {}) {
384633
384854
  const start = offset, header = await read(27);
384634
384855
  if (header[0] !== 79 || header[1] !== 103 || header[2] !== 103 || header[3] !== 83) throw new Error("Invalid Ogg page");
384635
384856
  const lacing = await read(header[26]);
384636
- let checksum = oggCrc(lacing, oggCrc(header), 27);
384857
+ let checksum2 = oggCrc(lacing, oggCrc(header), 27);
384637
384858
  const continuation = Boolean(header[5] & 1) !== packetSize > 0;
384638
384859
  let remaining = 0, chunk = new Uint8Array(), used = 0;
384639
384860
  for (const length of lacing) remaining += length;
@@ -384642,7 +384863,7 @@ async function readOggFlacHeader(source, options = {}) {
384642
384863
  if (used === chunk.length) {
384643
384864
  chunk = await read(Math.min(16384, remaining));
384644
384865
  used = 0;
384645
- checksum = oggCrc(chunk, checksum, offset - start - chunk.length);
384866
+ checksum2 = oggCrc(chunk, checksum2, offset - start - chunk.length);
384646
384867
  remaining -= chunk.length;
384647
384868
  }
384648
384869
  const take = Math.min(pending, chunk.length - used);
@@ -384660,7 +384881,7 @@ async function readOggFlacHeader(source, options = {}) {
384660
384881
  packetSize = 0;
384661
384882
  }
384662
384883
  }
384663
- if (checksum !== new DataView(header.buffer).getUint32(22, true)) throw new Error("Ogg CRC mismatch");
384884
+ if (checksum2 !== new DataView(header.buffer).getUint32(22, true)) throw new Error("Ogg CRC mismatch");
384664
384885
  if (continuation) throw new Error("Invalid Ogg packet continuation");
384665
384886
  if (firstSize >= 0 && !mapped) return void 0;
384666
384887
  }
@@ -386508,7 +386729,10 @@ function aacAst() {
386508
386729
  function isWavSignature(bytes) {
386509
386730
  return bytes.byteLength >= 12 && decodeFourCC(bytes, 0) === "RIFF" && decodeFourCC(bytes, 8) === "WAVE";
386510
386731
  }
386511
- var wavPacketFrames = 1024;
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
+ }
386512
386736
  function parseWav(bytes, options = {}) {
386513
386737
  const header = readWavHeader(bytes);
386514
386738
  const { formatTag, channels, sampleRate, bitsPerSample } = header;
@@ -386539,7 +386763,7 @@ function parseWav(bytes, options = {}) {
386539
386763
  decodedAudio = { sampleRate, channels, channelData };
386540
386764
  }
386541
386765
  const samples = [];
386542
- const chunkFrames = wavPacketFrames;
386766
+ const chunkFrames = wavPacketFrames(header.sampleRate, bytesPerFrame);
386543
386767
  for (let offsetSample = 0; offsetSample < totalPcmSamples; offsetSample += chunkFrames) {
386544
386768
  const count = Math.min(chunkFrames, totalPcmSamples - offsetSample);
386545
386769
  const byteStart = offsetSample * bytesPerFrame;
@@ -386642,7 +386866,6 @@ function wavMetadata(header, filename = "input.wav") {
386642
386866
  const bytesPerFrame = Math.max(1, header.channels * (header.bitsPerSample >>> 3));
386643
386867
  return { ...result, streams: [{
386644
386868
  ...result.streams[0],
386645
- nb_frames: String(Math.ceil(samples / wavPacketFrames)),
386646
386869
  bit_rate: doc.durationSeconds > 0 ? String(Math.round(samples * bytesPerFrame * 8 / doc.durationSeconds)) : "0"
386647
386870
  }] };
386648
386871
  }
@@ -386650,10 +386873,11 @@ function wavRecords(header, options) {
386650
386873
  const metadata = wavMetadata(header, options.filename), stream = metadata.streams[0];
386651
386874
  const bytesPerFrame = Math.max(1, header.channels * (header.bitsPerSample >>> 3));
386652
386875
  const samples = Math.floor(header.dataSize / bytesPerFrame), rate = Math.max(1, header.sampleRate);
386876
+ const chunkFrames = wavPacketFrames(header.sampleRate, bytesPerFrame);
386653
386877
  function* spans() {
386654
- for (let pts = 0; pts < samples; pts += wavPacketFrames) {
386878
+ for (let pts = 0; pts < samples; pts += chunkFrames) {
386655
386879
  options.signal?.throwIfAborted();
386656
- const count = Math.min(wavPacketFrames, samples - pts);
386880
+ const count = Math.min(chunkFrames, samples - pts);
386657
386881
  yield { pts, count, size: String(count * bytesPerFrame), time: (pts / rate).toFixed(6), duration: (count / rate).toFixed(6) };
386658
386882
  }
386659
386883
  options.signal?.throwIfAborted();
@@ -386672,7 +386896,7 @@ function wavRecords(header, options) {
386672
386896
  duration_time: s.duration,
386673
386897
  size: s.size,
386674
386898
  pos: String(s.pts * bytesPerFrame),
386675
- flags: "K_"
386899
+ flags: "K__"
386676
386900
  };
386677
386901
  } } : void 0,
386678
386902
  frames: options.showFrames ? { *[Symbol.iterator]() {
@@ -386752,20 +386976,21 @@ function isMp3Signature(bytes) {
386752
386976
  if (bytes[0] === 73 && bytes[1] === 68 && bytes[2] === 51) return true;
386753
386977
  return bytes[0] === 255 && (bytes[1] & 224) === 224 && (bytes[1] & 6) !== 0;
386754
386978
  }
386755
- function mp3Document(byteLength, samples) {
386756
- const sampleRate = 44100, channels = 2, count = Math.max(1, Math.floor(byteLength / 417));
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);
386757
386982
  return {
386758
386983
  containerFormat: "mp3",
386759
- timescale: sampleRate,
386760
- duration: count * 1152,
386761
- durationSeconds: count * 1152 / sampleRate,
386984
+ timescale: 14112e3,
386985
+ duration,
386986
+ durationSeconds: duration / 14112e3,
386762
386987
  tracks: [
386763
386988
  {
386764
386989
  id: 1,
386765
386990
  type: "audio",
386766
386991
  handlerType: "soun",
386767
- timescale: sampleRate,
386768
- duration: count * 1152,
386992
+ timescale: 14112e3,
386993
+ duration,
386769
386994
  language: "und",
386770
386995
  enabled: true,
386771
386996
  codecDescriptions: [
@@ -386784,24 +387009,27 @@ function mp3Document(byteLength, samples) {
386784
387009
  byteLength
386785
387010
  };
386786
387011
  }
386787
- function mp3Records(size, options) {
387012
+ function mp3Records(size, frames, options) {
386788
387013
  options.signal?.throwIfAborted();
386789
- if (!Number.isSafeInteger(size) || size < 0) throw new RangeError("Invalid MP3 source size");
386790
- const count = Math.max(1, Math.floor(size / 417)), doc = mp3Document(size, []);
387014
+ const doc = mp3Document(size, frames, []);
386791
387015
  const metadata = buildProbeResultFromDoc(doc, size, options.filename ?? "input.mp3", {
386792
387016
  formatName: "mp3",
386793
387017
  formatLongName: "MP2/3 (MPEG audio layer 2/3)"
386794
387018
  });
386795
387019
  const stream = {
386796
387020
  ...metadata.streams[0],
386797
- nb_frames: String(count),
386798
- bit_rate: String(Math.round(Math.min(size, count * 417) * 8 / doc.durationSeconds))
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))
386799
387025
  };
386800
387026
  function* spans() {
386801
- for (let index = 0; index < count; index++) {
387027
+ let pts = 0;
387028
+ for (const frame of frames) {
386802
387029
  options.signal?.throwIfAborted();
386803
- const pts = index * 1152;
386804
- yield { pts, time: (pts / 44100).toFixed(6), size: String(Math.min(417, size - index * 417)), pos: String(index * 417) };
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;
386805
387033
  }
386806
387034
  options.signal?.throwIfAborted();
386807
387035
  }
@@ -386816,52 +387044,48 @@ function mp3Records(size, options) {
386816
387044
  pts_time: s.time,
386817
387045
  dts: s.pts,
386818
387046
  dts_time: s.time,
386819
- duration: 1152,
386820
- duration_time: (1152 / 44100).toFixed(6),
386821
- size: s.size,
386822
- pos: s.pos,
386823
- flags: "K_"
387047
+ duration: s.duration,
387048
+ duration_time: s.durationTime,
387049
+ size: String(s.size),
387050
+ pos: String(s.offset),
387051
+ flags: "K__"
386824
387052
  };
386825
387053
  } } : void 0,
386826
387054
  frames: options.showFrames ? { *[Symbol.iterator]() {
386827
- for (const s of spans()) yield {
386828
- media_type: "audio",
386829
- stream_index: 0,
386830
- key_frame: 1,
386831
- pts: s.pts,
386832
- pts_time: s.time,
386833
- pkt_dts: s.pts,
386834
- pkt_dts_time: s.time,
386835
- best_effort_timestamp: s.pts,
386836
- best_effort_timestamp_time: s.time,
386837
- pkt_duration: 1152,
386838
- pkt_duration_time: (1152 / 44100).toFixed(6),
386839
- pkt_size: s.size,
386840
- width: void 0,
386841
- height: void 0,
386842
- pix_fmt: void 0,
386843
- pict_type: void 0,
386844
- sample_fmt: stream.sample_fmt,
386845
- nb_samples: 1152,
386846
- channels: 2
386847
- };
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
+ }
386848
387078
  } } : void 0
386849
387079
  };
386850
387080
  }
386851
387081
  function mp3Ast() {
386852
387082
  return {
386853
387083
  async probeMetadata(source, options = {}) {
386854
- return mp3Records(source.size, options);
387084
+ return mp3Records(source.size, await readMp3SourceFrames(source, options.signal), options);
386855
387085
  },
386856
387086
  async probeMetadataStream(source, options = {}) {
386857
- options.signal?.throwIfAborted();
386858
- let size = 0;
386859
- for await (const chunk of source) {
386860
- options.signal?.throwIfAborted();
386861
- size += chunk.byteLength;
386862
- if (!Number.isSafeInteger(size)) throw new RangeError("Invalid MP3 source size");
386863
- }
386864
- return mp3Records(size, options);
387087
+ const { frames, size } = await readMp3StreamFrames(source, options.signal);
387088
+ return mp3Records(size, frames, options);
386865
387089
  },
386866
387090
  id: "mp3",
386867
387091
  formatName: "mp3",
@@ -386878,23 +387102,24 @@ function mp3Ast() {
386878
387102
  return false;
386879
387103
  },
386880
387104
  parse(bytes) {
386881
- const numFrames = Math.max(1, Math.floor(bytes.byteLength / 417));
386882
- const samples = [];
386883
- for (let i = 0; i < numFrames; i++) {
386884
- const start = Math.min(bytes.byteLength, i * 417);
386885
- const end = Math.min(bytes.byteLength, start + 417);
386886
- samples.push({
386887
- data: bytes.subarray(start, end),
386888
- dts: i * 1152,
386889
- 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,
386890
387113
  cts: 0,
386891
- duration: 1152,
386892
- size: end - start,
387114
+ duration,
387115
+ size: frame.size,
386893
387116
  isKeyframe: true,
386894
387117
  sampleDescriptionIndex: 1
386895
- });
386896
- }
386897
- return mp3Document(bytes.byteLength, samples);
387118
+ };
387119
+ pts += duration;
387120
+ return sample;
387121
+ });
387122
+ return mp3Document(bytes.byteLength, frames, samples);
386898
387123
  },
386899
387124
  serialize(doc) {
386900
387125
  const numFrames = Math.max(1, Math.ceil((doc.durationSeconds || 1) * 44100 / 1152));
@@ -386905,13 +387130,13 @@ function mp3Ast() {
386905
387130
  frame[3] = 0;
386906
387131
  return concatBytes(Array.from({ length: numFrames }, () => frame));
386907
387132
  },
386908
- probe(bytes, options) {
386909
- const doc = this.parse(bytes, options);
386910
- return buildProbeResultFromDoc(doc, bytes.byteLength, options?.filename ?? "input.mp3", {
386911
- ...options,
386912
- formatName: "mp3",
386913
- formatLongName: "MP2/3 (MPEG audio layer 2/3)"
386914
- });
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
+ };
386915
387140
  },
386916
387141
  concat(docs, options) {
386917
387142
  return concatMp4(docs, options);
@@ -386976,42 +387201,61 @@ function flacDocument(bytes, byteLength, data = new Uint8Array()) {
386976
387201
  byteLength
386977
387202
  };
386978
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
+ }
386979
387231
  function flacAst() {
386980
387232
  return {
386981
387233
  async probeMetadata(source, options = {}) {
386982
387234
  options.signal?.throwIfAborted();
386983
387235
  if (!Number.isSafeInteger(source.size) || source.size < 0) throw new RangeError("Invalid FLAC source size");
386984
- const header = new Uint8Array(Math.min(42, source.size));
386985
- for (let offset = 0; offset < header.length; ) {
386986
- const chunk = await source.read(offset, header.length - offset);
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);
386987
387240
  options.signal?.throwIfAborted();
386988
387241
  if (!chunk.length) throw new Error("Unexpected end of FLAC source");
386989
- if (chunk.length > header.length - offset) throw new Error("FLAC source returned more bytes than requested");
386990
- header.set(chunk, offset);
386991
- offset += chunk.length;
387242
+ if (chunk.length > length) throw new Error("FLAC source returned more bytes than requested");
387243
+ scanner.push(chunk);
386992
387244
  }
386993
- return buildProbeResultFromDoc(flacDocument(header, source.size), source.size, options.filename ?? "input.flac", {
386994
- ...options,
386995
- formatName: "flac",
386996
- formatLongName: "raw FLAC"
386997
- });
387245
+ scanner.push(new Uint8Array(), true);
387246
+ return flacProbe(scanner, options);
386998
387247
  },
386999
387248
  async probeMetadataStream(source, options = {}) {
387000
387249
  options.signal?.throwIfAborted();
387001
- const header = new Uint8Array(42);
387002
- let size = 0;
387250
+ const scanner = new FlacFrameScanner();
387003
387251
  for await (const chunk of source) {
387004
387252
  options.signal?.throwIfAborted();
387005
- if (size < header.length) header.set(chunk.subarray(0, header.length - size), size);
387006
- size += chunk.length;
387007
- 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");
387008
387255
  }
387009
387256
  options.signal?.throwIfAborted();
387010
- return buildProbeResultFromDoc(flacDocument(header.subarray(0, Math.min(size, header.length)), size), size, options.filename ?? "input.flac", {
387011
- ...options,
387012
- formatName: "flac",
387013
- formatLongName: "raw FLAC"
387014
- });
387257
+ scanner.push(new Uint8Array(), true);
387258
+ return flacProbe(scanner, options);
387015
387259
  },
387016
387260
  id: "flac",
387017
387261
  formatName: "flac",
@@ -387036,12 +387280,9 @@ function flacAst() {
387036
387280
  return concatBytes(encodeFlacPackets(doc));
387037
387281
  },
387038
387282
  probe(bytes, options) {
387039
- const doc = this.parse(bytes, options);
387040
- return buildProbeResultFromDoc(doc, bytes.byteLength, options?.filename ?? "input.flac", {
387041
- ...options,
387042
- formatName: "flac",
387043
- formatLongName: "raw FLAC"
387044
- });
387283
+ const scanner = new FlacFrameScanner();
387284
+ scanner.push(bytes, true);
387285
+ return flacProbe(scanner, options);
387045
387286
  },
387046
387287
  concat(docs, options) {
387047
387288
  return concatMp4(docs, options);
@@ -388130,9 +388371,9 @@ async function* scanMp4CodecDescriptions(source, range, options = {}) {
388130
388371
  async function* scanMp4Packets(source, options = {}) {
388131
388372
  for await (const record of scanProbeRecords(source, options, "packets")) {
388132
388373
  if (!("sample" in record)) continue;
388133
- const { sample, track, bytePos } = record;
388374
+ const { sample, track } = record;
388134
388375
  const scale = Math.max(1, track.timescale);
388135
- 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(bytePos), flags: sample.isKeyframe ? "K_" : "__" };
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__" : "___" };
388136
388377
  }
388137
388378
  }
388138
388379
  async function* scanMp4Frames(source, options = {}) {
@@ -388156,7 +388397,7 @@ async function* scanMp4Frames(source, options = {}) {
388156
388397
  width: track.width,
388157
388398
  height: track.height,
388158
388399
  pix_fmt: track.type === "video" ? track.codec?.pixFmt ?? "yuv420p" : void 0,
388159
- pict_type: track.type === "video" ? sample.isKeyframe ? "I" : "P" : void 0,
388400
+ pict_type: void 0,
388160
388401
  sample_fmt: probeSampleFormat(track.type, track.codec?.codecName ?? (track.type === "video" ? "h264" : "aac")),
388161
388402
  nb_samples: track.type === "audio" ? sample.duration : void 0,
388162
388403
  channels: track.type === "audio" ? track.codec?.channels ?? 2 : void 0
@@ -388282,11 +388523,16 @@ async function* scanProbeRecords(source, options, mode) {
388282
388523
  }
388283
388524
  }
388284
388525
  let duration = 0, mediaEnd = 0, allPacked = true, count = 0, firstPts = 0;
388526
+ let highestPts = -Infinity, reorderSpan = 0;
388285
388527
  for await (const sample of samples()) {
388286
388528
  if (!count) firstPts = sample.pts;
388287
388529
  count++;
388288
388530
  duration += sample.duration;
388289
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
+ }
388290
388536
  if (type === "subtitle" && allPacked) {
388291
388537
  if (sample.size < 2) allPacked = false;
388292
388538
  else allPacked = new BinaryReader(await readMp4SampleRange(source, sample.offset, 2, work)).readU16BE() === sample.size - 2;
@@ -388299,18 +388545,20 @@ async function* scanProbeRecords(source, options, mode) {
388299
388545
  const version = header2.readU8();
388300
388546
  header2.skip(3);
388301
388547
  const count2 = header2.readU32BE(), width2 = version === 1 ? 20 : 12;
388302
- let total = 0, entries = 0, delay = 0, foundMedia = false;
388548
+ let total = 0, entries = 0, delay = 0, mediaStart = 0, foundMedia = false;
388303
388549
  for (let i = 0; i < count2 && 8 + i * width2 < elst.payloadSize; i++) {
388304
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) });
388305
388551
  let segment = version === 1 ? row.readU64BE() : row.readU32BE();
388306
388552
  const mediaTime = version === 1 ? row.readI64BE() : row.readI32BE();
388307
388553
  if (fragmented && segment === 0 && mediaTime >= 0) segment = Math.round(Math.max(0, mediaEnd - mediaTime) * movieTimescale / timescale);
388308
- if (mediaTime >= 0) foundMedia = true;
388309
- else if (!foundMedia) delay += segment;
388554
+ if (mediaTime >= 0 && !foundMedia) {
388555
+ mediaStart = mediaTime;
388556
+ foundMedia = true;
388557
+ } else if (!foundMedia) delay += segment;
388310
388558
  total += segment;
388311
388559
  entries++;
388312
388560
  }
388313
- 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;
388314
388562
  }
388315
388563
  const edits = consumeMp4SampleSteps(source, editDuration(), sampleOptions), result = await edits.next();
388316
388564
  if (!result.done) throw new Error("Unexpected MP4 edit sample");
@@ -388323,7 +388571,8 @@ async function* scanProbeRecords(source, options, mode) {
388323
388571
  formatStart = Math.min(formatStart, start);
388324
388572
  formatEnd = Math.max(formatEnd, start + probeDuration / Math.max(1, timescale));
388325
388573
  if (mode === "summary") continue;
388326
- let bytePos = 0, cursor = 0, previousPts = -Infinity;
388574
+ const timestampOffset = result.value ? result.value.start - result.value.mediaStart : 0;
388575
+ let cursor = 0, previousPts = -Infinity;
388327
388576
  const stats = { totalBytes: 0, count: 0, ticks: 0, firstPts: startPts, hasReorderedSamples: false };
388328
388577
  const packet = (sample) => {
388329
388578
  if (mode === "streams") {
@@ -388333,11 +388582,34 @@ async function* scanProbeRecords(source, options, mode) {
388333
388582
  stats.hasReorderedSamples ||= sample.pts < previousPts;
388334
388583
  previousPts = sample.pts;
388335
388584
  }
388336
- const record = { sample, track, bytePos };
388337
- bytePos += sample.size;
388338
- return record;
388585
+ return { sample, track };
388339
388586
  };
388340
- for await (const sample of samples()) {
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 };
388341
388613
  if (type !== "subtitle" || !count || allPacked) {
388342
388614
  const row2 = packet(sample);
388343
388615
  if (mode !== "streams") yield row2;
@@ -388345,12 +388617,12 @@ async function* scanProbeRecords(source, options, mode) {
388345
388617
  }
388346
388618
  const start2 = Math.max(cursor, Math.round(sample.pts));
388347
388619
  if (start2 > cursor) {
388348
- 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 });
388349
388621
  if (mode !== "streams") yield row2;
388350
388622
  cursor = start2;
388351
388623
  }
388352
388624
  const duration2 = Math.max(1, Math.round(sample.duration));
388353
- 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 });
388354
388626
  if (mode !== "streams") yield row;
388355
388627
  cursor += duration2;
388356
388628
  }
@@ -388403,6 +388675,7 @@ export {
388403
388675
  createSyntheticMp4,
388404
388676
  parseStreamingManifest,
388405
388677
  serializeDashDocument,
388678
+ wavPacketFrames,
388406
388679
  probeOggStreamMetadata,
388407
388680
  probeOggFlacSource,
388408
388681
  parseSubtitleDocument,