@remotion/webcodecs 4.0.251 → 4.0.253

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 (68) hide show
  1. package/dist/audio-decoder.d.ts +3 -2
  2. package/dist/audio-decoder.js +11 -9
  3. package/dist/audio-encoder.d.ts +4 -3
  4. package/dist/audio-encoder.js +10 -9
  5. package/dist/auto-select-writer.d.ts +1 -1
  6. package/dist/can-copy-video-track.js +2 -1
  7. package/dist/choose-correct-hevc-profile.d.ts +5 -0
  8. package/dist/choose-correct-hevc-profile.js +42 -0
  9. package/dist/controller.d.ts +16 -0
  10. package/dist/controller.js +16 -0
  11. package/dist/convert-media.d.ts +6 -6
  12. package/dist/convert-media.js +53 -21
  13. package/dist/create/iso-base-media/codec-specific/create-codec-specific-data.d.ts +11 -0
  14. package/dist/create/iso-base-media/codec-specific/create-codec-specific-data.js +29 -11
  15. package/dist/create/iso-base-media/codec-specific/hvc1.d.ts +2 -0
  16. package/dist/create/iso-base-media/codec-specific/hvc1.js +48 -0
  17. package/dist/create/iso-base-media/create-iso-base-media.js +8 -4
  18. package/dist/create/iso-base-media/serialize-track.js +3 -1
  19. package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-hvcc.d.ts +1 -0
  20. package/dist/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-hvcc.js +16 -0
  21. package/dist/create/matroska/cluster.d.ts +1 -1
  22. package/dist/create/matroska/create-matroska-media.js +8 -4
  23. package/dist/create/matroska/matroska-trackentry.js +3 -0
  24. package/dist/create/matroska/matroska-utils.d.ts +1 -1
  25. package/dist/create/media-fn.d.ts +2 -3
  26. package/dist/create/wav/create-wav.js +8 -4
  27. package/dist/emitter.d.ts +20 -0
  28. package/dist/emitter.js +29 -0
  29. package/dist/esm/buffer.mjs +5 -22
  30. package/dist/esm/index.mjs +633 -159
  31. package/dist/esm/web-fs.mjs +4 -22
  32. package/dist/get-available-containers.d.ts +1 -2
  33. package/dist/get-available-containers.js +3 -3
  34. package/dist/get-available-video-codecs.d.ts +1 -2
  35. package/dist/get-available-video-codecs.js +3 -4
  36. package/dist/get-codec-string.d.ts +7 -0
  37. package/dist/get-codec-string.js +21 -0
  38. package/dist/hevc-levels.d.ts +13 -0
  39. package/dist/hevc-levels.js +233 -0
  40. package/dist/index.d.ts +1 -1
  41. package/dist/index.js +3 -1
  42. package/dist/io-manager/io-synchronizer.d.ts +4 -3
  43. package/dist/io-manager/io-synchronizer.js +19 -14
  44. package/dist/io-manager/make-timeout-promise.d.ts +6 -1
  45. package/dist/io-manager/make-timeout-promise.js +23 -5
  46. package/dist/on-audio-track.d.ts +2 -2
  47. package/dist/on-audio-track.js +13 -16
  48. package/dist/on-video-track.d.ts +2 -2
  49. package/dist/on-video-track.js +10 -14
  50. package/dist/select-container-creator.d.ts +1 -1
  51. package/dist/test/remux-serverside.test.js +2 -2
  52. package/dist/throttled-state-update.d.ts +1 -1
  53. package/dist/throttled-state-update.js +2 -2
  54. package/dist/video-decoder.d.ts +3 -2
  55. package/dist/video-decoder.js +10 -8
  56. package/dist/video-encoder-config.js +4 -6
  57. package/dist/video-encoder.d.ts +4 -3
  58. package/dist/video-encoder.js +13 -8
  59. package/dist/wav-audio-encoder.d.ts +1 -1
  60. package/dist/wav-audio-encoder.js +2 -2
  61. package/dist/webcodecs-controller.d.ts +16 -0
  62. package/dist/webcodecs-controller.js +16 -0
  63. package/dist/writers/buffer-implementation/writer.d.ts +1 -1
  64. package/dist/writers/buffer-implementation/writer.js +5 -4
  65. package/dist/writers/buffer.d.ts +1 -1
  66. package/dist/writers/web-fs.d.ts +1 -1
  67. package/dist/writers/web-fs.js +4 -4
  68. package/package.json +5 -5
@@ -125,11 +125,14 @@ var createContent = async ({ filename }) => {
125
125
  writPromise = writPromise.then(() => write(arr));
126
126
  return writPromise;
127
127
  },
