@shopify/react-native-skia 1.2.2 → 1.3.0
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/CMakeLists.txt +1 -0
- package/android/cpp/jni/JniPlatformContext.cpp +23 -0
- package/android/cpp/jni/include/JniPlatformContext.h +2 -0
- package/android/cpp/rnskia-android/RNSkAndroidPlatformContext.h +6 -0
- package/android/cpp/rnskia-android/RNSkAndroidVideo.cpp +92 -0
- package/android/cpp/rnskia-android/RNSkAndroidVideo.h +36 -0
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +34 -14
- package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +2 -1
- package/android/src/main/java/com/shopify/reactnative/skia/PlatformContext.java +5 -0
- package/android/src/main/java/com/shopify/reactnative/skia/RNSkVideo.java +185 -0
- package/cpp/api/JsiSkApi.h +2 -0
- package/cpp/api/JsiSkImageFactory.h +3 -3
- package/cpp/api/JsiVideo.h +87 -0
- package/cpp/rnskia/RNSkPlatformContext.h +4 -1
- package/cpp/rnskia/RNSkVideo.h +23 -0
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.h +2 -0
- package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +7 -1
- package/ios/RNSkia-iOS/RNSkiOSVideo.h +40 -0
- package/ios/RNSkia-iOS/RNSkiOSVideo.mm +119 -0
- package/ios/RNSkia-iOS/RNSkiOSView.mm +37 -0
- package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +2 -2
- package/lib/commonjs/external/reanimated/index.d.ts +1 -0
- package/lib/commonjs/external/reanimated/index.js +11 -0
- package/lib/commonjs/external/reanimated/index.js.map +1 -1
- package/lib/commonjs/external/reanimated/useVideo.d.ts +10 -0
- package/lib/commonjs/external/reanimated/useVideo.js +93 -0
- package/lib/commonjs/external/reanimated/useVideo.js.map +1 -0
- package/lib/commonjs/mock/index.js +2 -1
- package/lib/commonjs/mock/index.js.map +1 -1
- package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +3 -3
- package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +2 -2
- package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
- package/lib/commonjs/skia/types/Skia.d.ts +2 -0
- package/lib/commonjs/skia/types/Skia.js.map +1 -1
- package/lib/commonjs/skia/types/Video/Video.d.ts +8 -0
- package/lib/commonjs/skia/types/Video/Video.js +6 -0
- package/lib/commonjs/skia/types/Video/Video.js.map +1 -0
- package/lib/commonjs/skia/types/Video/index.d.ts +1 -0
- package/lib/commonjs/skia/types/Video/index.js +17 -0
- package/lib/commonjs/skia/types/Video/index.js.map +1 -0
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -1
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +1 -1
- package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
- package/lib/commonjs/skia/web/JsiSkia.js +4 -1
- package/lib/commonjs/skia/web/JsiSkia.js.map +1 -1
- package/lib/module/external/reanimated/index.d.ts +1 -0
- package/lib/module/external/reanimated/index.js +1 -0
- package/lib/module/external/reanimated/index.js.map +1 -1
- package/lib/module/external/reanimated/useVideo.d.ts +10 -0
- package/lib/module/external/reanimated/useVideo.js +85 -0
- package/lib/module/external/reanimated/useVideo.js.map +1 -0
- package/lib/module/mock/index.js +2 -1
- package/lib/module/mock/index.js.map +1 -1
- package/lib/module/skia/types/Image/ImageFactory.d.ts +3 -3
- package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +2 -2
- package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
- package/lib/module/skia/types/Skia.d.ts +2 -0
- package/lib/module/skia/types/Skia.js.map +1 -1
- package/lib/module/skia/types/Video/Video.d.ts +8 -0
- package/lib/module/skia/types/Video/Video.js +2 -0
- package/lib/module/skia/types/Video/Video.js.map +1 -0
- package/lib/module/skia/types/Video/index.d.ts +1 -0
- package/lib/module/skia/types/Video/index.js +2 -0
- package/lib/module/skia/types/Video/index.js.map +1 -0
- package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -1
- package/lib/module/skia/web/JsiSkNativeBufferFactory.js +1 -1
- package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
- package/lib/module/skia/web/JsiSkia.js +4 -1
- package/lib/module/skia/web/JsiSkia.js.map +1 -1
- package/lib/typescript/src/external/reanimated/index.d.ts +1 -0
- package/lib/typescript/src/external/reanimated/useVideo.d.ts +10 -0
- package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +3 -3
- package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +2 -2
- package/lib/typescript/src/skia/types/Skia.d.ts +2 -0
- package/lib/typescript/src/skia/types/Video/Video.d.ts +8 -0
- package/lib/typescript/src/skia/types/Video/index.d.ts +1 -0
- package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +1 -1
- package/package.json +1 -1
- package/scripts/setup-canvaskit.js +1 -1
- package/src/external/reanimated/index.ts +1 -0
- package/src/external/reanimated/useVideo.ts +115 -0
- package/src/mock/index.ts +1 -0
- package/src/skia/types/Image/ImageFactory.ts +3 -3
- package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +2 -2
- package/src/skia/types/Skia.ts +2 -0
- package/src/skia/types/Video/Video.ts +9 -0
- package/src/skia/types/Video/index.ts +1 -0
- package/src/skia/web/JsiSkNativeBufferFactory.ts +1 -1
- package/src/skia/web/JsiSkia.ts +3 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import {
|
|
2
|
+
runOnUI,
|
|
3
|
+
useSharedValue,
|
|
4
|
+
type FrameInfo,
|
|
5
|
+
type SharedValue,
|
|
6
|
+
} from "react-native-reanimated";
|
|
7
|
+
import { useCallback, useEffect, useMemo } from "react";
|
|
8
|
+
|
|
9
|
+
import { Skia } from "../../skia/Skia";
|
|
10
|
+
import type { SkImage } from "../../skia/types";
|
|
11
|
+
import { Platform } from "../../Platform";
|
|
12
|
+
|
|
13
|
+
import Rea from "./ReanimatedProxy";
|
|
14
|
+
|
|
15
|
+
type Animated<T> = SharedValue<T> | T;
|
|
16
|
+
|
|
17
|
+
export interface PlaybackOptions {
|
|
18
|
+
playbackSpeed: Animated<number>;
|
|
19
|
+
looping: Animated<boolean>;
|
|
20
|
+
paused: Animated<boolean>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const defaultOptions = {
|
|
24
|
+
playbackSpeed: 1,
|
|
25
|
+
looping: true,
|
|
26
|
+
paused: false,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const useOption = <T>(value: Animated<T>) => {
|
|
30
|
+
"worklet";
|
|
31
|
+
// TODO: only create defaultValue is needed (via makeMutable)
|
|
32
|
+
const defaultValue = useSharedValue(
|
|
33
|
+
Rea.isSharedValue(value) ? value.value : value
|
|
34
|
+
);
|
|
35
|
+
return Rea.isSharedValue(value) ? value : defaultValue;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const useVideo = (
|
|
39
|
+
source: string | null,
|
|
40
|
+
userOptions?: Partial<PlaybackOptions>
|
|
41
|
+
) => {
|
|
42
|
+
const video = useMemo(() => (source ? Skia.Video(source) : null), [source]);
|
|
43
|
+
const isPaused = useOption(userOptions?.paused ?? defaultOptions.paused);
|
|
44
|
+
const looping = useOption(userOptions?.looping ?? defaultOptions.looping);
|
|
45
|
+
const playbackSpeed = useOption(
|
|
46
|
+
userOptions?.playbackSpeed ?? defaultOptions.playbackSpeed
|
|
47
|
+
);
|
|
48
|
+
const currentFrame = Rea.useSharedValue<null | SkImage>(null);
|
|
49
|
+
const lastTimestamp = Rea.useSharedValue(-1);
|
|
50
|
+
const startTimestamp = Rea.useSharedValue(-1);
|
|
51
|
+
|
|
52
|
+
const framerate = useMemo(() => (video ? video.framerate() : -1), [video]);
|
|
53
|
+
const duration = useMemo(() => (video ? video.duration() : -1), [video]);
|
|
54
|
+
const frameDuration = useMemo(
|
|
55
|
+
() => (framerate > 0 ? 1000 / framerate : -1),
|
|
56
|
+
[framerate]
|
|
57
|
+
);
|
|
58
|
+
const disposeVideo = useCallback(() => {
|
|
59
|
+
"worklet";
|
|
60
|
+
video?.dispose();
|
|
61
|
+
}, [video]);
|
|
62
|
+
|
|
63
|
+
Rea.useFrameCallback((frameInfo: FrameInfo) => {
|
|
64
|
+
if (!video) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (isPaused.value && lastTimestamp.value !== -1) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const { timestamp } = frameInfo;
|
|
71
|
+
|
|
72
|
+
// Initialize start timestamp
|
|
73
|
+
if (startTimestamp.value === -1) {
|
|
74
|
+
startTimestamp.value = timestamp;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Calculate the current time in the video
|
|
78
|
+
const currentTimestamp = timestamp - startTimestamp.value;
|
|
79
|
+
|
|
80
|
+
// Handle looping
|
|
81
|
+
if (currentTimestamp > duration && looping.value) {
|
|
82
|
+
video.seek(0);
|
|
83
|
+
startTimestamp.value = timestamp;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Update frame only if the elapsed time since last update is greater than the frame duration
|
|
87
|
+
const currentFrameDuration = frameDuration / playbackSpeed.value;
|
|
88
|
+
if (
|
|
89
|
+
lastTimestamp.value === -1 ||
|
|
90
|
+
timestamp - lastTimestamp.value >= currentFrameDuration
|
|
91
|
+
) {
|
|
92
|
+
const img = video.nextImage();
|
|
93
|
+
if (img) {
|
|
94
|
+
if (currentFrame.value) {
|
|
95
|
+
currentFrame.value.dispose();
|
|
96
|
+
}
|
|
97
|
+
if (Platform.OS === "android") {
|
|
98
|
+
currentFrame.value = img.makeNonTextureImage();
|
|
99
|
+
} else {
|
|
100
|
+
currentFrame.value = img;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
lastTimestamp.value = timestamp;
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
useEffect(() => {
|
|
108
|
+
return () => {
|
|
109
|
+
// TODO: should video simply be a shared value instead?
|
|
110
|
+
runOnUI(disposeVideo)();
|
|
111
|
+
};
|
|
112
|
+
}, [disposeVideo, video]);
|
|
113
|
+
|
|
114
|
+
return currentFrame;
|
|
115
|
+
};
|
package/src/mock/index.ts
CHANGED
|
@@ -54,7 +54,7 @@ export interface ImageFactory {
|
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Return an Image backed by a given native buffer.
|
|
57
|
-
* The
|
|
57
|
+
* The native buffer must be a valid owning reference.
|
|
58
58
|
*
|
|
59
59
|
* For instance, this API is used by
|
|
60
60
|
* [react-native-vision-camera](https://github.com/mrousavy/react-native-vision-camera)
|
|
@@ -62,9 +62,9 @@ export interface ImageFactory {
|
|
|
62
62
|
*
|
|
63
63
|
* - On Android; This is an `AHardwareBuffer*`
|
|
64
64
|
* - On iOS, this is a `CVPixelBufferRef`
|
|
65
|
-
* @param nativeBuffer A strong `uintptr_t` pointer to the native
|
|
65
|
+
* @param nativeBuffer A strong `uintptr_t` pointer to the native buffer
|
|
66
66
|
* @throws Throws an error if the Image could not be created, for example when the given
|
|
67
|
-
*
|
|
67
|
+
* native buffer is invalid.
|
|
68
68
|
*/
|
|
69
69
|
MakeImageFromNativeBuffer: (nativeBuffer: NativeBuffer) => SkImage;
|
|
70
70
|
|
|
@@ -32,7 +32,7 @@ export interface NativeBufferFactory {
|
|
|
32
32
|
*/
|
|
33
33
|
MakeFromImage: (image: SkImage) => NativeBuffer;
|
|
34
34
|
/**
|
|
35
|
-
* Release a
|
|
35
|
+
* Release a native buffer that was created with `MakeFromImage`.
|
|
36
36
|
*/
|
|
37
|
-
Release: (
|
|
37
|
+
Release: (nativeBuffer: NativeBuffer) => void;
|
|
38
38
|
}
|
package/src/skia/types/Skia.ts
CHANGED
|
@@ -30,6 +30,7 @@ import type { Color, SkColor } from "./Color";
|
|
|
30
30
|
import type { TypefaceFontProviderFactory } from "./Paragraph/TypefaceFontProviderFactory";
|
|
31
31
|
import type { AnimatedImageFactory } from "./AnimatedImage";
|
|
32
32
|
import type { ParagraphBuilderFactory } from "./Paragraph/ParagraphBuilder";
|
|
33
|
+
import type { Video } from "./Video";
|
|
33
34
|
import type { NativeBufferFactory } from "./NativeBuffer";
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -95,5 +96,6 @@ export interface Skia {
|
|
|
95
96
|
TextBlob: TextBlobFactory;
|
|
96
97
|
Surface: SurfaceFactory;
|
|
97
98
|
ParagraphBuilder: ParagraphBuilderFactory;
|
|
99
|
+
Video: (url: string) => Video;
|
|
98
100
|
NativeBuffer: NativeBufferFactory;
|
|
99
101
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./Video";
|
package/src/skia/web/JsiSkia.ts
CHANGED
|
@@ -127,4 +127,7 @@ export const JsiSkApi = (CanvasKit: CanvasKit): Skia => ({
|
|
|
127
127
|
FontMgr: new JsiSkFontMgrFactory(CanvasKit),
|
|
128
128
|
ParagraphBuilder: new JsiSkParagraphBuilderFactory(CanvasKit),
|
|
129
129
|
NativeBuffer: new JsiSkNativeBufferFactory(CanvasKit),
|
|
130
|
+
Video: (_localUri: string) => {
|
|
131
|
+
throw new Error("Not implemented on React Native Web");
|
|
132
|
+
},
|
|
130
133
|
});
|