@remotion/media 4.0.446 → 4.0.447

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.
@@ -1093,8 +1093,10 @@ var videoIteratorManager = ({
1093
1093
  let framesRendered = 0;
1094
1094
  let currentDelayHandle = null;
1095
1095
  if (canvas) {
1096
- canvas.width = videoTrack.displayWidth;
1097
- canvas.height = videoTrack.displayHeight;
1096
+ if (canvas.width !== videoTrack.displayWidth || canvas.height !== videoTrack.displayHeight) {
1097
+ canvas.width = videoTrack.displayWidth;
1098
+ canvas.height = videoTrack.displayHeight;
1099
+ }
1098
1100
  }
1099
1101
  const canvasSink = new CanvasSink(videoTrack, {
1100
1102
  poolSize: 2,
@@ -4521,6 +4523,29 @@ import {
4521
4523
  useVideoConfig as useVideoConfig3
4522
4524
  } from "remotion";
4523
4525
 
4526
+ // src/video/video-frame-cache.ts
4527
+ var cache = new Map;
4528
+ var cacheVideoFrame = (src, sourceCanvas) => {
4529
+ const { width, height } = sourceCanvas;
4530
+ if (width === 0 || height === 0) {
4531
+ return;
4532
+ }
4533
+ let cached = cache.get(src);
4534
+ if (!cached || cached.width !== width || cached.height !== height) {
4535
+ cached = new OffscreenCanvas(width, height);
4536
+ cache.set(src, cached);
4537
+ }
4538
+ const ctx = cached.getContext("2d");
4539
+ if (!ctx) {
4540
+ return;
4541
+ }
4542
+ ctx.clearRect(0, 0, width, height);
4543
+ ctx.drawImage(sourceCanvas, 0, 0);
4544
+ };
4545
+ var getCachedVideoFrame = (src) => {
4546
+ return cache.get(src) ?? null;
4547
+ };
4548
+
4524
4549
  // src/video/warn-object-fit-css.ts
4525
4550
  import { Internals as Internals20 } from "remotion";
4526
4551
  var OBJECT_FIT_CLASS_PATTERN = /\bobject-(contain|cover|fill|none|scale-down)\b/;
@@ -4581,7 +4606,8 @@ var VideoForPreviewAssertedShowing = ({
4581
4606
  onError,
4582
4607
  credentials,
4583
4608
  controls,
4584
- objectFit: objectFitProp
4609
+ objectFit: objectFitProp,
4610
+ _experimentalInitiallyDrawCachedFrame
4585
4611
  }) => {
4586
4612
  const src = usePreload2(unpreloadedSrc);
4587
4613
  const canvasRef = useRef2(null);
@@ -4658,6 +4684,44 @@ var VideoForPreviewAssertedShowing = ({
4658
4684
  const initialMuted = useRef2(effectiveMuted);
4659
4685
  const initialDurationInFrames = useRef2(videoConfig.durationInFrames);
4660
4686
  const initialSequenceOffset = useRef2(sequenceOffset);
4687
+ const hasDrawnRealFrameRef = useRef2(false);
4688
+ const isPremountingRef = useRef2(isPremounting);
4689
+ isPremountingRef.current = isPremounting;
4690
+ useLayoutEffect3(() => {
4691
+ if (!_experimentalInitiallyDrawCachedFrame) {
4692
+ return;
4693
+ }
4694
+ const canvas = canvasRef.current;
4695
+ if (!canvas) {
4696
+ return;
4697
+ }
4698
+ const cached = getCachedVideoFrame(src);
4699
+ if (!cached) {
4700
+ return;
4701
+ }
4702
+ canvas.width = cached.width;
4703
+ canvas.height = cached.height;
4704
+ const ctx = canvas.getContext("2d", {
4705
+ alpha: true,
4706
+ desynchronized: true
4707
+ });
4708
+ if (!ctx) {
4709
+ return;
4710
+ }
4711
+ ctx.drawImage(cached, 0, 0);
4712
+ }, [_experimentalInitiallyDrawCachedFrame, src]);
4713
+ useLayoutEffect3(() => {
4714
+ if (!_experimentalInitiallyDrawCachedFrame) {
4715
+ return;
4716
+ }
4717
+ const canvas = canvasRef.current;
4718
+ return () => {
4719
+ if (!canvas || !hasDrawnRealFrameRef.current || isPremountingRef.current) {
4720
+ return;
4721
+ }
4722
+ cacheVideoFrame(src, canvas);
4723
+ };
4724
+ }, [_experimentalInitiallyDrawCachedFrame, src]);
4661
4725
  useEffect3(() => {
4662
4726
  if (!sharedAudioContext)
4663
4727
  return;
@@ -4726,6 +4790,7 @@ var VideoForPreviewAssertedShowing = ({
4726
4790
  if (result.type === "success") {
4727
4791
  setMediaPlayerReady(true);
4728
4792
  setMediaDurationInSeconds(result.durationInSeconds);
4793
+ hasDrawnRealFrameRef.current = true;
4729
4794
  }
4730
4795
  }).catch((error) => {
4731
4796
  const [action, errorToUse] = callOnErrorAndResolve({
@@ -4763,6 +4828,7 @@ var VideoForPreviewAssertedShowing = ({
4763
4828
  }
4764
4829
  setMediaPlayerReady(false);
4765
4830
  setShouldFallbackToNativeVideo(false);
4831
+ hasDrawnRealFrameRef.current = false;
4766
4832
  };
4767
4833
  }, [
4768
4834
  audioStreamIndex,
@@ -5283,7 +5349,8 @@ var InnerVideo = ({
5283
5349
  onError,
5284
5350
  credentials,
5285
5351
  controls,
5286
- objectFit
5352
+ objectFit,
5353
+ _experimentalInitiallyDrawCachedFrame
5287
5354
  }) => {
5288
5355
  const environment = useRemotionEnvironment4();
5289
5356
  if (typeof src !== "string") {
@@ -5355,7 +5422,8 @@ var InnerVideo = ({
5355
5422
  onError,
5356
5423
  credentials,
5357
5424
  controls,
5358
- objectFit
5425
+ objectFit,
5426
+ _experimentalInitiallyDrawCachedFrame
5359
5427
  });
5360
5428
  };
5361
5429
  var VideoInner = ({
@@ -5387,6 +5455,7 @@ var VideoInner = ({
5387
5455
  credentials,
5388
5456
  controls,
5389
5457
  objectFit,
5458
+ _experimentalInitiallyDrawCachedFrame,
5390
5459
  from,
5391
5460
  durationInFrames
5392
5461
  }) => {
@@ -5424,7 +5493,8 @@ var VideoInner = ({
5424
5493
  onError,
5425
5494
  credentials,
5426
5495
  controls,
5427
- objectFit: objectFit ?? "contain"
5496
+ objectFit: objectFit ?? "contain",
5497
+ _experimentalInitiallyDrawCachedFrame: _experimentalInitiallyDrawCachedFrame ?? false
5428
5498
  })
5429
5499
  });
5430
5500
  };
package/dist/index.d.ts CHANGED
@@ -39,6 +39,7 @@ export declare const experimental_Video: import("react").ComponentType<{
39
39
  onError: import("./on-error").MediaOnError | undefined;
40
40
  credentials: RequestCredentials | undefined;
41
41
  objectFit: import(".").VideoObjectFit;
42
+ _experimentalInitiallyDrawCachedFrame: boolean;
42
43
  }> & {
43
44
  from?: number | undefined;
44
45
  durationInFrames?: number | undefined;
@@ -51,6 +51,7 @@ type OptionalVideoProps = {
51
51
  onError: MediaOnError | undefined;
52
52
  credentials: RequestCredentials | undefined;
53
53
  objectFit: VideoObjectFit;
54
+ _experimentalInitiallyDrawCachedFrame: boolean;
54
55
  };
55
56
  export type InnerVideoProps = MandatoryVideoProps & OuterVideoProps & OptionalVideoProps;
56
57
  export type VideoProps = MandatoryVideoProps & Partial<OuterVideoProps> & Partial<OptionalVideoProps> & {
@@ -27,6 +27,7 @@ type VideoForPreviewProps = {
27
27
  readonly onError: MediaOnError | undefined;
28
28
  readonly credentials: RequestCredentials | undefined;
29
29
  readonly objectFit: VideoObjectFit;
30
+ readonly _experimentalInitiallyDrawCachedFrame: boolean;
30
31
  };
31
32
  export declare const VideoForPreview: React.FC<VideoForPreviewProps & {
32
33
  readonly controls: SequenceControls | undefined;
@@ -0,0 +1,2 @@
1
+ export declare const cacheVideoFrame: (src: string, sourceCanvas: HTMLCanvasElement | OffscreenCanvas) => void;
2
+ export declare const getCachedVideoFrame: (src: string) => OffscreenCanvas | null;
@@ -31,6 +31,7 @@ export declare const Video: React.ComponentType<{
31
31
  onError: import("../on-error").MediaOnError | undefined;
32
32
  credentials: RequestCredentials | undefined;
33
33
  objectFit: import("./props").VideoObjectFit;
34
+ _experimentalInitiallyDrawCachedFrame: boolean;
34
35
  }> & {
35
36
  from?: number | undefined;
36
37
  durationInFrames?: number | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remotion/media",
3
- "version": "4.0.446",
3
+ "version": "4.0.447",
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.39.2",
26
- "remotion": "4.0.446",
26
+ "remotion": "4.0.447",
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.446",
34
+ "@remotion/eslint-config-internal": "4.0.447",
35
35
  "@vitest/browser-webdriverio": "4.0.9",
36
36
  "eslint": "9.19.0",
37
37
  "react": "19.2.3",