react-native-skia-webgpu-video 0.0.0-stage → 0.1.0-beta.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 (237) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +303 -2
  3. package/android/BUILD_VALIDATION.md +62 -0
  4. package/android/CMakeLists.txt +99 -0
  5. package/android/build-validation.json +262 -0
  6. package/android/build.gradle +185 -0
  7. package/android/cpp/EncoderTargets.cpp +226 -0
  8. package/android/cpp/EncoderTargets.h +70 -0
  9. package/android/cpp/JNIHelpers.cpp +15 -0
  10. package/android/cpp/JNIHelpers.h +20 -0
  11. package/android/cpp/NativeEventDispatcher.cpp +59 -0
  12. package/android/cpp/NativeEventDispatcher.h +31 -0
  13. package/android/cpp/NativeHardwareBuffer.cpp +397 -0
  14. package/android/cpp/NativeHardwareBuffer.h +34 -0
  15. package/android/cpp/NativeRgbaBuffer.cpp +45 -0
  16. package/android/cpp/NativeRgbaBuffer.h +9 -0
  17. package/android/cpp/ReturnedVideoFrames.h +37 -0
  18. package/android/cpp/RgbaFrameLease.h +53 -0
  19. package/android/cpp/VideoCapabilities.cpp +87 -0
  20. package/android/cpp/VideoCapabilities.h +44 -0
  21. package/android/cpp/VideoComposition.cpp +170 -0
  22. package/android/cpp/VideoComposition.h +36 -0
  23. package/android/cpp/VideoCompositionFramesExtractor.cpp +82 -0
  24. package/android/cpp/VideoCompositionFramesExtractor.h +48 -0
  25. package/android/cpp/VideoCompositionFramesExtractorHostObject.cpp +230 -0
  26. package/android/cpp/VideoCompositionFramesExtractorHostObject.h +42 -0
  27. package/android/cpp/VideoCompositionFramesExtractorSyncHostObject.cpp +133 -0
  28. package/android/cpp/VideoCompositionFramesExtractorSyncHostObject.h +46 -0
  29. package/android/cpp/VideoEncoderHostObject.cpp +318 -0
  30. package/android/cpp/VideoEncoderHostObject.h +76 -0
  31. package/android/cpp/VideoFrame.cpp +293 -0
  32. package/android/cpp/VideoFrame.h +27 -0
  33. package/android/cpp/VideoPlayer.cpp +96 -0
  34. package/android/cpp/VideoPlayer.h +52 -0
  35. package/android/cpp/VideoPlayerHostObject.cpp +225 -0
  36. package/android/cpp/VideoPlayerHostObject.h +43 -0
  37. package/android/cpp/cpp-adapter.cpp +316 -0
  38. package/android/gradle.properties +5 -0
  39. package/android/instrumentation-inventory.json +178 -0
  40. package/android/proguard-rules.pro +4 -0
  41. package/android/src/main/AndroidManifest.xml +2 -0
  42. package/android/src/main/java/com/azzapp/rnskv/AudioCompositionExporter.java +537 -0
  43. package/android/src/main/java/com/azzapp/rnskv/AudioCompositionPlayer.java +321 -0
  44. package/android/src/main/java/com/azzapp/rnskv/BufferLifetime.java +55 -0
  45. package/android/src/main/java/com/azzapp/rnskv/DecodeRequests.java +100 -0
  46. package/android/src/main/java/com/azzapp/rnskv/DecoderWindow.java +55 -0
  47. package/android/src/main/java/com/azzapp/rnskv/DisplayVsyncPeriod.java +72 -0
  48. package/android/src/main/java/com/azzapp/rnskv/EGLResourcesHolder.java +132 -0
  49. package/android/src/main/java/com/azzapp/rnskv/EGLUtils.java +225 -0
  50. package/android/src/main/java/com/azzapp/rnskv/FrameSize.java +50 -0
  51. package/android/src/main/java/com/azzapp/rnskv/GLFrameExtractor.java +510 -0
  52. package/android/src/main/java/com/azzapp/rnskv/JNIHelpers.java +12 -0
  53. package/android/src/main/java/com/azzapp/rnskv/NativeEventDispatcher.java +25 -0
  54. package/android/src/main/java/com/azzapp/rnskv/NativeHardwareBuffer.java +62 -0
  55. package/android/src/main/java/com/azzapp/rnskv/NativeRgbaBuffer.java +43 -0
  56. package/android/src/main/java/com/azzapp/rnskv/ReactNativeSkiaVideoModule.java +45 -0
  57. package/android/src/main/java/com/azzapp/rnskv/ReactNativeSkiaVideoPackage.java +43 -0
  58. package/android/src/main/java/com/azzapp/rnskv/ReactNativeSkiaVideoSpec.java +9 -0
  59. package/android/src/main/java/com/azzapp/rnskv/RgbaBufferAllocator.java +114 -0
  60. package/android/src/main/java/com/azzapp/rnskv/RgbaLayout.java +33 -0
  61. package/android/src/main/java/com/azzapp/rnskv/SurfaceOutputPolicy.java +13 -0
  62. package/android/src/main/java/com/azzapp/rnskv/TextureRenderer.java +150 -0
  63. package/android/src/main/java/com/azzapp/rnskv/TimeHelpers.java +11 -0
  64. package/android/src/main/java/com/azzapp/rnskv/VideoCapabilities.java +354 -0
  65. package/android/src/main/java/com/azzapp/rnskv/VideoComposition.java +147 -0
  66. package/android/src/main/java/com/azzapp/rnskv/VideoCompositionDecoder.java +779 -0
  67. package/android/src/main/java/com/azzapp/rnskv/VideoCompositionFramesExtractor.java +463 -0
  68. package/android/src/main/java/com/azzapp/rnskv/VideoCompositionFramesExtractorSync.java +241 -0
  69. package/android/src/main/java/com/azzapp/rnskv/VideoCompositionItemDecoder.java +492 -0
  70. package/android/src/main/java/com/azzapp/rnskv/VideoEncoder.java +639 -0
  71. package/android/src/main/java/com/azzapp/rnskv/VideoFrame.java +74 -0
  72. package/android/src/main/java/com/azzapp/rnskv/VideoPlayer.java +361 -0
  73. package/cpp/RNSVCheckedSizes.h +54 -0
  74. package/cpp/RNSVEventEmitter.cpp +199 -0
  75. package/cpp/RNSVEventEmitter.h +31 -0
  76. package/cpp/RNSVHostObject.cpp +79 -0
  77. package/cpp/RNSVHostObject.h +67 -0
  78. package/cpp/RNSVMemoryBudget.cpp +68 -0
  79. package/cpp/RNSVMemoryBudget.h +100 -0
  80. package/cpp/RNSVRuntimeLifecycleMonitor.cpp +88 -0
  81. package/cpp/RNSVRuntimeLifecycleMonitor.h +33 -0
  82. package/docs/ANDROID_DEVICE_306.md +95 -0
  83. package/docs/ANDROID_EXPORT_CACHE_306.md +48 -0
  84. package/docs/ANDROID_MEMORY_RETENTION_306.md +67 -0
  85. package/docs/BENCHMARKS.md +368 -0
  86. package/docs/IOS_DEVICE_TESTS.md +115 -0
  87. package/docs/IOS_SIMULATOR_TESTS.md +74 -0
  88. package/docs/MIGRATION.md +82 -0
  89. package/docs/NATIVE_MEMORY_INVESTIGATION_306.md +88 -0
  90. package/docs/PERFORMANCE_AB_IPHONE_303.md +196 -0
  91. package/docs/PERFORMANCE_AB_SIMULATOR.md +135 -0
  92. package/docs/PERFORMANCE_AB_SOAK_SIMULATOR.md +84 -0
  93. package/docs/PERFORMANCE_IPHONE_306_OPTIMIZATION.md +76 -0
  94. package/docs/PERFORMANCE_SIMULATOR.md +89 -0
  95. package/docs/PERFORMANCE_SIMULATOR_INITIAL.md +96 -0
  96. package/docs/PERFORMANCE_SOAK_IPHONE_303.md +41 -0
  97. package/docs/UPSTREAM_NOTES.md +188 -0
  98. package/docs/assets/banner.svg +26 -0
  99. package/examples/webgpu-overlay.ts +147 -0
  100. package/ios/AVAssetTrackUtils.h +24 -0
  101. package/ios/AudioCompositionUtils.h +27 -0
  102. package/ios/AudioCompositionUtils.mm +113 -0
  103. package/ios/DecoderWindow.h +52 -0
  104. package/ios/NativeResourceStats.h +32 -0
  105. package/ios/RNSVColorSpace.h +50 -0
  106. package/ios/RNSVJSIUtils.h +46 -0
  107. package/ios/RNSVScopedPixelBuffer.h +17 -0
  108. package/ios/RNSVVideoPlayer.h +46 -0
  109. package/ios/RNSVVideoPlayer.mm +410 -0
  110. package/ios/ReactNativeSkiaVideo.h +8 -0
  111. package/ios/ReactNativeSkiaVideo.mm +310 -0
  112. package/ios/SeekPolicy.h +27 -0
  113. package/ios/VideoComposition.h +148 -0
  114. package/ios/VideoCompositionFramesExtractorHostObject.h +105 -0
  115. package/ios/VideoCompositionFramesExtractorHostObject.mm +686 -0
  116. package/ios/VideoCompositionFramesExtractorSyncHostObject.h +37 -0
  117. package/ios/VideoCompositionFramesExtractorSyncHostObject.mm +168 -0
  118. package/ios/VideoCompositionItemDecoder.h +60 -0
  119. package/ios/VideoCompositionItemDecoder.mm +480 -0
  120. package/ios/VideoEncoderHostObject.h +83 -0
  121. package/ios/VideoEncoderHostObject.mm +706 -0
  122. package/ios/VideoFrame.h +66 -0
  123. package/ios/VideoFrame.mm +108 -0
  124. package/ios/VideoPlayerHostObject.h +52 -0
  125. package/ios/VideoPlayerHostObject.mm +332 -0
  126. package/lib/module/NativeReactNativeSkiaVideo.js +5 -0
  127. package/lib/module/NativeReactNativeSkiaVideo.js.map +1 -0
  128. package/lib/module/RNSkiaVideoModule.js +20 -0
  129. package/lib/module/RNSkiaVideoModule.js.map +1 -0
  130. package/lib/module/canvas.js +18 -0
  131. package/lib/module/canvas.js.map +1 -0
  132. package/lib/module/exportCache.js +22 -0
  133. package/lib/module/exportCache.js.map +1 -0
  134. package/lib/module/exportFrames.js +338 -0
  135. package/lib/module/exportFrames.js.map +1 -0
  136. package/lib/module/exportQueue.js +52 -0
  137. package/lib/module/exportQueue.js.map +1 -0
  138. package/lib/module/exportTarget.js +137 -0
  139. package/lib/module/exportTarget.js.map +1 -0
  140. package/lib/module/exportVideoComposition.js +492 -0
  141. package/lib/module/exportVideoComposition.js.map +1 -0
  142. package/lib/module/frameInterop.js +532 -0
  143. package/lib/module/frameInterop.js.map +1 -0
  144. package/lib/module/gpu.js +222 -0
  145. package/lib/module/gpu.js.map +1 -0
  146. package/lib/module/gpuDevice.js +54 -0
  147. package/lib/module/gpuDevice.js.map +1 -0
  148. package/lib/module/index.js +36 -0
  149. package/lib/module/index.js.map +1 -0
  150. package/lib/module/memory.js +38 -0
  151. package/lib/module/memory.js.map +1 -0
  152. package/lib/module/package.json +1 -0
  153. package/lib/module/previewLifecycle.js +52 -0
  154. package/lib/module/previewLifecycle.js.map +1 -0
  155. package/lib/module/runtimeYield.js +10 -0
  156. package/lib/module/runtimeYield.js.map +1 -0
  157. package/lib/module/types.js +4 -0
  158. package/lib/module/types.js.map +1 -0
  159. package/lib/module/utils/useEventListener.js +18 -0
  160. package/lib/module/utils/useEventListener.js.map +1 -0
  161. package/lib/module/videoCompositionPlayer.js +368 -0
  162. package/lib/module/videoCompositionPlayer.js.map +1 -0
  163. package/lib/module/videoFrameImage.js +185 -0
  164. package/lib/module/videoFrameImage.js.map +1 -0
  165. package/lib/module/videoPlayer.js +172 -0
  166. package/lib/module/videoPlayer.js.map +1 -0
  167. package/lib/module/yuvBlit.js +299 -0
  168. package/lib/module/yuvBlit.js.map +1 -0
  169. package/lib/typescript/package.json +1 -0
  170. package/lib/typescript/src/NativeReactNativeSkiaVideo.d.ts +7 -0
  171. package/lib/typescript/src/NativeReactNativeSkiaVideo.d.ts.map +1 -0
  172. package/lib/typescript/src/RNSkiaVideoModule.d.ts +4 -0
  173. package/lib/typescript/src/RNSkiaVideoModule.d.ts.map +1 -0
  174. package/lib/typescript/src/canvas.d.ts +4 -0
  175. package/lib/typescript/src/canvas.d.ts.map +1 -0
  176. package/lib/typescript/src/exportCache.d.ts +6 -0
  177. package/lib/typescript/src/exportCache.d.ts.map +1 -0
  178. package/lib/typescript/src/exportFrames.d.ts +57 -0
  179. package/lib/typescript/src/exportFrames.d.ts.map +1 -0
  180. package/lib/typescript/src/exportQueue.d.ts +5 -0
  181. package/lib/typescript/src/exportQueue.d.ts.map +1 -0
  182. package/lib/typescript/src/exportTarget.d.ts +28 -0
  183. package/lib/typescript/src/exportTarget.d.ts.map +1 -0
  184. package/lib/typescript/src/exportVideoComposition.d.ts +68 -0
  185. package/lib/typescript/src/exportVideoComposition.d.ts.map +1 -0
  186. package/lib/typescript/src/frameInterop.d.ts +17 -0
  187. package/lib/typescript/src/frameInterop.d.ts.map +1 -0
  188. package/lib/typescript/src/gpu.d.ts +39 -0
  189. package/lib/typescript/src/gpu.d.ts.map +1 -0
  190. package/lib/typescript/src/gpuDevice.d.ts +11 -0
  191. package/lib/typescript/src/gpuDevice.d.ts.map +1 -0
  192. package/lib/typescript/src/index.d.ts +21 -0
  193. package/lib/typescript/src/index.d.ts.map +1 -0
  194. package/lib/typescript/src/memory.d.ts +25 -0
  195. package/lib/typescript/src/memory.d.ts.map +1 -0
  196. package/lib/typescript/src/previewLifecycle.d.ts +22 -0
  197. package/lib/typescript/src/previewLifecycle.d.ts.map +1 -0
  198. package/lib/typescript/src/runtimeYield.d.ts +4 -0
  199. package/lib/typescript/src/runtimeYield.d.ts.map +1 -0
  200. package/lib/typescript/src/types.d.ts +631 -0
  201. package/lib/typescript/src/types.d.ts.map +1 -0
  202. package/lib/typescript/src/utils/useEventListener.d.ts +5 -0
  203. package/lib/typescript/src/utils/useEventListener.d.ts.map +1 -0
  204. package/lib/typescript/src/videoCompositionPlayer.d.ts +105 -0
  205. package/lib/typescript/src/videoCompositionPlayer.d.ts.map +1 -0
  206. package/lib/typescript/src/videoFrameImage.d.ts +60 -0
  207. package/lib/typescript/src/videoFrameImage.d.ts.map +1 -0
  208. package/lib/typescript/src/videoPlayer.d.ts +99 -0
  209. package/lib/typescript/src/videoPlayer.d.ts.map +1 -0
  210. package/lib/typescript/src/yuvBlit.d.ts +50 -0
  211. package/lib/typescript/src/yuvBlit.d.ts.map +1 -0
  212. package/package.json +155 -4
  213. package/patches/react-native-skia+3.7.0.patch +502 -0
  214. package/react-native-skia-webgpu-video.podspec +35 -0
  215. package/scripts/apply-skia-canvas-patch.mjs +48 -0
  216. package/scripts/skia-canvas-patch.json +291 -0
  217. package/src/NativeReactNativeSkiaVideo.ts +8 -0
  218. package/src/RNSkiaVideoModule.ts +27 -0
  219. package/src/canvas.ts +22 -0
  220. package/src/exportCache.ts +27 -0
  221. package/src/exportFrames.ts +421 -0
  222. package/src/exportQueue.ts +65 -0
  223. package/src/exportTarget.ts +179 -0
  224. package/src/exportVideoComposition.ts +718 -0
  225. package/src/frameInterop.ts +684 -0
  226. package/src/gpu.ts +290 -0
  227. package/src/gpuDevice.ts +80 -0
  228. package/src/index.tsx +45 -0
  229. package/src/memory.ts +48 -0
  230. package/src/previewLifecycle.ts +60 -0
  231. package/src/runtimeYield.ts +6 -0
  232. package/src/types.ts +661 -0
  233. package/src/utils/useEventListener.ts +22 -0
  234. package/src/videoCompositionPlayer.ts +568 -0
  235. package/src/videoFrameImage.ts +205 -0
  236. package/src/videoPlayer.ts +318 -0
  237. package/src/yuvBlit.ts +331 -0
