@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
package/README.md CHANGED
@@ -18,7 +18,7 @@ Remove the `^` character from the version number to use the exact version.
18
18
  See the [documentation](https://remotion.dev/webcodecs) for more information.
19
19
 
20
20
  ## License
21
- This package is licensed under the [/docs/license](Remotion License).
21
+ This package is licensed under the [Remotion License](/docs/license).
22
22
  We consider a team of 4 or more people a "company".
23
23
 
24
24
  **For "companies"**: A Remotion Company license needs to be obtained to use this package.
@@ -26,4 +26,4 @@ In a future version of `@remotion/webcodecs`, this package will also require the
26
26
 
27
27
  **For individuals and teams up to 3**: You can use this package for free.
28
28
 
29
- This is a short, non-binding explanation of our license. See the [https://remotion.dev/docs/license](License) itself for more details.
29
+ This is a short, non-binding explanation of our license. See the [License](https://remotion.dev/docs/license) itself for more details.
@@ -1 +1,2 @@
1
- export declare const getAudioDecoderConfig: (config: AudioDecoderConfig) => Promise<AudioDecoderConfig | null>;
1
+ import type { LogLevel } from './log';
2
+ export declare const getAudioDecoderConfig: (config: AudioDecoderConfig, logLevel: LogLevel) => Promise<AudioDecoderConfig | null>;
@@ -1,15 +1,56 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAudioDecoderConfig = void 0;
4
- const getAudioDecoderConfig = async (config) => {
4
+ const browser_quirks_1 = require("./browser-quirks");
5
+ const log_1 = require("./log");
6
+ const overrideBrowserQuirks = ({ config, logLevel, }) => {
7
+ const bytes = config.description;
8
+ if (!bytes) {
9
+ return config;
10
+ }
11
+ if (bytes[0] === 18 && bytes[1] === 8) {
12
+ // riverside_use_cursor_.mp4
13
+ if ((0, browser_quirks_1.isFirefox)()) {
14
+ return {
15
+ ...config,
16
+ codec: 'mp4a.40.2',
17
+ description: bytes,
18
+ };
19
+ }
20
+ if (!(0, browser_quirks_1.isChrome)()) {
21
+ return config;
22
+ }
23
+ log_1.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');
24
+ return {
25
+ ...config,
26
+ description: new Uint8Array([18, 16]),
27
+ };
28
+ }
29
+ if (bytes.byteLength === 2 && bytes[0] === 17 && bytes[1] === 136) {
30
+ log_1.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');
31
+ return {
32
+ ...config,
33
+ description: new Uint8Array([18, 144]),
34
+ };
35
+ }
36
+ return config;
37
+ };
38
+ const getAudioDecoderConfig = async (config, logLevel) => {
39
+ if (config.codec === 'pcm-s16') {
40
+ return config;
41
+ }
5
42
  if (typeof AudioDecoder === 'undefined') {
6
43
  return null;
7
44
  }
8
45
  if (typeof EncodedAudioChunk === 'undefined') {
9
46
  return null;
10
47
  }
11
- if ((await AudioDecoder.isConfigSupported(config)).supported) {
12
- return config;
48
+ const realConfig = overrideBrowserQuirks({
49
+ config,
50
+ logLevel,
51
+ });
52
+ if ((await AudioDecoder.isConfigSupported(realConfig)).supported) {
53
+ return realConfig;
13
54
  }
14
55
  return null;
15
56
  };
@@ -1,14 +1,17 @@
1
- import type { AudioOrVideoSample, LogLevel } from '@remotion/media-parser';
1
+ import type { AudioOrVideoSample, AudioTrack, LogLevel, ProgressTracker } from '@remotion/media-parser';
2
2
  export type WebCodecsAudioDecoder = {
3
3
  processSample: (audioSample: AudioOrVideoSample) => Promise<void>;
4
4
  waitForFinish: () => Promise<void>;
5
5
  close: () => void;
6
6
  flush: () => Promise<void>;
7
7
  };
8
- export declare const createAudioDecoder: ({ onFrame, onError, signal, config, logLevel, }: {
8
+ export type CreateAudioDecoderInit = {
9
9
  onFrame: (frame: AudioData) => Promise<void>;
10
10
  onError: (error: DOMException) => void;
11
11
  signal: AbortSignal;
12
12
  config: AudioDecoderConfig;
13
13
  logLevel: LogLevel;
14
- }) => WebCodecsAudioDecoder;
14
+ track: AudioTrack;
15
+ progressTracker: ProgressTracker;
16
+ };
17
+ export declare const createAudioDecoder: ({ onFrame, onError, signal, config, logLevel, track, progressTracker, }: CreateAudioDecoderInit) => WebCodecsAudioDecoder;
@@ -1,12 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAudioDecoder = void 0;
4
+ const get_wave_audio_decoder_1 = require("./get-wave-audio-decoder");
4
5
  const io_synchronizer_1 = require("./io-manager/io-synchronizer");
5
- const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) => {
6
+ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, track, progressTracker, }) => {
6
7
  if (signal.aborted) {
7
8
  throw new Error('Not creating audio decoder, already aborted');
8
9
  }
9
- const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)(logLevel, 'Audio decoder');
10
+ if (config.codec === 'pcm-s16') {
11
+ return (0, get_wave_audio_decoder_1.getWaveAudioDecoder)({ onFrame, track });
12
+ }
13
+ const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
14
+ logLevel,
15
+ label: 'Audio decoder',
16
+ progress: progressTracker,
17
+ });
10
18
  let outputQueue = Promise.resolve();
11
19
  const audioDecoder = new AudioDecoder({
12
20
  output(inputFrame) {
@@ -53,7 +61,11 @@ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) =>
53
61
  if (audioDecoder.state === 'closed') {
54
62
  return;
55
63
  }
56
- await ioSynchronizer.waitFor({ unemitted: 100, _unprocessed: 2 });
64
+ await ioSynchronizer.waitFor({
65
+ unemitted: 20,
66
+ _unprocessed: 20,
67
+ minimumProgress: audioSample.timestamp - 10000000,
68
+ });
57
69
  // Don't flush, it messes up the audio
58
70
  const chunk = new EncodedAudioChunk(audioSample);
59
71
  audioDecoder.decode(chunk);
@@ -62,11 +74,21 @@ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) =>
62
74
  let queue = Promise.resolve();
63
75
  return {
64
76
  processSample: (sample) => {
77
+ // In example.avi, we have samples with 0 data
78
+ // Chrome fails on these
79
+ if (sample.data.length === 0) {
80
+ return queue;
81
+ }
65
82
  queue = queue.then(() => processSample(sample));
66
83
  return queue;
67
84
  },
68
85
  waitForFinish: async () => {
69
- await audioDecoder.flush();
86
+ // Firefox might throw "Needs to be configured first"
87
+ try {
88
+ await audioDecoder.flush();
89
+ }
90
+ catch (_a) { }
91
+ await queue;
70
92
  await ioSynchronizer.waitForFinish();
71
93
  await outputQueue;
72
94
  },
@@ -1 +1,4 @@
1
- export declare const getAudioEncoderConfig: (config: AudioEncoderConfig) => Promise<AudioEncoderConfig | null>;
1
+ import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
2
+ export declare const getAudioEncoderConfig: (config: AudioEncoderConfig & {
3
+ codec: ConvertMediaAudioCodec;
4
+ }) => Promise<AudioEncoderConfig | null>;
@@ -8,6 +8,9 @@ const getCodecString = (audioCodec) => {
8
8
  if (audioCodec === 'aac') {
9
9
  return 'mp4a.40.02';
10
10
  }
11
+ if (audioCodec === 'wav') {
12
+ return 'wav-should-not-to-into-audio-encoder';
13
+ }
11
14
  throw new Error(`Unsupported audio codec: ${audioCodec}`);
12
15
  };
13
16
  const getAudioEncoderConfig = async (config) => {
@@ -15,6 +18,9 @@ const getAudioEncoderConfig = async (config) => {
15
18
  ...config,
16
19
  codec: getCodecString(config.codec),
17
20
  };
21
+ if (config.codec === 'wav') {
22
+ return actualConfig;
23
+ }
18
24
  if (typeof AudioEncoder === 'undefined') {
19
25
  return null;
20
26
  }
@@ -1,12 +1,12 @@
1
- import type { LogLevel } from '@remotion/media-parser';
2
- import type { ConvertMediaAudioCodec } from './codec-id';
1
+ import type { LogLevel, ProgressTracker } from '@remotion/media-parser';
2
+ import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
3
3
  export type WebCodecsAudioEncoder = {
4
4
  encodeFrame: (audioData: AudioData) => Promise<void>;
5
5
  waitForFinish: () => Promise<void>;
6
6
  close: () => void;
7
7
  flush: () => Promise<void>;
8
8
  };
9
- export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }: {
9
+ export type AudioEncoderInit = {
10
10
  onChunk: (chunk: EncodedAudioChunk) => Promise<void>;
11
11
  onError: (error: DOMException) => void;
12
12
  codec: ConvertMediaAudioCodec;
@@ -14,4 +14,6 @@ export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, con
14
14
  config: AudioEncoderConfig;
15
15
  logLevel: LogLevel;
16
16
  onNewAudioSampleRate: (sampleRate: number) => void;
17
- }) => WebCodecsAudioEncoder;
17
+ progressTracker: ProgressTracker;
18
+ };
19
+ export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, progressTracker, }: AudioEncoderInit) => WebCodecsAudioEncoder;
@@ -2,11 +2,19 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createAudioEncoder = void 0;
4
4
  const io_synchronizer_1 = require("./io-manager/io-synchronizer");
