@remotion/webcodecs 4.0.229 → 4.0.230

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 (59) hide show
  1. package/dist/arraybuffer-to-uint8-array.d.ts +1 -0
  2. package/dist/arraybuffer-to-uint8-array.js +7 -0
  3. package/dist/audio-decoder.d.ts +2 -2
  4. package/dist/audio-encoder-config.js +15 -2
  5. package/dist/audio-encoder.d.ts +2 -1
  6. package/dist/audio-encoder.js +16 -4
  7. package/dist/can-copy-audio-track.d.ts +2 -4
  8. package/dist/can-copy-audio-track.js +7 -4
  9. package/dist/can-copy-video-track.d.ts +2 -4
  10. package/dist/can-copy-video-track.js +6 -6
  11. package/dist/can-reencode-audio-track.js +1 -6
  12. package/dist/can-reencode-video-track.js +1 -0
  13. package/dist/choose-correct-avc1-profile.d.ts +5 -0
  14. package/dist/choose-correct-avc1-profile.js +54 -0
  15. package/dist/codec-id.d.ts +7 -4
  16. package/dist/codec-id.js +28 -5
  17. package/dist/convert-encoded-chunk.d.ts +2 -1
  18. package/dist/convert-encoded-chunk.js +25 -2
  19. package/dist/convert-media.d.ts +7 -8
  20. package/dist/convert-media.js +11 -9
  21. package/dist/default-on-audio-track-handler.d.ts +2 -0
  22. package/dist/default-on-audio-track-handler.js +36 -0
  23. package/dist/default-on-video-track-handler.d.ts +2 -0
  24. package/dist/default-on-video-track-handler.js +29 -0
  25. package/dist/esm/index.mjs +277 -106
  26. package/dist/get-default-audio-codec.d.ts +4 -0
  27. package/dist/get-default-audio-codec.js +13 -0
  28. package/dist/get-default-video-codec.d.ts +4 -0
  29. package/dist/get-default-video-codec.js +10 -0
  30. package/dist/index.d.ts +8 -4
  31. package/dist/index.js +10 -1
  32. package/dist/io-manager/io-synchronizer.js +2 -2
  33. package/dist/{resolve-audio-action.d.ts → on-audio-track-handler.d.ts} +5 -5
  34. package/dist/on-audio-track-handler.js +2 -0
  35. package/dist/on-audio-track.d.ts +6 -6
  36. package/dist/on-audio-track.js +37 -10
  37. package/dist/{resolve-video-action.d.ts → on-video-track-handler.d.ts} +5 -5
  38. package/dist/on-video-track-handler.js +2 -0
  39. package/dist/on-video-track.d.ts +6 -6
  40. package/dist/on-video-track.js +35 -9
  41. package/dist/video-decoder.d.ts +2 -2
  42. package/dist/video-decoder.js +5 -0
  43. package/dist/video-encoder-config.d.ts +2 -1
  44. package/dist/video-encoder-config.js +7 -2
  45. package/dist/video-encoder.d.ts +1 -1
  46. package/dist/video-encoder.js +4 -6
  47. package/package.json +3 -3
  48. package/dist/can-reencode-audio.d.ts +0 -7
  49. package/dist/can-reencode-audio.js +0 -21
  50. package/dist/can-reencode-video.d.ts +0 -6
  51. package/dist/can-reencode-video.js +0 -15
  52. package/dist/event-emitter.d.ts +0 -25
  53. package/dist/event-emitter.js +0 -23
  54. package/dist/polyfill-encoded-audio-chunk.d.ts +0 -3
  55. package/dist/polyfill-encoded-audio-chunk.js +0 -5
  56. package/dist/resolve-audio-action.js +0 -32
  57. package/dist/resolve-video-action.js +0 -26
  58. package/dist/wait-until-return.d.ts +0 -4
  59. package/dist/wait-until-return.js +0 -14