package/src/types.ts ADDED
@@ -0,0 +1,661 @@
1
+ import type { SkCanvas } from "react-native-skia";
2
+
3
+ /** A transient frame. Use makeVideoFrameImage/drawVideoFrame to obtain owned
4
+ * Skia pixels; raw Metal/GL handles are no longer supported by Graphite. */
5
+ export type VideoFrame = {
6
+ texture: unknown;
7
+ width: number;
8
+ height: number;
9
+ rotation: number;
10
+ crop?: { x: number; y: number; width: number; height: number };
11
+ /** Stable identity of the native frame, including after its buffer is released. */
12
+ id?: number;
13
+ /** Stable identity of the producer, used to bound imported image caches. */
14
+ producerId?: number;
15
+ /** Release a native source after copying/rendering and waiting for GPU completion. */
16
+ dispose?: () => void;
17
+ };
18
+
19
+ /**
20
+ * Represents the dimensions of a video.
21
+ */
22
+ export type VideoDimensions = {
23
+ /**
24
+ * The width in pixels of the video.
25
+ */
26
+ width: number;
27
+ /**
28
+ * The height in pixels of the video.
29
+ */
30
+ height: number;
31
+ /**
32
+ * The rotation in degrees of the video.
33
+ */
34
+ rotation: number;
35
+ };
36
+
37
+ /**
38
+ * Represents a range of buffered data.
39
+ */
40
+ export type BufferingRange = { start: number; duration: number };
41
+
42
+ /** Compatibility preference retained from Skia Video. This reference
43
+ * Graphite backend uses bounded, owned snapshots for both values. Native
44
+ * buffers first pass through a reusable WebGPU upload texture. Neither
45
+ * value exposes the legacy Metal/OpenGL texture lifetime contract. */
46
+ export type VideoTextureMode = "copy" | "direct";
47
+
48
+ /** Compatibility preference; both values use the same transport. iOS draws
49
+ * into the encoder's pool buffers on the GPU, falling back to CPU readback
50
+ * when IOSurface interop is unavailable. Android reads pixels back. */
51
+ export type VideoEncoderMode = "copy" | "direct";
52
+
53
+ /**
54
+ * The video player interface.
55
+ */
56
+ export type VideoPlayer = {
57
+ /**
58
+ * Resumes playback of the video.
59
+ */
60
+ play(): void;
61
+ /**
62
+ * Pauses playback.
63
+ */
64
+ pause(): void;
65
+ /**
66
+ * Seeks to a position specified in seconds.
67
+ * Once the seek is complete, the `seekComplete` event will be emitted.
68
+ *
69
+ * @param time The position in seconds to seek to.
70
+ */
71
+ seekTo(time: number): void;
72
+ /**
73
+ * Decodes the next frame of the video.
74
+ * This method should only be called from the ui thread.
75
+ *
76
+ * @returns The next frame of the video.
77
+ */
78
+ decodeNextFrame(): VideoFrame | null;
79
+ /**
80
+ * The current time in seconds of the playback.
81
+ */
82
+ readonly currentTime: number;
83
+ /**
84
+ * The duration in seconds of the video.
85
+ */
86
+ readonly duration: number;
87
+ /**
88
+ * Indicates whether the video is currently playing.
89
+ */
90
+ readonly isPlaying: boolean;
91
+ /**
92
+ * Indicates whether the video is set to loop.
93
+ */
94
+ isLooping: boolean;
95
+ /**
96
+ * The volume of the video.
97
+ * The value should be between 0 and 1.
98
+ */
99
+ volume: number;
100
+ /**
101
+ * The playback speed of the video.
102
+ * The value should be greater than 0. 1.0 is normal speed, 2.0 is double speed, 0.5 is half speed.
103
+ */
104
+ playbackSpeed: number;
105
+ /**
106
+ * Disposes of the video player.
107
+ */
108
+ dispose(): void;
109
+ /**
110
+ * Events dispatched by the video player once the video is ready to play.
111
+ */
112
+ on(
113
+ name: "ready",
114
+ listener: (dimensions: VideoDimensions) => void,
115
+ ): () => void;
116
+ /**
117
+ * Events dispatched by the video player when the video starts buffering.
118
+ */
119
+ on(name: "bufferingStart", listener: () => void): () => void;
120
+ /**
121
+ * Events dispatched by the video player when the video stops buffering.
122
+ */
123
+ on(name: "bufferingEnd", listener: () => void): () => void;
124
+ /**
125
+ * Events dispatched by the video player when the buffered ranges are updated.
126
+ */
127
+ on(
128
+ name: "bufferingUpdate",
129
+ listener: (loadedRanges: BufferingRange[]) => void,
130
+ ): () => void;
131
+ /**
132
+ * Events dispatched by the video player when the video playback completes.
133
+ */
134
+ on(name: "complete", listener: () => void): () => void;
135
+ /**
136
+ * Events dispatched by the video player when a seek operation completes.
137
+ */
138
+ on(name: "seekComplete", listener: () => void): () => void;
139
+ /**
140
+ * Events dispatched by the video player when the playing status changes.
141
+ */
142
+ on(
143
+ name: "playingStatusChange",
144
+ listener: (isPlaying: boolean) => void,
145
+ ): () => void;
146
+ /**
147
+ * Events dispatched by the video player when an error occurs.
148
+ */
149
+ on(name: "error", listener: (error: any) => void): () => void;
150
+ };
151
+
152
+ /**
153
+ * Represents a video composition.
154
+ */
155
+ export type VideoComposition = {
156
+ /**
157
+ * The items that make up the composition.
158
+ */
159
+ items: VideoCompositionItem[];
160
+ /**
161
+ * The duration in seconds of the composition.
162
+ */
163
+ duration: number;
164
+ /**
165
+ * Open each video item's decoder shortly before the item starts and close it
166
+ * shortly after it ends, instead of all of them at prepare. For compositions
167
+ * that play their items one after another: decoders and their frames are
168
+ * held for a few items at a time rather than for all of them.
169
+ *
170
+ * An item reached by a seek, rather than by playing up to it, shows no frame
171
+ * until its decoder has opened. The export always waits for it.
172
+ */
173
+ lazyDecoders?: boolean;
174
+ };
175
+
176
+ type VideoCompositionItemBase = {
177
+ /**
178
+ * The unique identifier of the item.
179
+ */
180
+ id: string;
181
+ /**
182
+ * The path to the media file.
183
+ * only support local file path
184
+ */
185
+ path: string;
186
+ /**
187
+ * The start time in seconds of the item within the composition.
188
+ */
189
+ compositionStartTime: number;
190
+ /**
191
+ * The start time in seconds of the item within the media.
192
+ */
193
+ startTime: number;
194
+ /**
195
+ * The duration in seconds of the item.
196
+ */
197
+ duration: number;
198
+ };
199
+
200
+ /**
201
+ * A video item of a composition. Produces frames passed to the `drawFrame`
202
+ * function. Video items are silent by default; set `audio` to also play
203
+ * the audio track of the video file.
204
+ */
205
+ export type VideoCompositionVideoItem = VideoCompositionItemBase & {
206
+ kind?: "video";
207
+ /**
208
+ * If provided, the resolution to scale the video to.
209
+ * If not provided, the original resolution of the video will be used.
210
+ * Downscaling the video can improve performance.
211
+ *
212
+ * Given in the file's *encoded* orientation, which for a portrait clip is
213
+ * the transpose of what it displays as — prefer `maxLongSide` unless an
214
+ * exact pixel size is needed.
215
+ */
216
+ resolution?: { width: number; height: number };
217
+ /**
218
+ * If provided, the longest side the frames are decoded at, keeping the
219
+ * file's own aspect. Ignored when `resolution` is set, and never upscales.
220
+ *
221
+ * The cap reduces decoder output/staging pixels. Android's hardware
222
+ * decoder can still allocate buffers at the encoded resolution; measure
223
+ * process/GPU memory separately from the library's explicit budget.
224
+ */
225
+ maxLongSide?: number;
226
+ /**
227
+ * How this item's frames reach Skia, see {@link VideoTextureMode}.
228
+ *
229
+ * @default 'copy'
230
+ */
231
+ textureMode?: VideoTextureMode;
232
+ /**
233
+ * If set, the audio track of the video file will be played (during
234
+ * playback) and mixed into the exported video (during export), following
235
+ * the same time mapping as the video frames.
236
+ * Defaults to false (video items are silent).
237
+ */
238
+ audio?: boolean | { volume?: number };
239
+ };
240
+
241
+ /**
242
+ * An audio item of a composition. Does not produce frames; its audio track
243
+ * is played during playback and mixed into the exported video during export.
244
+ * The source file can be an audio file or a video file (in which case its
245
+ * audio track is used).
246
+ */
247
+ export type VideoCompositionAudioItem = VideoCompositionItemBase & {
248
+ kind: "audio";
249
+ /**
250
+ * The volume of the item, between 0 and 1.
251
+ * Defaults to 1.
252
+ */
253
+ volume?: number;
254
+ };
255
+
256
+ export type VideoCompositionItem =
257
+ VideoCompositionVideoItem | VideoCompositionAudioItem;
258
+
259
+ /**
260
+ * Function that draws a video composition frame to a canvas.
261
+ */
262
+ export type FrameDrawer<T = undefined> = (args: {
263
+ /**
264
+ * The context created by the `before` function in video composition player.
265
+ * or in export video composition.
266
+ */
267
+ context: T;
268
+ /**
269
+ * The canvas to draw the frame to.
270
+ */
271
+ canvas: SkCanvas;
272
+ /**
273
+ * The current composition
274
+ */
275
+ videoComposition: VideoComposition;
276
+ /**
277
+ * The current time in seconds of the drawn frame.
278
+ */
279
+ currentTime: number;
280
+ /**
281
+ * The decoded video frames of the composition items.
282
+ * Only video items produce frames; audio items never appear in this map.
283
+ */
284
+ frames: Record<string, VideoFrame>;
285
+ /**
286
+ * The expected width of the frame in pixels.
287
+ */
288
+ width: number;
289
+ /**
290
+ * The expected height of the frame in pixels.
291
+ */
292
+ height: number;
293
+ }) => void;
294
+
295
+ /**
296
+ * The video composition frames extractor interface.
297
+ */
298
+ export type VideoCompositionFramesExtractor = {
299
+ /**
300
+ * Prepares the video composition frames extractor for extracting the frames.
301
+ */
302
+ prepare(): void;
303
+ /**
304
+ * Starts extracting the frames of the video composition.
305
+ */
306
+ play(): void;
307
+ /**
308
+ * Pauses the extraction of the frames.
309
+ */
310
+ pause(): void;
311
+ /**
312
+ * Seeks to a position specified in seconds.
313
+ * @param time The position in seconds to seek to.
314
+ */
315
+ seekTo(time: number): void;
316
+ /**
317
+ * Decodes the frames of the video composition items.
318
+ * This method should only be called from the ui thread.
319
+ *
320
+ * @returns The decoded video frames of the composition items.
321
+ */
322
+ decodeCompositionFrames(): Record<string, VideoFrame>;
323
+ /**
324
+ * Disposes of the video composition frames extractor.
325
+ */
326
+ dispose(): void;
327
+ /**
328
+ * The current time in seconds.
329
+ */
330
+ readonly currentTime: number;
331
+ /**
332
+ * A counter incremented every time `decodeCompositionFrames` returned a new
333
+ * frame for at least one item. Two equal values mean the frames did not
334
+ * change in between.
335
+ */
336
+ readonly framesVersion: number;
337
+ /**
338
+ * Whether the video composition frames extractor is currently playing.
339
+ */
340
+ readonly isPlaying: boolean;
341
+ /**
342
+ * Whether the video composition frames extractor is set to loop.
343
+ */
344
+ isLooping: boolean;
345
+ /**
346
+ * Events dispatched by the video composition frames extractor when the extraction is ready.
347
+ */
348
+ on(name: "ready", listener: () => void): () => void;
349
+ /**
350
+ * Events dispatched by the video composition frames extractor process completes.
351
+ */
352
+ on(name: "complete", listener: () => void): () => void;
353
+ /**
354
+ * Events dispatched by the video composition frames extractor when an error occurs.
355
+ */
356
+ on(name: "error", listener: (error: any) => void): () => void;
357
+ };
358
+
359
+ /**
360
+ * The video composition sync extractor interface.
361
+ */
362
+ export type VideoCompositionFramesExtractorSync = {
363
+ /**
364
+ * Starts extracting the frames of the video composition.
365
+ */
366
+ start(): void;
367
+ /**
368
+ * Decodes the frames until reaching the specified time.
369
+ * This method will block the current thread until the frames are decoded.
370
+ *
371
+ * The returned frames are only valid until the next call: draw them and
372
+ * flush the GPU synchronously (`surface.flush(true)`) before decoding
373
+ * further frames.
374
+ *
375
+ * @returns The decoded video frames of the composition items.
376
+ */
377
+ decodeCompositionFrames(currentTime: number): Record<string, VideoFrame>;
378
+ /**
379
+ * Disposes of the video composition frames extractor.
380
+ */
381
+ dispose(): void;
382
+ };
383
+
384
+ /**
385
+ * The video composition encoder interface.
386
+ */
387
+ export type VideoEncoder = {
388
+ /**
389
+ * Prepares the video composition encoder for writing.
390
+ */
391
+ prepare(): void;
392
+ /**
393
+ * Encodes the video frame to the video composition.
394
+ */
395
+ encodeFrame(texture: unknown, time: number): void;
396
+ /**
397
+ * Lends the next pool buffer to draw into on the GPU: a CVPixelBuffer on
398
+ * iOS, an RGBA AHardwareBuffer on Android. Pass it back as a native-buffer
399
+ * frame (on Android with the sync-fds ending its GPU access, in `fences`),
400
+ * or release it. One at a time.
401
+ */
402
+ acquireFrameBuffer?(): bigint;
403
+ /** Returns a lent buffer that will not be encoded. */
404
+ releaseFrameBuffer?(): void;
405
+ /*
406
+ * Finish writing the video to the output file.
407
+ */
408
+ finishWriting(): void;
409
+ /**
410
+ * Disposes of the video composition encoder.
411
+ */
412
+ dispose(): void;
413
+ };
414
+
415
+ /**
416
+ * The video codec used to encode an export.
417
+ *
418
+ * `h264` is supported by every device this library runs on, and is what
419
+ * playback and upload pipelines are universally built around. `hevc` produces
420
+ * roughly the same quality at about half the bitrate, but is not available
421
+ * everywhere — see {@link RNSkiaVideoModule.isEncodingSupported}.
422
+ */
423
+ export type VideoCodec = "h264" | "hevc";
424
+
425
+ /**
426
+ * The export options for a video composition.
427
+ */
428
+ export type ExportOptions = {
429
+ /**
430
+ * The path to save the exported video.
431
+ */
432
+ outPath: string;
433
+ /**
434
+ * The width of the exported video in pixels.
435
+ */
436
+ width: number;
437
+ /**
438
+ * The height of the exported video in pixels.
439
+ */
440
+ height: number;
441
+ /**
442
+ * The frame rate of the exported video in frames per second.
443
+ */
444
+ frameRate: number;
445
+ /**
446
+ * The bit rate of the exported video in bits per second.
447
+ */
448
+ bitRate: number;
449
+ /**
450
+ * The video codec to encode with.
451
+ *
452
+ * Falls back to `h264` when the requested codec has no encoder on the
453
+ * device, so passing `hevc` can never fail an export that `h264` would have
454
+ * completed. Call {@link RNSkiaVideoModule.isEncodingSupported} first if the
455
+ * choice is surfaced to a user, so the option can be hidden rather than
456
+ * silently ignored.
457
+ *
458
+ * @default 'h264'
459
+ */
460
+ codec?: VideoCodec;
461
+ /**
462
+ * The encoder name to use for the export.
463
+ *
464
+ * Takes precedence over {@link codec}: naming an encoder selects it
465
+ * directly, whatever codec it implements.
466
+ *
467
+ * @platform android
468
+ */
469
+ encoderName?: string | null;
470
+ /**
471
+ * How rendered frames reach the encoder, see {@link VideoEncoderMode}.
472
+ *
473
+ * @default 'copy'
474
+ * @platform ios
475
+ */
476
+ encoderMode?: VideoEncoderMode;
477
+ /**
478
+ * The bit rate of the exported audio track in bits per second.
479
+ * Only used if the composition contains audio.
480
+ * @default 128000
481
+ */
482
+ audioBitRate?: number;
483
+ /**
484
+ * The sample rate of the exported audio track in Hz.
485
+ * Only used if the composition contains audio.
486
+ * @default 44100
487
+ */
488
+ audioSampleRate?: number;
489
+ /**
490
+ * The number of channels of the exported audio track (1 = mono, 2 = stereo).
491
+ * Only used if the composition contains audio.
492
+ * @default 2
493
+ */
494
+ audioChannelCount?: number;
495
+ };
496
+
497
+ export type RNSkiaVideoModule = {
498
+ frameProtocolVersion?: number;
499
+ /** Internal Android capability negotiation, before creating a decoder. */
500
+ configureNativeBufferInterop?: (enabled: boolean) => void;
501
+ reserveMemory?: (bytes: number, label: string) => number;
502
+ releaseMemory?: (reservation: number) => void;
503
+ configureMemoryBudget?: (maxBytes: number) => void;
504
+ getMemoryBudgetStats?: () => {
505
+ currentBytes: number;
506
+ peakBytes: number;
507
+ allocations: number;
508
+ maxBytes: number;
509
+ };
510
+ getResourceStats?: () => Record<string, number>;
511
+ getBackendInfo?: () => Record<string, string | number | boolean>;
512
+
513
+ /**
514
+ * Creates a video player for the specified video file.
515
+ *
516
+ * @param uri The path to the video file.
517
+ * @param resolution If provided, the resolution to scale the video to.
518
+ * If not provided, the original resolution of the video will be used.
519
+ * Downscaling the video can improve performance.
520
+ * @returns The video player.
521
+ */
522
+ createVideoPlayer: (
523
+ uri: string,
524
+ resolution?: { width: number; height: number } | null,
525
+ options?: { textureMode?: VideoTextureMode } | null,
526
+ ) => VideoPlayer;
527
+ /**
528
+ * Creates a video composition frames extractor for the specified video composition.
529
+ * @param composition The video composition.
530
+ * @returns The video composition frames extractor.
531
+ */
532
+ createVideoCompositionFramesExtractor: (
533
+ /**
534
+ * The video composition to extract frames from.
535
+ */
536
+ composition: VideoComposition,
537
+ ) => VideoCompositionFramesExtractor;
538
+ /**
539
+ * Creates a synchronous video composition frames extractor for the specified video composition.
540
+ * @param composition The video composition.
541
+ * @returns The video composition frames extractor.
542
+ */
543
+ createVideoCompositionFramesExtractorSync: (
544
+ /**
545
+ * The video composition to extract frames from.
546
+ */
547
+ composition: VideoComposition,
548
+ ) => VideoCompositionFramesExtractorSync;
549
+
550
+ /**
551
+ * Creates a video composition encoder for the specified export options.
552
+ * @param options The export options for the video composition.
553
+ * @param composition The video composition being exported; used to encode
554
+ * the audio tracks of the composition items (if any).
555
+ * @returns The video composition encoder.
556
+ */
557
+ createVideoEncoder: (
558
+ /**
559
+ * The export options for the video composition.
560
+ */
561
+ options: ExportOptions,
562
+ /**
563
+ * The video composition being exported (used for audio encoding).
564
+ */
565
+ composition?: VideoComposition | null,
566
+ ) => VideoEncoder;
567
+ /**
568
+ * Runs the given function inside an autorelease pool. Worklet runtime
569
+ * threads never drain their autorelease pool, so any per-frame native
570
+ * garbage created by code running there would otherwise accumulate for the
571
+ * lifetime of the app.
572
+ *
573
+ * @platform ios
574
+ */
575
+ runWithAutoreleasePool?: <T>(fn: () => T) => T;
576
+ /**
577
+ * Returns the decoding capabilities of the current platform for the specified mimetype.
578
+ *
579
+ * @platform android
580
+ * @param mimetype The mimetype of the video.
581
+ */
582
+ getDecodingCapabilitiesFor(mimetype: string): {
583
+ /**
584
+ * The maximum number of instances that can be decoded simultaneously.
585
+ */
586
+ maxInstances: number;
587
+ /**
588
+ * The maximum width of the frame that the decoder will produce.
589
+ */
590
+ maxWidth: number;
591
+ /**
592
+ * The maximum height of the frame that the decoder will produce.
593
+ */
594
+ maxHeight: number;
595
+ } | null;
596
+
597
+ /**
598
+ * Whether the device can encode with the given codec.
599
+ *
600
+ * `h264` is always true. `hevc` depends on the hardware: an A10 or later on
601
+ * iOS, and a device dependent answer on Android, where HEVC decoding is far
602
+ * more common than HEVC encoding.
603
+ *
604
+ * Exports fall back to `h264` on their own when this returns false, so this
605
+ * is for the UI — hiding or disabling a codec the device cannot honour is
606
+ * better than accepting the choice and quietly ignoring it.
607
+ *
608
+ * @param codec The codec to test.
609
+ */
610
+ isEncodingSupported(codec: VideoCodec): boolean;
611
+
612
+ /**
613
+ * Given a set of encoder configurations,
614
+ * returns the closest supported configurations by the platform encoders.
615
+ *
616
+ * @param width The width of the video.
617
+ * @param height The height of the video.
618
+ * @param frameRate The frame rate of the video in frames per second.
619
+ * @param bitRate The bit rate of the video in bits per second.
620
+ * @param codec The codec the export will encode with, defaulting to `h264`.
621
+ * Pass the same value here and to {@link ExportOptions.codec}: the sizes and
622
+ * frame rates an H.264 encoder accepts say nothing about what the HEVC one on
623
+ * the same chip will take. A codec the device cannot encode falls back to
624
+ * `h264`, as an export would.
625
+ */
626
+ getValidEncoderConfigurations(
627
+ width: number,
628
+ height: number,
629
+ frameRate: number,
630
+ bitRate: number,
631
+ codec?: VideoCodec,
632
+ ):
633
+ | {
634
+ /**
635
+ * The name of the encoder.
636
+ * can be reused in the `exportVideoComposition` method.
637
+ */
638
+ encoderName: string;
639
+ /**
640
+ * Wether the encoder supports hardware acceleration.
641
+ */
642
+ hardwareAccelerated: boolean;
643
+ /**
644
+ * The width of the video.
645
+ */
646
+ width: number;
647
+ /**
648
+ * The height of the video.
649
+ */
650
+ height: number;
651
+ /**
652
+ * The frame rate of the video in frames per second.
653
+ */
654
+ frameRate: number;
655
+ /**
656
+ * The bit rate of the video in bits per second.
657
+ */
658
+ bitRate: number;
659
+ }[]
660
+ | null;
661
+ };
@@ -0,0 +1,22 @@
1
+ import { useEffect, useRef } from 'react';
2
+
3
+ const useEventListener = <TEvent extends string, Thandler>(
4
+ emitter: { on(event: TEvent, callback: Thandler): () => void } | null,
5
+ eventName: TEvent,
6
+ handler: any,
7
+ isCurrent?: () => boolean,
8
+ ) => {
9
+ const latest = useRef(handler);
10
+ latest.current = handler;
11
+ const enabled = Boolean(handler);
12
+ useEffect(() => {
13
+ if (!emitter || !enabled) return;
14
+ const callback = (...args: unknown[]) => {
15
+ if (isCurrent && !isCurrent()) return;
16
+ latest.current?.(...args);
17
+ };
18
+ return emitter.on(eventName, callback as Thandler);
19
+ }, [emitter, eventName, enabled, isCurrent]);
20
+ };
21
+
22
+ export default useEventListener;