@remotion/media 4.0.390 → 4.0.392
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 +2 -0
- package/dist/audio/audio-preview-iterator.d.ts +3 -2
- package/dist/audio/audio-preview-iterator.js +2 -2
- package/dist/audio-for-rendering.d.ts +3 -0
- package/dist/audio-for-rendering.js +94 -0
- package/dist/audio-iterator-manager.d.ts +5 -1
- package/dist/audio-iterator-manager.js +21 -5
- package/dist/audio.d.ts +3 -0
- package/dist/audio.js +60 -0
- package/dist/audiodata-to-array.d.ts +0 -0
- package/dist/audiodata-to-array.js +1 -0
- package/dist/convert-audiodata/data-types.d.ts +1 -0
- package/dist/convert-audiodata/data-types.js +22 -0
- package/dist/convert-audiodata/is-planar-format.d.ts +1 -0
- package/dist/convert-audiodata/is-planar-format.js +3 -0
- package/dist/convert-audiodata/log-audiodata.d.ts +1 -0
- package/dist/convert-audiodata/log-audiodata.js +8 -0
- package/dist/convert-audiodata/trim-audiodata.d.ts +0 -0
- package/dist/convert-audiodata/trim-audiodata.js +1 -0
- package/dist/deserialized-audiodata.d.ts +15 -0
- package/dist/deserialized-audiodata.js +26 -0
- package/dist/esm/index.mjs +185 -27
- package/dist/extract-audio.d.ts +7 -0
- package/dist/extract-audio.js +98 -0
- package/dist/extract-frame-via-broadcast-channel.d.ts +15 -0
- package/dist/extract-frame-via-broadcast-channel.js +104 -0
- package/dist/extract-frame.d.ts +27 -0
- package/dist/extract-frame.js +21 -0
- package/dist/extrct-audio.d.ts +7 -0
- package/dist/extrct-audio.js +94 -0
- package/dist/get-frames-since-keyframe.d.ts +22 -0
- package/dist/get-frames-since-keyframe.js +41 -0
- package/dist/get-time-in-seconds.d.ts +8 -0
- package/dist/get-time-in-seconds.js +15 -0
- package/dist/is-network-error.d.ts +6 -0
- package/dist/is-network-error.js +17 -0
- package/dist/keyframe-bank.d.ts +25 -0
- package/dist/keyframe-bank.js +120 -0
- package/dist/keyframe-manager.d.ts +23 -0
- package/dist/keyframe-manager.js +170 -0
- package/dist/log.d.ts +10 -0
- package/dist/log.js +33 -0
- package/dist/media-player.d.ts +4 -1
- package/dist/media-player.js +56 -17
- package/dist/new-video-for-rendering.d.ts +3 -0
- package/dist/new-video-for-rendering.js +108 -0
- package/dist/new-video.d.ts +3 -0
- package/dist/new-video.js +37 -0
- package/dist/prewarm-iterator-for-looping.d.ts +17 -0
- package/dist/prewarm-iterator-for-looping.js +56 -0
- package/dist/props.d.ts +29 -0
- package/dist/props.js +1 -0
- package/dist/remember-actual-matroska-timestamps.d.ts +4 -0
- package/dist/remember-actual-matroska-timestamps.js +19 -0
- package/dist/serialize-videoframe.d.ts +0 -0
- package/dist/serialize-videoframe.js +1 -0
- package/dist/video/media-player.d.ts +62 -0
- package/dist/video/media-player.js +361 -0
- package/dist/video/new-video-for-preview.d.ts +10 -0
- package/dist/video/new-video-for-preview.js +108 -0
- package/dist/video/timeout-utils.d.ts +2 -0
- package/dist/video/timeout-utils.js +18 -0
- package/dist/video/video-for-preview.js +2 -0
- package/dist/video/video-preview-iterator.d.ts +3 -2
- package/dist/video/video-preview-iterator.js +2 -2
- package/dist/video-extraction/media-player.d.ts +64 -0
- package/dist/video-extraction/media-player.js +501 -0
- package/dist/video-extraction/new-video-for-preview.d.ts +10 -0
- package/dist/video-extraction/new-video-for-preview.js +114 -0
- package/dist/video-for-rendering.d.ts +3 -0
- package/dist/video-for-rendering.js +108 -0
- package/dist/video-iterator-manager.d.ts +4 -1
- package/dist/video-iterator-manager.js +27 -4
- package/dist/video.d.ts +3 -0
- package/dist/video.js +37 -0
- package/package.json +3 -3
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useContext, useLayoutEffect, useMemo, useRef, useState, } from 'react';
|
|
3
|
+
import { cancelRender, Internals, useCurrentFrame, useDelayRender, useRemotionEnvironment, } from 'remotion';
|
|
4
|
+
import { extractFrameViaBroadcastChannel } from './extract-frame-via-broadcast-channel';
|
|
5
|
+
export const VideoForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds,
|
|
6
|
+
// call when a frame of the video, i.e. frame drawn on canvas
|
|
7
|
+
onVideoFrame, logLevel = window.remotion_logLevel, }) => {
|
|
8
|
+
const absoluteFrame = Internals.useTimelinePosition();
|
|
9
|
+
const videoConfig = Internals.useUnsafeVideoConfig();
|
|
10
|
+
const canvasRef = useRef(null);
|
|
11
|
+
const { registerRenderAsset, unregisterRenderAsset } = useContext(Internals.RenderAssetManager);
|
|
12
|
+
const frame = useCurrentFrame();
|
|
13
|
+
const volumePropsFrame = Internals.useFrameForVolumeProp(loopVolumeCurveBehavior ?? 'repeat');
|
|
14
|
+
const environment = useRemotionEnvironment();
|
|
15
|
+
const [id] = useState(() => `${Math.random()}`.replace('0.', ''));
|
|
16
|
+
if (!videoConfig) {
|
|
17
|
+
throw new Error('No video config found');
|
|
18
|
+
}
|
|
19
|
+
if (!src) {
|
|
20
|
+
throw new TypeError('No `src` was passed to <Video>.');
|
|
21
|
+
}
|
|
22
|
+
const volume = Internals.evaluateVolume({
|
|
23
|
+
volume: volumeProp,
|
|
24
|
+
frame: volumePropsFrame,
|
|
25
|
+
mediaVolume: 1,
|
|
26
|
+
});
|
|
27
|
+
Internals.warnAboutTooHighVolume(volume);
|
|
28
|
+
const shouldRenderAudio = useMemo(() => {
|
|
29
|
+
if (!window.remotion_audioEnabled) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
if (muted) {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (volume <= 0) {
|
|
36
|
+
return false;
|
|
37
|
+
}
|
|
38
|
+
return true;
|
|
39
|
+
}, [muted, volume]);
|
|
40
|
+
const { fps } = videoConfig;
|
|
41
|
+
const { delayRender, continueRender } = useDelayRender();
|
|
42
|
+
useLayoutEffect(() => {
|
|
43
|
+
if (!canvasRef.current) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const actualFps = playbackRate ? fps / playbackRate : fps;
|
|
47
|
+
const timestamp = frame / actualFps;
|
|
48
|
+
const durationInSeconds = 1 / actualFps;
|
|
49
|
+
const newHandle = delayRender(`Extracting frame number ${frame}`, {
|
|
50
|
+
retries: delayRenderRetries ?? undefined,
|
|
51
|
+
timeoutInMilliseconds: delayRenderTimeoutInMilliseconds ?? undefined,
|
|
52
|
+
});
|
|
53
|
+
extractFrameViaBroadcastChannel({
|
|
54
|
+
src,
|
|
55
|
+
timeInSeconds: timestamp,
|
|
56
|
+
durationInSeconds,
|
|
57
|
+
logLevel: logLevel ?? 'info',
|
|
58
|
+
shouldRenderAudio,
|
|
59
|
+
isClientSideRendering: environment.isClientSideRendering,
|
|
60
|
+
})
|
|
61
|
+
.then(({ frame: imageBitmap, audio }) => {
|
|
62
|
+
if (!imageBitmap) {
|
|
63
|
+
cancelRender(new Error('No video frame found'));
|
|
64
|
+
}
|
|
65
|
+
onVideoFrame?.(imageBitmap);
|
|
66
|
+
canvasRef.current?.getContext('2d')?.drawImage(imageBitmap, 0, 0);
|
|
67
|
+
imageBitmap.close();
|
|
68
|
+
if (audio) {
|
|
69
|
+
registerRenderAsset({
|
|
70
|
+
type: 'inline-audio',
|
|
71
|
+
id,
|
|
72
|
+
audio: Array.from(audio.data),
|
|
73
|
+
sampleRate: audio.sampleRate,
|
|
74
|
+
numberOfChannels: audio.numberOfChannels,
|
|
75
|
+
frame: absoluteFrame,
|
|
76
|
+
timestamp: audio.timestamp,
|
|
77
|
+
duration: (audio.numberOfFrames / audio.sampleRate) * 1000000,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
continueRender(newHandle);
|
|
81
|
+
})
|
|
82
|
+
.catch((error) => {
|
|
83
|
+
cancelRender(error);
|
|
84
|
+
});
|
|
85
|
+
return () => {
|
|
86
|
+
continueRender(newHandle);
|
|
87
|
+
unregisterRenderAsset(id);
|
|
88
|
+
};
|
|
89
|
+
}, [
|
|
90
|
+
absoluteFrame,
|
|
91
|
+
continueRender,
|
|
92
|
+
delayRender,
|
|
93
|
+
delayRenderRetries,
|
|
94
|
+
delayRenderTimeoutInMilliseconds,
|
|
95
|
+
environment.isClientSideRendering,
|
|
96
|
+
fps,
|
|
97
|
+
frame,
|
|
98
|
+
id,
|
|
99
|
+
logLevel,
|
|
100
|
+
onVideoFrame,
|
|
101
|
+
playbackRate,
|
|
102
|
+
registerRenderAsset,
|
|
103
|
+
shouldRenderAudio,
|
|
104
|
+
src,
|
|
105
|
+
unregisterRenderAsset,
|
|
106
|
+
]);
|
|
107
|
+
return (_jsx("canvas", { ref: canvasRef, width: videoConfig.width, height: videoConfig.height }));
|
|
108
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { InputVideoTrack, WrappedCanvas } from 'mediabunny';
|
|
2
2
|
import type { LogLevel } from 'remotion';
|
|
3
3
|
import type { Nonce } from './nonce-manager';
|
|
4
|
-
export declare const videoIteratorManager: ({ delayPlaybackHandleIfNotPremounting, canvas, context, drawDebugOverlay, logLevel, getOnVideoFrameCallback, videoTrack, }: {
|
|
4
|
+
export declare const videoIteratorManager: ({ delayPlaybackHandleIfNotPremounting, canvas, context, drawDebugOverlay, logLevel, getOnVideoFrameCallback, videoTrack, getEndTime, getStartTime, getIsLooping, }: {
|
|
5
5
|
videoTrack: InputVideoTrack;
|
|
6
6
|
delayPlaybackHandleIfNotPremounting: () => {
|
|
7
7
|
unblock: () => void;
|
|
@@ -11,6 +11,9 @@ export declare const videoIteratorManager: ({ delayPlaybackHandleIfNotPremountin
|
|
|
11
11
|
getOnVideoFrameCallback: () => null | ((frame: CanvasImageSource) => void);
|
|
12
12
|
logLevel: LogLevel;
|
|
13
13
|
drawDebugOverlay: () => void;
|
|
14
|
+
getEndTime: () => number;
|
|
15
|
+
getStartTime: () => number;
|
|
16
|
+
getIsLooping: () => boolean;
|
|
14
17
|
}) => {
|
|
15
18
|
startVideoIterator: (timeToSeek: number, nonce: Nonce) => Promise<void>;
|
|
16
19
|
getVideoIteratorsCreated: () => number;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { CanvasSink } from 'mediabunny';
|
|
2
2
|
import { Internals } from 'remotion';
|
|
3
|
+
import { makePrewarmedVideoIteratorCache } from './prewarm-iterator-for-looping';
|
|
3
4
|
import { createVideoIterator, } from './video/video-preview-iterator';
|
|
4
|
-
export const videoIteratorManager = ({ delayPlaybackHandleIfNotPremounting, canvas, context, drawDebugOverlay, logLevel, getOnVideoFrameCallback, videoTrack, }) => {
|
|
5
|
+
export const videoIteratorManager = ({ delayPlaybackHandleIfNotPremounting, canvas, context, drawDebugOverlay, logLevel, getOnVideoFrameCallback, videoTrack, getEndTime, getStartTime, getIsLooping, }) => {
|
|
5
6
|
let videoIteratorsCreated = 0;
|
|
6
7
|
let videoFrameIterator = null;
|
|
7
8
|
let framesRendered = 0;
|
|
9
|
+
let currentDelayHandle = null;
|
|
8
10
|
if (canvas) {
|
|
9
11
|
canvas.width = videoTrack.displayWidth;
|
|
10
12
|
canvas.height = videoTrack.displayHeight;
|
|
@@ -14,6 +16,7 @@ export const videoIteratorManager = ({ delayPlaybackHandleIfNotPremounting, canv
|
|
|
14
16
|
fit: 'contain',
|
|
15
17
|
alpha: true,
|
|
16
18
|
});
|
|
19
|
+
const prewarmedVideoIteratorCache = makePrewarmedVideoIteratorCache(canvasSink);
|
|
17
20
|
const drawFrame = (frame) => {
|
|
18
21
|
if (context && canvas) {
|
|
19
22
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
@@ -29,12 +32,19 @@ export const videoIteratorManager = ({ delayPlaybackHandleIfNotPremounting, canv
|
|
|
29
32
|
};
|
|
30
33
|
const startVideoIterator = async (timeToSeek, nonce) => {
|
|
31
34
|
videoFrameIterator?.destroy();
|
|
32
|
-
const iterator = createVideoIterator(timeToSeek,
|
|
35
|
+
const iterator = createVideoIterator(timeToSeek, prewarmedVideoIteratorCache);
|
|
33
36
|
videoIteratorsCreated++;
|
|
34
37
|
videoFrameIterator = iterator;
|
|
35
38
|
const delayHandle = delayPlaybackHandleIfNotPremounting();
|
|
36
|
-
|
|
37
|
-
|
|
39
|
+
currentDelayHandle = delayHandle;
|
|
40
|
+
let frameResult;
|
|
41
|
+
try {
|
|
42
|
+
frameResult = await iterator.getNext();
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
delayHandle.unblock();
|
|
46
|
+
currentDelayHandle = null;
|
|
47
|
+
}
|
|
38
48
|
if (iterator.isDestroyed()) {
|
|
39
49
|
return;
|
|
40
50
|
}
|
|
@@ -54,6 +64,14 @@ export const videoIteratorManager = ({ delayPlaybackHandleIfNotPremounting, canv
|
|
|
54
64
|
if (!videoFrameIterator) {
|
|
55
65
|
return;
|
|
56
66
|
}
|
|
67
|
+
if (getIsLooping()) {
|
|
68
|
+
// If less than 1 second from the end away, we pre-warm a new iterator
|
|
69
|
+
if (getEndTime() - newTime < 1) {
|
|
70
|
+
prewarmedVideoIteratorCache.prewarmIteratorForLooping({
|
|
71
|
+
timeToSeek: getStartTime(),
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
57
75
|
// Should return immediately, so it's okay to not use Promise.all here
|
|
58
76
|
const videoSatisfyResult = await videoFrameIterator.tryToSatisfySeek(newTime);
|
|
59
77
|
// Doing this before the staleness check, because
|
|
@@ -73,10 +91,15 @@ export const videoIteratorManager = ({ delayPlaybackHandleIfNotPremounting, canv
|
|
|
73
91
|
getVideoIteratorsCreated: () => videoIteratorsCreated,
|
|
74
92
|
seek,
|
|
75
93
|
destroy: () => {
|
|
94
|
+
prewarmedVideoIteratorCache.destroy();
|
|
76
95
|
videoFrameIterator?.destroy();
|
|
77
96
|
if (context && canvas) {
|
|
78
97
|
context.clearRect(0, 0, canvas.width, canvas.height);
|
|
79
98
|
}
|
|
99
|
+
if (currentDelayHandle) {
|
|
100
|
+
currentDelayHandle.unblock();
|
|
101
|
+
currentDelayHandle = null;
|
|
102
|
+
}
|
|
80
103
|
videoFrameIterator = null;
|
|
81
104
|
},
|
|
82
105
|
getVideoFrameIterator: () => videoFrameIterator,
|
package/dist/video.d.ts
ADDED
package/dist/video.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useCallback } from 'react';
|
|
3
|
+
import { Internals, Sequence, useRemotionEnvironment } from 'remotion';
|
|
4
|
+
import { VideoForRendering } from './video-for-rendering';
|
|
5
|
+
const { validateMediaTrimProps, resolveTrimProps, validateMediaProps, VideoForPreview, } = Internals;
|
|
6
|
+
export const Video = (props) => {
|
|
7
|
+
// Should only destruct `trimBefore` and `trimAfter` from props,
|
|
8
|
+
// rest gets drilled down
|
|
9
|
+
const { trimBefore, trimAfter, name, pauseWhenBuffering, stack, showInTimeline, ...otherProps } = props;
|
|
10
|
+
const environment = useRemotionEnvironment();
|
|
11
|
+
const onDuration = useCallback(() => undefined, []);
|
|
12
|
+
if (typeof props.src !== 'string') {
|
|
13
|
+
throw new TypeError(`The \`<Video>\` tag requires a string for \`src\`, but got ${JSON.stringify(props.src)} instead.`);
|
|
14
|
+
}
|
|
15
|
+
validateMediaTrimProps({
|
|
16
|
+
startFrom: undefined,
|
|
17
|
+
endAt: undefined,
|
|
18
|
+
trimBefore,
|
|
19
|
+
trimAfter,
|
|
20
|
+
});
|
|
21
|
+
const { trimBeforeValue, trimAfterValue } = resolveTrimProps({
|
|
22
|
+
startFrom: undefined,
|
|
23
|
+
endAt: undefined,
|
|
24
|
+
trimBefore,
|
|
25
|
+
trimAfter,
|
|
26
|
+
});
|
|
27
|
+
if (typeof trimBeforeValue !== 'undefined' ||
|
|
28
|
+
typeof trimAfterValue !== 'undefined') {
|
|
29
|
+
return (_jsx(Sequence, { layout: "none", from: 0 - (trimBeforeValue ?? 0), showInTimeline: false, durationInFrames: trimAfterValue, name: name, children: _jsx(Video, { pauseWhenBuffering: pauseWhenBuffering ?? false, ...otherProps }) }));
|
|
30
|
+
}
|
|
31
|
+
validateMediaProps(props, 'Video');
|
|
32
|
+
if (environment.isRendering) {
|
|
33
|
+
return _jsx(VideoForRendering, { ...otherProps });
|
|
34
|
+
}
|
|
35
|
+
const { onAutoPlayError, onVideoFrame, crossOrigin, delayRenderRetries, delayRenderTimeoutInMilliseconds, ...propsForPreview } = otherProps;
|
|
36
|
+
return (_jsx(VideoForPreview, { _remotionInternalStack: stack ?? null, _remotionInternalNativeLoopPassed: false, onDuration: onDuration, onlyWarnForMediaSeekingError: true, pauseWhenBuffering: pauseWhenBuffering ?? false, showInTimeline: showInTimeline ?? true, onAutoPlayError: onAutoPlayError ?? undefined, onVideoFrame: onVideoFrame ?? null, crossOrigin: crossOrigin, ...propsForPreview }));
|
|
37
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remotion/media",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.392",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -22,14 +22,14 @@
|
|
|
22
22
|
},
|
|
23
23
|
"dependencies": {
|
|
24
24
|
"mediabunny": "1.25.8",
|
|
25
|
-
"remotion": "4.0.
|
|
25
|
+
"remotion": "4.0.392"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": ">=16.8.0",
|
|
29
29
|
"react-dom": ">=16.8.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@remotion/eslint-config-internal": "4.0.
|
|
32
|
+
"@remotion/eslint-config-internal": "4.0.392",
|
|
33
33
|
"@vitest/browser-webdriverio": "4.0.9",
|
|
34
34
|
"eslint": "9.19.0",
|
|
35
35
|
"react": "19.2.3",
|