@remotion/webcodecs 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 (72) hide show
  1. package/README.md +2 -2
  2. package/dist/audio-decoder-config.d.ts +2 -1
  3. package/dist/audio-decoder-config.js +44 -3
  4. package/dist/audio-decoder.d.ts +6 -3
  5. package/dist/audio-decoder.js +26 -4
  6. package/dist/audio-encoder-config.d.ts +4 -1
  7. package/dist/audio-encoder-config.js +6 -0
  8. package/dist/audio-encoder.d.ts +6 -4
  9. package/dist/audio-encoder.js +15 -3
  10. package/dist/browser-quirks.d.ts +1 -0
  11. package/dist/browser-quirks.js +5 -1
  12. package/dist/can-copy-audio-track.d.ts +1 -1
  13. package/dist/can-copy-audio-track.js +3 -0
  14. package/dist/can-copy-video-track.d.ts +4 -2
  15. package/dist/can-copy-video-track.js +10 -2
  16. package/dist/can-reencode-audio-track.d.ts +4 -3
  17. package/dist/can-reencode-audio-track.js +5 -2
  18. package/dist/can-reencode-video-track.d.ts +1 -1
  19. package/dist/codec-id.d.ts +2 -2
  20. package/dist/codec-id.js +8 -2
  21. package/dist/convert-media.d.ts +5 -2
  22. package/dist/convert-media.js +11 -8
  23. package/dist/convert-to-correct-videoframe.d.ts +1 -1
  24. package/dist/convert-to-correct-videoframe.js +8 -0
  25. package/dist/default-on-video-track-handler.js +12 -2
  26. package/dist/esm/index.mjs +463 -160
  27. package/dist/generate-output-filename.d.ts +1 -1
  28. package/dist/get-available-audio-codecs.d.ts +7 -0
  29. package/dist/get-available-audio-codecs.js +18 -0
  30. package/dist/get-available-containers.d.ts +4 -0
  31. package/dist/get-available-containers.js +8 -0
  32. package/dist/get-available-video-codecs.d.ts +7 -0
  33. package/dist/get-available-video-codecs.js +18 -0
  34. package/dist/get-default-audio-codec.d.ts +2 -1
  35. package/dist/get-default-audio-codec.js +3 -0
  36. package/dist/get-default-video-codec.d.ts +3 -2
  37. package/dist/get-default-video-codec.js +7 -1
  38. package/dist/get-wave-audio-decoder.d.ts +2 -0
  39. package/dist/get-wave-audio-decoder.js +29 -0
  40. package/dist/index.d.ts +10 -1
  41. package/dist/index.js +12 -5
  42. package/dist/io-manager/event-emitter.d.ts +4 -0
  43. package/dist/io-manager/event-emitter.js +1 -0
  44. package/dist/io-manager/io-synchronizer.d.ts +8 -2
  45. package/dist/io-manager/io-synchronizer.js +31 -14
  46. package/dist/io-manager/make-timeout-promise.d.ts +4 -0
  47. package/dist/io-manager/make-timeout-promise.js +18 -0
  48. package/dist/on-audio-track-handler.d.ts +2 -1
  49. package/dist/on-audio-track.d.ts +5 -3
  50. package/dist/on-audio-track.js +9 -4
  51. package/dist/on-frame.d.ts +3 -2
  52. package/dist/on-frame.js +24 -19
  53. package/dist/on-video-track-handler.d.ts +4 -1
  54. package/dist/on-video-track.d.ts +6 -3
  55. package/dist/on-video-track.js +20 -5
  56. package/dist/rotate-video-frame.d.ts +5 -0
  57. package/dist/rotate-video-frame.js +48 -0
  58. package/dist/rotate-video.d.ts +4 -0
  59. package/dist/rotate-video.js +43 -0
  60. package/dist/rotation.d.ts +8 -0
  61. package/dist/rotation.js +10 -0
  62. package/dist/select-container-creator.d.ts +2 -0
  63. package/dist/select-container-creator.js +17 -0
  64. package/dist/test/avi-to-mp4.test.js +15 -0
  65. package/dist/video-decoder.d.ts +3 -2
  66. package/dist/video-decoder.js +11 -3
  67. package/dist/video-encoder-config.d.ts +1 -1
  68. package/dist/video-encoder.d.ts +4 -3
  69. package/dist/video-encoder.js +7 -2
  70. package/dist/wav-audio-encoder.d.ts +2 -0
  71. package/dist/wav-audio-encoder.js +26 -0
  72. package/package.json +5 -3
@@ -1,3 +1,59 @@
1
+ // src/rotation.ts
2
+ var calculateNewDimensionsFromDimensions = ({
3
+ width,
4
+ height,
5
+ rotation
6
+ }) => {
7
+ const switchDimensions = rotation % 90 === 0 && rotation % 180 !== 0;
8
+ const newHeight = switchDimensions ? width : height;
9
+ const newWidth = switchDimensions ? height : width;
10
+ return { height: newHeight, width: newWidth };
11
+ };
12
+
13
+ // src/rotate-video-frame.ts
14
+ var normalizeVideoRotation = (rotation) => {
15
+ return (rotation % 360 + 360) % 360;
16
+ };
17
+ var rotateVideoFrame = ({
18
+ frame,
19
+ rotation
20
+ }) => {
21
+ const normalized = (rotation % 360 + 360) % 360;
22
+ if (normalized % 360 === 0) {
23
+ return frame;
24
+ }
25
+ if (normalized % 90 !== 0) {
26
+ throw new Error("Only 90 degree rotations are supported");
27
+ }
28
+ const { height, width } = calculateNewDimensionsFromDimensions({
29
+ height: frame.displayHeight,
30
+ width: frame.displayWidth,
31
+ rotation
32
+ });
33
+ const canvas = new OffscreenCanvas(width, height);
34
+ const ctx = canvas.getContext("2d");
35
+ if (!ctx) {
36
+ throw new Error("Could not get 2d context");
37
+ }
38
+ canvas.width = width;
39
+ canvas.height = height;
40
+ if (normalized === 90) {
41
+ ctx.translate(width, 0);
42
+ } else if (normalized === 180) {
43
+ ctx.translate(width, height);
44
+ } else if (normalized === 270) {
45
+ ctx.translate(0, height);
46
+ }
47
+ ctx.rotate(normalized * (Math.PI / 180));
48
+ ctx.drawImage(frame, 0, 0);
49
+ return new VideoFrame(canvas, {
50
+ displayHeight: height,
51
+ displayWidth: width,
52
+ duration: frame.duration ?? undefined,
53
+ timestamp: frame.timestamp
54
+ });
55
+ };
56
+
1
57
  // src/set-remotion-imported.ts
