@remotion/webcodecs 4.0.304 → 4.0.306

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 (48) hide show
  1. package/dist/audio-decoder.d.ts +15 -10
  2. package/dist/audio-decoder.js +49 -52
  3. package/dist/audio-encoder.d.ts +5 -5
  4. package/dist/audio-encoder.js +20 -42
  5. package/dist/convert-encoded-chunk.d.ts +1 -1
  6. package/dist/convert-encoded-chunk.js +2 -5
  7. package/dist/convert-media.js +2 -2
  8. package/dist/copy-audio-track.d.ts +11 -0
  9. package/dist/copy-audio-track.js +31 -0
  10. package/dist/copy-video-track.d.ts +11 -0
  11. package/dist/copy-video-track.js +32 -0
  12. package/dist/create/event-emitter.d.ts +0 -1
  13. package/dist/create/iso-base-media/create-iso-base-media.js +3 -3
  14. package/dist/create/iso-base-media/example-stts.js +620 -620
  15. package/dist/create/iso-base-media/trak/mdia/minf/create-stbl.js +3 -1
  16. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-ctts.js +1 -1
  17. package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stts.js +3 -2
  18. package/dist/create/matroska/create-matroska-media.js +1 -1
  19. package/dist/create/progress-tracker.d.ts +0 -2
  20. package/dist/create/progress-tracker.js +3 -20
  21. package/dist/esm/index.mjs +583 -496
  22. package/dist/get-wave-audio-decoder.d.ts +6 -1
  23. package/dist/get-wave-audio-decoder.js +16 -11
  24. package/dist/io-manager/io-synchronizer.d.ts +6 -13
  25. package/dist/io-manager/io-synchronizer.js +31 -72
  26. package/dist/io-manager/make-timeout-promise.d.ts +1 -1
  27. package/dist/io-manager/make-timeout-promise.js +8 -4
  28. package/dist/on-audio-track.d.ts +2 -2
  29. package/dist/on-audio-track.js +15 -150
  30. package/dist/on-frame.d.ts +2 -4
  31. package/dist/on-frame.js +8 -9
  32. package/dist/on-video-track.d.ts +2 -2
  33. package/dist/on-video-track.js +18 -129
  34. package/dist/processing-queue.d.ts +19 -0
  35. package/dist/processing-queue.js +47 -0
  36. package/dist/reencode-audio-track.d.ts +18 -0
  37. package/dist/reencode-audio-track.js +164 -0
  38. package/dist/reencode-video-track.d.ts +19 -0
  39. package/dist/reencode-video-track.js +151 -0
  40. package/dist/sort-video-frames.d.ts +4 -3
  41. package/dist/sort-video-frames.js +7 -3
  42. package/dist/video-decoder.d.ts +14 -8
  43. package/dist/video-decoder.js +37 -72
  44. package/dist/video-encoder.d.ts +6 -5
  45. package/dist/video-encoder.js +16 -40
  46. package/dist/wav-audio-encoder.d.ts +4 -1
  47. package/dist/wav-audio-encoder.js +3 -2
  48. package/package.json +5 -5
@@ -1,4 +1,9 @@
1
+ import type { MediaParserLogLevel } from '@remotion/media-parser';
1
2
  import type { CreateAudioDecoderInit, WebCodecsAudioDecoder } from './audio-decoder';
