@remotion/media-parser 4.0.240 → 4.0.242

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. package/dist/add-avc-profile-to-track.js +2 -2
  2. package/dist/boxes/avc/codec-private.d.ts +1 -1
  3. package/dist/boxes/avc/codec-private.js +2 -2
  4. package/dist/boxes/avc/create-sps-pps-data.d.ts +2 -0
  5. package/dist/boxes/avc/create-sps-pps-data.js +28 -0
  6. package/dist/boxes/iso-base-media/get-keyframes.d.ts +3 -0
  7. package/dist/boxes/iso-base-media/get-keyframes.js +30 -0
  8. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +3 -3
  9. package/dist/boxes/iso-base-media/mdat/mdat.js +9 -5
  10. package/dist/boxes/iso-base-media/moov/moov.d.ts +3 -3
  11. package/dist/boxes/iso-base-media/moov/moov.js +5 -4
  12. package/dist/boxes/iso-base-media/process-box.d.ts +9 -9
  13. package/dist/boxes/iso-base-media/process-box.js +48 -56
  14. package/dist/boxes/iso-base-media/stsd/mebx.d.ts +3 -3
  15. package/dist/boxes/iso-base-media/stsd/mebx.js +5 -4
  16. package/dist/boxes/iso-base-media/stsd/samples.d.ts +5 -5
  17. package/dist/boxes/iso-base-media/stsd/samples.js +19 -16
  18. package/dist/boxes/iso-base-media/stsd/stsd.d.ts +3 -3
  19. package/dist/boxes/iso-base-media/stsd/stsd.js +2 -2
  20. package/dist/boxes/iso-base-media/trak/trak.d.ts +3 -3
  21. package/dist/boxes/iso-base-media/trak/trak.js +7 -6
  22. package/dist/boxes/riff/expect-riff-box.d.ts +3 -3
  23. package/dist/boxes/riff/expect-riff-box.js +5 -5
  24. package/dist/boxes/riff/get-tracks-from-avi.js +1 -1
  25. package/dist/boxes/riff/parse-box.d.ts +7 -7
  26. package/dist/boxes/riff/parse-box.js +29 -24
  27. package/dist/boxes/riff/parse-list-box.d.ts +3 -3
  28. package/dist/boxes/riff/parse-list-box.js +2 -2
  29. package/dist/boxes/riff/parse-movi.d.ts +5 -5
  30. package/dist/boxes/riff/parse-movi.js +35 -20
  31. package/dist/boxes/riff/parse-riff-box.d.ts +3 -3
  32. package/dist/boxes/riff/parse-riff-box.js +2 -2
  33. package/dist/boxes/transport-stream/adts-header.d.ts +1 -1
  34. package/dist/boxes/transport-stream/discard-rest-of-packet.d.ts +1 -1
  35. package/dist/boxes/transport-stream/get-tracks.js +1 -1
  36. package/dist/boxes/transport-stream/handle-aac-packet.d.ts +4 -3
  37. package/dist/boxes/transport-stream/handle-aac-packet.js +6 -4
  38. package/dist/boxes/transport-stream/handle-avc-packet.d.ts +4 -3
  39. package/dist/boxes/transport-stream/handle-avc-packet.js +8 -6
  40. package/dist/boxes/transport-stream/parse-packet.d.ts +3 -3
  41. package/dist/boxes/transport-stream/parse-packet.js +2 -2
  42. package/dist/boxes/transport-stream/parse-stream-packet.d.ts +3 -3
  43. package/dist/boxes/transport-stream/parse-stream-packet.js +14 -7
  44. package/dist/boxes/transport-stream/parse-transport-stream.d.ts +5 -6
  45. package/dist/boxes/transport-stream/parse-transport-stream.js +10 -9
  46. package/dist/boxes/transport-stream/process-stream-buffers.d.ts +6 -5
  47. package/dist/boxes/transport-stream/process-stream-buffers.js +18 -8
  48. package/dist/boxes/webm/ebml.d.ts +1 -1
  49. package/dist/boxes/webm/get-sample-from-block.d.ts +2 -2
  50. package/dist/boxes/webm/get-sample-from-block.js +8 -4
  51. package/dist/boxes/webm/make-header.d.ts +3 -3
  52. package/dist/boxes/webm/parse-ebml.d.ts +4 -4
  53. package/dist/boxes/webm/parse-ebml.js +18 -18
  54. package/dist/boxes/webm/parse-webm-header.d.ts +5 -5
  55. package/dist/boxes/webm/parse-webm-header.js +6 -5
  56. package/dist/boxes/webm/segments/parse-children.d.ts +5 -5
  57. package/dist/boxes/webm/segments/parse-children.js +12 -13
  58. package/dist/boxes/webm/segments.d.ts +3 -3
  59. package/dist/boxes/webm/segments.js +13 -13
  60. package/dist/buffer-iterator.d.ts +2 -6
  61. package/dist/buffer-iterator.js +4 -29
  62. package/dist/convert-audio-or-video-sample.js +2 -0
  63. package/dist/create/iso-base-media/codec-specific/avc1.d.ts +1 -1
  64. package/dist/create/iso-base-media/codec-specific/create-codec-specific-data.d.ts +1 -1
  65. package/dist/create/iso-base-media/codec-specific/mp4a.d.ts +1 -1
  66. package/dist/create/iso-base-media/create-colr.d.ts +1 -1
  67. package/dist/create/iso-base-media/create-ftyp.d.ts +2 -2
  68. package/dist/create/iso-base-media/create-ilst.d.ts +1 -1
  69. package/dist/create/iso-base-media/create-mdia.d.ts +1 -1
  70. package/dist/create/iso-base-media/create-moov.d.ts +1 -1
  71. package/dist/create/iso-base-media/create-mvhd.d.ts +1 -1
  72. package/dist/create/iso-base-media/create-trak.d.ts +1 -1
  73. package/dist/create/iso-base-media/create-udta.d.ts +1 -1
  74. package/dist/create/iso-base-media/create-url.d.ts +1 -1
  75. package/dist/create/iso-base-media/ilst/create-cmt.d.ts +1 -1
  76. package/dist/create/iso-base-media/ilst/create-too.d.ts +1 -1
  77. package/dist/create/iso-base-media/mdia/create-mdhd.d.ts +1 -1
  78. package/dist/create/iso-base-media/mp4-header.d.ts +1 -1
  79. package/dist/create/iso-base-media/primitives.d.ts +13 -13
  80. package/dist/create/iso-base-media/serialize-track.d.ts +1 -1
  81. package/dist/create/iso-base-media/trak/create-tkhd.d.ts +2 -2
  82. package/dist/create/iso-base-media/trak/mdia/create-minf.d.ts +1 -1
  83. package/dist/create/iso-base-media/trak/mdia/minf/create-dinf.d.ts +1 -1
  84. package/dist/create/iso-base-media/trak/mdia/minf/create-smhd.d.ts +1 -1
  85. package/dist/create/iso-base-media/trak/mdia/minf/create-stbl.d.ts +1 -1
  86. package/dist/create/iso-base-media/trak/mdia/minf/create-vmhd.d.ts +1 -1
  87. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-ctts.d.ts +1 -1
  88. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stco.d.ts +1 -1
  89. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stsc.d.ts +1 -1
  90. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stss.d.ts +1 -1
  91. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stsz.d.ts +1 -1
  92. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stts.d.ts +1 -1
  93. package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avc1.d.ts +1 -1
  94. package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-avcc.d.ts +1 -1
  95. package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-pasp.d.ts +1 -1
  96. package/dist/create/iso-base-media/udta/create-meta.d.ts +1 -1
  97. package/dist/create/iso-base-media/udta/meta/create-hdlr.d.ts +1 -1
  98. package/dist/create/matroska/cluster-segment.d.ts +1 -1
  99. package/dist/emit-available-info.d.ts +6 -4
  100. package/dist/emit-available-info.js +231 -79
  101. package/dist/errors/detect-file-type.d.ts +1 -0
  102. package/dist/errors/detect-file-type.js +88 -0
  103. package/dist/errors/file-types.d.ts +1 -0
  104. package/dist/errors/file-types.js +88 -0
  105. package/dist/errors.d.ts +68 -0
  106. package/dist/errors.js +71 -0
  107. package/dist/esm/from-fetch.mjs +1 -0
  108. package/dist/esm/from-node.mjs +1 -0
  109. package/dist/esm/from-web-file.mjs +2 -1
  110. package/dist/esm/index.mjs +1457 -542
  111. package/dist/file-types/bmp.d.ts +6 -0
  112. package/dist/file-types/bmp.js +23 -0
  113. package/dist/file-types/detect-file-type.d.ts +42 -0
  114. package/dist/file-types/detect-file-type.js +59 -0
  115. package/dist/file-types/get-jpeg-dimensions.d.ts +4 -0
  116. package/dist/file-types/get-jpeg-dimensions.js +32 -0
  117. package/dist/file-types/index.d.ts +2 -0
  118. package/dist/file-types/index.js +57 -0
  119. package/dist/file-types/jpeg.d.ts +12 -0
  120. package/dist/file-types/jpeg.js +44 -0
  121. package/dist/file-types/pdf.d.ts +4 -0
  122. package/dist/file-types/pdf.js +12 -0
  123. package/dist/file-types/png.d.ts +10 -0
  124. package/dist/file-types/png.js +32 -0
  125. package/dist/file-types/webp.d.ts +6 -0
  126. package/dist/file-types/webp.js +69 -0
  127. package/dist/file-types.d.ts +1 -0
  128. package/dist/file-types.js +88 -0
  129. package/dist/get-audio-codec.d.ts +1 -1
  130. package/dist/get-duration.d.ts +1 -0
  131. package/dist/get-duration.js +14 -1
  132. package/dist/get-fields-from-callbacks.d.ts +5 -0
  133. package/dist/get-fields-from-callbacks.js +32 -0
  134. package/dist/get-fps.d.ts +1 -0
  135. package/dist/get-fps.js +17 -12
  136. package/dist/get-keyframes.d.ts +5 -0
  137. package/dist/get-keyframes.js +20 -0
  138. package/dist/get-tracks.d.ts +7 -1
  139. package/dist/get-tracks.js +15 -10
  140. package/dist/has-all-info.d.ts +5 -4
  141. package/dist/has-all-info.js +31 -5
  142. package/dist/index.d.ts +2 -0
  143. package/dist/index.js +7 -1
  144. package/dist/may-skip-video-data/may-skip-video-data.d.ts +4 -0
  145. package/dist/may-skip-video-data/may-skip-video-data.js +14 -0
  146. package/dist/may-skip-video-data/need-samples-for-fields.d.ts +5 -0
  147. package/dist/may-skip-video-data/need-samples-for-fields.js +33 -0
  148. package/dist/options.d.ts +68 -53
  149. package/dist/parse-media.js +42 -31
  150. package/dist/parse-result.d.ts +2 -4
  151. package/dist/parse-video.d.ts +8 -5
  152. package/dist/parse-video.js +94 -17
  153. package/dist/probing/detect-file-type.d.ts +1 -0
  154. package/dist/probing/detect-file-type.js +88 -0
  155. package/dist/probing/get-jpeg-dimensions.d.ts +4 -0
  156. package/dist/probing/get-jpeg-dimensions.js +32 -0
  157. package/dist/readers/from-fetch.js +1 -0
  158. package/dist/readers/from-node.js +1 -0
  159. package/dist/readers/from-web-file.js +1 -0
  160. package/dist/readers/reader.d.ts +1 -0
  161. package/dist/register-track.d.ts +5 -5
  162. package/dist/register-track.js +12 -12
  163. package/dist/state/can-skip-tracks.js +6 -0
  164. package/dist/state/emitted-fields.d.ts +2 -0
  165. package/dist/state/emitted-fields.js +31 -0
  166. package/dist/state/has-tracks-section.d.ts +1 -0
  167. package/dist/state/keyframes.d.ts +6 -0
  168. package/dist/state/keyframes.js +15 -0
  169. package/dist/state/parser-state.d.ts +60 -29
  170. package/dist/state/parser-state.js +32 -150
  171. package/dist/state/riff.d.ts +10 -0
  172. package/dist/state/riff.js +32 -0
  173. package/dist/state/sample-callbacks.d.ts +31 -0
  174. package/dist/state/sample-callbacks.js +96 -0
  175. package/dist/state/slow-duration-fps.d.ts +8 -0
  176. package/dist/state/slow-duration-fps.js +36 -0
  177. package/dist/state/structure.d.ts +7 -0
  178. package/dist/state/structure.js +21 -0
  179. package/dist/state/tracks-and-samples.d.ts +0 -0
  180. package/dist/state/tracks-and-samples.js +1 -0
  181. package/dist/state/webm.d.ts +11 -0
  182. package/dist/state/webm.js +67 -0
  183. package/dist/version.d.ts +1 -1
  184. package/dist/version.js +1 -1
  185. package/dist/webcodec-sample-types.d.ts +2 -0
  186. package/package.json +3 -3
@@ -83,6 +83,7 @@ var fetchReader = {
83
83
  }
84
84
  },
85
85
  contentLength,
86
+ contentType: res.headers.get("content-type"),
86
87
  name: name ?? fallbackName,
87
88
  supportsContentRange
88
89
  };
