mediabunny 1.2.0 → 1.3.1

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.
Files changed (57) hide show
  1. package/dist/bundles/mediabunny.cjs +346 -130
  2. package/dist/bundles/mediabunny.min.cjs +4 -4
  3. package/dist/bundles/mediabunny.min.mjs +4 -4
  4. package/dist/bundles/mediabunny.mjs +346 -130
  5. package/dist/mediabunny.d.ts +26 -2
  6. package/dist/modules/codec-data.d.ts +9 -0
  7. package/dist/modules/codec-data.d.ts.map +1 -1
  8. package/dist/modules/codec-data.js +278 -145
  9. package/dist/modules/codec.js +2 -2
  10. package/dist/modules/conversion.js +8 -8
  11. package/dist/modules/index.js +14 -14
  12. package/dist/modules/input-format.js +11 -11
  13. package/dist/modules/input-track.d.ts +16 -3
  14. package/dist/modules/input-track.d.ts.map +1 -1
  15. package/dist/modules/input-track.js +34 -5
  16. package/dist/modules/input.js +4 -4
  17. package/dist/modules/isobmff/isobmff-boxes.js +5 -5
  18. package/dist/modules/isobmff/isobmff-demuxer.js +9 -9
  19. package/dist/modules/isobmff/isobmff-muxer.js +10 -10
  20. package/dist/modules/matroska/matroska-demuxer.js +9 -9
  21. package/dist/modules/matroska/matroska-muxer.d.ts.map +1 -1
  22. package/dist/modules/matroska/matroska-muxer.js +9 -11
  23. package/dist/modules/media-sink.d.ts +11 -0
  24. package/dist/modules/media-sink.d.ts.map +1 -1
  25. package/dist/modules/media-sink.js +70 -17
  26. package/dist/modules/media-source.js +7 -7
  27. package/dist/modules/misc.d.ts +1 -1
  28. package/dist/modules/misc.d.ts.map +1 -1
  29. package/dist/modules/misc.js +5 -2
  30. package/dist/modules/mp3/mp3-demuxer.js +6 -6
  31. package/dist/modules/mp3/mp3-muxer.js +4 -4
  32. package/dist/modules/mp3/mp3-reader.js +2 -2
  33. package/dist/modules/mp3/mp3-writer.js +1 -1
  34. package/dist/modules/muxer.js +1 -1
  35. package/dist/modules/ogg/ogg-demuxer.js +9 -9
  36. package/dist/modules/ogg/ogg-misc.js +2 -2
  37. package/dist/modules/ogg/ogg-muxer.js +6 -6
  38. package/dist/modules/ogg/ogg-reader.js +1 -1
  39. package/dist/modules/output-format.js +6 -6
  40. package/dist/modules/output.js +4 -4
  41. package/dist/modules/packet.js +1 -1
  42. package/dist/modules/reader.js +1 -1
  43. package/dist/modules/sample.js +1 -1
  44. package/dist/modules/source.d.ts.map +1 -1
  45. package/dist/modules/source.js +24 -3
  46. package/dist/modules/target.js +1 -1
  47. package/dist/modules/wave/wave-demuxer.js +6 -6
  48. package/dist/modules/wave/wave-muxer.js +5 -5
  49. package/dist/modules/writer.js +1 -1
  50. package/package.json +2 -2
  51. package/src/codec-data.ts +317 -155
  52. package/src/conversion.ts +1 -1
  53. package/src/input-track.ts +42 -3
  54. package/src/matroska/matroska-muxer.ts +1 -2
  55. package/src/media-sink.ts +88 -10
  56. package/src/misc.ts +9 -5
  57. package/src/source.ts +27 -2
