@remotion/media-parser 4.0.231 → 4.0.233

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 (115) hide show
  1. package/dist/add-avc-profile-to-track.d.ts +3 -0
  2. package/dist/add-avc-profile-to-track.js +35 -0
  3. package/dist/add-new-matroska-tracks.d.ts +6 -1
  4. package/dist/add-new-matroska-tracks.js +16 -1
  5. package/dist/boxes/avc/parse-avc.d.ts +18 -0
  6. package/dist/boxes/avc/parse-avc.js +96 -0
  7. package/dist/boxes/iso-base-media/esds/decoder-specific-config.d.ts +1 -2
  8. package/dist/boxes/iso-base-media/esds/decoder-specific-config.js +1 -5
  9. package/dist/boxes/iso-base-media/esds/esds-descriptors.d.ts +2 -4
  10. package/dist/boxes/iso-base-media/esds/esds-descriptors.js +3 -4
  11. package/dist/boxes/iso-base-media/esds/esds.d.ts +1 -3
  12. package/dist/boxes/iso-base-media/esds/esds.js +2 -2
  13. package/dist/boxes/iso-base-media/get-sample-positions-from-track.js +7 -1
  14. package/dist/boxes/iso-base-media/make-track.js +3 -3
  15. package/dist/boxes/iso-base-media/mdat/mdat.d.ts +2 -2
  16. package/dist/boxes/iso-base-media/mdat/mdat.js +5 -2
  17. package/dist/boxes/iso-base-media/moov/moov.js +2 -2
  18. package/dist/boxes/iso-base-media/process-box.d.ts +5 -5
  19. package/dist/boxes/iso-base-media/process-box.js +38 -38
  20. package/dist/boxes/iso-base-media/stsd/mebx.js +2 -2
  21. package/dist/boxes/iso-base-media/stsd/samples.d.ts +2 -2
  22. package/dist/boxes/iso-base-media/stsd/samples.js +15 -14
  23. package/dist/boxes/iso-base-media/trak/trak.js +2 -2
  24. package/dist/boxes/iso-base-media/traversal.d.ts +1 -1
  25. package/dist/boxes/riff/expect-riff-box.d.ts +16 -0
  26. package/dist/boxes/riff/expect-riff-box.js +49 -0
  27. package/dist/boxes/riff/get-tracks-from-avi.d.ts +21 -0
  28. package/dist/boxes/riff/get-tracks-from-avi.js +108 -0
  29. package/dist/boxes/riff/is-movi.d.ts +2 -0
  30. package/dist/boxes/riff/is-movi.js +12 -0
  31. package/dist/boxes/riff/parse-avih.d.ts +6 -0
  32. package/dist/boxes/riff/parse-avih.js +32 -0
  33. package/dist/boxes/riff/parse-box.d.ts +13 -0
  34. package/dist/boxes/riff/parse-box.js +113 -0
  35. package/dist/boxes/riff/parse-fmt-box.d.ts +7 -0
  36. package/dist/boxes/riff/parse-fmt-box.js +33 -0
  37. package/dist/boxes/riff/parse-list-box.d.ts +8 -0
  38. package/dist/boxes/riff/parse-list-box.js +30 -0
  39. package/dist/boxes/riff/parse-movi.d.ts +17 -0
  40. package/dist/boxes/riff/parse-movi.js +122 -0
  41. package/dist/boxes/riff/parse-riff-box.d.ts +10 -0
  42. package/dist/boxes/riff/parse-riff-box.js +33 -0
  43. package/dist/boxes/riff/parse-strf.d.ts +7 -0
  44. package/dist/boxes/riff/parse-strf.js +67 -0
  45. package/dist/boxes/riff/parse-strh.d.ts +6 -0
  46. package/dist/boxes/riff/parse-strh.js +46 -0
  47. package/dist/boxes/riff/riff-box.d.ts +81 -0
  48. package/dist/boxes/riff/riff-box.js +2 -0
  49. package/dist/boxes/riff/strf.d.ts +7 -0
  50. package/dist/boxes/riff/strf.js +67 -0
  51. package/dist/boxes/riff/timescale.d.ts +1 -0
  52. package/dist/boxes/riff/timescale.js +4 -0
  53. package/dist/boxes/riff/traversal.d.ts +8 -0
  54. package/dist/boxes/riff/traversal.js +36 -0
  55. package/dist/boxes/webm/parse-ebml.js +2 -2
  56. package/dist/boxes/webm/parse-webm-header.d.ts +2 -2
  57. package/dist/boxes/webm/parse-webm-header.js +7 -7
  58. package/dist/boxes/webm/traversal.d.ts +2 -2
  59. package/dist/buffer-iterator.d.ts +6 -1
  60. package/dist/buffer-iterator.js +24 -5
  61. package/dist/create/event-emitter.d.ts +31 -0
  62. package/dist/create/event-emitter.js +25 -0
  63. package/dist/create/iso-base-media/create-iso-base-media.d.ts +1 -1
  64. package/dist/create/iso-base-media/create-iso-base-media.js +3 -5
  65. package/dist/create/matroska/cluster.js +1 -1
  66. package/dist/create/matroska/create-matroska-media.d.ts +1 -1
  67. package/dist/create/matroska/create-matroska-media.js +7 -14
  68. package/dist/create/media-fn.d.ts +2 -1
  69. package/dist/create/mp3/create-mp3.d.ts +2 -0
  70. package/dist/create/mp3/create-mp3.js +49 -0
  71. package/dist/create/progress-tracker.d.ts +7 -0
  72. package/dist/create/progress-tracker.js +43 -0
  73. package/dist/create/wav/create-wav.d.ts +2 -0
  74. package/dist/create/wav/create-wav.js +110 -0
  75. package/dist/create/with-resolvers.d.ts +10 -0
  76. package/dist/create/with-resolvers.js +28 -0
  77. package/dist/emit-available-info.d.ts +2 -2
  78. package/dist/emit-available-info.js +17 -6
  79. package/dist/esm/from-node.mjs +2 -1
  80. package/dist/esm/index.mjs +1828 -605
  81. package/dist/get-audio-codec.d.ts +4 -3
  82. package/dist/get-audio-codec.js +17 -3
  83. package/dist/get-container.d.ts +3 -3
  84. package/dist/get-container.js +9 -7
  85. package/dist/get-dimensions.d.ts +3 -3
  86. package/dist/get-duration.d.ts +3 -3
  87. package/dist/get-duration.js +32 -14
  88. package/dist/get-fps.d.ts +3 -3
  89. package/dist/get-fps.js +31 -4
  90. package/dist/get-is-hdr.d.ts +4 -0
  91. package/dist/get-is-hdr.js +18 -0
  92. package/dist/get-sample-positions-from-lpcm.d.ts +3 -0
  93. package/dist/get-sample-positions-from-lpcm.js +46 -0
  94. package/dist/get-tracks.d.ts +7 -10
  95. package/dist/get-tracks.js +55 -27
  96. package/dist/get-video-codec.d.ts +5 -4
  97. package/dist/get-video-codec.js +47 -13
  98. package/dist/has-all-info.d.ts +2 -2
  99. package/dist/has-all-info.js +10 -5
  100. package/dist/index.d.ts +23 -3
  101. package/dist/index.js +9 -0
  102. package/dist/options.d.ts +16 -9
  103. package/dist/parse-media.js +3 -1
  104. package/dist/parse-result.d.ts +20 -6
  105. package/dist/parse-video.d.ts +2 -2
  106. package/dist/parse-video.js +5 -16
  107. package/dist/parser-context.d.ts +1 -0
  108. package/dist/parser-state.d.ts +11 -0
  109. package/dist/parser-state.js +30 -0
  110. package/dist/readers/from-node.js +2 -1
  111. package/dist/register-track.d.ts +13 -0
  112. package/dist/register-track.js +25 -0
  113. package/dist/version.d.ts +1 -1
  114. package/dist/version.js +1 -1
  115. package/package.json +3 -3
@@ -105,6 +105,27 @@ var fetchReader = {
105
105
  }
106
106
  };
107
107
 
108
+ // src/create/event-emitter.ts
109
+ class IoEventEmitter {
110
+ listeners = {
111
+ input: [],
112
+ output: [],
113
+ processed: [],
114
+ progress: []
115
+ };
116
+ addEventListener(name, callback) {
117
+ this.listeners[name].push(callback);
118
+ }
119
+ removeEventListener(name, callback) {
120
+ this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
121
+ }
122
+ dispatchEvent(dispatchName, context) {
123
+ this.listeners[dispatchName].forEach((callback) => {
124
+ callback({ detail: context });
125
+ });
126
+ }
127
+ }
128
+
108
129
  // src/boxes/webm/ebml.ts