@@ -1366,7 +1367,7 @@ var createIsoBaseMediaFtyp = ({
1366
1367
  };
1367
1368
 
1368
1369
  // src/version.ts
1369
- var VERSION = "4.0.240";
1370
+ var VERSION = "4.0.242";
1370
1371
 
1371
1372
  // src/create/iso-base-media/create-ilst.ts
1372
1373
  var createIlst = (items) => {
@@ -3529,6 +3530,120 @@ var createWav = async ({
3529
3530
  };
3530
3531
  };
3531
3532
 
3533
+ // src/errors.ts
3534
+ class IsAGifError extends Error {
3535
+ mimeType;
3536
+ sizeInBytes;
3537
+ fileName;
3538
+ constructor({
3539
+ message,
3540
+ mimeType,
3541
+ sizeInBytes,
3542
+ fileName
3543
+ }) {
3544
+ super(message);
3545
+ this.fileName = "IsAGifError";
3546
+ this.mimeType = mimeType;
3547
+ this.sizeInBytes = sizeInBytes;
3548
+ this.fileName = fileName;
3549
+ if (Error.captureStackTrace) {
3550
+ Error.captureStackTrace(this, IsAGifError);
3551
+ }
3552
+ }
3553
+ }
3554
+
3555
+ class IsAnImageError extends Error {
3556
+ imageType;
3557
+ dimensions;
3558
+ mimeType;
3559
+ sizeInBytes;
3560
+ fileName;
3561
+ constructor({
3562
+ dimensions,
3563
+ imageType,
3564
+ message,
3565
+ mimeType,
3566
+ sizeInBytes,
3567
+ fileName
3568
+ }) {
3569
+ super(message);
3570
+ this.name = "IsAnImageError";
3571
+ this.imageType = imageType;
3572
+ this.dimensions = dimensions;
3573
+ this.mimeType = mimeType;
3574
+ this.sizeInBytes = sizeInBytes;
3575
+ this.fileName = fileName;
3576
+ if (Error.captureStackTrace) {
3577
+ Error.captureStackTrace(this, IsAnImageError);
3578
+ }
3579
+ }
3580
+ }
3581
+
3582
+ class IsAPdfError extends Error {
3583
+ mimeType;
3584
+ sizeInBytes;
3585
+ fileName;
3586
+ constructor({
3587
+ message,
3588
+ mimeType,
3589
+ sizeInBytes,
3590
+ fileName
3591
+ }) {
3592
+ super(message);
3593
+ this.name = "IsAPdfError";
3594
+ this.mimeType = mimeType;
3595
+ this.sizeInBytes = sizeInBytes;
3596
+ this.fileName = fileName;
3597
+ if (Error.captureStackTrace) {
3598
+ Error.captureStackTrace(this, IsAPdfError);
3599
+ }
3600
+ }
3601
+ }
3602
+
3603
+ class IsAnUnsupportedFileTypeError extends Error {
3604
+ mimeType;
3605
+ sizeInBytes;
3606
+ fileName;
3607
+ constructor({
3608
+ message,
3609
+ mimeType,
3610
+ sizeInBytes,
3611
+ fileName
3612
+ }) {
3613
+ super(message);
3614
+ this.name = "IsAnUnsupportedFileTypeError";
3615
+ this.mimeType = mimeType;
3616
+ this.sizeInBytes = sizeInBytes;
3617
+ this.fileName = fileName;
3618
+ if (Error.captureStackTrace) {
3619
+ Error.captureStackTrace(this, IsAnUnsupportedFileTypeError);
3620
+ }
3621
+ }
3622
+ }
3623
+
3624
+ class IsAnUnsupportedAudioTypeError extends Error {
3625
+ mimeType;
3626
+ sizeInBytes;
3627
+ fileName;
3628
+ audioType;
3629
+ constructor({
3630
+ message,
3631
+ mimeType,
3632
+ sizeInBytes,
3633
+ fileName,
3634
+ audioType
3635
+ }) {
3636
+ super(message);
3637
+ this.name = "IsAnUnsupportedAudioTypeError";
3638
+ this.mimeType = mimeType;
3639
+ this.sizeInBytes = sizeInBytes;
3640
+ this.fileName = fileName;
3641
+ this.audioType = audioType;
3642
+ if (Error.captureStackTrace) {
3643
+ Error.captureStackTrace(this, IsAnUnsupportedAudioTypeError);
3644
+ }
3645
+ }
3646
+ }
3532
3647
  // src/boxes/iso-base-media/traversal.ts
3533
3648
  var getMoovBox = (segments) => {
3534
3649
  const moovBox = segments.find((s) => s.type === "moov-box");
@@ -4012,19 +4127,22 @@ var getFps = (segments) => {
4012
4127
  }
4013
4128
  throw new Error("Cannot get fps, not implemented");
4014
4129
  };
4015
- var hasFps = (boxes) => {
4130
+ var hasFpsSuitedForSlowFps = (boxes) => {
4016
4131
  try {
4017
- if (boxes.type === "matroska") {
4018
- return true;
4019
- }
4020
- if (boxes.type === "transport-stream") {
4021
- return true;
4022
- }
4023
4132
  return getFps(boxes) !== null;
4024
4133
  } catch {
4025
4134
  return false;
4026
4135
  }
4027
4136
  };
4137
+ var hasFps = (boxes) => {
4138
+ if (boxes.type === "matroska") {
4139
+ return true;
4140
+ }
4141
+ if (boxes.type === "transport-stream") {
4142
+ return true;
4143
+ }
4144
+ return hasFpsSuitedForSlowFps(boxes);
4145
+ };
4028
4146
 
4029
4147
  // src/get-audio-codec.ts
4030
4148
  var getAudioCodec = (boxes, parserState) => {
@@ -4358,6 +4476,234 @@ var getPrimariesFromIndex = (index) => {
4358
4476
  return index === 1 ? "bt709" : index === 5 ? "bt470bg" : index === 6 ? "smpte170m" : index === 9 ? "bt2020" : null;
4359
4477
  };
4360
4478
 
4479
+ // src/file-types/detect-file-type.ts
4480
+ var matchesPattern = (pattern) => {
4481
+ return (data) => {
4482
+ return pattern.every((value, index) => data[index] === value);
4483
+ };
4484
+ };
4485
+ var isRiffAvi2 = (data) => {
4486
+ const riffPattern = new Uint8Array([82, 73, 70, 70]);
4487
+ if (!matchesPattern(riffPattern)(data.subarray(0, 4))) {
4488
+ return false;
4489
+ }
4490
+ const fileType = data.subarray(8, 12);
4491
+ return new TextDecoder().decode(fileType) === "AVI ";
4492
+ };
4493
+ var isRiffWave = (data) => {
4494
+ const riffPattern = new Uint8Array([82, 73, 70, 70]);
4495
+ if (!matchesPattern(riffPattern)(data.subarray(0, 4))) {
4496
+ return false;
4497
+ }
4498
+ const fileType = data.subarray(8, 12);
4499
+ return new TextDecoder().decode(fileType) === "WAVE";
4500
+ };
4501
+ var isWebm = (data) => {
4502
+ return matchesPattern(webmPattern)(data.subarray(0, 4));
4503
+ };
4504
+ var isIsoBaseMedia = (data) => {
4505
+ const isoBaseMediaMp4Pattern = new TextEncoder().encode("ftyp");
4506
+ return matchesPattern(isoBaseMediaMp4Pattern)(data.subarray(4, 8));
4507
+ };
4508
+ var isTransportStream = (data) => {
4509
+ return data[0] === 71 && data[188] === 71;
4510
+ };
4511
+ var isMp3 = (data) => {
4512
+ const mpegPattern = new Uint8Array([255, 243, 228, 100]);
4513
+ const id3Pattern = new Uint8Array([73, 68, 51, 3]);
4514
+ const subarray = data.subarray(0, 4);
4515
+ return matchesPattern(mpegPattern)(subarray) || matchesPattern(id3Pattern)(subarray);
4516
+ };
4517
+ var isGif = (data) => {
4518
+ const gifPattern = new Uint8Array([71, 73, 70, 56]);
4519
+ return matchesPattern(gifPattern)(data.subarray(0, 4));
4520
+ };
4521
+ var isAac = (data) => {
4522
+ const aacPattern = new Uint8Array([255, 241]);
4523
+ return matchesPattern(aacPattern)(data.subarray(0, 2));
4524
+ };
4525
+
4526
+ // src/file-types/bmp.ts
4527
+ function getBmpDimensions(bmpData) {
4528
+ if (bmpData.length < 26) {
4529
+ return null;
4530
+ }
4531
+ const view = new DataView(bmpData.buffer, bmpData.byteOffset);
4532
+ return {
4533
+ width: view.getUint32(18, true),
4534
+ height: Math.abs(view.getInt32(22, true))
4535
+ };
4536
+ }
4537
+ var isBmp = (data) => {
4538
+ const bmpPattern = new Uint8Array([66, 77]);
4539
+ if (matchesPattern(bmpPattern)(data.subarray(0, 2))) {
4540
+ const bmp = getBmpDimensions(data);
4541
+ return { dimensions: bmp, type: "bmp" };
4542
+ }
4543
+ return null;
4544
+ };
4545
+
4546
+ // src/file-types/jpeg.ts
4547
+ function getJpegDimensions(data) {
4548
+ let offset = 0;
4549
+ function readUint16BE(o) {
4550
+ return data[o] << 8 | data[o + 1];
4551
+ }
4552
+ if (readUint16BE(offset) !== 65496) {
4553
+ return null;
4554
+ }
4555
+ offset += 2;
4556
+ while (offset < data.length) {
4557
+ if (data[offset] === 255) {
4558
+ const marker = data[offset + 1];
4559
+ if (marker === 192 || marker === 194) {
4560
+ const height = readUint16BE(offset + 5);
4561
+ const width = readUint16BE(offset + 7);
4562
+ return { width, height };
4563
+ }
4564
+ const length = readUint16BE(offset + 2);
4565
+ offset += length + 2;
4566
+ } else {
4567
+ offset++;
4568
+ }
4569
+ }
4570
+ return null;
4571
+ }
4572
+ var isJpeg = (data) => {
4573
+ const jpegPattern = new Uint8Array([255, 216]);
4574
+ const jpeg = matchesPattern(jpegPattern)(data.subarray(0, 2));
4575
+ if (!jpeg) {
4576
+ return null;
4577
+ }
4578
+ const dim = getJpegDimensions(data);
4579
+ return { dimensions: dim, type: "jpeg" };
4580
+ };
4581
+
4582
+ // src/file-types/pdf.ts
4583
+ var isPdf = (data) => {
4584
+ if (data.length < 4) {
4585
+ return null;
4586
+ }
4587
+ const pdfPattern = new Uint8Array([37, 80, 68, 70]);
4588
+ return matchesPattern(pdfPattern)(data.subarray(0, 4)) ? { type: "pdf" } : null;
4589
+ };
4590
+
4591
+ // src/file-types/png.ts
4592
+ function getPngDimensions(pngData) {
4593
+ if (pngData.length < 24) {
4594
+ return null;
4595
+ }
4596
+ const view = new DataView(pngData.buffer, pngData.byteOffset);
4597
+ const pngSignature = [137, 80, 78, 71, 13, 10, 26, 10];
4598
+ for (let i = 0;i < 8; i++) {
4599
+ if (pngData[i] !== pngSignature[i]) {
4600
+ return null;
4601
+ }
4602
+ }
4603
+ return {
4604
+ width: view.getUint32(16, false),
4605
+ height: view.getUint32(20, false)
4606
+ };
4607
+ }
4608
+ var isPng = (data) => {
4609
+ const pngPattern = new Uint8Array([137, 80, 78, 71]);
4610
+ if (matchesPattern(pngPattern)(data.subarray(0, 4))) {
4611
+ const png = getPngDimensions(data);
4612
+ return { dimensions: png, type: "png" };
4613
+ }
4614
+ return null;
4615
+ };
4616
+
4617
+ // src/file-types/webp.ts
4618
+ function getWebPDimensions(bytes) {
4619
+ if (bytes.length < 30) {
4620
+ return null;
4621
+ }
4622
+ if (bytes[0] !== 82 || bytes[1] !== 73 || bytes[2] !== 70 || bytes[3] !== 70 || bytes[8] !== 87 || bytes[9] !== 69 || bytes[10] !== 66 || bytes[11] !== 80) {
4623
+ return null;
4624
+ }
4625
+ if (bytes[12] === 86 && bytes[13] === 80 && bytes[14] === 56) {
4626
+ if (bytes[15] === 32) {
4627
+ return {
4628
+ width: bytes[26] | bytes[27] << 8 & 16383,
4629
+ height: bytes[28] | bytes[29] << 8 & 16383
4630
+ };
4631
+ }
4632
+ }
4633
+ if (bytes[12] === 86 && bytes[13] === 80 && bytes[14] === 56 && bytes[15] === 76) {
4634
+ return {
4635
+ width: 1 + (bytes[21] | (bytes[22] & 63) << 8),
4636
+ height: 1 + ((bytes[22] & 192) >> 6 | bytes[23] << 2 | (bytes[24] & 15) << 10)
4637
+ };
4638
+ }
4639
+ if (bytes[12] === 86 && bytes[13] === 80 && bytes[14] === 56 && bytes[15] === 88) {
4640
+ return {
4641
+ width: 1 + (bytes[24] | bytes[25] << 8 | bytes[26] << 16),
4642
+ height: 1 + (bytes[27] | bytes[28] << 8 | bytes[29] << 16)
4643
+ };
4644
+ }
4645
+ return null;
4646
+ }
4647
+ var isWebp = (data) => {
4648
+ const webpPattern = new Uint8Array([82, 73, 70, 70]);
4649
+ if (matchesPattern(webpPattern)(data.subarray(0, 4))) {
4650
+ return {
4651
+ type: "webp",
4652
+ dimensions: getWebPDimensions(data)
4653
+ };
4654
+ }
4655
+ return null;
4656
+ };
4657
+
4658
+ // src/file-types/index.ts
4659
+ var detectFileType = (data) => {
4660
+ if (isRiffWave(data)) {
4661
+ return { type: "wav" };
4662
+ }
4663
+ if (isRiffAvi2(data)) {
4664
+ return { type: "riff" };
4665
+ }
4666
+ if (isAac(data)) {
4667
+ return { type: "aac" };
4668
+ }
4669
+ const webp = isWebp(data);
4670
+ if (webp) {
4671
+ return webp;
4672
+ }
4673
+ if (isWebm(data)) {
4674
+ return { type: "webm" };
4675
+ }
4676
+ if (isIsoBaseMedia(data)) {
4677
+ return { type: "iso-base-media" };
4678
+ }
4679
+ if (isTransportStream(data)) {
4680
+ return { type: "transport-stream" };
4681
+ }
4682
+ if (isMp3(data)) {
4683
+ return { type: "mp3" };
4684
+ }
4685
+ if (isGif(data)) {
4686
+ return { type: "gif" };
4687
+ }
4688
+ const png = isPng(data);
4689
+ if (png) {
4690
+ return png;
4691
+ }
4692
+ const pdf = isPdf(data);
4693
+ if (pdf) {
4694
+ return pdf;
4695
+ }
4696
+ const bmp = isBmp(data);
4697
+ if (bmp) {
4698
+ return bmp;
4699
+ }
4700
+ const jpeg = isJpeg(data);
4701
+ if (jpeg) {
4702
+ return jpeg;
4703
+ }
4704
+ return { type: "unknown" };
4705
+ };
4706
+
4361
4707
  // src/buffer-iterator.ts
4362
4708
  class OffsetCounter {
4363
4709
  #offset;
@@ -4394,14 +4740,6 @@ class OffsetCounter {
4394
4740
  this.#offset -= amount;
4395
4741
  }
4396
4742
  }
4397
- var isoBaseMediaMp4Pattern = new TextEncoder().encode("ftyp");
4398
- var mpegPattern = new Uint8Array([255, 243, 228, 100]);
4399
- var riffPattern = new Uint8Array([82, 73, 70, 70]);
4400
- var matchesPattern = (pattern) => {
4401
- return (data) => {
4402
- return pattern.every((value, index) => data[index] === value);
4403
- };
4404
- };
4405
4743
  var makeOffsetCounter = () => {
4406
4744
  return new OffsetCounter(0);
4407
4745
  };
@@ -4542,21 +4880,6 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4542
4880
  const bytesRemaining = () => {
4543
4881
  return data.byteLength - counter.getDiscardedOffset();
4544
4882
  };
4545
- const isIsoBaseMedia = () => {
4546
- return matchesPattern(isoBaseMediaMp4Pattern)(data.subarray(4, 8));
4547
- };
4548
- const isRiff = () => {
4549
- return matchesPattern(riffPattern)(data.subarray(0, 4));
4550
- };
4551
- const isWebm = () => {
4552
- return matchesPattern(webmPattern)(data.subarray(0, 4));
4553
- };
4554
- const isMp3 = () => {
4555
- return matchesPattern(mpegPattern)(data.subarray(0, 4));
4556
- };
4557
- const isTransportStream = () => {
4558
- return data[0] === 71;
4559
- };
4560
4883
  const removeBytesRead = () => {
4561
4884
  if (!discardAllowed) {
4562
4885
  return;
@@ -4671,10 +4994,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4671
4994
  getBits,
4672
4995
  byteLength,
4673
4996
  bytesRemaining,
4674
- isIsoBaseMedia,
4675
4997
  leb128,
4676
4998
  removeBytesRead,
4677
- isWebm,
4678
4999
  discard,
4679
5000
  getEightByteNumber,
4680
5001
  getFourByteNumber,
@@ -4683,7 +5004,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4683
5004
  const atom = getSlice(4);
4684
5005
  return new TextDecoder().decode(atom);
4685
5006
  },
4686
- isRiff,
5007
+ detectFileType: () => {
5008
+ return detectFileType(data);
5009
+ },
4687
5010
  getPaddedFourByteNumber,
4688
5011
  getMatroskaSegmentId: () => {
4689
5012
  if (bytesRemaining() === 0) {
@@ -4836,11 +5159,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4836
5159
  getInt32Le,
4837
5160
  getInt32,
4838
5161
  destroy,
4839
- isMp3,
4840
5162
  disallowDiscard,
4841
5163
  allowDiscard,
4842
5164
  startBox,
4843
- isTransportStream,
4844
5165
  readExpGolomb
4845
5166
  };
4846
5167
  };
@@ -5136,14 +5457,19 @@ var makeBaseMediaTrack = (trakBox) => {
5136
5457
  return track;
5137
5458
  };
5138
5459
 
5139
- // src/boxes/avc/codec-private.ts
5140
- var getAvccBoxContent = (avc1Profile) => {
5460
+ // src/boxes/avc/codec-string.ts
5461
+ var getCodecStringFromSpsAndPps = (sps) => {
5462
+ return `avc1.${sps.spsData.profile.toString(16).padStart(2, "0")}${sps.spsData.compatibility.toString(16).padStart(2, "0")}${sps.spsData.level.toString(16).padStart(2, "0")}`;
5463
+ };
5464
+
5465
+ // src/boxes/avc/create-sps-pps-data.ts
5466
+ var createSpsPpsData = (avc1Profile) => {
5141
5467
  return combineUint8Arrays([
5142
5468
  new Uint8Array([
5143
5469
  1,
5144
- avc1Profile.sps.spsData.level,
5145
- avc1Profile.sps.spsData.compatibility,
5146
5470
  avc1Profile.sps.spsData.profile,
5471
+ avc1Profile.sps.spsData.compatibility,
5472
+ avc1Profile.sps.spsData.level,
5147
5473
  255,
5148
5474
  225
5149
5475
  ]),
@@ -5155,11 +5481,6 @@ var getAvccBoxContent = (avc1Profile) => {
5155
5481
  ]);
5156
5482
  };
5157
5483
 
5158
- // src/boxes/avc/codec-string.ts
5159
- var getCodecStringFromSpsAndPps = (sps) => {
5160
- 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")}`;
5161
- };
5162
-
5163
5484
  // src/add-avc-profile-to-track.ts
5164
5485
  var addAvcProfileToTrack = (track, avc1Profile) => {
5165
5486
  if (avc1Profile === null) {
@@ -5168,7 +5489,7 @@ var addAvcProfileToTrack = (track, avc1Profile) => {
5168
5489
  return {
5169
5490
  ...track,
5170
5491
  codec: getCodecStringFromSpsAndPps(avc1Profile.sps),
5171
- codecPrivate: getAvccBoxContent(avc1Profile)
5492
+ codecPrivate: createSpsPpsData(avc1Profile)
5172
5493
  };
5173
5494
  };
5174
5495
 
@@ -5257,7 +5578,7 @@ var getTracksFromAvi = (structure, state) => {
5257
5578
  continue;
5258
5579
  }
5259
5580
  if (strf.type === "strf-box-video") {
5260
- videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.getAvcProfile()));
5581
+ videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.riff.getAvcProfile()));
5261
5582
  } else if (strh.fccType === "auds") {
5262
5583
  audioTracks.push(makeAviAudioTrack({ strf, index: i }));
5263
5584
  } else {
@@ -5309,7 +5630,7 @@ var getStreamForId = (structure, packetIdentifier) => {
5309
5630
  // src/boxes/transport-stream/get-tracks.ts
5310
5631
  var getTracksFromTransportStream = (structure, parserState) => {
5311
5632
  const programMapTable = findProgramMapTableOrThrow(structure);
5312
- const parserTracks = parserState.tracks.getTracks();
5633
+ const parserTracks = parserState.callbacks.tracks.getTracks();
5313
5634
  const mapped = programMapTable.streams.map((stream) => {
5314
5635
  return parserTracks.find((track) => track.trackId === stream.pid);
5315
5636
  }).filter(truthy);
@@ -5711,6 +6032,15 @@ var getNumberOfTracks2 = (moovBox) => {
5711
6032
  }
5712
6033
  return mvHdBox.nextTrackId - 1;
5713
6034
  };
6035
+ var isoBaseMediaHasTracks = (structure) => {
6036
+ const moovBox = getMoovBox(structure.boxes);
6037
+ if (!moovBox) {
6038
+ return false;
6039
+ }
6040
+ const numberOfTracks = getNumberOfTracks2(moovBox);
6041
+ const tracks2 = getTraks(moovBox);
6042
+ return tracks2.length === numberOfTracks;
6043
+ };
5714
6044
  var hasTracks = (structure, state) => {
5715
6045
  if (structure.type === "matroska") {
5716
6046
  const mainSegment = getMainSegment(structure.boxes);
@@ -5720,13 +6050,7 @@ var hasTracks = (structure, state) => {
5720
6050
  return getTracksSegment(mainSegment) !== null;
5721
6051
  }
5722
6052
  if (structure.type === "iso-base-media") {
5723
- const moovBox = getMoovBox(structure.boxes);
5724
- if (!moovBox) {
5725
- return false;
5726
- }
5727
- const numberOfTracks = getNumberOfTracks2(moovBox);
5728
- const tracks2 = getTraks(moovBox);
5729
- return tracks2.length === numberOfTracks;
6053
+ return isoBaseMediaHasTracks(structure);
5730
6054
  }
5731
6055
  if (structure.type === "riff") {
5732
6056
  return hasAllTracksFromAvi(structure, state);
@@ -5744,7 +6068,7 @@ var getTracksFromMa = (segments, state) => {
5744
6068
  if (!mainSegment) {
5745
6069
  throw new Error("No main segment found");
5746
6070
  }
5747
- const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
6071
+ const matroskaTracks = getTracksFromMatroska(mainSegment, state.webm.getTimescale());
5748
6072
  for (const track of matroskaTracks) {
5749
6073
  if (track.type === "video") {
5750
6074
  videoTracks.push(track);
@@ -6155,6 +6479,13 @@ var getDuration = (structure, parserState) => {
6155
6479
  var hasDuration = (structure, parserState) => {
6156
6480
  return hasTracks(structure, parserState);
6157
6481
  };
6482
+ var hasSlowDuration = (structure, parserState) => {
6483
+ try {
6484
+ return getDuration(structure, parserState) !== null;
6485
+ } catch {
6486
+ return false;
6487
+ }
6488
+ };
6158
6489
 
6159
6490
  // src/get-is-hdr.ts
6160
6491
  var isVideoTrackHdr = (track) => {
@@ -6168,6 +6499,43 @@ var hasHdr = (boxes, state) => {
6168
6499
  return hasTracks(boxes, state);
6169
6500
  };
6170
6501
 
6502
+ // src/boxes/iso-base-media/get-keyframes.ts
6503
+ var getKeyframesFromIsoBaseMedia = (structure) => {
6504
+ const { videoTracks } = getTracksFromIsoBaseMedia(structure.boxes);
6505
+ const moofBox = getMoofBox(structure.boxes);
6506
+ const allSamples = videoTracks.map((t) => {
6507
+ const { timescale: ts } = t;
6508
+ const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
6509
+ const keyframes = samplePositions.filter((k) => {
6510
+ return k.isKeyframe;
6511
+ }).map((k) => {
6512
+ return {
6513
+ trackId: t.trackId,
6514
+ presentationTimeInSeconds: k.cts / ts,
6515
+ decodingTimeInSeconds: k.dts / ts,
6516
+ positionInBytes: k.offset,
6517
+ sizeInBytes: k.size
6518
+ };
6519
+ });
6520
+ return keyframes;
6521
+ });
6522
+ return allSamples.flat();
6523
+ };
6524
+
6525
+ // src/get-keyframes.ts
6526
+ var getKeyframes = (structure) => {
6527
+ if (structure.type === "iso-base-media") {
6528
+ return getKeyframesFromIsoBaseMedia(structure);
6529
+ }
6530
+ return null;
6531
+ };
6532
+ var hasKeyframes = (structure, parserState) => {
6533
+ if (structure.type === "iso-base-media") {
6534
+ return hasTracks(structure, parserState);
6535
+ }
6536
+ return true;
6537
+ };
6538
+
6171
6539
  // src/get-location.ts
6172
6540
  function parseLocation(locationString) {
6173
6541
  const locationPattern = /^([+-]\d{2}\.?\d{0,10})([+-]\d{3}\.?\d{0,10})([+-]\d+(\.\d+)?)?\/$/;
@@ -6205,145 +6573,282 @@ var getLocation = (structure) => {
6205
6573
  var emitAvailableInfo = ({
6206
6574
  hasInfo,
6207
6575
  parseResult,
6208
- moreFields,
6576
+ callbacks,
6209
6577
  state,
6210
6578
  returnValue,
6211
6579
  contentLength,
6212
- name
6580
+ name,
6581
+ mimeType,
6582
+ fieldsInReturnValue
6213
6583
  }) => {
6214
6584
  const keys = Object.keys(hasInfo);
6585
+ const segments = state.structure.getStructureOrNull();
6586
+ const { emittedFields } = state;
6215
6587
  for (const key of keys) {
6216
6588
  if (key === "structure") {
6217
- if (parseResult && hasInfo.structure && returnValue.structure === undefined) {
6218
- moreFields.onStructure?.(parseResult.segments);
6219
- returnValue.structure = parseResult.segments;
6589
+ if (parseResult && hasInfo.structure && !emittedFields.structure && segments) {
6590
+ callbacks.onStructure?.(segments);
6591
+ if (fieldsInReturnValue.structure) {
6592
+ returnValue.structure = segments;
6593
+ }
6594
+ emittedFields.structure = true;
6220
6595
  }
6221
6596
  continue;
6222
6597
  }
6223
6598
  if (key === "durationInSeconds") {
6224
- if (hasInfo.durationInSeconds && returnValue.durationInSeconds === undefined && parseResult) {
6225
- const durationInSeconds = getDuration(parseResult.segments, state);
6226
- moreFields.onDurationInSeconds?.(durationInSeconds);
6227
- returnValue.durationInSeconds = durationInSeconds;
6599
+ if (hasInfo.durationInSeconds && parseResult && segments) {
6600
+ if (!emittedFields.durationInSeconds) {
6601
+ const durationInSeconds = getDuration(segments, state);
6602
+ callbacks.onDurationInSeconds?.(durationInSeconds);
6603
+ if (fieldsInReturnValue.durationInSeconds) {
6604
+ returnValue.durationInSeconds = durationInSeconds;
6605
+ }
6606
+ emittedFields.durationInSeconds = true;
6607
+ }
6608
+ if (!emittedFields.slowDurationInSeconds) {
6609
+ const durationInSeconds = getDuration(segments, state);
6610
+ if (durationInSeconds !== null) {
6611
+ callbacks.onSlowDurationInSeconds?.(durationInSeconds);
6612
+ if (fieldsInReturnValue.slowDurationInSeconds) {
6613
+ returnValue.slowDurationInSeconds = durationInSeconds;
6614
+ }
6615
+ emittedFields.slowDurationInSeconds = true;
6616
+ }
6617
+ }
6618
+ }
6619
+ continue;
6620
+ }
6621
+ if (key === "slowDurationInSeconds") {
6622
+ if (hasInfo.slowDurationInSeconds && !emittedFields.slowDurationInSeconds && parseResult && segments) {
6623
+ const slowDurationInSeconds = state.slowDurationAndFps.getSlowDurationInSeconds();
6624
+ callbacks.onSlowDurationInSeconds?.(slowDurationInSeconds);
6625
+ if (fieldsInReturnValue.slowDurationInSeconds) {
6626
+ returnValue.slowDurationInSeconds = slowDurationInSeconds;
6627
+ }
6628
+ emittedFields.slowDurationInSeconds = true;
6629
+ }
6630
+ continue;
6631
+ }
6632
+ if (key === "fps") {
6633
+ if (hasInfo.fps && parseResult && segments) {
6634
+ if (!emittedFields.fps) {
6635
+ const fps = getFps(segments);
6636
+ callbacks.onFps?.(fps);
6637
+ if (fieldsInReturnValue.fps) {
6638
+ returnValue.fps = fps;
6639
+ }
6640
+ emittedFields.fps = true;
6641
+ }
6642
+ if (!emittedFields.slowFps) {
6643
+ const fps = getFps(segments);
6644
+ if (fps) {
6645
+ callbacks.onSlowFps?.(fps);
6646
+ if (fieldsInReturnValue.slowFps) {
6647
+ returnValue.slowFps = fps;
6648
+ }
6649
+ emittedFields.slowFps = true;
6650
+ }
6651
+ }
6652
+ }
6653
+ continue;
6654
+ }
6655
+ if (key === "slowFps") {
6656
+ if (hasInfo.slowFps && !emittedFields.slowFps && parseResult && segments) {
6657
+ const slowFps = state.slowDurationAndFps.getFps();
6658
+ callbacks.onSlowFps?.(slowFps);
6659
+ if (fieldsInReturnValue.slowFps) {
6660
+ returnValue.slowFps = slowFps;
6661
+ }
6662
+ emittedFields.slowFps = true;
6228
6663
  }
6229
6664
  continue;
6230
6665
  }
6231
6666
  if (key === "dimensions") {
6232
- if (hasInfo.dimensions && returnValue.dimensions === undefined && parseResult) {
6233
- const dimensionsQueried = getDimensions(parseResult.segments, state);
6667
+ if (hasInfo.dimensions && !emittedFields.dimensions && parseResult && segments) {
6668
+ const dimensionsQueried = getDimensions(segments, state);
6234
6669
  const dimensions = {
6235
6670
  height: dimensionsQueried.height,
6236
6671
  width: dimensionsQueried.width
6237
6672
  };
6238
- moreFields.onDimensions?.(dimensions);
6239
- returnValue.dimensions = dimensions;
6673
+ callbacks.onDimensions?.(dimensions);
6674
+ if (fieldsInReturnValue.dimensions) {
6675
+ returnValue.dimensions = dimensions;
6676
+ }
6677
+ emittedFields.dimensions = true;
6240
6678
  }
6241
6679
  continue;
6242
6680
  }
6243
6681
  if (key === "unrotatedDimensions") {
6244
- if (returnValue.unrotatedDimensions === undefined && hasInfo.unrotatedDimensions && parseResult) {
6245
- const dimensionsQueried = getDimensions(parseResult.segments, state);
6682
+ if (hasInfo.unrotatedDimensions && !emittedFields.unrotatedDimensions && parseResult && segments) {
6683
+ const dimensionsQueried = getDimensions(segments, state);
6246
6684
  const unrotatedDimensions = {
6247
6685
  height: dimensionsQueried.unrotatedHeight,
6248
6686
  width: dimensionsQueried.unrotatedWidth
6249
6687
  };
6250
- moreFields.onUnrotatedDimensions?.(unrotatedDimensions);
6251
- returnValue.unrotatedDimensions = unrotatedDimensions;
6688
+ callbacks.onUnrotatedDimensions?.(unrotatedDimensions);
6689
+ if (fieldsInReturnValue.unrotatedDimensions) {
6690
+ returnValue.unrotatedDimensions = unrotatedDimensions;
6691
+ }
6692
+ emittedFields.unrotatedDimensions = true;
6252
6693
  }
6253
6694
  continue;
6254
6695
  }
6255
6696
  if (key === "rotation") {
6256
- if (returnValue.rotation === undefined && hasInfo.rotation && parseResult) {
6257
- const dimensionsQueried = getDimensions(parseResult.segments, state);
6697
+ if (hasInfo.rotation && !emittedFields.rotation && parseResult && segments) {
6698
+ const dimensionsQueried = getDimensions(segments, state);
6258
6699
  const { rotation } = dimensionsQueried;
6259
- moreFields.onRotation?.(rotation);
6260
- returnValue.rotation = rotation;
6261
- }
6262
- continue;
6263
- }
6264
- if (key === "fps") {
6265
- if (returnValue.fps === undefined && hasInfo.fps && parseResult) {
6266
- const fps = getFps(parseResult.segments);
6267
- moreFields.onFps?.(fps);
6268
- returnValue.fps = fps;
6700
+ callbacks.onRotation?.(rotation);
6701
+ if (fieldsInReturnValue.rotation) {
6702
+ returnValue.rotation = rotation;
6703
+ }
6704
+ emittedFields.rotation = true;
6269
6705
  }
6270
6706
  continue;
6271
6707
  }
6272
6708
  if (key === "videoCodec") {
6273
- if (returnValue.videoCodec === undefined && hasInfo.videoCodec && parseResult) {
6274
- const videoCodec = getVideoCodec(parseResult.segments, state);
6275
- moreFields.onVideoCodec?.(videoCodec);
6276
- returnValue.videoCodec = videoCodec;
6709
+ if (!emittedFields.videoCodec && hasInfo.videoCodec && parseResult && segments) {
6710
+ const videoCodec = getVideoCodec(segments, state);
6711
+ callbacks.onVideoCodec?.(videoCodec);
6712
+ if (fieldsInReturnValue.videoCodec) {
6713
+ returnValue.videoCodec = videoCodec;
6714
+ }
6715
+ emittedFields.videoCodec = true;
6277
6716
  }
6278
6717
  continue;
6279
6718
  }
6280
6719
  if (key === "audioCodec") {
6281
- if (returnValue.audioCodec === undefined && hasInfo.audioCodec && parseResult) {
6282
- const audioCodec = getAudioCodec(parseResult.segments, state);
6283
- moreFields.onAudioCodec?.(audioCodec);
6284
- returnValue.audioCodec = audioCodec;
6720
+ if (!emittedFields.audioCodec && hasInfo.audioCodec && parseResult && segments) {
6721
+ const audioCodec = getAudioCodec(segments, state);
6722
+ callbacks.onAudioCodec?.(audioCodec);
6723
+ if (fieldsInReturnValue.audioCodec) {
6724
+ returnValue.audioCodec = audioCodec;
6725
+ }
6726
+ emittedFields.audioCodec = true;
6285
6727
  }
6286
6728
  continue;
6287
6729
  }
6288
6730
  if (key === "tracks") {
6289
- if (hasInfo.tracks && returnValue.videoTracks === undefined && returnValue.audioTracks === undefined && parseResult) {
6290
- const { videoTracks, audioTracks } = getTracks(parseResult.segments, state);
6291
- moreFields.onTracks?.({ videoTracks, audioTracks });
6292
- returnValue.videoTracks = videoTracks;
6293
- returnValue.audioTracks = audioTracks;
6731
+ if (!emittedFields.tracks && hasInfo.tracks && parseResult && segments) {
6732
+ const { videoTracks, audioTracks } = getTracks(segments, state);
6733
+ callbacks.onTracks?.({ videoTracks, audioTracks });
6734
+ if (fieldsInReturnValue.tracks) {
6735
+ returnValue.tracks = { videoTracks, audioTracks };
6736
+ }
6737
+ emittedFields.tracks = true;
6294
6738
  }
6295
6739
  continue;
6296
6740
  }
6297
6741
  if (key === "internalStats") {
6298
6742
  if (hasInfo.internalStats) {
6299
6743
  const internalStats = state.getInternalStats();
6300
- returnValue.internalStats = internalStats;
6744
+ if (fieldsInReturnValue.internalStats) {
6745
+ returnValue.internalStats = internalStats;
6746
+ }
6747
+ emittedFields.internalStats = true;
6301
6748
  }
6302
6749
  continue;
6303
6750
  }
6304
6751
  if (key === "size") {
6305
- if (returnValue.size === undefined && hasInfo.size) {
6306
- moreFields.onSize?.(contentLength);
6307
- returnValue.size = contentLength;
6752
+ if (!emittedFields.size && hasInfo.size) {
6753
+ callbacks.onSize?.(contentLength);
6754
+ if (fieldsInReturnValue.size) {
6755
+ returnValue.size = contentLength;
6756
+ }
6757
+ emittedFields.size = true;
6758
+ }
6759
+ continue;
6760
+ }
6761
+ if (key === "mimeType") {
6762
+ if (!emittedFields.mimeType && hasInfo.mimeType) {
6763
+ callbacks.onMimeType?.(mimeType);
6764
+ if (fieldsInReturnValue.mimeType) {
6765
+ returnValue.mimeType = mimeType;
6766
+ }
6767
+ emittedFields.mimeType = true;
6308
6768
  }
6309
6769
  continue;
6310
6770
  }
6311
6771
  if (key === "name") {
6312
- if (returnValue.name === undefined && hasInfo.name) {
6313
- moreFields.onName?.(name);
6314
- returnValue.name = name;
6772
+ if (!emittedFields.name && hasInfo.name) {
6773
+ callbacks.onName?.(name);
6774
+ if (fieldsInReturnValue.name) {
6775
+ returnValue.name = name;
6776
+ }
6777
+ emittedFields.name = true;
6315
6778
  }
6316
6779
  continue;
6317
6780
  }
6318
6781
  if (key === "isHdr") {
6319
- if (returnValue.isHdr === undefined && hasInfo.isHdr && parseResult) {
6320
- const isHdr = getIsHdr(parseResult.segments, state);
6321
- moreFields.onIsHdr?.(isHdr);
6322
- returnValue.isHdr = isHdr;
6782
+ if (!returnValue.isHdr && hasInfo.isHdr && parseResult && segments) {
6783
+ const isHdr = getIsHdr(segments, state);
6784
+ callbacks.onIsHdr?.(isHdr);
6785
+ if (fieldsInReturnValue.isHdr) {
6786
+ returnValue.isHdr = isHdr;
6787
+ }
6788
+ emittedFields.isHdr = true;
6323
6789
  }
6324
6790
  continue;
6325
6791
  }
6326
6792
  if (key === "container") {
6327
- if (returnValue.container === undefined && hasInfo.container && parseResult) {
6328
- const container = getContainer(parseResult.segments);
6329
- moreFields.onContainer?.(container);
6330
- returnValue.container = container;
6793
+ if (!returnValue.container && hasInfo.container && parseResult && segments) {
6794
+ const container = getContainer(segments);
6795
+ callbacks.onContainer?.(container);
6796
+ if (fieldsInReturnValue.container) {
6797
+ returnValue.container = container;
6798
+ }
6799
+ emittedFields.container = true;
6331
6800
  }
6332
6801
  continue;
6333
6802
  }
6334
6803
  if (key === "metadata") {
6335
- if (returnValue.metadata === undefined && hasInfo.metadata && parseResult) {
6336
- const metadata = getMetadata(parseResult.segments);
6337
- moreFields.onMetadata?.(metadata);
6338
- returnValue.metadata = metadata;
6804
+ if (!emittedFields.metadata && hasInfo.metadata && parseResult && segments) {
6805
+ const metadata = getMetadata(segments);
6806
+ callbacks.onMetadata?.(metadata);
6807
+ if (fieldsInReturnValue.metadata) {
6808
+ returnValue.metadata = metadata;
6809
+ }
6810
+ emittedFields.metadata = true;
6339
6811
  }
6340
6812
  continue;
6341
6813
  }
6342
6814
  if (key === "location") {
6343
- if (returnValue.location === undefined && hasInfo.location && parseResult) {
6344
- const location = getLocation(parseResult.segments);
6345
- moreFields.onLocation?.(location);
6346
- returnValue.location = location;
6815
+ if (!emittedFields.location && hasInfo.location && parseResult && segments) {
6816
+ const location = getLocation(segments);
6817
+ callbacks.onLocation?.(location);
6818
+ if (fieldsInReturnValue.location) {
6819
+ returnValue.location = location;
6820
+ }
6821
+ emittedFields.location = true;
6822
+ }
6823
+ continue;
6824
+ }
6825
+ if (key === "slowKeyframes") {
6826
+ if (!emittedFields.slowKeyframes && hasInfo.slowKeyframes && parseResult) {
6827
+ callbacks.onSlowKeyframes?.(state.keyframes.getKeyframes());
6828
+ if (fieldsInReturnValue.slowKeyframes) {
6829
+ returnValue.slowKeyframes = state.keyframes.getKeyframes();
6830
+ }
6831
+ emittedFields.slowKeyframes = true;
6832
+ }
6833
+ continue;
6834
+ }
6835
+ if (key === "slowNumberOfFrames") {
6836
+ if (!emittedFields.slowNumberOfFrames && hasInfo.slowNumberOfFrames && parseResult) {
6837
+ callbacks.onSlowNumberOfFrames?.(state.slowDurationAndFps.getSlowNumberOfFrames());
6838
+ if (fieldsInReturnValue.slowNumberOfFrames) {
6839
+ returnValue.slowNumberOfFrames = state.slowDurationAndFps.getSlowNumberOfFrames();
6840
+ }
6841
+ emittedFields.slowNumberOfFrames = true;
6842
+ }
6843
+ continue;
6844
+ }
6845
+ if (key === "keyframes") {
6846
+ if (!emittedFields.keyframes && hasInfo.keyframes && parseResult) {
6847
+ callbacks.onKeyframes?.(getKeyframes(state.structure.getStructure()));
6848
+ if (fieldsInReturnValue.keyframes) {
6849
+ returnValue.keyframes = getKeyframes(state.structure.getStructure());
6850
+ }
6851
+ emittedFields.keyframes = true;
6347
6852
  }
6348
6853
  continue;
6349
6854
  }
@@ -6351,9 +6856,88 @@ var emitAvailableInfo = ({
6351
6856
  }
6352
6857
  };
6353
6858
 
6859
+ // src/get-fields-from-callbacks.ts
6860
+ var getFieldsFromCallback = ({
6861
+ fields,
6862
+ callbacks
6863
+ }) => {
6864
+ const newFields = {
6865
+ audioCodec: Boolean(callbacks.onAudioCodec),
6866
+ container: Boolean(callbacks.onContainer),
6867
+ dimensions: Boolean(callbacks.onDimensions),
6868
+ durationInSeconds: Boolean(callbacks.onDurationInSeconds),
6869
+ fps: Boolean(callbacks.onFps),
6870
+ internalStats: Boolean(callbacks.onInternalStats),
6871
+ isHdr: Boolean(callbacks.onIsHdr),
6872
+ location: Boolean(callbacks.onLocation),
6873
+ metadata: Boolean(callbacks.onMetadata),
6874
+ mimeType: Boolean(callbacks.onMimeType),
6875
+ name: Boolean(callbacks.onName),
6876
+ rotation: Boolean(callbacks.onRotation),
6877
+ size: Boolean(callbacks.onSize),
6878
+ structure: Boolean(callbacks.onStructure),
6879
+ tracks: Boolean(callbacks.onTracks),
6880
+ unrotatedDimensions: Boolean(callbacks.onUnrotatedDimensions),
6881
+ videoCodec: Boolean(callbacks.onVideoCodec),
6882
+ slowKeyframes: Boolean(callbacks.onSlowKeyframes),
6883
+ slowDurationInSeconds: Boolean(callbacks.onSlowDurationInSeconds),
6884
+ slowFps: Boolean(callbacks.onSlowFps),
6885
+ slowNumberOfFrames: Boolean(callbacks.onSlowNumberOfFrames),
6886
+ keyframes: Boolean(callbacks.onKeyframes),
6887
+ ...fields
6888
+ };
6889
+ return newFields;
6890
+ };
6891
+
6892
+ // src/may-skip-video-data/need-samples-for-fields.ts
6893
+ var needsSamples = {
6894
+ slowDurationInSeconds: true,
6895
+ slowFps: true,
6896
+ slowKeyframes: true,
6897
+ slowNumberOfFrames: true,
6898
+ audioCodec: false,
6899
+ container: false,
6900
+ dimensions: false,
6901
+ durationInSeconds: false,
6902
+ fps: false,
6903
+ internalStats: false,
6904
+ isHdr: false,
6905
+ name: false,
6906
+ rotation: false,
6907
+ size: false,
6908
+ structure: false,
6909
+ tracks: false,
6910
+ unrotatedDimensions: false,
6911
+ videoCodec: false,
6912
+ metadata: false,
6913
+ location: false,
6914
+ mimeType: false,
6915
+ keyframes: false
6916
+ };
6917
+ var needsToIterateOverSamples = ({
6918
+ fields,
6919
+ emittedFields
6920
+ }) => {
6921
+ const keys = Object.keys(fields ?? {});
6922
+ const selectedKeys = keys.filter((k) => fields[k]);
6923
+ return selectedKeys.some((k) => needsSamples[k] && !emittedFields[k]);
6924
+ };
6925
+
6926
+ // src/may-skip-video-data/may-skip-video-data.ts
6927
+ var maySkipVideoData = ({ state }) => {
6928
+ return state.callbacks.tracks.hasAllTracks() && Object.values(state.callbacks.videoSampleCallbacks).length === 0 && Object.values(state.callbacks.audioSampleCallbacks).length === 0 && !needsToIterateOverSamples({
6929
+ emittedFields: state.emittedFields,
6930
+ fields: state.fields
6931
+ });
6932
+ };
6933
+
6354
6934
  // src/has-all-info.ts
6355
- var getAvailableInfo = (options, structure, state) => {
6356
- const keys = Object.entries(options).filter(([, value]) => value);
6935
+ var getAvailableInfo = ({
6936
+ fieldsToFetch,
6937
+ state
6938
+ }) => {
6939
+ const keys = Object.entries(fieldsToFetch).filter(([, value]) => value);
6940
+ const structure = state.structure.getStructureOrNull();
6357
6941
  const infos = keys.map(([_key]) => {
6358
6942
  const key = _key;
6359
6943
  if (key === "structure") {
@@ -6362,12 +6946,18 @@ var getAvailableInfo = (options, structure, state) => {
6362
6946
  if (key === "durationInSeconds") {
6363
6947
  return Boolean(structure && hasDuration(structure, state));
6364
6948
  }
6949
+ if (key === "slowDurationInSeconds") {
6950
+ return Boolean(structure && hasSlowDuration(structure, state));
6951
+ }
6365
6952
  if (key === "dimensions" || key === "rotation" || key === "unrotatedDimensions") {
6366
6953
  return Boolean(structure && hasDimensions(structure, state));
6367
6954
  }
6368
6955
  if (key === "fps") {
6369
6956
  return Boolean(structure && hasFps(structure));
6370
6957
  }
6958
+ if (key === "slowFps") {
6959
+ return Boolean(structure && hasFpsSuitedForSlowFps(structure));
6960
+ }
6371
6961
  if (key === "isHdr") {
6372
6962
  return Boolean(structure && hasHdr(structure, state));
6373
6963
  }
@@ -6380,12 +6970,18 @@ var getAvailableInfo = (options, structure, state) => {
6380
6970
  if (key === "tracks") {
6381
6971
  return Boolean(structure && hasTracks(structure, state));
6382
6972
  }
6973
+ if (key === "keyframes") {
6974
+ return Boolean(structure && hasKeyframes(structure, state));
6975
+ }
6383
6976
  if (key === "internalStats") {
6384
6977
  return true;
6385
6978
  }
6386
6979
  if (key === "size") {
6387
6980
  return true;
6388
6981
  }
6982
+ if (key === "mimeType") {
6983
+ return true;
6984
+ }
6389
6985
  if (key === "name") {
6390
6986
  return true;
6391
6987
  }
@@ -6395,6 +6991,12 @@ var getAvailableInfo = (options, structure, state) => {
6395
6991
  if (key === "metadata" || key === "location") {
6396
6992
  return false;
6397
6993
  }
6994
+ if (key === "slowKeyframes") {
6995
+ return false;
6996
+ }
6997
+ if (key === "slowNumberOfFrames") {
6998
+ return false;
6999
+ }
6398
7000
  throw new Error(`Unknown key: ${key}`);
6399
7001
  });
6400
7002
  const entries = [];
@@ -6406,42 +7008,44 @@ var getAvailableInfo = (options, structure, state) => {
6406
7008
  };
6407
7009
  var hasAllInfo = ({
6408
7010
  fields,
6409
- state,
6410
- structure
7011
+ state
6411
7012
  }) => {
6412
- const availableInfo = getAvailableInfo(fields ?? {}, structure, state);
6413
- return Object.values(availableInfo).every(Boolean) && (state.maySkipVideoData() || state.canSkipTracksState.canSkipTracks());
7013
+ const availableInfo = getAvailableInfo({
7014
+ fieldsToFetch: fields ?? {},
7015
+ state
7016
+ });
7017
+ return Object.values(availableInfo).every(Boolean) && (maySkipVideoData({ state }) || state.callbacks.canSkipTracksState.canSkipTracks());
6414
7018
  };
6415
7019
 
6416
7020
  // src/register-track.ts
6417
7021
  var registerTrack = async ({
6418
- options,
7022
+ state,
6419
7023
  track,
6420
7024
  container
6421
7025
  }) => {
6422
7026
  if (track.type === "video") {
6423
- options.parserState.tracks.addTrack(track);
6424
- if (options.onVideoTrack) {
6425
- const callback = await options.onVideoTrack({ track, container });
6426
- await options.parserState.registerVideoSampleCallback(track.trackId, callback ?? null);
7027
+ state.callbacks.tracks.addTrack(track);
7028
+ if (state.onVideoTrack) {
7029
+ const callback = await state.onVideoTrack({ track, container });
7030
+ await state.callbacks.registerVideoSampleCallback(track.trackId, callback ?? null);
6427
7031
  }
6428
7032
  }
6429
7033
  if (track.type === "audio") {
6430
- options.parserState.tracks.addTrack(track);
6431
- if (options.onAudioTrack) {
6432
- const callback = await options.onAudioTrack({ track, container });
6433
- await options.parserState.registerAudioSampleCallback(track.trackId, callback ?? null);
7034
+ state.callbacks.tracks.addTrack(track);
7035
+ if (state.onAudioTrack) {
7036
+ const callback = await state.onAudioTrack({ track, container });
7037
+ await state.callbacks.registerAudioSampleCallback(track.trackId, callback ?? null);
6434
7038
  }
6435
7039
  }
6436
7040
  };
6437
7041
  var registerVideoTrackWhenProfileIsAvailable = ({
6438
- options,
7042
+ state,
6439
7043
  track,
6440
7044
  container
6441
7045
  }) => {
6442
- options.parserState.registerOnAvcProfileCallback(async (profile) => {
7046
+ state.riff.registerOnAvcProfileCallback(async (profile) => {
6443
7047
  await registerTrack({
6444
- options,
7048
+ state,
6445
7049
  track: addAvcProfileToTrack(track, profile),
6446
7050
  container
6447
7051
  });
@@ -6616,7 +7220,9 @@ var convertAudioOrVideoSampleToWebCodecsTimestamps = (sample, timescale2) => {
6616
7220
  duration: (sample.duration ?? 0) * 1e6 / timescale2,
6617
7221
  data: sample.data,
6618
7222
  trackId: sample.trackId,
6619
- type: sample.type
7223
+ type: sample.type,
7224
+ offset: sample.offset,
7225
+ timescale: 1e6
6620
7226
  };
6621
7227
  };
6622
7228
 
@@ -6626,14 +7232,14 @@ var parseMdat = async ({
6626
7232
  size,
6627
7233
  fileOffset,
6628
7234
  existingBoxes,
6629
- options,
7235
+ state,
6630
7236
  signal,
6631
7237
  maySkipSampleProcessing
6632
7238
  }) => {
6633
7239
  const alreadyHas = hasTracks({
6634
7240
  type: "iso-base-media",
6635
7241
  boxes: existingBoxes
6636
- }, options.parserState);
7242
+ }, state);
6637
7243
  if (!alreadyHas) {
6638
7244
  if (maySkipSampleProcessing) {
6639
7245
  data.discard(size - (data.counter.getOffset() - fileOffset));
@@ -6653,7 +7259,7 @@ var parseMdat = async ({
6653
7259
  fileOffset
6654
7260
  });
6655
7261
  }
6656
- const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, options.parserState);
7262
+ const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, state);
6657
7263
  const allTracks = [
6658
7264
  ...tracks2.videoTracks,
6659
7265
  ...tracks2.audioTracks,
@@ -6695,25 +7301,29 @@ var parseMdat = async ({
6695
7301
  const bytes = data.getSlice(samplesWithIndex.samplePosition.size);
6696
7302
  const { cts, dts, duration: duration2 } = samplesWithIndex.samplePosition;
6697
7303
  if (samplesWithIndex.track.type === "audio") {
6698
- await options.parserState.onAudioSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
7304
+ await state.callbacks.onAudioSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
6699
7305
  data: bytes,
6700
7306
  timestamp: cts,
6701
7307
  duration: duration2,
6702
7308
  cts,
6703
7309
  dts,
6704
7310
  trackId: samplesWithIndex.track.trackId,
6705
- type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta"
7311
+ type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta",
7312
+ offset: samplesWithIndex.samplePosition.offset,
7313
+ timescale: samplesWithIndex.track.timescale
6706
7314
  }, samplesWithIndex.track.timescale));
6707
7315
  }
6708
7316
  if (samplesWithIndex.track.type === "video") {
6709
- await options.parserState.onVideoSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
7317
+ await state.callbacks.onVideoSample(samplesWithIndex.track.trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
6710
7318
  data: bytes,
6711
7319
  timestamp: cts,
6712
7320
  duration: duration2,
6713
7321
  cts,
6714
7322
  dts,
6715
7323
  trackId: samplesWithIndex.track.trackId,
6716
- type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta"
7324
+ type: samplesWithIndex.samplePosition.isKeyframe ? "key" : "delta",
7325
+ offset: samplesWithIndex.samplePosition.offset,
7326
+ timescale: samplesWithIndex.track.timescale
6717
7327
  }, samplesWithIndex.track.timescale));
6718
7328
  }
6719
7329
  const remaining = size - (data.counter.getOffset() - fileOffset);
@@ -6878,17 +7488,18 @@ var parseMoov = async ({
6878
7488
  iterator,
6879
7489
  offset,
6880
7490
  size,
6881
- options,
7491
+ state,
6882
7492
  signal,
6883
7493
  logLevel,
6884
7494
  fields
6885
7495
  }) => {
7496
+ const boxes = [];
6886
7497
  const children = await parseIsoBaseMediaBoxes({
6887
7498
  iterator,
6888
7499
  maxBytes: size - (iterator.counter.getOffset() - offset),
6889
7500
  allowIncompleteBoxes: false,
6890
- initialBoxes: [],
6891
- options,
7501
+ initialBoxes: boxes,
7502
+ state,
6892
7503
  continueMdat: false,
6893
7504
  signal,
6894
7505
  logLevel,
@@ -6901,7 +7512,7 @@ var parseMoov = async ({
6901
7512
  offset,
6902
7513
  boxSize: size,
6903
7514
  type: "moov-box",
6904
- children: children.segments.boxes
7515
+ children: boxes
6905
7516
  };
6906
7517
  };
6907
7518
 
@@ -7234,18 +7845,19 @@ var parseMebx = async ({
7234
7845
  iterator,
7235
7846
  offset,
7236
7847
  size,
7237
- options,
7848
+ state,
7238
7849
  signal,
7239
7850
  fields
7240
7851
  }) => {
7241
7852
  iterator.discard(6);
7242
7853
  const dataReferenceIndex = iterator.getUint16();
7854
+ const boxes = [];
7243
7855
  const children = await parseIsoBaseMediaBoxes({
7244
7856
  iterator,
7245
7857
  maxBytes: iterator.counter.getOffset() - offset,
7246
7858
  allowIncompleteBoxes: false,
7247
- initialBoxes: [],
7248
- options,
7859
+ initialBoxes: boxes,
7860
+ state,
7249
7861
  continueMdat: false,
7250
7862
  signal,
7251
7863
  logLevel: "info",
@@ -7260,7 +7872,7 @@ var parseMebx = async ({
7260
7872
  offset,
7261
7873
  dataReferenceIndex,
7262
7874
  format: "mebx",
7263
- children: children.segments.boxes
7875
+ children: boxes
7264
7876
  };
7265
7877
  };
7266
7878
 
@@ -7413,7 +8025,7 @@ var audioTags = [
7413
8025
  ];
7414
8026
  var processSample = async ({
7415
8027
  iterator,
7416
- options,
8028
+ state: options,
7417
8029
  signal,
7418
8030
  logLevel,
7419
8031
  fields
@@ -7453,12 +8065,13 @@ var processSample = async ({
7453
8065
  const packetSize = iterator.getUint16();
7454
8066
  const sampleRate = iterator.getFixedPointUnsigned1616Number();
7455
8067
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
8068
+ const initialBoxes = [];
7456
8069
  const children = await parseIsoBaseMediaBoxes({
7457
8070
  iterator,
7458
8071
  allowIncompleteBoxes: false,
7459
8072
  maxBytes: bytesRemainingInBox,
7460
- initialBoxes: [],
7461
- options,
8073
+ initialBoxes,
8074
+ state: options,
7462
8075
  continueMdat: false,
7463
8076
  signal,
7464
8077
  logLevel,
@@ -7486,7 +8099,7 @@ var processSample = async ({
7486
8099
  bytesPerPacket: null,
7487
8100
  bytesPerFrame: null,
7488
8101
  bitsPerSample: null,
7489
- children: children.segments.boxes
8102
+ children: initialBoxes
7490
8103
  }
7491
8104
  };
7492
8105
  }
@@ -7501,12 +8114,13 @@ var processSample = async ({
7501
8114
  const bytesPerFrame = iterator.getUint32();
7502
8115
  const bytesPerSample = iterator.getUint32();
7503
8116
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
8117
+ const initialBoxes = [];
7504
8118
  const children = await parseIsoBaseMediaBoxes({
7505
8119
  iterator,
7506
8120
  allowIncompleteBoxes: false,
7507
8121
  maxBytes: bytesRemainingInBox,
7508
- initialBoxes: [],
7509
- options,
8122
+ initialBoxes,
8123
+ state: options,
7510
8124
  continueMdat: false,
7511
8125
  signal,
7512
8126
  logLevel,
@@ -7534,7 +8148,7 @@ var processSample = async ({
7534
8148
  bytesPerPacket,
7535
8149
  bytesPerFrame,
7536
8150
  bitsPerSample: bytesPerSample,
7537
- children: children.segments.boxes
8151
+ children: initialBoxes
7538
8152
  }
7539
8153
  };
7540
8154
  }
@@ -7558,7 +8172,7 @@ var processSample = async ({
7558
8172
  allowIncompleteBoxes: false,
7559
8173
  maxBytes: bytesRemainingInBox,
7560
8174
  initialBoxes: [],
7561
- options,
8175
+ state: options,
7562
8176
  continueMdat: false,
7563
8177
  signal,
7564
8178
  logLevel,
@@ -7567,6 +8181,7 @@ var processSample = async ({
7567
8181
  if (children.status === "incomplete") {
7568
8182
  throw new Error("Incomplete boxes are not allowed");
7569
8183
  }
8184
+ const initialBoxes = [];
7570
8185
  return {
7571
8186
  sample: {
7572
8187
  format: boxFormat,
@@ -7586,7 +8201,7 @@ var processSample = async ({
7586
8201
  bytesPerPacket: null,
7587
8202
  bytesPerFrame,
7588
8203
  bitsPerSample: bitsPerChannel,
7589
- children: children.segments.boxes
8204
+ children: initialBoxes
7590
8205
  }
7591
8206
  };
7592
8207
  }
@@ -7608,17 +8223,18 @@ var processSample = async ({
7608
8223
  const depth = iterator.getUint16();
7609
8224
  const colorTableId = iterator.getInt16();
7610
8225
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
8226
+ const initialBoxes = [];
7611
8227
  const children = bytesRemainingInBox > 8 ? await parseIsoBaseMediaBoxes({
7612
8228
  iterator,
7613
8229
  allowIncompleteBoxes: false,
7614
8230
  maxBytes: bytesRemainingInBox,
7615
- initialBoxes: [],
7616
- options,
8231
+ initialBoxes,
8232
+ state: options,
7617
8233
  continueMdat: false,
7618
8234
  signal,
7619
8235
  logLevel,
7620
8236
  fields
7621
- }) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: { boxes: [], type: "iso-base-media" } });
8237
+ }) : (iterator.discard(bytesRemainingInBox), { status: "done" });
7622
8238
  if (children.status === "incomplete") {
7623
8239
  throw new Error("Incomplete boxes are not allowed");
7624
8240
  }
@@ -7643,7 +8259,7 @@ var processSample = async ({
7643
8259
  compressorName,
7644
8260
  depth,
7645
8261
  colorTableId,
7646
- descriptors: children.segments.boxes
8262
+ descriptors: initialBoxes
7647
8263
  }
7648
8264
  };
7649
8265
  }
@@ -7652,7 +8268,7 @@ var processSample = async ({
7652
8268
  var parseSamples = async ({
7653
8269
  iterator,
7654
8270
  maxBytes,
7655
- options,
8271
+ state,
7656
8272
  signal,
7657
8273
  logLevel,
7658
8274
  fields
@@ -7662,7 +8278,7 @@ var parseSamples = async ({
7662
8278
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
7663
8279
  const { sample } = await processSample({
7664
8280
  iterator,
7665
- options,
8281
+ state,
7666
8282
  signal,
7667
8283
  logLevel,
7668
8284
  fields
@@ -7679,7 +8295,7 @@ var parseStsd = async ({
7679
8295
  iterator,
7680
8296
  offset,
7681
8297
  size,
7682
- options,
8298
+ state,
7683
8299
  signal,
7684
8300
  fields
7685
8301
  }) => {
@@ -7693,7 +8309,7 @@ var parseStsd = async ({
7693
8309
  const boxes = await parseSamples({
7694
8310
  iterator,
7695
8311
  maxBytes: bytesRemainingInBox,
7696
- options,
8312
+ state,
7697
8313
  signal,
7698
8314
  logLevel: "info",
7699
8315
  fields
@@ -7965,30 +8581,31 @@ var parseTrak = async ({
7965
8581
  data,
7966
8582
  size,
7967
8583
  offsetAtStart,
7968
- options,
8584
+ state: options,
7969
8585
  signal,
7970
8586
  logLevel,
7971
8587
  fields
7972
8588
  }) => {
7973
- const children = await parseIsoBaseMediaBoxes({
8589
+ const initialBoxes = [];
8590
+ const result = await parseIsoBaseMediaBoxes({
7974
8591
  iterator: data,
7975
8592
  maxBytes: size - (data.counter.getOffset() - offsetAtStart),
7976
8593
  allowIncompleteBoxes: false,
7977
- initialBoxes: [],
7978
- options,
8594
+ initialBoxes,
8595
+ state: options,
7979
8596
  continueMdat: false,
7980
8597
  signal,
7981
8598
  logLevel,
7982
8599
  fields
7983
8600
  });
7984
- if (children.status === "incomplete") {
8601
+ if (result.status === "incomplete") {
7985
8602
  throw new Error("Incomplete boxes are not allowed");
7986
8603
  }
7987
8604
  return {
7988
8605
  offset: offsetAtStart,
7989
8606
  boxSize: size,
7990
8607
  type: "trak-box",
7991
- children: children.segments.boxes
8608
+ children: initialBoxes
7992
8609
  };
7993
8610
  };
7994
8611
 
@@ -8039,19 +8656,20 @@ var getChildren = async ({
8039
8656
  boxType,
8040
8657
  iterator,
8041
8658
  bytesRemainingInBox,
8042
- options,
8659
+ state,
8043
8660
  signal,
8044
8661
  logLevel,
8045
8662
  fields
8046
8663
  }) => {
8047
8664
  const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "udta" || boxType === "moof" || boxType === "dims" || boxType === "meta" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
8048
8665
  if (parseChildren) {
8666
+ const boxes = [];
8049
8667
  const parsed = await parseIsoBaseMediaBoxes({
8050
8668
  iterator,
8051
8669
  maxBytes: bytesRemainingInBox,
8052
8670
  allowIncompleteBoxes: false,
8053
- initialBoxes: [],
8054
- options,
8671
+ initialBoxes: boxes,
8672
+ state,
8055
8673
  continueMdat: false,
8056
8674
  signal,
8057
8675
  logLevel,
@@ -8060,7 +8678,7 @@ var getChildren = async ({
8060
8678
  if (parsed.status === "incomplete") {
8061
8679
  throw new Error("Incomplete boxes are not allowed");
8062
8680
  }
8063
- return parsed.segments.boxes;
8681
+ return boxes;
8064
8682
  }
8065
8683
  if (bytesRemainingInBox < 0) {
8066
8684
  throw new Error("Box size is too big " + JSON.stringify({ boxType }));
@@ -8073,7 +8691,7 @@ var parseMdatPartially = async ({
8073
8691
  boxSize,
8074
8692
  fileOffset,
8075
8693
  parsedBoxes,
8076
- options,
8694
+ state,
8077
8695
  signal
8078
8696
  }) => {
8079
8697
  const box = await parseMdat({
@@ -8081,9 +8699,9 @@ var parseMdatPartially = async ({
8081
8699
  size: boxSize,
8082
8700
  fileOffset,
8083
8701
  existingBoxes: parsedBoxes,
8084
- options,
8702
+ state,
8085
8703
  signal,
8086
- maySkipSampleProcessing: options.supportsContentRange
8704
+ maySkipSampleProcessing: state.supportsContentRange
8087
8705
  });
8088
8706
  if ((box.status === "samples-processed" || box.status === "samples-buffered") && box.fileOffset + boxSize === iterator.counter.getOffset()) {
8089
8707
  return {
@@ -8103,7 +8721,7 @@ var processBox = async ({
8103
8721
  iterator,
8104
8722
  allowIncompleteBoxes,
8105
8723
  parsedBoxes,
8106
- options,
8724
+ state,
8107
8725
  signal,
8108
8726
  logLevel,
8109
8727
  fields
@@ -8135,7 +8753,7 @@ var processBox = async ({
8135
8753
  const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;
8136
8754
  if (bytesRemaining < boxSize) {
8137
8755
  if (boxType === "mdat") {
8138
- const shouldSkip = options.parserState.maySkipVideoData() || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, options.parserState) && options.supportsContentRange;
8756
+ const shouldSkip = maySkipVideoData({ state }) || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, state) && state.supportsContentRange;
8139
8757
  if (shouldSkip) {
8140
8758
  const skipTo = fileOffset + boxSize;
8141
8759
  const bytesToSkip = skipTo - iterator.counter.getOffset();
@@ -8158,7 +8776,7 @@ var processBox = async ({
8158
8776
  boxSize,
8159
8777
  fileOffset,
8160
8778
  parsedBoxes,
8161
- options,
8779
+ state,
8162
8780
  signal
8163
8781
  });
8164
8782
  }
@@ -8233,7 +8851,7 @@ var processBox = async ({
8233
8851
  iterator,
8234
8852
  offset: fileOffset,
8235
8853
  size: boxSize,
8236
- options,
8854
+ state,
8237
8855
  signal,
8238
8856
  fields
8239
8857
  });
@@ -8328,7 +8946,7 @@ var processBox = async ({
8328
8946
  iterator,
8329
8947
  offset: fileOffset,
8330
8948
  size: boxSize,
8331
- options,
8949
+ state,
8332
8950
  signal,
8333
8951
  fields
8334
8952
  });
@@ -8375,12 +8993,12 @@ var processBox = async ({
8375
8993
  iterator,
8376
8994
  offset: fileOffset,
8377
8995
  size: boxSize,
8378
- options,
8996
+ state,
8379
8997
  signal,
8380
8998
  logLevel,
8381
8999
  fields
8382
9000
  });
8383
- options.parserState.tracks.setIsDone();
9001
+ state.callbacks.tracks.setIsDone();
8384
9002
  return {
8385
9003
  type: "complete",
8386
9004
  box,
@@ -8393,7 +9011,7 @@ var processBox = async ({
8393
9011
  data: iterator,
8394
9012
  size: boxSize,
8395
9013
  offsetAtStart: fileOffset,
8396
- options,
9014
+ state,
8397
9015
  signal,
8398
9016
  logLevel,
8399
9017
  fields
@@ -8401,7 +9019,7 @@ var processBox = async ({
8401
9019
  const transformedTrack = makeBaseMediaTrack(box);
8402
9020
  if (transformedTrack) {
8403
9021
  await registerTrack({
8404
- options,
9022
+ state,
8405
9023
  track: transformedTrack,
8406
9024
  container: "mp4"
8407
9025
  });
@@ -8508,9 +9126,9 @@ var processBox = async ({
8508
9126
  size: boxSize,
8509
9127
  fileOffset,
8510
9128
  existingBoxes: parsedBoxes,
8511
- options,
9129
+ state,
8512
9130
  signal,
8513
- maySkipSampleProcessing: options.supportsContentRange
9131
+ maySkipSampleProcessing: state.supportsContentRange
8514
9132
  });
8515
9133
  if (box === null) {
8516
9134
  throw new Error("Unexpected null");
@@ -8527,7 +9145,7 @@ var processBox = async ({
8527
9145
  boxType,
8528
9146
  iterator,
8529
9147
  bytesRemainingInBox,
8530
- options,
9148
+ state,
8531
9149
  signal,
8532
9150
  logLevel,
8533
9151
  fields
@@ -8550,31 +9168,27 @@ var parseIsoBaseMediaBoxes = async ({
8550
9168
  maxBytes,
8551
9169
  allowIncompleteBoxes,
8552
9170
  initialBoxes,
8553
- options,
9171
+ state,
8554
9172
  continueMdat,
8555
9173
  signal,
8556
9174
  logLevel,
8557
9175
  fields
8558
9176
  }) => {
8559
- const structure = {
8560
- type: "iso-base-media",
8561
- boxes: initialBoxes
8562
- };
8563
9177
  const initialOffset = iterator.counter.getOffset();
8564
- const alreadyHasMdat = structure.boxes.find((b) => b.type === "mdat-box");
9178
+ const alreadyHasMdat = state.structure.getStructureOrNull()?.boxes.find((b) => b.type === "mdat-box");
8565
9179
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
8566
9180
  const result = continueMdat ? await parseMdatPartially({
8567
9181
  iterator,
8568
9182
  boxSize: continueMdat.boxSize,
8569
9183
  fileOffset: continueMdat.fileOffset,
8570
9184
  parsedBoxes: initialBoxes,
8571
- options,
9185
+ state,
8572
9186
  signal
8573
9187
  }) : await processBox({
8574
9188
  iterator,
8575
9189
  allowIncompleteBoxes,
8576
9190
  parsedBoxes: initialBoxes,
8577
- options,
9191
+ state,
8578
9192
  signal,
8579
9193
  logLevel,
8580
9194
  fields
@@ -8585,14 +9199,13 @@ var parseIsoBaseMediaBoxes = async ({
8585
9199
  }
8586
9200
  return {
8587
9201
  status: "incomplete",
8588
- segments: structure,
8589
9202
  continueParsing: () => {
8590
9203
  return parseIsoBaseMediaBoxes({
8591
9204
  iterator,
8592
9205
  maxBytes,
8593
9206
  allowIncompleteBoxes,
8594
- initialBoxes: structure.boxes,
8595
- options,
9207
+ initialBoxes,
9208
+ state,
8596
9209
  continueMdat: false,
8597
9210
  signal,
8598
9211
  logLevel,
@@ -8605,14 +9218,13 @@ var parseIsoBaseMediaBoxes = async ({
8605
9218
  if (result.type === "partial-mdat-box") {
8606
9219
  return {
8607
9220
  status: "incomplete",
8608
- segments: structure,
8609
9221
  continueParsing: () => {
8610
9222
  return Promise.resolve(parseIsoBaseMediaBoxes({
8611
9223
  iterator,
8612
9224
  maxBytes,
8613
9225
  allowIncompleteBoxes,
8614
- initialBoxes: structure.boxes,
8615
- options,
9226
+ initialBoxes,
9227
+ state,
8616
9228
  continueMdat: result,
8617
9229
  signal,
8618
9230
  logLevel,
@@ -8623,36 +9235,34 @@ var parseIsoBaseMediaBoxes = async ({
8623
9235
  };
8624
9236
  }
8625
9237
  if (result.box.type === "mdat-box" && alreadyHasMdat) {
8626
- structure.boxes = structure.boxes.filter((b) => b.type !== "mdat-box");
8627
- structure.boxes.push(result.box);
9238
+ initialBoxes = initialBoxes.filter((b) => b.type !== "mdat-box");
9239
+ initialBoxes.push(result.box);
8628
9240
  iterator.allowDiscard();
8629
9241
  if (result.box.status !== "samples-processed") {
8630
9242
  throw new Error("unexpected");
8631
9243
  }
8632
9244
  break;
8633
9245
  } else {
8634
- structure.boxes.push(result.box);
8635
- if (hasAllInfo({ fields, state: options.parserState, structure })) {
9246
+ initialBoxes.push(result.box);
9247
+ if (hasAllInfo({ fields, state })) {
8636
9248
  return {
8637
- status: "done",
8638
- segments: structure
9249
+ status: "done"
8639
9250
  };
8640
9251
  }
8641
9252
  }
8642
9253
  if (result.skipTo !== null) {
8643
- if (!options.supportsContentRange) {
9254
+ if (!state.supportsContentRange) {
8644
9255
  throw new Error("Content-Range header is not supported by the reader, but was asked to seek");
8645
9256
  }
8646
9257
  return {
8647
9258
  status: "incomplete",
8648
- segments: structure,
8649
9259
  continueParsing: () => {
8650
9260
  return parseIsoBaseMediaBoxes({
8651
9261
  iterator,
8652
9262
  maxBytes,
8653
9263
  allowIncompleteBoxes,
8654
- initialBoxes: structure.boxes,
8655
- options,
9264
+ initialBoxes,
9265
+ state,
8656
9266
  continueMdat: false,
8657
9267
  signal,
8658
9268
  logLevel,
@@ -8665,14 +9275,13 @@ var parseIsoBaseMediaBoxes = async ({
8665
9275
  if (iterator.bytesRemaining() < 0) {
8666
9276
  return {
8667
9277
  status: "incomplete",
8668
- segments: structure,
8669
9278
  continueParsing: () => {
8670
9279
  return parseIsoBaseMediaBoxes({
8671
9280
  iterator,
8672
9281
  maxBytes,
8673
9282
  allowIncompleteBoxes,
8674
- initialBoxes: structure.boxes,
8675
- options,
9283
+ initialBoxes,
9284
+ state,
8676
9285
  continueMdat: false,
8677
9286
  signal,
8678
9287
  logLevel,
@@ -8684,13 +9293,12 @@ var parseIsoBaseMediaBoxes = async ({
8684
9293
  }
8685
9294
  iterator.removeBytesRead();
8686
9295
  }
8687
- const mdatState = getMdatBox(structure.boxes);
8688
- const skipped = mdatState?.status === "samples-skipped" && !options.parserState.maySkipVideoData() && options.supportsContentRange;
8689
- const buffered = mdatState?.status === "samples-buffered" && !options.parserState.maySkipVideoData();
9296
+ const mdatState = getMdatBox(initialBoxes);
9297
+ const skipped = mdatState?.status === "samples-skipped" && !maySkipVideoData({ state }) && state.supportsContentRange;
9298
+ const buffered = mdatState?.status === "samples-buffered" && !maySkipVideoData({ state });
8690
9299
  if (skipped || buffered) {
8691
9300
  return {
8692
9301
  status: "incomplete",
8693
- segments: structure,
8694
9302
  continueParsing: () => {
8695
9303
  if (buffered) {
8696
9304
  iterator.skipTo(mdatState.fileOffset, false);
@@ -8699,8 +9307,8 @@ var parseIsoBaseMediaBoxes = async ({
8699
9307
  iterator,
8700
9308
  maxBytes,
8701
9309
  allowIncompleteBoxes: false,
8702
- initialBoxes: structure.boxes,
8703
- options,
9310
+ initialBoxes,
9311
+ state,
8704
9312
  continueMdat: false,
8705
9313
  signal,
8706
9314
  logLevel,
@@ -8711,8 +9319,7 @@ var parseIsoBaseMediaBoxes = async ({
8711
9319
  };
8712
9320
  }
8713
9321
  return {
8714
- status: "done",
8715
- segments: structure
9322
+ status: "done"
8716
9323
  };
8717
9324
  };
8718
9325
 
@@ -8980,37 +9587,39 @@ var getStrhForIndex = (structure, trackId) => {
8980
9587
  };
8981
9588
  var handleChunk = async ({
8982
9589
  iterator,
8983
- options,
9590
+ state,
8984
9591
  structure,
8985
9592
  ckId,
8986
9593
  ckSize
8987
9594
  }) => {
9595
+ const offset = iterator.counter.getOffset();
8988
9596
  const videoChunk = ckId.match(/^([0-9]{2})dc$/);
8989
9597
  if (videoChunk) {
8990
9598
  const trackId = parseInt(videoChunk[1], 10);
8991
9599
  const strh = getStrhForIndex(structure, trackId);
8992
9600
  const samplesPerSecond = strh.rate / strh.scale;
8993
- const nthSample = options.parserState.getSamplesForTrack(trackId);
9601
+ const nthSample = state.callbacks.getSamplesForTrack(trackId);
8994
9602
  const timeInSec = nthSample / samplesPerSecond;
8995
- const timestamp = Math.floor(timeInSec);
8996
- const duration2 = Math.floor(1 / samplesPerSecond);
9603
+ const timestamp = timeInSec;
8997
9604
  const data = iterator.getSlice(ckSize);
8998
9605
  const infos = parseAvc(data);
8999
9606
  const keyOrDelta = getKeyFrameOrDeltaFromAvcInfo(infos);
9000
9607
  const avcProfile = infos.find((i) => i.type === "avc-profile");
9001
9608
  const ppsProfile = infos.find((i) => i.type === "avc-pps");
9002
9609
  if (avcProfile && ppsProfile) {
9003
- await options.parserState.onProfile({ pps: ppsProfile, sps: avcProfile });
9004
- options.parserState.tracks.setIsDone();
9610
+ await state.riff.onProfile({ pps: ppsProfile, sps: avcProfile });
9611
+ state.callbacks.tracks.setIsDone();
9005
9612
  }
9006
- await options.parserState.onVideoSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9613
+ await state.callbacks.onVideoSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9007
9614
  cts: timestamp,
9008
9615
  dts: timestamp,
9009
9616
  data,
9010
- duration: duration2,
9617
+ duration: undefined,
9011
9618
  timestamp,
9012
9619
  trackId,
9013
- type: keyOrDelta
9620
+ type: keyOrDelta,
9621
+ offset,
9622
+ timescale: samplesPerSecond
9014
9623
  }, 1));
9015
9624
  return;
9016
9625
  }
@@ -9019,25 +9628,27 @@ var handleChunk = async ({
9019
9628
  const trackId = parseInt(audioChunk[1], 10);
9020
9629
  const strh = getStrhForIndex(structure, trackId);
9021
9630
  const samplesPerSecond = strh.rate / strh.scale;
9022
- const nthSample = options.parserState.getSamplesForTrack(trackId);
9631
+ const nthSample = state.callbacks.getSamplesForTrack(trackId);
9023
9632
  const timeInSec = nthSample / samplesPerSecond;
9024
9633
  const timestamp = timeInSec;
9025
- const duration2 = 1 / samplesPerSecond;
9026
- await options.parserState.onAudioSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9634
+ const data = iterator.getSlice(ckSize);
9635
+ await state.callbacks.onAudioSample(trackId, convertAudioOrVideoSampleToWebCodecsTimestamps({
9027
9636
  cts: timestamp,
9028
9637
  dts: timestamp,
9029
- data: iterator.getSlice(ckSize),
9030
- duration: duration2,
9638
+ data,
9639
+ duration: undefined,
9031
9640
  timestamp,
9032
9641
  trackId,
9033
- type: "key"
9642
+ type: "key",
9643
+ offset,
9644
+ timescale: samplesPerSecond
9034
9645
  }, 1));
9035
9646
  }
9036
9647
  };
9037
9648
  var parseMovi = async ({
9038
9649
  iterator,
9039
9650
  maxOffset,
9040
- options,
9651
+ state,
9041
9652
  structure
9042
9653
  }) => {
9043
9654
  while (iterator.counter.getOffset() < maxOffset) {
@@ -9045,13 +9656,15 @@ var parseMovi = async ({
9045
9656
  return {
9046
9657
  type: "incomplete",
9047
9658
  continueParsing: () => {
9048
- return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
9659
+ return Promise.resolve(parseMovi({ iterator, maxOffset, state, structure }));
9049
9660
  }
9050
9661
  };
9051
9662
  }
9052
9663
  const ckId = iterator.getByteString(4);
9053
9664
  const ckSize = iterator.getUint32Le();
9054
- if (options.parserState.maySkipVideoData() && options.parserState.getAvcProfile()) {
9665
+ if (maySkipVideoData({
9666
+ state
9667
+ }) && state.riff.getAvcProfile()) {
9055
9668
  return {
9056
9669
  type: "complete",
9057
9670
  box: {
@@ -9065,11 +9678,11 @@ var parseMovi = async ({
9065
9678
  return {
9066
9679
  type: "incomplete",
9067
9680
  continueParsing: () => {
9068
- return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
9681
+ return Promise.resolve(parseMovi({ iterator, maxOffset, state, structure }));
9069
9682
  }
9070
9683
  };
9071
9684
  }
9072
- await handleChunk({ iterator, options, structure, ckId, ckSize });
9685
+ await handleChunk({ iterator, state, structure, ckId, ckSize });
9073
9686
  while (iterator.counter.getOffset() < maxOffset && iterator.bytesRemaining() > 0) {
9074
9687
  if (iterator.getUint8() !== 0) {
9075
9688
  iterator.counter.decrement(1);
@@ -9092,7 +9705,7 @@ var parseMovi = async ({
9092
9705
  return {
9093
9706
  type: "incomplete",
9094
9707
  continueParsing: () => {
9095
- return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
9708
+ return Promise.resolve(parseMovi({ iterator, maxOffset, state, structure }));
9096
9709
  }
9097
9710
  };
9098
9711
  };
@@ -9187,7 +9800,7 @@ var parseIsft = ({
9187
9800
  var parseListBox = async ({
9188
9801
  iterator,
9189
9802
  size,
9190
- options
9803
+ state
9191
9804
  }) => {
9192
9805
  const counter = iterator.counter.getOffset();
9193
9806
  const listType = iterator.getByteString(4);
@@ -9202,7 +9815,7 @@ var parseListBox = async ({
9202
9815
  structure,
9203
9816
  iterator,
9204
9817
  maxOffset: counter + size,
9205
- options
9818
+ state
9206
9819
  });
9207
9820
  if (result.status === "incomplete") {
9208
9821
  throw new Error(`Should only parse complete boxes (${listType})`);
@@ -9342,13 +9955,13 @@ var parseRiffBox = ({
9342
9955
  size,
9343
9956
  id,
9344
9957
  boxes,
9345
- options
9958
+ state
9346
9959
  }) => {
9347
9960
  if (id === "fmt") {
9348
9961
  return Promise.resolve(parseFmtBox({ iterator, boxes, size }));
9349
9962
  }
9350
9963
  if (id === "LIST") {
9351
- return parseListBox({ iterator, size, options });
9964
+ return parseListBox({ iterator, size, state });
9352
9965
  }
9353
9966
  if (id === "ISFT") {
9354
9967
  return Promise.resolve(parseIsft({ iterator, size }));
@@ -9374,14 +9987,14 @@ var parseRiffBox = ({
9374
9987
  // src/boxes/riff/expect-riff-box.ts
9375
9988
  var expectRiffBox = async ({
9376
9989
  iterator,
9377
- options,
9990
+ state,
9378
9991
  structure
9379
9992
  }) => {
9380
9993
  if (iterator.bytesRemaining() < 16) {
9381
9994
  return {
9382
9995
  type: "incomplete",
9383
9996
  continueParsing() {
9384
- return expectRiffBox({ structure, iterator, options });
9997
+ return expectRiffBox({ structure, iterator, state });
9385
9998
  }
9386
9999
  };
9387
10000
  }
@@ -9392,7 +10005,7 @@ var expectRiffBox = async ({
9392
10005
  return parseMovi({
9393
10006
  iterator,
9394
10007
  maxOffset: ckSize + iterator.counter.getOffset() - 4,
9395
- options,
10008
+ state,
9396
10009
  structure
9397
10010
  });
9398
10011
  }
@@ -9401,7 +10014,7 @@ var expectRiffBox = async ({
9401
10014
  return {
9402
10015
  type: "incomplete",
9403
10016
  continueParsing: () => {
9404
- return expectRiffBox({ structure, iterator, options });
10017
+ return expectRiffBox({ structure, iterator, state });
9405
10018
  }
9406
10019
  };
9407
10020
  }
@@ -9412,7 +10025,7 @@ var expectRiffBox = async ({
9412
10025
  iterator,
9413
10026
  size: ckSize,
9414
10027
  boxes: structure.boxes,
9415
- options
10028
+ state
9416
10029
  }),
9417
10030
  skipTo: null
9418
10031
  };
@@ -9424,7 +10037,7 @@ var continueAfterRiffBoxResult = ({
9424
10037
  structure,
9425
10038
  iterator,
9426
10039
  maxOffset,
9427
- options
10040
+ state: options
9428
10041
  }) => {
9429
10042
  if (result.type === "incomplete") {
9430
10043
  return Promise.resolve({
@@ -9435,7 +10048,7 @@ var continueAfterRiffBoxResult = ({
9435
10048
  structure,
9436
10049
  iterator,
9437
10050
  maxOffset,
9438
- options
10051
+ state: options
9439
10052
  }));
9440
10053
  },
9441
10054
  segments: structure,
@@ -9445,30 +10058,29 @@ var continueAfterRiffBoxResult = ({
9445
10058
  if (result.type === "complete" && result.box) {
9446
10059
  structure.boxes.push(result.box);
9447
10060
  }
9448
- return parseRiffBody({ iterator, maxOffset, options, structure });
10061
+ return parseRiffBody({ iterator, maxOffset, state: options, structure });
9449
10062
  };
9450
10063
  var parseRiffBody = async ({
9451
10064
  iterator,
9452
10065
  structure,
9453
10066
  maxOffset,
9454
- options
10067
+ state
9455
10068
  }) => {
9456
10069
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset) {
9457
10070
  const result = await expectRiffBox({
9458
10071
  iterator,
9459
- options,
10072
+ state,
9460
10073
  structure
9461
10074
  });
9462
10075
  if (result.type === "complete" && result.skipTo !== null) {
9463
10076
  return {
9464
10077
  status: "incomplete",
9465
10078
  skipTo: result.skipTo,
9466
- segments: structure,
9467
10079
  continueParsing() {
9468
10080
  return Promise.resolve(continueAfterRiffBoxResult({
9469
10081
  iterator,
9470
10082
  maxOffset,
9471
- options,
10083
+ state,
9472
10084
  result,
9473
10085
  structure
9474
10086
  }));
@@ -9482,12 +10094,11 @@ var parseRiffBody = async ({
9482
10094
  return Promise.resolve(continueAfterRiffBoxResult({
9483
10095
  iterator,
9484
10096
  maxOffset,
9485
- options,
10097
+ state,
9486
10098
  result: await result.continueParsing(),
9487
10099
  structure
9488
10100
  }));
9489
10101
  },
9490
- segments: structure,
9491
10102
  skipTo: null
9492
10103
  };
9493
10104
  }
@@ -9496,13 +10107,13 @@ var parseRiffBody = async ({
9496
10107
  }
9497
10108
  structure.boxes.push(result.box);
9498
10109
  if (result.box.type === "list-box" && result.box.listType === "hdrl") {
9499
- const tracks2 = getTracks(structure, options.parserState);
10110
+ const tracks2 = getTracks(structure, state);
9500
10111
  if (!tracks2.videoTracks.some((t) => t.codec === TO_BE_OVERRIDDEN_LATER)) {
9501
- options.parserState.tracks.setIsDone();
10112
+ state.callbacks.tracks.setIsDone();
9502
10113
  }
9503
10114
  }
9504
10115
  if (result.box.type === "wave-format-box") {
9505
- options.parserState.tracks.setIsDone();
10116
+ state.callbacks.tracks.setIsDone();
9506
10117
  }
9507
10118
  if (result.box.type === "strf-box-video" || result.box.type === "strf-box-audio") {
9508
10119
  const strh = getStrhBox(structure.boxes);
@@ -9510,60 +10121,67 @@ var parseRiffBody = async ({
9510
10121
  if (!strh || !strf) {
9511
10122
  throw new Error("strh or strf box missing");
9512
10123
  }
9513
- if (strf.type === "strf-box-audio" && options.onAudioTrack) {
10124
+ if (strf.type === "strf-box-audio" && state.onAudioTrack) {
9514
10125
  const audioTrack = makeAviAudioTrack({
9515
- index: options.nextTrackIndex,
10126
+ index: state.riff.getNextTrackIndex(),
9516
10127
  strf
9517
10128
  });
9518
10129
  await registerTrack({
9519
- options,
10130
+ state,
9520
10131
  track: audioTrack,
9521
10132
  container: "avi"
9522
10133
  });
9523
10134
  }
9524
- if (options.onVideoTrack && strf.type === "strf-box-video") {
10135
+ if (state.onVideoTrack && strf.type === "strf-box-video") {
9525
10136
  const videoTrack = makeAviVideoTrack({
9526
10137
  strh,
9527
- index: options.nextTrackIndex,
10138
+ index: state.riff.getNextTrackIndex(),
9528
10139
  strf
9529
10140
  });
9530
10141
  registerVideoTrackWhenProfileIsAvailable({
9531
- options,
10142
+ state,
9532
10143
  track: videoTrack,
9533
10144
  container: "avi"
9534
10145
  });
9535
10146
  }
9536
- options.nextTrackIndex++;
10147
+ state.riff.incrementNextTrackIndex();
9537
10148
  }
9538
10149
  }
9539
10150
  return {
9540
- status: "done",
9541
- segments: structure
10151
+ status: "done"
9542
10152
  };
9543
10153
  };
9544
10154
  var parseRiff = ({
9545
10155
  iterator,
9546
- options,
10156
+ state,
9547
10157
  fields
9548
10158
  }) => {
9549
- const structure = { type: "riff", boxes: [] };
9550
10159
  const riff = iterator.getByteString(4);
9551
10160
  if (riff !== "RIFF") {
9552
10161
  throw new Error("Not a RIFF file");
9553
10162
  }
10163
+ const structure = state.structure.getStructure();
10164
+ if (structure.type !== "riff") {
10165
+ throw new Error("Structure is not a RIFF structure");
10166
+ }
9554
10167
  const size = iterator.getUint32Le();
9555
10168
  const fileType = iterator.getByteString(4);
9556
10169
  if (fileType !== "WAVE" && fileType !== "AVI") {
9557
10170
  throw new Error(`File type ${fileType} not supported`);
9558
10171
  }
9559
10172
  structure.boxes.push({ type: "riff-header", fileSize: size, fileType });
9560
- if (hasAllInfo({ fields, structure, state: options.parserState })) {
10173
+ if (hasAllInfo({ fields, state })) {
9561
10174
  return Promise.resolve({
9562
10175
  status: "done",
9563
10176
  segments: structure
9564
10177
  });
9565
10178
  }
9566
- return parseRiffBody({ iterator, structure, maxOffset: Infinity, options });
10179
+ return parseRiffBody({
10180
+ iterator,
10181
+ maxOffset: Infinity,
10182
+ state,
10183
+ structure
10184
+ });
9567
10185
  };
9568
10186
 
9569
10187
  // src/boxes/transport-stream/next-pes-header-store.ts
@@ -9903,10 +10521,11 @@ var MPEG_TIMESCALE = 90000;
9903
10521
  var handleAvcPacket = async ({
9904
10522
  streamBuffer,
9905
10523
  programId,
9906
- options
10524
+ state,
10525
+ offset
9907
10526
  }) => {
9908
10527
  const avc = parseAvc(streamBuffer.buffer);
9909
- const isTrackRegistered = options.parserState.tracks.getTracks().find((t) => {
10528
+ const isTrackRegistered = state.callbacks.tracks.getTracks().find((t) => {
9910
10529
  return t.trackId === programId;
9911
10530
  });
9912
10531
  if (!isTrackRegistered) {
@@ -9919,7 +10538,7 @@ var handleAvcPacket = async ({
9919
10538
  type: "video",
9920
10539
  timescale: MPEG_TIMESCALE,
9921
10540
  codec: getCodecStringFromSpsAndPps(spsAndPps.sps),
9922
- codecPrivate: getAvccBoxContent(spsAndPps),
10541
+ codecPrivate: createSpsPpsData(spsAndPps),
9923
10542
  fps: null,
9924
10543
  codedWidth: dimensions.width,
9925
10544
  codedHeight: dimensions.height,
@@ -9936,7 +10555,7 @@ var handleAvcPacket = async ({
9936
10555
  },
9937
10556
  color: getVideoColorFromSps(spsAndPps.sps.spsData)
9938
10557
  };
9939
- await registerTrack({ track, options, container: "transport-stream" });
10558
+ await registerTrack({ track, state, container: "transport-stream" });
9940
10559
  }
9941
10560
  const sample = {
9942
10561
  cts: streamBuffer.pesHeader.pts,
@@ -9945,23 +10564,26 @@ var handleAvcPacket = async ({
9945
10564
  duration: undefined,
9946
10565
  data: new Uint8Array(streamBuffer.buffer),
9947
10566
  trackId: programId,
9948
- type: getKeyFrameOrDeltaFromAvcInfo(avc)
10567
+ type: getKeyFrameOrDeltaFromAvcInfo(avc),
10568
+ offset,
10569
+ timescale: MPEG_TIMESCALE
9949
10570
  };
9950
- await options.parserState.onVideoSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
10571
+ await state.callbacks.onVideoSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
9951
10572
  };
9952
10573
 
9953
10574
  // src/boxes/transport-stream/handle-aac-packet.ts
9954
10575
  var handleAacPacket = async ({
9955
10576
  streamBuffer,
9956
- options,
9957
- programId
10577
+ state,
10578
+ programId,
10579
+ offset
9958
10580
  }) => {
9959
10581
  const adtsHeader = readAdtsHeader(streamBuffer.buffer);
9960
10582
  if (!adtsHeader) {
9961
10583
  throw new Error("Invalid ADTS header - too short");
9962
10584
  }
9963
10585
  const { channelConfiguration, codecPrivate: codecPrivate2, sampleRate, audioObjectType } = adtsHeader;
9964
- const isTrackRegistered = options.parserState.tracks.getTracks().find((t) => {
10586
+ const isTrackRegistered = state.callbacks.tracks.getTracks().find((t) => {
9965
10587
  return t.trackId === programId;
9966
10588
  });
9967
10589
  if (!isTrackRegistered) {
@@ -9979,7 +10601,7 @@ var handleAacPacket = async ({
9979
10601
  };
9980
10602
  await registerTrack({
9981
10603
  track,
9982
- options,
10604
+ state,
9983
10605
  container: "transport-stream"
9984
10606
  });
9985
10607
  }
@@ -9990,15 +10612,17 @@ var handleAacPacket = async ({
9990
10612
  duration: undefined,
9991
10613
  data: new Uint8Array(streamBuffer.buffer),
9992
10614
  trackId: programId,
9993
- type: "key"
10615
+ type: "key",
10616
+ offset,
10617
+ timescale: MPEG_TIMESCALE
9994
10618
  };
9995
- await options.parserState.onAudioSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
10619
+ await state.callbacks.onAudioSample(programId, convertAudioOrVideoSampleToWebCodecsTimestamps(sample, MPEG_TIMESCALE));
9996
10620
  };
9997
10621
 
9998
10622
  // src/boxes/transport-stream/process-stream-buffers.ts
9999
10623
  var processStreamBuffer = async ({
10000
10624
  streamBuffer,
10001
- options,
10625
+ state,
10002
10626
  programId,
10003
10627
  structure
10004
10628
  }) => {
@@ -10007,28 +10631,38 @@ var processStreamBuffer = async ({
10007
10631
  throw new Error("No stream found");
10008
10632
  }
10009
10633
  if (stream.streamType === 27) {
10010
- await handleAvcPacket({ programId, streamBuffer, options });
10634
+ await handleAvcPacket({
10635
+ programId,
10636
+ streamBuffer,
10637
+ state,
10638
+ offset: streamBuffer.offset
10639
+ });
10011
10640
  } else if (stream.streamType === 15) {
10012
- await handleAacPacket({ streamBuffer, options, programId });
10641
+ await handleAacPacket({
10642
+ streamBuffer,
10643
+ state,
10644
+ programId,
10645
+ offset: streamBuffer.offset
10646
+ });
10013
10647
  }
10014
- if (!options.parserState.tracks.hasAllTracks()) {
10015
- const tracksRegistered = options.parserState.tracks.getTracks().length;
10648
+ if (!state.callbacks.tracks.hasAllTracks()) {
10649
+ const tracksRegistered = state.callbacks.tracks.getTracks().length;
10016
10650
  const { streams } = findProgramMapTableOrThrow(structure);
10017
10651
  if (streams.length === tracksRegistered) {
10018
- options.parserState.tracks.setIsDone();
10652
+ state.callbacks.tracks.setIsDone();
10019
10653
  }
10020
10654
  }
10021
10655
  };
10022
10656
  var processFinalStreamBuffers = async ({
10023
10657
  streamBufferMap,
10024
- parserContext,
10658
+ state,
10025
10659
  structure
10026
10660
  }) => {
10027
10661
  for (const [programId, buffer] of streamBufferMap) {
10028
10662
  if (buffer.buffer.byteLength > 0) {
10029
10663
  await processStreamBuffer({
10030
10664
  streamBuffer: buffer,
10031
- options: parserContext,
10665
+ state,
10032
10666
  programId,
10033
10667
  structure
10034
10668
  });
@@ -10043,14 +10677,16 @@ var parseAdtsStream = async ({
10043
10677
  transportStreamEntry,
10044
10678
  streamBuffers,
10045
10679
  nextPesHeader,
10046
- options,
10047
- structure
10680
+ state,
10681
+ structure,
10682
+ offset
10048
10683
  }) => {
10049
10684
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
10050
10685
  if (!streamBuffer) {
10051
10686
  streamBuffers.set(transportStreamEntry.pid, {
10052
10687
  buffer: restOfPacket,
10053
- pesHeader: nextPesHeader
10688
+ pesHeader: nextPesHeader,
10689
+ offset
10054
10690
  });
10055
10691
  return;
10056
10692
  }
@@ -10064,13 +10700,14 @@ var parseAdtsStream = async ({
10064
10700
  await processStreamBuffer({
10065
10701
  streamBuffer,
10066
10702
  programId: transportStreamEntry.pid,
10067
- options,
10703
+ state,
10068
10704
  structure
10069
10705
  });
10070
10706
  const rest = restOfPacket.slice(bytesToTake);
10071
10707
  streamBuffers.set(transportStreamEntry.pid, {
10072
10708
  buffer: rest,
10073
- pesHeader: nextPesHeader
10709
+ pesHeader: nextPesHeader,
10710
+ offset
10074
10711
  });
10075
10712
  }
10076
10713
  };
@@ -10080,8 +10717,9 @@ var parseAvcStream = async ({
10080
10717
  streamBuffers,
10081
10718
  nextPesHeader,
10082
10719
  programId,
10083
- parserContext,
10084
- structure
10720
+ state,
10721
+ structure,
10722
+ offset
10085
10723
  }) => {
10086
10724
  const indexOfSeparator = findNextSeparator(restOfPacket, transportStreamEntry);
10087
10725
  const streamBuffer = streamBuffers.get(transportStreamEntry.pid);
@@ -10095,7 +10733,8 @@ var parseAvcStream = async ({
10095
10733
  }
10096
10734
  streamBuffers.set(programId, {
10097
10735
  pesHeader: nextPesHeader,
10098
- buffer: restOfPacket
10736
+ buffer: restOfPacket,
10737
+ offset
10099
10738
  });
10100
10739
  return;
10101
10740
  }
@@ -10103,7 +10742,7 @@ var parseAvcStream = async ({
10103
10742
  const packet = restOfPacket.slice(0, indexOfSeparator);
10104
10743
  streamBuffer.buffer = combineUint8Arrays([streamBuffer.buffer, packet]);
10105
10744
  await processStreamBuffer({
10106
- options: parserContext,
10745
+ state,
10107
10746
  streamBuffer,
10108
10747
  programId,
10109
10748
  structure
@@ -10111,7 +10750,8 @@ var parseAvcStream = async ({
10111
10750
  const rest = restOfPacket.slice(indexOfSeparator);
10112
10751
  streamBuffers.set(programId, {
10113
10752
  pesHeader: nextPesHeader,
10114
- buffer: rest
10753
+ buffer: rest,
10754
+ offset
10115
10755
  });
10116
10756
  return;
10117
10757
  }
@@ -10120,14 +10760,15 @@ var parseAvcStream = async ({
10120
10760
  }
10121
10761
  streamBuffers.set(programId, {
10122
10762
  pesHeader: nextPesHeader,
10123
- buffer: restOfPacket.slice(indexOfSeparator)
10763
+ buffer: restOfPacket.slice(indexOfSeparator),
10764
+ offset
10124
10765
  });
10125
10766
  };
10126
10767
  var parseStream = ({
10127
10768
  iterator,
10128
10769
  transportStreamEntry,
10129
10770
  streamBuffers,
10130
- parserContext,
10771
+ state,
10131
10772
  programId,
10132
10773
  structure,
10133
10774
  nextPesHeader
@@ -10139,9 +10780,10 @@ var parseStream = ({
10139
10780
  transportStreamEntry,
10140
10781
  streamBuffers,
10141
10782
  nextPesHeader,
10142
- parserContext,
10783
+ state,
10143
10784
  programId,
10144
- structure
10785
+ structure,
10786
+ offset: iterator.counter.getOffset()
10145
10787
  });
10146
10788
  }
10147
10789
  if (transportStreamEntry.streamType === 15) {
@@ -10150,8 +10792,9 @@ var parseStream = ({
10150
10792
  transportStreamEntry,
10151
10793
  streamBuffers,
10152
10794
  nextPesHeader,
10153
- options: parserContext,
10154
- structure
10795
+ state,
10796
+ structure,
10797
+ offset: iterator.counter.getOffset()
10155
10798
  });
10156
10799
  }
10157
10800
  throw new Error(`Unsupported stream type ${transportStreamEntry.streamType}`);
@@ -10162,7 +10805,7 @@ var parsePacket = async ({
10162
10805
  iterator,
10163
10806
  structure,
10164
10807
  streamBuffers,
10165
- parserContext,
10808
+ parserState,
10166
10809
  nextPesHeaderStore
10167
10810
  }) => {
10168
10811
  const offset = iterator.counter.getOffset();
@@ -10226,7 +10869,7 @@ var parsePacket = async ({
10226
10869
  transportStreamEntry: stream,
10227
10870
  streamBuffers,
10228
10871
  nextPesHeader: nextPesHeaderStore.getNextPesHeader(),
10229
- parserContext,
10872
+ state: parserState,
10230
10873
  programId,
10231
10874
  structure
10232
10875
  });
@@ -10238,16 +10881,19 @@ var parsePacket = async ({
10238
10881
  // src/boxes/transport-stream/parse-transport-stream.ts
10239
10882
  var parseTransportStream = async ({
10240
10883
  iterator,
10241
- parserContext,
10242
- structure,
10884
+ state,
10243
10885
  streamBuffers,
10244
10886
  fields,
10245
10887
  nextPesHeaderStore
10246
10888
  }) => {
10889
+ const structure = state.structure.getStructure();
10890
+ if (structure.type !== "transport-stream") {
10891
+ throw new Error("Invalid structure type");
10892
+ }
10247
10893
  if (iterator.bytesRemaining() === 0) {
10248
10894
  await processFinalStreamBuffers({
10249
10895
  streamBufferMap: streamBuffers,
10250
- parserContext,
10896
+ state,
10251
10897
  structure
10252
10898
  });
10253
10899
  return Promise.resolve({
@@ -10258,8 +10904,7 @@ var parseTransportStream = async ({
10258
10904
  while (true) {
10259
10905
  if (hasAllInfo({
10260
10906
  fields,
10261
- state: parserContext.parserState,
10262
- structure
10907
+ state
10263
10908
  })) {
10264
10909
  break;
10265
10910
  }
@@ -10271,8 +10916,7 @@ var parseTransportStream = async ({
10271
10916
  continueParsing: () => {
10272
10917
  return parseTransportStream({
10273
10918
  iterator,
10274
- parserContext,
10275
- structure,
10919
+ state,
10276
10920
  streamBuffers,
10277
10921
  fields,
10278
10922
  nextPesHeaderStore
@@ -10284,7 +10928,7 @@ var parseTransportStream = async ({
10284
10928
  iterator,
10285
10929
  structure,
10286
10930
  streamBuffers,
10287
- parserContext,
10931
+ parserState: state,
10288
10932
  nextPesHeaderStore
10289
10933
  });
10290
10934
  if (packet) {
@@ -10298,8 +10942,7 @@ var parseTransportStream = async ({
10298
10942
  continueParsing() {
10299
10943
  return parseTransportStream({
10300
10944
  iterator,
10301
- parserContext,
10302
- structure,
10945
+ state,
10303
10946
  streamBuffers,
10304
10947
  fields,
10305
10948
  nextPesHeaderStore
@@ -10342,7 +10985,7 @@ var parseBlockFlags = (iterator, type) => {
10342
10985
  };
10343
10986
 
10344
10987
  // src/boxes/webm/get-sample-from-block.ts
10345
- var getSampleFromBlock = (ebml, parserContext, offset) => {
10988
+ var getSampleFromBlock = (ebml, state, offset) => {
10346
10989
  const iterator = getArrayBufferIterator(ebml.value, ebml.value.length);
10347
10990
  const trackNumber2 = iterator.getVint();
10348
10991
  if (trackNumber2 === null) {
@@ -10350,9 +10993,9 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10350
10993
  }
10351
10994
  const timecodeRelativeToCluster = iterator.getInt16();
10352
10995
  const { keyframe } = parseBlockFlags(iterator, ebml.type === "SimpleBlock" ? matroskaElements.SimpleBlock : matroskaElements.Block);
10353
- const { codec, trackTimescale } = parserContext.parserState.getTrackInfoByNumber(trackNumber2);
10354
- const clusterOffset = parserContext.parserState.getTimestampOffsetForByteOffset(offset);
10355
- const timescale2 = parserContext.parserState.getTimescale();
10996
+ const { codec, trackTimescale } = state.webm.getTrackInfoByNumber(trackNumber2);
10997
+ const clusterOffset = state.webm.getTimestampOffsetForByteOffset(offset);
10998
+ const timescale2 = state.webm.getTimescale();
10356
10999
  if (clusterOffset === undefined) {
10357
11000
  throw new Error("Could not find offset for byte offset " + offset);
10358
11001
  }
@@ -10369,7 +11012,9 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10369
11012
  dts: timecodeInMicroseconds,
10370
11013
  duration: undefined,
10371
11014
  trackId: trackNumber2,
10372
- timestamp: timecodeInMicroseconds
11015
+ timestamp: timecodeInMicroseconds,
11016
+ offset,
11017
+ timescale: timescale2
10373
11018
  };
10374
11019
  if (keyframe === null) {
10375
11020
  iterator.destroy();
@@ -10396,7 +11041,9 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10396
11041
  type: "key",
10397
11042
  duration: undefined,
10398
11043
  cts: timecodeInMicroseconds,
10399
- dts: timecodeInMicroseconds
11044
+ dts: timecodeInMicroseconds,
11045
+ offset,
11046
+ timescale: timescale2
10400
11047
  };
10401
11048
  iterator.destroy();
10402
11049
  return {
@@ -10411,7 +11058,7 @@ var getSampleFromBlock = (ebml, parserContext, offset) => {
10411
11058
  };
10412
11059
 
10413
11060
  // src/boxes/webm/parse-ebml.ts
10414
- var parseEbml = async (iterator, parserContext) => {
11061
+ var parseEbml = async (iterator, state) => {
10415
11062
  const hex = iterator.getMatroskaSegmentId();
10416
11063
  if (hex === null) {
10417
11064
  throw new Error("Not enough bytes left to parse EBML - this should not happen");
@@ -10480,11 +11127,11 @@ var parseEbml = async (iterator, parserContext) => {
10480
11127
  break;
10481
11128
  }
10482
11129
  const offset = iterator.counter.getOffset();
10483
- const value = await parseEbml(iterator, parserContext);
11130
+ const value = await parseEbml(iterator, state);
10484
11131
  const remapped = await postprocessEbml({
10485
11132
  offset,
10486
11133
  ebml: value,
10487
- parserContext
11134
+ state
10488
11135
  });
10489
11136
  children.push(remapped);
10490
11137
  const offsetNow = iterator.counter.getOffset();
@@ -10502,47 +11149,47 @@ var parseEbml = async (iterator, parserContext) => {
10502
11149
  var postprocessEbml = async ({
10503
11150
  offset,
10504
11151
  ebml,
10505
- parserContext
11152
+ state
10506
11153
  }) => {
10507
11154
  if (ebml.type === "TimestampScale") {
10508
- parserContext.parserState.setTimescale(ebml.value.value);
11155
+ state.webm.setTimescale(ebml.value.value);
10509
11156
  }
10510
11157
  if (ebml.type === "TrackEntry") {
10511
- parserContext.parserState.onTrackEntrySegment(ebml);
11158
+ state.webm.onTrackEntrySegment(ebml);
10512
11159
  const track = getTrack({
10513
11160
  track: ebml,
10514
- timescale: parserContext.parserState.getTimescale()
11161
+ timescale: state.webm.getTimescale()
10515
11162
  });
10516
11163
  if (track) {
10517
11164
  await registerTrack({
10518
- options: parserContext,
11165
+ state,
10519
11166
  track,
10520
11167
  container: "webm"
10521
11168
  });
10522
11169
  }
10523
11170
  }
10524
11171
  if (ebml.type === "Timestamp") {
10525
- parserContext.parserState.setTimestampOffset(offset, ebml.value.value);
11172
+ state.webm.setTimestampOffset(offset, ebml.value.value);
10526
11173
  }
10527
11174
  if (ebml.type === "Block" || ebml.type === "SimpleBlock") {
10528
- const sample = getSampleFromBlock(ebml, parserContext, offset);
10529
- if (sample.type === "video-sample" && parserContext.nullifySamples) {
10530
- await parserContext.parserState.onVideoSample(sample.videoSample.trackId, sample.videoSample);
11175
+ const sample = getSampleFromBlock(ebml, state, offset);
11176
+ if (sample.type === "video-sample" && state.nullifySamples) {
11177
+ await state.callbacks.onVideoSample(sample.videoSample.trackId, sample.videoSample);
10531
11178
  return {
10532
11179
  type: "Block",
10533
11180
  value: new Uint8Array([]),
10534
11181
  minVintWidth: ebml.minVintWidth
10535
11182
  };
10536
11183
  }
10537
- if (sample.type === "audio-sample" && parserContext.nullifySamples) {
10538
- await parserContext.parserState.onAudioSample(sample.audioSample.trackId, sample.audioSample);
11184
+ if (sample.type === "audio-sample" && state.nullifySamples) {
11185
+ await state.callbacks.onAudioSample(sample.audioSample.trackId, sample.audioSample);
10539
11186
  return {
10540
11187
  type: "Block",
10541
11188
  value: new Uint8Array([]),
10542
11189
  minVintWidth: ebml.minVintWidth
10543
11190
  };
10544
11191
  }
10545
- if (sample.type === "no-sample" && parserContext.nullifySamples) {
11192
+ if (sample.type === "no-sample" && state.nullifySamples) {
10546
11193
  return {
10547
11194
  type: "Block",
10548
11195
  value: new Uint8Array([]),
@@ -10556,15 +11203,15 @@ var postprocessEbml = async ({
10556
11203
  throw new Error("Expected block segment");
10557
11204
  }
10558
11205
  const hasReferenceBlock = ebml.value.find((c) => c.type === "ReferenceBlock");
10559
- const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2, parserContext, offset);
11206
+ const sample = block2.value.length === 0 ? null : getSampleFromBlock(block2, state, offset);
10560
11207
  if (sample && sample.type === "partial-video-sample") {
10561
11208
  const completeFrame = {
10562
11209
  ...sample.partialVideoSample,
10563
11210
  type: hasReferenceBlock ? "delta" : "key"
10564
11211
  };
10565
- await parserContext.parserState.onVideoSample(sample.partialVideoSample.trackId, completeFrame);
11212
+ await state.callbacks.onVideoSample(sample.partialVideoSample.trackId, completeFrame);
10566
11213
  }
10567
- if (parserContext.nullifySamples) {
11214
+ if (state.nullifySamples) {
10568
11215
  return {
10569
11216
  type: "BlockGroup",
10570
11217
  value: [],
@@ -10579,7 +11226,7 @@ var postprocessEbml = async ({
10579
11226
  var continueAfterMatroskaParseResult = async ({
10580
11227
  result,
10581
11228
  iterator,
10582
- parserContext,
11229
+ state,
10583
11230
  segment
10584
11231
  }) => {
10585
11232
  if (result.status === "done") {
@@ -10597,7 +11244,7 @@ var continueAfterMatroskaParseResult = async ({
10597
11244
  return continueAfterMatroskaParseResult({
10598
11245
  result: proceeded,
10599
11246
  iterator,
10600
- parserContext,
11247
+ state,
10601
11248
  segment
10602
11249
  });
10603
11250
  },
@@ -10607,7 +11254,7 @@ var continueAfterMatroskaParseResult = async ({
10607
11254
  };
10608
11255
  var expectSegment = async ({
10609
11256
  iterator,
10610
- parserContext,
11257
+ state,
10611
11258
  offset,
10612
11259
  children,
10613
11260
  fields,
@@ -10620,7 +11267,7 @@ var expectSegment = async ({
10620
11267
  continueParsing: () => {
10621
11268
  return expectAndProcessSegment({
10622
11269
  iterator,
10623
- parserContext,
11270
+ state,
10624
11271
  offset,
10625
11272
  children,
10626
11273
  fields,
@@ -10638,7 +11285,7 @@ var expectSegment = async ({
10638
11285
  continueParsing: () => {
10639
11286
  return expectAndProcessSegment({
10640
11287
  iterator,
10641
- parserContext,
11288
+ state,
10642
11289
  offset,
10643
11290
  children,
10644
11291
  fields,
@@ -10658,7 +11305,7 @@ var expectSegment = async ({
10658
11305
  continueParsing: () => {
10659
11306
  return expectSegment({
10660
11307
  iterator,
10661
- parserContext,
11308
+ state,
10662
11309
  offset,
10663
11310
  children,
10664
11311
  fields,
@@ -10679,7 +11326,7 @@ var expectSegment = async ({
10679
11326
  iterator,
10680
11327
  length,
10681
11328
  children: newSegment.value,
10682
- parserContext,
11329
+ state,
10683
11330
  startOffset: iterator.counter.getOffset(),
10684
11331
  fields,
10685
11332
  topLevelStructure
@@ -10690,7 +11337,7 @@ var expectSegment = async ({
10690
11337
  continueParsing: () => {
10691
11338
  return continueAfterMatroskaParseResult({
10692
11339
  iterator,
10693
- parserContext,
11340
+ state,
10694
11341
  result: main,
10695
11342
  segment: newSegment
10696
11343
  });
@@ -10712,7 +11359,7 @@ var expectSegment = async ({
10712
11359
  continueParsing: () => {
10713
11360
  return expectSegment({
10714
11361
  iterator,
10715
- parserContext,
11362
+ state,
10716
11363
  offset,
10717
11364
  children,
10718
11365
  fields,
@@ -10725,7 +11372,7 @@ var expectSegment = async ({
10725
11372
  segmentId,
10726
11373
  iterator,
10727
11374
  length,
10728
- parserContext,
11375
+ state,
10729
11376
  headerReadSoFar: iterator.counter.getOffset() - offset
10730
11377
  });
10731
11378
  return {
@@ -10737,7 +11384,7 @@ var parseSegment = async ({
10737
11384
  segmentId,
10738
11385
  iterator,
10739
11386
  length,
10740
- parserContext,
11387
+ state,
10741
11388
  headerReadSoFar
10742
11389
  }) => {
10743
11390
  if (length < 0) {
@@ -10745,8 +11392,8 @@ var parseSegment = async ({
10745
11392
  }
10746
11393
  iterator.counter.decrement(headerReadSoFar);
10747
11394
  const offset = iterator.counter.getOffset();
10748
- const ebml = await parseEbml(iterator, parserContext);
10749
- const remapped = await postprocessEbml({ offset, ebml, parserContext });
11395
+ const ebml = await parseEbml(iterator, state);
11396
+ const remapped = await postprocessEbml({ offset, ebml, state });
10750
11397
  return remapped;
10751
11398
  };
10752
11399
 
@@ -10760,14 +11407,14 @@ var processParseResult = ({
10760
11407
  }) => {
10761
11408
  if (parseResult.segment && !children.includes(parseResult.segment)) {
10762
11409
  children.push(parseResult.segment);
10763
- if (hasAllInfo({ fields, state, structure: topLevelStructure })) {
11410
+ if (hasAllInfo({ fields, state })) {
10764
11411
  return {
10765
11412
  status: "done",
10766
11413
  segment: parseResult.segment
10767
11414
  };
10768
11415
  }
10769
11416
  if (parseResult.segment.type === "Tracks") {
10770
- state.tracks.setIsDone();
11417
+ state.callbacks.tracks.setIsDone();
10771
11418
  }
10772
11419
  }
10773
11420
  if (parseResult.status === "incomplete") {
@@ -10793,7 +11440,7 @@ var processParseResult = ({
10793
11440
  };
10794
11441
  var expectAndProcessSegment = async ({
10795
11442
  iterator,
10796
- parserContext,
11443
+ state,
10797
11444
  offset,
10798
11445
  children,
10799
11446
  fields,
@@ -10801,7 +11448,7 @@ var expectAndProcessSegment = async ({
10801
11448
  }) => {
10802
11449
  const segment = await expectSegment({
10803
11450
  iterator,
10804
- parserContext,
11451
+ state,
10805
11452
  offset,
10806
11453
  children,
10807
11454
  fields,
@@ -10810,7 +11457,7 @@ var expectAndProcessSegment = async ({
10810
11457
  return processParseResult({
10811
11458
  children,
10812
11459
  parseResult: segment,
10813
- state: parserContext.parserState,
11460
+ state,
10814
11461
  fields,
10815
11462
  topLevelStructure
10816
11463
  });
@@ -10819,7 +11466,7 @@ var continueAfterSegmentResult = async ({
10819
11466
  result,
10820
11467
  length,
10821
11468
  children,
10822
- parserContext,
11469
+ state,
10823
11470
  iterator,
10824
11471
  startOffset,
10825
11472
  fields,
@@ -10837,7 +11484,7 @@ var continueAfterSegmentResult = async ({
10837
11484
  children,
10838
11485
  iterator,
10839
11486
  length,
10840
- parserContext,
11487
+ state,
10841
11488
  startOffset,
10842
11489
  fields,
10843
11490
  topLevelStructure
@@ -10854,7 +11501,7 @@ var continueAfterSegmentResult = async ({
10854
11501
  children,
10855
11502
  iterator,
10856
11503
  length,
10857
- parserContext,
11504
+ state,
10858
11505
  startOffset,
10859
11506
  fields,
10860
11507
  topLevelStructure
@@ -10867,7 +11514,7 @@ var expectChildren = async ({
10867
11514
  iterator,
10868
11515
  length,
10869
11516
  children,
10870
- parserContext,
11517
+ state,
10871
11518
  startOffset,
10872
11519
  fields,
10873
11520
  topLevelStructure
@@ -10879,7 +11526,7 @@ var expectChildren = async ({
10879
11526
  const currentOffset = iterator.counter.getOffset();
10880
11527
  const child = await expectAndProcessSegment({
10881
11528
  iterator,
10882
- parserContext,
11529
+ state,
10883
11530
  offset: currentOffset,
10884
11531
  children,
10885
11532
  fields,
@@ -10887,8 +11534,7 @@ var expectChildren = async ({
10887
11534
  });
10888
11535
  if (hasAllInfo({
10889
11536
  fields,
10890
- state: parserContext.parserState,
10891
- structure: topLevelStructure
11537
+ state
10892
11538
  })) {
10893
11539
  return {
10894
11540
  status: "done"
@@ -10903,7 +11549,7 @@ var expectChildren = async ({
10903
11549
  children,
10904
11550
  iterator,
10905
11551
  length: length - (currentOffset - startOffset),
10906
- parserContext,
11552
+ state,
10907
11553
  startOffset: currentOffset,
10908
11554
  fields,
10909
11555
  topLevelStructure
@@ -10922,13 +11568,11 @@ var expectChildren = async ({
10922
11568
  var continueAfterMatroskaResult = (result, structure) => {
10923
11569
  if (result.status === "done") {
10924
11570
  return {
10925
- status: "done",
10926
- segments: structure
11571
+ status: "done"
10927
11572
  };
10928
11573
  }
10929
11574
  return {
10930
11575
  status: "incomplete",
10931
- segments: structure,
10932
11576
  continueParsing: async () => {
10933
11577
  const newResult = await result.continueParsing();
10934
11578
  return continueAfterMatroskaResult(newResult, structure);
@@ -10938,15 +11582,18 @@ var continueAfterMatroskaResult = (result, structure) => {
10938
11582
  };
10939
11583
  var parseWebm = async ({
10940
11584
  counter,
10941
- parserContext,
11585
+ state,
10942
11586
  fields
10943
11587
  }) => {
10944
- const structure = { type: "matroska", boxes: [] };
11588
+ const structure = state.structure.getStructure();
11589
+ if (structure.type !== "matroska") {
11590
+ throw new Error("Invalid structure type");
11591
+ }
10945
11592
  const results = await expectChildren({
10946
11593
  iterator: counter,
10947
11594
  length: Infinity,
10948
11595
  children: structure.boxes,
10949
- parserContext,
11596
+ state,
10950
11597
  startOffset: counter.counter.getOffset(),
10951
11598
  fields,
10952
11599
  topLevelStructure: structure
@@ -10957,53 +11604,201 @@ var parseWebm = async ({
10957
11604
  // src/parse-video.ts
10958
11605
  var parseVideo = ({
10959
11606
  iterator,
10960
- options,
11607
+ state,
10961
11608
  signal,
10962
11609
  logLevel,
10963
- fields
11610
+ fields,
11611
+ mimeType,
11612
+ contentLength,
11613
+ name
10964
11614
  }) => {
10965
11615
  if (iterator.bytesRemaining() === 0) {
10966
11616
  return Promise.reject(new Error("no bytes"));
10967
11617
  }
10968
- if (iterator.isRiff()) {
11618
+ const fileType = iterator.detectFileType();
11619
+ if (fileType.type === "riff") {
10969
11620
  Log.verbose(logLevel, "Detected RIFF container");
10970
- return Promise.resolve(parseRiff({ iterator, options, fields }));
11621
+ state.structure.setStructure({
11622
+ type: "riff",
11623
+ boxes: []
11624
+ });
11625
+ return Promise.resolve(parseRiff({ iterator, state, fields }));
10971
11626
  }
10972
- if (iterator.isIsoBaseMedia()) {
11627
+ if (fileType.type === "iso-base-media") {
10973
11628
  Log.verbose(logLevel, "Detected ISO Base Media container");
11629
+ const initialBoxes = [];
11630
+ state.structure.setStructure({
11631
+ type: "iso-base-media",
11632
+ boxes: initialBoxes
11633
+ });
10974
11634
  return parseIsoBaseMediaBoxes({
10975
11635
  iterator,
10976
11636
  maxBytes: Infinity,
10977
11637
  allowIncompleteBoxes: true,
10978
- initialBoxes: [],
10979
- options,
11638
+ initialBoxes,
11639
+ state,
10980
11640
  continueMdat: false,
10981
11641
  signal,
10982
11642
  logLevel,
10983
11643
  fields
10984
11644
  });
10985
11645
  }
10986
- if (iterator.isWebm()) {
11646
+ if (fileType.type === "webm") {
10987
11647
  Log.verbose(logLevel, "Detected Matroska container");
10988
- return parseWebm({ counter: iterator, parserContext: options, fields });
11648
+ state.structure.setStructure({
11649
+ boxes: [],
11650
+ type: "matroska"
11651
+ });
11652
+ return parseWebm({ counter: iterator, state, fields });
10989
11653
  }
10990
- if (iterator.isTransportStream()) {
11654
+ if (fileType.type === "transport-stream") {
11655
+ Log.verbose(logLevel, "Detected MPEG-2 Transport Stream");
11656
+ state.structure.setStructure({
11657
+ boxes: [],
11658
+ type: "transport-stream"
11659
+ });
10991
11660
  return parseTransportStream({
10992
11661
  iterator,
10993
- parserContext: options,
10994
- structure: {
10995
- type: "transport-stream",
10996
- boxes: []
10997
- },
11662
+ state,
10998
11663
  streamBuffers: new Map,
10999
11664
  fields,
11000
11665
  nextPesHeaderStore: makeNextPesHeaderStore()
11001
11666
  });
11002
11667
  }
11003
- if (iterator.isMp3()) {
11004
- return Promise.reject(new Error("MP3 files are not yet supported"));
11005
- }
11006
- return Promise.reject(new Error("Unknown video format"));
11668
+ if (fileType.type === "mp3") {
11669
+ return Promise.reject(new IsAnUnsupportedAudioTypeError({
11670
+ message: "MP3 files are not yet supported",
11671
+ mimeType,
11672
+ sizeInBytes: contentLength,
11673
+ fileName: name,
11674
+ audioType: "mp3"
11675
+ }));
11676
+ }
11677
+ if (fileType.type === "wav") {
11678
+ return Promise.reject(new IsAnUnsupportedAudioTypeError({
11679
+ message: "WAV files are not yet supported",
11680
+ mimeType,
11681
+ sizeInBytes: contentLength,
11682
+ fileName: name,
11683
+ audioType: "wav"
11684
+ }));
11685
+ }
11686
+ if (fileType.type === "aac") {
11687
+ return Promise.reject(new IsAnUnsupportedAudioTypeError({
11688
+ message: "AAC files are not yet supported",
11689
+ mimeType,
11690
+ sizeInBytes: contentLength,
11691
+ fileName: name,
11692
+ audioType: "aac"
11693
+ }));
11694
+ }
11695
+ if (fileType.type === "gif") {
11696
+ return Promise.reject(new IsAGifError({
11697
+ message: "GIF files are not yet supported",
11698
+ mimeType,
11699
+ sizeInBytes: contentLength,
11700
+ fileName: name
11701
+ }));
11702
+ }
11703
+ if (fileType.type === "pdf") {
11704
+ return Promise.reject(new IsAPdfError({
11705
+ message: "GIF files are not supported",
11706
+ mimeType,
11707
+ sizeInBytes: contentLength,
11708
+ fileName: name
11709
+ }));
11710
+ }
11711
+ if (fileType.type === "bmp" || fileType.type === "jpeg" || fileType.type === "png" || fileType.type === "webp") {
11712
+ return Promise.reject(new IsAnImageError({
11713
+ message: "Image files are not supported",
11714
+ imageType: fileType.type,
11715
+ dimensions: fileType.dimensions,
11716
+ mimeType,
11717
+ sizeInBytes: contentLength,
11718
+ fileName: name
11719
+ }));
11720
+ }
11721
+ if (fileType.type === "unknown") {
11722
+ return Promise.reject(new IsAnUnsupportedFileTypeError({
11723
+ message: "Unknown file format",
11724
+ mimeType,
11725
+ sizeInBytes: contentLength,
11726
+ fileName: name
11727
+ }));
11728
+ }
11729
+ return Promise.reject(new Error("Unknown video format " + fileType));
11730
+ };
11731
+
11732
+ // src/state/emitted-fields.ts
11733
+ var emittedState = () => {
11734
+ const emittedFields = {
11735
+ audioCodec: false,
11736
+ container: false,
11737
+ dimensions: false,
11738
+ durationInSeconds: false,
11739
+ fps: false,
11740
+ internalStats: false,
11741
+ isHdr: false,
11742
+ location: false,
11743
+ metadata: false,
11744
+ mimeType: false,
11745
+ name: false,
11746
+ rotation: false,
11747
+ size: false,
11748
+ structure: false,
11749
+ tracks: false,
11750
+ videoCodec: false,
11751
+ unrotatedDimensions: false,
11752
+ slowDurationInSeconds: false,
11753
+ slowFps: false,
11754
+ slowKeyframes: false,
11755
+ slowNumberOfFrames: false,
11756
+ keyframes: false
11757
+ };
11758
+ return emittedFields;
11759
+ };
11760
+
11761
+ // src/state/keyframes.ts
11762
+ var keyframesState = () => {
11763
+ const keyframes = [];
11764
+ return {
11765
+ addKeyframe: (keyframe) => {
11766
+ keyframes.push(keyframe);
11767
+ },
11768
+ getKeyframes: () => {
11769
+ return keyframes;
11770
+ }
11771
+ };
11772
+ };
11773
+
11774
+ // src/state/riff.ts
11775
+ var riffSpecificState = () => {
11776
+ let avcProfile = null;
11777
+ let nextTrackIndex = 0;
11778
+ const profileCallbacks = [];
11779
+ const registerOnAvcProfileCallback = (callback) => {
11780
+ profileCallbacks.push(callback);
11781
+ };
11782
+ const onProfile = async (profile) => {
11783
+ avcProfile = profile;
11784
+ for (const callback of profileCallbacks) {
11785
+ await callback(profile);
11786
+ }
11787
+ profileCallbacks.length = 0;
11788
+ };
11789
+ return {
11790
+ getAvcProfile: () => {
11791
+ return avcProfile;
11792
+ },
11793
+ onProfile,
11794
+ registerOnAvcProfileCallback,
11795
+ getNextTrackIndex: () => {
11796
+ return nextTrackIndex;
11797
+ },
11798
+ incrementNextTrackIndex: () => {
11799
+ nextTrackIndex++;
11800
+ }
11801
+ };
11007
11802
  };
11008
11803
 
11009
11804
  // src/state/can-skip-tracks.ts
@@ -11012,6 +11807,8 @@ var needsTracksField = {
11012
11807
  container: false,
11013
11808
  dimensions: true,
11014
11809
  durationInSeconds: true,
11810
+ slowDurationInSeconds: true,
11811
+ slowFps: true,
11015
11812
  fps: true,
11016
11813
  internalStats: false,
11017
11814
  isHdr: true,
@@ -11023,7 +11820,11 @@ var needsTracksField = {
11023
11820
  unrotatedDimensions: true,
11024
11821
  videoCodec: true,
11025
11822
  metadata: true,
11026
- location: true
11823
+ location: true,
11824
+ mimeType: false,
11825
+ slowKeyframes: true,
11826
+ slowNumberOfFrames: true,
11827
+ keyframes: true
11027
11828
  };
11028
11829
  var makeCanSkipTracksState = ({
11029
11830
  hasAudioTrackHandlers,
@@ -11066,92 +11867,28 @@ var makeTracksSectionState = (canSkipTracksState) => {
11066
11867
  };
11067
11868
  };
11068
11869
 
11069
- // src/state/parser-state.ts
11070
- var makeParserState = ({
11870
+ // src/state/sample-callbacks.ts
11871
+ var sampleCallback = ({
11872
+ signal,
11071
11873
  hasAudioTrackHandlers,
11072
11874
  hasVideoTrackHandlers,
11073
- signal,
11074
- getIterator,
11075
- fields
11875
+ fields,
11876
+ keyframes,
11877
+ emittedFields,
11878
+ slowDurationAndFpsState
11076
11879
  }) => {
11077
- const trackEntries = {};
11078
- const onTrackEntrySegment = (trackEntry2) => {
11079
- const trackId = getTrackId(trackEntry2);
11080
- if (!trackId) {
11081
- throw new Error("Expected track id");
11082
- }
11083
- if (trackEntries[trackId]) {
11084
- return;
11085
- }
11086
- const codec = getTrackCodec(trackEntry2);
11087
- if (!codec) {
11088
- throw new Error("Expected codec");
11089
- }
11090
- const trackTimescale = getTrackTimestampScale(trackEntry2);
11091
- trackEntries[trackId] = {
11092
- codec: codec.value,
11093
- trackTimescale: trackTimescale?.value ?? null
11094
- };
11095
- };
11096
11880
  const videoSampleCallbacks = {};
11097
11881
  const audioSampleCallbacks = {};
11098
11882
  const queuedAudioSamples = {};
11099
11883
  const queuedVideoSamples = {};
11100
- let timescale2 = null;
11101
- let skippedBytes = 0;
11102
- const getTimescale = () => {
11103
- if (timescale2 === null) {
11104
- return 1e6;
11105
- }
11106
- return timescale2;
11107
- };
11108
- const increaseSkippedBytes = (bytes) => {
11109
- skippedBytes += bytes;
11110
- };
11111
- const setTimescale = (newTimescale) => {
11112
- timescale2 = newTimescale;
11113
- };
11114
- const timestampMap = new Map;
11115
- const setTimestampOffset = (byteOffset, timestamp) => {
11116
- timestampMap.set(byteOffset, timestamp);
11117
- };
11118
- const getTimestampOffsetForByteOffset = (byteOffset) => {
11119
- const entries = Array.from(timestampMap.entries());
11120
- const sortedByByteOffset = entries.sort((a, b) => {
11121
- return a[0] - b[0];
11122
- }).reverse();
11123
- for (const [offset, timestamp] of sortedByByteOffset) {
11124
- if (offset >= byteOffset) {
11125
- continue;
11126
- }
11127
- return timestamp;
11128
- }
11129
- return timestampMap.get(byteOffset);
11130
- };
11131
- const samplesForTrack = {};
11132
- const profileCallbacks = [];
11133
- const registerOnAvcProfileCallback = (callback) => {
11134
- profileCallbacks.push(callback);
11135
- };
11136
- let avcProfile = null;
11137
- const onProfile = async (profile) => {
11138
- avcProfile = profile;
11139
- for (const callback of profileCallbacks) {
11140
- await callback(profile);
11141
- }
11142
- profileCallbacks.length = 0;
11143
- };
11144
11884
  const canSkipTracksState = makeCanSkipTracksState({
11145
11885
  hasAudioTrackHandlers,
11146
11886
  fields,
11147
11887
  hasVideoTrackHandlers
11148
11888
  });
11149
11889
  const tracksState = makeTracksSectionState(canSkipTracksState);
11890
+ const samplesForTrack = {};
11150
11891
  return {
11151
- onTrackEntrySegment,
11152
- onProfile,
11153
- registerOnAvcProfileCallback,
11154
- getTrackInfoByNumber: (id) => trackEntries[id],
11155
11892
  registerVideoSampleCallback: async (id, callback) => {
11156
11893
  if (callback === null) {
11157
11894
  delete videoSampleCallbacks[id];
@@ -11163,19 +11900,6 @@ var makeParserState = ({
11163
11900
  }
11164
11901
  queuedVideoSamples[id] = [];
11165
11902
  },
11166
- setTimestampOffset,
11167
- getTimestampOffsetForByteOffset,
11168
- registerAudioSampleCallback: async (id, callback) => {
11169
- if (callback === null) {
11170
- delete audioSampleCallbacks[id];
11171
- return;
11172
- }
11173
- audioSampleCallbacks[id] = callback;
11174
- for (const queued of queuedAudioSamples[id] ?? []) {
11175
- await callback(queued);
11176
- }
11177
- queuedAudioSamples[id] = [];
11178
- },
11179
11903
  onAudioSample: async (trackId, audioSample) => {
11180
11904
  if (signal?.aborted) {
11181
11905
  throw new Error("Aborted");
@@ -11189,6 +11913,9 @@ var makeParserState = ({
11189
11913
  await callback(audioSample);
11190
11914
  }
11191
11915
  },
11916
+ getSamplesForTrack: (trackId) => {
11917
+ return samplesForTrack[trackId] ?? 0;
11918
+ },
11192
11919
  onVideoSample: async (trackId, videoSample) => {
11193
11920
  if (signal?.aborted) {
11194
11921
  throw new Error("Aborted");
@@ -11198,36 +11925,207 @@ var makeParserState = ({
11198
11925
  }
11199
11926
  samplesForTrack[trackId]++;
11200
11927
  const callback = videoSampleCallbacks[trackId];
11201
- if (callback) {
11928
+ if (callback && videoSample.data.length > 0) {
11202
11929
  await callback(videoSample);
11203
11930
  }
11931
+ if (needsToIterateOverSamples({
11932
+ fields,
11933
+ emittedFields
11934
+ })) {
11935
+ if (fields.slowKeyframes && videoSample.type === "key") {
11936
+ keyframes.addKeyframe({
11937
+ trackId,
11938
+ decodingTimeInSeconds: videoSample.dts / videoSample.timescale,
11939
+ positionInBytes: videoSample.offset,
11940
+ presentationTimeInSeconds: videoSample.cts / videoSample.timescale,
11941
+ sizeInBytes: videoSample.data.length
11942
+ });
11943
+ }
11944
+ slowDurationAndFpsState.addSample(videoSample);
11945
+ }
11204
11946
  },
11205
- getTimescale,
11206
- setTimescale,
11207
- getSamplesForTrack: (trackId) => {
11208
- return samplesForTrack[trackId] ?? 0;
11947
+ canSkipTracksState,
11948
+ registerAudioSampleCallback: async (id, callback) => {
11949
+ if (callback === null) {
11950
+ delete audioSampleCallbacks[id];
11951
+ return;
11952
+ }
11953
+ audioSampleCallbacks[id] = callback;
11954
+ for (const queued of queuedAudioSamples[id] ?? []) {
11955
+ await callback(queued);
11956
+ }
11957
+ queuedAudioSamples[id] = [];
11209
11958
  },
11210
- getAvcProfile: () => {
11211
- return avcProfile;
11959
+ tracks: tracksState,
11960
+ audioSampleCallbacks,
11961
+ videoSampleCallbacks
11962
+ };
11963
+ };
11964
+
11965
+ // src/state/slow-duration-fps.ts
11966
+ var slowDurationAndFpsState = () => {
11967
+ let smallestSample;
11968
+ let largestSample;
11969
+ let samples = 0;
11970
+ const getSlowDurationInSeconds = () => {
11971
+ if (smallestSample !== undefined && largestSample !== undefined) {
11972
+ const startingTimestampDifference = largestSample - smallestSample;
11973
+ const timeBetweenSamples = startingTimestampDifference / (samples - 1);
11974
+ return timeBetweenSamples * samples;
11975
+ }
11976
+ throw new Error("No samples");
11977
+ };
11978
+ return {
11979
+ addSample: (videoSample) => {
11980
+ samples++;
11981
+ const presentationTimeInSeconds = videoSample.cts / videoSample.timescale;
11982
+ if (largestSample === undefined || presentationTimeInSeconds > largestSample) {
11983
+ largestSample = presentationTimeInSeconds;
11984
+ }
11985
+ if (smallestSample === undefined || presentationTimeInSeconds < smallestSample) {
11986
+ smallestSample = presentationTimeInSeconds;
11987
+ }
11988
+ },
11989
+ getSlowDurationInSeconds,
11990
+ getFps: () => {
11991
+ return samples / getSlowDurationInSeconds();
11992
+ },
11993
+ getSlowNumberOfFrames: () => samples
11994
+ };
11995
+ };
11996
+
11997
+ // src/state/structure.ts
11998
+ var structureState = () => {
11999
+ let structure = null;
12000
+ return {
12001
+ getStructureOrNull: () => {
12002
+ return structure;
11212
12003
  },
12004
+ getStructure: () => {
12005
+ if (structure === null) {
12006
+ throw new Error("Expected structure");
12007
+ }
12008
+ return structure;
12009
+ },
12010
+ setStructure: (value) => {
12011
+ structure = value;
12012
+ }
12013
+ };
12014
+ };
12015
+
12016
+ // src/state/webm.ts
12017
+ var webmState = () => {
12018
+ const trackEntries = {};
12019
+ const onTrackEntrySegment = (trackEntry2) => {
12020
+ const trackId = getTrackId(trackEntry2);
12021
+ if (!trackId) {
12022
+ throw new Error("Expected track id");
12023
+ }
12024
+ if (trackEntries[trackId]) {
12025
+ return;
12026
+ }
12027
+ const codec = getTrackCodec(trackEntry2);
12028
+ if (!codec) {
12029
+ throw new Error("Expected codec");
12030
+ }
12031
+ const trackTimescale = getTrackTimestampScale(trackEntry2);
12032
+ trackEntries[trackId] = {
12033
+ codec: codec.value,
12034
+ trackTimescale: trackTimescale?.value ?? null
12035
+ };
12036
+ };
12037
+ const timestampMap = new Map;
12038
+ const getTimestampOffsetForByteOffset = (byteOffset) => {
12039
+ const entries = Array.from(timestampMap.entries());
12040
+ const sortedByByteOffset = entries.sort((a, b) => {
12041
+ return a[0] - b[0];
12042
+ }).reverse();
12043
+ for (const [offset, timestamp] of sortedByByteOffset) {
12044
+ if (offset >= byteOffset) {
12045
+ continue;
12046
+ }
12047
+ return timestamp;
12048
+ }
12049
+ return timestampMap.get(byteOffset);
12050
+ };
12051
+ const setTimestampOffset = (byteOffset, timestamp) => {
12052
+ timestampMap.set(byteOffset, timestamp);
12053
+ };
12054
+ let timescale2 = null;
12055
+ const setTimescale = (newTimescale) => {
12056
+ timescale2 = newTimescale;
12057
+ };
12058
+ const getTimescale = () => {
12059
+ if (timescale2 === null) {
12060
+ return 1e6;
12061
+ }
12062
+ return timescale2;
12063
+ };
12064
+ return {
12065
+ onTrackEntrySegment,
12066
+ getTrackInfoByNumber: (id) => trackEntries[id],
12067
+ setTimestampOffset,
12068
+ getTimestampOffsetForByteOffset,
12069
+ timescale: timescale2,
12070
+ getTimescale,
12071
+ setTimescale
12072
+ };
12073
+ };
12074
+
12075
+ // src/state/parser-state.ts
12076
+ var makeParserState = ({
12077
+ hasAudioTrackHandlers,
12078
+ hasVideoTrackHandlers,
12079
+ signal,
12080
+ getIterator,
12081
+ fields,
12082
+ nullifySamples,
12083
+ onAudioTrack,
12084
+ onVideoTrack,
12085
+ supportsContentRange
12086
+ }) => {
12087
+ let skippedBytes = 0;
12088
+ const increaseSkippedBytes = (bytes) => {
12089
+ skippedBytes += bytes;
12090
+ };
12091
+ const structure = structureState();
12092
+ const keyframes = keyframesState();
12093
+ const emittedFields = emittedState();
12094
+ const slowDurationAndFps = slowDurationAndFpsState();
12095
+ return {
12096
+ riff: riffSpecificState(),
12097
+ callbacks: sampleCallback({
12098
+ signal,
12099
+ hasAudioTrackHandlers,
12100
+ hasVideoTrackHandlers,
12101
+ fields,
12102
+ keyframes,
12103
+ emittedFields,
12104
+ slowDurationAndFpsState: slowDurationAndFps
12105
+ }),
11213
12106
  getInternalStats: () => ({
11214
12107
  skippedBytes,
11215
12108
  finalCursorOffset: getIterator()?.counter.getOffset() ?? 0
11216
12109
  }),
11217
12110
  getSkipBytes: () => skippedBytes,
11218
12111
  increaseSkippedBytes,
11219
- maySkipVideoData: () => {
11220
- return tracksState.hasAllTracks() && Object.values(videoSampleCallbacks).length === 0 && Object.values(audioSampleCallbacks).length === 0;
11221
- },
11222
- tracks: tracksState,
11223
- canSkipTracksState
12112
+ keyframes,
12113
+ structure,
12114
+ nullifySamples,
12115
+ onAudioTrack,
12116
+ onVideoTrack,
12117
+ supportsContentRange,
12118
+ webm: webmState(),
12119
+ emittedFields,
12120
+ fields,
12121
+ slowDurationAndFps
11224
12122
  };
11225
12123
  };
11226
12124
 
11227
12125
  // src/parse-media.ts
11228
- var parseMedia = async ({
12126
+ var parseMedia = async function({
11229
12127
  src,
11230
- fields,
12128
+ fields: _fieldsInReturnValue,
11231
12129
  reader: readerInterface = fetchReader,
11232
12130
  onAudioTrack,
11233
12131
  onVideoTrack,
@@ -11235,44 +12133,51 @@ var parseMedia = async ({
11235
12133
  logLevel = "info",
11236
12134
  onParseProgress,
11237
12135
  ...more
11238
- }) => {
12136
+ }) {
11239
12137
  let iterator = null;
11240
12138
  let parseResult = null;
11241
- const state = makeParserState({
11242
- hasAudioTrackHandlers: Boolean(onAudioTrack),
11243
- hasVideoTrackHandlers: Boolean(onVideoTrack),
11244
- signal,
11245
- getIterator: () => iterator,
11246
- fields: fields ?? {}
12139
+ const fieldsInReturnValue = _fieldsInReturnValue ?? {};
12140
+ const fields = getFieldsFromCallback({
12141
+ fields: fieldsInReturnValue,
12142
+ callbacks: more
11247
12143
  });
11248
12144
  const {
11249
12145
  reader,
11250
12146
  contentLength,
11251
12147
  name,
12148
+ contentType,
11252
12149
  supportsContentRange: readerSupportsContentRange
11253
12150
  } = await readerInterface.read(src, null, signal);
11254
- let currentReader = reader;
11255
12151
  const supportsContentRange = readerSupportsContentRange && !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.DISABLE_CONTENT_RANGE === "true");
11256
- const returnValue = {};
11257
- const moreFields = more;
11258
- const options = {
12152
+ const state = makeParserState({
12153
+ hasAudioTrackHandlers: Boolean(onAudioTrack),
12154
+ hasVideoTrackHandlers: Boolean(onVideoTrack),
12155
+ signal,
12156
+ getIterator: () => iterator,
12157
+ fields,
11259
12158
  onAudioTrack: onAudioTrack ?? null,
11260
12159
  onVideoTrack: onVideoTrack ?? null,
11261
- parserState: state,
11262
12160
  nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
11263
- supportsContentRange,
11264
- nextTrackIndex: 0
11265
- };
12161
+ supportsContentRange
12162
+ });
12163
+ let currentReader = reader;
12164
+ const returnValue = {};
12165
+ const moreFields = more;
11266
12166
  const triggerInfoEmit = () => {
11267
- const availableInfo = getAvailableInfo(fields ?? {}, parseResult?.segments ?? null, state);
12167
+ const availableInfo = getAvailableInfo({
12168
+ fieldsToFetch: fields,
12169
+ state
12170
+ });
11268
12171
  emitAvailableInfo({
11269
12172
  hasInfo: availableInfo,
11270
- moreFields,
12173
+ callbacks: moreFields,
12174
+ fieldsInReturnValue,
11271
12175
  parseResult,
11272
12176
  state,
11273
12177
  returnValue,
11274
12178
  contentLength,
11275
- name
12179
+ name,
12180
+ mimeType: contentType
11276
12181
  });
11277
12182
  };
11278
12183
  triggerInfoEmit();
@@ -11309,23 +12214,25 @@ var parseMedia = async ({
11309
12214
  });
11310
12215
  triggerInfoEmit();
11311
12216
  if (parseResult && parseResult.status === "incomplete") {
11312
- Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
12217
+ Log.trace(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
11313
12218
  parseResult = await parseResult.continueParsing();
11314
12219
  } else {
11315
12220
  parseResult = await parseVideo({
11316
12221
  iterator,
11317
- options,
12222
+ state,
11318
12223
  signal: signal ?? null,
11319
12224
  logLevel,
11320
- fields: fields ?? {}
12225
+ fields,
12226
+ mimeType: contentType,
12227
+ contentLength,
12228
+ name
11321
12229
  });
11322
12230
  }
11323
12231
  if (parseResult.status === "incomplete" && parseResult.skipTo !== null) {
11324
12232
  state.increaseSkippedBytes(parseResult.skipTo - iterator.counter.getOffset());
11325
12233
  }
11326
12234
  if (hasAllInfo({
11327
- fields: fields ?? {},
11328
- structure: parseResult.segments,
12235
+ fields,
11329
12236
  state
11330
12237
  })) {
11331
12238
  Log.verbose(logLevel, "Got all info, skipping to the end.");
@@ -11350,23 +12257,26 @@ var parseMedia = async ({
11350
12257
  }
11351
12258
  }
11352
12259
  Log.verbose(logLevel, "Finished parsing file");
12260
+ const hasInfo = Object.keys(fields).reduce((acc, key) => {
12261
+ if (fields?.[key]) {
12262
+ acc[key] = true;
12263
+ }
12264
+ return acc;
12265
+ }, {});
11353
12266
  emitAvailableInfo({
11354
- hasInfo: Object.keys(fields ?? {}).reduce((acc, key) => {
11355
- if (fields?.[key]) {
11356
- acc[key] = true;
11357
- }
11358
- return acc;
11359
- }, {}),
11360
- moreFields,
12267
+ hasInfo,
12268
+ callbacks: moreFields,
12269
+ fieldsInReturnValue,
11361
12270
  parseResult,
11362
12271
  state,
11363
12272
  returnValue,
11364
12273
  contentLength,
12274
+ mimeType: contentType,
11365
12275
  name
11366
12276
  });
11367
12277
  currentReader.abort();
11368
12278
  iterator?.destroy();
11369
- state.tracks.ensureHasTracksAtEnd();
12279
+ state.callbacks.tracks.ensureHasTracksAtEnd();
11370
12280
  return returnValue;
11371
12281
  };
11372
12282
  // src/index.ts
@@ -11384,5 +12294,10 @@ var MediaParserInternals = {
11384
12294
  export {
11385
12295
  parseMedia,
11386
12296
  VERSION,
11387
- MediaParserInternals
12297
+ MediaParserInternals,
12298
+ IsAnUnsupportedFileTypeError,
12299
+ IsAnUnsupportedAudioTypeError,
12300
+ IsAnImageError,
12301
+ IsAPdfError,
12302
+ IsAGifError
11388
12303
  };