@remotion/webcodecs 4.0.271 → 4.0.272
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.js +3 -5
- package/dist/can-reencode-video-track.js +1 -1
- package/dist/choose-correct-avc1-profile.js +1 -1
- package/dist/choose-correct-hevc-profile.js +1 -1
- package/dist/convert-encoded-chunk.js +1 -2
- package/dist/convert-media.d.ts +2 -1
- package/dist/convert-media.js +49 -52
- package/dist/create/iso-base-media/create-iso-base-media.d.ts +1 -1
- package/dist/create/iso-base-media/create-iso-base-media.js +8 -8
- package/dist/create/iso-base-media/header-length.d.ts +1 -0
- package/dist/create/iso-base-media/header-length.js +21 -0
- package/dist/create/iso-base-media/mp4-header.d.ts +4 -1
- package/dist/create/iso-base-media/mp4-header.js +11 -4
- package/dist/create/iso-base-media/primitives.d.ts +1 -0
- package/dist/create/iso-base-media/primitives.js +16 -2
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stco.js +8 -2
- package/dist/create/iso-base-media/trak/mdia/minf/stbl/create-stts.js +1 -2
- package/dist/create/matroska/create-matroska-media.js +8 -9
- package/dist/create/matroska/matroska-utils.js +3 -4
- package/dist/create/media-fn.d.ts +1 -0
- package/dist/create/wav/create-wav.js +1 -2
- package/dist/esm/index.mjs +50 -10
- package/dist/index.d.ts +1 -1
- package/dist/on-audio-track.js +7 -7
- package/dist/on-frame.js +1 -2
- package/dist/on-video-track.js +9 -11
- package/dist/rotate-and-resize-video-frame.js +1 -2
- package/dist/select-container-creator.d.ts +1 -1
- package/dist/send-telemetry-event.js +1 -2
- package/dist/test/mp4-header-length.test.d.ts +1 -0
- package/dist/test/mp4-header-length.test.js +12 -0
- package/dist/throttled-state-update.js +2 -2
- package/dist/video-decoder.js +1 -2
- package/dist/video-encoder-config.js +1 -1
- package/dist/video-encoder.js +2 -3
- package/dist/writers/web-fs.js +2 -2
- package/package.json +5 -5
package/dist/audio-decoder.js
CHANGED
|
@@ -18,8 +18,7 @@ const createAudioDecoder = ({ onFrame, onError, controller, config, logLevel, tr
|
|
|
18
18
|
let outputQueue = Promise.resolve();
|
|
19
19
|
const audioDecoder = new AudioDecoder({
|
|
20
20
|
output(frame) {
|
|
21
|
-
|
|
22
|
-
ioSynchronizer.onOutput(frame.timestamp + ((_a = frame.duration) !== null && _a !== void 0 ? _a : 0));
|
|
21
|
+
ioSynchronizer.onOutput(frame.timestamp + (frame.duration ?? 0));
|
|
23
22
|
const abortHandler = () => {
|
|
24
23
|
frame.close();
|
|
25
24
|
};
|
|
@@ -61,11 +60,10 @@ const createAudioDecoder = ({ onFrame, onError, controller, config, logLevel, tr
|
|
|
61
60
|
controller._internals.signal.addEventListener('abort', onAbort);
|
|
62
61
|
audioDecoder.configure(config);
|
|
63
62
|
const processSample = async (audioSample) => {
|
|
64
|
-
var _a, _b;
|
|
65
63
|
if (audioDecoder.state === 'closed') {
|
|
66
64
|
return;
|
|
67
65
|
}
|
|
68
|
-
progressTracker.setPossibleLowestTimestamp(Math.min(audioSample.timestamp,
|
|
66
|
+
progressTracker.setPossibleLowestTimestamp(Math.min(audioSample.timestamp, audioSample.dts ?? Infinity, audioSample.cts ?? Infinity));
|
|
69
67
|
await ioSynchronizer.waitFor({
|
|
70
68
|
unemitted: 20,
|
|
71
69
|
unprocessed: 20,
|
|
@@ -95,7 +93,7 @@ const createAudioDecoder = ({ onFrame, onError, controller, config, logLevel, tr
|
|
|
95
93
|
try {
|
|
96
94
|
await audioDecoder.flush();
|
|
97
95
|
}
|
|
98
|
-
catch
|
|
96
|
+
catch { }
|
|
99
97
|
await queue;
|
|
100
98
|
await ioSynchronizer.waitForFinish(controller);
|
|
101
99
|
await outputQueue;
|
|
@@ -8,7 +8,7 @@ const canReencodeVideoTrack = async ({ videoCodec, track, resizeOperation, rotat
|
|
|
8
8
|
const { height, width } = (0, rotation_1.calculateNewDimensionsFromRotateAndScale)({
|
|
9
9
|
height: track.displayAspectHeight,
|
|
10
10
|
resizeOperation,
|
|
11
|
-
rotation: rotate
|
|
11
|
+
rotation: rotate ?? 0,
|
|
12
12
|
videoCodec,
|
|
13
13
|
width: track.displayAspectWidth,
|
|
14
14
|
});
|
|
@@ -43,7 +43,7 @@ const chooseCorrectAvc1Profile = ({ width, height, fps, }) => {
|
|
|
43
43
|
return false;
|
|
44
44
|
}
|
|
45
45
|
// if has no fps, use 60 as a conservative fallback
|
|
46
|
-
const fallbackFps = fps
|
|
46
|
+
const fallbackFps = fps ?? 60;
|
|
47
47
|
return fallbackFps <= p.fps;
|
|
48
48
|
});
|
|
49
49
|
if (!profile) {
|
|
@@ -12,7 +12,7 @@ const chooseCorrectHevcProfile = ({ width, height, fps, }) => {
|
|
|
12
12
|
return false;
|
|
13
13
|
}
|
|
14
14
|
// if has no fps, use 60 as a conservative fallback
|
|
15
|
-
const fallbackFps = fps
|
|
15
|
+
const fallbackFps = fps ?? 60;
|
|
16
16
|
return fallbackFps <= max.fps;
|
|
17
17
|
});
|
|
18
18
|
});
|
|
@@ -2,12 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.convertEncodedChunk = void 0;
|
|
4
4
|
const convertEncodedChunk = (chunk, trackId) => {
|
|
5
|
-
var _a;
|
|
6
5
|
const arr = new Uint8Array(chunk.byteLength);
|
|
7
6
|
chunk.copyTo(arr);
|
|
8
7
|
return {
|
|
9
8
|
data: arr,
|
|
10
|
-
duration:
|
|
9
|
+
duration: chunk.duration ?? undefined,
|
|
11
10
|
timestamp: chunk.timestamp,
|
|
12
11
|
type: chunk.type,
|
|
13
12
|
cts: chunk.timestamp,
|
package/dist/convert-media.d.ts
CHANGED
|
@@ -35,7 +35,7 @@ export type ConvertMediaOnAudioData = (options: {
|
|
|
35
35
|
audioData: AudioData;
|
|
36
36
|
track: AudioTrack;
|
|
37
37
|
}) => Promise<AudioData> | AudioData;
|
|
38
|
-
export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, onM3uStreams, selectM3uStream, selectM3uAssociatedPlaylists, ...more }: {
|
|
38
|
+
export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller, onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel, writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, onM3uStreams, selectM3uStream, selectM3uAssociatedPlaylists, expectedDurationInSeconds, ...more }: {
|
|
39
39
|
src: ParseMediaOptions<F>["src"];
|
|
40
40
|
container: ConvertMediaContainer;
|
|
41
41
|
onVideoFrame?: ConvertMediaOnVideoFrame;
|
|
@@ -48,6 +48,7 @@ export declare const convertMedia: <F extends Options<ParseMediaFields>>({ src,
|
|
|
48
48
|
onVideoTrack?: ConvertMediaOnVideoTrackHandler;
|
|
49
49
|
selectM3uStream?: ParseMediaOptions<F>["selectM3uStream"];
|
|
50
50
|
selectM3uAssociatedPlaylists?: ParseMediaOptions<F>["selectM3uAssociatedPlaylists"];
|
|
51
|
+
expectedDurationInSeconds?: number | null;
|
|
51
52
|
reader?: ParseMediaOptions<F>["reader"];
|
|
52
53
|
logLevel?: LogLevel;
|
|
53
54
|
writer?: WriterInterface;
|
package/dist/convert-media.js
CHANGED
|
@@ -21,8 +21,7 @@ const select_container_creator_1 = require("./select-container-creator");
|
|
|
21
21
|
const send_telemetry_event_1 = require("./send-telemetry-event");
|
|
22
22
|
const throttled_state_update_1 = require("./throttled-state-update");
|
|
23
23
|
const webcodecs_controller_1 = require("./webcodecs-controller");
|
|
24
|
-
const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller = (0, webcodecs_controller_1.webcodecsController)(), onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, onM3uStreams, selectM3uStream, selectM3uAssociatedPlaylists, ...more }) {
|
|
25
|
-
var _a, _b;
|
|
24
|
+
const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgress: onProgressDoNotCallDirectly, audioCodec, container, videoCodec, controller = (0, webcodecs_controller_1.webcodecsController)(), onAudioTrack: userAudioResolver, onVideoTrack: userVideoResolver, reader, fields, logLevel = 'info', writer, progressIntervalInMs, rotate, apiKey, resize, onAudioCodec, onContainer, onDimensions, onDurationInSeconds, onFps, onImages, onInternalStats, onIsHdr, onKeyframes, onLocation, onMetadata, onMimeType, onName, onNumberOfAudioChannels, onRotation, onSampleRate, onSize, onSlowAudioBitrate, onSlowDurationInSeconds, onSlowFps, onSlowKeyframes, onSlowNumberOfFrames, onSlowVideoBitrate, onStructure, onTracks, onUnrotatedDimensions, onVideoCodec, onM3uStreams, selectM3uStream, selectM3uAssociatedPlaylists, expectedDurationInSeconds, ...more }) {
|
|
26
25
|
if (controller._internals.signal.aborted) {
|
|
27
26
|
return Promise.reject(new media_parser_1.MediaParserAbortError('Aborted'));
|
|
28
27
|
}
|
|
@@ -45,8 +44,8 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
45
44
|
controller._internals.signal.addEventListener('abort', onUserAbort);
|
|
46
45
|
const creator = (0, select_container_creator_1.selectContainerCreator)(container);
|
|
47
46
|
const throttledState = (0, throttled_state_update_1.throttledStateUpdate)({
|
|
48
|
-
updateFn: onProgressDoNotCallDirectly
|
|
49
|
-
everyMilliseconds: progressIntervalInMs
|
|
47
|
+
updateFn: onProgressDoNotCallDirectly ?? null,
|
|
48
|
+
everyMilliseconds: progressIntervalInMs ?? 100,
|
|
50
49
|
signal: controller._internals.signal,
|
|
51
50
|
});
|
|
52
51
|
const progressTracker = (0, progress_tracker_1.makeProgressTracker)();
|
|
@@ -54,8 +53,7 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
54
53
|
filename: (0, generate_output_filename_1.generateOutputFilename)(src, container),
|
|
55
54
|
writer: await (0, auto_select_writer_1.autoSelectWriter)(writer, logLevel),
|
|
56
55
|
onBytesProgress: (bytesWritten) => {
|
|
57
|
-
|
|
58
|
-
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
56
|
+
throttledState.update?.((prevState) => {
|
|
59
57
|
return {
|
|
60
58
|
...prevState,
|
|
61
59
|
bytesWritten,
|
|
@@ -63,8 +61,7 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
63
61
|
});
|
|
64
62
|
},
|
|
65
63
|
onMillisecondsProgress: (millisecondsWritten) => {
|
|
66
|
-
|
|
67
|
-
(_a = throttledState.update) === null || _a === void 0 ? void 0 : _a.call(throttledState, (prevState) => {
|
|
64
|
+
throttledState.update?.((prevState) => {
|
|
68
65
|
if (millisecondsWritten > prevState.millisecondsWritten) {
|
|
69
66
|
return {
|
|
70
67
|
...prevState,
|
|
@@ -80,32 +77,33 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
80
77
|
},
|
|
81
78
|
logLevel,
|
|
82
79
|
progressTracker,
|
|
80
|
+
expectedDurationInSeconds: expectedDurationInSeconds ?? null,
|
|
83
81
|
});
|
|
84
82
|
const onVideoTrack = (0, on_video_track_1.makeVideoTrackHandler)({
|
|
85
83
|
state,
|
|
86
|
-
onVideoFrame: onVideoFrame
|
|
87
|
-
onMediaStateUpdate:
|
|
84
|
+
onVideoFrame: onVideoFrame ?? null,
|
|
85
|
+
onMediaStateUpdate: throttledState.update ?? null,
|
|
88
86
|
abortConversion,
|
|
89
87
|
controller,
|
|
90
|
-
defaultVideoCodec: videoCodec
|
|
91
|
-
onVideoTrack: userVideoResolver
|
|
88
|
+
defaultVideoCodec: videoCodec ?? null,
|
|
89
|
+
onVideoTrack: userVideoResolver ?? null,
|
|
92
90
|
logLevel,
|
|
93
91
|
outputContainer: container,
|
|
94
|
-
rotate: rotate
|
|
92
|
+
rotate: rotate ?? 0,
|
|
95
93
|
progress: progressTracker,
|
|
96
|
-
resizeOperation: resize
|
|
94
|
+
resizeOperation: resize ?? null,
|
|
97
95
|
});
|
|
98
96
|
const onAudioTrack = (0, on_audio_track_1.makeAudioTrackHandler)({
|
|
99
97
|
abortConversion,
|
|
100
|
-
defaultAudioCodec: audioCodec
|
|
98
|
+
defaultAudioCodec: audioCodec ?? null,
|
|
101
99
|
controller,
|
|
102
|
-
onMediaStateUpdate:
|
|
100
|
+
onMediaStateUpdate: throttledState.update ?? null,
|
|
103
101
|
state,
|
|
104
|
-
onAudioTrack: userAudioResolver
|
|
102
|
+
onAudioTrack: userAudioResolver ?? null,
|
|
105
103
|
logLevel,
|
|
106
104
|
outputContainer: container,
|
|
107
105
|
progressTracker,
|
|
108
|
-
onAudioData: onAudioData
|
|
106
|
+
onAudioData: onAudioData ?? null,
|
|
109
107
|
});
|
|
110
108
|
media_parser_1.MediaParserInternals.internalParseMedia({
|
|
111
109
|
logLevel,
|
|
@@ -117,10 +115,9 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
117
115
|
...fields,
|
|
118
116
|
durationInSeconds: true,
|
|
119
117
|
},
|
|
120
|
-
reader: reader
|
|
118
|
+
reader: reader ?? web_1.webReader,
|
|
121
119
|
...more,
|
|
122
120
|
onDurationInSeconds: (durationInSeconds) => {
|
|
123
|
-
var _a;
|
|
124
121
|
if (durationInSeconds === null) {
|
|
125
122
|
return null;
|
|
126
123
|
}
|
|
@@ -129,7 +126,7 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
129
126
|
casted.onDurationInSeconds(durationInSeconds);
|
|
130
127
|
}
|
|
131
128
|
const expectedOutputDurationInMs = durationInSeconds * 1000;
|
|
132
|
-
|
|
129
|
+
throttledState.update?.((prevState) => {
|
|
133
130
|
return {
|
|
134
131
|
...prevState,
|
|
135
132
|
expectedOutputDurationInMs,
|
|
@@ -146,36 +143,36 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
146
143
|
onError: () => ({ action: 'fail' }),
|
|
147
144
|
onParseProgress: null,
|
|
148
145
|
progressIntervalInMs: null,
|
|
149
|
-
onAudioCodec: onAudioCodec
|
|
150
|
-
onContainer: onContainer
|
|
151
|
-
onDimensions: onDimensions
|
|
152
|
-
onFps: onFps
|
|
153
|
-
onImages: onImages
|
|
154
|
-
onInternalStats: onInternalStats
|
|
155
|
-
onIsHdr: onIsHdr
|
|
156
|
-
onKeyframes: onKeyframes
|
|
157
|
-
onLocation: onLocation
|
|
158
|
-
onMetadata: onMetadata
|
|
159
|
-
onMimeType: onMimeType
|
|
160
|
-
onName: onName
|
|
161
|
-
onNumberOfAudioChannels: onNumberOfAudioChannels
|
|
162
|
-
onRotation: onRotation
|
|
163
|
-
onSampleRate: onSampleRate
|
|
164
|
-
onSize: onSize
|
|
165
|
-
onSlowAudioBitrate: onSlowAudioBitrate
|
|
166
|
-
onSlowDurationInSeconds: onSlowDurationInSeconds
|
|
167
|
-
onSlowFps: onSlowFps
|
|
168
|
-
onSlowKeyframes: onSlowKeyframes
|
|
169
|
-
onSlowNumberOfFrames: onSlowNumberOfFrames
|
|
170
|
-
onSlowVideoBitrate: onSlowVideoBitrate
|
|
171
|
-
onStructure: onStructure
|
|
172
|
-
onTracks: onTracks
|
|
173
|
-
onUnrotatedDimensions: onUnrotatedDimensions
|
|
174
|
-
onVideoCodec: onVideoCodec
|
|
146
|
+
onAudioCodec: onAudioCodec ?? null,
|
|
147
|
+
onContainer: onContainer ?? null,
|
|
148
|
+
onDimensions: onDimensions ?? null,
|
|
149
|
+
onFps: onFps ?? null,
|
|
150
|
+
onImages: onImages ?? null,
|
|
151
|
+
onInternalStats: onInternalStats ?? null,
|
|
152
|
+
onIsHdr: onIsHdr ?? null,
|
|
153
|
+
onKeyframes: onKeyframes ?? null,
|
|
154
|
+
onLocation: onLocation ?? null,
|
|
155
|
+
onMetadata: onMetadata ?? null,
|
|
156
|
+
onMimeType: onMimeType ?? null,
|
|
157
|
+
onName: onName ?? null,
|
|
158
|
+
onNumberOfAudioChannels: onNumberOfAudioChannels ?? null,
|
|
159
|
+
onRotation: onRotation ?? null,
|
|
160
|
+
onSampleRate: onSampleRate ?? null,
|
|
161
|
+
onSize: onSize ?? null,
|
|
162
|
+
onSlowAudioBitrate: onSlowAudioBitrate ?? null,
|
|
163
|
+
onSlowDurationInSeconds: onSlowDurationInSeconds ?? null,
|
|
164
|
+
onSlowFps: onSlowFps ?? null,
|
|
165
|
+
onSlowKeyframes: onSlowKeyframes ?? null,
|
|
166
|
+
onSlowNumberOfFrames: onSlowNumberOfFrames ?? null,
|
|
167
|
+
onSlowVideoBitrate: onSlowVideoBitrate ?? null,
|
|
168
|
+
onStructure: onStructure ?? null,
|
|
169
|
+
onTracks: onTracks ?? null,
|
|
170
|
+
onUnrotatedDimensions: onUnrotatedDimensions ?? null,
|
|
171
|
+
onVideoCodec: onVideoCodec ?? null,
|
|
175
172
|
apiName: 'convertMedia()',
|
|
176
|
-
onM3uStreams: onM3uStreams
|
|
177
|
-
selectM3uStream: selectM3uStream
|
|
178
|
-
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylists
|
|
173
|
+
onM3uStreams: onM3uStreams ?? null,
|
|
174
|
+
selectM3uStream: selectM3uStream ?? media_parser_1.defaultSelectM3uStreamFn,
|
|
175
|
+
selectM3uAssociatedPlaylists: selectM3uAssociatedPlaylists ?? media_parser_1.defaultSelectM3uAssociatedPlaylists,
|
|
179
176
|
mp4HeaderSegment: null,
|
|
180
177
|
})
|
|
181
178
|
.then(() => {
|
|
@@ -189,12 +186,12 @@ const convertMedia = async function ({ src, onVideoFrame, onAudioData, onProgres
|
|
|
189
186
|
});
|
|
190
187
|
})
|
|
191
188
|
.then(() => {
|
|
192
|
-
(0, send_telemetry_event_1.sendUsageEvent)({ succeeded: true, apiKey: apiKey
|
|
189
|
+
(0, send_telemetry_event_1.sendUsageEvent)({ succeeded: true, apiKey: apiKey ?? null }).catch((err) => {
|
|
193
190
|
log_1.Log.error('Failed to send usage event', err);
|
|
194
191
|
});
|
|
195
192
|
})
|
|
196
193
|
.catch((err) => {
|
|
197
|
-
(0, send_telemetry_event_1.sendUsageEvent)({ succeeded: false, apiKey: apiKey
|
|
194
|
+
(0, send_telemetry_event_1.sendUsageEvent)({ succeeded: false, apiKey: apiKey ?? null }).catch((err2) => {
|
|
198
195
|
log_1.Log.error('Failed to send usage event', err2);
|
|
199
196
|
});
|
|
200
197
|
reject(err);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { MediaFn, MediaFnGeneratorInput } from '../media-fn';
|
|
2
|
-
export declare const createIsoBaseMedia: ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, }: MediaFnGeneratorInput) => Promise<MediaFn>;
|
|
2
|
+
export declare const createIsoBaseMedia: ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, }: MediaFnGeneratorInput) => Promise<MediaFn>;
|
|
@@ -7,7 +7,7 @@ const create_ftyp_1 = require("./create-ftyp");
|
|
|
7
7
|
const mp4_header_1 = require("./mp4-header");
|
|
8
8
|
const primitives_1 = require("./primitives");
|
|
9
9
|
const CONTAINER_TIMESCALE = 1000;
|
|
10
|
-
const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, }) => {
|
|
10
|
+
const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, }) => {
|
|
11
11
|
const header = (0, create_ftyp_1.createIsoBaseMediaFtyp)({
|
|
12
12
|
compatibleBrands: ['isom', 'iso2', 'avc1', 'mp42'],
|
|
13
13
|
majorBrand: 'isom',
|
|
@@ -30,15 +30,16 @@ const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgr
|
|
|
30
30
|
return (0, mp4_header_1.createPaddedMoovAtom)({
|
|
31
31
|
durationInUnits: globalDurationInUnits,
|
|
32
32
|
trackInfo: currentTracks.map((track) => {
|
|
33
|
-
var _a, _b;
|
|
34
33
|
return {
|
|
35
34
|
track,
|
|
36
|
-
durationInUnits:
|
|
37
|
-
samplePositions:
|
|
35
|
+
durationInUnits: trackDurations[track.trackNumber] ?? 0,
|
|
36
|
+
samplePositions: samplePositions[track.trackNumber] ?? [],
|
|
38
37
|
timescale: track.timescale,
|
|
39
38
|
};
|
|
40
39
|
}),
|
|
41
40
|
timescale: CONTAINER_TIMESCALE,
|
|
41
|
+
expectedDurationInSeconds,
|
|
42
|
+
logLevel,
|
|
42
43
|
});
|
|
43
44
|
};
|
|
44
45
|
await w.write(getPaddedMoovAtom());
|
|
@@ -68,12 +69,11 @@ const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgr
|
|
|
68
69
|
};
|
|
69
70
|
let lastChunkWasVideo = false;
|
|
70
71
|
const addSample = async ({ chunk, trackNumber, isVideo, codecPrivate, }) => {
|
|
71
|
-
var _a, _b, _c, _d;
|
|
72
72
|
const position = w.getWrittenByteCount();
|
|
73
73
|
await w.write(chunk.data);
|
|
74
74
|
mdatSize += chunk.data.length;
|
|
75
75
|
onBytesProgress(w.getWrittenByteCount());
|
|
76
|
-
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp,
|
|
76
|
+
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp, chunk.cts ?? Infinity, chunk.dts ?? Infinity));
|
|
77
77
|
progressTracker.updateTrackProgress(trackNumber, chunk.timestamp);
|
|
78
78
|
if (codecPrivate) {
|
|
79
79
|
addCodecPrivateToTrack({ trackNumber, codecPrivate });
|
|
@@ -90,7 +90,7 @@ const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgr
|
|
|
90
90
|
throw new Error(`Tried to add sample to track ${trackNumber}, but it has no timestamp`);
|
|
91
91
|
}
|
|
92
92
|
const newDurationInMicroSeconds = chunk.timestamp +
|
|
93
|
-
(
|
|
93
|
+
(chunk.duration ?? 0) -
|
|
94
94
|
lowestTrackTimestamps[trackNumber];
|
|
95
95
|
const newDurationInTrackTimeUnits = Math.round(newDurationInMicroSeconds / (1000000 / currentTrack.timescale));
|
|
96
96
|
trackDurations[trackNumber] = newDurationInTrackTimeUnits;
|
|
@@ -125,7 +125,7 @@ const createIsoBaseMedia = async ({ writer, onBytesProgress, onMillisecondsProgr
|
|
|
125
125
|
chunk: sampleChunkIndices[trackNumber],
|
|
126
126
|
cts: Math.round((chunk.cts / 1000000) * currentTrack.timescale),
|
|
127
127
|
dts: Math.round((chunk.dts / 1000000) * currentTrack.timescale),
|
|
128
|
-
duration: Math.round(((
|
|
128
|
+
duration: Math.round(((chunk.duration ?? 0) / 1000000) * currentTrack.timescale),
|
|
129
129
|
size: chunk.data.length,
|
|
130
130
|
};
|
|
131
131
|
lastChunkWasVideo = isVideo;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const calculateAReasonableMp4HeaderLength: (expectedDurationInSeconds: number | null) => number;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.calculateAReasonableMp4HeaderLength = void 0;
|
|
4
|
+
const calculateAReasonableMp4HeaderLength = (expectedDurationInSeconds) => {
|
|
5
|
+
if (expectedDurationInSeconds === null) {
|
|
6
|
+
return 2048000;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* we had a video that was 1 hour 40 minutes long and the header ended up being 3.7MB. the header approximately grows linearly to the video length in seconds, but we should reserve enough, like at least 50KB in any case.
|
|
10
|
+
* it's better to be safe than to fail, so let's add a 30% safety margin
|
|
11
|
+
*/
|
|
12
|
+
// 1h40m = 6000 seconds resulted in 3.7MB header
|
|
13
|
+
// So bytes per second = 3.7MB / 6000 = ~616 bytes/second
|
|
14
|
+
const bytesPerSecond = (3.7 * 1024 * 1024) / 6000;
|
|
15
|
+
// Add 20% safety margin
|
|
16
|
+
const bytesWithSafetyMargin = bytesPerSecond * 1.2;
|
|
17
|
+
// Calculate based on duration, with minimum 50KB
|
|
18
|
+
const calculatedBytes = Math.max(50 * 1024, Math.ceil(expectedDurationInSeconds * bytesWithSafetyMargin));
|
|
19
|
+
return calculatedBytes;
|
|
20
|
+
};
|
|
21
|
+
exports.calculateAReasonableMp4HeaderLength = calculateAReasonableMp4HeaderLength;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import type { LogLevel } from '@remotion/media-parser';
|
|
1
2
|
import type { IsoBaseMediaTrackData } from './serialize-track';
|
|
2
|
-
export declare const createPaddedMoovAtom: ({ durationInUnits, trackInfo, timescale, }: {
|
|
3
|
+
export declare const createPaddedMoovAtom: ({ durationInUnits, trackInfo, timescale, expectedDurationInSeconds, logLevel, }: {
|
|
3
4
|
durationInUnits: number;
|
|
4
5
|
trackInfo: IsoBaseMediaTrackData[];
|
|
5
6
|
timescale: number;
|
|
7
|
+
expectedDurationInSeconds: number | null;
|
|
8
|
+
logLevel: LogLevel;
|
|
6
9
|
}) => Uint8Array;
|
|
@@ -2,19 +2,26 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.createPaddedMoovAtom = void 0;
|
|
4
4
|
const media_parser_1 = require("@remotion/media-parser");
|
|
5
|
+
const log_1 = require("../../log");
|
|
5
6
|
const create_ilst_1 = require("./create-ilst");
|
|
6
7
|
const create_moov_1 = require("./create-moov");
|
|
7
8
|
const create_mvhd_1 = require("./create-mvhd");
|
|
8
9
|
const create_udta_1 = require("./create-udta");
|
|
10
|
+
const header_length_1 = require("./header-length");
|
|
9
11
|
const create_cmt_1 = require("./ilst/create-cmt");
|
|
10
12
|
const create_too_1 = require("./ilst/create-too");
|
|
11
13
|
const primitives_1 = require("./primitives");
|
|
12
14
|
const serialize_track_1 = require("./serialize-track");
|
|
13
15
|
const create_meta_1 = require("./udta/create-meta");
|
|
14
16
|
const create_hdlr_1 = require("./udta/meta/create-hdlr");
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
17
|
+
const createPaddedMoovAtom = ({ durationInUnits, trackInfo, timescale, expectedDurationInSeconds, logLevel, }) => {
|
|
18
|
+
const headerLength = (0, header_length_1.calculateAReasonableMp4HeaderLength)(expectedDurationInSeconds);
|
|
19
|
+
if (expectedDurationInSeconds !== null) {
|
|
20
|
+
log_1.Log.verbose(logLevel, `Expecting duration of the video to be ${expectedDurationInSeconds} seconds, allocating ${headerLength} bytes for the MP4 header.`);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
log_1.Log.verbose(logLevel, `No duration was provided, allocating ${headerLength} bytes for the MP4 header.`);
|
|
24
|
+
}
|
|
18
25
|
return (0, primitives_1.padIsoBaseMediaBytes)((0, create_moov_1.createMoov)({
|
|
19
26
|
mvhd: (0, create_mvhd_1.createMvhd)({
|
|
20
27
|
timescale,
|
|
@@ -43,6 +50,6 @@ const createPaddedMoovAtom = ({ durationInUnits, trackInfo, timescale, }) => {
|
|
|
43
50
|
(0, create_cmt_1.createCmt)(`Made with @remotion/webcodecs ${media_parser_1.VERSION}`),
|
|
44
51
|
]),
|
|
45
52
|
})),
|
|
46
|
-
}),
|
|
53
|
+
}), headerLength);
|
|
47
54
|
};
|
|
48
55
|
exports.createPaddedMoovAtom = createPaddedMoovAtom;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const stringsToUint8Array: (str: string) => Uint8Array;
|
|
2
2
|
export declare const numberTo32BitUIntOrInt: (num: number) => Uint8Array;
|
|
3
|
+
export declare const numberTo64BitUIntOrInt: (num: number | bigint) => Uint8Array;
|
|
3
4
|
export declare const numberTo32BitUIntOrIntLeading128: (num: number) => Uint8Array;
|
|
4
5
|
export declare const numberTo16BitUIntOrInt: (num: number) => Uint8Array;
|
|
5
6
|
export declare const setFixedPointSignedOrUnsigned1616Number: (num: number) => Uint8Array;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.IDENTITY_MATRIX = exports.padIsoBaseMediaBytes = exports.stringToPascalString = exports.serializeMatrix = exports.floatTo16Point16_16Bit = exports.floatTo16Point1632Bit = exports.addLeading128Size = exports.addSize = exports.setFixedPointSigned230Number = exports.setFixedPointSignedOrUnsigned1616Number = exports.numberTo16BitUIntOrInt = exports.numberTo32BitUIntOrIntLeading128 = exports.numberTo32BitUIntOrInt = exports.stringsToUint8Array = void 0;
|
|
3
|
+
exports.IDENTITY_MATRIX = exports.padIsoBaseMediaBytes = exports.stringToPascalString = exports.serializeMatrix = exports.floatTo16Point16_16Bit = exports.floatTo16Point1632Bit = exports.addLeading128Size = exports.addSize = exports.setFixedPointSigned230Number = exports.setFixedPointSignedOrUnsigned1616Number = exports.numberTo16BitUIntOrInt = exports.numberTo32BitUIntOrIntLeading128 = exports.numberTo64BitUIntOrInt = exports.numberTo32BitUIntOrInt = exports.stringsToUint8Array = void 0;
|
|
4
4
|
const matroska_utils_1 = require("../matroska/matroska-utils");
|
|
5
5
|
const stringsToUint8Array = (str) => {
|
|
6
6
|
return new TextEncoder().encode(str);
|
|
@@ -15,6 +15,20 @@ const numberTo32BitUIntOrInt = (num) => {
|
|
|
15
15
|
]);
|
|
16
16
|
};
|
|
17
17
|
exports.numberTo32BitUIntOrInt = numberTo32BitUIntOrInt;
|
|
18
|
+
const numberTo64BitUIntOrInt = (num) => {
|
|
19
|
+
const bigNum = BigInt(num);
|
|
20
|
+
return new Uint8Array([
|
|
21
|
+
Number((bigNum >> 56n) & 0xffn),
|
|
22
|
+
Number((bigNum >> 48n) & 0xffn),
|
|
23
|
+
Number((bigNum >> 40n) & 0xffn),
|
|
24
|
+
Number((bigNum >> 32n) & 0xffn),
|
|
25
|
+
Number((bigNum >> 24n) & 0xffn),
|
|
26
|
+
Number((bigNum >> 16n) & 0xffn),
|
|
27
|
+
Number((bigNum >> 8n) & 0xffn),
|
|
28
|
+
Number(bigNum & 0xffn),
|
|
29
|
+
]);
|
|
30
|
+
};
|
|
31
|
+
exports.numberTo64BitUIntOrInt = numberTo64BitUIntOrInt;
|
|
18
32
|
const numberTo32BitUIntOrIntLeading128 = (num) => {
|
|
19
33
|
const arr = [
|
|
20
34
|
(num >> 24) & 0xff,
|
|
@@ -116,7 +130,7 @@ const stringToPascalString = (str) => {
|
|
|
116
130
|
exports.stringToPascalString = stringToPascalString;
|
|
117
131
|
const padIsoBaseMediaBytes = (data, totalLength) => {
|
|
118
132
|
if (data.length - 8 > totalLength) {
|
|
119
|
-
throw new Error(`Data is longer than the total length: ${data.length - 8} > ${totalLength}`);
|
|
133
|
+
throw new Error(`Data is longer than the total length: ${data.length - 8} > ${totalLength}. Set the 'expectedDurationInSeconds' value to avoid this problem: https://www.remotion.dev/docs/webcodecs/convert-media#expecteddurationinseconds`);
|
|
120
134
|
}
|
|
121
135
|
if (data.length - 8 === totalLength) {
|
|
122
136
|
return data;
|
|
@@ -6,15 +6,19 @@ const primitives_1 = require("../../../../primitives");
|
|
|
6
6
|
const createStcoAtom = (samplePositions) => {
|
|
7
7
|
const chunkOffsets = [];
|
|
8
8
|
let lastChunk;
|
|
9
|
+
let needs64Bit = false;
|
|
9
10
|
for (const sample of samplePositions) {
|
|
10
11
|
if (lastChunk !== sample.chunk) {
|
|
11
12
|
chunkOffsets.push(sample.offset);
|
|
12
13
|
}
|
|
14
|
+
if (sample.offset > 2 ** 32) {
|
|
15
|
+
needs64Bit = true;
|
|
16
|
+
}
|
|
13
17
|
lastChunk = sample.chunk;
|
|
14
18
|
}
|
|
15
19
|
return (0, primitives_1.addSize)((0, matroska_utils_1.combineUint8Arrays)([
|
|
16
20
|
// type
|
|
17
|
-
(0, primitives_1.stringsToUint8Array)('stco'),
|
|
21
|
+
(0, primitives_1.stringsToUint8Array)(needs64Bit ? 'co64' : 'stco'),
|
|
18
22
|
// version
|
|
19
23
|
new Uint8Array([0]),
|
|
20
24
|
// flags
|
|
@@ -22,7 +26,9 @@ const createStcoAtom = (samplePositions) => {
|
|
|
22
26
|
// number of entries
|
|
23
27
|
(0, primitives_1.numberTo32BitUIntOrInt)(chunkOffsets.length),
|
|
24
28
|
// chunk offsets
|
|
25
|
-
|
|
29
|
+
(0, matroska_utils_1.combineUint8Arrays)(chunkOffsets.map((offset) => needs64Bit
|
|
30
|
+
? (0, primitives_1.numberTo64BitUIntOrInt)(offset)
|
|
31
|
+
: (0, primitives_1.numberTo32BitUIntOrInt)(offset))),
|
|
26
32
|
]));
|
|
27
33
|
};
|
|
28
34
|
exports.createStcoAtom = createStcoAtom;
|
|
@@ -15,11 +15,10 @@ const makeEntry = (entry) => {
|
|
|
15
15
|
const createSttsAtom = (samplePositions) => {
|
|
16
16
|
let lastDuration = null;
|
|
17
17
|
const durations = samplePositions.map((_, i, a) => {
|
|
18
|
-
var _a, _b;
|
|
19
18
|
// TODO: Why does 0 appear here?
|
|
20
19
|
if (a[i].duration === undefined || a[i].duration === 0) {
|
|
21
20
|
if (a[i + 1] === undefined) {
|
|
22
|
-
return a[i].dts - (
|
|
21
|
+
return a[i].dts - (a[i - 1]?.dts ?? a[i].dts);
|
|
23
22
|
}
|
|
24
23
|
return a[i + 1].dts - a[i].dts;
|
|
25
24
|
}
|
|
@@ -14,7 +14,6 @@ const matroska_utils_1 = require("./matroska-utils");
|
|
|
14
14
|
const { matroskaElements } = media_parser_1.MediaParserInternals;
|
|
15
15
|
const timescale = 1000000;
|
|
16
16
|
const createMatroskaMedia = async ({ writer, onBytesProgress, onMillisecondsProgress, filename, logLevel, progressTracker, }) => {
|
|
17
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
18
17
|
const header = (0, matroska_header_1.makeMatroskaHeader)();
|
|
19
18
|
const w = await writer.createContent({
|
|
20
19
|
filename,
|
|
@@ -35,11 +34,13 @@ const createMatroskaMedia = async ({ writer, onBytesProgress, onMillisecondsProg
|
|
|
35
34
|
...(0, matroska_trackentry_1.makeMatroskaTracks)(currentTracks),
|
|
36
35
|
]);
|
|
37
36
|
const infoSegment = matroskaSegment.offsets.children.find((o) => o.field === 'Info');
|
|
38
|
-
const durationOffset = (
|
|
37
|
+
const durationOffset = (infoSegment?.children.find((c) => c.field === 'Duration')?.offset ?? 0) +
|
|
39
38
|
w.getWrittenByteCount();
|
|
40
|
-
const tracksOffset = (
|
|
41
|
-
|
|
42
|
-
const
|
|
39
|
+
const tracksOffset = (matroskaSegment.offsets.children.find((o) => o.field === 'Tracks')
|
|
40
|
+
?.offset ?? 0) + w.getWrittenByteCount();
|
|
41
|
+
const seekHeadOffset = (matroskaSegment.offsets.children.find((o) => o.field === 'SeekHead')
|
|
42
|
+
?.offset ?? 0) + w.getWrittenByteCount();
|
|
43
|
+
const infoOffset = (infoSegment?.offset ?? 0) + w.getWrittenByteCount();
|
|
43
44
|
if (!seekHeadOffset) {
|
|
44
45
|
throw new Error('could not get seek offset');
|
|
45
46
|
}
|
|
@@ -87,8 +88,7 @@ const createMatroskaMedia = async ({ writer, onBytesProgress, onMillisecondsProg
|
|
|
87
88
|
// In Safari, samples can arrive out of order, e.g public/bigbuckbunny.mp4
|
|
88
89
|
// Therefore, only updating track number progress if it is a keyframe
|
|
89
90
|
// to allow for timestamps to be lower than the previous one
|
|
90
|
-
|
|
91
|
-
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp, (_a = chunk.cts) !== null && _a !== void 0 ? _a : Infinity, (_b = chunk.dts) !== null && _b !== void 0 ? _b : Infinity));
|
|
91
|
+
progressTracker.setPossibleLowestTimestamp(Math.min(chunk.timestamp, chunk.cts ?? Infinity, chunk.dts ?? Infinity));
|
|
92
92
|
const smallestProgress = progressTracker.getSmallestProgress();
|
|
93
93
|
if (!currentCluster.shouldMakeNewCluster({
|
|
94
94
|
newT: smallestProgress,
|
|
@@ -111,12 +111,11 @@ const createMatroskaMedia = async ({ writer, onBytesProgress, onMillisecondsProg
|
|
|
111
111
|
onBytesProgress(w.getWrittenByteCount());
|
|
112
112
|
};
|
|
113
113
|
const addSample = async ({ chunk, trackNumber, isVideo, }) => {
|
|
114
|
-
var _a;
|
|
115
114
|
const { cluster, isNew, smallestProgress } = await getClusterOrMakeNew({
|
|
116
115
|
chunk,
|
|
117
116
|
isVideo,
|
|
118
117
|
});
|
|
119
|
-
const newDuration = Math.round((chunk.timestamp + (
|
|
118
|
+
const newDuration = Math.round((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
120
119
|
await updateDuration(newDuration);
|
|
121
120
|
const { timecodeRelativeToCluster } = await cluster.addSample(chunk, trackNumber);
|
|
122
121
|
if (isNew) {
|
|
@@ -4,8 +4,7 @@ exports.padMatroskaBytes = exports.makeMatroskaBytes = exports.getVariableInt =
|
|
|
4
4
|
exports.serializeUint16 = serializeUint16;
|
|
5
5
|
const media_parser_1 = require("@remotion/media-parser");
|
|
6
6
|
const getIdForName = (name) => {
|
|
7
|
-
|
|
8
|
-
const value = (_a = Object.entries(media_parser_1.MediaParserInternals.matroskaElements).find(([key]) => key === name)) === null || _a === void 0 ? void 0 : _a[1];
|
|
7
|
+
const value = Object.entries(media_parser_1.MediaParserInternals.matroskaElements).find(([key]) => key === name)?.[1];
|
|
9
8
|
if (!value) {
|
|
10
9
|
throw new Error(`Could not find id for name ${name}`);
|
|
11
10
|
}
|
|
@@ -17,7 +16,7 @@ function putUintDynamic(number, minimumLength) {
|
|
|
17
16
|
throw new Error('This function is designed for non-negative integers only.');
|
|
18
17
|
}
|
|
19
18
|
// Calculate the minimum number of bytes needed to store the integer
|
|
20
|
-
const length = Math.max(minimumLength
|
|
19
|
+
const length = Math.max(minimumLength ?? 0, Math.ceil(Math.log2(number + 1) / 8));
|
|
21
20
|
const bytes = new Uint8Array(length);
|
|
22
21
|
for (let i = 0; i < length; i++) {
|
|
23
22
|
// Extract each byte from the number
|
|
@@ -179,7 +178,7 @@ const measureEBMLVarInt = (value) => {
|
|
|
179
178
|
};
|
|
180
179
|
exports.measureEBMLVarInt = measureEBMLVarInt;
|
|
181
180
|
const getVariableInt = (value, minWidth) => {
|
|
182
|
-
const width = Math.max((0, exports.measureEBMLVarInt)(value), minWidth
|
|
181
|
+
const width = Math.max((0, exports.measureEBMLVarInt)(value), minWidth ?? 0);
|
|
183
182
|
switch (width) {
|
|
184
183
|
case 1:
|
|
185
184
|
return new Uint8Array([(1 << 7) | value]);
|
|
@@ -60,10 +60,9 @@ const createWav = async ({ filename, logLevel, onBytesProgress, onMillisecondsPr
|
|
|
60
60
|
await w.updateDataAt(blockAlignPosition, new Uint8Array(numberTo16BitLittleEndian(numberOfChannels * BYTES_PER_SAMPLE)));
|
|
61
61
|
};
|
|
62
62
|
const addSample = async (chunk) => {
|
|
63
|
-
var _a;
|
|
64
63
|
log_1.Log.trace(logLevel, 'Adding sample', chunk);
|
|
65
64
|
await w.write(chunk.data);
|
|
66
|
-
onMillisecondsProgress((chunk.timestamp + (
|
|
65
|
+
onMillisecondsProgress((chunk.timestamp + (chunk.duration ?? 0)) / 1000);
|
|
67
66
|
onBytesProgress(w.getWrittenByteCount());
|
|
68
67
|
};
|
|
69
68
|
const waitForFinishPromises = [];
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1753,7 +1753,7 @@ var makeAudioTrackHandler = ({
|
|
|
1753
1753
|
});
|
|
1754
1754
|
},
|
|
1755
1755
|
onError: (err) => {
|
|
1756
|
-
abortConversion(new Error(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
|
|
1756
|
+
abortConversion(new Error(`Audio encoder of track ${track.trackId} failed (see .cause of this error)`, {
|
|
1757
1757
|
cause: err
|
|
1758
1758
|
}));
|
|
1759
1759
|
},
|
|
@@ -2659,6 +2659,19 @@ var numberTo32BitUIntOrInt = (num) => {
|
|
|
2659
2659
|
num & 255
|
|
2660
2660
|
]);
|
|
2661
2661
|
};
|
|
2662
|
+
var numberTo64BitUIntOrInt = (num) => {
|
|
2663
|
+
const bigNum = BigInt(num);
|
|
2664
|
+
return new Uint8Array([
|
|
2665
|
+
Number(bigNum >> 56n & 0xffn),
|
|
2666
|
+
Number(bigNum >> 48n & 0xffn),
|
|
2667
|
+
Number(bigNum >> 40n & 0xffn),
|
|
2668
|
+
Number(bigNum >> 32n & 0xffn),
|
|
2669
|
+
Number(bigNum >> 24n & 0xffn),
|
|
2670
|
+
Number(bigNum >> 16n & 0xffn),
|
|
2671
|
+
Number(bigNum >> 8n & 0xffn),
|
|
2672
|
+
Number(bigNum & 0xffn)
|
|
2673
|
+
]);
|
|
2674
|
+
};
|
|
2662
2675
|
var numberTo32BitUIntOrIntLeading128 = (num) => {
|
|
2663
2676
|
const arr = [
|
|
2664
2677
|
num >> 24 & 255,
|
|
@@ -2739,7 +2752,7 @@ var stringToPascalString = (str) => {
|
|
|
2739
2752
|
};
|
|
2740
2753
|
var padIsoBaseMediaBytes = (data, totalLength) => {
|
|
2741
2754
|
if (data.length - 8 > totalLength) {
|
|
2742
|
-
throw new Error(`Data is longer than the total length: ${data.length - 8} > ${totalLength}`);
|
|
2755
|
+
throw new Error(`Data is longer than the total length: ${data.length - 8} > ${totalLength}. Set the 'expectedDurationInSeconds' value to avoid this problem: https://www.remotion.dev/docs/webcodecs/convert-media#expecteddurationinseconds`);
|
|
2743
2756
|
}
|
|
2744
2757
|
if (data.length - 8 === totalLength) {
|
|
2745
2758
|
return data;
|
|
@@ -2855,6 +2868,17 @@ var createUdta = (children) => {
|
|
|
2855
2868
|
]));
|
|
2856
2869
|
};
|
|
2857
2870
|
|
|
2871
|
+
// src/create/iso-base-media/header-length.ts
|
|
2872
|
+
var calculateAReasonableMp4HeaderLength = (expectedDurationInSeconds) => {
|
|
2873
|
+
if (expectedDurationInSeconds === null) {
|
|
2874
|
+
return 2048000;
|
|
2875
|
+
}
|
|
2876
|
+
const bytesPerSecond = 3.7 * 1024 * 1024 / 6000;
|
|
2877
|
+
const bytesWithSafetyMargin = bytesPerSecond * 1.2;
|
|
2878
|
+
const calculatedBytes = Math.max(50 * 1024, Math.ceil(expectedDurationInSeconds * bytesWithSafetyMargin));
|
|
2879
|
+
return calculatedBytes;
|
|
2880
|
+
};
|
|
2881
|
+
|
|
2858
2882
|
// src/create/iso-base-media/ilst/create-cmt.ts
|
|
2859
2883
|
var createCmt = (comment) => {
|
|
2860
2884
|
return addSize(combineUint8Arrays([
|
|
@@ -3279,18 +3303,22 @@ var createCttsBox = (samplePositions) => {
|
|
|
3279
3303
|
var createStcoAtom = (samplePositions) => {
|
|
3280
3304
|
const chunkOffsets = [];
|
|
3281
3305
|
let lastChunk;
|
|
3306
|
+
let needs64Bit = false;
|
|
3282
3307
|
for (const sample of samplePositions) {
|
|
3283
3308
|
if (lastChunk !== sample.chunk) {
|
|
3284
3309
|
chunkOffsets.push(sample.offset);
|
|
3285
3310
|
}
|
|
3311
|
+
if (sample.offset > 2 ** 32) {
|
|
3312
|
+
needs64Bit = true;
|
|
3313
|
+
}
|
|
3286
3314
|
lastChunk = sample.chunk;
|
|
3287
3315
|
}
|
|
3288
3316
|
return addSize(combineUint8Arrays([
|
|
3289
|
-
stringsToUint8Array("stco"),
|
|
3317
|
+
stringsToUint8Array(needs64Bit ? "co64" : "stco"),
|
|
3290
3318
|
new Uint8Array([0]),
|
|
3291
3319
|
new Uint8Array([0, 0, 0]),
|
|
3292
3320
|
numberTo32BitUIntOrInt(chunkOffsets.length),
|
|
3293
|
-
|
|
3321
|
+
combineUint8Arrays(chunkOffsets.map((offset) => needs64Bit ? numberTo64BitUIntOrInt(offset) : numberTo32BitUIntOrInt(offset)))
|
|
3294
3322
|
]));
|
|
3295
3323
|
};
|
|
3296
3324
|
|
|
@@ -3581,12 +3609,19 @@ var createMeta = ({
|
|
|
3581
3609
|
};
|
|
3582
3610
|
|
|
3583
3611
|
// src/create/iso-base-media/mp4-header.ts
|
|
3584
|
-
var HEADER_LENGTH = 2048000;
|
|
3585
3612
|
var createPaddedMoovAtom = ({
|
|
3586
3613
|
durationInUnits,
|
|
3587
3614
|
trackInfo,
|
|
3588
|
-
timescale
|
|
3615
|
+
timescale,
|
|
3616
|
+
expectedDurationInSeconds,
|
|
3617
|
+
logLevel
|
|
3589
3618
|
}) => {
|
|
3619
|
+
const headerLength = calculateAReasonableMp4HeaderLength(expectedDurationInSeconds);
|
|
3620
|
+
if (expectedDurationInSeconds !== null) {
|
|
3621
|
+
Log.verbose(logLevel, `Expecting duration of the video to be ${expectedDurationInSeconds} seconds, allocating ${headerLength} bytes for the MP4 header.`);
|
|
3622
|
+
} else {
|
|
3623
|
+
Log.verbose(logLevel, `No duration was provided, allocating ${headerLength} bytes for the MP4 header.`);
|
|
3624
|
+
}
|
|
3590
3625
|
return padIsoBaseMediaBytes(createMoov({
|
|
3591
3626
|
mvhd: createMvhd({
|
|
3592
3627
|
timescale,
|
|
@@ -3613,7 +3648,7 @@ var createPaddedMoovAtom = ({
|
|
|
3613
3648
|
createCmt(`Made with @remotion/webcodecs ${VERSION2}`)
|
|
3614
3649
|
])
|
|
3615
3650
|
}))
|
|
3616
|
-
}),
|
|
3651
|
+
}), headerLength);
|
|
3617
3652
|
};
|
|
3618
3653
|
|
|
3619
3654
|
// src/create/iso-base-media/create-iso-base-media.ts
|
|
@@ -3624,7 +3659,8 @@ var createIsoBaseMedia = async ({
|
|
|
3624
3659
|
onMillisecondsProgress,
|
|
3625
3660
|
logLevel,
|
|
3626
3661
|
filename,
|
|
3627
|
-
progressTracker
|
|
3662
|
+
progressTracker,
|
|
3663
|
+
expectedDurationInSeconds
|
|
3628
3664
|
}) => {
|
|
3629
3665
|
const header = createIsoBaseMediaFtyp({
|
|
3630
3666
|
compatibleBrands: ["isom", "iso2", "avc1", "mp42"],
|
|
@@ -3655,7 +3691,9 @@ var createIsoBaseMedia = async ({
|
|
|
3655
3691
|
timescale: track.timescale
|
|
3656
3692
|
};
|
|
3657
3693
|
}),
|
|
3658
|
-
timescale: CONTAINER_TIMESCALE
|
|
3694
|
+
timescale: CONTAINER_TIMESCALE,
|
|
3695
|
+
expectedDurationInSeconds,
|
|
3696
|
+
logLevel
|
|
3659
3697
|
});
|
|
3660
3698
|
};
|
|
3661
3699
|
await w.write(getPaddedMoovAtom());
|
|
@@ -4871,6 +4909,7 @@ var convertMedia = async function({
|
|
|
4871
4909
|
onM3uStreams,
|
|
4872
4910
|
selectM3uStream,
|
|
4873
4911
|
selectM3uAssociatedPlaylists,
|
|
4912
|
+
expectedDurationInSeconds,
|
|
4874
4913
|
...more
|
|
4875
4914
|
}) {
|
|
4876
4915
|
if (controller._internals.signal.aborted) {
|
|
@@ -4927,7 +4966,8 @@ var convertMedia = async function({
|
|
|
4927
4966
|
});
|
|
4928
4967
|
},
|
|
4929
4968
|
logLevel,
|
|
4930
|
-
progressTracker
|
|
4969
|
+
progressTracker,
|
|
4970
|
+
expectedDurationInSeconds: expectedDurationInSeconds ?? null
|
|
4931
4971
|
});
|
|
4932
4972
|
const onVideoTrack = makeVideoTrackHandler({
|
|
4933
4973
|
state,
|
package/dist/index.d.ts
CHANGED
|
@@ -40,6 +40,6 @@ export declare const WebCodecsInternals: {
|
|
|
40
40
|
height: number;
|
|
41
41
|
rotation: number;
|
|
42
42
|
resizeOperation: import("./resizing/mode").ResizeOperation | null;
|
|
43
|
-
videoCodec: import("./get-available-video-codecs").ConvertMediaVideoCodec | import("@remotion/media-parser
|
|
43
|
+
videoCodec: import("./get-available-video-codecs").ConvertMediaVideoCodec | import("@remotion/media-parser").MediaParserVideoCodec;
|
|
44
44
|
}) => import("./resizing/mode").Dimensions;
|
|
45
45
|
};
|
package/dist/on-audio-track.js
CHANGED
|
@@ -17,8 +17,8 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
17
17
|
outputContainer,
|
|
18
18
|
inputContainer,
|
|
19
19
|
});
|
|
20
|
-
const audioOperation = await (onAudioTrack
|
|
21
|
-
defaultAudioCodec: audioCodec
|
|
20
|
+
const audioOperation = await (onAudioTrack ?? default_on_audio_track_handler_1.defaultOnAudioTrackHandler)({
|
|
21
|
+
defaultAudioCodec: audioCodec ?? (0, get_default_audio_codec_1.getDefaultAudioCodec)({ container: outputContainer }),
|
|
22
22
|
track,
|
|
23
23
|
logLevel,
|
|
24
24
|
outputContainer,
|
|
@@ -48,7 +48,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
48
48
|
isVideo: false,
|
|
49
49
|
codecPrivate: track.codecPrivate,
|
|
50
50
|
});
|
|
51
|
-
onMediaStateUpdate
|
|
51
|
+
onMediaStateUpdate?.((prevState) => {
|
|
52
52
|
return {
|
|
53
53
|
...prevState,
|
|
54
54
|
encodedAudioFrames: prevState.encodedAudioFrames + 1,
|
|
@@ -109,7 +109,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
109
109
|
isVideo: false,
|
|
110
110
|
codecPrivate,
|
|
111
111
|
});
|
|
112
|
-
onMediaStateUpdate
|
|
112
|
+
onMediaStateUpdate?.((prevState) => {
|
|
113
113
|
return {
|
|
114
114
|
...prevState,
|
|
115
115
|
encodedAudioFrames: prevState.encodedAudioFrames + 1,
|
|
@@ -117,7 +117,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
117
117
|
});
|
|
118
118
|
},
|
|
119
119
|
onError: (err) => {
|
|
120
|
-
abortConversion(new Error(`Audio encoder of ${track.trackId} failed (see .cause of this error)`, {
|
|
120
|
+
abortConversion(new Error(`Audio encoder of track ${track.trackId} failed (see .cause of this error)`, {
|
|
121
121
|
cause: err,
|
|
122
122
|
}));
|
|
123
123
|
},
|
|
@@ -130,7 +130,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
130
130
|
const audioDecoder = (0, audio_decoder_1.createAudioDecoder)({
|
|
131
131
|
onFrame: async (audioData) => {
|
|
132
132
|
const newAudioData = onAudioData
|
|
133
|
-
? await
|
|
133
|
+
? await onAudioData?.({ audioData, track })
|
|
134
134
|
: audioData;
|
|
135
135
|
if (newAudioData !== audioData) {
|
|
136
136
|
if (newAudioData.duration !== audioData.duration) {
|
|
@@ -151,7 +151,7 @@ const makeAudioTrackHandler = ({ state, defaultAudioCodec: audioCodec, controlle
|
|
|
151
151
|
audioData.close();
|
|
152
152
|
}
|
|
153
153
|
await audioEncoder.encodeFrame(newAudioData);
|
|
154
|
-
onMediaStateUpdate
|
|
154
|
+
onMediaStateUpdate?.((prevState) => {
|
|
155
155
|
return {
|
|
156
156
|
...prevState,
|
|
157
157
|
decodedAudioFrames: prevState.decodedAudioFrames + 1,
|
package/dist/on-frame.js
CHANGED
|
@@ -5,7 +5,6 @@ const browser_quirks_1 = require("./browser-quirks");
|
|
|
5
5
|
const convert_to_correct_videoframe_1 = require("./convert-to-correct-videoframe");
|
|
6
6
|
const rotate_and_resize_video_frame_1 = require("./rotate-and-resize-video-frame");
|
|
7
7
|
const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, track, outputCodec, rotation, resizeOperation, }) => {
|
|
8
|
-
var _a, _b;
|
|
9
8
|
const rotated = (0, rotate_and_resize_video_frame_1.rotateAndResizeVideoFrame)({
|
|
10
9
|
rotation,
|
|
11
10
|
frame: unrotatedFrame,
|
|
@@ -29,7 +28,7 @@ const onFrame = async ({ frame: unrotatedFrame, onVideoFrame, videoEncoder, trac
|
|
|
29
28
|
if (userProcessedFrame.timestamp !== rotated.timestamp && !(0, browser_quirks_1.isSafari)()) {
|
|
30
29
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different timestamp (${userProcessedFrame.timestamp}) than the input frame (${rotated.timestamp}). When calling new VideoFrame(), pass {timestamp: frame.timestamp} as second argument`);
|
|
31
30
|
}
|
|
32
|
-
if ((
|
|
31
|
+
if ((userProcessedFrame.duration ?? 0) !== (rotated.duration ?? 0)) {
|
|
33
32
|
throw new Error(`Returned VideoFrame of track ${track.trackId} has different duration (${userProcessedFrame.duration}) than the input frame (${rotated.duration}). When calling new VideoFrame(), pass {duration: frame.duration} as second argument`);
|
|
34
33
|
}
|
|
35
34
|
const fixedFrame = (0, convert_to_correct_videoframe_1.convertToCorrectVideoFrame)({
|
package/dist/on-video-track.js
CHANGED
|
@@ -14,7 +14,6 @@ const video_decoder_config_1 = require("./video-decoder-config");
|
|
|
14
14
|
const video_encoder_1 = require("./video-encoder");
|
|
15
15
|
const video_encoder_config_1 = require("./video-encoder-config");
|
|
16
16
|
const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortConversion, controller, defaultVideoCodec, onVideoTrack, logLevel, outputContainer, rotate, progress, resizeOperation, }) => async ({ track, container: inputContainer }) => {
|
|
17
|
-
var _a, _b;
|
|
18
17
|
if (controller._internals.signal.aborted) {
|
|
19
18
|
throw new Error('Aborted');
|
|
20
19
|
}
|
|
@@ -25,9 +24,9 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
25
24
|
inputTrack: track,
|
|
26
25
|
resizeOperation,
|
|
27
26
|
});
|
|
28
|
-
const videoOperation = await (onVideoTrack
|
|
27
|
+
const videoOperation = await (onVideoTrack ?? default_on_video_track_handler_1.defaultOnVideoTrackHandler)({
|
|
29
28
|
track,
|
|
30
|
-
defaultVideoCodec: defaultVideoCodec
|
|
29
|
+
defaultVideoCodec: defaultVideoCodec ?? (0, get_default_video_codec_1.getDefaultVideoCodec)({ container: outputContainer }),
|
|
31
30
|
logLevel,
|
|
32
31
|
outputContainer,
|
|
33
32
|
rotate,
|
|
@@ -59,7 +58,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
59
58
|
isVideo: true,
|
|
60
59
|
codecPrivate: track.codecPrivate,
|
|
61
60
|
});
|
|
62
|
-
onMediaStateUpdate
|
|
61
|
+
onMediaStateUpdate?.((prevState) => {
|
|
63
62
|
return {
|
|
64
63
|
...prevState,
|
|
65
64
|
decodedVideoFrames: prevState.decodedVideoFrames + 1,
|
|
@@ -70,13 +69,13 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
70
69
|
if (videoOperation.type !== 'reencode') {
|
|
71
70
|
throw new Error(`Video track with ID ${track.trackId} could not be resolved with a valid operation. Received ${JSON.stringify(videoOperation)}, but must be either "copy", "reencode", "drop" or "fail"`);
|
|
72
71
|
}
|
|
73
|
-
const rotation = (
|
|
72
|
+
const rotation = (videoOperation.rotate ?? rotate) - track.rotation;
|
|
74
73
|
const { height: newHeight, width: newWidth } = (0, rotation_1.calculateNewDimensionsFromRotateAndScale)({
|
|
75
74
|
width: track.codedWidth,
|
|
76
75
|
height: track.codedHeight,
|
|
77
76
|
rotation,
|
|
78
77
|
videoCodec: videoOperation.videoCodec,
|
|
79
|
-
resizeOperation:
|
|
78
|
+
resizeOperation: videoOperation.resize ?? null,
|
|
80
79
|
});
|
|
81
80
|
const videoEncoderConfig = await (0, video_encoder_config_1.getVideoEncoderConfig)({
|
|
82
81
|
codec: videoOperation.videoCodec,
|
|
@@ -105,14 +104,14 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
105
104
|
log_1.Log.verbose(logLevel, `Created new video track with ID ${trackNumber}, codec ${videoOperation.videoCodec} and timescale ${track.timescale}`);
|
|
106
105
|
const videoEncoder = (0, video_encoder_1.createVideoEncoder)({
|
|
107
106
|
onChunk: async (chunk, metadata) => {
|
|
108
|
-
var _a, _b;
|
|
109
107
|
await state.addSample({
|
|
110
108
|
chunk: (0, convert_encoded_chunk_1.convertEncodedChunk)(chunk, trackNumber),
|
|
111
109
|
trackNumber,
|
|
112
110
|
isVideo: true,
|
|
113
|
-
codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)((
|
|
111
|
+
codecPrivate: (0, arraybuffer_to_uint8_array_1.arrayBufferToUint8Array)((metadata?.decoderConfig?.description ??
|
|
112
|
+
null)),
|
|
114
113
|
});
|
|
115
|
-
onMediaStateUpdate
|
|
114
|
+
onMediaStateUpdate?.((prevState) => {
|
|
116
115
|
return {
|
|
117
116
|
...prevState,
|
|
118
117
|
encodedVideoFrames: prevState.encodedVideoFrames + 1,
|
|
@@ -133,7 +132,6 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
133
132
|
const videoDecoder = (0, video_decoder_1.createVideoDecoder)({
|
|
134
133
|
config: videoDecoderConfig,
|
|
135
134
|
onFrame: async (frame) => {
|
|
136
|
-
var _a;
|
|
137
135
|
await (0, on_frame_1.onFrame)({
|
|
138
136
|
frame,
|
|
139
137
|
track,
|
|
@@ -141,7 +139,7 @@ const makeVideoTrackHandler = ({ state, onVideoFrame, onMediaStateUpdate, abortC
|
|
|
141
139
|
onVideoFrame,
|
|
142
140
|
outputCodec: videoOperation.videoCodec,
|
|
143
141
|
rotation,
|
|
144
|
-
resizeOperation:
|
|
142
|
+
resizeOperation: videoOperation.resize ?? null,
|
|
145
143
|
});
|
|
146
144
|
},
|
|
147
145
|
onError: (err) => {
|
|
@@ -7,7 +7,6 @@ const normalizeVideoRotation = (rotation) => {
|
|
|
7
7
|
};
|
|
8
8
|
exports.normalizeVideoRotation = normalizeVideoRotation;
|
|
9
9
|
const rotateAndResizeVideoFrame = ({ frame, rotation, videoCodec, resizeOperation, }) => {
|
|
10
|
-
var _a;
|
|
11
10
|
const normalized = ((rotation % 360) + 360) % 360;
|
|
12
11
|
// No resize, no rotation
|
|
13
12
|
if (normalized === 0 && resizeOperation === null) {
|
|
@@ -60,7 +59,7 @@ const rotateAndResizeVideoFrame = ({ frame, rotation, videoCodec, resizeOperatio
|
|
|
60
59
|
return new VideoFrame(canvas, {
|
|
61
60
|
displayHeight: height,
|
|
62
61
|
displayWidth: width,
|
|
63
|
-
duration:
|
|
62
|
+
duration: frame.duration ?? undefined,
|
|
64
63
|
timestamp: frame.timestamp,
|
|
65
64
|
});
|
|
66
65
|
};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { ConvertMediaContainer } from './get-available-containers';
|
|
2
|
-
export declare const selectContainerCreator: (container: ConvertMediaContainer) => ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, }: import("./create/media-fn").MediaFnGeneratorInput) => Promise<import("./create/media-fn").MediaFn>;
|
|
2
|
+
export declare const selectContainerCreator: (container: ConvertMediaContainer) => ({ writer, onBytesProgress, onMillisecondsProgress, logLevel, filename, progressTracker, expectedDurationInSeconds, }: import("./create/media-fn").MediaFnGeneratorInput) => Promise<import("./create/media-fn").MediaFn>;
|
|
@@ -3,12 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.sendUsageEvent = void 0;
|
|
4
4
|
const licensing_1 = require("@remotion/licensing");
|
|
5
5
|
const sendUsageEvent = async ({ apiKey, succeeded, }) => {
|
|
6
|
-
var _a;
|
|
7
6
|
const host = typeof window === 'undefined'
|
|
8
7
|
? null
|
|
9
8
|
: typeof window.location === 'undefined'
|
|
10
9
|
? null
|
|
11
|
-
: (
|
|
10
|
+
: (window.location.origin ?? null);
|
|
12
11
|
if (host === null) {
|
|
13
12
|
return;
|
|
14
13
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const bun_test_1 = require("bun:test");
|
|
4
|
+
const header_length_1 = require("../create/iso-base-media/header-length");
|
|
5
|
+
(0, bun_test_1.test)('should calculate good header length', () => {
|
|
6
|
+
const result = (0, header_length_1.calculateAReasonableMp4HeaderLength)(60 * 110);
|
|
7
|
+
(0, bun_test_1.expect)(result).toBe(5121246);
|
|
8
|
+
});
|
|
9
|
+
(0, bun_test_1.test)('should calculate good header length for null', () => {
|
|
10
|
+
const result = (0, header_length_1.calculateAReasonableMp4HeaderLength)(0);
|
|
11
|
+
(0, bun_test_1.expect)(result).toBe(51200);
|
|
12
|
+
});
|
|
@@ -33,7 +33,7 @@ const throttledStateUpdate = ({ updateFn, everyMilliseconds, signal, }) => {
|
|
|
33
33
|
const onAbort = () => {
|
|
34
34
|
clearInterval(interval);
|
|
35
35
|
};
|
|
36
|
-
signal
|
|
36
|
+
signal?.addEventListener('abort', onAbort, { once: true });
|
|
37
37
|
return {
|
|
38
38
|
get: () => currentState,
|
|
39
39
|
update: (fn) => {
|
|
@@ -41,7 +41,7 @@ const throttledStateUpdate = ({ updateFn, everyMilliseconds, signal, }) => {
|
|
|
41
41
|
},
|
|
42
42
|
stopAndGetLastProgress: () => {
|
|
43
43
|
clearInterval(interval);
|
|
44
|
-
signal
|
|
44
|
+
signal?.removeEventListener('abort', onAbort);
|
|
45
45
|
return currentState;
|
|
46
46
|
},
|
|
47
47
|
};
|
package/dist/video-decoder.js
CHANGED
|
@@ -66,7 +66,6 @@ const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, pr
|
|
|
66
66
|
controller._internals.signal.addEventListener('abort', onAbort);
|
|
67
67
|
videoDecoder.configure(config);
|
|
68
68
|
const processSample = async (sample) => {
|
|
69
|
-
var _a, _b;
|
|
70
69
|
if (videoDecoder.state === 'closed') {
|
|
71
70
|
return;
|
|
72
71
|
}
|
|
@@ -74,7 +73,7 @@ const createVideoDecoder = ({ onFrame, onError, controller, config, logLevel, pr
|
|
|
74
73
|
if (videoDecoder.state === 'closed') {
|
|
75
74
|
return;
|
|
76
75
|
}
|
|
77
|
-
progress.setPossibleLowestTimestamp(Math.min(sample.timestamp,
|
|
76
|
+
progress.setPossibleLowestTimestamp(Math.min(sample.timestamp, sample.dts ?? Infinity, sample.cts ?? Infinity));
|
|
78
77
|
await ioSynchronizer.waitFor({
|
|
79
78
|
unemitted: 20,
|
|
80
79
|
unprocessed: 10,
|
|
@@ -13,7 +13,7 @@ const getVideoEncoderConfig = async ({ codec, height, width, fps, }) => {
|
|
|
13
13
|
width,
|
|
14
14
|
bitrate: (0, browser_quirks_1.isSafari)() ? 3000000 : undefined,
|
|
15
15
|
bitrateMode: codec === 'vp9' && !(0, browser_quirks_1.isSafari)() ? 'quantizer' : undefined,
|
|
16
|
-
framerate: fps
|
|
16
|
+
framerate: fps ?? undefined,
|
|
17
17
|
};
|
|
18
18
|
const hardware = {
|
|
19
19
|
...config,
|
package/dist/video-encoder.js
CHANGED
|
@@ -20,15 +20,14 @@ const createVideoEncoder = ({ onChunk, onError, controller, config, logLevel, ou
|
|
|
20
20
|
onError(error);
|
|
21
21
|
},
|
|
22
22
|
output(chunk, metadata) {
|
|
23
|
-
|
|
24
|
-
const timestamp = chunk.timestamp + ((_a = chunk.duration) !== null && _a !== void 0 ? _a : 0);
|
|
23
|
+
const timestamp = chunk.timestamp + (chunk.duration ?? 0);
|
|
25
24
|
ioSynchronizer.onOutput(timestamp);
|
|
26
25
|
outputQueue = outputQueue
|
|
27
26
|
.then(() => {
|
|
28
27
|
if (controller._internals.signal.aborted) {
|
|
29
28
|
return;
|
|
30
29
|
}
|
|
31
|
-
return onChunk(chunk, metadata
|
|
30
|
+
return onChunk(chunk, metadata ?? null);
|
|
32
31
|
})
|
|
33
32
|
.then(() => {
|
|
34
33
|
ioSynchronizer.onProcessed();
|
package/dist/writers/web-fs.js
CHANGED
|
@@ -10,7 +10,7 @@ const createContent = async ({ filename }) => {
|
|
|
10
10
|
recursive: true,
|
|
11
11
|
});
|
|
12
12
|
}
|
|
13
|
-
catch
|
|
13
|
+
catch { }
|
|
14
14
|
};
|
|
15
15
|
await remove();
|
|
16
16
|
const fileHandle = await directoryHandle.getFileHandle(actualFilename, {
|
|
@@ -38,7 +38,7 @@ const createContent = async ({ filename }) => {
|
|
|
38
38
|
try {
|
|
39
39
|
await writable.close();
|
|
40
40
|
}
|
|
41
|
-
catch
|
|
41
|
+
catch {
|
|
42
42
|
// Ignore, could already be closed
|
|
43
43
|
}
|
|
44
44
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/webcodecs",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.272",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -17,15 +17,15 @@
|
|
|
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.
|
|
21
|
-
"@remotion/licensing": "4.0.
|
|
20
|
+
"@remotion/media-parser": "4.0.272",
|
|
21
|
+
"@remotion/licensing": "4.0.272"
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/dom-webcodecs": "0.1.11",
|
|
26
26
|
"eslint": "9.19.0",
|
|
27
|
-
"@remotion/
|
|
28
|
-
"@remotion/
|
|
27
|
+
"@remotion/eslint-config-internal": "4.0.272",
|
|
28
|
+
"@remotion/example-videos": "4.0.272"
|
|
29
29
|
},
|
|
30
30
|
"keywords": [],
|
|
31
31
|
"publishConfig": {
|