@remotion/media 4.0.506 → 4.0.507
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-extraction/audio-manager.d.ts +8 -1
- package/dist/audio-extraction/extract-audio.d.ts +2 -0
- package/dist/caches.d.ts +289 -5
- package/dist/esm/index.mjs +446 -259
- package/dist/extract-frame-and-audio.d.ts +95 -1
- package/dist/get-sink.d.ts +14 -12
- package/dist/video-extraction/extract-frame-via-broadcast-channel.d.ts +95 -1
- package/dist/video-extraction/extract-frame.d.ts +2 -0
- package/dist/video-extraction/get-frames-since-keyframe.d.ts +14 -11
- package/dist/video-extraction/keyframe-manager.d.ts +8 -2
- package/package.json +4 -4
package/dist/esm/index.mjs
CHANGED
|
@@ -2789,7 +2789,7 @@ import {
|
|
|
2789
2789
|
|
|
2790
2790
|
// src/caches.ts
|
|
2791
2791
|
import React2 from "react";
|
|
2792
|
-
import { cancelRender, Internals as
|
|
2792
|
+
import { cancelRender, Internals as Internals14 } from "remotion";
|
|
2793
2793
|
|
|
2794
2794
|
// src/audio-extraction/audio-manager.ts
|
|
2795
2795
|
import { Internals as Internals9 } from "remotion";
|
|
@@ -2991,8 +2991,11 @@ var makeAudioIterator2 = ({
|
|
|
2991
2991
|
};
|
|
2992
2992
|
|
|
2993
2993
|
// src/audio-extraction/audio-manager.ts
|
|
2994
|
-
var makeAudioManager = (
|
|
2994
|
+
var makeAudioManager = ({
|
|
2995
|
+
getTotalCacheStats
|
|
2996
|
+
}) => {
|
|
2995
2997
|
const iterators = [];
|
|
2998
|
+
let disposed = false;
|
|
2996
2999
|
const makeIterator = ({
|
|
2997
3000
|
timeInSeconds,
|
|
2998
3001
|
src,
|
|
@@ -3053,6 +3056,9 @@ var makeAudioManager = () => {
|
|
|
3053
3056
|
logLevel,
|
|
3054
3057
|
maxCacheSize
|
|
3055
3058
|
}) => {
|
|
3059
|
+
if (disposed) {
|
|
3060
|
+
throw new Error("Media cache has already been disposed");
|
|
3061
|
+
}
|
|
3056
3062
|
let attempts = 0;
|
|
3057
3063
|
const maxAttempts = 3;
|
|
3058
3064
|
while ((await getTotalCacheStats()).totalSize > maxCacheSize && attempts < maxAttempts) {
|
|
@@ -3075,6 +3081,9 @@ var makeAudioManager = () => {
|
|
|
3075
3081
|
}
|
|
3076
3082
|
}
|
|
3077
3083
|
deleteDuplicateIterators(logLevel);
|
|
3084
|
+
if (disposed) {
|
|
3085
|
+
throw new Error("Media cache has already been disposed");
|
|
3086
|
+
}
|
|
3078
3087
|
return makeIterator({
|
|
3079
3088
|
src,
|
|
3080
3089
|
timeInSeconds,
|
|
@@ -3099,6 +3108,19 @@ var makeAudioManager = () => {
|
|
|
3099
3108
|
iterator.logOpenFrames();
|
|
3100
3109
|
}
|
|
3101
3110
|
};
|
|
3111
|
+
const clearAll = () => {
|
|
3112
|
+
for (const iterator of iterators) {
|
|
3113
|
+
iterator.prepareForDeletion();
|
|
3114
|
+
}
|
|
3115
|
+
iterators.length = 0;
|
|
3116
|
+
};
|
|
3117
|
+
const dispose = () => {
|
|
3118
|
+
if (disposed) {
|
|
3119
|
+
return;
|
|
3120
|
+
}
|
|
3121
|
+
disposed = true;
|
|
3122
|
+
clearAll();
|
|
3123
|
+
};
|
|
3102
3124
|
let queue = Promise.resolve(undefined);
|
|
3103
3125
|
return {
|
|
3104
3126
|
getIterator: ({
|
|
@@ -3124,13 +3146,251 @@ var makeAudioManager = () => {
|
|
|
3124
3146
|
getCacheStats,
|
|
3125
3147
|
getIteratorMostInThePast,
|
|
3126
3148
|
logOpenFrames,
|
|
3127
|
-
deleteDuplicateIterators
|
|
3149
|
+
deleteDuplicateIterators,
|
|
3150
|
+
clearAll,
|
|
3151
|
+
dispose
|
|
3128
3152
|
};
|
|
3129
3153
|
};
|
|
3130
3154
|
|
|
3131
|
-
// src/
|
|
3155
|
+
// src/get-sink.ts
|
|
3132
3156
|
import { Internals as Internals11 } from "remotion";
|
|
3133
3157
|
|
|
3158
|
+
// src/video-extraction/get-frames-since-keyframe.ts
|
|
3159
|
+
import {
|
|
3160
|
+
ALL_FORMATS as ALL_FORMATS2,
|
|
3161
|
+
AudioSampleSink,
|
|
3162
|
+
EncodedPacketSink,
|
|
3163
|
+
Input as Input2,
|
|
3164
|
+
MATROSKA,
|
|
3165
|
+
UrlSource as UrlSource2,
|
|
3166
|
+
VideoSampleSink,
|
|
3167
|
+
WEBM
|
|
3168
|
+
} from "mediabunny";
|
|
3169
|
+
import { Internals as Internals10 } from "remotion";
|
|
3170
|
+
|
|
3171
|
+
// src/browser-can-use-webgl2.ts
|
|
3172
|
+
var browserCanUseWebGl2 = null;
|
|
3173
|
+
var browserCanUseWebGl2Uncached = () => {
|
|
3174
|
+
const canvas = new OffscreenCanvas(1, 1);
|
|
3175
|
+
const context = canvas.getContext("webgl2");
|
|
3176
|
+
return context !== null;
|
|
3177
|
+
};
|
|
3178
|
+
var canBrowserUseWebGl2 = () => {
|
|
3179
|
+
if (browserCanUseWebGl2 !== null) {
|
|
3180
|
+
return browserCanUseWebGl2;
|
|
3181
|
+
}
|
|
3182
|
+
browserCanUseWebGl2 = browserCanUseWebGl2Uncached();
|
|
3183
|
+
return browserCanUseWebGl2;
|
|
3184
|
+
};
|
|
3185
|
+
|
|
3186
|
+
// src/video-extraction/remember-actual-matroska-timestamps.ts
|
|
3187
|
+
var rememberActualMatroskaTimestamps = (isMatroska) => {
|
|
3188
|
+
const observations = [];
|
|
3189
|
+
const observeTimestamp = (startTime) => {
|
|
3190
|
+
if (!isMatroska) {
|
|
3191
|
+
return;
|
|
3192
|
+
}
|
|
3193
|
+
observations.push(startTime);
|
|
3194
|
+
};
|
|
3195
|
+
const getRealTimestamp = (observedTimestamp) => {
|
|
3196
|
+
if (!isMatroska) {
|
|
3197
|
+
return observedTimestamp;
|
|
3198
|
+
}
|
|
3199
|
+
return observations.find((observation) => Math.abs(observedTimestamp - observation) < 0.001) ?? null;
|
|
3200
|
+
};
|
|
3201
|
+
return {
|
|
3202
|
+
observeTimestamp,
|
|
3203
|
+
getRealTimestamp
|
|
3204
|
+
};
|
|
3205
|
+
};
|
|
3206
|
+
|
|
3207
|
+
// src/video-extraction/get-frames-since-keyframe.ts
|
|
3208
|
+
var getRetryDelay = () => {
|
|
3209
|
+
return null;
|
|
3210
|
+
};
|
|
3211
|
+
var getFormatOrNullOrNetworkError = async (input) => {
|
|
3212
|
+
try {
|
|
3213
|
+
return await input.getFormat();
|
|
3214
|
+
} catch (err) {
|
|
3215
|
+
if (isNetworkError(err)) {
|
|
3216
|
+
return "network-error";
|
|
3217
|
+
}
|
|
3218
|
+
return null;
|
|
3219
|
+
}
|
|
3220
|
+
};
|
|
3221
|
+
var makeSinks = (src, logLevel, credentials, requestInit) => {
|
|
3222
|
+
const resolvedRequestInit = resolveRequestInit({ credentials, requestInit });
|
|
3223
|
+
const input = new Input2({
|
|
3224
|
+
formats: ALL_FORMATS2,
|
|
3225
|
+
source: new UrlSource2(src, {
|
|
3226
|
+
getRetryDelay,
|
|
3227
|
+
...resolvedRequestInit ? { requestInit: resolvedRequestInit } : undefined
|
|
3228
|
+
})
|
|
3229
|
+
});
|
|
3230
|
+
const getSinks = async () => {
|
|
3231
|
+
const format = await getFormatOrNullOrNetworkError(input);
|
|
3232
|
+
const isMatroska = format === MATROSKA || format === WEBM;
|
|
3233
|
+
const getVideoSinks = async () => {
|
|
3234
|
+
if (format === "network-error") {
|
|
3235
|
+
return "network-error";
|
|
3236
|
+
}
|
|
3237
|
+
if (format === null) {
|
|
3238
|
+
return "unknown-container-format";
|
|
3239
|
+
}
|
|
3240
|
+
const videoTrack = await input.getPrimaryVideoTrack();
|
|
3241
|
+
if (!videoTrack) {
|
|
3242
|
+
return "no-video-track";
|
|
3243
|
+
}
|
|
3244
|
+
if (await videoTrack.isLive()) {
|
|
3245
|
+
throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + src);
|
|
3246
|
+
}
|
|
3247
|
+
if (await videoTrack.isRelativeToUnixEpoch()) {
|
|
3248
|
+
throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + src);
|
|
3249
|
+
}
|
|
3250
|
+
const canDecode = await videoTrack.canDecode();
|
|
3251
|
+
if (!canDecode) {
|
|
3252
|
+
if (videoTrack.codec === "prores") {
|
|
3253
|
+
return "cannot-decode-prores";
|
|
3254
|
+
}
|
|
3255
|
+
return "cannot-decode";
|
|
3256
|
+
}
|
|
3257
|
+
const sampleSink = new VideoSampleSink(videoTrack);
|
|
3258
|
+
const packetSink = new EncodedPacketSink(videoTrack);
|
|
3259
|
+
const startPacket = await packetSink.getFirstPacket({
|
|
3260
|
+
verifyKeyPackets: true
|
|
3261
|
+
});
|
|
3262
|
+
const hasAlpha = startPacket?.sideData.alpha;
|
|
3263
|
+
if (hasAlpha && !canBrowserUseWebGl2()) {
|
|
3264
|
+
Internals10.Log.warn({ logLevel, tag: "@remotion/media" }, `WebGL2 is not available, using the non-fast CPU path to decode alpha for ${src}.`);
|
|
3265
|
+
}
|
|
3266
|
+
return {
|
|
3267
|
+
sampleSink
|
|
3268
|
+
};
|
|
3269
|
+
};
|
|
3270
|
+
let videoSinksPromise = null;
|
|
3271
|
+
const getVideoSinksPromise = () => {
|
|
3272
|
+
if (videoSinksPromise) {
|
|
3273
|
+
return videoSinksPromise;
|
|
3274
|
+
}
|
|
3275
|
+
videoSinksPromise = getVideoSinks();
|
|
3276
|
+
return videoSinksPromise;
|
|
3277
|
+
};
|
|
3278
|
+
const audioSinksPromise = {};
|
|
3279
|
+
const getAudioSinks = async (index) => {
|
|
3280
|
+
if (format === null) {
|
|
3281
|
+
return "unknown-container-format";
|
|
3282
|
+
}
|
|
3283
|
+
if (format === "network-error") {
|
|
3284
|
+
return "network-error";
|
|
3285
|
+
}
|
|
3286
|
+
const [videoTrack, audioTracks] = await Promise.all([
|
|
3287
|
+
input.getPrimaryVideoTrack(),
|
|
3288
|
+
input.getAudioTracks()
|
|
3289
|
+
]);
|
|
3290
|
+
const audioTrack = await resolveAudioTrack({
|
|
3291
|
+
videoTrack,
|
|
3292
|
+
audioTracks,
|
|
3293
|
+
audioStreamIndex: index
|
|
3294
|
+
});
|
|
3295
|
+
if (!audioTrack) {
|
|
3296
|
+
return "no-audio-track";
|
|
3297
|
+
}
|
|
3298
|
+
const canDecode = await audioTrack.canDecode();
|
|
3299
|
+
if (!canDecode) {
|
|
3300
|
+
return "cannot-decode-audio";
|
|
3301
|
+
}
|
|
3302
|
+
return {
|
|
3303
|
+
sampleSink: new AudioSampleSink(audioTrack)
|
|
3304
|
+
};
|
|
3305
|
+
};
|
|
3306
|
+
const getAudioSinksPromise = (index) => {
|
|
3307
|
+
const keyIndex = index === null ? -1 : index;
|
|
3308
|
+
if (audioSinksPromise[keyIndex]) {
|
|
3309
|
+
return audioSinksPromise[keyIndex];
|
|
3310
|
+
}
|
|
3311
|
+
audioSinksPromise[keyIndex] = getAudioSinks(index);
|
|
3312
|
+
return audioSinksPromise[keyIndex];
|
|
3313
|
+
};
|
|
3314
|
+
return {
|
|
3315
|
+
getVideo: () => getVideoSinksPromise(),
|
|
3316
|
+
getAudio: (index) => getAudioSinksPromise(index),
|
|
3317
|
+
actualMatroskaTimestamps: rememberActualMatroskaTimestamps(isMatroska),
|
|
3318
|
+
isMatroska,
|
|
3319
|
+
getDuration: () => {
|
|
3320
|
+
return getDurationOrCompute(input);
|
|
3321
|
+
}
|
|
3322
|
+
};
|
|
3323
|
+
};
|
|
3324
|
+
return {
|
|
3325
|
+
promise: getSinks(),
|
|
3326
|
+
dispose: () => input.dispose()
|
|
3327
|
+
};
|
|
3328
|
+
};
|
|
3329
|
+
|
|
3330
|
+
// src/get-sink.ts
|
|
3331
|
+
var getSinkCacheKey = ({
|
|
3332
|
+
src,
|
|
3333
|
+
credentials,
|
|
3334
|
+
requestInit
|
|
3335
|
+
}) => JSON.stringify([
|
|
3336
|
+
src,
|
|
3337
|
+
credentials,
|
|
3338
|
+
getMediaRequestInitFingerprint(requestInit)
|
|
3339
|
+
]);
|
|
3340
|
+
var makeSinkManager = () => {
|
|
3341
|
+
const sinkPromises = {};
|
|
3342
|
+
const inputDisposers = {};
|
|
3343
|
+
let disposed = false;
|
|
3344
|
+
return {
|
|
3345
|
+
getSink: (src, logLevel, credentials, requestInit) => {
|
|
3346
|
+
if (disposed) {
|
|
3347
|
+
return Promise.reject(new Error("Media cache has already been disposed"));
|
|
3348
|
+
}
|
|
3349
|
+
const normalizedRequestInit = normalizeMediaRequestInit(requestInit);
|
|
3350
|
+
const cacheKey = getSinkCacheKey({
|
|
3351
|
+
src,
|
|
3352
|
+
credentials,
|
|
3353
|
+
requestInit: normalizedRequestInit
|
|
3354
|
+
});
|
|
3355
|
+
let promise = sinkPromises[cacheKey];
|
|
3356
|
+
if (!promise) {
|
|
3357
|
+
Internals11.Log.verbose({
|
|
3358
|
+
logLevel,
|
|
3359
|
+
tag: "@remotion/media"
|
|
3360
|
+
}, `Sink for ${src} was not found, creating new sink`);
|
|
3361
|
+
const sinks = makeSinks(src, logLevel, credentials, normalizedRequestInit);
|
|
3362
|
+
promise = sinks.promise;
|
|
3363
|
+
sinkPromises[cacheKey] = promise;
|
|
3364
|
+
inputDisposers[cacheKey] = sinks.dispose;
|
|
3365
|
+
}
|
|
3366
|
+
return promise;
|
|
3367
|
+
},
|
|
3368
|
+
dispose: () => {
|
|
3369
|
+
if (disposed) {
|
|
3370
|
+
return;
|
|
3371
|
+
}
|
|
3372
|
+
disposed = true;
|
|
3373
|
+
let firstError = null;
|
|
3374
|
+
for (const cacheKey of Object.keys(inputDisposers)) {
|
|
3375
|
+
try {
|
|
3376
|
+
inputDisposers[cacheKey]();
|
|
3377
|
+
} catch (error) {
|
|
3378
|
+
firstError ??= error;
|
|
3379
|
+
} finally {
|
|
3380
|
+
delete inputDisposers[cacheKey];
|
|
3381
|
+
delete sinkPromises[cacheKey];
|
|
3382
|
+
}
|
|
3383
|
+
}
|
|
3384
|
+
if (firstError !== null) {
|
|
3385
|
+
throw firstError;
|
|
3386
|
+
}
|
|
3387
|
+
}
|
|
3388
|
+
};
|
|
3389
|
+
};
|
|
3390
|
+
|
|
3391
|
+
// src/video-extraction/keyframe-manager.ts
|
|
3392
|
+
import { Internals as Internals13 } from "remotion";
|
|
3393
|
+
|
|
3134
3394
|
// src/render-timestamp-range.ts
|
|
3135
3395
|
var renderTimestampRange = (timestamps) => {
|
|
3136
3396
|
if (timestamps.length === 0) {
|
|
@@ -3143,12 +3403,13 @@ var renderTimestampRange = (timestamps) => {
|
|
|
3143
3403
|
};
|
|
3144
3404
|
|
|
3145
3405
|
// src/video-extraction/keyframe-bank.ts
|
|
3146
|
-
import { Internals as
|
|
3406
|
+
import { Internals as Internals12 } from "remotion";
|
|
3147
3407
|
|
|
3148
3408
|
// src/video-extraction/get-allocation-size.ts
|
|
3409
|
+
var BYTES_PER_PIXEL_FOR_OPAQUE_FRAME = 3;
|
|
3149
3410
|
var getAllocationSize = (sample) => {
|
|
3150
3411
|
if (sample.format === null) {
|
|
3151
|
-
return sample.codedHeight * sample.codedWidth *
|
|
3412
|
+
return sample.codedHeight * sample.codedWidth * BYTES_PER_PIXEL_FOR_OPAQUE_FRAME;
|
|
3152
3413
|
}
|
|
3153
3414
|
return sample.allocationSize();
|
|
3154
3415
|
};
|
|
@@ -3222,7 +3483,7 @@ var makeKeyframeBank = async ({
|
|
|
3222
3483
|
}
|
|
3223
3484
|
}
|
|
3224
3485
|
if (deletedTimestamps.length > 0) {
|
|
3225
|
-
|
|
3486
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${deletedTimestamps.length} frame${deletedTimestamps.length === 1 ? "" : "s"} ${renderTimestampRange(deletedTimestamps)} for src ${src} because it is lower than ${timestampInSeconds}. Remaining: ${renderTimestampRange(frameTimestamps)}`);
|
|
3226
3487
|
}
|
|
3227
3488
|
};
|
|
3228
3489
|
const hasDecodedEnoughForTimestamp = (timestamp) => {
|
|
@@ -3251,7 +3512,7 @@ var makeKeyframeBank = async ({
|
|
|
3251
3512
|
frameTimestamps.push(frame.timestamp);
|
|
3252
3513
|
allocationSize += getAllocationSize(frame);
|
|
3253
3514
|
lastUsed = Date.now();
|
|
3254
|
-
|
|
3515
|
+
Internals12.Log.trace({ logLevel, tag: "@remotion/media" }, `Added frame at ${frame.timestamp}sec to bank`);
|
|
3255
3516
|
};
|
|
3256
3517
|
const ensureEnoughFramesForTimestamp = async (timestampInSeconds, logLevel, fps) => {
|
|
3257
3518
|
while (!hasDecodedEnoughForTimestamp(timestampInSeconds)) {
|
|
@@ -3306,7 +3567,7 @@ var makeKeyframeBank = async ({
|
|
|
3306
3567
|
throw new Error("No first frame found");
|
|
3307
3568
|
}
|
|
3308
3569
|
const startTimestampInSeconds = firstFrame.value.timestamp;
|
|
3309
|
-
|
|
3570
|
+
Internals12.Log.verbose({ logLevel: parentLogLevel, tag: "@remotion/media" }, `Creating keyframe bank from ${startTimestampInSeconds}sec`);
|
|
3310
3571
|
addFrame(firstFrame.value, parentLogLevel);
|
|
3311
3572
|
const getRangeOfTimestamps = () => {
|
|
3312
3573
|
if (frameTimestamps.length === 0) {
|
|
@@ -3323,7 +3584,7 @@ var makeKeyframeBank = async ({
|
|
|
3323
3584
|
const prepareForDeletion = (logLevel, reason) => {
|
|
3324
3585
|
const range = getRangeOfTimestamps();
|
|
3325
3586
|
if (range) {
|
|
3326
|
-
|
|
3587
|
+
Internals12.Log.verbose({ logLevel, tag: "@remotion/media" }, `Preparing for deletion (${reason}) of keyframe bank from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec`);
|
|
3327
3588
|
}
|
|
3328
3589
|
let framesDeleted = 0;
|
|
3329
3590
|
for (const frameTimestamp of frameTimestamps.slice()) {
|
|
@@ -3384,11 +3645,23 @@ var makeKeyframeBank = async ({
|
|
|
3384
3645
|
};
|
|
3385
3646
|
|
|
3386
3647
|
// src/video-extraction/keyframe-manager.ts
|
|
3387
|
-
var makeKeyframeManager = (
|
|
3648
|
+
var makeKeyframeManager = ({
|
|
3649
|
+
getTotalCacheStats
|
|
3650
|
+
}) => {
|
|
3388
3651
|
let sources = {};
|
|
3389
|
-
|
|
3652
|
+
let disposed = false;
|
|
3653
|
+
const addKeyframeBank = ({
|
|
3654
|
+
src,
|
|
3655
|
+
bank,
|
|
3656
|
+
logLevel
|
|
3657
|
+
}) => {
|
|
3658
|
+
if (disposed) {
|
|
3659
|
+
bank.prepareForDeletion(logLevel, "media cache was disposed");
|
|
3660
|
+
return false;
|
|
3661
|
+
}
|
|
3390
3662
|
sources[src] = sources[src] ?? [];
|
|
3391
3663
|
sources[src].push(bank);
|
|
3664
|
+
return true;
|
|
3392
3665
|
};
|
|
3393
3666
|
const logCacheStats = (logLevel) => {
|
|
3394
3667
|
let count = 0;
|
|
@@ -3401,10 +3674,10 @@ var makeKeyframeManager = () => {
|
|
|
3401
3674
|
if (size === 0) {
|
|
3402
3675
|
continue;
|
|
3403
3676
|
}
|
|
3404
|
-
|
|
3677
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Open frames for src ${src}: ${renderTimestampRange(timestamps)}`);
|
|
3405
3678
|
}
|
|
3406
3679
|
}
|
|
3407
|
-
|
|
3680
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Video cache stats: ${count} open frames, ${totalSize} bytes`);
|
|
3408
3681
|
};
|
|
3409
3682
|
const getCacheStats = () => {
|
|
3410
3683
|
let count = 0;
|
|
@@ -3458,7 +3731,7 @@ var makeKeyframeManager = () => {
|
|
|
3458
3731
|
const { framesDeleted } = mostInThePastBank.prepareForDeletion(logLevel, "deleted oldest keyframe bank to stay under max cache size");
|
|
3459
3732
|
sources[mostInThePastSrc].splice(mostInThePastIndex, 1);
|
|
3460
3733
|
if (range) {
|
|
3461
|
-
|
|
3734
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Deleted ${framesDeleted} frames for src ${mostInThePastSrc} from ${range?.firstTimestamp}sec to ${range?.lastTimestamp}sec to free up memory.`);
|
|
3462
3735
|
}
|
|
3463
3736
|
}
|
|
3464
3737
|
return { finish: false };
|
|
@@ -3472,12 +3745,12 @@ var makeKeyframeManager = () => {
|
|
|
3472
3745
|
if (finish) {
|
|
3473
3746
|
break;
|
|
3474
3747
|
}
|
|
3475
|
-
|
|
3748
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, "Deleted oldest keyframe bank to stay under max cache size", (cacheStats.totalSize / 1024 / 1024).toFixed(1), "out of", (maxCacheSize / 1024 / 1024).toFixed(1));
|
|
3476
3749
|
cacheStats = getTotalCacheStats();
|
|
3477
3750
|
attempts++;
|
|
3478
3751
|
}
|
|
3479
3752
|
if (cacheStats.totalSize > maxCacheSize && attempts >= maxAttempts) {
|
|
3480
|
-
|
|
3753
|
+
Internals13.Log.warn({ logLevel, tag: "@remotion/media" }, `Exceeded max cache size after ${maxAttempts} attempts. Remaining cache size: ${(cacheStats.totalSize / 1024 / 1024).toFixed(1)} MB, target was ${(maxCacheSize / 1024 / 1024).toFixed(1)} MB.`);
|
|
3481
3754
|
}
|
|
3482
3755
|
};
|
|
3483
3756
|
const clearKeyframeBanksBeforeTime = ({
|
|
@@ -3498,7 +3771,7 @@ var makeKeyframeManager = () => {
|
|
|
3498
3771
|
}
|
|
3499
3772
|
if (range.lastTimestamp < threshold) {
|
|
3500
3773
|
bank.prepareForDeletion(logLevel, "cleared before threshold " + threshold);
|
|
3501
|
-
|
|
3774
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `[Video] Cleared frames for src ${src} from ${range.firstTimestamp}sec to ${range.lastTimestamp}sec`);
|
|
3502
3775
|
const bankIndex = banks.indexOf(bank);
|
|
3503
3776
|
delete sources[src][bankIndex];
|
|
3504
3777
|
} else {
|
|
@@ -3520,21 +3793,23 @@ var makeKeyframeManager = () => {
|
|
|
3520
3793
|
const existingBanks = sources[src] ?? [];
|
|
3521
3794
|
const existingBank = existingBanks?.find((bank) => bank.canSatisfyTimestamp(timestamp));
|
|
3522
3795
|
if (!existingBank) {
|
|
3523
|
-
|
|
3796
|
+
Internals13.Log.trace({ logLevel, tag: "@remotion/media" }, `Creating new keyframe bank for src ${src} at timestamp ${timestamp}`);
|
|
3524
3797
|
const newKeyframeBank = await makeKeyframeBank({
|
|
3525
3798
|
videoSampleSink,
|
|
3526
3799
|
logLevel,
|
|
3527
3800
|
src,
|
|
3528
3801
|
initialTimestampRequest: timestamp
|
|
3529
3802
|
});
|
|
3530
|
-
addKeyframeBank({ src, bank: newKeyframeBank })
|
|
3803
|
+
if (!addKeyframeBank({ src, bank: newKeyframeBank, logLevel })) {
|
|
3804
|
+
return null;
|
|
3805
|
+
}
|
|
3531
3806
|
return newKeyframeBank;
|
|
3532
3807
|
}
|
|
3533
3808
|
if (existingBank.canSatisfyTimestamp(timestamp)) {
|
|
3534
|
-
|
|
3809
|
+
Internals13.Log.trace({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists and satisfies timestamp ${timestamp}`);
|
|
3535
3810
|
return existingBank;
|
|
3536
3811
|
}
|
|
3537
|
-
|
|
3812
|
+
Internals13.Log.verbose({ logLevel, tag: "@remotion/media" }, `Keyframe bank exists but frame at time ${timestamp} does not exist anymore.`);
|
|
3538
3813
|
existingBank.prepareForDeletion(logLevel, "already existed but evicted");
|
|
3539
3814
|
sources[src] = sources[src].filter((bank) => bank !== existingBank);
|
|
3540
3815
|
const replacementKeybank = await makeKeyframeBank({
|
|
@@ -3543,7 +3818,9 @@ var makeKeyframeManager = () => {
|
|
|
3543
3818
|
logLevel,
|
|
3544
3819
|
src
|
|
3545
3820
|
});
|
|
3546
|
-
addKeyframeBank({ src, bank: replacementKeybank })
|
|
3821
|
+
if (!addKeyframeBank({ src, bank: replacementKeybank, logLevel })) {
|
|
3822
|
+
return null;
|
|
3823
|
+
}
|
|
3547
3824
|
return replacementKeybank;
|
|
3548
3825
|
};
|
|
3549
3826
|
const requestKeyframeBank = async ({
|
|
@@ -3554,6 +3831,9 @@ var makeKeyframeManager = () => {
|
|
|
3554
3831
|
maxCacheSize,
|
|
3555
3832
|
fps
|
|
3556
3833
|
}) => {
|
|
3834
|
+
if (disposed) {
|
|
3835
|
+
return null;
|
|
3836
|
+
}
|
|
3557
3837
|
ensureToStayUnderMaxCacheSize(logLevel, maxCacheSize);
|
|
3558
3838
|
clearKeyframeBanksBeforeTime({
|
|
3559
3839
|
timestampInSeconds: timestamp,
|
|
@@ -3580,6 +3860,13 @@ var makeKeyframeManager = () => {
|
|
|
3580
3860
|
}
|
|
3581
3861
|
sources = {};
|
|
3582
3862
|
};
|
|
3863
|
+
const dispose = (logLevel) => {
|
|
3864
|
+
if (disposed) {
|
|
3865
|
+
return;
|
|
3866
|
+
}
|
|
3867
|
+
disposed = true;
|
|
3868
|
+
clearAll(logLevel);
|
|
3869
|
+
};
|
|
3583
3870
|
let queue = Promise.resolve(undefined);
|
|
3584
3871
|
return {
|
|
3585
3872
|
requestKeyframeBank: ({
|
|
@@ -3601,22 +3888,96 @@ var makeKeyframeManager = () => {
|
|
|
3601
3888
|
return queue;
|
|
3602
3889
|
},
|
|
3603
3890
|
getCacheStats,
|
|
3604
|
-
clearAll
|
|
3891
|
+
clearAll,
|
|
3892
|
+
dispose
|
|
3605
3893
|
};
|
|
3606
3894
|
};
|
|
3607
3895
|
|
|
3608
3896
|
// src/caches.ts
|
|
3609
3897
|
var getSafeWindowOfMonotonicity = (fps) => 0.2 * 30 / fps;
|
|
3610
|
-
var
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3898
|
+
var makeMediaCache = () => {
|
|
3899
|
+
const sinkManager = makeSinkManager();
|
|
3900
|
+
const managerInstances = {
|
|
3901
|
+
keyframe: null,
|
|
3902
|
+
audio: null
|
|
3903
|
+
};
|
|
3904
|
+
const getCacheStats = () => {
|
|
3905
|
+
const { keyframe: currentKeyframeManager, audio: currentAudioManager } = managerInstances;
|
|
3906
|
+
if (currentKeyframeManager === null || currentAudioManager === null) {
|
|
3907
|
+
throw new Error("Media cache managers have not been initialized");
|
|
3908
|
+
}
|
|
3909
|
+
const keyframeManagerCacheStats = currentKeyframeManager.getCacheStats();
|
|
3910
|
+
const audioManagerCacheStats = currentAudioManager.getCacheStats();
|
|
3911
|
+
return {
|
|
3912
|
+
count: keyframeManagerCacheStats.count + audioManagerCacheStats.count,
|
|
3913
|
+
totalSize: keyframeManagerCacheStats.totalSize + audioManagerCacheStats.totalSize
|
|
3914
|
+
};
|
|
3915
|
+
};
|
|
3916
|
+
const keyframeManagerInstance = makeKeyframeManager({
|
|
3917
|
+
getTotalCacheStats: getCacheStats
|
|
3918
|
+
});
|
|
3919
|
+
const audioManagerInstance = makeAudioManager({
|
|
3920
|
+
getTotalCacheStats: getCacheStats
|
|
3921
|
+
});
|
|
3922
|
+
managerInstances.keyframe = keyframeManagerInstance;
|
|
3923
|
+
managerInstances.audio = audioManagerInstance;
|
|
3924
|
+
let frameExtractionQueue = Promise.resolve(undefined);
|
|
3925
|
+
let audioExtractionQueue = Promise.resolve(undefined);
|
|
3926
|
+
let disposed = false;
|
|
3615
3927
|
return {
|
|
3616
|
-
|
|
3617
|
-
|
|
3928
|
+
sinkManager,
|
|
3929
|
+
keyframeManager: keyframeManagerInstance,
|
|
3930
|
+
audioManager: audioManagerInstance,
|
|
3931
|
+
getTotalCacheStats: getCacheStats,
|
|
3932
|
+
isDisposed: () => disposed,
|
|
3933
|
+
queueFrameExtraction: (extract) => {
|
|
3934
|
+
const extraction = frameExtractionQueue.then(extract);
|
|
3935
|
+
frameExtractionQueue = extraction.catch(() => {
|
|
3936
|
+
return;
|
|
3937
|
+
});
|
|
3938
|
+
return extraction;
|
|
3939
|
+
},
|
|
3940
|
+
queueAudioExtraction: (extract) => {
|
|
3941
|
+
const extraction = audioExtractionQueue.then(extract);
|
|
3942
|
+
audioExtractionQueue = extraction.catch(() => {
|
|
3943
|
+
return;
|
|
3944
|
+
});
|
|
3945
|
+
return extraction;
|
|
3946
|
+
},
|
|
3947
|
+
dispose: (logLevel) => {
|
|
3948
|
+
if (disposed) {
|
|
3949
|
+
return;
|
|
3950
|
+
}
|
|
3951
|
+
disposed = true;
|
|
3952
|
+
try {
|
|
3953
|
+
keyframeManagerInstance.dispose(logLevel);
|
|
3954
|
+
} finally {
|
|
3955
|
+
try {
|
|
3956
|
+
audioManagerInstance.dispose();
|
|
3957
|
+
} finally {
|
|
3958
|
+
sinkManager.dispose();
|
|
3959
|
+
}
|
|
3960
|
+
}
|
|
3961
|
+
}
|
|
3618
3962
|
};
|
|
3619
3963
|
};
|
|
3964
|
+
var globalMediaCache = makeMediaCache();
|
|
3965
|
+
var useRenderMediaCache = (logLevel) => {
|
|
3966
|
+
const renderResourceManager = React2.useContext(Internals14.RenderResourceManagerContext);
|
|
3967
|
+
if (renderResourceManager === null) {
|
|
3968
|
+
return globalMediaCache;
|
|
3969
|
+
}
|
|
3970
|
+
return renderResourceManager.getOrCreateResource({
|
|
3971
|
+
key: "@remotion/media/cache",
|
|
3972
|
+
create: () => {
|
|
3973
|
+
const resource = makeMediaCache();
|
|
3974
|
+
return {
|
|
3975
|
+
resource,
|
|
3976
|
+
dispose: () => resource.dispose(logLevel)
|
|
3977
|
+
};
|
|
3978
|
+
}
|
|
3979
|
+
});
|
|
3980
|
+
};
|
|
3620
3981
|
var getUncachedMaxCacheSize = (logLevel) => {
|
|
3621
3982
|
if (typeof window !== "undefined" && window.remotion_mediaCacheSizeInBytes !== undefined && window.remotion_mediaCacheSizeInBytes !== null) {
|
|
3622
3983
|
if (window.remotion_mediaCacheSizeInBytes < 240 * 1024 * 1024) {
|
|
@@ -3625,20 +3986,20 @@ var getUncachedMaxCacheSize = (logLevel) => {
|
|
|
3625
3986
|
if (window.remotion_mediaCacheSizeInBytes > 20000 * 1024 * 1024) {
|
|
3626
3987
|
cancelRender(new Error(`The maximum value for the "mediaCacheSizeInBytes" prop is 20GB (${20000 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
|
|
3627
3988
|
}
|
|
3628
|
-
|
|
3989
|
+
Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
|
|
3629
3990
|
return window.remotion_mediaCacheSizeInBytes;
|
|
3630
3991
|
}
|
|
3631
3992
|
if (typeof window !== "undefined" && window.remotion_initialMemoryAvailable !== undefined && window.remotion_initialMemoryAvailable !== null) {
|
|
3632
3993
|
const value = window.remotion_initialMemoryAvailable / 2;
|
|
3633
3994
|
if (value < 500 * 1024 * 1024) {
|
|
3634
|
-
|
|
3995
|
+
Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on minimum value of 500MB (which is more than half of the available system memory!)`);
|
|
3635
3996
|
return 500 * 1024 * 1024;
|
|
3636
3997
|
}
|
|
3637
3998
|
if (value > 20000 * 1024 * 1024) {
|
|
3638
|
-
|
|
3999
|
+
Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on maximum value of 20GB (which is less than half of the available system memory)`);
|
|
3639
4000
|
return 20000 * 1024 * 1024;
|
|
3640
4001
|
}
|
|
3641
|
-
|
|
4002
|
+
Internals14.Log.verbose({ logLevel, tag: "@remotion/media" }, `Using cache size set based on available memory (50% of available memory): ${(value / 1024 / 1024).toFixed(1)} MB`);
|
|
3642
4003
|
return value;
|
|
3643
4004
|
}
|
|
3644
4005
|
return 1000 * 1000 * 1000;
|
|
@@ -3652,7 +4013,7 @@ var getMaxVideoCacheSize = (logLevel) => {
|
|
|
3652
4013
|
return cachedMaxCacheSize;
|
|
3653
4014
|
};
|
|
3654
4015
|
var useMaxMediaCacheSize = (logLevel) => {
|
|
3655
|
-
const context = React2.useContext(
|
|
4016
|
+
const context = React2.useContext(Internals14.MaxMediaCacheSizeContext);
|
|
3656
4017
|
if (context === null) {
|
|
3657
4018
|
return getMaxVideoCacheSize(logLevel);
|
|
3658
4019
|
}
|
|
@@ -3905,205 +4266,6 @@ var combineAudioDataAndClosePrevious = (audioDataArray) => {
|
|
|
3905
4266
|
};
|
|
3906
4267
|
};
|
|
3907
4268
|
|
|
3908
|
-
// src/get-sink.ts
|
|
3909
|
-
import { Internals as Internals14 } from "remotion";
|
|
3910
|
-
|
|
3911
|
-
// src/video-extraction/get-frames-since-keyframe.ts
|
|
3912
|
-
import {
|
|
3913
|
-
ALL_FORMATS as ALL_FORMATS2,
|
|
3914
|
-
AudioSampleSink,
|
|
3915
|
-
EncodedPacketSink,
|
|
3916
|
-
Input as Input2,
|
|
3917
|
-
MATROSKA,
|
|
3918
|
-
UrlSource as UrlSource2,
|
|
3919
|
-
VideoSampleSink,
|
|
3920
|
-
WEBM
|
|
3921
|
-
} from "mediabunny";
|
|
3922
|
-
import { Internals as Internals13 } from "remotion";
|
|
3923
|
-
|
|
3924
|
-
// src/browser-can-use-webgl2.ts
|
|
3925
|
-
var browserCanUseWebGl2 = null;
|
|
3926
|
-
var browserCanUseWebGl2Uncached = () => {
|
|
3927
|
-
const canvas = new OffscreenCanvas(1, 1);
|
|
3928
|
-
const context = canvas.getContext("webgl2");
|
|
3929
|
-
return context !== null;
|
|
3930
|
-
};
|
|
3931
|
-
var canBrowserUseWebGl2 = () => {
|
|
3932
|
-
if (browserCanUseWebGl2 !== null) {
|
|
3933
|
-
return browserCanUseWebGl2;
|
|
3934
|
-
}
|
|
3935
|
-
browserCanUseWebGl2 = browserCanUseWebGl2Uncached();
|
|
3936
|
-
return browserCanUseWebGl2;
|
|
3937
|
-
};
|
|
3938
|
-
|
|
3939
|
-
// src/video-extraction/remember-actual-matroska-timestamps.ts
|
|
3940
|
-
var rememberActualMatroskaTimestamps = (isMatroska) => {
|
|
3941
|
-
const observations = [];
|
|
3942
|
-
const observeTimestamp = (startTime) => {
|
|
3943
|
-
if (!isMatroska) {
|
|
3944
|
-
return;
|
|
3945
|
-
}
|
|
3946
|
-
observations.push(startTime);
|
|
3947
|
-
};
|
|
3948
|
-
const getRealTimestamp = (observedTimestamp) => {
|
|
3949
|
-
if (!isMatroska) {
|
|
3950
|
-
return observedTimestamp;
|
|
3951
|
-
}
|
|
3952
|
-
return observations.find((observation) => Math.abs(observedTimestamp - observation) < 0.001) ?? null;
|
|
3953
|
-
};
|
|
3954
|
-
return {
|
|
3955
|
-
observeTimestamp,
|
|
3956
|
-
getRealTimestamp
|
|
3957
|
-
};
|
|
3958
|
-
};
|
|
3959
|
-
|
|
3960
|
-
// src/video-extraction/get-frames-since-keyframe.ts
|
|
3961
|
-
var getRetryDelay = () => {
|
|
3962
|
-
return null;
|
|
3963
|
-
};
|
|
3964
|
-
var getFormatOrNullOrNetworkError = async (input) => {
|
|
3965
|
-
try {
|
|
3966
|
-
return await input.getFormat();
|
|
3967
|
-
} catch (err) {
|
|
3968
|
-
if (isNetworkError(err)) {
|
|
3969
|
-
return "network-error";
|
|
3970
|
-
}
|
|
3971
|
-
return null;
|
|
3972
|
-
}
|
|
3973
|
-
};
|
|
3974
|
-
var getSinks = async (src, logLevel, credentials, requestInit) => {
|
|
3975
|
-
const resolvedRequestInit = resolveRequestInit({ credentials, requestInit });
|
|
3976
|
-
const input = new Input2({
|
|
3977
|
-
formats: ALL_FORMATS2,
|
|
3978
|
-
source: new UrlSource2(src, {
|
|
3979
|
-
getRetryDelay,
|
|
3980
|
-
...resolvedRequestInit ? { requestInit: resolvedRequestInit } : undefined
|
|
3981
|
-
})
|
|
3982
|
-
});
|
|
3983
|
-
const format = await getFormatOrNullOrNetworkError(input);
|
|
3984
|
-
const isMatroska = format === MATROSKA || format === WEBM;
|
|
3985
|
-
const getVideoSinks = async () => {
|
|
3986
|
-
if (format === "network-error") {
|
|
3987
|
-
return "network-error";
|
|
3988
|
-
}
|
|
3989
|
-
if (format === null) {
|
|
3990
|
-
return "unknown-container-format";
|
|
3991
|
-
}
|
|
3992
|
-
const videoTrack = await input.getPrimaryVideoTrack();
|
|
3993
|
-
if (!videoTrack) {
|
|
3994
|
-
return "no-video-track";
|
|
3995
|
-
}
|
|
3996
|
-
if (await videoTrack.isLive()) {
|
|
3997
|
-
throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + src);
|
|
3998
|
-
}
|
|
3999
|
-
if (await videoTrack.isRelativeToUnixEpoch()) {
|
|
4000
|
-
throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + src);
|
|
4001
|
-
}
|
|
4002
|
-
const canDecode = await videoTrack.canDecode();
|
|
4003
|
-
if (!canDecode) {
|
|
4004
|
-
if (videoTrack.codec === "prores") {
|
|
4005
|
-
return "cannot-decode-prores";
|
|
4006
|
-
}
|
|
4007
|
-
return "cannot-decode";
|
|
4008
|
-
}
|
|
4009
|
-
const sampleSink = new VideoSampleSink(videoTrack);
|
|
4010
|
-
const packetSink = new EncodedPacketSink(videoTrack);
|
|
4011
|
-
const startPacket = await packetSink.getFirstPacket({
|
|
4012
|
-
verifyKeyPackets: true
|
|
4013
|
-
});
|
|
4014
|
-
const hasAlpha = startPacket?.sideData.alpha;
|
|
4015
|
-
if (hasAlpha && !canBrowserUseWebGl2()) {
|
|
4016
|
-
Internals13.Log.warn({ logLevel, tag: "@remotion/media" }, `WebGL2 is not available, using the non-fast CPU path to decode alpha for ${src}.`);
|
|
4017
|
-
}
|
|
4018
|
-
return {
|
|
4019
|
-
sampleSink
|
|
4020
|
-
};
|
|
4021
|
-
};
|
|
4022
|
-
let videoSinksPromise = null;
|
|
4023
|
-
const getVideoSinksPromise = () => {
|
|
4024
|
-
if (videoSinksPromise) {
|
|
4025
|
-
return videoSinksPromise;
|
|
4026
|
-
}
|
|
4027
|
-
videoSinksPromise = getVideoSinks();
|
|
4028
|
-
return videoSinksPromise;
|
|
4029
|
-
};
|
|
4030
|
-
const audioSinksPromise = {};
|
|
4031
|
-
const getAudioSinks = async (index) => {
|
|
4032
|
-
if (format === null) {
|
|
4033
|
-
return "unknown-container-format";
|
|
4034
|
-
}
|
|
4035
|
-
if (format === "network-error") {
|
|
4036
|
-
return "network-error";
|
|
4037
|
-
}
|
|
4038
|
-
const [videoTrack, audioTracks] = await Promise.all([
|
|
4039
|
-
input.getPrimaryVideoTrack(),
|
|
4040
|
-
input.getAudioTracks()
|
|
4041
|
-
]);
|
|
4042
|
-
const audioTrack = await resolveAudioTrack({
|
|
4043
|
-
videoTrack,
|
|
4044
|
-
audioTracks,
|
|
4045
|
-
audioStreamIndex: index
|
|
4046
|
-
});
|
|
4047
|
-
if (!audioTrack) {
|
|
4048
|
-
return "no-audio-track";
|
|
4049
|
-
}
|
|
4050
|
-
const canDecode = await audioTrack.canDecode();
|
|
4051
|
-
if (!canDecode) {
|
|
4052
|
-
return "cannot-decode-audio";
|
|
4053
|
-
}
|
|
4054
|
-
return {
|
|
4055
|
-
sampleSink: new AudioSampleSink(audioTrack)
|
|
4056
|
-
};
|
|
4057
|
-
};
|
|
4058
|
-
const getAudioSinksPromise = (index) => {
|
|
4059
|
-
const keyIndex = index === null ? -1 : index;
|
|
4060
|
-
if (audioSinksPromise[keyIndex]) {
|
|
4061
|
-
return audioSinksPromise[keyIndex];
|
|
4062
|
-
}
|
|
4063
|
-
audioSinksPromise[keyIndex] = getAudioSinks(index);
|
|
4064
|
-
return audioSinksPromise[keyIndex];
|
|
4065
|
-
};
|
|
4066
|
-
return {
|
|
4067
|
-
getVideo: () => getVideoSinksPromise(),
|
|
4068
|
-
getAudio: (index) => getAudioSinksPromise(index),
|
|
4069
|
-
actualMatroskaTimestamps: rememberActualMatroskaTimestamps(isMatroska),
|
|
4070
|
-
isMatroska,
|
|
4071
|
-
getDuration: () => {
|
|
4072
|
-
return getDurationOrCompute(input);
|
|
4073
|
-
}
|
|
4074
|
-
};
|
|
4075
|
-
};
|
|
4076
|
-
|
|
4077
|
-
// src/get-sink.ts
|
|
4078
|
-
var sinkPromises = {};
|
|
4079
|
-
var getSinkCacheKey = ({
|
|
4080
|
-
src,
|
|
4081
|
-
credentials,
|
|
4082
|
-
requestInit
|
|
4083
|
-
}) => JSON.stringify([
|
|
4084
|
-
src,
|
|
4085
|
-
credentials,
|
|
4086
|
-
getMediaRequestInitFingerprint(requestInit)
|
|
4087
|
-
]);
|
|
4088
|
-
var getSink = (src, logLevel, credentials, requestInit) => {
|
|
4089
|
-
const normalizedRequestInit = normalizeMediaRequestInit(requestInit);
|
|
4090
|
-
const cacheKey = getSinkCacheKey({
|
|
4091
|
-
src,
|
|
4092
|
-
credentials,
|
|
4093
|
-
requestInit: normalizedRequestInit
|
|
4094
|
-
});
|
|
4095
|
-
let promise = sinkPromises[cacheKey];
|
|
4096
|
-
if (!promise) {
|
|
4097
|
-
Internals14.Log.verbose({
|
|
4098
|
-
logLevel,
|
|
4099
|
-
tag: "@remotion/media"
|
|
4100
|
-
}, `Sink for ${src} was not found, creating new sink`);
|
|
4101
|
-
promise = getSinks(src, logLevel, credentials, normalizedRequestInit);
|
|
4102
|
-
sinkPromises[cacheKey] = promise;
|
|
4103
|
-
}
|
|
4104
|
-
return promise;
|
|
4105
|
-
};
|
|
4106
|
-
|
|
4107
4269
|
// src/audio-extraction/extract-audio.ts
|
|
4108
4270
|
var extractAudioInternal = async ({
|
|
4109
4271
|
src,
|
|
@@ -4118,9 +4280,10 @@ var extractAudioInternal = async ({
|
|
|
4118
4280
|
fps,
|
|
4119
4281
|
maxCacheSize,
|
|
4120
4282
|
credentials,
|
|
4121
|
-
requestInit
|
|
4283
|
+
requestInit,
|
|
4284
|
+
mediaCache
|
|
4122
4285
|
}) => {
|
|
4123
|
-
const { getAudio, actualMatroskaTimestamps, isMatroska, getDuration } = await getSink(src, logLevel, credentials, requestInit);
|
|
4286
|
+
const { getAudio, actualMatroskaTimestamps, isMatroska, getDuration } = await mediaCache.sinkManager.getSink(src, logLevel, credentials, requestInit);
|
|
4124
4287
|
let mediaDurationInSeconds = null;
|
|
4125
4288
|
if (loop) {
|
|
4126
4289
|
mediaDurationInSeconds = await getDuration();
|
|
@@ -4153,7 +4316,7 @@ var extractAudioInternal = async ({
|
|
|
4153
4316
|
return { data: null, durationInSeconds: mediaDurationInSeconds };
|
|
4154
4317
|
}
|
|
4155
4318
|
try {
|
|
4156
|
-
const sampleIterator = await audioManager.getIterator({
|
|
4319
|
+
const sampleIterator = await mediaCache.audioManager.getIterator({
|
|
4157
4320
|
src,
|
|
4158
4321
|
timeInSeconds,
|
|
4159
4322
|
audioSampleSink: audio.sampleSink,
|
|
@@ -4164,7 +4327,7 @@ var extractAudioInternal = async ({
|
|
|
4164
4327
|
});
|
|
4165
4328
|
const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
|
|
4166
4329
|
const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
|
|
4167
|
-
audioManager.logOpenFrames();
|
|
4330
|
+
mediaCache.audioManager.logOpenFrames();
|
|
4168
4331
|
const audioDataArray = [];
|
|
4169
4332
|
for (let i = 0;i < samples.length; i++) {
|
|
4170
4333
|
const sample = samples[i];
|
|
@@ -4229,10 +4392,8 @@ var extractAudioInternal = async ({
|
|
|
4229
4392
|
throw err;
|
|
4230
4393
|
}
|
|
4231
4394
|
};
|
|
4232
|
-
var queue = Promise.resolve(undefined);
|
|
4233
4395
|
var extractAudio = (params) => {
|
|
4234
|
-
|
|
4235
|
-
return queue;
|
|
4396
|
+
return params.mediaCache.queueAudioExtraction(() => extractAudioInternal(params));
|
|
4236
4397
|
};
|
|
4237
4398
|
|
|
4238
4399
|
// src/video-extraction/extract-frame.ts
|
|
@@ -4248,9 +4409,10 @@ var extractFrameInternal = async ({
|
|
|
4248
4409
|
fps,
|
|
4249
4410
|
maxCacheSize,
|
|
4250
4411
|
credentials,
|
|
4251
|
-
requestInit
|
|
4412
|
+
requestInit,
|
|
4413
|
+
mediaCache
|
|
4252
4414
|
}) => {
|
|
4253
|
-
const sink = await getSink(src, logLevel, credentials, requestInit);
|
|
4415
|
+
const sink = await mediaCache.sinkManager.getSink(src, logLevel, credentials, requestInit);
|
|
4254
4416
|
const [video, mediaDurationInSecondsRaw] = await Promise.all([
|
|
4255
4417
|
sink.getVideo(),
|
|
4256
4418
|
loop ? sink.getDuration() : Promise.resolve(null)
|
|
@@ -4300,7 +4462,7 @@ var extractFrameInternal = async ({
|
|
|
4300
4462
|
};
|
|
4301
4463
|
}
|
|
4302
4464
|
try {
|
|
4303
|
-
const keyframeBank = await keyframeManager.requestKeyframeBank({
|
|
4465
|
+
const keyframeBank = await mediaCache.keyframeManager.requestKeyframeBank({
|
|
4304
4466
|
videoSampleSink: video.sampleSink,
|
|
4305
4467
|
timestamp: timeInSeconds,
|
|
4306
4468
|
src,
|
|
@@ -4329,10 +4491,8 @@ var extractFrameInternal = async ({
|
|
|
4329
4491
|
return { type: "cannot-decode", durationInSeconds: mediaDurationInSeconds };
|
|
4330
4492
|
}
|
|
4331
4493
|
};
|
|
4332
|
-
var queue2 = Promise.resolve(undefined);
|
|
4333
4494
|
var extractFrame = (params) => {
|
|
4334
|
-
|
|
4335
|
-
return queue2;
|
|
4495
|
+
return params.mediaCache.queueFrameExtraction(() => extractFrameInternal(params));
|
|
4336
4496
|
};
|
|
4337
4497
|
|
|
4338
4498
|
// src/video-extraction/rotate-frame.ts
|
|
@@ -4384,7 +4544,8 @@ var extractFrameAndAudio = async ({
|
|
|
4384
4544
|
fps,
|
|
4385
4545
|
maxCacheSize,
|
|
4386
4546
|
credentials,
|
|
4387
|
-
requestInit
|
|
4547
|
+
requestInit,
|
|
4548
|
+
mediaCache
|
|
4388
4549
|
}) => {
|
|
4389
4550
|
try {
|
|
4390
4551
|
const [video, audio] = await Promise.all([
|
|
@@ -4399,7 +4560,8 @@ var extractFrameAndAudio = async ({
|
|
|
4399
4560
|
fps,
|
|
4400
4561
|
maxCacheSize,
|
|
4401
4562
|
credentials,
|
|
4402
|
-
requestInit
|
|
4563
|
+
requestInit,
|
|
4564
|
+
mediaCache
|
|
4403
4565
|
}) : null,
|
|
4404
4566
|
includeAudio ? extractAudio({
|
|
4405
4567
|
src,
|
|
@@ -4414,7 +4576,8 @@ var extractFrameAndAudio = async ({
|
|
|
4414
4576
|
trimBefore,
|
|
4415
4577
|
maxCacheSize,
|
|
4416
4578
|
credentials,
|
|
4417
|
-
requestInit
|
|
4579
|
+
requestInit,
|
|
4580
|
+
mediaCache
|
|
4418
4581
|
}) : null
|
|
4419
4582
|
]);
|
|
4420
4583
|
if (video?.type === "cannot-decode") {
|
|
@@ -4505,7 +4668,8 @@ var addBroadcastChannelListener = () => {
|
|
|
4505
4668
|
fps: data.fps,
|
|
4506
4669
|
maxCacheSize: data.maxCacheSize,
|
|
4507
4670
|
credentials: data.credentials,
|
|
4508
|
-
requestInit: data.requestInit
|
|
4671
|
+
requestInit: data.requestInit,
|
|
4672
|
+
mediaCache: globalMediaCache
|
|
4509
4673
|
});
|
|
4510
4674
|
if (result.type === "cannot-decode") {
|
|
4511
4675
|
const cannotDecodeResponse = {
|
|
@@ -4613,7 +4777,8 @@ var extractFrameViaBroadcastChannel = async ({
|
|
|
4613
4777
|
fps,
|
|
4614
4778
|
maxCacheSize,
|
|
4615
4779
|
credentials,
|
|
4616
|
-
requestInit
|
|
4780
|
+
requestInit,
|
|
4781
|
+
mediaCache
|
|
4617
4782
|
}) => {
|
|
4618
4783
|
if (isClientSideRendering || window.remotion_isMainTab) {
|
|
4619
4784
|
return extractFrameAndAudio({
|
|
@@ -4631,7 +4796,8 @@ var extractFrameViaBroadcastChannel = async ({
|
|
|
4631
4796
|
fps,
|
|
4632
4797
|
maxCacheSize,
|
|
4633
4798
|
credentials,
|
|
4634
|
-
requestInit
|
|
4799
|
+
requestInit,
|
|
4800
|
+
mediaCache
|
|
4635
4801
|
});
|
|
4636
4802
|
}
|
|
4637
4803
|
await waitForMainTabToBeReady(window.remotion_broadcastChannel);
|
|
@@ -4786,6 +4952,7 @@ var AudioForRendering = ({
|
|
|
4786
4952
|
sequenceContext?.durationInFrames
|
|
4787
4953
|
]);
|
|
4788
4954
|
const maxCacheSize = useMaxMediaCacheSize(logLevel);
|
|
4955
|
+
const mediaCache = useRenderMediaCache(logLevel);
|
|
4789
4956
|
const audioEnabled = Internals16.useAudioEnabled();
|
|
4790
4957
|
useLayoutEffect2(() => {
|
|
4791
4958
|
const timestamp = frame / fps;
|
|
@@ -4825,8 +4992,12 @@ var AudioForRendering = ({
|
|
|
4825
4992
|
fps,
|
|
4826
4993
|
maxCacheSize,
|
|
4827
4994
|
credentials,
|
|
4828
|
-
requestInit: initialRequestInit
|
|
4995
|
+
requestInit: initialRequestInit,
|
|
4996
|
+
mediaCache
|
|
4829
4997
|
}).then((result) => {
|
|
4998
|
+
if (mediaCache.isDisposed()) {
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
4830
5001
|
const handleError = (error, clientSideError, fallbackMessage) => {
|
|
4831
5002
|
const [action, errorToUse] = callOnErrorAndResolve({
|
|
4832
5003
|
onError,
|
|
@@ -4888,6 +5059,9 @@ var AudioForRendering = ({
|
|
|
4888
5059
|
}
|
|
4889
5060
|
continueRender(newHandle);
|
|
4890
5061
|
}).catch((error) => {
|
|
5062
|
+
if (mediaCache.isDisposed()) {
|
|
5063
|
+
return;
|
|
5064
|
+
}
|
|
4891
5065
|
cancelRender2(error);
|
|
4892
5066
|
});
|
|
4893
5067
|
return () => {
|
|
@@ -4924,7 +5098,8 @@ var AudioForRendering = ({
|
|
|
4924
5098
|
audioEnabled,
|
|
4925
5099
|
onError,
|
|
4926
5100
|
credentials,
|
|
4927
|
-
initialRequestInit
|
|
5101
|
+
initialRequestInit,
|
|
5102
|
+
mediaCache
|
|
4928
5103
|
]);
|
|
4929
5104
|
if (replaceWithHtml5Audio) {
|
|
4930
5105
|
return /* @__PURE__ */ jsx2(Html5Audio, {
|
|
@@ -5674,6 +5849,7 @@ var VideoForRendering = ({
|
|
|
5674
5849
|
const audioEnabled = Internals21.useAudioEnabled();
|
|
5675
5850
|
const videoEnabled = Internals21.useVideoEnabled();
|
|
5676
5851
|
const maxCacheSize = useMaxMediaCacheSize(logLevel);
|
|
5852
|
+
const mediaCache = useRenderMediaCache(logLevel);
|
|
5677
5853
|
const effectChainState = Internals21.useEffectChainState();
|
|
5678
5854
|
const [error, setError] = useState5(null);
|
|
5679
5855
|
if (error) {
|
|
@@ -5720,8 +5896,15 @@ var VideoForRendering = ({
|
|
|
5720
5896
|
fps,
|
|
5721
5897
|
maxCacheSize,
|
|
5722
5898
|
credentials,
|
|
5723
|
-
requestInit: initialRequestInit
|
|
5899
|
+
requestInit: initialRequestInit,
|
|
5900
|
+
mediaCache
|
|
5724
5901
|
}).then(async (result) => {
|
|
5902
|
+
if (mediaCache.isDisposed()) {
|
|
5903
|
+
if (result.type === "success") {
|
|
5904
|
+
result.frame?.close();
|
|
5905
|
+
}
|
|
5906
|
+
return;
|
|
5907
|
+
}
|
|
5725
5908
|
const handleError = (err, clientSideError, fallbackMessage, mediaDurationInSeconds) => {
|
|
5726
5909
|
if (environment.isClientSideRendering) {
|
|
5727
5910
|
cancelRender3(clientSideError);
|
|
@@ -5791,7 +5974,7 @@ var VideoForRendering = ({
|
|
|
5791
5974
|
width: imageBitmap.width,
|
|
5792
5975
|
height: imageBitmap.height
|
|
5793
5976
|
});
|
|
5794
|
-
if (!completed) {
|
|
5977
|
+
if (!completed || mediaCache.isDisposed()) {
|
|
5795
5978
|
imageBitmap.close();
|
|
5796
5979
|
return;
|
|
5797
5980
|
}
|
|
@@ -5834,6 +6017,9 @@ var VideoForRendering = ({
|
|
|
5834
6017
|
}
|
|
5835
6018
|
continueRender(newHandle);
|
|
5836
6019
|
}).catch((err) => {
|
|
6020
|
+
if (mediaCache.isDisposed()) {
|
|
6021
|
+
return;
|
|
6022
|
+
}
|
|
5837
6023
|
cancelRender3(err);
|
|
5838
6024
|
});
|
|
5839
6025
|
return () => {
|
|
@@ -5876,7 +6062,8 @@ var VideoForRendering = ({
|
|
|
5876
6062
|
credentials,
|
|
5877
6063
|
effectChainState,
|
|
5878
6064
|
effects,
|
|
5879
|
-
initialRequestInit
|
|
6065
|
+
initialRequestInit,
|
|
6066
|
+
mediaCache
|
|
5880
6067
|
]);
|
|
5881
6068
|
warnAboutObjectFitInStyleOrClassName({ style, className, logLevel });
|
|
5882
6069
|
const classNameValue = useMemo5(() => {
|