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.
Files changed (53) hide show
  1. package/android/cpp/AndroidPlatformContext.h +42 -8
  2. package/android/cpp/AndroidVideoPlayer.h +307 -0
  3. package/android/src/main/java/com/webgpu/WebGPUModule.java +10 -0
  4. package/android/src/main/java/com/webgpu/WebGPUVideoPlayer.java +420 -0
  5. package/apple/AppleVideoPlayer.mm +157 -47
  6. package/cpp/rnwgpu/PlatformContext.h +25 -5
  7. package/cpp/rnwgpu/api/GPUDevice.cpp +2 -1
  8. package/cpp/rnwgpu/api/GPUDevice.h +6 -0
  9. package/cpp/rnwgpu/api/GPUQueue.cpp +80 -10
  10. package/cpp/rnwgpu/api/GPUQueue.h +15 -4
  11. package/cpp/rnwgpu/api/VideoFrameBlit.h +355 -0
  12. package/cpp/rnwgpu/api/VideoPlayer.h +50 -3
  13. package/cpp/rnwgpu/api/descriptors/GPUImageCopyExternalImage.h +30 -3
  14. package/lib/commonjs/importDevice.js +2 -2
  15. package/lib/commonjs/index.js.map +1 -1
  16. package/lib/commonjs/main/index.js +12 -0
  17. package/lib/commonjs/main/index.js.map +1 -1
  18. package/lib/commonjs/main/index.web.js +11 -0
  19. package/lib/commonjs/main/index.web.js.map +1 -1
  20. package/lib/commonjs/video.js +58 -0
  21. package/lib/commonjs/video.js.map +1 -0
  22. package/lib/module/importDevice.js +2 -2
  23. package/lib/module/index.js.map +1 -1
  24. package/lib/module/main/index.js +1 -0
  25. package/lib/module/main/index.js.map +1 -1
  26. package/lib/module/main/index.web.js +1 -0
  27. package/lib/module/main/index.web.js.map +1 -1
  28. package/lib/module/video.js +49 -0
  29. package/lib/module/video.js.map +1 -0
  30. package/lib/typescript/lib/commonjs/video.d.ts +30 -0
  31. package/lib/typescript/lib/commonjs/video.d.ts.map +1 -0
  32. package/lib/typescript/lib/module/main/index.d.ts +1 -0
  33. package/lib/typescript/lib/module/main/index.web.d.ts +1 -0
  34. package/lib/typescript/lib/module/video.d.ts +4 -0
  35. package/lib/typescript/lib/module/video.d.ts.map +1 -0
  36. package/lib/typescript/src/importDevice.d.ts +2 -2
  37. package/lib/typescript/src/index.d.ts +5 -3
  38. package/lib/typescript/src/index.d.ts.map +1 -1
  39. package/lib/typescript/src/main/index.d.ts +1 -0
  40. package/lib/typescript/src/main/index.d.ts.map +1 -1
  41. package/lib/typescript/src/main/index.web.d.ts +1 -0
  42. package/lib/typescript/src/main/index.web.d.ts.map +1 -1
  43. package/lib/typescript/src/types.d.ts +19 -0
  44. package/lib/typescript/src/types.d.ts.map +1 -1
  45. package/lib/typescript/src/video.d.ts +41 -0
  46. package/lib/typescript/src/video.d.ts.map +1 -0
  47. package/package.json +1 -1
  48. package/src/importDevice.ts +2 -2
  49. package/src/index.tsx +28 -3
  50. package/src/main/index.tsx +1 -0
  51. package/src/main/index.web.tsx +1 -0
  52. package/src/types.ts +60 -7
  53. 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-webgpu",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
4
4
  "description": "React Native WebGPU",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -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.MakeNativeTextureFromImage()`:
29
+ * `Skia.Image.MakeGPUTextureFromImage()`:
30
30
  *
31
31
  * ```ts
32
- * const texture = adoptTexture(Skia.Image.MakeNativeTextureFromImage(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.MakeNativeTextureFromImage()).
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
- path: string,
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 (e.g. Skia.Image.MakeImageFromNativeTexture).
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
@@ -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";
@@ -6,5 +6,6 @@ export * from "../WebGPUViewNativeComponent";
6
6
  export * from "../hooks";
7
7
  export * from "../GPUDeviceProvider";
8
8
  export * from "../formats";
9
+ export * from "../video";
9
10
 
10
11
  // We don't need to set all global properties on web, webgpu is already available globally
package/src/types.ts CHANGED
@@ -63,21 +63,74 @@ export interface NativeVideoFrame {
63
63
  release(): void;
64
64
  }
65
65
 
66
- // A handle to a decoded video stream. Poll copyLatestFrame() each render tick
67
- // to obtain the most recently decoded frame as an IOSurface/AHardwareBuffer
68
- // (returns null between frames so callers can skip the import work).
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
- // 'bgra8' (default): emit a single-plane BGRA surface, suitable for
78
- // SharedTextureMemory and a regular sampled GPUTexture.
79
- // 'nv12': emit biplanar Y + CbCr surfaces, suitable for
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);