128
- save: async () => {
128
+ finish: async () => {
129
+ await writPromise;
129
130
  try {
130
131
  await writable.close();
131
132
  } catch {
132
133
  }
134
+ },
135
+ async getBlob() {
133
136
  const newHandle = await directoryHandle.getFileHandle(actualFilename, {
134
137
  create: true
135
138
  });
@@ -141,9 +144,6 @@ var createContent = async ({ filename }) => {
141
144
  writPromise = writPromise.then(() => updateDataAt(position, data));
142
145
  return writPromise;
143
146
  },
144
- waitForFinish: async () => {
145
- await writPromise;
146
- },
147
147
  remove
148
148
  };
149
149
  return writer;
@@ -192,10 +192,14 @@ var createContent2 = ({ filename, mimeType }) => {
192
192
  writPromise = writPromise.then(() => write(arr));
193
193
  return writPromise;
194
194
  },
195
- save: () => {
195
+ finish: async () => {
196
+ await writPromise;
196
197
  if (removed) {
197
198
  return Promise.reject(new Error("Already called .remove() on the result"));
198
199
  }
200
+ return Promise.resolve();
201
+ },
202
+ getBlob() {
199
203
  const arr = new Uint8Array(buf);
200
204
  return Promise.resolve(new File([arr.slice()], filename, { type: mimeType }));
201
205
  },
@@ -207,9 +211,6 @@ var createContent2 = ({ filename, mimeType }) => {
207
211
  updateDataAt: (position, newData) => {
208
212
  writPromise = writPromise.then(() => updateDataAt(position, newData));
209
213
  return writPromise;
210
- },
211
- waitForFinish: async () => {
212
- await writPromise;
213
214
  }
214
215
  };
215
216
  return Promise.resolve(writer);
@@ -504,16 +505,38 @@ import { MediaParserInternals } from "@remotion/media-parser";
504
505
  var { Log } = MediaParserInternals;
505
506
 
506
507
  // src/io-manager/make-timeout-promise.ts
507
- var makeTimeoutPromise = (label, ms) => {
508
+ var makeTimeoutPromise = ({
509
+ label,
510
+ ms,
511
+ controller
512
+ }) => {
508
513
  const { promise, reject, resolve } = withResolvers();
509
- const timeout = setTimeout(() => {
510
- reject(new Error(`${label()} (timed out after ${ms}ms)`));
511
- }, ms);
514
+ let timeout = null;
515
+ const set = () => {
516
+ timeout = setTimeout(() => {
517
+ reject(new Error(`${label()} (timed out after ${ms}ms)`));
518
+ }, ms);
519
+ };
520
+ set();
521
+ const onPause = () => {
522
+ if (timeout) {
523
+ clearTimeout(timeout);
524
+ }
525
+ };
526
+ const onResume = () => {
527
+ set();
528
+ };
529
+ controller.addEventListener("pause", onPause);
530
+ controller.addEventListener("resume", onResume);
512
531
  return {
513
532
  timeoutPromise: promise,
514
533
  clear: () => {
515
- clearTimeout(timeout);
534
+ if (timeout) {
535
+ clearTimeout(timeout);
536
+ }
516
537
  resolve();
538
+ controller.removeEventListener("pause", onPause);
539
+ controller.removeEventListener("resume", onResume);
517
540
  }
518
541
  };
519
542
  };
@@ -589,19 +612,24 @@ var makeIoSynchronizer = ({
589
612
  unprocessed,
590
613
  unemitted,
591
614
  minimumProgress,
592
- signal
615
+ controller
593
616
  }) => {
594
- const { timeoutPromise, clear } = makeTimeoutPromise(() => [
595
- `Waited too long for ${label} to finish:`,
596
- `${getUnemittedItems()} unemitted items`,
597
- `${getUnprocessed()} unprocessed items: ${JSON.stringify(_unprocessed)}`,
598
- `smallest progress: ${progress.getSmallestProgress()}`,
599
- `inputs: ${JSON.stringify(inputs)}`,
600
- `last output: ${lastOutput}`,
601
- `wanted: ${unemitted} unemitted items, ${unprocessed} unprocessed items, minimum progress ${minimumProgress}`
602
- ].join(`
603
- `), 1e4);
604
- signal.addEventListener("abort", clear);
617
+ await controller._internals.checkForAbortAndPause();
618
+ const { timeoutPromise, clear } = makeTimeoutPromise({
619
+ label: () => [
620
+ `Waited too long for ${label} to finish:`,
621
+ `${getUnemittedItems()} unemitted items`,
622
+ `${getUnprocessed()} unprocessed items: ${JSON.stringify(_unprocessed)}`,
623
+ `smallest progress: ${progress.getSmallestProgress()}`,
624
+ `inputs: ${JSON.stringify(inputs)}`,
625
+ `last output: ${lastOutput}`,
626
+ `wanted: ${unemitted} unemitted items, ${unprocessed} unprocessed items, minimum progress ${minimumProgress}`
627
+ ].join(`
628
+ `),
629
+ ms: 1e4,
630
+ controller
631
+ });
632
+ controller._internals.signal.addEventListener("abort", clear);
605
633
  await Promise.race([
606
634
  timeoutPromise,
607
635
  Promise.all([
@@ -622,14 +650,14 @@ var makeIoSynchronizer = ({
622
650
  })()
623
651
  ])
624
652
  ]).finally(() => clear());
625
- signal.removeEventListener("abort", clear);
653
+ controller._internals.signal.removeEventListener("abort", clear);
626
654
  };
627
- const waitForFinish = async (signal) => {
655
+ const waitForFinish = async (controller) => {
628
656
  await waitFor({
629
657
  unprocessed: 0,
630
658
  unemitted: 0,
631
659
  minimumProgress: null,
632
- signal
660
+ controller
633
661
  });
634
662
  };
635
663
  const onProcessed = () => {
@@ -650,13 +678,13 @@ var makeIoSynchronizer = ({
650
678
  var createAudioDecoder = ({
651
679
  onFrame,
652
680
  onError,
653
- signal,
681
+ controller,
654
682
  config,
655
683
  logLevel,
656
684
  track,
657
685
  progressTracker
658
686
  }) => {
659
- if (signal.aborted) {
687
+ if (controller._internals.signal.aborted) {
660
688
  throw new Error("Not creating audio decoder, already aborted");
661
689
  }
662
690
  if (config.codec === "pcm-s16") {
@@ -674,15 +702,17 @@ var createAudioDecoder = ({
674
702
  const abortHandler = () => {
675
703
  frame.close();
676
704
  };
677
- signal.addEventListener("abort", abortHandler, { once: true });
705
+ controller._internals.signal.addEventListener("abort", abortHandler, {
706
+ once: true
707
+ });
678
708
  outputQueue = outputQueue.then(() => {
679
- if (signal.aborted) {
709
+ if (controller._internals.signal.aborted) {
680
710
  return;
681
711
  }
682
712
  return onFrame(frame);
683
713
  }).then(() => {
684
714
  ioSynchronizer.onProcessed();
685
- signal.removeEventListener("abort", abortHandler);
715
+ controller._internals.signal.removeEventListener("abort", abortHandler);
686
716
  return Promise.resolve();
687
717
  }).catch((err) => {
688
718
  frame.close();
@@ -694,7 +724,7 @@ var createAudioDecoder = ({
694
724
  }
695
725
  });
696
726
  const close = () => {
697
- signal.removeEventListener("abort", onAbort);
727
+ controller._internals.signal.removeEventListener("abort", onAbort);
698
728
  if (audioDecoder.state === "closed") {
699
729
  return;
700
730
  }
@@ -703,7 +733,7 @@ var createAudioDecoder = ({
703
733
  const onAbort = () => {
704
734
  close();
705
735
  };
706
- signal.addEventListener("abort", onAbort);
736
+ controller._internals.signal.addEventListener("abort", onAbort);
707
737
  audioDecoder.configure(config);
708
738
  const processSample = async (audioSample) => {
709
739
  if (audioDecoder.state === "closed") {
@@ -714,7 +744,7 @@ var createAudioDecoder = ({
714
744
  unemitted: 20,
715
745
  unprocessed: 20,
716
746
  minimumProgress: audioSample.timestamp - 1e7,
717
- signal
747
+ controller
718
748
  });
719
749
  const chunk = new EncodedAudioChunk(audioSample);
720
750
  audioDecoder.decode(chunk);
@@ -732,7 +762,7 @@ var createAudioDecoder = ({
732
762
  } catch {
733
763
  }
734
764
  await queue;
735
- await ioSynchronizer.waitForFinish(signal);
765
+ await ioSynchronizer.waitForFinish(controller);
736
766
  await outputQueue;
737
767
  },
738
768
  close,
@@ -741,17 +771,20 @@ var createAudioDecoder = ({
741
771
  }
742
772
  };
743
773
  };
774
+ // src/audio-encoder.ts
775
+ import { MediaParserAbortError } from "@remotion/media-parser";
776
+
744
777
  // src/wav-audio-encoder.ts
745
778
  var getWaveAudioEncoder = ({
746
779
  onChunk,
747
- signal
780
+ controller
748
781
  }) => {
749
782
  return {
750
783
  close: () => {
751
784
  return Promise.resolve();
752
785
  },
753
786
  encodeFrame: (audioData) => {
754
- if (signal.aborted) {
787
+ if (controller._internals.signal.aborted) {
755
788
  return Promise.resolve();
756
789
  }
757
790
  const chunk = {
@@ -773,17 +806,17 @@ var createAudioEncoder = ({
773
806
  onChunk,
774
807
  onError,
775
808
  codec,
776
- signal,
809
+ controller,
777
810
  config: audioEncoderConfig,
778
811
  logLevel,
779
812
  onNewAudioSampleRate,
780
813
  progressTracker
781
814
  }) => {
782
- if (signal.aborted) {
783
- throw new Error("Not creating audio encoder, already aborted");
815
+ if (controller._internals.signal.aborted) {
816
+ throw new MediaParserAbortError("Not creating audio encoder, already aborted");
784
817
  }
785
818
  if (codec === "wav") {
786
- return getWaveAudioEncoder({ onChunk, signal });
819
+ return getWaveAudioEncoder({ onChunk, controller });
787
820
  }
788
821
  const ioSynchronizer = makeIoSynchronizer({
789
822
  logLevel,
@@ -795,7 +828,7 @@ var createAudioEncoder = ({
795
828
  output: (chunk) => {
796
829
  ioSynchronizer.onOutput(chunk.timestamp);
797
830
  prom = prom.then(() => {
798
- if (signal.aborted) {
831
+ if (controller._internals.signal.aborted) {
799
832
  return;
800
833
  }
801
834
  return onChunk(chunk);
@@ -811,7 +844,7 @@ var createAudioEncoder = ({
811
844
  }
812
845
  });
813
846
  const close = () => {
814
- signal.removeEventListener("abort", onAbort);
847
+ controller._internals.signal.removeEventListener("abort", onAbort);
815
848
  if (encoder.state === "closed") {
816
849
  return;
817
850
  }
@@ -820,7 +853,7 @@ var createAudioEncoder = ({
820
853
  const onAbort = () => {
821
854
  close();
822
855
  };
823
- signal.addEventListener("abort", onAbort);
856
+ controller._internals.signal.addEventListener("abort", onAbort);
824
857
  if (codec !== "opus" && codec !== "aac") {
825
858
  throw new Error('Only `codec: "opus"` and `codec: "aac"` is supported currently');
826
859
  }
@@ -834,7 +867,7 @@ var createAudioEncoder = ({
834
867
  unemitted: 20,
835
868
  unprocessed: 20,
836
869
  minimumProgress: audioData.timestamp - 1e7,
837
- signal
870
+ controller
838
871
  });
839
872
  if (encoder.state === "closed") {
840
873
  return;
@@ -861,7 +894,7 @@ var createAudioEncoder = ({
861
894
  },
862
895
  waitForFinish: async () => {
863
896
  await encoder.flush();
864
- await ioSynchronizer.waitForFinish(signal);
897
+ await ioSynchronizer.waitForFinish(controller);
865
898
  await prom;
866
899
  },
867
900
  close,
@@ -912,7 +945,7 @@ var canCopyVideoTrack = ({
912
945
  return inputTrack.codecWithoutConfig === "vp8" || inputTrack.codecWithoutConfig === "vp9";
913
946
  }
914
947
  if (outputContainer === "mp4") {
915
- return inputTrack.codecWithoutConfig === "h264" && (inputContainer === "mp4" || inputContainer === "avi");
948
+ return (inputTrack.codecWithoutConfig === "h264" || inputTrack.codecWithoutConfig === "h265") && (inputContainer === "mp4" || inputContainer === "avi");
916
949
  }
917
950
  if (outputContainer === "wav") {
918
951
  return false;
@@ -1049,6 +1082,284 @@ var chooseCorrectAvc1Profile = ({
1049
1082
  return `avc1.6400${profile.hex}`;
1050
1083
  };
1051
1084
 
1085
+ // src/hevc-levels.ts
1086
+ var hevcLevels = [
1087
+ {
1088
+ level: "3.1",
1089
+ maxBitrateMainTier: 1e4,
1090
+ maxBitrateHighTier: null,
1091
+ maxResolutionsAndFrameRates: [
1092
+ {
1093
+ width: 720,
1094
+ height: 480,
1095
+ fps: 84.3
1096
+ },
1097
+ {
1098
+ width: 720,
1099
+ height: 576,
1100
+ fps: 75
1101
+ },
1102
+ {
1103
+ width: 960,
1104
+ height: 540,
1105
+ fps: 60
1106
+ },
1107
+ {
1108
+ width: 1280,
1109
+ height: 720,
1110
+ fps: 33.7
1111
+ }
1112
+ ]
1113
+ },
1114
+ {
1115
+ level: "4",
1116
+ maxBitrateMainTier: 12000,
1117
+ maxBitrateHighTier: 30000,
1118
+ maxResolutionsAndFrameRates: [
1119
+ {
1120
+ width: 1280,
1121
+ height: 720,
1122
+ fps: 68
1123
+ },
1124
+ {
1125
+ width: 1920,
1126
+ height: 1080,
1127
+ fps: 32
1128
+ },
1129
+ {
1130
+ width: 2048,
1131
+ height: 1080,
1132
+ fps: 30
1133
+ }
1134
+ ]
1135
+ },
1136
+ {
1137
+ level: "4.1",
1138
+ maxBitrateMainTier: 20000,
1139
+ maxBitrateHighTier: 50000,
1140
+ maxResolutionsAndFrameRates: [
1141
+ {
1142
+ width: 1280,
1143
+ height: 720,
1144
+ fps: 136
1145
+ },
1146
+ {
1147
+ width: 1920,
1148
+ height: 1080,
1149
+ fps: 64
1150
+ },
1151
+ {
1152
+ width: 2048,
1153
+ height: 1080,
1154
+ fps: 60
1155
+ }
1156
+ ]
1157
+ },
1158
+ {
1159
+ level: "5",
1160
+ maxBitrateMainTier: 25000,
1161
+ maxBitrateHighTier: 1e5,
1162
+ maxResolutionsAndFrameRates: [
1163
+ {
1164
+ width: 1920,
1165
+ height: 1080,
1166
+ fps: 128
1167
+ },
1168
+ {
1169
+ width: 2048,
1170
+ height: 1080,
1171
+ fps: 120
1172
+ },
1173
+ {
1174
+ width: 3840,
1175
+ height: 2160,
1176
+ fps: 32
1177
+ },
1178
+ {
1179
+ width: 4096,
1180
+ height: 2160,
1181
+ fps: 30
1182
+ }
1183
+ ]
1184
+ },
1185
+ {
1186
+ level: "5.1",
1187
+ maxBitrateMainTier: 40000,
1188
+ maxBitrateHighTier: 160000,
1189
+ maxResolutionsAndFrameRates: [
1190
+ {
1191
+ width: 1920,
1192
+ height: 1080,
1193
+ fps: 256
1194
+ },
1195
+ {
1196
+ width: 2048,
1197
+ height: 1080,
1198
+ fps: 240
1199
+ },
1200
+ {
1201
+ width: 3840,
1202
+ height: 2160,
1203
+ fps: 64
1204
+ },
1205
+ {
1206
+ width: 4096,
1207
+ height: 2160,
1208
+ fps: 60
1209
+ }
1210
+ ]
1211
+ },
1212
+ {
1213
+ level: "5.2",
1214
+ maxBitrateMainTier: 60000,
1215
+ maxBitrateHighTier: 240000,
1216
+ maxResolutionsAndFrameRates: [
1217
+ {
1218
+ width: 2048,
1219
+ height: 1080,
1220
+ fps: 300
1221
+ },
1222
+ {
1223
+ width: 3840,
1224
+ height: 2160,
1225
+ fps: 128
1226
+ },
1227
+ {
1228
+ width: 4096,
1229
+ height: 2160,
1230
+ fps: 120
1231
+ }
1232
+ ]
1233
+ },
1234
+ {
1235
+ level: "6",
1236
+ maxBitrateMainTier: 60000,
1237
+ maxBitrateHighTier: 240000,
1238
+ maxResolutionsAndFrameRates: [
1239
+ {
1240
+ width: 3840,
1241
+ height: 2160,
1242
+ fps: 128
1243
+ },
1244
+ {
1245
+ width: 4096,
1246
+ height: 2160,
1247
+ fps: 120
1248
+ },
1249
+ {
1250
+ width: 7680,
1251
+ height: 4320,
1252
+ fps: 32
1253
+ },
1254
+ {
1255
+ width: 8192,
1256
+ height: 4320,
1257
+ fps: 30
1258
+ }
1259
+ ]
1260
+ },
1261
+ {
1262
+ level: "6.1",
1263
+ maxBitrateMainTier: 120000,
1264
+ maxBitrateHighTier: 480000,
1265
+ maxResolutionsAndFrameRates: [
1266
+ {
1267
+ width: 3840,
1268
+ height: 2160,
1269
+ fps: 256
1270
+ },
1271
+ {
1272
+ width: 4096,
1273
+ height: 2160,
1274
+ fps: 240
1275
+ },
1276
+ {
1277
+ width: 7680,
1278
+ height: 4320,
1279
+ fps: 64
1280
+ },
1281
+ {
1282
+ width: 8192,
1283
+ height: 4320,
1284
+ fps: 60
1285
+ }
1286
+ ]
1287
+ },
1288
+ {
1289
+ level: "6.2",
1290
+ maxBitrateMainTier: 240000,
1291
+ maxBitrateHighTier: 800000,
1292
+ maxResolutionsAndFrameRates: [
1293
+ {
1294
+ width: 3840,
1295
+ height: 2160,
1296
+ fps: 512
1297
+ },
1298
+ {
1299
+ width: 4096,
1300
+ height: 2160,
1301
+ fps: 480
1302
+ },
1303
+ {
1304
+ width: 7680,
1305
+ height: 4320,
1306
+ fps: 128
1307
+ },
1308
+ {
1309
+ width: 8192,
1310
+ height: 4320,
1311
+ fps: 120
1312
+ }
1313
+ ]
1314
+ }
1315
+ ];
1316
+
1317
+ // src/choose-correct-hevc-profile.ts
1318
+ var chooseCorrectHevcProfile = ({
1319
+ width,
1320
+ height,
1321
+ fps
1322
+ }) => {
1323
+ const profile = hevcLevels.find((p) => {
1324
+ return p.maxResolutionsAndFrameRates.some((max) => {
1325
+ if (width > max.width) {
1326
+ return false;
1327
+ }
1328
+ if (height > max.height) {
1329
+ return false;
1330
+ }
1331
+ const fallbackFps = fps ?? 60;
1332
+ return fallbackFps <= max.fps;
1333
+ });
1334
+ });
1335
+ if (!profile) {
1336
+ throw new Error(`No suitable HEVC profile found for ${width}x${height}@${fps}fps`);
1337
+ }
1338
+ return `hvc1.${1}.${0}.${"L"}${Math.round(Number(profile.level) * 30)}.${"b0"}`;
1339
+ };
1340
+
1341
+ // src/get-codec-string.ts
1342
+ var getCodecStringForEncoder = ({
1343
+ codec,
1344
+ fps,
1345
+ height,
1346
+ width
1347
+ }) => {
1348
+ if (codec === "h264") {
1349
+ return chooseCorrectAvc1Profile({ fps, height, width });
1350
+ }
1351
+ if (codec === "h265") {
1352
+ return chooseCorrectHevcProfile({ fps, height, width });
1353
+ }
1354
+ if (codec === "vp8") {
1355
+ return "vp8";
1356
+ }
1357
+ if (codec === "vp9") {
1358
+ return "vp09.00.10.08";
1359
+ }
1360
+ throw new Error(`Unknown codec: ${codec}`);
1361
+ };
1362
+
1052
1363
  // src/video-encoder-config.ts
1053
1364
  var getVideoEncoderConfig = async ({
1054
1365
  codec,
@@ -1060,10 +1371,12 @@ var getVideoEncoderConfig = async ({
1060
1371
  return null;
1061
1372
  }
1062
1373
  const config = {
1063
- codec: codec === "h264" ? chooseCorrectAvc1Profile({ fps, height, width }) : codec === "vp9" ? "vp09.00.10.08" : codec,
1374
+ codec: getCodecStringForEncoder({ codec, fps, height, width }),
1064
1375
  height,
1065
1376
  width,
1066
- bitrate: isSafari() ? 3000000 : undefined
1377
+ bitrate: isSafari() ? 3000000 : undefined,
1378
+ bitrateMode: codec === "vp9" && !isSafari() ? "quantizer" : undefined,
1379
+ framerate: fps ?? undefined
1067
1380
  };
1068
1381
  const hardware = {
1069
1382
  ...config,
@@ -1106,7 +1419,11 @@ var canReencodeVideoTrack = async ({
1106
1419
  return Boolean(videoDecoderConfig && videoEncoderConfig);
1107
1420
  };
1108
1421
  // src/convert-media.ts
1109
- import { parseMedia } from "@remotion/media-parser";
1422
+ import {
1423
+ MediaParserAbortError as MediaParserAbortError3,
1424
+ MediaParserInternals as MediaParserInternals9
1425
+ } from "@remotion/media-parser";
1426
+ import { fetchReader } from "@remotion/media-parser/fetch";
1110
1427
 
1111
1428
  // src/auto-select-writer.ts
1112
1429
  var autoSelectWriter = async (writer, logLevel) => {
@@ -1211,9 +1528,6 @@ var makeProgressTracker = () => {
1211
1528
  };
1212
1529
  };
1213
1530
 
1214
- // src/error-cause.ts
1215
- var error_cause_default = Error;
1216
-
1217
1531
  // src/generate-output-filename.ts
1218
1532
  var generateOutputFilename = (source, container) => {
1219
1533
  const filename = typeof source === "string" ? source : source instanceof File ? source.name : "converted";
@@ -1222,6 +1536,29 @@ var generateOutputFilename = (source, container) => {
1222
1536
  return `${withoutExtension}.${container}`;
1223
1537
  };
1224
1538
 
1539
+ // src/get-available-containers.ts
1540
+ var availableContainers = ["webm", "mp4", "wav"];
1541
+ var getAvailableContainers = () => {
1542
+ return availableContainers;
1543
+ };
1544
+
1545
+ // src/get-available-video-codecs.ts
1546
+ var availableVideoCodecs = ["vp8", "vp9", "h264", "h265"];
1547
+ var getAvailableVideoCodecs = ({
1548
+ container
1549
+ }) => {
1550
+ if (container === "mp4") {
1551
+ return ["h264", "h265"];
1552
+ }
1553
+ if (container === "webm") {
1554
+ return ["vp8", "vp9"];
1555
+ }
1556
+ if (container === "wav") {
1557
+ return [];
1558
+ }
1559
+ throw new Error(`Unsupported container: ${container}`);
1560
+ };
1561
+
1225
1562
  // src/on-audio-track.ts
1226
1563
  import {
1227
1564
  MediaParserInternals as MediaParserInternals3
@@ -1325,7 +1662,7 @@ var makeAudioTrackHandler = ({
1325
1662
  return null;
1326
1663
  }
1327
1664
  if (audioOperation.type === "fail") {
1328
- throw new error_cause_default(`Audio track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
1665
+ throw new Error(`Audio track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
1329
1666
  }
1330
1667
  if (audioOperation.type === "copy") {
1331
1668
  const addedTrack = await state.addTrack({
@@ -1365,17 +1702,18 @@ var makeAudioTrackHandler = ({
1365
1702
  description: track.description
1366
1703
  });
1367
1704
  if (!audioEncoderConfig) {
1368
- abortConversion(new error_cause_default(`Could not configure audio encoder of track ${track.trackId}`));
1705
+ abortConversion(new Error(`Could not configure audio encoder of track ${track.trackId}`));
1369
1706
  return null;
1370
1707
  }
1371
1708
  if (!audioDecoderConfig) {
1372
- abortConversion(new error_cause_default(`Could not configure audio decoder of track ${track.trackId}`));
1709
+ abortConversion(new Error(`Could not configure audio decoder of track ${track.trackId}`));
1373
1710
  return null;
1374
1711
  }
1375
1712
  const codecPrivate = audioOperation.audioCodec === "aac" ? MediaParserInternals3.createAacCodecPrivate({
1376
1713
  audioObjectType: 2,
1377
1714
  sampleRate: track.sampleRate,
1378
- channelConfiguration: track.numberOfChannels
1715
+ channelConfiguration: track.numberOfChannels,
1716
+ codecPrivate: null
1379
1717
  }) : null;
1380
1718
  const { trackNumber } = await state.addTrack({
1381
1719
  type: "audio",
@@ -1404,12 +1742,12 @@ var makeAudioTrackHandler = ({
1404
1742
  });
1405
1743
  },
1406
1744
  onError: (err) => {
1407
- abortConversion(new error_cause_default(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
1745
+ abortConversion(new Error(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
1408
1746
  cause: err
1409
1747
  }));
1410
1748
  },
1411
1749
  codec: audioOperation.audioCodec,
1412
- signal: controller.signal,
1750
+ controller,
1413
1751
  config: audioEncoderConfig,
1414
1752
  logLevel,
1415
1753
  progressTracker
@@ -1419,19 +1757,19 @@ var makeAudioTrackHandler = ({
1419
1757
  const newAudioData = onAudioData ? await onAudioData?.({ audioData, track }) : audioData;
1420
1758
  if (newAudioData !== audioData) {
1421
1759
  if (newAudioData.duration !== audioData.duration) {
1422
- throw new error_cause_default(`onAudioData returned a different duration than the input audio data. Original duration: ${audioData.duration}, new duration: ${newAudioData.duration}`);
1760
+ throw new Error(`onAudioData returned a different duration than the input audio data. Original duration: ${audioData.duration}, new duration: ${newAudioData.duration}`);
1423
1761
  }
1424
1762
  if (newAudioData.numberOfChannels !== audioData.numberOfChannels) {
1425
- throw new error_cause_default(`onAudioData returned a different number of channels than the input audio data. Original channels: ${audioData.numberOfChannels}, new channels: ${newAudioData.numberOfChannels}`);
1763
+ throw new Error(`onAudioData returned a different number of channels than the input audio data. Original channels: ${audioData.numberOfChannels}, new channels: ${newAudioData.numberOfChannels}`);
1426
1764
  }
1427
1765
  if (newAudioData.sampleRate !== audioData.sampleRate) {
1428
- throw new error_cause_default(`onAudioData returned a different sample rate than the input audio data. Original sample rate: ${audioData.sampleRate}, new sample rate: ${newAudioData.sampleRate}`);
1766
+ throw new Error(`onAudioData returned a different sample rate than the input audio data. Original sample rate: ${audioData.sampleRate}, new sample rate: ${newAudioData.sampleRate}`);
1429
1767
  }
1430
1768
  if (newAudioData.format !== audioData.format) {
1431
- throw new error_cause_default(`onAudioData returned a different format than the input audio data. Original format: ${audioData.format}, new format: ${newAudioData.format}`);
1769
+ throw new Error(`onAudioData returned a different format than the input audio data. Original format: ${audioData.format}, new format: ${newAudioData.format}`);
1432
1770
  }
1433
1771
  if (newAudioData.timestamp !== audioData.timestamp) {
1434
- throw new error_cause_default(`onAudioData returned a different timestamp than the input audio data. Original timestamp: ${audioData.timestamp}, new timestamp: ${newAudioData.timestamp}`);
1772
+ throw new Error(`onAudioData returned a different timestamp than the input audio data. Original timestamp: ${audioData.timestamp}, new timestamp: ${newAudioData.timestamp}`);
1435
1773
  }
1436
1774
  audioData.close();
1437
1775
  }
@@ -1445,11 +1783,11 @@ var makeAudioTrackHandler = ({
1445
1783
  newAudioData.close();
1446
1784
  },
1447
1785
  onError(error) {
1448
- abortConversion(new error_cause_default(`Audio decoder of track ${track.trackId} failed. Config: ${JSON.stringify(audioDecoderConfig)} (see .cause of this error)`, {
1786
+ abortConversion(new Error(`Audio decoder of track ${track.trackId} failed. Config: ${JSON.stringify(audioDecoderConfig)} (see .cause of this error)`, {
1449
1787
  cause: error
1450
1788
  }));
1451
1789
  },
1452
- signal: controller.signal,
1790
+ controller,
1453
1791
  config: audioDecoderConfig,
1454
1792
  logLevel,
1455
1793
  track,
@@ -1610,7 +1948,7 @@ var onFrame = async ({
1610
1948
  var createVideoDecoder = ({
1611
1949
  onFrame: onFrame2,
1612
1950
  onError,
1613
- signal,
1951
+ controller,
1614
1952
  config,
1615
1953
  logLevel,
1616
1954
  progress
@@ -1627,15 +1965,17 @@ var createVideoDecoder = ({
1627
1965
  const abortHandler = () => {
1628
1966
  inputFrame.close();
1629
1967
  };
1630
- signal.addEventListener("abort", abortHandler, { once: true });
1968
+ controller._internals.signal.addEventListener("abort", abortHandler, {
1969
+ once: true
1970
+ });
1631
1971
  outputQueue = outputQueue.then(() => {
1632
- if (signal.aborted) {
1972
+ if (controller._internals.signal.aborted) {
1633
1973
  return;
1634
1974
  }
1635
1975
  return onFrame2(inputFrame);
1636
1976
  }).then(() => {
1637
1977
  ioSynchronizer.onProcessed();
1638
- signal.removeEventListener("abort", abortHandler);
1978
+ controller._internals.signal.removeEventListener("abort", abortHandler);
1639
1979
  return Promise.resolve();
1640
1980
  }).catch((err) => {
1641
1981
  inputFrame.close();
@@ -1647,7 +1987,7 @@ var createVideoDecoder = ({
1647
1987
  }
1648
1988
  });
1649
1989
  const close = () => {
1650
- signal.removeEventListener("abort", onAbort);
1990
+ controller._internals.signal.removeEventListener("abort", onAbort);
1651
1991
  if (videoDecoder.state === "closed") {
1652
1992
  return;
1653
1993
  }
@@ -1656,7 +1996,7 @@ var createVideoDecoder = ({
1656
1996
  const onAbort = () => {
1657
1997
  close();
1658
1998
  };
1659
- signal.addEventListener("abort", onAbort);
1999
+ controller._internals.signal.addEventListener("abort", onAbort);
1660
2000
  videoDecoder.configure(config);
1661
2001
  const processSample = async (sample) => {
1662
2002
  if (videoDecoder.state === "closed") {
@@ -1670,7 +2010,7 @@ var createVideoDecoder = ({
1670
2010
  unemitted: 20,
1671
2011
  unprocessed: 2,
1672
2012
  minimumProgress: sample.timestamp - 1e7,
1673
- signal
2013
+ controller
1674
2014
  });
1675
2015
  if (sample.type === "key") {
1676
2016
  await videoDecoder.flush();
@@ -1687,7 +2027,7 @@ var createVideoDecoder = ({
1687
2027
  waitForFinish: async () => {
1688
2028
  await videoDecoder.flush();
1689
2029
  Log.verbose(logLevel, "Flushed video decoder");
1690
- await ioSynchronizer.waitForFinish(signal);
2030
+ await ioSynchronizer.waitForFinish(controller);
1691
2031
  Log.verbose(logLevel, "IO synchro finished");
1692
2032
  await outputQueue;
1693
2033
  Log.verbose(logLevel, "Output queue finished");
@@ -1702,17 +2042,18 @@ var createVideoDecoder = ({
1702
2042
  };
1703
2043
 
1704
2044
  // src/video-encoder.ts
2045
+ import { MediaParserAbortError as MediaParserAbortError2 } from "@remotion/media-parser";
1705
2046
  var createVideoEncoder = ({
1706
2047
  onChunk,
1707
2048
  onError,
1708
- signal,
2049
+ controller,
1709
2050
  config,
1710
2051
  logLevel,
1711
2052
  outputCodec,
1712
2053
  progress
1713
2054
  }) => {
1714
- if (signal.aborted) {
1715
- throw new Error("Not creating video encoder, already aborted");
2055
+ if (controller._internals.signal.aborted) {
2056
+ throw new MediaParserAbortError2("Not creating video encoder, already aborted");
1716
2057
  }
1717
2058
  const ioSynchronizer = makeIoSynchronizer({
1718
2059
  logLevel,
@@ -1728,7 +2069,7 @@ var createVideoEncoder = ({
1728
2069
  const timestamp = chunk.timestamp + (chunk.duration ?? 0);
1729
2070
  ioSynchronizer.onOutput(timestamp);
1730
2071
  outputQueue = outputQueue.then(() => {
1731
- if (signal.aborted) {
2072
+ if (controller._internals.signal.aborted) {
1732
2073
  return;
1733
2074
  }
1734
2075
  return onChunk(chunk, metadata ?? null);
@@ -1741,7 +2082,7 @@ var createVideoEncoder = ({
1741
2082
  }
1742
2083
  });
1743
2084
  const close = () => {
1744
- signal.removeEventListener("abort", onAbort);
2085
+ controller._internals.signal.removeEventListener("abort", onAbort);
1745
2086
  if (encoder.state === "closed") {
1746
2087
  return;
1747
2088
  }
@@ -1750,7 +2091,7 @@ var createVideoEncoder = ({
1750
2091
  const onAbort = () => {
1751
2092
  close();
1752
2093
  };
1753
- signal.addEventListener("abort", onAbort);
2094
+ controller._internals.signal.addEventListener("abort", onAbort);
1754
2095
  Log.verbose(logLevel, "Configuring video encoder", config);
1755
2096
  encoder.configure(config);
1756
2097
  let framesProcessed = 0;
@@ -1763,14 +2104,17 @@ var createVideoEncoder = ({
1763
2104
  unemitted: 10,
1764
2105
  unprocessed: 10,
1765
2106
  minimumProgress: frame.timestamp - 1e7,
1766
- signal
2107
+ controller
1767
2108
  });
1768
2109
  if (encoder.state === "closed") {
1769
2110
  return;
1770
2111
  }
1771
2112
  const keyFrame = framesProcessed % 40 === 0;
1772
2113
  encoder.encode(convertToCorrectVideoFrame({ videoFrame: frame, outputCodec }), {
1773
- keyFrame
2114
+ keyFrame,
2115
+ vp9: {
2116
+ quantizer: 36
2117
+ }
1774
2118
  });
1775
2119
  ioSynchronizer.inputItem(frame.timestamp, keyFrame);
1776
2120
  framesProcessed++;
@@ -1784,7 +2128,7 @@ var createVideoEncoder = ({
1784
2128
  waitForFinish: async () => {
1785
2129
  await encoder.flush();
1786
2130
  await outputQueue;
1787
- await ioSynchronizer.waitForFinish(signal);
2131
+ await ioSynchronizer.waitForFinish(controller);
1788
2132
  },
1789
2133
  close,
1790
2134
  flush: async () => {
@@ -1808,8 +2152,8 @@ var makeVideoTrackHandler = ({
1808
2152
  progress,
1809
2153
  resizeOperation
1810
2154
  }) => async ({ track, container: inputContainer }) => {
1811
- if (controller.signal.aborted) {
1812
- throw new error_cause_default("Aborted");
2155
+ if (controller._internals.signal.aborted) {
2156
+ throw new Error("Aborted");
1813
2157
  }
1814
2158
  const canCopyTrack = canCopyVideoTrack({
1815
2159
  inputContainer,
@@ -1832,7 +2176,7 @@ var makeVideoTrackHandler = ({
1832
2176
  return null;
1833
2177
  }
1834
2178
  if (videoOperation.type === "fail") {
1835
- throw new error_cause_default(`Video track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this video track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
2179
+ throw new Error(`Video track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this video track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
1836
2180
  }
1837
2181
  if (videoOperation.type === "copy") {
1838
2182
  Log.verbose(logLevel, `Copying video track with codec ${track.codec} and timescale ${track.timescale}`);
@@ -1861,7 +2205,7 @@ var makeVideoTrackHandler = ({
1861
2205
  };
1862
2206
  }
1863
2207
  if (videoOperation.type !== "reencode") {
1864
- throw new error_cause_default(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
2208
+ throw new Error(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
1865
2209
  }
1866
2210
  const rotation = (videoOperation.rotate ?? rotate) - track.rotation;
1867
2211
  const { height: newHeight, width: newWidth } = calculateNewDimensionsFromRotateAndScale({
@@ -1879,11 +2223,11 @@ var makeVideoTrackHandler = ({
1879
2223
  });
1880
2224
  const videoDecoderConfig = await getVideoDecoderConfigWithHardwareAcceleration(track);
1881
2225
  if (videoEncoderConfig === null) {
1882
- abortConversion(new error_cause_default(`Could not configure video encoder of track ${track.trackId}`));
2226
+ abortConversion(new Error(`Could not configure video encoder of track ${track.trackId}`));
1883
2227
  return null;
1884
2228
  }
1885
2229
  if (videoDecoderConfig === null) {
1886
- abortConversion(new error_cause_default(`Could not configure video decoder of track ${track.trackId}`));
2230
+ abortConversion(new Error(`Could not configure video decoder of track ${track.trackId}`));
1887
2231
  return null;
1888
2232
  }
1889
2233
  const { trackNumber } = await state.addTrack({
@@ -1912,11 +2256,11 @@ var makeVideoTrackHandler = ({
1912
2256
  });
1913
2257
  },
1914
2258
  onError: (err) => {
1915
- abortConversion(new error_cause_default(`Video encoder of track ${track.trackId} failed (see .cause of this error)`, {
2259
+ abortConversion(new Error(`Video encoder of track ${track.trackId} failed (see .cause of this error)`, {
1916
2260
  cause: err
1917
2261
  }));
1918
2262
  },
1919
- signal: controller.signal,
2263
+ controller,
1920
2264
  config: videoEncoderConfig,
1921
2265
  logLevel,
1922
2266
  outputCodec: videoOperation.videoCodec,
@@ -1936,11 +2280,11 @@ var makeVideoTrackHandler = ({
1936
2280
  });
1937
2281
  },
1938
2282
  onError: (err) => {
1939
- abortConversion(new error_cause_default(`Video decoder of track ${track.trackId} failed (see .cause of this error)`, {
2283
+ abortConversion(new Error(`Video decoder of track ${track.trackId} failed (see .cause of this error)`, {
1940
2284
  cause: err
1941
2285
  }));
1942
2286
  },
1943
- signal: controller.signal,
2287
+ controller,
1944
2288
  logLevel,
1945
2289
  progress
1946
2290
  });
@@ -2479,6 +2823,17 @@ var createAvccBox = (privateData) => {
2479
2823
  ]));
2480
2824
  };
2481
2825
 
2826
+ // src/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-hvcc.ts
2827
+ var createHvccBox = (privateData) => {
2828
+ if (!privateData) {
2829
+ throw new Error("privateData is required");
2830
+ }
2831
+ return addSize(combineUint8Arrays([
2832
+ stringsToUint8Array("hvcC"),
2833
+ privateData
2834
+ ]));
2835
+ };
2836
+
2482
2837
  // src/create/iso-base-media/trak/mdia/minf/stbl/stsd/create-pasp.ts
2483
2838
  var createPasp = (x, y) => {
2484
2839
  return addSize(combineUint8Arrays([
@@ -2522,6 +2877,40 @@ var createAvc1Data = ({
2522
2877
  ]));
2523
2878
  };
2524
2879
 
2880
+ // src/create/iso-base-media/codec-specific/hvc1.ts
2881
+ var createHvc1Data = ({
2882
+ compressorName,
2883
+ depth,
2884
+ height,
2885
+ horizontalResolution,
2886
+ hvccBox,
2887
+ pasp,
2888
+ verticalResolution,
2889
+ width
2890
+ }) => {
2891
+ return addSize(combineUint8Arrays([
2892
+ stringsToUint8Array("hvc1"),
2893
+ new Uint8Array([0, 0, 0, 0, 0, 0]),
2894
+ new Uint8Array([0, 1]),
2895
+ new Uint8Array([0, 0]),
2896
+ new Uint8Array([0, 0]),
2897
+ new Uint8Array([0, 0, 0, 0]),
2898
+ new Uint8Array([0, 0, 0, 0]),
2899
+ new Uint8Array([0, 0, 0, 0]),
2900
+ numberTo16BitUIntOrInt(width),
2901
+ numberTo16BitUIntOrInt(height),
2902
+ setFixedPointSignedOrUnsigned1616Number(horizontalResolution),
2903
+ setFixedPointSignedOrUnsigned1616Number(verticalResolution),
2904
+ new Uint8Array([0, 0, 0, 0]),
2905
+ numberTo16BitUIntOrInt(1),
2906
+ stringToPascalString(compressorName),
2907
+ numberTo16BitUIntOrInt(depth),
2908
+ numberTo16BitUIntOrInt(-1),
2909
+ hvccBox,
2910
+ pasp
2911
+ ]));
2912
+ };
2913
+
2525
2914
  // src/create/iso-base-media/codec-specific/mp4a.ts
2526
2915
  var createMp4a = ({
2527
2916
  sampleRate,
@@ -2574,17 +2963,33 @@ var createMp4a = ({
2574
2963
  // src/create/iso-base-media/codec-specific/create-codec-specific-data.ts
2575
2964
  var createCodecSpecificData = (track) => {
2576
2965
  if (track.type === "video") {
2577
- return createAvc1Data({
2578
- avccBox: createAvccBox(track.codecPrivate),
2579
- compressorName: "WebCodecs",
2580
- depth: 24,
2581
- horizontalResolution: 72,
2582
- verticalResolution: 72,
2583
- height: track.height,
2584
- width: track.width,
2585
- pasp: createPasp(1, 1),
2586
- type: "avc1-data"
2587
- });
2966
+ if (track.codec === "h264") {
2967
+ return createAvc1Data({
2968
+ avccBox: createAvccBox(track.codecPrivate),
2969
+ compressorName: "WebCodecs",
2970
+ depth: 24,
2971
+ horizontalResolution: 72,
2972
+ verticalResolution: 72,
2973
+ height: track.height,
2974
+ width: track.width,
2975
+ pasp: createPasp(1, 1),
2976
+ type: "avc1-data"
2977
+ });
2978
+ }
2979
+ if (track.codec === "h265") {
2980
+ return createHvc1Data({
2981
+ hvccBox: createHvccBox(track.codecPrivate),
2982
+ compressorName: "WebCodecs",
2983
+ depth: 24,
2984
+ horizontalResolution: 72,
2985
+ verticalResolution: 72,
2986
+ height: track.height,
2987
+ width: track.width,
2988
+ pasp: createPasp(1, 1),
2989
+ type: "hvc1-data"
2990
+ });
2991
+ }
2992
+ throw new Error("Unsupported codec specific data " + track.codec);
2588
2993
  }
2589
2994
  if (track.type === "audio") {
2590
2995
  return createMp4a({
@@ -3041,7 +3446,7 @@ var serializeTrack = ({
3041
3446
  samplePositions,
3042
3447
  timescale
3043
3448
  }) => {
3044
- if (track.codec !== "h264" && track.codec !== "aac") {
3449
+ if (track.codec !== "h264" && track.codec !== "h265" && track.codec !== "aac") {
3045
3450
  throw new Error("Currently only H.264 and AAC is supported");
3046
3451
  }
3047
3452
  return createTrak({
@@ -3150,7 +3555,11 @@ var createIsoBaseMedia = async ({
3150
3555
  majorBrand: "isom",
3151
3556
  minorBrand: 512
3152
3557
  });
3153
- const w = await writer.createContent({ filename, mimeType: "video/mp4" });
3558
+ const w = await writer.createContent({
3559
+ filename,
3560
+ mimeType: "video/mp4",
3561
+ logLevel
3562
+ });
3154
3563
  await w.write(header);
3155
3564
  let globalDurationInUnits = 0;
3156
3565
  const lowestTrackTimestamps = {};
@@ -3266,8 +3675,8 @@ var createIsoBaseMedia = async ({
3266
3675
  };
3267
3676
  const waitForFinishPromises = [];
3268
3677
  return {
3269
- save: () => {
3270
- return w.save();
3678
+ getBlob: () => {
3679
+ return w.getBlob();
3271
3680
  },
3272
3681
  remove: async () => {
3273
3682
  await w.remove();
@@ -3308,7 +3717,7 @@ var createIsoBaseMedia = async ({
3308
3717
  await updateMoov();
3309
3718
  await updateMdatSize();
3310
3719
  MediaParserInternals6.Log.verbose(logLevel, "All write operations done. Waiting for finish...");
3311
- await w.waitForFinish();
3720
+ await w.finish();
3312
3721
  }
3313
3722
  };
3314
3723
  };
@@ -3743,6 +4152,9 @@ var makeAudioCodecId = (codecId) => {
3743
4152
  if (codecId === "aac") {
3744
4153
  return "A_AAC";
3745
4154
  }
4155
+ if (codecId === "ac3") {
4156
+ return "A_AC3";
4157
+ }
3746
4158
  if (codecId === "mp3") {
3747
4159
  return "A_MPEG/L3";
3748
4160
  }
@@ -3943,7 +4355,11 @@ var createMatroskaMedia = async ({
3943
4355
  progressTracker
3944
4356
  }) => {
3945
4357
  const header = makeMatroskaHeader();
3946
- const w = await writer.createContent({ filename, mimeType: "video/webm" });
4358
+ const w = await writer.createContent({
4359
+ filename,
4360
+ mimeType: "video/webm",
4361
+ logLevel
4362
+ });
3947
4363
  await w.write(header.bytes);
3948
4364
  const matroskaInfo = makeMatroskaInfo({
3949
4365
  timescale
@@ -4076,8 +4492,8 @@ var createMatroskaMedia = async ({
4076
4492
  }
4077
4493
  });
4078
4494
  },
4079
- save: () => {
4080
- return w.save();
4495
+ getBlob: async () => {
4496
+ return w.getBlob();
4081
4497
  },
4082
4498
  remove: async () => {
4083
4499
  await w.remove();
@@ -4104,9 +4520,9 @@ var createMatroskaMedia = async ({
4104
4520
  });
4105
4521
  await updateSeekWrite();
4106
4522
  await w.write(createMatroskaCues(cues).bytes);
4107
- await w.waitForFinish();
4108
4523
  const segmentSize = w.getWrittenByteCount() - segmentOffset - matroskaToHex(matroskaElements.Segment).byteLength - MATROSKA_SEGMENT_MIN_VINT_WIDTH;
4109
4524
  await updateSegmentSize(segmentSize);
4525
+ await w.finish();
4110
4526
  }
4111
4527
  };
4112
4528
  };
@@ -4133,7 +4549,11 @@ var createWav = async ({
4133
4549
  writer,
4134
4550
  progressTracker
4135
4551
  }) => {
4136
- const w = await writer.createContent({ filename, mimeType: "audio/wav" });
4552
+ const w = await writer.createContent({
4553
+ filename,
4554
+ mimeType: "audio/wav",
4555
+ logLevel
4556
+ });
4137
4557
  await w.write(new Uint8Array([82, 73, 70, 70]));
4138
4558
  const sizePosition = w.getWrittenByteCount();
4139
4559
  await w.write(new Uint8Array([0, 0, 0, 0]));
@@ -4183,8 +4603,8 @@ var createWav = async ({
4183
4603
  };
4184
4604
  const waitForFinishPromises = [];
4185
4605
  return {
4186
- save: () => {
4187
- return w.save();
4606
+ getBlob: () => {
4607
+ return w.getBlob();
4188
4608
  },
4189
4609
  remove: () => {
4190
4610
  return w.remove();
@@ -4208,7 +4628,7 @@ var createWav = async ({
4208
4628
  await Promise.all(waitForFinishPromises.map((p) => p()));
4209
4629
  await operationProm.current;
4210
4630
  await updateSize();
4211
- await w.waitForFinish();
4631
+ await w.finish();
4212
4632
  },
4213
4633
  addTrack: async (track) => {
4214
4634
  if (track.type !== "audio") {
@@ -4297,7 +4717,7 @@ var throttledStateUpdate = ({
4297
4717
  const onAbort = () => {
4298
4718
  clearInterval(interval);
4299
4719
  };
4300
- signal.addEventListener("abort", onAbort, { once: true });
4720
+ signal?.addEventListener("abort", onAbort, { once: true });
4301
4721
  return {
4302
4722
  get: () => currentState,
4303
4723
  update: (fn) => {
@@ -4305,12 +4725,26 @@ var throttledStateUpdate = ({
4305
4725
  },
4306
4726
  stopAndGetLastProgress: () => {
4307
4727
  clearInterval(interval);
4308
- signal.removeEventListener("abort", onAbort);
4728
+ signal?.removeEventListener("abort", onAbort);
4309
4729
  return currentState;
4310
4730
  }
4311
4731
  };
4312
4732
  };
4313
4733
 
4734
+ // src/webcodecs-controller.ts
4735
+ import { mediaParserController } from "@remotion/media-parser";
4736
+ var webcodecsController = () => {
4737
+ const controller = mediaParserController();
4738
+ return {
4739
+ abort: controller.abort,
4740
+ pause: controller.pause,
4741
+ resume: controller.resume,
4742
+ addEventListener: controller.addEventListener,
4743
+ removeEventListener: controller.removeEventListener,
4744
+ _internals: controller._internals
4745
+ };
4746
+ };
4747
+
4314
4748
  // src/convert-media.ts
4315
4749
  var convertMedia = async function({
4316
4750
  src,
@@ -4320,7 +4754,7 @@ var convertMedia = async function({
4320
4754
  audioCodec,
4321
4755
  container,
4322
4756
  videoCodec,
4323
- signal: userPassedAbortSignal,
4757
+ controller = webcodecsController(),
4324
4758
  onAudioTrack: userAudioResolver,
4325
4759
  onVideoTrack: userVideoResolver,
4326
4760
  reader,
@@ -4331,34 +4765,60 @@ var convertMedia = async function({
4331
4765
  rotate,
4332
4766
  apiKey,
4333
4767
  resize,
4768
+ onAudioCodec,
4769
+ onContainer,
4770
+ onDimensions,
4771
+ onDurationInSeconds,
4772
+ onFps,
4773
+ onImages,
4774
+ onInternalStats,
4775
+ onIsHdr,
4776
+ onKeyframes,
4777
+ onLocation,
4778
+ onMetadata,
4779
+ onMimeType,
4780
+ onName,
4781
+ onNumberOfAudioChannels,
4782
+ onRotation,
4783
+ onSampleRate,
4784
+ onSize,
4785
+ onSlowAudioBitrate,
4786
+ onSlowDurationInSeconds,
4787
+ onSlowFps,
4788
+ onSlowKeyframes,
4789
+ onSlowNumberOfFrames,
4790
+ onSlowVideoBitrate,
4791
+ onStructure,
4792
+ onTracks,
4793
+ onUnrotatedDimensions,
4794
+ onVideoCodec,
4334
4795
  ...more
4335
4796
  }) {
4336
- if (userPassedAbortSignal?.aborted) {
4337
- return Promise.reject(new error_cause_default("Aborted"));
4797
+ if (controller._internals.signal.aborted) {
4798
+ return Promise.reject(new MediaParserAbortError3("Aborted"));
4338
4799
  }
4339
- if (container !== "webm" && container !== "mp4" && container !== "wav") {
4340
- return Promise.reject(new TypeError('Only `to: "webm"`, `to: "mp4"` and `to: "wav"` is supported currently'));
4800
+ if (availableContainers.indexOf(container) === -1) {
4801
+ return Promise.reject(new TypeError(`Only the following values for "container" are supported currently: ${JSON.stringify(availableContainers)}`));
4341
4802
  }
4342
- if (videoCodec && videoCodec !== "vp8" && videoCodec !== "vp9") {
4343
- return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
4803
+ if (videoCodec && availableVideoCodecs.indexOf(videoCodec) === -1) {
4804
+ return Promise.reject(new TypeError(`Only the following values for "videoCodec" are supported currently: ${JSON.stringify(availableVideoCodecs)}`));
4344
4805
  }
4345
4806
  const { resolve, reject, getPromiseToImmediatelyReturn } = withResolversAndWaitForReturn();
4346
- const controller = new AbortController;
4347
4807
  const abortConversion = (errCause) => {
4348
4808
  reject(errCause);
4349
- if (!controller.signal.aborted) {
4809
+ if (!controller._internals.signal.aborted) {
4350
4810
  controller.abort();
4351
4811
  }
4352
4812
  };
4353
4813
  const onUserAbort = () => {
4354
- abortConversion(new error_cause_default("Conversion aborted by user"));
4814
+ abortConversion(new MediaParserAbortError3("Conversion aborted by user"));
4355
4815
  };
4356
- userPassedAbortSignal?.addEventListener("abort", onUserAbort);
4816
+ controller._internals.signal.addEventListener("abort", onUserAbort);
4357
4817
  const creator = selectContainerCreator(container);
4358
4818
  const throttledState = throttledStateUpdate({
4359
4819
  updateFn: onProgressDoNotCallDirectly ?? null,
4360
4820
  everyMilliseconds: progressIntervalInMs ?? 100,
4361
- signal: controller.signal
4821
+ signal: controller._internals.signal
4362
4822
  });
4363
4823
  const progressTracker = makeProgressTracker();
4364
4824
  const state = await creator({
@@ -4416,17 +4876,17 @@ var convertMedia = async function({
4416
4876
  progressTracker,
4417
4877
  onAudioData: onAudioData ?? null
4418
4878
  });
4419
- parseMedia({
4879
+ MediaParserInternals9.internalParseMedia({
4420
4880
  logLevel,
4421
4881
  src,
4422
4882
  onVideoTrack,
4423
4883
  onAudioTrack,
4424
- signal: controller.signal,
4884
+ controller,
4425
4885
  fields: {
4426
4886
  ...fields,
4427
4887
  durationInSeconds: true
4428
4888
  },
4429
- reader,
4889
+ reader: reader ?? fetchReader,
4430
4890
  ...more,
4431
4891
  onDurationInSeconds: (durationInSeconds) => {
4432
4892
  if (durationInSeconds === null) {
@@ -4447,12 +4907,45 @@ var convertMedia = async function({
4447
4907
  })
4448
4908
  };
4449
4909
  });
4450
- }
4910
+ },
4911
+ acknowledgeRemotionLicense: true,
4912
+ mode: "query",
4913
+ onDiscardedData: null,
4914
+ onError: () => ({ action: "fail" }),
4915
+ onParseProgress: null,
4916
+ progressIntervalInMs: null,
4917
+ onAudioCodec: onAudioCodec ?? null,
4918
+ onContainer: onContainer ?? null,
4919
+ onDimensions: onDimensions ?? null,
4920
+ onFps: onFps ?? null,
4921
+ onImages: onImages ?? null,
4922
+ onInternalStats: onInternalStats ?? null,
4923
+ onIsHdr: onIsHdr ?? null,
4924
+ onKeyframes: onKeyframes ?? null,
4925
+ onLocation: onLocation ?? null,
4926
+ onMetadata: onMetadata ?? null,
4927
+ onMimeType: onMimeType ?? null,
4928
+ onName: onName ?? null,
4929
+ onNumberOfAudioChannels: onNumberOfAudioChannels ?? null,
4930
+ onRotation: onRotation ?? null,
4931
+ onSampleRate: onSampleRate ?? null,
4932
+ onSize: onSize ?? null,
4933
+ onSlowAudioBitrate: onSlowAudioBitrate ?? null,
4934
+ onSlowDurationInSeconds: onSlowDurationInSeconds ?? null,
4935
+ onSlowFps: onSlowFps ?? null,
4936
+ onSlowKeyframes: onSlowKeyframes ?? null,
4937
+ onSlowNumberOfFrames: onSlowNumberOfFrames ?? null,
4938
+ onSlowVideoBitrate: onSlowVideoBitrate ?? null,
4939
+ onStructure: onStructure ?? null,
4940
+ onTracks: onTracks ?? null,
4941
+ onUnrotatedDimensions: onUnrotatedDimensions ?? null,
4942
+ onVideoCodec: onVideoCodec ?? null,
4943
+ apiName: "convertMedia()"
4451
4944
  }).then(() => {
4452
4945
  return state.waitForFinish();
4453
4946
  }).then(() => {
4454
4947
  resolve({
4455
- save: state.save,
4948
+ save: state.getBlob,
4456
4949
  remove: state.remove,
4457
4950
  finalState: throttledState.get()
4458
4951
  });
@@ -4469,7 +4962,7 @@ var convertMedia = async function({
4469
4962
  throttledState.stopAndGetLastProgress();
4470
4963
  });
4471
4964
  return getPromiseToImmediatelyReturn().finally(() => {
4472
- userPassedAbortSignal?.removeEventListener("abort", onUserAbort);
4965
+ controller._internals.signal.removeEventListener("abort", onUserAbort);
4473
4966
  });
4474
4967
  };
4475
4968
  // src/get-available-audio-codecs.ts
@@ -4487,26 +4980,6 @@ var getAvailableAudioCodecs = ({
4487
4980
  }
4488
4981
  throw new Error(`Unsupported container: ${container}`);
4489
4982
  };
4490
- // src/get-available-containers.ts
4491
- var availableContainers = ["webm", "mp4", "wav"];
4492
- var getAvailableContainers = () => {
4493
- return availableContainers;
4494
- };
4495
- // src/get-available-video-codecs.ts
4496
- var getAvailableVideoCodecs = ({
4497
- container
4498
- }) => {
4499
- if (container === "mp4") {
4500
- return ["h264"];
4501
- }
4502
- if (container === "webm") {
4503
- return ["vp8", "vp9"];
4504
- }
4505
- if (container === "wav") {
4506
- return [];
4507
- }
4508
- throw new Error(`Unsupported container: ${container}`);
4509
- };
4510
4983
  // src/index.ts
4511
4984
  var WebCodecsInternals = {
4512
4985
  rotateAndResizeVideoFrame,
@@ -4515,6 +4988,7 @@ var WebCodecsInternals = {
4515
4988
  };
4516
4989
  setRemotionImported();
4517
4990
  export {
4991
+ webcodecsController,
4518
4992
  getDefaultVideoCodec,
4519
4993
  getDefaultAudioCodec,
4520
4994
  getAvailableVideoCodecs,