@remotion/media 4.0.362 → 4.0.364
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 +4 -1
- package/dist/audio/audio-for-rendering.js +14 -5
- package/dist/audio/audio-iterator.d.ts +11 -0
- package/dist/audio/audio-iterator.js +24 -0
- package/dist/audio/audio-preview-iterator.d.ts +14 -0
- package/dist/audio/audio-preview-iterator.js +43 -0
- package/dist/audio/audio.js +0 -1
- package/dist/caches.js +4 -2
- package/dist/debug-overlay/preview-overlay.d.ts +5 -0
- package/dist/debug-overlay/preview-overlay.js +13 -0
- package/dist/esm/index.mjs +702 -517
- package/dist/helpers/round-to-4-digits.d.ts +1 -0
- package/dist/helpers/round-to-4-digits.js +4 -0
- package/dist/media-player.d.ts +95 -0
- package/dist/media-player.js +496 -0
- package/dist/video/props.d.ts +1 -0
- package/dist/video/video-for-preview.d.ts +3 -2
- package/dist/video/video-for-preview.js +25 -14
- package/dist/video/video-for-rendering.js +8 -6
- package/dist/video/video-preview-iterator.d.ts +14 -0
- package/dist/video/video-preview-iterator.js +122 -0
- package/dist/video/video.js +5 -4
- package/dist/video-extraction/extract-frame-via-broadcast-channel.js +3 -1
- package/dist/video-extraction/get-frames-since-keyframe.d.ts +2 -1
- package/dist/video-extraction/get-frames-since-keyframe.js +2 -1
- package/dist/video-extraction/keyframe-bank.d.ts +7 -4
- package/dist/video-extraction/keyframe-bank.js +37 -34
- package/dist/video-extraction/keyframe-manager.js +18 -7
- package/package.json +4 -4
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Internals, Audio as RemotionAudio, useBufferState, useCurrentFrame, } from 'remotion';
|
|
4
|
+
import { MediaPlayer } from '../media-player';
|
|
4
5
|
import { useLoopDisplay } from '../show-in-timeline';
|
|
5
6
|
import { useMediaInTimeline } from '../use-media-in-timeline';
|
|
6
|
-
import { MediaPlayer } from '../video/media-player';
|
|
7
7
|
const { useUnsafeVideoConfig, Timeline, SharedAudioContext, useMediaMutedState, useMediaVolumeState, useFrameForVolumeProp, evaluateVolume, warnAboutTooHighVolume, usePreload, SequenceContext, } = Internals;
|
|
8
8
|
const NewAudioForPreview = ({ src, playbackRate, logLevel, muted, volume, loopVolumeCurveBehavior, loop, trimAfter, trimBefore, name, showInTimeline, stack, disallowFallbackToHtml5Audio, toneFrequency, audioStreamIndex, fallbackHtml5AudioProps, }) => {
|
|
9
9
|
const videoConfig = useUnsafeVideoConfig();
|
|
@@ -76,6 +76,8 @@ const NewAudioForPreview = ({ src, playbackRate, logLevel, muted, volume, loopVo
|
|
|
76
76
|
canvas: null,
|
|
77
77
|
playbackRate,
|
|
78
78
|
audioStreamIndex: audioStreamIndex ?? 0,
|
|
79
|
+
debugOverlay: false,
|
|
80
|
+
bufferState: buffer,
|
|
79
81
|
});
|
|
80
82
|
mediaPlayerRef.current = player;
|
|
81
83
|
player
|
|
@@ -152,6 +154,7 @@ const NewAudioForPreview = ({ src, playbackRate, logLevel, muted, volume, loopVo
|
|
|
152
154
|
videoConfig.fps,
|
|
153
155
|
audioStreamIndex,
|
|
154
156
|
disallowFallbackToHtml5Audio,
|
|
157
|
+
buffer,
|
|
155
158
|
]);
|
|
156
159
|
useEffect(() => {
|
|
157
160
|
const audioPlayer = mediaPlayerRef.current;
|
|
@@ -5,7 +5,7 @@ import { applyVolume } from '../convert-audiodata/apply-volume';
|
|
|
5
5
|
import { TARGET_SAMPLE_RATE } from '../convert-audiodata/resample-audiodata';
|
|
6
6
|
import { frameForVolumeProp } from '../looped-frame';
|
|
7
7
|
import { extractFrameViaBroadcastChannel } from '../video-extraction/extract-frame-via-broadcast-channel';
|
|
8
|
-
export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds, logLevel
|
|
8
|
+
export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds, logLevel, loop, fallbackHtml5AudioProps, audioStreamIndex, showInTimeline, style, name, disallowFallbackToHtml5Audio, toneFrequency, trimAfter, trimBefore, }) => {
|
|
9
9
|
const frame = useCurrentFrame();
|
|
10
10
|
const absoluteFrame = Internals.useTimelinePosition();
|
|
11
11
|
const videoConfig = Internals.useUnsafeVideoConfig();
|
|
@@ -54,7 +54,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
54
54
|
timeInSeconds: timestamp,
|
|
55
55
|
durationInSeconds,
|
|
56
56
|
playbackRate: playbackRate ?? 1,
|
|
57
|
-
logLevel,
|
|
57
|
+
logLevel: logLevel ?? window.remotion_logLevel,
|
|
58
58
|
includeAudio: shouldRenderAudio,
|
|
59
59
|
includeVideo: false,
|
|
60
60
|
isClientSideRendering: environment.isClientSideRendering,
|
|
@@ -69,7 +69,10 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
69
69
|
if (disallowFallbackToHtml5Audio) {
|
|
70
70
|
cancelRender(new Error(`Unknown container format ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
|
|
71
71
|
}
|
|
72
|
-
Internals.Log.warn({
|
|
72
|
+
Internals.Log.warn({
|
|
73
|
+
logLevel: logLevel ?? window.remotion_logLevel,
|
|
74
|
+
tag: '@remotion/media',
|
|
75
|
+
}, `Unknown container format for ${src} (Supported formats: https://www.remotion.dev/docs/mediabunny/formats), falling back to <Html5Audio>`);
|
|
73
76
|
setReplaceWithHtml5Audio(true);
|
|
74
77
|
return;
|
|
75
78
|
}
|
|
@@ -77,7 +80,10 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
77
80
|
if (disallowFallbackToHtml5Audio) {
|
|
78
81
|
cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
|
|
79
82
|
}
|
|
80
|
-
Internals.Log.warn({
|
|
83
|
+
Internals.Log.warn({
|
|
84
|
+
logLevel: logLevel ?? window.remotion_logLevel,
|
|
85
|
+
tag: '@remotion/media',
|
|
86
|
+
}, `Cannot decode ${src}, falling back to <Html5Audio>`);
|
|
81
87
|
setReplaceWithHtml5Audio(true);
|
|
82
88
|
return;
|
|
83
89
|
}
|
|
@@ -88,7 +94,10 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
|
|
|
88
94
|
if (disallowFallbackToHtml5Audio) {
|
|
89
95
|
cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
|
|
90
96
|
}
|
|
91
|
-
Internals.Log.warn({
|
|
97
|
+
Internals.Log.warn({
|
|
98
|
+
logLevel: logLevel ?? window.remotion_logLevel,
|
|
99
|
+
tag: '@remotion/media',
|
|
100
|
+
}, `Network error fetching ${src}, falling back to <Html5Audio>`);
|
|
92
101
|
setReplaceWithHtml5Audio(true);
|
|
93
102
|
return;
|
|
94
103
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AudioBufferSink } from 'mediabunny';
|
|
2
|
+
export declare const HEALTHY_BUFFER_THRESHOLD_SECONDS = 1;
|
|
3
|
+
export declare const makeAudioIterator: (audioSink: AudioBufferSink, startFromSecond: number) => {
|
|
4
|
+
iterator: AsyncGenerator<import("mediabunny").WrappedAudioBuffer, void, unknown>;
|
|
5
|
+
destroy: () => void;
|
|
6
|
+
isReadyToPlay: () => boolean;
|
|
7
|
+
setAudioIteratorStarted: (started: boolean) => void;
|
|
8
|
+
getNext: () => Promise<IteratorResult<import("mediabunny").WrappedAudioBuffer, void>>;
|
|
9
|
+
setAudioBufferHealth: (health: number) => void;
|
|
10
|
+
};
|
|
11
|
+
export type AudioIterator = ReturnType<typeof makeAudioIterator>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export const HEALTHY_BUFFER_THRESHOLD_SECONDS = 1;
|
|
2
|
+
export const makeAudioIterator = (audioSink, startFromSecond) => {
|
|
3
|
+
const iterator = audioSink.buffers(startFromSecond);
|
|
4
|
+
let audioIteratorStarted = false;
|
|
5
|
+
let audioBufferHealth = 0;
|
|
6
|
+
return {
|
|
7
|
+
iterator,
|
|
8
|
+
destroy: () => {
|
|
9
|
+
iterator.return().catch(() => undefined);
|
|
10
|
+
},
|
|
11
|
+
isReadyToPlay: () => {
|
|
12
|
+
return audioIteratorStarted && audioBufferHealth > 0;
|
|
13
|
+
},
|
|
14
|
+
setAudioIteratorStarted: (started) => {
|
|
15
|
+
audioIteratorStarted = started;
|
|
16
|
+
},
|
|
17
|
+
getNext: () => {
|
|
18
|
+
return iterator.next();
|
|
19
|
+
},
|
|
20
|
+
setAudioBufferHealth: (health) => {
|
|
21
|
+
audioBufferHealth = health;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { AudioBufferSink } from 'mediabunny';
|
|
2
|
+
export declare const HEALTHY_BUFFER_THRESHOLD_SECONDS = 1;
|
|
3
|
+
export declare const makeAudioIterator: (audioSink: AudioBufferSink, startFromSecond: number) => {
|
|
4
|
+
cleanupAudioQueue: () => void;
|
|
5
|
+
destroy: () => void;
|
|
6
|
+
isReadyToPlay: () => boolean;
|
|
7
|
+
setAudioIteratorStarted: (started: boolean) => void;
|
|
8
|
+
getNext: () => Promise<IteratorResult<import("mediabunny").WrappedAudioBuffer, void>>;
|
|
9
|
+
setAudioBufferHealth: (health: number) => void;
|
|
10
|
+
isDestroyed: () => boolean;
|
|
11
|
+
addQueuedAudioNode: (node: AudioBufferSourceNode) => void;
|
|
12
|
+
removeQueuedAudioNode: (node: AudioBufferSourceNode) => void;
|
|
13
|
+
};
|
|
14
|
+
export type AudioIterator = ReturnType<typeof makeAudioIterator>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
export const HEALTHY_BUFFER_THRESHOLD_SECONDS = 1;
|
|
2
|
+
export const makeAudioIterator = (audioSink, startFromSecond) => {
|
|
3
|
+
let destroyed = false;
|
|
4
|
+
const iterator = audioSink.buffers(startFromSecond);
|
|
5
|
+
let audioIteratorStarted = false;
|
|
6
|
+
let audioBufferHealth = 0;
|
|
7
|
+
const queuedAudioNodes = new Set();
|
|
8
|
+
const cleanupAudioQueue = () => {
|
|
9
|
+
for (const node of queuedAudioNodes) {
|
|
10
|
+
node.stop();
|
|
11
|
+
}
|
|
12
|
+
queuedAudioNodes.clear();
|
|
13
|
+
};
|
|
14
|
+
return {
|
|
15
|
+
cleanupAudioQueue,
|
|
16
|
+
destroy: () => {
|
|
17
|
+
cleanupAudioQueue();
|
|
18
|
+
destroyed = true;
|
|
19
|
+
iterator.return().catch(() => undefined);
|
|
20
|
+
},
|
|
21
|
+
isReadyToPlay: () => {
|
|
22
|
+
return audioIteratorStarted && audioBufferHealth > 0;
|
|
23
|
+
},
|
|
24
|
+
setAudioIteratorStarted: (started) => {
|
|
25
|
+
audioIteratorStarted = started;
|
|
26
|
+
},
|
|
27
|
+
getNext: () => {
|
|
28
|
+
return iterator.next();
|
|
29
|
+
},
|
|
30
|
+
setAudioBufferHealth: (health) => {
|
|
31
|
+
audioBufferHealth = health;
|
|
32
|
+
},
|
|
33
|
+
isDestroyed: () => {
|
|
34
|
+
return destroyed;
|
|
35
|
+
},
|
|
36
|
+
addQueuedAudioNode: (node) => {
|
|
37
|
+
queuedAudioNodes.add(node);
|
|
38
|
+
},
|
|
39
|
+
removeQueuedAudioNode: (node) => {
|
|
40
|
+
queuedAudioNodes.delete(node);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
};
|
package/dist/audio/audio.js
CHANGED
package/dist/caches.js
CHANGED
|
@@ -14,7 +14,8 @@ export const getTotalCacheStats = async () => {
|
|
|
14
14
|
};
|
|
15
15
|
};
|
|
16
16
|
const getUncachedMaxCacheSize = (logLevel) => {
|
|
17
|
-
if (window
|
|
17
|
+
if (typeof window !== 'undefined' &&
|
|
18
|
+
window.remotion_mediaCacheSizeInBytes !== undefined &&
|
|
18
19
|
window.remotion_mediaCacheSizeInBytes !== null) {
|
|
19
20
|
if (window.remotion_mediaCacheSizeInBytes < 240 * 1024 * 1024) {
|
|
20
21
|
cancelRender(new Error(`The minimum value for the "mediaCacheSizeInBytes" prop is 240MB (${240 * 1024 * 1024}), got: ${window.remotion_mediaCacheSizeInBytes}`));
|
|
@@ -25,7 +26,8 @@ const getUncachedMaxCacheSize = (logLevel) => {
|
|
|
25
26
|
Internals.Log.verbose({ logLevel, tag: '@remotion/media' }, `Using cache size set using "mediaCacheSizeInBytes": ${(window.remotion_mediaCacheSizeInBytes / 1024 / 1024).toFixed(1)} MB`);
|
|
26
27
|
return window.remotion_mediaCacheSizeInBytes;
|
|
27
28
|
}
|
|
28
|
-
if (window
|
|
29
|
+
if (typeof window !== 'undefined' &&
|
|
30
|
+
window.remotion_initialMemoryAvailable !== undefined &&
|
|
29
31
|
window.remotion_initialMemoryAvailable !== null) {
|
|
30
32
|
const value = window.remotion_initialMemoryAvailable / 2;
|
|
31
33
|
if (value < 500 * 1024 * 1024) {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const drawPreviewOverlay = (context, stats, audioContextState, audioSyncAnchor) => {
|
|
2
|
+
// Optionally, set a background for text legibility
|
|
3
|
+
context.fillStyle = 'rgba(0, 0, 0, 1)';
|
|
4
|
+
context.fillRect(20, 20, 600, 180);
|
|
5
|
+
context.fillStyle = 'white';
|
|
6
|
+
context.font = '24px sans-serif';
|
|
7
|
+
context.textBaseline = 'top';
|
|
8
|
+
context.fillText(`Debug overlay`, 30, 30);
|
|
9
|
+
context.fillText(`Video iterators created: ${stats.videoIteratorsCreated}`, 30, 60);
|
|
10
|
+
context.fillText(`Frames rendered: ${stats.framesRendered}`, 30, 90);
|
|
11
|
+
context.fillText(`Audio context state: ${audioContextState}`, 30, 120);
|
|
12
|
+
context.fillText(`Audio time: ${audioSyncAnchor.toFixed(3)}s`, 30, 150);
|
|
13
|
+
};
|