2
58
  import { VERSION } from "@remotion/media-parser";
3
59
  var setRemotionImported = () => {
@@ -13,58 +69,65 @@ var setRemotionImported = () => {
13
69
  }
14
70
  };
15
71
 
16
- // src/log.ts
17
- import { MediaParserInternals } from "@remotion/media-parser";
18
- var { Log } = MediaParserInternals;
19
-
20
- // src/with-resolvers.ts
21
- var withResolvers = function() {
22
- let resolve;
23
- let reject;
24
- const promise = new Promise((res, rej) => {
25
- resolve = res;
26
- reject = rej;
27
- });
28
- return { promise, resolve, reject };
29
- };
30
- var withResolversAndWaitForReturn = () => {
31
- const { promise, reject, resolve } = withResolvers();
32
- const { promise: returnPromise, resolve: resolveReturn } = withResolvers();
72
+ // src/get-wave-audio-decoder.ts
73
+ var getWaveAudioDecoder = ({
74
+ onFrame,
75
+ track
76
+ }) => {
77
+ let queue = Promise.resolve();
78
+ const processSample = async (audioSample) => {
79
+ await onFrame(new AudioData({
80
+ data: audioSample.data,
81
+ format: "s16",
82
+ numberOfChannels: track.numberOfChannels,
83
+ numberOfFrames: audioSample.data.byteLength / 2,
84
+ sampleRate: track.sampleRate,
85
+ timestamp: audioSample.timestamp
86
+ }));
87
+ };
33
88
  return {
34
- getPromiseToImmediatelyReturn: () => {
35
- resolveReturn(undefined);
36
- return promise;
89
+ close() {
90
+ return Promise.resolve();
37
91
  },
38
- reject: (reason) => {
39
- returnPromise.then(() => reject(reason));
92
+ processSample(audioSample) {
93
+ queue = queue.then(() => processSample(audioSample));
94
+ return queue;
40
95
  },
41
- resolve
96
+ flush: () => Promise.resolve(),
97
+ waitForFinish: () => Promise.resolve()
42
98
  };
43
99
  };
44
100
 
45
- // src/io-manager/event-emitter.ts
46
- class IoEventEmitter {
47
- listeners = {
48
- input: [],
49
- output: [],
50
- processed: []
101
+ // src/io-manager/io-synchronizer.ts
102
+ import { MediaParserInternals as MediaParserInternals3 } from "@remotion/media-parser";
103
+
104
+ // src/log.ts
105
+ import { MediaParserInternals } from "@remotion/media-parser";
106
+ var { Log } = MediaParserInternals;
107
+
108
+ // src/io-manager/make-timeout-promise.ts
109
+ import { MediaParserInternals as MediaParserInternals2 } from "@remotion/media-parser";
110
+ var makeTimeoutPromise = (label, ms) => {
111
+ const { promise, reject, resolve } = MediaParserInternals2.withResolvers();
112
+ const timeout = setTimeout(() => {
113
+ reject(new Error(`${label} (timed out after ${ms}ms)`));
114
+ }, ms);
115
+ return {
116
+ timeoutPromise: promise,
117
+ clear: () => {
118
+ clearTimeout(timeout);
119
+ resolve();
120
+ }
51
121
  };
52
- addEventListener(name, callback) {
53
- this.listeners[name].push(callback);
54
- }
55
- removeEventListener(name, callback) {
56
- this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
57
- }
58
- dispatchEvent(dispatchName, context) {
59
- this.listeners[dispatchName].forEach((callback) => {
60
- callback({ detail: context });
61
- });
62
- }
63
- }
122
+ };
64
123
 
65
124
  // src/io-manager/io-synchronizer.ts
66
- var makeIoSynchronizer = (logLevel, label) => {
67
- const eventEmitter = new IoEventEmitter;
125
+ var makeIoSynchronizer = ({
126
+ logLevel,
127
+ label,
128
+ progress
129
+ }) => {
130
+ const eventEmitter = new MediaParserInternals3.IoEventEmitter;
68
131
  let lastInput = 0;
69
132
  let lastInputKeyframe = 0;
70
133
  let lastOutput = 0;
@@ -108,7 +171,7 @@ var makeIoSynchronizer = (logLevel, label) => {
108
171
  printState("Got output");
109
172
  };
110
173
  const waitForOutput = () => {
111
- const { promise, resolve } = withResolvers();
174
+ const { promise, resolve } = MediaParserInternals3.withResolvers();
112
175
  const on = () => {
113
176
  eventEmitter.removeEventListener("output", on);
114
177
  resolve();
@@ -117,7 +180,7 @@ var makeIoSynchronizer = (logLevel, label) => {
117
180
  return promise;
118
181
  };
119
182
  const waitForProcessed = () => {
120
- const { promise, resolve } = withResolvers();
183
+ const { promise, resolve } = MediaParserInternals3.withResolvers();
121
184
  const on = () => {
122
185
  eventEmitter.removeEventListener("processed", on);
123
186
  resolve();
@@ -127,17 +190,33 @@ var makeIoSynchronizer = (logLevel, label) => {
127
190
  };
128
191
  const waitFor = async ({
129
192
  _unprocessed,
130
- unemitted
193
+ unemitted,
194
+ minimumProgress
131
195
  }) => {
132
- while (getUnemittedItems() > unemitted) {
133
- await waitForOutput();
134
- }
135
- while (getUnprocessed() > _unprocessed) {
136
- await waitForProcessed();
137
- }
196
+ const { timeoutPromise, clear } = makeTimeoutPromise(`Waited too long for ${label}`, 1e4);
197
+ await Promise.race([
198
+ timeoutPromise,
199
+ Promise.all([
200
+ (async () => {
201
+ while (getUnemittedItems() > unemitted) {
202
+ await waitForOutput();
203
+ }
204
+ })(),
205
+ (async () => {
206
+ while (getUnprocessed() > _unprocessed) {
207
+ await waitForProcessed();
208
+ }
209
+ })(),
210
+ minimumProgress === null ? Promise.resolve() : (async () => {
211
+ while (progress.getSmallestProgress() < minimumProgress) {
212
+ await progress.waitForProgress();
213
+ }
214
+ })()
215
+ ])
216
+ ]).finally(() => clear());
138
217
  };
139
218
  const waitForFinish = async () => {
140
- await waitFor({ _unprocessed: 0, unemitted: 0 });
219
+ await waitFor({ _unprocessed: 0, unemitted: 0, minimumProgress: null });
141
220
  };
142
221
  const onProcessed = () => {
143
222
  eventEmitter.dispatchEvent("processed", {});
@@ -159,12 +238,21 @@ var createAudioDecoder = ({
159
238
  onError,
160
239
  signal,
161
240
  config,
162
- logLevel
241
+ logLevel,
242
+ track,
243
+ progressTracker
163
244
  }) => {
164
245
  if (signal.aborted) {
165
246
  throw new Error("Not creating audio decoder, already aborted");
166
247
  }
167
- const ioSynchronizer = makeIoSynchronizer(logLevel, "Audio decoder");
248
+ if (config.codec === "pcm-s16") {
249
+ return getWaveAudioDecoder({ onFrame, track });
250
+ }
251
+ const ioSynchronizer = makeIoSynchronizer({
252
+ logLevel,
253
+ label: "Audio decoder",
254
+ progress: progressTracker
255
+ });
168
256
  let outputQueue = Promise.resolve();
169
257
  const audioDecoder = new AudioDecoder({
170
258
  output(inputFrame) {
@@ -207,7 +295,11 @@ var createAudioDecoder = ({
207
295
  if (audioDecoder.state === "closed") {
208
296
  return;
209
297
  }
210
- await ioSynchronizer.waitFor({ unemitted: 100, _unprocessed: 2 });
298
+ await ioSynchronizer.waitFor({
299
+ unemitted: 20,
300
+ _unprocessed: 20,
301
+ minimumProgress: audioSample.timestamp - 1e7
302
+ });
211
303
  const chunk = new EncodedAudioChunk(audioSample);
212
304
  audioDecoder.decode(chunk);
213
305
  ioSynchronizer.inputItem(chunk.timestamp, audioSample.type === "key");
@@ -215,11 +307,18 @@ var createAudioDecoder = ({
215
307
  let queue = Promise.resolve();
216
308
  return {
217
309
  processSample: (sample) => {
310
+ if (sample.data.length === 0) {
311
+ return queue;
312
+ }
218
313
  queue = queue.then(() => processSample(sample));
219
314
  return queue;
220
315
  },
221
316
  waitForFinish: async () => {
222
- await audioDecoder.flush();
317
+ try {
318
+ await audioDecoder.flush();
319
+ } catch {
320
+ }
321
+ await queue;
223
322
  await ioSynchronizer.waitForFinish();
224
323
  await outputQueue;
225
324
  },
@@ -229,6 +328,33 @@ var createAudioDecoder = ({
229
328
  }
230
329
  };
231
330
  };
331
+ // src/wav-audio-encoder.ts
332
+ var getWaveAudioEncoder = ({
333
+ onChunk,
334
+ signal
335
+ }) => {
336
+ return {
337
+ close: () => {
338
+ return Promise.resolve();
339
+ },
340
+ encodeFrame: (audioData) => {
341
+ if (signal.aborted) {
342
+ return Promise.resolve();
343
+ }
344
+ const chunk = {
345
+ timestamp: audioData.timestamp,
346
+ duration: audioData.duration,
347
+ type: "key",
348
+ copyTo: (destination) => audioData.copyTo(destination, { planeIndex: 0, format: "s16" }),
349
+ byteLength: audioData.allocationSize({ planeIndex: 0, format: "s16" })
350
+ };
351
+ return onChunk(chunk);
352
+ },
353
+ flush: () => Promise.resolve(),
354
+ waitForFinish: () => Promise.resolve()
355
+ };
356
+ };
357
+
232
358
  // src/audio-encoder.ts
233
359
  var createAudioEncoder = ({
234
360
  onChunk,
@@ -237,12 +363,20 @@ var createAudioEncoder = ({
237
363
  signal,
238
364
  config: audioEncoderConfig,
239
365
  logLevel,
240
- onNewAudioSampleRate
366
+ onNewAudioSampleRate,
367
+ progressTracker
241
368
  }) => {
242
369
  if (signal.aborted) {
243
370
  throw new Error("Not creating audio encoder, already aborted");
244
371
  }
245
- const ioSynchronizer = makeIoSynchronizer(logLevel, "Audio encoder");
372
+ if (codec === "wav") {
373
+ return getWaveAudioEncoder({ onChunk, signal });
374
+ }
375
+ const ioSynchronizer = makeIoSynchronizer({
376
+ logLevel,
377
+ label: "Audio encoder",
378
+ progress: progressTracker
379
+ });
246
380
  let prom = Promise.resolve();
247
381
  const encoder = new AudioEncoder({
248
382
  output: (chunk) => {
@@ -282,7 +416,11 @@ var createAudioEncoder = ({
282
416
  if (encoder.state === "closed") {
283
417
  return;
284
418
  }
285
- await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 20 });
419
+ await ioSynchronizer.waitFor({
420
+ unemitted: 20,
421
+ _unprocessed: 20,
422
+ minimumProgress: audioData.timestamp - 1e7
423
+ });
286
424
  if (encoder.state === "closed") {
287
425
  return;
288
426
  }
@@ -328,31 +466,94 @@ var canCopyAudioTrack = ({
328
466
  if (container === "mp4") {
329
467
  return inputCodec === "aac";
330
468
  }
469
+ if (container === "wav") {
470
+ return false;
471
+ }
331
472
  throw new Error(`Unhandled codec: ${container}`);
332
473
  };
333
474
  // src/can-copy-video-track.ts
334
475
  var canCopyVideoTrack = ({
335
476
  inputCodec,
336
- container
477
+ container,
478
+ inputRotation,
479
+ rotationToApply
337
480
  }) => {
481
+ if (normalizeVideoRotation(inputRotation) !== normalizeVideoRotation(rotationToApply)) {
482
+ return false;
483
+ }
338
484
  if (container === "webm") {
339
485
  return inputCodec === "vp8" || inputCodec === "vp9";
340
486
  }
341
487
  if (container === "mp4") {
342
- return inputCodec === "h264" || inputCodec === "h265";
488
+ return inputCodec === "h264";
489
+ }
490
+ if (container === "wav") {
491
+ return false;
343
492
  }
344
493
  throw new Error(`Unhandled codec: ${container}`);
345
494
  };
495
+ // src/browser-quirks.ts
496
+ var isFirefox = () => {
497
+ return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
498
+ };
499
+ var isSafari = () => {
500
+ return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
501
+ };
502
+ var isChrome = () => {
503
+ return navigator.userAgent.toLowerCase().indexOf("chrome") > -1;
504
+ };
505
+
346
506
  // src/audio-decoder-config.ts
347
- var getAudioDecoderConfig = async (config) => {
507
+ var overrideBrowserQuirks = ({
508
+ config,
509
+ logLevel
510
+ }) => {
511
+ const bytes = config.description;
512
+ if (!bytes) {
513
+ return config;
514
+ }
515
+ if (bytes[0] === 18 && bytes[1] === 8) {
516
+ if (isFirefox()) {
517
+ return {
518
+ ...config,
519
+ codec: "mp4a.40.2",
520
+ description: bytes
521
+ };
522
+ }
523
+ if (!isChrome()) {
524
+ return config;
525
+ }
526
+ 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");
527
+ return {
528
+ ...config,
529
+ description: new Uint8Array([18, 16])
530
+ };
531
+ }
532
+ if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
533
+ 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");
534
+ return {
535
+ ...config,
536
+ description: new Uint8Array([18, 144])
537
+ };
538
+ }
539
+ return config;
540
+ };
541
+ var getAudioDecoderConfig = async (config, logLevel) => {
542
+ if (config.codec === "pcm-s16") {
543
+ return config;
544
+ }
348
545
  if (typeof AudioDecoder === "undefined") {
349
546
  return null;
350
547
  }
351
548
  if (typeof EncodedAudioChunk === "undefined") {
352
549
  return null;
353
550
  }
354
- if ((await AudioDecoder.isConfigSupported(config)).supported) {
355
- return config;
551
+ const realConfig = overrideBrowserQuirks({
552
+ config,
553
+ logLevel
554
+ });
555
+ if ((await AudioDecoder.isConfigSupported(realConfig)).supported) {
556
+ return realConfig;
356
557
  }
357
558
  return null;
358
559
  };
@@ -365,6 +566,9 @@ var getCodecString = (audioCodec) => {
365
566
  if (audioCodec === "aac") {
366
567
  return "mp4a.40.02";
367
568
  }
569
+ if (audioCodec === "wav") {
570
+ return "wav-should-not-to-into-audio-encoder";
571
+ }
368
572
  throw new Error(`Unsupported audio codec: ${audioCodec}`);
369
573
  };
370
574
  var getAudioEncoderConfig = async (config) => {
@@ -372,6 +576,9 @@ var getAudioEncoderConfig = async (config) => {
372
576
  ...config,
373
577
  codec: getCodecString(config.codec)
374
578
  };
579
+ if (config.codec === "wav") {
580
+ return actualConfig;
581
+ }
375
582
  if (typeof AudioEncoder === "undefined") {
376
583
  return null;
377
584
  }
@@ -385,9 +592,13 @@ var getAudioEncoderConfig = async (config) => {
385
592
  var canReencodeAudioTrack = async ({
386
593
  track,
387
594
  audioCodec,
388
- bitrate
595
+ bitrate,
596
+ logLevel = "info"
389
597
  }) => {
390
- const audioDecoderConfig = await getAudioDecoderConfig(track);
598
+ const audioDecoderConfig = await getAudioDecoderConfig(track, logLevel);
599
+ if (audioCodec === "wav" && audioDecoderConfig) {
600
+ return true;
601
+ }
391
602
  const audioEncoderConfig = await getAudioEncoderConfig({
392
603
  codec: audioCodec,
393
604
  numberOfChannels: track.numberOfChannels,
@@ -418,14 +629,6 @@ var getVideoDecoderConfigWithHardwareAcceleration = async (config) => {
418
629
  return null;
419
630
  };
420
631
 
421
- // src/browser-quirks.ts
422
- var isFirefox = () => {
423
- return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
424
- };
425
- var isSafari = () => {
426
- return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
427
- };
428
-
429
632
  // src/choose-correct-avc1-profile.ts
430
633
  var chooseCorrectAvc1Profile = ({
431
634
  width,
@@ -508,32 +711,9 @@ var canReencodeVideoTrack = async ({
508
711
  const videoDecoderConfig = await getVideoDecoderConfigWithHardwareAcceleration(track);
509
712
  return Boolean(videoDecoderConfig && videoEncoderConfig);
510
713
  };
511
- // src/codec-id.ts
512
- var availableContainers = ["webm", "mp4"];
513
- var getAvailableContainers = () => {
514
- return availableContainers;
515
- };
516
- var getAvailableVideoCodecs = (container) => {
517
- if (container === "mp4") {
518
- return ["h264"];
519
- }
520
- if (container === "webm") {
521
- return ["vp8", "vp9"];
522
- }
523
- throw new Error(`Unsupported container: ${container}`);
524
- };
525
- var getAvailableAudioCodecs = (container) => {
526
- if (container === "mp4") {
527
- return ["aac"];
528
- }
529
- if (container === "webm") {
530
- return ["opus"];
531
- }
532
- throw new Error(`Unsupported container: ${container}`);
533
- };
534
714
  // src/convert-media.ts
535
715
  import {
536
- MediaParserInternals as MediaParserInternals4,
716
+ MediaParserInternals as MediaParserInternals7,
537
717
  parseMedia
538
718
  } from "@remotion/media-parser";
539
719
 
@@ -592,7 +772,7 @@ var convertEncodedChunk = (chunk, trackId) => {
592
772
  };
593
773
 
594
774
  // src/default-on-audio-track-handler.ts
595
- import { MediaParserInternals as MediaParserInternals2 } from "@remotion/media-parser";
775
+ import { MediaParserInternals as MediaParserInternals4 } from "@remotion/media-parser";
596
776
 
597
777
  // src/get-default-audio-codec.ts
598
778
  var getDefaultAudioCodec = ({
@@ -604,6 +784,9 @@ var getDefaultAudioCodec = ({
604
784
  if (container === "mp4") {
605
785
  return "aac";
606
786
  }
787
+ if (container === "wav") {
788
+ return "wav";
789
+ }
607
790
  throw new Error(`Unhandled container: ${container}`);
608
791
  };
609
792
 
@@ -621,7 +804,7 @@ var defaultOnAudioTrackHandler = async ({
621
804
  container
622
805
  });
623
806
  if (canCopy) {
624
- MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can copy track, therefore copying`);
807
+ MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can copy track, therefore copying`);
625
808
  return Promise.resolve({ type: "copy" });
626
809
  }
627
810
  const audioCodec = defaultAudioCodec ?? getDefaultAudioCodec({ container });
@@ -631,14 +814,14 @@ var defaultOnAudioTrackHandler = async ({
631
814
  bitrate
632
815
  });
633
816
  if (canReencode) {
634
- MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
817
+ MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
635
818
  return Promise.resolve({
636
819
  type: "reencode",
637
820
  bitrate,
638
821
  audioCodec
639
822
  });
640
823
  }
641
- MediaParserInternals2.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
824
+ MediaParserInternals4.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
642
825
  return Promise.resolve({ type: "fail" });
643
826
  };
644
827
 
@@ -651,7 +834,8 @@ var makeAudioTrackHandler = ({
651
834
  onMediaStateUpdate,
652
835
  onAudioTrack,
653
836
  logLevel,
654
- container
837
+ container,
838
+ progressTracker
655
839
  }) => async (track) => {
656
840
  const audioOperation = await (onAudioTrack ?? defaultOnAudioTrackHandler)({
657
841
  defaultAudioCodec: audioCodec,
@@ -702,7 +886,7 @@ var makeAudioTrackHandler = ({
702
886
  numberOfChannels: track.numberOfChannels,
703
887
  sampleRate: track.sampleRate,
704
888
  description: track.description
705
- });
889
+ }, logLevel);
706
890
  if (!audioEncoderConfig) {
707
891
  abortConversion(new error_cause_default(`Could not configure audio encoder of track ${track.trackId}`));
708
892
  return null;
@@ -714,7 +898,7 @@ var makeAudioTrackHandler = ({
714
898
  const codecPrivate = audioOperation.audioCodec === "aac" ? new Uint8Array([17, 144]) : null;
715
899
  const { trackNumber } = await state.addTrack({
716
900
  type: "audio",
717
- codec: audioOperation.audioCodec,
901
+ codec: audioOperation.audioCodec === "wav" ? "pcm-s16" : audioOperation.audioCodec,
718
902
  numberOfChannels: track.numberOfChannels,
719
903
  sampleRate: track.sampleRate,
720
904
  codecPrivate,
@@ -747,7 +931,8 @@ var makeAudioTrackHandler = ({
747
931
  codec: audioOperation.audioCodec,
748
932
  signal: controller.signal,
749
933
  config: audioEncoderConfig,
750
- logLevel
934
+ logLevel,
935
+ progressTracker
751
936
  });
752
937
  const audioDecoder = createAudioDecoder({
753
938
  onFrame: async (frame) => {
@@ -761,13 +946,15 @@ var makeAudioTrackHandler = ({
761
946
  frame.close();
762
947
  },
763
948
  onError(error) {
764
- abortConversion(new error_cause_default(`Audio decoder of track ${track.trackId} failed (see .cause of this error)`, {
949
+ abortConversion(new error_cause_default(`Audio decoder of track ${track.trackId} failed. Config: ${JSON.stringify(audioDecoderConfig)} (see .cause of this error)`, {
765
950
  cause: error
766
951
  }));
767
952
  },
768
953
  signal: controller.signal,
769
954
  config: audioDecoderConfig,
770
- logLevel
955
+ logLevel,
956
+ track,
957
+ progressTracker
771
958
  });
772
959
  state.addWaitForFinishPromise(async () => {
773
960
  await audioDecoder.waitForFinish();
@@ -786,7 +973,7 @@ var arrayBufferToUint8Array = (buffer) => {
786
973
  };
787
974
 
788
975
  // src/default-on-video-track-handler.ts
789
- import { MediaParserInternals as MediaParserInternals3 } from "@remotion/media-parser";
976
+ import { MediaParserInternals as MediaParserInternals5 } from "@remotion/media-parser";
790
977
 
791
978
  // src/get-default-video-codec.ts
792
979
  var getDefaultVideoCodec = ({
@@ -795,7 +982,13 @@ var getDefaultVideoCodec = ({
795
982
  if (container === "webm") {
796
983
  return "vp8";
797
984
  }
798
- throw new Error(`Unhandled container: ${container} satisfies never`);
985
+ if (container === "mp4") {
986
+ return "h264";
987
+ }
988
+ if (container === "wav") {
989
+ return null;
990
+ }
991
+ throw new Error(`Unhandled container: ${container}`);
799
992
  };
800
993
 
801
994
  // src/default-on-video-track-handler.ts
@@ -803,26 +996,37 @@ var defaultOnVideoTrackHandler = async ({
803
996
  track,
804
997
  defaultVideoCodec,
805
998
  logLevel,
806
- container
999
+ container,
1000
+ rotate
807
1001
  }) => {
808
1002
  const canCopy = canCopyVideoTrack({
809
1003
  inputCodec: track.codecWithoutConfig,
810
- container
1004
+ container,
1005
+ inputRotation: track.rotation,
1006
+ rotationToApply: rotate
811
1007
  });
812
1008
  if (canCopy) {
813
- MediaParserInternals3.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
1009
+ MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
814
1010
  return Promise.resolve({ type: "copy" });
815
1011
  }
816
1012
  const videoCodec = defaultVideoCodec ?? getDefaultVideoCodec({ container });
1013
+ if (videoCodec === null) {
1014
+ MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): No default video codec, therefore dropping`);
1015
+ return Promise.resolve({ type: "drop" });
1016
+ }
817
1017
  const canReencode = await canReencodeVideoTrack({
818
1018
  videoCodec,
819
1019
  track
820
1020
  });
821
1021
  if (canReencode) {
822
- MediaParserInternals3.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
823
- return Promise.resolve({ type: "reencode", videoCodec });
1022
+ MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
1023
+ return Promise.resolve({
1024
+ type: "reencode",
1025
+ videoCodec,
1026
+ rotation: rotate - track.rotation
1027
+ });
824
1028
  }
825
- MediaParserInternals3.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
1029
+ MediaParserInternals5.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
826
1030
  return Promise.resolve({ type: "fail" });
827
1031
  };
828
1032
 
@@ -831,6 +1035,12 @@ var needsToCorrectVideoFrame = ({
831
1035
  videoFrame,
832
1036
  outputCodec
833
1037
  }) => {
1038
+ if (videoFrame.format === null) {
1039
+ return true;
1040
+ }
1041
+ if (videoFrame.format === "I420P10") {
1042
+ return true;
1043
+ }
834
1044
  return isFirefox() && videoFrame.format === "BGRX" && outputCodec === "h264";
835
1045
  };
836
1046
  var convertToCorrectVideoFrame = ({
@@ -858,41 +1068,43 @@ var convertToCorrectVideoFrame = ({
858
1068
 
859
1069
  // src/on-frame.ts
860
1070
  var onFrame = async ({
861
- frame,
1071
+ frame: unrotatedFrame,
862
1072
  onVideoFrame,
863
1073
  videoEncoder,
864
1074
  track,
865
- outputCodec
1075
+ outputCodec,
1076
+ rotation
866
1077
  }) => {
867
- const newFrame = onVideoFrame ? await onVideoFrame({ frame, track }) : frame;
868
- if (newFrame.codedHeight !== frame.displayHeight) {
869
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame displayHeight (${frame.displayHeight})`);
870
- }
871
- if (newFrame.codedWidth !== frame.displayWidth) {
872
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame displayWidth (${frame.displayWidth})`);
1078
+ const rotated = rotateVideoFrame({
1079
+ rotation,
1080
+ frame: unrotatedFrame
1081
+ });
1082
+ if (unrotatedFrame !== rotated) {
1083
+ unrotatedFrame.close();
873
1084
  }
874
- if (newFrame.displayWidth !== frame.displayWidth) {
875
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${newFrame.displayWidth}) than the input frame (${newFrame.displayHeight})`);
1085
+ const userProcessedFrame = onVideoFrame ? await onVideoFrame({ frame: rotated, track }) : rotated;
1086
+ if (userProcessedFrame.displayWidth !== rotated.displayWidth) {
1087
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${userProcessedFrame.displayWidth}) than the input frame (${userProcessedFrame.displayHeight})`);
876
1088
  }
877
- if (newFrame.displayHeight !== frame.displayHeight) {
878
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${newFrame.displayHeight}) than the input frame (${newFrame.displayHeight})`);
1089
+ if (userProcessedFrame.displayHeight !== rotated.displayHeight) {
1090
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${userProcessedFrame.displayHeight}) than the input frame (${userProcessedFrame.displayHeight})`);
879
1091
  }
880
- if (newFrame.timestamp !== frame.timestamp) {
881
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different timestamp (${newFrame.timestamp}) than the input frame (${newFrame.timestamp}). When calling new VideoFrame(), pass {timestamp: frame.timestamp} as second argument`);
1092
+ if (userProcessedFrame.timestamp !== rotated.timestamp) {
1093
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different timestamp (${userProcessedFrame.timestamp}) than the input frame (${rotated.timestamp}). When calling new VideoFrame(), pass {timestamp: frame.timestamp} as second argument`);
882
1094
  }
883
- if (newFrame.duration !== frame.duration) {
884
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${newFrame.duration}) than the input frame (${newFrame.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
1095
+ if ((userProcessedFrame.duration ?? 0) !== (rotated.duration ?? 0)) {
1096
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${userProcessedFrame.duration}) than the input frame (${rotated.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
885
1097
  }
886
1098
  const fixedFrame = convertToCorrectVideoFrame({
887
- videoFrame: newFrame,
1099
+ videoFrame: userProcessedFrame,
888
1100
  outputCodec
889
1101
  });
890
1102
  await videoEncoder.encodeFrame(fixedFrame, fixedFrame.timestamp);
891
1103
  fixedFrame.close();
892
- if (frame !== newFrame) {
893
- frame.close();
1104
+ if (rotated !== userProcessedFrame) {
1105
+ rotated.close();
894
1106
  }
895
- if (fixedFrame !== newFrame) {
1107
+ if (fixedFrame !== userProcessedFrame) {
896
1108
  fixedFrame.close();
897
1109
  }
898
1110
  };
@@ -903,9 +1115,14 @@ var createVideoDecoder = ({
903
1115
  onError,
904
1116
  signal,
905
1117
  config,
906
- logLevel
1118
+ logLevel,
1119
+ progress
907
1120
  }) => {
908
- const ioSynchronizer = makeIoSynchronizer(logLevel, "Video decoder");
1121
+ const ioSynchronizer = makeIoSynchronizer({
1122
+ logLevel,
1123
+ label: "Video decoder",
1124
+ progress
1125
+ });
909
1126
  let outputQueue = Promise.resolve();
910
1127
  const videoDecoder = new VideoDecoder({
911
1128
  output(inputFrame) {
@@ -951,7 +1168,11 @@ var createVideoDecoder = ({
951
1168
  if (videoDecoder.state === "closed") {
952
1169
  return;
953
1170
  }
954
- await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 2 });
1171
+ await ioSynchronizer.waitFor({
1172
+ unemitted: 20,
1173
+ _unprocessed: 2,
1174
+ minimumProgress: sample.timestamp - 5000000
1175
+ });
955
1176
  if (sample.type === "key") {
956
1177
  await videoDecoder.flush();
957
1178
  }
@@ -988,12 +1209,17 @@ var createVideoEncoder = ({
988
1209
  signal,
989
1210
  config,
990
1211
  logLevel,
991
- outputCodec
1212
+ outputCodec,
1213
+ progress
992
1214
  }) => {
993
1215
  if (signal.aborted) {
994
1216
  throw new Error("Not creating video encoder, already aborted");
995
1217
  }
996
- const ioSynchronizer = makeIoSynchronizer(logLevel, "Video encoder");
1218
+ const ioSynchronizer = makeIoSynchronizer({
1219
+ logLevel,
1220
+ label: "Video encoder",
1221
+ progress
1222
+ });
997
1223
  let outputQueue = Promise.resolve();
998
1224
  const encoder = new VideoEncoder({
999
1225
  error(error) {
@@ -1035,7 +1261,8 @@ var createVideoEncoder = ({
1035
1261
  }
1036
1262
  await ioSynchronizer.waitFor({
1037
1263
  unemitted: 10,
1038
- _unprocessed: 10
1264
+ _unprocessed: 10,
1265
+ minimumProgress: frame.timestamp - 5000000
1039
1266
  });
1040
1267
  if (encoder.state === "closed") {
1041
1268
  return;
@@ -1075,7 +1302,9 @@ var makeVideoTrackHandler = ({
1075
1302
  defaultVideoCodec,
1076
1303
  onVideoTrack,
1077
1304
  logLevel,
1078
- container
1305
+ container,
1306
+ rotate,
1307
+ progress
1079
1308
  }) => async (track) => {
1080
1309
  if (controller.signal.aborted) {
1081
1310
  throw new error_cause_default("Aborted");
@@ -1084,7 +1313,8 @@ var makeVideoTrackHandler = ({
1084
1313
  track,
1085
1314
  defaultVideoCodec,
1086
1315
  logLevel,
1087
- container
1316
+ container,
1317
+ rotate
1088
1318
  });
1089
1319
  if (videoOperation.type === "drop") {
1090
1320
  return null;
@@ -1119,10 +1349,19 @@ var makeVideoTrackHandler = ({
1119
1349
  });
1120
1350
  };
1121
1351
  }
1352
+ if (videoOperation.type !== "reencode") {
1353
+ 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"`);
1354
+ }
1355
+ const rotation = videoOperation.rotate ?? -track.rotation;
1356
+ const { height: newHeight, width: newWidth } = calculateNewDimensionsFromDimensions({
1357
+ width: track.codedWidth,
1358
+ height: track.codedHeight,
1359
+ rotation
1360
+ });
1122
1361
  const videoEncoderConfig = await getVideoEncoderConfig({
1123
1362
  codec: videoOperation.videoCodec,
1124
- height: track.displayAspectHeight,
1125
- width: track.displayAspectWidth,
1363
+ height: newHeight,
1364
+ width: newWidth,
1126
1365
  fps: track.fps
1127
1366
  });
1128
1367
  const videoDecoderConfig = await getVideoDecoderConfigWithHardwareAcceleration(track);
@@ -1137,8 +1376,8 @@ var makeVideoTrackHandler = ({
1137
1376
  const { trackNumber } = await state.addTrack({
1138
1377
  type: "video",
1139
1378
  color: track.color,
1140
- width: track.codedWidth,
1141
- height: track.codedHeight,
1379
+ width: newWidth,
1380
+ height: newHeight,
1142
1381
  codec: videoOperation.videoCodec,
1143
1382
  codecPrivate: null,
1144
1383
  timescale: track.timescale
@@ -1168,7 +1407,8 @@ var makeVideoTrackHandler = ({
1168
1407
  signal: controller.signal,
1169
1408
  config: videoEncoderConfig,
1170
1409
  logLevel,
1171
- outputCodec: videoOperation.videoCodec
1410
+ outputCodec: videoOperation.videoCodec,
1411
+ progress
1172
1412
  });
1173
1413
  const videoDecoder = createVideoDecoder({
1174
1414
  config: videoDecoderConfig,
@@ -1178,7 +1418,8 @@ var makeVideoTrackHandler = ({
1178
1418
  track,
1179
1419
  videoEncoder,
1180
1420
  onVideoFrame,
1181
- outputCodec: videoOperation.videoCodec
1421
+ outputCodec: videoOperation.videoCodec,
1422
+ rotation
1182
1423
  });
1183
1424
  },
1184
1425
  onError: (err) => {
@@ -1187,7 +1428,8 @@ var makeVideoTrackHandler = ({
1187
1428
  }));
1188
1429
  },
1189
1430
  signal: controller.signal,
1190
- logLevel
1431
+ logLevel,
1432
+ progress
1191
1433
  });
1192
1434
  state.addWaitForFinishPromise(async () => {
1193
1435
  Log.verbose(logLevel, "Waiting for video decoder to finish");
@@ -1203,6 +1445,21 @@ var makeVideoTrackHandler = ({
1203
1445
  };
1204
1446
  };
1205
1447
 
1448
+ // src/select-container-creator.ts
1449
+ import { MediaParserInternals as MediaParserInternals6 } from "@remotion/media-parser";
1450
+ var selectContainerCreator = (container) => {
1451
+ if (container === "mp4") {
1452
+ return MediaParserInternals6.createIsoBaseMedia;
1453
+ }
1454
+ if (container === "wav") {
1455
+ return MediaParserInternals6.createWav;
1456
+ }
1457
+ if (container === "webm") {
1458
+ return MediaParserInternals6.createMatroskaMedia;
1459
+ }
1460
+ throw new Error(`Unsupported container: ${container}`);
1461
+ };
1462
+
1206
1463
  // src/throttled-state-update.ts
1207
1464
  var throttledStateUpdate = ({
1208
1465
  updateFn,
@@ -1271,18 +1528,19 @@ var convertMedia = async function({
1271
1528
  logLevel = "info",
1272
1529
  writer,
1273
1530
  progressIntervalInMs,
1531
+ rotate,
1274
1532
  ...more
1275
1533
  }) {
1276
1534
  if (userPassedAbortSignal?.aborted) {
1277
1535
  return Promise.reject(new error_cause_default("Aborted"));
1278
1536
  }
1279
- if (container !== "webm" && container !== "mp4") {
1280
- return Promise.reject(new TypeError('Only `to: "webm"` and `to: "mp4"` is supported currently'));
1537
+ if (container !== "webm" && container !== "mp4" && container !== "wav") {
1538
+ return Promise.reject(new TypeError('Only `to: "webm"`, `to: "mp4"` and `to: "wav"` is supported currently'));
1281
1539
  }
1282
1540
  if (videoCodec && videoCodec !== "vp8" && videoCodec !== "vp9") {
1283
1541
  return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
1284
1542
  }
1285
- const { resolve, reject, getPromiseToImmediatelyReturn } = withResolversAndWaitForReturn();
1543
+ const { resolve, reject, getPromiseToImmediatelyReturn } = MediaParserInternals7.withResolversAndWaitForReturn();
1286
1544
  const controller = new AbortController;
1287
1545
  const abortConversion = (errCause) => {
1288
1546
  reject(errCause);
@@ -1294,12 +1552,13 @@ var convertMedia = async function({
1294
1552
  abortConversion(new error_cause_default("Conversion aborted by user"));
1295
1553
  };
1296
1554
  userPassedAbortSignal?.addEventListener("abort", onUserAbort);
1297
- const creator = container === "webm" ? MediaParserInternals4.createMatroskaMedia : MediaParserInternals4.createIsoBaseMedia;
1555
+ const creator = selectContainerCreator(container);
1298
1556
  const throttledState = throttledStateUpdate({
1299
1557
  updateFn: onProgressDoNotCallDirectly ?? null,
1300
1558
  everyMilliseconds: progressIntervalInMs ?? 100,
1301
1559
  signal: controller.signal
1302
1560
  });
1561
+ const progressTracker = MediaParserInternals7.makeProgressTracker();
1303
1562
  const state = await creator({
1304
1563
  filename: generateOutputFilename(src, container),
1305
1564
  writer: await autoSelectWriter(writer, logLevel),
@@ -1326,7 +1585,8 @@ var convertMedia = async function({
1326
1585
  return prevState;
1327
1586
  });
1328
1587
  },
1329
- logLevel
1588
+ logLevel,
1589
+ progressTracker
1330
1590
  });
1331
1591
  const onVideoTrack = makeVideoTrackHandler({
1332
1592
  state,
@@ -1337,7 +1597,9 @@ var convertMedia = async function({
1337
1597
  defaultVideoCodec: videoCodec ?? null,
1338
1598
  onVideoTrack: userVideoResolver ?? null,
1339
1599
  logLevel,
1340
- container
1600
+ container,
1601
+ rotate: rotate ?? 0,
1602
+ progress: progressTracker
1341
1603
  });
1342
1604
  const onAudioTrack = makeAudioTrackHandler({
1343
1605
  abortConversion,
@@ -1347,7 +1609,8 @@ var convertMedia = async function({
1347
1609
  state,
1348
1610
  onAudioTrack: userAudioResolver ?? null,
1349
1611
  logLevel,
1350
- container
1612
+ container,
1613
+ progressTracker
1351
1614
  });
1352
1615
  parseMedia({
1353
1616
  logLevel,
@@ -1398,7 +1661,46 @@ var convertMedia = async function({
1398
1661
  userPassedAbortSignal?.removeEventListener("abort", onUserAbort);
1399
1662
  });
1400
1663
  };
1664
+ // src/get-available-audio-codecs.ts
1665
+ var getAvailableAudioCodecs = ({
1666
+ container
1667
+ }) => {
1668
+ if (container === "mp4") {
1669
+ return ["aac"];
1670
+ }
1671
+ if (container === "webm") {
1672
+ return ["opus"];
1673
+ }
1674
+ if (container === "wav") {
1675
+ return ["wav"];
1676
+ }
1677
+ throw new Error(`Unsupported container: ${container}`);
1678
+ };
1679
+ // src/get-available-containers.ts
1680
+ var availableContainers = ["webm", "mp4", "wav"];
1681
+ var getAvailableContainers = () => {
1682
+ return availableContainers;
1683
+ };
1684
+ // src/get-available-video-codecs.ts
1685
+ var getAvailableVideoCodecs = ({
1686
+ container
1687
+ }) => {
1688
+ if (container === "mp4") {
1689
+ return ["h264"];
1690
+ }
1691
+ if (container === "webm") {
1692
+ return ["vp8", "vp9"];
1693
+ }
1694
+ if (container === "wav") {
1695
+ return [];
1696
+ }
1697
+ throw new Error(`Unsupported container: ${container}`);
1698
+ };
1401
1699
  // src/index.ts
1700
+ var WebCodecsInternals = {
1701
+ rotateVideoFrame,
1702
+ normalizeVideoRotation
1703
+ };
1402
1704
  setRemotionImported();
1403
1705
  export {
1404
1706
  getDefaultVideoCodec,
@@ -1416,5 +1718,6 @@ export {
1416
1718
  canReencodeVideoTrack,
1417
1719
  canReencodeAudioTrack,
1418
1720
  canCopyVideoTrack,
1419
- canCopyAudioTrack
1721
+ canCopyAudioTrack,
1722
+ WebCodecsInternals
1420
1723
  };