@remotion/media 4.0.401 → 4.0.403

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.
@@ -270,6 +270,7 @@ const AudioForPreviewAssertedShowing = ({ src, playbackRate, logLevel, muted, vo
270
270
  };
271
271
  export const AudioForPreview = ({ loop, src, logLevel, muted, name, volume, loopVolumeCurveBehavior, playbackRate, trimAfter, trimBefore, showInTimeline, stack, disallowFallbackToHtml5Audio, toneFrequency, audioStreamIndex, fallbackHtml5AudioProps, }) => {
272
272
  const preloadedSrc = usePreload(src);
273
+ const defaultLogLevel = Internals.useLogLevel();
273
274
  const frame = useCurrentFrame();
274
275
  const videoConfig = useVideoConfig();
275
276
  const currentTime = frame / videoConfig.fps;
@@ -297,8 +298,5 @@ export const AudioForPreview = ({ loop, src, logLevel, muted, name, volume, loop
297
298
  if (!showShow) {
298
299
  return null;
299
300
  }
300
- return (_jsx(AudioForPreviewAssertedShowing, { audioStreamIndex: audioStreamIndex ?? 0, src: preloadedSrc, playbackRate: playbackRate ?? 1, logLevel: logLevel ??
301
- (typeof window !== 'undefined'
302
- ? (window.remotion_logLevel ?? 'info')
303
- : 'info'), muted: muted ?? false, volume: volume ?? 1, loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? 'repeat', loop: loop ?? false, trimAfter: trimAfter, trimBefore: trimBefore, name: name, showInTimeline: showInTimeline ?? true, stack: stack, disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false, toneFrequency: toneFrequency, fallbackHtml5AudioProps: fallbackHtml5AudioProps }));
301
+ return (_jsx(AudioForPreviewAssertedShowing, { audioStreamIndex: audioStreamIndex ?? 0, src: preloadedSrc, playbackRate: playbackRate ?? 1, logLevel: logLevel ?? defaultLogLevel, muted: muted ?? false, volume: volume ?? 1, loopVolumeCurveBehavior: loopVolumeCurveBehavior ?? 'repeat', loop: loop ?? false, trimAfter: trimAfter, trimBefore: trimBefore, name: name, showInTimeline: showInTimeline ?? true, stack: stack, disallowFallbackToHtml5Audio: disallowFallbackToHtml5Audio ?? false, toneFrequency: toneFrequency, fallbackHtml5AudioProps: fallbackHtml5AudioProps }));
304
302
  };
@@ -6,7 +6,9 @@ import { applyVolume } from '../convert-audiodata/apply-volume';
6
6
  import { TARGET_SAMPLE_RATE } from '../convert-audiodata/resample-audiodata';
7
7
  import { frameForVolumeProp } from '../looped-frame';
8
8
  import { extractFrameViaBroadcastChannel } from '../video-extraction/extract-frame-via-broadcast-channel';
9
- export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds, logLevel = window.remotion_logLevel ?? 'info', loop, fallbackHtml5AudioProps, audioStreamIndex, showInTimeline, style, name, disallowFallbackToHtml5Audio, toneFrequency, trimAfter, trimBefore, }) => {
9
+ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted, loopVolumeCurveBehavior, delayRenderRetries, delayRenderTimeoutInMilliseconds, logLevel: overriddenLogLevel, loop, fallbackHtml5AudioProps, audioStreamIndex, showInTimeline, style, name, disallowFallbackToHtml5Audio, toneFrequency, trimAfter, trimBefore, }) => {
10
+ const defaultLogLevel = Internals.useLogLevel();
11
+ const logLevel = overriddenLogLevel ?? defaultLogLevel;
10
12
  const frame = useCurrentFrame();
11
13
  const absoluteFrame = Internals.useTimelinePosition();
12
14
  const videoConfig = Internals.useUnsafeVideoConfig();
@@ -31,7 +33,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
31
33
  sequenceContext?.relativeFrom,
32
34
  sequenceContext?.durationInFrames,
33
35
  ]);
34
- const maxCacheSize = useMaxMediaCacheSize(logLevel ?? window.remotion_logLevel);
36
+ const maxCacheSize = useMaxMediaCacheSize(logLevel);
35
37
  const audioEnabled = Internals.useAudioEnabled();
