@remotion/media 4.0.496 → 4.0.498
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/audio.d.ts +2 -0
- package/dist/audio-iterator-manager.d.ts +2 -0
- package/dist/debug-overlay/preview-overlay.d.ts +8 -2
- package/dist/esm/index.mjs +108 -34
- package/dist/video/video-preview-iterator.d.ts +4 -1
- package/dist/video/video.d.ts +2 -0
- package/dist/video-iterator-manager.d.ts +15 -2
- package/package.json +4 -4
package/dist/audio/audio.d.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { type AudioBufferSlice } from './make-iterator-with-priming';
|
|
|
5
5
|
import type { Nonce } from './nonce-manager';
|
|
6
6
|
import type { SharedAudioContextForMediaPlayer } from './shared-audio-context-for-media-player';
|
|
7
7
|
type ScheduleAudioNode = (node: AudioBufferSourceNode, mediaTimestamp: number, originalUnloopedMediaTimestamp: number, sourceOffsetInSeconds: number, sourceDurationInSeconds: number) => ScheduleAudioNodeResult;
|
|
8
|
+
export declare const MINIMUM_AUDIO_BUFFERING_TIME_SECONDS = 0.1;
|
|
9
|
+
export declare const hasEnoughAudioToStartPlayback: (bufferedDuration: number) => boolean;
|
|
8
10
|
export type AudioIteratorAnchor = {
|
|
9
11
|
unloopedStartInSeconds: number;
|
|
10
12
|
mediaStartInSeconds: number;
|
|
@@ -68,16 +68,22 @@ export declare const drawPreviewOverlay: ({ context, audioTime, audioContextStat
|
|
|
68
68
|
videoIteratorManager: {
|
|
69
69
|
startVideoIterator: (timeToSeek: number, nonce: import("../nonce-manager").Nonce) => Promise<void>;
|
|
70
70
|
getVideoIteratorsCreated: () => number;
|
|
71
|
-
seek: ({ newTime, nonce }: {
|
|
71
|
+
seek: ({ newTime, nonce, fps, playbackRate, isPlaying, }: {
|
|
72
72
|
newTime: number;
|
|
73
73
|
nonce: import("../nonce-manager").Nonce;
|
|
74
|
+
fps: number;
|
|
75
|
+
playbackRate: number;
|
|
76
|
+
isPlaying: boolean;
|
|
74
77
|
}) => Promise<void>;
|
|
75
78
|
destroy: () => void;
|
|
76
79
|
getVideoFrameIterator: () => {
|
|
77
80
|
destroy: () => void;
|
|
78
81
|
initialFrame: import("mediabunny").WrappedCanvas | null;
|
|
79
82
|
isDestroyed: () => boolean;
|
|
80
|
-
tryToSatisfySeek: (time: number
|
|
83
|
+
tryToSatisfySeek: (time: number, options: {
|
|
84
|
+
pendingFrameBehavior: "restart-iterator" | "wait";
|
|
85
|
+
shouldContinue: () => boolean;
|
|
86
|
+
}) => Promise<{
|
|
81
87
|
type: "not-satisfied";
|
|
82
88
|
reason: string;
|
|
83
89
|
} | {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -415,6 +415,10 @@ async function* makeLoopingIterator({
|
|
|
415
415
|
}
|
|
416
416
|
|
|
417
417
|
// src/audio-iterator-manager.ts
|
|
418
|
+
var MINIMUM_AUDIO_BUFFERING_TIME_SECONDS = 0.1;
|
|
419
|
+
var hasEnoughAudioToStartPlayback = (bufferedDuration) => {
|
|
420
|
+
return bufferedDuration >= MINIMUM_AUDIO_BUFFERING_TIME_SECONDS;
|
|
421
|
+
};
|
|
418
422
|
var anchorToContinuousTime = ({
|
|
419
423
|
anchor,
|
|
420
424
|
unloopedTimeInSeconds,
|
|
@@ -597,7 +601,7 @@ var audioIteratorManager = ({
|
|
|
597
601
|
onDone();
|
|
598
602
|
return;
|
|
599
603
|
}
|
|
600
|
-
onScheduled(result.value.
|
|
604
|
+
onScheduled(result.value.sourceDurationInSeconds);
|
|
601
605
|
notifyNodeScheduled();
|
|
602
606
|
onAudioChunk({
|
|
603
607
|
buffer: result.value,
|
|
@@ -679,24 +683,32 @@ var audioIteratorManager = ({
|
|
|
679
683
|
});
|
|
680
684
|
audioIteratorsCreated++;
|
|
681
685
|
audioBufferIterator = iterator;
|
|
682
|
-
let
|
|
686
|
+
let bufferedDuration = 0;
|
|
687
|
+
let hasUnblockedPlayback = false;
|
|
688
|
+
const unblockPlayback = () => {
|
|
689
|
+
if (hasUnblockedPlayback) {
|
|
690
|
+
return;
|
|
691
|
+
}
|
|
692
|
+
hasUnblockedPlayback = true;
|
|
693
|
+
delayHandle.unblock();
|
|
694
|
+
};
|
|
683
695
|
proceedScheduling({
|
|
684
696
|
iterator,
|
|
685
697
|
nonce,
|
|
686
698
|
getTargetTime,
|
|
687
699
|
playbackRate,
|
|
688
700
|
scheduleAudioNode,
|
|
689
|
-
onScheduled: () => {
|
|
690
|
-
|
|
691
|
-
if (
|
|
692
|
-
|
|
701
|
+
onScheduled: (sourceDurationInSeconds) => {
|
|
702
|
+
bufferedDuration += sourceDurationInSeconds;
|
|
703
|
+
if (hasEnoughAudioToStartPlayback(bufferedDuration)) {
|
|
704
|
+
unblockPlayback();
|
|
693
705
|
}
|
|
694
706
|
},
|
|
695
707
|
onDestroyed: () => {
|
|
696
|
-
|
|
708
|
+
unblockPlayback();
|
|
697
709
|
},
|
|
698
710
|
onDone: () => {
|
|
699
|
-
|
|
711
|
+
unblockPlayback();
|
|
700
712
|
},
|
|
701
713
|
logLevel,
|
|
702
714
|
currentTime: sharedAudioContext.audioContext.currentTime,
|
|
@@ -1265,7 +1277,6 @@ var makePrewarmedVideoIteratorCache = (videoSink) => {
|
|
|
1265
1277
|
};
|
|
1266
1278
|
|
|
1267
1279
|
// src/video/video-preview-iterator.ts
|
|
1268
|
-
var MAXIMUM_AWAITED_PEEK_DISTANCE_SECONDS = 0.05;
|
|
1269
1280
|
var createVideoIterator = async (timeToSeek, cache) => {
|
|
1270
1281
|
let destroyed = false;
|
|
1271
1282
|
const iterator = cache.makeIteratorOrUsePrewarmed(timeToSeek);
|
|
@@ -1303,22 +1314,12 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1303
1314
|
wait: next.wait
|
|
1304
1315
|
};
|
|
1305
1316
|
};
|
|
1306
|
-
const peek = async () => {
|
|
1307
|
-
const peeked = peekIfReady();
|
|
1308
|
-
if (peeked.type === "ready") {
|
|
1309
|
-
return peeked.frame;
|
|
1310
|
-
}
|
|
1311
|
-
return setPeekedFrame(await peeked.wait());
|
|
1312
|
-
};
|
|
1313
1317
|
const getFrameEndTimestampFromPeek = (frame) => {
|
|
1314
1318
|
return frame ? roundTo4Digits(frame.timestamp) : Infinity;
|
|
1315
1319
|
};
|
|
1316
|
-
const getFrameEndTimestamp = async (
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
const getFrameEndTimestampIfCloseEnough = async ({
|
|
1320
|
-
timestamp,
|
|
1321
|
-
frameTimestamp
|
|
1320
|
+
const getFrameEndTimestamp = async ({
|
|
1321
|
+
pendingFrameBehavior,
|
|
1322
|
+
shouldContinue
|
|
1322
1323
|
}) => {
|
|
1323
1324
|
const peeked = peekIfReady();
|
|
1324
1325
|
if (peeked.type === "ready") {
|
|
@@ -1327,10 +1328,16 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1327
1328
|
timestamp: getFrameEndTimestampFromPeek(peeked.frame)
|
|
1328
1329
|
};
|
|
1329
1330
|
}
|
|
1330
|
-
if (
|
|
1331
|
+
if (pendingFrameBehavior === "restart-iterator") {
|
|
1331
1332
|
return { type: "pending" };
|
|
1332
1333
|
}
|
|
1334
|
+
if (!shouldContinue()) {
|
|
1335
|
+
return { type: "cancelled" };
|
|
1336
|
+
}
|
|
1333
1337
|
const awaitedPeeked = setPeekedFrame(await peeked.wait());
|
|
1338
|
+
if (!shouldContinue()) {
|
|
1339
|
+
return { type: "cancelled" };
|
|
1340
|
+
}
|
|
1334
1341
|
return {
|
|
1335
1342
|
type: "ready",
|
|
1336
1343
|
timestamp: getFrameEndTimestampFromPeek(awaitedPeeked)
|
|
@@ -1384,7 +1391,13 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1384
1391
|
return;
|
|
1385
1392
|
});
|
|
1386
1393
|
};
|
|
1387
|
-
const tryToSatisfySeek = async (time) => {
|
|
1394
|
+
const tryToSatisfySeek = async (time, options) => {
|
|
1395
|
+
if (!options.shouldContinue()) {
|
|
1396
|
+
return {
|
|
1397
|
+
type: "not-satisfied",
|
|
1398
|
+
reason: "seek was superseded"
|
|
1399
|
+
};
|
|
1400
|
+
}
|
|
1388
1401
|
const timestamp = roundTo4Digits(time);
|
|
1389
1402
|
if (lastReturnedFrame) {
|
|
1390
1403
|
const frameTimestamp = roundTo4Digits(lastReturnedFrame.timestamp);
|
|
@@ -1402,8 +1415,23 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1402
1415
|
reason: `iterator is too far, most recently returned ${frameTimestamp}`
|
|
1403
1416
|
};
|
|
1404
1417
|
}
|
|
1405
|
-
const frameEndTimestamp = await getFrameEndTimestamp(
|
|
1406
|
-
|
|
1418
|
+
const frameEndTimestamp = await getFrameEndTimestamp({
|
|
1419
|
+
pendingFrameBehavior: options.pendingFrameBehavior,
|
|
1420
|
+
shouldContinue: options.shouldContinue
|
|
1421
|
+
});
|
|
1422
|
+
if (frameEndTimestamp.type === "cancelled") {
|
|
1423
|
+
return {
|
|
1424
|
+
type: "not-satisfied",
|
|
1425
|
+
reason: "seek was superseded"
|
|
1426
|
+
};
|
|
1427
|
+
}
|
|
1428
|
+
if (frameEndTimestamp.type === "pending") {
|
|
1429
|
+
return {
|
|
1430
|
+
type: "not-satisfied",
|
|
1431
|
+
reason: "iterator did not have next frame ready"
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
if (frameTimestamp <= timestamp && frameEndTimestamp.timestamp > timestamp) {
|
|
1407
1435
|
return {
|
|
1408
1436
|
type: "satisfied",
|
|
1409
1437
|
frame: lastReturnedFrame
|
|
@@ -1423,6 +1451,12 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1423
1451
|
};
|
|
1424
1452
|
}
|
|
1425
1453
|
while (true) {
|
|
1454
|
+
if (!options.shouldContinue()) {
|
|
1455
|
+
return {
|
|
1456
|
+
type: "not-satisfied",
|
|
1457
|
+
reason: "seek was superseded"
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1426
1460
|
const frame = getNextOrNullIfNotAvailable();
|
|
1427
1461
|
if (frame.type === "need-to-wait-for-it") {
|
|
1428
1462
|
return {
|
|
@@ -1445,10 +1479,16 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1445
1479
|
};
|
|
1446
1480
|
}
|
|
1447
1481
|
const frameTimestamp = roundTo4Digits(frame.frame.timestamp);
|
|
1448
|
-
const frameEndTimestamp = await
|
|
1449
|
-
|
|
1450
|
-
|
|
1482
|
+
const frameEndTimestamp = await getFrameEndTimestamp({
|
|
1483
|
+
pendingFrameBehavior: options.pendingFrameBehavior,
|
|
1484
|
+
shouldContinue: options.shouldContinue
|
|
1451
1485
|
});
|
|
1486
|
+
if (frameEndTimestamp.type === "cancelled") {
|
|
1487
|
+
return {
|
|
1488
|
+
type: "not-satisfied",
|
|
1489
|
+
reason: "seek was superseded"
|
|
1490
|
+
};
|
|
1491
|
+
}
|
|
1452
1492
|
if (frameEndTimestamp.type === "pending") {
|
|
1453
1493
|
return {
|
|
1454
1494
|
type: "not-satisfied",
|
|
@@ -1478,6 +1518,19 @@ var createVideoIterator = async (timeToSeek, cache) => {
|
|
|
1478
1518
|
|
|
1479
1519
|
// src/video-iterator-manager.ts
|
|
1480
1520
|
var { runEffectChain } = Internals4;
|
|
1521
|
+
var isSequentialMediaTimeAdvance = ({
|
|
1522
|
+
previousTime,
|
|
1523
|
+
newTime,
|
|
1524
|
+
fps,
|
|
1525
|
+
playbackRate,
|
|
1526
|
+
isPlaying
|
|
1527
|
+
}) => {
|
|
1528
|
+
if (!isPlaying || newTime < previousTime) {
|
|
1529
|
+
return false;
|
|
1530
|
+
}
|
|
1531
|
+
const maximumSequentialAdvance = Math.abs(playbackRate) / fps;
|
|
1532
|
+
return roundTo4Digits(newTime - previousTime) <= roundTo4Digits(maximumSequentialAdvance);
|
|
1533
|
+
};
|
|
1481
1534
|
var videoIteratorManager = async ({
|
|
1482
1535
|
delayPlaybackHandleIfNotPremounting,
|
|
1483
1536
|
canvas,
|
|
@@ -1587,13 +1640,20 @@ var videoIteratorManager = async ({
|
|
|
1587
1640
|
__callDispose(__stack, _err, _hasErr);
|
|
1588
1641
|
}
|
|
1589
1642
|
};
|
|
1590
|
-
const seek = async ({
|
|
1643
|
+
const seek = async ({
|
|
1644
|
+
newTime,
|
|
1645
|
+
nonce,
|
|
1646
|
+
fps,
|
|
1647
|
+
playbackRate,
|
|
1648
|
+
isPlaying
|
|
1649
|
+
}) => {
|
|
1591
1650
|
if (!videoFrameIterator) {
|
|
1592
1651
|
return;
|
|
1593
1652
|
}
|
|
1594
1653
|
if (currentSeek !== null && roundTo4Digits(currentSeek) === roundTo4Digits(newTime)) {
|
|
1595
1654
|
return;
|
|
1596
1655
|
}
|
|
1656
|
+
const previousTime = currentSeek;
|
|
1597
1657
|
currentSeek = newTime;
|
|
1598
1658
|
if (getIsLooping()) {
|
|
1599
1659
|
if (getLoopSegmentMediaEndTimestamp() - newTime < 1) {
|
|
@@ -1602,7 +1662,17 @@ var videoIteratorManager = async ({
|
|
|
1602
1662
|
});
|
|
1603
1663
|
}
|
|
1604
1664
|
}
|
|
1605
|
-
const
|
|
1665
|
+
const pendingFrameBehavior = previousTime !== null && isSequentialMediaTimeAdvance({
|
|
1666
|
+
previousTime,
|
|
1667
|
+
newTime,
|
|
1668
|
+
fps,
|
|
1669
|
+
playbackRate,
|
|
1670
|
+
isPlaying
|
|
1671
|
+
}) ? "wait" : "restart-iterator";
|
|
1672
|
+
const videoSatisfyResult = await videoFrameIterator.tryToSatisfySeek(newTime, {
|
|
1673
|
+
pendingFrameBehavior,
|
|
1674
|
+
shouldContinue: () => !nonce.isStale()
|
|
1675
|
+
});
|
|
1606
1676
|
if (videoSatisfyResult.type === "satisfied") {
|
|
1607
1677
|
await drawFrame(videoSatisfyResult.frame);
|
|
1608
1678
|
return;
|
|
@@ -1937,7 +2007,10 @@ class MediaPlayer {
|
|
|
1937
2007
|
await Promise.all([
|
|
1938
2008
|
this.videoIteratorManager?.seek({
|
|
1939
2009
|
newTime,
|
|
1940
|
-
nonce
|
|
2010
|
+
nonce,
|
|
2011
|
+
fps: this.fps,
|
|
2012
|
+
playbackRate: this.playbackRate,
|
|
2013
|
+
isPlaying: this.playing
|
|
1941
2014
|
}),
|
|
1942
2015
|
this.audioIteratorManager?.seek({
|
|
1943
2016
|
newTime,
|
|
@@ -5893,7 +5966,6 @@ var videoSchema = {
|
|
|
5893
5966
|
},
|
|
5894
5967
|
...Internals22.baseSchema,
|
|
5895
5968
|
...Internals22.premountSchema,
|
|
5896
|
-
...Internals22.premountStyleSchema,
|
|
5897
5969
|
volume: {
|
|
5898
5970
|
type: "number",
|
|
5899
5971
|
min: 0,
|
|
@@ -5914,7 +5986,9 @@ var videoSchema = {
|
|
|
5914
5986
|
},
|
|
5915
5987
|
muted: { type: "boolean", default: false, description: "Muted" },
|
|
5916
5988
|
loop: { type: "boolean", default: false, description: "Loop" },
|
|
5917
|
-
...Internals22.transformSchema
|
|
5989
|
+
...Internals22.transformSchema,
|
|
5990
|
+
...Interactive2.backgroundSchema,
|
|
5991
|
+
...Interactive2.borderSchema
|
|
5918
5992
|
};
|
|
5919
5993
|
var InnerVideo = ({
|
|
5920
5994
|
src,
|
|
@@ -12,7 +12,10 @@ export declare const createVideoIterator: (timeToSeek: number, cache: {
|
|
|
12
12
|
destroy: () => void;
|
|
13
13
|
initialFrame: WrappedCanvas | null;
|
|
14
14
|
isDestroyed: () => boolean;
|
|
15
|
-
tryToSatisfySeek: (time: number
|
|
15
|
+
tryToSatisfySeek: (time: number, options: {
|
|
16
|
+
pendingFrameBehavior: "restart-iterator" | "wait";
|
|
17
|
+
shouldContinue: () => boolean;
|
|
18
|
+
}) => Promise<{
|
|
16
19
|
type: "not-satisfied";
|
|
17
20
|
reason: string;
|
|
18
21
|
} | {
|
package/dist/video/video.d.ts
CHANGED
|
@@ -2,6 +2,13 @@ import type { InputVideoTrack, WrappedCanvas } from 'mediabunny';
|
|
|
2
2
|
import type { EffectChainState, EffectDefinitionAndStack } from 'remotion';
|
|
3
3
|
import type { DelayPlaybackIfNotPremounting } from './delay-playback-if-not-premounting';
|
|
4
4
|
import type { Nonce } from './nonce-manager';
|
|
5
|
+
export declare const isSequentialMediaTimeAdvance: ({ previousTime, newTime, fps, playbackRate, isPlaying, }: {
|
|
6
|
+
previousTime: number;
|
|
7
|
+
newTime: number;
|
|
8
|
+
fps: number;
|
|
9
|
+
playbackRate: number;
|
|
10
|
+
isPlaying: boolean;
|
|
11
|
+
}) => boolean;
|
|
5
12
|
export declare const videoIteratorManager: ({ delayPlaybackHandleIfNotPremounting, canvas, context, drawDebugOverlay, logLevel, getOnVideoFrameCallback, videoTrack, getLoopSegmentMediaEndTimestamp, getStartTime, getIsLooping, getEffects, getEffectChainState, }: {
|
|
6
13
|
videoTrack: InputVideoTrack;
|
|
7
14
|
delayPlaybackHandleIfNotPremounting: () => DelayPlaybackIfNotPremounting;
|
|
@@ -18,16 +25,22 @@ export declare const videoIteratorManager: ({ delayPlaybackHandleIfNotPremountin
|
|
|
18
25
|
}) => Promise<{
|
|
19
26
|
startVideoIterator: (timeToSeek: number, nonce: Nonce) => Promise<void>;
|
|
20
27
|
getVideoIteratorsCreated: () => number;
|
|
21
|
-
seek: ({ newTime, nonce }: {
|
|
28
|
+
seek: ({ newTime, nonce, fps, playbackRate, isPlaying, }: {
|
|
22
29
|
newTime: number;
|
|
23
30
|
nonce: Nonce;
|
|
31
|
+
fps: number;
|
|
32
|
+
playbackRate: number;
|
|
33
|
+
isPlaying: boolean;
|
|
24
34
|
}) => Promise<void>;
|
|
25
35
|
destroy: () => void;
|
|
26
36
|
getVideoFrameIterator: () => {
|
|
27
37
|
destroy: () => void;
|
|
28
38
|
initialFrame: WrappedCanvas | null;
|
|
29
39
|
isDestroyed: () => boolean;
|
|
30
|
-
tryToSatisfySeek: (time: number
|
|
40
|
+
tryToSatisfySeek: (time: number, options: {
|
|
41
|
+
pendingFrameBehavior: "restart-iterator" | "wait";
|
|
42
|
+
shouldContinue: () => boolean;
|
|
43
|
+
}) => Promise<{
|
|
31
44
|
type: "not-satisfied";
|
|
32
45
|
reason: string;
|
|
33
46
|
} | {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/media",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.498",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"mediabunny": "1.50.8",
|
|
26
|
-
"remotion": "4.0.
|
|
26
|
+
"remotion": "4.0.498",
|
|
27
27
|
"zod": "4.3.6"
|
|
28
28
|
},
|
|
29
29
|
"peerDependencies": {
|
|
@@ -31,8 +31,8 @@
|
|
|
31
31
|
"react-dom": ">=16.8.0"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
35
|
-
"@remotion/player": "4.0.
|
|
34
|
+
"@remotion/eslint-config-internal": "4.0.498",
|
|
35
|
+
"@remotion/player": "4.0.498",
|
|
36
36
|
"@vitest/browser-webdriverio": "4.0.9",
|
|
37
37
|
"eslint": "9.19.0",
|
|
38
38
|
"react": "19.2.3",
|