@remotion/media-parser 4.0.241 → 4.0.242

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 (106) hide show
  1. package/dist/add-avc-profile-to-track.js +2 -2
  2. package/dist/boxes/avc/codec-private.js +2 -2
  3. package/dist/boxes/avc/create-sps-pps-data.d.ts +2 -0
  4. package/dist/boxes/avc/create-sps-pps-data.js +28 -0
  5. package/dist/boxes/iso-base-media/get-keyframes.d.ts +3 -0
  6. package/dist/boxes/iso-base-media/get-keyframes.js +30 -0
  7. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +3 -3
  8. package/dist/boxes/iso-base-media/mdat/mdat.js +9 -5
  9. package/dist/boxes/iso-base-media/moov/moov.d.ts +3 -3
  10. package/dist/boxes/iso-base-media/moov/moov.js +5 -4
  11. package/dist/boxes/iso-base-media/process-box.d.ts +9 -9
  12. package/dist/boxes/iso-base-media/process-box.js +48 -56
  13. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +3 -3
  14. package/dist/boxes/iso-base-media/stsd/mebx.js +5 -4
  15. package/dist/boxes/iso-base-media/stsd/samples.d.ts +5 -5
  16. package/dist/boxes/iso-base-media/stsd/samples.js +19 -16
  17. package/dist/boxes/iso-base-media/stsd/stsd.d.ts +3 -3
  18. package/dist/boxes/iso-base-media/stsd/stsd.js +2 -2
  19. package/dist/boxes/iso-base-media/trak/trak.d.ts +3 -3
  20. package/dist/boxes/iso-base-media/trak/trak.js +7 -6
  21. package/dist/boxes/riff/expect-riff-box.d.ts +3 -3
  22. package/dist/boxes/riff/expect-riff-box.js +5 -5
  23. package/dist/boxes/riff/get-tracks-from-avi.js +1 -1
  24. package/dist/boxes/riff/parse-box.d.ts +7 -7
  25. package/dist/boxes/riff/parse-box.js +29 -24
  26. package/dist/boxes/riff/parse-list-box.d.ts +3 -3
  27. package/dist/boxes/riff/parse-list-box.js +2 -2
  28. package/dist/boxes/riff/parse-movi.d.ts +5 -5
  29. package/dist/boxes/riff/parse-movi.js +35 -20
  30. package/dist/boxes/riff/parse-riff-box.d.ts +3 -3
  31. package/dist/boxes/riff/parse-riff-box.js +2 -2
  32. package/dist/boxes/transport-stream/get-tracks.js +1 -1
  33. package/dist/boxes/transport-stream/handle-aac-packet.d.ts +4 -3
  34. package/dist/boxes/transport-stream/handle-aac-packet.js +6 -4
  35. package/dist/boxes/transport-stream/handle-avc-packet.d.ts +4 -3
  36. package/dist/boxes/transport-stream/handle-avc-packet.js +8 -6
  37. package/dist/boxes/transport-stream/parse-packet.d.ts +3 -3
  38. package/dist/boxes/transport-stream/parse-packet.js +2 -2
  39. package/dist/boxes/transport-stream/parse-stream-packet.d.ts +3 -3
  40. package/dist/boxes/transport-stream/parse-stream-packet.js +14 -7
  41. package/dist/boxes/transport-stream/parse-transport-stream.d.ts +5 -6
  42. package/dist/boxes/transport-stream/parse-transport-stream.js +10 -9
  43. package/dist/boxes/transport-stream/process-stream-buffers.d.ts +6 -5
  44. package/dist/boxes/transport-stream/process-stream-buffers.js +18 -8
  45. package/dist/boxes/webm/ebml.d.ts +1 -1
  46. package/dist/boxes/webm/get-sample-from-block.d.ts +2 -2
  47. package/dist/boxes/webm/get-sample-from-block.js +8 -4
  48. package/dist/boxes/webm/parse-ebml.d.ts +4 -4
  49. package/dist/boxes/webm/parse-ebml.js +18 -18
  50. package/dist/boxes/webm/parse-webm-header.d.ts +5 -5
  51. package/dist/boxes/webm/parse-webm-header.js +6 -5
  52. package/dist/boxes/webm/segments/parse-children.d.ts +5 -5
  53. package/dist/boxes/webm/segments/parse-children.js +12 -13
  54. package/dist/boxes/webm/segments.d.ts +3 -3
  55. package/dist/boxes/webm/segments.js +13 -13
  56. package/dist/convert-audio-or-video-sample.js +2 -0
  57. package/dist/emit-available-info.d.ts +4 -5
  58. package/dist/emit-available-info.js +171 -57
  59. package/dist/esm/index.mjs +881 -490
  60. package/dist/get-duration.d.ts +1 -0
  61. package/dist/get-duration.js +14 -1
  62. package/dist/get-fields-from-callbacks.js +5 -0
  63. package/dist/get-fps.d.ts +1 -0
  64. package/dist/get-fps.js +17 -12
  65. package/dist/get-keyframes.d.ts +5 -0
  66. package/dist/get-keyframes.js +20 -0
  67. package/dist/get-tracks.d.ts +7 -1
  68. package/dist/get-tracks.js +15 -10
  69. package/dist/has-all-info.d.ts +2 -5
  70. package/dist/has-all-info.js +23 -4
  71. package/dist/index.d.ts +2 -1
  72. package/dist/may-skip-video-data/may-skip-video-data.d.ts +4 -0
  73. package/dist/may-skip-video-data/may-skip-video-data.js +14 -0
  74. package/dist/may-skip-video-data/need-samples-for-fields.d.ts +5 -0
  75. package/dist/may-skip-video-data/need-samples-for-fields.js +33 -0
  76. package/dist/options.d.ts +32 -0
  77. package/dist/parse-media.js +12 -40
  78. package/dist/parse-result.d.ts +2 -4
  79. package/dist/parse-video.d.ts +5 -5
  80. package/dist/parse-video.js +24 -10
  81. package/dist/register-track.d.ts +5 -5
  82. package/dist/register-track.js +12 -12
  83. package/dist/state/can-skip-tracks.js +5 -0
  84. package/dist/state/emitted-fields.d.ts +2 -0
  85. package/dist/state/emitted-fields.js +31 -0
  86. package/dist/state/has-tracks-section.d.ts +1 -0
  87. package/dist/state/keyframes.d.ts +6 -0
  88. package/dist/state/keyframes.js +15 -0
  89. package/dist/state/parser-state.d.ts +60 -29
  90. package/dist/state/parser-state.js +32 -150
  91. package/dist/state/riff.d.ts +10 -0
  92. package/dist/state/riff.js +32 -0
  93. package/dist/state/sample-callbacks.d.ts +31 -0
  94. package/dist/state/sample-callbacks.js +96 -0
  95. package/dist/state/slow-duration-fps.d.ts +8 -0
  96. package/dist/state/slow-duration-fps.js +36 -0
  97. package/dist/state/structure.d.ts +7 -0
  98. package/dist/state/structure.js +21 -0
  99. package/dist/state/tracks-and-samples.d.ts +0 -0
  100. package/dist/state/tracks-and-samples.js +1 -0
  101. package/dist/state/webm.d.ts +11 -0
  102. package/dist/state/webm.js +67 -0
  103. package/dist/version.d.ts +1 -1
  104. package/dist/version.js +1 -1
  105. package/dist/webcodec-sample-types.d.ts +2 -0
  106. package/package.json +3 -3