36
38
  useLayoutEffect(() => {
37
39
  const timestamp = frame / fps;
@@ -60,7 +62,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
60
62
  timeInSeconds: timestamp,
61
63
  durationInSeconds,
62
64
  playbackRate: playbackRate ?? 1,
63
- logLevel: logLevel ?? window.remotion_logLevel,
65
+ logLevel,
64
66
  includeAudio: shouldRenderAudio,
65
67
  includeVideo: false,
66
68
  isClientSideRendering: environment.isClientSideRendering,
@@ -81,7 +83,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
81
83
  cancelRender(new Error(`Unknown container format ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
82
84
  }
83
85
  Internals.Log.warn({
84
- logLevel: logLevel ?? window.remotion_logLevel,
86
+ logLevel,
85
87
  tag: '@remotion/media',
86
88
  }, `Unknown container format for ${src} (Supported formats: https://www.remotion.dev/docs/mediabunny/formats), falling back to <Html5Audio>`);
87
89
  setReplaceWithHtml5Audio(true);
@@ -96,7 +98,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
96
98
  cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
97
99
  }
98
100
  Internals.Log.warn({
99
- logLevel: logLevel ?? window.remotion_logLevel,
101
+ logLevel,
100
102
  tag: '@remotion/media',
101
103
  }, `Cannot decode ${src}, falling back to <Html5Audio>`);
102
104
  setReplaceWithHtml5Audio(true);
@@ -114,7 +116,7 @@ export const AudioForRendering = ({ volume: volumeProp, playbackRate, src, muted
114
116
  cancelRender(new Error(`Cannot decode ${src}, and 'disallowFallbackToHtml5Audio' was set. Failing the render.`));
115
117
  }
116
118
  Internals.Log.warn({
117
- logLevel: logLevel ?? window.remotion_logLevel,
119
+ logLevel,
118
120
  tag: '@remotion/media',
119
121
  }, `Network error fetching ${src}, falling back to <Html5Audio>`);
120
122
  setReplaceWithHtml5Audio(true);
@@ -1,5 +1,5 @@
1
1
  import { Internals } from 'remotion';
2
- import { SAFE_BACK_WINDOW_IN_SECONDS } from '../caches';
2
+ import { SAFE_WINDOW_OF_MONOTONICITY } from '../caches';
3
3
  import { makeAudioCache } from './audio-cache';
4
4
  // https://discord.com/channels/@me/1409810025844838481/1415028953093111870
5
5
  // Audio frames might have dependencies on previous and next frames so we need to decode a bit more
@@ -47,7 +47,7 @@ export const makeAudioIterator = ({ audioSampleSink, isMatroska, startTimestamp,
47
47
  if (fullDuration !== null && timestamp > fullDuration) {
48
48
  // Clear all samples before the timestamp
49
49
  // Do this in the while loop because samples might start from 0
50
- cache.clearBeforeThreshold(fullDuration - SAFE_BACK_WINDOW_IN_SECONDS);
50
+ cache.clearBeforeThreshold(fullDuration - SAFE_WINDOW_OF_MONOTONICITY);
51
51
  return [];
52
52
  }
53
53
  const samples = cache.getSamples(timestamp, durationInSeconds);
@@ -64,7 +64,7 @@ export const makeAudioIterator = ({ audioSampleSink, isMatroska, startTimestamp,
64
64
  // Also do this after a sample has just been added, if it was the last sample we now have the duration
65
65
  // and can prevent deleting the last sample
66
66
  const deleteBefore = fullDuration === null ? timestamp : Math.min(timestamp, fullDuration);
67
- cache.clearBeforeThreshold(deleteBefore - SAFE_BACK_WINDOW_IN_SECONDS);
67
+ cache.clearBeforeThreshold(deleteBefore - SAFE_WINDOW_OF_MONOTONICITY);
68
68
  if (sample === null) {
69
69
  break;
70
70
  }
@@ -48,8 +48,16 @@ export const makeAudioManager = () => {
48
48
  }
49
49
  };
50
50
  const getIterator = async ({ src, timeInSeconds, audioSampleSink, isMatroska, actualMatroskaTimestamps, logLevel, maxCacheSize, }) => {
51
- while ((await getTotalCacheStats()).totalSize > maxCacheSize) {
51
+ let attempts = 0;
52
+ const maxAttempts = 3;
53
+ while ((await getTotalCacheStats()).totalSize > maxCacheSize &&
54
+ attempts < maxAttempts) {
52
55
  deleteOldestIterator();
56
+ attempts++;
57
+ }
58
+ if ((await getTotalCacheStats()).totalSize > maxCacheSize &&
59
+ attempts >= maxAttempts) {
60
+ Internals.Log.warn({ logLevel, tag: '@remotion/media' }, `Audio cache: Exceeded max cache size after ${maxAttempts} attempts. Still ${(await getTotalCacheStats()).totalSize} bytes used, target was ${maxCacheSize} bytes.`);
53
61
  }
54
62
  for (const iterator of iterators) {
55
63
  if (iterator.src === src &&
package/dist/caches.d.ts CHANGED
@@ -1,19 +1,18 @@
1
1
  import { type LogLevel } from 'remotion';
2
- export declare const SAFE_BACK_WINDOW_IN_SECONDS = 1;
2
+ export declare const SAFE_WINDOW_OF_MONOTONICITY = 0.2;
3
3
  export declare const keyframeManager: {
4
- requestKeyframeBank: ({ packetSink, timestamp, videoSampleSink, src, logLevel, maxCacheSize, }: {
5
- packetSink: import("mediabunny").EncodedPacketSink;
4
+ requestKeyframeBank: ({ timestamp, videoSampleSink, src, logLevel, maxCacheSize, }: {
6
5
  timestamp: number;
7
6
  videoSampleSink: import("mediabunny").VideoSampleSink;
8
7
  src: string;
9
8
  logLevel: LogLevel;
10
9
  maxCacheSize: number;
11
- }) => Promise<import("./video-extraction/keyframe-bank").KeyframeBank | "has-alpha" | null>;
12
- getCacheStats: () => Promise<{
10
+ }) => Promise<import("./video-extraction/keyframe-bank").KeyframeBank>;
11
+ getCacheStats: () => {
13
12
  count: number;
14
13
  totalSize: number;
15
- }>;
16
- clearAll: (logLevel: LogLevel) => Promise<void>;
14
+ };
15
+ clearAll: (logLevel: LogLevel) => void;
17
16
  };
18
17
  export declare const audioManager: {
19
18
  getIterator: ({ src, timeInSeconds, audioSampleSink, isMatroska, actualMatroskaTimestamps, logLevel, maxCacheSize, }: {
package/dist/caches.js CHANGED
@@ -2,8 +2,8 @@ import React from 'react';
2
2
  import { cancelRender, Internals } from 'remotion';
3
3
  import { makeAudioManager } from './audio-extraction/audio-manager';
4
4
  import { makeKeyframeManager } from './video-extraction/keyframe-manager';
5
- // TODO: make it dependent on the fps and concurrency
6
- export const SAFE_BACK_WINDOW_IN_SECONDS = 1;
5
+ // Frames can be out of order, but we don't expect them to be more than 1 second out of order
6
+ export const SAFE_WINDOW_OF_MONOTONICITY = 0.2;
7
7
  export const keyframeManager = makeKeyframeManager();
8
8
  export const audioManager = makeAudioManager();
9
9
  export const getTotalCacheStats = async () => {
@@ -2,8 +2,8 @@ import type { AudioIteratorManager } from '../audio-iterator-manager';
2
2
  import type { VideoIteratorManager } from '../video-iterator-manager';
3
3
  export declare const drawPreviewOverlay: ({ context, audioTime, audioContextState, audioSyncAnchor, playing, audioIteratorManager, videoIteratorManager, }: {
4
4
  context: OffscreenCanvasRenderingContext2D | CanvasRenderingContext2D;
5
- audioTime: number;
6
- audioContextState: AudioContextState;
5
+ audioTime: number | null;
6
+ audioContextState: AudioContextState | null;
7
7
  audioSyncAnchor: number;
8
8
  playing: boolean;
9
9
  audioIteratorManager: AudioIteratorManager | null;
@@ -6,8 +6,10 @@ export const drawPreviewOverlay = ({ context, audioTime, audioContextState, audi
6
6
  `Audio iterators created: ${audioIteratorManager?.getAudioIteratorsCreated()}`,
7
7
  `Frames rendered: ${videoIteratorManager?.getFramesRendered()}`,
8
8
  `Audio context state: ${audioContextState}`,
9
- `Audio time: ${(audioTime - audioSyncAnchor).toFixed(3)}s`,
10
- ];
9
+ audioTime
10
+ ? `Audio time: ${(audioTime - audioSyncAnchor).toFixed(3)}s`
11
+ : null,
12
+ ].filter(Boolean);
11
13
  if (audioIteratorManager) {
12
14
  const queuedPeriod = audioIteratorManager
13
15
  .getAudioBufferIterator()
@@ -15,7 +17,7 @@ export const drawPreviewOverlay = ({ context, audioTime, audioContextState, audi
15
17
  const numberOfChunksAfterResuming = audioIteratorManager
16
18
  ?.getAudioBufferIterator()
17
19
  ?.getNumberOfChunksAfterResuming();
18
- if (queuedPeriod) {
20
+ if (queuedPeriod && audioTime) {
19
21
  lines.push(`Audio queued until: ${(queuedPeriod.until - (audioTime - audioSyncAnchor)).toFixed(3)}s`);
20
22
  }
21
23
  else if (numberOfChunksAfterResuming) {