@@ -0,0 +1 @@
1
+ export declare const arrayBufferToUint8Array: (buffer: ArrayBuffer | null) => Uint8Array | null;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.arrayBufferToUint8Array = void 0;
4
+ const arrayBufferToUint8Array = (buffer) => {
5
+ return buffer ? new Uint8Array(buffer) : null;
6
+ };
7
+ exports.arrayBufferToUint8Array = arrayBufferToUint8Array;
@@ -1,6 +1,6 @@
1
- import type { AudioSample, LogLevel } from '@remotion/media-parser';
1
+ import type { AudioOrVideoSample, LogLevel } from '@remotion/media-parser';
2
2
  export type WebCodecsAudioDecoder = {
3
- processSample: (audioSample: AudioSample) => Promise<void>;
3
+ processSample: (audioSample: AudioOrVideoSample) => Promise<void>;
4
4
  waitForFinish: () => Promise<void>;
5
5
  close: () => void;
6
6
  flush: () => Promise<void>;
@@ -1,12 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getAudioEncoderConfig = void 0;
4
+ const getCodecString = (audioCodec) => {
5
+ if (audioCodec === 'opus') {
6
+ return 'opus';
7
+ }
8
+ if (audioCodec === 'aac') {
9
+ return 'mp4a.40.02';
10
+ }
11
+ throw new Error(`Unsupported audio codec: ${audioCodec}`);
12
+ };
4
13
  const getAudioEncoderConfig = async (config) => {
14
+ const actualConfig = {
15
+ ...config,
16
+ codec: getCodecString(config.codec),
17
+ };
5
18
  if (typeof AudioEncoder === 'undefined') {
6
19
  return null;
7
20
  }
8
- if ((await AudioEncoder.isConfigSupported(config)).supported) {
9
- return config;
21
+ if ((await AudioEncoder.isConfigSupported(actualConfig)).supported) {
22
+ return actualConfig;
10
23
  }
11
24
  return null;
12
25
  };
@@ -6,11 +6,12 @@ export type WebCodecsAudioEncoder = {
6
6
  close: () => void;
7
7
  flush: () => Promise<void>;
8
8
  };
9
- export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, }: {
9
+ export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }: {
10
10
  onChunk: (chunk: EncodedAudioChunk) => Promise<void>;
11
11
  onError: (error: DOMException) => void;
12
12
  codec: ConvertMediaAudioCodec;
13
13
  signal: AbortSignal;
14
14
  config: AudioEncoderConfig;
15
15
  logLevel: LogLevel;
16
+ onNewAudioSampleRate: (sampleRate: number) => void;
16
17
  }) => WebCodecsAudioEncoder;
@@ -2,7 +2,7 @@
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, }) => {
5
+ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }) => {
6
6
  if (signal.aborted) {
7
7
  throw new Error('Not creating audio encoder, already aborted');
8
8
  }
@@ -42,10 +42,10 @@ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEnco
42
42
  close();
43
43
  };
44
44
  signal.addEventListener('abort', onAbort);
