@remotion/webcodecs 4.0.237 → 4.0.240

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 (36) hide show
  1. package/dist/audio-decoder.js +11 -7
  2. package/dist/audio-encoder.js +4 -2
  3. package/dist/auto-select-writer.d.ts +1 -1
  4. package/dist/auto-select-writer.js +22 -5
  5. package/dist/can-copy-audio-track.d.ts +4 -3
  6. package/dist/can-copy-audio-track.js +7 -6
  7. package/dist/can-copy-video-track.d.ts +4 -3
  8. package/dist/can-copy-video-track.js +7 -6
  9. package/dist/convert-media.js +2 -2
  10. package/dist/default-on-audio-track-handler.js +9 -11
  11. package/dist/default-on-video-track-handler.js +6 -15
  12. package/dist/esm/index.mjs +188 -140
  13. package/dist/io-manager/io-synchronizer.d.ts +4 -3
  14. package/dist/io-manager/io-synchronizer.js +25 -10
  15. package/dist/on-audio-track-handler.d.ts +4 -2
  16. package/dist/on-audio-track.d.ts +2 -2
  17. package/dist/on-audio-track.js +13 -6
  18. package/dist/on-frame.js +4 -1
  19. package/dist/on-video-track-handler.d.ts +4 -2
  20. package/dist/on-video-track.d.ts +2 -2
  21. package/dist/on-video-track.js +15 -6
  22. package/dist/video-decoder.js +5 -2
  23. package/dist/video-encoder.js +4 -2
  24. package/package.json +4 -4
  25. package/dist/codec-id.d.ts +0 -10
  26. package/dist/codec-id.js +0 -38
  27. package/dist/create-aac-codecprivate.d.ts +0 -14
  28. package/dist/create-aac-codecprivate.js +0 -72
  29. package/dist/io-manager/event-emitter.d.ts +0 -31
  30. package/dist/io-manager/event-emitter.js +0 -25
  31. package/dist/rotate-video.d.ts +0 -4
  32. package/dist/rotate-video.js +0 -43
  33. package/dist/test/aac-codecprivate.test.js +0 -12
  34. package/dist/with-resolvers.d.ts +0 -10
  35. package/dist/with-resolvers.js +0 -28
  36. /package/dist/test/{aac-codecprivate.test.d.ts → avi-to-mp4.test.d.ts} +0 -0
@@ -14,8 +14,8 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
14
14
  let keyframes = [];
15
15
  // Once WebCodecs emits items, the user has to handle them
16
16
  // Let's keep count of how many items are unprocessed
17
- let unprocessed = 0;
18
- const getUnprocessed = () => unprocessed;
17
+ let _unprocessed = 0;
18
+ const getUnprocessed = () => _unprocessed;
19
19
  const getUnemittedItems = () => {
20
20
  inputs = inputs.filter((input) => Math.floor(input) > Math.floor(lastOutput));
21
21
  return inputs.length;
@@ -47,7 +47,7 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
47
47
  eventEmitter.dispatchEvent('output', {
48
48
  timestamp,
49
49
  });
50
- unprocessed++;
50
+ _unprocessed++;
51
51
  printState('Got output');
52
52
  };
53
53
  const waitForOutput = () => {
@@ -68,8 +68,17 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
68
68
  eventEmitter.addEventListener('processed', on);
69
69
  return promise;
70
70
  };
71
- const waitFor = async ({ _unprocessed, unemitted, minimumProgress, }) => {
72
- const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)(`Waited too long for ${label}`, 10000);
71
+ const waitFor = async ({ unprocessed, unemitted, minimumProgress, signal, }) => {
72
+ const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)([
73
+ `Waited too long for ${label}:`,
74
+ `${getUnemittedItems()} unemitted items`,
75
+ `${getUnprocessed()} unprocessed items`,
76
+ `minimum progress ${minimumProgress}`,
77
+ `smallest progress: ${progress.getSmallestProgress()}`,
78
+ `inputs: ${JSON.stringify(inputs)}`,
79
+ `last output: ${lastOutput}`,
80
+ ].join('\n'), 10000);
81
+ signal.addEventListener('abort', clear);
73
82
  await Promise.race([
74
83
  timeoutPromise,
75
84
  Promise.all([
@@ -79,11 +88,11 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
79
88
  }
80
89
  })(),
81
90
  (async () => {
82
- while (getUnprocessed() > _unprocessed) {
91
+ while (getUnprocessed() > unprocessed) {
83
92
  await waitForProcessed();
84
93
  }
85
94
  })(),
86
- minimumProgress === null
95
+ minimumProgress === null || progress.getSmallestProgress() === null
87
96
  ? Promise.resolve()
88
97
  : (async () => {
89
98
  while (progress.getSmallestProgress() < minimumProgress) {
@@ -92,13 +101,19 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
92
101
  })(),
93
102
  ]),
94
103
  ]).finally(() => clear());