2
- export declare const getWaveAudioDecoder: ({ onFrame, track, sampleFormat, }: Pick<CreateAudioDecoderInit, "onFrame" | "track"> & {
3
+ import type { IoSynchronizer } from './io-manager/io-synchronizer';
4
+ export declare const getWaveAudioDecoder: ({ onFrame, config, sampleFormat, ioSynchronizer, onError, }: Pick<CreateAudioDecoderInit, "onFrame" | "config"> & {
3
5
  sampleFormat: AudioSampleFormat;
6
+ logLevel: MediaParserLogLevel;
7
+ ioSynchronizer: IoSynchronizer;
8
+ onError: (error: Error) => void;
4
9
  }) => WebCodecsAudioDecoder;
@@ -28,30 +28,35 @@ const getBytesPerSample = (sampleFormat) => {
28
28
  }
29
29
  throw new Error(`Unsupported sample format: ${sampleFormat}`);
30
30
  };
31
- // TODO: Should also be subject to throttling
32
- const getWaveAudioDecoder = ({ onFrame, track, sampleFormat, }) => {
33
- let queue = Promise.resolve();
31
+ const getWaveAudioDecoder = ({ onFrame, config, sampleFormat, ioSynchronizer, onError, }) => {
34
32
  const processSample = async (audioSample) => {
35
33
  const bytesPerSample = getBytesPerSample(sampleFormat);
36
- await onFrame(new AudioData({
34
+ const audioData = new AudioData({
37
35
  data: audioSample.data,
38
36
  format: sampleFormat,
39
- numberOfChannels: track.numberOfChannels,
40
- numberOfFrames: audioSample.data.byteLength / bytesPerSample / track.numberOfChannels,
41
- sampleRate: track.sampleRate,
37
+ numberOfChannels: config.numberOfChannels,
38
+ numberOfFrames: audioSample.data.byteLength / bytesPerSample / config.numberOfChannels,
39
+ sampleRate: config.sampleRate,
42
40
  timestamp: audioSample.timestamp,
43
- }));
41
+ });
42
+ try {
43
+ await onFrame(audioData);
44
+ }
45
+ catch (err) {
46
+ audioData.close();
47
+ onError(err);
48
+ }
44
49
  };
45
50
  return {
46
51
  close() {
47
52
  return Promise.resolve();
48
53
  },
49
- processSample(audioSample) {
50
- queue = queue.then(() => processSample(audioSample));
51
- return queue;
54
+ decode(audioSample) {
55
+ processSample(audioSample);
52
56
  },
53
57
  flush: () => Promise.resolve(),
54
58
  waitForFinish: () => Promise.resolve(),
59
+ waitForQueueToBeLessThan: ioSynchronizer.waitForQueueSize,
55
60
  };
56
61
  };
57
62
  exports.getWaveAudioDecoder = getWaveAudioDecoder;
@@ -1,20 +1,13 @@
1
- import type { ProgressTracker } from '../create/progress-tracker';
2
1
  import type { LogLevel } from '../log';
3
2
  import type { WebCodecsController } from '../webcodecs-controller';
4
- export declare const makeIoSynchronizer: ({ logLevel, label, progress, }: {
3
+ export declare const makeIoSynchronizer: ({ logLevel, label, controller, }: {
5
4
  logLevel: LogLevel;
6
5
  label: string;
7
- progress: ProgressTracker;
6
+ controller: WebCodecsController | null;
8
7
  }) => {
9
- inputItem: (timestamp: number, keyFrame: boolean) => void;
8
+ inputItem: (timestamp: number) => void;
10
9
  onOutput: (timestamp: number) => void;
11
- waitFor: ({ unprocessed, unemitted, minimumProgress, controller, }: {
12
- unemitted: number;
13
- unprocessed: number;
14
- minimumProgress: number | null;
15
- controller: WebCodecsController;
16
- }) => Promise<void>;
17
- waitForFinish: (controller: WebCodecsController) => Promise<void>;
18
- onProcessed: () => void;
19
- getUnprocessed: () => number;
10
+ waitForFinish: () => Promise<void>;
11
+ waitForQueueSize: (queueSize: number) => Promise<void>;
20
12
  };
13
+ export type IoSynchronizer = ReturnType<typeof makeIoSynchronizer>;
@@ -5,40 +5,25 @@ const event_emitter_1 = require("../create/event-emitter");
5
5
  const with_resolvers_1 = require("../create/with-resolvers");
6
6
  const log_1 = require("../log");
7
7
  const make_timeout_promise_1 = require("./make-timeout-promise");
8
- const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
8
+ const makeIoSynchronizer = ({ logLevel, label, controller, }) => {
9
9
  const eventEmitter = new event_emitter_1.IoEventEmitter();
10
10
  let lastInput = 0;
11
- let lastInputKeyframe = 0;
12
11
  let lastOutput = 0;
13
12
  let inputsSinceLastOutput = 0;
14
13
  let inputs = [];
15
- let keyframes = [];
16
- // Once WebCodecs emits items, the user has to handle them
17
- // Let's keep count of how many items are unprocessed
18
- let _unprocessed = 0;
19
- const getUnprocessed = () => _unprocessed;
20
- const getUnemittedItems = () => {
14
+ const getQueuedItems = () => {
21
15
  inputs = inputs.filter((input) => Math.floor(input) > Math.floor(lastOutput));
22
16
  return inputs.length;
23
17
  };
24
- const getUnemittedKeyframes = () => {
25
- keyframes = keyframes.filter((keyframe) => Math.floor(keyframe) > Math.floor(lastOutput));
26
- return keyframes.length;
27
- };
28
18
  const printState = (prefix) => {
29
- log_1.Log.trace(logLevel, `[${label}] ${prefix}, state: Last input = ${lastInput} Last input keyframe = ${lastInputKeyframe} Last output = ${lastOutput} Inputs since last output = ${inputsSinceLastOutput}, Queue = ${getUnemittedItems()} (${getUnemittedKeyframes()} keyframes), Unprocessed = ${getUnprocessed()}`);
19
+ log_1.Log.trace(logLevel, `[${label}] ${prefix}, state: Last input = ${lastInput} Last output = ${lastOutput} Inputs since last output = ${inputsSinceLastOutput}, Queue = ${getQueuedItems()}`);
30
20
  };
31
- const inputItem = (timestamp, keyFrame) => {
21
+ const inputItem = (timestamp) => {
32
22
  lastInput = timestamp;
33
- if (keyFrame) {
34
- lastInputKeyframe = timestamp;
35
- keyframes.push(timestamp);
36
- }
37
23
  inputsSinceLastOutput++;
38
24
  inputs.push(timestamp);
39
25
  eventEmitter.dispatchEvent('input', {
40
26
  timestamp,
41
- keyFrame,
42
27
  });
43
28
  printState('Input item');
44
29
  };
@@ -48,7 +33,6 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
48
33
  eventEmitter.dispatchEvent('output', {
49
34
  timestamp,
50
35
  });
51
- _unprocessed++;
52
36
  printState('Got output');
53
37
  };
54
38
  const waitForOutput = () => {
@@ -60,75 +44,50 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
60
44
  eventEmitter.addEventListener('output', on);
61
45
  return promise;
62
46
  };
63
- const waitForProcessed = () => {
64
- const { promise, resolve } = (0, with_resolvers_1.withResolvers)();
65
- const on = () => {
66
- eventEmitter.removeEventListener('processed', on);
67
- resolve();
68
- };
69
- eventEmitter.addEventListener('processed', on);
70
- return promise;
47
+ const makeErrorBanner = () => {
48
+ return [
49
+ `Waited too long for ${label} to finish:`,
50
+ `${getQueuedItems()} queued items`,
51
+ `inputs: ${JSON.stringify(inputs)}`,
52
+ `last output: ${lastOutput}`,
53
+ ];
71
54
  };
72
- const waitFor = async ({ unprocessed, unemitted, minimumProgress, controller, }) => {
73
- await controller._internals._mediaParserController._internals.checkForAbortAndPause();
55
+ const waitForQueueSize = async (queueSize) => {
56
+ if (getQueuedItems() <= queueSize) {
57
+ return Promise.resolve();
58
+ }
74
59
  const { timeoutPromise, clear } = (0, make_timeout_promise_1.makeTimeoutPromise)({
75
60
  label: () => [
76
- `Waited too long for ${label} to finish:`,
77
- `${getUnemittedItems()} unemitted items`,
78
- `${getUnprocessed()} unprocessed items: ${JSON.stringify(_unprocessed)}`,
79
- `smallest progress: ${progress.getSmallestProgress()}`,
80
- `inputs: ${JSON.stringify(inputs)}`,
81
- `last output: ${lastOutput}`,
82
- `wanted: ${unemitted} unemitted items, ${unprocessed} unprocessed items, minimum progress ${minimumProgress}`,
61
+ ...makeErrorBanner(),
62
+ `wanted: <${queueSize} queued items`,
83
63
  `Report this at https://remotion.dev/report`,
84
64
  ].join('\n'),
85
65
  ms: 10000,
86
66
  controller,
87
67
  });
88
- controller._internals._mediaParserController._internals.signal.addEventListener('abort', clear);
68
+ if (controller) {
69
+ controller._internals._mediaParserController._internals.signal.addEventListener('abort', clear);
70
+ }
89
71
  await Promise.race([
90
72
  timeoutPromise,
91
- Promise.all([
92
- (async () => {
93
- while (getUnemittedItems() > unemitted) {
94
- await waitForOutput();
95
- }
96
- })(),
97
- (async () => {
98
- while (getUnprocessed() > unprocessed) {
99
- await waitForProcessed();
100
- }
101
- })(),
102
- minimumProgress === null || progress.getSmallestProgress() === null
103
- ? Promise.resolve()
104
- : (async () => {
105
- while (progress.getSmallestProgress() < minimumProgress) {
106
- await progress.waitForProgress();
107
- }
108
- })(),
109
- ]),
73
+ (async () => {
74
+ while (getQueuedItems() > queueSize) {
75
+ await waitForOutput();
76
+ }
77
+ })(),
110
78
  ]).finally(() => clear());
111
- controller._internals._mediaParserController._internals.signal.removeEventListener('abort', clear);
112
- };
113
- const waitForFinish = async (controller) => {
114
- await waitFor({
115
- unprocessed: 0,
116
- unemitted: 0,
117
- minimumProgress: null,
118
- controller,
119
- });
79
+ if (controller) {
80
+ controller._internals._mediaParserController._internals.signal.removeEventListener('abort', clear);
81
+ }
120
82
  };
121
- const onProcessed = () => {
122
- eventEmitter.dispatchEvent('processed', {});
123
- _unprocessed--;
83
+ const waitForFinish = async () => {
84
+ await waitForQueueSize(0);
124
85
  };
125
86
  return {
126
87
  inputItem,
127
88
  onOutput,
128
- waitFor,
129
89
  waitForFinish,
130
- onProcessed,
131
- getUnprocessed,
90
+ waitForQueueSize,
132
91
  };
133
92
  };
134
93
  exports.makeIoSynchronizer = makeIoSynchronizer;
@@ -2,7 +2,7 @@ import type { WebCodecsController } from '../webcodecs-controller';
2
2
  export declare const makeTimeoutPromise: ({ label, ms, controller, }: {
3
3
  label: () => string;
4
4
  ms: number;
5
- controller: WebCodecsController;
5
+ controller: WebCodecsController | null;
6
6
  }) => {
7
7
  timeoutPromise: Promise<void>;
8
8
  clear: () => void;
@@ -19,8 +19,10 @@ const makeTimeoutPromise = ({ label, ms, controller, }) => {
19
19
  const onResume = () => {
20
20
  set();
21
21
  };
22
- controller.addEventListener('pause', onPause);
23
- controller.addEventListener('resume', onResume);
22
+ if (controller) {
23
+ controller.addEventListener('pause', onPause);
24
+ controller.addEventListener('resume', onResume);
25
+ }
24
26
  return {
25
27
  timeoutPromise: promise,
26
28
  clear: () => {
@@ -28,8 +30,10 @@ const makeTimeoutPromise = ({ label, ms, controller, }) => {
28
30
  clearTimeout(timeout);
29
31
  }
30
32
  resolve();
31
- controller.removeEventListener('pause', onPause);
32
- controller.removeEventListener('resume', onResume);
33
+ if (controller) {
34
+ controller.removeEventListener('pause', onPause);
35
+ controller.removeEventListener('resume', onResume);
36
+ }
33
37
  },
34
38
  };
35
39
  };
@@ -7,7 +7,7 @@ import type { ConvertMediaContainer } from './get-available-containers';
7
7
  import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
8
8
  import type { ConvertMediaProgressFn } from './throttled-state-update';
9
9
  import type { WebCodecsController } from './webcodecs-controller';
10
- export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, progressTracker, onAudioData, }: {
10
+ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, onAudioData, progressTracker, }: {
11
11
  state: MediaFn;
12
12
  defaultAudioCodec: ConvertMediaAudioCodec | null;
13
13
  controller: WebCodecsController;
@@ -16,6 +16,6 @@ export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCo
16
16
  onAudioTrack: ConvertMediaOnAudioTrackHandler | null;
17
17
  logLevel: MediaParserLogLevel;
18
18
  outputContainer: ConvertMediaContainer;
19
- progressTracker: ProgressTracker;
20
19
  onAudioData: ConvertMediaOnAudioData | null;
20
+ progressTracker: ProgressTracker;
21
21
  }) => MediaParserOnAudioTrack;
@@ -1,17 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.makeAudioTrackHandler = void 0;
4
- const media_parser_1 = require("@remotion/media-parser");
5
- const audio_decoder_1 = require("./audio-decoder");
6
- const audio_decoder_config_1 = require("./audio-decoder-config");
7
- const audio_encoder_1 = require("./audio-encoder");
8
- const audio_encoder_config_1 = require("./audio-encoder-config");
9
4
  const can_copy_audio_track_1 = require("./can-copy-audio-track");
10
- const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
5
+ const copy_audio_track_1 = require("./copy-audio-track");
11
6
  const default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
12
7
  const get_default_audio_codec_1 = require("./get-default-audio-codec");
13
- const log_1 = require("./log");
14
- const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, progressTracker, onAudioData, }) => async ({ track, container: inputContainer }) => {
8
+ const reencode_audio_track_1 = require("./reencode-audio-track");
9
+ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer, onAudioData, progressTracker, }) => async ({ track, container: inputContainer }) => {
15
10
  const canCopyTrack = (0, can_copy_audio_track_1.canCopyAudioTrack)({
16
11
  inputCodec: track.codecEnum,
17
12
  outputContainer,
@@ -32,154 +27,24 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
32
27
  throw new Error(`Audio track with ID ${track.trackId} resolved with {"type": "fail"}. This could mean that this audio track could neither be copied to the output container or re-encoded. You have the option to drop the track instead of failing it: https://remotion.dev/docs/webcodecs/track-transformation`);
33
28
  }
34
29
  if (audioOperation.type === 'copy') {
35
- const addedTrack = await state.addTrack({
36
- type: 'audio',
37
- codec: track.codecEnum,
38
- numberOfChannels: track.numberOfChannels,
39
- sampleRate: track.sampleRate,
40
- codecPrivate: track.codecData?.data ?? null,
41
- timescale: track.timescale,
30
+ return (0, copy_audio_track_1.copyAudioTrack)({
31
+ logLevel,
32
+ onMediaStateUpdate,
33
+ state,
34
+ track,
35
+ progressTracker,
42
36
  });
43
- log_1.Log.verbose(logLevel, `Copying audio track ${track.trackId} as track ${addedTrack.trackNumber}. Timescale = ${track.timescale}, codec = ${track.codecEnum} (${track.codec}) `);
44
- return async (audioSample) => {
45
- await state.addSample({
46
- chunk: audioSample,
47
- trackNumber: addedTrack.trackNumber,
48
- isVideo: false,
49
- codecPrivate: track.codecData?.data ?? null,
50
- });
51
- onMediaStateUpdate?.((prevState) => {
52
- return {
53
- ...prevState,
54
- encodedAudioFrames: prevState.encodedAudioFrames + 1,
55
- };
56
- });
57
- };
58
37
  }
59
- const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
60
- numberOfChannels: track.numberOfChannels,
61
- sampleRate: audioOperation.sampleRate ?? track.sampleRate,
62
- codec: audioOperation.audioCodec,
63
- bitrate: audioOperation.bitrate,
64
- });
65
- const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)({
66
- codec: track.codec,
67
- numberOfChannels: track.numberOfChannels,
68
- sampleRate: track.sampleRate,
69
- description: track.description,
70
- });
71
- log_1.Log.verbose(logLevel, 'Audio encoder config', audioEncoderConfig);
72
- log_1.Log.verbose(logLevel, 'Audio decoder config', audioDecoderConfig ?? track);
73
- if (!audioEncoderConfig) {
74
- abortConversion(new Error(`Could not configure audio encoder of track ${track.trackId}`));
75
- return null;
76
- }
77
- if (!audioDecoderConfig) {
78
- abortConversion(new Error(`Could not configure audio decoder of track ${track.trackId}`));
79
- return null;
80
- }
81
- const codecPrivate = audioOperation.audioCodec === 'aac'
82
- ? media_parser_1.MediaParserInternals.createAacCodecPrivate({
83
- audioObjectType: 2,
84
- sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
85
- channelConfiguration: audioEncoderConfig.numberOfChannels,
86
- codecPrivate: null,
87
- })
88
- : null;
89
- const { trackNumber } = await state.addTrack({
90
- type: 'audio',
91
- codec: audioOperation.audioCodec === 'wav'
92
- ? 'pcm-s16'
93
- : audioOperation.audioCodec,
94
- numberOfChannels: audioEncoderConfig.numberOfChannels,
95
- sampleRate: audioOperation.sampleRate ?? audioEncoderConfig.sampleRate,
96
- codecPrivate,
97
- timescale: track.timescale,
98
- });
99
- const audioEncoder = (0, audio_encoder_1.createAudioEncoder)({
100
- // This is weird 😵‍💫
101
- // Chrome completely ignores the sample rate and uses it's own
102
- // We cannot determine it here because it depends on the system
103
- // sample rate. Unhardcode then declare it later once we know.
104
- onNewAudioSampleRate: (sampleRate) => {
105
- state.updateTrackSampleRate({ sampleRate, trackNumber });
106
- },
107
- onChunk: async (chunk) => {
108
- await state.addSample({
109
- chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
110
- trackNumber,
111
- isVideo: false,
112
- codecPrivate,
113
- });
114
- onMediaStateUpdate?.((prevState) => {
115
- return {
116
- ...prevState,
117
- encodedAudioFrames: prevState.encodedAudioFrames + 1,
118
- };
119
- });
120
- },
121
- onError: (err) => {
122
- abortConversion(new Error(`Audio encoder of track ${track.trackId} failed (see .cause of this error)`, {
123
- cause: err,
124
- }));
125
- },
126
- codec: audioOperation.audioCodec,
127
- controller,
128
- config: audioEncoderConfig,
129
- logLevel,
130
- progressTracker,
131
- });
132
- const audioDecoder = (0, audio_decoder_1.createAudioDecoder)({
133
- onFrame: async (audioData) => {
134
- const newAudioData = onAudioData
135
- ? await onAudioData?.({ audioData, track })
136
- : audioData;
137
- if (newAudioData !== audioData) {
138
- if (newAudioData.duration !== audioData.duration) {
139
- throw new Error(`onAudioData returned a different duration than the input audio data. Original duration: ${audioData.duration}, new duration: ${newAudioData.duration}`);
140
- }
141
- if (newAudioData.numberOfChannels !== audioData.numberOfChannels) {
142
- throw new Error(`onAudioData returned a different number of channels than the input audio data. Original channels: ${audioData.numberOfChannels}, new channels: ${newAudioData.numberOfChannels}`);
143
- }
144
- if (newAudioData.sampleRate !== audioData.sampleRate) {
145
- throw new Error(`onAudioData returned a different sample rate than the input audio data. Original sample rate: ${audioData.sampleRate}, new sample rate: ${newAudioData.sampleRate}`);
146
- }
147
- if (newAudioData.format !== audioData.format) {
148
- throw new Error(`onAudioData returned a different format than the input audio data. Original format: ${audioData.format}, new format: ${newAudioData.format}`);
149
- }
150
- if (newAudioData.timestamp !== audioData.timestamp) {
151
- throw new Error(`onAudioData returned a different timestamp than the input audio data. Original timestamp: ${audioData.timestamp}, new timestamp: ${newAudioData.timestamp}`);
152
- }
153
- audioData.close();
154
- }
155
- await audioEncoder.encodeFrame(newAudioData);
156
- onMediaStateUpdate?.((prevState) => {
157
- return {
158
- ...prevState,
159
- decodedAudioFrames: prevState.decodedAudioFrames + 1,
160
- };
161
- });
162
- newAudioData.close();
163
- },
164
- onError(error) {
165
- abortConversion(new Error(`Audio decoder of track ${track.trackId} failed. Config: ${JSON.stringify(audioDecoderConfig)} (see .cause of this error)`, {
166
- cause: error,
167
- }));
168
- },
38
+ return (0, reencode_audio_track_1.reencodeAudioTrack)({
39
+ abortConversion,
169
40
  controller,
170
- config: audioDecoderConfig,
171
41
  logLevel,
42
+ onMediaStateUpdate,
43
+ audioOperation,
44
+ onAudioData,
45
+ state,
172
46
  track,
173
47
  progressTracker,
174
48
  });
175
- state.addWaitForFinishPromise(async () => {
176
- await audioDecoder.waitForFinish();
177
- await audioEncoder.waitForFinish();
178
- audioDecoder.close();
179
- audioEncoder.close();
180
- });
181
- return async (audioSample) => {
182
- await audioDecoder.processSample(audioSample);
183
- };
184
49
  };
185
50
  exports.makeAudioTrackHandler = makeAudioTrackHandler;
@@ -2,13 +2,11 @@ import type { MediaParserVideoTrack } from '@remotion/media-parser';
2
2
  import type { ConvertMediaOnVideoFrame } from './convert-media';
3
3
  import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
4
4
  import type { ResizeOperation } from './resizing/mode';
5
- import type { WebCodecsVideoEncoder } from './video-encoder';
6
- export declare const onFrame: ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, resizeOperation, }: {
5
+ export declare const onFrame: ({ frame: unrotatedFrame, onVideoFrame, track, outputCodec, rotation, resizeOperation, }: {
7
6
  frame: VideoFrame;
8
7
  onVideoFrame: ConvertMediaOnVideoFrame | null;
9
- videoEncoder: WebCodecsVideoEncoder;
10
8
  track: MediaParserVideoTrack;
11
9
  outputCodec: ConvertMediaVideoCodec;
12
10
  rotation: number;
13
11
  resizeOperation: ResizeOperation | null;
14
- }) => Promise<void>;
12
+ }) => Promise<VideoFrame>;
package/dist/on-frame.js CHANGED
@@ -4,7 +4,7 @@ exports.onFrame = void 0;
4
4
  const browser_quirks_1 = require("./browser-quirks");
5
5
  const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
6
6
  const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
7
- const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, resizeOperation, }) => {
7
+ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, track, outputCodec, rotation, resizeOperation, }) => {
8
8
  const rotated = (0, rotate_and_resize_video_frame_1.rotateAndResizeVideoFrame)({
9
9
  rotation,
10
10
  frame: unrotatedFrame,
@@ -18,10 +18,10 @@ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, trac
18
18
  ? await onVideoFrame({ frame: rotated, track })
19
19
  : rotated;
20
20
  if (userProcessedFrame.displayWidth !== rotated.displayWidth) {
21
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${userProcessedFrame.displayWidth}) than the input frame (${userProcessedFrame.displayHeight})`);
21
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${userProcessedFrame.displayWidth}) than the input frame (${rotated.displayWidth})`);
22
22
  }
23
23
  if (userProcessedFrame.displayHeight !== rotated.displayHeight) {
24
- throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${userProcessedFrame.displayHeight}) than the input frame (${userProcessedFrame.displayHeight})`);
24
+ throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayHeight (${userProcessedFrame.displayHeight}) than the input frame (${rotated.displayHeight})`);
25
25
  }
26
26
  // In Safari, calling new VideoFrame() might change the timestamp
27
27
  // In flipVideo test from 803000 to 803299
@@ -31,17 +31,16 @@ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, trac
31
31
  if ((userProcessedFrame.duration ?? 0) !== (rotated.duration ?? 0)) {
32
32
  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`);
33
33
  }
34
+ if (rotated !== userProcessedFrame) {
35
+ rotated.close();
36
+ }
34
37
  const fixedFrame = (0, convert_to_correct_videoframe_1.convertToCorrectVideoFrame)({
35
38
  videoFrame: userProcessedFrame,
36
39
  outputCodec,
37
40
  });
38
- await videoEncoder.encodeFrame(fixedFrame, fixedFrame.timestamp);
39
- fixedFrame.close();
40
- if (rotated !== userProcessedFrame) {
41
- rotated.close();
42
- }
43
41
  if (fixedFrame !== userProcessedFrame) {
44
- fixedFrame.close();
42
+ userProcessedFrame.close();
45
43
  }
44
+ return fixedFrame;
46
45
  };
47
46
  exports.onFrame = onFrame;
@@ -8,7 +8,7 @@ import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
8
8
  import type { ResizeOperation } from './resizing/mode';
9
9
  import type { ConvertMediaProgressFn } from './throttled-state-update';
10
10
  import type { WebCodecsController } from './webcodecs-controller';
11
- export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, resizeOperation, }: {
11
+ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, resizeOperation, progressTracker, }: {
12
12
  state: MediaFn;
13
13
  onVideoFrame: null | ConvertMediaOnVideoFrame;
14
14
  onMediaStateUpdate: null | ConvertMediaProgressFn;
@@ -19,6 +19,6 @@ export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaState
19
19
  logLevel: MediaParserLogLevel;
20
20
  outputContainer: ConvertMediaContainer;
21
21
  rotate: number;
22
- progress: ProgressTracker;
23
22
  resizeOperation: ResizeOperation | null;
23
+ progressTracker: ProgressTracker;
24
24
  }) => MediaParserOnVideoTrack;