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