@remotion/webcodecs 4.0.230 → 4.0.232
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 +12 -1
- package/dist/audio-decoder.js +6 -0
- package/dist/audio-encoder-config.d.ts +4 -1
- package/dist/audio-encoder-config.js +6 -0
- package/dist/audio-encoder.d.ts +4 -3
- package/dist/audio-encoder.js +5 -1
- package/dist/browser-quirks.d.ts +2 -0
- package/dist/browser-quirks.js +11 -0
- 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 +1 -1
- package/dist/can-copy-video-track.js +4 -1
- package/dist/can-reencode-audio-track.d.ts +1 -1
- package/dist/can-reencode-audio-track.js +3 -0
- 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 +9 -5
- package/dist/convert-media.js +55 -42
- package/dist/convert-to-correct-videoframe.d.ts +9 -0
- package/dist/convert-to-correct-videoframe.js +32 -0
- package/dist/default-on-video-track-handler.js +4 -0
- package/dist/esm/index.mjs +347 -110
- package/dist/generate-output-filename.d.ts +2 -0
- package/dist/generate-output-filename.js +14 -0
- 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/index.d.ts +8 -6
- package/dist/index.js +9 -5
- package/dist/io-manager/io-synchronizer.js +12 -6
- package/dist/on-audio-track-handler.d.ts +2 -1
- package/dist/on-audio-track.d.ts +5 -5
- package/dist/on-audio-track.js +22 -8
- package/dist/on-frame.d.ts +4 -4
- package/dist/on-frame.js +11 -11
- package/dist/on-video-track-handler.d.ts +2 -1
- package/dist/on-video-track.d.ts +6 -5
- package/dist/on-video-track.js +15 -7
- package/dist/select-container-creator.d.ts +2 -0
- package/dist/select-container-creator.js +17 -0
- package/dist/set-remotion-imported.d.ts +6 -0
- package/dist/set-remotion-imported.js +25 -0
- package/dist/throttled-state-update.d.ts +13 -0
- package/dist/throttled-state-update.js +49 -0
- package/dist/video-encoder-config.d.ts +1 -1
- package/dist/video-encoder-config.js +2 -0
- package/dist/video-encoder.d.ts +3 -1
- package/dist/video-encoder.js +8 -4
- package/dist/wav-audio-encoder.d.ts +2 -0
- package/dist/wav-audio-encoder.js +26 -0
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -15,4 +15,15 @@ Remove the `^` character from the version number to use the exact version.
|
|
|
15
15
|
|
|
16
16
|
## Usage
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
See the [documentation](https://remotion.dev/webcodecs) for more information.
|
|
19
|
+
|
|
20
|
+
## License
|
|
21
|
+
This package is licensed under the [/docs/license](Remotion License).
|
|
22
|
+
We consider a team of 4 or more people a "company".
|
|
23
|
+
|
|
24
|
+
**For "companies"**: A Remotion Company license needs to be obtained to use this package.
|
|
25
|
+
In a future version of `@remotion/webcodecs`, this package will also require the purchase of a newly created "WebCodecs Conversion Seat". [Get in touch](https://remotion.dev/contact) with us if you are planning to use this package.
|
|
26
|
+
|
|
27
|
+
**For individuals and teams up to 3**: You can use this package for free.
|
|
28
|
+
|
|
29
|
+
This is a short, non-binding explanation of our license. See the [https://remotion.dev/docs/license](License) itself for more details.
|
package/dist/audio-decoder.js
CHANGED
|
@@ -62,11 +62,17 @@ const createAudioDecoder = ({ onFrame, onError, signal, config, logLevel, }) =>
|
|
|
62
62
|
let queue = Promise.resolve();
|
|
63
63
|
return {
|
|
64
64
|
processSample: (sample) => {
|
|
65
|
+
// In example.avi, we have samples with 0 data
|
|
66
|
+
// Chrome fails on these
|
|
67
|
+
if (sample.data.length === 0) {
|
|
68
|
+
return queue;
|
|
69
|
+
}
|
|
65
70
|
queue = queue.then(() => processSample(sample));
|
|
66
71
|
return queue;
|
|
67
72
|
},
|
|
68
73
|
waitForFinish: async () => {
|
|
69
74
|
await audioDecoder.flush();
|
|
75
|
+
await queue;
|
|
70
76
|
await ioSynchronizer.waitForFinish();
|
|
71
77
|
await outputQueue;
|
|
72
78
|
},
|
|
@@ -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
1
|
import type { LogLevel } from '@remotion/media-parser';
|
|
2
|
-
import type { ConvertMediaAudioCodec } from './
|
|
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,5 @@ 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
|
+
};
|
|
18
|
+
export declare const createAudioEncoder: ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }: AudioEncoderInit) => WebCodecsAudioEncoder;
|
package/dist/audio-encoder.js
CHANGED
|
@@ -2,10 +2,14 @@
|
|
|
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 wav_audio_encoder_1 = require("./wav-audio-encoder");
|
|
5
6
|
const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEncoderConfig, logLevel, onNewAudioSampleRate, }) => {
|
|
6
7
|
if (signal.aborted) {
|
|
7
8
|
throw new Error('Not creating audio encoder, already aborted');
|
|
8
9
|
}
|
|
10
|
+
if (codec === 'wav') {
|
|
11
|
+
return (0, wav_audio_encoder_1.getWaveAudioEncoder)({ onChunk, signal });
|
|
12
|
+
}
|
|
9
13
|
const ioSynchronizer = (0, io_synchronizer_1.makeIoSynchronizer)(logLevel, 'Audio encoder');
|
|
10
14
|
let prom = Promise.resolve();
|
|
11
15
|
const encoder = new AudioEncoder({
|
|
@@ -50,7 +54,7 @@ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEnco
|
|
|
50
54
|
if (encoder.state === 'closed') {
|
|
51
55
|
return;
|
|
52
56
|
}
|
|
53
|
-
await ioSynchronizer.waitFor({ unemitted:
|
|
57
|
+
await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 20 });
|
|
54
58
|
// @ts-expect-error - can have changed in the meanwhile
|
|
55
59
|
if (encoder.state === 'closed') {
|
|
56
60
|
return;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.isSafari = exports.isFirefox = void 0;
|
|
4
|
+
const isFirefox = () => {
|
|
5
|
+
return navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
|
|
6
|
+
};
|
|
7
|
+
exports.isFirefox = isFirefox;
|
|
8
|
+
const isSafari = () => {
|
|
9
|
+
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
10
|
+
};
|
|
11
|
+
exports.isSafari = isSafari;
|
|
@@ -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,5 +1,5 @@
|
|
|
1
1
|
import type { MediaParserVideoCodec } from '@remotion/media-parser';
|
|
2
|
-
import type { ConvertMediaContainer } from './
|
|
2
|
+
import type { ConvertMediaContainer } from './get-available-containers';
|
|
3
3
|
export declare const canCopyVideoTrack: ({ inputCodec, container, }: {
|
|
4
4
|
inputCodec: MediaParserVideoCodec;
|
|
5
5
|
container: ConvertMediaContainer;
|
|
@@ -6,7 +6,10 @@ const canCopyVideoTrack = ({ inputCodec, container, }) => {
|
|
|
6
6
|
return inputCodec === 'vp8' || inputCodec === 'vp9';
|
|
7
7
|
}
|
|
8
8
|
if (container === 'mp4') {
|
|
9
|
-
return inputCodec === 'h264'
|
|
9
|
+
return inputCodec === 'h264';
|
|
10
|
+
}
|
|
11
|
+
if (container === 'wav') {
|
|
12
|
+
return false;
|
|
10
13
|
}
|
|
11
14
|
throw new Error(`Unhandled codec: ${container}`);
|
|
12
15
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AudioTrack } from '@remotion/media-parser';
|
|
2
|
-
import type { ConvertMediaAudioCodec } from './
|
|
2
|
+
import type { ConvertMediaAudioCodec } from './get-available-audio-codecs';
|
|
3
3
|
export declare const canReencodeAudioTrack: ({ track, audioCodec, bitrate, }: {
|
|
4
4
|
track: AudioTrack;
|
|
5
5
|
audioCodec: ConvertMediaAudioCodec;
|
|
@@ -5,6 +5,9 @@ const audio_decoder_config_1 = require("./audio-decoder-config");
|
|
|
5
5
|
const audio_encoder_config_1 = require("./audio-encoder-config");
|
|
6
6
|
const canReencodeAudioTrack = async ({ track, audioCodec, bitrate, }) => {
|
|
7
7
|
const audioDecoderConfig = await (0, audio_decoder_config_1.getAudioDecoderConfig)(track);
|
|
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,10 +3,12 @@
|
|
|
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
|
-
export type
|
|
11
|
+
export type ConvertMediaProgress = {
|
|
10
12
|
decodedVideoFrames: number;
|
|
11
13
|
decodedAudioFrames: number;
|
|
12
14
|
encodedVideoFrames: number;
|
|
@@ -19,17 +21,18 @@ export type ConvertMediaState = {
|
|
|
19
21
|
export type ConvertMediaResult = {
|
|
20
22
|
save: () => Promise<Blob>;
|
|
21
23
|
remove: () => Promise<void>;
|
|
24
|
+
finalState: ConvertMediaProgress;
|
|
22
25
|
};
|
|
23
|
-
export type
|
|
26
|
+
export type ConvertMediaOnProgress = (state: ConvertMediaProgress) => void;
|
|
24
27
|
export type ConvertMediaOnVideoFrame = (options: {
|
|
25
28
|
frame: VideoFrame;
|
|
26
29
|
track: VideoTrack;
|
|
27
30
|
}) => Promise<VideoFrame> | VideoFrame;
|
|
28
|
-
export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame,
|
|
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, ...more }: {
|
|
29
32
|
src: ParseMediaOptions<F>["src"];
|
|
30
33
|
container: ConvertMediaContainer;
|
|
31
34
|
onVideoFrame?: ConvertMediaOnVideoFrame;
|
|
32
|
-
|
|
35
|
+
onProgress?: ConvertMediaOnProgress;
|
|
33
36
|
videoCodec?: ConvertMediaVideoCodec;
|
|
34
37
|
audioCodec?: ConvertMediaAudioCodec;
|
|
35
38
|
signal?: AbortSignal;
|
|
@@ -38,4 +41,5 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
|
|
|
38
41
|
reader?: ParseMediaOptions<F>["reader"];
|
|
39
42
|
logLevel?: LogLevel;
|
|
40
43
|
writer?: WriterInterface;
|
|
44
|
+
progressIntervalInMs?: number;
|
|
41
45
|
} & ParseMediaDynamicOptions<F>) => Promise<ConvertMediaResult>;
|
package/dist/convert-media.js
CHANGED
|
@@ -12,15 +12,19 @@ const media_parser_1 = require("@remotion/media-parser");
|
|
|
12
12
|
const auto_select_writer_1 = require("./auto-select-writer");
|
|
13
13
|
const calculate_progress_1 = require("./calculate-progress");
|
|
14
14
|
const error_cause_1 = __importDefault(require("./error-cause"));
|
|
15
|
+
const generate_output_filename_1 = require("./generate-output-filename");
|
|
15
16
|
const on_audio_track_1 = require("./on-audio-track");
|
|
16
17
|
const on_video_track_1 = require("./on-video-track");
|
|
18
|
+
const select_container_creator_1 = require("./select-container-creator");
|
|
19
|
+
const throttled_state_update_1 = require("./throttled-state-update");
|
|
17
20
|
const with_resolvers_1 = require("./with-resolvers");
|
|
18
|
-
const convertMedia = async function ({ src, onVideoFrame,
|
|
21
|
+
const convertMedia = async function ({ src, onVideoFrame, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, signal: userPassedAbortSignal, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, ...more }) {
|
|
22
|
+
var _a, _b;
|
|
19
23
|
if (userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.aborted) {
|
|
20
24
|
return Promise.reject(new error_cause_1.default('Aborted'));
|
|
21
25
|
}
|
|
22
|
-
if (container !== 'webm' && container !== 'mp4') {
|
|
23
|
-
return Promise.reject(new TypeError('Only `to: "webm"` and `to: "
|
|
26
|
+
if (container !== 'webm' && container !== 'mp4' && container !== 'wav') {
|
|
27
|
+
return Promise.reject(new TypeError('Only `to: "webm"`, `to: "mp4"` and `to: "wav"` is supported currently'));
|
|
24
28
|
}
|
|
25
29
|
if (videoCodec && videoCodec !== 'vp8' && videoCodec !== 'vp9') {
|
|
26
30
|
return Promise.reject(new TypeError('Only `videoCodec: "vp8"` and `videoCodec: "vp9"` are supported currently'));
|
|
@@ -37,49 +41,47 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
37
41
|
abortConversion(new error_cause_1.default('Conversion aborted by user'));
|
|
38
42
|
};
|
|
39
43
|
userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.addEventListener('abort', onUserAbort);
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
millisecondsWritten: 0,
|
|
47
|
-
expectedOutputDurationInMs: null,
|
|
48
|
-
overallProgress: 0,
|
|
49
|
-
};
|
|
50
|
-
const onMediaStateUpdate = (newState) => {
|
|
51
|
-
if (controller.signal.aborted) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
onMediaStateDoNoCallDirectly === null || onMediaStateDoNoCallDirectly === void 0 ? void 0 : onMediaStateDoNoCallDirectly(newState);
|
|
55
|
-
};
|
|
56
|
-
const creator = container === 'webm'
|
|
57
|
-
? media_parser_1.MediaParserInternals.createMatroskaMedia
|
|
58
|
-
: media_parser_1.MediaParserInternals.createIsoBaseMedia;
|
|
44
|
+
const creator = (0, select_container_creator_1.selectContainerCreator)(container);
|
|
45
|
+
const throttledState = (0, throttled_state_update_1.throttledStateUpdate)({
|
|
46
|
+
updateFn: onProgressDoNotCallDirectly !== null && onProgressDoNotCallDirectly !== void 0 ? onProgressDoNotCallDirectly : null,
|
|
47
|
+
everyMilliseconds: progressIntervalInMs !== null && progressIntervalInMs !== void 0 ? progressIntervalInMs : 100,
|
|
48
|
+
signal: controller.signal,
|
|
49
|
+
});
|
|
59
50
|
const state = await creator({
|
|
51
|
+
filename: (0, generate_output_filename_1.generateOutputFilename)(src, container),
|
|
60
52
|
writer: await (0, auto_select_writer_1.autoSelectWriter)(writer, logLevel),
|
|
61
53
|
onBytesProgress: (bytesWritten) => {
|
|
62
|
-
|
|
63
|
-
|
|
54
|
+
var _a;
|
|
55
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
56
|
+
return {
|
|
57
|
+
...prevState,
|
|
58
|
+
bytesWritten,
|
|
59
|
+
};
|
|
60
|
+
});
|
|
64
61
|
},
|
|
65
62
|
onMillisecondsProgress: (millisecondsWritten) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
63
|
+
var _a;
|
|
64
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
65
|
+
if (millisecondsWritten > prevState.millisecondsWritten) {
|
|
66
|
+
return {
|
|
67
|
+
...prevState,
|
|
68
|
+
millisecondsWritten,
|
|
69
|
+
overallProgress: (0, calculate_progress_1.calculateProgress)({
|
|
70
|
+
millisecondsWritten: prevState.millisecondsWritten,
|
|
71
|
+
expectedOutputDurationInMs: prevState.expectedOutputDurationInMs,
|
|
72
|
+
}),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
return prevState;
|
|
76
|
+
});
|
|
74
77
|
},
|
|
75
78
|
logLevel,
|
|
76
79
|
});
|
|
77
80
|
const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
|
|
78
81
|
state,
|
|
79
82
|
onVideoFrame: onVideoFrame !== null && onVideoFrame !== void 0 ? onVideoFrame : null,
|
|
80
|
-
onMediaStateUpdate:
|
|
83
|
+
onMediaStateUpdate: (_a = throttledState.update) !== null && _a !== void 0 ? _a : null,
|
|
81
84
|
abortConversion,
|
|
82
|
-
convertMediaState,
|
|
83
85
|
controller,
|
|
84
86
|
defaultVideoCodec: videoCodec !== null && videoCodec !== void 0 ? videoCodec : null,
|
|
85
87
|
onVideoTrack: userVideoResolver !== null && userVideoResolver !== void 0 ? userVideoResolver : null,
|
|
@@ -90,8 +92,7 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
90
92
|
abortConversion,
|
|
91
93
|
defaultAudioCodec: audioCodec !== null && audioCodec !== void 0 ? audioCodec : null,
|
|
92
94
|
controller,
|
|
93
|
-
|
|
94
|
-
onMediaStateUpdate: onMediaStateUpdate !== null && onMediaStateUpdate !== void 0 ? onMediaStateUpdate : null,
|
|
95
|
+
onMediaStateUpdate: (_b = throttledState.update) !== null && _b !== void 0 ? _b : null,
|
|
95
96
|
state,
|
|
96
97
|
onAudioTrack: userAudioResolver !== null && userAudioResolver !== void 0 ? userAudioResolver : null,
|
|
97
98
|
logLevel,
|
|
@@ -110,6 +111,7 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
110
111
|
reader,
|
|
111
112
|
...more,
|
|
112
113
|
onDurationInSeconds: (durationInSeconds) => {
|
|
114
|
+
var _a;
|
|
113
115
|
if (durationInSeconds === null) {
|
|
114
116
|
return null;
|
|
115
117
|
}
|
|
@@ -118,22 +120,33 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
118
120
|
casted.onDurationInSeconds(durationInSeconds);
|
|
119
121
|
}
|
|
120
122
|
const expectedOutputDurationInMs = durationInSeconds * 1000;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
124
|
+
return {
|
|
125
|
+
...prevState,
|
|
126
|
+
expectedOutputDurationInMs,
|
|
127
|
+
overallProgress: (0, calculate_progress_1.calculateProgress)({
|
|
128
|
+
millisecondsWritten: prevState.millisecondsWritten,
|
|
129
|
+
expectedOutputDurationInMs,
|
|
130
|
+
}),
|
|
131
|
+
};
|
|
125
132
|
});
|
|
126
|
-
onMediaStateUpdate(convertMediaState);
|
|
127
133
|
},
|
|
128
134
|
})
|
|
129
135
|
.then(() => {
|
|
130
136
|
return state.waitForFinish();
|
|
131
137
|
})
|
|
132
138
|
.then(() => {
|
|
133
|
-
resolve({
|
|
139
|
+
resolve({
|
|
140
|
+
save: state.save,
|
|
141
|
+
remove: state.remove,
|
|
142
|
+
finalState: throttledState.get(),
|
|
143
|
+
});
|
|
134
144
|
})
|
|
135
145
|
.catch((err) => {
|
|
136
146
|
reject(err);
|
|
147
|
+
})
|
|
148
|
+
.finally(() => {
|
|
149
|
+
throttledState.stopAndGetLastProgress();
|
|
137
150
|
});
|
|
138
151
|
return getPromiseToImmediatelyReturn().finally(() => {
|
|
139
152
|
userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.removeEventListener('abort', onUserAbort);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConvertMediaVideoCodec } from './get-available-video-codecs';
|
|
2
|
+
export declare const needsToCorrectVideoFrame: ({ videoFrame, outputCodec, }: {
|
|
3
|
+
videoFrame: VideoFrame;
|
|
4
|
+
outputCodec: ConvertMediaVideoCodec;
|
|
5
|
+
}) => boolean;
|
|
6
|
+
export declare const convertToCorrectVideoFrame: ({ videoFrame, outputCodec, }: {
|
|
7
|
+
videoFrame: VideoFrame;
|
|
8
|
+
outputCodec: ConvertMediaVideoCodec;
|
|
9
|
+
}) => VideoFrame;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.convertToCorrectVideoFrame = exports.needsToCorrectVideoFrame = void 0;
|
|
4
|
+
const browser_quirks_1 = require("./browser-quirks");
|
|
5
|
+
const needsToCorrectVideoFrame = ({ videoFrame, outputCodec, }) => {
|
|
6
|
+
// On Chrome when dropping a vertical iPhone video
|
|
7
|
+
if (videoFrame.format === null) {
|
|
8
|
+
return true;
|
|
9
|
+
}
|
|
10
|
+
return (0, browser_quirks_1.isFirefox)() && videoFrame.format === 'BGRX' && outputCodec === 'h264';
|
|
11
|
+
};
|
|
12
|
+
exports.needsToCorrectVideoFrame = needsToCorrectVideoFrame;
|
|
13
|
+
const convertToCorrectVideoFrame = ({ videoFrame, outputCodec, }) => {
|
|
14
|
+
if (!(0, exports.needsToCorrectVideoFrame)({ videoFrame, outputCodec })) {
|
|
15
|
+
return videoFrame;
|
|
16
|
+
}
|
|
17
|
+
const canvas = new OffscreenCanvas(videoFrame.displayWidth, videoFrame.displayHeight);
|
|
18
|
+
canvas.width = videoFrame.displayWidth;
|
|
19
|
+
canvas.height = videoFrame.displayHeight;
|
|
20
|
+
const ctx = canvas.getContext('2d');
|
|
21
|
+
if (!ctx) {
|
|
22
|
+
throw new Error('Could not get 2d context');
|
|
23
|
+
}
|
|
24
|
+
ctx.drawImage(videoFrame, 0, 0);
|
|
25
|
+
return new VideoFrame(canvas, {
|
|
26
|
+
displayHeight: videoFrame.displayHeight,
|
|
27
|
+
displayWidth: videoFrame.displayWidth,
|
|
28
|
+
duration: videoFrame.duration,
|
|
29
|
+
timestamp: videoFrame.timestamp,
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
exports.convertToCorrectVideoFrame = convertToCorrectVideoFrame;
|
|
@@ -15,6 +15,10 @@ const defaultOnVideoTrackHandler = async ({ track, defaultVideoCodec, logLevel,
|
|
|
15
15
|
return Promise.resolve({ type: 'copy' });
|
|
16
16
|
}
|
|
17
17
|
const videoCodec = defaultVideoCodec !== null && defaultVideoCodec !== void 0 ? defaultVideoCodec : (0, get_default_video_codec_1.getDefaultVideoCodec)({ container });
|
|
18
|
+
if (videoCodec === null) {
|
|
19
|
+
media_parser_1.MediaParserInternals.Log.verbose(logLevel, `Track ${track.trackId} (video): No default video codec, therefore dropping`);
|
|
20
|
+
return Promise.resolve({ type: 'drop' });
|
|
21
|
+
}
|
|
18
22
|
const canReencode = await (0, can_reencode_video_track_1.canReencodeVideoTrack)({
|
|
19
23
|
videoCodec,
|
|
20
24
|
track,
|