@shopify/react-native-skia 1.3.2 → 1.3.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
};
|