@remotion/media-parser 4.0.241 → 4.0.243

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