@shopify/react-native-skia 1.3.2 → 1.3.3

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.
Files changed (53) hide show
  1. package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp +59 -1
  2. package/android/cpp/rnskia-android/RNSkAndroidVideo.h +4 -0
  3. package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java +80 -7
  4. package/cpp/api/JsiVideo.h +32 -7
  5. package/cpp/rnskia/RNSkVideo.h +4 -0
  6. package/ios/RNSkia-iOS/RNSkiOSVideo.h +13 -4
  7. package/ios/RNSkia-iOS/RNSkiOSVideo.mm +65 -67
  8. package/lib/commonjs/dom/nodes/datatypes/Fitting.js +42 -30
  9. package/lib/commonjs/dom/nodes/datatypes/Fitting.js.map +1 -1
  10. package/lib/commonjs/external/reanimated/useVideo.d.ts +16 -4
  11. package/lib/commonjs/external/reanimated/useVideo.js +76 -14
  12. package/lib/commonjs/external/reanimated/useVideo.js.map +1 -1
  13. package/lib/commonjs/renderer/components/shapes/FitBox.d.ts +2 -10
  14. package/lib/commonjs/renderer/components/shapes/FitBox.js +32 -3
  15. package/lib/commonjs/renderer/components/shapes/FitBox.js.map +1 -1
  16. package/lib/commonjs/skia/core/Matrix.js +5 -1
  17. package/lib/commonjs/skia/core/Matrix.js.map +1 -1
  18. package/lib/commonjs/skia/types/Matrix.js +2 -0
  19. package/lib/commonjs/skia/types/Matrix.js.map +1 -1
  20. package/lib/commonjs/skia/types/Video/Video.d.ts +9 -1
  21. package/lib/commonjs/skia/types/Video/Video.js.map +1 -1
  22. package/lib/module/dom/nodes/datatypes/Fitting.js +41 -29
  23. package/lib/module/dom/nodes/datatypes/Fitting.js.map +1 -1
  24. package/lib/module/external/reanimated/useVideo.d.ts +16 -4
  25. package/lib/module/external/reanimated/useVideo.js +76 -14
  26. package/lib/module/external/reanimated/useVideo.js.map +1 -1
  27. package/lib/module/renderer/components/shapes/FitBox.d.ts +2 -10
  28. package/lib/module/renderer/components/shapes/FitBox.js +32 -3
  29. package/lib/module/renderer/components/shapes/FitBox.js.map +1 -1
  30. package/lib/module/skia/core/Matrix.js +5 -1
  31. package/lib/module/skia/core/Matrix.js.map +1 -1
  32. package/lib/module/skia/types/Matrix.js +2 -0
  33. package/lib/module/skia/types/Matrix.js.map +1 -1
  34. package/lib/module/skia/types/Video/Video.d.ts +9 -1
  35. package/lib/module/skia/types/Video/Video.js.map +1 -1
  36. package/lib/typescript/src/external/reanimated/useVideo.d.ts +16 -4
  37. package/lib/typescript/src/renderer/components/shapes/FitBox.d.ts +2 -10
  38. package/lib/typescript/src/skia/types/Video/Video.d.ts +9 -1
  39. package/package.json +1 -1
  40. package/src/dom/nodes/datatypes/Fitting.ts +28 -21
  41. package/src/external/reanimated/useVideo.ts +90 -29
  42. package/src/renderer/components/shapes/FitBox.tsx +38 -4
  43. package/src/skia/core/Matrix.ts +4 -2
  44. package/src/skia/types/Matrix.ts +1 -0
  45. package/src/skia/types/Video/Video.ts +7 -1
  46. package/lib/commonjs/external/reanimated/video.d.ts +0 -16
  47. package/lib/commonjs/external/reanimated/video.js +0 -54
  48. package/lib/commonjs/external/reanimated/video.js.map +0 -1
  49. package/lib/module/external/reanimated/video.d.ts +0 -16
  50. package/lib/module/external/reanimated/video.js +0 -46
  51. package/lib/module/external/reanimated/video.js.map +0 -1
  52. package/lib/typescript/src/external/reanimated/video.d.ts +0 -16
  53. package/src/external/reanimated/video.ts +0 -82
@@ -1,13 +1,28 @@
1
1
  import { useEffect, useMemo } from "react";
2
2
  import { Skia } from "../../skia/Skia";
3
+ import { Platform } from "../../Platform";
3
4
  import Rea from "./ReanimatedProxy";
4
- import { processVideoState } from "./video";
5
+ const setFrame = (video, currentFrame) => {
6
+ "worklet";
7
+
8
+ const img = video.nextImage();
9
+ if (img) {
10
+ if (currentFrame.value) {
11
+ currentFrame.value.dispose();
12
+ }
13
+ if (Platform.OS === "android") {
14
+ currentFrame.value = img.makeNonTextureImage();
15
+ } else {
16
+ currentFrame.value = img;
17
+ }
18
+ }
19
+ };
5
20
  const defaultOptions = {
6
- playbackSpeed: 1,
7
21
  looping: true,
8
22
  paused: false,
9
23
  seek: null,
10
- currentTime: 0
24
+ currentTime: 0,
25
+ volume: 0
11
26
  };
