@remotion/media 4.0.474 → 4.0.476

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.
@@ -77,13 +77,13 @@ export declare const drawPreviewOverlay: ({ context, audioTime, audioContextStat
77
77
  destroy: () => void;
78
78
  initialFrame: import("mediabunny").WrappedCanvas | null;
79
79
  isDestroyed: () => boolean;
80
- tryToSatisfySeek: (time: number) => {
80
+ tryToSatisfySeek: (time: number) => Promise<{
81
81
  type: "not-satisfied";
82
82
  reason: string;
83
83
  } | {
84
84
  type: "satisfied";
85
85
  frame: import("mediabunny").WrappedCanvas;
86
- };
86
+ }>;
87
87
  } | null;
88
88
  drawFrame: (frame: import("mediabunny").WrappedCanvas) => Promise<void>;
89
89
  redrawCurrentFrame: () => Promise<void>;
@@ -1000,6 +1000,11 @@ var resolveRequestInit = ({
1000
1000
  import { CanvasSink } from "mediabunny";
1001
1001
  import { Internals as Internals4 } from "remotion";
1002
1002
 
1003
+ // src/helpers/round-to-4-digits.ts
1004
+ var roundTo4Digits = (timestamp) => {
1005
+ return Math.round(timestamp * 1000) / 1000;
1006
+ };
1007
+
1003
1008
  // src/canvas-ahead-of-time.ts
1004
1009
  var BUFFER_SIZE = 3;
1005
1010
  var canvasesAheadOfTime = (videoSink, startTimestamp) => {
@@ -1119,11 +1124,6 @@ var makePrewarmedVideoIteratorCache = (videoSink) => {
1119
1124
  };
1120
1125
  };
1121
1126
 
1122
- // src/helpers/round-to-4-digits.ts
1123
- var roundTo4Digits = (timestamp) => {
1124
- return Math.round(timestamp * 1000) / 1000;
1125
- };
1126
-
1127
1127
  // src/video/video-preview-iterator.ts
1128
1128
  var createVideoIterator = async (timeToSeek, cache) => {
1129
1129
  let destroyed = false;
@@ -1132,7 +1132,28 @@ var createVideoIterator = async (timeToSeek, cache) => {
1132
1132
  const firstAwait = iterator.next();
1133
1133
  const initialFrame = firstAwait && firstAwait.type === "ready" ? firstAwait.frame : await firstAwait.wait();
1134
1134
  let lastReturnedFrame = initialFrame;
1135
+ let peekedFrame = null;
1136
+ const peek = async () => {
1137
+ if (peekedFrame) {
1138
+ return peekedFrame;
1139
+ }
1140
+ const next = iterator.next();
1141
+ if (next.type === "ready") {
1142
+ peekedFrame = next.frame;
1143
+ } else {
1144
+ peekedFrame = await next.wait();
1145
+ }
1146
+ return peekedFrame;
1147
+ };
1135
1148
  const getNextOrNullIfNotAvailable = () => {
1149
+ if (peekedFrame) {
1150
+ const retValue = {
1151
+ type: "got-frame-or-end",
1152
+ frame: peekedFrame
1153
+ };
1154
+ peekedFrame = null;
1155
+ return retValue;
1156
+ }
1136
1157
  const next = iterator.next();
1137
1158
  if (next.type === "pending") {
1138
1159
  return {
@@ -1165,7 +1186,7 @@ var createVideoIterator = async (timeToSeek, cache) => {
1165
1186
  return;
1166
1187
  });
1167
1188
  };
1168
- const tryToSatisfySeek = (time) => {
1189
+ const tryToSatisfySeek = async (time) => {
1169
1190
  if (lastReturnedFrame) {
1170
1191
  const frameTimestamp = roundTo4Digits(lastReturnedFrame.timestamp);
1171
1192
  if (roundTo4Digits(time) < frameTimestamp) {
@@ -1182,7 +1203,14 @@ var createVideoIterator = async (timeToSeek, cache) => {
1182
1203
  reason: `iterator is too far, most recently returned ${frameTimestamp}`
1183
1204
  };
1184
1205
  }
1185
- const frameEndTimestamp = roundTo4Digits(lastReturnedFrame.timestamp + lastReturnedFrame.duration);
1206
+ let lastFrameDuration = lastReturnedFrame.duration;
1207
+ if (lastFrameDuration === 0) {
1208
+ const peeked = await peek();
1209
+ if (peeked) {
1210
+ lastFrameDuration = peeked.timestamp - lastReturnedFrame.timestamp;
1211
+ }
1212
+ }
1213
+ const frameEndTimestamp = roundTo4Digits(lastReturnedFrame.timestamp + lastFrameDuration);
1186
1214
  const timestamp = roundTo4Digits(time);
1187
1215
  if (frameTimestamp <= timestamp && frameEndTimestamp > timestamp) {
1188
1216
  return {
@@ -1270,6 +1298,7 @@ var videoIteratorManager = async ({
1270
1298
  let framesRendered = 0;
1271
1299
  let currentDelayHandle = null;
1272
1300
  let lastDrawnFrame = null;
1301
+ let currentSeek = null;
1273
1302
  const clearLastDrawnFrame = () => {
1274
1303
  lastDrawnFrame = null;
1275
1304
  };
@@ -1336,6 +1365,7 @@ var videoIteratorManager = async ({
1336
1365
  videoFrameIterator?.destroy();
1337
1366
  const delayHandle = __using(__stack, delayPlaybackHandleIfNotPremounting(), 0);
1338
1367
  currentDelayHandle = delayHandle;
1368
+ currentSeek = timeToSeek;
1339
1369
  const iterator = await createVideoIterator(timeToSeek, prewarmedVideoIteratorCache);
1340
1370
  videoIteratorsCreated++;
1341
1371
  videoFrameIterator = iterator;
@@ -1362,6 +1392,10 @@ var videoIteratorManager = async ({
1362
1392
  if (!videoFrameIterator) {
1363
1393
  return;
1364
1394
  }
1395
+ if (currentSeek !== null && roundTo4Digits(currentSeek) === roundTo4Digits(newTime)) {
1396
+ return;
1397
+ }
1398
+ currentSeek = newTime;
1365
1399
  if (getIsLooping()) {
1366
1400
  if (getLoopSegmentMediaEndTimestamp() - newTime < 1) {
1367
1401
  prewarmedVideoIteratorCache.prewarmIteratorForLooping({
@@ -1369,7 +1403,7 @@ var videoIteratorManager = async ({
1369
1403
  });
1370
1404
  }
1371
1405
  }
1372
- const videoSatisfyResult = videoFrameIterator.tryToSatisfySeek(newTime);
1406
+ const videoSatisfyResult = await videoFrameIterator.tryToSatisfySeek(newTime);
1373
1407
  if (videoSatisfyResult.type === "satisfied") {
1374
1408
  await drawFrame(videoSatisfyResult.frame);
1375
1409
  return;
@@ -2166,7 +2200,7 @@ var AudioForPreviewAssertedShowing = ({
2166
2200
  const parentSequence = useContext2(SequenceContext);
2167
2201
  const isPremounting = Boolean(parentSequence?.premounting);
2168
2202
  const isPostmounting = Boolean(parentSequence?.postmounting);
2169
- const sequenceOffset = ((parentSequence?.cumulatedFrom ?? 0) + (parentSequence?.relativeFrom ?? 0)) / videoConfig.fps;
2203
+ const sequenceOffset = (parentSequence?.absoluteFrom ?? 0) / videoConfig.fps;
2170
2204
  const bufferingContext = useContext2(Internals7.BufferingContextReact);
2171
2205
  if (!bufferingContext) {
2172
2206
  throw new Error("useMediaPlayback must be used inside a <BufferingContext>");
@@ -4581,7 +4615,7 @@ var audioSchema = {
4581
4615
  min: 0.1,
4582
4616
  step: 0.01,
4583
4617
  default: 1,
4584
- description: "Playback Rate",
4618
+ description: "Playback rate",
4585
4619
  hiddenFromList: false,
4586
4620
  keyframable: false
4587
4621
  },
@@ -4832,7 +4866,7 @@ var VideoForPreviewAssertedShowing = ({
4832
4866
  const parentSequence = useContext4(SequenceContext2);
4833
4867
  const isPremounting = Boolean(parentSequence?.premounting);
4834
4868
  const isPostmounting = Boolean(parentSequence?.postmounting);
4835
- const sequenceOffset = ((parentSequence?.cumulatedFrom ?? 0) + (parentSequence?.relativeFrom ?? 0)) / videoConfig.fps;
4869
+ const sequenceOffset = (parentSequence?.absoluteFrom ?? 0) / videoConfig.fps;
4836
4870
  const currentTime = frame / videoConfig.fps;
4837
4871
  const currentTimeRef = useRef2(currentTime);
4838
4872
  currentTimeRef.current = currentTime;
@@ -5507,7 +5541,7 @@ var videoSchema = {
5507
5541
  min: 0.1,
5508
5542
  step: 0.01,
5509
5543
  default: 1,
5510
- description: "Playback Rate",
5544
+ description: "Playback rate",
5511
5545
  hiddenFromList: false,
5512
5546
  keyframable: false
5513
5547
  },
package/dist/index.d.ts CHANGED
@@ -62,7 +62,7 @@ export declare const experimental_Video: import("react").ComponentType<{
62
62
  objectFit: import(".").VideoObjectFit;
63
63
  _experimentalInitiallyDrawCachedFrame: boolean;
64
64
  effects: import("remotion").EffectsProp;
65
- }> & Omit<import("react").HTMLAttributes<HTMLElement>, "_experimentalInitiallyDrawCachedFrame" | "audioStreamIndex" | "className" | "credentials" | "debugOverlay" | "delayRenderRetries" | "delayRenderTimeoutInMilliseconds" | "disallowFallbackToOffthreadVideo" | "effects" | "fallbackOffthreadVideoProps" | "headless" | "logLevel" | "loop" | "loopVolumeCurveBehavior" | "muted" | "objectFit" | "onError" | "onVideoFrame" | "playbackRate" | "requestInit" | "showInTimeline" | "src" | "stack" | "style" | "toneFrequency" | "trimAfter" | "trimBefore" | "volume"> & Record<`data-${string}`, string | undefined> & Pick<import("remotion").SequenceProps, "durationInFrames" | "from" | "hidden" | "name">>;
65
+ }> & Omit<import("react").HTMLAttributes<HTMLElement>, "_experimentalInitiallyDrawCachedFrame" | "audioStreamIndex" | "className" | "credentials" | "debugOverlay" | "delayRenderRetries" | "delayRenderTimeoutInMilliseconds" | "disallowFallbackToOffthreadVideo" | "effects" | "fallbackOffthreadVideoProps" | "headless" | "logLevel" | "loop" | "loopVolumeCurveBehavior" | "muted" | "objectFit" | "onError" | "onVideoFrame" | "playbackRate" | "requestInit" | "showInTimeline" | "src" | "stack" | "style" | "toneFrequency" | "trimAfter" | "trimBefore" | "volume"> & Record<`data-${string}`, string | undefined> & Pick<import("remotion").SequenceProps, "durationInFrames" | "from" | "hidden" | "name" | "showInTimeline">>;
66
66
  export { AudioForPreview } from './audio/audio-for-preview';
67
67
  export { AudioProps, FallbackHtml5AudioProps } from './audio/props';
68
68
  export { MediaErrorAction } from './on-error';
@@ -64,5 +64,5 @@ export type NativeVideoProps = Omit<React.HTMLAttributes<HTMLElement>, keyof Man
64
64
  export type InnerVideoProps = MandatoryVideoProps & OuterVideoProps & Omit<OptionalVideoProps, 'effects'> & NativeVideoProps & {
65
65
  effects: EffectDefinitionAndStack<unknown>[];
66
66
  };
67
- export type VideoProps = MandatoryVideoProps & Partial<OuterVideoProps> & Partial<OptionalVideoProps> & NativeVideoProps & Pick<SequenceProps, 'durationInFrames' | 'from' | 'name' | 'hidden'>;
67
+ export type VideoProps = MandatoryVideoProps & Partial<OuterVideoProps> & Partial<OptionalVideoProps> & NativeVideoProps & Pick<SequenceProps, 'durationInFrames' | 'from' | 'name' | 'showInTimeline' | 'hidden'>;
68
68
  export {};
@@ -12,12 +12,12 @@ export declare const createVideoIterator: (timeToSeek: number, cache: {
12
12
  destroy: () => void;
13
13
  initialFrame: WrappedCanvas | null;
14
14
  isDestroyed: () => boolean;
15
- tryToSatisfySeek: (time: number) => {
15
+ tryToSatisfySeek: (time: number) => Promise<{
16
16
  type: "not-satisfied";
17
17
  reason: string;
18
18
  } | {
19
19
  type: "satisfied";
20
20
  frame: WrappedCanvas;
21
- };
21
+ }>;
22
22
  }>;
23
23
  export type VideoIterator = Awaited<ReturnType<typeof createVideoIterator>>;
@@ -32,4 +32,4 @@ export declare const Video: React.ComponentType<{
32
32
  objectFit: import("./props").VideoObjectFit;
33
33
  _experimentalInitiallyDrawCachedFrame: boolean;
34
34
  effects: import("remotion").EffectsProp;
35
- }> & Omit<React.HTMLAttributes<HTMLElement>, "_experimentalInitiallyDrawCachedFrame" | "audioStreamIndex" | "className" | "credentials" | "debugOverlay" | "delayRenderRetries" | "delayRenderTimeoutInMilliseconds" | "disallowFallbackToOffthreadVideo" | "effects" | "fallbackOffthreadVideoProps" | "headless" | "logLevel" | "loop" | "loopVolumeCurveBehavior" | "muted" | "objectFit" | "onError" | "onVideoFrame" | "playbackRate" | "requestInit" | "showInTimeline" | "src" | "stack" | "style" | "toneFrequency" | "trimAfter" | "trimBefore" | "volume"> & Record<`data-${string}`, string | undefined> & Pick<import("remotion").SequenceProps, "durationInFrames" | "from" | "hidden" | "name">>;
35
+ }> & Omit<React.HTMLAttributes<HTMLElement>, "_experimentalInitiallyDrawCachedFrame" | "audioStreamIndex" | "className" | "credentials" | "debugOverlay" | "delayRenderRetries" | "delayRenderTimeoutInMilliseconds" | "disallowFallbackToOffthreadVideo" | "effects" | "fallbackOffthreadVideoProps" | "headless" | "logLevel" | "loop" | "loopVolumeCurveBehavior" | "muted" | "objectFit" | "onError" | "onVideoFrame" | "playbackRate" | "requestInit" | "showInTimeline" | "src" | "stack" | "style" | "toneFrequency" | "trimAfter" | "trimBefore" | "volume"> & Record<`data-${string}`, string | undefined> & Pick<import("remotion").SequenceProps, "durationInFrames" | "from" | "hidden" | "name" | "showInTimeline">>;
@@ -27,13 +27,13 @@ export declare const videoIteratorManager: ({ delayPlaybackHandleIfNotPremountin
27
27
  destroy: () => void;
28
28
  initialFrame: WrappedCanvas | null;
29
29
  isDestroyed: () => boolean;
30
- tryToSatisfySeek: (time: number) => {
30
+ tryToSatisfySeek: (time: number) => Promise<{
31
31
  type: "not-satisfied";
32
32
  reason: string;
33
33
  } | {
34
34
  type: "satisfied";
35
35
  frame: WrappedCanvas;
36
- };
36
+ }>;
37
37
  } | null;
38
38
  drawFrame: (frame: WrappedCanvas) => Promise<void>;
39
39
  redrawCurrentFrame: () => Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/media",
3
- "version": "4.0.474",
3
+ "version": "4.0.476",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/esm/index.mjs",
@@ -23,7 +23,7 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "mediabunny": "1.45.0",
26
- "remotion": "4.0.474",
26
+ "remotion": "4.0.476",
27
27
  "zod": "4.3.6"
28
28
  },
29
29
  "peerDependencies": {
@@ -31,7 +31,7 @@
31
31
  "react-dom": ">=16.8.0"
32
32
  },
33
33
  "devDependencies": {
34
- "@remotion/eslint-config-internal": "4.0.474",
34
+ "@remotion/eslint-config-internal": "4.0.476",
35
35
  "@vitest/browser-webdriverio": "4.0.9",
36
36
  "eslint": "9.19.0",
37
37
  "react": "19.2.3",