@remotion/media 4.0.372 → 4.0.373
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-for-preview.js +1 -1
- package/dist/audio-extraction/extract-audio.js +3 -1
- package/dist/esm/index.mjs +18 -10
- package/dist/video/video-for-preview.js +1 -1
- package/dist/video-extraction/keyframe-bank.js +20 -8
- package/dist/video-extraction/keyframe-manager.js +5 -2
- package/package.json +6 -6
|
@@ -13,7 +13,7 @@ const AudioForPreviewAssertedShowing = ({ src, playbackRate, logLevel, muted, vo
|
|
|
13
13
|
const [mediaPlayerReady, setMediaPlayerReady] = useState(false);
|
|
14
14
|
const [shouldFallbackToNativeAudio, setShouldFallbackToNativeAudio] = useState(false);
|
|
15
15
|
const [playing] = Timeline.usePlayingState();
|
|
16
|
-
const timelineContext = useContext(
|
|
16
|
+
const timelineContext = useContext(Internals.TimelineContext);
|
|
17
17
|
const globalPlaybackRate = timelineContext.playbackRate;
|
|
18
18
|
const sharedAudioContext = useContext(SharedAudioContext);
|
|
19
19
|
const buffer = useBufferState();
|
|
@@ -44,6 +44,7 @@ const extractAudioInternal = async ({ src, timeInSeconds: unloopedTimeInSeconds,
|
|
|
44
44
|
const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
|
|
45
45
|
const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
|
|
46
46
|
audioManager.logOpenFrames();
|
|
47
|
+
const trimStartToleranceInSeconds = 0.002;
|
|
47
48
|
const audioDataArray = [];
|
|
48
49
|
for (let i = 0; i < samples.length; i++) {
|
|
49
50
|
const sample = samples[i];
|
|
@@ -65,7 +66,8 @@ const extractAudioInternal = async ({ src, timeInSeconds: unloopedTimeInSeconds,
|
|
|
65
66
|
let trimEndInSeconds = 0;
|
|
66
67
|
if (isFirstSample) {
|
|
67
68
|
trimStartInSeconds = timeInSeconds - sample.timestamp;
|
|
68
|
-
if (trimStartInSeconds < 0 &&
|
|
69
|
+
if (trimStartInSeconds < 0 &&
|
|
70
|
+
trimStartInSeconds > -trimStartToleranceInSeconds) {
|
|
69
71
|
trimStartInSeconds = 0;
|
|
70
72
|
}
|
|
71
73
|
if (trimStartInSeconds < 0) {
|
package/dist/esm/index.mjs
CHANGED
|
@@ -1362,7 +1362,7 @@ var AudioForPreviewAssertedShowing = ({
|
|
|
1362
1362
|
const [mediaPlayerReady, setMediaPlayerReady] = useState2(false);
|
|
1363
1363
|
const [shouldFallbackToNativeAudio, setShouldFallbackToNativeAudio] = useState2(false);
|
|
1364
1364
|
const [playing] = Timeline.usePlayingState();
|
|
1365
|
-
const timelineContext = useContext2(
|
|
1365
|
+
const timelineContext = useContext2(Internals6.TimelineContext);
|
|
1366
1366
|
const globalPlaybackRate = timelineContext.playbackRate;
|
|
1367
1367
|
const sharedAudioContext = useContext2(SharedAudioContext);
|
|
1368
1368
|
const buffer = useBufferState();
|
|
@@ -2270,19 +2270,26 @@ var makeKeyframeBank = ({
|
|
|
2270
2270
|
};
|
|
2271
2271
|
const getFrameFromTimestamp = async (timestampInSeconds) => {
|
|
2272
2272
|
lastUsed = Date.now();
|
|
2273
|
-
|
|
2274
|
-
|
|
2273
|
+
const maxClampToleranceInSeconds = 0.1;
|
|
2274
|
+
let adjustedTimestamp = timestampInSeconds;
|
|
2275
|
+
if (roundTo4Digits(timestampInSeconds) < roundTo4Digits(startTimestampInSeconds)) {
|
|
2276
|
+
const differenceInSeconds = startTimestampInSeconds - timestampInSeconds;
|
|
2277
|
+
if (differenceInSeconds <= maxClampToleranceInSeconds) {
|
|
2278
|
+
adjustedTimestamp = startTimestampInSeconds;
|
|
2279
|
+
} else {
|
|
2280
|
+
return Promise.reject(new Error(`Timestamp is before start timestamp (requested: ${timestampInSeconds}sec, start: ${startTimestampInSeconds}sec, difference: ${differenceInSeconds.toFixed(3)}sec exceeds tolerance of ${maxClampToleranceInSeconds}sec)`));
|
|
2281
|
+
}
|
|
2275
2282
|
}
|
|
2276
|
-
if (
|
|
2277
|
-
return Promise.reject(new Error(`Timestamp is after end timestamp (requested: ${timestampInSeconds}sec, end: ${endTimestampInSeconds})`));
|
|
2283
|
+
if (roundTo4Digits(adjustedTimestamp) > roundTo4Digits(endTimestampInSeconds)) {
|
|
2284
|
+
return Promise.reject(new Error(`Timestamp is after end timestamp (requested: ${timestampInSeconds}sec, end: ${endTimestampInSeconds}sec)`));
|
|
2278
2285
|
}
|
|
2279
|
-
await ensureEnoughFramesForTimestamp(
|
|
2286
|
+
await ensureEnoughFramesForTimestamp(adjustedTimestamp);
|
|
2280
2287
|
for (let i = frameTimestamps.length - 1;i >= 0; i--) {
|
|
2281
2288
|
const sample = frames[frameTimestamps[i]];
|
|
2282
2289
|
if (!sample) {
|
|
2283
2290
|
return null;
|
|
2284
2291
|
}
|
|
2285
|
-
if (roundTo4Digits(sample.timestamp) <= roundTo4Digits(
|
|
2292
|
+
if (roundTo4Digits(sample.timestamp) <= roundTo4Digits(adjustedTimestamp) || Math.abs(sample.timestamp - adjustedTimestamp) <= 0.001) {
|
|
2286
2293
|
return sample;
|
|
2287
2294
|
}
|
|
2288
2295
|
}
|
|
@@ -2588,7 +2595,7 @@ var makeKeyframeManager = () => {
|
|
|
2588
2595
|
}) => {
|
|
2589
2596
|
const startPacket = await packetSink.getKeyPacket(timestamp, {
|
|
2590
2597
|
verifyKeyPackets: true
|
|
2591
|
-
});
|
|
2598
|
+
}) ?? await packetSink.getFirstPacket({ verifyKeyPackets: true });
|
|
2592
2599
|
const hasAlpha = startPacket?.sideData.alpha;
|
|
2593
2600
|
if (hasAlpha && !canBrowserUseWebGl2()) {
|
|
2594
2601
|
return "has-alpha";
|
|
@@ -2890,6 +2897,7 @@ var extractAudioInternal = async ({
|
|
|
2890
2897
|
const durationInSeconds = durationNotYetApplyingPlaybackRate * playbackRate;
|
|
2891
2898
|
const samples = await sampleIterator.getSamples(timeInSeconds, durationInSeconds);
|
|
2892
2899
|
audioManager.logOpenFrames();
|
|
2900
|
+
const trimStartToleranceInSeconds = 0.002;
|
|
2893
2901
|
const audioDataArray = [];
|
|
2894
2902
|
for (let i = 0;i < samples.length; i++) {
|
|
2895
2903
|
const sample = samples[i];
|
|
@@ -2906,7 +2914,7 @@ var extractAudioInternal = async ({
|
|
|
2906
2914
|
let trimEndInSeconds = 0;
|
|
2907
2915
|
if (isFirstSample) {
|
|
2908
2916
|
trimStartInSeconds = timeInSeconds - sample.timestamp;
|
|
2909
|
-
if (trimStartInSeconds < 0 && trimStartInSeconds > -
|
|
2917
|
+
if (trimStartInSeconds < 0 && trimStartInSeconds > -trimStartToleranceInSeconds) {
|
|
2910
2918
|
trimStartInSeconds = 0;
|
|
2911
2919
|
}
|
|
2912
2920
|
if (trimStartInSeconds < 0) {
|
|
@@ -3583,7 +3591,7 @@ var VideoForPreviewAssertedShowing = ({
|
|
|
3583
3591
|
const [mediaPlayerReady, setMediaPlayerReady] = useState4(false);
|
|
3584
3592
|
const [shouldFallbackToNativeVideo, setShouldFallbackToNativeVideo] = useState4(false);
|
|
3585
3593
|
const [playing] = Timeline2.usePlayingState();
|
|
3586
|
-
const timelineContext = useContext4(
|
|
3594
|
+
const timelineContext = useContext4(Internals15.TimelineContext);
|
|
3587
3595
|
const globalPlaybackRate = timelineContext.playbackRate;
|
|
3588
3596
|
const sharedAudioContext = useContext4(SharedAudioContext2);
|
|
3589
3597
|
const buffer = useBufferState2();
|
|
@@ -15,7 +15,7 @@ const VideoForPreviewAssertedShowing = ({ src: unpreloadedSrc, style, playbackRa
|
|
|
15
15
|
const [mediaPlayerReady, setMediaPlayerReady] = useState(false);
|
|
16
16
|
const [shouldFallbackToNativeVideo, setShouldFallbackToNativeVideo] = useState(false);
|
|
17
17
|
const [playing] = Timeline.usePlayingState();
|
|
18
|
-
const timelineContext = useContext(
|
|
18
|
+
const timelineContext = useContext(Internals.TimelineContext);
|
|
19
19
|
const globalPlaybackRate = timelineContext.playbackRate;
|
|
20
20
|
const sharedAudioContext = useContext(SharedAudioContext);
|
|
21
21
|
const buffer = useBufferState();
|
|
@@ -68,23 +68,35 @@ export const makeKeyframeBank = ({ startTimestampInSeconds, endTimestampInSecond
|
|
|
68
68
|
};
|
|
69
69
|
const getFrameFromTimestamp = async (timestampInSeconds) => {
|
|
70
70
|
lastUsed = Date.now();
|
|
71
|
-
if
|
|
72
|
-
|
|
71
|
+
// Videos may start slightly after timestamp 0 due to encoding, but if the requested timestamp is too far before the bank start, something is likely wrong.
|
|
72
|
+
const maxClampToleranceInSeconds = 0.1;
|
|
73
|
+
// If the requested timestamp is before the start of this bank, clamp it to the start if within tolerance. This handles videos that don't start at timestamp 0.
|
|
74
|
+
// For example, requesting frame at 0sec when video starts at 0.04sec should return the frame at 0.04sec.
|
|
75
|
+
// Test case: https://github.com/remotion-dev/remotion/issues/5915
|
|
76
|
+
let adjustedTimestamp = timestampInSeconds;
|
|
77
|
+
if (roundTo4Digits(timestampInSeconds) <
|
|
78
|
+
roundTo4Digits(startTimestampInSeconds)) {
|
|
79
|
+
const differenceInSeconds = startTimestampInSeconds - timestampInSeconds;
|
|
80
|
+
if (differenceInSeconds <= maxClampToleranceInSeconds) {
|
|
81
|
+
adjustedTimestamp = startTimestampInSeconds;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return Promise.reject(new Error(`Timestamp is before start timestamp (requested: ${timestampInSeconds}sec, start: ${startTimestampInSeconds}sec, difference: ${differenceInSeconds.toFixed(3)}sec exceeds tolerance of ${maxClampToleranceInSeconds}sec)`));
|
|
85
|
+
}
|
|
73
86
|
}
|
|
74
|
-
if (
|
|
75
|
-
return Promise.reject(new Error(`Timestamp is after end timestamp (requested: ${timestampInSeconds}sec, end: ${endTimestampInSeconds})`));
|
|
87
|
+
if (roundTo4Digits(adjustedTimestamp) > roundTo4Digits(endTimestampInSeconds)) {
|
|
88
|
+
return Promise.reject(new Error(`Timestamp is after end timestamp (requested: ${timestampInSeconds}sec, end: ${endTimestampInSeconds}sec)`));
|
|
76
89
|
}
|
|
77
|
-
await ensureEnoughFramesForTimestamp(
|
|
90
|
+
await ensureEnoughFramesForTimestamp(adjustedTimestamp);
|
|
78
91
|
for (let i = frameTimestamps.length - 1; i >= 0; i--) {
|
|
79
92
|
const sample = frames[frameTimestamps[i]];
|
|
80
93
|
if (!sample) {
|
|
81
94
|
return null;
|
|
82
95
|
}
|
|
83
|
-
if (roundTo4Digits(sample.timestamp) <=
|
|
84
|
-
roundTo4Digits(timestampInSeconds) ||
|
|
96
|
+
if (roundTo4Digits(sample.timestamp) <= roundTo4Digits(adjustedTimestamp) ||
|
|
85
97
|
// Match 0.3333333333 to 0.33355555
|
|
86
98
|
// this does not satisfy the previous condition, since one rounds up and one rounds down
|
|
87
|
-
Math.abs(sample.timestamp -
|
|
99
|
+
Math.abs(sample.timestamp - adjustedTimestamp) <= 0.001) {
|
|
88
100
|
return sample;
|
|
89
101
|
}
|
|
90
102
|
}
|
|
@@ -111,9 +111,12 @@ export const makeKeyframeManager = () => {
|
|
|
111
111
|
await logCacheStats(logLevel);
|
|
112
112
|
};
|
|
113
113
|
const getKeyframeBankOrRefetch = async ({ packetSink, timestamp, videoSampleSink, src, logLevel, }) => {
|
|
114
|
-
|
|
114
|
+
// Try to get the keypacket at the requested timestamp.
|
|
115
|
+
// If it returns null (timestamp is before the first keypacket), fall back to the first packet.
|
|
116
|
+
// This matches mediabunny's internal behavior and handles videos that don't start at timestamp 0.
|
|
117
|
+
const startPacket = (await packetSink.getKeyPacket(timestamp, {
|
|
115
118
|
verifyKeyPackets: true,
|
|
116
|
-
});
|
|
119
|
+
})) ?? (await packetSink.getFirstPacket({ verifyKeyPackets: true }));
|
|
117
120
|
const hasAlpha = startPacket?.sideData.alpha;
|
|
118
121
|
if (hasAlpha && !canBrowserUseWebGl2()) {
|
|
119
122
|
return 'has-alpha';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/media",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.373",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -22,20 +22,20 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"mediabunny": "1.24.3",
|
|
25
|
-
"remotion": "4.0.
|
|
26
|
-
"webdriverio": "9.19.2"
|
|
25
|
+
"remotion": "4.0.373"
|
|
27
26
|
},
|
|
28
27
|
"peerDependencies": {
|
|
29
28
|
"react": ">=16.8.0",
|
|
30
29
|
"react-dom": ">=16.8.0"
|
|
31
30
|
},
|
|
32
31
|
"devDependencies": {
|
|
33
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
34
|
-
"@vitest/browser": "
|
|
32
|
+
"@remotion/eslint-config-internal": "4.0.373",
|
|
33
|
+
"@vitest/browser-webdriverio": "4.0.7",
|
|
35
34
|
"eslint": "9.19.0",
|
|
36
35
|
"react": "19.0.0",
|
|
37
36
|
"react-dom": "19.0.0",
|
|
38
|
-
"vitest": "
|
|
37
|
+
"vitest": "4.0.7",
|
|
38
|
+
"webdriverio": "9.19.2"
|
|
39
39
|
},
|
|
40
40
|
"keywords": [],
|
|
41
41
|
"publishConfig": {
|