104
+ signal.removeEventListener('abort', clear);
95
105
  };
96
- const waitForFinish = async () => {
97
- await waitFor({ _unprocessed: 0, unemitted: 0, minimumProgress: null });
106
+ const waitForFinish = async (signal) => {
107
+ await waitFor({
108
+ unprocessed: 0,
109
+ unemitted: 0,
110
+ minimumProgress: null,
111
+ signal,
112
+ });
98
113
  };
99
114
  const onProcessed = () => {
100
115
  eventEmitter.dispatchEvent('processed', {});
101
- unprocessed--;
116
+ _unprocessed--;
102
117
  };
103
118
  return {
104
119
  inputItem,
@@ -1,4 +1,4 @@
1
- import type { AudioTrack, LogLevel } from '@remotion/media-parser';
1
+ import type { AudioTrack, LogLevel, ParseMediaContainer } from '@remotion/media-parser';
2
2
  import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
3
3
  import type { ConvertMediaContainer } from './get-available-containers';
4
4
  export type AudioOperation = {
@@ -16,5 +16,7 @@ export type ConvertMediaOnAudioTrackHandler = (options: {
16
16
  track: AudioTrack;
17
17
  defaultAudioCodec: ConvertMediaAudioCodec | null;
18
18
  logLevel: LogLevel;
19
- container: ConvertMediaContainer;
19
+ outputContainer: ConvertMediaContainer;
20
+ inputContainer: ParseMediaContainer;
21
+ canCopyTrack: boolean;
20
22
  }) => AudioOperation | Promise<AudioOperation>;
@@ -4,7 +4,7 @@ import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
4
4
  import type { ConvertMediaContainer } from './get-available-containers';
5
5
  import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
6
6
  import type { ConvertMediaProgressFn } from './throttled-state-update';
7
- export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, progressTracker, }: {
7
+ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, progressTracker, }: {
8
8
  state: MediaFn;
9
9
  defaultAudioCodec: ConvertMediaAudioCodec | null;
10
10
  controller: AbortController;
@@ -12,6 +12,6 @@ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCo
12
12
  onMediaStateUpdate: null | ConvertMediaProgressFn;
13
13
  onAudioTrack: ConvertMediaOnAudioTrackHandler | null;
14
14
  logLevel: LogLevel;
15
- container: ConvertMediaContainer;
15
+ outputContainer: ConvertMediaContainer;
16
16
  progressTracker: ProgressTracker;
17
17
  }) => OnAudioTrack;
@@ -9,22 +9,31 @@ const audio_decoder_1 = require("./audio-decoder");
9
9
  const audio_decoder_config_1 = require("./audio-decoder-config");
10
10
  const audio_encoder_1 = require("./audio-encoder");
11
11
  const audio_encoder_config_1 = require("./audio-encoder-config");
12
+ const can_copy_audio_track_1 = require("./can-copy-audio-track");
12
13
  const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
13
14
  const default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
14
15
  const error_cause_1 = __importDefault(require("./error-cause"));
16
+ const get_default_audio_codec_1 = require("./get-default-audio-codec");
15
17
  const log_1 = require("./log");
16
- const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, progressTracker, }) => async (track) => {
18
+ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, progressTracker, }) => async ({ track, container: inputContainer }) => {
19
+ const canCopyTrack = (0, can_copy_audio_track_1.canCopyAudioTrack)({
20
+ inputCodec: track.codecWithoutConfig,
21
+ outputContainer,
22
+ inputContainer,
23
+ });
17
24
  const audioOperation = await (onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : default_on_audio_track_handler_1.defaultOnAudioTrackHandler)({
18
- defaultAudioCodec: audioCodec,
25
+ defaultAudioCodec: audioCodec !== null && audioCodec !== void 0 ? audioCodec : (0, get_default_audio_codec_1.getDefaultAudioCodec)({ container: outputContainer }),
19
26
  track,
20
27
  logLevel,
21
- container,
28
+ outputContainer,
29
+ inputContainer,
30
+ canCopyTrack,
22
31
  });
23
32
  if (audioOperation.type === 'drop') {
24
33
  return null;
25
34
  }
26
35
  if (audioOperation.type === 'fail') {
27
- throw new error_cause_1.default(`Audio track with ID ${track.trackId} could resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
36
+ throw new error_cause_1.default(`Audio track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
28
37
  }
29
38
  if (audioOperation.type === 'copy') {
30
39
  const addedTrack = await state.addTrack({
@@ -41,7 +50,6 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
41
50
  chunk: audioSample,
42
51
  trackNumber: addedTrack.trackNumber,
43
52
  isVideo: false,
44
- timescale: track.timescale,
45
53
  codecPrivate: track.codecPrivate,
46
54
  });
47
55
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
@@ -102,7 +110,6 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
102
110
  chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
103
111
  trackNumber,
104
112
  isVideo: false,
105
- timescale: track.timescale,
106
113
  codecPrivate,
107
114
  });
108
115
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
package/dist/on-frame.js CHANGED
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.onFrame = void 0;
4
+ const browser_quirks_1 = require("./browser-quirks");
4
5
  const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
5
6
  const rotate_video_frame_1 = require("./rotate-video-frame");
6
7
  const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, }) => {
@@ -21,7 +22,9 @@ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, trac
21
22
  if (userProcessedFrame.displayHeight !== rotated.displayHeight) {
22
23
  throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${userProcessedFrame.displayHeight}) than the input frame (${userProcessedFrame.displayHeight})`);
23
24
  }
24
- if (userProcessedFrame.timestamp !== rotated.timestamp) {
25
+ // In Safari, calling new VideoFrame() might change the timestamp
26
+ // In flipVideo test from 803000 to 803299
27
+ if (userProcessedFrame.timestamp !== rotated.timestamp && !(0, browser_quirks_1.isSafari)()) {
25
28
  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`);