5
- const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }) => {
5
+ const wav_audio_encoder_1 = require("./wav-audio-encoder");
6
+ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, progressTracker, }) => {
6
7
  if (signal.aborted) {
7
8
  throw new Error('Not creating audio encoder, already aborted');
8
9
  }
9
- const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)(logLevel, 'Audio encoder');
10
+ if (codec === 'wav') {
11
+ return (0, wav_audio_encoder_1.getWaveAudioEncoder)({ onChunk, signal });
12
+ }
13
+ const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
14
+ logLevel,
15
+ label: 'Audio encoder',
16
+ progress: progressTracker,
17
+ });
10
18
  let prom = Promise.resolve();
11
19
  const encoder = new AudioEncoder({
12
20
  output: (chunk) => {
@@ -50,7 +58,11 @@ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEnco
50
58
  if (encoder.state === 'closed') {
51
59
  return;
52
60
  }
53
- await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 20 });
61
+ await ioSynchronizer.waitFor({
62
+ unemitted: 20,
63
+ _unprocessed: 20,
64
+ minimumProgress: audioData.timestamp - 10000000,
65
+ });
54
66
  // @ts-expect-error - can have changed in the meanwhile
55
67
  if (encoder.state === 'closed') {
56
68
  return;
@@ -1,2 +1,3 @@
1
1
  export declare const isFirefox: () => boolean;
2
2
  export declare const isSafari: () => boolean;
3
+ export declare const isChrome: () => boolean;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isSafari = exports.isFirefox = void 0;
3
+ exports.isChrome = exports.isSafari = exports.isFirefox = void 0;
4
4
  const isFirefox = () => {
5
5
  return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
6
6
  };
@@ -9,3 +9,7 @@ const isSafari = () => {
9
9
  return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
10
10
  };
11
11
  exports.isSafari = isSafari;
12
+ const isChrome = () => {
13
+ return navigator.userAgent.toLowerCase().indexOf('chrome') > -1;
14
+ };
15
+ exports.isChrome = isChrome;
@@ -1,5 +1,5 @@
1
1
  import type { MediaParserAudioCodec } from '@remotion/media-parser';
2
- import type { ConvertMediaContainer } from './codec-id';
2
+ import type { ConvertMediaContainer } from './get-available-containers';
3
3
  export declare const canCopyAudioTrack: ({ inputCodec, container, }: {
4
4
  inputCodec: MediaParserAudioCodec;
5
5
  container: ConvertMediaContainer;
@@ -8,6 +8,9 @@ const canCopyAudioTrack = ({ inputCodec, container, }) => {
8
8
  if (container === 'mp4') {
9
9
  return inputCodec === 'aac';
10
10
  }
11
+ if (container === 'wav') {
12
+ return false;
13
+ }
11
14
  throw new Error(`Unhandled codec: ${container}`);
12
15
  };
13
16
  exports.canCopyAudioTrack = canCopyAudioTrack;
@@ -1,6 +1,8 @@
1
1
  import type { MediaParserVideoCodec } from '@remotion/media-parser';
2
- import type { ConvertMediaContainer } from './codec-id';
3
- export declare const canCopyVideoTrack: ({ inputCodec, container, }: {
2
+ import type { ConvertMediaContainer } from './get-available-containers';
3
+ export declare const canCopyVideoTrack: ({ inputCodec, container, inputRotation, rotationToApply, }: {
4
4
  inputCodec: MediaParserVideoCodec;
5
+ inputRotation: number;
6
+ rotationToApply: number;
5
7
  container: ConvertMediaContainer;
6
8
  }) => boolean;
@@ -1,12 +1,20 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canCopyVideoTrack = void 0;
4
- const canCopyVideoTrack = ({ inputCodec, container, }) => {
4
+ const rotate_video_frame_1 = require("./rotate-video-frame");
5
+ const canCopyVideoTrack = ({ inputCodec, container, inputRotation, rotationToApply, }) => {
6
+ if ((0, rotate_video_frame_1.normalizeVideoRotation)(inputRotation) !==
7
+ (0, rotate_video_frame_1.normalizeVideoRotation)(rotationToApply)) {
8
+ return false;
9
+ }
5
10
  if (container === 'webm') {
6
11
  return inputCodec === 'vp8' || inputCodec === 'vp9';
7
12
  }
8
13
  if (container === 'mp4') {
9
- return inputCodec === 'h264' || inputCodec === 'h265';
14
+ return inputCodec === 'h264';
15
+ }
16
+ if (container === 'wav') {
17
+ return false;
10
18
  }
11
19
  throw new Error(`Unhandled codec: ${container}`);
12
20
  };
@@ -1,7 +1,8 @@
1
- import type { AudioTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaAudioCodec } from './codec-id';
3
- export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, }: {
1
+ import type { AudioTrack, LogLevel } from '@remotion/media-parser';
2
+ import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
3
+ export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, logLevel, }: {
4
4
  track: AudioTrack;
5
5
  audioCodec: ConvertMediaAudioCodec;
6
6
  bitrate: number;
7
+ logLevel?: LogLevel;
7
8
  }) => Promise<boolean>;
@@ -3,8 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canReencodeAudioTrack = void 0;
4
4
  const audio_decoder_config_1 = require("./audio-decoder-config");
5
5
  const audio_encoder_config_1 = require("./audio-encoder-config");
6
- const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, }) => {
7
- const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track);
6
+ const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, logLevel = 'info', }) => {
7
+ const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track, logLevel);
8
+ if (audioCodec === 'wav' && audioDecoderConfig) {
9
+ return true;
10
+ }
8
11
  const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
9
12
  codec: audioCodec,
10
13
  numberOfChannels: track.numberOfChannels,
@@ -1,5 +1,5 @@
1
1
  import type { VideoTrack } from '@remotion/media-parser';
2
- import type { ConvertMediaVideoCodec } from './codec-id';
2
+ import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
3
3
  export declare const canReencodeVideoTrack: ({ videoCodec, track, }: {
4
4
  videoCodec: ConvertMediaVideoCodec;
5
5
  track: VideoTrack;
@@ -1,10 +1,10 @@
1
- declare const availableContainers: readonly ["webm", "mp4"];
1
+ declare const availableContainers: readonly ["webm", "mp4", "wav"];
2
2
  export type ConvertMediaContainer = (typeof availableContainers)[number];
3
3
  export declare const getAvailableContainers: () => readonly ConvertMediaContainer[];
4
4
  declare const availableVideoCodecs: readonly ["vp8", "vp9", "h264"];
5
5
  export type ConvertMediaVideoCodec = (typeof availableVideoCodecs)[number];
6
6
  export declare const getAvailableVideoCodecs: (container: ConvertMediaContainer) => ConvertMediaVideoCodec[];
7
- declare const availableAudioCodecs: readonly ["opus", "aac"];
7
+ declare const availableAudioCodecs: readonly ["opus", "aac", "wav"];
8
8
  export declare const getAvailableAudioCodecs: (container: ConvertMediaContainer) => ConvertMediaAudioCodec[];
9
9
  export type ConvertMediaAudioCodec = (typeof availableAudioCodecs)[number];
10
10
  export {};
package/dist/codec-id.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAvailableAudioCodecs = exports.getAvailableVideoCodecs = exports.getAvailableContainers = void 0;
4
- const availableContainers = ['webm', 'mp4'];
4
+ const availableContainers = ['webm', 'mp4', 'wav'];
5
5
  const getAvailableContainers = () => {
6
6
  return availableContainers;
7
7
  };
@@ -15,11 +15,14 @@ const getAvailableVideoCodecs = (container) => {
15
15
  if (container === 'webm') {
16
16
  return ['vp8', 'vp9'];
17
17
  }
18
+ if (container === 'wav') {
19
+ return [];
20
+ }
18
21
  throw new Error(`Unsupported container: ${container}`);
19
22
  };
20
23
  exports.getAvailableVideoCodecs = getAvailableVideoCodecs;
21
24
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
- const availableAudioCodecs = ['opus', 'aac'];
25
+ const availableAudioCodecs = ['opus', 'aac', 'wav'];
23
26
  const getAvailableAudioCodecs = (container) => {
24
27
  if (container === 'mp4') {
25
28
  return ['aac'];
@@ -27,6 +30,9 @@ const getAvailableAudioCodecs = (container) => {
27
30
  if (container === 'webm') {
28
31
  return ['opus'];
29
32
  }
33
+ if (container === 'wav') {
34
+ return ['wav'];
35
+ }
30
36
  throw new Error(`Unsupported container: ${container}`);
31
37
  };
32
38
  exports.getAvailableAudioCodecs = getAvailableAudioCodecs;
@@ -3,7 +3,9 @@
3
3
  * For licensing, see: https://remotion.dev/docs/webcodecs#license
4
4
  */
5
5
  import type { LogLevel, Options, ParseMediaDynamicOptions, ParseMediaFields, ParseMediaOptions, VideoTrack, WriterInterface } from '@remotion/media-parser';
6
- import type { ConvertMediaAudioCodec, ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
6
+ import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
7
+ import type { ConvertMediaContainer } from './get-available-containers';
8
+ import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
7
9
  import { type ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
8
10
  import { type ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
9
11
  export type ConvertMediaProgress = {
@@ -26,7 +28,7 @@ export type ConvertMediaOnVideoFrame = (options: {
26
28
  frame: VideoFrame;
27
29
  track: VideoTrack;
28
30
  }) => Promise<VideoFrame> | VideoFrame;
29
- export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, ...more }: {
31
+ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, rotate, ...more }: {
30
32
  src: ParseMediaOptions<F>["src"];
31
33
  container: ConvertMediaContainer;
32
34
  onVideoFrame?: ConvertMediaOnVideoFrame;
@@ -40,4 +42,5 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
40
42
  logLevel?: LogLevel;
41
43
  writer?: WriterInterface;
42
44
  progressIntervalInMs?: number;
45
+ rotate?: number;
43
46
  } & ParseMediaDynamicOptions<F>) => Promise<ConvertMediaResult>;
@@ -15,20 +15,20 @@ const error_cause_1 = __importDefault(require("./error-cause"));
15
15
  const generate_output_filename_1 = require("./generate-output-filename");
16
16
  const on_audio_track_1 = require("./on-audio-track");
17
17
  const on_video_track_1 = require("./on-video-track");
18
+ const select_container_creator_1 = require("./select-container-creator");
18
19
  const throttled_state_update_1 = require("./throttled-state-update");
19
- const with_resolvers_1 = require("./with-resolvers");
20
- const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, ...more }) {
20
+ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, rotate, ...more }) {
21
21
  var _a, _b;
22
22
  if (userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.aborted) {
23
23
  return Promise.reject(new error_cause_1.default('Aborted'));
24
24
  }
25
- if (container !== 'webm' && container !== 'mp4') {
26
- return Promise.reject(new TypeError('Only `to: "webm"` and `to: "mp4"` is supported currently'));
25
+ if (container !== 'webm' && container !== 'mp4' && container !== 'wav') {
26
+ return Promise.reject(new TypeError('Only `to: "webm"`, `to: "mp4"` and `to: "wav"` is supported currently'));
27
27
  }
28
28
  if (videoCodec && videoCodec !== 'vp8' && videoCodec !== 'vp9') {
29
29
  return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
30
30
  }
31
- const { resolve, reject, getPromiseToImmediatelyReturn } = (0, with_resolvers_1.withResolversAndWaitForReturn)();
31
+ const { resolve, reject, getPromiseToImmediatelyReturn } = media_parser_1.MediaParserInternals.withResolversAndWaitForReturn();
32
32
  const controller = new AbortController();
33
33
  const abortConversion = (errCause) => {
34
34
  reject(errCause);
@@ -40,14 +40,13 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
40
40
  abortConversion(new error_cause_1.default('Conversion aborted by user'));
41
41
  };
42
42
  userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.addEventListener('abort', onUserAbort);
43
- const creator = container === 'webm'
44
- ? media_parser_1.MediaParserInternals.createMatroskaMedia
45
- : media_parser_1.MediaParserInternals.createIsoBaseMedia;
43
+ const creator = (0, select_container_creator_1.selectContainerCreator)(container);
46
44
  const throttledState = (0, throttled_state_update_1.throttledStateUpdate)({
47
45
  updateFn: onProgressDoNotCallDirectly !== null && onProgressDoNotCallDirectly !== void 0 ? onProgressDoNotCallDirectly : null,
48
46
  everyMilliseconds: progressIntervalInMs !== null && progressIntervalInMs !== void 0 ? progressIntervalInMs : 100,
49
47
  signal: controller.signal,
50
48
  });
49
+ const progressTracker = media_parser_1.MediaParserInternals.makeProgressTracker();
51
50
  const state = await creator({
52
51
  filename: (0, generate_output_filename_1.generateOutputFilename)(src, container),
53
52
  writer: await (0, auto_select_writer_1.autoSelectWriter)(writer, logLevel),
@@ -77,6 +76,7 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
77
76
  });
78
77
  },
79
78
  logLevel,
79
+ progressTracker,
80
80
  });
81
81
  const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
82
82
  state,
@@ -88,6 +88,8 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
88
88
  onVideoTrack: userVideoResolver !== null && userVideoResolver !== void 0 ? userVideoResolver : null,
89
89
  logLevel,
90
90
  container,
91
+ rotate: rotate !== null && rotate !== void 0 ? rotate : 0,
92
+ progress: progressTracker,
91
93
  });
92
94
  const onAudioTrack = (0, on_audio_track_1.makeAudioTrackHandler)({
93
95
  abortConversion,
@@ -98,6 +100,7 @@ const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgress
98
100
  onAudioTrack: userAudioResolver !== null && userAudioResolver !== void 0 ? userAudioResolver : null,
99
101
  logLevel,
100
102
  container,
103
+ progressTracker,
101
104
  });
102
105
  (0, media_parser_1.parseMedia)({
103
106
  logLevel,
@@ -1,4 +1,4 @@
1
- import type { ConvertMediaVideoCodec } from './codec-id';
1
+ import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
2
2
  export declare const needsToCorrectVideoFrame: ({ videoFrame, outputCodec, }: {
3
3
  videoFrame: VideoFrame;
4
4
  outputCodec: ConvertMediaVideoCodec;
@@ -3,6 +3,14 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.convertToCorrectVideoFrame = exports.needsToCorrectVideoFrame = void 0;
4
4
  const browser_quirks_1 = require("./browser-quirks");
5
5
  const needsToCorrectVideoFrame = ({ videoFrame, outputCodec, }) => {
6
+ // On Chrome when dropping a vertical iPhone video
7
+ if (videoFrame.format === null) {
8
+ return true;
9
+ }
10
+ // copy8f9178c2-e8ab-4538-9591-f8336602e49b-3mp4 - HDR videos
11
+ if (videoFrame.format === 'I420P10') {
12
+ return true;
13
+ }
6
14
  return (0, browser_quirks_1.isFirefox)() && videoFrame.format === 'BGRX' && outputCodec === 'h264';
7
15
  };
8
16
  exports.needsToCorrectVideoFrame = needsToCorrectVideoFrame;
@@ -5,23 +5,33 @@ const media_parser_1 = require("@remotion/media-parser");
5
5
  const can_copy_video_track_1 = require("./can-copy-video-track");
6
6
  const can_reencode_video_track_1 = require("./can-reencode-video-track");
7
7
  const get_default_video_codec_1 = require("./get-default-video-codec");
8
- const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel, container, }) => {
8
+ const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel, container, rotate, }) => {
9
9
  const canCopy = (0, can_copy_video_track_1.canCopyVideoTrack)({
10
10
  inputCodec: track.codecWithoutConfig,
11
11
  container,
12
+ inputRotation: track.rotation,
13
+ rotationToApply: rotate,
12
14
  });
13
15
  if (canCopy) {
14
16
  media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
15
17
  return Promise.resolve({ type: 'copy' });
16
18
  }
17
19
  const videoCodec = defaultVideoCodec !== null && defaultVideoCodec !== void 0 ? defaultVideoCodec : (0, get_default_video_codec_1.getDefaultVideoCodec)({ container });
20
+ if (videoCodec === null) {
21
+ media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): No default video codec, therefore dropping`);
22
+ return Promise.resolve({ type: 'drop' });
23
+ }
18
24
  const canReencode = await (0, can_reencode_video_track_1.canReencodeVideoTrack)({
19
25
  videoCodec,
20
26
  track,
21
27
  });
22
28
  if (canReencode) {
23
29
  media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Cannot copy, but re-enconde, therefore re-encoding`);
24
- return Promise.resolve({ type: 'reencode', videoCodec });
30
+ return Promise.resolve({
31
+ type: 'reencode',
32
+ videoCodec,
33
+ rotation: rotate - track.rotation,
34
+ });
25
35
  }
26
36
  media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
27
37
  return Promise.resolve({ type: 'fail' });