@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.
- package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp +59 -1
- package/android/cpp/rnskia-android/RNSkAndroidVideo.h +4 -0
- package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java +80 -7
- package/cpp/api/JsiVideo.h +32 -7
- package/cpp/rnskia/RNSkVideo.h +4 -0
- package/ios/RNSkia-iOS/RNSkiOSVideo.h +13 -4
- package/ios/RNSkia-iOS/RNSkiOSVideo.mm +65 -67
- package/lib/commonjs/dom/nodes/datatypes/Fitting.js +42 -30
- package/lib/commonjs/dom/nodes/datatypes/Fitting.js.map +1 -1
- package/lib/commonjs/external/reanimated/useVideo.d.ts +16 -4
- package/lib/commonjs/external/reanimated/useVideo.js +76 -14
- package/lib/commonjs/external/reanimated/useVideo.js.map +1 -1
- package/lib/commonjs/renderer/components/shapes/FitBox.d.ts +2 -10
- package/lib/commonjs/renderer/components/shapes/FitBox.js +32 -3
- package/lib/commonjs/renderer/components/shapes/FitBox.js.map +1 -1
- package/lib/commonjs/skia/core/Matrix.js +5 -1
- package/lib/commonjs/skia/core/Matrix.js.map +1 -1
- package/lib/commonjs/skia/types/Matrix.js +2 -0
- package/lib/commonjs/skia/types/Matrix.js.map +1 -1
- package/lib/commonjs/skia/types/Video/Video.d.ts +9 -1
- package/lib/commonjs/skia/types/Video/Video.js.map +1 -1
- package/lib/module/dom/nodes/datatypes/Fitting.js +41 -29
- package/lib/module/dom/nodes/datatypes/Fitting.js.map +1 -1
- package/lib/module/external/reanimated/useVideo.d.ts +16 -4
- package/lib/module/external/reanimated/useVideo.js +76 -14
- package/lib/module/external/reanimated/useVideo.js.map +1 -1
- package/lib/module/renderer/components/shapes/FitBox.d.ts +2 -10
- package/lib/module/renderer/components/shapes/FitBox.js +32 -3
- package/lib/module/renderer/components/shapes/FitBox.js.map +1 -1
- package/lib/module/skia/core/Matrix.js +5 -1
- package/lib/module/skia/core/Matrix.js.map +1 -1
- package/lib/module/skia/types/Matrix.js +2 -0
- package/lib/module/skia/types/Matrix.js.map +1 -1
- package/lib/module/skia/types/Video/Video.d.ts +9 -1
- package/lib/module/skia/types/Video/Video.js.map +1 -1
- package/lib/typescript/src/external/reanimated/useVideo.d.ts +16 -4
- package/lib/typescript/src/renderer/components/shapes/FitBox.d.ts +2 -10
- package/lib/typescript/src/skia/types/Video/Video.d.ts +9 -1
- package/package.json +1 -1
- package/src/dom/nodes/datatypes/Fitting.ts +28 -21
- package/src/external/reanimated/useVideo.ts +90 -29
- package/src/renderer/components/shapes/FitBox.tsx +38 -4
- package/src/skia/core/Matrix.ts +4 -2
- package/src/skia/types/Matrix.ts +1 -0
- package/src/skia/types/Video/Video.ts +7 -1
- package/lib/commonjs/external/reanimated/video.d.ts +0 -16
- package/lib/commonjs/external/reanimated/video.js +0 -54
- package/lib/commonjs/external/reanimated/video.js.map +0 -1
- package/lib/module/external/reanimated/video.d.ts +0 -16
- package/lib/module/external/reanimated/video.js +0 -46
- package/lib/module/external/reanimated/video.js.map +0 -1
- package/lib/typescript/src/external/reanimated/video.d.ts +0 -16
- 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
|
-
|
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$
|
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
|
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
|
43
|
-
var _video$
|
44
|
-
return (_video$
|
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
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
}
|
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
|
-
|
125
|
+
rotation,
|
126
|
+
size
|
65
127
|
};
|
66
128
|
};
|
67
129
|
//# sourceMappingURL=useVideo.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"names":["useEffect","useMemo","Skia","Rea","
|
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
|
-
|
6
|
-
|
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
|
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 =>
|
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)
|
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
|
-
|
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
|
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
|
-
|
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:
|
5
|
-
currentTime:
|
11
|
+
currentFrame: SharedValue<SkImage | null>;
|
12
|
+
currentTime: SharedValue<number>;
|
6
13
|
duration: number;
|
7
14
|
framerate: number;
|
8
|
-
|
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
|
-
|
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.
|
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) =>
|
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 {
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
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
|
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
|
53
|
-
|
54
|
-
|
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
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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 {
|
135
|
+
return {
|
136
|
+
currentFrame,
|
137
|
+
currentTime,
|
138
|
+
duration,
|
139
|
+
framerate,
|
140
|
+
rotation,
|
141
|
+
size,
|
142
|
+
};
|
82
143
|
};
|