@remotion/webcodecs 4.0.306 → 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 +3 -3
- package/dist/audio-encoder.js +1 -1
- 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/create/matroska/matroska-utils.d.ts +1 -1
- 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 +336 -263
- package/dist/get-wave-audio-decoder.d.ts +1 -1
- package/dist/get-wave-audio-decoder.js +13 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +5 -5
- package/dist/io-manager/io-synchronizer.d.ts +0 -1
- package/dist/io-manager/io-synchronizer.js +0 -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.js +1 -0
- package/dist/on-video-track.js +1 -0
- package/dist/processing-queue.d.ts +0 -1
- package/dist/reencode-audio-track.js +4 -4
- package/dist/reencode-video-track.js +4 -4
- package/dist/video-encoder.js +1 -1
- package/package.json +5 -5
- package/dist/select-container-creator.d.ts +0 -2
- package/dist/select-container-creator.js +0 -19
package/dist/audio-decoder.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MediaParserLogLevel } from '@remotion/media-parser';
|
|
2
2
|
import type { WebCodecsController } from './webcodecs-controller';
|
|
3
3
|
export type WebCodecsAudioDecoder = {
|
|
4
|
-
decode: (audioSample:
|
|
4
|
+
decode: (audioSample: EncodedAudioChunkInit | EncodedAudioChunk) => void;
|
|
5
5
|
close: () => void;
|
|
6
6
|
flush: () => Promise<void>;
|
|
7
7
|
waitForFinish: () => Promise<void>;
|
|
@@ -17,7 +17,7 @@ export type CreateAudioDecoderInit = {
|
|
|
17
17
|
export declare const internalCreateAudioDecoder: ({ onFrame, onError, controller, config, logLevel, }: CreateAudioDecoderInit) => WebCodecsAudioDecoder;
|
|
18
18
|
export declare const createAudioDecoder: ({ onFrame, onError, controller, track, logLevel, }: {
|
|
19
19
|
track: AudioDecoderConfig;
|
|
20
|
-
onFrame: (frame: AudioData
|
|
20
|
+
onFrame: (frame: AudioData) => Promise<void> | void;
|
|
21
21
|
onError: (error: Error) => void;
|
|
22
22
|
controller?: WebCodecsController | null;
|
|
23
23
|
logLevel?: MediaParserLogLevel;
|
package/dist/audio-encoder.js
CHANGED
|
@@ -77,7 +77,7 @@ const createAudioEncoder = ({ onChunk, onError, codec, controller, config: audio
|
|
|
77
77
|
},
|
|
78
78
|
waitForFinish: async () => {
|
|
79
79
|
await encoder.flush();
|
|
80
|
-
await ioSynchronizer.
|
|
80
|
+
await ioSynchronizer.waitForQueueSize(0);
|
|
81
81
|
},
|
|
82
82
|
close,
|
|
83
83
|
flush: async () => {
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { MediaParserAudioCodec, MediaParserContainer } from '@remotion/media-parser';
|
|
2
|
+
import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
|
|
2
3
|
import type { ConvertMediaContainer } from './get-available-containers';
|
|
3
|
-
export declare const canCopyAudioTrack: ({ inputCodec, outputContainer, inputContainer, }: {
|
|
4
|
+
export declare const canCopyAudioTrack: ({ inputCodec, outputContainer, inputContainer, outputAudioCodec, }: {
|
|
4
5
|
inputCodec: MediaParserAudioCodec;
|
|
5
6
|
outputContainer: ConvertMediaContainer;
|
|
6
7
|
inputContainer: MediaParserContainer;
|
|
8
|
+
outputAudioCodec: ConvertMediaAudioCodec | null;
|
|
7
9
|
}) => boolean;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.canCopyAudioTrack = void 0;
|
|
4
|
-
const
|
|
4
|
+
const is_different_video_codec_1 = require("./is-different-video-codec");
|
|
5
|
+
const canCopyAudioTrack = ({ inputCodec, outputContainer, inputContainer, outputAudioCodec, }) => {
|
|
6
|
+
if (outputAudioCodec) {
|
|
7
|
+
if (!(0, is_different_video_codec_1.isSameAudioCodec)({
|
|
8
|
+
inputAudioCodec: inputCodec,
|
|
9
|
+
outputCodec: outputAudioCodec,
|
|
10
|
+
})) {
|
|
11
|
+
return false;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
5
14
|
if (outputContainer === 'webm') {
|
|
6
15
|
return inputCodec === 'opus';
|
|
7
16
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import type { MediaParserContainer, MediaParserVideoTrack } from '@remotion/media-parser';
|
|
2
2
|
import type { ConvertMediaContainer } from './get-available-containers';
|
|
3
|
+
import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
|
|
3
4
|
import type { ResizeOperation } from './resizing/mode';
|
|
4
|
-
export declare const canCopyVideoTrack: ({ outputContainer, rotationToApply, inputContainer, resizeOperation, inputTrack, }: {
|
|
5
|
+
export declare const canCopyVideoTrack: ({ outputContainer, rotationToApply, inputContainer, resizeOperation, inputTrack, outputVideoCodec, }: {
|
|
5
6
|
inputContainer: MediaParserContainer;
|
|
6
7
|
inputTrack: MediaParserVideoTrack;
|
|
7
8
|
rotationToApply: number;
|
|
8
9
|
outputContainer: ConvertMediaContainer;
|
|
10
|
+
outputVideoCodec: ConvertMediaVideoCodec | null;
|
|
9
11
|
resizeOperation: ResizeOperation | null;
|
|
10
12
|
}) => boolean;
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.canCopyVideoTrack = void 0;
|
|
4
|
+
const is_different_video_codec_1 = require("./is-different-video-codec");
|
|
4
5
|
const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
|
|
5
6
|
const rotation_1 = require("./rotation");
|
|
6
|
-
const canCopyVideoTrack = ({ outputContainer, rotationToApply, inputContainer, resizeOperation, inputTrack, }) => {
|
|
7
|
+
const canCopyVideoTrack = ({ outputContainer, rotationToApply, inputContainer, resizeOperation, inputTrack, outputVideoCodec, }) => {
|
|
7
8
|
if ((0, rotate_and_resize_video_frame_1.normalizeVideoRotation)(inputTrack.rotation) !==
|
|
8
9
|
(0, rotate_and_resize_video_frame_1.normalizeVideoRotation)(rotationToApply)) {
|
|
9
10
|
return false;
|
|
10
11
|
}
|
|
12
|
+
if (outputVideoCodec) {
|
|
13
|
+
if (!(0, is_different_video_codec_1.isSameVideoCodec)({
|
|
14
|
+
inputVideoCodec: inputTrack.codecEnum,
|
|
15
|
+
outputCodec: outputVideoCodec,
|
|
16
|
+
})) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
11
20
|
const newDimensions = (0, rotation_1.calculateNewDimensionsFromRotateAndScale)({
|
|
12
21
|
height: inputTrack.height,
|
|
13
22
|
resizeOperation,
|
|
@@ -22,7 +22,7 @@ export type EbmlParsedOrUint8Array<T extends MediaParserInternalTypes['Ebml']> =
|
|
|
22
22
|
value: EbmlValueOrUint8Array<T>;
|
|
23
23
|
minVintWidth: number | null;
|
|
24
24
|
};
|
|
25
|
-
export declare const measureEBMLVarInt: (value: number) =>
|
|
25
|
+
export declare const measureEBMLVarInt: (value: number) => 1 | 2 | 4 | 3 | 5 | 6;
|
|
26
26
|
export declare const getVariableInt: (value: number, minWidth: number | null) => Uint8Array<ArrayBuffer>;
|
|
27
27
|
export declare const makeMatroskaBytes: (fields: PossibleEbmlOrUint8Array) => BytesAndOffset;
|
|
28
28
|
export type PossibleEbmlOrUint8Array = Prettify<{
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { MediaParserLogLevel } from '@remotion/media-parser';
|
|
2
|
+
import type { WebCodecsController } from './webcodecs-controller';
|
|
3
|
+
export type WebCodecsAudioDecoder = {
|
|
4
|
+
decode: (audioSample: EncodedAudioChunkInit | EncodedAudioChunk) => Promise<void>;
|
|
5
|
+
close: () => void;
|
|
6
|
+
flush: () => Promise<void>;
|
|
7
|
+
waitForQueueToBeLessThan: (items: number) => Promise<void>;
|
|
8
|
+
reset: () => void;
|
|
9
|
+
};
|
|
10
|
+
export type CreateAudioDecoderInit = {
|
|
11
|
+
onFrame: (frame: AudioData) => Promise<void> | void;
|
|
12
|
+
onError: (error: Error) => void;
|
|
13
|
+
controller: WebCodecsController | null;
|
|
14
|
+
config: AudioDecoderConfig;
|
|
15
|
+
logLevel: MediaParserLogLevel;
|
|
16
|
+
};
|
|
17
|
+
export declare const internalCreateAudioDecoder: ({ onFrame, onError, controller, config, logLevel, }: CreateAudioDecoderInit) => WebCodecsAudioDecoder;
|
|
18
|
+
export declare const createAudioDecoder: ({ track, onFrame, onError, controller, logLevel, }: {
|
|
19
|
+
track: AudioDecoderConfig;
|
|
20
|
+
onFrame: (frame: AudioData) => Promise<void> | void;
|
|
21
|
+
onError: (error: Error) => void;
|
|
22
|
+
controller?: WebCodecsController | null;
|
|
23
|
+
logLevel?: MediaParserLogLevel;
|
|
24
|
+
}) => WebCodecsAudioDecoder;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createAudioDecoder = exports.internalCreateAudioDecoder = void 0;
|
|
4
|
+
const get_wave_audio_decoder_1 = require("./get-wave-audio-decoder");
|
|
5
|
+
const io_synchronizer_1 = require("./io-manager/io-synchronizer");
|
|
6
|
+
const internalCreateAudioDecoder = ({ onFrame, onError, controller, config, logLevel, }) => {
|
|
7
|
+
if (controller &&
|
|
8
|
+
controller._internals._mediaParserController._internals.signal.aborted) {
|
|
9
|
+
throw new Error('Not creating audio decoder, already aborted');
|
|
10
|
+
}
|
|
11
|
+
const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
|
|
12
|
+
logLevel,
|
|
13
|
+
label: 'Audio decoder',
|
|
14
|
+
controller,
|
|
15
|
+
});
|
|
16
|
+
if (config.codec === 'pcm-s16') {
|
|
17
|
+
return (0, get_wave_audio_decoder_1.getWaveAudioDecoder)({
|
|
18
|
+
onFrame,
|
|
19
|
+
config,
|
|
20
|
+
sampleFormat: 's16',
|
|
21
|
+
logLevel,
|
|
22
|
+
ioSynchronizer,
|
|
23
|
+
onError,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
const audioDecoder = new AudioDecoder({
|
|
27
|
+
async output(frame) {
|
|
28
|
+
try {
|
|
29
|
+
await onFrame(frame);
|
|
30
|
+
}
|
|
31
|
+
catch (err) {
|
|
32
|
+
frame.close();
|
|
33
|
+
onError(err);
|
|
34
|
+
}
|
|
35
|
+
ioSynchronizer.onOutput(frame.timestamp + (frame.duration ?? 0));
|
|
36
|
+
},
|
|
37
|
+
error(error) {
|
|
38
|
+
onError(error);
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
const close = () => {
|
|
42
|
+
if (controller) {
|
|
43
|
+
controller._internals._mediaParserController._internals.signal.removeEventListener('abort',
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
45
|
+
onAbort);
|
|
46
|
+
}
|
|
47
|
+
if (audioDecoder.state === 'closed') {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
audioDecoder.close();
|
|
51
|
+
};
|
|
52
|
+
const onAbort = () => {
|
|
53
|
+
close();
|
|
54
|
+
};
|
|
55
|
+
if (controller) {
|
|
56
|
+
controller._internals._mediaParserController._internals.signal.addEventListener('abort', onAbort);
|
|
57
|
+
}
|
|
58
|
+
audioDecoder.configure(config);
|
|
59
|
+
const decode = async (audioSample) => {
|
|
60
|
+
if (audioDecoder.state === 'closed') {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
await controller?._internals._mediaParserController._internals.checkForAbortAndPause();
|
|
65
|
+
}
|
|
66
|
+
catch (err) {
|
|
67
|
+
onError(err);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
// Don't flush, it messes up the audio
|
|
71
|
+
const chunk = audioSample instanceof EncodedAudioChunk
|
|
72
|
+
? audioSample
|
|
73
|
+
: new EncodedAudioChunk(audioSample);
|
|
74
|
+
audioDecoder.decode(chunk);
|
|
75
|
+
// https://test-streams.mux.dev/x36xhzz/url_0/url_525/193039199_mp4_h264_aac_hd_7.ts
|
|
76
|
+
// has a 16 byte audio sample at the end which chrome does not decode
|
|
77
|
+
// Might be empty audio
|
|
78
|
+
// For now only reporting chunks that are bigger than that
|
|
79
|
+
// 16 was chosen arbitrarily, can be improved
|
|
80
|
+
if (chunk.byteLength > 16) {
|
|
81
|
+
ioSynchronizer.inputItem(chunk.timestamp);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
return {
|
|
85
|
+
decode,
|
|
86
|
+
close,
|
|
87
|
+
flush: async () => {
|
|
88
|
+
// Firefox might throw "Needs to be configured first"
|
|
89
|
+
try {
|
|
90
|
+
await audioDecoder.flush();
|
|
91
|
+
}
|
|
92
|
+
catch { }
|
|
93
|
+
await ioSynchronizer.waitForQueueSize(0);
|
|
94
|
+
},
|
|
95
|
+
waitForQueueToBeLessThan: ioSynchronizer.waitForQueueSize,
|
|
96
|
+
reset: () => {
|
|
97
|
+
audioDecoder.reset();
|
|
98
|
+
audioDecoder.configure(config);
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
exports.internalCreateAudioDecoder = internalCreateAudioDecoder;
|
|
103
|
+
const createAudioDecoder = ({ track, onFrame, onError, controller, logLevel, }) => {
|
|
104
|
+
return (0, exports.internalCreateAudioDecoder)({
|
|
105
|
+
onFrame,
|
|
106
|
+
onError,
|
|
107
|
+
controller: controller ?? null,
|
|
108
|
+
config: track,
|
|
109
|
+
logLevel: logLevel ?? 'error',
|
|
110
|
+
});
|
|
111
|
+
};
|
|
112
|
+
exports.createAudioDecoder = createAudioDecoder;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { MediaParserLogLevel } from '@remotion/media-parser';
|
|
2
|
+
import type { WebCodecsController } from './webcodecs-controller';
|
|
3
|
+
export type WebCodecsVideoDecoder = {
|
|
4
|
+
decode: (videoSample: EncodedVideoChunkInit | EncodedVideoChunk) => void;
|
|
5
|
+
close: () => void;
|
|
6
|
+
flush: () => Promise<void>;
|
|
7
|
+
waitForQueueToBeLessThan: (items: number) => Promise<void>;
|
|
8
|
+
reset: () => void;
|
|
9
|
+
};
|
|
10
|
+
export declare const internalCreateVideoDecoder: ({ onFrame, onError, controller, config, logLevel, }: {
|
|
11
|
+
onFrame: (frame: VideoFrame) => Promise<void> | void;
|
|
12
|
+
onError: (error: Error) => void;
|
|
13
|
+
controller: WebCodecsController | null;
|
|
14
|
+
config: VideoDecoderConfig;
|
|
15
|
+
logLevel: MediaParserLogLevel;
|
|
16
|
+
}) => WebCodecsVideoDecoder;
|
|
17
|
+
export declare const createVideoDecoder: ({ onFrame, onError, controller, track, logLevel, }: {
|
|
18
|
+
track: VideoDecoderConfig;
|
|
19
|
+
onFrame: (frame: VideoFrame) => Promise<void> | void;
|
|
20
|
+
onError: (error: Error) => void;
|
|
21
|
+
controller?: WebCodecsController;
|
|
22
|
+
logLevel?: MediaParserLogLevel;
|
|
23
|
+
}) => WebCodecsVideoDecoder;
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createVideoDecoder = exports.internalCreateVideoDecoder = void 0;
|
|
4
|
+
const io_synchronizer_1 = require("./io-manager/io-synchronizer");
|
|
5
|
+
const internalCreateVideoDecoder = ({ onFrame, onError, controller, config, logLevel, }) => {
|
|
6
|
+
const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)({
|
|
7
|
+
logLevel,
|
|
8
|
+
label: 'Video decoder',
|
|
9
|
+
controller,
|
|
10
|
+
});
|
|
11
|
+
const videoDecoder = new VideoDecoder({
|
|
12
|
+
async output(frame) {
|
|
13
|
+
try {
|
|
14
|
+
await onFrame(frame);
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
onError(err);
|
|
18
|
+
frame.close();
|
|
19
|
+
}
|
|
20
|
+
ioSynchronizer.onOutput(frame.timestamp);
|
|
21
|
+
},
|
|
22
|
+
error(error) {
|
|
23
|
+
onError(error);
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
const close = () => {
|
|
27
|
+
if (controller) {
|
|
28
|
+
controller._internals._mediaParserController._internals.signal.removeEventListener('abort',
|
|
29
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
30
|
+
onAbort);
|
|
31
|
+
}
|
|
32
|
+
if (videoDecoder.state === 'closed') {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
videoDecoder.close();
|
|
36
|
+
};
|
|
37
|
+
const onAbort = () => {
|
|
38
|
+
close();
|
|
39
|
+
};
|
|
40
|
+
if (controller) {
|
|
41
|
+
controller._internals._mediaParserController._internals.signal.addEventListener('abort', onAbort);
|
|
42
|
+
}
|
|
43
|
+
videoDecoder.configure(config);
|
|
44
|
+
const decode = async (sample) => {
|
|
45
|
+
if (videoDecoder.state === 'closed') {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
await controller?._internals._mediaParserController._internals.checkForAbortAndPause();
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
onError(err);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const encodedChunk = sample instanceof EncodedVideoChunk
|
|
56
|
+
? sample
|
|
57
|
+
: new EncodedVideoChunk(sample);
|
|
58
|
+
videoDecoder.decode(encodedChunk);
|
|
59
|
+
ioSynchronizer.inputItem(sample.timestamp);
|
|
60
|
+
};
|
|
61
|
+
return {
|
|
62
|
+
decode,
|
|
63
|
+
close,
|
|
64
|
+
flush: async () => {
|
|
65
|
+
// Firefox might throw "Needs to be configured first"
|
|
66
|
+
try {
|
|
67
|
+
await videoDecoder.flush();
|
|
68
|
+
}
|
|
69
|
+
catch { }
|
|
70
|
+
await ioSynchronizer.waitForQueueSize(0);
|
|
71
|
+
},
|
|
72
|
+
waitForQueueToBeLessThan: ioSynchronizer.waitForQueueSize,
|
|
73
|
+
reset: () => {
|
|
74
|
+
videoDecoder.reset();
|
|
75
|
+
videoDecoder.configure(config);
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
exports.internalCreateVideoDecoder = internalCreateVideoDecoder;
|
|
80
|
+
const createVideoDecoder = ({ onFrame, onError, controller, track, logLevel, }) => {
|
|
81
|
+
return (0, exports.internalCreateVideoDecoder)({
|
|
82
|
+
onFrame,
|
|
83
|
+
onError,
|
|
84
|
+
controller: controller ?? null,
|
|
85
|
+
config: track,
|
|
86
|
+
logLevel: logLevel ?? 'info',
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
exports.createVideoDecoder = createVideoDecoder;
|