@remotion/webcodecs 4.0.230 → 4.0.231
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-encoder.js +1 -1
- package/dist/browser-quirks.d.ts +2 -0
- package/dist/browser-quirks.js +11 -0
- package/dist/convert-media.d.ts +6 -4
- package/dist/convert-media.js +51 -37
- package/dist/convert-to-correct-videoframe.d.ts +9 -0
- package/dist/convert-to-correct-videoframe.js +28 -0
- package/dist/esm/index.mjs +217 -69
- package/dist/generate-output-filename.d.ts +2 -0
- package/dist/generate-output-filename.js +14 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.js +2 -0
- package/dist/on-audio-track.d.ts +3 -4
- package/dist/on-audio-track.js +19 -7
- package/dist/on-frame.d.ts +4 -4
- package/dist/on-frame.js +15 -9
- package/dist/on-video-track.d.ts +4 -4
- package/dist/on-video-track.js +15 -7
- 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.js +2 -0
- package/dist/video-encoder.d.ts +3 -1
- package/dist/video-encoder.js +8 -4
- 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-encoder.js
CHANGED
|
@@ -50,7 +50,7 @@ const createAudioEncoder = ({ onChunk, onError, codec, signal, config: audioEnco
|
|
|
50
50
|
if (encoder.state === 'closed') {
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
-
await ioSynchronizer.waitFor({ unemitted:
|
|
53
|
+
await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 20 });
|
|
54
54
|
// @ts-expect-error - can have changed in the meanwhile
|
|
55
55
|
if (encoder.state === 'closed') {
|
|
56
56
|
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;
|
package/dist/convert-media.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ import type { LogLevel, Options, ParseMediaDynamicOptions, ParseMediaFields, Par
|
|
|
6
6
|
import type { ConvertMediaAudioCodec, ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
|
|
7
7
|
import { type ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
|
|
8
8
|
import { type ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
|
|
9
|
-
export type
|
|
9
|
+
export type ConvertMediaProgress = {
|
|
10
10
|
decodedVideoFrames: number;
|
|
11
11
|
decodedAudioFrames: number;
|
|
12
12
|
encodedVideoFrames: number;
|
|
@@ -19,17 +19,18 @@ export type ConvertMediaState = {
|
|
|
19
19
|
export type ConvertMediaResult = {
|
|
20
20
|
save: () => Promise<Blob>;
|
|
21
21
|
remove: () => Promise<void>;
|
|
22
|
+
finalState: ConvertMediaProgress;
|
|
22
23
|
};
|
|
23
|
-
export type
|
|
24
|
+
export type ConvertMediaOnProgress = (state: ConvertMediaProgress) => void;
|
|
24
25
|
export type ConvertMediaOnVideoFrame = (options: {
|
|
25
26
|
frame: VideoFrame;
|
|
26
27
|
track: VideoTrack;
|
|
27
28
|
}) => Promise<VideoFrame> | VideoFrame;
|
|
28
|
-
export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame,
|
|
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 }: {
|
|
29
30
|
src: ParseMediaOptions<F>["src"];
|
|
30
31
|
container: ConvertMediaContainer;
|
|
31
32
|
onVideoFrame?: ConvertMediaOnVideoFrame;
|
|
32
|
-
|
|
33
|
+
onProgress?: ConvertMediaOnProgress;
|
|
33
34
|
videoCodec?: ConvertMediaVideoCodec;
|
|
34
35
|
audioCodec?: ConvertMediaAudioCodec;
|
|
35
36
|
signal?: AbortSignal;
|
|
@@ -38,4 +39,5 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
|
|
|
38
39
|
reader?: ParseMediaOptions<F>["reader"];
|
|
39
40
|
logLevel?: LogLevel;
|
|
40
41
|
writer?: WriterInterface;
|
|
42
|
+
progressIntervalInMs?: number;
|
|
41
43
|
} & ParseMediaDynamicOptions<F>) => Promise<ConvertMediaResult>;
|
package/dist/convert-media.js
CHANGED
|
@@ -12,10 +12,13 @@ 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 throttled_state_update_1 = require("./throttled-state-update");
|
|
17
19
|
const with_resolvers_1 = require("./with-resolvers");
|
|
18
|
-
const convertMedia = async function ({ src, onVideoFrame,
|
|
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 }) {
|
|
21
|
+
var _a, _b;
|
|
19
22
|
if (userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.aborted) {
|
|
20
23
|
return Promise.reject(new error_cause_1.default('Aborted'));
|
|
21
24
|
}
|
|
@@ -37,49 +40,49 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
37
40
|
abortConversion(new error_cause_1.default('Conversion aborted by user'));
|
|
38
41
|
};
|
|
39
42
|
userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.addEventListener('abort', onUserAbort);
|
|
40
|
-
const convertMediaState = {
|
|
41
|
-
decodedAudioFrames: 0,
|
|
42
|
-
decodedVideoFrames: 0,
|
|
43
|
-
encodedVideoFrames: 0,
|
|
44
|
-
encodedAudioFrames: 0,
|
|
45
|
-
bytesWritten: 0,
|
|
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
43
|
const creator = container === 'webm'
|
|
57
44
|
? media_parser_1.MediaParserInternals.createMatroskaMedia
|
|
58
45
|
: media_parser_1.MediaParserInternals.createIsoBaseMedia;
|
|
46
|
+
const throttledState = (0, throttled_state_update_1.throttledStateUpdate)({
|
|
47
|
+
updateFn: onProgressDoNotCallDirectly !== null && onProgressDoNotCallDirectly !== void 0 ? onProgressDoNotCallDirectly : null,
|
|
48
|
+
everyMilliseconds: progressIntervalInMs !== null && progressIntervalInMs !== void 0 ? progressIntervalInMs : 100,
|
|
49
|
+
signal: controller.signal,
|
|
50
|
+
});
|
|
59
51
|
const state = await creator({
|
|
52
|
+
filename: (0, generate_output_filename_1.generateOutputFilename)(src, container),
|
|
60
53
|
writer: await (0, auto_select_writer_1.autoSelectWriter)(writer, logLevel),
|
|
61
54
|
onBytesProgress: (bytesWritten) => {
|
|
62
|
-
|
|
63
|
-
|
|
55
|
+
var _a;
|
|
56
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
57
|
+
return {
|
|
58
|
+
...prevState,
|
|
59
|
+
bytesWritten,
|
|
60
|
+
};
|
|
61
|
+
});
|
|
64
62
|
},
|
|
65
63
|
onMillisecondsProgress: (millisecondsWritten) => {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
64
|
+
var _a;
|
|
65
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
66
|
+
if (millisecondsWritten > prevState.millisecondsWritten) {
|
|
67
|
+
return {
|
|
68
|
+
...prevState,
|
|
69
|
+
millisecondsWritten,
|
|
70
|
+
overallProgress: (0, calculate_progress_1.calculateProgress)({
|
|
71
|
+
millisecondsWritten: prevState.millisecondsWritten,
|
|
72
|
+
expectedOutputDurationInMs: prevState.expectedOutputDurationInMs,
|
|
73
|
+
}),
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
return prevState;
|
|
77
|
+
});
|
|
74
78
|
},
|
|
75
79
|
logLevel,
|
|
76
80
|
});
|
|
77
81
|
const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
|
|
78
82
|
state,
|
|
79
83
|
onVideoFrame: onVideoFrame !== null && onVideoFrame !== void 0 ? onVideoFrame : null,
|
|
80
|
-
onMediaStateUpdate:
|
|
84
|
+
onMediaStateUpdate: (_a = throttledState.update) !== null && _a !== void 0 ? _a : null,
|
|
81
85
|
abortConversion,
|
|
82
|
-
convertMediaState,
|
|
83
86
|
controller,
|
|
84
87
|
defaultVideoCodec: videoCodec !== null && videoCodec !== void 0 ? videoCodec : null,
|
|
85
88
|
onVideoTrack: userVideoResolver !== null && userVideoResolver !== void 0 ? userVideoResolver : null,
|
|
@@ -90,8 +93,7 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
90
93
|
abortConversion,
|
|
91
94
|
defaultAudioCodec: audioCodec !== null && audioCodec !== void 0 ? audioCodec : null,
|
|
92
95
|
controller,
|
|
93
|
-
|
|
94
|
-
onMediaStateUpdate: onMediaStateUpdate !== null && onMediaStateUpdate !== void 0 ? onMediaStateUpdate : null,
|
|
96
|
+
onMediaStateUpdate: (_b = throttledState.update) !== null && _b !== void 0 ? _b : null,
|
|
95
97
|
state,
|
|
96
98
|
onAudioTrack: userAudioResolver !== null && userAudioResolver !== void 0 ? userAudioResolver : null,
|
|
97
99
|
logLevel,
|
|
@@ -110,6 +112,7 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
110
112
|
reader,
|
|
111
113
|
...more,
|
|
112
114
|
onDurationInSeconds: (durationInSeconds) => {
|
|
115
|
+
var _a;
|
|
113
116
|
if (durationInSeconds === null) {
|
|
114
117
|
return null;
|
|
115
118
|
}
|
|
@@ -118,22 +121,33 @@ const convertMedia = async function ({ src, onVideoFrame, onMediaStateUpdate: on
|
|
|
118
121
|
casted.onDurationInSeconds(durationInSeconds);
|
|
119
122
|
}
|
|
120
123
|
const expectedOutputDurationInMs = durationInSeconds * 1000;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
124
|
+
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
125
|
+
return {
|
|
126
|
+
...prevState,
|
|
127
|
+
expectedOutputDurationInMs,
|
|
128
|
+
overallProgress: (0, calculate_progress_1.calculateProgress)({
|
|
129
|
+
millisecondsWritten: prevState.millisecondsWritten,
|
|
130
|
+
expectedOutputDurationInMs,
|
|
131
|
+
}),
|
|
132
|
+
};
|
|
125
133
|
});
|
|
126
|
-
onMediaStateUpdate(convertMediaState);
|
|
127
134
|
},
|
|
128
135
|
})
|
|
129
136
|
.then(() => {
|
|
130
137
|
return state.waitForFinish();
|
|
131
138
|
})
|
|
132
139
|
.then(() => {
|
|
133
|
-
resolve({
|
|
140
|
+
resolve({
|
|
141
|
+
save: state.save,
|
|
142
|
+
remove: state.remove,
|
|
143
|
+
finalState: throttledState.get(),
|
|
144
|
+
});
|
|
134
145
|
})
|
|
135
146
|
.catch((err) => {
|
|
136
147
|
reject(err);
|
|
148
|
+
})
|
|
149
|
+
.finally(() => {
|
|
150
|
+
throttledState.stopAndGetLastProgress();
|
|
137
151
|
});
|
|
138
152
|
return getPromiseToImmediatelyReturn().finally(() => {
|
|
139
153
|
userPassedAbortSignal === null || userPassedAbortSignal === void 0 ? void 0 : userPassedAbortSignal.removeEventListener('abort', onUserAbort);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ConvertMediaVideoCodec } from './codec-id';
|
|
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,28 @@
|
|
|
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
|
+
return (0, browser_quirks_1.isFirefox)() && videoFrame.format === 'BGRX' && outputCodec === 'h264';
|
|
7
|
+
};
|
|
8
|
+
exports.needsToCorrectVideoFrame = needsToCorrectVideoFrame;
|
|
9
|
+
const convertToCorrectVideoFrame = ({ videoFrame, outputCodec, }) => {
|
|
10
|
+
if (!(0, exports.needsToCorrectVideoFrame)({ videoFrame, outputCodec })) {
|
|
11
|
+
return videoFrame;
|
|
12
|
+
}
|
|
13
|
+
const canvas = new OffscreenCanvas(videoFrame.displayWidth, videoFrame.displayHeight);
|
|
14
|
+
canvas.width = videoFrame.displayWidth;
|
|
15
|
+
canvas.height = videoFrame.displayHeight;
|
|
16
|
+
const ctx = canvas.getContext('2d');
|
|
17
|
+
if (!ctx) {
|
|
18
|
+
throw new Error('Could not get 2d context');
|
|
19
|
+
}
|
|
20
|
+
ctx.drawImage(videoFrame, 0, 0);
|
|
21
|
+
return new VideoFrame(canvas, {
|
|
22
|
+
displayHeight: videoFrame.displayHeight,
|
|
23
|
+
displayWidth: videoFrame.displayWidth,
|
|
24
|
+
duration: videoFrame.duration,
|
|
25
|
+
timestamp: videoFrame.timestamp,
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
exports.convertToCorrectVideoFrame = convertToCorrectVideoFrame;
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
// src/set-remotion-imported.ts
|
|
2
|
+
import { VERSION } from "@remotion/media-parser";
|
|
3
|
+
var setRemotionImported = () => {
|
|
4
|
+
if (typeof globalThis === "undefined") {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
if (globalThis.remotion_imported) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
globalThis.remotion_imported = VERSION;
|
|
11
|
+
if (typeof window !== "undefined") {
|
|
12
|
+
window.remotion_imported = `${VERSION}-webcodecs`;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
1
16
|
// src/log.ts
|
|
2
17
|
import { MediaParserInternals } from "@remotion/media-parser";
|
|
3
18
|
var { Log } = MediaParserInternals;
|
|
@@ -267,7 +282,7 @@ var createAudioEncoder = ({
|
|
|
267
282
|
if (encoder.state === "closed") {
|
|
268
283
|
return;
|
|
269
284
|
}
|
|
270
|
-
await ioSynchronizer.waitFor({ unemitted:
|
|
285
|
+
await ioSynchronizer.waitFor({ unemitted: 20, _unprocessed: 20 });
|
|
271
286
|
if (encoder.state === "closed") {
|
|
272
287
|
return;
|
|
273
288
|
}
|
|
@@ -403,6 +418,14 @@ var getVideoDecoderConfigWithHardwareAcceleration = async (config) => {
|
|
|
403
418
|
return null;
|
|
404
419
|
};
|
|
405
420
|
|
|
421
|
+
// src/browser-quirks.ts
|
|
422
|
+
var isFirefox = () => {
|
|
423
|
+
return navigator.userAgent.toLowerCase().indexOf("firefox") > -1;
|
|
424
|
+
};
|
|
425
|
+
var isSafari = () => {
|
|
426
|
+
return /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
|
|
427
|
+
};
|
|
428
|
+
|
|
406
429
|
// src/choose-correct-avc1-profile.ts
|
|
407
430
|
var chooseCorrectAvc1Profile = ({
|
|
408
431
|
width,
|
|
@@ -451,7 +474,8 @@ var getVideoEncoderConfig = async ({
|
|
|
451
474
|
const config = {
|
|
452
475
|
codec: codec === "h264" ? chooseCorrectAvc1Profile({ fps, height, width }) : codec === "vp9" ? "vp09.00.10.08" : codec,
|
|
453
476
|
height,
|
|
454
|
-
width
|
|
477
|
+
width,
|
|
478
|
+
bitrate: isSafari() ? 3000000 : undefined
|
|
455
479
|
};
|
|
456
480
|
const hardware = {
|
|
457
481
|
...config,
|
|
@@ -544,6 +568,14 @@ var calculateProgress = ({
|
|
|
544
568
|
// src/error-cause.ts
|
|
545
569
|
var error_cause_default = Error;
|
|
546
570
|
|
|
571
|
+
// src/generate-output-filename.ts
|
|
572
|
+
var generateOutputFilename = (source, container) => {
|
|
573
|
+
const filename = typeof source === "string" ? source : source instanceof File ? source.name : "converted";
|
|
574
|
+
const behindSlash = filename.split("/").pop();
|
|
575
|
+
const withoutExtension = behindSlash.split(".").slice(0, -1).join(".");
|
|
576
|
+
return `${withoutExtension}.${container}`;
|
|
577
|
+
};
|
|
578
|
+
|
|
547
579
|
// src/convert-encoded-chunk.ts
|
|
548
580
|
var convertEncodedChunk = (chunk, trackId) => {
|
|
549
581
|
const arr = new Uint8Array(chunk.byteLength);
|
|
@@ -614,7 +646,6 @@ var defaultOnAudioTrackHandler = async ({
|
|
|
614
646
|
var makeAudioTrackHandler = ({
|
|
615
647
|
state,
|
|
616
648
|
defaultAudioCodec: audioCodec,
|
|
617
|
-
convertMediaState,
|
|
618
649
|
controller,
|
|
619
650
|
abortConversion,
|
|
620
651
|
onMediaStateUpdate,
|
|
@@ -652,8 +683,12 @@ var makeAudioTrackHandler = ({
|
|
|
652
683
|
timescale: track.timescale,
|
|
653
684
|
codecPrivate: track.codecPrivate
|
|
654
685
|
});
|
|
655
|
-
|
|
656
|
-
|
|
686
|
+
onMediaStateUpdate?.((prevState) => {
|
|
687
|
+
return {
|
|
688
|
+
...prevState,
|
|
689
|
+
encodedAudioFrames: prevState.encodedAudioFrames + 1
|
|
690
|
+
};
|
|
691
|
+
});
|
|
657
692
|
};
|
|
658
693
|
}
|
|
659
694
|
const audioEncoderConfig = await getAudioEncoderConfig({
|
|
@@ -697,8 +732,12 @@ var makeAudioTrackHandler = ({
|
|
|
697
732
|
timescale: track.timescale,
|
|
698
733
|
codecPrivate
|
|
699
734
|
});
|
|
700
|
-
|
|
701
|
-
|
|
735
|
+
onMediaStateUpdate?.((prevState) => {
|
|
736
|
+
return {
|
|
737
|
+
...prevState,
|
|
738
|
+
encodedAudioFrames: prevState.encodedAudioFrames + 1
|
|
739
|
+
};
|
|
740
|
+
});
|
|
702
741
|
},
|
|
703
742
|
onError: (err) => {
|
|
704
743
|
abortConversion(new error_cause_default(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
|
|
@@ -713,8 +752,12 @@ var makeAudioTrackHandler = ({
|
|
|
713
752
|
const audioDecoder = createAudioDecoder({
|
|
714
753
|
onFrame: async (frame) => {
|
|
715
754
|
await audioEncoder.encodeFrame(frame);
|
|
716
|
-
|
|
717
|
-
|
|
755
|
+
onMediaStateUpdate?.((prevState) => {
|
|
756
|
+
return {
|
|
757
|
+
...prevState,
|
|
758
|
+
decodedAudioFrames: prevState.decodedAudioFrames + 1
|
|
759
|
+
};
|
|
760
|
+
});
|
|
718
761
|
frame.close();
|
|
719
762
|
},
|
|
720
763
|
onError(error) {
|
|
@@ -783,21 +826,50 @@ var defaultOnVideoTrackHandler = async ({
|
|
|
783
826
|
return Promise.resolve({ type: "fail" });
|
|
784
827
|
};
|
|
785
828
|
|
|
829
|
+
// src/convert-to-correct-videoframe.ts
|
|
830
|
+
var needsToCorrectVideoFrame = ({
|
|
831
|
+
videoFrame,
|
|
832
|
+
outputCodec
|
|
833
|
+
}) => {
|
|
834
|
+
return isFirefox() && videoFrame.format === "BGRX" && outputCodec === "h264";
|
|
835
|
+
};
|
|
836
|
+
var convertToCorrectVideoFrame = ({
|
|
837
|
+
videoFrame,
|
|
838
|
+
outputCodec
|
|
839
|
+
}) => {
|
|
840
|
+
if (!needsToCorrectVideoFrame({ videoFrame, outputCodec })) {
|
|
841
|
+
return videoFrame;
|
|
842
|
+
}
|
|
843
|
+
const canvas = new OffscreenCanvas(videoFrame.displayWidth, videoFrame.displayHeight);
|
|
844
|
+
canvas.width = videoFrame.displayWidth;
|
|
845
|
+
canvas.height = videoFrame.displayHeight;
|
|
846
|
+
const ctx = canvas.getContext("2d");
|
|
847
|
+
if (!ctx) {
|
|
848
|
+
throw new Error("Could not get 2d context");
|
|
849
|
+
}
|
|
850
|
+
ctx.drawImage(videoFrame, 0, 0);
|
|
851
|
+
return new VideoFrame(canvas, {
|
|
852
|
+
displayHeight: videoFrame.displayHeight,
|
|
853
|
+
displayWidth: videoFrame.displayWidth,
|
|
854
|
+
duration: videoFrame.duration,
|
|
855
|
+
timestamp: videoFrame.timestamp
|
|
856
|
+
});
|
|
857
|
+
};
|
|
858
|
+
|
|
786
859
|
// src/on-frame.ts
|
|
787
860
|
var onFrame = async ({
|
|
788
861
|
frame,
|
|
789
862
|
onVideoFrame,
|
|
790
863
|
videoEncoder,
|
|
791
|
-
onMediaStateUpdate,
|
|
792
864
|
track,
|
|
793
|
-
|
|
865
|
+
outputCodec
|
|
794
866
|
}) => {
|
|
795
867
|
const newFrame = onVideoFrame ? await onVideoFrame({ frame, track }) : frame;
|
|
796
|
-
if (newFrame.codedHeight !== frame.
|
|
797
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame (${frame.
|
|
868
|
+
if (newFrame.codedHeight !== frame.displayHeight) {
|
|
869
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame displayHeight (${frame.displayHeight})`);
|
|
798
870
|
}
|
|
799
|
-
if (newFrame.codedWidth !== frame.
|
|
800
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame (${frame.
|
|
871
|
+
if (newFrame.codedWidth !== frame.displayWidth) {
|
|
872
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame displayWidth (${frame.displayWidth})`);
|
|
801
873
|
}
|
|
802
874
|
if (newFrame.displayWidth !== frame.displayWidth) {
|
|
803
875
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${newFrame.displayWidth}) than the input frame (${newFrame.displayHeight})`);
|
|
@@ -811,13 +883,18 @@ var onFrame = async ({
|
|
|
811
883
|
if (newFrame.duration !== frame.duration) {
|
|
812
884
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${newFrame.duration}) than the input frame (${newFrame.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
|
|
813
885
|
}
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
886
|
+
const fixedFrame = convertToCorrectVideoFrame({
|
|
887
|
+
videoFrame: newFrame,
|
|
888
|
+
outputCodec
|
|
889
|
+
});
|
|
890
|
+
await videoEncoder.encodeFrame(fixedFrame, fixedFrame.timestamp);
|
|
891
|
+
fixedFrame.close();
|
|
818
892
|
if (frame !== newFrame) {
|
|
819
893
|
frame.close();
|
|
820
894
|
}
|
|
895
|
+
if (fixedFrame !== newFrame) {
|
|
896
|
+
fixedFrame.close();
|
|
897
|
+
}
|
|
821
898
|
};
|
|
822
899
|
|
|
823
900
|
// src/video-decoder.ts
|
|
@@ -910,7 +987,8 @@ var createVideoEncoder = ({
|
|
|
910
987
|
onError,
|
|
911
988
|
signal,
|
|
912
989
|
config,
|
|
913
|
-
logLevel
|
|
990
|
+
logLevel,
|
|
991
|
+
outputCodec
|
|
914
992
|
}) => {
|
|
915
993
|
if (signal.aborted) {
|
|
916
994
|
throw new Error("Not creating video encoder, already aborted");
|
|
@@ -948,6 +1026,7 @@ var createVideoEncoder = ({
|
|
|
948
1026
|
close();
|
|
949
1027
|
};
|
|
950
1028
|
signal.addEventListener("abort", onAbort);
|
|
1029
|
+
Log.verbose(logLevel, "Configuring video encoder", config);
|
|
951
1030
|
encoder.configure(config);
|
|
952
1031
|
let framesProcessed = 0;
|
|
953
1032
|
const encodeFrame = async (frame) => {
|
|
@@ -955,14 +1034,14 @@ var createVideoEncoder = ({
|
|
|
955
1034
|
return;
|
|
956
1035
|
}
|
|
957
1036
|
await ioSynchronizer.waitFor({
|
|
958
|
-
unemitted:
|
|
959
|
-
_unprocessed:
|
|
1037
|
+
unemitted: 10,
|
|
1038
|
+
_unprocessed: 10
|
|
960
1039
|
});
|
|
961
1040
|
if (encoder.state === "closed") {
|
|
962
1041
|
return;
|
|
963
1042
|
}
|
|
964
1043
|
const keyFrame = framesProcessed % 40 === 0;
|
|
965
|
-
encoder.encode(frame, {
|
|
1044
|
+
encoder.encode(convertToCorrectVideoFrame({ videoFrame: frame, outputCodec }), {
|
|
966
1045
|
keyFrame
|
|
967
1046
|
});
|
|
968
1047
|
ioSynchronizer.inputItem(frame.timestamp, keyFrame);
|
|
@@ -992,7 +1071,6 @@ var makeVideoTrackHandler = ({
|
|
|
992
1071
|
onVideoFrame,
|
|
993
1072
|
onMediaStateUpdate,
|
|
994
1073
|
abortConversion,
|
|
995
|
-
convertMediaState,
|
|
996
1074
|
controller,
|
|
997
1075
|
defaultVideoCodec,
|
|
998
1076
|
onVideoTrack,
|
|
@@ -1033,8 +1111,12 @@ var makeVideoTrackHandler = ({
|
|
|
1033
1111
|
timescale: track.timescale,
|
|
1034
1112
|
codecPrivate: track.codecPrivate
|
|
1035
1113
|
});
|
|
1036
|
-
|
|
1037
|
-
|
|
1114
|
+
onMediaStateUpdate?.((prevState) => {
|
|
1115
|
+
return {
|
|
1116
|
+
...prevState,
|
|
1117
|
+
decodedVideoFrames: prevState.decodedVideoFrames + 1
|
|
1118
|
+
};
|
|
1119
|
+
});
|
|
1038
1120
|
};
|
|
1039
1121
|
}
|
|
1040
1122
|
const videoEncoderConfig = await getVideoEncoderConfig({
|
|
@@ -1071,8 +1153,12 @@ var makeVideoTrackHandler = ({
|
|
|
1071
1153
|
timescale: track.timescale,
|
|
1072
1154
|
codecPrivate: arrayBufferToUint8Array(metadata?.decoderConfig?.description ?? null)
|
|
1073
1155
|
});
|
|
1074
|
-
|
|
1075
|
-
|
|
1156
|
+
onMediaStateUpdate?.((prevState) => {
|
|
1157
|
+
return {
|
|
1158
|
+
...prevState,
|
|
1159
|
+
encodedVideoFrames: prevState.encodedVideoFrames + 1
|
|
1160
|
+
};
|
|
1161
|
+
});
|
|
1076
1162
|
},
|
|
1077
1163
|
onError: (err) => {
|
|
1078
1164
|
abortConversion(new error_cause_default(`Video encoder of track ${track.trackId} failed (see .cause of this error)`, {
|
|
@@ -1081,18 +1167,18 @@ var makeVideoTrackHandler = ({
|
|
|
1081
1167
|
},
|
|
1082
1168
|
signal: controller.signal,
|
|
1083
1169
|
config: videoEncoderConfig,
|
|
1084
|
-
logLevel
|
|
1170
|
+
logLevel,
|
|
1171
|
+
outputCodec: videoOperation.videoCodec
|
|
1085
1172
|
});
|
|
1086
1173
|
const videoDecoder = createVideoDecoder({
|
|
1087
1174
|
config: videoDecoderConfig,
|
|
1088
1175
|
onFrame: async (frame) => {
|
|
1089
1176
|
await onFrame({
|
|
1090
|
-
convertMediaState,
|
|
1091
1177
|
frame,
|
|
1092
|
-
onMediaStateUpdate,
|
|
1093
1178
|
track,
|
|
1094
1179
|
videoEncoder,
|
|
1095
|
-
onVideoFrame
|
|
1180
|
+
onVideoFrame,
|
|
1181
|
+
outputCodec: videoOperation.videoCodec
|
|
1096
1182
|
});
|
|
1097
1183
|
},
|
|
1098
1184
|
onError: (err) => {
|
|
@@ -1117,11 +1203,63 @@ var makeVideoTrackHandler = ({
|
|
|
1117
1203
|
};
|
|
1118
1204
|
};
|
|
1119
1205
|
|
|
1206
|
+
// src/throttled-state-update.ts
|
|
1207
|
+
var throttledStateUpdate = ({
|
|
1208
|
+
updateFn,
|
|
1209
|
+
everyMilliseconds,
|
|
1210
|
+
signal
|
|
1211
|
+
}) => {
|
|
1212
|
+
let currentState = {
|
|
1213
|
+
decodedAudioFrames: 0,
|
|
1214
|
+
decodedVideoFrames: 0,
|
|
1215
|
+
encodedVideoFrames: 0,
|
|
1216
|
+
encodedAudioFrames: 0,
|
|
1217
|
+
bytesWritten: 0,
|
|
1218
|
+
millisecondsWritten: 0,
|
|
1219
|
+
expectedOutputDurationInMs: null,
|
|
1220
|
+
overallProgress: 0
|
|
1221
|
+
};
|
|
1222
|
+
if (!updateFn) {
|
|
1223
|
+
return {
|
|
1224
|
+
get: () => currentState,
|
|
1225
|
+
update: null,
|
|
1226
|
+
stopAndGetLastProgress: () => {
|
|
1227
|
+
}
|
|
1228
|
+
};
|
|
1229
|
+
}
|
|
1230
|
+
let lastUpdated = null;
|
|
1231
|
+
const callUpdateIfChanged = () => {
|
|
1232
|
+
if (currentState === lastUpdated) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
updateFn(currentState);
|
|
1236
|
+
lastUpdated = currentState;
|
|
1237
|
+
};
|
|
1238
|
+
const interval = setInterval(() => {
|
|
1239
|
+
callUpdateIfChanged();
|
|
1240
|
+
}, everyMilliseconds);
|
|
1241
|
+
const onAbort = () => {
|
|
1242
|
+
clearInterval(interval);
|
|
1243
|
+
};
|
|
1244
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
1245
|
+
return {
|
|
1246
|
+
get: () => currentState,
|
|
1247
|
+
update: (fn) => {
|
|
1248
|
+
currentState = fn(currentState);
|
|
1249
|
+
},
|
|
1250
|
+
stopAndGetLastProgress: () => {
|
|
1251
|
+
clearInterval(interval);
|
|
1252
|
+
signal.removeEventListener("abort", onAbort);
|
|
1253
|
+
return currentState;
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
};
|
|
1257
|
+
|
|
1120
1258
|
// src/convert-media.ts
|
|
1121
1259
|
var convertMedia = async function({
|
|
1122
1260
|
src,
|
|
1123
1261
|
onVideoFrame,
|
|
1124
|
-
|
|
1262
|
+
onProgress: onProgressDoNotCallDirectly,
|
|
1125
1263
|
audioCodec,
|
|
1126
1264
|
container,
|
|
1127
1265
|
videoCodec,
|
|
@@ -1132,6 +1270,7 @@ var convertMedia = async function({
|
|
|
1132
1270
|
fields,
|
|
1133
1271
|
logLevel = "info",
|
|
1134
1272
|
writer,
|
|
1273
|
+
progressIntervalInMs,
|
|
1135
1274
|
...more
|
|
1136
1275
|
}) {
|
|
1137
1276
|
if (userPassedAbortSignal?.aborted) {
|
|
@@ -1155,47 +1294,45 @@ var convertMedia = async function({
|
|
|
1155
1294
|
abortConversion(new error_cause_default("Conversion aborted by user"));
|
|
1156
1295
|
};
|
|
1157
1296
|
userPassedAbortSignal?.addEventListener("abort", onUserAbort);
|
|
1158
|
-
const convertMediaState = {
|
|
1159
|
-
decodedAudioFrames: 0,
|
|
1160
|
-
decodedVideoFrames: 0,
|
|
1161
|
-
encodedVideoFrames: 0,
|
|
1162
|
-
encodedAudioFrames: 0,
|
|
1163
|
-
bytesWritten: 0,
|
|
1164
|
-
millisecondsWritten: 0,
|
|
1165
|
-
expectedOutputDurationInMs: null,
|
|
1166
|
-
overallProgress: 0
|
|
1167
|
-
};
|
|
1168
|
-
const onMediaStateUpdate = (newState) => {
|
|
1169
|
-
if (controller.signal.aborted) {
|
|
1170
|
-
return;
|
|
1171
|
-
}
|
|
1172
|
-
onMediaStateDoNoCallDirectly?.(newState);
|
|
1173
|
-
};
|
|
1174
1297
|
const creator = container === "webm" ? MediaParserInternals4.createMatroskaMedia : MediaParserInternals4.createIsoBaseMedia;
|
|
1298
|
+
const throttledState = throttledStateUpdate({
|
|
1299
|
+
updateFn: onProgressDoNotCallDirectly ?? null,
|
|
1300
|
+
everyMilliseconds: progressIntervalInMs ?? 100,
|
|
1301
|
+
signal: controller.signal
|
|
1302
|
+
});
|
|
1175
1303
|
const state = await creator({
|
|
1304
|
+
filename: generateOutputFilename(src, container),
|
|
1176
1305
|
writer: await autoSelectWriter(writer, logLevel),
|
|
1177
1306
|
onBytesProgress: (bytesWritten) => {
|
|
1178
|
-
|
|
1179
|
-
|
|
1307
|
+
throttledState.update?.((prevState) => {
|
|
1308
|
+
return {
|
|
1309
|
+
...prevState,
|
|
1310
|
+
bytesWritten
|
|
1311
|
+
};
|
|
1312
|
+
});
|
|
1180
1313
|
},
|
|
1181
1314
|
onMillisecondsProgress: (millisecondsWritten) => {
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1315
|
+
throttledState.update?.((prevState) => {
|
|
1316
|
+
if (millisecondsWritten > prevState.millisecondsWritten) {
|
|
1317
|
+
return {
|
|
1318
|
+
...prevState,
|
|
1319
|
+
millisecondsWritten,
|
|
1320
|
+
overallProgress: calculateProgress({
|
|
1321
|
+
millisecondsWritten: prevState.millisecondsWritten,
|
|
1322
|
+
expectedOutputDurationInMs: prevState.expectedOutputDurationInMs
|
|
1323
|
+
})
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
return prevState;
|
|
1327
|
+
});
|
|
1190
1328
|
},
|
|
1191
1329
|
logLevel
|
|
1192
1330
|
});
|
|
1193
1331
|
const onVideoTrack = makeVideoTrackHandler({
|
|
1194
1332
|
state,
|
|
1195
1333
|
onVideoFrame: onVideoFrame ?? null,
|
|
1196
|
-
onMediaStateUpdate:
|
|
1334
|
+
onMediaStateUpdate: throttledState.update ?? null,
|
|
1197
1335
|
abortConversion,
|
|
1198
|
-
convertMediaState,
|
|
1199
1336
|
controller,
|
|
1200
1337
|
defaultVideoCodec: videoCodec ?? null,
|
|
1201
1338
|
onVideoTrack: userVideoResolver ?? null,
|
|
@@ -1206,8 +1343,7 @@ var convertMedia = async function({
|
|
|
1206
1343
|
abortConversion,
|
|
1207
1344
|
defaultAudioCodec: audioCodec ?? null,
|
|
1208
1345
|
controller,
|
|
1209
|
-
|
|
1210
|
-
onMediaStateUpdate: onMediaStateUpdate ?? null,
|
|
1346
|
+
onMediaStateUpdate: throttledState.update ?? null,
|
|
1211
1347
|
state,
|
|
1212
1348
|
onAudioTrack: userAudioResolver ?? null,
|
|
1213
1349
|
logLevel,
|
|
@@ -1234,24 +1370,36 @@ var convertMedia = async function({
|
|
|
1234
1370
|
casted.onDurationInSeconds(durationInSeconds);
|
|
1235
1371
|
}
|
|
1236
1372
|
const expectedOutputDurationInMs = durationInSeconds * 1000;
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1373
|
+
throttledState.update?.((prevState) => {
|
|
1374
|
+
return {
|
|
1375
|
+
...prevState,
|
|
1376
|
+
expectedOutputDurationInMs,
|
|
1377
|
+
overallProgress: calculateProgress({
|
|
1378
|
+
millisecondsWritten: prevState.millisecondsWritten,
|
|
1379
|
+
expectedOutputDurationInMs
|
|
1380
|
+
})
|
|
1381
|
+
};
|
|
1241
1382
|
});
|
|
1242
|
-
onMediaStateUpdate(convertMediaState);
|
|
1243
1383
|
}
|
|
1244
1384
|
}).then(() => {
|
|
1245
1385
|
return state.waitForFinish();
|
|
1246
1386
|
}).then(() => {
|
|
1247
|
-
resolve({
|
|
1387
|
+
resolve({
|
|
1388
|
+
save: state.save,
|
|
1389
|
+
remove: state.remove,
|
|
1390
|
+
finalState: throttledState.get()
|
|
1391
|
+
});
|
|
1248
1392
|
}).catch((err) => {
|
|
1249
1393
|
reject(err);
|
|
1394
|
+
}).finally(() => {
|
|
1395
|
+
throttledState.stopAndGetLastProgress();
|
|
1250
1396
|
});
|
|
1251
1397
|
return getPromiseToImmediatelyReturn().finally(() => {
|
|
1252
1398
|
userPassedAbortSignal?.removeEventListener("abort", onUserAbort);
|
|
1253
1399
|
});
|
|
1254
1400
|
};
|
|
1401
|
+
// src/index.ts
|
|
1402
|
+
setRemotionImported();
|
|
1255
1403
|
export {
|
|
1256
1404
|
getDefaultVideoCodec,
|
|
1257
1405
|
getDefaultAudioCodec,
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateOutputFilename = void 0;
|
|
4
|
+
const generateOutputFilename = (source, container) => {
|
|
5
|
+
const filename = typeof source === 'string'
|
|
6
|
+
? source
|
|
7
|
+
: source instanceof File
|
|
8
|
+
? source.name
|
|
9
|
+
: 'converted';
|
|
10
|
+
const behindSlash = filename.split('/').pop();
|
|
11
|
+
const withoutExtension = behindSlash.split('.').slice(0, -1).join('.');
|
|
12
|
+
return `${withoutExtension}.${container}`;
|
|
13
|
+
};
|
|
14
|
+
exports.generateOutputFilename = generateOutputFilename;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
1
|
+
export { createAudioDecoder, WebCodecsAudioDecoder } from './audio-decoder';
|
|
2
|
+
export { createAudioEncoder, WebCodecsAudioEncoder } from './audio-encoder';
|
|
3
3
|
export { canCopyAudioTrack } from './can-copy-audio-track';
|
|
4
4
|
export { canCopyVideoTrack } from './can-copy-video-track';
|
|
5
5
|
export { canReencodeAudioTrack } from './can-reencode-audio-track';
|
|
6
6
|
export { canReencodeVideoTrack } from './can-reencode-video-track';
|
|
7
7
|
export { ConvertMediaAudioCodec, ConvertMediaContainer, ConvertMediaVideoCodec, getAvailableAudioCodecs, getAvailableContainers, getAvailableVideoCodecs, } from './codec-id';
|
|
8
|
-
export {
|
|
8
|
+
export { convertMedia, ConvertMediaOnProgress, ConvertMediaOnVideoFrame, ConvertMediaProgress, ConvertMediaResult, } from './convert-media';
|
|
9
9
|
export { defaultOnAudioTrackHandler } from './default-on-audio-track-handler';
|
|
10
10
|
export { defaultOnVideoTrackHandler } from './default-on-video-track-handler';
|
|
11
11
|
export { getDefaultAudioCodec } from './get-default-audio-codec';
|
|
12
12
|
export { getDefaultVideoCodec } from './get-default-video-codec';
|
|
13
13
|
export { AudioOperation, ConvertMediaOnAudioTrackHandler, } from './on-audio-track-handler';
|
|
14
14
|
export { ConvertMediaOnVideoTrackHandler, VideoOperation, } from './on-video-track-handler';
|
|
15
|
-
export {
|
|
16
|
-
export {
|
|
15
|
+
export { createVideoDecoder, WebCodecsVideoDecoder } from './video-decoder';
|
|
16
|
+
export { createVideoEncoder, WebCodecsVideoEncoder } from './video-encoder';
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createVideoEncoder = exports.createVideoDecoder = exports.getDefaultVideoCodec = exports.getDefaultAudioCodec = exports.defaultOnVideoTrackHandler = exports.defaultOnAudioTrackHandler = exports.convertMedia = exports.getAvailableVideoCodecs = exports.getAvailableContainers = exports.getAvailableAudioCodecs = exports.canReencodeVideoTrack = exports.canReencodeAudioTrack = exports.canCopyVideoTrack = exports.canCopyAudioTrack = exports.createAudioEncoder = exports.createAudioDecoder = void 0;
|
|
4
|
+
const set_remotion_imported_1 = require("./set-remotion-imported");
|
|
4
5
|
var audio_decoder_1 = require("./audio-decoder");
|
|
5
6
|
Object.defineProperty(exports, "createAudioDecoder", { enumerable: true, get: function () { return audio_decoder_1.createAudioDecoder; } });
|
|
6
7
|
var audio_encoder_1 = require("./audio-encoder");
|
|
@@ -31,3 +32,4 @@ var video_decoder_1 = require("./video-decoder");
|
|
|
31
32
|
Object.defineProperty(exports, "createVideoDecoder", { enumerable: true, get: function () { return video_decoder_1.createVideoDecoder; } });
|
|
32
33
|
var video_encoder_1 = require("./video-encoder");
|
|
33
34
|
Object.defineProperty(exports, "createVideoEncoder", { enumerable: true, get: function () { return video_encoder_1.createVideoEncoder; } });
|
|
35
|
+
(0, set_remotion_imported_1.setRemotionImported)();
|
package/dist/on-audio-track.d.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
import type { LogLevel, MediaFn, OnAudioTrack } from '@remotion/media-parser';
|
|
2
2
|
import type { ConvertMediaAudioCodec, ConvertMediaContainer } from './codec-id';
|
|
3
|
-
import type { ConvertMediaState } from './convert-media';
|
|
4
3
|
import Error from './error-cause';
|
|
5
4
|
import type { ConvertMediaOnAudioTrackHandler } from './on-audio-track-handler';
|
|
6
|
-
|
|
5
|
+
import type { ConvertMediaProgressFn } from './throttled-state-update';
|
|
6
|
+
export declare const makeAudioTrackHandler: ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }: {
|
|
7
7
|
state: MediaFn;
|
|
8
8
|
defaultAudioCodec: ConvertMediaAudioCodec | null;
|
|
9
|
-
convertMediaState: ConvertMediaState;
|
|
10
9
|
controller: AbortController;
|
|
11
10
|
abortConversion: (errCause: Error) => void;
|
|
12
|
-
onMediaStateUpdate: null |
|
|
11
|
+
onMediaStateUpdate: null | ConvertMediaProgressFn;
|
|
13
12
|
onAudioTrack: ConvertMediaOnAudioTrackHandler | null;
|
|
14
13
|
logLevel: LogLevel;
|
|
15
14
|
container: ConvertMediaContainer;
|
package/dist/on-audio-track.js
CHANGED
|
@@ -12,7 +12,7 @@ const convert_encoded_chunk_1 = require("./convert-encoded-chunk");
|
|
|
12
12
|
const default_on_audio_track_handler_1 = require("./default-on-audio-track-handler");
|
|
13
13
|
const error_cause_1 = __importDefault(require("./error-cause"));
|
|
14
14
|
const log_1 = require("./log");
|
|
15
|
-
const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec,
|
|
15
|
+
const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controller, abortConversion, onMediaStateUpdate, onAudioTrack, logLevel, container, }) => async (track) => {
|
|
16
16
|
const audioOperation = await (onAudioTrack !== null && onAudioTrack !== void 0 ? onAudioTrack : default_on_audio_track_handler_1.defaultOnAudioTrackHandler)({
|
|
17
17
|
defaultAudioCodec: audioCodec,
|
|
18
18
|
track,
|
|
@@ -43,8 +43,12 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, convertMe
|
|
|
43
43
|
timescale: track.timescale,
|
|
44
44
|
codecPrivate: track.codecPrivate,
|
|
45
45
|
});
|
|
46
|
-
|
|
47
|
-
|
|
46
|
+
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
47
|
+
return {
|
|
48
|
+
...prevState,
|
|
49
|
+
encodedAudioFrames: prevState.encodedAudioFrames + 1,
|
|
50
|
+
};
|
|
51
|
+
});
|
|
48
52
|
};
|
|
49
53
|
}
|
|
50
54
|
const audioEncoderConfig = await (0, audio_encoder_config_1.getAudioEncoderConfig)({
|
|
@@ -92,8 +96,12 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, convertMe
|
|
|
92
96
|
timescale: track.timescale,
|
|
93
97
|
codecPrivate,
|
|
94
98
|
});
|
|
95
|
-
|
|
96
|
-
|
|
99
|
+
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
100
|
+
return {
|
|
101
|
+
...prevState,
|
|
102
|
+
encodedAudioFrames: prevState.encodedAudioFrames + 1,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
97
105
|
},
|
|
98
106
|
onError: (err) => {
|
|
99
107
|
abortConversion(new error_cause_1.default(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
|
|
@@ -108,8 +116,12 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, convertMe
|
|
|
108
116
|
const audioDecoder = (0, audio_decoder_1.createAudioDecoder)({
|
|
109
117
|
onFrame: async (frame) => {
|
|
110
118
|
await audioEncoder.encodeFrame(frame);
|
|
111
|
-
|
|
112
|
-
|
|
119
|
+
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
120
|
+
return {
|
|
121
|
+
...prevState,
|
|
122
|
+
decodedAudioFrames: prevState.decodedAudioFrames + 1,
|
|
123
|
+
};
|
|
124
|
+
});
|
|
113
125
|
frame.close();
|
|
114
126
|
},
|
|
115
127
|
onError(error) {
|
package/dist/on-frame.d.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { VideoTrack } from '@remotion/media-parser';
|
|
2
|
-
import type {
|
|
2
|
+
import type { ConvertMediaVideoCodec } from './codec-id';
|
|
3
|
+
import type { ConvertMediaOnVideoFrame } from './convert-media';
|
|
3
4
|
import type { WebCodecsVideoEncoder } from './video-encoder';
|
|
4
|
-
export declare const onFrame: ({ frame, onVideoFrame, videoEncoder,
|
|
5
|
+
export declare const onFrame: ({ frame, onVideoFrame, videoEncoder, track, outputCodec, }: {
|
|
5
6
|
frame: VideoFrame;
|
|
6
7
|
onVideoFrame: ConvertMediaOnVideoFrame | null;
|
|
7
8
|
videoEncoder: WebCodecsVideoEncoder;
|
|
8
|
-
onMediaStateUpdate: ConvertMediaOnMediaStateUpdate | null;
|
|
9
9
|
track: VideoTrack;
|
|
10
|
-
|
|
10
|
+
outputCodec: ConvertMediaVideoCodec;
|
|
11
11
|
}) => Promise<void>;
|
package/dist/on-frame.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.onFrame = void 0;
|
|
4
|
-
const
|
|
4
|
+
const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
|
|
5
|
+
const onFrame = async ({ frame, onVideoFrame, videoEncoder, track, outputCodec, }) => {
|
|
5
6
|
const newFrame = onVideoFrame ? await onVideoFrame({ frame, track }) : frame;
|
|
6
|
-
if (newFrame.codedHeight !== frame.
|
|
7
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame (${frame.
|
|
7
|
+
if (newFrame.codedHeight !== frame.displayHeight) {
|
|
8
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedHeight (${newFrame.codedHeight}) than the input frame displayHeight (${frame.displayHeight})`);
|
|
8
9
|
}
|
|
9
|
-
if (newFrame.codedWidth !== frame.
|
|
10
|
-
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame (${frame.
|
|
10
|
+
if (newFrame.codedWidth !== frame.displayWidth) {
|
|
11
|
+
throw new Error(`Returned VideoFrame of track ${track.trackId} has different codedWidth (${newFrame.codedWidth}) than the input frame displayWidth (${frame.displayWidth})`);
|
|
11
12
|
}
|
|
12
13
|
if (newFrame.displayWidth !== frame.displayWidth) {
|
|
13
14
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different displayWidth (${newFrame.displayWidth}) than the input frame (${newFrame.displayHeight})`);
|
|
@@ -21,12 +22,17 @@ const onFrame = async ({ frame, onVideoFrame, videoEncoder, onMediaStateUpdate,
|
|
|
21
22
|
if (newFrame.duration !== frame.duration) {
|
|
22
23
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${newFrame.duration}) than the input frame (${newFrame.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
|
|
23
24
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
const fixedFrame = (0, convert_to_correct_videoframe_1.convertToCorrectVideoFrame)({
|
|
26
|
+
videoFrame: newFrame,
|
|
27
|
+
outputCodec,
|
|
28
|
+
});
|
|
29
|
+
await videoEncoder.encodeFrame(fixedFrame, fixedFrame.timestamp);
|
|
30
|
+
fixedFrame.close();
|
|
28
31
|
if (frame !== newFrame) {
|
|
29
32
|
frame.close();
|
|
30
33
|
}
|
|
34
|
+
if (fixedFrame !== newFrame) {
|
|
35
|
+
fixedFrame.close();
|
|
36
|
+
}
|
|
31
37
|
};
|
|
32
38
|
exports.onFrame = onFrame;
|
package/dist/on-video-track.d.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import type { LogLevel, MediaFn, OnVideoTrack } from '@remotion/media-parser';
|
|
2
2
|
import type { ConvertMediaContainer, ConvertMediaVideoCodec } from './codec-id';
|
|
3
|
-
import type {
|
|
3
|
+
import type { ConvertMediaOnVideoFrame } from './convert-media';
|
|
4
4
|
import Error from './error-cause';
|
|
5
5
|
import type { ConvertMediaOnVideoTrackHandler } from './on-video-track-handler';
|
|
6
|
-
|
|
6
|
+
import type { ConvertMediaProgressFn } from './throttled-state-update';
|
|
7
|
+
export declare const makeVideoTrackHandler: ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, container, }: {
|
|
7
8
|
state: MediaFn;
|
|
8
9
|
onVideoFrame: null | ConvertMediaOnVideoFrame;
|
|
9
|
-
onMediaStateUpdate: null |
|
|
10
|
+
onMediaStateUpdate: null | ConvertMediaProgressFn;
|
|
10
11
|
abortConversion: (errCause: Error) => void;
|
|
11
|
-
convertMediaState: ConvertMediaState;
|
|
12
12
|
controller: AbortController;
|
|
13
13
|
defaultVideoCodec: ConvertMediaVideoCodec | null;
|
|
14
14
|
onVideoTrack: ConvertMediaOnVideoTrackHandler | null;
|
package/dist/on-video-track.js
CHANGED
|
@@ -14,7 +14,7 @@ const video_decoder_1 = require("./video-decoder");
|
|
|
14
14
|
const video_decoder_config_1 = require("./video-decoder-config");
|
|
15
15
|
const video_encoder_1 = require("./video-encoder");
|
|
16
16
|
const video_encoder_config_1 = require("./video-encoder-config");
|
|
17
|
-
const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion,
|
|
17
|
+
const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, container, }) => async (track) => {
|
|
18
18
|
if (controller.signal.aborted) {
|
|
19
19
|
throw new error_cause_1.default('Aborted');
|
|
20
20
|
}
|
|
@@ -49,8 +49,12 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
49
49
|
timescale: track.timescale,
|
|
50
50
|
codecPrivate: track.codecPrivate,
|
|
51
51
|
});
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
53
|
+
return {
|
|
54
|
+
...prevState,
|
|
55
|
+
decodedVideoFrames: prevState.decodedVideoFrames + 1,
|
|
56
|
+
};
|
|
57
|
+
});
|
|
54
58
|
};
|
|
55
59
|
}
|
|
56
60
|
const videoEncoderConfig = await (0, video_encoder_config_1.getVideoEncoderConfig)({
|
|
@@ -88,8 +92,12 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
88
92
|
timescale: track.timescale,
|
|
89
93
|
codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)(((_b = (_a = metadata === null || metadata === void 0 ? void 0 : metadata.decoderConfig) === null || _a === void 0 ? void 0 : _a.description) !== null && _b !== void 0 ? _b : null)),
|
|
90
94
|
});
|
|
91
|
-
|
|
92
|
-
|
|
95
|
+
onMediaStateUpdate === null || onMediaStateUpdate === void 0 ? void 0 : onMediaStateUpdate((prevState) => {
|
|
96
|
+
return {
|
|
97
|
+
...prevState,
|
|
98
|
+
encodedVideoFrames: prevState.encodedVideoFrames + 1,
|
|
99
|
+
};
|
|
100
|
+
});
|
|
93
101
|
},
|
|
94
102
|
onError: (err) => {
|
|
95
103
|
abortConversion(new error_cause_1.default(`Video encoder of track ${track.trackId} failed (see .cause of this error)`, {
|
|
@@ -99,17 +107,17 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
99
107
|
signal: controller.signal,
|
|
100
108
|
config: videoEncoderConfig,
|
|
101
109
|
logLevel,
|
|
110
|
+
outputCodec: videoOperation.videoCodec,
|
|
102
111
|
});
|
|
103
112
|
const videoDecoder = (0, video_decoder_1.createVideoDecoder)({
|
|
104
113
|
config: videoDecoderConfig,
|
|
105
114
|
onFrame: async (frame) => {
|
|
106
115
|
await (0, on_frame_1.onFrame)({
|
|
107
|
-
convertMediaState,
|
|
108
116
|
frame,
|
|
109
|
-
onMediaStateUpdate,
|
|
110
117
|
track,
|
|
111
118
|
videoEncoder,
|
|
112
119
|
onVideoFrame,
|
|
120
|
+
outputCodec: videoOperation.videoCodec,
|
|
113
121
|
});
|
|
114
122
|
},
|
|
115
123
|
onError: (err) => {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setRemotionImported = void 0;
|
|
4
|
+
const media_parser_1 = require("@remotion/media-parser");
|
|
5
|
+
// We set the `window.remotion_imported` variable for the sole purpose
|
|
6
|
+
// of being picked up by Wappalyzer.
|
|
7
|
+
// The Wappalyzer Chrome extension is used to detect the technologies
|
|
8
|
+
// used on websites, and it looks for this variable.
|
|
9
|
+
// Remotion is a customer of Wappalyzer and buys a list of domains
|
|
10
|
+
// where Remotion is used from time to time.
|
|
11
|
+
// Remotion uses this data to ensure companies which are required to get
|
|
12
|
+
// a company license for this pacakge are actually doing so.
|
|
13
|
+
const setRemotionImported = () => {
|
|
14
|
+
if (typeof globalThis === 'undefined') {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
if (globalThis.remotion_imported) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
globalThis.remotion_imported = media_parser_1.VERSION;
|
|
21
|
+
if (typeof window !== 'undefined') {
|
|
22
|
+
window.remotion_imported = `${media_parser_1.VERSION}-webcodecs`;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
exports.setRemotionImported = setRemotionImported;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ConvertMediaOnProgress, ConvertMediaProgress } from './convert-media';
|
|
2
|
+
export type ConvertMediaProgressFn = (state: (prevState: ConvertMediaProgress) => ConvertMediaProgress) => void;
|
|
3
|
+
type ReturnType = {
|
|
4
|
+
get: () => ConvertMediaProgress;
|
|
5
|
+
update: ConvertMediaProgressFn | null;
|
|
6
|
+
stopAndGetLastProgress: () => void;
|
|
7
|
+
};
|
|
8
|
+
export declare const throttledStateUpdate: ({ updateFn, everyMilliseconds, signal, }: {
|
|
9
|
+
updateFn: ConvertMediaOnProgress | null;
|
|
10
|
+
everyMilliseconds: number;
|
|
11
|
+
signal: AbortSignal;
|
|
12
|
+
}) => ReturnType;
|
|
13
|
+
export {};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.throttledStateUpdate = void 0;
|
|
4
|
+
const throttledStateUpdate = ({ updateFn, everyMilliseconds, signal, }) => {
|
|
5
|
+
let currentState = {
|
|
6
|
+
decodedAudioFrames: 0,
|
|
7
|
+
decodedVideoFrames: 0,
|
|
8
|
+
encodedVideoFrames: 0,
|
|
9
|
+
encodedAudioFrames: 0,
|
|
10
|
+
bytesWritten: 0,
|
|
11
|
+
millisecondsWritten: 0,
|
|
12
|
+
expectedOutputDurationInMs: null,
|
|
13
|
+
overallProgress: 0,
|
|
14
|
+
};
|
|
15
|
+
if (!updateFn) {
|
|
16
|
+
return {
|
|
17
|
+
get: () => currentState,
|
|
18
|
+
update: null,
|
|
19
|
+
stopAndGetLastProgress: () => { },
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
let lastUpdated = null;
|
|
23
|
+
const callUpdateIfChanged = () => {
|
|
24
|
+
if (currentState === lastUpdated) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
updateFn(currentState);
|
|
28
|
+
lastUpdated = currentState;
|
|
29
|
+
};
|
|
30
|
+
const interval = setInterval(() => {
|
|
31
|
+
callUpdateIfChanged();
|
|
32
|
+
}, everyMilliseconds);
|
|
33
|
+
const onAbort = () => {
|
|
34
|
+
clearInterval(interval);
|
|
35
|
+
};
|
|
36
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
37
|
+
return {
|
|
38
|
+
get: () => currentState,
|
|
39
|
+
update: (fn) => {
|
|
40
|
+
currentState = fn(currentState);
|
|
41
|
+
},
|
|
42
|
+
stopAndGetLastProgress: () => {
|
|
43
|
+
clearInterval(interval);
|
|
44
|
+
signal.removeEventListener('abort', onAbort);
|
|
45
|
+
return currentState;
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
exports.throttledStateUpdate = throttledStateUpdate;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getVideoEncoderConfig = void 0;
|
|
4
|
+
const browser_quirks_1 = require("./browser-quirks");
|
|
4
5
|
const choose_correct_avc1_profile_1 = require("./choose-correct-avc1-profile");
|
|
5
6
|
const getVideoEncoderConfig = async ({ codec, height, width, fps, }) => {
|
|
6
7
|
if (typeof VideoEncoder === 'undefined') {
|
|
@@ -14,6 +15,7 @@ const getVideoEncoderConfig = async ({ codec, height, width, fps, }) => {
|
|
|
14
15
|
: codec,
|
|
15
16
|
height,
|
|
16
17
|
width,
|
|
18
|
+
bitrate: (0, browser_quirks_1.isSafari)() ? 3000000 : undefined,
|
|
17
19
|
};
|
|
18
20
|
const hardware = {
|
|
19
21
|
...config,
|
package/dist/video-encoder.d.ts
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import type { LogLevel } from '@remotion/media-parser';
|
|
2
|
+
import type { ConvertMediaVideoCodec } from './codec-id';
|
|
2
3
|
export type WebCodecsVideoEncoder = {
|
|
3
4
|
encodeFrame: (videoFrame: VideoFrame, timestamp: number) => Promise<void>;
|
|
4
5
|
waitForFinish: () => Promise<void>;
|
|
5
6
|
close: () => void;
|
|
6
7
|
flush: () => Promise<void>;
|
|
7
8
|
};
|
|
8
|
-
export declare const createVideoEncoder: ({ onChunk, onError, signal, config, logLevel, }: {
|
|
9
|
+
export declare const createVideoEncoder: ({ onChunk, onError, signal, config, logLevel, outputCodec, }: {
|
|
9
10
|
onChunk: (chunk: EncodedVideoChunk, metadata: EncodedVideoChunkMetadata | null) => Promise<void>;
|
|
10
11
|
onError: (error: DOMException) => void;
|
|
11
12
|
signal: AbortSignal;
|
|
12
13
|
config: VideoEncoderConfig;
|
|
13
14
|
logLevel: LogLevel;
|
|
15
|
+
outputCodec: ConvertMediaVideoCodec;
|
|
14
16
|
}) => WebCodecsVideoEncoder;
|
package/dist/video-encoder.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createVideoEncoder = void 0;
|
|
4
|
+
const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
|
|
4
5
|
const io_synchronizer_1 = require("./io-manager/io-synchronizer");
|
|
5
|
-
const
|
|
6
|
+
const log_1 = require("./log");
|
|
7
|
+
const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, outputCodec, }) => {
|
|
6
8
|
if (signal.aborted) {
|
|
7
9
|
throw new Error('Not creating video encoder, already aborted');
|
|
8
10
|
}
|
|
@@ -44,6 +46,7 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, }) =>
|
|
|
44
46
|
close();
|
|
45
47
|
};
|
|
46
48
|
signal.addEventListener('abort', onAbort);
|
|
49
|
+
log_1.Log.verbose(logLevel, 'Configuring video encoder', config);
|
|
47
50
|
encoder.configure(config);
|
|
48
51
|
let framesProcessed = 0;
|
|
49
52
|
const encodeFrame = async (frame) => {
|
|
@@ -51,15 +54,16 @@ const createVideoEncoder = ({ onChunk, onError, signal, config, logLevel, }) =>
|
|
|
51
54
|
return;
|
|
52
55
|
}
|
|
53
56
|
await ioSynchronizer.waitFor({
|
|
54
|
-
|
|
55
|
-
|
|
57
|
+
// Firefox stalls if too few frames are passed
|
|
58
|
+
unemitted: 10,
|
|
59
|
+
_unprocessed: 10,
|
|
56
60
|
});
|
|
57
61
|
// @ts-expect-error - can have changed in the meanwhile
|
|
58
62
|
if (encoder.state === 'closed') {
|
|
59
63
|
return;
|
|
60
64
|
}
|
|
61
65
|
const keyFrame = framesProcessed % 40 === 0;
|
|
62
|
-
encoder.encode(frame, {
|
|
66
|
+
encoder.encode((0, convert_to_correct_videoframe_1.convertToCorrectVideoFrame)({ videoFrame: frame, outputCodec }), {
|
|
63
67
|
keyFrame,
|
|
64
68
|
});
|
|
65
69
|
ioSynchronizer.inputItem(frame.timestamp, keyFrame);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/webcodecs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.231",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -17,19 +17,20 @@
|
|
|
17
17
|
"author": "Jonny Burger <jonny@remotion.dev>",
|
|
18
18
|
"license": "Remotion License (See https://remotion.dev/docs/webcodecs#license)",
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@remotion/media-parser": "4.0.
|
|
20
|
+
"@remotion/media-parser": "4.0.231"
|
|
21
21
|
},
|
|
22
22
|
"peerDependencies": {},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@types/dom-webcodecs": "0.1.11",
|
|
25
25
|
"eslint": "9.14.0",
|
|
26
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
26
|
+
"@remotion/eslint-config-internal": "4.0.231"
|
|
27
27
|
},
|
|
28
28
|
"keywords": [],
|
|
29
29
|
"publishConfig": {
|
|
30
30
|
"access": "public"
|
|
31
31
|
},
|
|
32
32
|
"description": "Media conversion in the browser",
|
|
33
|
+
"homepage": "https://remotion.dev/webcodecs",
|
|
33
34
|
"scripts": {
|
|
34
35
|
"formatting": "prettier src --check",
|
|
35
36
|
"lint": "eslint src",
|