@remotion/webcodecs 4.0.305 → 4.0.308
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.
- package/dist/audio-decoder.d.ts +15 -10
- package/dist/audio-decoder.js +49 -52
- package/dist/audio-encoder.d.ts +5 -5
- package/dist/audio-encoder.js +20 -42
- package/dist/can-copy-audio-track.d.ts +3 -1
- package/dist/can-copy-audio-track.js +10 -1
- package/dist/can-copy-video-track.d.ts +3 -1
- package/dist/can-copy-video-track.js +10 -1
- package/dist/convert-media.js +2 -2
- package/dist/copy-audio-track.d.ts +11 -0
- package/dist/copy-audio-track.js +31 -0
- package/dist/copy-video-track.d.ts +11 -0
- package/dist/copy-video-track.js +32 -0
- package/dist/create/event-emitter.d.ts +0 -1
- package/dist/create/matroska/matroska-utils.d.ts +1 -1
- package/dist/create/progress-tracker.d.ts +0 -2
- package/dist/create/progress-tracker.js +3 -20
- package/dist/create-audio-decoder.d.ts +24 -0
- package/dist/create-audio-decoder.js +112 -0
- package/dist/create-video-decoder.d.ts +23 -0
- package/dist/create-video-decoder.js +89 -0
- package/dist/esm/index.mjs +794 -631
- package/dist/get-wave-audio-decoder.d.ts +7 -2
- package/dist/get-wave-audio-decoder.js +27 -13
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -5
- package/dist/io-manager/io-synchronizer.d.ts +5 -13
- package/dist/io-manager/io-synchronizer.js +29 -74
- package/dist/io-manager/make-timeout-promise.d.ts +1 -1
- package/dist/io-manager/make-timeout-promise.js +8 -4
- package/dist/is-different-video-codec.d.ts +11 -0
- package/dist/is-different-video-codec.js +36 -0
- package/dist/on-audio-track.d.ts +2 -2
- package/dist/on-audio-track.js +16 -150
- package/dist/on-frame.d.ts +2 -4
- package/dist/on-frame.js +8 -9
- package/dist/on-video-track.d.ts +2 -2
- package/dist/on-video-track.js +19 -129
- package/dist/processing-queue.d.ts +18 -0
- package/dist/processing-queue.js +47 -0
- package/dist/reencode-audio-track.d.ts +18 -0
- package/dist/reencode-audio-track.js +164 -0
- package/dist/reencode-video-track.d.ts +19 -0
- package/dist/reencode-video-track.js +151 -0
- package/dist/sort-video-frames.d.ts +4 -3
- package/dist/sort-video-frames.js +7 -3
- package/dist/video-decoder.d.ts +14 -8
- package/dist/video-decoder.js +37 -72
- package/dist/video-encoder.d.ts +6 -5
- package/dist/video-encoder.js +16 -40
- package/dist/wav-audio-encoder.d.ts +4 -1
- package/dist/wav-audio-encoder.js +3 -2
- package/package.json +5 -5
- package/dist/select-container-creator.d.ts +0 -2
- package/dist/select-container-creator.js +0 -19
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type { MediaParserLogLevel } from '@remotion/media-parser';
|
|
2
|
+
import type { CreateAudioDecoderInit, WebCodecsAudioDecoder } from './create-audio-decoder';
|
|
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,44 @@ const getBytesPerSample = (sampleFormat) => {
|
|
|
28
28
|
}
|
|
29
29
|
throw new Error(`Unsupported sample format: ${sampleFormat}`);
|
|
30
30
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
31
|
+
const getAudioData = (audioSample) => {
|
|
32
|
+
if (audioSample instanceof EncodedAudioChunk) {
|
|
33
|
+
const data = new Uint8Array(audioSample.byteLength);
|
|
34
|
+
audioSample.copyTo(data);
|
|
35
|
+
return data;
|
|
36
|
+
}
|
|
37
|
+
return audioSample.data;
|
|
38
|
+
};
|
|
39
|
+
const getWaveAudioDecoder = ({ onFrame, config, sampleFormat, ioSynchronizer, onError, }) => {
|
|
34
40
|
const processSample = async (audioSample) => {
|
|
35
41
|
const bytesPerSample = getBytesPerSample(sampleFormat);
|
|
36
|
-
|
|
37
|
-
|
|
42
|
+
const data = getAudioData(audioSample);
|
|
43
|
+
const audioData = new AudioData({
|
|
44
|
+
data,
|
|
38
45
|
format: sampleFormat,
|
|
39
|
-
numberOfChannels:
|
|
40
|
-
numberOfFrames:
|
|
41
|
-
sampleRate:
|
|
46
|
+
numberOfChannels: config.numberOfChannels,
|
|
47
|
+
numberOfFrames: data.byteLength / bytesPerSample / config.numberOfChannels,
|
|
48
|
+
sampleRate: config.sampleRate,
|
|
42
49
|
timestamp: audioSample.timestamp,
|
|
43
|
-
})
|
|
50
|
+
});
|
|
51
|
+
try {
|
|
52
|
+
await onFrame(audioData);
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
audioData.close();
|
|
56
|
+
onError(err);
|
|
57
|
+
}
|
|
44
58
|
};
|
|
45
59
|
return {
|
|
46
60
|
close() {
|
|
47
61
|
return Promise.resolve();
|
|
48
62
|
},
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
return queue;
|
|
63
|
+
decode(audioSample) {
|
|
64
|
+
return processSample(audioSample);
|
|
52
65
|
},
|
|
53
66
|
flush: () => Promise.resolve(),
|
|
54
|
-
|
|
67
|
+
waitForQueueToBeLessThan: ioSynchronizer.waitForQueueSize,
|
|
68
|
+
reset: () => { },
|
|
55
69
|
};
|
|
56
70
|
};
|
|
57
71
|
exports.getWaveAudioDecoder = getWaveAudioDecoder;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
export { createAudioDecoder } from './audio-decoder';
|
|
2
|
-
export type { WebCodecsAudioDecoder } from './audio-decoder';
|
|
3
1
|
export { createAudioEncoder } from './audio-encoder';
|
|
4
2
|
export type { WebCodecsAudioEncoder } from './audio-encoder';
|
|
5
3
|
export { canCopyAudioTrack } from './can-copy-audio-track';
|
|
@@ -9,6 +7,10 @@ export { canReencodeVideoTrack } from './can-reencode-video-track';
|
|
|
9
7
|
export { convertAudioData, ConvertAudioDataOptions } from './convert-audiodata';
|
|
10
8
|
export { convertMedia } from './convert-media';
|
|
11
9
|
export type { ConvertMediaOnAudioData, ConvertMediaOnProgress, ConvertMediaOnVideoFrame, ConvertMediaProgress, ConvertMediaResult, } from './convert-media';
|
|
10
|
+
export { createAudioDecoder } from './create-audio-decoder';
|
|
11
|
+
export type { WebCodecsAudioDecoder } from './create-audio-decoder';
|
|
12
|
+
export { createVideoDecoder } from './create-video-decoder';
|
|
13
|
+
export type { WebCodecsVideoDecoder } from './create-video-decoder';
|
|
12
14
|
export { defaultOnAudioTrackHandler } from './default-on-audio-track-handler';
|
|
13
15
|
export { defaultOnVideoTrackHandler } from './default-on-video-track-handler';
|
|
14
16
|
export { getAvailableAudioCodecs } from './get-available-audio-codecs';
|
|
@@ -22,8 +24,6 @@ export { getDefaultVideoCodec } from './get-default-video-codec';
|
|
|
22
24
|
export type { AudioOperation, ConvertMediaOnAudioTrackHandler, } from './on-audio-track-handler';
|
|
23
25
|
export type { ConvertMediaOnVideoTrackHandler, VideoOperation, } from './on-video-track-handler';
|
|
24
26
|
export type { ResizeOperation } from './resizing/mode';
|
|
25
|
-
export { createVideoDecoder } from './video-decoder';
|
|
26
|
-
export type { WebCodecsVideoDecoder } from './video-decoder';
|
|
27
27
|
export { createVideoEncoder } from './video-encoder';
|
|
28
28
|
export type { WebCodecsVideoEncoder } from './video-encoder';
|
|
29
29
|
export { webcodecsController } from './webcodecs-controller';
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.WebCodecsInternals = exports.webcodecsController = exports.createVideoEncoder = exports.
|
|
3
|
+
exports.WebCodecsInternals = exports.webcodecsController = exports.createVideoEncoder = exports.getDefaultVideoCodec = exports.getDefaultAudioCodec = exports.getAvailableVideoCodecs = exports.getAvailableContainers = exports.getAvailableAudioCodecs = exports.defaultOnVideoTrackHandler = exports.defaultOnAudioTrackHandler = exports.createVideoDecoder = exports.createAudioDecoder = exports.convertMedia = exports.convertAudioData = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = void 0;
|
|
4
4
|
const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
|
|
5
5
|
const rotation_1 = require("./rotation");
|
|
6
6
|
const set_remotion_imported_1 = require("./set-remotion-imported");
|
|
7
|
-
var audio_decoder_1 = require("./audio-decoder");
|
|
8
|
-
Object.defineProperty(exports, "createAudioDecoder", { enumerable: true, get: function () { return audio_decoder_1.createAudioDecoder; } });
|
|
9
7
|
var audio_encoder_1 = require("./audio-encoder");
|
|
10
8
|
Object.defineProperty(exports, "createAudioEncoder", { enumerable: true, get: function () { return audio_encoder_1.createAudioEncoder; } });
|
|
11
9
|
var can_copy_audio_track_1 = require("./can-copy-audio-track");
|
|
@@ -20,6 +18,10 @@ var convert_audiodata_1 = require("./convert-audiodata");
|
|
|
20
18
|
Object.defineProperty(exports, "convertAudioData", { enumerable: true, get: function () { return convert_audiodata_1.convertAudioData; } });
|
|
21
19
|
var convert_media_1 = require("./convert-media");
|
|
22
20
|
Object.defineProperty(exports, "convertMedia", { enumerable: true, get: function () { return convert_media_1.convertMedia; } });
|
|
21
|
+
var create_audio_decoder_1 = require("./create-audio-decoder");
|
|
22
|
+
Object.defineProperty(exports, "createAudioDecoder", { enumerable: true, get: function () { return create_audio_decoder_1.createAudioDecoder; } });
|
|
23
|
+
var create_video_decoder_1 = require("./create-video-decoder");
|
|
24
|
+
Object.defineProperty(exports, "createVideoDecoder", { enumerable: true, get: function () { return create_video_decoder_1.createVideoDecoder; } });
|
|
23
25
|
var default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
|
|
24
26
|
Object.defineProperty(exports, "defaultOnAudioTrackHandler", { enumerable: true, get: function () { return default_on_audio_track_handler_1.defaultOnAudioTrackHandler; } });
|
|
25
27
|
var default_on_video_track_handler_1 = require("./default-on-video-track-handler");
|
|
@@ -34,8 +36,6 @@ var get_default_audio_codec_1 = require("./get-default-audio-codec");
|
|
|
34
36
|
Object.defineProperty(exports, "getDefaultAudioCodec", { enumerable: true, get: function () { return get_default_audio_codec_1.getDefaultAudioCodec; } });
|
|
35
37
|
var get_default_video_codec_1 = require("./get-default-video-codec");
|
|
36
38
|
Object.defineProperty(exports, "getDefaultVideoCodec", { enumerable: true, get: function () { return get_default_video_codec_1.getDefaultVideoCodec; } });
|
|
37
|
-
var video_decoder_1 = require("./video-decoder");
|
|
38
|
-
Object.defineProperty(exports, "createVideoDecoder", { enumerable: true, get: function () { return video_decoder_1.createVideoDecoder; } });
|
|
39
39
|
var video_encoder_1 = require("./video-encoder");
|
|
40
40
|
Object.defineProperty(exports, "createVideoEncoder", { enumerable: true, get: function () { return video_encoder_1.createVideoEncoder; } });
|
|
41
41
|
var webcodecs_controller_1 = require("./webcodecs-controller");
|
|
@@ -1,20 +1,12 @@
|
|
|
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,
|
|
3
|
+
export declare const makeIoSynchronizer: ({ logLevel, label, controller, }: {
|
|
5
4
|
logLevel: LogLevel;
|
|
6
5
|
label: string;
|
|
7
|
-
|
|
6
|
+
controller: WebCodecsController | null;
|
|
8
7
|
}) => {
|
|
9
|
-
inputItem: (timestamp: number
|
|
8
|
+
inputItem: (timestamp: number) => void;
|
|
10
9
|
onOutput: (timestamp: number) => void;
|
|
11
|
-
|
|
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
|
+
waitForQueueSize: (queueSize: number) => Promise<void>;
|
|
20
11
|
};
|
|
12
|
+
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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,46 @@ const makeIoSynchronizer = ({ logLevel, label, progress, }) => {
|
|
|
60
44
|
eventEmitter.addEventListener('output', on);
|
|
61
45
|
return promise;
|
|
62
46
|
};
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
|
73
|
-
|
|
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
|
-
|
|
77
|
-
|
|
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
|
|
68
|
+
if (controller) {
|
|
69
|
+
controller._internals._mediaParserController._internals.signal.addEventListener('abort', clear);
|
|
70
|
+
}
|
|
89
71
|
await Promise.race([
|
|
90
72
|
timeoutPromise,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
await waitFor({
|
|
115
|
-
unprocessed: 0,
|
|
116
|
-
unemitted: 0,
|
|
117
|
-
minimumProgress: null,
|
|
118
|
-
controller,
|
|
119
|
-
});
|
|
120
|
-
};
|
|
121
|
-
const onProcessed = () => {
|
|
122
|
-
eventEmitter.dispatchEvent('processed', {});
|
|
123
|
-
_unprocessed--;
|
|
79
|
+
if (controller) {
|
|
80
|
+
controller._internals._mediaParserController._internals.signal.removeEventListener('abort', clear);
|
|
81
|
+
}
|
|
124
82
|
};
|
|
125
83
|
return {
|
|
126
84
|
inputItem,
|
|
127
85
|
onOutput,
|
|
128
|
-
|
|
129
|
-
waitForFinish,
|
|
130
|
-
onProcessed,
|
|
131
|
-
getUnprocessed,
|
|
86
|
+
waitForQueueSize,
|
|
132
87
|
};
|
|
133
88
|
};
|
|
134
89
|
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
|
|
23
|
-
|
|
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
|
|
32
|
-
|
|
33
|
+
if (controller) {
|
|
34
|
+
controller.removeEventListener('pause', onPause);
|
|
35
|
+
controller.removeEventListener('resume', onResume);
|
|
36
|
+
}
|
|
33
37
|
},
|
|
34
38
|
};
|
|
35
39
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MediaParserAudioCodec, MediaParserVideoCodec } from '@remotion/media-parser';
|
|
2
|
+
import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
|
|
3
|
+
import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
|
|
4
|
+
export declare const isSameVideoCodec: ({ inputVideoCodec, outputCodec, }: {
|
|
5
|
+
inputVideoCodec: MediaParserVideoCodec;
|
|
6
|
+
outputCodec: ConvertMediaVideoCodec;
|
|
7
|
+
}) => boolean;
|
|
8
|
+
export declare const isSameAudioCodec: ({ inputAudioCodec, outputCodec, }: {
|
|
9
|
+
inputAudioCodec: MediaParserAudioCodec;
|
|
10
|
+
outputCodec: ConvertMediaAudioCodec;
|
|
11
|
+
}) => boolean;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isSameAudioCodec = exports.isSameVideoCodec = void 0;
|
|
4
|
+
const isSameVideoCodec = ({ inputVideoCodec, outputCodec, }) => {
|
|
5
|
+
if (outputCodec === 'h264') {
|
|
6
|
+
return inputVideoCodec === 'h264';
|
|
7
|
+
}
|
|
8
|
+
if (outputCodec === 'h265') {
|
|
9
|
+
return inputVideoCodec === 'h265';
|
|
10
|
+
}
|
|
11
|
+
if (outputCodec === 'vp8') {
|
|
12
|
+
return inputVideoCodec === 'vp8';
|
|
13
|
+
}
|
|
14
|
+
if (outputCodec === 'vp9') {
|
|
15
|
+
return inputVideoCodec === 'vp9';
|
|
16
|
+
}
|
|
17
|
+
throw new Error(`Unsupported output codec: ${outputCodec}`);
|
|
18
|
+
};
|
|
19
|
+
exports.isSameVideoCodec = isSameVideoCodec;
|
|
20
|
+
const isSameAudioCodec = ({ inputAudioCodec, outputCodec, }) => {
|
|
21
|
+
if (outputCodec === 'aac') {
|
|
22
|
+
return inputAudioCodec === 'aac';
|
|
23
|
+
}
|
|
24
|
+
if (outputCodec === 'opus') {
|
|
25
|
+
return inputAudioCodec === 'opus';
|
|
26
|
+
}
|
|
27
|
+
if (outputCodec === 'wav') {
|
|
28
|
+
return (inputAudioCodec === 'pcm-f32' ||
|
|
29
|
+
inputAudioCodec === 'pcm-s16' ||
|
|
30
|
+
inputAudioCodec === 'pcm-s24' ||
|
|
31
|
+
inputAudioCodec === 'pcm-s32' ||
|
|
32
|
+
inputAudioCodec === 'pcm-u8');
|
|
33
|
+
}
|
|
34
|
+
throw new Error(`Unsupported output codec: ${outputCodec}`);
|
|
35
|
+
};
|
|
36
|
+
exports.isSameAudioCodec = isSameAudioCodec;
|
package/dist/on-audio-track.d.ts
CHANGED
|
@@ -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,
|
|
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;
|
package/dist/on-audio-track.js
CHANGED
|
@@ -1,21 +1,17 @@
|
|
|
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
|
|
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
|
|
14
|
-
const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, outputContainer,
|
|
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,
|
|
18
13
|
inputContainer,
|
|
14
|
+
outputAudioCodec: audioCodec,
|
|
19
15
|
});
|
|
20
16
|
const audioOperation = await (onAudioTrack ?? default_on_audio_track_handler_1.defaultOnAudioTrackHandler)({
|
|
21
17
|
defaultAudioCodec: audioCodec ?? (0, get_default_audio_codec_1.getDefaultAudioCodec)({ container: outputContainer }),
|
|
@@ -32,154 +28,24 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
32
28
|
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
29
|
}
|
|
34
30
|
if (audioOperation.type === 'copy') {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
timescale: track.originalTimescale,
|
|
31
|
+
return (0, copy_audio_track_1.copyAudioTrack)({
|
|
32
|
+
logLevel,
|
|
33
|
+
onMediaStateUpdate,
|
|
34
|
+
state,
|
|
35
|
+
track,
|
|
36
|
+
progressTracker,
|
|
42
37
|
});
|
|
43
|
-
log_1.Log.verbose(logLevel, `Copying audio track ${track.trackId} as track ${addedTrack.trackNumber}. Timescale = ${track.originalTimescale}, 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
38
|
}
|
|
59
|
-
|
|
60
|
-
|
|
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.originalTimescale,
|
|
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),
|
|
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
|
-
},
|
|
39
|
+
return (0, reencode_audio_track_1.reencodeAudioTrack)({
|
|
40
|
+
abortConversion,
|
|
169
41
|
controller,
|
|
170
|
-
config: audioDecoderConfig,
|
|
171
42
|
logLevel,
|
|
43
|
+
onMediaStateUpdate,
|
|
44
|
+
audioOperation,
|
|
45
|
+
onAudioData,
|
|
46
|
+
state,
|
|
172
47
|
track,
|
|
173
48
|
progressTracker,
|
|
174
49
|
});
|
|
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
50
|
};
|
|
185
51
|
exports.makeAudioTrackHandler = makeAudioTrackHandler;
|
package/dist/on-frame.d.ts
CHANGED
|
@@ -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
|
-
|
|
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<
|
|
12
|
+
}) => Promise<VideoFrame>;
|