@@ -1367,7 +1367,7 @@ var createIsoBaseMediaFtyp = ({
1367
1367
  };
1368
1368
 
1369
1369
  // src/version.ts
1370
- var VERSION = "4.0.241";
1370
+ var VERSION = "4.0.242";
1371
1371
 
1372
1372
  // src/create/iso-base-media/create-ilst.ts
1373
1373
  var createIlst = (items) => {
@@ -4127,19 +4127,22 @@ var getFps = (segments) => {
4127
4127
  }
4128
4128
  throw new Error("Cannot get fps, not implemented");
4129
4129
  };
4130
- var hasFps = (boxes) => {
4130
+ var hasFpsSuitedForSlowFps = (boxes) => {
4131
4131
  try {
4132
- if (boxes.type === "matroska") {
4133
- return true;
4134
- }
4135
- if (boxes.type === "transport-stream") {
4136
- return true;
4137
- }
4138
4132
  return getFps(boxes) !== null;
4139
4133
  } catch {
4140
4134
  return false;
4141
4135
  }
4142
4136
  };
4137
+ var hasFps = (boxes) => {
4138
+ if (boxes.type === "matroska") {
4139
+ return true;
4140
+ }
4141
+ if (boxes.type === "transport-stream") {
4142
+ return true;
4143
+ }
4144
+ return hasFpsSuitedForSlowFps(boxes);
4145
+ };
4143
4146
 
4144
4147
  // src/get-audio-codec.ts
4145
4148
  var getAudioCodec = (boxes, parserState) => {
@@ -5454,14 +5457,19 @@ var makeBaseMediaTrack = (trakBox) => {
5454
5457
  return track;
5455
5458
  };
5456
5459
 
5457
- // src/boxes/avc/codec-private.ts
5458
- var getAvccBoxContent = (avc1Profile) => {
5460
+ // src/boxes/avc/codec-string.ts
5461
+ var getCodecStringFromSpsAndPps = (sps) => {
5462
+ return `avc1.${sps.spsData.profile.toString(16).padStart(2, "0")}${sps.spsData.compatibility.toString(16).padStart(2, "0")}${sps.spsData.level.toString(16).padStart(2, "0")}`;
5463
+ };
5464
+
5465
+ // src/boxes/avc/create-sps-pps-data.ts
5466
+ var createSpsPpsData = (avc1Profile) => {
5459
5467
  return combineUint8Arrays([
5460
5468
  new Uint8Array([
5461
5469
  1,
5462
- avc1Profile.sps.spsData.level,
5463
- avc1Profile.sps.spsData.compatibility,
5464
5470
  avc1Profile.sps.spsData.profile,
5471
+ avc1Profile.sps.spsData.compatibility,
5472
+ avc1Profile.sps.spsData.level,
5465
5473
  255,
5466
5474
  225
5467
5475
  ]),
@@ -5473,11 +5481,6 @@ var getAvccBoxContent = (avc1Profile) => {
5473
5481
  ]);
5474
5482
  };
5475
5483
 
5476
- // src/boxes/avc/codec-string.ts
5477
- var getCodecStringFromSpsAndPps = (sps) => {
5478
- return `avc1.${sps.spsData.profile.toString(16).padStart(2, "0")}${sps.spsData.compatibility.toString(16).padStart(2, "0")}${sps.spsData.level.toString(16).padStart(2, "0")}`;
5479
- };
5480
-
5481
5484
  // src/add-avc-profile-to-track.ts
5482
5485
  var addAvcProfileToTrack = (track, avc1Profile) => {
5483
5486
  if (avc1Profile === null) {
@@ -5486,7 +5489,7 @@ var addAvcProfileToTrack = (track, avc1Profile) => {
5486
5489
  return {
5487
5490
  ...track,
5488
5491
  codec: getCodecStringFromSpsAndPps(avc1Profile.sps),
5489
- codecPrivate: getAvccBoxContent(avc1Profile)
5492
+ codecPrivate: createSpsPpsData(avc1Profile)
5490
5493
  };
5491
5494
  };
5492
5495
 
@@ -5575,7 +5578,7 @@ var getTracksFromAvi = (structure, state) => {
5575
5578
  continue;
5576
5579
  }
5577
5580
  if (strf.type === "strf-box-video") {
5578
- videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.getAvcProfile()));
5581
+ videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.riff.getAvcProfile()));
5579
5582
  } else if (strh.fccType === "auds") {
5580
5583
  audioTracks.push(makeAviAudioTrack({ strf, index: i }));
5581
5584
  } else {
@@ -5627,7 +5630,7 @@ var getStreamForId = (structure, packetIdentifier) => {
5627
5630
  // src/boxes/transport-stream/get-tracks.ts
5628
5631
  var getTracksFromTransportStream = (structure, parserState) => {
5629
5632
  const programMapTable = findProgramMapTableOrThrow(structure);
5630
- const parserTracks = parserState.tracks.getTracks();
5633
+ const parserTracks = parserState.callbacks.tracks.getTracks();
5631
5634
  const mapped = programMapTable.streams.map((stream) => {
5632
5635
  return parserTracks.find((track) => track.trackId === stream.pid);
5633
5636
  }).filter(truthy);
@@ -6029,6 +6032,15 @@ var getNumberOfTracks2 = (moovBox) => {
6029
6032
  }
6030
6033
  return mvHdBox.nextTrackId - 1;
6031
6034
  };
6035
+ var isoBaseMediaHasTracks = (structure) => {
6036
+ const moovBox = getMoovBox(structure.boxes);
6037
+ if (!moovBox) {
6038
+ return false;
6039
+ }
6040
+ const numberOfTracks = getNumberOfTracks2(moovBox);
6041
+ const tracks2 = getTraks(moovBox);
6042
+ return tracks2.length === numberOfTracks;
6043
+ };
6032
6044
  var hasTracks = (structure, state) => {
6033
6045
  if (structure.type === "matroska") {
6034
6046
  const mainSegment = getMainSegment(structure.boxes);
@@ -6038,13 +6050,7 @@ var hasTracks = (structure, state) => {
6038
6050
  return getTracksSegment(mainSegment) !== null;
6039
6051
  }
6040
6052
  if (structure.type === "iso-base-media") {
6041
- const moovBox = getMoovBox(structure.boxes);
6042
- if (!moovBox) {
6043
- return false;
6044
- }
6045
- const numberOfTracks = getNumberOfTracks2(moovBox);
6046
- const tracks2 = getTraks(moovBox);
6047
- return tracks2.length === numberOfTracks;
6053
+ return isoBaseMediaHasTracks(structure);
6048
6054
  }
6049
6055
  if (structure.type === "riff") {
6050
6056
  return hasAllTracksFromAvi(structure, state);
@@ -6062,7 +6068,7 @@ var getTracksFromMa = (segments, state) => {
6062
6068
  if (!mainSegment) {
6063
6069
  throw new Error("No main segment found");
6064
6070
  }
6065
- const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
6071
+ const matroskaTracks = getTracksFromMatroska(mainSegment, state.webm.getTimescale());
6066
6072
  for (const track of matroskaTracks) {
6067
6073
  if (track.type === "video") {
6068
6074
  videoTracks.push(track);
@@ -6473,6 +6479,13 @@ var getDuration = (structure, parserState) => {
6473
6479
  var hasDuration = (structure, parserState) => {
6474
6480
  return hasTracks(structure, parserState);
6475
6481
  };
6482
+ var hasSlowDuration = (structure, parserState) => {
6483
+ try {
6484
+ return getDuration(structure, parserState) !== null;
6485
+ } catch {
6486
+ return false;
6487
+ }
6488
+ };
6476
6489
 
6477
6490
  // src/get-is-hdr.ts
6478
6491
  var isVideoTrackHdr = (track) => {
@@ -6486,6 +6499,43 @@ var hasHdr = (boxes, state) => {
6486
6499
  return hasTracks(boxes, state);
6487
6500
  };
6488
6501
 
6502
+ // src/boxes/iso-base-media/get-keyframes.ts
6503
+ var getKeyframesFromIsoBaseMedia = (structure) => {
6504
+ const { videoTracks } = getTracksFromIsoBaseMedia(structure.boxes);
6505
+ const moofBox = getMoofBox(structure.boxes);
6506
+ const allSamples = videoTracks.map((t) => {
6507
+ const { timescale: ts } = t;
6508
+ const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
6509
+ const keyframes = samplePositions.filter((k) => {
6510
+ return k.isKeyframe;
6511
+ }).map((k) => {
6512
+ return {
6513
+ trackId: t.trackId,
6514
+ presentationTimeInSeconds: k.cts / ts,
6515
+ decodingTimeInSeconds: k.dts / ts,
6516
+ positionInBytes: k.offset,
6517
+ sizeInBytes: k.size
6518
+ };
6519
+ });
6520
+ return keyframes;
6521
+ });
6522
+ return allSamples.flat();
6523
+ };
6524
+
6525
+ // src/get-keyframes.ts
6526
+ var getKeyframes = (structure) => {
6527
+ if (structure.type === "iso-base-media") {
6528
+ return getKeyframesFromIsoBaseMedia(structure);
6529
+ }
6530
+ return null;
6531
+ };
6532
+ var hasKeyframes = (structure, parserState) => {
6533
+ if (structure.type === "iso-base-media") {
6534
+ return hasTracks(structure, parserState);
6535
+ }
6536
+ return true;
6537
+ };
6538
+
6489
6539
  // src/get-location.ts
6490
6540
  function parseLocation(locationString) {
6491
6541
  const locationPattern = /^([+-]\d{2}\.?\d{0,10})([+-]\d{3}\.?\d{0,10})([+-]\d+(\.\d+)?)?\/$/;
@@ -6529,35 +6579,93 @@ var emitAvailableInfo = ({
6529
6579
  contentLength,
6530
6580
  name,
6531
6581
  mimeType,
6532
- fieldsInReturnValue,
6533
- emittedFields
6582
+ fieldsInReturnValue
6534
6583
  }) => {
6535
6584
  const keys = Object.keys(hasInfo);
6585
+ const segments = state.structure.getStructureOrNull();
6586
+ const { emittedFields } = state;
6536
6587
  for (const key of keys) {
6537
6588
  if (key === "structure") {
6538
- if (parseResult && hasInfo.structure && !emittedFields.structure) {
6539
- callbacks.onStructure?.(parseResult.segments);
6589
+ if (parseResult && hasInfo.structure && !emittedFields.structure && segments) {
6590
+ callbacks.onStructure?.(segments);
6540
6591
  if (fieldsInReturnValue.structure) {
6541
- returnValue.structure = parseResult.segments;
6592
+ returnValue.structure = segments;
6542
6593
  }
6543
6594
  emittedFields.structure = true;
6544
6595
  }
6545
6596
  continue;
6546
6597
  }
6547
6598
  if (key === "durationInSeconds") {
6548
- if (hasInfo.durationInSeconds && !emittedFields.durationInSeconds && parseResult) {
6549
- const durationInSeconds = getDuration(parseResult.segments, state);
6550
- callbacks.onDurationInSeconds?.(durationInSeconds);
6551
- if (fieldsInReturnValue.durationInSeconds) {
6552
- returnValue.durationInSeconds = durationInSeconds;
6599
+ if (hasInfo.durationInSeconds && parseResult && segments) {
6600
+ if (!emittedFields.durationInSeconds) {
6601
+ const durationInSeconds = getDuration(segments, state);
6602
+ callbacks.onDurationInSeconds?.(durationInSeconds);
6603
+ if (fieldsInReturnValue.durationInSeconds) {
6604
+ returnValue.durationInSeconds = durationInSeconds;
6605
+ }
6606
+ emittedFields.durationInSeconds = true;
6607
+ }
6608
+ if (!emittedFields.slowDurationInSeconds) {
6609
+ const durationInSeconds = getDuration(segments, state);
6610
+ if (durationInSeconds !== null) {
6611
+ callbacks.onSlowDurationInSeconds?.(durationInSeconds);
6612
+ if (fieldsInReturnValue.slowDurationInSeconds) {
6613
+ returnValue.slowDurationInSeconds = durationInSeconds;
6614
+ }
6615
+ emittedFields.slowDurationInSeconds = true;
6616
+ }
6617
+ }
6618
+ }
6619
+ continue;
6620
+ }
6621
+ if (key === "slowDurationInSeconds") {
6622
+ if (hasInfo.slowDurationInSeconds && !emittedFields.slowDurationInSeconds && parseResult && segments) {
6623
+ const slowDurationInSeconds = state.slowDurationAndFps.getSlowDurationInSeconds();
6624
+ callbacks.onSlowDurationInSeconds?.(slowDurationInSeconds);
6625
+ if (fieldsInReturnValue.slowDurationInSeconds) {
6626
+ returnValue.slowDurationInSeconds = slowDurationInSeconds;
6627
+ }
6628
+ emittedFields.slowDurationInSeconds = true;
6629
+ }
6630
+ continue;
6631
+ }
6632
+ if (key === "fps") {
6633
+ if (hasInfo.fps && parseResult && segments) {
6634
+ if (!emittedFields.fps) {
6635
+ const fps = getFps(segments);
6636
+ callbacks.onFps?.(fps);
6637
+ if (fieldsInReturnValue.fps) {
6638
+ returnValue.fps = fps;
6639
+ }
6640
+ emittedFields.fps = true;
6641
+ }
6642
+ if (!emittedFields.slowFps) {
6643
+ const fps = getFps(segments);
6644
+ if (fps) {
6645
+ callbacks.onSlowFps?.(fps);
6646
+ if (fieldsInReturnValue.slowFps) {
6647
+ returnValue.slowFps = fps;
6648
+ }
6649
+ emittedFields.slowFps = true;
6650
+ }
6651
+ }
6652
+ }
6653
+ continue;
6654
+ }
6655
+ if (key === "slowFps") {
6656
+ if (hasInfo.slowFps && !emittedFields.slowFps && parseResult && segments) {
6657
+ const slowFps = state.slowDurationAndFps.getFps();
6658
+ callbacks.onSlowFps?.(slowFps);
6659
+ if (fieldsInReturnValue.slowFps) {
6660
+ returnValue.slowFps = slowFps;
6553
6661
  }
6554
- emittedFields.durationInSeconds = true;
6662
+ emittedFields.slowFps = true;
6555
6663
  }
6556
6664
  continue;
6557
6665
  }
6558
6666
  if (key === "dimensions") {
6559
- if (hasInfo.dimensions && !emittedFields.dimensions && parseResult) {
6560
- const dimensionsQueried = getDimensions(parseResult.segments, state);
6667
+ if (hasInfo.dimensions && !emittedFields.dimensions && parseResult && segments) {
6668
+ const dimensionsQueried = getDimensions(segments, state);
6561
6669
  const dimensions = {
6562
6670
  height: dimensionsQueried.height,
6563
6671
  width: dimensionsQueried.width
@@ -6571,8 +6679,8 @@ var emitAvailableInfo = ({
6571
6679
  continue;
6572
6680
  }
6573
6681
  if (key === "unrotatedDimensions") {
6574
- if (hasInfo.unrotatedDimensions && !emittedFields.unrotatedDimensions && parseResult) {
6575
- const dimensionsQueried = getDimensions(parseResult.segments, state);
6682
+ if (hasInfo.unrotatedDimensions && !emittedFields.unrotatedDimensions && parseResult && segments) {
6683
+ const dimensionsQueried = getDimensions(segments, state);
6576
6684
  const unrotatedDimensions = {
6577
6685
  height: dimensionsQueried.unrotatedHeight,
6578
6686
  width: dimensionsQueried.unrotatedWidth
@@ -6586,8 +6694,8 @@ var emitAvailableInfo = ({
6586
6694
  continue;
6587
6695
  }
6588
6696
  if (key === "rotation") {
6589
- if (hasInfo.rotation && !emittedFields.rotation && parseResult) {
6590
- const dimensionsQueried = getDimensions(parseResult.segments, state);
6697
+ if (hasInfo.rotation && !emittedFields.rotation && parseResult && segments) {
6698
+ const dimensionsQueried = getDimensions(segments, state);
6591
6699
  const { rotation } = dimensionsQueried;
6592
6700
  callbacks.onRotation?.(rotation);
6593
6701
  if (fieldsInReturnValue.rotation) {
@@ -6597,20 +6705,9 @@ var emitAvailableInfo = ({
6597
6705
  }
6598
6706
  continue;
6599
6707
  }
6600
- if (key === "fps") {
6601
- if (!emittedFields.fps && hasInfo.fps && parseResult) {
6602
- const fps = getFps(parseResult.segments);
6603
- callbacks.onFps?.(fps);
6604
- if (fieldsInReturnValue.fps) {
6605
- returnValue.fps = fps;
6606
- }
6607
- emittedFields.fps = true;
6608
- }
6609
- continue;
6610
- }
6611
6708
  if (key === "videoCodec") {
6612
- if (!emittedFields.videoCodec && hasInfo.videoCodec && parseResult) {
6613
- const videoCodec = getVideoCodec(parseResult.segments, state);
6709
+ if (!emittedFields.videoCodec && hasInfo.videoCodec && parseResult && segments) {
6710
+ const videoCodec = getVideoCodec(segments, state);
6614
6711
  callbacks.onVideoCodec?.(videoCodec);
6615
6712
  if (fieldsInReturnValue.videoCodec) {
6616
6713
  returnValue.videoCodec = videoCodec;
@@ -6620,8 +6717,8 @@ var emitAvailableInfo = ({
6620
6717
  continue;
6621
6718
  }
6622
6719
  if (key === "audioCodec") {
6623
- if (!emittedFields.audioCodec && hasInfo.audioCodec && parseResult) {
6624
- const audioCodec = getAudioCodec(parseResult.segments, state);
6720
+ if (!emittedFields.audioCodec && hasInfo.audioCodec && parseResult && segments) {
6721
+ const audioCodec = getAudioCodec(segments, state);
6625
6722
  callbacks.onAudioCodec?.(audioCodec);
6626
6723
  if (fieldsInReturnValue.audioCodec) {
6627
6724
  returnValue.audioCodec = audioCodec;
@@ -6631,8 +6728,8 @@ var emitAvailableInfo = ({
6631
6728
  continue;
6632
6729
  }
6633
6730
  if (key === "tracks") {
6634
- if (!emittedFields.tracks && hasInfo.tracks && parseResult) {
6635
- const { videoTracks, audioTracks } = getTracks(parseResult.segments, state);
6731
+ if (!emittedFields.tracks && hasInfo.tracks && parseResult && segments) {
6732
+ const { videoTracks, audioTracks } = getTracks(segments, state);
6636
6733
  callbacks.onTracks?.({ videoTracks, audioTracks });
6637
6734
  if (fieldsInReturnValue.tracks) {
6638
6735
  returnValue.tracks = { videoTracks, audioTracks };
@@ -6682,8 +6779,8 @@ var emitAvailableInfo = ({
6682
6779
  continue;
6683
6780
  }
6684
6781
  if (key === "isHdr") {
6685
- if (!returnValue.isHdr && hasInfo.isHdr && parseResult) {
6686
- const isHdr = getIsHdr(parseResult.segments, state);
6782
+ if (!returnValue.isHdr && hasInfo.isHdr && parseResult && segments) {
6783
+ const isHdr = getIsHdr(segments, state);
6687
6784
  callbacks.onIsHdr?.(isHdr);
6688
6785
  if (fieldsInReturnValue.isHdr) {
6689
6786
  returnValue.isHdr = isHdr;
@@ -6693,8 +6790,8 @@ var emitAvailableInfo = ({
6693
6790
  continue;
6694
6791
  }
6695
6792
  if (key === "container") {
6696
- if (!returnValue.container && hasInfo.container && parseResult) {
6697
- const container = getContainer(parseResult.segments);
6793
+ if (!returnValue.container && hasInfo.container && parseResult && segments) {
6794
+ const container = getContainer(segments);
6698
6795
  callbacks.onContainer?.(container);
6699
6796
  if (fieldsInReturnValue.container) {
6700
6797
  returnValue.container = container;
@@ -6704,8 +6801,8 @@ var emitAvailableInfo = ({
6704
6801
  continue;
6705
6802
  }
6706
6803
  if (key === "metadata") {
6707
- if (!emittedFields.metadata && hasInfo.metadata && parseResult) {
6708
- const metadata = getMetadata(parseResult.segments);
6804
+ if (!emittedFields.metadata && hasInfo.metadata && parseResult && segments) {
6805
+ const metadata = getMetadata(segments);
6709
6806
  callbacks.onMetadata?.(metadata);
6710
6807
  if (fieldsInReturnValue.metadata) {
6711
6808
  returnValue.metadata = metadata;
@@ -6715,8 +6812,8 @@ var emitAvailableInfo = ({
6715
6812
  continue;
6716
6813
  }
6717
6814
  if (key === "location") {
6718
- if (!emittedFields.location && hasInfo.location && parseResult) {
6719
- const location = getLocation(parseResult.segments);
6815
+ if (!emittedFields.location && hasInfo.location && parseResult && segments) {
6816
+ const location = getLocation(segments);
6720
6817
  callbacks.onLocation?.(location);
6721
6818
  if (fieldsInReturnValue.location) {
6722
6819
  returnValue.location = location;
@@ -6725,6 +6822,36 @@ var emitAvailableInfo = ({
6725
6822
  }
6726
6823
  continue;
6727
6824
  }
6825
+ if (key === "slowKeyframes") {
6826
+ if (!emittedFields.slowKeyframes && hasInfo.slowKeyframes && parseResult) {
6827
+ callbacks.onSlowKeyframes?.(state.keyframes.getKeyframes());
6828
+ if (fieldsInReturnValue.slowKeyframes) {
6829
+ returnValue.slowKeyframes = state.keyframes.getKeyframes();
6830
+ }
6831
+ emittedFields.slowKeyframes = true;
6832
+ }
6833
+ continue;
6834
+ }
6835
+ if (key === "slowNumberOfFrames") {
6836
+ if (!emittedFields.slowNumberOfFrames && hasInfo.slowNumberOfFrames && parseResult) {
6837
+ callbacks.onSlowNumberOfFrames?.(state.slowDurationAndFps.getSlowNumberOfFrames());
6838
+ if (fieldsInReturnValue.slowNumberOfFrames) {
6839
+ returnValue.slowNumberOfFrames = state.slowDurationAndFps.getSlowNumberOfFrames();
6840
+ }
6841
+ emittedFields.slowNumberOfFrames = true;
6842
+ }
6843
+ continue;
6844
+ }
6845
+ if (key === "keyframes") {
6846
+ if (!emittedFields.keyframes && hasInfo.keyframes && parseResult) {
6847
+ callbacks.onKeyframes?.(getKeyframes(state.structure.getStructure()));
6848
+ if (fieldsInReturnValue.keyframes) {
6849
+ returnValue.keyframes = getKeyframes(state.structure.getStructure());
6850
+ }
6851
+ emittedFields.keyframes = true;
6852
+ }
6853
+ continue;
6854
+ }
6728
6855
  throw new Error(`Unhandled key: ${key}`);
6729
6856
  }
6730
6857
  };
@@ -6752,18 +6879,65 @@ var getFieldsFromCallback = ({
6752
6879
  tracks: Boolean(callbacks.onTracks),
6753
6880
  unrotatedDimensions: Boolean(callbacks.onUnrotatedDimensions),
6754
6881
  videoCodec: Boolean(callbacks.onVideoCodec),
6882
+ slowKeyframes: Boolean(callbacks.onSlowKeyframes),
6883
+ slowDurationInSeconds: Boolean(callbacks.onSlowDurationInSeconds),
6884
+ slowFps: Boolean(callbacks.onSlowFps),
6885
+ slowNumberOfFrames: Boolean(callbacks.onSlowNumberOfFrames),
6886
+ keyframes: Boolean(callbacks.onKeyframes),
6755
6887
  ...fields
6756
6888
  };
6757
6889
  return newFields;
6758
6890
  };
6759
6891
 
6892
+ // src/may-skip-video-data/need-samples-for-fields.ts
6893
+ var needsSamples = {
6894
+ slowDurationInSeconds: true,
6895
+ slowFps: true,
6896
+ slowKeyframes: true,
6897
+ slowNumberOfFrames: true,
6898
+ audioCodec: false,
6899
+ container: false,
6900
+ dimensions: false,
6901
+ durationInSeconds: false,
6902
+ fps: false,
6903
+ internalStats: false,
6904
+ isHdr: false,
6905
+ name: false,
6906
+ rotation: false,
6907
+ size: false,
6908
+ structure: false,
6909
+ tracks: false,
6910
+ unrotatedDimensions: false,
6911
+ videoCodec: false,
6912
+ metadata: false,
6913
+ location: false,
6914
+ mimeType: false,
6915
+ keyframes: false
6916
+ };
6917
+ var needsToIterateOverSamples = ({
6918
+ fields,
6919
+ emittedFields
6920
+ }) => {
6921
+ const keys = Object.keys(fields ?? {});
6922
+ const selectedKeys = keys.filter((k) => fields[k]);
6923
+ return selectedKeys.some((k) => needsSamples[k] && !emittedFields[k]);
6924
+ };
6925
+
6926
+ // src/may-skip-video-data/may-skip-video-data.ts
6927
+ var maySkipVideoData = ({ state }) => {
6928
+ return state.callbacks.tracks.hasAllTracks() && Object.values(state.callbacks.videoSampleCallbacks).length === 0 && Object.values(state.callbacks.audioSampleCallbacks).length === 0 && !needsToIterateOverSamples({
6929
+ emittedFields: state.emittedFields,
6930
+ fields: state.fields
6931
+ });
6932
+ };
6933
+
6760
6934
  // src/has-all-info.ts
6761
6935
  var getAvailableInfo = ({
6762
6936
  fieldsToFetch,
6763
- structure,
6764
6937
  state
6765
6938
  }) => {
6766
6939
  const keys = Object.entries(fieldsToFetch).filter(([, value]) => value);
6940
+ const structure = state.structure.getStructureOrNull();
6767
6941
  const infos = keys.map(([_key]) => {
6768
6942
  const key = _key;
6769
6943
  if (key === "structure") {
@@ -6772,12 +6946,18 @@ var getAvailableInfo = ({
6772
6946
  if (key === "durationInSeconds") {
6773
6947
  return Boolean(structure && hasDuration(structure, state));
6774
6948
  }
6949
+ if (key === "slowDurationInSeconds") {
6950
+ return Boolean(structure && hasSlowDuration(structure, state));
6951
+ }
6775
6952
  if (key === "dimensions" || key === "rotation" || key === "unrotatedDimensions") {
6776
6953
  return Boolean(structure && hasDimensions(structure, state));
6777
6954
  }
6778
6955
  if (key === "fps") {
6779
6956
  return Boolean(structure && hasFps(structure));
6780
6957
  }
6958
+ if (key === "slowFps") {
6959
+ return Boolean(structure && hasFpsSuitedForSlowFps(structure));
6960
+ }
6781
6961
  if (key === "isHdr") {
6782
6962
  return Boolean(structure && hasHdr(structure, state));
6783
6963
  }
@@ -6790,6 +6970,9 @@ var getAvailableInfo = ({
6790
6970
  if (key === "tracks") {
6791
6971
  return Boolean(structure && hasTracks(structure, state));
6792
6972
  }
6973
+ if (key === "keyframes") {
6974
+ return Boolean(structure && hasKeyframes(structure, state));
6975
+ }
6793
6976
  if (key === "internalStats") {
6794
6977
  return true;
6795
6978
  }
@@ -6808,6 +6991,12 @@ var getAvailableInfo = ({
6808
6991
  if (key === "metadata" || key === "location") {
6809
6992
  return false;
6810
6993
  }
6994
+ if (key === "slowKeyframes") {
6995
+ return false;
6996
+ }
6997
+ if (key === "slowNumberOfFrames") {
6998
+ return false;
6999
+ }
6811
7000
  throw new Error(`Unknown key: ${key}`);
6812
7001
  });
6813
7002
  const entries = [];
@@ -6819,46 +7008,44 @@ var getAvailableInfo = ({
6819
7008
  };
6820
7009
  var hasAllInfo = ({
6821
7010
  fields,
6822
- state,
6823
- structure
7011
+ state
6824
7012
  }) => {
6825
7013
  const availableInfo = getAvailableInfo({
6826
7014
  fieldsToFetch: fields ?? {},
6827
- structure,
6828
7015
  state
6829
7016
  });
6830
- return Object.values(availableInfo).every(Boolean) && (state.maySkipVideoData() || state.canSkipTracksState.canSkipTracks());
7017
+ return Object.values(availableInfo).every(Boolean) && (maySkipVideoData({ state }) || state.callbacks.canSkipTracksState.canSkipTracks());
6831
7018
  };
6832
7019
 
6833
7020
  // src/register-track.ts
6834
7021
  var registerTrack = async ({
6835
- options,
7022
+ state,
6836
7023
  track,
6837
7024
  container
6838
7025
  }) => {
6839
7026
  if (track.type === "video") {
6840
- options.parserState.tracks.addTrack(track);
6841
- if (options.onVideoTrack) {
6842
- const callback = await options.onVideoTrack({ track, container });
6843
- await options.parserState.registerVideoSampleCallback(track.trackId, callback ?? null);
7027
+ state.callbacks.tracks.addTrack(track);
7028
+ if (state.onVideoTrack) {
7029
+ const callback = await state.onVideoTrack({ track, container });
7030
+ await state.callbacks.registerVideoSampleCallback(track.trackId, callback ?? null);
6844
7031
  }
6845
7032
  }
6846
7033
  if (track.type === "audio") {
6847
- options.parserState.tracks.addTrack(track);
6848
- if (options.onAudioTrack) {
6849
- const callback = await options.onAudioTrack({ track, container });
6850
- await options.parserState.registerAudioSampleCallback(track.trackId, callback ?? null);
7034
+ state.callbacks.tracks.addTrack(track);
7035
+ if (state.onAudioTrack) {
7036
+ const callback = await state.onAudioTrack({ track, container });
7037
+ await state.callbacks.registerAudioSampleCallback(track.trackId, callback ?? null);
6851
7038
  }
6852
7039
  }
6853
7040
  };
6854
7041
  var registerVideoTrackWhenProfileIsAvailable = ({
6855
- options,
7042
+ state,
6856
7043
  track,
6857
7044
  container
6858
7045
  }) => {
6859
- options.parserState.registerOnAvcProfileCallback(async (profile) => {
7046
+ state.riff.registerOnAvcProfileCallback(async (profile) => {
6860
7047
  await registerTrack({
6861
- options,
7048
+ state,
6862
7049
  track: addAvcProfileToTrack(track, profile),
6863
7050
  container
6864
7051
  });
@@ -7033,7 +7220,9 @@ var convertAudioOrVideoSampleToWebCodecsTimestamps = (sample, timescale2) => {
7033
7220
  duration: (sample.duration ?? 0) * 1e6 / timescale2,
7034
7221
  data: sample.data,
7035
7222
  trackId: sample.trackId,
7036
- type: sample.type
7223
+ type: sample.type,
7224
+ offset: sample.offset,
7225
+ timescale: 1e6
7037
7226
  };
7038
7227
  };
7039
7228
 
@@ -7043,14 +7232,14 @@ var parseMdat = async ({
7043
7232
  size,
7044
7233
  fileOffset,
7045
7234
  existingBoxes,
7046
- options,
7235
+ state,
7047
7236
  signal,
7048
7237
  maySkipSampleProcessing
7049
7238
  }) => {
7050
7239
  const alreadyHas = hasTracks({
7051
7240
  type: "iso-base-media",
7052
7241
  boxes: existingBoxes
7053
- }, options.parserState);
7242
+ }, state);
7054
7243
  if (!alreadyHas) {
7055
7244
  if (maySkipSampleProcessing) {
7056
7245
  data.discard(size - (data.counter.getOffset() - fileOffset));
@@ -7070,7 +7259,7 @@ var parseMdat = async ({
7070
7259
  fileOffset
7071
7260
  });
7072
7261
  }
7073
- const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, options.parserState);
7262
+ const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, state);
7074
7263
  const allTracks = [
7075
7264
  ...tracks2.videoTracks,
7076
7265
  ...tracks2.audioTracks,
@@ -7112,25 +7301,29 @@ var parseMdat = async ({
7112
7301
  const bytes = data.getSlice(samplesWithIndex.samplePosition.size);
7113
7302
  const { cts, dts, duration: duration2 } = samplesWithIndex.samplePosition;
7114
7303
  if (samplesWithIndex.track.type === "audio") {
7115
- await options.parserState.onAudioSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
7304
+ await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
7116
7305
  data: bytes,
7117
7306
  timestamp: cts,
7118
7307
  duration: duration2,
7119
7308
  cts,
7120
7309
  dts,
7121
7310
  trackId: samplesWithIndex.track.trackId,
7122
- type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta"
7311
+ type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta",
7312
+ offset: samplesWithIndex.samplePosition.offset,
7313
+ timescale: samplesWithIndex.track.timescale
7123
7314
  }, samplesWithIndex.track.timescale));
7124
7315
  }
7125
7316
  if (samplesWithIndex.track.type === "video") {
7126
- await options.parserState.onVideoSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
7317
+ await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
7127
7318
  data: bytes,
7128
7319
  timestamp: cts,
7129
7320
  duration: duration2,
7130
7321
  cts,
7131
7322
  dts,
7132
7323
  trackId: samplesWithIndex.track.trackId,
7133
- type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta"
7324
+ type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta",
7325
+ offset: samplesWithIndex.samplePosition.offset,
7326
+ timescale: samplesWithIndex.track.timescale
7134
7327
  }, samplesWithIndex.track.timescale));
7135
7328
  }
7136
7329
  const remaining = size - (data.counter.getOffset() - fileOffset);
@@ -7295,17 +7488,18 @@ var parseMoov = async ({
7295
7488
  iterator,
7296
7489
  offset,
7297
7490
  size,
7298
- options,
7491
+ state,
7299
7492
  signal,
7300
7493
  logLevel,
7301
7494
  fields
7302
7495
  }) => {
7496
+ const boxes = [];
7303
7497
  const children = await parseIsoBaseMediaBoxes({
7304
7498
  iterator,
7305
7499
  maxBytes: size - (iterator.counter.getOffset() - offset),
7306
7500
  allowIncompleteBoxes: false,
7307
- initialBoxes: [],
7308
- options,
7501
+ initialBoxes: boxes,
7502
+ state,
7309
7503
  continueMdat: false,
7310
7504
  signal,
7311
7505
  logLevel,
@@ -7318,7 +7512,7 @@ var parseMoov = async ({
7318
7512
  offset,
7319
7513
  boxSize: size,
7320
7514
  type: "moov-box",
7321
- children: children.segments.boxes
7515
+ children: boxes
7322
7516
  };
7323
7517
  };
7324
7518
 
@@ -7651,18 +7845,19 @@ var parseMebx = async ({
7651
7845
  iterator,
7652
7846
  offset,
7653
7847
  size,
7654
- options,
7848
+ state,
7655
7849
  signal,
7656
7850
  fields
7657
7851
  }) => {
7658
7852
  iterator.discard(6);
7659
7853
  const dataReferenceIndex = iterator.getUint16();
7854
+ const boxes = [];
7660
7855
  const children = await parseIsoBaseMediaBoxes({
7661
7856
  iterator,
7662
7857
  maxBytes: iterator.counter.getOffset() - offset,
7663
7858
  allowIncompleteBoxes: false,
7664
- initialBoxes: [],
7665
- options,
7859
+ initialBoxes: boxes,
7860
+ state,
7666
7861
  continueMdat: false,
7667
7862
  signal,
7668
7863
  logLevel: "info",
@@ -7677,7 +7872,7 @@ var parseMebx = async ({
7677
7872
  offset,
7678
7873
  dataReferenceIndex,
7679
7874
  format: "mebx",
7680
- children: children.segments.boxes
7875
+ children: boxes
7681
7876
  };
7682
7877
  };
7683
7878
 
@@ -7830,7 +8025,7 @@ var audioTags = [
7830
8025
  ];
7831
8026
  var processSample = async ({
7832
8027
  iterator,
7833
- options,
8028
+ state: options,
7834
8029
  signal,
7835
8030
  logLevel,
7836
8031
  fields
@@ -7870,12 +8065,13 @@ var processSample = async ({
7870
8065
  const packetSize = iterator.getUint16();
7871
8066
  const sampleRate = iterator.getFixedPointUnsigned1616Number();
7872
8067
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
8068
+ const initialBoxes = [];
7873
8069
  const children = await parseIsoBaseMediaBoxes({
7874
8070
  iterator,
7875
8071
  allowIncompleteBoxes: false,
7876
8072
  maxBytes: bytesRemainingInBox,
7877
- initialBoxes: [],
7878
- options,
8073
+ initialBoxes,
8074
+ state: options,
7879
8075
  continueMdat: false,
7880
8076
  signal,
7881
8077
  logLevel,
@@ -7903,7 +8099,7 @@ var processSample = async ({
7903
8099
  bytesPerPacket: null,
7904
8100
  bytesPerFrame: null,
7905
8101
  bitsPerSample: null,
7906
- children: children.segments.boxes
8102
+ children: initialBoxes
7907
8103
  }
7908
8104
  };
7909
8105
  }
@@ -7918,12 +8114,13 @@ var processSample = async ({
7918
8114
  const bytesPerFrame = iterator.getUint32();
7919
8115
  const bytesPerSample = iterator.getUint32();
7920
8116
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
8117
+ const initialBoxes = [];
7921
8118
  const children = await parseIsoBaseMediaBoxes({
7922
8119
  iterator,
7923
8120
  allowIncompleteBoxes: false,
7924
8121
  maxBytes: bytesRemainingInBox,
7925
- initialBoxes: [],
7926
- options,
8122
+ initialBoxes,
8123
+ state: options,
7927
8124
  continueMdat: false,
7928
8125
  signal,
7929
8126
  logLevel,
@@ -7951,7 +8148,7 @@ var processSample = async ({
7951
8148
  bytesPerPacket,
7952
8149
  bytesPerFrame,
7953
8150
  bitsPerSample: bytesPerSample,
7954
- children: children.segments.boxes
8151
+ children: initialBoxes
7955
8152
  }
7956
8153
  };
7957
8154
  }
@@ -7975,7 +8172,7 @@ var processSample = async ({
7975
8172
  allowIncompleteBoxes: false,
7976
8173
  maxBytes: bytesRemainingInBox,
7977
8174
  initialBoxes: [],
7978
- options,
8175
+ state: options,
7979
8176
  continueMdat: false,
7980
8177
  signal,
7981
8178
  logLevel,
@@ -7984,6 +8181,7 @@ var processSample = async ({
7984
8181
  if (children.status === "incomplete") {
7985
8182
  throw new Error("Incomplete boxes are not allowed");
7986
8183
  }
8184
+ const initialBoxes = [];
7987
8185
  return {
7988
8186
  sample: {
7989
8187
  format: boxFormat,
@@ -8003,7 +8201,7 @@ var processSample = async ({
8003
8201
  bytesPerPacket: null,
8004
8202
  bytesPerFrame,
8005
8203
  bitsPerSample: bitsPerChannel,
8006
- children: children.segments.boxes
8204
+ children: initialBoxes
8007
8205
  }
8008
8206
  };
8009
8207
  }
@@ -8025,17 +8223,18 @@ var processSample = async ({
8025
8223
  const depth = iterator.getUint16();
8026
8224
  const colorTableId = iterator.getInt16();
8027
8225
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
8226
+ const initialBoxes = [];
8028
8227
  const children = bytesRemainingInBox > 8 ? await parseIsoBaseMediaBoxes({
8029
8228
  iterator,
8030
8229
  allowIncompleteBoxes: false,
8031
8230
  maxBytes: bytesRemainingInBox,
8032
- initialBoxes: [],
8033
- options,
8231
+ initialBoxes,
8232
+ state: options,
8034
8233
  continueMdat: false,
8035
8234
  signal,
8036
8235
  logLevel,
8037
8236
  fields
8038
- }) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: { boxes: [], type: "iso-base-media" } });
8237
+ }) : (iterator.discard(bytesRemainingInBox), { status: "done" });
8039
8238
  if (children.status === "incomplete") {
8040
8239
  throw new Error("Incomplete boxes are not allowed");
8041
8240
  }
@@ -8060,7 +8259,7 @@ var processSample = async ({
8060
8259
  compressorName,
8061
8260
  depth,
8062
8261
  colorTableId,
8063
- descriptors: children.segments.boxes
8262
+ descriptors: initialBoxes
8064
8263
  }
8065
8264
  };
8066
8265
  }
@@ -8069,7 +8268,7 @@ var processSample = async ({
8069
8268
  var parseSamples = async ({
8070
8269
  iterator,
8071
8270
  maxBytes,
8072
- options,
8271
+ state,
8073
8272
  signal,
8074
8273
  logLevel,
8075
8274
  fields
@@ -8079,7 +8278,7 @@ var parseSamples = async ({
8079
8278
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
8080
8279
  const { sample } = await processSample({
8081
8280
  iterator,
8082
- options,
8281
+ state,
8083
8282
  signal,
8084
8283
  logLevel,
8085
8284
  fields
@@ -8096,7 +8295,7 @@ var parseStsd = async ({
8096
8295
  iterator,
8097
8296
  offset,
8098
8297
  size,
8099
- options,
8298
+ state,
8100
8299
  signal,
8101
8300
  fields
8102
8301
  }) => {
@@ -8110,7 +8309,7 @@ var parseStsd = async ({
8110
8309
  const boxes = await parseSamples({
8111
8310
  iterator,
8112
8311
  maxBytes: bytesRemainingInBox,
8113
- options,
8312
+ state,
8114
8313
  signal,
8115
8314
  logLevel: "info",
8116
8315
  fields
@@ -8382,30 +8581,31 @@ var parseTrak = async ({
8382
8581
  data,
8383
8582
  size,
8384
8583
  offsetAtStart,
8385
- options,
8584
+ state: options,
8386
8585
  signal,
8387
8586
  logLevel,
8388
8587
  fields
8389
8588
  }) => {
8390
- const children = await parseIsoBaseMediaBoxes({
8589
+ const initialBoxes = [];
8590
+ const result = await parseIsoBaseMediaBoxes({
8391
8591
  iterator: data,
8392
8592
  maxBytes: size - (data.counter.getOffset() - offsetAtStart),
8393
8593
  allowIncompleteBoxes: false,
8394
- initialBoxes: [],
8395
- options,
8594
+ initialBoxes,
8595
+ state: options,
8396
8596
  continueMdat: false,
8397
8597
  signal,
8398
8598
  logLevel,
8399
8599
  fields
8400
8600
  });
8401
- if (children.status === "incomplete") {
8601
+ if (result.status === "incomplete") {
8402
8602
  throw new Error("Incomplete boxes are not allowed");
8403
8603
  }
8404
8604
  return {
8405
8605
  offset: offsetAtStart,
8406
8606
  boxSize: size,
8407
8607
  type: "trak-box",
8408
- children: children.segments.boxes
8608
+ children: initialBoxes
8409
8609
  };
8410
8610
  };
8411
8611
 
@@ -8456,19 +8656,20 @@ var getChildren = async ({
8456
8656
  boxType,
8457
8657
  iterator,
8458
8658
  bytesRemainingInBox,
8459
- options,
8659
+ state,
8460
8660
  signal,
8461
8661
  logLevel,
8462
8662
  fields
8463
8663
  }) => {
8464
8664
  const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
8465
8665
  if (parseChildren) {
8666
+ const boxes = [];
8466
8667
  const parsed = await parseIsoBaseMediaBoxes({
8467
8668
  iterator,
8468
8669
  maxBytes: bytesRemainingInBox,
8469
8670
  allowIncompleteBoxes: false,
8470
- initialBoxes: [],
8471
- options,
8671
+ initialBoxes: boxes,
8672
+ state,
8472
8673
  continueMdat: false,
8473
8674
  signal,
8474
8675
  logLevel,
@@ -8477,7 +8678,7 @@ var getChildren = async ({
8477
8678
  if (parsed.status === "incomplete") {
8478
8679
  throw new Error("Incomplete boxes are not allowed");
8479
8680
  }
8480
- return parsed.segments.boxes;
8681
+ return boxes;
8481
8682
  }
8482
8683
  if (bytesRemainingInBox < 0) {
8483
8684
  throw new Error("Box size is too big " + JSON.stringify({ boxType }));
@@ -8490,7 +8691,7 @@ var parseMdatPartially = async ({
8490
8691
  boxSize,
8491
8692
  fileOffset,
8492
8693
  parsedBoxes,
8493
- options,
8694
+ state,
8494
8695
  signal
8495
8696
  }) => {
8496
8697
  const box = await parseMdat({
@@ -8498,9 +8699,9 @@ var parseMdatPartially = async ({
8498
8699
  size: boxSize,
8499
8700
  fileOffset,
8500
8701
  existingBoxes: parsedBoxes,
8501
- options,
8702
+ state,
8502
8703
  signal,
8503
- maySkipSampleProcessing: options.supportsContentRange
8704
+ maySkipSampleProcessing: state.supportsContentRange
8504
8705
  });
8505
8706
  if ((box.status === "samples-processed" || box.status === "samples-buffered") && box.fileOffset + boxSize === iterator.counter.getOffset()) {
8506
8707
  return {
@@ -8520,7 +8721,7 @@ var processBox = async ({
8520
8721
  iterator,
8521
8722
  allowIncompleteBoxes,
8522
8723
  parsedBoxes,
8523
- options,
8724
+ state,
8524
8725
  signal,
8525
8726
  logLevel,
8526
8727
  fields
@@ -8552,7 +8753,7 @@ var processBox = async ({
8552
8753
  const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;
8553
8754
  if (bytesRemaining < boxSize) {
8554
8755
  if (boxType === "mdat") {
8555
- const shouldSkip = options.parserState.maySkipVideoData() || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, options.parserState) && options.supportsContentRange;
8756
+ const shouldSkip = maySkipVideoData({ state }) || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, state) && state.supportsContentRange;
8556
8757
  if (shouldSkip) {
8557
8758
  const skipTo = fileOffset + boxSize;
8558
8759
  const bytesToSkip = skipTo - iterator.counter.getOffset();
@@ -8575,7 +8776,7 @@ var processBox = async ({
8575
8776
  boxSize,
8576
8777
  fileOffset,
8577
8778
  parsedBoxes,
8578
- options,
8779
+ state,
8579
8780
  signal
8580
8781
  });
8581
8782
  }
@@ -8650,7 +8851,7 @@ var processBox = async ({
8650
8851
  iterator,
8651
8852
  offset: fileOffset,
8652
8853
  size: boxSize,
8653
- options,
8854
+ state,
8654
8855
  signal,
8655
8856
  fields
8656
8857
  });
@@ -8745,7 +8946,7 @@ var processBox = async ({
8745
8946
  iterator,
8746
8947
  offset: fileOffset,
8747
8948
  size: boxSize,
8748
- options,
8949
+ state,
8749
8950
  signal,
8750
8951
  fields
8751
8952
  });
@@ -8792,12 +8993,12 @@ var processBox = async ({
8792
8993
  iterator,
8793
8994
  offset: fileOffset,
8794
8995
  size: boxSize,
8795
- options,
8996
+ state,
8796
8997
  signal,
8797
8998
  logLevel,
8798
8999
  fields
8799
9000
  });
8800
- options.parserState.tracks.setIsDone();
9001
+ state.callbacks.tracks.setIsDone();
8801
9002
  return {
8802
9003
  type: "complete",
8803
9004
  box,
@@ -8810,7 +9011,7 @@ var processBox = async ({
8810
9011
  data: iterator,
8811
9012
  size: boxSize,
8812
9013
  offsetAtStart: fileOffset,
8813
- options,
9014
+ state,
8814
9015
  signal,
8815
9016
  logLevel,
8816
9017
  fields
@@ -8818,7 +9019,7 @@ var processBox = async ({
8818
9019
  const transformedTrack = makeBaseMediaTrack(box);
8819
9020
  if (transformedTrack) {
8820
9021
  await registerTrack({
8821
- options,
9022
+ state,
8822
9023
  track: transformedTrack,
8823
9024
  container: "mp4"
8824
9025
  });
@@ -8925,9 +9126,9 @@ var processBox = async ({
8925
9126
  size: boxSize,
8926
9127
  fileOffset,
8927
9128
  existingBoxes: parsedBoxes,
8928
- options,
9129
+ state,
8929
9130
  signal,
8930
- maySkipSampleProcessing: options.supportsContentRange
9131
+ maySkipSampleProcessing: state.supportsContentRange
8931
9132
  });
8932
9133
  if (box === null) {
8933
9134
  throw new Error("Unexpected null");
@@ -8944,7 +9145,7 @@ var processBox = async ({
8944
9145
  boxType,
8945
9146
  iterator,
8946
9147
  bytesRemainingInBox,
8947
- options,
9148
+ state,
8948
9149
  signal,
8949
9150
  logLevel,
8950
9151
  fields
@@ -8967,31 +9168,27 @@ var parseIsoBaseMediaBoxes = async ({
8967
9168
  maxBytes,
8968
9169
  allowIncompleteBoxes,
8969
9170
  initialBoxes,
8970
- options,
9171
+ state,
8971
9172
  continueMdat,
8972
9173
  signal,
8973
9174
  logLevel,
8974
9175
  fields
8975
9176
  }) => {
8976
- const structure = {
8977
- type: "iso-base-media",
8978
- boxes: initialBoxes
8979
- };
8980
9177
  const initialOffset = iterator.counter.getOffset();
8981
- const alreadyHasMdat = structure.boxes.find((b) => b.type === "mdat-box");
9178
+ const alreadyHasMdat = state.structure.getStructureOrNull()?.boxes.find((b) => b.type === "mdat-box");
8982
9179
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
8983
9180
  const result = continueMdat ? await parseMdatPartially({
8984
9181
  iterator,
8985
9182
  boxSize: continueMdat.boxSize,
8986
9183
  fileOffset: continueMdat.fileOffset,
8987
9184
  parsedBoxes: initialBoxes,
8988
- options,
9185
+ state,
8989
9186
  signal
8990
9187
  }) : await processBox({
8991
9188
  iterator,
8992
9189
  allowIncompleteBoxes,
8993
9190
  parsedBoxes: initialBoxes,
8994
- options,
9191
+ state,
8995
9192
  signal,
8996
9193
  logLevel,
8997
9194
  fields
@@ -9002,14 +9199,13 @@ var parseIsoBaseMediaBoxes = async ({
9002
9199
  }
9003
9200
  return {
9004
9201
  status: "incomplete",
9005
- segments: structure,
9006
9202
  continueParsing: () => {
9007
9203
  return parseIsoBaseMediaBoxes({
9008
9204
  iterator,
9009
9205
  maxBytes,
9010
9206
  allowIncompleteBoxes,
9011
- initialBoxes: structure.boxes,
9012
- options,
9207
+ initialBoxes,
9208
+ state,
9013
9209
  continueMdat: false,
9014
9210
  signal,
9015
9211
  logLevel,
@@ -9022,14 +9218,13 @@ var parseIsoBaseMediaBoxes = async ({
9022
9218
  if (result.type === "partial-mdat-box") {
9023
9219
  return {
9024
9220
  status: "incomplete",
9025
- segments: structure,
9026
9221
  continueParsing: () => {
9027
9222
  return Promise.resolve(parseIsoBaseMediaBoxes({
9028
9223
  iterator,
9029
9224
  maxBytes,
9030
9225
  allowIncompleteBoxes,
9031
- initialBoxes: structure.boxes,
9032
- options,
9226
+ initialBoxes,
9227
+ state,
9033
9228
  continueMdat: result,
9034
9229
  signal,
9035
9230
  logLevel,
@@ -9040,36 +9235,34 @@ var parseIsoBaseMediaBoxes = async ({
9040
9235
  };
9041
9236
  }
9042
9237
  if (result.box.type === "mdat-box" && alreadyHasMdat) {
9043
- structure.boxes = structure.boxes.filter((b) => b.type !== "mdat-box");
9044
- structure.boxes.push(result.box);
9238
+ initialBoxes = initialBoxes.filter((b) => b.type !== "mdat-box");
9239
+ initialBoxes.push(result.box);
9045
9240
  iterator.allowDiscard();
9046
9241
  if (result.box.status !== "samples-processed") {
9047
9242
  throw new Error("unexpected");
9048
9243
  }
9049
9244
  break;
9050
9245
  } else {
9051
- structure.boxes.push(result.box);
9052
- if (hasAllInfo({ fields, state: options.parserState, structure })) {
9246
+ initialBoxes.push(result.box);
9247
+ if (hasAllInfo({ fields, state })) {
9053
9248
  return {
9054
- status: "done",
9055
- segments: structure
9249
+ status: "done"
9056
9250
  };
9057
9251
  }
9058
9252
  }
9059
9253
  if (result.skipTo !== null) {
9060
- if (!options.supportsContentRange) {
9254
+ if (!state.supportsContentRange) {
9061
9255
  throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
9062
9256
  }
9063
9257
  return {
9064
9258
  status: "incomplete",
9065
- segments: structure,
9066
9259
  continueParsing: () => {
9067
9260
  return parseIsoBaseMediaBoxes({
9068
9261
  iterator,
9069
9262
  maxBytes,
9070
9263
  allowIncompleteBoxes,
9071
- initialBoxes: structure.boxes,
9072
- options,
9264
+ initialBoxes,
9265
+ state,
9073
9266
  continueMdat: false,
9074
9267
  signal,
9075
9268
  logLevel,
@@ -9082,14 +9275,13 @@ var parseIsoBaseMediaBoxes = async ({
9082
9275
  if (iterator.bytesRemaining() < 0) {
9083
9276
  return {
9084
9277
  status: "incomplete",
9085
- segments: structure,
9086
9278
  continueParsing: () => {
9087
9279
  return parseIsoBaseMediaBoxes({
9088
9280
  iterator,
9089
9281
  maxBytes,
9090
9282
  allowIncompleteBoxes,
9091
- initialBoxes: structure.boxes,
9092
- options,
9283
+ initialBoxes,
9284
+ state,
9093
9285
  continueMdat: false,
9094
9286
  signal,
9095
9287
  logLevel,
@@ -9101,13 +9293,12 @@ var parseIsoBaseMediaBoxes = async ({
9101
9293
  }
9102
9294
  iterator.removeBytesRead();
9103
9295
  }
9104
- const mdatState = getMdatBox(structure.boxes);
9105
- const skipped = mdatState?.status === "samples-skipped" && !options.parserState.maySkipVideoData() && options.supportsContentRange;
9106
- const buffered = mdatState?.status === "samples-buffered" && !options.parserState.maySkipVideoData();
9296
+ const mdatState = getMdatBox(initialBoxes);
9297
+ const skipped = mdatState?.status === "samples-skipped" && !maySkipVideoData({ state }) && state.supportsContentRange;
9298
+ const buffered = mdatState?.status === "samples-buffered" && !maySkipVideoData({ state });
9107
9299
  if (skipped || buffered) {
9108
9300
  return {
9109
9301
  status: "incomplete",
9110
- segments: structure,
9111
9302
  continueParsing: () => {
9112
9303
  if (buffered) {
9113
9304
  iterator.skipTo(mdatState.fileOffset, false);
@@ -9116,8 +9307,8 @@ var parseIsoBaseMediaBoxes = async ({
9116
9307
  iterator,
9117
9308
  maxBytes,
9118
9309
  allowIncompleteBoxes: false,
9119
- initialBoxes: structure.boxes,
9120
- options,
9310
+ initialBoxes,
9311
+ state,
9121
9312
  continueMdat: false,
9122
9313
  signal,
9123
9314
  logLevel,
@@ -9128,8 +9319,7 @@ var parseIsoBaseMediaBoxes = async ({
9128
9319
  };
9129
9320
  }
9130
9321
  return {
9131
- status: "done",
9132
- segments: structure
9322
+ status: "done"
9133
9323
  };
9134
9324
  };
9135
9325
 
@@ -9397,37 +9587,39 @@ var getStrhForIndex = (structure, trackId) => {
9397
9587
  };
9398
9588
  var handleChunk = async ({
9399
9589
  iterator,
9400
- options,
9590
+ state,
9401
9591
  structure,
9402
9592
  ckId,
9403
9593
  ckSize
9404
9594
  }) => {
9595
+ const offset = iterator.counter.getOffset();
9405
9596
  const videoChunk = ckId.match(/^([0-9]{2})dc$/);
9406
9597
  if (videoChunk) {
9407
9598
  const trackId = parseInt(videoChunk[1], 10);
9408
9599
  const strh = getStrhForIndex(structure, trackId);
9409
9600
  const samplesPerSecond = strh.rate / strh.scale;
9410
- const nthSample = options.parserState.getSamplesForTrack(trackId);
9601
+ const nthSample = state.callbacks.getSamplesForTrack(trackId);
9411
9602
  const timeInSec = nthSample / samplesPerSecond;
9412
- const timestamp = Math.floor(timeInSec);
9413
- const duration2 = Math.floor(1 / samplesPerSecond);
9603
+ const timestamp = timeInSec;
9414
9604
  const data = iterator.getSlice(ckSize);
9415
9605
  const infos = parseAvc(data);
9416
9606
  const keyOrDelta = getKeyFrameOrDeltaFromAvcInfo(infos);
9417
9607
  const avcProfile = infos.find((i) => i.type === "avc-profile");
9418
9608
  const ppsProfile = infos.find((i) => i.type === "avc-pps");
9419
9609
  if (avcProfile && ppsProfile) {
9420
- await options.parserState.onProfile({ pps: ppsProfile, sps: avcProfile });
9421
- options.parserState.tracks.setIsDone();
9610
+ await state.riff.onProfile({ pps: ppsProfile, sps: avcProfile });
9611
+ state.callbacks.tracks.setIsDone();
9422
9612
  }
9423
- await options.parserState.onVideoSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9613
+ await state.callbacks.onVideoSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9424
9614
  cts: timestamp,
9425
9615
  dts: timestamp,
9426
9616
  data,
9427
- duration: duration2,
9617
+ duration: undefined,
9428
9618
  timestamp,
9429
9619
  trackId,
9430
- type: keyOrDelta
9620
+ type: keyOrDelta,
9621
+ offset,
9622
+ timescale: samplesPerSecond
9431
9623
  }, 1));
9432
9624
  return;
9433
9625
  }
@@ -9436,25 +9628,27 @@ var handleChunk = async ({
9436
9628
  const trackId = parseInt(audioChunk[1], 10);
9437
9629
  const strh = getStrhForIndex(structure, trackId);
9438
9630
  const samplesPerSecond = strh.rate / strh.scale;
9439
- const nthSample = options.parserState.getSamplesForTrack(trackId);
9631
+ const nthSample = state.callbacks.getSamplesForTrack(trackId);
9440
9632
  const timeInSec = nthSample / samplesPerSecond;
9441
9633
  const timestamp = timeInSec;
9442
- const duration2 = 1 / samplesPerSecond;
9443
- await options.parserState.onAudioSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9634
+ const data = iterator.getSlice(ckSize);
9635
+ await state.callbacks.onAudioSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9444
9636
  cts: timestamp,
9445
9637
  dts: timestamp,
9446
- data: iterator.getSlice(ckSize),
9447
- duration: duration2,
9638
+ data,
9639
+ duration: undefined,
9448
9640
  timestamp,
9449
9641
  trackId,
9450
- type: "key"
9642
+ type: "key",
9643
+ offset,
9644
+ timescale: samplesPerSecond
9451
9645
  }, 1));
9452
9646
  }
9453
9647
  };
9454
9648
  var parseMovi = async ({
9455
9649
  iterator,
9456
9650
  maxOffset,
9457
- options,
9651
+ state,
9458
9652
  structure
9459
9653
  }) => {
9460
9654
  while (iterator.counter.getOffset() < maxOffset) {
@@ -9462,13 +9656,15 @@ var parseMovi = async ({
9462
9656
  return {
9463
9657
  type: "incomplete",
9464
9658
  continueParsing: () => {
9465
- return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
9659
+ return Promise.resolve(parseMovi({ iterator, maxOffset, state, structure }));
9466
9660
  }
9467
9661
  };
9468
9662
  }
9469
9663
  const ckId = iterator.getByteString(4);
9470
9664
  const ckSize = iterator.getUint32Le();
9471
- if (options.parserState.maySkipVideoData() && options.parserState.getAvcProfile()) {
9665
+ if (maySkipVideoData({
9666
+ state
9667
+ }) && state.riff.getAvcProfile()) {
9472
9668
  return {
9473
9669
  type: "complete",
9474
9670
  box: {
@@ -9482,11 +9678,11 @@ var parseMovi = async ({
9482
9678
  return {
9483
9679
  type: "incomplete",
9484
9680
  continueParsing: () => {
9485
- return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
9681
+ return Promise.resolve(parseMovi({ iterator, maxOffset, state, structure }));
9486
9682
  }
9487
9683
  };
9488
9684
  }
9489
- await handleChunk({ iterator, options, structure, ckId, ckSize });
9685
+ await handleChunk({ iterator, state, structure, ckId, ckSize });
9490
9686
  while (iterator.counter.getOffset() < maxOffset && iterator.bytesRemaining() > 0) {
9491
9687
  if (iterator.getUint8() !== 0) {
9492
9688
  iterator.counter.decrement(1);
@@ -9509,7 +9705,7 @@ var parseMovi = async ({
9509
9705
  return {
9510
9706
  type: "incomplete",
9511
9707
  continueParsing: () => {
9512
- return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
9708
+ return Promise.resolve(parseMovi({ iterator, maxOffset, state, structure }));
9513
9709
  }
9514
9710
  };
9515
9711
  };
@@ -9604,7 +9800,7 @@ var parseIsft = ({
9604
9800
  var parseListBox = async ({
9605
9801
  iterator,
9606
9802
  size,
9607
- options
9803
+ state
9608
9804
  }) => {
9609
9805
  const counter = iterator.counter.getOffset();
9610
9806
  const listType = iterator.getByteString(4);
@@ -9619,7 +9815,7 @@ var parseListBox = async ({
9619
9815
  structure,
9620
9816
  iterator,
9621
9817
  maxOffset: counter + size,
9622
- options
9818
+ state
9623
9819
  });
9624
9820
  if (result.status === "incomplete") {
9625
9821
  throw new Error(`Should only parse complete boxes (${listType})`);
@@ -9759,13 +9955,13 @@ var parseRiffBox = ({
9759
9955
  size,
9760
9956
  id,
9761
9957
  boxes,
9762
- options
9958
+ state
9763
9959
  }) => {
9764
9960
  if (id === "fmt") {
9765
9961
  return Promise.resolve(parseFmtBox({ iterator, boxes, size }));
9766
9962
  }
9767
9963
  if (id === "LIST") {
9768
- return parseListBox({ iterator, size, options });
9964
+ return parseListBox({ iterator, size, state });
9769
9965
  }
9770
9966
  if (id === "ISFT") {
9771
9967
  return Promise.resolve(parseIsft({ iterator, size }));
@@ -9791,14 +9987,14 @@ var parseRiffBox = ({
9791
9987
  // src/boxes/riff/expect-riff-box.ts
9792
9988
  var expectRiffBox = async ({
9793
9989
  iterator,
9794
- options,
9990
+ state,
9795
9991
  structure
9796
9992
  }) => {
9797
9993
  if (iterator.bytesRemaining() < 16) {
9798
9994
  return {
9799
9995
  type: "incomplete",
9800
9996
  continueParsing() {
9801
- return expectRiffBox({ structure, iterator, options });
9997
+ return expectRiffBox({ structure, iterator, state });
9802
9998
  }
9803
9999
  };
9804
10000
  }
@@ -9809,7 +10005,7 @@ var expectRiffBox = async ({
9809
10005
  return parseMovi({
9810
10006
  iterator,
9811
10007
  maxOffset: ckSize + iterator.counter.getOffset() - 4,
9812
- options,
10008
+ state,
9813
10009
  structure
9814
10010
  });
9815
10011
  }
@@ -9818,7 +10014,7 @@ var expectRiffBox = async ({
9818
10014
  return {
9819
10015
  type: "incomplete",
9820
10016
  continueParsing: () => {
9821
- return expectRiffBox({ structure, iterator, options });
10017
+ return expectRiffBox({ structure, iterator, state });
9822
10018
  }
9823
10019
  };
9824
10020
  }
@@ -9829,7 +10025,7 @@ var expectRiffBox = async ({
9829
10025
  iterator,
9830
10026
  size: ckSize,
9831
10027
  boxes: structure.boxes,
9832
- options
10028
+ state
9833
10029
  }),
9834
10030
  skipTo: null
9835
10031
  };
@@ -9841,7 +10037,7 @@ var continueAfterRiffBoxResult = ({
9841
10037
  structure,
9842
10038
  iterator,
9843
10039
  maxOffset,
9844
- options
10040
+ state: options
9845
10041
  }) => {
9846
10042
  if (result.type === "incomplete") {
9847
10043
  return Promise.resolve({
@@ -9852,7 +10048,7 @@ var continueAfterRiffBoxResult = ({
9852
10048
  structure,
9853
10049
  iterator,
9854
10050
  maxOffset,
9855
- options
10051
+ state: options
9856
10052
  }));
9857
10053
  },
9858
10054
  segments: structure,
@@ -9862,30 +10058,29 @@ var continueAfterRiffBoxResult = ({
9862
10058
  if (result.type === "complete" && result.box) {
9863
10059
  structure.boxes.push(result.box);
9864
10060
  }
9865
- return parseRiffBody({ iterator, maxOffset, options, structure });
10061
+ return parseRiffBody({ iterator, maxOffset, state: options, structure });
9866
10062
  };
9867
10063
  var parseRiffBody = async ({
9868
10064
  iterator,
9869
10065
  structure,
9870
10066
  maxOffset,
9871
- options
10067
+ state
9872
10068
  }) => {
9873
10069
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset) {
9874
10070
  const result = await expectRiffBox({
9875
10071
  iterator,
9876
- options,
10072
+ state,
9877
10073
  structure
9878
10074
  });
9879
10075
  if (result.type === "complete" && result.skipTo !== null) {
9880
10076
  return {
9881
10077
  status: "incomplete",
9882
10078
  skipTo: result.skipTo,
9883
- segments: structure,
9884
10079
  continueParsing() {
9885
10080
  return Promise.resolve(continueAfterRiffBoxResult({
9886
10081
  iterator,
9887
10082
  maxOffset,
9888
- options,
10083
+ state,
9889
10084
  result,
9890
10085
  structure
9891
10086
  }));
@@ -9899,12 +10094,11 @@ var parseRiffBody = async ({
9899
10094
  return Promise.resolve(continueAfterRiffBoxResult({
9900
10095
  iterator,
9901
10096
  maxOffset,
9902
- options,
10097
+ state,
9903
10098
  result: await result.continueParsing(),
9904
10099
  structure
9905
10100
  }));
9906
10101
  },
9907
- segments: structure,
9908
10102
  skipTo: null
9909
10103
  };
9910
10104
  }
@@ -9913,13 +10107,13 @@ var parseRiffBody = async ({
9913
10107
  }
9914
10108
  structure.boxes.push(result.box);
9915
10109
  if (result.box.type === "list-box" && result.box.listType === "hdrl") {
9916
- const tracks2 = getTracks(structure, options.parserState);
10110
+ const tracks2 = getTracks(structure, state);
9917
10111
  if (!tracks2.videoTracks.some((t) => t.codec === TO_BE_OVERRIDDEN_LATER)) {
9918
- options.parserState.tracks.setIsDone();
10112
+ state.callbacks.tracks.setIsDone();
9919
10113
  }
9920
10114
  }
9921
10115
  if (result.box.type === "wave-format-box") {
9922
- options.parserState.tracks.setIsDone();
10116
+ state.callbacks.tracks.setIsDone();
9923
10117
  }
9924
10118
  if (result.box.type === "strf-box-video" || result.box.type === "strf-box-audio") {
9925
10119
  const strh = getStrhBox(structure.boxes);
@@ -9927,60 +10121,67 @@ var parseRiffBody = async ({
9927
10121
  if (!strh || !strf) {
9928
10122
  throw new Error("strh or strf box missing");
9929
10123
  }
9930
- if (strf.type === "strf-box-audio" && options.onAudioTrack) {
10124
+ if (strf.type === "strf-box-audio" && state.onAudioTrack) {
9931
10125
  const audioTrack = makeAviAudioTrack({
9932
- index: options.nextTrackIndex,
10126
+ index: state.riff.getNextTrackIndex(),
9933
10127
  strf
9934
10128
  });
9935
10129
  await registerTrack({
9936
- options,
10130
+ state,
9937
10131
  track: audioTrack,
9938
10132
  container: "avi"
9939
10133
  });
9940
10134
  }
9941
- if (options.onVideoTrack && strf.type === "strf-box-video") {
10135
+ if (state.onVideoTrack && strf.type === "strf-box-video") {
9942
10136
  const videoTrack = makeAviVideoTrack({
9943
10137
  strh,
9944
- index: options.nextTrackIndex,
10138
+ index: state.riff.getNextTrackIndex(),
9945
10139
  strf
9946
10140
  });
9947
10141
  registerVideoTrackWhenProfileIsAvailable({
9948
- options,
10142
+ state,
9949
10143
  track: videoTrack,
9950
10144
  container: "avi"
9951
10145
  });
9952
10146
  }
9953
- options.nextTrackIndex++;
10147
+ state.riff.incrementNextTrackIndex();
9954
10148
  }
9955
10149
  }
9956
10150
  return {
9957
- status: "done",
9958
- segments: structure
10151
+ status: "done"
9959
10152
  };
9960
10153
  };
9961
10154
  var parseRiff = ({
9962
10155
  iterator,
9963
- options,
10156
+ state,
9964
10157
  fields
9965
10158
  }) => {
9966
- const structure = { type: "riff", boxes: [] };
9967
10159
  const riff = iterator.getByteString(4);
9968
10160
  if (riff !== "RIFF") {
9969
10161
  throw new Error("Not a RIFF file");
9970
10162
  }
10163
+ const structure = state.structure.getStructure();
10164
+ if (structure.type !== "riff") {
10165
+ throw new Error("Structure is not a RIFF structure");
10166
+ }
9971
10167
  const size = iterator.getUint32Le();
9972
10168
  const fileType = iterator.getByteString(4);
9973
10169
  if (fileType !== "WAVE" && fileType !== "AVI") {
9974
10170
  throw new Error(`File type ${fileType} not supported`);
9975
10171
  }
9976
10172
  structure.boxes.push({ type: "riff-header", fileSize: size, fileType });
9977
- if (hasAllInfo({ fields, structure, state: options.parserState })) {
10173
+ if (hasAllInfo({ fields, state })) {
9978
10174
  return Promise.resolve({
9979
10175
  status: "done",
9980
10176
  segments: structure
9981
10177
  });
9982
10178
  }
9983
- return parseRiffBody({ iterator, structure, maxOffset: Infinity, options });
10179
+ return parseRiffBody({
10180
+ iterator,
10181
+ maxOffset: Infinity,
10182
+ state,
10183
+ structure
10184
+ });
9984
10185
  };
9985
10186
 
9986
10187
  // src/boxes/transport-stream/next-pes-header-store.ts
@@ -10320,10 +10521,11 @@ var MPEG_TIMESCALE = 90000;
10320
10521
  var handleAvcPacket = async ({
10321
10522
  streamBuffer,
10322
10523
  programId,
10323
- options
10524
+ state,
10525
+ offset
10324
10526
  }) => {
10325
10527
  const avc = parseAvc(streamBuffer.buffer);
10326
- const isTrackRegistered = options.parserState.tracks.getTracks().find((t) => {
10528
+ const isTrackRegistered = state.callbacks.tracks.getTracks().find((t) => {
10327
10529
  return t.trackId === programId;
10328
10530
  });
10329
10531
  if (!isTrackRegistered) {
@@ -10336,7 +10538,7 @@ var handleAvcPacket = async ({
10336
10538
  type: "video",
10337
10539
  timescale: MPEG_TIMESCALE,
10338
10540
  codec: getCodecStringFromSpsAndPps(spsAndPps.sps),
10339
- codecPrivate: getAvccBoxContent(spsAndPps),
10541
+ codecPrivate: createSpsPpsData(spsAndPps),
10340
10542
  fps: null,
10341
10543
  codedWidth: dimensions.width,
10342
10544
  codedHeight: dimensions.height,
@@ -10353,7 +10555,7 @@ var handleAvcPacket = async ({
10353
10555
  },
10354
10556
  color: getVideoColorFromSps(spsAndPps.sps.spsData)
10355
10557
  };
10356
- await registerTrack({ track, options, container: "transport-stream" });
10558
+ await registerTrack({ track, state, container: "transport-stream" });
10357
10559
  }
10358
10560
  const sample = {
10359
10561
  cts: streamBuffer.pesHeader.pts,
@@ -10362,23 +10564,26 @@ var handleAvcPacket = async ({
10362
10564
  duration: undefined,
10363
10565
  data: new Uint8Array(streamBuffer.buffer),
10364
10566
  trackId: programId,
10365
- type: getKeyFrameOrDeltaFromAvcInfo(avc)
10567
+ type: getKeyFrameOrDeltaFromAvcInfo(avc),
10568
+ offset,
10569
+ timescale: MPEG_TIMESCALE
10366
10570
  };
10367
- await options.parserState.onVideoSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
10571
+ await state.callbacks.onVideoSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
10368
10572
  };
10369
10573
 
10370
10574
  // src/boxes/transport-stream/handle-aac-packet.ts
10371
10575
  var handleAacPacket = async ({
10372
10576
  streamBuffer,
10373
- options,
10374
- programId
10577
+ state,
10578
+ programId,
10579
+ offset
10375
10580
  }) => {
10376
10581
  const adtsHeader = readAdtsHeader(streamBuffer.buffer);
10377
10582
  if (!adtsHeader) {
10378
10583
  throw new Error("Invalid ADTS header - too short");
10379
10584
  }
10380
10585
  const { channelConfiguration, codecPrivate: codecPrivate2, sampleRate, audioObjectType } = adtsHeader;
10381
- const isTrackRegistered = options.parserState.tracks.getTracks().find((t) => {
10586
+ const isTrackRegistered = state.callbacks.tracks.getTracks().find((t) => {
10382
10587
  return t.trackId === programId;
10383
10588
  });
10384
10589
  if (!isTrackRegistered) {
@@ -10396,7 +10601,7 @@ var handleAacPacket = async ({
10396
10601
  };
10397
10602
  await registerTrack({
10398
10603
  track,
10399
- options,
10604
+ state,
10400
10605
  container: "transport-stream"
10401
10606
  });
10402
10607
  }
@@ -10407,15 +10612,17 @@ var handleAacPacket = async ({
10407
10612
  duration: undefined,
10408
10613
  data: new Uint8Array(streamBuffer.buffer),
10409
10614
  trackId: programId,
10410
- type: "key"
10615
+ type: "key",
10616
+ offset,
10617
+ timescale: MPEG_TIMESCALE
10411
10618
  };
10412
- await options.parserState.onAudioSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
10619
+ await state.callbacks.onAudioSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
10413
10620
  };
10414
10621
 
10415
10622
  // src/boxes/transport-stream/process-stream-buffers.ts
10416
10623
  var processStreamBuffer = async ({
10417
10624
  streamBuffer,
10418
- options,
10625
+ state,
10419
10626
  programId,
10420
10627
  structure
10421
10628
  }) => {
@@ -10424,28 +10631,38 @@ var processStreamBuffer = async ({
10424
10631
  throw new Error("No stream found");
10425
10632
  }
10426
10633
  if (stream.streamType === 27) {
10427
- await handleAvcPacket({ programId, streamBuffer, options });
10634
+ await handleAvcPacket({
10635
+ programId,
10636
+ streamBuffer,
10637
+ state,
10638
+ offset: streamBuffer.offset
10639
+ });
10428
10640
  } else if (stream.streamType === 15) {
10429
- await handleAacPacket({ streamBuffer, options, programId });
10641
+ await handleAacPacket({
10642
+ streamBuffer,
10643
+ state,
10644
+ programId,
10645
+ offset: streamBuffer.offset
10646
+ });
10430
10647
  }
10431
- if (!options.parserState.tracks.hasAllTracks()) {
10432
- const tracksRegistered = options.parserState.tracks.getTracks().length;
10648
+ if (!state.callbacks.tracks.hasAllTracks()) {
10649
+ const tracksRegistered = state.callbacks.tracks.getTracks().length;
10433
10650
  const { streams } = findProgramMapTableOrThrow(structure);
10434
10651
  if (streams.length === tracksRegistered) {
10435
- options.parserState.tracks.setIsDone();
10652
+ state.callbacks.tracks.setIsDone();
10436
10653
  }
10437
10654
  }
10438
10655
  };
10439
10656
  var processFinalStreamBuffers = async ({
10440
10657
  streamBufferMap,
10441
- parserContext,
10658
+ state,
10442
10659
  structure
10443
10660
  }) => {
10444
10661
  for (const [programId, buffer] of streamBufferMap) {
10445
10662
  if (buffer.buffer.byteLength > 0) {
10446
10663
  await processStreamBuffer({
10447
10664
  streamBuffer: buffer,
10448
- options: parserContext,
10665
+ state,
10449
10666
  programId,
10450
10667
  structure
10451
10668
  });
@@ -10460,14 +10677,16 @@ var parseAdtsStream = async ({
10460
10677
  transportStreamEntry,
10461
10678
  streamBuffers,
10462
10679
  nextPesHeader,
10463
- options,
10464
- structure
10680
+ state,
10681
+ structure,
10682
+ offset
10465
10683
  }) => {
10466
10684
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
10467
10685
  if (!streamBuffer) {
10468
10686
  streamBuffers.set(transportStreamEntry.pid, {
10469
10687
  buffer: restOfPacket,
10470
- pesHeader: nextPesHeader
10688
+ pesHeader: nextPesHeader,
10689
+ offset
10471
10690
  });
10472
10691
  return;
10473
10692
  }
@@ -10481,13 +10700,14 @@ var parseAdtsStream = async ({
10481
10700
  await processStreamBuffer({
10482
10701
  streamBuffer,
10483
10702
  programId: transportStreamEntry.pid,
10484
- options,
10703
+ state,
10485
10704
  structure
10486
10705
  });
10487
10706
  const rest = restOfPacket.slice(bytesToTake);
10488
10707
  streamBuffers.set(transportStreamEntry.pid, {
10489
10708
  buffer: rest,
10490
- pesHeader: nextPesHeader
10709
+ pesHeader: nextPesHeader,
10710
+ offset
10491
10711
  });
10492
10712
  }
10493
10713
  };
@@ -10497,8 +10717,9 @@ var parseAvcStream = async ({
10497
10717
  streamBuffers,
10498
10718
  nextPesHeader,
10499
10719
  programId,
10500
- parserContext,
10501
- structure
10720
+ state,
10721
+ structure,
10722
+ offset
10502
10723
  }) => {
10503
10724
  const indexOfSeparator = findNextSeparator(restOfPacket, transportStreamEntry);
10504
10725
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
@@ -10512,7 +10733,8 @@ var parseAvcStream = async ({
10512
10733
  }
10513
10734
  streamBuffers.set(programId, {
10514
10735
  pesHeader: nextPesHeader,
10515
- buffer: restOfPacket
10736
+ buffer: restOfPacket,
10737
+ offset
10516
10738
  });
10517
10739
  return;
10518
10740
  }
@@ -10520,7 +10742,7 @@ var parseAvcStream = async ({
10520
10742
  const packet = restOfPacket.slice(0, indexOfSeparator);
10521
10743
  streamBuffer.buffer = combineUint8Arrays([streamBuffer.buffer, packet]);
10522
10744
  await processStreamBuffer({
10523
- options: parserContext,
10745
+ state,
10524
10746
  streamBuffer,
10525
10747
  programId,
10526
10748
  structure
@@ -10528,7 +10750,8 @@ var parseAvcStream = async ({
10528
10750
  const rest = restOfPacket.slice(indexOfSeparator);
10529
10751
  streamBuffers.set(programId, {
10530
10752
  pesHeader: nextPesHeader,
10531
- buffer: rest
10753
+ buffer: rest,
10754
+ offset
10532
10755
  });
10533
10756
  return;
10534
10757
  }
@@ -10537,14 +10760,15 @@ var parseAvcStream = async ({
10537
10760
  }
10538
10761
  streamBuffers.set(programId, {
10539
10762
  pesHeader: nextPesHeader,
10540
- buffer: restOfPacket.slice(indexOfSeparator)
10763
+ buffer: restOfPacket.slice(indexOfSeparator),
10764
+ offset
10541
10765
  });
10542
10766
  };
10543
10767
  var parseStream = ({
10544
10768
  iterator,
10545
10769
  transportStreamEntry,
10546
10770
  streamBuffers,
10547
- parserContext,
10771
+ state,
10548
10772
  programId,
10549
10773
  structure,
10550
10774
  nextPesHeader
@@ -10556,9 +10780,10 @@ var parseStream = ({
10556
10780
  transportStreamEntry,
10557
10781
  streamBuffers,
10558
10782
  nextPesHeader,
10559
- parserContext,
10783
+ state,
10560
10784
  programId,
10561
- structure
10785
+ structure,
10786
+ offset: iterator.counter.getOffset()
10562
10787
  });
10563
10788
  }
10564
10789
  if (transportStreamEntry.streamType === 15) {
@@ -10567,8 +10792,9 @@ var parseStream = ({
10567
10792
  transportStreamEntry,
10568
10793
  streamBuffers,
10569
10794
  nextPesHeader,
10570
- options: parserContext,
10571
- structure
10795
+ state,
10796
+ structure,
10797
+ offset: iterator.counter.getOffset()
10572
10798
  });
10573
10799
  }
10574
10800
  throw new Error(`Unsupported stream type ${transportStreamEntry.streamType}`);
@@ -10579,7 +10805,7 @@ var parsePacket = async ({
10579
10805
  iterator,
10580
10806
  structure,
10581
10807
  streamBuffers,
10582
- parserContext,
10808
+ parserState,
10583
10809
  nextPesHeaderStore
10584
10810
  }) => {
10585
10811
  const offset = iterator.counter.getOffset();
@@ -10643,7 +10869,7 @@ var parsePacket = async ({
10643
10869
  transportStreamEntry: stream,
10644
10870
  streamBuffers,
10645
10871
  nextPesHeader: nextPesHeaderStore.getNextPesHeader(),
10646
- parserContext,
10872
+ state: parserState,
10647
10873
  programId,
10648
10874
  structure
10649
10875
  });
@@ -10655,16 +10881,19 @@ var parsePacket = async ({
10655
10881
  // src/boxes/transport-stream/parse-transport-stream.ts
10656
10882
  var parseTransportStream = async ({
10657
10883
  iterator,
10658
- parserContext,
10659
- structure,
10884
+ state,
10660
10885
  streamBuffers,
10661
10886
  fields,
10662
10887
  nextPesHeaderStore
10663
10888
  }) => {
10889
+ const structure = state.structure.getStructure();
10890
+ if (structure.type !== "transport-stream") {
10891
+ throw new Error("Invalid structure type");
10892
+ }
10664
10893
  if (iterator.bytesRemaining() === 0) {
10665
10894
  await processFinalStreamBuffers({
10666
10895
  streamBufferMap: streamBuffers,
10667
- parserContext,
10896
+ state,
10668
10897
  structure
10669
10898
  });
10670
10899
  return Promise.resolve({
@@ -10675,8 +10904,7 @@ var parseTransportStream = async ({
10675
10904
  while (true) {
10676
10905
  if (hasAllInfo({
10677
10906
  fields,
10678
- state: parserContext.parserState,
10679
- structure
10907
+ state
10680
10908
  })) {
10681
10909
  break;
10682
10910
  }
@@ -10688,8 +10916,7 @@ var parseTransportStream = async ({
10688
10916
  continueParsing: () => {
10689
10917
  return parseTransportStream({
10690
10918
  iterator,
10691
- parserContext,
10692
- structure,
10919
+ state,
10693
10920
  streamBuffers,
10694
10921
  fields,
10695
10922
  nextPesHeaderStore
@@ -10701,7 +10928,7 @@ var parseTransportStream = async ({
10701
10928
  iterator,
10702
10929
  structure,
10703
10930
  streamBuffers,
10704
- parserContext,
10931
+ parserState: state,
10705
10932
  nextPesHeaderStore
10706
10933
  });
10707
10934
  if (packet) {
@@ -10715,8 +10942,7 @@ var parseTransportStream = async ({
10715
10942
  continueParsing() {
10716
10943
  return parseTransportStream({
10717
10944
  iterator,
10718
- parserContext,
10719
- structure,
10945
+ state,
10720
10946
  streamBuffers,
10721
10947
  fields,
10722
10948
  nextPesHeaderStore
@@ -10759,7 +10985,7 @@ var parseBlockFlags = (iterator, type) => {
10759
10985
  };
10760
10986
 
10761
10987
  // src/boxes/webm/get-sample-from-block.ts
10762
- var getSampleFromBlock = (ebml, parserContext, offset) => {
10988
+ var getSampleFromBlock = (ebml, state, offset) => {
10763
10989
  const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
10764
10990
  const trackNumber2 = iterator.getVint();
10765
10991
  if (trackNumber2 === null) {
@@ -10767,9 +10993,9 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10767
10993
  }
10768
10994
  const timecodeRelativeToCluster = iterator.getInt16();
10769
10995
  const { keyframe } = parseBlockFlags(iterator, ebml.type === "SimpleBlock" ? matroskaElements.SimpleBlock : matroskaElements.Block);
10770
- const { codec, trackTimescale } = parserContext.parserState.getTrackInfoByNumber(trackNumber2);
10771
- const clusterOffset = parserContext.parserState.getTimestampOffsetForByteOffset(offset);
10772
- const timescale2 = parserContext.parserState.getTimescale();
10996
+ const { codec, trackTimescale } = state.webm.getTrackInfoByNumber(trackNumber2);
10997
+ const clusterOffset = state.webm.getTimestampOffsetForByteOffset(offset);
10998
+ const timescale2 = state.webm.getTimescale();
10773
10999
  if (clusterOffset === undefined) {
10774
11000
  throw new Error("Could not find offset for byte offset " + offset);
10775
11001
  }
@@ -10786,7 +11012,9 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10786
11012
  dts: timecodeInMicroseconds,
10787
11013
  duration: undefined,
10788
11014
  trackId: trackNumber2,
10789
- timestamp: timecodeInMicroseconds
11015
+ timestamp: timecodeInMicroseconds,
11016
+ offset,
11017
+ timescale: timescale2
10790
11018
  };
10791
11019
  if (keyframe === null) {
10792
11020
  iterator.destroy();
@@ -10813,7 +11041,9 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10813
11041
  type: "key",
10814
11042
  duration: undefined,
10815
11043
  cts: timecodeInMicroseconds,
10816
- dts: timecodeInMicroseconds
11044
+ dts: timecodeInMicroseconds,
11045
+ offset,
11046
+ timescale: timescale2
10817
11047
  };
10818
11048
  iterator.destroy();
10819
11049
  return {
@@ -10828,7 +11058,7 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10828
11058
  };
10829
11059
 
10830
11060
  // src/boxes/webm/parse-ebml.ts
10831
- var parseEbml = async (iterator, parserContext) => {
11061
+ var parseEbml = async (iterator, state) => {
10832
11062
  const hex = iterator.getMatroskaSegmentId();
10833
11063
  if (hex === null) {
10834
11064
  throw new Error("Not enough bytes left to parse EBML - this should not happen");
@@ -10897,11 +11127,11 @@ var parseEbml = async (iterator, parserContext) => {
10897
11127
  break;
10898
11128
  }
10899
11129
  const offset = iterator.counter.getOffset();
10900
- const value = await parseEbml(iterator, parserContext);
11130
+ const value = await parseEbml(iterator, state);
10901
11131
  const remapped = await postprocessEbml({
10902
11132
  offset,
10903
11133
  ebml: value,
10904
- parserContext
11134
+ state
10905
11135
  });
10906
11136
  children.push(remapped);
10907
11137
  const offsetNow = iterator.counter.getOffset();
@@ -10919,47 +11149,47 @@ var parseEbml = async (iterator, parserContext) => {
10919
11149
  var postprocessEbml = async ({
10920
11150
  offset,
10921
11151
  ebml,
10922
- parserContext
11152
+ state
10923
11153
  }) => {
10924
11154
  if (ebml.type === "TimestampScale") {
10925
- parserContext.parserState.setTimescale(ebml.value.value);
11155
+ state.webm.setTimescale(ebml.value.value);
10926
11156
  }
10927
11157
  if (ebml.type === "TrackEntry") {
10928
- parserContext.parserState.onTrackEntrySegment(ebml);
11158
+ state.webm.onTrackEntrySegment(ebml);
10929
11159
  const track = getTrack({
10930
11160
  track: ebml,
10931
- timescale: parserContext.parserState.getTimescale()
11161
+ timescale: state.webm.getTimescale()
10932
11162
  });
10933
11163
  if (track) {
10934
11164
  await registerTrack({
10935
- options: parserContext,
11165
+ state,
10936
11166
  track,
10937
11167
  container: "webm"
10938
11168
  });
10939
11169
  }
10940
11170
  }
10941
11171
  if (ebml.type === "Timestamp") {
10942
- parserContext.parserState.setTimestampOffset(offset, ebml.value.value);
11172
+ state.webm.setTimestampOffset(offset, ebml.value.value);
10943
11173
  }
10944
11174
  if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
10945
- const sample = getSampleFromBlock(ebml, parserContext, offset);
10946
- if (sample.type === "video-sample" && parserContext.nullifySamples) {
10947
- await parserContext.parserState.onVideoSample(sample.videoSample.trackId, sample.videoSample);
11175
+ const sample = getSampleFromBlock(ebml, state, offset);
11176
+ if (sample.type === "video-sample" && state.nullifySamples) {
11177
+ await state.callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
10948
11178
  return {
10949
11179
  type: "Block",
10950
11180
  value: new Uint8Array([]),
10951
11181
  minVintWidth: ebml.minVintWidth
10952
11182
  };
10953
11183
  }
10954
- if (sample.type === "audio-sample" && parserContext.nullifySamples) {
10955
- await parserContext.parserState.onAudioSample(sample.audioSample.trackId, sample.audioSample);
11184
+ if (sample.type === "audio-sample" && state.nullifySamples) {
11185
+ await state.callbacks.onAudioSample(sample.audioSample.trackId, sample.audioSample);
10956
11186
  return {
10957
11187
  type: "Block",
10958
11188
  value: new Uint8Array([]),
10959
11189
  minVintWidth: ebml.minVintWidth
10960
11190
  };
10961
11191
  }
10962
- if (sample.type === "no-sample" && parserContext.nullifySamples) {
11192
+ if (sample.type === "no-sample" && state.nullifySamples) {
10963
11193
  return {
10964
11194
  type: "Block",
10965
11195
  value: new Uint8Array([]),
@@ -10973,15 +11203,15 @@ var postprocessEbml = async ({
10973
11203
  throw new Error("Expected block segment");
10974
11204
  }
10975
11205
  const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
10976
- const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2, parserContext, offset);
11206
+ const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2, state, offset);
10977
11207
  if (sample && sample.type === "partial-video-sample") {
10978
11208
  const completeFrame = {
10979
11209
  ...sample.partialVideoSample,
10980
11210
  type: hasReferenceBlock ? "delta" : "key"
10981
11211
  };
10982
- await parserContext.parserState.onVideoSample(sample.partialVideoSample.trackId, completeFrame);
11212
+ await state.callbacks.onVideoSample(sample.partialVideoSample.trackId, completeFrame);
10983
11213
  }
10984
- if (parserContext.nullifySamples) {
11214
+ if (state.nullifySamples) {
10985
11215
  return {
10986
11216
  type: "BlockGroup",
10987
11217
  value: [],
@@ -10996,7 +11226,7 @@ var postprocessEbml = async ({
10996
11226
  var continueAfterMatroskaParseResult = async ({
10997
11227
  result,
10998
11228
  iterator,
10999
- parserContext,
11229
+ state,
11000
11230
  segment
11001
11231
  }) => {
11002
11232
  if (result.status === "done") {
@@ -11014,7 +11244,7 @@ var continueAfterMatroskaParseResult = async ({
11014
11244
  return continueAfterMatroskaParseResult({
11015
11245
  result: proceeded,
11016
11246
  iterator,
11017
- parserContext,
11247
+ state,
11018
11248
  segment
11019
11249
  });
11020
11250
  },
@@ -11024,7 +11254,7 @@ var continueAfterMatroskaParseResult = async ({
11024
11254
  };
11025
11255
  var expectSegment = async ({
11026
11256
  iterator,
11027
- parserContext,
11257
+ state,
11028
11258
  offset,
11029
11259
  children,
11030
11260
  fields,
@@ -11037,7 +11267,7 @@ var expectSegment = async ({
11037
11267
  continueParsing: () => {
11038
11268
  return expectAndProcessSegment({
11039
11269
  iterator,
11040
- parserContext,
11270
+ state,
11041
11271
  offset,
11042
11272
  children,
11043
11273
  fields,
@@ -11055,7 +11285,7 @@ var expectSegment = async ({
11055
11285
  continueParsing: () => {
11056
11286
  return expectAndProcessSegment({
11057
11287
  iterator,
11058
- parserContext,
11288
+ state,
11059
11289
  offset,
11060
11290
  children,
11061
11291
  fields,
@@ -11075,7 +11305,7 @@ var expectSegment = async ({
11075
11305
  continueParsing: () => {
11076
11306
  return expectSegment({
11077
11307
  iterator,
11078
- parserContext,
11308
+ state,
11079
11309
  offset,
11080
11310
  children,
11081
11311
  fields,
@@ -11096,7 +11326,7 @@ var expectSegment = async ({
11096
11326
  iterator,
11097
11327
  length,
11098
11328
  children: newSegment.value,
11099
- parserContext,
11329
+ state,
11100
11330
  startOffset: iterator.counter.getOffset(),
11101
11331
  fields,
11102
11332
  topLevelStructure
@@ -11107,7 +11337,7 @@ var expectSegment = async ({
11107
11337
  continueParsing: () => {
11108
11338
  return continueAfterMatroskaParseResult({
11109
11339
  iterator,
11110
- parserContext,
11340
+ state,
11111
11341
  result: main,
11112
11342
  segment: newSegment
11113
11343
  });
@@ -11129,7 +11359,7 @@ var expectSegment = async ({
11129
11359
  continueParsing: () => {
11130
11360
  return expectSegment({
11131
11361
  iterator,
11132
- parserContext,
11362
+ state,
11133
11363
  offset,
11134
11364
  children,
11135
11365
  fields,
@@ -11142,7 +11372,7 @@ var expectSegment = async ({
11142
11372
  segmentId,
11143
11373
  iterator,
11144
11374
  length,
11145
- parserContext,
11375
+ state,
11146
11376
  headerReadSoFar: iterator.counter.getOffset() - offset
11147
11377
  });
11148
11378
  return {
@@ -11154,7 +11384,7 @@ var parseSegment = async ({
11154
11384
  segmentId,
11155
11385
  iterator,
11156
11386
  length,
11157
- parserContext,
11387
+ state,
11158
11388
  headerReadSoFar
11159
11389
  }) => {
11160
11390
  if (length < 0) {
@@ -11162,8 +11392,8 @@ var parseSegment = async ({
11162
11392
  }
11163
11393
  iterator.counter.decrement(headerReadSoFar);
11164
11394
  const offset = iterator.counter.getOffset();
11165
- const ebml = await parseEbml(iterator, parserContext);
11166
- const remapped = await postprocessEbml({ offset, ebml, parserContext });
11395
+ const ebml = await parseEbml(iterator, state);
11396
+ const remapped = await postprocessEbml({ offset, ebml, state });
11167
11397
  return remapped;
11168
11398
  };
11169
11399
 
@@ -11177,14 +11407,14 @@ var processParseResult = ({
11177
11407
  }) => {
11178
11408
  if (parseResult.segment && !children.includes(parseResult.segment)) {
11179
11409
  children.push(parseResult.segment);
11180
- if (hasAllInfo({ fields, state, structure: topLevelStructure })) {
11410
+ if (hasAllInfo({ fields, state })) {
11181
11411
  return {
11182
11412
  status: "done",
11183
11413
  segment: parseResult.segment
11184
11414
  };
11185
11415
  }
11186
11416
  if (parseResult.segment.type === "Tracks") {
11187
- state.tracks.setIsDone();
11417
+ state.callbacks.tracks.setIsDone();
11188
11418
  }
11189
11419
  }
11190
11420
  if (parseResult.status === "incomplete") {
@@ -11210,7 +11440,7 @@ var processParseResult = ({
11210
11440
  };
11211
11441
  var expectAndProcessSegment = async ({
11212
11442
  iterator,
11213
- parserContext,
11443
+ state,
11214
11444
  offset,
11215
11445
  children,
11216
11446
  fields,
@@ -11218,7 +11448,7 @@ var expectAndProcessSegment = async ({
11218
11448
  }) => {
11219
11449
  const segment = await expectSegment({
11220
11450
  iterator,
11221
- parserContext,
11451
+ state,
11222
11452
  offset,
11223
11453
  children,
11224
11454
  fields,
@@ -11227,7 +11457,7 @@ var expectAndProcessSegment = async ({
11227
11457
  return processParseResult({
11228
11458
  children,
11229
11459
  parseResult: segment,
11230
- state: parserContext.parserState,
11460
+ state,
11231
11461
  fields,
11232
11462
  topLevelStructure
11233
11463
  });
@@ -11236,7 +11466,7 @@ var continueAfterSegmentResult = async ({
11236
11466
  result,
11237
11467
  length,
11238
11468
  children,
11239
- parserContext,
11469
+ state,
11240
11470
  iterator,
11241
11471
  startOffset,
11242
11472
  fields,
@@ -11254,7 +11484,7 @@ var continueAfterSegmentResult = async ({
11254
11484
  children,
11255
11485
  iterator,
11256
11486
  length,
11257
- parserContext,
11487
+ state,
11258
11488
  startOffset,
11259
11489
  fields,
11260
11490
  topLevelStructure
@@ -11271,7 +11501,7 @@ var continueAfterSegmentResult = async ({
11271
11501
  children,
11272
11502
  iterator,
11273
11503
  length,
11274
- parserContext,
11504
+ state,
11275
11505
  startOffset,
11276
11506
  fields,
11277
11507
  topLevelStructure
@@ -11284,7 +11514,7 @@ var expectChildren = async ({
11284
11514
  iterator,
11285
11515
  length,
11286
11516
  children,
11287
- parserContext,
11517
+ state,
11288
11518
  startOffset,
11289
11519
  fields,
11290
11520
  topLevelStructure
@@ -11296,7 +11526,7 @@ var expectChildren = async ({
11296
11526
  const currentOffset = iterator.counter.getOffset();
11297
11527
  const child = await expectAndProcessSegment({
11298
11528
  iterator,
11299
- parserContext,
11529
+ state,
11300
11530
  offset: currentOffset,
11301
11531
  children,
11302
11532
  fields,
@@ -11304,8 +11534,7 @@ var expectChildren = async ({
11304
11534
  });
11305
11535
  if (hasAllInfo({
11306
11536
  fields,
11307
- state: parserContext.parserState,
11308
- structure: topLevelStructure
11537
+ state
11309
11538
  })) {
11310
11539
  return {
11311
11540
  status: "done"
@@ -11320,7 +11549,7 @@ var expectChildren = async ({
11320
11549
  children,
11321
11550
  iterator,
11322
11551
  length: length - (currentOffset - startOffset),
11323
- parserContext,
11552
+ state,
11324
11553
  startOffset: currentOffset,
11325
11554
  fields,
11326
11555
  topLevelStructure
@@ -11339,13 +11568,11 @@ var expectChildren = async ({
11339
11568
  var continueAfterMatroskaResult = (result, structure) => {
11340
11569
  if (result.status === "done") {
11341
11570
  return {
11342
- status: "done",
11343
- segments: structure
11571
+ status: "done"
11344
11572
  };
11345
11573
  }
11346
11574
  return {
11347
11575
  status: "incomplete",
11348
- segments: structure,
11349
11576
  continueParsing: async () => {
11350
11577
  const newResult = await result.continueParsing();
11351
11578
  return continueAfterMatroskaResult(newResult, structure);
@@ -11355,15 +11582,18 @@ var continueAfterMatroskaResult = (result, structure) => {
11355
11582
  };
11356
11583
  var parseWebm = async ({
11357
11584
  counter,
11358
- parserContext,
11585
+ state,
11359
11586
  fields
11360
11587
  }) => {
11361
- const structure = { type: "matroska", boxes: [] };
11588
+ const structure = state.structure.getStructure();
11589
+ if (structure.type !== "matroska") {
11590
+ throw new Error("Invalid structure type");
11591
+ }
11362
11592
  const results = await expectChildren({
11363
11593
  iterator: counter,
11364
11594
  length: Infinity,
11365
11595
  children: structure.boxes,
11366
- parserContext,
11596
+ state,
11367
11597
  startOffset: counter.counter.getOffset(),
11368
11598
  fields,
11369
11599
  topLevelStructure: structure
@@ -11374,7 +11604,7 @@ var parseWebm = async ({
11374
11604
  // src/parse-video.ts
11375
11605
  var parseVideo = ({
11376
11606
  iterator,
11377
- options,
11607
+ state,
11378
11608
  signal,
11379
11609
  logLevel,
11380
11610
  fields,
@@ -11388,16 +11618,25 @@ var parseVideo = ({
11388
11618
  const fileType = iterator.detectFileType();
11389
11619
  if (fileType.type === "riff") {
11390
11620
  Log.verbose(logLevel, "Detected RIFF container");
11391
- return Promise.resolve(parseRiff({ iterator, options, fields }));
11621
+ state.structure.setStructure({
11622
+ type: "riff",
11623
+ boxes: []
11624
+ });
11625
+ return Promise.resolve(parseRiff({ iterator, state, fields }));
11392
11626
  }
11393
11627
  if (fileType.type === "iso-base-media") {
11394
11628
  Log.verbose(logLevel, "Detected ISO Base Media container");
11629
+ const initialBoxes = [];
11630
+ state.structure.setStructure({
11631
+ type: "iso-base-media",
11632
+ boxes: initialBoxes
11633
+ });
11395
11634
  return parseIsoBaseMediaBoxes({
11396
11635
  iterator,
11397
11636
  maxBytes: Infinity,
11398
11637
  allowIncompleteBoxes: true,
11399
- initialBoxes: [],
11400
- options,
11638
+ initialBoxes,
11639
+ state,
11401
11640
  continueMdat: false,
11402
11641
  signal,
11403
11642
  logLevel,
@@ -11406,16 +11645,21 @@ var parseVideo = ({
11406
11645
  }
11407
11646
  if (fileType.type === "webm") {
11408
11647
  Log.verbose(logLevel, "Detected Matroska container");
11409
- return parseWebm({ counter: iterator, parserContext: options, fields });
11648
+ state.structure.setStructure({
11649
+ boxes: [],
11650
+ type: "matroska"
11651
+ });
11652
+ return parseWebm({ counter: iterator, state, fields });
11410
11653
  }
11411
11654
  if (fileType.type === "transport-stream") {
11655
+ Log.verbose(logLevel, "Detected MPEG-2 Transport Stream");
11656
+ state.structure.setStructure({
11657
+ boxes: [],
11658
+ type: "transport-stream"
11659
+ });
11412
11660
  return parseTransportStream({
11413
11661
  iterator,
11414
- parserContext: options,
11415
- structure: {
11416
- type: "transport-stream",
11417
- boxes: []
11418
- },
11662
+ state,
11419
11663
  streamBuffers: new Map,
11420
11664
  fields,
11421
11665
  nextPesHeaderStore: makeNextPesHeaderStore()
@@ -11485,12 +11729,86 @@ var parseVideo = ({
11485
11729
  return Promise.reject(new Error("Unknown video format " + fileType));
11486
11730
  };
11487
11731
 
11732
+ // src/state/emitted-fields.ts
11733
+ var emittedState = () => {
11734
+ const emittedFields = {
11735
+ audioCodec: false,
11736
+ container: false,
11737
+ dimensions: false,
11738
+ durationInSeconds: false,
11739
+ fps: false,
11740
+ internalStats: false,
11741
+ isHdr: false,
11742
+ location: false,
11743
+ metadata: false,
11744
+ mimeType: false,
11745
+ name: false,
11746
+ rotation: false,
11747
+ size: false,
11748
+ structure: false,
11749
+ tracks: false,
11750
+ videoCodec: false,
11751
+ unrotatedDimensions: false,
11752
+ slowDurationInSeconds: false,
11753
+ slowFps: false,
11754
+ slowKeyframes: false,
11755
+ slowNumberOfFrames: false,
11756
+ keyframes: false
11757
+ };
11758
+ return emittedFields;
11759
+ };
11760
+
11761
+ // src/state/keyframes.ts
11762
+ var keyframesState = () => {
11763
+ const keyframes = [];
11764
+ return {
11765
+ addKeyframe: (keyframe) => {
11766
+ keyframes.push(keyframe);
11767
+ },
11768
+ getKeyframes: () => {
11769
+ return keyframes;
11770
+ }
11771
+ };
11772
+ };
11773
+
11774
+ // src/state/riff.ts
11775
+ var riffSpecificState = () => {
11776
+ let avcProfile = null;
11777
+ let nextTrackIndex = 0;
11778
+ const profileCallbacks = [];
11779
+ const registerOnAvcProfileCallback = (callback) => {
11780
+ profileCallbacks.push(callback);
11781
+ };
11782
+ const onProfile = async (profile) => {
11783
+ avcProfile = profile;
11784
+ for (const callback of profileCallbacks) {
11785
+ await callback(profile);
11786
+ }
11787
+ profileCallbacks.length = 0;
11788
+ };
11789
+ return {
11790
+ getAvcProfile: () => {
11791
+ return avcProfile;
11792
+ },
11793
+ onProfile,
11794
+ registerOnAvcProfileCallback,
11795
+ getNextTrackIndex: () => {
11796
+ return nextTrackIndex;
11797
+ },
11798
+ incrementNextTrackIndex: () => {
11799
+ nextTrackIndex++;
11800
+ }
11801
+ };
11802
+ };
11803
+
11488
11804
  // src/state/can-skip-tracks.ts
11489
11805
  var needsTracksField = {
11490
11806
  audioCodec: true,
11491
11807
  container: false,
11492
11808
  dimensions: true,
11493
11809
  durationInSeconds: true,
11810
+ slowDurationInSeconds: true,
11811
+ slowFps: true,
11494
11812
  fps: true,
11495
11813
  internalStats: false,
11496
11814
  isHdr: true,
@@ -11503,7 +11821,10 @@ var needsTracksField = {
11503
11821
  videoCodec: true,
11504
11822
  metadata: true,
11505
11823
  location: true,
11506
- mimeType: false
11824
+ mimeType: false,
11825
+ slowKeyframes: true,
11826
+ slowNumberOfFrames: true,
11827
+ keyframes: true
11507
11828
  };
11508
11829
  var makeCanSkipTracksState = ({
11509
11830
  hasAudioTrackHandlers,
@@ -11546,92 +11867,28 @@ var makeTracksSectionState = (canSkipTracksState) => {
11546
11867
  };
11547
11868
  };
11548
11869
 
11549
- // src/state/parser-state.ts
11550
- var makeParserState = ({
11870
+ // src/state/sample-callbacks.ts
11871
+ var sampleCallback = ({
11872
+ signal,
11551
11873
  hasAudioTrackHandlers,
11552
11874
  hasVideoTrackHandlers,
11553
- signal,
11554
- getIterator,
11555
- fields
11875
+ fields,
11876
+ keyframes,
11877
+ emittedFields,
11878
+ slowDurationAndFpsState
11556
11879
  }) => {
11557
- const trackEntries = {};
11558
- const onTrackEntrySegment = (trackEntry2) => {
11559
- const trackId = getTrackId(trackEntry2);
11560
- if (!trackId) {
11561
- throw new Error("Expected track id");
11562
- }
11563
- if (trackEntries[trackId]) {
11564
- return;
11565
- }
11566
- const codec = getTrackCodec(trackEntry2);
11567
- if (!codec) {
11568
- throw new Error("Expected codec");
11569
- }
11570
- const trackTimescale = getTrackTimestampScale(trackEntry2);
11571
- trackEntries[trackId] = {
11572
- codec: codec.value,
11573
- trackTimescale: trackTimescale?.value ?? null
11574
- };
11575
- };
11576
11880
  const videoSampleCallbacks = {};
11577
11881
  const audioSampleCallbacks = {};
11578
11882
  const queuedAudioSamples = {};
11579
11883
  const queuedVideoSamples = {};
11580
- let timescale2 = null;
11581
- let skippedBytes = 0;
11582
- const getTimescale = () => {
11583
- if (timescale2 === null) {
11584
- return 1e6;
11585
- }
11586
- return timescale2;
11587
- };
11588
- const increaseSkippedBytes = (bytes) => {
11589
- skippedBytes += bytes;
11590
- };
11591
- const setTimescale = (newTimescale) => {
11592
- timescale2 = newTimescale;
11593
- };
11594
- const timestampMap = new Map;
11595
- const setTimestampOffset = (byteOffset, timestamp) => {
11596
- timestampMap.set(byteOffset, timestamp);
11597
- };
11598
- const getTimestampOffsetForByteOffset = (byteOffset) => {
11599
- const entries = Array.from(timestampMap.entries());
11600
- const sortedByByteOffset = entries.sort((a, b) => {
11601
- return a[0] - b[0];
11602
- }).reverse();
11603
- for (const [offset, timestamp] of sortedByByteOffset) {
11604
- if (offset >= byteOffset) {
11605
- continue;
11606
- }
11607
- return timestamp;
11608
- }
11609
- return timestampMap.get(byteOffset);
11610
- };
11611
- const samplesForTrack = {};
11612
- const profileCallbacks = [];
11613
- const registerOnAvcProfileCallback = (callback) => {
11614
- profileCallbacks.push(callback);
11615
- };
11616
- let avcProfile = null;
11617
- const onProfile = async (profile) => {
11618
- avcProfile = profile;
11619
- for (const callback of profileCallbacks) {
11620
- await callback(profile);
11621
- }
11622
- profileCallbacks.length = 0;
11623
- };
11624
11884
  const canSkipTracksState = makeCanSkipTracksState({
11625
11885
  hasAudioTrackHandlers,
11626
11886
  fields,
11627
11887
  hasVideoTrackHandlers
11628
11888
  });
11629
11889
  const tracksState = makeTracksSectionState(canSkipTracksState);
11890
+ const samplesForTrack = {};
11630
11891
  return {
11631
- onTrackEntrySegment,
11632
- onProfile,
11633
- registerOnAvcProfileCallback,
11634
- getTrackInfoByNumber: (id) => trackEntries[id],
11635
11892
  registerVideoSampleCallback: async (id, callback) => {
11636
11893
  if (callback === null) {
11637
11894
  delete videoSampleCallbacks[id];
@@ -11643,19 +11900,6 @@ var makeParserState = ({
11643
11900
  }
11644
11901
  queuedVideoSamples[id] = [];
11645
11902
  },
11646
- setTimestampOffset,
11647
- getTimestampOffsetForByteOffset,
11648
- registerAudioSampleCallback: async (id, callback) => {
11649
- if (callback === null) {
11650
- delete audioSampleCallbacks[id];
11651
- return;
11652
- }
11653
- audioSampleCallbacks[id] = callback;
11654
- for (const queued of queuedAudioSamples[id] ?? []) {
11655
- await callback(queued);
11656
- }
11657
- queuedAudioSamples[id] = [];
11658
- },
11659
11903
  onAudioSample: async (trackId, audioSample) => {
11660
11904
  if (signal?.aborted) {
11661
11905
  throw new Error("Aborted");
@@ -11669,6 +11913,9 @@ var makeParserState = ({
11669
11913
  await callback(audioSample);
11670
11914
  }
11671
11915
  },
11916
+ getSamplesForTrack: (trackId) => {
11917
+ return samplesForTrack[trackId] ?? 0;
11918
+ },
11672
11919
  onVideoSample: async (trackId, videoSample) => {
11673
11920
  if (signal?.aborted) {
11674
11921
  throw new Error("Aborted");
@@ -11678,29 +11925,200 @@ var makeParserState = ({
11678
11925
  }
11679
11926
  samplesForTrack[trackId]++;
11680
11927
  const callback = videoSampleCallbacks[trackId];
11681
- if (callback) {
11928
+ if (callback && videoSample.data.length > 0) {
11682
11929
  await callback(videoSample);
11683
11930
  }
11931
+ if (needsToIterateOverSamples({
11932
+ fields,
11933
+ emittedFields
11934
+ })) {
11935
+ if (fields.slowKeyframes && videoSample.type === "key") {
11936
+ keyframes.addKeyframe({
11937
+ trackId,
11938
+ decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
11939
+ positionInBytes: videoSample.offset,
11940
+ presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
11941
+ sizeInBytes: videoSample.data.length
11942
+ });
11943
+ }
11944
+ slowDurationAndFpsState.addSample(videoSample);
11945
+ }
11684
11946
  },
11685
- getTimescale,
11686
- setTimescale,
11687
- getSamplesForTrack: (trackId) => {
11688
- return samplesForTrack[trackId] ?? 0;
11947
+ canSkipTracksState,
11948
+ registerAudioSampleCallback: async (id, callback) => {
11949
+ if (callback === null) {
11950
+ delete audioSampleCallbacks[id];
11951
+ return;
11952
+ }
11953
+ audioSampleCallbacks[id] = callback;
11954
+ for (const queued of queuedAudioSamples[id] ?? []) {
11955
+ await callback(queued);
11956
+ }
11957
+ queuedAudioSamples[id] = [];
11689
11958
  },
11690
- getAvcProfile: () => {
11691
- return avcProfile;
11959
+ tracks: tracksState,
11960
+ audioSampleCallbacks,
11961
+ videoSampleCallbacks
11962
+ };
11963
+ };
11964
+
11965
+ // src/state/slow-duration-fps.ts
11966
+ var slowDurationAndFpsState = () => {
11967
+ let smallestSample;
11968
+ let largestSample;
11969
+ let samples = 0;
11970
+ const getSlowDurationInSeconds = () => {
11971
+ if (smallestSample !== undefined && largestSample !== undefined) {
11972
+ const startingTimestampDifference = largestSample - smallestSample;
11973
+ const timeBetweenSamples = startingTimestampDifference / (samples - 1);
11974
+ return timeBetweenSamples * samples;
11975
+ }
11976
+ throw new Error("No samples");
11977
+ };
11978
+ return {
11979
+ addSample: (videoSample) => {
11980
+ samples++;
11981
+ const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
11982
+ if (largestSample === undefined || presentationTimeInSeconds > largestSample) {
11983
+ largestSample = presentationTimeInSeconds;
11984
+ }
11985
+ if (smallestSample === undefined || presentationTimeInSeconds < smallestSample) {
11986
+ smallestSample = presentationTimeInSeconds;
11987
+ }
11988
+ },
11989
+ getSlowDurationInSeconds,
11990
+ getFps: () => {
11991
+ return samples / getSlowDurationInSeconds();
11992
+ },
11993
+ getSlowNumberOfFrames: () => samples
11994
+ };
11995
+ };
11996
+
11997
+ // src/state/structure.ts
11998
+ var structureState = () => {
11999
+ let structure = null;
12000
+ return {
12001
+ getStructureOrNull: () => {
12002
+ return structure;
12003
+ },
12004
+ getStructure: () => {
12005
+ if (structure === null) {
12006
+ throw new Error("Expected structure");
12007
+ }
12008
+ return structure;
11692
12009
  },
12010
+ setStructure: (value) => {
12011
+ structure = value;
12012
+ }
12013
+ };
12014
+ };
12015
+
12016
+ // src/state/webm.ts
12017
+ var webmState = () => {
12018
+ const trackEntries = {};
12019
+ const onTrackEntrySegment = (trackEntry2) => {
12020
+ const trackId = getTrackId(trackEntry2);
12021
+ if (!trackId) {
12022
+ throw new Error("Expected track id");
12023
+ }
12024
+ if (trackEntries[trackId]) {
12025
+ return;
12026
+ }
12027
+ const codec = getTrackCodec(trackEntry2);
12028
+ if (!codec) {
12029
+ throw new Error("Expected codec");
12030
+ }
12031
+ const trackTimescale = getTrackTimestampScale(trackEntry2);
12032
+ trackEntries[trackId] = {
12033
+ codec: codec.value,
12034
+ trackTimescale: trackTimescale?.value ?? null
12035
+ };
12036
+ };
12037
+ const timestampMap = new Map;
12038
+ const getTimestampOffsetForByteOffset = (byteOffset) => {
12039
+ const entries = Array.from(timestampMap.entries());
12040
+ const sortedByByteOffset = entries.sort((a, b) => {
12041
+ return a[0] - b[0];
12042
+ }).reverse();
12043
+ for (const [offset, timestamp] of sortedByByteOffset) {
12044
+ if (offset >= byteOffset) {
12045
+ continue;
12046
+ }
12047
+ return timestamp;
12048
+ }
12049
+ return timestampMap.get(byteOffset);
12050
+ };
12051
+ const setTimestampOffset = (byteOffset, timestamp) => {
12052
+ timestampMap.set(byteOffset, timestamp);
12053
+ };
12054
+ let timescale2 = null;
12055
+ const setTimescale = (newTimescale) => {
12056
+ timescale2 = newTimescale;
12057
+ };
12058
+ const getTimescale = () => {
12059
+ if (timescale2 === null) {
12060
+ return 1e6;
12061
+ }
12062
+ return timescale2;
12063
+ };
12064
+ return {
12065
+ onTrackEntrySegment,
12066
+ getTrackInfoByNumber: (id) => trackEntries[id],
12067
+ setTimestampOffset,
12068
+ getTimestampOffsetForByteOffset,
12069
+ timescale: timescale2,
12070
+ getTimescale,
12071
+ setTimescale
12072
+ };
12073
+ };
12074
+
12075
+ // src/state/parser-state.ts
12076
+ var makeParserState = ({
12077
+ hasAudioTrackHandlers,
12078
+ hasVideoTrackHandlers,
12079
+ signal,
12080
+ getIterator,
12081
+ fields,
12082
+ nullifySamples,
12083
+ onAudioTrack,
12084
+ onVideoTrack,
12085
+ supportsContentRange
12086
+ }) => {
12087
+ let skippedBytes = 0;
12088
+ const increaseSkippedBytes = (bytes) => {
12089
+ skippedBytes += bytes;
12090
+ };
12091
+ const structure = structureState();
12092
+ const keyframes = keyframesState();
12093
+ const emittedFields = emittedState();
12094
+ const slowDurationAndFps = slowDurationAndFpsState();
12095
+ return {
12096
+ riff: riffSpecificState(),
12097
+ callbacks: sampleCallback({
12098
+ signal,
12099
+ hasAudioTrackHandlers,
12100
+ hasVideoTrackHandlers,
12101
+ fields,
12102
+ keyframes,
12103
+ emittedFields,
12104
+ slowDurationAndFpsState: slowDurationAndFps
12105
+ }),
11693
12106
  getInternalStats: () => ({
11694
12107
  skippedBytes,
11695
12108
  finalCursorOffset: getIterator()?.counter.getOffset() ?? 0
11696
12109
  }),
11697
12110
  getSkipBytes: () => skippedBytes,
11698
12111
  increaseSkippedBytes,
11699
- maySkipVideoData: () => {
11700
- return tracksState.hasAllTracks() && Object.values(videoSampleCallbacks).length === 0 && Object.values(audioSampleCallbacks).length === 0;
11701
- },
11702
- tracks: tracksState,
11703
- canSkipTracksState
12112
+ keyframes,
12113
+ structure,
12114
+ nullifySamples,
12115
+ onAudioTrack,
12116
+ onVideoTrack,
12117
+ supportsContentRange,
12118
+ webm: webmState(),
12119
+ emittedFields,
12120
+ fields,
12121
+ slowDurationAndFps
11704
12122
  };
11705
12123
  };
11706
12124
 
@@ -11723,13 +12141,6 @@ var parseMedia = async function({
11723
12141
  fields: fieldsInReturnValue,
11724
12142
  callbacks: more
11725
12143
  });
11726
- const state = makeParserState({
11727
- hasAudioTrackHandlers: Boolean(onAudioTrack),
11728
- hasVideoTrackHandlers: Boolean(onVideoTrack),
11729
- signal,
11730
- getIterator: () => iterator,
11731
- fields
11732
- });
11733
12144
  const {
11734
12145
  reader,
11735
12146
  contentLength,
@@ -11737,41 +12148,24 @@ var parseMedia = async function({
11737
12148
  contentType,
11738
12149
  supportsContentRange: readerSupportsContentRange
11739
12150
  } = await readerInterface.read(src, null, signal);
11740
- let currentReader = reader;
11741
- const emittedFields = {
11742
- audioCodec: false,
11743
- container: false,
11744
- dimensions: false,
11745
- durationInSeconds: false,
11746
- fps: false,
11747
- internalStats: false,
11748
- isHdr: false,
11749
- location: false,
11750
- metadata: false,
11751
- mimeType: false,
11752
- name: false,
11753
- rotation: false,
11754
- size: false,
11755
- structure: false,
11756
- tracks: false,
11757
- videoCodec: false,
11758
- unrotatedDimensions: false
11759
- };
11760
12151
  const supportsContentRange = readerSupportsContentRange && !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.DISABLE_CONTENT_RANGE === "true");
11761
- const returnValue = {};
11762
- const moreFields = more;
11763
- const options = {
12152
+ const state = makeParserState({
12153
+ hasAudioTrackHandlers: Boolean(onAudioTrack),
12154
+ hasVideoTrackHandlers: Boolean(onVideoTrack),
12155
+ signal,
12156
+ getIterator: () => iterator,
12157
+ fields,
11764
12158
  onAudioTrack: onAudioTrack ?? null,
11765
12159
  onVideoTrack: onVideoTrack ?? null,
11766
- parserState: state,
11767
12160
  nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
11768
- supportsContentRange,
11769
- nextTrackIndex: 0
11770
- };
12161
+ supportsContentRange
12162
+ });
12163
+ let currentReader = reader;
12164
+ const returnValue = {};
12165
+ const moreFields = more;
11771
12166
  const triggerInfoEmit = () => {
11772
12167
  const availableInfo = getAvailableInfo({
11773
12168
  fieldsToFetch: fields,
11774
- structure: parseResult?.segments ?? null,
11775
12169
  state
11776
12170
  });
11777
12171
  emitAvailableInfo({
@@ -11783,8 +12177,7 @@ var parseMedia = async function({
11783
12177
  returnValue,
11784
12178
  contentLength,
11785
12179
  name,
11786
- mimeType: contentType,
11787
- emittedFields
12180
+ mimeType: contentType
11788
12181
  });
11789
12182
  };
11790
12183
  triggerInfoEmit();
@@ -11821,12 +12214,12 @@ var parseMedia = async function({
11821
12214
  });
11822
12215
  triggerInfoEmit();
11823
12216
  if (parseResult && parseResult.status === "incomplete") {
11824
- Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
12217
+ Log.trace(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
11825
12218
  parseResult = await parseResult.continueParsing();
11826
12219
  } else {
11827
12220
  parseResult = await parseVideo({
11828
12221
  iterator,
11829
- options,
12222
+ state,
11830
12223
  signal: signal ?? null,
11831
12224
  logLevel,
11832
12225
  fields,
@@ -11840,7 +12233,6 @@ var parseMedia = async function({
11840
12233
  }
11841
12234
  if (hasAllInfo({
11842
12235
  fields,
11843
- structure: parseResult.segments,
11844
12236
  state
11845
12237
  })) {
11846
12238
  Log.verbose(logLevel, "Got all info, skipping to the end.");
@@ -11880,12 +12272,11 @@ var parseMedia = async function({
11880
12272
  returnValue,
11881
12273
  contentLength,
11882
12274
  mimeType: contentType,
11883
- name,
11884
- emittedFields
12275
+ name
11885
12276
  });
11886
12277
  currentReader.abort();
11887
12278
  iterator?.destroy();
11888
- state.tracks.ensureHasTracksAtEnd();
12279
+ state.callbacks.tracks.ensureHasTracksAtEnd();
11889
12280
  return returnValue;
11890
12281
  };
11891
12282
  // src/index.ts