@@ -159,6 +159,9 @@ var Mediabunny = (() => {
159
159
  return bit;
160
160
  }
161
161
  readBits(n) {
162
+ if (n === 1) {
163
+ return this.readBit();
164
+ }
162
165
  let result = 0;
163
166
  for (let i = 0; i < n; i++) {
164
167
  result <<= 1;
@@ -189,7 +192,7 @@ var Mediabunny = (() => {
189
192
  };
190
193
  var readExpGolomb = (bitstream) => {
191
194
  let leadingZeroBits = 0;
192
- while (bitstream.readBit() === 0 && leadingZeroBits < 32) {
195
+ while (bitstream.readBits(1) === 0 && leadingZeroBits < 32) {
193
196
  leadingZeroBits++;
194
197
  }
195
198
  if (leadingZeroBits >= 32) {
@@ -494,12 +497,12 @@ var Mediabunny = (() => {
494
497
  try {
495
498
  return await fetch(url2, requestInit);
496
499
  } catch (error) {
497
- console.error("Retrying failed fetch. Error:", error);
498
500
  attempts++;
499
501
  const retryDelayInSeconds = getRetryDelay(attempts);
500
502
  if (retryDelayInSeconds === null) {
501
503
  throw error;
502
504
  }
505
+ console.error("Retrying failed fetch. Error:", error);
503
506
  if (!Number.isFinite(retryDelayInSeconds) || retryDelayInSeconds < 0) {
504
507
  throw new TypeError("Retry delay must be a non-negative finite number.");
505
508
  }
@@ -1773,6 +1776,31 @@ var Mediabunny = (() => {
1773
1776
  }
1774
1777
  return nalUnits;
1775
1778
  };
1779
+ var findNalUnitsInLengthPrefixed = (packetData, lengthSize) => {
1780
+ const nalUnits = [];
1781
+ let offset = 0;
1782
+ const dataView = new DataView(packetData.buffer, packetData.byteOffset, packetData.byteLength);
1783
+ while (offset + lengthSize <= packetData.length) {
1784
+ let nalUnitLength;
1785
+ if (lengthSize === 1) {
1786
+ nalUnitLength = dataView.getUint8(offset);
1787
+ } else if (lengthSize === 2) {
1788
+ nalUnitLength = dataView.getUint16(offset, false);
1789
+ } else if (lengthSize === 3) {
1790
+ nalUnitLength = (dataView.getUint16(offset, false) << 8) + dataView.getUint8(offset + 2);
1791
+ } else if (lengthSize === 4) {
1792
+ nalUnitLength = dataView.getUint32(offset, false);
1793
+ } else {
1794
+ assertNever(lengthSize);
1795
+ assert(false);
1796
+ }
1797
+ offset += lengthSize;
1798
+ const nalUnit = packetData.subarray(offset, offset + nalUnitLength);
1799
+ nalUnits.push(nalUnit);
1800
+ offset += nalUnitLength;
1801
+ }
1802
+ return nalUnits;
1803
+ };
1776
1804
  var removeEmulationPreventionBytes = (data) => {
1777
1805
  const result = [];
1778
1806
  const len = data.length;
@@ -2348,22 +2376,6 @@ var Mediabunny = (() => {
2348
2376
  return new Uint8Array(bytes2);
2349
2377
  };
2350
2378
  var extractVp9CodecInfoFromPacket = (packet) => {
2351
- const lastByte = packet[packet.length - 1];
2352
- if (lastByte && (lastByte & 224) === 192) {
2353
- const bytesPerFrameSize = ((lastByte & 24) >> 3) + 1;
2354
- const numFrames = (lastByte & 7) + 1;
2355
- const indexSize = 2 + numFrames * bytesPerFrameSize;
2356
- if (packet[packet.length - indexSize] !== lastByte) {
2357
- return null;
2358
- }
2359
- let frameSize = 0;
2360
- const offset = packet.length - indexSize + 1;
2361
- for (let i = 0; i < bytesPerFrameSize; i++) {
2362
- if (!packet[offset + i]) return null;
2363
- frameSize |= packet[offset + i] << 8 * i;
2364
- }
2365
- packet = packet.subarray(0, frameSize);
2366
- }
2367
2379
  const bitstream = new Bitstream(packet);
2368
2380
  const frameMarker = bitstream.readBits(2);
2369
2381
  if (frameMarker !== 2) {
@@ -2437,13 +2449,12 @@ var Mediabunny = (() => {
2437
2449
  matrixCoefficients
2438
2450
  };
2439
2451
  };
2440
- var extractAv1CodecInfoFromPacket = (packet) => {
2452
+ function* iterateAv1PacketObus(packet) {
2441
2453
  const bitstream = new Bitstream(packet);
2442
2454
  const readLeb128 = () => {
2443
2455
  let value = 0;
2444
2456
  for (let i = 0; i < 8; i++) {
2445
2457
  const byte = bitstream.readAlignedByte();
2446
- if (byte === void 0) return 0;
2447
2458
  value |= (byte & 127) << i * 7;
2448
2459
  if (!(byte & 128)) {
2449
2460
  break;
@@ -2458,121 +2469,133 @@ var Mediabunny = (() => {
2458
2469
  return value;
2459
2470
  };
2460
2471
  while (bitstream.getBitsLeft() >= 8) {
2461
- const obuHeader = bitstream.readBits(8);
2462
- const obuType = obuHeader >> 3 & 15;
2463
- const obuExtension = obuHeader >> 2 & 1;
2464
- const obuHasSizeField = obuHeader >> 1 & 1;
2472
+ bitstream.skipBits(1);
2473
+ const obuType = bitstream.readBits(4);
2474
+ const obuExtension = bitstream.readBits(1);
2475
+ const obuHasSizeField = bitstream.readBits(1);
2476
+ bitstream.skipBits(1);
2465
2477
  if (obuExtension) {
2466
2478
  bitstream.skipBits(8);
2467
2479
  }
2468
2480
  let obuSize;
2469
2481
  if (obuHasSizeField) {
2470
2482
  const obuSizeValue = readLeb128();
2471
- if (obuSizeValue === null) return null;
2483
+ if (obuSizeValue === null) return;
2472
2484
  obuSize = obuSizeValue;
2473
2485
  } else {
2474
2486
  obuSize = Math.floor(bitstream.getBitsLeft() / 8);
2475
2487
  }
2476
- if (obuType === 1) {
2477
- const seqProfile = bitstream.readBits(3);
2478
- const stillPicture = bitstream.readBits(1);
2479
- const reducedStillPictureHeader = bitstream.readBits(1);
2480
- let seqLevel = 0;
2481
- let seqTier = 0;
2482
- let bufferDelayLengthMinus1 = 0;
2483
- if (reducedStillPictureHeader) {
2484
- seqLevel = bitstream.readBits(5);
2485
- } else {
2486
- const timingInfoPresentFlag = bitstream.readBits(1);
2487
- if (timingInfoPresentFlag) {
2488
- bitstream.skipBits(32);
2489
- bitstream.skipBits(32);
2490
- const equalPictureInterval = bitstream.readBits(1);
2491
- if (equalPictureInterval) {
2492
- return null;
2493
- }
2488
+ assert(bitstream.pos % 8 === 0);
2489
+ yield {
2490
+ type: obuType,
2491
+ data: packet.subarray(bitstream.pos / 8, bitstream.pos / 8 + obuSize)
2492
+ };
2493
+ bitstream.skipBits(obuSize * 8);
2494
+ }
2495
+ }
2496
+ var extractAv1CodecInfoFromPacket = (packet) => {
2497
+ for (const { type, data } of iterateAv1PacketObus(packet)) {
2498
+ if (type !== 1) {
2499
+ continue;
2500
+ }
2501
+ const bitstream = new Bitstream(data);
2502
+ const seqProfile = bitstream.readBits(3);
2503
+ const stillPicture = bitstream.readBits(1);
2504
+ const reducedStillPictureHeader = bitstream.readBits(1);
2505
+ let seqLevel = 0;
2506
+ let seqTier = 0;
2507
+ let bufferDelayLengthMinus1 = 0;
2508
+ if (reducedStillPictureHeader) {
2509
+ seqLevel = bitstream.readBits(5);
2510
+ } else {
2511
+ const timingInfoPresentFlag = bitstream.readBits(1);
2512
+ if (timingInfoPresentFlag) {
2513
+ bitstream.skipBits(32);
2514
+ bitstream.skipBits(32);
2515
+ const equalPictureInterval = bitstream.readBits(1);
2516
+ if (equalPictureInterval) {
2517
+ return null;
2494
2518
  }
2495
- const decoderModelInfoPresentFlag = bitstream.readBits(1);
2496
- if (decoderModelInfoPresentFlag) {
2497
- bufferDelayLengthMinus1 = bitstream.readBits(5);
2498
- bitstream.skipBits(32);
2499
- bitstream.skipBits(5);
2500
- bitstream.skipBits(5);
2519
+ }
2520
+ const decoderModelInfoPresentFlag = bitstream.readBits(1);
2521
+ if (decoderModelInfoPresentFlag) {
2522
+ bufferDelayLengthMinus1 = bitstream.readBits(5);
2523
+ bitstream.skipBits(32);
2524
+ bitstream.skipBits(5);
2525
+ bitstream.skipBits(5);
2526
+ }
2527
+ const operatingPointsCntMinus1 = bitstream.readBits(5);
2528
+ for (let i = 0; i <= operatingPointsCntMinus1; i++) {
2529
+ bitstream.skipBits(12);
2530
+ const seqLevelIdx = bitstream.readBits(5);
2531
+ if (i === 0) {
2532
+ seqLevel = seqLevelIdx;
2501
2533
  }
2502
- const operatingPointsCntMinus1 = bitstream.readBits(5);
2503
- for (let i = 0; i <= operatingPointsCntMinus1; i++) {
2504
- bitstream.skipBits(12);
2505
- const seqLevelIdx = bitstream.readBits(5);
2534
+ if (seqLevelIdx > 7) {
2535
+ const seqTierTemp = bitstream.readBits(1);
2506
2536
  if (i === 0) {
2507
- seqLevel = seqLevelIdx;
2508
- }
2509
- if (seqLevelIdx > 7) {
2510
- const seqTierTemp = bitstream.readBits(1);
2511
- if (i === 0) {
2512
- seqTier = seqTierTemp;
2513
- }
2514
- }
2515
- if (decoderModelInfoPresentFlag) {
2516
- const decoderModelPresentForThisOp = bitstream.readBits(1);
2517
- if (decoderModelPresentForThisOp) {
2518
- const n = bufferDelayLengthMinus1 + 1;
2519
- bitstream.skipBits(n);
2520
- bitstream.skipBits(n);
2521
- bitstream.skipBits(1);
2522
- }
2537
+ seqTier = seqTierTemp;
2523
2538
  }
2524
- const initialDisplayDelayPresentFlag = bitstream.readBits(1);
2525
- if (initialDisplayDelayPresentFlag) {
2526
- bitstream.skipBits(4);
2539
+ }
2540
+ if (decoderModelInfoPresentFlag) {
2541
+ const decoderModelPresentForThisOp = bitstream.readBits(1);
2542
+ if (decoderModelPresentForThisOp) {
2543
+ const n = bufferDelayLengthMinus1 + 1;
2544
+ bitstream.skipBits(n);
2545
+ bitstream.skipBits(n);
2546
+ bitstream.skipBits(1);
2527
2547
  }
2528
2548
  }
2549
+ const initialDisplayDelayPresentFlag = bitstream.readBits(1);
2550
+ if (initialDisplayDelayPresentFlag) {
2551
+ bitstream.skipBits(4);
2552
+ }
2529
2553
  }
2530
- const highBitdepth = bitstream.readBits(1);
2531
- let bitDepth = 8;
2532
- if (seqProfile === 2 && highBitdepth) {
2533
- const twelveBit = bitstream.readBits(1);
2534
- bitDepth = twelveBit ? 12 : 10;
2535
- } else if (seqProfile <= 2) {
2536
- bitDepth = highBitdepth ? 10 : 8;
2537
- }
2538
- let monochrome = 0;
2539
- if (seqProfile !== 1) {
2540
- monochrome = bitstream.readBits(1);
2541
- }
2542
- let chromaSubsamplingX = 1;
2543
- let chromaSubsamplingY = 1;
2544
- let chromaSamplePosition = 0;
2545
- if (!monochrome) {
2546
- if (seqProfile === 0) {
2547
- chromaSubsamplingX = 1;
2548
- chromaSubsamplingY = 1;
2549
- } else if (seqProfile === 1) {
2550
- chromaSubsamplingX = 0;
2551
- chromaSubsamplingY = 0;
2552
- } else {
2553
- if (bitDepth === 12) {
2554
- chromaSubsamplingX = bitstream.readBits(1);
2555
- if (chromaSubsamplingX) {
2556
- chromaSubsamplingY = bitstream.readBits(1);
2557
- }
2554
+ }
2555
+ const highBitdepth = bitstream.readBits(1);
2556
+ let bitDepth = 8;
2557
+ if (seqProfile === 2 && highBitdepth) {
2558
+ const twelveBit = bitstream.readBits(1);
2559
+ bitDepth = twelveBit ? 12 : 10;
2560
+ } else if (seqProfile <= 2) {
2561
+ bitDepth = highBitdepth ? 10 : 8;
2562
+ }
2563
+ let monochrome = 0;
2564
+ if (seqProfile !== 1) {
2565
+ monochrome = bitstream.readBits(1);
2566
+ }
2567
+ let chromaSubsamplingX = 1;
2568
+ let chromaSubsamplingY = 1;
2569
+ let chromaSamplePosition = 0;
2570
+ if (!monochrome) {
2571
+ if (seqProfile === 0) {
2572
+ chromaSubsamplingX = 1;
2573
+ chromaSubsamplingY = 1;
2574
+ } else if (seqProfile === 1) {
2575
+ chromaSubsamplingX = 0;
2576
+ chromaSubsamplingY = 0;
2577
+ } else {
2578
+ if (bitDepth === 12) {
2579
+ chromaSubsamplingX = bitstream.readBits(1);
2580
+ if (chromaSubsamplingX) {
2581
+ chromaSubsamplingY = bitstream.readBits(1);
2558
2582
  }
2559
2583
  }
2560
- if (chromaSubsamplingX && chromaSubsamplingY) {
2561
- chromaSamplePosition = bitstream.readBits(2);
2562
- }
2563
2584
  }
2564
- return {
2565
- profile: seqProfile,
2566
- level: seqLevel,
2567
- tier: seqTier,
2568
- bitDepth,
2569
- monochrome,
2570
- chromaSubsamplingX,
2571
- chromaSubsamplingY,
2572
- chromaSamplePosition
2573
- };
2585
+ if (chromaSubsamplingX && chromaSubsamplingY) {
2586
+ chromaSamplePosition = bitstream.readBits(2);
2587
+ }
2574
2588
  }
2575
- bitstream.skipBits(obuSize * 8);
2589
+ return {
2590
+ profile: seqProfile,
2591
+ level: seqLevel,
2592
+ tier: seqTier,
2593
+ bitDepth,
2594
+ monochrome,
2595
+ chromaSubsamplingX,
2596
+ chromaSubsamplingY,
2597
+ chromaSamplePosition
2598
+ };
2576
2599
  }
2577
2600
  return null;
2578
2601
  };
@@ -2703,6 +2726,105 @@ var Mediabunny = (() => {
2703
2726
  }
2704
2727
  return { modeBlockflags };
2705
2728
  };
2729
+ var determineVideoPacketType = async (videoTrack, packet) => {
2730
+ assert(videoTrack.codec);
2731
+ switch (videoTrack.codec) {
2732
+ case "avc":
2733
+ {
2734
+ const decoderConfig = await videoTrack.getDecoderConfig();
2735
+ assert(decoderConfig);
2736
+ let nalUnits;
2737
+ if (decoderConfig.description) {
2738
+ const bytes2 = toUint8Array(decoderConfig.description);
2739
+ const lengthSizeMinusOne = bytes2[4] & 3;
2740
+ const lengthSize = lengthSizeMinusOne + 1;
2741
+ nalUnits = findNalUnitsInLengthPrefixed(packet.data, lengthSize);
2742
+ } else {
2743
+ nalUnits = findNalUnitsInAnnexB(packet.data);
2744
+ }
2745
+ const isKeyframe = nalUnits.some((x) => extractNalUnitTypeForAvc(x) === 5);
2746
+ return isKeyframe ? "key" : "delta";
2747
+ }
2748
+ ;
2749
+ case "hevc":
2750
+ {
2751
+ const decoderConfig = await videoTrack.getDecoderConfig();
2752
+ assert(decoderConfig);
2753
+ let nalUnits;
2754
+ if (decoderConfig.description) {
2755
+ const bytes2 = toUint8Array(decoderConfig.description);
2756
+ const lengthSizeMinusOne = bytes2[21] & 3;
2757
+ const lengthSize = lengthSizeMinusOne + 1;
2758
+ nalUnits = findNalUnitsInLengthPrefixed(packet.data, lengthSize);
2759
+ } else {
2760
+ nalUnits = findNalUnitsInAnnexB(packet.data);
2761
+ }
2762
+ const isKeyframe = nalUnits.some((x) => {
2763
+ const type = extractNalUnitTypeForHevc(x);
2764
+ return 16 <= type && type <= 23;
2765
+ });
2766
+ return isKeyframe ? "key" : "delta";
2767
+ }
2768
+ ;
2769
+ case "vp8":
2770
+ {
2771
+ const frameType = packet.data[0] & 1;
2772
+ return frameType === 0 ? "key" : "delta";
2773
+ }
2774
+ ;
2775
+ case "vp9":
2776
+ {
2777
+ const bitstream = new Bitstream(packet.data);
2778
+ if (bitstream.readBits(2) !== 2) {
2779
+ return null;
2780
+ }
2781
+ ;
2782
+ const profileLowBit = bitstream.readBits(1);
2783
+ const profileHighBit = bitstream.readBits(1);
2784
+ const profile = (profileHighBit << 1) + profileLowBit;
2785
+ if (profile === 3) {
2786
+ bitstream.skipBits(1);
2787
+ }
2788
+ const showExistingFrame = bitstream.readBits(1);
2789
+ if (showExistingFrame) {
2790
+ return null;
2791
+ }
2792
+ const frameType = bitstream.readBits(1);
2793
+ return frameType === 0 ? "key" : "delta";
2794
+ }
2795
+ ;
2796
+ case "av1":
2797
+ {
2798
+ let reducedStillPictureHeader = false;
2799
+ for (const { type, data } of iterateAv1PacketObus(packet.data)) {
2800
+ if (type === 1) {
2801
+ const bitstream = new Bitstream(data);
2802
+ bitstream.skipBits(4);
2803
+ reducedStillPictureHeader = !!bitstream.readBits(1);
2804
+ } else if (type === 3 || type === 6 || type === 7) {
2805
+ if (reducedStillPictureHeader) {
2806
+ return "key";
2807
+ }
2808
+ const bitstream = new Bitstream(data);
2809
+ const showExistingFrame = bitstream.readBits(1);
2810
+ if (showExistingFrame) {
2811
+ return null;
2812
+ }
2813
+ const frameType = bitstream.readBits(2);
2814
+ return frameType === 0 ? "key" : "delta";
2815
+ }
2816
+ }
2817
+ return null;
2818
+ }
2819
+ ;
2820
+ default:
2821
+ {
2822
+ assertNever(videoTrack.codec);
2823
+ assert(false);
2824
+ }
2825
+ ;
2826
+ }
2827
+ };
2706
2828
 
2707
2829
  // src/isobmff/isobmff-boxes.ts
2708
2830
  var IsobmffBoxWriter = class {
@@ -5970,7 +6092,7 @@ ${cue.notes ?? ""}`;
5970
6092
  if (chunk.type !== "key") return;
5971
6093
  if (!trackData.info.decoderConfig.colorSpace || !trackData.info.decoderConfig.colorSpace.matrix) return;
5972
6094
  const bitstream = new Bitstream(chunk.data);
5973
- if (bitstream.readBits(2) !== 2) return;
6095
+ bitstream.skipBits(2);
5974
6096
  const profileLowBit = bitstream.readBits(1);
5975
6097
  const profileHighBit = bitstream.readBits(1);
5976
6098
  const profile = (profileHighBit << 1) + profileLowBit;
@@ -7933,12 +8055,34 @@ ${cue.notes ?? ""}`;
7933
8055
  if (options.metadataOnly !== void 0 && typeof options.metadataOnly !== "boolean") {
7934
8056
  throw new TypeError("options.metadataOnly, when defined, must be a boolean.");
7935
8057
  }
8058
+ if (options.verifyKeyPackets !== void 0 && typeof options.verifyKeyPackets !== "boolean") {
8059
+ throw new TypeError("options.verifyKeyPackets, when defined, must be a boolean.");
8060
+ }
8061
+ if (options.verifyKeyPackets && options.metadataOnly) {
8062
+ throw new TypeError("options.verifyKeyPackets and options.metadataOnly cannot be enabled together.");
8063
+ }
7936
8064
  };
7937
8065
  var validateTimestamp = (timestamp) => {
7938
8066
  if (typeof timestamp !== "number" || Number.isNaN(timestamp)) {
7939
8067
  throw new TypeError("timestamp must be a number.");
7940
8068
  }
7941
8069
  };
8070
+ var maybeFixPacketType = (track, promise, options) => {
8071
+ if (options.verifyKeyPackets) {
8072
+ return promise.then(async (packet) => {
8073
+ if (!packet || packet.type === "delta") {
8074
+ return packet;
8075
+ }
8076
+ const determinedType = await track.determinePacketType(packet);
8077
+ if (determinedType) {
8078
+ packet.type = determinedType;
8079
+ }
8080
+ return packet;
8081
+ });
8082
+ } else {
8083
+ return promise;
8084
+ }
8085
+ };
7942
8086
  var EncodedPacketSink = class {
7943
8087
  constructor(track) {
7944
8088
  if (!(track instanceof InputTrack)) {
@@ -7952,7 +8096,7 @@ ${cue.notes ?? ""}`;
7952
8096
  */
7953
8097
  getFirstPacket(options = {}) {
7954
8098
  validatePacketRetrievalOptions(options);
7955
- return this._track._backing.getFirstPacket(options);
8099
+ return maybeFixPacketType(this._track, this._track._backing.getFirstPacket(options), options);
7956
8100
  }
7957
8101
  /**
7958
8102
  * Retrieves the packet corresponding to the given timestamp, in seconds. More specifically, returns the last packet
@@ -7965,7 +8109,7 @@ ${cue.notes ?? ""}`;
7965
8109
  getPacket(timestamp, options = {}) {
7966
8110
  validateTimestamp(timestamp);
7967
8111
  validatePacketRetrievalOptions(options);
7968
- return this._track._backing.getPacket(timestamp, options);
8112
+ return maybeFixPacketType(this._track, this._track._backing.getPacket(timestamp, options), options);
7969
8113
  }
7970
8114
  /**
7971
8115
  * Retrieves the packet following the given packet (in decode order), or null if the given packet is the
@@ -7976,7 +8120,7 @@ ${cue.notes ?? ""}`;
7976
8120
  throw new TypeError("packet must be an EncodedPacket.");
7977
8121
  }
7978
8122
  validatePacketRetrievalOptions(options);
7979
- return this._track._backing.getNextPacket(packet, options);
8123
+ return maybeFixPacketType(this._track, this._track._backing.getNextPacket(packet, options), options);
7980
8124
  }
7981
8125
  /**
7982
8126
  * Retrieves the key packet corresponding to the given timestamp, in seconds. More specifically, returns the last
@@ -7985,23 +8129,49 @@ ${cue.notes ?? ""}`;
7985
8129
  * last key packet using `getKeyPacket(Infinity)`. The method returns null if the timestamp is before the first
7986
8130
  * key packet in the track.
7987
8131
  *
8132
+ * To ensure that the returned packet is guaranteed to be a real key frame, enable `options.verifyKeyPackets`.
8133
+ *
7988
8134
  * @param timestamp - The timestamp used for retrieval, in seconds.
7989
8135
  */
7990
- getKeyPacket(timestamp, options = {}) {
8136
+ async getKeyPacket(timestamp, options = {}) {
7991
8137
  validateTimestamp(timestamp);
7992
8138
  validatePacketRetrievalOptions(options);
7993
- return this._track._backing.getKeyPacket(timestamp, options);
8139
+ if (!options.verifyKeyPackets) {
8140
+ return this._track._backing.getKeyPacket(timestamp, options);
8141
+ }
8142
+ const packet = await this._track._backing.getKeyPacket(timestamp, options);
8143
+ if (!packet || packet.type === "delta") {
8144
+ return packet;
8145
+ }
8146
+ const determinedType = await this._track.determinePacketType(packet);
8147
+ if (determinedType === "delta") {
8148
+ return this.getKeyPacket(packet.timestamp - 1 / this._track.timeResolution, options);
8149
+ }
8150
+ return packet;
7994
8151
  }
7995
8152
  /**
7996
8153
  * Retrieves the key packet following the given packet (in decode order), or null if the given packet is the last
7997
8154
  * key packet.
8155
+ *
8156
+ * To ensure that the returned packet is guaranteed to be a real key frame, enable `options.verifyKeyPackets`.
7998
8157
  */
7999
- getNextKeyPacket(packet, options = {}) {
8158
+ async getNextKeyPacket(packet, options = {}) {
8000
8159
  if (!(packet instanceof EncodedPacket)) {
8001
8160
  throw new TypeError("packet must be an EncodedPacket.");
8002
8161
  }
8003
8162
  validatePacketRetrievalOptions(options);
8004
- return this._track._backing.getNextKeyPacket(packet, options);
8163
+ if (!options.verifyKeyPackets) {
8164
+ return this._track._backing.getNextKeyPacket(packet, options);
8165
+ }
8166
+ const nextPacket = await this._track._backing.getNextKeyPacket(packet, options);
8167
+ if (!nextPacket || nextPacket.type === "delta") {
8168
+ return nextPacket;
8169
+ }
8170
+ const determinedType = await this._track.determinePacketType(nextPacket);
8171
+ if (determinedType === "delta") {
8172
+ return this.getNextKeyPacket(nextPacket, options);
8173
+ }
8174
+ return nextPacket;
8005
8175
  }
8006
8176
  /**
8007
8177
  * Creates an async iterator that yields the packets in this track in decode order. To enable fast iteration, this
@@ -8147,7 +8317,7 @@ ${cue.notes ?? ""}`;
8147
8317
  }
8148
8318
  });
8149
8319
  const packetSink = this._createPacketSink();
8150
- const keyPacket = await packetSink.getKeyPacket(startTimestamp) ?? await packetSink.getFirstPacket();
8320
+ const keyPacket = await packetSink.getKeyPacket(startTimestamp, { verifyKeyPackets: true }) ?? await packetSink.getFirstPacket();
8151
8321
  if (!keyPacket) {
8152
8322
  return;
8153
8323
  }
@@ -8155,7 +8325,7 @@ ${cue.notes ?? ""}`;
8155
8325
  let endPacket = void 0;
8156
8326
  if (endTimestamp < Infinity) {
8157
8327
  const packet = await packetSink.getPacket(endTimestamp);
8158
- const keyPacket2 = !packet ? null : packet.type === "key" && packet.timestamp === endTimestamp ? packet : await packetSink.getNextKeyPacket(packet);
8328
+ const keyPacket2 = !packet ? null : packet.type === "key" && packet.timestamp === endTimestamp ? packet : await packetSink.getNextKeyPacket(packet, { verifyKeyPackets: true });
8159
8329
  if (keyPacket2) {
8160
8330
  endPacket = keyPacket2;
8161
8331
  }
@@ -8307,7 +8477,7 @@ ${cue.notes ?? ""}`;
8307
8477
  break;
8308
8478
  }
8309
8479
  const targetPacket = await packetSink.getPacket(timestamp);
8310
- const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp);
8480
+ const keyPacket = targetPacket && await packetSink.getKeyPacket(timestamp, { verifyKeyPackets: true });
8311
8481
  if (!keyPacket) {
8312
8482
  if (maxSequenceNumber !== -1) {
8313
8483
  await decodePackets();
@@ -9158,7 +9328,10 @@ ${cue.notes ?? ""}`;
9158
9328
  const colorSpace = await this._backing.getColorSpace();
9159
9329
  return colorSpace.primaries === "bt2020" || colorSpace.primaries === "smpte432" || colorSpace.transfer === "pg" || colorSpace.transfer === "hlg" || colorSpace.matrix === "bt2020-ncl";
9160
9330
  }
9161
- /** Returns the decoder configuration for decoding the track's packets using a VideoDecoder. */
9331
+ /**
9332
+ * Returns the decoder configuration for decoding the track's packets using a VideoDecoder. Returns null if the
9333
+ * track's codec is unknown.
9334
+ */
9162
9335
  getDecoderConfig() {
9163
9336
  return this._backing.getDecoderConfig();
9164
9337
  }
@@ -9187,6 +9360,18 @@ ${cue.notes ?? ""}`;
9187
9360
  return false;
9188
9361
  }
9189
9362
  }
9363
+ async determinePacketType(packet) {
9364
+ if (!(packet instanceof EncodedPacket)) {
9365
+ throw new TypeError("packet must be an EncodedPacket.");
9366
+ }
9367
+ if (packet.isMetadataOnly) {
9368
+ throw new TypeError("packet must not be metadata-only to determine its type.");
9369
+ }
9370
+ if (this.codec === null) {
9371
+ return null;
9372
+ }
9373
+ return determineVideoPacketType(this, packet);
9374
+ }
9190
9375
  };
9191
9376
  var InputAudioTrack = class extends InputTrack {
9192
9377
  /** @internal */
@@ -9208,7 +9393,10 @@ ${cue.notes ?? ""}`;
9208
9393
  get sampleRate() {
9209
9394
  return this._backing.getSampleRate();
9210
9395
  }
9211
- /** Returns the decoder configuration for decoding the track's packets using an AudioDecoder. */
9396
+ /**
9397
+ * Returns the decoder configuration for decoding the track's packets using an AudioDecoder. Returns null if the
9398
+ * track's codec is unknown.
9399
+ */
9212
9400
  getDecoderConfig() {
9213
9401
  return this._backing.getDecoderConfig();
9214
9402
  }
@@ -9241,6 +9429,15 @@ ${cue.notes ?? ""}`;
9241
9429
  return false;
9242
9430
  }
9243
9431
  }
9432
+ async determinePacketType(packet) {
9433
+ if (!(packet instanceof EncodedPacket)) {
9434
+ throw new TypeError("packet must be an EncodedPacket.");
9435
+ }
9436
+ if (this.codec === null) {
9437
+ return null;
9438
+ }
9439
+ return "key";
9440
+ }
9244
9441
  };
9245
9442
 
9246
9443
  // src/reader.ts
@@ -11498,7 +11695,7 @@ ${cue.notes ?? ""}`;
11498
11695
  throw new Error(`Error fetching ${this._url}: ${response.status} ${response.statusText}`);
11499
11696
  }
11500
11697
  const buffer = await response.arrayBuffer();
11501
- if (!range) {
11698
+ if (response.status === 200) {
11502
11699
  this._fullData = buffer;
11503
11700
  }
11504
11701
  return {
@@ -11523,6 +11720,22 @@ ${cue.notes ?? ""}`;
11523
11720
  if (this._fullData) {
11524
11721
  return this._fullData.byteLength;
11525
11722
  }
11723
+ try {
11724
+ const headResponse = await retriedFetch(
11725
+ this._url,
11726
+ mergeObjectsDeeply(this._options.requestInit ?? {}, {
11727
+ method: "HEAD"
11728
+ }),
11729
+ this._options.getRetryDelay ?? (() => null)
11730
+ );
11731
+ if (headResponse.ok) {
11732
+ const contentLength = headResponse.headers.get("Content-Length");
11733
+ if (contentLength) {
11734
+ return parseInt(contentLength);
11735
+ }
11736
+ }
11737
+ } catch {
11738
+ }
11526
11739
  const rangeResponse = await retriedFetch(
11527
11740
  this._url,
11528
11741
  mergeObjectsDeeply(this._options.requestInit ?? {}, {
@@ -11536,9 +11749,12 @@ ${cue.notes ?? ""}`;
11536
11749
  if (contentRange) {
11537
11750
  const match = contentRange.match(/bytes \d+-\d+\/(\d+)/);
11538
11751
  if (match && match[1]) {
11539
- return parseInt(match[1], 10);
11752
+ return parseInt(match[1]);
11540
11753
  }
11541
11754
  }
11755
+ } else if (rangeResponse.status === 200) {
11756
+ this._fullData = await rangeResponse.arrayBuffer();
11757
+ return this._fullData.byteLength;
11542
11758
  }
11543
11759
  const { response } = await this._makeRequest();
11544
11760
  return response.byteLength;
@@ -16448,7 +16664,7 @@ ${cue.notes ?? ""}`;
16448
16664
  const decoderConfig = await track.getDecoderConfig();
16449
16665
  const meta = { decoderConfig: decoderConfig ?? void 0 };
16450
16666
  const endPacket = Number.isFinite(this._endTimestamp) ? await sink.getPacket(this._endTimestamp, { metadataOnly: true }) ?? void 0 : void 0;
16451
- for await (const packet of sink.packets(void 0, endPacket)) {
16667
+ for await (const packet of sink.packets(void 0, endPacket, { verifyKeyPackets: true })) {
16452
16668
  if (this._synchronizer.shouldWait(track.id, packet.timestamp)) {
16453
16669
  await this._synchronizer.wait(packet.timestamp);
16454
16670
  }