26
29
  }
27
30
  if (((_a = userProcessedFrame.duration) !== null && _a !== void 0 ? _a : 0) !== ((_b = rotated.duration) !== null && _b !== void 0 ? _b : 0)) {
@@ -1,4 +1,4 @@
1
- import type { LogLevel, VideoTrack } from '@remotion/media-parser';
1
+ import type { LogLevel, ParseMediaContainer, VideoTrack } from '@remotion/media-parser';
2
2
  import type { ConvertMediaContainer } from './get-available-containers';
3
3
  import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
4
4
  export type VideoOperation = {
@@ -16,6 +16,8 @@ export type ConvertMediaOnVideoTrackHandler = (options: {
16
16
  defaultVideoCodec: ConvertMediaVideoCodec | null;
17
17
  track: VideoTrack;
18
18
  logLevel: LogLevel;
19
- container: ConvertMediaContainer;
19
+ outputContainer: ConvertMediaContainer;
20
20
  rotate: number;
21
+ inputContainer: ParseMediaContainer;
22
+ canCopyTrack: boolean;
21
23
  }) => VideoOperation | Promise<VideoOperation>;
@@ -5,7 +5,7 @@ import type { ConvertMediaContainer } from './get-available-containers';
5
5
  import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
6
6
  import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
7
7
  import type { ConvertMediaProgressFn } from './throttled-state-update';
8
- export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, container, rotate, progress, }: {
8
+ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, }: {
9
9
  state: MediaFn;
10
10
  onVideoFrame: null | ConvertMediaOnVideoFrame;
11
11
  onMediaStateUpdate: null | ConvertMediaProgressFn;
@@ -14,7 +14,7 @@ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaState
14
14
  defaultVideoCodec: ConvertMediaVideoCodec | null;
15
15
  onVideoTrack: ConvertMediaOnVideoTrackHandler | null;
16
16
  logLevel: LogLevel;
17
- container: ConvertMediaContainer;
17
+ outputContainer: ConvertMediaContainer;
18
18
  rotate: number;
19
19
  progress: ProgressTracker;
20
20
  }) => OnVideoTrack;
