@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
package/dist/media-player.js
CHANGED
|
@@ -3,12 +3,12 @@ import { Internals } from 'remotion';
|
|
|
3
3
|
import { audioIteratorManager, } from './audio-iterator-manager';
|
|
4
4
|
import { calculatePlaybackTime } from './calculate-playbacktime';
|
|
5
5
|
import { drawPreviewOverlay } from './debug-overlay/preview-overlay';
|
|
6
|
-
import { getTimeInSeconds } from './get-time-in-seconds';
|
|
6
|
+
import { calculateEndTime, getTimeInSeconds } from './get-time-in-seconds';
|
|
7
7
|
import { isNetworkError } from './is-type-of-error';
|
|
8
8
|
import { makeNonceManager } from './nonce-manager';
|
|
9
9
|
import { videoIteratorManager } from './video-iterator-manager';
|
|
10
10
|
export class MediaPlayer {
|
|
11
|
-
constructor({ canvas, src, logLevel, sharedAudioContext, loop, trimBefore, trimAfter, playbackRate, globalPlaybackRate, audioStreamIndex, fps, debugOverlay, bufferState, isPremounting, isPostmounting, onVideoFrameCallback, }) {
|
|
11
|
+
constructor({ canvas, src, logLevel, sharedAudioContext, loop, trimBefore, trimAfter, playbackRate, globalPlaybackRate, audioStreamIndex, fps, debugOverlay, bufferState, isPremounting, isPostmounting, onVideoFrameCallback, playing, }) {
|
|
12
12
|
this.audioIteratorManager = null;
|
|
13
13
|
this.videoIteratorManager = null;
|
|
14
14
|
// this is the time difference between Web Audio timeline
|
|
@@ -71,6 +71,7 @@ export class MediaPlayer {
|
|
|
71
71
|
this.isPostmounting = isPostmounting;
|
|
72
72
|
this.nonceManager = makeNonceManager();
|
|
73
73
|
this.onVideoFrameCallback = onVideoFrameCallback;
|
|
74
|
+
this.playing = playing;
|
|
74
75
|
this.input = new Input({
|
|
75
76
|
source: new UrlSource(this.src),
|
|
76
77
|
formats: ALL_FORMATS,
|
|
@@ -95,9 +96,24 @@ export class MediaPlayer {
|
|
|
95
96
|
initialize(startTimeUnresolved) {
|
|
96
97
|
const promise = this._initialize(startTimeUnresolved);
|
|
97
98
|
this.initializationPromise = promise;
|
|
99
|
+
this.seekPromiseChain = promise;
|
|
98
100
|
return promise;
|
|
99
101
|
}
|
|
102
|
+
getStartTime() {
|
|
103
|
+
return (this.trimBefore ?? 0) / this.fps;
|
|
104
|
+
}
|
|
105
|
+
getEndTime() {
|
|
106
|
+
return calculateEndTime({
|
|
107
|
+
mediaDurationInSeconds: this.totalDuration,
|
|
108
|
+
ifNoMediaDuration: 'fail',
|
|
109
|
+
src: this.src,
|
|
110
|
+
trimAfter: this.trimAfter,
|
|
111
|
+
trimBefore: this.trimBefore,
|
|
112
|
+
fps: this.fps,
|
|
113
|
+
});
|
|
114
|
+
}
|
|
100
115
|
async _initialize(startTimeUnresolved) {
|
|
116
|
+
const delayHandle = this.delayPlaybackHandleIfNotPremounting();
|
|
101
117
|
try {
|
|
102
118
|
if (this.input.disposed) {
|
|
103
119
|
return { type: 'disposed' };
|
|
@@ -145,6 +161,9 @@ export class MediaPlayer {
|
|
|
145
161
|
getOnVideoFrameCallback: () => this.onVideoFrameCallback,
|
|
146
162
|
logLevel: this.logLevel,
|
|
147
163
|
drawDebugOverlay: this.drawDebugOverlay,
|
|
164
|
+
getEndTime: () => this.getEndTime(),
|
|
165
|
+
getStartTime: () => this.getStartTime(),
|
|
166
|
+
getIsLooping: () => this.loop,
|
|
148
167
|
});
|
|
149
168
|
}
|
|
150
169
|
const startTime = getTimeInSeconds({
|
|
@@ -167,21 +186,28 @@ export class MediaPlayer {
|
|
|
167
186
|
audioTrack,
|
|
168
187
|
delayPlaybackHandleIfNotPremounting: this.delayPlaybackHandleIfNotPremounting,
|
|
169
188
|
sharedAudioContext: this.sharedAudioContext,
|
|
189
|
+
getIsLooping: () => this.loop,
|
|
190
|
+
getEndTime: () => this.getEndTime(),
|
|
191
|
+
getStartTime: () => this.getStartTime(),
|
|
192
|
+
updatePlaybackTime: (time) => this.setPlaybackTime(time, this.playbackRate * this.globalPlaybackRate),
|
|
170
193
|
});
|
|
171
194
|
}
|
|
172
195
|
const nonce = this.nonceManager.createAsyncOperation();
|
|
173
196
|
try {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
197
|
+
await Promise.all([
|
|
198
|
+
this.audioIteratorManager
|
|
199
|
+
? this.audioIteratorManager.startAudioIterator({
|
|
200
|
+
nonce,
|
|
201
|
+
playbackRate: this.playbackRate * this.globalPlaybackRate,
|
|
202
|
+
startFromSecond: startTime,
|
|
203
|
+
getIsPlaying: () => this.playing,
|
|
204
|
+
scheduleAudioNode: this.scheduleAudioNode,
|
|
205
|
+
})
|
|
206
|
+
: Promise.resolve(),
|
|
207
|
+
this.videoIteratorManager
|
|
208
|
+
? this.videoIteratorManager.startVideoIterator(startTime, nonce)
|
|
209
|
+
: Promise.resolve(),
|
|
210
|
+
]);
|
|
185
211
|
}
|
|
186
212
|
catch (error) {
|
|
187
213
|
if (this.isDisposalError()) {
|
|
@@ -200,6 +226,9 @@ export class MediaPlayer {
|
|
|
200
226
|
Internals.Log.error({ logLevel: this.logLevel, tag: '@remotion/media' }, '[MediaPlayer] Failed to initialize', error);
|
|
201
227
|
throw error;
|
|
202
228
|
}
|
|
229
|
+
finally {
|
|
230
|
+
delayHandle.unblock();
|
|
231
|
+
}
|
|
203
232
|
}
|
|
204
233
|
async seekTo(time) {
|
|
205
234
|
const newTime = getTimeInSeconds({
|
|
@@ -246,6 +275,9 @@ export class MediaPlayer {
|
|
|
246
275
|
]);
|
|
247
276
|
}
|
|
248
277
|
async play(time) {
|
|
278
|
+
if (this.playing) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
249
281
|
const newTime = getTimeInSeconds({
|
|
250
282
|
unloopedTimeInSeconds: time,
|
|
251
283
|
playbackRate: this.playbackRate,
|
|
@@ -274,6 +306,9 @@ export class MediaPlayer {
|
|
|
274
306
|
this.drawDebugOverlay();
|
|
275
307
|
}
|
|
276
308
|
pause() {
|
|
309
|
+
if (!this.playing) {
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
277
312
|
this.playing = false;
|
|
278
313
|
this.audioIteratorManager?.pausePlayback();
|
|
279
314
|
this.drawDebugOverlay();
|
|
@@ -310,12 +345,16 @@ export class MediaPlayer {
|
|
|
310
345
|
this.audioIteratorManager?.destroyIterator();
|
|
311
346
|
}
|
|
312
347
|
setTrimBefore(trimBefore, unloopedTimeInSeconds) {
|
|
313
|
-
this.trimBefore
|
|
314
|
-
|
|
348
|
+
if (this.trimBefore !== trimBefore) {
|
|
349
|
+
this.trimBefore = trimBefore;
|
|
350
|
+
this.updateAfterTrimChange(unloopedTimeInSeconds);
|
|
351
|
+
}
|
|
315
352
|
}
|
|
316
353
|
setTrimAfter(trimAfter, unloopedTimeInSeconds) {
|
|
317
|
-
this.trimAfter
|
|
318
|
-
|
|
354
|
+
if (this.trimAfter !== trimAfter) {
|
|
355
|
+
this.trimAfter = trimAfter;
|
|
356
|
+
this.updateAfterTrimChange(unloopedTimeInSeconds);
|
|
357
|
+
}
|
|
319
358
|
}
|
|
320
359
|
setDebugOverlay(debugOverlay) {
|
|
321
360
|
this.debugOverlay = debugOverlay;
|
|
@@ -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
|
+
};
|
|
@@ -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 './new-video-for-rendering';
|
|
5
|
+
const { validateMediaTrimProps, resolveTrimProps, validateMediaProps, VideoForPreview, } = Internals;
|
|
6
|
+
export const Video = (props) => {
|
|
7
|
+
// Should only destruct `startFrom` and `endAt` 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
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AudioBufferSink, CanvasSink, WrappedAudioBuffer, WrappedCanvas } from 'mediabunny';
|
|
2
|
+
export declare const makePrewarmedVideoIteratorCache: (videoSink: CanvasSink) => {
|
|
3
|
+
prewarmIteratorForLooping: ({ timeToSeek }: {
|
|
4
|
+
timeToSeek: number;
|
|
5
|
+
}) => void;
|
|
6
|
+
makeIteratorOrUsePrewarmed: (timeToSeek: number) => AsyncGenerator<WrappedCanvas, void, unknown>;
|
|
7
|
+
destroy: () => void;
|
|
8
|
+
};
|
|
9
|
+
export type PrewarmedVideoIteratorCache = ReturnType<typeof makePrewarmedVideoIteratorCache>;
|
|
10
|
+
export declare const makePrewarmedAudioIteratorCache: (audioSink: AudioBufferSink) => {
|
|
11
|
+
prewarmIteratorForLooping: ({ timeToSeek }: {
|
|
12
|
+
timeToSeek: number;
|
|
13
|
+
}) => void;
|
|
14
|
+
makeIteratorOrUsePrewarmed: (timeToSeek: number) => AsyncGenerator<WrappedAudioBuffer, void, unknown>;
|
|
15
|
+
destroy: () => void;
|
|
16
|
+
};
|
|
17
|
+
export type PrewarmedAudioIteratorCache = ReturnType<typeof makePrewarmedAudioIteratorCache>;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const makePrewarmedVideoIteratorCache = (videoSink) => {
|
|
2
|
+
const prewarmedVideoIterators = new Map();
|
|
3
|
+
const prewarmIteratorForLooping = ({ timeToSeek }) => {
|
|
4
|
+
if (!prewarmedVideoIterators.has(timeToSeek)) {
|
|
5
|
+
prewarmedVideoIterators.set(timeToSeek, videoSink.canvases(timeToSeek));
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
const makeIteratorOrUsePrewarmed = (timeToSeek) => {
|
|
9
|
+
const prewarmedIterator = prewarmedVideoIterators.get(timeToSeek);
|
|
10
|
+
if (prewarmedIterator) {
|
|
11
|
+
prewarmedVideoIterators.delete(timeToSeek);
|
|
12
|
+
return prewarmedIterator;
|
|
13
|
+
}
|
|
14
|
+
const iterator = videoSink.canvases(timeToSeek);
|
|
15
|
+
return iterator;
|
|
16
|
+
};
|
|
17
|
+
const destroy = () => {
|
|
18
|
+
for (const iterator of prewarmedVideoIterators.values()) {
|
|
19
|
+
iterator.return();
|
|
20
|
+
}
|
|
21
|
+
prewarmedVideoIterators.clear();
|
|
22
|
+
};
|
|
23
|
+
return {
|
|
24
|
+
prewarmIteratorForLooping,
|
|
25
|
+
makeIteratorOrUsePrewarmed,
|
|
26
|
+
destroy,
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
export const makePrewarmedAudioIteratorCache = (audioSink) => {
|
|
30
|
+
const prewarmedAudioIterators = new Map();
|
|
31
|
+
const prewarmIteratorForLooping = ({ timeToSeek }) => {
|
|
32
|
+
if (!prewarmedAudioIterators.has(timeToSeek)) {
|
|
33
|
+
prewarmedAudioIterators.set(timeToSeek, audioSink.buffers(timeToSeek));
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
const makeIteratorOrUsePrewarmed = (timeToSeek) => {
|
|
37
|
+
const prewarmedIterator = prewarmedAudioIterators.get(timeToSeek);
|
|
38
|
+
if (prewarmedIterator) {
|
|
39
|
+
prewarmedAudioIterators.delete(timeToSeek);
|
|
40
|
+
return prewarmedIterator;
|
|
41
|
+
}
|
|
42
|
+
const iterator = audioSink.buffers(timeToSeek);
|
|
43
|
+
return iterator;
|
|
44
|
+
};
|
|
45
|
+
const destroy = () => {
|
|
46
|
+
for (const iterator of prewarmedAudioIterators.values()) {
|
|
47
|
+
iterator.return();
|
|
48
|
+
}
|
|
49
|
+
prewarmedAudioIterators.clear();
|
|
50
|
+
};
|
|
51
|
+
return {
|
|
52
|
+
prewarmIteratorForLooping,
|
|
53
|
+
makeIteratorOrUsePrewarmed,
|
|
54
|
+
destroy,
|
|
55
|
+
};
|
|
56
|
+
};
|
package/dist/props.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { LoopVolumeCurveBehavior, VolumeProp } from 'remotion';
|
|
2
|
+
import type { LogLevel } from './log';
|
|
3
|
+
export type AudioProps = {
|
|
4
|
+
src: string;
|
|
5
|
+
trimBefore?: number;
|
|
6
|
+
trimAfter?: number;
|
|
7
|
+
volume?: VolumeProp;
|
|
8
|
+
loopVolumeCurveBehavior?: LoopVolumeCurveBehavior;
|
|
9
|
+
name?: string;
|
|
10
|
+
pauseWhenBuffering?: boolean;
|
|
11
|
+
showInTimeline?: boolean;
|
|
12
|
+
onAutoPlayError?: null | (() => void);
|
|
13
|
+
playbackRate?: number;
|
|
14
|
+
muted?: boolean;
|
|
15
|
+
delayRenderRetries?: number;
|
|
16
|
+
delayRenderTimeoutInMilliseconds?: number;
|
|
17
|
+
crossOrigin?: '' | 'anonymous' | 'use-credentials';
|
|
18
|
+
style?: React.CSSProperties;
|
|
19
|
+
onError?: (err: Error) => void;
|
|
20
|
+
useWebAudioApi?: boolean;
|
|
21
|
+
acceptableTimeShiftInSeconds?: number;
|
|
22
|
+
/**
|
|
23
|
+
* @deprecated For internal use only
|
|
24
|
+
*/
|
|
25
|
+
stack?: string;
|
|
26
|
+
logLevel?: LogLevel;
|
|
27
|
+
loop?: boolean;
|
|
28
|
+
_remotionInternalNativeLoopPassed?: boolean;
|
|
29
|
+
};
|
package/dist/props.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export const rememberActualMatroskaTimestamps = (isMatroska) => {
|
|
2
|
+
const observations = [];
|
|
3
|
+
const observeTimestamp = (startTime) => {
|
|
4
|
+
if (!isMatroska) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
observations.push(startTime);
|
|
8
|
+
};
|
|
9
|
+
const getRealTimestamp = (observedTimestamp) => {
|
|
10
|
+
if (!isMatroska) {
|
|
11
|
+
return observedTimestamp;
|
|
12
|
+
}
|
|
13
|
+
return (observations.find((observation) => Math.abs(observedTimestamp - observation) < 0.001) ?? null);
|
|
14
|
+
};
|
|
15
|
+
return {
|
|
16
|
+
observeTimestamp,
|
|
17
|
+
getRealTimestamp,
|
|
18
|
+
};
|
|
19
|
+
};
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { LogLevel } from 'remotion';
|
|
2
|
+
export declare const SEEK_THRESHOLD = 0.05;
|
|
3
|
+
export declare class MediaPlayer {
|
|
4
|
+
private canvas;
|
|
5
|
+
private context;
|
|
6
|
+
private src;
|
|
7
|
+
private logLevel;
|
|
8
|
+
private canvasSink;
|
|
9
|
+
private videoFrameIterator;
|
|
10
|
+
private nextFrame;
|
|
11
|
+
private audioSink;
|
|
12
|
+
private audioBufferIterator;
|
|
13
|
+
private queuedAudioNodes;
|
|
14
|
+
private gainNode;
|
|
15
|
+
private sharedAudioContext;
|
|
16
|
+
private audioSyncAnchor;
|
|
17
|
+
private playing;
|
|
18
|
+
private animationFrameId;
|
|
19
|
+
private videoAsyncId;
|
|
20
|
+
private initialized;
|
|
21
|
+
private totalDuration;
|
|
22
|
+
private isBuffering;
|
|
23
|
+
private onBufferingChangeCallback?;
|
|
24
|
+
private audioBufferHealth;
|
|
25
|
+
private audioIteratorStarted;
|
|
26
|
+
private readonly HEALTHY_BUFER_THRESHOLD_SECONDS;
|
|
27
|
+
constructor({ canvas, src, logLevel, sharedAudioContext, }: {
|
|
28
|
+
canvas: HTMLCanvasElement;
|
|
29
|
+
src: string;
|
|
30
|
+
logLevel: LogLevel;
|
|
31
|
+
sharedAudioContext: AudioContext;
|
|
32
|
+
});
|
|
33
|
+
private input;
|
|
34
|
+
private isReady;
|
|
35
|
+
private hasAudio;
|
|
36
|
+
private isCurrentlyBuffering;
|
|
37
|
+
initialize(startTime?: number): Promise<void>;
|
|
38
|
+
private cleanupAudioQueue;
|
|
39
|
+
private cleanAudioIteratorAndNodes;
|
|
40
|
+
seekTo(time: number): Promise<void>;
|
|
41
|
+
play(): Promise<void>;
|
|
42
|
+
pause(): void;
|
|
43
|
+
dispose(): void;
|
|
44
|
+
private getPlaybackTime;
|
|
45
|
+
private scheduleAudioChunk;
|
|
46
|
+
onBufferingChange(callback: (isBuffering: boolean) => void): void;
|
|
47
|
+
private canRenderVideo;
|
|
48
|
+
private startRenderLoop;
|
|
49
|
+
private stopRenderLoop;
|
|
50
|
+
private render;
|
|
51
|
+
private shouldRenderFrame;
|
|
52
|
+
private drawCurrentFrame;
|
|
53
|
+
private startAudioIterator;
|
|
54
|
+
private startVideoIterator;
|
|
55
|
+
private updateNextFrame;
|
|
56
|
+
private bufferingStartedAtMs;
|
|
57
|
+
private minBufferingTimeoutMs;
|
|
58
|
+
private setBufferingState;
|
|
59
|
+
private maybeResumeFromBuffering;
|
|
60
|
+
private maybeForceResumeFromBuffering;
|
|
61
|
+
private runAudioIterator;
|
|
62
|
+
}
|