12
27
  const useOption = value => {
13
28
  "worklet";
@@ -22,12 +37,12 @@ const disposeVideo = video => {
22
37
  video === null || video === void 0 || video.dispose();
23
38
  };
24
39
  export const useVideo = (source, userOptions) => {
25
- var _userOptions$paused, _userOptions$looping, _userOptions$seek, _userOptions$playback;
40
+ var _userOptions$paused, _userOptions$looping, _userOptions$seek, _userOptions$volume;
26
41
  const video = useMemo(() => source ? Skia.Video(source) : null, [source]);
27
42
  const isPaused = useOption((_userOptions$paused = userOptions === null || userOptions === void 0 ? void 0 : userOptions.paused) !== null && _userOptions$paused !== void 0 ? _userOptions$paused : defaultOptions.paused);
28
43
  const looping = useOption((_userOptions$looping = userOptions === null || userOptions === void 0 ? void 0 : userOptions.looping) !== null && _userOptions$looping !== void 0 ? _userOptions$looping : defaultOptions.looping);
29
44
  const seek = useOption((_userOptions$seek = userOptions === null || userOptions === void 0 ? void 0 : userOptions.seek) !== null && _userOptions$seek !== void 0 ? _userOptions$seek : defaultOptions.seek);
30
- const playbackSpeed = useOption((_userOptions$playback = userOptions === null || userOptions === void 0 ? void 0 : userOptions.playbackSpeed) !== null && _userOptions$playback !== void 0 ? _userOptions$playback : defaultOptions.playbackSpeed);
45
+ const volume = useOption((_userOptions$volume = userOptions === null || userOptions === void 0 ? void 0 : userOptions.volume) !== null && _userOptions$volume !== void 0 ? _userOptions$volume : defaultOptions.volume);
31
46
  const currentFrame = Rea.useSharedValue(null);
32
47
  const currentTime = Rea.useSharedValue(0);
33
48
  const lastTimestamp = Rea.useSharedValue(-1);
@@ -39,16 +54,62 @@ export const useVideo = (source, userOptions) => {
39
54
  var _video$framerate;
40
55
  return (_video$framerate = video === null || video === void 0 ? void 0 : video.framerate()) !== null && _video$framerate !== void 0 ? _video$framerate : 0;
41
56
  }, [video]);
42
- const rotationInDegrees = useMemo(() => {
43
- var _video$getRotationInD;
44
- return (_video$getRotationInD = video === null || video === void 0 ? void 0 : video.getRotationInDegrees()) !== null && _video$getRotationInD !== void 0 ? _video$getRotationInD : 0;
57
+ const size = useMemo(() => {
58
+ var _video$size;
59
+ return (_video$size = video === null || video === void 0 ? void 0 : video.size()) !== null && _video$size !== void 0 ? _video$size : {
60
+ width: 0,
61
+ height: 0
62
+ };
63
+ }, [video]);
64
+ const rotation = useMemo(() => {
65
+ var _video$rotation;
66
+ return (_video$rotation = video === null || video === void 0 ? void 0 : video.rotation()) !== null && _video$rotation !== void 0 ? _video$rotation : 0;
45
67
  }, [video]);
68
+ const frameDuration = 1000 / framerate;
69
+ const currentFrameDuration = Math.floor(frameDuration);
70
+ Rea.useAnimatedReaction(() => isPaused.value, paused => {
71
+ if (paused) {
72
+ video === null || video === void 0 || video.pause();
73
+ } else {
74
+ lastTimestamp.value = -1;
75
+ video === null || video === void 0 || video.play();
76
+ }
77
+ });
78
+ Rea.useAnimatedReaction(() => seek.value, value => {
79
+ if (value !== null) {
80
+ video === null || video === void 0 || video.seek(value);
81
+ currentTime.value = value;
82
+ seek.value = null;
83
+ }
84
+ });
85
+ Rea.useAnimatedReaction(() => volume.value, value => {
86
+ video === null || video === void 0 || video.setVolume(value);
87
+ });
46
88
  Rea.useFrameCallback(frameInfo => {
47
- processVideoState(video, duration, framerate, frameInfo.timestamp, {
48
- paused: isPaused.value,
49
- looping: looping.value,
50
- playbackSpeed: playbackSpeed.value
51
- }, currentTime, currentFrame, lastTimestamp, seek);
89
+ "worklet";
90
+
91
+ if (!video) {
92
+ return;
93
+ }
94
+ if (isPaused.value) {
95
+ return;
96
+ }
97
+ const currentTimestamp = frameInfo.timestamp;
98
+ if (lastTimestamp.value === -1) {
99
+ lastTimestamp.value = currentTimestamp;
100
+ }
101
+ const delta = currentTimestamp - lastTimestamp.value;
102
+ const isOver = currentTime.value + delta > duration;
103
+ if (isOver && looping.value) {
104
+ seek.value = 0;
105
+ currentTime.value = seek.value;
106
+ lastTimestamp.value = currentTimestamp;
107
+ }
108
+ if (delta >= currentFrameDuration && !isOver) {
109
+ setFrame(video, currentFrame);
110
+ currentTime.value += delta;
111
+ lastTimestamp.value = currentTimestamp;
112
+ }
52
113
  });
53
114
  useEffect(() => {
54
115
  return () => {
@@ -61,7 +122,8 @@ export const useVideo = (source, userOptions) => {
61
122
  currentTime,
62
123
  duration,
63
124
  framerate,
64
- rotationInDegrees
125
+ rotation,
126
+ size
65
127
  };
66
128
  };
67
129
  //# sourceMappingURL=useVideo.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["useEffect","useMemo","Skia","Rea","processVideoState","defaultOptions","playbackSpeed","looping","paused","seek","currentTime","useOption","value","defaultValue","useSharedValue","isSharedValue","disposeVideo","video","dispose","useVideo","source","userOptions","_userOptions$paused","_userOptions$looping","_userOptions$seek","_userOptions$playback","Video","isPaused","currentFrame","lastTimestamp","duration","_video$duration","framerate","_video$framerate","rotationInDegrees","_video$getRotationInD","getRotationInDegrees","useFrameCallback","frameInfo","timestamp","runOnUI"],"sources":["useVideo.ts"],"sourcesContent":["import { type FrameInfo } from \"react-native-reanimated\";\nimport { useEffect, useMemo } from \"react\";\n\nimport { Skia } from \"../../skia/Skia\";\nimport type { SkImage, Video } from \"../../skia/types\";\n\nimport Rea from \"./ReanimatedProxy\";\nimport {\n processVideoState,\n type Animated,\n type PlaybackOptions,\n} from \"./video\";\n\nconst defaultOptions = {\n playbackSpeed: 1,\n looping: true,\n paused: false,\n seek: null,\n currentTime: 0,\n};\n\nconst useOption = <T>(value: Animated<T>) => {\n \"worklet\";\n // TODO: only create defaultValue is needed (via makeMutable)\n const defaultValue = Rea.useSharedValue(\n Rea.isSharedValue(value) ? value.value : value\n );\n return Rea.isSharedValue(value) ? value : defaultValue;\n};\n\nconst disposeVideo = (video: Video | null) => {\n \"worklet\";\n video?.dispose();\n};\n\nexport const useVideo = (\n source: string | null,\n userOptions?: Partial<PlaybackOptions>\n) => {\n const video = useMemo(() => (source ? Skia.Video(source) : null), [source]);\n const isPaused = useOption(userOptions?.paused ?? defaultOptions.paused);\n const looping = useOption(userOptions?.looping ?? defaultOptions.looping);\n const seek = useOption(userOptions?.seek ?? defaultOptions.seek);\n const playbackSpeed = useOption(\n userOptions?.playbackSpeed ?? defaultOptions.playbackSpeed\n );\n const currentFrame = Rea.useSharedValue<null | SkImage>(null);\n const currentTime = Rea.useSharedValue(0);\n const lastTimestamp = Rea.useSharedValue(-1);\n const duration = useMemo(() => video?.duration() ?? 0, [video]);\n const framerate = useMemo(() => video?.framerate() ?? 0, [video]);\n const rotationInDegrees = useMemo(\n () => video?.getRotationInDegrees() ?? 0,\n [video]\n );\n Rea.useFrameCallback((frameInfo: FrameInfo) => {\n processVideoState(\n video,\n duration,\n framerate,\n frameInfo.timestamp,\n {\n paused: isPaused.value,\n looping: looping.value,\n playbackSpeed: playbackSpeed.value,\n },\n currentTime,\n currentFrame,\n lastTimestamp,\n seek\n );\n });\n\n useEffect(() => {\n return () => {\n // TODO: should video simply be a shared value instead?\n Rea.runOnUI(disposeVideo)(video);\n };\n }, [video]);\n\n return { currentFrame, currentTime, duration, framerate, rotationInDegrees };\n};\n"],"mappings":"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"}
1
+ {"version":3,"names":["useEffect","useMemo","Skia","Platform","Rea","setFrame","video","currentFrame","img","nextImage","value","dispose","OS","makeNonTextureImage","defaultOptions","looping","paused","seek","currentTime","volume","useOption","defaultValue","useSharedValue","isSharedValue","disposeVideo","useVideo","source","userOptions","_userOptions$paused","_userOptions$looping","_userOptions$seek","_userOptions$volume","Video","isPaused","lastTimestamp","duration","_video$duration","framerate","_video$framerate","size","_video$size","width","height","rotation","_video$rotation","frameDuration","currentFrameDuration","Math","floor","useAnimatedReaction","pause","play","setVolume","useFrameCallback","frameInfo","currentTimestamp","timestamp","delta","isOver","runOnUI"],"sources":["useVideo.ts"],"sourcesContent":["import type { SharedValue, FrameInfo } from \"react-native-reanimated\";\nimport { useEffect, useMemo } from \"react\";\n\nimport { Skia } from \"../../skia/Skia\";\nimport type { SkImage, Video } from \"../../skia/types\";\nimport { Platform } from \"../../Platform\";\n\nimport Rea from \"./ReanimatedProxy\";\n\ntype Animated<T> = SharedValue<T> | T;\n\ninterface PlaybackOptions {\n looping: Animated<boolean>;\n paused: Animated<boolean>;\n seek: Animated<number | null>;\n volume: Animated<number>;\n}\n\nconst setFrame = (video: Video, currentFrame: SharedValue<SkImage | null>) => {\n \"worklet\";\n const img = video.nextImage();\n if (img) {\n if (currentFrame.value) {\n currentFrame.value.dispose();\n }\n if (Platform.OS === \"android\") {\n currentFrame.value = img.makeNonTextureImage();\n } else {\n currentFrame.value = img;\n }\n }\n};\n\nconst defaultOptions = {\n looping: true,\n paused: false,\n seek: null,\n currentTime: 0,\n volume: 0,\n};\n\nconst useOption = <T>(value: Animated<T>) => {\n \"worklet\";\n // TODO: only create defaultValue is needed (via makeMutable)\n const defaultValue = Rea.useSharedValue(\n Rea.isSharedValue(value) ? value.value : value\n );\n return Rea.isSharedValue(value) ? value : defaultValue;\n};\n\nconst disposeVideo = (video: Video | null) => {\n \"worklet\";\n video?.dispose();\n};\n\nexport const useVideo = (\n source: string | null,\n userOptions?: Partial<PlaybackOptions>\n) => {\n const video = useMemo(() => (source ? Skia.Video(source) : null), [source]);\n const isPaused = useOption(userOptions?.paused ?? defaultOptions.paused);\n const looping = useOption(userOptions?.looping ?? defaultOptions.looping);\n const seek = useOption(userOptions?.seek ?? defaultOptions.seek);\n const volume = useOption(userOptions?.volume ?? defaultOptions.volume);\n const currentFrame = Rea.useSharedValue<null | SkImage>(null);\n const currentTime = Rea.useSharedValue(0);\n const lastTimestamp = Rea.useSharedValue(-1);\n const duration = useMemo(() => video?.duration() ?? 0, [video]);\n const framerate = useMemo(() => video?.framerate() ?? 0, [video]);\n const size = useMemo(() => video?.size() ?? { width: 0, height: 0 }, [video]);\n const rotation = useMemo(() => video?.rotation() ?? 0, [video]);\n const frameDuration = 1000 / framerate;\n const currentFrameDuration = Math.floor(frameDuration);\n Rea.useAnimatedReaction(\n () => isPaused.value,\n (paused) => {\n if (paused) {\n video?.pause();\n } else {\n lastTimestamp.value = -1;\n video?.play();\n }\n }\n );\n Rea.useAnimatedReaction(\n () => seek.value,\n (value) => {\n if (value !== null) {\n video?.seek(value);\n currentTime.value = value;\n seek.value = null;\n }\n }\n );\n Rea.useAnimatedReaction(\n () => volume.value,\n (value) => {\n video?.setVolume(value);\n }\n );\n Rea.useFrameCallback((frameInfo: FrameInfo) => {\n \"worklet\";\n if (!video) {\n return;\n }\n if (isPaused.value) {\n return;\n }\n const currentTimestamp = frameInfo.timestamp;\n if (lastTimestamp.value === -1) {\n lastTimestamp.value = currentTimestamp;\n }\n const delta = currentTimestamp - lastTimestamp.value;\n\n const isOver = currentTime.value + delta > duration;\n if (isOver && looping.value) {\n seek.value = 0;\n currentTime.value = seek.value;\n lastTimestamp.value = currentTimestamp;\n }\n if (delta >= currentFrameDuration && !isOver) {\n setFrame(video, currentFrame);\n currentTime.value += delta;\n lastTimestamp.value = currentTimestamp;\n }\n });\n\n useEffect(() => {\n return () => {\n // TODO: should video simply be a shared value instead?\n Rea.runOnUI(disposeVideo)(video);\n };\n }, [video]);\n\n return {\n currentFrame,\n currentTime,\n duration,\n framerate,\n rotation,\n size,\n };\n};\n"],"mappings":"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"}
@@ -1,21 +1,13 @@
1
1
  import type { ReactNode } from "react";
2
2
  import React from "react";
3
3
  import type { Fit } from "../../../dom/nodes";
4
- import type { SkRect } from "../../../skia/types";
4
+ import type { SkRect, Transforms3d } from "../../../skia/types";
5
5
  interface FitProps {
6
6
  fit?: Fit;
7
7
  src: SkRect;
8
8
  dst: SkRect;
9
9
  children: ReactNode | ReactNode[];
10
10
  }
11
- export declare const fitbox: (fit: Fit, src: SkRect, dst: SkRect) => [{
12
- translateX: number;
13
- }, {
14
- translateY: number;
15
- }, {
16
- scaleX: number;
17
- }, {
18
- scaleY: number;
19
- }];
11
+ export declare const fitbox: (fit: Fit, src: SkRect, dst: SkRect, rotation?: 0 | 90 | 180 | 270) => Transforms3d;
20
12
  export declare const FitBox: ({ fit, src, dst, children }: FitProps) => React.JSX.Element;
21
13
  export {};
@@ -1,9 +1,38 @@
1
1
  import React, { useMemo } from "react";
2
2
  import { fitRects, rect2rect } from "../../../dom/nodes";
3
3
  import { Group } from "../Group";
4
- export const fitbox = (fit, src, dst) => {
5
- const rects = fitRects(fit, src, dst);
6
- return rect2rect(rects.src, rects.dst);
4
+ export const fitbox = (fit, src, dst, rotation = 0) => {
5
+ "worklet";
6
+
7
+ const rects = fitRects(fit, rotation === 90 || rotation === 270 ? {
8
+ x: 0,
9
+ y: 0,
10
+ width: src.height,
11
+ height: src.width
12
+ } : src, dst);
13
+ const result = rect2rect(rects.src, rects.dst);
14
+ if (rotation === 90) {
15
+ return [...result, {
16
+ translate: [src.height, 0]
17
+ }, {
18
+ rotate: Math.PI / 2
19
+ }];
20
+ }
21
+ if (rotation === 180) {
22
+ return [...result, {
23
+ translate: [src.width, src.height]
24
+ }, {
25
+ rotate: Math.PI
26
+ }];
27
+ }
28
+ if (rotation === 270) {
29
+ return [...result, {
30
+ translate: [0, src.width]
31
+ }, {
32
+ rotate: -Math.PI / 2
33
+ }];
34
+ }
35
+ return result;
7
36
  };
8
37
  export const FitBox = ({
9
38
  fit = "contain",
@@ -1 +1 @@
1
- {"version":3,"names":["React","useMemo","fitRects","rect2rect","Group","fitbox","fit","src","dst","rects","FitBox","children","transform","createElement"],"sources":["FitBox.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport React, { useMemo } from \"react\";\n\nimport type { Fit } from \"../../../dom/nodes\";\nimport { fitRects, rect2rect } from \"../../../dom/nodes\";\nimport type { SkRect } from \"../../../skia/types\";\nimport { Group } from \"../Group\";\n\ninterface FitProps {\n fit?: Fit;\n src: SkRect;\n dst: SkRect;\n children: ReactNode | ReactNode[];\n}\n\nexport const fitbox = (fit: Fit, src: SkRect, dst: SkRect) => {\n const rects = fitRects(fit, src, dst);\n return rect2rect(rects.src, rects.dst);\n};\n\nexport const FitBox = ({ fit = \"contain\", src, dst, children }: FitProps) => {\n const transform = useMemo(() => fitbox(fit, src, dst), [dst, fit, src]);\n return <Group transform={transform}>{children}</Group>;\n};\n"],"mappings":"AACA,OAAOA,KAAK,IAAIC,OAAO,QAAQ,OAAO;AAGtC,SAASC,QAAQ,EAAEC,SAAS,QAAQ,oBAAoB;AAExD,SAASC,KAAK,QAAQ,UAAU;AAShC,OAAO,MAAMC,MAAM,GAAGA,CAACC,GAAQ,EAAEC,GAAW,EAAEC,GAAW,KAAK;EAC5D,MAAMC,KAAK,GAAGP,QAAQ,CAACI,GAAG,EAAEC,GAAG,EAAEC,GAAG,CAAC;EACrC,OAAOL,SAAS,CAACM,KAAK,CAACF,GAAG,EAAEE,KAAK,CAACD,GAAG,CAAC;AACxC,CAAC;AAED,OAAO,MAAME,MAAM,GAAGA,CAAC;EAAEJ,GAAG,GAAG,SAAS;EAAEC,GAAG;EAAEC,GAAG;EAAEG;AAAmB,CAAC,KAAK;EAC3E,MAAMC,SAAS,GAAGX,OAAO,CAAC,MAAMI,MAAM,CAACC,GAAG,EAAEC,GAAG,EAAEC,GAAG,CAAC,EAAE,CAACA,GAAG,EAAEF,GAAG,EAAEC,GAAG,CAAC,CAAC;EACvE,oBAAOP,KAAA,CAAAa,aAAA,CAACT,KAAK;IAACQ,SAAS,EAAEA;EAAU,GAAED,QAAgB,CAAC;AACxD,CAAC"}
1
+ {"version":3,"names":["React","useMemo","fitRects","rect2rect","Group","fitbox","fit","src","dst","rotation","rects","x","y","width","height","result","translate","rotate","Math","PI","FitBox","children","transform","createElement"],"sources":["FitBox.tsx"],"sourcesContent":["import type { ReactNode } from \"react\";\nimport React, { useMemo } from \"react\";\n\nimport type { Fit } from \"../../../dom/nodes\";\nimport { fitRects, rect2rect } from \"../../../dom/nodes\";\nimport type { SkRect, Transforms3d } from \"../../../skia/types\";\nimport { Group } from \"../Group\";\n\ninterface FitProps {\n fit?: Fit;\n src: SkRect;\n dst: SkRect;\n children: ReactNode | ReactNode[];\n}\n\nexport const fitbox = (\n fit: Fit,\n src: SkRect,\n dst: SkRect,\n rotation: 0 | 90 | 180 | 270 = 0\n) => {\n \"worklet\";\n const rects = fitRects(\n fit,\n rotation === 90 || rotation === 270\n ? { x: 0, y: 0, width: src.height, height: src.width }\n : src,\n dst\n );\n const result = rect2rect(rects.src, rects.dst);\n if (rotation === 90) {\n return [\n ...result,\n { translate: [src.height, 0] },\n { rotate: Math.PI / 2 },\n ] as Transforms3d;\n }\n if (rotation === 180) {\n return [\n ...result,\n { translate: [src.width, src.height] },\n { rotate: Math.PI },\n ] as Transforms3d;\n }\n if (rotation === 270) {\n return [\n ...result,\n { translate: [0, src.width] },\n { rotate: -Math.PI / 2 },\n ] as Transforms3d;\n }\n return result;\n};\n\nexport const FitBox = ({ fit = \"contain\", src, dst, children }: FitProps) => {\n const transform = useMemo(() => fitbox(fit, src, dst), [dst, fit, src]);\n return <Group transform={transform}>{children}</Group>;\n};\n"],"mappings":"AACA,OAAOA,KAAK,IAAIC,OAAO,QAAQ,OAAO;AAGtC,SAASC,QAAQ,EAAEC,SAAS,QAAQ,oBAAoB;AAExD,SAASC,KAAK,QAAQ,UAAU;AAShC,OAAO,MAAMC,MAAM,GAAGA,CACpBC,GAAQ,EACRC,GAAW,EACXC,GAAW,EACXC,QAA4B,GAAG,CAAC,KAC7B;EACH,SAAS;;EACT,MAAMC,KAAK,GAAGR,QAAQ,CACpBI,GAAG,EACHG,QAAQ,KAAK,EAAE,IAAIA,QAAQ,KAAK,GAAG,GAC/B;IAAEE,CAAC,EAAE,CAAC;IAAEC,CAAC,EAAE,CAAC;IAAEC,KAAK,EAAEN,GAAG,CAACO,MAAM;IAAEA,MAAM,EAAEP,GAAG,CAACM;EAAM,CAAC,GACpDN,GAAG,EACPC,GACF,CAAC;EACD,MAAMO,MAAM,GAAGZ,SAAS,CAACO,KAAK,CAACH,GAAG,EAAEG,KAAK,CAACF,GAAG,CAAC;EAC9C,IAAIC,QAAQ,KAAK,EAAE,EAAE;IACnB,OAAO,CACL,GAAGM,MAAM,EACT;MAAEC,SAAS,EAAE,CAACT,GAAG,CAACO,MAAM,EAAE,CAAC;IAAE,CAAC,EAC9B;MAAEG,MAAM,EAAEC,IAAI,CAACC,EAAE,GAAG;IAAE,CAAC,CACxB;EACH;EACA,IAAIV,QAAQ,KAAK,GAAG,EAAE;IACpB,OAAO,CACL,GAAGM,MAAM,EACT;MAAEC,SAAS,EAAE,CAACT,GAAG,CAACM,KAAK,EAAEN,GAAG,CAACO,MAAM;IAAE,CAAC,EACtC;MAAEG,MAAM,EAAEC,IAAI,CAACC;IAAG,CAAC,CACpB;EACH;EACA,IAAIV,QAAQ,KAAK,GAAG,EAAE;IACpB,OAAO,CACL,GAAGM,MAAM,EACT;MAAEC,SAAS,EAAE,CAAC,CAAC,EAAET,GAAG,CAACM,KAAK;IAAE,CAAC,EAC7B;MAAEI,MAAM,EAAE,CAACC,IAAI,CAACC,EAAE,GAAG;IAAE,CAAC,CACzB;EACH;EACA,OAAOJ,MAAM;AACf,CAAC;AAED,OAAO,MAAMK,MAAM,GAAGA,CAAC;EAAEd,GAAG,GAAG,SAAS;EAAEC,GAAG;EAAEC,GAAG;EAAEa;AAAmB,CAAC,KAAK;EAC3E,MAAMC,SAAS,GAAGrB,OAAO,CAAC,MAAMI,MAAM,CAACC,GAAG,EAAEC,GAAG,EAAEC,GAAG,CAAC,EAAE,CAACA,GAAG,EAAEF,GAAG,EAAEC,GAAG,CAAC,CAAC;EACvE,oBAAOP,KAAA,CAAAuB,aAAA,CAACnB,KAAK;IAACkB,SAAS,EAAEA;EAAU,GAAED,QAAgB,CAAC;AACxD,CAAC"}
@@ -1,4 +1,8 @@
1
1
  import { Skia } from "../Skia";
2
2
  import { processTransform } from "../types";
3
- export const processTransform2d = transforms => processTransform(Skia.Matrix(), transforms);
3
+ export const processTransform2d = transforms => {
4
+ "worklet";
5
+
6
+ return processTransform(Skia.Matrix(), transforms);
7
+ };
4
8
  //# sourceMappingURL=Matrix.js.map
@@ -1 +1 @@
1
- {"version":3,"names":["Skia","processTransform","processTransform2d","transforms","Matrix"],"sources":["Matrix.ts"],"sourcesContent":["import { Skia } from \"../Skia\";\nimport type { Transforms3d } from \"../types\";\nimport { processTransform } from \"../types\";\n\nexport const processTransform2d = (transforms: Transforms3d) =>\n processTransform(Skia.Matrix(), transforms);\n"],"mappings":"AAAA,SAASA,IAAI,QAAQ,SAAS;AAE9B,SAASC,gBAAgB,QAAQ,UAAU;AAE3C,OAAO,MAAMC,kBAAkB,GAAIC,UAAwB,IACzDF,gBAAgB,CAACD,IAAI,CAACI,MAAM,CAAC,CAAC,EAAED,UAAU,CAAC"}
1
+ {"version":3,"names":["Skia","processTransform","processTransform2d","transforms","Matrix"],"sources":["Matrix.ts"],"sourcesContent":["import { Skia } from \"../Skia\";\nimport type { Transforms3d } from \"../types\";\nimport { processTransform } from \"../types\";\n\nexport const processTransform2d = (transforms: Transforms3d) => {\n \"worklet\";\n return processTransform(Skia.Matrix(), transforms);\n};\n"],"mappings":"AAAA,SAASA,IAAI,QAAQ,SAAS;AAE9B,SAASC,gBAAgB,QAAQ,UAAU;AAE3C,OAAO,MAAMC,kBAAkB,GAAIC,UAAwB,IAAK;EAC9D,SAAS;;EACT,OAAOF,gBAAgB,CAACD,IAAI,CAACI,MAAM,CAAC,CAAC,EAAED,UAAU,CAAC;AACpD,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import { processTransform3d } from "./Matrix4";
2
2
  export const isMatrix = obj => obj !== null && obj.__typename__ === "Matrix";
3
3
  export const processTransform = (m, transforms) => {
4
+ "worklet";
5
+
4
6
  const m3 = processTransform3d(transforms);
5
7
  m.concat(m3);
6
8
  return m;
@@ -1 +1 @@
1
- {"version":3,"names":["processTransform3d","isMatrix","obj","__typename__","processTransform","m","transforms","m3","concat","toDegrees","rad","Math","PI"],"sources":["Matrix.ts"],"sourcesContent":["import type { SkJSIInstance } from \"./JsiInstance\";\nimport type { SkCanvas } from \"./Canvas\";\nimport type { Matrix3, Matrix4, Transforms3d } from \"./Matrix4\";\nimport { processTransform3d } from \"./Matrix4\";\n\nexport const isMatrix = (obj: unknown): obj is SkMatrix =>\n obj !== null && (obj as SkJSIInstance<string>).__typename__ === \"Matrix\";\n\nexport interface SkMatrix extends SkJSIInstance<\"Matrix\"> {\n concat: (matrix: InputMatrix) => SkMatrix;\n translate: (x: number, y: number) => SkMatrix;\n scale: (x: number, y?: number) => SkMatrix;\n skew: (x: number, y: number) => SkMatrix;\n rotate: (theta: number) => SkMatrix;\n postTranslate: (x: number, y: number) => SkMatrix;\n postScale: (x: number, y?: number) => SkMatrix;\n postSkew: (x: number, y: number) => SkMatrix;\n postRotate: (theta: number) => SkMatrix;\n identity: () => SkMatrix;\n get: () => number[];\n}\n\nexport type InputMatrix = SkMatrix | Matrix3 | Matrix4 | number[];\n\nexport interface TransformProp {\n transform?: Transforms3d;\n}\n\nexport const processTransform = <T extends SkMatrix | SkCanvas>(\n m: T,\n transforms: Transforms3d\n) => {\n const m3 = processTransform3d(transforms);\n m.concat(m3);\n return m;\n};\n\nexport const toDegrees = (rad: number) => {\n return (rad * 180) / Math.PI;\n};\n"],"mappings":"AAGA,SAASA,kBAAkB,QAAQ,WAAW;AAE9C,OAAO,MAAMC,QAAQ,GAAIC,GAAY,IACnCA,GAAG,KAAK,IAAI,IAAKA,GAAG,CAA2BC,YAAY,KAAK,QAAQ;AAsB1E,OAAO,MAAMC,gBAAgB,GAAGA,CAC9BC,CAAI,EACJC,UAAwB,KACrB;EACH,MAAMC,EAAE,GAAGP,kBAAkB,CAACM,UAAU,CAAC;EACzCD,CAAC,CAACG,MAAM,CAACD,EAAE,CAAC;EACZ,OAAOF,CAAC;AACV,CAAC;AAED,OAAO,MAAMI,SAAS,GAAIC,GAAW,IAAK;EACxC,OAAQA,GAAG,GAAG,GAAG,GAAIC,IAAI,CAACC,EAAE;AAC9B,CAAC"}
1
+ {"version":3,"names":["processTransform3d","isMatrix","obj","__typename__","processTransform","m","transforms","m3","concat","toDegrees","rad","Math","PI"],"sources":["Matrix.ts"],"sourcesContent":["import type { SkJSIInstance } from \"./JsiInstance\";\nimport type { SkCanvas } from \"./Canvas\";\nimport type { Matrix3, Matrix4, Transforms3d } from \"./Matrix4\";\nimport { processTransform3d } from \"./Matrix4\";\n\nexport const isMatrix = (obj: unknown): obj is SkMatrix =>\n obj !== null && (obj as SkJSIInstance<string>).__typename__ === \"Matrix\";\n\nexport interface SkMatrix extends SkJSIInstance<\"Matrix\"> {\n concat: (matrix: InputMatrix) => SkMatrix;\n translate: (x: number, y: number) => SkMatrix;\n scale: (x: number, y?: number) => SkMatrix;\n skew: (x: number, y: number) => SkMatrix;\n rotate: (theta: number) => SkMatrix;\n postTranslate: (x: number, y: number) => SkMatrix;\n postScale: (x: number, y?: number) => SkMatrix;\n postSkew: (x: number, y: number) => SkMatrix;\n postRotate: (theta: number) => SkMatrix;\n identity: () => SkMatrix;\n get: () => number[];\n}\n\nexport type InputMatrix = SkMatrix | Matrix3 | Matrix4 | number[];\n\nexport interface TransformProp {\n transform?: Transforms3d;\n}\n\nexport const processTransform = <T extends SkMatrix | SkCanvas>(\n m: T,\n transforms: Transforms3d\n) => {\n \"worklet\";\n const m3 = processTransform3d(transforms);\n m.concat(m3);\n return m;\n};\n\nexport const toDegrees = (rad: number) => {\n return (rad * 180) / Math.PI;\n};\n"],"mappings":"AAGA,SAASA,kBAAkB,QAAQ,WAAW;AAE9C,OAAO,MAAMC,QAAQ,GAAIC,GAAY,IACnCA,GAAG,KAAK,IAAI,IAAKA,GAAG,CAA2BC,YAAY,KAAK,QAAQ;AAsB1E,OAAO,MAAMC,gBAAgB,GAAGA,CAC9BC,CAAI,EACJC,UAAwB,KACrB;EACH,SAAS;;EACT,MAAMC,EAAE,GAAGP,kBAAkB,CAACM,UAAU,CAAC;EACzCD,CAAC,CAACG,MAAM,CAACD,EAAE,CAAC;EACZ,OAAOF,CAAC;AACV,CAAC;AAED,OAAO,MAAMI,SAAS,GAAIC,GAAW,IAAK;EACxC,OAAQA,GAAG,GAAG,GAAG,GAAIC,IAAI,CAACC,EAAE;AAC9B,CAAC"}
@@ -1,9 +1,17 @@
1
1
  import type { SkImage } from "../Image";
2
2
  import type { SkJSIInstance } from "../JsiInstance";
3
+ export type VideoRotation = 0 | 90 | 180 | 270;
3
4
  export interface Video extends SkJSIInstance<"Video"> {
4
5
  duration(): number;
5
6
  framerate(): number;
6
7
  nextImage(): SkImage | null;
7
8
  seek(time: number): void;
8
- getRotationInDegrees(): number;
9
+ rotation(): VideoRotation;
10
+ size(): {
11
+ width: number;
12
+ height: number;
13
+ };
14
+ pause(): void;
15
+ play(): void;
16
+ setVolume(volume: number): void;
9
17
  }
@@ -1 +1 @@
1
- {"version":3,"names":[],"sources":["Video.ts"],"sourcesContent":["import type { SkImage } from \"../Image\";\nimport type { SkJSIInstance } from \"../JsiInstance\";\n\nexport interface Video extends SkJSIInstance<\"Video\"> {\n duration(): number;\n framerate(): number;\n nextImage(): SkImage | null;\n seek(time: number): void;\n getRotationInDegrees(): number;\n}\n"],"mappings":""}
1
+ {"version":3,"names":[],"sources":["Video.ts"],"sourcesContent":["import type { SkImage } from \"../Image\";\nimport type { SkJSIInstance } from \"../JsiInstance\";\n\nexport type VideoRotation = 0 | 90 | 180 | 270;\n\nexport interface Video extends SkJSIInstance<\"Video\"> {\n duration(): number;\n framerate(): number;\n nextImage(): SkImage | null;\n seek(time: number): void;\n rotation(): VideoRotation;\n size(): { width: number; height: number };\n pause(): void;\n play(): void;\n setVolume(volume: number): void;\n}\n"],"mappings":""}
@@ -1,9 +1,21 @@
1
+ import type { SharedValue } from "react-native-reanimated";
1
2
  import type { SkImage } from "../../skia/types";
2
- import { type PlaybackOptions } from "./video";
3
+ type Animated<T> = SharedValue<T> | T;
4
+ interface PlaybackOptions {
5
+ looping: Animated<boolean>;
6
+ paused: Animated<boolean>;
7
+ seek: Animated<number | null>;
8
+ volume: Animated<number>;
9
+ }
3
10
  export declare const useVideo: (source: string | null, userOptions?: Partial<PlaybackOptions>) => {
4
- currentFrame: import("react-native-reanimated").SharedValue<SkImage | null>;
5
- currentTime: import("react-native-reanimated").SharedValue<number>;
11
+ currentFrame: SharedValue<SkImage | null>;
12
+ currentTime: SharedValue<number>;
6
13
  duration: number;
7
14
  framerate: number;
8
- rotationInDegrees: number;
15
+ rotation: import("../../skia/types").VideoRotation;
16
+ size: {
17
+ width: number;
18
+ height: number;
19
+ };
9
20
  };
21
+ export {};
@@ -1,21 +1,13 @@
1
1
  import type { ReactNode } from "react";
2
2
  import React from "react";
3
3
  import type { Fit } from "../../../dom/nodes";
4
- import type { SkRect } from "../../../skia/types";
4
+ import type { SkRect, Transforms3d } from "../../../skia/types";
5
5
  interface FitProps {
6
6
  fit?: Fit;
7
7
  src: SkRect;
8
8
  dst: SkRect;
9
9
  children: ReactNode | ReactNode[];
10
10
  }
11
- export declare const fitbox: (fit: Fit, src: SkRect, dst: SkRect) => [{
12
- translateX: number;
13
- }, {
14
- translateY: number;
15
- }, {
16
- scaleX: number;
17
- }, {
18
- scaleY: number;
19
- }];
11
+ export declare const fitbox: (fit: Fit, src: SkRect, dst: SkRect, rotation?: 0 | 90 | 180 | 270) => Transforms3d;
20
12
  export declare const FitBox: ({ fit, src, dst, children }: FitProps) => React.JSX.Element;
21
13
  export {};
@@ -1,9 +1,17 @@
1
1
  import type { SkImage } from "../Image";
2
2
  import type { SkJSIInstance } from "../JsiInstance";
3
+ export type VideoRotation = 0 | 90 | 180 | 270;
3
4
  export interface Video extends SkJSIInstance<"Video"> {
4
5
  duration(): number;
5
6
  framerate(): number;
6
7
  nextImage(): SkImage | null;
7
8
  seek(time: number): void;
8
- getRotationInDegrees(): number;
9
+ rotation(): VideoRotation;
10
+ size(): {
11
+ width: number;
12
+ height: number;
13
+ };
14
+ pause(): void;
15
+ play(): void;
16
+ setVolume(volume: number): void;
9
17
  }
package/package.json CHANGED
@@ -7,7 +7,7 @@
7
7
  "setup-skia-web": "./scripts/setup-canvaskit.js"
8
8
  },
9
9
  "title": "React Native Skia",
10
- "version": "1.3.2",
10
+ "version": "1.3.3",
11
11
  "description": "High-performance React Native Graphics using Skia",
12
12
  "main": "lib/module/index.js",
13
13
  "react-native": "src/index.ts",
@@ -7,7 +7,10 @@ export interface Size {
7
7
  height: number;
8
8
  }
9
9
 
10
- export const size = (width = 0, height = 0) => ({ width, height });
10
+ export const size = (width = 0, height = 0) => {
11
+ "worklet";
12
+ return { width, height };
13
+ };
11
14
 
12
15
  export const rect2rect = (
13
16
  src: SkRect,
@@ -18,6 +21,7 @@ export const rect2rect = (
18
21
  { scaleX: number },
19
22
  { scaleY: number }
20
23
  ] => {
24
+ "worklet";
21
25
  const scaleX = dst.width / src.width;
22
26
  const scaleY = dst.height / src.height;
23
27
  const translateX = dst.x - src.x * scaleX;
@@ -25,30 +29,11 @@ export const rect2rect = (
25
29
  return [{ translateX }, { translateY }, { scaleX }, { scaleY }];
26
30
  };
27
31
 
28
- export const fitRects = (
29
- fit: Fit,
30
- rect: SkRect,
31
- { x, y, width, height }: SkRect
32
- ) => {
33
- const sizes = applyBoxFit(
34
- fit,
35
- { width: rect.width, height: rect.height },
36
- { width, height }
37
- );
38
- const src = inscribe(sizes.src, rect);
39
- const dst = inscribe(sizes.dst, {
40
- x,
41
- y,
42
- width,
43
- height,
44
- });
45
- return { src, dst };
46
- };
47
-
48
32
  const inscribe = (
49
33
  { width, height }: Size,
50
34
  rect: { x: number; y: number; width: number; height: number }
51
35
  ) => {
36
+ "worklet";
52
37
  const halfWidthDelta = (rect.width - width) / 2.0;
53
38
  const halfHeightDelta = (rect.height - height) / 2.0;
54
39
  return {
@@ -60,6 +45,7 @@ const inscribe = (
60
45
  };
61
46
 
62
47
  const applyBoxFit = (fit: Fit, input: Size, output: Size) => {
48
+ "worklet";
63
49
  let src = size(),
64
50
  dst = size();
65
51
  if (
@@ -122,3 +108,24 @@ const applyBoxFit = (fit: Fit, input: Size, output: Size) => {
122
108
  }
123
109
  return { src, dst };
124
110
  };
111
+
112
+ export const fitRects = (
113
+ fit: Fit,
114
+ rect: SkRect,
115
+ { x, y, width, height }: SkRect
116
+ ) => {
117
+ "worklet";
118
+ const sizes = applyBoxFit(
119
+ fit,
120
+ { width: rect.width, height: rect.height },
121
+ { width, height }
122
+ );
123
+ const src = inscribe(sizes.src, rect);
124
+ const dst = inscribe(sizes.dst, {
125
+ x,
126
+ y,
127
+ width,
128
+ height,
129
+ });
130
+ return { src, dst };
131
+ };
@@ -1,22 +1,42 @@
1
- import { type FrameInfo } from "react-native-reanimated";
1
+ import type { SharedValue, FrameInfo } from "react-native-reanimated";
2
2
  import { useEffect, useMemo } from "react";
3
3
 
4
4
  import { Skia } from "../../skia/Skia";
5
5
  import type { SkImage, Video } from "../../skia/types";
6
+ import { Platform } from "../../Platform";
6
7
 
7
8
  import Rea from "./ReanimatedProxy";
8
- import {
9
- processVideoState,
10
- type Animated,
11
- type PlaybackOptions,
12
- } from "./video";
9
+
10
+ type Animated<T> = SharedValue<T> | T;
11
+
12
+ interface PlaybackOptions {
13
+ looping: Animated<boolean>;
14
+ paused: Animated<boolean>;
15
+ seek: Animated<number | null>;
16
+ volume: Animated<number>;
17
+ }
18
+
19
+ const setFrame = (video: Video, currentFrame: SharedValue<SkImage | null>) => {
20
+ "worklet";
21
+ const img = video.nextImage();
22
+ if (img) {
23
+ if (currentFrame.value) {
24
+ currentFrame.value.dispose();
25
+ }
26
+ if (Platform.OS === "android") {
27
+ currentFrame.value = img.makeNonTextureImage();
28
+ } else {
29
+ currentFrame.value = img;
30
+ }
31
+ }
32
+ };
13
33
 
14
34
  const defaultOptions = {
15
- playbackSpeed: 1,
16
35
  looping: true,
17
36
  paused: false,
18
37
  seek: null,
19
38
  currentTime: 0,
39
+ volume: 0,
20
40
  };
21
41
 
22
42
  const useOption = <T>(value: Animated<T>) => {
@@ -41,34 +61,68 @@ export const useVideo = (
41
61
  const isPaused = useOption(userOptions?.paused ?? defaultOptions.paused);
42
62
  const looping = useOption(userOptions?.looping ?? defaultOptions.looping);
43
63
  const seek = useOption(userOptions?.seek ?? defaultOptions.seek);
44
- const playbackSpeed = useOption(
45
- userOptions?.playbackSpeed ?? defaultOptions.playbackSpeed
46
- );
64
+ const volume = useOption(userOptions?.volume ?? defaultOptions.volume);
47
65
  const currentFrame = Rea.useSharedValue<null | SkImage>(null);
48
66
  const currentTime = Rea.useSharedValue(0);
49
67
  const lastTimestamp = Rea.useSharedValue(-1);
50
68
  const duration = useMemo(() => video?.duration() ?? 0, [video]);
51
69
  const framerate = useMemo(() => video?.framerate() ?? 0, [video]);
52
- const rotationInDegrees = useMemo(
53
- () => video?.getRotationInDegrees() ?? 0,
54
- [video]
70
+ const size = useMemo(() => video?.size() ?? { width: 0, height: 0 }, [video]);
71
+ const rotation = useMemo(() => video?.rotation() ?? 0, [video]);
72
+ const frameDuration = 1000 / framerate;
73
+ const currentFrameDuration = Math.floor(frameDuration);
74
+ Rea.useAnimatedReaction(
75
+ () => isPaused.value,
76
+ (paused) => {
77
+ if (paused) {
78
+ video?.pause();
79
+ } else {
80
+ lastTimestamp.value = -1;
81
+ video?.play();
82
+ }
83
+ }
84
+ );
85
+ Rea.useAnimatedReaction(
86
+ () => seek.value,
87
+ (value) => {
88
+ if (value !== null) {
89
+ video?.seek(value);
90
+ currentTime.value = value;
91
+ seek.value = null;
92
+ }
93
+ }
94
+ );
95
+ Rea.useAnimatedReaction(
96
+ () => volume.value,
97
+ (value) => {
98
+ video?.setVolume(value);
99
+ }
55
100
  );
56
101
  Rea.useFrameCallback((frameInfo: FrameInfo) => {
57
- processVideoState(
58
- video,
59
- duration,
60
- framerate,
61
- frameInfo.timestamp,
62
- {
63
- paused: isPaused.value,
64
- looping: looping.value,
65
- playbackSpeed: playbackSpeed.value,
66
- },
67
- currentTime,
68
- currentFrame,
69
- lastTimestamp,
70
- seek
71
- );
102
+ "worklet";
103
+ if (!video) {
104
+ return;
105
+ }
106
+ if (isPaused.value) {
107
+ return;
108
+ }
109
+ const currentTimestamp = frameInfo.timestamp;
110
+ if (lastTimestamp.value === -1) {
111
+ lastTimestamp.value = currentTimestamp;
112
+ }
113
+ const delta = currentTimestamp - lastTimestamp.value;
114
+
115
+ const isOver = currentTime.value + delta > duration;
116
+ if (isOver && looping.value) {
117
+ seek.value = 0;
118
+ currentTime.value = seek.value;
119
+ lastTimestamp.value = currentTimestamp;
120
+ }
121
+ if (delta >= currentFrameDuration && !isOver) {
122
+ setFrame(video, currentFrame);
123
+ currentTime.value += delta;
124
+ lastTimestamp.value = currentTimestamp;
125
+ }
72
126
  });
73
127
 
74
128
  useEffect(() => {
@@ -78,5 +132,12 @@ export const useVideo = (
78
132
  };
79
133
  }, [video]);
80
134
 
81
- return { currentFrame, currentTime, duration, framerate, rotationInDegrees };
135
+ return {
136
+ currentFrame,
137
+ currentTime,
138
+ duration,
139
+ framerate,
140
+ rotation,
141
+ size,
142
+ };
82
143
  };