109
130
  var measureEBMLVarInt = (value) => {
110
131
  if (value < (1 << 7) - 1) {
@@ -848,6 +869,15 @@ var incrementOffsetAndChildren = (offset, increment) => {
848
869
  };
849
870
 
850
871
  // src/boxes/webm/make-header.ts
872
+ var webmPattern = new Uint8Array([26, 69, 223, 163]);
873
+ var matroskaToHex = (matrId) => {
874
+ const numbers = new Uint8Array((matrId.length - 2) / 2);
875
+ for (let i = 2;i < matrId.length; i += 2) {
876
+ const hex = matrId.substring(i, i + 2);
877
+ numbers[(i - 2) / 2] = parseInt(hex, 16);
878
+ }
879
+ return numbers;
880
+ };
851
881
  function putUintDynamic(number, minimumLength) {
852
882
  if (number < 0) {
853
883
  throw new Error("This function is designed for non-negative integers only.");
@@ -859,21 +889,6 @@ function putUintDynamic(number, minimumLength) {
859
889
  }
860
890
  return bytes;
861
891
  }
862
- function serializeUint16(value) {
863
- const buffer = new ArrayBuffer(2);
864
- const view = new DataView(buffer);
865
- view.setUint16(0, value);
866
- return new Uint8Array(buffer);
867
- }
868
- var webmPattern = new Uint8Array([26, 69, 223, 163]);
869
- var matroskaToHex = (matrId) => {
870
- const numbers = new Uint8Array((matrId.length - 2) / 2);
871
- for (let i = 2;i < matrId.length; i += 2) {
872
- const hex = matrId.substring(i, i + 2);
873
- numbers[(i - 2) / 2] = parseInt(hex, 16);
874
- }
875
- return numbers;
876
- };
877
892
  var makeFromStructure = (fields) => {
878
893
  if ("bytes" in fields) {
879
894
  return fields;
@@ -1020,6 +1035,12 @@ var combineUint8Arrays = (arrays) => {
1020
1035
  }
1021
1036
  return result;
1022
1037
  };
1038
+ function serializeUint16(value) {
1039
+ const buffer = new ArrayBuffer(2);
1040
+ const view = new DataView(buffer);
1041
+ view.setUint16(0, value);
1042
+ return new Uint8Array(buffer);
1043
+ }
1023
1044
 
1024
1045
  // src/log.ts
1025
1046
  var logLevels = ["trace", "verbose", "info", "warn", "error"];
@@ -1855,7 +1876,7 @@ var createHdlr = (type) => {
1855
1876
  type === "mdir" ? numberTo32BitUIntOrInt(1634758764) : new Uint8Array([0, 0, 0, 0]),
1856
1877
  new Uint8Array([0, 0, 0, 0]),
1857
1878
  new Uint8Array([0, 0, 0, 0]),
1858
- stringsToUint8Array(type === "mdir" ? "\0" : type === "video" ? "VideoHandler\0" : "SoundHandler\0")
1879
+ stringsToUint8Array(type === "mdir" ? "\x00" : type === "video" ? "VideoHandler\x00" : "SoundHandler\x00")
1859
1880
  ]));
1860
1881
  };
1861
1882
 
@@ -1966,7 +1987,8 @@ var createIsoBaseMedia = async ({
1966
1987
  onBytesProgress,
1967
1988
  onMillisecondsProgress,
1968
1989
  logLevel,
1969
- filename
1990
+ filename,
1991
+ progressTracker
1970
1992
  }) => {
1971
1993
  const header = createIsoBaseMediaFtyp({
1972
1994
  compatibleBrands: ["isom", "iso2", "avc1", "mp42"],
@@ -2036,6 +2058,7 @@ var createIsoBaseMedia = async ({
2036
2058
  await w.write(chunk.data);
2037
2059
  mdatSize += chunk.data.length;
2038
2060
  onBytesProgress(w.getWrittenByteCount());
2061
+ progressTracker.updateTrackProgress(trackNumber2, chunk.timestamp);
2039
2062
  if (codecPrivate2) {
2040
2063
  addCodecPrivateToTrack({ trackNumber: trackNumber2, codecPrivate: codecPrivate2 });
2041
2064
  }
@@ -2069,6 +2092,7 @@ var createIsoBaseMedia = async ({
2069
2092
  const addTrack = (track) => {
2070
2093
  const trackNumber2 = currentTracks.length + 1;
2071
2094
  currentTracks.push({ ...track, trackNumber: trackNumber2 });
2095
+ progressTracker.registerTrack(trackNumber2);
2072
2096
  return Promise.resolve({ trackNumber: trackNumber2 });
2073
2097
  };
2074
2098
  const waitForFinishPromises = [];
@@ -2117,10 +2141,6 @@ var createIsoBaseMedia = async ({
2117
2141
  await updateMdatSize();
2118
2142
  Log.verbose(logLevel, "All write operations done. Waiting for finish...");
2119
2143
  await w.waitForFinish();
2120
- },
2121
- updateDuration: (duration2) => {
2122
- operationProm.current = operationProm.current.then(() => updateDuration(duration2));
2123
- return operationProm.current;
2124
2144
  }
2125
2145
  };
2126
2146
  };
@@ -2178,7 +2198,7 @@ var canFitInCluster = ({
2178
2198
  }) => {
2179
2199
  const timecodeRelativeToCluster = timestampToClusterTimestamp(chunk.timestamp, timescale) - timestampToClusterTimestamp(clusterStartTimestamp, timescale);
2180
2200
  if (timecodeRelativeToCluster < 0) {
2181
- throw new Error(`timecodeRelativeToCluster is negative`);
2201
+ throw new Error(`timecodeRelativeToCluster is negative, tried to add ${chunk.timestamp} to ${clusterStartTimestamp}`);
2182
2202
  }
2183
2203
  return timecodeRelativeToCluster <= maxClusterTimestamp;
2184
2204
  };
@@ -2947,7 +2967,8 @@ var createMatroskaMedia = async ({
2947
2967
  onBytesProgress,
2948
2968
  onMillisecondsProgress,
2949
2969
  filename,
2950
- logLevel
2970
+ logLevel,
2971
+ progressTracker
2951
2972
  }) => {
2952
2973
  const header = makeMatroskaHeader();
2953
2974
  const w = await writer.createContent({ filename, mimeType: "video/webm" });
@@ -3012,17 +3033,11 @@ var createMatroskaMedia = async ({
3012
3033
  hexString: matroskaElements.Cluster,
3013
3034
  byte: clusterOffset - seekHeadOffset
3014
3035
  });
3015
- const trackNumberProgresses = {};
3016
3036
  const getClusterOrMakeNew = async ({
3017
3037
  chunk,
3018
- isVideo,
3019
- trackNumber: trackNumber2
3038
+ isVideo
3020
3039
  }) => {
3021
- const trackProgressValues = Object.values(trackNumberProgresses);
3022
- const smallestProgress = trackProgressValues.length === 0 ? 0 : Math.min(...trackProgressValues);
3023
- if (chunk.type === "key") {
3024
- trackNumberProgresses[trackNumber2] = chunk.timestamp;
3025
- }
3040
+ const smallestProgress = progressTracker.getSmallestProgress();
3026
3041
  if (!currentCluster.shouldMakeNewCluster({
3027
3042
  newT: smallestProgress,
3028
3043
  isVideo,
@@ -3050,8 +3065,7 @@ var createMatroskaMedia = async ({
3050
3065
  }) => {
3051
3066
  const { cluster, isNew, smallestProgress } = await getClusterOrMakeNew({
3052
3067
  chunk,
3053
- isVideo,
3054
- trackNumber: trackNumber2
3068
+ isVideo
3055
3069
  });
3056
3070
  const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
3057
3071
  await updateDuration(newDuration);
@@ -3064,12 +3078,16 @@ var createMatroskaMedia = async ({
3064
3078
  trackNumber: trackNumber2
3065
3079
  });
3066
3080
  }
3081
+ if (chunk.type === "key") {
3082
+ progressTracker.updateTrackProgress(trackNumber2, chunk.timestamp);
3083
+ }
3067
3084
  onBytesProgress(w.getWrittenByteCount());
3068
3085
  onMillisecondsProgress(newDuration);
3069
3086
  };
3070
3087
  const addTrack = async (track) => {
3071
3088
  currentTracks.push(track);
3072
3089
  const newTracks = makeMatroskaTracks(currentTracks);
3090
+ progressTracker.registerTrack(track.trackNumber);
3073
3091
  await w.updateDataAt(tracksOffset, combineUint8Arrays(newTracks.map((b) => b.bytes)));
3074
3092
  };
3075
3093
  const operationProm = { current: Promise.resolve() };
@@ -3095,10 +3113,6 @@ var createMatroskaMedia = async ({
3095
3113
  operationProm.current = operationProm.current.then(() => addSample({ chunk, trackNumber: trackNumber2, isVideo }));
3096
3114
  return operationProm.current;
3097
3115
  },
3098
- updateDuration: (duration2) => {
3099
- operationProm.current = operationProm.current.then(() => updateDuration(duration2));
3100
- return operationProm.current;
3101
- },
3102
3116
  addTrack: (track) => {
3103
3117
  const trackNumber2 = currentTracks.length + 1;
3104
3118
  operationProm.current = operationProm.current.then(() => addTrack({ ...track, trackNumber: trackNumber2 }));
@@ -3124,6 +3138,186 @@ var createMatroskaMedia = async ({
3124
3138
  };
3125
3139
  };
3126
3140
 
3141
+ // src/create/with-resolvers.ts
3142
+ var withResolvers = function() {
3143
+ let resolve;
3144
+ let reject;
3145
+ const promise = new Promise((res, rej) => {
3146
+ resolve = res;
3147
+ reject = rej;
3148
+ });
3149
+ return { promise, resolve, reject };
3150
+ };
3151
+ var withResolversAndWaitForReturn = () => {
3152
+ const { promise, reject, resolve } = withResolvers();
3153
+ const { promise: returnPromise, resolve: resolveReturn } = withResolvers();
3154
+ return {
3155
+ getPromiseToImmediatelyReturn: () => {
3156
+ resolveReturn(undefined);
3157
+ return promise;
3158
+ },
3159
+ reject: (reason) => {
3160
+ returnPromise.then(() => reject(reason));
3161
+ },
3162
+ resolve
3163
+ };
3164
+ };
3165
+
3166
+ // src/create/progress-tracker.ts
3167
+ var makeProgressTracker = () => {
3168
+ const trackNumberProgresses = {};
3169
+ const eventEmitter = new IoEventEmitter;
3170
+ const calculateSmallestProgress = () => {
3171
+ const progressValues = Object.values(trackNumberProgresses);
3172
+ if (progressValues.length === 0) {
3173
+ return 0;
3174
+ }
3175
+ return Math.min(...progressValues);
3176
+ };
3177
+ return {
3178
+ registerTrack: (trackNumber2) => {
3179
+ trackNumberProgresses[trackNumber2] = 0;
3180
+ },
3181
+ getSmallestProgress: () => {
3182
+ return calculateSmallestProgress();
3183
+ },
3184
+ updateTrackProgress: (trackNumber2, progress) => {
3185
+ if (trackNumberProgresses[trackNumber2] === undefined) {
3186
+ throw new Error(`Tried to update progress for a track that was not registered: ${trackNumber2}`);
3187
+ }
3188
+ trackNumberProgresses[trackNumber2] = progress;
3189
+ eventEmitter.dispatchEvent("progress", {
3190
+ smallestProgress: calculateSmallestProgress()
3191
+ });
3192
+ },
3193
+ waitForProgress: () => {
3194
+ const { promise, resolve } = withResolvers();
3195
+ const on = () => {
3196
+ eventEmitter.removeEventListener("processed", on);
3197
+ resolve();
3198
+ };
3199
+ eventEmitter.addEventListener("processed", on);
3200
+ return promise;
3201
+ }
3202
+ };
3203
+ };
3204
+
3205
+ // src/create/wav/create-wav.ts
3206
+ var numberTo32BiIntLittleEndian = (num) => {
3207
+ return new Uint8Array([
3208
+ num & 255,
3209
+ num >> 8 & 255,
3210
+ num >> 16 & 255,
3211
+ num >> 24 & 255
3212
+ ]);
3213
+ };
3214
+ var numberTo16BitLittleEndian = (num) => {
3215
+ return new Uint8Array([num & 255, num >> 8 & 255]);
3216
+ };
3217
+ var BIT_DEPTH = 16;
3218
+ var BYTES_PER_SAMPLE = BIT_DEPTH / 8;
3219
+ var createWav = async ({
3220
+ filename,
3221
+ logLevel,
3222
+ onBytesProgress,
3223
+ onMillisecondsProgress,
3224
+ writer,
3225
+ progressTracker
3226
+ }) => {
3227
+ const w = await writer.createContent({ filename, mimeType: "audio/wav" });
3228
+ await w.write(new Uint8Array([82, 73, 70, 70]));
3229
+ const sizePosition = w.getWrittenByteCount();
3230
+ await w.write(new Uint8Array([0, 0, 0, 0]));
3231
+ await w.write(new Uint8Array([87, 65, 86, 69]));
3232
+ await w.write(new Uint8Array([102, 109, 116, 32]));
3233
+ await w.write(new Uint8Array([16, 0, 0, 0]));
3234
+ await w.write(new Uint8Array([1, 0]));
3235
+ const channelNumPosition = w.getWrittenByteCount();
3236
+ await w.write(new Uint8Array([1, 0]));
3237
+ const sampleRatePosition = w.getWrittenByteCount();
3238
+ await w.write(new Uint8Array([0, 0, 0, 0]));
3239
+ const byteRatePosition = w.getWrittenByteCount();
3240
+ await w.write(new Uint8Array([0, 0, 0, 0]));
3241
+ const blockAlignPosition = w.getWrittenByteCount();
3242
+ await w.write(new Uint8Array([0, 0]));
3243
+ await w.write(numberTo16BitLittleEndian(BIT_DEPTH));
3244
+ await w.write(new Uint8Array([100, 97, 116, 97]));
3245
+ const dataSizePosition = w.getWrittenByteCount();
3246
+ await w.write(new Uint8Array([0, 0, 0, 0]));
3247
+ const operationProm = { current: Promise.resolve() };
3248
+ const updateSize = async () => {
3249
+ const size = w.getWrittenByteCount() - sizePosition - 4;
3250
+ await w.updateDataAt(sizePosition, numberTo32BiIntLittleEndian(size));
3251
+ const dataSize = w.getWrittenByteCount() - dataSizePosition - 4;
3252
+ await w.updateDataAt(dataSizePosition, numberTo32BiIntLittleEndian(dataSize));
3253
+ };
3254
+ const updateChannelNum = async (numberOfChannels) => {
3255
+ await w.updateDataAt(channelNumPosition, new Uint8Array([numberOfChannels, 0]));
3256
+ };
3257
+ const updateSampleRate = async (sampleRate) => {
3258
+ await w.updateDataAt(sampleRatePosition, numberTo32BiIntLittleEndian(sampleRate));
3259
+ };
3260
+ const updateByteRate = async ({
3261
+ sampleRate,
3262
+ numberOfChannels
3263
+ }) => {
3264
+ await w.updateDataAt(byteRatePosition, numberTo32BiIntLittleEndian(sampleRate * numberOfChannels + BYTES_PER_SAMPLE));
3265
+ };
3266
+ const updateBlockAlign = async (numberOfChannels) => {
3267
+ await w.updateDataAt(blockAlignPosition, new Uint8Array(numberTo16BitLittleEndian(numberOfChannels * BYTES_PER_SAMPLE)));
3268
+ };
3269
+ const addSample = async (chunk) => {
3270
+ Log.verbose(logLevel, "Adding sample", chunk);
3271
+ await w.write(chunk.data);
3272
+ onMillisecondsProgress((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
3273
+ onBytesProgress(w.getWrittenByteCount());
3274
+ };
3275
+ const waitForFinishPromises = [];
3276
+ return {
3277
+ save: () => {
3278
+ return w.save();
3279
+ },
3280
+ remove: () => {
3281
+ return w.remove();
3282
+ },
3283
+ addSample: ({ chunk, trackNumber: trackNumber2 }) => {
3284
+ if (trackNumber2 !== 1) {
3285
+ throw new Error("Only one track supported for WAV");
3286
+ }
3287
+ operationProm.current = operationProm.current.then(() => addSample(chunk));
3288
+ progressTracker.updateTrackProgress(trackNumber2, chunk.timestamp);
3289
+ return operationProm.current;
3290
+ },
3291
+ updateTrackSampleRate: () => {
3292
+ throw new Error("updateTrackSampleRate() not implemented for WAV encoder");
3293
+ },
3294
+ addWaitForFinishPromise: (promise) => {
3295
+ waitForFinishPromises.push(promise);
3296
+ },
3297
+ async waitForFinish() {
3298
+ Log.verbose(logLevel, "All write operations queued. Waiting for finish...");
3299
+ await Promise.all(waitForFinishPromises.map((p) => p()));
3300
+ await operationProm.current;
3301
+ await updateSize();
3302
+ await w.waitForFinish();
3303
+ },
3304
+ addTrack: async (track) => {
3305
+ if (track.type !== "audio") {
3306
+ throw new Error("Only audio tracks supported for WAV");
3307
+ }
3308
+ await updateChannelNum(track.numberOfChannels);
3309
+ await updateSampleRate(track.sampleRate);
3310
+ await updateByteRate({
3311
+ sampleRate: track.sampleRate,
3312
+ numberOfChannels: track.numberOfChannels
3313
+ });
3314
+ await updateBlockAlign(track.numberOfChannels);
3315
+ progressTracker.registerTrack(1);
3316
+ return Promise.resolve({ trackNumber: 1 });
3317
+ }
3318
+ };
3319
+ };
3320
+
3127
3321
  // src/boxes/iso-base-media/traversal.ts
3128
3322
  var getMoovBox = (segments) => {
3129
3323
  const moovBox = segments.find((s) => s.type === "moov-box");
@@ -3289,317 +3483,133 @@ var getMdatBox = (anySegment) => {
3289
3483
  return mdat;
3290
3484
  };
3291
3485
 
3292
- // src/get-sample-positions.ts
3293
- var getSamplePositions = ({
3294
- stcoBox,
3295
- stszBox,
3296
- stscBox,
3297
- stssBox,
3486
+ // src/boxes/riff/traversal.ts
3487
+ var isRiffAvi = (structure) => {
3488
+ return structure.boxes.some((box) => box.type === "riff-header" && box.fileType === "AVI");
3489
+ };
3490
+ var getHdlrBox = (structure) => {
3491
+ return structure.boxes.find((box) => box.type === "list-box" && box.listType === "hdrl");
3492
+ };
3493
+ var getAvihBox = (structure) => {
3494
+ const hdlrBox = getHdlrBox(structure);
3495
+ if (!hdlrBox) {
3496
+ return null;
3497
+ }
3498
+ return hdlrBox.children.find((box) => box.type === "avih-box");
3499
+ };
3500
+ var getStrlBoxes = (structure) => {
3501
+ const hdlrBox = getHdlrBox(structure);
3502
+ if (!hdlrBox) {
3503
+ return [];
3504
+ }
3505
+ return hdlrBox.children.filter((box) => box.type === "list-box" && box.listType === "strl");
3506
+ };
3507
+ var getStrhBox = (strlBoxChildren) => {
3508
+ return strlBoxChildren.find((box) => box.type === "strh-box");
3509
+ };
3510
+ var getStrfBox = (strlBoxChildren) => {
3511
+ return strlBoxChildren.find((box) => box.type === "strf-box-audio" || box.type === "strf-box-video") ?? null;
3512
+ };
3513
+
3514
+ // src/get-fps.ts
3515
+ var calculateFps = ({
3298
3516
  sttsBox,
3299
- cttsBox
3517
+ timeScale,
3518
+ durationInSamples
3300
3519
  }) => {
3301
- const sttsDeltas = [];
3302
- for (const distribution of sttsBox.sampleDistribution) {
3303
- for (let i = 0;i < distribution.sampleCount; i++) {
3304
- sttsDeltas.push(distribution.sampleDelta);
3305
- }
3520
+ let totalSamples = 0;
3521
+ for (const sample of sttsBox.sampleDistribution) {
3522
+ totalSamples += sample.sampleCount;
3306
3523
  }
3307
- const cttsEntries = [];
3308
- for (const entry of cttsBox?.entries ?? [
3309
- { sampleCount: sttsDeltas.length, sampleOffset: 0 }
3310
- ]) {
3311
- for (let i = 0;i < entry.sampleCount; i++) {
3312
- cttsEntries.push(entry.sampleOffset);
3313
- }
3524
+ const durationInSeconds = durationInSamples / timeScale;
3525
+ const fps = totalSamples / durationInSeconds;
3526
+ return fps;
3527
+ };
3528
+ var trakBoxContainsAudio = (trakBox) => {
3529
+ const stsd = getStsdBox(trakBox);
3530
+ if (!stsd) {
3531
+ return false;
3314
3532
  }
3315
- let dts = 0;
3316
- const chunks = stcoBox.entries;
3317
- const samples = [];
3318
- let samplesPerChunk = 1;
3319
- for (let i = 0;i < chunks.length; i++) {
3320
- const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
3321
- if (hasEntry) {
3322
- samplesPerChunk = hasEntry.samplesPerChunk;
3533
+ const videoSample = stsd.samples.find((s) => s.type === "audio");
3534
+ if (!videoSample || videoSample.type !== "audio") {
3535
+ return false;
3536
+ }
3537
+ return true;
3538
+ };
3539
+ var trakBoxContainsVideo = (trakBox) => {
3540
+ const stsd = getStsdBox(trakBox);
3541
+ if (!stsd) {
3542
+ return false;
3543
+ }
3544
+ const videoSample = stsd.samples.find((s) => s.type === "video");
3545
+ if (!videoSample || videoSample.type !== "video") {
3546
+ return false;
3547
+ }
3548
+ return true;
3549
+ };
3550
+ var getTimescaleAndDuration = (trakBox) => {
3551
+ const mdhdBox = getMdhdBox(trakBox);
3552
+ if (mdhdBox) {
3553
+ return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
3554
+ }
3555
+ return null;
3556
+ };
3557
+ var getFpsFromMp4TrakBox = (trakBox) => {
3558
+ const timescaleAndDuration = getTimescaleAndDuration(trakBox);
3559
+ if (!timescaleAndDuration) {
3560
+ return null;
3561
+ }
3562
+ const sttsBox = getSttsBox(trakBox);
3563
+ if (!sttsBox) {
3564
+ return null;
3565
+ }
3566
+ return calculateFps({
3567
+ sttsBox,
3568
+ timeScale: timescaleAndDuration.timescale,
3569
+ durationInSamples: timescaleAndDuration.duration
3570
+ });
3571
+ };
3572
+ var getFpsFromIsoMaseMedia = (structure) => {
3573
+ const moovBox = getMoovBox(structure.boxes);
3574
+ if (!moovBox) {
3575
+ return null;
3576
+ }
3577
+ const trackBoxes = getTraks(moovBox);
3578
+ const trackBox = trackBoxes.find(trakBoxContainsVideo);
3579
+ if (!trackBox) {
3580
+ return null;
3581
+ }
3582
+ return getFpsFromMp4TrakBox(trackBox);
3583
+ };
3584
+ var getFpsFromAvi = (structure) => {
3585
+ const strl = getStrlBoxes(structure);
3586
+ for (const s of strl) {
3587
+ const strh = getStrhBox(s.children);
3588
+ if (!strh) {
3589
+ throw new Error("No strh box");
3323
3590
  }
3324
- let offsetInThisChunk = 0;
3325
- for (let j = 0;j < samplesPerChunk; j++) {
3326
- const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
3327
- const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
3328
- const delta = sttsDeltas[samples.length];
3329
- const ctsOffset = cttsEntries[samples.length];
3330
- const cts = dts + ctsOffset;
3331
- samples.push({
3332
- offset: Number(chunks[i]) + offsetInThisChunk,
3333
- size,
3334
- isKeyframe,
3335
- dts,
3336
- cts,
3337
- duration: delta,
3338
- chunk: i
3339
- });
3340
- dts += delta;
3341
- offsetInThisChunk += size;
3591
+ if (strh.fccType === "auds") {
3592
+ continue;
3342
3593
  }
3594
+ return strh.rate;
3343
3595
  }
3344
- return samples;
3596
+ return null;
3345
3597
  };
3346
-
3347
- // src/samples-from-moof.ts
3348
- var getSamplesFromTraf = (trafSegment, moofOffset) => {
3349
- if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
3350
- throw new Error("Expected traf-box");
3598
+ var getFps = (segments) => {
3599
+ if (segments.type === "iso-base-media") {
3600
+ return getFpsFromIsoMaseMedia(segments);
3351
3601
  }
3352
- const tfhdBox = getTfhdBox(trafSegment);
3353
- const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
3354
- const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
3355
- const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
3356
- const tfdtBox = getTfdtBox(trafSegment);
3357
- const trunBoxes = getTrunBoxes(trafSegment);
3358
- let time = 0;
3359
- let offset = 0;
3360
- let dataOffset = 0;
3361
- const samples = [];
3362
- for (const trunBox of trunBoxes) {
3363
- let i = -1;
3364
- if (trunBox.dataOffset) {
3365
- dataOffset = trunBox.dataOffset;
3366
- offset = 0;
3367
- }
3368
- for (const sample of trunBox.samples) {
3369
- i++;
3370
- const duration2 = sample.sampleDuration ?? defaultSampleDuration;
3371
- if (duration2 === null) {
3372
- throw new Error("Expected duration");
3373
- }
3374
- const size = sample.sampleSize ?? defaultSampleSize;
3375
- if (size === null) {
3376
- throw new Error("Expected size");
3377
- }
3378
- const isFirstSample = i === 0;
3379
- const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
3380
- if (sampleFlags === null) {
3381
- throw new Error("Expected sample flags");
3382
- }
3383
- const keyframe = !(sampleFlags >> 16 & 1);
3384
- const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
3385
- const samplePosition = {
3386
- offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
3387
- dts,
3388
- cts: dts,
3389
- duration: duration2,
3390
- isKeyframe: keyframe,
3391
- size,
3392
- chunk: 0
3393
- };
3394
- samples.push(samplePosition);
3395
- offset += size;
3396
- time += duration2;
3397
- }
3398
- }
3399
- return samples;
3400
- };
3401
- var getSamplesFromMoof = ({
3402
- moofBox,
3403
- trackId
3404
- }) => {
3405
- if (moofBox.type !== "regular-box") {
3406
- throw new Error("Expected moof-box");
3407
- }
3408
- const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
3409
- const mapped = trafs.map((traf) => {
3410
- const tfhdBox = getTfhdBox(traf);
3411
- return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
3412
- });
3413
- return mapped.flat(1);
3414
- };
3415
-
3416
- // src/boxes/iso-base-media/get-sample-positions-from-track.ts
3417
- var getSamplePositionsFromTrack = (trakBox, moofBox) => {
3418
- const stszBox = getStszBox(trakBox);
3419
- const stcoBox = getStcoBox(trakBox);
3420
- const stscBox = getStscBox(trakBox);
3421
- const stssBox = getStssBox(trakBox);
3422
- const sttsBox = getSttsBox(trakBox);
3423
- const tkhdBox = getTkhdBox(trakBox);
3424
- const cttsBox = getCttsBox(trakBox);
3425
- const timescaleAndDuration = getTimescaleAndDuration(trakBox);
3426
- if (!tkhdBox) {
3427
- throw new Error("Expected tkhd box in trak box");
3428
- }
3429
- if (!stszBox) {
3430
- throw new Error("Expected stsz box in trak box");
3431
- }
3432
- if (!stcoBox) {
3433
- throw new Error("Expected stco box in trak box");
3434
- }
3435
- if (!stscBox) {
3436
- throw new Error("Expected stsc box in trak box");
3437
- }
3438
- if (!sttsBox) {
3439
- throw new Error("Expected stts box in trak box");
3440
- }
3441
- if (!timescaleAndDuration) {
3442
- throw new Error("Expected timescale and duration in trak box");
3443
- }
3444
- let samplePositions = getSamplePositions({
3445
- stcoBox,
3446
- stscBox,
3447
- stszBox,
3448
- stssBox,
3449
- sttsBox,
3450
- cttsBox
3451
- });
3452
- if (samplePositions.length === 0 && moofBox) {
3453
- samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
3454
- }
3455
- return samplePositions;
3456
- };
3457
-
3458
- // src/get-duration.ts
3459
- var getDurationFromMatroska = (segments) => {
3460
- const mainSegment = segments.find((s) => s.type === "Segment");
3461
- if (!mainSegment || mainSegment.type !== "Segment") {
3462
- return null;
3463
- }
3464
- const { value: children } = mainSegment;
3465
- if (!children) {
3466
- return null;
3467
- }
3468
- const infoSegment = children.find((s) => s.type === "Info");
3469
- const relevantBoxes = [
3470
- ...mainSegment.value,
3471
- ...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
3472
- ];
3473
- const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
3474
- if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
3475
- return null;
3476
- }
3477
- const duration2 = relevantBoxes.find((s) => s.type === "Duration");
3478
- if (!duration2 || duration2.type !== "Duration") {
3479
- return null;
3480
- }
3481
- return duration2.value.value / timestampScale2.value.value * 1000;
3482
- };
3483
- var isMatroska = (boxes) => {
3484
- const matroskaBox = boxes.find((b) => b.type === "Segment");
3485
- return matroskaBox;
3486
- };
3487
- var getDuration = (boxes, parserState) => {
3488
- if (isMatroska(boxes)) {
3489
- return getDurationFromMatroska(boxes);
3490
- }
3491
- const moovBox = getMoovBox(boxes);
3492
- if (!moovBox) {
3493
- return null;
3602
+ if (segments.type === "riff") {
3603
+ return getFpsFromAvi(segments);
3494
3604
  }
3495
- const moofBox = getMoofBox(boxes);
3496
- const mvhdBox = getMvhdBox(moovBox);
3497
- if (!mvhdBox) {
3498
- return null;
3499
- }
3500
- if (mvhdBox.type !== "mvhd-box") {
3501
- throw new Error("Expected mvhd-box");
3502
- }
3503
- if (mvhdBox.durationInSeconds > 0) {
3504
- return mvhdBox.durationInSeconds;
3505
- }
3506
- const tracks2 = getTracks(boxes, parserState);
3507
- const allTracks = [
3508
- ...tracks2.videoTracks,
3509
- ...tracks2.audioTracks,
3510
- ...tracks2.otherTracks
3511
- ];
3512
- const allSamples = allTracks.map((t) => {
3513
- const { timescale: ts } = t;
3514
- const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
3515
- const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
3516
- return highest ?? 0;
3517
- });
3518
- const highestTimestamp = Math.max(...allSamples);
3519
- return highestTimestamp;
3520
- };
3521
- var hasDuration = (boxes, parserState) => {
3522
- try {
3523
- const duration2 = getDuration(boxes, parserState);
3524
- return getDuration(boxes, parserState) !== null && duration2 !== 0;
3525
- } catch {
3526
- return false;
3527
- }
3528
- };
3529
-
3530
- // src/get-fps.ts
3531
- var calculateFps = ({
3532
- sttsBox,
3533
- timeScale,
3534
- durationInSamples
3535
- }) => {
3536
- let totalSamples = 0;
3537
- for (const sample of sttsBox.sampleDistribution) {
3538
- totalSamples += sample.sampleCount;
3539
- }
3540
- const durationInSeconds = durationInSamples / timeScale;
3541
- const fps = totalSamples / durationInSeconds;
3542
- return fps;
3543
- };
3544
- var trakBoxContainsAudio = (trakBox) => {
3545
- const stsd = getStsdBox(trakBox);
3546
- if (!stsd) {
3547
- return false;
3548
- }
3549
- const videoSample = stsd.samples.find((s) => s.type === "audio");
3550
- if (!videoSample || videoSample.type !== "audio") {
3551
- return false;
3552
- }
3553
- return true;
3554
- };
3555
- var trakBoxContainsVideo = (trakBox) => {
3556
- const stsd = getStsdBox(trakBox);
3557
- if (!stsd) {
3558
- return false;
3559
- }
3560
- const videoSample = stsd.samples.find((s) => s.type === "video");
3561
- if (!videoSample || videoSample.type !== "video") {
3562
- return false;
3563
- }
3564
- return true;
3565
- };
3566
- var getTimescaleAndDuration = (trakBox) => {
3567
- const mdhdBox = getMdhdBox(trakBox);
3568
- if (mdhdBox) {
3569
- return { timescale: mdhdBox.timescale, duration: mdhdBox.duration };
3570
- }
3571
- return null;
3572
- };
3573
- var getFpsFromMp4TrakBox = (trakBox) => {
3574
- const timescaleAndDuration = getTimescaleAndDuration(trakBox);
3575
- if (!timescaleAndDuration) {
3576
- return null;
3577
- }
3578
- const sttsBox = getSttsBox(trakBox);
3579
- if (!sttsBox) {
3580
- return null;
3581
- }
3582
- return calculateFps({
3583
- sttsBox,
3584
- timeScale: timescaleAndDuration.timescale,
3585
- durationInSamples: timescaleAndDuration.duration
3586
- });
3587
- };
3588
- var getFps = (segments) => {
3589
- const moovBox = getMoovBox(segments);
3590
- if (!moovBox) {
3591
- return null;
3592
- }
3593
- const trackBoxes = getTraks(moovBox);
3594
- const trackBox = trackBoxes.find(trakBoxContainsVideo);
3595
- if (!trackBox) {
3605
+ if (segments.type === "matroska") {
3596
3606
  return null;
3597
3607
  }
3598
- return getFpsFromMp4TrakBox(trackBox);
3608
+ throw new Error("Cannot get fps, not implemented");
3599
3609
  };
3600
3610
  var hasFps = (boxes) => {
3601
3611
  try {
3602
- if (isMatroska(boxes)) {
3612
+ if (boxes.type === "matroska") {
3603
3613
  return true;
3604
3614
  }
3605
3615
  return getFps(boxes) !== null;
@@ -3624,8 +3634,8 @@ var getAudioCodec = (boxes, parserState) => {
3624
3634
  }
3625
3635
  return null;
3626
3636
  };
3627
- var hasAudioCodec = (boxes) => {
3628
- return hasTracks(boxes);
3637
+ var hasAudioCodec = (boxes, state) => {
3638
+ return hasTracks(boxes, state);
3629
3639
  };
3630
3640
  var getCodecSpecificatorFromEsdsBox = ({
3631
3641
  child
@@ -3741,11 +3751,20 @@ var getAudioCodecFromTrak = (trak) => {
3741
3751
  }
3742
3752
  return null;
3743
3753
  };
3754
+ var isLpcmAudioCodec = (trak) => {
3755
+ return getAudioCodecFromTrak(trak)?.format === "lpcm";
3756
+ };
3744
3757
  var getAudioCodecStringFromTrak = (trak) => {
3745
3758
  const codec = getAudioCodecFromTrak(trak);
3746
3759
  if (!codec) {
3747
3760
  throw new Error("Expected codec");
3748
3761
  }
3762
+ if (codec.format === "lpcm") {
3763
+ return {
3764
+ codecString: "pcm-s16",
3765
+ description: codec.description
3766
+ };
3767
+ }
3749
3768
  const codecStringWithoutMp3Exception = [
3750
3769
  codec.format,
3751
3770
  codec.primarySpecificator ? codec.primarySpecificator.toString(16) : null,
@@ -3761,6 +3780,9 @@ var getAudioCodecFromAudioCodecInfo = (codec) => {
3761
3780
  if (codec.format === "twos") {
3762
3781
  return "pcm-s16";
3763
3782
  }
3783
+ if (codec.format === "lpcm") {
3784
+ return "pcm-s16";
3785
+ }
3764
3786
  if (codec.format === "sowt") {
3765
3787
  return "aiff";
3766
3788
  }
@@ -3787,16 +3809,6 @@ var getAudioCodecFromTrack = (track) => {
3787
3809
  };
3788
3810
 
3789
3811
  // src/get-sample-aspect-ratio.ts
3790
- function gcd(a, b) {
3791
- return b === 0 ? a : gcd(b, a % b);
3792
- }
3793
- function reduceFraction(numerator, denominator) {
3794
- const greatestCommonDivisor = gcd(Math.abs(numerator), Math.abs(denominator));
3795
- return {
3796
- numerator: numerator / greatestCommonDivisor,
3797
- denominator: denominator / greatestCommonDivisor
3798
- };
3799
- }
3800
3812
  var getStsdVideoConfig = (trakBox) => {
3801
3813
  const stsdBox = getStsdBox(trakBox);
3802
3814
  if (!stsdBox) {
@@ -3908,6 +3920,16 @@ var applyAspectRatios = ({
3908
3920
  height: newHeight
3909
3921
  };
3910
3922
  };
3923
+ function gcd(a, b) {
3924
+ return b === 0 ? a : gcd(b, a % b);
3925
+ }
3926
+ function reduceFraction(numerator, denominator) {
3927
+ const greatestCommonDivisor = gcd(Math.abs(numerator), Math.abs(denominator));
3928
+ return {
3929
+ numerator: numerator / greatestCommonDivisor,
3930
+ denominator: denominator / greatestCommonDivisor
3931
+ };
3932
+ }
3911
3933
  var getDisplayAspectRatio = ({
3912
3934
  sampleAspectRatio,
3913
3935
  nativeDimensions
@@ -3987,6 +4009,9 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
3987
4009
  const allowDiscard = () => {
3988
4010
  discardAllowed = true;
3989
4011
  };
4012
+ const discard = (length) => {
4013
+ counter.increment(length);
4014
+ };
3990
4015
  const getUint8 = () => {
3991
4016
  const val = view.getUint8(counter.getDiscardedOffset());
3992
4017
  counter.increment(1);
@@ -4032,8 +4057,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4032
4057
  }
4033
4058
  return lastInt;
4034
4059
  };
4035
- const getUint32 = (littleEndian = false) => {
4036
- const val = view.getUint32(counter.getDiscardedOffset(), littleEndian);
4060
+ const getUint32 = () => {
4061
+ const val = view.getUint32(counter.getDiscardedOffset());
4037
4062
  counter.increment(4);
4038
4063
  return val;
4039
4064
  };
@@ -4042,9 +4067,21 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4042
4067
  counter.increment(8);
4043
4068
  return val;
4044
4069
  };
4045
- const getUint32Le = () => {
4046
- const val = view.getUint32(counter.getDiscardedOffset(), true);
4047
- counter.increment(4);
4070
+ const startBox = (size) => {
4071
+ const startOffset = counter.getOffset();
4072
+ return {
4073
+ discardRest: () => discard(size - (counter.getOffset() - startOffset)),
4074
+ expectNoMoreBytes: () => {
4075
+ const remaining = size - (counter.getOffset() - startOffset);
4076
+ if (remaining !== 0) {
4077
+ throw new Error("expected 0 bytes, got " + remaining);
4078
+ }
4079
+ }
4080
+ };
4081
+ };
4082
+ const getUint32Le = () => {
4083
+ const val = view.getUint32(counter.getDiscardedOffset(), true);
4084
+ counter.increment(4);
4048
4085
  return val;
4049
4086
  };
4050
4087
  const getInt32Le = () => {
@@ -4185,9 +4222,7 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4185
4222
  leb128,
4186
4223
  removeBytesRead,
4187
4224
  isWebm,
4188
- discard: (length) => {
4189
- counter.increment(length);
4190
- },
4225
+ discard,
4191
4226
  getEightByteNumber,
4192
4227
  getFourByteNumber,
4193
4228
  getSlice,
@@ -4281,6 +4316,11 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4281
4316
  counter.increment(2);
4282
4317
  return val;
4283
4318
  },
4319
+ getUint16Le: () => {
4320
+ const val = view.getUint16(counter.getDiscardedOffset(), true);
4321
+ counter.increment(2);
4322
+ return val;
4323
+ },
4284
4324
  getUint24: () => {
4285
4325
  const val1 = view.getUint8(counter.getDiscardedOffset());
4286
4326
  const val2 = view.getUint8(counter.getDiscardedOffset() + 1);
@@ -4336,7 +4376,8 @@ var getArrayBufferIterator = (initialData, maxBytes) => {
4336
4376
  destroy,
4337
4377
  isMp3,
4338
4378
  disallowDiscard,
4339
- allowDiscard
4379
+ allowDiscard,
4380
+ startBox
4340
4381
  };
4341
4382
  };
4342
4383
 
@@ -4445,14 +4486,7 @@ var getVideoCodecFromIsoTrak = (trakBox) => {
4445
4486
  }
4446
4487
  throw new Error("Could not find video codec");
4447
4488
  };
4448
- var getVideoCodec = (boxes) => {
4449
- const moovBox = getMoovBox(boxes);
4450
- if (moovBox) {
4451
- const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0];
4452
- if (trakBox) {
4453
- return getVideoCodecFromIsoTrak(trakBox);
4454
- }
4455
- }
4489
+ var getVideoCodecFromMatroska = (boxes) => {
4456
4490
  const mainSegment = boxes.find((b) => b.type === "Segment");
4457
4491
  if (!mainSegment || mainSegment.type !== "Segment") {
4458
4492
  return null;
@@ -4483,10 +4517,44 @@ var getVideoCodec = (boxes) => {
4483
4517
  }
4484
4518
  }
4485
4519
  }
4520
+ throw new Error("Could not find video codec");
4521
+ };
4522
+ var getVideoCodecFromAvi = (structure) => {
4523
+ const strl = getStrlBoxes(structure);
4524
+ for (const s of strl) {
4525
+ const strh = getStrhBox(s.children);
4526
+ if (!strh) {
4527
+ throw new Error("No strh box");
4528
+ }
4529
+ if (strh.fccType === "auds") {
4530
+ continue;
4531
+ }
4532
+ if (strh.handler === "H264") {
4533
+ return "h264";
4534
+ }
4535
+ }
4536
+ throw new Error("Unsupported codec");
4537
+ };
4538
+ var getVideoCodec = (boxes) => {
4539
+ if (boxes.type === "iso-base-media") {
4540
+ const moovBox = getMoovBox(boxes.boxes);
4541
+ if (moovBox) {
4542
+ const trakBox = getTraks(moovBox).filter((t) => trakBoxContainsVideo(t))[0];
4543
+ if (trakBox) {
4544
+ return getVideoCodecFromIsoTrak(trakBox);
4545
+ }
4546
+ }
4547
+ }
4548
+ if (boxes.type === "riff") {
4549
+ return getVideoCodecFromAvi(boxes);
4550
+ }
4551
+ if (boxes.type === "matroska") {
4552
+ return getVideoCodecFromMatroska(boxes.boxes);
4553
+ }
4486
4554
  return null;
4487
4555
  };
4488
- var hasVideoCodec = (boxes) => {
4489
- return hasTracks(boxes);
4556
+ var hasVideoCodec = (boxes, state) => {
4557
+ return hasTracks(boxes, state);
4490
4558
  };
4491
4559
  var getVideoPrivateData = (trakBox) => {
4492
4560
  const videoSample = getStsdVideoConfig(trakBox);
@@ -4521,9 +4589,9 @@ var getIsoBmColrConfig = (trakBox) => {
4521
4589
  }
4522
4590
  return {
4523
4591
  fullRange: colrAtom.fullRangeFlag,
4524
- matrixCoefficients: colrAtom.matrixIndex === 1 ? "bt709" : colrAtom.matrixIndex === 5 ? "bt470bg" : colrAtom.matrixIndex === 6 ? "smpte170m" : null,
4525
- primaries: colrAtom.primaries === 1 ? "bt709" : colrAtom.primaries === 5 ? "bt470bg" : colrAtom.primaries === 6 ? "smpte170m" : null,
4526
- transferCharacteristics: colrAtom.transfer === 1 ? "bt709" : colrAtom.transfer === 6 ? "smpte170m" : colrAtom.transfer === 13 ? "iec61966-2-1" : null
4592
+ matrixCoefficients: colrAtom.matrixIndex === 1 ? "bt709" : colrAtom.matrixIndex === 5 ? "bt470bg" : colrAtom.matrixIndex === 6 ? "smpte170m" : colrAtom.matrixIndex === 9 ? "bt2020" : null,
4593
+ primaries: colrAtom.primaries === 1 ? "bt709" : colrAtom.primaries === 5 ? "bt470bg" : colrAtom.primaries === 6 ? "smpte170m" : colrAtom.primaries === 9 ? "bt2020" : null,
4594
+ transferCharacteristics: colrAtom.transfer === 1 ? "bt709" : colrAtom.transfer === 6 ? "smpte170m" : colrAtom.transfer === 13 ? "iec61966-2-1" : colrAtom.transfer === 18 ? "arib-std-b67" : null
4527
4595
  };
4528
4596
  };
4529
4597
  var getVideoCodecString = (trakBox) => {
@@ -4577,7 +4645,7 @@ var makeBaseMediaTrack = (trakBox) => {
4577
4645
  sampleRate,
4578
4646
  description,
4579
4647
  trakBox,
4580
- codecPrivate: getCodecPrivateFromTrak(trakBox),
4648
+ codecPrivate: getCodecPrivateFromTrak(trakBox) ?? description ?? null,
4581
4649
  codecWithoutConfig: getAudioCodecFromTrack(trakBox)
4582
4650
  };
4583
4651
  }
@@ -4636,6 +4704,135 @@ var makeBaseMediaTrack = (trakBox) => {
4636
4704
  return track;
4637
4705
  };
4638
4706
 
4707
+ // src/add-avc-profile-to-track.ts
4708
+ var addAvcProfileToTrack = (track, avc1Profile) => {
4709
+ if (avc1Profile === null) {
4710
+ return track;
4711
+ }
4712
+ return {
4713
+ ...track,
4714
+ codec: `avc1.${avc1Profile.sps.profile.toString(16).padStart(2, "0")}${avc1Profile.sps.compatibility.toString(16).padStart(2, "0")}${avc1Profile.sps.level.toString(16).padStart(2, "0")}`,
4715
+ codecPrivate: combineUint8Arrays([
4716
+ new Uint8Array([
4717
+ 1,
4718
+ avc1Profile.sps.level,
4719
+ avc1Profile.sps.compatibility,
4720
+ avc1Profile.sps.profile,
4721
+ 255,
4722
+ 225
4723
+ ]),
4724
+ serializeUint16(avc1Profile.sps.sps.length),
4725
+ avc1Profile.sps.sps,
4726
+ new Uint8Array([1]),
4727
+ serializeUint16(avc1Profile.pps.pps.length),
4728
+ avc1Profile.pps.pps
4729
+ ])
4730
+ };
4731
+ };
4732
+
4733
+ // src/boxes/riff/timescale.ts
4734
+ var MEDIA_PARSER_RIFF_TIMESCALE = 1e6;
4735
+
4736
+ // src/boxes/riff/get-tracks-from-avi.ts
4737
+ var getNumberOfTracks = (structure) => {
4738
+ const avihBox = getAvihBox(structure);
4739
+ if (avihBox) {
4740
+ return avihBox.streams;
4741
+ }
4742
+ throw new Error("No avih box found");
4743
+ };
4744
+ var makeAviAudioTrack = ({
4745
+ strf,
4746
+ index
4747
+ }) => {
4748
+ if (strf.formatTag !== 255) {
4749
+ throw new Error(`Unsupported audio format ${strf.formatTag}`);
4750
+ }
4751
+ return {
4752
+ type: "audio",
4753
+ codec: "mp4a.40.2",
4754
+ codecPrivate: new Uint8Array([18, 16]),
4755
+ codecWithoutConfig: "aac",
4756
+ description: new Uint8Array([18, 16]),
4757
+ numberOfChannels: strf.numberOfChannels,
4758
+ sampleRate: strf.sampleRate,
4759
+ timescale: MEDIA_PARSER_RIFF_TIMESCALE,
4760
+ trackId: index,
4761
+ trakBox: null
4762
+ };
4763
+ };
4764
+ var makeAviVideoTrack = ({
4765
+ strh,
4766
+ strf,
4767
+ index
4768
+ }) => {
4769
+ if (strh.handler !== "H264") {
4770
+ throw new Error(`Unsupported video codec ${strh.handler}`);
4771
+ }
4772
+ return {
4773
+ codecPrivate: null,
4774
+ codec: "to-be-overriden-later",
4775
+ codecWithoutConfig: "h264",
4776
+ codedHeight: strf.height,
4777
+ codedWidth: strf.width,
4778
+ width: strf.width,
4779
+ height: strf.height,
4780
+ type: "video",
4781
+ displayAspectHeight: strf.height,
4782
+ timescale: MEDIA_PARSER_RIFF_TIMESCALE,
4783
+ description: undefined,
4784
+ trackId: index,
4785
+ color: {
4786
+ fullRange: null,
4787
+ matrixCoefficients: null,
4788
+ primaries: null,
4789
+ transferCharacteristics: null
4790
+ },
4791
+ displayAspectWidth: strf.width,
4792
+ trakBox: null,
4793
+ rotation: 0,
4794
+ sampleAspectRatio: {
4795
+ numerator: 1,
4796
+ denominator: 1
4797
+ },
4798
+ fps: strh.rate / strh.scale
4799
+ };
4800
+ };
4801
+ var getTracksFromAvi = (structure, state) => {
4802
+ if (!isRiffAvi(structure)) {
4803
+ throw new Error("Not an AVI file");
4804
+ }
4805
+ const videoTracks = [];
4806
+ const audioTracks = [];
4807
+ const otherTracks = [];
4808
+ const boxes = getStrlBoxes(structure);
4809
+ let i = 0;
4810
+ for (const box of boxes) {
4811
+ const strh = getStrhBox(box.children);
4812
+ const strf = getStrfBox(box.children);
4813
+ if (!strh || !strf) {
4814
+ continue;
4815
+ }
4816
+ if (strf.type === "strf-box-video") {
4817
+ videoTracks.push(addAvcProfileToTrack(makeAviVideoTrack({ strh, strf, index: i }), state.getAvcProfile()));
4818
+ } else if (strh.fccType === "auds") {
4819
+ audioTracks.push(makeAviAudioTrack({ strf, index: i }));
4820
+ } else {
4821
+ throw new Error(`Unsupported track type ${strh.fccType}`);
4822
+ }
4823
+ i++;
4824
+ }
4825
+ return { audioTracks, otherTracks, videoTracks };
4826
+ };
4827
+ var hasAllTracksFromAvi = (structure, state) => {
4828
+ if (!isRiffAvi(structure)) {
4829
+ throw new Error("Not an AVI file");
4830
+ }
4831
+ const numberOfTracks = getNumberOfTracks(structure);
4832
+ const tracks2 = getTracksFromAvi(structure, state);
4833
+ return tracks2.videoTracks.length + tracks2.audioTracks.length + tracks2.otherTracks.length === numberOfTracks;
4834
+ };
4835
+
4639
4836
  // src/make-hvc1-codec-strings.ts
4640
4837
  var getHvc1CodecString = (data) => {
4641
4838
  const configurationVersion = data.getUint8();
@@ -4980,147 +5177,485 @@ var getTrack = ({
4980
5177
  })
4981
5178
  };
4982
5179
  }
4983
- return null;
5180
+ return null;
5181
+ };
5182
+
5183
+ // src/boxes/webm/get-ready-tracks.ts
5184
+ var getTracksFromMatroska = (segment, timescale2) => {
5185
+ const tracksSegment = getTracksSegment(segment);
5186
+ if (!tracksSegment) {
5187
+ throw new Error("No tracks segment");
5188
+ }
5189
+ const tracks2 = [];
5190
+ for (const trackEntrySegment of tracksSegment.value) {
5191
+ if (trackEntrySegment.type === "Crc32") {
5192
+ continue;
5193
+ }
5194
+ if (trackEntrySegment.type !== "TrackEntry") {
5195
+ throw new Error("Expected track entry segment");
5196
+ }
5197
+ const track = getTrack({
5198
+ track: trackEntrySegment,
5199
+ timescale: timescale2
5200
+ });
5201
+ if (track) {
5202
+ tracks2.push(track);
5203
+ }
5204
+ }
5205
+ return tracks2;
5206
+ };
5207
+
5208
+ // src/get-tracks.ts
5209
+ var getNumberOfTracks2 = (moovBox) => {
5210
+ const mvHdBox = getMvhdBox(moovBox);
5211
+ if (!mvHdBox) {
5212
+ return 0;
5213
+ }
5214
+ return mvHdBox.nextTrackId - 1;
5215
+ };
5216
+ var hasTracks = (structure, state) => {
5217
+ if (structure.type === "matroska") {
5218
+ const mainSegment = getMainSegment(structure.boxes);
5219
+ if (!mainSegment) {
5220
+ throw new Error("No main segment found");
5221
+ }
5222
+ return getTracksSegment(mainSegment) !== null;
5223
+ }
5224
+ if (structure.type === "iso-base-media") {
5225
+ const moovBox = getMoovBox(structure.boxes);
5226
+ if (!moovBox) {
5227
+ return false;
5228
+ }
5229
+ const numberOfTracks = getNumberOfTracks2(moovBox);
5230
+ const tracks2 = getTraks(moovBox);
5231
+ return tracks2.length === numberOfTracks;
5232
+ }
5233
+ if (structure.type === "riff") {
5234
+ return hasAllTracksFromAvi(structure, state);
5235
+ }
5236
+ throw new Error("Unknown container");
5237
+ };
5238
+ var getTracksFromMa = (segments, state) => {
5239
+ const videoTracks = [];
5240
+ const audioTracks = [];
5241
+ const otherTracks = [];
5242
+ const mainSegment = segments.find((s) => s.type === "Segment");
5243
+ if (!mainSegment) {
5244
+ throw new Error("No main segment found");
5245
+ }
5246
+ const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
5247
+ for (const track of matroskaTracks) {
5248
+ if (track.type === "video") {
5249
+ videoTracks.push(track);
5250
+ } else if (track.type === "audio") {
5251
+ audioTracks.push(track);
5252
+ } else if (track.type === "other") {
5253
+ otherTracks.push(track);
5254
+ }
5255
+ }
5256
+ return {
5257
+ videoTracks,
5258
+ audioTracks,
5259
+ otherTracks
5260
+ };
5261
+ };
5262
+ var getTracksFromIsoBaseMedia = (segments) => {
5263
+ const videoTracks = [];
5264
+ const audioTracks = [];
5265
+ const otherTracks = [];
5266
+ const moovBox = getMoovBox(segments);
5267
+ if (!moovBox) {
5268
+ return {
5269
+ videoTracks,
5270
+ audioTracks,
5271
+ otherTracks
5272
+ };
5273
+ }
5274
+ const tracks2 = getTraks(moovBox);
5275
+ for (const trakBox of tracks2) {
5276
+ const track = makeBaseMediaTrack(trakBox);
5277
+ if (!track) {
5278
+ continue;
5279
+ }
5280
+ if (track.type === "video") {
5281
+ videoTracks.push(track);
5282
+ } else if (track.type === "audio") {
5283
+ audioTracks.push(track);
5284
+ } else if (track.type === "other") {
5285
+ otherTracks.push(track);
5286
+ }
5287
+ }
5288
+ return {
5289
+ videoTracks,
5290
+ audioTracks,
5291
+ otherTracks
5292
+ };
5293
+ };
5294
+ var getTracks = (segments, state) => {
5295
+ if (segments.type === "matroska") {
5296
+ return getTracksFromMa(segments.boxes, state);
5297
+ }
5298
+ if (segments.type === "iso-base-media") {
5299
+ return getTracksFromIsoBaseMedia(segments.boxes);
5300
+ }
5301
+ if (segments.type === "riff") {
5302
+ return getTracksFromAvi(segments, state);
5303
+ }
5304
+ throw new Error("Unknown container");
5305
+ };
5306
+
5307
+ // src/get-container.ts
5308
+ var getContainer = (segments) => {
5309
+ if (segments.type === "iso-base-media") {
5310
+ return "mp4";
5311
+ }
5312
+ if (segments.type === "matroska") {
5313
+ return "webm";
5314
+ }
5315
+ if (segments.type === "riff") {
5316
+ if (isRiffAvi(segments)) {
5317
+ return "avi";
5318
+ }
5319
+ }
5320
+ throw new Error("Unknown container");
5321
+ };
5322
+ var hasContainer = (boxes) => {
5323
+ try {
5324
+ return getContainer(boxes) !== null;
5325
+ } catch {
5326
+ return false;
5327
+ }
5328
+ };
5329
+
5330
+ // src/get-dimensions.ts
5331
+ var getDimensions = (boxes, state) => {
5332
+ const { videoTracks } = getTracks(boxes, state);
5333
+ if (!videoTracks.length) {
5334
+ throw new Error("Expected video track");
5335
+ }
5336
+ const firstVideoTrack = videoTracks[0];
5337
+ return {
5338
+ width: firstVideoTrack.width,
5339
+ height: firstVideoTrack.height,
5340
+ rotation: firstVideoTrack.rotation,
5341
+ unrotatedHeight: firstVideoTrack.displayAspectHeight,
5342
+ unrotatedWidth: firstVideoTrack.displayAspectWidth
5343
+ };
5344
+ };
5345
+ var hasDimensions = (boxes, state) => {
5346
+ try {
5347
+ return getDimensions(boxes, state) !== null;
5348
+ } catch {
5349
+ return false;
5350
+ }
5351
+ };
5352
+
5353
+ // src/get-sample-positions.ts
5354
+ var getSamplePositions = ({
5355
+ stcoBox,
5356
+ stszBox,
5357
+ stscBox,
5358
+ stssBox,
5359
+ sttsBox,
5360
+ cttsBox
5361
+ }) => {
5362
+ const sttsDeltas = [];
5363
+ for (const distribution of sttsBox.sampleDistribution) {
5364
+ for (let i = 0;i < distribution.sampleCount; i++) {
5365
+ sttsDeltas.push(distribution.sampleDelta);
5366
+ }
5367
+ }
5368
+ const cttsEntries = [];
5369
+ for (const entry of cttsBox?.entries ?? [
5370
+ { sampleCount: sttsDeltas.length, sampleOffset: 0 }
5371
+ ]) {
5372
+ for (let i = 0;i < entry.sampleCount; i++) {
5373
+ cttsEntries.push(entry.sampleOffset);
5374
+ }
5375
+ }
5376
+ let dts = 0;
5377
+ const chunks = stcoBox.entries;
5378
+ const samples = [];
5379
+ let samplesPerChunk = 1;
5380
+ for (let i = 0;i < chunks.length; i++) {
5381
+ const hasEntry = stscBox.entries.find((entry) => entry.firstChunk === i + 1);
5382
+ if (hasEntry) {
5383
+ samplesPerChunk = hasEntry.samplesPerChunk;
5384
+ }
5385
+ let offsetInThisChunk = 0;
5386
+ for (let j = 0;j < samplesPerChunk; j++) {
5387
+ const size = stszBox.countType === "fixed" ? stszBox.sampleSize : stszBox.entries[samples.length];
5388
+ const isKeyframe = stssBox ? stssBox.sampleNumber.includes(samples.length + 1) : true;
5389
+ const delta = sttsDeltas[samples.length];
5390
+ const ctsOffset = cttsEntries[samples.length];
5391
+ const cts = dts + ctsOffset;
5392
+ samples.push({
5393
+ offset: Number(chunks[i]) + offsetInThisChunk,
5394
+ size,
5395
+ isKeyframe,
5396
+ dts,
5397
+ cts,
5398
+ duration: delta,
5399
+ chunk: i
5400
+ });
5401
+ dts += delta;
5402
+ offsetInThisChunk += size;
5403
+ }
5404
+ }
5405
+ return samples;
5406
+ };
5407
+
5408
+ // src/get-sample-positions-from-lpcm.ts
5409
+ var getSamplePositionsFromLpcm = (trakBox) => {
5410
+ const stscBox = getStscBox(trakBox);
5411
+ const stszBox = getStszBox(trakBox);
5412
+ const stcoBox = getStcoBox(trakBox);
5413
+ if (!stscBox) {
5414
+ throw new Error("Expected stsc box in trak box");
5415
+ }
5416
+ if (!stcoBox) {
5417
+ throw new Error("Expected stco box in trak box");
5418
+ }
5419
+ if (!stszBox) {
5420
+ throw new Error("Expected stsz box in trak box");
5421
+ }
5422
+ if (stszBox.countType !== "fixed") {
5423
+ throw new Error("Only supporting fixed count type in stsz box");
5424
+ }
5425
+ const samples = [];
5426
+ let timestamp = 0;
5427
+ for (let i = 0;i < stcoBox.entries.length; i++) {
5428
+ const entry = stcoBox.entries[i];
5429
+ const chunk = i + 1;
5430
+ const stscEntry = stscBox.entries.findLast((e) => e.firstChunk <= chunk);
5431
+ if (!stscEntry) {
5432
+ throw new Error("should not be");
5433
+ }
5434
+ samples.push({
5435
+ chunk,
5436
+ cts: timestamp,
5437
+ dts: timestamp,
5438
+ offset: Number(entry),
5439
+ size: stszBox.sampleSize * stscEntry.samplesPerChunk,
5440
+ duration: stscEntry.samplesPerChunk,
5441
+ isKeyframe: true
5442
+ });
5443
+ timestamp += stscEntry.samplesPerChunk;
5444
+ }
5445
+ return samples;
5446
+ };
5447
+
5448
+ // src/samples-from-moof.ts
5449
+ var getSamplesFromTraf = (trafSegment, moofOffset) => {
5450
+ if (trafSegment.type !== "regular-box" || trafSegment.boxType !== "traf") {
5451
+ throw new Error("Expected traf-box");
5452
+ }
5453
+ const tfhdBox = getTfhdBox(trafSegment);
5454
+ const defaultSampleDuration = tfhdBox?.defaultSampleDuration ?? null;
5455
+ const defaultSampleSize = tfhdBox?.defaultSampleSize ?? null;
5456
+ const defaultSampleFlags = tfhdBox?.defaultSampleFlags ?? null;
5457
+ const tfdtBox = getTfdtBox(trafSegment);
5458
+ const trunBoxes = getTrunBoxes(trafSegment);
5459
+ let time = 0;
5460
+ let offset = 0;
5461
+ let dataOffset = 0;
5462
+ const samples = [];
5463
+ for (const trunBox of trunBoxes) {
5464
+ let i = -1;
5465
+ if (trunBox.dataOffset) {
5466
+ dataOffset = trunBox.dataOffset;
5467
+ offset = 0;
5468
+ }
5469
+ for (const sample of trunBox.samples) {
5470
+ i++;
5471
+ const duration2 = sample.sampleDuration ?? defaultSampleDuration;
5472
+ if (duration2 === null) {
5473
+ throw new Error("Expected duration");
5474
+ }
5475
+ const size = sample.sampleSize ?? defaultSampleSize;
5476
+ if (size === null) {
5477
+ throw new Error("Expected size");
5478
+ }
5479
+ const isFirstSample = i === 0;
5480
+ const sampleFlags = sample.sampleFlags ? sample.sampleFlags : isFirstSample && trunBox.firstSampleFlags !== null ? trunBox.firstSampleFlags : defaultSampleFlags;
5481
+ if (sampleFlags === null) {
5482
+ throw new Error("Expected sample flags");
5483
+ }
5484
+ const keyframe = !(sampleFlags >> 16 & 1);
5485
+ const dts = time + (tfdtBox?.baseMediaDecodeTime ?? 0);
5486
+ const samplePosition = {
5487
+ offset: offset + (moofOffset ?? 0) + (dataOffset ?? 0),
5488
+ dts,
5489
+ cts: dts,
5490
+ duration: duration2,
5491
+ isKeyframe: keyframe,
5492
+ size,
5493
+ chunk: 0
5494
+ };
5495
+ samples.push(samplePosition);
5496
+ offset += size;
5497
+ time += duration2;
5498
+ }
5499
+ }
5500
+ return samples;
4984
5501
  };
4985
-
4986
- // src/boxes/webm/get-ready-tracks.ts
4987
- var getTracksFromMatroska = (segment, timescale2) => {
4988
- const tracksSegment = getTracksSegment(segment);
4989
- if (!tracksSegment) {
4990
- throw new Error("No tracks segment");
4991
- }
4992
- const tracks2 = [];
4993
- for (const trackEntrySegment of tracksSegment.value) {
4994
- if (trackEntrySegment.type === "Crc32") {
4995
- continue;
4996
- }
4997
- if (trackEntrySegment.type !== "TrackEntry") {
4998
- throw new Error("Expected track entry segment");
4999
- }
5000
- const track = getTrack({
5001
- track: trackEntrySegment,
5002
- timescale: timescale2
5003
- });
5004
- if (track) {
5005
- tracks2.push(track);
5006
- }
5502
+ var getSamplesFromMoof = ({
5503
+ moofBox,
5504
+ trackId
5505
+ }) => {
5506
+ if (moofBox.type !== "regular-box") {
5507
+ throw new Error("Expected moof-box");
5007
5508
  }
5008
- return tracks2;
5509
+ const trafs = moofBox.children.filter((c) => c.type === "regular-box" && c.boxType === "traf");
5510
+ const mapped = trafs.map((traf) => {
5511
+ const tfhdBox = getTfhdBox(traf);
5512
+ return tfhdBox?.trackId === trackId ? getSamplesFromTraf(traf, moofBox.offset) : [];
5513
+ });
5514
+ return mapped.flat(1);
5009
5515
  };
5010
5516
 
5011
- // src/get-tracks.ts
5012
- var getNumberOfTracks = (moovBox) => {
5013
- const mvHdBox = getMvhdBox(moovBox);
5014
- if (!mvHdBox) {
5015
- return 0;
5517
+ // src/boxes/iso-base-media/get-sample-positions-from-track.ts
5518
+ var getSamplePositionsFromTrack = (trakBox, moofBox) => {
5519
+ const isLpcm = isLpcmAudioCodec(trakBox);
5520
+ const timescaleAndDuration = getTimescaleAndDuration(trakBox);
5521
+ if (isLpcm) {
5522
+ return getSamplePositionsFromLpcm(trakBox);
5016
5523
  }
5017
- return mvHdBox.nextTrackId - 1;
5018
- };
5019
- var hasTracks = (segments) => {
5020
- const mainSegment = getMainSegment(segments);
5021
- if (mainSegment) {
5022
- return getTracksSegment(mainSegment) !== null;
5524
+ const stszBox = getStszBox(trakBox);
5525
+ const stcoBox = getStcoBox(trakBox);
5526
+ const stscBox = getStscBox(trakBox);
5527
+ const stssBox = getStssBox(trakBox);
5528
+ const sttsBox = getSttsBox(trakBox);
5529
+ const tkhdBox = getTkhdBox(trakBox);
5530
+ const cttsBox = getCttsBox(trakBox);
5531
+ if (!tkhdBox) {
5532
+ throw new Error("Expected tkhd box in trak box");
5023
5533
  }
5024
- const moovBox = getMoovBox(segments);
5025
- if (!moovBox) {
5026
- return false;
5534
+ if (!stszBox) {
5535
+ throw new Error("Expected stsz box in trak box");
5027
5536
  }
5028
- const numberOfTracks = getNumberOfTracks(moovBox);
5029
- const tracks2 = getTraks(moovBox);
5030
- return tracks2.length === numberOfTracks;
5537
+ if (!stcoBox) {
5538
+ throw new Error("Expected stco box in trak box");
5539
+ }
5540
+ if (!stscBox) {
5541
+ throw new Error("Expected stsc box in trak box");
5542
+ }
5543
+ if (!sttsBox) {
5544
+ throw new Error("Expected stts box in trak box");
5545
+ }
5546
+ if (!timescaleAndDuration) {
5547
+ throw new Error("Expected timescale and duration in trak box");
5548
+ }
5549
+ let samplePositions = getSamplePositions({
5550
+ stcoBox,
5551
+ stscBox,
5552
+ stszBox,
5553
+ stssBox,
5554
+ sttsBox,
5555
+ cttsBox
5556
+ });
5557
+ if (samplePositions.length === 0 && moofBox) {
5558
+ samplePositions = getSamplesFromMoof({ moofBox, trackId: tkhdBox.trackId });
5559
+ }
5560
+ return samplePositions;
5031
5561
  };
5032
- var getTracks = (segments, state) => {
5033
- const videoTracks = [];
5034
- const audioTracks = [];
5035
- const otherTracks = [];
5562
+
5563
+ // src/get-duration.ts
5564
+ var getDurationFromMatroska = (segments) => {
5036
5565
  const mainSegment = segments.find((s) => s.type === "Segment");
5037
- if (mainSegment && mainSegment.type === "Segment") {
5038
- const matroskaTracks = getTracksFromMatroska(mainSegment, state.getTimescale());
5039
- for (const track of matroskaTracks) {
5040
- if (track.type === "video") {
5041
- videoTracks.push(track);
5042
- } else if (track.type === "audio") {
5043
- audioTracks.push(track);
5044
- } else if (track.type === "other") {
5045
- otherTracks.push(track);
5046
- }
5047
- }
5048
- return {
5049
- videoTracks,
5050
- audioTracks,
5051
- otherTracks
5052
- };
5566
+ if (!mainSegment || mainSegment.type !== "Segment") {
5567
+ return null;
5053
5568
  }
5054
- const moovBox = getMoovBox(segments);
5569
+ const { value: children } = mainSegment;
5570
+ if (!children) {
5571
+ return null;
5572
+ }
5573
+ const infoSegment = children.find((s) => s.type === "Info");
5574
+ const relevantBoxes = [
5575
+ ...mainSegment.value,
5576
+ ...infoSegment && infoSegment.type === "Info" ? infoSegment.value : []
5577
+ ];
5578
+ const timestampScale2 = relevantBoxes.find((s) => s.type === "TimestampScale");
5579
+ if (!timestampScale2 || timestampScale2.type !== "TimestampScale") {
5580
+ return null;
5581
+ }
5582
+ const duration2 = relevantBoxes.find((s) => s.type === "Duration");
5583
+ if (!duration2 || duration2.type !== "Duration") {
5584
+ return null;
5585
+ }
5586
+ return duration2.value.value / timestampScale2.value.value * 1000;
5587
+ };
5588
+ var getDurationFromIsoBaseMedia = (structure, parserState) => {
5589
+ const moovBox = getMoovBox(structure.boxes);
5055
5590
  if (!moovBox) {
5056
- return {
5057
- videoTracks,
5058
- audioTracks,
5059
- otherTracks
5060
- };
5591
+ return null;
5061
5592
  }
5062
- const tracks2 = getTraks(moovBox);
5063
- for (const trakBox of tracks2) {
5064
- const track = makeBaseMediaTrack(trakBox);
5065
- if (!track) {
5066
- continue;
5067
- }
5068
- if (track.type === "video") {
5069
- videoTracks.push(track);
5070
- } else if (track.type === "audio") {
5071
- audioTracks.push(track);
5072
- } else if (track.type === "other") {
5073
- otherTracks.push(track);
5593
+ const moofBox = getMoofBox(structure.boxes);
5594
+ const mvhdBox = getMvhdBox(moovBox);
5595
+ if (!mvhdBox) {
5596
+ return null;
5597
+ }
5598
+ if (mvhdBox.type !== "mvhd-box") {
5599
+ throw new Error("Expected mvhd-box");
5600
+ }
5601
+ if (mvhdBox.durationInSeconds > 0) {
5602
+ return mvhdBox.durationInSeconds;
5603
+ }
5604
+ const tracks2 = getTracks(structure, parserState);
5605
+ const allTracks = [
5606
+ ...tracks2.videoTracks,
5607
+ ...tracks2.audioTracks,
5608
+ ...tracks2.otherTracks
5609
+ ];
5610
+ const allSamples = allTracks.map((t) => {
5611
+ const { timescale: ts } = t;
5612
+ const samplePositions = getSamplePositionsFromTrack(t.trakBox, moofBox);
5613
+ const highest = samplePositions?.map((sp) => (sp.cts + sp.duration) / ts).reduce((a, b) => Math.max(a, b), 0);
5614
+ return highest ?? 0;
5615
+ });
5616
+ const highestTimestamp = Math.max(...allSamples);
5617
+ return highestTimestamp;
5618
+ };
5619
+ var getDurationFromAvi = (structure) => {
5620
+ const strl = getStrlBoxes(structure);
5621
+ const lengths = [];
5622
+ for (const s of strl) {
5623
+ const strh = getStrhBox(s.children);
5624
+ if (!strh) {
5625
+ throw new Error("No strh box");
5074
5626
  }
5627
+ const samplesPerSecond = strh.rate / strh.scale;
5628
+ const streamLength = strh.length / samplesPerSecond;
5629
+ lengths.push(streamLength);
5075
5630
  }
5076
- return {
5077
- videoTracks,
5078
- audioTracks,
5079
- otherTracks
5080
- };
5631
+ return Math.max(...lengths);
5081
5632
  };
5082
-
5083
- // src/get-container.ts
5084
- var getContainer = (segments) => {
5085
- const moovBox = getMoovBox(segments);
5086
- if (moovBox) {
5087
- return "mp4";
5633
+ var getDuration = (structure, parserState) => {
5634
+ if (structure.type === "matroska") {
5635
+ return getDurationFromMatroska(structure.boxes);
5088
5636
  }
5089
- const mainSegment = getMainSegment(segments);
5090
- if (mainSegment) {
5091
- return "webm";
5637
+ if (structure.type === "iso-base-media") {
5638
+ return getDurationFromIsoBaseMedia(structure, parserState);
5092
5639
  }
5093
- return null;
5094
- };
5095
- var hasContainer = (boxes) => {
5096
- try {
5097
- return getContainer(boxes) !== null;
5098
- } catch {
5099
- return false;
5640
+ if (structure.type === "riff") {
5641
+ return getDurationFromAvi(structure);
5100
5642
  }
5643
+ throw new Error("Has no duration");
5644
+ };
5645
+ var hasDuration = (structure, parserState) => {
5646
+ return hasTracks(structure, parserState);
5101
5647
  };
5102
5648
 
5103
- // src/get-dimensions.ts
5104
- var getDimensions = (boxes, state) => {
5649
+ // src/get-is-hdr.ts
5650
+ var isVideoTrackHdr = (track) => {
5651
+ return track.color.matrixCoefficients === "bt2020" && track.color.transferCharacteristics === "arib-std-b67" && track.color.primaries === "bt2020";
5652
+ };
5653
+ var getIsHdr = (boxes, state) => {
5105
5654
  const { videoTracks } = getTracks(boxes, state);
5106
- if (!videoTracks.length) {
5107
- throw new Error("Expected video track");
5108
- }
5109
- const firstVideoTrack = videoTracks[0];
5110
- return {
5111
- width: firstVideoTrack.width,
5112
- height: firstVideoTrack.height,
5113
- rotation: firstVideoTrack.rotation,
5114
- unrotatedHeight: firstVideoTrack.displayAspectHeight,
5115
- unrotatedWidth: firstVideoTrack.displayAspectWidth
5116
- };
5655
+ return videoTracks.some((track) => isVideoTrackHdr(track));
5117
5656
  };
5118
- var hasDimensions = (boxes, state) => {
5119
- try {
5120
- return getDimensions(boxes, state) !== null;
5121
- } catch {
5122
- return false;
5123
- }
5657
+ var hasHdr = (boxes, state) => {
5658
+ return hasTracks(boxes, state);
5124
5659
  };
5125
5660
 
5126
5661
  // src/emit-available-info.ts
@@ -5135,10 +5670,10 @@ var emitAvailableInfo = ({
5135
5670
  }) => {
5136
5671
  const keys = Object.keys(hasInfo);
5137
5672
  for (const key of keys) {
5138
- if (key === "boxes") {
5139
- if (parseResult && hasInfo.boxes && returnValue.boxes === undefined) {
5140
- moreFields.onBoxes?.(parseResult.segments);
5141
- returnValue.boxes = parseResult.segments;
5673
+ if (key === "structure") {
5674
+ if (parseResult && hasInfo.structure && returnValue.structure === undefined) {
5675
+ moreFields.onStructure?.(parseResult.segments);
5676
+ returnValue.structure = parseResult.segments;
5142
5677
  }
5143
5678
  continue;
5144
5679
  }
@@ -5238,6 +5773,14 @@ var emitAvailableInfo = ({
5238
5773
  }
5239
5774
  continue;
5240
5775
  }
5776
+ if (key === "isHdr") {
5777
+ if (returnValue.isHdr === undefined && hasInfo.isHdr && parseResult) {
5778
+ const isHdr = getIsHdr(parseResult.segments, state);
5779
+ moreFields.onIsHdr?.(isHdr);
5780
+ returnValue.isHdr = isHdr;
5781
+ }
5782
+ continue;
5783
+ }
5241
5784
  if (key === "container") {
5242
5785
  if (returnValue.container === undefined && hasInfo.container && parseResult) {
5243
5786
  const container = getContainer(parseResult.segments);
@@ -5253,8 +5796,9 @@ var emitAvailableInfo = ({
5253
5796
  // src/has-all-info.ts
5254
5797
  var getAvailableInfo = (options, parseResult, state) => {
5255
5798
  const keys = Object.entries(options).filter(([, value]) => value);
5256
- const infos = keys.map(([key]) => {
5257
- if (key === "boxes") {
5799
+ const infos = keys.map(([_key]) => {
5800
+ const key = _key;
5801
+ if (key === "structure") {
5258
5802
  return Boolean(parseResult && parseResult.status === "done");
5259
5803
  }
5260
5804
  if (key === "durationInSeconds") {
@@ -5266,14 +5810,17 @@ var getAvailableInfo = (options, parseResult, state) => {
5266
5810
  if (key === "fps") {
5267
5811
  return Boolean(parseResult && hasFps(parseResult.segments));
5268
5812
  }
5813
+ if (key === "isHdr") {
5814
+ return Boolean(parseResult && hasHdr(parseResult.segments, state));
5815
+ }
5269
5816
  if (key === "videoCodec") {
5270
- return Boolean(parseResult && hasVideoCodec(parseResult.segments));
5817
+ return Boolean(parseResult && hasVideoCodec(parseResult.segments, state));
5271
5818
  }
5272
5819
  if (key === "audioCodec") {
5273
- return Boolean(parseResult && hasAudioCodec(parseResult.segments));
5820
+ return Boolean(parseResult && hasAudioCodec(parseResult.segments, state));
5274
5821
  }
5275
5822
  if (key === "tracks") {
5276
- return Boolean(parseResult && hasTracks(parseResult.segments));
5823
+ return Boolean(parseResult && hasTracks(parseResult.segments, state));
5277
5824
  }
5278
5825
  if (key === "internalStats") {
5279
5826
  return false;
@@ -5297,8 +5844,37 @@ var getAvailableInfo = (options, parseResult, state) => {
5297
5844
  return Object.fromEntries(entries);
5298
5845
  };
5299
5846
 
5847
+ // src/register-track.ts
5848
+ var registerTrack = async ({
5849
+ state,
5850
+ options,
5851
+ track
5852
+ }) => {
5853
+ if (track.type === "video" && options.onVideoTrack) {
5854
+ const callback = await options.onVideoTrack(track);
5855
+ await state.registerVideoSampleCallback(track.trackId, callback ?? null);
5856
+ }
5857
+ if (track.type === "audio" && options.onAudioTrack) {
5858
+ const callback = await options.onAudioTrack(track);
5859
+ await state.registerAudioSampleCallback(track.trackId, callback ?? null);
5860
+ }
5861
+ };
5862
+ var registerVideoTrackWhenProfileIsAvailable = ({
5863
+ options,
5864
+ state,
5865
+ track
5866
+ }) => {
5867
+ state.registerOnAvcProfileCallback(async (profile) => {
5868
+ await registerTrack({
5869
+ options,
5870
+ state,
5871
+ track: addAvcProfileToTrack(track, profile)
5872
+ });
5873
+ });
5874
+ };
5875
+
5300
5876
  // src/boxes/iso-base-media/esds/decoder-specific-config.ts
5301
- var parseDecoderSpecificConfig = (iterator, logLevel) => {
5877
+ var parseDecoderSpecificConfig = (iterator) => {
5302
5878
  const layerTag = iterator.getUint8();
5303
5879
  const layerSize = iterator.getPaddedFourByteNumber();
5304
5880
  const start = iterator.counter.getOffset();
@@ -5322,9 +5898,6 @@ var parseDecoderSpecificConfig = (iterator, logLevel) => {
5322
5898
  if (read < layerSize) {
5323
5899
  iterator.discard(layerSize - read);
5324
5900
  }
5325
- if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
5326
- Log.warn(logLevel, "Chrome has a bug and might not be able to decode this audio. It will be fixed, see: https://issues.chromium.org/issues/360083330");
5327
- }
5328
5901
  return {
5329
5902
  type: "mp4a-specific-config",
5330
5903
  audioObjectType,
@@ -5345,8 +5918,7 @@ var mapToObjectAudioIndicator = (num) => {
5345
5918
  return "unknown";
5346
5919
  };
5347
5920
  var processDescriptor = ({
5348
- iterator,
5349
- logLevel
5921
+ iterator
5350
5922
  }) => {
5351
5923
  const tag = iterator.getUint8();
5352
5924
  if (tag === 4) {
@@ -5363,7 +5935,7 @@ var processDescriptor = ({
5363
5935
  const avgBitrate = iterator.getUint32();
5364
5936
  const decoderSpecificConfigs = [];
5365
5937
  while (size - (iterator.counter.getOffset() - initialOffset) > 0) {
5366
- const decoderSpecificConfig = parseDecoderSpecificConfig(iterator, logLevel);
5938
+ const decoderSpecificConfig = parseDecoderSpecificConfig(iterator);
5367
5939
  decoderSpecificConfigs.push(decoderSpecificConfig);
5368
5940
  }
5369
5941
  return {
@@ -5393,13 +5965,12 @@ var processDescriptor = ({
5393
5965
  descriptor: null
5394
5966
  };
5395
5967
  };
5396
- var parseDescriptors = (iterator, maxBytes, logLevel) => {
5968
+ var parseDescriptors = (iterator, maxBytes) => {
5397
5969
  const descriptors = [];
5398
5970
  const initialOffset = iterator.counter.getOffset();
5399
5971
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
5400
5972
  const { descriptor } = processDescriptor({
5401
- iterator,
5402
- logLevel
5973
+ iterator
5403
5974
  });
5404
5975
  if (descriptor) {
5405
5976
  descriptors.push(descriptor);
@@ -5414,8 +5985,7 @@ var parseDescriptors = (iterator, maxBytes, logLevel) => {
5414
5985
  var parseEsds = ({
5415
5986
  data,
5416
5987
  size,
5417
- fileOffset,
5418
- logLevel
5988
+ fileOffset
5419
5989
  }) => {
5420
5990
  const version = data.getUint8();
5421
5991
  data.discard(3);
@@ -5424,7 +5994,7 @@ var parseEsds = ({
5424
5994
  const esId = data.getUint16();
5425
5995
  data.discard(1);
5426
5996
  const remaining = size - (data.counter.getOffset() - fileOffset);
5427
- const descriptors = parseDescriptors(data, remaining, logLevel);
5997
+ const descriptors = parseDescriptors(data, remaining);
5428
5998
  const remainingNow = size - (data.counter.getOffset() - fileOffset);
5429
5999
  data.discard(remainingNow);
5430
6000
  return {
@@ -5471,7 +6041,10 @@ var parseMdat = async ({
5471
6041
  signal,
5472
6042
  maySkipSampleProcessing
5473
6043
  }) => {
5474
- const alreadyHas = hasTracks(existingBoxes);
6044
+ const alreadyHas = hasTracks({
6045
+ type: "iso-base-media",
6046
+ boxes: existingBoxes
6047
+ }, options.parserState);
5475
6048
  if (!alreadyHas) {
5476
6049
  if (maySkipSampleProcessing) {
5477
6050
  data.discard(size - (data.counter.getOffset() - fileOffset));
@@ -5491,7 +6064,7 @@ var parseMdat = async ({
5491
6064
  fileOffset
5492
6065
  });
5493
6066
  }
5494
- const tracks2 = getTracks(existingBoxes, options.parserState);
6067
+ const tracks2 = getTracks({ type: "iso-base-media", boxes: existingBoxes }, options.parserState);
5495
6068
  const allTracks = [
5496
6069
  ...tracks2.videoTracks,
5497
6070
  ...tracks2.audioTracks,
@@ -5610,7 +6183,7 @@ var parseMoov = async ({
5610
6183
  signal,
5611
6184
  logLevel
5612
6185
  }) => {
5613
- const children = await parseBoxes({
6186
+ const children = await parseIsoBaseMediaBoxes({
5614
6187
  iterator,
5615
6188
  maxBytes: size - (iterator.counter.getOffset() - offset),
5616
6189
  allowIncompleteBoxes: false,
@@ -5627,7 +6200,7 @@ var parseMoov = async ({
5627
6200
  offset,
5628
6201
  boxSize: size,
5629
6202
  type: "moov-box",
5630
- children: children.segments
6203
+ children: children.segments.boxes
5631
6204
  };
5632
6205
  };
5633
6206
 
@@ -5932,7 +6505,7 @@ var parseMebx = async ({
5932
6505
  }) => {
5933
6506
  iterator.discard(6);
5934
6507
  const dataReferenceIndex = iterator.getUint16();
5935
- const children = await parseBoxes({
6508
+ const children = await parseIsoBaseMediaBoxes({
5936
6509
  iterator,
5937
6510
  maxBytes: iterator.counter.getOffset() - offset,
5938
6511
  allowIncompleteBoxes: false,
@@ -5951,7 +6524,7 @@ var parseMebx = async ({
5951
6524
  offset,
5952
6525
  dataReferenceIndex,
5953
6526
  format: "mebx",
5954
- children: children.segments
6527
+ children: children.segments.boxes
5955
6528
  };
5956
6529
  };
5957
6530
 
@@ -6085,6 +6658,7 @@ var audioTags = [
6085
6658
  "MAC6 ",
6086
6659
  "ima4",
6087
6660
  "fl32",
6661
+ "lpcm",
6088
6662
  "fl64",
6089
6663
  "in24",
6090
6664
  "in32",
@@ -6142,7 +6716,7 @@ var processSample = async ({
6142
6716
  const packetSize = iterator.getUint16();
6143
6717
  const sampleRate = iterator.getFixedPointUnsigned1616Number();
6144
6718
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
6145
- const children = await parseBoxes({
6719
+ const children = await parseIsoBaseMediaBoxes({
6146
6720
  iterator,
6147
6721
  allowIncompleteBoxes: false,
6148
6722
  maxBytes: bytesRemainingInBox,
@@ -6174,7 +6748,7 @@ var processSample = async ({
6174
6748
  bytesPerPacket: null,
6175
6749
  bytesPerFrame: null,
6176
6750
  bitsPerSample: null,
6177
- children: children.segments
6751
+ children: children.segments.boxes
6178
6752
  }
6179
6753
  };
6180
6754
  }
@@ -6189,7 +6763,7 @@ var processSample = async ({
6189
6763
  const bytesPerFrame = iterator.getUint32();
6190
6764
  const bytesPerSample = iterator.getUint32();
6191
6765
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
6192
- const children = await parseBoxes({
6766
+ const children = await parseIsoBaseMediaBoxes({
6193
6767
  iterator,
6194
6768
  allowIncompleteBoxes: false,
6195
6769
  maxBytes: bytesRemainingInBox,
@@ -6221,26 +6795,26 @@ var processSample = async ({
6221
6795
  bytesPerPacket,
6222
6796
  bytesPerFrame,
6223
6797
  bitsPerSample: bytesPerSample,
6224
- children: children.segments
6798
+ children: children.segments.boxes
6225
6799
  }
6226
6800
  };
6227
6801
  }
6228
6802
  if (version === 2) {
6229
- const numberOfChannels = iterator.getUint16();
6803
+ iterator.getUint16();
6230
6804
  const sampleSize = iterator.getUint16();
6231
6805
  const compressionId = iterator.getUint16();
6232
6806
  const packetSize = iterator.getUint16();
6233
6807
  iterator.getFixedPointUnsigned1616Number();
6234
6808
  iterator.getUint32();
6235
6809
  const higherSampleRate = iterator.getFloat64();
6810
+ const numAudioChannel = iterator.getUint32();
6236
6811
  iterator.getUint32();
6237
- iterator.getUint32();
6238
- const bitsPerCodedSample = iterator.getUint32();
6812
+ const bitsPerChannel = iterator.getUint32();
6239
6813
  iterator.getUint32();
6240
6814
  const bytesPerFrame = iterator.getUint32();
6241
6815
  const samplesPerPacket = iterator.getUint32();
6242
6816
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
6243
- const children = await parseBoxes({
6817
+ const children = await parseIsoBaseMediaBoxes({
6244
6818
  iterator,
6245
6819
  allowIncompleteBoxes: false,
6246
6820
  maxBytes: bytesRemainingInBox,
@@ -6263,7 +6837,7 @@ var processSample = async ({
6263
6837
  vendor: [...Array.from(new Uint8Array(vendor))],
6264
6838
  size: boxSize,
6265
6839
  type: "audio",
6266
- numberOfChannels,
6840
+ numberOfChannels: numAudioChannel,
6267
6841
  sampleSize,
6268
6842
  compressionId,
6269
6843
  packetSize,
@@ -6271,8 +6845,8 @@ var processSample = async ({
6271
6845
  samplesPerPacket,
6272
6846
  bytesPerPacket: null,
6273
6847
  bytesPerFrame,
6274
- bitsPerSample: bitsPerCodedSample,
6275
- children: children.segments
6848
+ bitsPerSample: bitsPerChannel,
6849
+ children: children.segments.boxes
6276
6850
  }
6277
6851
  };
6278
6852
  }
@@ -6294,7 +6868,7 @@ var processSample = async ({
6294
6868
  const depth = iterator.getUint16();
6295
6869
  const colorTableId = iterator.getInt16();
6296
6870
  const bytesRemainingInBox = boxSize - (iterator.counter.getOffset() - fileOffset);
6297
- const children = bytesRemainingInBox > 8 ? await parseBoxes({
6871
+ const children = bytesRemainingInBox > 8 ? await parseIsoBaseMediaBoxes({
6298
6872
  iterator,
6299
6873
  allowIncompleteBoxes: false,
6300
6874
  maxBytes: bytesRemainingInBox,
@@ -6303,7 +6877,7 @@ var processSample = async ({
6303
6877
  continueMdat: false,
6304
6878
  signal,
6305
6879
  logLevel
6306
- }) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: [] });
6880
+ }) : (iterator.discard(bytesRemainingInBox), { status: "done", segments: { boxes: [], type: "iso-base-media" } });
6307
6881
  if (children.status === "incomplete") {
6308
6882
  throw new Error("Incomplete boxes are not allowed");
6309
6883
  }
@@ -6328,7 +6902,7 @@ var processSample = async ({
6328
6902
  compressorName,
6329
6903
  depth,
6330
6904
  colorTableId,
6331
- descriptors: children.segments
6905
+ descriptors: children.segments.boxes
6332
6906
  }
6333
6907
  };
6334
6908
  }
@@ -6650,7 +7224,7 @@ var parseTrak = async ({
6650
7224
  signal,
6651
7225
  logLevel
6652
7226
  }) => {
6653
- const children = await parseBoxes({
7227
+ const children = await parseIsoBaseMediaBoxes({
6654
7228
  iterator: data,
6655
7229
  maxBytes: size - (data.counter.getOffset() - offsetAtStart),
6656
7230
  allowIncompleteBoxes: false,
@@ -6667,7 +7241,7 @@ var parseTrak = async ({
6667
7241
  offset: offsetAtStart,
6668
7242
  boxSize: size,
6669
7243
  type: "trak-box",
6670
- children: children.segments
7244
+ children: children.segments.boxes
6671
7245
  };
6672
7246
  };
6673
7247
 
@@ -6724,7 +7298,7 @@ var getChildren = async ({
6724
7298
  }) => {
6725
7299
  const parseChildren = boxType === "mdia" || boxType === "minf" || boxType === "stbl" || boxType === "moof" || boxType === "dims" || boxType === "wave" || boxType === "traf" || boxType === "stsb";
6726
7300
  if (parseChildren) {
6727
- const parsed = await parseBoxes({
7301
+ const parsed = await parseIsoBaseMediaBoxes({
6728
7302
  iterator,
6729
7303
  maxBytes: bytesRemainingInBox,
6730
7304
  allowIncompleteBoxes: false,
@@ -6737,7 +7311,7 @@ var getChildren = async ({
6737
7311
  if (parsed.status === "incomplete") {
6738
7312
  throw new Error("Incomplete boxes are not allowed");
6739
7313
  }
6740
- return parsed.segments;
7314
+ return parsed.segments.boxes;
6741
7315
  }
6742
7316
  if (bytesRemainingInBox < 0) {
6743
7317
  throw new Error("Box size is too big " + JSON.stringify({ boxType }));
@@ -6811,7 +7385,7 @@ var processBox = async ({
6811
7385
  const boxSize = boxSizeRaw === 1 ? iterator.getEightByteNumber() : boxSizeRaw;
6812
7386
  if (bytesRemaining < boxSize) {
6813
7387
  if (boxType === "mdat") {
6814
- const shouldSkip = (options.canSkipVideoData || !hasTracks(parsedBoxes)) && options.supportsContentRange;
7388
+ const shouldSkip = (options.canSkipVideoData || !hasTracks({ type: "iso-base-media", boxes: parsedBoxes }, options.parserState)) && options.supportsContentRange;
6815
7389
  if (shouldSkip) {
6816
7390
  const skipTo = fileOffset + boxSize;
6817
7391
  const bytesToSkip = skipTo - iterator.counter.getOffset();
@@ -7040,14 +7614,11 @@ var processBox = async ({
7040
7614
  });
7041
7615
  const transformedTrack = makeBaseMediaTrack(box);
7042
7616
  if (transformedTrack) {
7043
- if (transformedTrack.type === "audio") {
7044
- const callback = await options.onAudioTrack?.(transformedTrack);
7045
- await options.parserState.registerAudioSampleCallback(transformedTrack.trackId, callback ?? null);
7046
- }
7047
- if (transformedTrack.type === "video") {
7048
- const callback = await options.onVideoTrack?.(transformedTrack);
7049
- await options.parserState.registerVideoSampleCallback(transformedTrack.trackId, callback ?? null);
7050
- }
7617
+ await registerTrack({
7618
+ options,
7619
+ state: options.parserState,
7620
+ track: transformedTrack
7621
+ });
7051
7622
  }
7052
7623
  return {
7053
7624
  type: "complete",
@@ -7136,8 +7707,7 @@ var processBox = async ({
7136
7707
  const box = parseEsds({
7137
7708
  data: iterator,
7138
7709
  size: boxSize,
7139
- fileOffset,
7140
- logLevel
7710
+ fileOffset
7141
7711
  });
7142
7712
  return {
7143
7713
  type: "complete",
@@ -7188,7 +7758,7 @@ var processBox = async ({
7188
7758
  skipTo: null
7189
7759
  };
7190
7760
  };
7191
- var parseBoxes = async ({
7761
+ var parseIsoBaseMediaBoxes = async ({
7192
7762
  iterator,
7193
7763
  maxBytes,
7194
7764
  allowIncompleteBoxes,
@@ -7198,9 +7768,12 @@ var parseBoxes = async ({
7198
7768
  signal,
7199
7769
  logLevel
7200
7770
  }) => {
7201
- let boxes = initialBoxes;
7771
+ const structure = {
7772
+ type: "iso-base-media",
7773
+ boxes: initialBoxes
7774
+ };
7202
7775
  const initialOffset = iterator.counter.getOffset();
7203
- const alreadyHasMdat = boxes.find((b) => b.type === "mdat-box");
7776
+ const alreadyHasMdat = structure.boxes.find((b) => b.type === "mdat-box");
7204
7777
  while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() - initialOffset < maxBytes) {
7205
7778
  const result = continueMdat ? await parseMdatPartially({
7206
7779
  iterator,
@@ -7223,13 +7796,13 @@ var parseBoxes = async ({
7223
7796
  }
7224
7797
  return {
7225
7798
  status: "incomplete",
7226
- segments: boxes,
7799
+ segments: structure,
7227
7800
  continueParsing: () => {
7228
- return parseBoxes({
7801
+ return parseIsoBaseMediaBoxes({
7229
7802
  iterator,
7230
7803
  maxBytes,
7231
7804
  allowIncompleteBoxes,
7232
- initialBoxes: boxes,
7805
+ initialBoxes: structure.boxes,
7233
7806
  options,
7234
7807
  continueMdat: false,
7235
7808
  signal,
@@ -7242,13 +7815,13 @@ var parseBoxes = async ({
7242
7815
  if (result.type === "partial-mdat-box") {
7243
7816
  return {
7244
7817
  status: "incomplete",
7245
- segments: boxes,
7818
+ segments: structure,
7246
7819
  continueParsing: () => {
7247
- return Promise.resolve(parseBoxes({
7820
+ return Promise.resolve(parseIsoBaseMediaBoxes({
7248
7821
  iterator,
7249
7822
  maxBytes,
7250
7823
  allowIncompleteBoxes,
7251
- initialBoxes: boxes,
7824
+ initialBoxes: structure.boxes,
7252
7825
  options,
7253
7826
  continueMdat: result,
7254
7827
  signal,
@@ -7259,15 +7832,15 @@ var parseBoxes = async ({
7259
7832
  };
7260
7833
  }
7261
7834
  if (result.box.type === "mdat-box" && alreadyHasMdat) {
7262
- boxes = boxes.filter((b) => b.type !== "mdat-box");
7263
- boxes.push(result.box);
7835
+ structure.boxes = structure.boxes.filter((b) => b.type !== "mdat-box");
7836
+ structure.boxes.push(result.box);
7264
7837
  iterator.allowDiscard();
7265
7838
  if (result.box.status !== "samples-processed") {
7266
7839
  throw new Error("unexpected");
7267
7840
  }
7268
7841
  break;
7269
7842
  } else {
7270
- boxes.push(result.box);
7843
+ structure.boxes.push(result.box);
7271
7844
  }
7272
7845
  if (result.skipTo !== null) {
7273
7846
  if (!options.supportsContentRange) {
@@ -7275,13 +7848,13 @@ var parseBoxes = async ({
7275
7848
  }
7276
7849
  return {
7277
7850
  status: "incomplete",
7278
- segments: boxes,
7851
+ segments: structure,
7279
7852
  continueParsing: () => {
7280
- return parseBoxes({
7853
+ return parseIsoBaseMediaBoxes({
7281
7854
  iterator,
7282
7855
  maxBytes,
7283
7856
  allowIncompleteBoxes,
7284
- initialBoxes: boxes,
7857
+ initialBoxes: structure.boxes,
7285
7858
  options,
7286
7859
  continueMdat: false,
7287
7860
  signal,
@@ -7294,13 +7867,13 @@ var parseBoxes = async ({
7294
7867
  if (iterator.bytesRemaining() < 0) {
7295
7868
  return {
7296
7869
  status: "incomplete",
7297
- segments: boxes,
7870
+ segments: structure,
7298
7871
  continueParsing: () => {
7299
- return parseBoxes({
7872
+ return parseIsoBaseMediaBoxes({
7300
7873
  iterator,
7301
7874
  maxBytes,
7302
7875
  allowIncompleteBoxes,
7303
- initialBoxes: boxes,
7876
+ initialBoxes: structure.boxes,
7304
7877
  options,
7305
7878
  continueMdat: false,
7306
7879
  signal,
@@ -7312,22 +7885,22 @@ var parseBoxes = async ({
7312
7885
  }
7313
7886
  iterator.removeBytesRead();
7314
7887
  }
7315
- const mdatState = getMdatBox(boxes);
7888
+ const mdatState = getMdatBox(structure.boxes);
7316
7889
  const skipped = mdatState?.status === "samples-skipped" && !options.canSkipVideoData && options.supportsContentRange;
7317
7890
  const buffered = mdatState?.status === "samples-buffered" && !options.canSkipVideoData;
7318
7891
  if (skipped || buffered) {
7319
7892
  return {
7320
7893
  status: "incomplete",
7321
- segments: boxes,
7894
+ segments: structure,
7322
7895
  continueParsing: () => {
7323
7896
  if (buffered) {
7324
7897
  iterator.skipTo(mdatState.fileOffset, false);
7325
7898
  }
7326
- return parseBoxes({
7899
+ return parseIsoBaseMediaBoxes({
7327
7900
  iterator,
7328
7901
  maxBytes,
7329
7902
  allowIncompleteBoxes: false,
7330
- initialBoxes: boxes,
7903
+ initialBoxes: structure.boxes,
7331
7904
  options,
7332
7905
  continueMdat: false,
7333
7906
  signal,
@@ -7339,24 +7912,651 @@ var parseBoxes = async ({
7339
7912
  }
7340
7913
  return {
7341
7914
  status: "done",
7342
- segments: boxes
7915
+ segments: structure
7343
7916
  };
7344
7917
  };
7345
7918
 
7346
- // src/add-new-matroska-tracks.ts
7347
- var registerTrack = async ({
7348
- state,
7919
+ // src/boxes/riff/is-movi.ts
7920
+ var isMoviAtom = (iterator, ckId) => {
7921
+ if (ckId !== "LIST") {
7922
+ return false;
7923
+ }
7924
+ const listType = iterator.getByteString(4);
7925
+ iterator.counter.decrement(4);
7926
+ return listType === "movi";
7927
+ };
7928
+
7929
+ // src/boxes/avc/parse-avc.ts
7930
+ var readSps = (iterator) => {
7931
+ const profile = iterator.getUint8();
7932
+ const compatibility = iterator.getUint8();
7933
+ const level = iterator.getUint8();
7934
+ return {
7935
+ profile,
7936
+ compatibility,
7937
+ level
7938
+ };
7939
+ };
7940
+ var findEnd = (buffer) => {
7941
+ let zeroesInARow = 0;
7942
+ for (let i = 0;i < buffer.length; i++) {
7943
+ const val = buffer[i];
7944
+ if (val === 0) {
7945
+ zeroesInARow++;
7946
+ continue;
7947
+ }
7948
+ if (zeroesInARow >= 2 && val === 1) {
7949
+ return i - zeroesInARow;
7950
+ }
7951
+ zeroesInARow = 0;
7952
+ }
7953
+ return null;
7954
+ };
7955
+ var inspect = (buffer) => {
7956
+ const iterator = getArrayBufferIterator(buffer, buffer.byteLength);
7957
+ iterator.startReadingBits();
7958
+ iterator.getBits(1);
7959
+ iterator.getBits(2);
7960
+ const type = iterator.getBits(5);
7961
+ iterator.stopReadingBits();
7962
+ if (type === 7) {
7963
+ const end = findEnd(buffer);
7964
+ const data = readSps(iterator);
7965
+ const sps = buffer.slice(1, end === null ? Infinity : end);
7966
+ return {
7967
+ level: data.level,
7968
+ profile: data.profile,
7969
+ compatibility: data.compatibility,
7970
+ sps,
7971
+ type: "avc-profile"
7972
+ };
7973
+ }
7974
+ if (type === 5) {
7975
+ return {
7976
+ type: "keyframe"
7977
+ };
7978
+ }
7979
+ if (type === 8) {
7980
+ const end = findEnd(buffer);
7981
+ const pps = buffer.slice(0, end === null ? Infinity : end);
7982
+ return {
7983
+ type: "avc-pps",
7984
+ pps
7985
+ };
7986
+ }
7987
+ if (type === 1) {
7988
+ return {
7989
+ type: "delta-frame"
7990
+ };
7991
+ }
7992
+ iterator.destroy();
7993
+ return null;
7994
+ };
7995
+ var parseAvc = (buffer) => {
7996
+ let zeroesInARow = 0;
7997
+ const infos = [];
7998
+ for (let i = 0;i < buffer.length; i++) {
7999
+ const val = buffer[i];
8000
+ if (val === 0) {
8001
+ zeroesInARow++;
8002
+ continue;
8003
+ }
8004
+ if (zeroesInARow >= 2 && val === 1) {
8005
+ zeroesInARow = 0;
8006
+ const info = inspect(buffer.slice(i + 1, i + 100));
8007
+ if (info) {
8008
+ infos.push(info);
8009
+ if (info.type === "keyframe" || info.type === "delta-frame") {
8010
+ break;
8011
+ }
8012
+ }
8013
+ }
8014
+ if (val !== 1) {
8015
+ zeroesInARow = 0;
8016
+ }
8017
+ }
8018
+ return infos;
8019
+ };
8020
+
8021
+ // src/boxes/riff/parse-movi.ts
8022
+ var getStrhForIndex = (structure, trackId) => {
8023
+ const boxes = getStrlBoxes(structure);
8024
+ const box = boxes[trackId];
8025
+ if (!box) {
8026
+ throw new Error("Expected box");
8027
+ }
8028
+ const strh = getStrhBox(box.children);
8029
+ if (!strh) {
8030
+ throw new Error("strh");
8031
+ }
8032
+ return strh;
8033
+ };
8034
+ var handleChunk = async ({
8035
+ iterator,
7349
8036
  options,
7350
- track
8037
+ structure,
8038
+ ckId,
8039
+ ckSize
7351
8040
  }) => {
7352
- if (track.type === "video" && options.onVideoTrack) {
7353
- const callback = await options.onVideoTrack(track);
7354
- await state.registerVideoSampleCallback(track.trackId, callback ?? null);
8041
+ const videoChunk = ckId.match(/^([0-9]{2})dc$/);
8042
+ if (videoChunk) {
8043
+ const trackId = parseInt(videoChunk[1], 10);
8044
+ const strh = getStrhForIndex(structure, trackId);
8045
+ const samplesPerSecond = strh.rate / strh.scale;
8046
+ const nthSample = options.parserState.getSamplesForTrack(trackId);
8047
+ const timeInSec = nthSample / samplesPerSecond;
8048
+ const timestamp = Math.floor(timeInSec * MEDIA_PARSER_RIFF_TIMESCALE);
8049
+ const duration2 = Math.floor(1 / samplesPerSecond * MEDIA_PARSER_RIFF_TIMESCALE);
8050
+ const data = iterator.getSlice(ckSize);
8051
+ const infos = parseAvc(data);
8052
+ const keyOrDelta = infos.find((i) => i.type === "keyframe" || i.type === "delta-frame");
8053
+ if (!keyOrDelta) {
8054
+ throw new Error("expected avc to contain info about key or delta");
8055
+ }
8056
+ const avcProfile = infos.find((i) => i.type === "avc-profile");
8057
+ const ppsProfile = infos.find((i) => i.type === "avc-pps");
8058
+ if (avcProfile && ppsProfile) {
8059
+ await options.parserState.onProfile({ pps: ppsProfile, sps: avcProfile });
8060
+ }
8061
+ await options.parserState.onVideoSample(trackId, {
8062
+ cts: timestamp,
8063
+ dts: timestamp,
8064
+ data,
8065
+ duration: duration2,
8066
+ timestamp,
8067
+ trackId,
8068
+ type: keyOrDelta.type === "keyframe" ? "key" : "delta"
8069
+ });
8070
+ } else {
8071
+ const audioChunk = ckId.match(/^([0-9]{2})wb$/);
8072
+ if (audioChunk) {
8073
+ const trackId = parseInt(audioChunk[1], 10);
8074
+ const strh = getStrhForIndex(structure, trackId);
8075
+ const samplesPerSecond = strh.rate / strh.scale;
8076
+ const nthSample = options.parserState.getSamplesForTrack(trackId);
8077
+ const timeInSec = nthSample / samplesPerSecond;
8078
+ const timestamp = timeInSec * MEDIA_PARSER_RIFF_TIMESCALE;
8079
+ const duration2 = 1 / samplesPerSecond * MEDIA_PARSER_RIFF_TIMESCALE;
8080
+ await options.parserState.onAudioSample(trackId, {
8081
+ cts: timestamp,
8082
+ dts: timestamp,
8083
+ data: iterator.getSlice(ckSize),
8084
+ duration: duration2,
8085
+ timestamp,
8086
+ trackId,
8087
+ type: "key"
8088
+ });
8089
+ }
7355
8090
  }
7356
- if (track.type === "audio" && options.onAudioTrack) {
7357
- const callback = await options.onAudioTrack(track);
7358
- await state.registerAudioSampleCallback(track.trackId, callback ?? null);
8091
+ };
8092
+ var parseMovi = async ({
8093
+ iterator,
8094
+ maxOffset,
8095
+ options,
8096
+ structure
8097
+ }) => {
8098
+ while (iterator.counter.getOffset() < maxOffset) {
8099
+ if (iterator.bytesRemaining() < 8) {
8100
+ return {
8101
+ type: "incomplete",
8102
+ continueParsing: () => {
8103
+ return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
8104
+ }
8105
+ };
8106
+ }
8107
+ const ckId = iterator.getByteString(4);
8108
+ const ckSize = iterator.getUint32Le();
8109
+ if (iterator.bytesRemaining() < ckSize) {
8110
+ iterator.counter.decrement(8);
8111
+ return {
8112
+ type: "incomplete",
8113
+ continueParsing: () => {
8114
+ return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
8115
+ }
8116
+ };
8117
+ }
8118
+ await handleChunk({ iterator, options, structure, ckId, ckSize });
8119
+ while (iterator.counter.getOffset() < maxOffset && iterator.bytesRemaining() > 0) {
8120
+ if (iterator.getUint8() !== 0) {
8121
+ iterator.counter.decrement(1);
8122
+ break;
8123
+ }
8124
+ }
8125
+ }
8126
+ if (iterator.counter.getOffset() === maxOffset) {
8127
+ return {
8128
+ type: "complete",
8129
+ box: {
8130
+ type: "movi-box"
8131
+ }
8132
+ };
8133
+ }
8134
+ if (iterator.counter.getOffset() > maxOffset) {
8135
+ throw new Error("Oops, this should not happen!");
8136
+ }
8137
+ return {
8138
+ type: "incomplete",
8139
+ continueParsing: () => {
8140
+ return Promise.resolve(parseMovi({ iterator, maxOffset, options, structure }));
8141
+ }
8142
+ };
8143
+ };
8144
+
8145
+ // src/boxes/riff/parse-avih.ts
8146
+ var parseAvih = ({
8147
+ iterator,
8148
+ size
8149
+ }) => {
8150
+ const { expectNoMoreBytes } = iterator.startBox(size);
8151
+ const dwMicroSecPerFrame = iterator.getUint32Le();
8152
+ const dwMaxBytesPerSec = iterator.getUint32Le();
8153
+ const paddingGranularity = iterator.getUint32Le();
8154
+ const flags = iterator.getUint32Le();
8155
+ const totalFrames = iterator.getUint32Le();
8156
+ const initialFrames = iterator.getUint32Le();
8157
+ const streams = iterator.getUint32Le();
8158
+ const suggestedBufferSize = iterator.getUint32Le();
8159
+ const width = iterator.getUint32Le();
8160
+ const height = iterator.getUint32Le();
8161
+ iterator.discard(16);
8162
+ expectNoMoreBytes();
8163
+ return {
8164
+ type: "avih-box",
8165
+ microSecPerFrame: dwMicroSecPerFrame,
8166
+ maxBytesPerSecond: dwMaxBytesPerSec,
8167
+ paddingGranularity,
8168
+ flags,
8169
+ totalFrames,
8170
+ initialFrames,
8171
+ streams,
8172
+ suggestedBufferSize,
8173
+ height,
8174
+ width
8175
+ };
8176
+ };
8177
+
8178
+ // src/boxes/riff/parse-fmt-box.ts
8179
+ var parseFmtBox = ({
8180
+ iterator,
8181
+ boxes,
8182
+ size
8183
+ }) => {
8184
+ const box = iterator.startBox(size);
8185
+ const header = boxes.find((b) => b.type === "riff-header");
8186
+ if (!header) {
8187
+ throw new Error("Expected RIFF header");
8188
+ }
8189
+ if (header.fileType !== "WAVE") {
8190
+ throw new Error("Only supporting WAVE type");
8191
+ }
8192
+ const wFormatTag = iterator.getUint16Le();
8193
+ if (wFormatTag !== 1) {
8194
+ throw new Error("Expected wFormatTag to be 1, only supporting this");
8195
+ }
8196
+ const numberOfChannels = iterator.getUint16Le();
8197
+ const sampleRate = iterator.getUint32Le();
8198
+ const byteRate = iterator.getUint32Le();
8199
+ const blockAlign = iterator.getUint16Le();
8200
+ const bitsPerSample = iterator.getUint16Le();
8201
+ box.expectNoMoreBytes();
8202
+ return {
8203
+ type: "wave-format-box",
8204
+ formatTag: wFormatTag,
8205
+ numberOfChannels,
8206
+ sampleRate,
8207
+ blockAlign,
8208
+ byteRate,
8209
+ bitsPerSample
8210
+ };
8211
+ };
8212
+
8213
+ // src/boxes/riff/parse-list-box.ts
8214
+ var parseListBox = async ({
8215
+ iterator,
8216
+ size,
8217
+ options
8218
+ }) => {
8219
+ const counter = iterator.counter.getOffset();
8220
+ const listType = iterator.getByteString(4);
8221
+ if (listType === "movi") {
8222
+ throw new Error("should not be handled here");
8223
+ }
8224
+ const structure = {
8225
+ type: "riff",
8226
+ boxes: []
8227
+ };
8228
+ const result = await parseRiffBody({
8229
+ structure,
8230
+ iterator,
8231
+ maxOffset: counter + size,
8232
+ options
8233
+ });
8234
+ if (result.status === "incomplete") {
8235
+ throw new Error(`Should only parse complete boxes (${listType})`);
8236
+ }
8237
+ return {
8238
+ type: "list-box",
8239
+ listType,
8240
+ children: structure.boxes
8241
+ };
8242
+ };
8243
+
8244
+ // src/boxes/riff/parse-strf.ts
8245
+ var parseStrfAudio = ({
8246
+ iterator,
8247
+ size
8248
+ }) => {
8249
+ const box = iterator.startBox(size);
8250
+ const formatTag = iterator.getUint16Le();
8251
+ const numberOfChannels = iterator.getUint16Le();
8252
+ const samplesPerSec = iterator.getUint32Le();
8253
+ const avgBytesPerSec = iterator.getUint32Le();
8254
+ const blockAlign = iterator.getUint16Le();
8255
+ const bitsPerSample = iterator.getUint16Le();
8256
+ const cbSize = iterator.getUint16Le();
8257
+ box.expectNoMoreBytes();
8258
+ return {
8259
+ type: "strf-box-audio",
8260
+ avgBytesPerSecond: avgBytesPerSec,
8261
+ bitsPerSample,
8262
+ blockAlign,
8263
+ cbSize,
8264
+ formatTag,
8265
+ numberOfChannels,
8266
+ sampleRate: samplesPerSec
8267
+ };
8268
+ };
8269
+ var parseStrfVideo = ({
8270
+ iterator,
8271
+ size
8272
+ }) => {
8273
+ const box = iterator.startBox(size);
8274
+ const biSize = iterator.getUint32Le();
8275
+ const width = iterator.getInt32Le();
8276
+ const height = iterator.getInt32Le();
8277
+ const planes = iterator.getUint16Le();
8278
+ const bitCount = iterator.getUint16Le();
8279
+ const compression = iterator.getByteString(4);
8280
+ const sizeImage = iterator.getUint32Le();
8281
+ const xPelsPerMeter = iterator.getInt32Le();
8282
+ const yPelsPerMeter = iterator.getInt32Le();
8283
+ const clrUsed = iterator.getUint32Le();
8284
+ const clrImportant = iterator.getUint32Le();
8285
+ box.expectNoMoreBytes();
8286
+ return {
8287
+ type: "strf-box-video",
8288
+ biSize,
8289
+ bitCount,
8290
+ clrImportant,
8291
+ clrUsed,
8292
+ compression,
8293
+ height,
8294
+ planes,
8295
+ sizeImage,
8296
+ width,
8297
+ xPelsPerMeter,
8298
+ yPelsPerMeter
8299
+ };
8300
+ };
8301
+ var parseStrf = ({
8302
+ iterator,
8303
+ size,
8304
+ boxes
8305
+ }) => {
8306
+ const strh = boxes.find((b) => b.type === "strh-box");
8307
+ if (!strh) {
8308
+ throw new Error("strh box not found");
8309
+ }
8310
+ if (strh.fccType === "vids") {
8311
+ return parseStrfVideo({ iterator, size });
8312
+ }
8313
+ if (strh.fccType === "auds") {
8314
+ return parseStrfAudio({ iterator, size });
8315
+ }
8316
+ throw new Error(`Unsupported fccType: ${strh.fccType}`);
8317
+ };
8318
+
8319
+ // src/boxes/riff/parse-strh.ts
8320
+ var parseStrh = ({
8321
+ iterator,
8322
+ size
8323
+ }) => {
8324
+ const box = iterator.startBox(size);
8325
+ const fccType = iterator.getByteString(4);
8326
+ if (fccType !== "vids" && fccType !== "auds") {
8327
+ throw new Error("Expected AVI handler to be vids / auds");
8328
+ }
8329
+ const handler = fccType === "vids" ? iterator.getByteString(4) : iterator.getUint32Le();
8330
+ if (typeof handler === "string" && handler !== "H264") {
8331
+ throw new Error(`Only H264 is supported as a stream type in .avi, got ${handler}`);
8332
+ }
8333
+ if (fccType === "auds" && handler !== 1) {
8334
+ throw new Error(`Only "1" is supported as a stream type in .avi, got ${handler}`);
8335
+ }
8336
+ const flags = iterator.getUint32Le();
8337
+ const priority = iterator.getUint16Le();
8338
+ const language2 = iterator.getUint16Le();
8339
+ const initialFrames = iterator.getUint32Le();
8340
+ const scale = iterator.getUint32Le();
8341
+ const rate = iterator.getUint32Le();
8342
+ const start = iterator.getUint32Le();
8343
+ const length = iterator.getUint32Le();
8344
+ const suggestedBufferSize = iterator.getUint32Le();
8345
+ const quality = iterator.getUint32Le();
8346
+ const sampleSize = iterator.getUint32Le();
8347
+ box.discardRest();
8348
+ return {
8349
+ type: "strh-box",
8350
+ fccType,
8351
+ handler,
8352
+ flags,
8353
+ priority,
8354
+ initialFrames,
8355
+ length,
8356
+ quality,
8357
+ rate,
8358
+ sampleSize,
8359
+ scale,
8360
+ start,
8361
+ suggestedBufferSize,
8362
+ language: language2
8363
+ };
8364
+ };
8365
+
8366
+ // src/boxes/riff/parse-riff-box.ts
8367
+ var parseRiffBox = ({
8368
+ iterator,
8369
+ size,
8370
+ id,
8371
+ boxes,
8372
+ options
8373
+ }) => {
8374
+ if (id === "fmt") {
8375
+ return Promise.resolve(parseFmtBox({ iterator, boxes, size }));
8376
+ }
8377
+ if (id === "LIST") {
8378
+ return parseListBox({ iterator, size, options });
8379
+ }
8380
+ if (id === "avih") {
8381
+ return Promise.resolve(parseAvih({ iterator, size }));
8382
+ }
8383
+ if (id === "strh") {
8384
+ return Promise.resolve(parseStrh({ iterator, size }));
8385
+ }
8386
+ if (id === "strf") {
8387
+ return Promise.resolve(parseStrf({ iterator, size, boxes }));
8388
+ }
8389
+ iterator.discard(size);
8390
+ const box = {
8391
+ type: "riff-box",
8392
+ size,
8393
+ id
8394
+ };
8395
+ return Promise.resolve(box);
8396
+ };
8397
+
8398
+ // src/boxes/riff/expect-riff-box.ts
8399
+ var expectRiffBox = async ({
8400
+ iterator,
8401
+ options,
8402
+ structure
8403
+ }) => {
8404
+ if (iterator.bytesRemaining() < 16) {
8405
+ return {
8406
+ type: "incomplete",
8407
+ continueParsing() {
8408
+ return expectRiffBox({ structure, iterator, options });
8409
+ }
8410
+ };
8411
+ }
8412
+ const ckId = iterator.getByteString(4);
8413
+ const ckSize = iterator.getUint32Le();
8414
+ if (isMoviAtom(iterator, ckId)) {
8415
+ iterator.discard(4);
8416
+ return parseMovi({
8417
+ iterator,
8418
+ maxOffset: ckSize + iterator.counter.getOffset() - 4,
8419
+ options,
8420
+ structure
8421
+ });
8422
+ }
8423
+ if (iterator.bytesRemaining() < ckSize) {
8424
+ iterator.counter.decrement(8);
8425
+ return {
8426
+ type: "incomplete",
8427
+ continueParsing: () => {
8428
+ return expectRiffBox({ structure, iterator, options });
8429
+ }
8430
+ };
8431
+ }
8432
+ return {
8433
+ type: "complete",
8434
+ box: await parseRiffBox({
8435
+ id: ckId,
8436
+ iterator,
8437
+ size: ckSize,
8438
+ boxes: structure.boxes,
8439
+ options
8440
+ })
8441
+ };
8442
+ };
8443
+
8444
+ // src/boxes/riff/parse-box.ts
8445
+ var continueAfterRiffBoxResult = ({
8446
+ result,
8447
+ structure,
8448
+ iterator,
8449
+ maxOffset,
8450
+ options
8451
+ }) => {
8452
+ if (result.type === "incomplete") {
8453
+ return Promise.resolve({
8454
+ status: "incomplete",
8455
+ async continueParsing() {
8456
+ return Promise.resolve(continueAfterRiffBoxResult({
8457
+ result: await result.continueParsing(),
8458
+ structure,
8459
+ iterator,
8460
+ maxOffset,
8461
+ options
8462
+ }));
8463
+ },
8464
+ segments: structure,
8465
+ skipTo: null
8466
+ });
8467
+ }
8468
+ if (result.type === "complete") {
8469
+ if (result.box) {
8470
+ structure.boxes.push(result.box);
8471
+ }
8472
+ }
8473
+ return parseRiffBody({ iterator, maxOffset, options, structure });
8474
+ };
8475
+ var parseRiffBody = async ({
8476
+ iterator,
8477
+ structure,
8478
+ maxOffset,
8479
+ options
8480
+ }) => {
8481
+ while (iterator.bytesRemaining() > 0 && iterator.counter.getOffset() < maxOffset) {
8482
+ const result = await expectRiffBox({
8483
+ iterator,
8484
+ options,
8485
+ structure
8486
+ });
8487
+ if (result.type === "incomplete") {
8488
+ return {
8489
+ status: "incomplete",
8490
+ async continueParsing() {
8491
+ return Promise.resolve(continueAfterRiffBoxResult({
8492
+ iterator,
8493
+ maxOffset,
8494
+ options,
8495
+ result: await result.continueParsing(),
8496
+ structure
8497
+ }));
8498
+ },
8499
+ segments: structure,
8500
+ skipTo: null
8501
+ };
8502
+ }
8503
+ if (result.box === null) {
8504
+ continue;
8505
+ }
8506
+ structure.boxes.push(result.box);
8507
+ if (result.box.type === "strf-box-video" || result.box.type === "strf-box-audio") {
8508
+ const strh = getStrhBox(structure.boxes);
8509
+ const strf = getStrfBox(structure.boxes);
8510
+ if (!strh || !strf) {
8511
+ throw new Error("strh or strf box missing");
8512
+ }
8513
+ if (strf.type === "strf-box-audio" && options.onAudioTrack) {
8514
+ const audioTrack = makeAviAudioTrack({
8515
+ index: options.nextTrackIndex,
8516
+ strf
8517
+ });
8518
+ await registerTrack({
8519
+ options,
8520
+ state: options.parserState,
8521
+ track: audioTrack
8522
+ });
8523
+ }
8524
+ if (options.onVideoTrack && strf.type === "strf-box-video") {
8525
+ const videoTrack = makeAviVideoTrack({
8526
+ strh,
8527
+ index: options.nextTrackIndex,
8528
+ strf
8529
+ });
8530
+ registerVideoTrackWhenProfileIsAvailable({
8531
+ options,
8532
+ state: options.parserState,
8533
+ track: videoTrack
8534
+ });
8535
+ }
8536
+ options.nextTrackIndex++;
8537
+ }
8538
+ }
8539
+ return {
8540
+ status: "done",
8541
+ segments: structure
8542
+ };
8543
+ };
8544
+ var parseRiff = ({
8545
+ iterator,
8546
+ options
8547
+ }) => {
8548
+ const structure = { type: "riff", boxes: [] };
8549
+ const riff = iterator.getByteString(4);
8550
+ if (riff !== "RIFF") {
8551
+ throw new Error("Not a RIFF file");
7359
8552
  }
8553
+ const size = iterator.getUint32Le();
8554
+ const fileType = iterator.getByteString(4);
8555
+ if (fileType !== "WAVE" && fileType !== "AVI") {
8556
+ throw new Error(`File type ${fileType} not supported`);
8557
+ }
8558
+ structure.boxes.push({ type: "riff-header", fileSize: size, fileType });
8559
+ return parseRiffBody({ iterator, structure, maxOffset: Infinity, options });
7360
8560
  };
7361
8561
 
7362
8562
  // src/boxes/webm/segments/block-simple-block-flags.ts
@@ -7904,33 +9104,33 @@ var expectChildren = async ({
7904
9104
  };
7905
9105
 
7906
9106
  // src/boxes/webm/parse-webm-header.ts
7907
- var continueAfterMatroskaResult = (result, children) => {
9107
+ var continueAfterMatroskaResult = (result, structure) => {
7908
9108
  if (result.status === "done") {
7909
9109
  return {
7910
9110
  status: "done",
7911
- segments: children
9111
+ segments: structure
7912
9112
  };
7913
9113
  }
7914
9114
  return {
7915
9115
  status: "incomplete",
7916
- segments: children,
9116
+ segments: structure,
7917
9117
  continueParsing: async () => {
7918
9118
  const newResult = await result.continueParsing();
7919
- return continueAfterMatroskaResult(newResult, children);
9119
+ return continueAfterMatroskaResult(newResult, structure);
7920
9120
  },
7921
9121
  skipTo: null
7922
9122
  };
7923
9123
  };
7924
9124
  var parseWebm = async (counter, parserContext) => {
7925
- const children = [];
9125
+ const structure = { type: "matroska", boxes: [] };
7926
9126
  const results = await expectChildren({
7927
9127
  iterator: counter,
7928
9128
  length: Infinity,
7929
- children,
9129
+ children: structure.boxes,
7930
9130
  parserContext,
7931
9131
  startOffset: counter.counter.getOffset()
7932
9132
  });
7933
- return continueAfterMatroskaResult(results, children);
9133
+ return continueAfterMatroskaResult(results, structure);
7934
9134
  };
7935
9135
 
7936
9136
  // src/parse-video.ts
@@ -7941,26 +9141,14 @@ var parseVideo = ({
7941
9141
  logLevel
7942
9142
  }) => {
7943
9143
  if (iterator.bytesRemaining() === 0) {
7944
- return Promise.resolve({
7945
- status: "incomplete",
7946
- segments: [],
7947
- continueParsing: () => {
7948
- return parseVideo({
7949
- iterator,
7950
- options,
7951
- signal,
7952
- logLevel
7953
- });
7954
- },
7955
- skipTo: null
7956
- });
9144
+ return Promise.reject(new Error("no bytes"));
7957
9145
  }
7958
9146
  if (iterator.isRiff()) {
7959
- throw new Error("AVI files are not yet supported");
9147
+ return Promise.resolve(parseRiff({ iterator, options }));
7960
9148
  }
7961
9149
  if (iterator.isIsoBaseMedia()) {
7962
9150
  Log.verbose(logLevel, "Detected ISO Base Media container");
7963
- return parseBoxes({
9151
+ return parseIsoBaseMediaBoxes({
7964
9152
  iterator,
7965
9153
  maxBytes: Infinity,
7966
9154
  allowIncompleteBoxes: true,
@@ -7973,7 +9161,7 @@ var parseVideo = ({
7973
9161
  }
7974
9162
  if (iterator.isWebm()) {
7975
9163
  Log.verbose(logLevel, "Detected Matroska container");
7976
- return Promise.resolve(parseWebm(iterator, options));
9164
+ return parseWebm(iterator, options);
7977
9165
  }
7978
9166
  if (iterator.isMp3()) {
7979
9167
  return Promise.reject(new Error("MP3 files are not yet supported"));
@@ -8038,8 +9226,23 @@ var makeParserState = ({
8038
9226
  }
8039
9227
  return timestampMap.get(byteOffset);
8040
9228
  };
9229
+ const samplesForTrack = {};
9230
+ const profileCallbacks = [];
9231
+ const registerOnAvcProfileCallback = (callback) => {
9232
+ profileCallbacks.push(callback);
9233
+ };
9234
+ let avcProfile = null;
9235
+ const onProfile = async (profile) => {
9236
+ avcProfile = profile;
9237
+ for (const callback of profileCallbacks) {
9238
+ await callback(profile);
9239
+ }
9240
+ profileCallbacks.length = 0;
9241
+ };
8041
9242
  return {
8042
9243
  onTrackEntrySegment,
9244
+ onProfile,
9245
+ registerOnAvcProfileCallback,
8043
9246
  getTrackInfoByNumber: (id) => trackEntries[id],
8044
9247
  registerVideoSampleCallback: async (id, callback) => {
8045
9248
  if (callback === null) {
@@ -8071,6 +9274,10 @@ var makeParserState = ({
8071
9274
  if (signal?.aborted) {
8072
9275
  throw new Error("Aborted");
8073
9276
  }
9277
+ if (typeof samplesForTrack[trackId] === "undefined") {
9278
+ samplesForTrack[trackId] = 0;
9279
+ }
9280
+ samplesForTrack[trackId]++;
8074
9281
  const callback = audioSampleCallbacks[trackId];
8075
9282
  if (callback) {
8076
9283
  await callback(audioSample);
@@ -8087,6 +9294,10 @@ var makeParserState = ({
8087
9294
  if (signal?.aborted) {
8088
9295
  throw new Error("Aborted");
8089
9296
  }
9297
+ if (typeof samplesForTrack[trackId] === "undefined") {
9298
+ samplesForTrack[trackId] = 0;
9299
+ }
9300
+ samplesForTrack[trackId]++;
8090
9301
  const callback = videoSampleCallbacks[trackId];
8091
9302
  if (callback) {
8092
9303
  await callback(videoSample);
@@ -8101,7 +9312,13 @@ var makeParserState = ({
8101
9312
  },
8102
9313
  getInternalStats: () => ({}),
8103
9314
  getTimescale,
8104
- setTimescale
9315
+ setTimescale,
9316
+ getSamplesForTrack: (trackId) => {
9317
+ return samplesForTrack[trackId] ?? 0;
9318
+ },
9319
+ getAvcProfile: () => {
9320
+ return avcProfile;
9321
+ }
8105
9322
  };
8106
9323
  };
8107
9324
 
@@ -8146,7 +9363,8 @@ var parseMedia = async ({
8146
9363
  onVideoTrack: onVideoTrack ?? null,
8147
9364
  parserState: state,
8148
9365
  nullifySamples: !(typeof process !== "undefined" && typeof process.env !== "undefined" && process.env.KEEP_SAMPLES === "true"),
8149
- supportsContentRange
9366
+ supportsContentRange,
9367
+ nextTrackIndex: 0
8150
9368
  };
8151
9369
  const hasAllInfo = () => {
8152
9370
  if (parseResult === null) {
@@ -8201,7 +9419,7 @@ var parseMedia = async ({
8201
9419
  });
8202
9420
  triggerInfoEmit();
8203
9421
  if (parseResult && parseResult.status === "incomplete") {
8204
- Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset(), getAvailableInfo(fields ?? {}, parseResult, state));
9422
+ Log.verbose(logLevel, "Continuing parsing of file, currently at position", iterator.counter.getOffset());
8205
9423
  parseResult = await parseResult.continueParsing();
8206
9424
  } else {
8207
9425
  parseResult = await parseVideo({
@@ -8242,13 +9460,18 @@ var parseMedia = async ({
8242
9460
  return returnValue;
8243
9461
  };
8244
9462
  // src/version.ts
8245
- var VERSION = "4.0.231";
9463
+ var VERSION = "4.0.233";
8246
9464
 
8247
9465
  // src/index.ts
8248
9466
  var MediaParserInternals = {
8249
9467
  createMatroskaMedia,
8250
9468
  createIsoBaseMedia,
8251
- Log
9469
+ createWav,
9470
+ Log,
9471
+ IoEventEmitter,
9472
+ makeProgressTracker,
9473
+ withResolvers,
9474
+ withResolversAndWaitForReturn
8252
9475
  };
8253
9476
  export {
8254
9477
  parseMedia,