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.
- package/LICENSE +22 -0
- package/README.md +303 -2
- package/android/BUILD_VALIDATION.md +62 -0
- package/android/CMakeLists.txt +99 -0
- package/android/build-validation.json +262 -0
- package/android/build.gradle +185 -0
- package/android/cpp/EncoderTargets.cpp +226 -0
- package/android/cpp/EncoderTargets.h +70 -0
- package/android/cpp/JNIHelpers.cpp +15 -0
- package/android/cpp/JNIHelpers.h +20 -0
- package/android/cpp/NativeEventDispatcher.cpp +59 -0
- package/android/cpp/NativeEventDispatcher.h +31 -0
- package/android/cpp/NativeHardwareBuffer.cpp +397 -0
- package/android/cpp/NativeHardwareBuffer.h +34 -0
- package/android/cpp/NativeRgbaBuffer.cpp +45 -0
- package/android/cpp/NativeRgbaBuffer.h +9 -0
- package/android/cpp/ReturnedVideoFrames.h +37 -0
- package/android/cpp/RgbaFrameLease.h +53 -0
- package/android/cpp/VideoCapabilities.cpp +87 -0
- package/android/cpp/VideoCapabilities.h +44 -0
- package/android/cpp/VideoComposition.cpp +170 -0
- package/android/cpp/VideoComposition.h +36 -0
- package/android/cpp/VideoCompositionFramesExtractor.cpp +82 -0
- package/android/cpp/VideoCompositionFramesExtractor.h +48 -0
- package/android/cpp/VideoCompositionFramesExtractorHostObject.cpp +230 -0
- package/android/cpp/VideoCompositionFramesExtractorHostObject.h +42 -0
- package/android/cpp/VideoCompositionFramesExtractorSyncHostObject.cpp +133 -0
- package/android/cpp/VideoCompositionFramesExtractorSyncHostObject.h +46 -0
- package/android/cpp/VideoEncoderHostObject.cpp +318 -0
- package/android/cpp/VideoEncoderHostObject.h +76 -0
- package/android/cpp/VideoFrame.cpp +293 -0
- package/android/cpp/VideoFrame.h +27 -0
- package/android/cpp/VideoPlayer.cpp +96 -0
- package/android/cpp/VideoPlayer.h +52 -0
- package/android/cpp/VideoPlayerHostObject.cpp +225 -0
- package/android/cpp/VideoPlayerHostObject.h +43 -0
- package/android/cpp/cpp-adapter.cpp +316 -0
- package/android/gradle.properties +5 -0
- package/android/instrumentation-inventory.json +178 -0
- package/android/proguard-rules.pro +4 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/azzapp/rnskv/AudioCompositionExporter.java +537 -0
- package/android/src/main/java/com/azzapp/rnskv/AudioCompositionPlayer.java +321 -0
- package/android/src/main/java/com/azzapp/rnskv/BufferLifetime.java +55 -0
- package/android/src/main/java/com/azzapp/rnskv/DecodeRequests.java +100 -0
- package/android/src/main/java/com/azzapp/rnskv/DecoderWindow.java +55 -0
- package/android/src/main/java/com/azzapp/rnskv/DisplayVsyncPeriod.java +72 -0
- package/android/src/main/java/com/azzapp/rnskv/EGLResourcesHolder.java +132 -0
- package/android/src/main/java/com/azzapp/rnskv/EGLUtils.java +225 -0
- package/android/src/main/java/com/azzapp/rnskv/FrameSize.java +50 -0
- package/android/src/main/java/com/azzapp/rnskv/GLFrameExtractor.java +510 -0
- package/android/src/main/java/com/azzapp/rnskv/JNIHelpers.java +12 -0
- package/android/src/main/java/com/azzapp/rnskv/NativeEventDispatcher.java +25 -0
- package/android/src/main/java/com/azzapp/rnskv/NativeHardwareBuffer.java +62 -0
- package/android/src/main/java/com/azzapp/rnskv/NativeRgbaBuffer.java +43 -0
- package/android/src/main/java/com/azzapp/rnskv/ReactNativeSkiaVideoModule.java +45 -0
- package/android/src/main/java/com/azzapp/rnskv/ReactNativeSkiaVideoPackage.java +43 -0
- package/android/src/main/java/com/azzapp/rnskv/ReactNativeSkiaVideoSpec.java +9 -0
- package/android/src/main/java/com/azzapp/rnskv/RgbaBufferAllocator.java +114 -0
- package/android/src/main/java/com/azzapp/rnskv/RgbaLayout.java +33 -0
- package/android/src/main/java/com/azzapp/rnskv/SurfaceOutputPolicy.java +13 -0
- package/android/src/main/java/com/azzapp/rnskv/TextureRenderer.java +150 -0
- package/android/src/main/java/com/azzapp/rnskv/TimeHelpers.java +11 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoCapabilities.java +354 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoComposition.java +147 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoCompositionDecoder.java +779 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoCompositionFramesExtractor.java +463 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoCompositionFramesExtractorSync.java +241 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoCompositionItemDecoder.java +492 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoEncoder.java +639 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoFrame.java +74 -0
- package/android/src/main/java/com/azzapp/rnskv/VideoPlayer.java +361 -0
- package/cpp/RNSVCheckedSizes.h +54 -0
- package/cpp/RNSVEventEmitter.cpp +199 -0
- package/cpp/RNSVEventEmitter.h +31 -0
- package/cpp/RNSVHostObject.cpp +79 -0
- package/cpp/RNSVHostObject.h +67 -0
- package/cpp/RNSVMemoryBudget.cpp +68 -0
- package/cpp/RNSVMemoryBudget.h +100 -0
- package/cpp/RNSVRuntimeLifecycleMonitor.cpp +88 -0
- package/cpp/RNSVRuntimeLifecycleMonitor.h +33 -0
- package/docs/ANDROID_DEVICE_306.md +95 -0
- package/docs/ANDROID_EXPORT_CACHE_306.md +48 -0
- package/docs/ANDROID_MEMORY_RETENTION_306.md +67 -0
- package/docs/BENCHMARKS.md +368 -0
- package/docs/IOS_DEVICE_TESTS.md +115 -0
- package/docs/IOS_SIMULATOR_TESTS.md +74 -0
- package/docs/MIGRATION.md +82 -0
- package/docs/NATIVE_MEMORY_INVESTIGATION_306.md +88 -0
- package/docs/PERFORMANCE_AB_IPHONE_303.md +196 -0
- package/docs/PERFORMANCE_AB_SIMULATOR.md +135 -0
- package/docs/PERFORMANCE_AB_SOAK_SIMULATOR.md +84 -0
- package/docs/PERFORMANCE_IPHONE_306_OPTIMIZATION.md +76 -0
- package/docs/PERFORMANCE_SIMULATOR.md +89 -0
- package/docs/PERFORMANCE_SIMULATOR_INITIAL.md +96 -0
- package/docs/PERFORMANCE_SOAK_IPHONE_303.md +41 -0
- package/docs/UPSTREAM_NOTES.md +188 -0
- package/docs/assets/banner.svg +26 -0
- package/examples/webgpu-overlay.ts +147 -0
- package/ios/AVAssetTrackUtils.h +24 -0
- package/ios/AudioCompositionUtils.h +27 -0
- package/ios/AudioCompositionUtils.mm +113 -0
- package/ios/DecoderWindow.h +52 -0
- package/ios/NativeResourceStats.h +32 -0
- package/ios/RNSVColorSpace.h +50 -0
- package/ios/RNSVJSIUtils.h +46 -0
- package/ios/RNSVScopedPixelBuffer.h +17 -0
- package/ios/RNSVVideoPlayer.h +46 -0
- package/ios/RNSVVideoPlayer.mm +410 -0
- package/ios/ReactNativeSkiaVideo.h +8 -0
- package/ios/ReactNativeSkiaVideo.mm +310 -0
- package/ios/SeekPolicy.h +27 -0
- package/ios/VideoComposition.h +148 -0
- package/ios/VideoCompositionFramesExtractorHostObject.h +105 -0
- package/ios/VideoCompositionFramesExtractorHostObject.mm +686 -0
- package/ios/VideoCompositionFramesExtractorSyncHostObject.h +37 -0
- package/ios/VideoCompositionFramesExtractorSyncHostObject.mm +168 -0
- package/ios/VideoCompositionItemDecoder.h +60 -0
- package/ios/VideoCompositionItemDecoder.mm +480 -0
- package/ios/VideoEncoderHostObject.h +83 -0
- package/ios/VideoEncoderHostObject.mm +706 -0
- package/ios/VideoFrame.h +66 -0
- package/ios/VideoFrame.mm +108 -0
- package/ios/VideoPlayerHostObject.h +52 -0
- package/ios/VideoPlayerHostObject.mm +332 -0
- package/lib/module/NativeReactNativeSkiaVideo.js +5 -0
- package/lib/module/NativeReactNativeSkiaVideo.js.map +1 -0
- package/lib/module/RNSkiaVideoModule.js +20 -0
- package/lib/module/RNSkiaVideoModule.js.map +1 -0
- package/lib/module/canvas.js +18 -0
- package/lib/module/canvas.js.map +1 -0
- package/lib/module/exportCache.js +22 -0
- package/lib/module/exportCache.js.map +1 -0
- package/lib/module/exportFrames.js +338 -0
- package/lib/module/exportFrames.js.map +1 -0
- package/lib/module/exportQueue.js +52 -0
- package/lib/module/exportQueue.js.map +1 -0
- package/lib/module/exportTarget.js +137 -0
- package/lib/module/exportTarget.js.map +1 -0
- package/lib/module/exportVideoComposition.js +492 -0
- package/lib/module/exportVideoComposition.js.map +1 -0
- package/lib/module/frameInterop.js +532 -0
- package/lib/module/frameInterop.js.map +1 -0
- package/lib/module/gpu.js +222 -0
- package/lib/module/gpu.js.map +1 -0
- package/lib/module/gpuDevice.js +54 -0
- package/lib/module/gpuDevice.js.map +1 -0
- package/lib/module/index.js +36 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/memory.js +38 -0
- package/lib/module/memory.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/previewLifecycle.js +52 -0
- package/lib/module/previewLifecycle.js.map +1 -0
- package/lib/module/runtimeYield.js +10 -0
- package/lib/module/runtimeYield.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/module/utils/useEventListener.js +18 -0
- package/lib/module/utils/useEventListener.js.map +1 -0
- package/lib/module/videoCompositionPlayer.js +368 -0
- package/lib/module/videoCompositionPlayer.js.map +1 -0
- package/lib/module/videoFrameImage.js +185 -0
- package/lib/module/videoFrameImage.js.map +1 -0
- package/lib/module/videoPlayer.js +172 -0
- package/lib/module/videoPlayer.js.map +1 -0
- package/lib/module/yuvBlit.js +299 -0
- package/lib/module/yuvBlit.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeReactNativeSkiaVideo.d.ts +7 -0
- package/lib/typescript/src/NativeReactNativeSkiaVideo.d.ts.map +1 -0
- package/lib/typescript/src/RNSkiaVideoModule.d.ts +4 -0
- package/lib/typescript/src/RNSkiaVideoModule.d.ts.map +1 -0
- package/lib/typescript/src/canvas.d.ts +4 -0
- package/lib/typescript/src/canvas.d.ts.map +1 -0
- package/lib/typescript/src/exportCache.d.ts +6 -0
- package/lib/typescript/src/exportCache.d.ts.map +1 -0
- package/lib/typescript/src/exportFrames.d.ts +57 -0
- package/lib/typescript/src/exportFrames.d.ts.map +1 -0
- package/lib/typescript/src/exportQueue.d.ts +5 -0
- package/lib/typescript/src/exportQueue.d.ts.map +1 -0
- package/lib/typescript/src/exportTarget.d.ts +28 -0
- package/lib/typescript/src/exportTarget.d.ts.map +1 -0
- package/lib/typescript/src/exportVideoComposition.d.ts +68 -0
- package/lib/typescript/src/exportVideoComposition.d.ts.map +1 -0
- package/lib/typescript/src/frameInterop.d.ts +17 -0
- package/lib/typescript/src/frameInterop.d.ts.map +1 -0
- package/lib/typescript/src/gpu.d.ts +39 -0
- package/lib/typescript/src/gpu.d.ts.map +1 -0
- package/lib/typescript/src/gpuDevice.d.ts +11 -0
- package/lib/typescript/src/gpuDevice.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +21 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/memory.d.ts +25 -0
- package/lib/typescript/src/memory.d.ts.map +1 -0
- package/lib/typescript/src/previewLifecycle.d.ts +22 -0
- package/lib/typescript/src/previewLifecycle.d.ts.map +1 -0
- package/lib/typescript/src/runtimeYield.d.ts +4 -0
- package/lib/typescript/src/runtimeYield.d.ts.map +1 -0
- package/lib/typescript/src/types.d.ts +631 -0
- package/lib/typescript/src/types.d.ts.map +1 -0
- package/lib/typescript/src/utils/useEventListener.d.ts +5 -0
- package/lib/typescript/src/utils/useEventListener.d.ts.map +1 -0
- package/lib/typescript/src/videoCompositionPlayer.d.ts +105 -0
- package/lib/typescript/src/videoCompositionPlayer.d.ts.map +1 -0
- package/lib/typescript/src/videoFrameImage.d.ts +60 -0
- package/lib/typescript/src/videoFrameImage.d.ts.map +1 -0
- package/lib/typescript/src/videoPlayer.d.ts +99 -0
- package/lib/typescript/src/videoPlayer.d.ts.map +1 -0
- package/lib/typescript/src/yuvBlit.d.ts +50 -0
- package/lib/typescript/src/yuvBlit.d.ts.map +1 -0
- package/package.json +155 -4
- package/patches/react-native-skia+3.7.0.patch +502 -0
- package/react-native-skia-webgpu-video.podspec +35 -0
- package/scripts/apply-skia-canvas-patch.mjs +48 -0
- package/scripts/skia-canvas-patch.json +291 -0
- package/src/NativeReactNativeSkiaVideo.ts +8 -0
- package/src/RNSkiaVideoModule.ts +27 -0
- package/src/canvas.ts +22 -0
- package/src/exportCache.ts +27 -0
- package/src/exportFrames.ts +421 -0
- package/src/exportQueue.ts +65 -0
- package/src/exportTarget.ts +179 -0
- package/src/exportVideoComposition.ts +718 -0
- package/src/frameInterop.ts +684 -0
- package/src/gpu.ts +290 -0
- package/src/gpuDevice.ts +80 -0
- package/src/index.tsx +45 -0
- package/src/memory.ts +48 -0
- package/src/previewLifecycle.ts +60 -0
- package/src/runtimeYield.ts +6 -0
- package/src/types.ts +661 -0
- package/src/utils/useEventListener.ts +22 -0
- package/src/videoCompositionPlayer.ts +568 -0
- package/src/videoFrameImage.ts +205 -0
- package/src/videoPlayer.ts +318 -0
- package/src/yuvBlit.ts +331 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
package com.azzapp.rnskv;
|
|
2
|
+
|
|
3
|
+
import android.opengl.EGL14;
|
|
4
|
+
import android.opengl.EGLExt;
|
|
5
|
+
import android.view.Surface;
|
|
6
|
+
|
|
7
|
+
import java.util.function.Supplier;
|
|
8
|
+
import javax.microedition.khronos.egl.EGL10;
|
|
9
|
+
import javax.microedition.khronos.egl.EGLConfig;
|
|
10
|
+
import javax.microedition.khronos.egl.EGLContext;
|
|
11
|
+
import javax.microedition.khronos.egl.EGLDisplay;
|
|
12
|
+
import javax.microedition.khronos.egl.EGLSurface;
|
|
13
|
+
|
|
14
|
+
/** A session-owned EGL context. The display is process-owned and is never terminated here. */
|
|
15
|
+
public final class EGLResourcesHolder {
|
|
16
|
+
private final EGL10 egl;
|
|
17
|
+
private final EGLDisplay display;
|
|
18
|
+
private final EGLContext context;
|
|
19
|
+
private final EGLSurface surface;
|
|
20
|
+
private boolean released;
|
|
21
|
+
|
|
22
|
+
public static EGLResourcesHolder createWithWindowedSurface(EGLContext sharedContext, Surface surface) {
|
|
23
|
+
return create(sharedContext, surface);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public static EGLResourcesHolder createWithPBBufferSurface(EGLContext sharedContext) {
|
|
27
|
+
return create(sharedContext, null);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
private static EGLResourcesHolder create(EGLContext sharedContext, Surface window) {
|
|
31
|
+
EGL10 egl = (EGL10) EGLContext.getEGL();
|
|
32
|
+
EGLDisplay display = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
|
|
33
|
+
if (display == EGL10.EGL_NO_DISPLAY || !egl.eglInitialize(display, new int[2])) {
|
|
34
|
+
throw new IllegalStateException("Could not initialize the video EGL display");
|
|
35
|
+
}
|
|
36
|
+
EGLContext context = EGL10.EGL_NO_CONTEXT;
|
|
37
|
+
EGLSurface surface = EGL10.EGL_NO_SURFACE;
|
|
38
|
+
try {
|
|
39
|
+
int[] attributes = window == null ? new int[]{
|
|
40
|
+
EGL10.EGL_RED_SIZE, 8, EGL10.EGL_GREEN_SIZE, 8, EGL10.EGL_BLUE_SIZE, 8,
|
|
41
|
+
EGL10.EGL_ALPHA_SIZE, 8, EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
|
|
42
|
+
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, EGL10.EGL_NONE
|
|
43
|
+
} : new int[]{
|
|
44
|
+
EGL10.EGL_RED_SIZE, 8, EGL10.EGL_GREEN_SIZE, 8, EGL10.EGL_BLUE_SIZE, 8,
|
|
45
|
+
EGL10.EGL_ALPHA_SIZE, 8, EGL10.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
|
|
46
|
+
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
|
|
47
|
+
EGLUtils.EGL_RECORDABLE_ANDROID, 1, EGL10.EGL_NONE
|
|
48
|
+
};
|
|
49
|
+
EGLConfig[] configs = new EGLConfig[1];
|
|
50
|
+
int[] count = new int[1];
|
|
51
|
+
if (!egl.eglChooseConfig(display, attributes, configs, 1, count) || count[0] == 0) {
|
|
52
|
+
throw new IllegalStateException("No video EGL config found");
|
|
53
|
+
}
|
|
54
|
+
context = egl.eglCreateContext(display, configs[0], sharedContext,
|
|
55
|
+
new int[]{EGLUtils.EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE});
|
|
56
|
+
if (context == EGL10.EGL_NO_CONTEXT) {
|
|
57
|
+
throw new IllegalStateException("Could not create video EGL context");
|
|
58
|
+
}
|
|
59
|
+
surface = window == null
|
|
60
|
+
? egl.eglCreatePbufferSurface(display, configs[0],
|
|
61
|
+
new int[]{EGL10.EGL_WIDTH, 1, EGL10.EGL_HEIGHT, 1, EGL10.EGL_NONE})
|
|
62
|
+
: egl.eglCreateWindowSurface(display, configs[0], window, new int[]{EGL10.EGL_NONE});
|
|
63
|
+
if (surface == EGL10.EGL_NO_SURFACE) {
|
|
64
|
+
throw new IllegalStateException("Could not create video EGL surface");
|
|
65
|
+
}
|
|
66
|
+
return new EGLResourcesHolder(egl, display, context, surface);
|
|
67
|
+
} catch (RuntimeException error) {
|
|
68
|
+
if (surface != EGL10.EGL_NO_SURFACE) egl.eglDestroySurface(display, surface);
|
|
69
|
+
if (context != EGL10.EGL_NO_CONTEXT) egl.eglDestroyContext(display, context);
|
|
70
|
+
throw error;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
private EGLResourcesHolder(EGL10 egl, EGLDisplay display, EGLContext context, EGLSurface surface) {
|
|
75
|
+
this.egl = egl;
|
|
76
|
+
this.display = display;
|
|
77
|
+
this.context = context;
|
|
78
|
+
this.surface = surface;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public boolean makeCurrent() {
|
|
82
|
+
if (released || !egl.eglMakeCurrent(display, surface, surface, context)) {
|
|
83
|
+
throw new IllegalStateException("Could not bind video EGL context");
|
|
84
|
+
}
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Always detach our context before returning, including when the caller has no EGL context. */
|
|
89
|
+
public <T> T withContextCurrent(Supplier<T> action) {
|
|
90
|
+
android.opengl.EGLDisplay previousDisplay = EGL14.eglGetCurrentDisplay();
|
|
91
|
+
android.opengl.EGLContext previousContext = EGL14.eglGetCurrentContext();
|
|
92
|
+
android.opengl.EGLSurface previousDraw = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
|
|
93
|
+
android.opengl.EGLSurface previousRead = EGL14.eglGetCurrentSurface(EGL14.EGL_READ);
|
|
94
|
+
makeCurrent();
|
|
95
|
+
try {
|
|
96
|
+
return action.get();
|
|
97
|
+
} finally {
|
|
98
|
+
if (!EGL14.EGL_NO_CONTEXT.equals(previousContext)) {
|
|
99
|
+
if (!EGL14.eglMakeCurrent(previousDisplay, previousDraw, previousRead, previousContext)) {
|
|
100
|
+
throw new IllegalStateException("Could not restore the caller's EGL context");
|
|
101
|
+
}
|
|
102
|
+
} else if (!egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE,
|
|
103
|
+
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT)) {
|
|
104
|
+
throw new IllegalStateException("Could not detach video EGL context");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
public void runWithContextCurrent(Runnable action) {
|
|
110
|
+
withContextCurrent(() -> { action.run(); return null; });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
public boolean swapBuffers() { return egl.eglSwapBuffers(display, surface); }
|
|
114
|
+
|
|
115
|
+
public void setPresentationTime(long nanoseconds) {
|
|
116
|
+
if (!EGLExt.eglPresentationTimeANDROID(EGL14.eglGetCurrentDisplay(),
|
|
117
|
+
EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW), nanoseconds)) {
|
|
118
|
+
throw new IllegalStateException("Could not timestamp video encoder surface");
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
public void release() {
|
|
123
|
+
if (released) return;
|
|
124
|
+
if (egl.eglGetCurrentContext().equals(context)) {
|
|
125
|
+
egl.eglMakeCurrent(display, EGL10.EGL_NO_SURFACE,
|
|
126
|
+
EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
|
|
127
|
+
}
|
|
128
|
+
egl.eglDestroySurface(display, surface);
|
|
129
|
+
egl.eglDestroyContext(display, context);
|
|
130
|
+
released = true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
package com.azzapp.rnskv;
|
|
2
|
+
|
|
3
|
+
import android.graphics.Bitmap;
|
|
4
|
+
import android.opengl.GLES20;
|
|
5
|
+
import android.opengl.GLU;
|
|
6
|
+
import android.opengl.Matrix;
|
|
7
|
+
import android.util.Log;
|
|
8
|
+
|
|
9
|
+
import java.nio.ByteBuffer;
|
|
10
|
+
import java.nio.ByteOrder;
|
|
11
|
+
import java.nio.FloatBuffer;
|
|
12
|
+
|
|
13
|
+
import javax.microedition.khronos.egl.EGL10;
|
|
14
|
+
import javax.microedition.khronos.egl.EGLContext;
|
|
15
|
+
|
|
16
|
+
public class EGLUtils {
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* The EGL constant for the client version of the context.
|
|
20
|
+
*/
|
|
21
|
+
public static final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* The EGL constant for the recordable attribute.
|
|
25
|
+
*/
|
|
26
|
+
public static final int EGL_RECORDABLE_ANDROID = 0x3142;
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
public static final float[] IDENTITY_MATRIX = new float[16];
|
|
30
|
+
|
|
31
|
+
static {
|
|
32
|
+
Matrix.setIdentityM(IDENTITY_MATRIX, 0);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
static public EGLContext getCurrentContextOrThrows() {
|
|
36
|
+
EGLContext context = ((EGL10) EGLContext.getEGL()).eglGetCurrentContext();
|
|
37
|
+
if (context == EGL10.EGL_NO_CONTEXT) {
|
|
38
|
+
throw new RuntimeException("Skia context is not initialized");
|
|
39
|
+
}
|
|
40
|
+
return context;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Create an OpenGL program from the given vertex and fragment shaders.
|
|
45
|
+
*
|
|
46
|
+
* @param vertexSource the vertex shader source code
|
|
47
|
+
* @param fragmentSource the fragment shader source code
|
|
48
|
+
* @return the program identifier
|
|
49
|
+
*/
|
|
50
|
+
public static int createProgram(String vertexSource, String fragmentSource) {
|
|
51
|
+
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexSource);
|
|
52
|
+
if (vertexShader == 0) {
|
|
53
|
+
return 0;
|
|
54
|
+
}
|
|
55
|
+
int fragmentShared = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentSource);
|
|
56
|
+
if (fragmentShared == 0) {
|
|
57
|
+
GLES20.glDeleteShader(vertexShader);
|
|
58
|
+
return 0;
|
|
59
|
+
}
|
|
60
|
+
int program = GLES20.glCreateProgram();
|
|
61
|
+
try {
|
|
62
|
+
if (program == 0) {
|
|
63
|
+
throw new IllegalStateException("Could not allocate GL program");
|
|
64
|
+
}
|
|
65
|
+
GLES20.glAttachShader(program, vertexShader);
|
|
66
|
+
GLES20.glAttachShader(program, fragmentShared);
|
|
67
|
+
GLES20.glLinkProgram(program);
|
|
68
|
+
int[] linkStatus = new int[1];
|
|
69
|
+
GLES20.glGetProgramiv(
|
|
70
|
+
program, GLES20.GL_LINK_STATUS, linkStatus,
|
|
71
|
+
0
|
|
72
|
+
);
|
|
73
|
+
if (linkStatus[0] != GLES20.GL_TRUE) {
|
|
74
|
+
String info = GLES20.glGetProgramInfoLog(program);
|
|
75
|
+
GLES20.glDeleteProgram(program);
|
|
76
|
+
throw new RuntimeException("Could not link program: " + info);
|
|
77
|
+
}
|
|
78
|
+
return program;
|
|
79
|
+
} finally {
|
|
80
|
+
// Linked programs retain their compiled code. The shader objects are
|
|
81
|
+
// independent allocations and must not accumulate over mount cycles.
|
|
82
|
+
GLES20.glDeleteShader(vertexShader);
|
|
83
|
+
GLES20.glDeleteShader(fragmentShared);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Load a shader from the given source code.
|
|
89
|
+
*
|
|
90
|
+
* @param shaderType the type of the shader, e.g. {@link GLES20#GL_VERTEX_SHADER} or
|
|
91
|
+
* {@link GLES20#GL_FRAGMENT_SHADER}
|
|
92
|
+
* @param source the source code of the shader
|
|
93
|
+
* @return the shader identifier
|
|
94
|
+
*/
|
|
95
|
+
public static int loadShader(int shaderType, String source) {
|
|
96
|
+
int shader = GLES20.glCreateShader(shaderType);
|
|
97
|
+
if (shader != 0) {
|
|
98
|
+
GLES20.glShaderSource(shader, source);
|
|
99
|
+
GLES20.glCompileShader(shader);
|
|
100
|
+
int[] compiled = new int[1];
|
|
101
|
+
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
|
102
|
+
if (compiled[0] == 0) {
|
|
103
|
+
String info = GLES20.glGetShaderInfoLog(shader);
|
|
104
|
+
GLES20.glDeleteShader(shader);
|
|
105
|
+
throw new RuntimeException("Could not compile shader " + shaderType + ":" + info);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return shader;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Create a float buffer from the given values.
|
|
113
|
+
*
|
|
114
|
+
* @param values the values to put in the buffer
|
|
115
|
+
* @return the float buffer
|
|
116
|
+
*/
|
|
117
|
+
public static FloatBuffer createFloatBuffer(float... values) {
|
|
118
|
+
ByteBuffer byteBuffer = ByteBuffer.allocateDirect(
|
|
119
|
+
values.length * 4
|
|
120
|
+
);
|
|
121
|
+
byteBuffer.order(ByteOrder.nativeOrder());
|
|
122
|
+
FloatBuffer floatBuffer = byteBuffer.asFloatBuffer();
|
|
123
|
+
floatBuffer.put(values);
|
|
124
|
+
floatBuffer.position(0);
|
|
125
|
+
return floatBuffer;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Purge all OpenGL errors.
|
|
131
|
+
* Useful to call this method before starting a new OpenGL operation.
|
|
132
|
+
* Especially since react-native-skia seems to leave some errors behind.
|
|
133
|
+
*/
|
|
134
|
+
public static void purgeOpenGLError() {
|
|
135
|
+
int i = 0;
|
|
136
|
+
while (true) {
|
|
137
|
+
if (GLES20.glGetError() == GLES20.GL_NO_ERROR || i >= 9) {
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
i++;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Check for OpenGL errors and throw an exception if an error is found.
|
|
146
|
+
*
|
|
147
|
+
* @param prefix the prefix to add to the error message
|
|
148
|
+
*/
|
|
149
|
+
public static void checkGlError(String prefix) {
|
|
150
|
+
StringBuilder errorMessageBuilder = new StringBuilder();
|
|
151
|
+
boolean foundError = false;
|
|
152
|
+
int error;
|
|
153
|
+
if (prefix != null) {
|
|
154
|
+
errorMessageBuilder.append(prefix).append(": ");
|
|
155
|
+
}
|
|
156
|
+
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
|
|
157
|
+
if (foundError) {
|
|
158
|
+
errorMessageBuilder.append('\n');
|
|
159
|
+
}
|
|
160
|
+
String errorString = GLU.gluErrorString(error);
|
|
161
|
+
if (errorString == null) {
|
|
162
|
+
errorString = "error code: 0x" + Integer.toHexString(error);
|
|
163
|
+
} else {
|
|
164
|
+
errorString = "error code: 0x" + Integer.toHexString(error) + " " + errorString;
|
|
165
|
+
}
|
|
166
|
+
errorMessageBuilder.append("glError: ").append(errorString);
|
|
167
|
+
foundError = true;
|
|
168
|
+
}
|
|
169
|
+
if (foundError) {
|
|
170
|
+
if (BuildConfig.DEBUG) {
|
|
171
|
+
throw new RuntimeException(errorMessageBuilder.toString());
|
|
172
|
+
} else {
|
|
173
|
+
Log.e("RNSkiaVideo", errorMessageBuilder.toString());
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Binds the texture of the given type with default configuration of GL_LINEAR filtering and
|
|
180
|
+
* GL_CLAMP_TO_EDGE wrapping.
|
|
181
|
+
*
|
|
182
|
+
* @param target The target to which the texture is bound, e.g. {@link GLES20#GL_TEXTURE_2D}
|
|
183
|
+
* for a two-dimensional texture or {@link android.opengl.GLES11Ext#GL_TEXTURE_EXTERNAL_OES}
|
|
184
|
+
* for an external texture.
|
|
185
|
+
* @param texId The texture identifier.
|
|
186
|
+
*/
|
|
187
|
+
public static void configureTexture(int target, int texId) {
|
|
188
|
+
GLES20.glBindTexture(target, texId);
|
|
189
|
+
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
|
|
190
|
+
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
|
|
191
|
+
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
|
192
|
+
GLES20.glTexParameteri(target, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Save the texture to a bitmap. (Useful for debugging purposes)
|
|
197
|
+
*
|
|
198
|
+
* @param texture the texture identifier
|
|
199
|
+
* @param width the width of the texture
|
|
200
|
+
* @param height the height of the texture
|
|
201
|
+
*/
|
|
202
|
+
public static Bitmap saveTexture(int texture, int width, int height) {
|
|
203
|
+
int[] frame = new int[1];
|
|
204
|
+
GLES20.glGenFramebuffers(1, frame, 0);
|
|
205
|
+
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frame[0]);
|
|
206
|
+
GLES20.glFramebufferTexture2D(
|
|
207
|
+
GLES20.GL_FRAMEBUFFER,
|
|
208
|
+
GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, texture,
|
|
209
|
+
0
|
|
210
|
+
);
|
|
211
|
+
ByteBuffer buffer = ByteBuffer.allocate(width * height * 4);
|
|
212
|
+
GLES20.glReadPixels(
|
|
213
|
+
0, 0, width, height, GLES20.GL_RGBA,
|
|
214
|
+
GLES20.GL_UNSIGNED_BYTE, buffer
|
|
215
|
+
);
|
|
216
|
+
Bitmap bitmap = Bitmap.createBitmap(
|
|
217
|
+
width, height,
|
|
218
|
+
Bitmap.Config.ARGB_8888
|
|
219
|
+
);
|
|
220
|
+
bitmap.copyPixelsFromBuffer(buffer);
|
|
221
|
+
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
|
222
|
+
GLES20.glDeleteFramebuffers(1, frame, 0);
|
|
223
|
+
return bitmap;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
package com.azzapp.rnskv;
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The size an item's frames are drawn out at, in display orientation.
|
|
5
|
+
* Pure arithmetic, apart from the GL work that uses it.
|
|
6
|
+
*/
|
|
7
|
+
final class FrameSize {
|
|
8
|
+
|
|
9
|
+
private FrameSize() {
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* @param width an explicit width in the file's encoded orientation, or 0
|
|
14
|
+
* @param height an explicit height in the file's encoded orientation, or 0
|
|
15
|
+
* @param maxLongSide a cap on the longest side, or 0; ignored when a size is
|
|
16
|
+
* given, and never upscales
|
|
17
|
+
* @param videoWidth the decoder's encoded width
|
|
18
|
+
* @param videoHeight the decoder's encoded height
|
|
19
|
+
* @param rotation the file's rotation in degrees
|
|
20
|
+
* @return {width, height}, swapped for a file turned by 90 or 270 degrees
|
|
21
|
+
*/
|
|
22
|
+
static int[] of(
|
|
23
|
+
int width,
|
|
24
|
+
int height,
|
|
25
|
+
int maxLongSide,
|
|
26
|
+
int videoWidth,
|
|
27
|
+
int videoHeight,
|
|
28
|
+
int rotation
|
|
29
|
+
) {
|
|
30
|
+
int w = videoWidth;
|
|
31
|
+
int h = videoHeight;
|
|
32
|
+
if (width > 0 && height > 0) {
|
|
33
|
+
w = width;
|
|
34
|
+
h = height;
|
|
35
|
+
} else if (maxLongSide > 0 && Math.max(w, h) > maxLongSide) {
|
|
36
|
+
double scale = (double) maxLongSide / Math.max(w, h);
|
|
37
|
+
// Even, as on iOS: hardware scalers dislike odd sizes.
|
|
38
|
+
w = even(w * scale);
|
|
39
|
+
h = even(h * scale);
|
|
40
|
+
}
|
|
41
|
+
if (rotation == 90 || rotation == 270) {
|
|
42
|
+
return new int[]{h, w};
|
|
43
|
+
}
|
|
44
|
+
return new int[]{w, h};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
private static int even(double value) {
|
|
48
|
+
return Math.max(2, (int) Math.round(value / 2) * 2);
|
|
49
|
+
}
|
|
50
|
+
}
|