@remotion/media 4.0.428 → 4.0.430
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/README.md +7 -7
- package/dist/audio/allow-wait.js +15 -0
- package/dist/audio/audio-for-preview.d.ts +0 -1
- package/dist/audio/audio-for-preview.js +304 -0
- package/dist/audio/audio-for-rendering.js +194 -0
- package/dist/audio/audio-preview-iterator.d.ts +4 -2
- package/dist/audio/audio-preview-iterator.js +176 -0
- package/dist/audio/audio.js +20 -0
- package/dist/audio/props.js +1 -0
- package/dist/audio-extraction/audio-cache.js +66 -0
- package/dist/audio-extraction/audio-iterator.js +132 -0
- package/dist/audio-extraction/audio-manager.js +113 -0
- package/dist/audio-extraction/extract-audio.js +132 -0
- package/dist/audio-iterator-manager.d.ts +10 -9
- package/dist/audio-iterator-manager.js +228 -0
- package/dist/browser-can-use-webgl2.js +13 -0
- package/dist/caches.js +61 -0
- package/dist/calculate-playbacktime.js +4 -0
- package/dist/convert-audiodata/apply-volume.js +17 -0
- package/dist/convert-audiodata/combine-audiodata.js +23 -0
- package/dist/convert-audiodata/convert-audiodata.js +73 -0
- package/dist/convert-audiodata/resample-audiodata.js +94 -0
- package/dist/debug-overlay/preview-overlay.d.ts +9 -7
- package/dist/debug-overlay/preview-overlay.js +42 -0
- package/dist/esm/index.mjs +246 -103
- package/dist/extract-frame-and-audio.js +101 -0
- package/dist/get-sink.js +15 -0
- package/dist/get-time-in-seconds.js +40 -0
- package/dist/helpers/round-to-4-digits.js +4 -0
- package/dist/index.js +12 -0
- package/dist/is-type-of-error.js +20 -0
- package/dist/looped-frame.js +10 -0
- package/dist/media-player.d.ts +9 -5
- package/dist/media-player.js +431 -0
- package/dist/nonce-manager.js +13 -0
- package/dist/prewarm-iterator-for-looping.js +56 -0
- package/dist/render-timestamp-range.js +9 -0
- package/dist/show-in-timeline.js +31 -0
- package/dist/use-media-in-timeline.d.ts +3 -2
- package/dist/use-media-in-timeline.js +103 -0
- package/dist/video/props.js +1 -0
- package/dist/video/video-for-preview.js +331 -0
- package/dist/video/video-for-rendering.js +263 -0
- package/dist/video/video-preview-iterator.js +122 -0
- package/dist/video/video.js +35 -0
- package/dist/video-extraction/add-broadcast-channel-listener.js +125 -0
- package/dist/video-extraction/extract-frame-via-broadcast-channel.js +113 -0
- package/dist/video-extraction/extract-frame.js +85 -0
- package/dist/video-extraction/get-allocation-size.js +6 -0
- package/dist/video-extraction/get-frames-since-keyframe.js +108 -0
- package/dist/video-extraction/keyframe-bank.js +159 -0
- package/dist/video-extraction/keyframe-manager.js +206 -0
- package/dist/video-extraction/remember-actual-matroska-timestamps.js +19 -0
- package/dist/video-extraction/rotate-frame.js +34 -0
- package/dist/video-iterator-manager.js +109 -0
- package/package.json +7 -5
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { extractAudio } from './audio-extraction/extract-audio';
|
|
2
|
+
import { isNetworkError } from './is-type-of-error';
|
|
3
|
+
import { extractFrame } from './video-extraction/extract-frame';
|
|
4
|
+
import { rotateFrame } from './video-extraction/rotate-frame';
|
|
5
|
+
export const extractFrameAndAudio = async ({ src, timeInSeconds, logLevel, durationInSeconds, playbackRate, includeAudio, includeVideo, loop, audioStreamIndex, trimAfter, trimBefore, fps, maxCacheSize, }) => {
|
|
6
|
+
try {
|
|
7
|
+
const [frame, audio] = await Promise.all([
|
|
8
|
+
includeVideo
|
|
9
|
+
? extractFrame({
|
|
10
|
+
src,
|
|
11
|
+
timeInSeconds,
|
|
12
|
+
logLevel,
|
|
13
|
+
loop,
|
|
14
|
+
trimAfter,
|
|
15
|
+
playbackRate,
|
|
16
|
+
trimBefore,
|
|
17
|
+
fps,
|
|
18
|
+
maxCacheSize,
|
|
19
|
+
})
|
|
20
|
+
: null,
|
|
21
|
+
includeAudio
|
|
22
|
+
? extractAudio({
|
|
23
|
+
src,
|
|
24
|
+
timeInSeconds,
|
|
25
|
+
durationInSeconds,
|
|
26
|
+
logLevel,
|
|
27
|
+
loop,
|
|
28
|
+
playbackRate,
|
|
29
|
+
audioStreamIndex,
|
|
30
|
+
trimAfter,
|
|
31
|
+
fps,
|
|
32
|
+
trimBefore,
|
|
33
|
+
maxCacheSize,
|
|
34
|
+
})
|
|
35
|
+
: null,
|
|
36
|
+
]);
|
|
37
|
+
if (frame?.type === 'cannot-decode') {
|
|
38
|
+
return {
|
|
39
|
+
type: 'cannot-decode',
|
|
40
|
+
durationInSeconds: frame.durationInSeconds,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
if (frame?.type === 'unknown-container-format') {
|
|
44
|
+
return { type: 'unknown-container-format' };
|
|
45
|
+
}
|
|
46
|
+
if (frame?.type === 'cannot-decode-alpha') {
|
|
47
|
+
return {
|
|
48
|
+
type: 'cannot-decode-alpha',
|
|
49
|
+
durationInSeconds: frame.durationInSeconds,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (frame?.type === 'network-error') {
|
|
53
|
+
return { type: 'network-error' };
|
|
54
|
+
}
|
|
55
|
+
if (audio === 'unknown-container-format') {
|
|
56
|
+
if (frame !== null) {
|
|
57
|
+
frame?.frame?.close();
|
|
58
|
+
}
|
|
59
|
+
return { type: 'unknown-container-format' };
|
|
60
|
+
}
|
|
61
|
+
if (audio === 'network-error') {
|
|
62
|
+
if (frame !== null) {
|
|
63
|
+
frame?.frame?.close();
|
|
64
|
+
}
|
|
65
|
+
return { type: 'network-error' };
|
|
66
|
+
}
|
|
67
|
+
if (audio === 'cannot-decode') {
|
|
68
|
+
if (frame?.type === 'success' && frame.frame !== null) {
|
|
69
|
+
frame?.frame.close();
|
|
70
|
+
}
|
|
71
|
+
return {
|
|
72
|
+
type: 'cannot-decode',
|
|
73
|
+
durationInSeconds: frame?.type === 'success' ? frame.durationInSeconds : null,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
if (!frame?.frame) {
|
|
77
|
+
return {
|
|
78
|
+
type: 'success',
|
|
79
|
+
frame: null,
|
|
80
|
+
audio: audio?.data ?? null,
|
|
81
|
+
durationInSeconds: audio?.durationInSeconds ?? null,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
type: 'success',
|
|
86
|
+
frame: await rotateFrame({
|
|
87
|
+
frame: frame.frame.toVideoFrame(),
|
|
88
|
+
rotation: frame.frame.rotation,
|
|
89
|
+
}),
|
|
90
|
+
audio: audio?.data ?? null,
|
|
91
|
+
durationInSeconds: audio?.durationInSeconds ?? null,
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const error = err;
|
|
96
|
+
if (isNetworkError(error)) {
|
|
97
|
+
return { type: 'network-error' };
|
|
98
|
+
}
|
|
99
|
+
throw err;
|
|
100
|
+
}
|
|
101
|
+
};
|
package/dist/get-sink.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Internals } from 'remotion';
|
|
2
|
+
import { getSinks } from './video-extraction/get-frames-since-keyframe';
|
|
3
|
+
export const sinkPromises = {};
|
|
4
|
+
export const getSink = (src, logLevel) => {
|
|
5
|
+
let promise = sinkPromises[src];
|
|
6
|
+
if (!promise) {
|
|
7
|
+
Internals.Log.verbose({
|
|
8
|
+
logLevel,
|
|
9
|
+
tag: '@remotion/media',
|
|
10
|
+
}, `Sink for ${src} was not found, creating new sink`);
|
|
11
|
+
promise = getSinks(src);
|
|
12
|
+
sinkPromises[src] = promise;
|
|
13
|
+
}
|
|
14
|
+
return promise;
|
|
15
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Internals } from 'remotion';
|
|
2
|
+
export const getTimeInSeconds = ({ loop, mediaDurationInSeconds, unloopedTimeInSeconds, src, trimAfter, trimBefore, fps, playbackRate, ifNoMediaDuration, }) => {
|
|
3
|
+
if (mediaDurationInSeconds === null && loop && ifNoMediaDuration === 'fail') {
|
|
4
|
+
throw new Error(`Could not determine duration of ${src}, but "loop" was set.`);
|
|
5
|
+
}
|
|
6
|
+
const loopDuration = loop
|
|
7
|
+
? Internals.calculateMediaDuration({
|
|
8
|
+
trimAfter,
|
|
9
|
+
mediaDurationInFrames: mediaDurationInSeconds
|
|
10
|
+
? mediaDurationInSeconds * fps
|
|
11
|
+
: Infinity,
|
|
12
|
+
// Playback rate was already specified before
|
|
13
|
+
playbackRate: 1,
|
|
14
|
+
trimBefore,
|
|
15
|
+
}) / fps
|
|
16
|
+
: Infinity;
|
|
17
|
+
const timeInSeconds = (unloopedTimeInSeconds * playbackRate) % loopDuration;
|
|
18
|
+
if ((trimAfter ?? null) !== null && !loop) {
|
|
19
|
+
const time = (trimAfter - (trimBefore ?? 0)) / fps;
|
|
20
|
+
if (timeInSeconds >= time) {
|
|
21
|
+
return null;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
return timeInSeconds + (trimBefore ?? 0) / fps;
|
|
25
|
+
};
|
|
26
|
+
export const calculateEndTime = ({ mediaDurationInSeconds, ifNoMediaDuration, src, trimAfter, trimBefore, fps, }) => {
|
|
27
|
+
if (mediaDurationInSeconds === null && ifNoMediaDuration === 'fail') {
|
|
28
|
+
throw new Error(`Could not determine duration of ${src}, but "loop" was set.`);
|
|
29
|
+
}
|
|
30
|
+
const mediaDuration = Internals.calculateMediaDuration({
|
|
31
|
+
trimAfter,
|
|
32
|
+
mediaDurationInFrames: mediaDurationInSeconds
|
|
33
|
+
? mediaDurationInSeconds * fps
|
|
34
|
+
: Infinity,
|
|
35
|
+
// Playback rate was already specified before
|
|
36
|
+
playbackRate: 1,
|
|
37
|
+
trimBefore,
|
|
38
|
+
}) / fps;
|
|
39
|
+
return mediaDuration + (trimBefore ?? 0) / fps;
|
|
40
|
+
};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Audio } from './audio/audio';
|
|
2
|
+
import { Video } from './video/video';
|
|
3
|
+
/**
|
|
4
|
+
* @deprecated Now just `Audio`
|
|
5
|
+
*/
|
|
6
|
+
export const experimental_Audio = Audio;
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Now just `Video`
|
|
9
|
+
*/
|
|
10
|
+
export const experimental_Video = Video;
|
|
11
|
+
export { AudioForPreview } from './audio/audio-for-preview';
|
|
12
|
+
export { Audio, Video };
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utility to check if error is network error
|
|
3
|
+
* @param error
|
|
4
|
+
* @returns
|
|
5
|
+
*/
|
|
6
|
+
export function isNetworkError(error) {
|
|
7
|
+
if (
|
|
8
|
+
// Chrome
|
|
9
|
+
error.message.includes('Failed to fetch') ||
|
|
10
|
+
// Safari
|
|
11
|
+
error.message.includes('Load failed') ||
|
|
12
|
+
// Firefox
|
|
13
|
+
error.message.includes('NetworkError when attempting to fetch resource')) {
|
|
14
|
+
return true;
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
export function isUnsupportedConfigurationError(error) {
|
|
19
|
+
return error.message.includes('Unsupported configuration');
|
|
20
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const frameForVolumeProp = ({ behavior, loop, assetDurationInSeconds, fps, frame, startsAt, }) => {
|
|
2
|
+
if (!loop) {
|
|
3
|
+
return frame + startsAt;
|
|
4
|
+
}
|
|
5
|
+
if (behavior === 'extend') {
|
|
6
|
+
return frame + startsAt;
|
|
7
|
+
}
|
|
8
|
+
const assetDurationInFrames = Math.floor(assetDurationInSeconds * fps) - startsAt;
|
|
9
|
+
return (frame % assetDurationInFrames) + startsAt;
|
|
10
|
+
};
|
package/dist/media-player.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { LogLevel, useBufferState } from 'remotion';
|
|
2
2
|
import { type AudioIteratorManager } from './audio-iterator-manager';
|
|
3
|
-
import type { Nonce } from './nonce-manager';
|
|
4
3
|
import type { VideoIteratorManager } from './video-iterator-manager';
|
|
5
4
|
export type MediaPlayerInitResult = {
|
|
6
5
|
type: 'success';
|
|
@@ -33,6 +32,7 @@ export declare class MediaPlayer {
|
|
|
33
32
|
private fps;
|
|
34
33
|
private trimBefore;
|
|
35
34
|
private trimAfter;
|
|
35
|
+
private durationInFrames;
|
|
36
36
|
private totalDuration;
|
|
37
37
|
private debugOverlay;
|
|
38
38
|
private nonceManager;
|
|
@@ -42,7 +42,7 @@ export declare class MediaPlayer {
|
|
|
42
42
|
private isPremounting;
|
|
43
43
|
private isPostmounting;
|
|
44
44
|
private seekPromiseChain;
|
|
45
|
-
constructor({ canvas, src, logLevel, sharedAudioContext, loop, trimBefore, trimAfter, playbackRate, globalPlaybackRate, audioStreamIndex, fps, debugOverlay, bufferState, isPremounting, isPostmounting, onVideoFrameCallback, playing }: {
|
|
45
|
+
constructor({ canvas, src, logLevel, sharedAudioContext, loop, trimBefore, trimAfter, playbackRate, globalPlaybackRate, audioStreamIndex, fps, debugOverlay, bufferState, isPremounting, isPostmounting, durationInFrames, onVideoFrameCallback, playing }: {
|
|
46
46
|
canvas: HTMLCanvasElement | OffscreenCanvas | null;
|
|
47
47
|
src: string;
|
|
48
48
|
logLevel: LogLevel;
|
|
@@ -58,6 +58,7 @@ export declare class MediaPlayer {
|
|
|
58
58
|
bufferState: ReturnType<typeof useBufferState>;
|
|
59
59
|
isPremounting: boolean;
|
|
60
60
|
isPostmounting: boolean;
|
|
61
|
+
durationInFrames: number;
|
|
61
62
|
onVideoFrameCallback: null | ((frame: CanvasImageSource) => void);
|
|
62
63
|
playing: boolean;
|
|
63
64
|
});
|
|
@@ -69,27 +70,30 @@ export declare class MediaPlayer {
|
|
|
69
70
|
private _initialize;
|
|
70
71
|
private seekToWithQueue;
|
|
71
72
|
seekTo(time: number): Promise<void>;
|
|
72
|
-
seekToDoNotCallDirectly
|
|
73
|
+
private seekToDoNotCallDirectly;
|
|
74
|
+
playAudio(time: number): Promise<void>;
|
|
73
75
|
play(time: number): Promise<void>;
|
|
74
76
|
private delayPlaybackHandleIfNotPremounting;
|
|
75
77
|
pause(): void;
|
|
76
78
|
setMuted(muted: boolean): void;
|
|
77
79
|
setVolume(volume: number): void;
|
|
80
|
+
private getTrimmedTime;
|
|
78
81
|
private updateAfterTrimChange;
|
|
79
82
|
setTrimBefore(trimBefore: number | undefined, unloopedTimeInSeconds: number): Promise<void>;
|
|
80
83
|
setTrimAfter(trimAfter: number | undefined, unloopedTimeInSeconds: number): Promise<void>;
|
|
81
84
|
setDebugOverlay(debugOverlay: boolean): void;
|
|
82
85
|
private updateAudioTimeAfterPlaybackRateChange;
|
|
83
|
-
setPlaybackRate(rate: number): void
|
|
86
|
+
setPlaybackRate(rate: number, unloopedTimeInSeconds: number): Promise<void>;
|
|
84
87
|
setGlobalPlaybackRate(rate: number): void;
|
|
85
88
|
setFps(fps: number): void;
|
|
86
89
|
setIsPremounting(isPremounting: boolean): void;
|
|
87
90
|
setIsPostmounting(isPostmounting: boolean): void;
|
|
88
91
|
setLoop(loop: boolean): void;
|
|
92
|
+
setDurationInFrames(durationInFrames: number): void;
|
|
89
93
|
dispose(): Promise<void>;
|
|
90
94
|
private scheduleAudioNode;
|
|
91
95
|
private getAudioPlaybackTime;
|
|
92
|
-
private
|
|
96
|
+
private setAudioPlaybackTime;
|
|
93
97
|
setVideoFrameCallback(callback: null | ((frame: CanvasImageSource) => void)): void;
|
|
94
98
|
private drawDebugOverlay;
|
|
95
99
|
}
|