react-native-webgpu 0.11.0 → 0.11.1
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/AndroidPlatformContext.h +42 -8
- package/android/cpp/AndroidVideoPlayer.h +307 -0
- package/android/src/main/java/com/webgpu/WebGPUModule.java +10 -0
- package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +420 -0
- package/apple/AppleVideoPlayer.mm +157 -47
- package/cpp/rnwgpu/PlatformContext.h +25 -5
- package/cpp/rnwgpu/api/GPUDevice.cpp +2 -1
- package/cpp/rnwgpu/api/GPUDevice.h +6 -0
- package/cpp/rnwgpu/api/GPUQueue.cpp +80 -10
- package/cpp/rnwgpu/api/GPUQueue.h +15 -4
- package/cpp/rnwgpu/api/VideoFrameBlit.h +355 -0
- package/cpp/rnwgpu/api/VideoPlayer.h +50 -3
- package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +30 -3
- package/lib/commonjs/importDevice.js +2 -2
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/main/index.js +12 -0
- package/lib/commonjs/main/index.js.map +1 -1
- package/lib/commonjs/main/index.web.js +11 -0
- package/lib/commonjs/main/index.web.js.map +1 -1
- package/lib/commonjs/video.js +58 -0
- package/lib/commonjs/video.js.map +1 -0
- package/lib/module/importDevice.js +2 -2
- package/lib/module/index.js.map +1 -1
- package/lib/module/main/index.js +1 -0
- package/lib/module/main/index.js.map +1 -1
- package/lib/module/main/index.web.js +1 -0
- package/lib/module/main/index.web.js.map +1 -1
- package/lib/module/video.js +49 -0
- package/lib/module/video.js.map +1 -0
- package/lib/typescript/lib/commonjs/video.d.ts +30 -0
- package/lib/typescript/lib/commonjs/video.d.ts.map +1 -0
- package/lib/typescript/lib/module/main/index.d.ts +1 -0
- package/lib/typescript/lib/module/main/index.web.d.ts +1 -0
- package/lib/typescript/lib/module/video.d.ts +4 -0
- package/lib/typescript/lib/module/video.d.ts.map +1 -0
- package/lib/typescript/src/importDevice.d.ts +2 -2
- package/lib/typescript/src/index.d.ts +5 -3
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/main/index.d.ts +1 -0
- package/lib/typescript/src/main/index.d.ts.map +1 -1
- package/lib/typescript/src/main/index.web.d.ts +1 -0
- package/lib/typescript/src/main/index.web.d.ts.map +1 -1
- package/lib/typescript/src/types.d.ts +19 -0
- package/lib/typescript/src/types.d.ts.map +1 -1
- package/lib/typescript/src/video.d.ts +41 -0
- package/lib/typescript/src/video.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/importDevice.ts +2 -2
- package/src/index.tsx +28 -3
- package/src/main/index.tsx +1 -0
- package/src/main/index.web.tsx +1 -0
- package/src/types.ts +60 -7
- package/src/video.ts +69 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { CreateVideoPlayerOptions, NativeVideoFrame, VideoPlayer } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Decodes a video into native frames the GPU samples without any copy.
|
|
4
|
+
*
|
|
5
|
+
* `source` is a URL (`http`, `https`, `file`) or a file path. Playback is
|
|
6
|
+
* controlled like an HTMLMediaElement (`play()`, `pause()`, `currentTime`,
|
|
7
|
+
* `loop`, `volume`); frames are pulled with `copyLatestFrame()` on every
|
|
8
|
+
* render tick and sampled through `importExternalTexture()` or
|
|
9
|
+
* `importSharedTextureMemory()`:
|
|
10
|
+
*
|
|
11
|
+
* ```ts
|
|
12
|
+
* const player = createVideoPlayer(url);
|
|
13
|
+
* player.play();
|
|
14
|
+
* const render = () => {
|
|
15
|
+
* const frame = player.copyLatestFrame();
|
|
16
|
+
* if (frame) {
|
|
17
|
+
* // import, draw, then release once the frame is no longer sampled
|
|
18
|
+
* }
|
|
19
|
+
* requestAnimationFrame(render);
|
|
20
|
+
* };
|
|
21
|
+
* ```
|
|
22
|
+
*
|
|
23
|
+
* On Apple platforms the frames are BGRA by default, or NV12 with
|
|
24
|
+
* `{ pixelFormat: "nv12" }`. On Android they are always in the decoder's
|
|
25
|
+
* native YUV layout, for `importExternalTexture()`.
|
|
26
|
+
*/
|
|
27
|
+
export declare const createVideoPlayer: (source: string, options?: CreateVideoPlayerOptions) => VideoPlayer;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps a native buffer produced by another library (a `CVPixelBufferRef` on
|
|
30
|
+
* Apple platforms, an `AHardwareBuffer*` on Android, for instance
|
|
31
|
+
* VisionCamera's `frame.getNativeBuffer().pointer`) into a `NativeVideoFrame`
|
|
32
|
+
* that keeps it alive until released.
|
|
33
|
+
*/
|
|
34
|
+
export declare const createVideoFrameFromNativeBuffer: (pointer: bigint) => NativeVideoFrame;
|
|
35
|
+
/**
|
|
36
|
+
* Allocates a native frame of the given size filled with a test pattern (a
|
|
37
|
+
* red/green gradient with diagonal stripes in the blue channel), for examples
|
|
38
|
+
* and tests that need a frame without a camera or a video.
|
|
39
|
+
*/
|
|
40
|
+
export declare const createTestVideoFrame: (width: number, height: number) => NativeVideoFrame;
|
|
41
|
+
//# sourceMappingURL=video.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"video.d.ts","sourceRoot":"","sources":["../../../src/video.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,gBAAgB,EAChB,WAAW,EACZ,MAAM,SAAS,CAAC;AAWjB;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,MAAM,EACd,UAAU,wBAAwB,KACjC,WAC0E,CAAC;AAE9E;;;;;GAKG;AACH,eAAO,MAAM,gCAAgC,GAC3C,SAAS,MAAM,KACd,gBAGA,CAAC;AAEJ;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,GAC/B,OAAO,MAAM,EACb,QAAQ,MAAM,KACb,gBACiE,CAAC"}
|
package/package.json
CHANGED
package/src/importDevice.ts
CHANGED
|
@@ -26,10 +26,10 @@ export const importDevice = (pointer: bigint): GPUDevice => {
|
|
|
26
26
|
* ownership of one reference: the returned texture releases it when destroyed.
|
|
27
27
|
*
|
|
28
28
|
* Pair with producers that hand out a +1 reference, such as
|
|
29
|
-
* `Skia.Image.
|
|
29
|
+
* `Skia.Image.MakeGPUTextureFromImage()`:
|
|
30
30
|
*
|
|
31
31
|
* ```ts
|
|
32
|
-
* const texture = adoptTexture(Skia.Image.
|
|
32
|
+
* const texture = adoptTexture(Skia.Image.MakeGPUTextureFromImage(image));
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
35
35
|
export const adoptTexture = (pointer: bigint): GPUTexture => {
|
package/src/index.tsx
CHANGED
|
@@ -5,8 +5,10 @@ import type {
|
|
|
5
5
|
GPUSharedFence,
|
|
6
6
|
GPUSharedFenceDescriptor,
|
|
7
7
|
GPUDawnTogglesDescriptor,
|
|
8
|
+
GPUNativeExternalTextureDescriptor,
|
|
8
9
|
GPUSharedTextureMemory,
|
|
9
10
|
GPUSharedTextureMemoryDescriptor,
|
|
11
|
+
GPUCopyExternalNativeFrameSourceInfo,
|
|
10
12
|
NativeCanvas,
|
|
11
13
|
RNCanvasContext,
|
|
12
14
|
VideoPlayer,
|
|
@@ -30,7 +32,9 @@ export type {
|
|
|
30
32
|
GPUSharedTextureMemoryEndAccessState,
|
|
31
33
|
NativeVideoPixelFormat,
|
|
32
34
|
CreateVideoPlayerOptions,
|
|
35
|
+
GPUCopyExternalNativeFrameSourceInfo,
|
|
33
36
|
GPUDawnTogglesDescriptor,
|
|
37
|
+
GPUNativeExternalTextureDescriptor,
|
|
34
38
|
GPUDrawElementImageDestination,
|
|
35
39
|
GPUDrawElementImageSource,
|
|
36
40
|
GPUDrawElementImageSourceView,
|
|
@@ -69,10 +73,11 @@ declare global {
|
|
|
69
73
|
importDevice: (pointer: bigint) => GPUDevice;
|
|
70
74
|
// Wrap an externally created WGPUTexture pointer into a GPUTexture,
|
|
71
75
|
// taking ownership of one reference (pair with producers that return a
|
|
72
|
-
// +1 pointer, e.g. Skia.Image.
|
|
76
|
+
// +1 pointer, e.g. Skia.Image.MakeGPUTextureFromImage()).
|
|
73
77
|
adoptTexture: (pointer: bigint) => GPUTexture;
|
|
78
|
+
// Prefer the createVideoPlayer() export, which takes an options object.
|
|
74
79
|
createVideoPlayer: (
|
|
75
|
-
|
|
80
|
+
source: string,
|
|
76
81
|
pixelFormat?: NativeVideoPixelFormat,
|
|
77
82
|
) => VideoPlayer;
|
|
78
83
|
writeTestVideoFile: () => string;
|
|
@@ -80,12 +85,20 @@ declare global {
|
|
|
80
85
|
|
|
81
86
|
interface GPUTexture {
|
|
82
87
|
// Non-spec RN extension: raw WGPUTexture handle as a BigInt for
|
|
83
|
-
// pointer-based interop (
|
|
88
|
+
// pointer-based interop (Skia.Image.MakeImageFromGPUTexture reads it).
|
|
84
89
|
// Borrowed: keep this GPUTexture alive while the pointer is in use.
|
|
85
90
|
readonly nativePointer: bigint;
|
|
86
91
|
}
|
|
87
92
|
|
|
88
93
|
interface GPUDevice {
|
|
94
|
+
// Non-spec RN extension: the source of an external texture is a
|
|
95
|
+
// NativeVideoFrame (from a VideoPlayer, createVideoFrameFromNativeBuffer
|
|
96
|
+
// or createTestVideoFrame) instead of the web's HTMLVideoElement /
|
|
97
|
+
// VideoFrame. Overloads the spec signature, which stays available for
|
|
98
|
+
// the web implementation.
|
|
99
|
+
importExternalTexture(
|
|
100
|
+
descriptor: GPUNativeExternalTextureDescriptor,
|
|
101
|
+
): GPUExternalTexture;
|
|
89
102
|
importSharedTextureMemory(
|
|
90
103
|
descriptor: GPUSharedTextureMemoryDescriptor,
|
|
91
104
|
): GPUSharedTextureMemory;
|
|
@@ -114,6 +127,18 @@ declare global {
|
|
|
114
127
|
source: GPUDrawElementImageSource,
|
|
115
128
|
destination: GPUDrawElementImageDestination,
|
|
116
129
|
): Promise<void>;
|
|
130
|
+
// Non-spec extension: a NativeVideoFrame (from createVideoPlayer,
|
|
131
|
+
// createVideoFrameFromNativeBuffer or createTestVideoFrame) as the copy
|
|
132
|
+
// source. The frame is rendered into the destination on the GPU through
|
|
133
|
+
// an external texture, which converts YUV to RGB and applies `rotation`
|
|
134
|
+
// and `mirrored`; the destination needs GPUTextureUsage.RENDER_ATTACHMENT
|
|
135
|
+
// and an rgba8unorm, bgra8unorm (or -srgb), rgba16float or rgb10a2unorm
|
|
136
|
+
// format. The frame can be released as soon as the call returns.
|
|
137
|
+
copyExternalImageToTexture(
|
|
138
|
+
source: GPUCopyExternalNativeFrameSourceInfo,
|
|
139
|
+
destination: GPUCopyExternalImageDestInfo,
|
|
140
|
+
copySize: GPUExtent3DStrict,
|
|
141
|
+
): undefined;
|
|
117
142
|
}
|
|
118
143
|
|
|
119
144
|
// Non-standard, Dawn-only. Lets callers set Dawn device-stage toggles at
|
package/src/main/index.tsx
CHANGED
|
@@ -56,6 +56,7 @@ export * from "../WebGPUViewNativeComponent";
|
|
|
56
56
|
export * from "../hooks";
|
|
57
57
|
export * from "../GPUDeviceProvider";
|
|
58
58
|
export * from "../importDevice";
|
|
59
|
+
export * from "../video";
|
|
59
60
|
export * from "../formats";
|
|
60
61
|
|
|
61
62
|
export { default as WebGPUModule } from "../NativeWebGPUModule";
|
package/src/main/index.web.tsx
CHANGED
package/src/types.ts
CHANGED
|
@@ -63,21 +63,74 @@ export interface NativeVideoFrame {
|
|
|
63
63
|
release(): void;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
//
|
|
66
|
+
// GPUExternalTextureDescriptor with a NativeVideoFrame as the source: what
|
|
67
|
+
// GPUDevice.importExternalTexture() takes on React Native, where there is no
|
|
68
|
+
// HTMLVideoElement or WebCodecs VideoFrame. The other members (label,
|
|
69
|
+
// colorSpace, and the rotation / mirrored extensions) are the same.
|
|
70
|
+
export interface GPUNativeExternalTextureDescriptor extends Omit<
|
|
71
|
+
GPUExternalTextureDescriptor,
|
|
72
|
+
"source"
|
|
73
|
+
> {
|
|
74
|
+
source: NativeVideoFrame;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// A decoded video, modeled on HTMLMediaElement: play(), pause(), paused,
|
|
78
|
+
// currentTime (in seconds, assign it to seek), duration, volume and loop work
|
|
79
|
+
// as on the web. Frames are pulled instead of displayed: poll
|
|
80
|
+
// copyLatestFrame() on every render tick to obtain the most recently decoded
|
|
81
|
+
// frame as an IOSurface/AHardwareBuffer-backed NativeVideoFrame (null between
|
|
82
|
+
// frames, so callers can skip the import work).
|
|
69
83
|
export interface VideoPlayer {
|
|
70
84
|
copyLatestFrame(): NativeVideoFrame | null;
|
|
71
85
|
play(): void;
|
|
72
86
|
pause(): void;
|
|
87
|
+
// Stops playback and releases the decoder. Frames already copied stay
|
|
88
|
+
// valid until they are released.
|
|
73
89
|
release(): void;
|
|
90
|
+
readonly paused: boolean;
|
|
91
|
+
// The playback position in seconds. Assign it to seek, also while paused:
|
|
92
|
+
// the next copyLatestFrame() then returns the frame at the new position.
|
|
93
|
+
currentTime: number;
|
|
94
|
+
// The length in seconds, 0 until the metadata has loaded.
|
|
95
|
+
readonly duration: number;
|
|
96
|
+
// 0 to 1.
|
|
97
|
+
volume: number;
|
|
98
|
+
// Restart from the beginning at the end of the stream. Unlike on the web,
|
|
99
|
+
// it defaults to true.
|
|
100
|
+
loop: boolean;
|
|
101
|
+
// The coded size of the frames in pixels, 0 until the metadata has loaded.
|
|
102
|
+
readonly videoWidth: number;
|
|
103
|
+
readonly videoHeight: number;
|
|
104
|
+
// The clockwise rotation to apply when displaying the frames: a video
|
|
105
|
+
// recorded in portrait stores landscape frames with a rotation. Pass it as
|
|
106
|
+
// the `rotation` of importExternalTexture().
|
|
107
|
+
readonly rotation: 0 | 90 | 180 | 270;
|
|
108
|
+
// The nominal frame rate of the video track, 0 if unknown.
|
|
109
|
+
readonly frameRate: number;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
// The source info of GPUQueue.copyExternalImageToTexture() for a native
|
|
113
|
+
// frame (a React Native extension of GPUCopyExternalImageSourceInfo). The
|
|
114
|
+
// frame is rendered into the destination through an external texture, which
|
|
115
|
+
// converts YUV to RGB and applies `rotation` and `mirrored` (the extension of
|
|
116
|
+
// importExternalTexture), so the destination needs
|
|
117
|
+
// GPUTextureUsage.RENDER_ATTACHMENT. `origin` and the copy size are in the
|
|
118
|
+
// upright frame, after rotation.
|
|
119
|
+
export interface GPUCopyExternalNativeFrameSourceInfo {
|
|
120
|
+
source: NativeVideoFrame;
|
|
121
|
+
origin?: GPUOrigin2D;
|
|
122
|
+
flipY?: boolean;
|
|
123
|
+
rotation?: 0 | 90 | 180 | 270;
|
|
124
|
+
mirrored?: boolean;
|
|
74
125
|
}
|
|
75
126
|
|
|
76
127
|
export interface CreateVideoPlayerOptions {
|
|
77
|
-
//
|
|
78
|
-
//
|
|
79
|
-
//
|
|
80
|
-
// GPUDevice.importExternalTexture.
|
|
128
|
+
// The layout of the frames on Apple platforms:
|
|
129
|
+
// 'bgra8' (default): single-plane BGRA surfaces, for importSharedTextureMemory
|
|
130
|
+
// and a regular sampled GPUTexture.
|
|
131
|
+
// 'nv12': biplanar Y + CbCr surfaces, for GPUDevice.importExternalTexture.
|
|
132
|
+
// On Android the decoder always writes its native YUV layout (reported as
|
|
133
|
+
// 'nv12'), which only importExternalTexture samples; the option is ignored.
|
|
81
134
|
pixelFormat?: NativeVideoPixelFormat;
|
|
82
135
|
}
|
|
83
136
|
|
package/src/video.ts
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CreateVideoPlayerOptions,
|
|
3
|
+
NativeVideoFrame,
|
|
4
|
+
VideoPlayer,
|
|
5
|
+
} from "./types";
|
|
6
|
+
|
|
7
|
+
const native = (name: string) => {
|
|
8
|
+
if (typeof RNWebGPU === "undefined") {
|
|
9
|
+
throw new Error(
|
|
10
|
+
`react-native-webgpu is not installed natively; ${name} is unavailable`,
|
|
11
|
+
);
|
|
12
|
+
}
|
|
13
|
+
return RNWebGPU;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Decodes a video into native frames the GPU samples without any copy.
|
|
18
|
+
*
|
|
19
|
+
* `source` is a URL (`http`, `https`, `file`) or a file path. Playback is
|
|
20
|
+
* controlled like an HTMLMediaElement (`play()`, `pause()`, `currentTime`,
|
|
21
|
+
* `loop`, `volume`); frames are pulled with `copyLatestFrame()` on every
|
|
22
|
+
* render tick and sampled through `importExternalTexture()` or
|
|
23
|
+
* `importSharedTextureMemory()`:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* const player = createVideoPlayer(url);
|
|
27
|
+
* player.play();
|
|
28
|
+
* const render = () => {
|
|
29
|
+
* const frame = player.copyLatestFrame();
|
|
30
|
+
* if (frame) {
|
|
31
|
+
* // import, draw, then release once the frame is no longer sampled
|
|
32
|
+
* }
|
|
33
|
+
* requestAnimationFrame(render);
|
|
34
|
+
* };
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* On Apple platforms the frames are BGRA by default, or NV12 with
|
|
38
|
+
* `{ pixelFormat: "nv12" }`. On Android they are always in the decoder's
|
|
39
|
+
* native YUV layout, for `importExternalTexture()`.
|
|
40
|
+
*/
|
|
41
|
+
export const createVideoPlayer = (
|
|
42
|
+
source: string,
|
|
43
|
+
options?: CreateVideoPlayerOptions,
|
|
44
|
+
): VideoPlayer =>
|
|
45
|
+
native("createVideoPlayer").createVideoPlayer(source, options?.pixelFormat);
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Wraps a native buffer produced by another library (a `CVPixelBufferRef` on
|
|
49
|
+
* Apple platforms, an `AHardwareBuffer*` on Android, for instance
|
|
50
|
+
* VisionCamera's `frame.getNativeBuffer().pointer`) into a `NativeVideoFrame`
|
|
51
|
+
* that keeps it alive until released.
|
|
52
|
+
*/
|
|
53
|
+
export const createVideoFrameFromNativeBuffer = (
|
|
54
|
+
pointer: bigint,
|
|
55
|
+
): NativeVideoFrame =>
|
|
56
|
+
native("createVideoFrameFromNativeBuffer").createVideoFrameFromNativeBuffer(
|
|
57
|
+
pointer,
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Allocates a native frame of the given size filled with a test pattern (a
|
|
62
|
+
* red/green gradient with diagonal stripes in the blue channel), for examples
|
|
63
|
+
* and tests that need a frame without a camera or a video.
|
|
64
|
+
*/
|
|
65
|
+
export const createTestVideoFrame = (
|
|
66
|
+
width: number,
|
|
67
|
+
height: number,
|
|
68
|
+
): NativeVideoFrame =>
|
|
69
|
+
native("createTestVideoFrame").createTestVideoFrame(width, height);
|