@remotion/studio 4.0.452 → 4.0.454
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-waveform-worker.d.ts +1 -0
- package/dist/audio-waveform-worker.js +102 -0
- package/dist/components/AudioWaveform.d.ts +2 -0
- package/dist/components/AudioWaveform.js +168 -18
- package/dist/components/CurrentAsset.js +13 -5
- package/dist/components/Timeline/LoopedIndicator.js +5 -19
- package/dist/components/Timeline/TimelineSequence.js +18 -10
- package/dist/components/Timeline/TimelineVideoInfo.d.ts +2 -0
- package/dist/components/Timeline/TimelineVideoInfo.js +51 -12
- package/dist/components/audio-waveform-worker-types.d.ts +28 -0
- package/dist/components/audio-waveform-worker-types.js +2 -0
- package/dist/components/draw-peaks.d.ts +1 -1
- package/dist/components/load-waveform-peaks.d.ts +11 -1
- package/dist/components/load-waveform-peaks.js +33 -36
- package/dist/components/looped-media-timeline.d.ts +6 -0
- package/dist/components/looped-media-timeline.js +14 -0
- package/dist/components/slice-waveform-peaks.d.ts +7 -0
- package/dist/components/slice-waveform-peaks.js +15 -0
- package/dist/components/waveform-peak-processor.d.ts +23 -0
- package/dist/components/waveform-peak-processor.js +77 -0
- package/dist/esm/audio-waveform-worker.mjs +351 -0
- package/dist/esm/{chunk-hxr6txpe.js → chunk-g39hwn0a.js} +434 -108
- package/dist/esm/internals.mjs +434 -108
- package/dist/esm/previewEntry.mjs +434 -108
- package/dist/esm/renderEntry.mjs +1 -1
- package/dist/helpers/calculate-timeline.js +16 -0
- package/dist/helpers/extract-frames.js +12 -3
- package/dist/helpers/get-duration-or-compute.d.ts +2 -0
- package/dist/helpers/get-duration-or-compute.js +10 -0
- package/dist/helpers/get-timeline-nestedness.js +2 -1
- package/dist/helpers/use-max-media-duration.js +2 -2
- package/dist/make-audio-waveform-worker.d.ts +1 -0
- package/dist/make-audio-waveform-worker.js +10 -0
- package/package.json +19 -10
|
@@ -4366,6 +4366,13 @@ import { ALL_FORMATS, Input, UrlSource } from "mediabunny";
|
|
|
4366
4366
|
import { useContext as useContext12, useEffect as useEffect14, useMemo as useMemo24, useState as useState17 } from "react";
|
|
4367
4367
|
import { Internals as Internals9, staticFile } from "remotion";
|
|
4368
4368
|
|
|
4369
|
+
// src/helpers/get-duration-or-compute.ts
|
|
4370
|
+
var getDurationOrCompute = async (input) => {
|
|
4371
|
+
return await input.getDurationFromMetadata(undefined, {
|
|
4372
|
+
skipLiveWait: true
|
|
4373
|
+
}) ?? input.computeDuration(undefined, { skipLiveWait: true });
|
|
4374
|
+
};
|
|
4375
|
+
|
|
4369
4376
|
// src/components/use-static-files.ts
|
|
4370
4377
|
import React26, { createContext as createContext10, useContext as useContext11, useEffect as useEffect13, useState as useState16 } from "react";
|
|
4371
4378
|
import { useRemotionEnvironment } from "remotion";
|
|
@@ -4509,15 +4516,21 @@ var CurrentAsset = () => {
|
|
|
4509
4516
|
source: new UrlSource(url)
|
|
4510
4517
|
});
|
|
4511
4518
|
Promise.all([
|
|
4512
|
-
input
|
|
4519
|
+
getDurationOrCompute(input),
|
|
4513
4520
|
input.getFormat(),
|
|
4514
4521
|
input.getPrimaryVideoTrack()
|
|
4515
|
-
]).then(([duration, format, videoTrack]) => {
|
|
4522
|
+
]).then(async ([duration, format, videoTrack]) => {
|
|
4523
|
+
if (videoTrack && await videoTrack.isLive()) {
|
|
4524
|
+
throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + url);
|
|
4525
|
+
}
|
|
4526
|
+
if (videoTrack && await videoTrack.isRelativeToUnixEpoch()) {
|
|
4527
|
+
throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + url);
|
|
4528
|
+
}
|
|
4516
4529
|
setMediaMetadata({
|
|
4517
4530
|
duration,
|
|
4518
4531
|
format: format.name,
|
|
4519
|
-
width: videoTrack
|
|
4520
|
-
height: videoTrack
|
|
4532
|
+
width: videoTrack ? await videoTrack.getDisplayWidth() : null,
|
|
4533
|
+
height: videoTrack ? await videoTrack.getDisplayHeight() : null
|
|
4521
4534
|
});
|
|
4522
4535
|
}).catch(() => {});
|
|
4523
4536
|
return () => {
|
|
@@ -20439,7 +20452,8 @@ var getTimelineNestedLevel = (sequence, allSequences, depth) => {
|
|
|
20439
20452
|
if (!parentSequence) {
|
|
20440
20453
|
throw new Error("has parentId but no parent");
|
|
20441
20454
|
}
|
|
20442
|
-
|
|
20455
|
+
const parentContributes = parentSequence.showInTimeline;
|
|
20456
|
+
return getTimelineNestedLevel(parentSequence, allSequences, parentContributes ? depth + 1 : depth);
|
|
20443
20457
|
};
|
|
20444
20458
|
|
|
20445
20459
|
// src/helpers/get-timeline-sequence-hash.ts
|
|
@@ -20488,6 +20502,19 @@ var getTimelineSequenceSequenceSortKey = (track, tracks, sameHashes = {}, nonceR
|
|
|
20488
20502
|
};
|
|
20489
20503
|
|
|
20490
20504
|
// src/helpers/calculate-timeline.ts
|
|
20505
|
+
var getInheritedLoopDisplay = (sequence, sequences) => {
|
|
20506
|
+
if (sequence.loopDisplay) {
|
|
20507
|
+
return sequence.loopDisplay;
|
|
20508
|
+
}
|
|
20509
|
+
if (!sequence.parent) {
|
|
20510
|
+
return;
|
|
20511
|
+
}
|
|
20512
|
+
const parent = sequences.find((s) => s.id === sequence.parent);
|
|
20513
|
+
if (!parent) {
|
|
20514
|
+
return;
|
|
20515
|
+
}
|
|
20516
|
+
return getInheritedLoopDisplay(parent, sequences);
|
|
20517
|
+
};
|
|
20491
20518
|
var calculateTimeline = ({
|
|
20492
20519
|
sequences
|
|
20493
20520
|
}) => {
|
|
@@ -20516,7 +20543,8 @@ var calculateTimeline = ({
|
|
|
20516
20543
|
sequence: {
|
|
20517
20544
|
...sequence,
|
|
20518
20545
|
from: visibleStart,
|
|
20519
|
-
duration: visibleDuration
|
|
20546
|
+
duration: visibleDuration,
|
|
20547
|
+
loopDisplay: sequence.type === "audio" || sequence.type === "video" ? getInheritedLoopDisplay(sequence, sortedSequences) : sequence.loopDisplay
|
|
20520
20548
|
},
|
|
20521
20549
|
depth: getTimelineNestedLevel(sequence, sortedSequences, 0),
|
|
20522
20550
|
hash: actualHash,
|
|
@@ -23125,7 +23153,7 @@ var useMaxMediaDuration = (s, fps) => {
|
|
|
23125
23153
|
formats: ALL_FORMATS2,
|
|
23126
23154
|
source: new UrlSource2(src)
|
|
23127
23155
|
});
|
|
23128
|
-
input2
|
|
23156
|
+
getDurationOrCompute(input2).then((duration) => {
|
|
23129
23157
|
cache.set(src, Math.floor(duration * fps));
|
|
23130
23158
|
setMaxMediaDuration(Math.floor(duration * fps));
|
|
23131
23159
|
}).catch((e) => {
|
|
@@ -23152,6 +23180,13 @@ var useMaxMediaDuration = (s, fps) => {
|
|
|
23152
23180
|
import { useEffect as useEffect72, useMemo as useMemo119, useRef as useRef43, useState as useState77 } from "react";
|
|
23153
23181
|
import { Internals as Internals55 } from "remotion";
|
|
23154
23182
|
|
|
23183
|
+
// src/make-audio-waveform-worker.ts
|
|
23184
|
+
var makeAudioWaveformWorker = () => {
|
|
23185
|
+
return new Worker(new URL("./audio-waveform-worker.mjs", import.meta.url), {
|
|
23186
|
+
type: "module"
|
|
23187
|
+
});
|
|
23188
|
+
};
|
|
23189
|
+
|
|
23155
23190
|
// src/components/parse-color.ts
|
|
23156
23191
|
var colorCache = new Map;
|
|
23157
23192
|
var parseColor = (color) => {
|
|
@@ -23227,12 +23262,107 @@ var drawBars = (canvas, peaks, color, volume, width) => {
|
|
|
23227
23262
|
|
|
23228
23263
|
// src/components/load-waveform-peaks.ts
|
|
23229
23264
|
import { ALL_FORMATS as ALL_FORMATS3, AudioSampleSink, Input as Input3, UrlSource as UrlSource3 } from "mediabunny";
|
|
23265
|
+
|
|
23266
|
+
// src/components/waveform-peak-processor.ts
|
|
23267
|
+
var emitWaveformProgress = ({
|
|
23268
|
+
completedPeaks,
|
|
23269
|
+
final,
|
|
23270
|
+
onProgress,
|
|
23271
|
+
peaks,
|
|
23272
|
+
totalPeaks
|
|
23273
|
+
}) => {
|
|
23274
|
+
onProgress?.({
|
|
23275
|
+
peaks,
|
|
23276
|
+
completedPeaks,
|
|
23277
|
+
totalPeaks,
|
|
23278
|
+
final
|
|
23279
|
+
});
|
|
23280
|
+
};
|
|
23281
|
+
var createWaveformPeakProcessor = ({
|
|
23282
|
+
totalPeaks,
|
|
23283
|
+
samplesPerPeak,
|
|
23284
|
+
onProgress,
|
|
23285
|
+
progressIntervalInMs,
|
|
23286
|
+
now
|
|
23287
|
+
}) => {
|
|
23288
|
+
const peaks = new Float32Array(totalPeaks);
|
|
23289
|
+
let peakIndex = 0;
|
|
23290
|
+
let peakMax = 0;
|
|
23291
|
+
let sampleInPeak = 0;
|
|
23292
|
+
let lastProgressAt = 0;
|
|
23293
|
+
let lastProgressPeak = 0;
|
|
23294
|
+
const emitProgress = (force) => {
|
|
23295
|
+
const timestamp = now();
|
|
23296
|
+
if (!force && peakIndex === lastProgressPeak && sampleInPeak === 0) {
|
|
23297
|
+
return;
|
|
23298
|
+
}
|
|
23299
|
+
if (!force && timestamp - lastProgressAt < progressIntervalInMs) {
|
|
23300
|
+
return;
|
|
23301
|
+
}
|
|
23302
|
+
lastProgressAt = timestamp;
|
|
23303
|
+
lastProgressPeak = peakIndex;
|
|
23304
|
+
emitWaveformProgress({
|
|
23305
|
+
peaks,
|
|
23306
|
+
completedPeaks: peakIndex,
|
|
23307
|
+
totalPeaks,
|
|
23308
|
+
final: force,
|
|
23309
|
+
onProgress
|
|
23310
|
+
});
|
|
23311
|
+
};
|
|
23312
|
+
return {
|
|
23313
|
+
peaks,
|
|
23314
|
+
processSampleChunk: (floats, channels) => {
|
|
23315
|
+
const frameCount = Math.floor(floats.length / Math.max(1, channels));
|
|
23316
|
+
for (let frame2 = 0;frame2 < frameCount; frame2++) {
|
|
23317
|
+
let framePeak = 0;
|
|
23318
|
+
for (let channel = 0;channel < channels; channel++) {
|
|
23319
|
+
const sampleIndex = frame2 * channels + channel;
|
|
23320
|
+
const abs = Math.abs(floats[sampleIndex] ?? 0);
|
|
23321
|
+
if (abs > framePeak) {
|
|
23322
|
+
framePeak = abs;
|
|
23323
|
+
}
|
|
23324
|
+
}
|
|
23325
|
+
if (framePeak > peakMax) {
|
|
23326
|
+
peakMax = framePeak;
|
|
23327
|
+
}
|
|
23328
|
+
sampleInPeak++;
|
|
23329
|
+
if (sampleInPeak >= samplesPerPeak) {
|
|
23330
|
+
if (peakIndex < totalPeaks) {
|
|
23331
|
+
peaks[peakIndex] = peakMax;
|
|
23332
|
+
}
|
|
23333
|
+
peakIndex++;
|
|
23334
|
+
peakMax = 0;
|
|
23335
|
+
sampleInPeak = 0;
|
|
23336
|
+
}
|
|
23337
|
+
}
|
|
23338
|
+
emitProgress(false);
|
|
23339
|
+
},
|
|
23340
|
+
finalize: () => {
|
|
23341
|
+
if (sampleInPeak > 0 && peakIndex < totalPeaks) {
|
|
23342
|
+
peaks[peakIndex] = peakMax;
|
|
23343
|
+
peakIndex++;
|
|
23344
|
+
}
|
|
23345
|
+
emitProgress(true);
|
|
23346
|
+
}
|
|
23347
|
+
};
|
|
23348
|
+
};
|
|
23349
|
+
|
|
23350
|
+
// src/components/load-waveform-peaks.ts
|
|
23230
23351
|
var TARGET_SAMPLE_RATE = 100;
|
|
23352
|
+
var DEFAULT_PROGRESS_INTERVAL_IN_MS = 50;
|
|
23231
23353
|
var peaksCache = new Map;
|
|
23232
|
-
async function loadWaveformPeaks(url, signal) {
|
|
23354
|
+
async function loadWaveformPeaks(url, signal, options) {
|
|
23233
23355
|
const cached = peaksCache.get(url);
|
|
23234
|
-
if (cached)
|
|
23356
|
+
if (cached) {
|
|
23357
|
+
emitWaveformProgress({
|
|
23358
|
+
peaks: cached,
|
|
23359
|
+
completedPeaks: cached.length,
|
|
23360
|
+
totalPeaks: cached.length,
|
|
23361
|
+
final: true,
|
|
23362
|
+
onProgress: options?.onProgress
|
|
23363
|
+
});
|
|
23235
23364
|
return cached;
|
|
23365
|
+
}
|
|
23236
23366
|
const input2 = new Input3({
|
|
23237
23367
|
formats: ALL_FORMATS3,
|
|
23238
23368
|
source: new UrlSource3(url)
|
|
@@ -23242,15 +23372,24 @@ async function loadWaveformPeaks(url, signal) {
|
|
|
23242
23372
|
if (!audioTrack) {
|
|
23243
23373
|
return new Float32Array(0);
|
|
23244
23374
|
}
|
|
23245
|
-
|
|
23246
|
-
|
|
23375
|
+
if (await audioTrack.isLive()) {
|
|
23376
|
+
throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + url);
|
|
23377
|
+
}
|
|
23378
|
+
if (await audioTrack.isRelativeToUnixEpoch()) {
|
|
23379
|
+
throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + url);
|
|
23380
|
+
}
|
|
23381
|
+
const sampleRate = await audioTrack.getSampleRate();
|
|
23382
|
+
const durationInSeconds = await audioTrack.getDurationFromMetadata({ skipLiveWait: true }) ?? await audioTrack.computeDuration({ skipLiveWait: true });
|
|
23247
23383
|
const totalPeaks = Math.ceil(durationInSeconds * TARGET_SAMPLE_RATE);
|
|
23248
23384
|
const samplesPerPeak = Math.max(1, Math.floor(sampleRate / TARGET_SAMPLE_RATE));
|
|
23249
|
-
const peaks = new Float32Array(totalPeaks);
|
|
23250
|
-
let peakIndex = 0;
|
|
23251
|
-
let peakMax = 0;
|
|
23252
|
-
let sampleInPeak = 0;
|
|
23253
23385
|
const sink = new AudioSampleSink(audioTrack);
|
|
23386
|
+
const processor = createWaveformPeakProcessor({
|
|
23387
|
+
totalPeaks,
|
|
23388
|
+
samplesPerPeak,
|
|
23389
|
+
onProgress: options?.onProgress,
|
|
23390
|
+
progressIntervalInMs: options?.progressIntervalInMs ?? DEFAULT_PROGRESS_INTERVAL_IN_MS,
|
|
23391
|
+
now: () => Date.now()
|
|
23392
|
+
});
|
|
23254
23393
|
for await (const sample of sink.samples()) {
|
|
23255
23394
|
if (signal.aborted) {
|
|
23256
23395
|
sample.close();
|
|
@@ -23263,34 +23402,11 @@ async function loadWaveformPeaks(url, signal) {
|
|
|
23263
23402
|
const floats = new Float32Array(bytesNeeded / 4);
|
|
23264
23403
|
sample.copyTo(floats, { format: "f32", planeIndex: 0 });
|
|
23265
23404
|
const channels = Math.max(1, sample.numberOfChannels);
|
|
23266
|
-
const frames = sample.numberOfFrames;
|
|
23267
23405
|
sample.close();
|
|
23268
|
-
|
|
23269
|
-
let framePeak = 0;
|
|
23270
|
-
for (let channel = 0;channel < channels; channel++) {
|
|
23271
|
-
const sampleIndex = frame2 * channels + channel;
|
|
23272
|
-
const abs = Math.abs(floats[sampleIndex] ?? 0);
|
|
23273
|
-
if (abs > framePeak) {
|
|
23274
|
-
framePeak = abs;
|
|
23275
|
-
}
|
|
23276
|
-
}
|
|
23277
|
-
if (framePeak > peakMax) {
|
|
23278
|
-
peakMax = framePeak;
|
|
23279
|
-
}
|
|
23280
|
-
sampleInPeak++;
|
|
23281
|
-
if (sampleInPeak >= samplesPerPeak) {
|
|
23282
|
-
if (peakIndex < totalPeaks) {
|
|
23283
|
-
peaks[peakIndex] = peakMax;
|
|
23284
|
-
}
|
|
23285
|
-
peakIndex++;
|
|
23286
|
-
peakMax = 0;
|
|
23287
|
-
sampleInPeak = 0;
|
|
23288
|
-
}
|
|
23289
|
-
}
|
|
23290
|
-
}
|
|
23291
|
-
if (sampleInPeak > 0 && peakIndex < totalPeaks) {
|
|
23292
|
-
peaks[peakIndex] = peakMax;
|
|
23406
|
+
processor.processSampleChunk(floats, channels);
|
|
23293
23407
|
}
|
|
23408
|
+
processor.finalize();
|
|
23409
|
+
const { peaks } = processor;
|
|
23294
23410
|
peaksCache.set(url, peaks);
|
|
23295
23411
|
return peaks;
|
|
23296
23412
|
} finally {
|
|
@@ -23298,8 +23414,50 @@ async function loadWaveformPeaks(url, signal) {
|
|
|
23298
23414
|
}
|
|
23299
23415
|
}
|
|
23300
23416
|
|
|
23417
|
+
// src/components/looped-media-timeline.ts
|
|
23418
|
+
var shouldTileLoopDisplay = (loopDisplay) => {
|
|
23419
|
+
return loopDisplay !== undefined && loopDisplay.numberOfTimes > 1;
|
|
23420
|
+
};
|
|
23421
|
+
var getLoopDisplayWidth = ({
|
|
23422
|
+
visualizationWidth,
|
|
23423
|
+
loopDisplay
|
|
23424
|
+
}) => {
|
|
23425
|
+
if (!shouldTileLoopDisplay(loopDisplay)) {
|
|
23426
|
+
return visualizationWidth;
|
|
23427
|
+
}
|
|
23428
|
+
return visualizationWidth / loopDisplay.numberOfTimes;
|
|
23429
|
+
};
|
|
23430
|
+
|
|
23431
|
+
// src/components/slice-waveform-peaks.ts
|
|
23432
|
+
var sliceWaveformPeaks = ({
|
|
23433
|
+
durationInFrames,
|
|
23434
|
+
fps,
|
|
23435
|
+
peaks,
|
|
23436
|
+
playbackRate,
|
|
23437
|
+
startFrom
|
|
23438
|
+
}) => {
|
|
23439
|
+
if (peaks.length === 0) {
|
|
23440
|
+
return peaks;
|
|
23441
|
+
}
|
|
23442
|
+
const startTimeInSeconds = startFrom / fps;
|
|
23443
|
+
const durationInSeconds = durationInFrames / fps * playbackRate;
|
|
23444
|
+
const startPeakIndex = Math.floor(startTimeInSeconds * TARGET_SAMPLE_RATE);
|
|
23445
|
+
const endPeakIndex = Math.ceil((startTimeInSeconds + durationInSeconds) * TARGET_SAMPLE_RATE);
|
|
23446
|
+
return peaks.subarray(Math.max(0, startPeakIndex), Math.min(peaks.length, endPeakIndex));
|
|
23447
|
+
};
|
|
23448
|
+
|
|
23301
23449
|
// src/components/AudioWaveform.tsx
|
|
23302
23450
|
import { jsx as jsx209, jsxs as jsxs101 } from "react/jsx-runtime";
|
|
23451
|
+
var EMPTY_PEAKS = new Float32Array(0);
|
|
23452
|
+
var canRetryCanvasTransfer = (err) => {
|
|
23453
|
+
return err instanceof DOMException && err.name === "InvalidStateError";
|
|
23454
|
+
};
|
|
23455
|
+
var canUseAudioWaveformWorker = () => {
|
|
23456
|
+
if (typeof Worker === "undefined" || typeof OffscreenCanvas === "undefined" || typeof HTMLCanvasElement === "undefined") {
|
|
23457
|
+
return false;
|
|
23458
|
+
}
|
|
23459
|
+
return "transferControlToOffscreen" in HTMLCanvasElement.prototype;
|
|
23460
|
+
};
|
|
23303
23461
|
var container42 = {
|
|
23304
23462
|
display: "flex",
|
|
23305
23463
|
flexDirection: "row",
|
|
@@ -23318,11 +23476,41 @@ var errorMessage = {
|
|
|
23318
23476
|
opacity: 0.75
|
|
23319
23477
|
};
|
|
23320
23478
|
var waveformCanvasStyle = {
|
|
23321
|
-
pointerEvents: "none"
|
|
23479
|
+
pointerEvents: "none",
|
|
23480
|
+
width: "100%",
|
|
23481
|
+
height: "100%"
|
|
23322
23482
|
};
|
|
23323
23483
|
var volumeCanvasStyle = {
|
|
23324
23484
|
position: "absolute"
|
|
23325
23485
|
};
|
|
23486
|
+
var drawLoopedWaveform = ({
|
|
23487
|
+
canvas,
|
|
23488
|
+
peaks,
|
|
23489
|
+
volume,
|
|
23490
|
+
visualizationWidth,
|
|
23491
|
+
loopWidth
|
|
23492
|
+
}) => {
|
|
23493
|
+
const h = canvas.height;
|
|
23494
|
+
const w = Math.ceil(visualizationWidth);
|
|
23495
|
+
const targetCanvas = document.createElement("canvas");
|
|
23496
|
+
targetCanvas.width = Math.max(1, Math.ceil(loopWidth));
|
|
23497
|
+
targetCanvas.height = h;
|
|
23498
|
+
drawBars(targetCanvas, peaks, "rgba(255, 255, 255, 0.6)", volume, targetCanvas.width);
|
|
23499
|
+
canvas.width = w;
|
|
23500
|
+
canvas.height = h;
|
|
23501
|
+
const ctx = canvas.getContext("2d");
|
|
23502
|
+
if (!ctx) {
|
|
23503
|
+
throw new Error("Failed to get canvas context");
|
|
23504
|
+
}
|
|
23505
|
+
const pattern = ctx.createPattern(targetCanvas, "repeat-x");
|
|
23506
|
+
if (!pattern) {
|
|
23507
|
+
return;
|
|
23508
|
+
}
|
|
23509
|
+
pattern.setTransform(new DOMMatrix().scaleSelf(loopWidth / targetCanvas.width, 1));
|
|
23510
|
+
ctx.clearRect(0, 0, w, h);
|
|
23511
|
+
ctx.fillStyle = pattern;
|
|
23512
|
+
ctx.fillRect(0, 0, w, h);
|
|
23513
|
+
};
|
|
23326
23514
|
var AudioWaveform = ({
|
|
23327
23515
|
src,
|
|
23328
23516
|
startFrom,
|
|
@@ -23330,10 +23518,13 @@ var AudioWaveform = ({
|
|
|
23330
23518
|
visualizationWidth,
|
|
23331
23519
|
volume,
|
|
23332
23520
|
doesVolumeChange,
|
|
23333
|
-
playbackRate
|
|
23521
|
+
playbackRate,
|
|
23522
|
+
loopDisplay
|
|
23334
23523
|
}) => {
|
|
23335
23524
|
const [peaks, setPeaks] = useState77(null);
|
|
23336
23525
|
const [error, setError] = useState77(null);
|
|
23526
|
+
const [waveformCanvasKey, setWaveformCanvasKey] = useState77(0);
|
|
23527
|
+
const canUseWorkerPath = useMemo119(() => canUseAudioWaveformWorker(), []);
|
|
23337
23528
|
const vidConf = Internals55.useUnsafeVideoConfig();
|
|
23338
23529
|
if (vidConf === null) {
|
|
23339
23530
|
throw new Error("Expected video config");
|
|
@@ -23341,8 +23532,15 @@ var AudioWaveform = ({
|
|
|
23341
23532
|
const containerRef = useRef43(null);
|
|
23342
23533
|
const waveformCanvas = useRef43(null);
|
|
23343
23534
|
const volumeCanvas = useRef43(null);
|
|
23535
|
+
const waveformWorker = useRef43(null);
|
|
23536
|
+
const hasTransferredCanvas = useRef43(false);
|
|
23537
|
+
const latestRequestId = useRef43(0);
|
|
23344
23538
|
useEffect72(() => {
|
|
23539
|
+
if (canUseWorkerPath) {
|
|
23540
|
+
return;
|
|
23541
|
+
}
|
|
23345
23542
|
const controller = new AbortController;
|
|
23543
|
+
setPeaks(null);
|
|
23346
23544
|
setError(null);
|
|
23347
23545
|
loadWaveformPeaks(src, controller.signal).then((p) => {
|
|
23348
23546
|
if (!controller.signal.aborted) {
|
|
@@ -23354,30 +23552,127 @@ var AudioWaveform = ({
|
|
|
23354
23552
|
}
|
|
23355
23553
|
});
|
|
23356
23554
|
return () => controller.abort();
|
|
23357
|
-
}, [src]);
|
|
23555
|
+
}, [canUseWorkerPath, src]);
|
|
23556
|
+
useEffect72(() => {
|
|
23557
|
+
if (!canUseWorkerPath) {
|
|
23558
|
+
return;
|
|
23559
|
+
}
|
|
23560
|
+
const canvasElement = waveformCanvas.current;
|
|
23561
|
+
if (!canvasElement || hasTransferredCanvas.current) {
|
|
23562
|
+
return;
|
|
23563
|
+
}
|
|
23564
|
+
const worker = makeAudioWaveformWorker();
|
|
23565
|
+
waveformWorker.current = worker;
|
|
23566
|
+
worker.addEventListener("message", (event) => {
|
|
23567
|
+
if (event.data.type === "error") {
|
|
23568
|
+
if (event.data.requestId !== latestRequestId.current) {
|
|
23569
|
+
return;
|
|
23570
|
+
}
|
|
23571
|
+
setError(new Error(event.data.message));
|
|
23572
|
+
}
|
|
23573
|
+
});
|
|
23574
|
+
let offscreen;
|
|
23575
|
+
try {
|
|
23576
|
+
offscreen = canvasElement.transferControlToOffscreen();
|
|
23577
|
+
} catch (err) {
|
|
23578
|
+
worker.terminate();
|
|
23579
|
+
waveformWorker.current = null;
|
|
23580
|
+
if (canRetryCanvasTransfer(err)) {
|
|
23581
|
+
setWaveformCanvasKey((key4) => key4 + 1);
|
|
23582
|
+
return;
|
|
23583
|
+
}
|
|
23584
|
+
throw err;
|
|
23585
|
+
}
|
|
23586
|
+
hasTransferredCanvas.current = true;
|
|
23587
|
+
worker.postMessage({ type: "init", canvas: offscreen }, [offscreen]);
|
|
23588
|
+
return () => {
|
|
23589
|
+
worker.postMessage({ type: "dispose" });
|
|
23590
|
+
worker.terminate();
|
|
23591
|
+
waveformWorker.current = null;
|
|
23592
|
+
hasTransferredCanvas.current = false;
|
|
23593
|
+
};
|
|
23594
|
+
}, [canUseWorkerPath, waveformCanvasKey]);
|
|
23358
23595
|
const portionPeaks = useMemo119(() => {
|
|
23359
|
-
if (
|
|
23596
|
+
if (canUseWorkerPath || !peaks) {
|
|
23360
23597
|
return null;
|
|
23361
23598
|
}
|
|
23362
|
-
|
|
23363
|
-
|
|
23364
|
-
|
|
23365
|
-
|
|
23366
|
-
|
|
23367
|
-
|
|
23599
|
+
return sliceWaveformPeaks({
|
|
23600
|
+
durationInFrames: shouldTileLoopDisplay(loopDisplay) ? loopDisplay.durationInFrames : durationInFrames,
|
|
23601
|
+
fps: vidConf.fps,
|
|
23602
|
+
peaks,
|
|
23603
|
+
playbackRate,
|
|
23604
|
+
startFrom
|
|
23605
|
+
});
|
|
23606
|
+
}, [
|
|
23607
|
+
canUseWorkerPath,
|
|
23608
|
+
durationInFrames,
|
|
23609
|
+
loopDisplay,
|
|
23610
|
+
peaks,
|
|
23611
|
+
playbackRate,
|
|
23612
|
+
startFrom,
|
|
23613
|
+
vidConf.fps
|
|
23614
|
+
]);
|
|
23368
23615
|
useEffect72(() => {
|
|
23369
23616
|
const { current: canvasElement } = waveformCanvas;
|
|
23370
23617
|
const { current: containerElement } = containerRef;
|
|
23371
|
-
if (!canvasElement || !containerElement
|
|
23618
|
+
if (!canvasElement || !containerElement) {
|
|
23372
23619
|
return;
|
|
23373
23620
|
}
|
|
23374
23621
|
const h = containerElement.clientHeight;
|
|
23375
23622
|
const w = Math.ceil(visualizationWidth);
|
|
23623
|
+
const vol = typeof volume === "number" ? volume : 1;
|
|
23624
|
+
if (canUseWorkerPath) {
|
|
23625
|
+
const worker = waveformWorker.current;
|
|
23626
|
+
if (!worker || !hasTransferredCanvas.current) {
|
|
23627
|
+
return;
|
|
23628
|
+
}
|
|
23629
|
+
latestRequestId.current += 1;
|
|
23630
|
+
setError(null);
|
|
23631
|
+
const message = {
|
|
23632
|
+
type: "render",
|
|
23633
|
+
requestId: latestRequestId.current,
|
|
23634
|
+
src,
|
|
23635
|
+
width: w,
|
|
23636
|
+
height: h,
|
|
23637
|
+
volume: vol,
|
|
23638
|
+
startFrom,
|
|
23639
|
+
durationInFrames,
|
|
23640
|
+
fps: vidConf.fps,
|
|
23641
|
+
playbackRate,
|
|
23642
|
+
loopDisplay
|
|
23643
|
+
};
|
|
23644
|
+
worker.postMessage(message);
|
|
23645
|
+
return;
|
|
23646
|
+
}
|
|
23376
23647
|
canvasElement.width = w;
|
|
23377
23648
|
canvasElement.height = h;
|
|
23378
|
-
|
|
23379
|
-
|
|
23380
|
-
|
|
23649
|
+
if (shouldTileLoopDisplay(loopDisplay)) {
|
|
23650
|
+
drawLoopedWaveform({
|
|
23651
|
+
canvas: canvasElement,
|
|
23652
|
+
peaks: portionPeaks ?? EMPTY_PEAKS,
|
|
23653
|
+
volume: vol,
|
|
23654
|
+
visualizationWidth,
|
|
23655
|
+
loopWidth: getLoopDisplayWidth({
|
|
23656
|
+
visualizationWidth,
|
|
23657
|
+
loopDisplay
|
|
23658
|
+
})
|
|
23659
|
+
});
|
|
23660
|
+
} else {
|
|
23661
|
+
drawBars(canvasElement, portionPeaks ?? EMPTY_PEAKS, "rgba(255, 255, 255, 0.6)", vol, w);
|
|
23662
|
+
}
|
|
23663
|
+
}, [
|
|
23664
|
+
canUseWorkerPath,
|
|
23665
|
+
durationInFrames,
|
|
23666
|
+
loopDisplay,
|
|
23667
|
+
playbackRate,
|
|
23668
|
+
portionPeaks,
|
|
23669
|
+
src,
|
|
23670
|
+
startFrom,
|
|
23671
|
+
vidConf.fps,
|
|
23672
|
+
visualizationWidth,
|
|
23673
|
+
volume,
|
|
23674
|
+
waveformCanvasKey
|
|
23675
|
+
]);
|
|
23381
23676
|
useEffect72(() => {
|
|
23382
23677
|
const { current: volumeCanvasElement } = volumeCanvas;
|
|
23383
23678
|
const { current: containerElement } = containerRef;
|
|
@@ -23411,6 +23706,7 @@ var AudioWaveform = ({
|
|
|
23411
23706
|
context.stroke();
|
|
23412
23707
|
}, [visualizationWidth, volume, doesVolumeChange]);
|
|
23413
23708
|
if (error) {
|
|
23709
|
+
console.error(error);
|
|
23414
23710
|
return /* @__PURE__ */ jsx209("div", {
|
|
23415
23711
|
style: container42,
|
|
23416
23712
|
children: /* @__PURE__ */ jsx209("div", {
|
|
@@ -23419,7 +23715,7 @@ var AudioWaveform = ({
|
|
|
23419
23715
|
})
|
|
23420
23716
|
});
|
|
23421
23717
|
}
|
|
23422
|
-
if (!peaks) {
|
|
23718
|
+
if (!canUseWorkerPath && !peaks) {
|
|
23423
23719
|
return null;
|
|
23424
23720
|
}
|
|
23425
23721
|
return /* @__PURE__ */ jsxs101("div", {
|
|
@@ -23429,7 +23725,7 @@ var AudioWaveform = ({
|
|
|
23429
23725
|
/* @__PURE__ */ jsx209("canvas", {
|
|
23430
23726
|
ref: waveformCanvas,
|
|
23431
23727
|
style: waveformCanvasStyle
|
|
23432
|
-
}),
|
|
23728
|
+
}, waveformCanvasKey),
|
|
23433
23729
|
/* @__PURE__ */ jsx209("canvas", {
|
|
23434
23730
|
ref: volumeCanvas,
|
|
23435
23731
|
style: volumeCanvasStyle
|
|
@@ -23452,7 +23748,8 @@ var width = {
|
|
|
23452
23748
|
position: "relative"
|
|
23453
23749
|
};
|
|
23454
23750
|
var icon4 = {
|
|
23455
|
-
height: 12
|
|
23751
|
+
height: 12,
|
|
23752
|
+
filter: "drop-shadow(0 0 2px rgba(0, 0, 0, 0.9)) drop-shadow(0 1px 2px rgba(0, 0, 0, 0.8))"
|
|
23456
23753
|
};
|
|
23457
23754
|
var Icon = () => /* @__PURE__ */ jsx210("svg", {
|
|
23458
23755
|
viewBox: "0 0 512 512",
|
|
@@ -23462,44 +23759,23 @@ var Icon = () => /* @__PURE__ */ jsx210("svg", {
|
|
|
23462
23759
|
d: "M512 256c0 88.224-71.775 160-160 160H170.067l34.512 32.419c9.875 9.276 10.119 24.883.539 34.464l-10.775 10.775c-9.373 9.372-24.568 9.372-33.941 0l-92.686-92.686c-9.373-9.373-9.373-24.568 0-33.941l92.686-92.686c9.373-9.373 24.568-9.373 33.941 0l10.775 10.775c9.581 9.581 9.337 25.187-.539 34.464L170.067 352H352c52.935 0 96-43.065 96-96 0-13.958-2.996-27.228-8.376-39.204-4.061-9.039-2.284-19.626 4.723-26.633l12.183-12.183c11.499-11.499 30.965-8.526 38.312 5.982C505.814 205.624 512 230.103 512 256zM72.376 295.204C66.996 283.228 64 269.958 64 256c0-52.935 43.065-96 96-96h181.933l-34.512 32.419c-9.875 9.276-10.119 24.883-.539 34.464l10.775 10.775c9.373 9.372 24.568 9.372 33.941 0l92.686-92.686c9.373-9.373 9.373-24.568 0-33.941l-92.686-92.686c-9.373-9.373-24.568-9.373-33.941 0L306.882 29.12c-9.581 9.581-9.337 25.187.539 34.464L341.933 96H160C71.775 96 0 167.776 0 256c0 25.897 6.186 50.376 17.157 72.039 7.347 14.508 26.813 17.481 38.312 5.982l12.183-12.183c7.008-7.008 8.786-17.595 4.724-26.634z"
|
|
23463
23760
|
})
|
|
23464
23761
|
});
|
|
23465
|
-
var
|
|
23466
|
-
|
|
23467
|
-
height: 2,
|
|
23468
|
-
width: 1,
|
|
23469
|
-
background: LIGHT_COLOR
|
|
23470
|
-
};
|
|
23471
|
-
var bottomLine = {
|
|
23472
|
-
top: 0,
|
|
23473
|
-
height: 2,
|
|
23762
|
+
var verticalLine = {
|
|
23763
|
+
height: "100%",
|
|
23474
23764
|
width: 1,
|
|
23475
|
-
background:
|
|
23476
|
-
};
|
|
23477
|
-
var topContainer = {
|
|
23478
|
-
justifyContent: "flex-start",
|
|
23479
|
-
alignItems: "center"
|
|
23765
|
+
background: "rgb(255,255,255, 0.5)"
|
|
23480
23766
|
};
|
|
23481
23767
|
var centerContainer = {
|
|
23482
23768
|
justifyContent: "center",
|
|
23483
23769
|
alignItems: "center"
|
|
23484
23770
|
};
|
|
23485
|
-
var bottomContainer = {
|
|
23486
|
-
justifyContent: "flex-end",
|
|
23487
|
-
alignItems: "center"
|
|
23488
|
-
};
|
|
23489
23771
|
var LoopedIndicator = () => {
|
|
23490
23772
|
return /* @__PURE__ */ jsxs102("div", {
|
|
23491
23773
|
style: width,
|
|
23492
23774
|
children: [
|
|
23493
23775
|
/* @__PURE__ */ jsx210(AbsoluteFill3, {
|
|
23494
|
-
style:
|
|
23495
|
-
children: /* @__PURE__ */ jsx210("div", {
|
|
23496
|
-
style: topLine
|
|
23497
|
-
})
|
|
23498
|
-
}),
|
|
23499
|
-
/* @__PURE__ */ jsx210(AbsoluteFill3, {
|
|
23500
|
-
style: bottomContainer,
|
|
23776
|
+
style: centerContainer,
|
|
23501
23777
|
children: /* @__PURE__ */ jsx210("div", {
|
|
23502
|
-
style:
|
|
23778
|
+
style: verticalLine
|
|
23503
23779
|
})
|
|
23504
23780
|
}),
|
|
23505
23781
|
/* @__PURE__ */ jsx210(AbsoluteFill3, {
|
|
@@ -23642,17 +23918,23 @@ async function extractFrames({
|
|
|
23642
23918
|
}
|
|
23643
23919
|
try {
|
|
23644
23920
|
const [durationInSeconds, format, videoTrack] = await Promise.all([
|
|
23645
|
-
input2
|
|
23921
|
+
getDurationOrCompute(input2),
|
|
23646
23922
|
input2.getFormat(),
|
|
23647
23923
|
input2.getPrimaryVideoTrack()
|
|
23648
23924
|
]);
|
|
23649
23925
|
if (!videoTrack) {
|
|
23650
23926
|
throw new Error("No video track found in the input");
|
|
23651
23927
|
}
|
|
23928
|
+
if (await videoTrack.isLive()) {
|
|
23929
|
+
throw new Error("Live streams are not currently supported by Remotion. Sorry! Source: " + src);
|
|
23930
|
+
}
|
|
23931
|
+
if (await videoTrack.isRelativeToUnixEpoch()) {
|
|
23932
|
+
throw new Error("Streams with UNIX timestamps are not currently supported by Remotion. Sorry! Source: " + src);
|
|
23933
|
+
}
|
|
23652
23934
|
const timestamps = typeof timestampsInSeconds === "function" ? await timestampsInSeconds({
|
|
23653
23935
|
track: {
|
|
23654
|
-
width: videoTrack.
|
|
23655
|
-
height: videoTrack.
|
|
23936
|
+
width: await videoTrack.getDisplayWidth(),
|
|
23937
|
+
height: await videoTrack.getDisplayHeight()
|
|
23656
23938
|
},
|
|
23657
23939
|
container: format.name,
|
|
23658
23940
|
durationInSeconds
|
|
@@ -23971,7 +24253,8 @@ var TimelineVideoInfo = ({
|
|
|
23971
24253
|
volume,
|
|
23972
24254
|
doesVolumeChange,
|
|
23973
24255
|
premountWidth,
|
|
23974
|
-
postmountWidth
|
|
24256
|
+
postmountWidth,
|
|
24257
|
+
loopDisplay
|
|
23975
24258
|
}) => {
|
|
23976
24259
|
const { fps } = useVideoConfig5();
|
|
23977
24260
|
const ref2 = useRef45(null);
|
|
@@ -23994,25 +24277,54 @@ var TimelineVideoInfo = ({
|
|
|
23994
24277
|
return;
|
|
23995
24278
|
}
|
|
23996
24279
|
current.appendChild(canvas);
|
|
24280
|
+
const loopWidth = getLoopDisplayWidth({
|
|
24281
|
+
visualizationWidth: naturalWidth,
|
|
24282
|
+
loopDisplay
|
|
24283
|
+
});
|
|
24284
|
+
const shouldRepeatVideo = shouldTileLoopDisplay(loopDisplay);
|
|
24285
|
+
const targetCanvas = shouldRepeatVideo ? document.createElement("canvas") : canvas;
|
|
24286
|
+
targetCanvas.width = shouldRepeatVideo ? Math.max(1, Math.ceil(loopWidth)) : canvas.width;
|
|
24287
|
+
targetCanvas.height = canvas.height;
|
|
24288
|
+
const targetCtx = shouldRepeatVideo ? targetCanvas.getContext("2d") : ctx;
|
|
24289
|
+
if (!targetCtx) {
|
|
24290
|
+
current.removeChild(canvas);
|
|
24291
|
+
return;
|
|
24292
|
+
}
|
|
24293
|
+
const repeatTarget = () => {
|
|
24294
|
+
if (!shouldRepeatVideo) {
|
|
24295
|
+
return;
|
|
24296
|
+
}
|
|
24297
|
+
const pattern = ctx.createPattern(targetCanvas, "repeat-x");
|
|
24298
|
+
if (!pattern) {
|
|
24299
|
+
return;
|
|
24300
|
+
}
|
|
24301
|
+
pattern.setTransform(new DOMMatrix().scaleSelf(loopWidth / targetCanvas.width, 1));
|
|
24302
|
+
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
24303
|
+
ctx.fillStyle = pattern;
|
|
24304
|
+
ctx.fillRect(0, 0, canvas.width, canvas.height);
|
|
24305
|
+
};
|
|
23997
24306
|
const filledSlots = new Map;
|
|
23998
24307
|
const fromSeconds = trimBefore / fps;
|
|
23999
|
-
const
|
|
24308
|
+
const visibleDurationInFrames = shouldRepeatVideo && loopDisplay ? loopDisplay.durationInFrames : durationInFrames;
|
|
24309
|
+
const toSeconds = fromSeconds + visibleDurationInFrames * playbackRate / fps;
|
|
24310
|
+
const targetWidth = shouldRepeatVideo ? targetCanvas.width : naturalWidth;
|
|
24000
24311
|
if (aspectRatio.current !== null) {
|
|
24001
24312
|
ensureSlots({
|
|
24002
24313
|
filledSlots,
|
|
24003
|
-
naturalWidth,
|
|
24314
|
+
naturalWidth: targetWidth,
|
|
24004
24315
|
fromSeconds,
|
|
24005
24316
|
toSeconds,
|
|
24006
24317
|
aspectRatio: aspectRatio.current
|
|
24007
24318
|
});
|
|
24008
24319
|
fillWithCachedFrames({
|
|
24009
|
-
ctx,
|
|
24010
|
-
naturalWidth,
|
|
24320
|
+
ctx: targetCtx,
|
|
24321
|
+
naturalWidth: targetWidth,
|
|
24011
24322
|
filledSlots,
|
|
24012
24323
|
src,
|
|
24013
24324
|
segmentDuration: toSeconds - fromSeconds,
|
|
24014
24325
|
fromSeconds
|
|
24015
24326
|
});
|
|
24327
|
+
repeatTarget();
|
|
24016
24328
|
const unfilled = Array.from(filledSlots.keys()).filter((timestamp) => !filledSlots.get(timestamp));
|
|
24017
24329
|
if (unfilled.length === 0) {
|
|
24018
24330
|
return () => {
|
|
@@ -24030,7 +24342,7 @@ var TimelineVideoInfo = ({
|
|
|
24030
24342
|
filledSlots,
|
|
24031
24343
|
fromSeconds,
|
|
24032
24344
|
toSeconds,
|
|
24033
|
-
naturalWidth,
|
|
24345
|
+
naturalWidth: targetWidth,
|
|
24034
24346
|
aspectRatio: aspectRatio.current
|
|
24035
24347
|
});
|
|
24036
24348
|
return Array.from(filledSlots.keys()).map((timestamp) => timestamp / WEBCODECS_TIMESCALE);
|
|
@@ -24058,17 +24370,18 @@ var TimelineVideoInfo = ({
|
|
|
24058
24370
|
filledSlots,
|
|
24059
24371
|
fromSeconds,
|
|
24060
24372
|
toSeconds,
|
|
24061
|
-
naturalWidth,
|
|
24373
|
+
naturalWidth: targetWidth,
|
|
24062
24374
|
aspectRatio: aspectRatio.current
|
|
24063
24375
|
});
|
|
24064
24376
|
fillFrameWhereItFits({
|
|
24065
|
-
ctx,
|
|
24377
|
+
ctx: targetCtx,
|
|
24066
24378
|
filledSlots,
|
|
24067
|
-
visualizationWidth:
|
|
24379
|
+
visualizationWidth: targetWidth,
|
|
24068
24380
|
frame: transformed,
|
|
24069
24381
|
segmentDuration: toSeconds - fromSeconds,
|
|
24070
24382
|
fromSeconds
|
|
24071
24383
|
});
|
|
24384
|
+
repeatTarget();
|
|
24072
24385
|
} catch (e) {
|
|
24073
24386
|
if (frame2) {
|
|
24074
24387
|
frame2.close();
|
|
@@ -24084,13 +24397,14 @@ var TimelineVideoInfo = ({
|
|
|
24084
24397
|
return;
|
|
24085
24398
|
}
|
|
24086
24399
|
fillWithCachedFrames({
|
|
24087
|
-
ctx,
|
|
24088
|
-
naturalWidth,
|
|
24400
|
+
ctx: targetCtx,
|
|
24401
|
+
naturalWidth: targetWidth,
|
|
24089
24402
|
filledSlots,
|
|
24090
24403
|
src,
|
|
24091
24404
|
segmentDuration: toSeconds - fromSeconds,
|
|
24092
24405
|
fromSeconds
|
|
24093
24406
|
});
|
|
24407
|
+
repeatTarget();
|
|
24094
24408
|
}).catch((e) => {
|
|
24095
24409
|
setError(e);
|
|
24096
24410
|
});
|
|
@@ -24102,6 +24416,7 @@ var TimelineVideoInfo = ({
|
|
|
24102
24416
|
durationInFrames,
|
|
24103
24417
|
error,
|
|
24104
24418
|
fps,
|
|
24419
|
+
loopDisplay,
|
|
24105
24420
|
naturalWidth,
|
|
24106
24421
|
playbackRate,
|
|
24107
24422
|
src,
|
|
@@ -24133,7 +24448,8 @@ var TimelineVideoInfo = ({
|
|
|
24133
24448
|
durationInFrames,
|
|
24134
24449
|
volume,
|
|
24135
24450
|
doesVolumeChange,
|
|
24136
|
-
playbackRate
|
|
24451
|
+
playbackRate,
|
|
24452
|
+
loopDisplay
|
|
24137
24453
|
})
|
|
24138
24454
|
})
|
|
24139
24455
|
]
|
|
@@ -24158,29 +24474,37 @@ var TimelineSequence = ({ s }) => {
|
|
|
24158
24474
|
var Inner4 = ({ s, windowWidth }) => {
|
|
24159
24475
|
const video = Internals56.useVideo();
|
|
24160
24476
|
const maxMediaDuration = useMaxMediaDuration(s, video?.fps ?? 30);
|
|
24477
|
+
const effectiveMaxMediaDuration = s.loopDisplay ? null : maxMediaDuration;
|
|
24161
24478
|
if (!video) {
|
|
24162
24479
|
throw new TypeError("Expected video config");
|
|
24163
24480
|
}
|
|
24164
24481
|
const frame2 = useCurrentFrame2();
|
|
24165
24482
|
const relativeFrame = frame2 - s.from;
|
|
24483
|
+
const displayDurationInFrames = s.loopDisplay ? s.loopDisplay.durationInFrames * s.loopDisplay.numberOfTimes : s.duration;
|
|
24166
24484
|
const relativeFrameWithPremount = relativeFrame + (s.premountDisplay ?? 0);
|
|
24167
|
-
const relativeFrameWithPostmount = relativeFrame -
|
|
24485
|
+
const relativeFrameWithPostmount = relativeFrame - displayDurationInFrames;
|
|
24168
24486
|
const roundedFrame = Math.round(relativeFrame * 100) / 100;
|
|
24169
|
-
const isInRange = relativeFrame >= 0 && relativeFrame <
|
|
24170
|
-
const isPremounting = relativeFrameWithPremount >= 0 && relativeFrameWithPremount <
|
|
24487
|
+
const isInRange = relativeFrame >= 0 && relativeFrame < displayDurationInFrames;
|
|
24488
|
+
const isPremounting = relativeFrameWithPremount >= 0 && relativeFrameWithPremount < displayDurationInFrames && !isInRange;
|
|
24171
24489
|
const isPostmounting = relativeFrameWithPostmount >= 0 && relativeFrameWithPostmount < (s.postmountDisplay ?? 0) && !isInRange;
|
|
24172
24490
|
const { marginLeft, width: width2, naturalWidth, premountWidth, postmountWidth } = useMemo121(() => {
|
|
24173
24491
|
return getTimelineSequenceLayout({
|
|
24174
|
-
durationInFrames:
|
|
24492
|
+
durationInFrames: displayDurationInFrames,
|
|
24175
24493
|
startFrom: s.loopDisplay ? s.from + s.loopDisplay.startOffset : s.from,
|
|
24176
24494
|
startFromMedia: s.type === "sequence" || s.type === "image" ? 0 : s.startMediaFrom,
|
|
24177
|
-
maxMediaDuration,
|
|
24495
|
+
maxMediaDuration: effectiveMaxMediaDuration,
|
|
24178
24496
|
video,
|
|
24179
24497
|
windowWidth,
|
|
24180
24498
|
premountDisplay: s.premountDisplay,
|
|
24181
24499
|
postmountDisplay: s.postmountDisplay
|
|
24182
24500
|
});
|
|
24183
|
-
}, [
|
|
24501
|
+
}, [
|
|
24502
|
+
displayDurationInFrames,
|
|
24503
|
+
effectiveMaxMediaDuration,
|
|
24504
|
+
s,
|
|
24505
|
+
video,
|
|
24506
|
+
windowWidth
|
|
24507
|
+
]);
|
|
24184
24508
|
const style11 = useMemo121(() => {
|
|
24185
24509
|
return {
|
|
24186
24510
|
background: s.type === "audio" ? AUDIO_GRADIENT : s.type === "video" ? VIDEO_GRADIENT : s.type === "image" ? IMAGE_GRADIENT : BLUE,
|
|
@@ -24195,7 +24519,7 @@ var Inner4 = ({ s, windowWidth }) => {
|
|
|
24195
24519
|
opacity: isInRange ? 1 : 0.5
|
|
24196
24520
|
};
|
|
24197
24521
|
}, [isInRange, marginLeft, s.type, width2]);
|
|
24198
|
-
if (maxMediaDuration === null) {
|
|
24522
|
+
if (maxMediaDuration === null && !s.loopDisplay) {
|
|
24199
24523
|
return null;
|
|
24200
24524
|
}
|
|
24201
24525
|
return /* @__PURE__ */ jsxs105("div", {
|
|
@@ -24238,7 +24562,8 @@ var Inner4 = ({ s, windowWidth }) => {
|
|
|
24238
24562
|
startFrom: s.startMediaFrom,
|
|
24239
24563
|
durationInFrames: s.duration,
|
|
24240
24564
|
volume: s.volume,
|
|
24241
|
-
playbackRate: s.playbackRate
|
|
24565
|
+
playbackRate: s.playbackRate,
|
|
24566
|
+
loopDisplay: s.loopDisplay
|
|
24242
24567
|
}) : null,
|
|
24243
24568
|
s.type === "video" ? /* @__PURE__ */ jsx215(TimelineVideoInfo, {
|
|
24244
24569
|
src: s.src,
|
|
@@ -24250,7 +24575,8 @@ var Inner4 = ({ s, windowWidth }) => {
|
|
|
24250
24575
|
volume: s.volume,
|
|
24251
24576
|
doesVolumeChange: s.doesVolumeChange,
|
|
24252
24577
|
premountWidth: premountWidth ?? 0,
|
|
24253
|
-
postmountWidth: postmountWidth ?? 0
|
|
24578
|
+
postmountWidth: postmountWidth ?? 0,
|
|
24579
|
+
loopDisplay: s.loopDisplay
|
|
24254
24580
|
}) : null,
|
|
24255
24581
|
s.type === "image" ? /* @__PURE__ */ jsx215(TimelineImageInfo, {
|
|
24256
24582
|
src: s.src,
|