45
- if (codec !== 'opus') {
46
- throw new Error('Only `codec: "opus"` is supported currently');
45
+ if (codec !== 'opus' && codec !== 'aac') {
46
+ throw new Error('Only `codec: "opus"` and `codec: "aac"` is supported currently');
47
47
  }
48
- encoder.configure(audioEncoderConfig);
48
+ const wantedSampleRate = audioEncoderConfig.sampleRate;
49
49
  const encodeFrame = async (audioData) => {
50
50
  if (encoder.state === 'closed') {
51
51
  return;
@@ -55,6 +55,18 @@ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEnco
55
55
  if (encoder.state === 'closed') {
56
56
  return;
57
57
  }
58
+ if (encoder.state === 'unconfigured') {
59
+ if (audioData.sampleRate === wantedSampleRate) {
60
+ encoder.configure(audioEncoderConfig);
61
+ }
62
+ else {
63
+ encoder.configure({
64
+ ...audioEncoderConfig,
65
+ sampleRate: audioData.sampleRate,
66
+ });
67
+ onNewAudioSampleRate(audioData.sampleRate);
68
+ }
69
+ }
58
70
  encoder.encode(audioData);
59
71
  ioSynchronizer.inputItem(audioData.timestamp, true);
60
72
  };
@@ -1,8 +1,6 @@
1
1
  import type { MediaParserAudioCodec } from '@remotion/media-parser';
2
- import type { ConvertMediaAudioCodec } from './codec-id';
3
- import type { ConvertMediaContainer } from './convert-media';
4
- export declare const canCopyAudioTrack: ({ inputCodec, outputCodec, container, }: {
2
+ import type { ConvertMediaContainer } from './codec-id';
3
+ export declare const canCopyAudioTrack: ({ inputCodec, container, }: {
5
4
  inputCodec: MediaParserAudioCodec;
6
- outputCodec: ConvertMediaAudioCodec;
7
5
  container: ConvertMediaContainer;
8
6
  }) => boolean;
@@ -1,10 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canCopyAudioTrack = void 0;
4
- const canCopyAudioTrack = ({ inputCodec, outputCodec, container, }) => {
5
- if (outputCodec === 'opus') {
6
- return inputCodec === 'opus' && container === 'webm';
4
+ const canCopyAudioTrack = ({ inputCodec, container, }) => {
5
+ if (container === 'webm') {
6
+ return inputCodec === 'opus';
7
7
  }
8
- throw new Error(`Unhandled codec: ${outputCodec}`);
8
+ if (container === 'mp4') {
9
+ return inputCodec === 'aac';
10
+ }
11
+ throw new Error(`Unhandled codec: ${container}`);
9
12
  };
10
13
  exports.canCopyAudioTrack = canCopyAudioTrack;
@@ -1,8 +1,6 @@
1
1
  import type { MediaParserVideoCodec } from '@remotion/media-parser';
2
- import type { ConvertMediaVideoCodec } from './codec-id';
3
- import type { ConvertMediaContainer } from './convert-media';
4
- export declare const canCopyVideoTrack: ({ inputCodec, outputCodec, container, }: {
2
+ import type { ConvertMediaContainer } from './codec-id';
3
+ export declare const canCopyVideoTrack: ({ inputCodec, container, }: {
5
4
  inputCodec: MediaParserVideoCodec;
6
- outputCodec: ConvertMediaVideoCodec;
7
5
  container: ConvertMediaContainer;
8
6
  }) => boolean;
@@ -1,13 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.canCopyVideoTrack = void 0;
4
- const canCopyVideoTrack = ({ inputCodec, outputCodec, container, }) => {
5
- if (outputCodec === 'vp8') {
6
- return inputCodec === 'vp8' && container === 'webm';
4
+ const canCopyVideoTrack = ({ inputCodec, container, }) => {
5
+ if (container === 'webm') {
6
+ return inputCodec === 'vp8' || inputCodec === 'vp9';
7
7
  }
8
- if (outputCodec === 'vp9') {
9
- return inputCodec === 'vp9' && container === 'webm';
8
+ if (container === 'mp4') {
9
+ return inputCodec === 'h264' || inputCodec === 'h265';
10
10
  }
11
- throw new Error(`Unhandled codec: ${outputCodec}`);
11
+ throw new Error(`Unhandled codec: ${container}`);
12
12
  };
13
13
  exports.canCopyVideoTrack = canCopyVideoTrack;
@@ -4,12 +4,7 @@ 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
6
  const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, }) => {
7
- const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)({
8
- codec: track.codec,
9
- numberOfChannels: track.numberOfChannels,
10
- sampleRate: track.sampleRate,
11
- description: track.description,
12
- });
7
+ const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track);
13
8
  const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
14
9
  codec: audioCodec,
15
10
  numberOfChannels: track.numberOfChannels,
@@ -8,6 +8,7 @@ const canReencodeVideoTrack = async ({ videoCodec, track, }) => {
8
8
  codec: videoCodec,
9
9
  height: track.displayAspectHeight,
10
10
  width: track.displayAspectWidth,
11
+ fps: track.fps,
11
12
  });
12
13
  const videoDecoderConfig = await (0, video_decoder_config_1.getVideoDecoderConfigWithHardwareAcceleration)(track);
13
14
  return Boolean(videoDecoderConfig && videoEncoderConfig);
@@ -0,0 +1,5 @@
1
+ export declare const chooseCorrectAvc1Profile: ({ width, height, fps, }: {
2
+ width: number;
3
+ height: number;
4
+ fps: number | null;
5
+ }) => string;
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.chooseCorrectAvc1Profile = void 0;
4
+ const chooseCorrectAvc1Profile = ({ width, height, fps, }) => {
5
+ // 0x42 = Baseline profile
6
+ // 0x4D = Main profile
7
+ // 0x58 = Extended profile
8
+ // 0x64 = High profile
9
+ // According to Wikipedia, 0x64 is the most widely supported profile.
10
+ // So we always choose 0x64.
11
+ /**
12
+ Ignoring lower levels of <720p, let's only support Players that can play 720p and above.
13
+ • Level 3.1 = 1F (hex) -> 1,280×720@30.0 (5)
14
+ • Level 3.2 = 20 (hex) -> 1,280×1,024@42.2 (4)
15
+ • Level 4.0 = 28 (hex) -> 2,048×1,024@30.0 (4)
16
+ • Level 4.1 = 29 (hex) -> 2,048×1,024@30.0 (4)
17
+ • Level 4.2 = 2A (hex) -> 2,048×1,080@60.0 (4)
18
+ • Level 5.0 = 32 (hex) -> 3,672×1,536@26.7 (5)
19
+ • Level 5.1 = 33 (hex) -> 4,096×2,304@26.7 (5)
20
+ • Level 5.2 = 34 (hex) -> 4,096×2,304@56.3 (5)
21
+ • Level 6.0 = 3C (hex) -> 8,192×4,320@30.2 (5)
22
+ • Level 6.1 = 3D (hex) -> 8,192×4,320@60.4 (5)
23
+ • Level 6.2 = 3E (hex) -> 8,192×4,320@120.8 (5)
24
+ */
25
+ const profiles = [
26
+ { level: '3.1', hex: '1F', width: 1280, height: 720, fps: 30.0 },
27
+ { level: '3.2', hex: '20', width: 1280, height: 1024, fps: 42.2 },
28
+ { level: '4.0', hex: '28', width: 2048, height: 1024, fps: 30.0 },
29
+ { level: '4.1', hex: '29', width: 2048, height: 1024, fps: 30.0 },
30
+ { level: '4.2', hex: '2A', width: 2048, height: 1080, fps: 60.0 },
31
+ { level: '5.0', hex: '32', width: 3672, height: 1536, fps: 26.7 },
32
+ { level: '5.1', hex: '33', width: 4096, height: 2304, fps: 26.7 },
33
+ { level: '5.2', hex: '34', width: 4096, height: 2304, fps: 56.3 },
34
+ { level: '6.0', hex: '3C', width: 8192, height: 4320, fps: 30.2 },
35
+ { level: '6.1', hex: '3D', width: 8192, height: 4320, fps: 60.4 },
36
+ { level: '6.2', hex: '3E', width: 8192, height: 4320, fps: 120.8 },
37
+ ];
38
+ const profile = profiles.find((p) => {
39
+ if (width > p.width) {
40
+ return false;
41
+ }
42
+ if (height > p.height) {
43
+ return false;
44
+ }
45
+ // if has no fps, use 60 as a conservative fallback
46
+ const fallbackFps = fps !== null && fps !== void 0 ? fps : 60;
47
+ return fallbackFps <= p.fps;
48
+ });
49
+ if (!profile) {
50
+ throw new Error(`No suitable AVC1 profile found for ${width}x${height}@${fps}fps`);
51
+ }
52
+ return `avc1.6400${profile.hex}`;
53
+ };
54
+ exports.chooseCorrectAvc1Profile = chooseCorrectAvc1Profile;
@@ -1,7 +1,10 @@
1
- declare const availableVideoCodecs: readonly ["vp8", "vp9"];
2
- export declare const getAvailableVideoCodecs: () => readonly ["vp8", "vp9"];
1
+ declare const availableContainers: readonly ["webm", "mp4"];
2
+ export type ConvertMediaContainer = (typeof availableContainers)[number];
3
+ export declare const getAvailableContainers: () => readonly ConvertMediaContainer[];
4
+ declare const availableVideoCodecs: readonly ["vp8", "vp9", "h264"];
3
5
  export type ConvertMediaVideoCodec = (typeof availableVideoCodecs)[number];
4
- declare const availableAudioCodecs: readonly ["opus"];
5
- export declare const getAvailableAudioCodecs: () => readonly ["opus"];
6
+ export declare const getAvailableVideoCodecs: (container: ConvertMediaContainer) => ConvertMediaVideoCodec[];
7
+ declare const availableAudioCodecs: readonly ["opus", "aac"];
8
+ export declare const getAvailableAudioCodecs: (container: ConvertMediaContainer) => ConvertMediaAudioCodec[];
6
9
  export type ConvertMediaAudioCodec = (typeof availableAudioCodecs)[number];
7
10
  export {};
package/dist/codec-id.js CHANGED
@@ -1,9 +1,32 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAvailableAudioCodecs = exports.getAvailableVideoCodecs = void 0;
4
- const availableVideoCodecs = ['vp8', 'vp9'];
5
- const getAvailableVideoCodecs = () => availableVideoCodecs;
3
+ exports.getAvailableAudioCodecs = exports.getAvailableVideoCodecs = exports.getAvailableContainers = void 0;
4
+ const availableContainers = ['webm', 'mp4'];
5
+ const getAvailableContainers = () => {
6
+ return availableContainers;
7
+ };
8
+ exports.getAvailableContainers = getAvailableContainers;
9
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
10
+ const availableVideoCodecs = ['vp8', 'vp9', 'h264'];
11
+ const getAvailableVideoCodecs = (container) => {
12
+ if (container === 'mp4') {
13
+ return ['h264'];
14
+ }
15
+ if (container === 'webm') {
16
+ return ['vp8', 'vp9'];
17
+ }
18
+ throw new Error(`Unsupported container: ${container}`);
19
+ };
6
20
  exports.getAvailableVideoCodecs = getAvailableVideoCodecs;
7
- const availableAudioCodecs = ['opus'];
8
- const getAvailableAudioCodecs = () => availableAudioCodecs;
21
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
22
+ const availableAudioCodecs = ['opus', 'aac'];
23
+ const getAvailableAudioCodecs = (container) => {
24
+ if (container === 'mp4') {
25
+ return ['aac'];
26
+ }
27
+ if (container === 'webm') {
28
+ return ['opus'];
29
+ }
30
+ throw new Error(`Unsupported container: ${container}`);
31
+ };
9
32
  exports.getAvailableAudioCodecs = getAvailableAudioCodecs;
@@ -1,2 +1,3 @@
1
1
  import type { AudioOrVideoSample } from '@remotion/media-parser';
2
- export declare const convertEncodedChunk: (chunk: EncodedAudioChunk | EncodedVideoChunk) => AudioOrVideoSample;
2
+ export declare const combineUint8Arrays: (arrays: Uint8Array[]) => Uint8Array;
3
+ export declare const convertEncodedChunk: (chunk: EncodedAudioChunk | EncodedVideoChunk, trackId: number) => AudioOrVideoSample;
@@ -1,7 +1,27 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.convertEncodedChunk = void 0;
4
- const convertEncodedChunk = (chunk) => {
3
+ exports.convertEncodedChunk = exports.combineUint8Arrays = void 0;
4
+ const combineUint8Arrays = (arrays) => {
5
+ if (arrays.length === 0) {
6
+ return new Uint8Array([]);
7
+ }
8
+ if (arrays.length === 1) {
9
+ return arrays[0];
10
+ }
11
+ let totalLength = 0;
12
+ for (const array of arrays) {
13
+ totalLength += array.length;
14
+ }
15
+ const result = new Uint8Array(totalLength);
16
+ let offset = 0;
17
+ for (const array of arrays) {
18
+ result.set(array, offset);
19
+ offset += array.length;
20
+ }
21
+ return result;
22
+ };
23
+ exports.combineUint8Arrays = combineUint8Arrays;
24
+ const convertEncodedChunk = (chunk, trackId) => {
5
25
  var _a;
6
26
  const arr = new Uint8Array(chunk.byteLength);
7
27
  chunk.copyTo(arr);
@@ -10,6 +30,9 @@ const convertEncodedChunk = (chunk) => {
10
30
  duration: (_a = chunk.duration) !== null && _a !== void 0 ? _a : undefined,
11
31
  timestamp: chunk.timestamp,
12
32
  type: chunk.type,
33
+ cts: chunk.timestamp,
34
+ dts: chunk.timestamp,
35
+ trackId,
13
36
  };
14
37
  };
15
38
  exports.convertEncodedChunk = convertEncodedChunk;
@@ -3,9 +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, ConvertMediaVideoCodec } from './codec-id';
7
- import { type ResolveAudioActionFn } from './resolve-audio-action';
8
- import { type ResolveVideoActionFn } from './resolve-video-action';
6
+ import type { ConvertMediaAudioCodec, ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
7
+ import { type ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
8
+ import { type ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
9
9
  export type ConvertMediaState = {
10
10
  decodedVideoFrames: number;
11
11
  decodedAudioFrames: number;
@@ -16,7 +16,6 @@ export type ConvertMediaState = {
16
16
  expectedOutputDurationInMs: number | null;
17
17
  overallProgress: number | null;
18
18
  };
19
- export type ConvertMediaContainer = 'webm';
20
19
  export type ConvertMediaResult = {
21
20
  save: () => Promise<Blob>;
22
21
  remove: () => Promise<void>;
@@ -31,11 +30,11 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
31
30
  container: ConvertMediaContainer;
32
31
  onVideoFrame?: ConvertMediaOnVideoFrame;
33
32
  onMediaStateUpdate?: ConvertMediaOnMediaStateUpdate;
34
- videoCodec: ConvertMediaVideoCodec;
35
- audioCodec: ConvertMediaAudioCodec;
33
+ videoCodec?: ConvertMediaVideoCodec;
34
+ audioCodec?: ConvertMediaAudioCodec;
36
35
  signal?: AbortSignal;
37
- onAudioTrack?: ResolveAudioActionFn;
38
- onVideoTrack?: ResolveVideoActionFn;
36
+ onAudioTrack?: ConvertMediaOnAudioTrackHandler;
37
+ onVideoTrack?: ConvertMediaOnVideoTrackHandler;
39
38
  reader?: ParseMediaOptions<F>["reader"];
40
39
  logLevel?: LogLevel;
41
40
  writer?: WriterInterface;
@@ -19,13 +19,10 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
19
19
  if (userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.aborted) {
20
20
  return Promise.reject(new error_cause_1.default('Aborted'));
21
21
  }
22
- if (container !== 'webm') {
23
- return Promise.reject(new TypeError('Only `to: "webm"` is supported currently'));
22
+ if (container !== 'webm' && container !== 'mp4') {
23
+ return Promise.reject(new TypeError('Only `to: "webm"` and `to: "mp4"` is supported currently'));
24
24
  }
25
- if (audioCodec !== 'opus') {
26
- return Promise.reject(new TypeError('Only `audioCodec: "opus"` is supported currently'));
27
- }
28
- if (videoCodec !== 'vp8' && videoCodec !== 'vp9') {
25
+ if (videoCodec && videoCodec !== 'vp8' && videoCodec !== 'vp9') {
29
26
  return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
30
27
  }
31
28
  const { resolve, reject, getPromiseToImmediatelyReturn } = (0, with_resolvers_1.withResolversAndWaitForReturn)();
@@ -56,7 +53,10 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
56
53
  }
57
54
  onMediaStateDoNoCallDirectly === null || onMediaStateDoNoCallDirectly === void 0 ? void 0 : onMediaStateDoNoCallDirectly(newState);
58
55
  };
59
- const state = await media_parser_1.MediaParserInternals.createMedia({
56
+ const creator = container === 'webm'
57
+ ? media_parser_1.MediaParserInternals.createMatroskaMedia
58
+ : media_parser_1.MediaParserInternals.createIsoBaseMedia;
59
+ const state = await creator({
60
60
  writer: await (0, auto_select_writer_1.autoSelectWriter)(writer, logLevel),
61
61
  onBytesProgress: (bytesWritten) => {
62
62
  convertMediaState.bytesWritten = bytesWritten;
@@ -72,6 +72,7 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
72
72
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate(convertMediaState);
73
73
  }
74
74
  },
75
+ logLevel,
75
76
  });
76
77
  const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
77
78
  state,
@@ -80,14 +81,14 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
80
81
  abortConversion,
81
82
  convertMediaState,
82
83
  controller,
83
- videoCodec,
84
+ defaultVideoCodec: videoCodec !== null && videoCodec !== void 0 ? videoCodec : null,
84
85
  onVideoTrack: userVideoResolver !== null && userVideoResolver !== void 0 ? userVideoResolver : null,
85
86
  logLevel,
86
87
  container,
87
88
  });
88
89
  const onAudioTrack = (0, on_audio_track_1.makeAudioTrackHandler)({
89
90
  abortConversion,
90
- audioCodec,
91
+ defaultAudioCodec: audioCodec !== null && audioCodec !== void 0 ? audioCodec : null,
91
92
  controller,
92
93
  convertMediaState,
93
94
  onMediaStateUpdate: onMediaStateUpdate !== null && onMediaStateUpdate !== void 0 ? onMediaStateUpdate : null,
@@ -97,6 +98,7 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
97
98
  container,
98
99
  });
99
100
  (0, media_parser_1.parseMedia)({
101
+ logLevel,
100
102
  src,
101
103
  onVideoTrack,
102
104
  onAudioTrack,
@@ -0,0 +1,2 @@
1
+ import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
2
+ export declare const defaultOnAudioTrackHandler: ConvertMediaOnAudioTrackHandler;
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultOnAudioTrackHandler = void 0;
4
+ const media_parser_1 = require("@remotion/media-parser");
5
+ const can_copy_audio_track_1 = require("./can-copy-audio-track");
6
+ const can_reencode_audio_track_1 = require("./can-reencode-audio-track");
7
+ const get_default_audio_codec_1 = require("./get-default-audio-codec");
8
+ const DEFAULT_BITRATE = 128000;
9
+ const defaultOnAudioTrackHandler = async ({ track, defaultAudioCodec, logLevel, container, }) => {
10
+ const bitrate = DEFAULT_BITRATE;
11
+ const canCopy = (0, can_copy_audio_track_1.canCopyAudioTrack)({
12
+ inputCodec: track.codecWithoutConfig,
13
+ container,
14
+ });
15
+ if (canCopy) {
16
+ media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can copy track, therefore copying`);
17
+ return Promise.resolve({ type: 'copy' });
18
+ }
19
+ const audioCodec = defaultAudioCodec !== null && defaultAudioCodec !== void 0 ? defaultAudioCodec : (0, get_default_audio_codec_1.getDefaultAudioCodec)({ container });
20
+ const canReencode = await (0, can_reencode_audio_track_1.canReencodeAudioTrack)({
21
+ audioCodec,
22
+ track,
23
+ bitrate,
24
+ });
25
+ if (canReencode) {
26
+ media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (audio): Cannot copy, but re-encode, therefore re-encoding`);
27
+ return Promise.resolve({
28
+ type: 'reencode',
29
+ bitrate,
30
+ audioCodec,
31
+ });
32
+ }
33
+ media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (audio): Can neither re-encode nor copy, failing render`);
34
+ return Promise.resolve({ type: 'fail' });
35
+ };
36
+ exports.defaultOnAudioTrackHandler = defaultOnAudioTrackHandler;
@@ -0,0 +1,2 @@
1
+ import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
2
+ export declare const defaultOnVideoTrackHandler: ConvertMediaOnVideoTrackHandler;
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultOnVideoTrackHandler = void 0;
4
+ const media_parser_1 = require("@remotion/media-parser");
5
+ const can_copy_video_track_1 = require("./can-copy-video-track");
6
+ const can_reencode_video_track_1 = require("./can-reencode-video-track");
7
+ const get_default_video_codec_1 = require("./get-default-video-codec");
8
+ const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel, container, }) => {
9
+ const canCopy = (0, can_copy_video_track_1.canCopyVideoTrack)({
10
+ inputCodec: track.codecWithoutConfig,
11
+ container,
12
+ });
13
+ if (canCopy) {
14
+ media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Can copy, therefore copying`);
15
+ return Promise.resolve({ type: 'copy' });
16
+ }
17
+ const videoCodec = defaultVideoCodec !== null && defaultVideoCodec !== void 0 ? defaultVideoCodec : (0, get_default_video_codec_1.getDefaultVideoCodec)({ container });
18
+ const canReencode = await (0, can_reencode_video_track_1.canReencodeVideoTrack)({
19
+ videoCodec,
20
+ track,
21
+ });
22
+ if (canReencode) {
23
+ 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 });
25
+ }
26
+ media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): Can neither copy nor re-encode, therefore failing`);
27
+ return Promise.resolve({ type: 'fail' });
28
+ };
29
+ exports.defaultOnVideoTrackHandler = defaultOnVideoTrackHandler;