@@ -5,9 +5,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.makeVideoTrackHandler = void 0;
7
7
  const arraybuffer_to_uint8_array_1 = require("./arraybuffer-to-uint8-array");
8
+ const can_copy_video_track_1 = require("./can-copy-video-track");
8
9
  const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
9
10
  const default_on_video_track_handler_1 = require("./default-on-video-track-handler");
10
11
  const error_cause_1 = __importDefault(require("./error-cause"));
12
+ const get_default_video_codec_1 = require("./get-default-video-codec");
11
13
  const log_1 = require("./log");
12
14
  const on_frame_1 = require("./on-frame");
13
15
  const rotation_1 = require("./rotation");
@@ -15,23 +17,32 @@ const video_decoder_1 = require("./video-decoder");
15
17
  const video_decoder_config_1 = require("./video-decoder-config");
16
18
  const video_encoder_1 = require("./video-encoder");
17
19
  const video_encoder_config_1 = require("./video-encoder-config");
18
- const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, container, rotate, progress, }) => async (track) => {
20
+ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, }) => async ({ track, container: inputContainer }) => {
19
21
  var _a;
20
22
  if (controller.signal.aborted) {
21
23
  throw new error_cause_1.default('Aborted');
22
24
  }
25
+ const canCopyTrack = (0, can_copy_video_track_1.canCopyVideoTrack)({
26
+ inputCodec: track.codecWithoutConfig,
27
+ inputContainer,
28
+ inputRotation: track.rotation,
29
+ outputContainer,
30
+ rotationToApply: rotate,
31
+ });
23
32
  const videoOperation = await (onVideoTrack !== null && onVideoTrack !== void 0 ? onVideoTrack : default_on_video_track_handler_1.defaultOnVideoTrackHandler)({
24
33
  track,
25
- defaultVideoCodec,
34
+ defaultVideoCodec: defaultVideoCodec !== null && defaultVideoCodec !== void 0 ? defaultVideoCodec : (0, get_default_video_codec_1.getDefaultVideoCodec)({ container: outputContainer }),
26
35
  logLevel,
27
- container,
36
+ outputContainer,
28
37
  rotate,
38
+ inputContainer,
39
+ canCopyTrack,
29
40
  });
30
41
  if (videoOperation.type === 'drop') {
31
42
  return null;
32
43
  }
33
44
  if (videoOperation.type === 'fail') {
34
- throw new error_cause_1.default(`Video track with ID ${track.trackId} could resolved with {"type": "fail"}. This could mean that this video track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
45
+ throw new error_cause_1.default(`Video track with ID ${track.trackId} could with {"type": "fail"}. This could mean that this video track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
35
46
  }
36
47
  if (videoOperation.type === 'copy') {
37
48
  log_1.Log.verbose(logLevel, `Copying video track with codec ${track.codec} and timescale ${track.timescale}`);
@@ -49,7 +60,6 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
49
60
  chunk: sample,
50
61
  trackNumber: videoTrack.trackNumber,
51
62
  isVideo: true,
52
- timescale: track.timescale,
53
63
  codecPrivate: track.codecPrivate,
54
64
  });
55
65
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
@@ -101,7 +111,6 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
101
111
  chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
102
112
  trackNumber,
103
113
  isVideo: true,
104
- timescale: track.timescale,
105
114
  codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)(((_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.decoderConfig) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null)),
106
115
  });
107
116
  onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
@@ -52,6 +52,7 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, progre
52
52
  signal.addEventListener('abort', onAbort);
53
53
  videoDecoder.configure(config);
54
54
  const processSample = async (sample) => {
55
+ var _a, _b;
55
56
  if (videoDecoder.state === 'closed') {
56
57
  return;
57
58
  }
@@ -59,10 +60,12 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, progre
59
60
  if (videoDecoder.state === 'closed') {
60
61
  return;
61
62
  }
63
+ progress.setPossibleLowestTimestamp(Math.min(sample.timestamp, (_a = sample.dts) !== null && _a !== void 0 ? _a : Infinity, (_b = sample.cts) !== null && _b !== void 0 ? _b : Infinity));
62
64
  await ioSynchronizer.waitFor({
63
65
  unemitted: 20,
64
- _unprocessed: 2,
66
+ unprocessed: 2,
65
67
  minimumProgress: sample.timestamp - 5000000,
68
+ signal,
66
69
  });
67
70
  if (sample.type === 'key') {
68
71
  await videoDecoder.flush();
@@ -79,7 +82,7 @@ const createVideoDecoder = ({ onFrame, onError, signal, config, logLevel, progre
79
82
  waitForFinish: async () => {
80
83
  await videoDecoder.flush();
81
84
  log_1.Log.verbose(logLevel, 'Flushed video decoder');
82
- await ioSynchronizer.waitForFinish();
85
+ await ioSynchronizer.waitForFinish(signal);
83
86
  log_1.Log.verbose(logLevel, 'IO synchro finished');
84
87
  await outputQueue;
85
88
  log_1.Log.verbose(logLevel, 'Output queue finished');
@@ -57,11 +57,13 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, output
57
57
  if (encoder.state === 'closed') {
58
58
  return;
59
59
  }
60
+ progress.setPossibleLowestTimestamp(frame.timestamp);
60
61
  await ioSynchronizer.waitFor({
61
62
  // Firefox stalls if too few frames are passed
62
63
  unemitted: 10,
63
- _unprocessed: 10,
64
+ unprocessed: 10,
64
65
  minimumProgress: frame.timestamp - 5000000,
66
+ signal,
65
67
  });
66
68
  // @ts-expect-error - can have changed in the meanwhile
67
69
  if (encoder.state === 'closed') {
@@ -83,7 +85,7 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, output
83
85
  waitForFinish: async () => {
84
86
  await encoder.flush();
85
87
  await outputQueue;
86
- await ioSynchronizer.waitForFinish();
88
+ await ioSynchronizer.waitForFinish(signal);
87
89
  },
88
90
  close,
89
91
  flush: async () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/webcodecs",
3
- "version": "4.0.237",
3
+ "version": "4.0.240",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -17,14 +17,14 @@
17
17
  "author": "Jonny Burger <jonny@remotion.dev>",
18
18
  "license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
19
19
  "dependencies": {
20
- "@remotion/media-parser": "4.0.237"
20
+ "@remotion/media-parser": "4.0.240"
21
21
  },
22
22
  "peerDependencies": {},
23
23
  "devDependencies": {
24
24
  "@types/dom-webcodecs": "0.1.11",
25
25
  "eslint": "9.14.0",
26
- "@remotion/example-videos": "4.0.237",
27
- "@remotion/eslint-config-internal": "4.0.237"
26
+ "@remotion/example-videos": "4.0.240",
27
+ "@remotion/eslint-config-internal": "4.0.240"
28
28
  },
29
29
  "keywords": [],
30
30
  "publishConfig": {
@@ -1,10 +0,0 @@
1
- declare const availableContainers: readonly ["webm", "mp4", "wav"];
2
- export type ConvertMediaContainer = (typeof availableContainers)[number];
3
- export declare const getAvailableContainers: () => readonly ConvertMediaContainer[];
4
- declare const availableVideoCodecs: readonly ["vp8", "vp9", "h264"];
5
- export type ConvertMediaVideoCodec = (typeof availableVideoCodecs)[number];
6
- export declare const getAvailableVideoCodecs: (container: ConvertMediaContainer) => ConvertMediaVideoCodec[];
7
- declare const availableAudioCodecs: readonly ["opus", "aac", "wav"];
8
- export declare const getAvailableAudioCodecs: (container: ConvertMediaContainer) => ConvertMediaAudioCodec[];
9
- export type ConvertMediaAudioCodec = (typeof availableAudioCodecs)[number];
10
- export {};
package/dist/codec-id.js DELETED
@@ -1,38 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getAvailableAudioCodecs = exports.getAvailableVideoCodecs = exports.getAvailableContainers = void 0;
4
- const availableContainers = ['webm', 'mp4', 'wav'];
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
- if (container === 'wav') {
19
- return [];
20
- }
21
- throw new Error(`Unsupported container: ${container}`);
22
- };
23
- exports.getAvailableVideoCodecs = getAvailableVideoCodecs;
24
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
25
- const availableAudioCodecs = ['opus', 'aac', 'wav'];
26
- const getAvailableAudioCodecs = (container) => {
27
- if (container === 'mp4') {
28
- return ['aac'];
29
- }
30
- if (container === 'webm') {
31
- return ['opus'];
32
- }
33
- if (container === 'wav') {
34
- return ['wav'];
35
- }
36
- throw new Error(`Unsupported container: ${container}`);
37
- };
38
- exports.getAvailableAudioCodecs = getAvailableAudioCodecs;
@@ -1,14 +0,0 @@
1
- /**
2
- * bytes 17,144: 00010 001 | 1 0010 000
3
- ^^^^^ ^^^ ^ ^^^^ ^
4
- | | | | padding
5
- | | |
6
- | | +-- channelConfiguration (2)
7
- | +-- samplingFrequencyIndex (3)
8
- +-- audioConfigType (2)
9
- */
10
- export declare const createAacCodecPrivate: ({ audioObjectType, sampleRate, channelConfiguration, }: {
11
- audioObjectType: number;
12
- sampleRate: number;
13
- channelConfiguration: number;
14
- }) => Uint8Array;
@@ -1,72 +0,0 @@
1
- "use strict";
2
- // codec private, for example [17, 144]
3
- // audioObjectType = 2 = 'AAC LC'
4
- // samplingFrequencyIndex = 3 = '48000 Hz'
5
- // channelConfiguration = 2 = '2 channels'
6
- /**
7
- * bytes 17,144: 00010 001 | 1 0010 000
8
- ^^^^^ ^^^ ^ ^^^^ ^
9
- | | | | padding
10
- | | |
11
- | | +-- channelConfiguration (2)
12
- | +-- samplingFrequencyIndex (3)
13
- +-- audioConfigType (2)
14
- */
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.createAacCodecPrivate = void 0;
17
- // https://wiki.multimedia.cx/index.php/MPEG-4_Audio#Channel_Configurations
18
- const getConfigForSampleRate = (sampleRate) => {
19
- if (sampleRate === 96000) {
20
- return 0;
21
- }
22
- if (sampleRate === 88200) {
23
- return 1;
24
- }
25
- if (sampleRate === 64000) {
26
- return 2;
27
- }
28
- if (sampleRate === 48000) {
29
- return 3;
30
- }
31
- if (sampleRate === 44100) {
32
- return 4;
33
- }
34
- if (sampleRate === 32000) {
35
- return 5;
36
- }
37
- if (sampleRate === 24000) {
38
- return 6;
39
- }
40
- if (sampleRate === 22050) {
41
- return 7;
42
- }
43
- if (sampleRate === 16000) {
44
- return 8;
45
- }
46
- if (sampleRate === 12000) {
47
- return 9;
48
- }
49
- if (sampleRate === 11025) {
50
- return 10;
51
- }
52
- if (sampleRate === 8000) {
53
- return 11;
54
- }
55
- if (sampleRate === 7350) {
56
- return 12;
57
- }
58
- throw new Error(`Unexpected sample rate ${sampleRate}`);
59
- };
60
- const createAacCodecPrivate = ({ audioObjectType, sampleRate, channelConfiguration, }) => {
61
- const bits = `${audioObjectType.toString(2).padStart(5, '0')}${getConfigForSampleRate(sampleRate).toString(2).padStart(4, '0')}${channelConfiguration.toString(2).padStart(4, '0')}000`;
62
- if (bits.length !== 16) {
63
- throw new Error('Invalid AAC codec private ' + bits.length);
64
- }
65
- if (channelConfiguration === 0 || channelConfiguration > 7) {
66
- throw new Error('Invalid channel configuration ' + channelConfiguration);
67
- }
68
- const firstByte = parseInt(bits.slice(0, 8), 2);
69
- const secondByte = parseInt(bits.slice(8, 16), 2);
70
- return new Uint8Array([firstByte, secondByte]);
71
- };
72
- exports.createAacCodecPrivate = createAacCodecPrivate;
@@ -1,31 +0,0 @@
1
- type Input = {
2
- timestamp: number;
3
- keyFrame: boolean;
4
- };
5
- type Output = {
6
- timestamp: number;
7
- };
8
- type Processed = {};
9
- type Progress = {
10
- smallestProgress: number;
11
- };
12
- type IoEventMap = {
13
- input: Input;
14
- output: Output;
15
- processed: Processed;
16
- progress: Progress;
17
- };
18
- export type IoEventTypes = keyof IoEventMap;
19
- export type CallbackListener<T extends IoEventTypes> = (data: {
20
- detail: IoEventMap[T];
21
- }) => void;
22
- type IoListeners = {
23
- [EventType in IoEventTypes]: CallbackListener<EventType>[];
24
- };
25
- export declare class IoEventEmitter {
26
- listeners: IoListeners;
27
- addEventListener<Q extends IoEventTypes>(name: Q, callback: CallbackListener<Q>): void;
28
- removeEventListener<Q extends IoEventTypes>(name: Q, callback: CallbackListener<Q>): void;
29
- dispatchEvent<T extends IoEventTypes>(dispatchName: T, context: IoEventMap[T]): void;
30
- }
31
- export {};
@@ -1,25 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.IoEventEmitter = void 0;
4
- class IoEventEmitter {
5
- constructor() {
6
- this.listeners = {
7
- input: [],
8
- output: [],
9
- processed: [],
10
- progress: [],
11
- };
12
- }
13
- addEventListener(name, callback) {
14
- this.listeners[name].push(callback);
15
- }
16
- removeEventListener(name, callback) {
17
- this.listeners[name] = this.listeners[name].filter((l) => l !== callback);
18
- }
19
- dispatchEvent(dispatchName, context) {
20
- this.listeners[dispatchName].forEach((callback) => {
21
- callback({ detail: context });
22
- });
23
- }
24
- }
25
- exports.IoEventEmitter = IoEventEmitter;
@@ -1,4 +0,0 @@
1
- export declare const rotateVideo: ({ frame, rotation, }: {
2
- frame: VideoFrame;
3
- rotation: number;
4
- }) => VideoFrame;
@@ -1,43 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.rotateVideo = void 0;
4
- const rotation_1 = require("./rotation");
5
- const rotateVideo = ({ frame, rotation, }) => {
6
- const normalized = ((rotation % 360) + 360) % 360;
7
- if (normalized % 360 === 0) {
8
- return frame;
9
- }
10
- if (normalized % 90 !== 0) {
11
- throw new Error('Only 90 degree rotations are supported');
12
- }
13
- const { height, width } = (0, rotation_1.calculateNewDimensionsFromDimensions)({
14
- height: frame.displayHeight,
15
- width: frame.displayWidth,
16
- rotation,
17
- });
18
- const canvas = new OffscreenCanvas(width, height);
19
- const ctx = canvas.getContext('2d');
20
- if (!ctx) {
21
- throw new Error('Could not get 2d context');
22
- }
23
- canvas.width = width;
24
- canvas.height = height;
25
- if (normalized === 90) {
26
- ctx.translate(width, 0);
27
- }
28
- else if (normalized === 180) {
29
- ctx.translate(width, height);
30
- }
31
- else if (normalized === 270) {
32
- ctx.translate(0, height);
33
- }
34
- ctx.rotate(normalized * (Math.PI / 180));
35
- ctx.drawImage(frame, 0, 0);
36
- return new VideoFrame(canvas, {
37
- displayHeight: height,
38
- displayWidth: width,
39
- duration: frame.duration,
40
- timestamp: frame.timestamp,
41
- });
42
- };
43
- exports.rotateVideo = rotateVideo;
@@ -1,12 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const bun_test_1 = require("bun:test");
4
- const create_aac_codecprivate_1 = require("../create-aac-codecprivate");
5
- (0, bun_test_1.test)('AACCodecPrivate', () => {
6
- const codecPrivate = (0, create_aac_codecprivate_1.createAacCodecPrivate)({
7
- audioObjectType: 2,
8
- sampleRate: 48000,
9
- channelConfiguration: 2,
10
- });
11
- (0, bun_test_1.expect)(codecPrivate).toEqual(new Uint8Array([17, 144]));
12
- });
@@ -1,10 +0,0 @@
1
- export declare const withResolvers: <T>() => {
2
- promise: Promise<T>;
3
- resolve: (value: T | PromiseLike<T>) => void;
4
- reject: (reason?: any) => void;
5
- };
6
- export declare const withResolversAndWaitForReturn: <T>() => {
7
- getPromiseToImmediatelyReturn: () => Promise<T>;
8
- reject: (reason: unknown) => void;
9
- resolve: (value: T | PromiseLike<T>) => void;
10
- };