@shopify/react-native-skia 1.2.1 → 1.2.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.cpp +34 -14
  2. package/android/cpp/rnskia-android/SkiaOpenGLSurfaceFactory.h +2 -1
  3. package/android/src/main/java/com/shopify/reactnative/skia/ViewScreenshotService.java +13 -8
  4. package/cpp/api/JsiSkImageFactory.h +3 -3
  5. package/cpp/rnskia/RNSkPlatformContext.h +3 -3
  6. package/ios/RNSkia-iOS/RNSkiOSPlatformContext.mm +2 -6
  7. package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.h +42 -7
  8. package/ios/RNSkia-iOS/SkiaCVPixelBufferUtils.mm +178 -5
  9. package/ios/RNSkia-iOS/SkiaMetalSurfaceFactory.mm +10 -13
  10. package/lib/commonjs/external/ModuleProxy.d.ts +10 -0
  11. package/lib/commonjs/external/ModuleProxy.js +36 -0
  12. package/lib/commonjs/external/ModuleProxy.js.map +1 -0
  13. package/lib/commonjs/external/reanimated/ReanimatedProxy.d.ts +3 -0
  14. package/lib/commonjs/external/reanimated/ReanimatedProxy.js +18 -0
  15. package/lib/commonjs/external/reanimated/ReanimatedProxy.js.map +1 -0
  16. package/lib/commonjs/external/reanimated/buffers.js +9 -6
  17. package/lib/commonjs/external/reanimated/buffers.js.map +1 -1
  18. package/lib/commonjs/external/reanimated/interpolators.js +8 -7
  19. package/lib/commonjs/external/reanimated/interpolators.js.map +1 -1
  20. package/lib/commonjs/external/reanimated/renderHelpers.js +27 -11
  21. package/lib/commonjs/external/reanimated/renderHelpers.js.map +1 -1
  22. package/lib/commonjs/external/reanimated/textures.js +4 -3
  23. package/lib/commonjs/external/reanimated/textures.js.map +1 -1
  24. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js +6 -6
  25. package/lib/commonjs/external/reanimated/useAnimatedImageValue.js.map +1 -1
  26. package/lib/commonjs/external/reanimated/useDerivedValueOnJS.js +6 -5
  27. package/lib/commonjs/external/reanimated/useDerivedValueOnJS.js.map +1 -1
  28. package/lib/commonjs/renderer/Offscreen.js +1 -5
  29. package/lib/commonjs/renderer/Offscreen.js.map +1 -1
  30. package/lib/commonjs/skia/types/Image/ImageFactory.d.ts +3 -3
  31. package/lib/commonjs/skia/types/Image/ImageFactory.js.map +1 -1
  32. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.d.ts +3 -3
  33. package/lib/commonjs/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
  34. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.d.ts +1 -1
  35. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js +1 -1
  36. package/lib/commonjs/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
  37. package/lib/commonjs/specs/NativeSkiaModule.web.d.ts +0 -2
  38. package/lib/commonjs/specs/NativeSkiaModule.web.js +0 -8
  39. package/lib/commonjs/specs/NativeSkiaModule.web.js.map +1 -1
  40. package/lib/module/external/ModuleProxy.d.ts +10 -0
  41. package/lib/module/external/ModuleProxy.js +28 -0
  42. package/lib/module/external/ModuleProxy.js.map +1 -0
  43. package/lib/module/external/reanimated/ReanimatedProxy.d.ts +3 -0
  44. package/lib/module/external/reanimated/ReanimatedProxy.js +12 -0
  45. package/lib/module/external/reanimated/ReanimatedProxy.js.map +1 -0
  46. package/lib/module/external/reanimated/buffers.js +8 -6
  47. package/lib/module/external/reanimated/buffers.js.map +1 -1
  48. package/lib/module/external/reanimated/interpolators.js +7 -7
  49. package/lib/module/external/reanimated/interpolators.js.map +1 -1
  50. package/lib/module/external/reanimated/renderHelpers.js +26 -11
  51. package/lib/module/external/reanimated/renderHelpers.js.map +1 -1
  52. package/lib/module/external/reanimated/textures.js +3 -3
  53. package/lib/module/external/reanimated/textures.js.map +1 -1
  54. package/lib/module/external/reanimated/useAnimatedImageValue.js +5 -6
  55. package/lib/module/external/reanimated/useAnimatedImageValue.js.map +1 -1
  56. package/lib/module/external/reanimated/useDerivedValueOnJS.js +5 -5
  57. package/lib/module/external/reanimated/useDerivedValueOnJS.js.map +1 -1
  58. package/lib/module/renderer/Offscreen.js +1 -5
  59. package/lib/module/renderer/Offscreen.js.map +1 -1
  60. package/lib/module/skia/types/Image/ImageFactory.d.ts +3 -3
  61. package/lib/module/skia/types/Image/ImageFactory.js.map +1 -1
  62. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.d.ts +3 -3
  63. package/lib/module/skia/types/NativeBuffer/NativeBufferFactory.js.map +1 -1
  64. package/lib/module/skia/web/JsiSkNativeBufferFactory.d.ts +1 -1
  65. package/lib/module/skia/web/JsiSkNativeBufferFactory.js +1 -1
  66. package/lib/module/skia/web/JsiSkNativeBufferFactory.js.map +1 -1
  67. package/lib/module/specs/NativeSkiaModule.web.d.ts +0 -2
  68. package/lib/module/specs/NativeSkiaModule.web.js +0 -3
  69. package/lib/module/specs/NativeSkiaModule.web.js.map +1 -1
  70. package/lib/typescript/src/external/ModuleProxy.d.ts +10 -0
  71. package/lib/typescript/src/external/reanimated/ReanimatedProxy.d.ts +3 -0
  72. package/lib/typescript/src/skia/types/Image/ImageFactory.d.ts +3 -3
  73. package/lib/typescript/src/skia/types/NativeBuffer/NativeBufferFactory.d.ts +3 -3
  74. package/lib/typescript/src/skia/web/JsiSkNativeBufferFactory.d.ts +1 -1
  75. package/lib/typescript/src/specs/NativeSkiaModule.web.d.ts +0 -2
  76. package/libs/ios/libskia.xcframework/Info.plist +5 -5
  77. package/libs/ios/libskia.xcframework/ios-arm64_arm64e/libskia.a +0 -0
  78. package/libs/ios/libskia.xcframework/ios-arm64_arm64e_x86_64-simulator/libskia.a +0 -0
  79. package/libs/ios/libskottie.xcframework/Info.plist +5 -5
  80. package/libs/ios/libskottie.xcframework/ios-arm64_arm64e/libskottie.a +0 -0
  81. package/libs/ios/libskottie.xcframework/ios-arm64_arm64e_x86_64-simulator/libskottie.a +0 -0
  82. package/libs/ios/libskparagraph.xcframework/ios-arm64_arm64e/libskparagraph.a +0 -0
  83. package/libs/ios/libskparagraph.xcframework/ios-arm64_arm64e_x86_64-simulator/libskparagraph.a +0 -0
  84. package/libs/ios/libsksg.xcframework/ios-arm64_arm64e/libsksg.a +0 -0
  85. package/libs/ios/libsksg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsksg.a +0 -0
  86. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e/libskshaper.a +0 -0
  87. package/libs/ios/libskshaper.xcframework/ios-arm64_arm64e_x86_64-simulator/libskshaper.a +0 -0
  88. package/libs/ios/libskunicode.xcframework/ios-arm64_arm64e/libskunicode.a +0 -0
  89. package/libs/ios/libskunicode.xcframework/ios-arm64_arm64e_x86_64-simulator/libskunicode.a +0 -0
  90. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e/libsvg.a +0 -0
  91. package/libs/ios/libsvg.xcframework/ios-arm64_arm64e_x86_64-simulator/libsvg.a +0 -0
  92. package/package.json +1 -1
  93. package/src/external/ModuleProxy.ts +30 -0
  94. package/src/external/reanimated/ReanimatedProxy.ts +18 -0
  95. package/src/external/reanimated/buffers.ts +7 -6
  96. package/src/external/reanimated/interpolators.ts +7 -12
  97. package/src/external/reanimated/renderHelpers.ts +31 -18
  98. package/src/external/reanimated/textures.tsx +3 -3
  99. package/src/external/reanimated/useAnimatedImageValue.ts +5 -10
  100. package/src/external/reanimated/useDerivedValueOnJS.ts +5 -10
  101. package/src/renderer/Offscreen.tsx +1 -7
  102. package/src/skia/types/Image/ImageFactory.ts +3 -3
  103. package/src/skia/types/NativeBuffer/NativeBufferFactory.ts +3 -3
  104. package/src/skia/web/JsiSkNativeBufferFactory.ts +1 -1
  105. package/src/specs/NativeSkiaModule.web.ts +0 -4
  106. package/android/src/paper/java/com/facebook/react/viewmanagers/SkiaDrawViewManagerDelegate.java +0 -34
  107. package/cpp/skia/include/gpu/GrBackendDrawableInfo.h +0 -9
  108. package/lib/commonjs/external/reanimated/moduleWrapper.d.ts +0 -15
  109. package/lib/commonjs/external/reanimated/moduleWrapper.js +0 -46
  110. package/lib/commonjs/external/reanimated/moduleWrapper.js.map +0 -1
  111. package/lib/module/external/reanimated/moduleWrapper.d.ts +0 -15
  112. package/lib/module/external/reanimated/moduleWrapper.js +0 -37
  113. package/lib/module/external/reanimated/moduleWrapper.js.map +0 -1
  114. package/lib/typescript/src/external/reanimated/moduleWrapper.d.ts +0 -15
  115. package/src/external/reanimated/moduleWrapper.ts +0 -83
@@ -16,16 +16,13 @@ namespace RNSkia {
16
16
  thread_local SkiaOpenGLContext ThreadContextHolder::ThreadSkiaOpenGLContext;
17
17
 
18
18
  sk_sp<SkImage>
19
- SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer) {
19
+ SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer,
20
+ bool requireKnownFormat) {
20
21
  #if __ANDROID_API__ >= 26
21
22
  // Setup OpenGL and Skia:
22
23
  if (!SkiaOpenGLHelper::createSkiaDirectContextIfNecessary(
23
- &ThreadContextHolder::ThreadSkiaOpenGLContext)) {
24
-
25
- RNSkLogger::logToConsole(
26
- "Could not create Skia Surface from native window / surface. "
27
- "Failed creating Skia Direct Context");
28
- return nullptr;
24
+ &ThreadContextHolder::ThreadSkiaOpenGLContext)) [[unlikely]] {
25
+ throw std::runtime_error("Failed to create Skia Context for this Thread!");
29
26
  }
30
27
  const AHardwareBuffer *hardwareBuffer =
31
28
  static_cast<AHardwareBuffer *>(buffer);
@@ -35,23 +32,46 @@ SkiaOpenGLSurfaceFactory::makeImageFromHardwareBuffer(void *buffer) {
35
32
 
36
33
  AHardwareBuffer_Desc description;
37
34
  AHardwareBuffer_describe(hardwareBuffer, &description);
38
- if (description.format != AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM) {
39
- throw std::runtime_error("AHardwareBuffer has unknown format (" +
40
- std::to_string(description.format) +
41
- ") - cannot convert to SkImage!");
35
+ GrBackendFormat format;
36
+ switch (description.format) {
37
+ // TODO: find out if we can detect, which graphic buffers support
38
+ // GR_GL_TEXTURE_2D
39
+ case AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM:
40
+ case AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM:
41
+ format = GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
42
+ case AHARDWAREBUFFER_FORMAT_R16G16B16A16_FLOAT:
43
+ format = GrBackendFormats::MakeGL(GR_GL_RGBA16F, GR_GL_TEXTURE_EXTERNAL);
44
+ case AHARDWAREBUFFER_FORMAT_R5G6B5_UNORM:
45
+ format = GrBackendFormats::MakeGL(GR_GL_RGB565, GR_GL_TEXTURE_EXTERNAL);
46
+ case AHARDWAREBUFFER_FORMAT_R10G10B10A2_UNORM:
47
+ format = GrBackendFormats::MakeGL(GR_GL_RGB10_A2, GR_GL_TEXTURE_EXTERNAL);
48
+ case AHARDWAREBUFFER_FORMAT_R8G8B8_UNORM:
49
+ format = GrBackendFormats::MakeGL(GR_GL_RGB8, GR_GL_TEXTURE_EXTERNAL);
50
+ #if __ANDROID_API__ >= 33
51
+ case AHARDWAREBUFFER_FORMAT_R8_UNORM:
52
+ format = GrBackendFormats::MakeGL(GR_GL_R8, GR_GL_TEXTURE_EXTERNAL);
53
+ #endif
54
+ default:
55
+ if (requireKnownFormat) {
56
+ format = GrBackendFormat();
57
+ } else {
58
+ format = GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
59
+ }
42
60
  }
43
- GrBackendFormat format =
44
- GrBackendFormats::MakeGL(GR_GL_RGBA8, GR_GL_TEXTURE_EXTERNAL);
45
61
 
46
62
  auto backendTex = MakeGLBackendTexture(
47
63
  ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
48
64
  const_cast<AHardwareBuffer *>(hardwareBuffer), description.width,
49
65
  description.height, &deleteImageProc, &updateImageProc, &deleteImageCtx,
50
66
  false, format, false);
67
+ if (!backendTex.isValid()) [[unlikely]] {
68
+ throw std::runtime_error(
69
+ "Failed to convert HardwareBuffer to OpenGL Texture!");
70
+ }
51
71
  sk_sp<SkImage> image = SkImages::BorrowTextureFrom(
52
72
  ThreadContextHolder::ThreadSkiaOpenGLContext.directContext.get(),
53
73
  backendTex, kTopLeft_GrSurfaceOrigin, kRGBA_8888_SkColorType,
54
- kOpaque_SkAlphaType, nullptr);
74
+ kOpaque_SkAlphaType, nullptr, deleteImageProc, deleteImageCtx);
55
75
  return image;
56
76
  #else
57
77
  throw std::runtime_error(
@@ -149,7 +149,8 @@ public:
149
149
  */
150
150
  static sk_sp<SkSurface> makeOffscreenSurface(int width, int height);
151
151
 
152
- static sk_sp<SkImage> makeImageFromHardwareBuffer(void *buffer);
152
+ static sk_sp<SkImage>
153
+ makeImageFromHardwareBuffer(void *buffer, bool requireKnownFormat = false);
153
154
 
154
155
  /**
155
156
  * Creates a windowed Skia Surface holder.
@@ -162,16 +162,21 @@ public class ViewScreenshotService {
162
162
  latch.await(SURFACE_VIEW_READ_PIXELS_TIMEOUT, TimeUnit.SECONDS);
163
163
  } catch (Exception e) {
164
164
  Log.e(TAG, "Cannot PixelCopy for " + sv, e);
165
+ drawSurfaceViewFromCache(canvas, sv, paint, opacity);
165
166
  }
166
167
  } else {
167
- Bitmap cache = sv.getDrawingCache();
168
- if (cache != null) {
169
- canvas.save();
170
- applyTransformations(canvas, sv);
171
- paint.setAlpha(Math.round(opacity * 255)); // Set paint alpha based on opacity
172
- canvas.drawBitmap(cache, 0, 0, paint);
173
- canvas.restore();
174
- }
168
+ drawSurfaceViewFromCache(canvas, sv, paint, opacity);
169
+ }
170
+ }
171
+
172
+ private static void drawSurfaceViewFromCache(Canvas canvas, SurfaceView sv, Paint paint, float opacity) {
173
+ Bitmap cache = sv.getDrawingCache();
174
+ if (cache != null) {
175
+ canvas.save();
176
+ applyTransformations(canvas, sv);
177
+ paint.setAlpha(Math.round(opacity * 255)); // Set paint alpha based on opacity
178
+ canvas.drawBitmap(cache, 0, 0, paint);
179
+ canvas.restore();
175
180
  }
176
181
  }
177
182
 
@@ -29,11 +29,11 @@ public:
29
29
 
30
30
  JSI_HOST_FUNCTION(MakeImageFromNativeBuffer) {
31
31
  jsi::BigInt pointer = arguments[0].asBigInt(runtime);
32
- const uintptr_t platformBufferPointer = pointer.asUint64(runtime);
33
- void *rawPointer = reinterpret_cast<void *>(platformBufferPointer);
32
+ const uintptr_t nativeBufferPointer = pointer.asUint64(runtime);
33
+ void *rawPointer = reinterpret_cast<void *>(nativeBufferPointer);
34
34
  auto image = getContext()->makeImageFromNativeBuffer(rawPointer);
35
35
  if (image == nullptr) {
36
- throw std::runtime_error("Failed to convert PlatformBuffer to SkImage!");
36
+ throw std::runtime_error("Failed to convert NativeBuffer to SkImage!");
37
37
  }
38
38
  return jsi::Object::createFromHostObject(
39
39
  runtime, std::make_shared<JsiSkImage>(getContext(), std::move(image)));
@@ -134,10 +134,10 @@ public:
134
134
  virtual sk_sp<SkSurface> makeOffscreenSurface(int width, int height) = 0;
135
135
 
136
136
  /**
137
- * Creates an image from a native buffer. (for testing purposes only)
138
- * - On iOS, this is a `CVPixelBufferRef*`
137
+ * Creates an image from a native buffer.
138
+ * - On iOS, this is a `CVPixelBufferRef`
139
139
  * - On Android, this is a `AHardwareBuffer*`
140
- * @param buffer The native platform buffer.
140
+ * @param buffer The native buffer.
141
141
  * @return sk_sp<SkImage>
142
142
  */
143
143
  virtual sk_sp<SkImage> makeImageFromNativeBuffer(void *buffer) = 0;
@@ -59,11 +59,7 @@ void RNSkiOSPlatformContext::performStreamOperation(
59
59
  }
60
60
 
61
61
  void RNSkiOSPlatformContext::releaseNativeBuffer(uint64_t pointer) {
62
- CMSampleBufferRef sampleBuffer = reinterpret_cast<CMSampleBufferRef>(pointer);
63
- CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
64
- if (sampleBuffer) {
65
- CFRelease(sampleBuffer);
66
- }
62
+ CVPixelBufferRef pixelBuffer = reinterpret_cast<CVPixelBufferRef>(pointer);
67
63
  if (pixelBuffer) {
68
64
  CFRelease(pixelBuffer);
69
65
  }
@@ -79,7 +75,7 @@ uint64_t RNSkiOSPlatformContext::makeNativeBuffer(sk_sp<SkImage> image) {
79
75
  if (image == nullptr) {
80
76
  throw std::runtime_error(
81
77
  "Failed to convert image to BGRA_8888 colortype! Only BGRA_8888 "
82
- "PlatformBuffers are supported.");
78
+ "NativeBuffers are supported.");
83
79
  }
84
80
  }
85
81
 
@@ -6,6 +6,9 @@
6
6
  //
7
7
 
8
8
  #pragma once
9
+
10
+ #import <vector>
11
+
9
12
  #import <CoreMedia/CMSampleBuffer.h>
10
13
  #import <CoreVideo/CVMetalTextureCache.h>
11
14
  #import <MetalKit/MetalKit.h>
@@ -13,7 +16,9 @@
13
16
  #pragma clang diagnostic push
14
17
  #pragma clang diagnostic ignored "-Wdocumentation"
15
18
  #import "include/core/SkColorSpace.h"
16
- #import <include/gpu/GrBackendSurface.h>
19
+ #import "include/core/SkImage.h"
20
+ #import "include/gpu/GrBackendSurface.h"
21
+ #import "include/gpu/GrYUVABackendTextures.h"
17
22
  #pragma clang diagnostic pop
18
23
 
19
24
  /**
@@ -36,7 +41,7 @@ public:
36
41
  retained with `CFRetain`, and will later be manually
37
42
  released with `CFRelease`.
38
43
  */
39
- explicit TextureHolder(CVMetalTextureRef texture);
44
+ TextureHolder(CVMetalTextureRef texture);
40
45
  ~TextureHolder();
41
46
 
42
47
  /**
@@ -48,9 +53,21 @@ private:
48
53
  CVMetalTextureRef _texture;
49
54
  };
50
55
 
56
+ /**
57
+ Same as `TextureHolder`, but for multiple planar textures (e.g. YUVA)
58
+ */
59
+ class MultiTexturesHolder {
60
+ public:
61
+ ~MultiTexturesHolder();
62
+ void addTexture(TextureHolder *texture);
63
+
64
+ private:
65
+ std::vector<TextureHolder *> _textures;
66
+ };
67
+
51
68
  class SkiaCVPixelBufferUtils {
52
69
  public:
53
- enum class CVPixelBufferBaseFormat { rgb };
70
+ enum class CVPixelBufferBaseFormat { rgb, yuv };
54
71
 
55
72
  /**
56
73
  Get the base format (currently only RGB) of the PixelBuffer.
@@ -63,14 +80,32 @@ public:
63
80
  class RGB {
64
81
  public:
65
82
  /**
66
- Gets the Skia Color Type of the RGB pixel-buffer.
83
+ Creates a GPU-backed Skia Texture (SkImage) with the given RGB
84
+ CVPixelBuffer.
67
85
  */
86
+ static sk_sp<SkImage>
87
+ makeSkImageFromCVPixelBuffer(GrDirectContext *context,
88
+ CVPixelBufferRef pixelBuffer);
89
+
90
+ private:
68
91
  static SkColorType getCVPixelBufferColorType(CVPixelBufferRef pixelBuffer);
92
+ };
93
+
94
+ class YUV {
95
+ public:
69
96
  /**
70
- Gets a GPU-backed Skia Texture for the given RGB CVPixelBuffer.
97
+ Creates a GPU-backed Skia Texture (SkImage) with the given YUV
98
+ CVPixelBuffer.
71
99
  */
72
- static TextureHolder *
73
- getSkiaTextureForCVPixelBuffer(CVPixelBufferRef pixelBuffer);
100
+ static sk_sp<SkImage>
101
+ makeSkImageFromCVPixelBuffer(GrDirectContext *context,
102
+ CVPixelBufferRef pixelBuffer);
103
+
104
+ private:
105
+ static SkYUVAInfo::PlaneConfig getPlaneConfig(OSType pixelFormat);
106
+ static SkYUVAInfo::Subsampling getSubsampling(OSType pixelFormat);
107
+ static SkYUVColorSpace getColorspace(OSType pixelFormat);
108
+ static SkYUVAInfo getYUVAInfoForCVPixelBuffer(CVPixelBufferRef pixelBuffer);
74
109
  };
75
110
 
76
111
  private:
@@ -12,6 +12,7 @@
12
12
  #pragma clang diagnostic ignored "-Wdocumentation"
13
13
  #import "include/core/SkColorSpace.h"
14
14
  #import <include/gpu/GrBackendSurface.h>
15
+ #import <include/gpu/ganesh/SkImageGanesh.h>
15
16
  #pragma clang diagnostic pop
16
17
 
17
18
  #include <TargetConditionals.h>
@@ -32,7 +33,10 @@
32
33
  // pragma MARK: TextureHolder
33
34
 
34
35
  TextureHolder::TextureHolder(CVMetalTextureRef texture) : _texture(texture) {}
35
- TextureHolder::~TextureHolder() { CFRelease(_texture); }
36
+ TextureHolder::~TextureHolder() {
37
+ // ARC will now automatically release _texture.
38
+ CFRelease(_texture);
39
+ }
36
40
 
37
41
  GrBackendTexture TextureHolder::toGrBackendTexture() {
38
42
  // Unwrap the underlying MTLTexture
@@ -51,6 +55,16 @@ GrBackendTexture TextureHolder::toGrBackendTexture() {
51
55
  return texture;
52
56
  }
53
57
 
58
+ MultiTexturesHolder::~MultiTexturesHolder() {
59
+ for (TextureHolder *texture : _textures) {
60
+ delete texture;
61
+ }
62
+ }
63
+
64
+ void MultiTexturesHolder::addTexture(TextureHolder *texture) {
65
+ _textures.push_back(texture);
66
+ }
67
+
54
68
  // pragma MARK: Base
55
69
 
56
70
  SkiaCVPixelBufferUtils::CVPixelBufferBaseFormat
@@ -59,12 +73,30 @@ SkiaCVPixelBufferUtils::getCVPixelBufferBaseFormat(
59
73
  OSType format = CVPixelBufferGetPixelFormatType(pixelBuffer);
60
74
 
61
75
  switch (format) {
76
+ // 8-bit YUV formats
77
+ case kCVPixelFormatType_420YpCbCr8Planar:
78
+ case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
79
+ case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
80
+ case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
81
+ // 10-bit YUV formats
82
+ case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
83
+ case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
84
+ case kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange:
85
+ case kCVPixelFormatType_422YpCbCr10BiPlanarFullRange:
86
+ case kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange:
87
+ case kCVPixelFormatType_444YpCbCr10BiPlanarFullRange:
88
+ return CVPixelBufferBaseFormat::yuv;
89
+ case kCVPixelFormatType_24RGB:
90
+ case kCVPixelFormatType_24BGR:
91
+ case kCVPixelFormatType_32ARGB:
62
92
  case kCVPixelFormatType_32BGRA:
93
+ case kCVPixelFormatType_32ABGR:
63
94
  case kCVPixelFormatType_32RGBA:
64
95
  return CVPixelBufferBaseFormat::rgb;
65
96
  default:
66
97
  [[unlikely]] throw std::runtime_error(
67
- "CVPixelBuffer has unsupported pixel-format! " +
98
+ "CVPixelBuffer has unknown pixel format! " +
99
+ std::string("Expected: any RGB or YUV format, Received: ") +
68
100
  std::string(FourCC2Str(format)));
69
101
  }
70
102
  }
@@ -80,7 +112,7 @@ SkColorType SkiaCVPixelBufferUtils::RGB::getCVPixelBufferColorType(
80
112
  [[likely]] return kBGRA_8888_SkColorType;
81
113
  case kCVPixelFormatType_32RGBA:
82
114
  return kRGBA_8888_SkColorType;
83
- // This can be extended with branches for specific RGB formats if new Apple
115
+ // This can be extended with branches for specific RGB formats if Apple
84
116
  // uses new formats.
85
117
  default:
86
118
  [[unlikely]] throw std::runtime_error(
@@ -89,9 +121,150 @@ SkColorType SkiaCVPixelBufferUtils::RGB::getCVPixelBufferColorType(
89
121
  }
90
122
  }
91
123
 
92
- TextureHolder *SkiaCVPixelBufferUtils::RGB::getSkiaTextureForCVPixelBuffer(
124
+ sk_sp<SkImage> SkiaCVPixelBufferUtils::RGB::makeSkImageFromCVPixelBuffer(
125
+ GrDirectContext *context, CVPixelBufferRef pixelBuffer) {
126
+ // 1. Get Skia color type for RGB buffer
127
+ SkColorType colorType = getCVPixelBufferColorType(pixelBuffer);
128
+
129
+ // 2. Get texture, RGB buffers only have one plane
130
+ TextureHolder *texture =
131
+ getSkiaTextureForCVPixelBufferPlane(pixelBuffer, /* planeIndex */ 0);
132
+
133
+ // 3. Convert to image with manual memory cleanup
134
+ return SkImages::BorrowTextureFrom(
135
+ context, texture->toGrBackendTexture(), kTopLeft_GrSurfaceOrigin,
136
+ colorType, kOpaque_SkAlphaType, nullptr,
137
+ [](void *texture) { delete (TextureHolder *)texture; }, (void *)texture);
138
+ }
139
+
140
+ // pragma MARK: YUV
141
+
142
+ sk_sp<SkImage> SkiaCVPixelBufferUtils::YUV::makeSkImageFromCVPixelBuffer(
143
+ GrDirectContext *context, CVPixelBufferRef pixelBuffer) {
144
+ // 1. Get all planes (YUV, Y_UV, Y_U_V or Y_U_V_A)
145
+ size_t planesCount = CVPixelBufferGetPlaneCount(pixelBuffer);
146
+ MultiTexturesHolder *texturesHolder = new MultiTexturesHolder();
147
+ GrBackendTexture textures[planesCount];
148
+
149
+ for (size_t planeIndex = 0; planeIndex < planesCount; planeIndex++) {
150
+ TextureHolder *textureHolder =
151
+ getSkiaTextureForCVPixelBufferPlane(pixelBuffer, planeIndex);
152
+ textures[planeIndex] = textureHolder->toGrBackendTexture();
153
+ texturesHolder->addTexture(textureHolder);
154
+ }
155
+
156
+ // 2. Wrap info about buffer
157
+ SkYUVAInfo info = getYUVAInfoForCVPixelBuffer(pixelBuffer);
158
+
159
+ // 3. Wrap as YUVA textures type
160
+ GrYUVABackendTextures yuvaTextures(info, textures, kTopLeft_GrSurfaceOrigin);
161
+
162
+ // 4. Wrap into SkImage type with manualy memory cleanup
163
+ return SkImages::TextureFromYUVATextures(
164
+ context, yuvaTextures, nullptr,
165
+ [](void *textureHolders) {
166
+ delete (MultiTexturesHolder *)textureHolders;
167
+ },
168
+ (void *)texturesHolder);
169
+ }
170
+
171
+ SkYUVAInfo SkiaCVPixelBufferUtils::YUV::getYUVAInfoForCVPixelBuffer(
93
172
  CVPixelBufferRef pixelBuffer) {
94
- return getSkiaTextureForCVPixelBufferPlane(pixelBuffer, /* planeIndex */ 0);
173
+ size_t width = CVPixelBufferGetWidth(pixelBuffer);
174
+ size_t height = CVPixelBufferGetHeight(pixelBuffer);
175
+ SkISize size =
176
+ SkISize::Make(static_cast<int>(width), static_cast<int>(height));
177
+
178
+ OSType format = CVPixelBufferGetPixelFormatType(pixelBuffer);
179
+ SkYUVAInfo::PlaneConfig planeConfig = getPlaneConfig(format);
180
+ SkYUVAInfo::Subsampling subsampling = getSubsampling(format);
181
+ SkYUVColorSpace colorspace = getColorspace(format);
182
+
183
+ return SkYUVAInfo(size, planeConfig, subsampling, colorspace);
184
+ }
185
+
186
+ // pragma MARK: YUV getPlaneConfig()
187
+
188
+ SkYUVAInfo::PlaneConfig
189
+ SkiaCVPixelBufferUtils::YUV::getPlaneConfig(OSType pixelFormat) {
190
+ switch (pixelFormat) {
191
+ case kCVPixelFormatType_420YpCbCr8Planar:
192
+ case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
193
+ return SkYUVAInfo::PlaneConfig::kYUV;
194
+ case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
195
+ case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
196
+ case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
197
+ case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
198
+ case kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange:
199
+ case kCVPixelFormatType_422YpCbCr10BiPlanarFullRange:
200
+ case kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange:
201
+ case kCVPixelFormatType_444YpCbCr10BiPlanarFullRange:
202
+ [[likely]] return SkYUVAInfo::PlaneConfig::kY_UV;
203
+
204
+ // This can be extended with branches for specific YUV formats if Apple
205
+ // uses new formats.
206
+ default:
207
+ [[unlikely]] throw std::runtime_error("Invalid pixel format! " +
208
+ std::string(FourCC2Str(pixelFormat)));
209
+ }
210
+ }
211
+
212
+ // pragma MARK: YUV getSubsampling()
213
+
214
+ SkYUVAInfo::Subsampling
215
+ SkiaCVPixelBufferUtils::YUV::getSubsampling(OSType pixelFormat) {
216
+ switch (pixelFormat) {
217
+ case kCVPixelFormatType_420YpCbCr8Planar:
218
+ case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
219
+ case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
220
+ case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
221
+ case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
222
+ case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
223
+ [[likely]] return SkYUVAInfo::Subsampling::k420;
224
+ case kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange:
225
+ case kCVPixelFormatType_422YpCbCr10BiPlanarFullRange:
226
+ return SkYUVAInfo::Subsampling::k422;
227
+ case kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange:
228
+ case kCVPixelFormatType_444YpCbCr10BiPlanarFullRange:
229
+ return SkYUVAInfo::Subsampling::k444;
230
+ // This can be extended with branches for specific YUV formats if Apple
231
+ // uses new formats.
232
+ default:
233
+ [[unlikely]] throw std::runtime_error("Invalid pixel format! " +
234
+ std::string(FourCC2Str(pixelFormat)));
235
+ }
236
+ }
237
+
238
+ // pragma MARK: YUV getColorspace()
239
+
240
+ SkYUVColorSpace SkiaCVPixelBufferUtils::YUV::getColorspace(OSType pixelFormat) {
241
+ switch (pixelFormat) {
242
+ case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange:
243
+ [[likely]]
244
+ // 8-bit limited
245
+ return SkYUVColorSpace::kRec709_Limited_SkYUVColorSpace;
246
+ case kCVPixelFormatType_420YpCbCr8Planar:
247
+ case kCVPixelFormatType_420YpCbCr8PlanarFullRange:
248
+ case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange:
249
+ [[likely]]
250
+ // 8-bit full
251
+ return SkYUVColorSpace::kRec709_Full_SkYUVColorSpace;
252
+ case kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange:
253
+ case kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange:
254
+ case kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange:
255
+ // 10-bit limited
256
+ return SkYUVColorSpace::kBT2020_10bit_Limited_SkYUVColorSpace;
257
+ case kCVPixelFormatType_420YpCbCr10BiPlanarFullRange:
258
+ case kCVPixelFormatType_422YpCbCr10BiPlanarFullRange:
259
+ case kCVPixelFormatType_444YpCbCr10BiPlanarFullRange:
260
+ // 10-bit full
261
+ return SkYUVColorSpace::kBT2020_10bit_Full_SkYUVColorSpace;
262
+ // This can be extended with branches for specific YUV formats if Apple
263
+ // uses new formats.
264
+ default:
265
+ [[unlikely]] throw std::runtime_error("Invalid pixel format! " +
266
+ std::string(FourCC2Str(pixelFormat)));
267
+ }
95
268
  }
96
269
 
97
270
  // pragma MARK: CVPixelBuffer -> Skia Texture
@@ -119,22 +119,19 @@ sk_sp<SkImage> SkiaMetalSurfaceFactory::makeTextureFromCVPixelBuffer(
119
119
  SkiaCVPixelBufferUtils::getCVPixelBufferBaseFormat(pixelBuffer);
120
120
  switch (format) {
121
121
  case SkiaCVPixelBufferUtils::CVPixelBufferBaseFormat::rgb: {
122
- // CVPixelBuffer is in any RGB format.
123
- SkColorType colorType =
124
- SkiaCVPixelBufferUtils::RGB::getCVPixelBufferColorType(pixelBuffer);
125
- TextureHolder *texture =
126
- SkiaCVPixelBufferUtils::RGB::getSkiaTextureForCVPixelBuffer(
127
- pixelBuffer);
128
- return SkImages::BorrowTextureFrom(
129
- context.skContext.get(), texture->toGrBackendTexture(),
130
- kTopLeft_GrSurfaceOrigin, colorType, kOpaque_SkAlphaType, nullptr,
131
- [](void *texture) { delete (TextureHolder *)texture; },
132
- (void *)texture);
122
+ // CVPixelBuffer is in any RGB format, single-plane
123
+ return SkiaCVPixelBufferUtils::RGB::makeSkImageFromCVPixelBuffer(
124
+ context.skContext.get(), pixelBuffer);
125
+ }
126
+ case SkiaCVPixelBufferUtils::CVPixelBufferBaseFormat::yuv: {
127
+ // CVPixelBuffer is in any YUV format, multi-plane
128
+ return SkiaCVPixelBufferUtils::YUV::makeSkImageFromCVPixelBuffer(
129
+ context.skContext.get(), pixelBuffer);
133
130
  }
134
131
  default:
135
132
  [[unlikely]] {
136
- throw std::runtime_error("Failed to convert PlatformBuffer to SkImage - "
137
- "PlatformBuffer has unsupported PixelFormat! " +
133
+ throw std::runtime_error("Failed to convert NativeBuffer to SkImage - "
134
+ "NativeBuffer has unsupported PixelFormat! " +
138
135
  std::to_string(static_cast<int>(format)));
139
136
  }
140
137
  }
@@ -0,0 +1,10 @@
1
+ type ImportType = ReturnType<typeof require>;
2
+ /**
3
+ * Create a lazily-imported module proxy.
4
+ * This is useful for lazily requiring optional dependencies.
5
+ */
6
+ export declare const createModuleProxy: <TModule>(getModule: () => ImportType) => TModule;
7
+ export declare class OptionalDependencyNotInstalledError extends Error {
8
+ constructor(name: string);
9
+ }
10
+ export {};
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.createModuleProxy = exports.OptionalDependencyNotInstalledError = void 0;
7
+ // https://github.com/mrousavy/react-native-vision-camera/blob/main/package/src/dependencies/ModuleProxy.ts
8
+
9
+ /**
10
+ * Create a lazily-imported module proxy.
11
+ * This is useful for lazily requiring optional dependencies.
12
+ */
13
+ const createModuleProxy = getModule => {
14
+ const holder = {
15
+ module: undefined
16
+ };
17
+ const proxy = new Proxy(holder, {
18
+ get: (target, property) => {
19
+ if (target.module == null) {
20
+ // lazy initialize module via require()
21
+ // caller needs to make sure the require() call is wrapped in a try/catch
22
+ target.module = getModule();
23
+ }
24
+ return target.module[property];
25
+ }
26
+ });
27
+ return proxy;
28
+ };
29
+ exports.createModuleProxy = createModuleProxy;
30
+ class OptionalDependencyNotInstalledError extends Error {
31
+ constructor(name) {
32
+ super(`${name} is not installed!`);
33
+ }
34
+ }
35
+ exports.OptionalDependencyNotInstalledError = OptionalDependencyNotInstalledError;
36
+ //# sourceMappingURL=ModuleProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["createModuleProxy","getModule","holder","module","undefined","proxy","Proxy","get","target","property","exports","OptionalDependencyNotInstalledError","Error","constructor","name"],"sources":["ModuleProxy.ts"],"sourcesContent":["// https://github.com/mrousavy/react-native-vision-camera/blob/main/package/src/dependencies/ModuleProxy.ts\ntype ImportType = ReturnType<typeof require>;\n\n/**\n * Create a lazily-imported module proxy.\n * This is useful for lazily requiring optional dependencies.\n */\nexport const createModuleProxy = <TModule>(\n getModule: () => ImportType\n): TModule => {\n const holder: { module: TModule | undefined } = { module: undefined };\n\n const proxy = new Proxy(holder, {\n get: (target, property) => {\n if (target.module == null) {\n // lazy initialize module via require()\n // caller needs to make sure the require() call is wrapped in a try/catch\n target.module = getModule() as TModule;\n }\n return target.module[property as keyof typeof holder.module];\n },\n });\n return proxy as unknown as TModule;\n};\n\nexport class OptionalDependencyNotInstalledError extends Error {\n constructor(name: string) {\n super(`${name} is not installed!`);\n }\n}\n"],"mappings":";;;;;;AAAA;;AAGA;AACA;AACA;AACA;AACO,MAAMA,iBAAiB,GAC5BC,SAA2B,IACf;EACZ,MAAMC,MAAuC,GAAG;IAAEC,MAAM,EAAEC;EAAU,CAAC;EAErE,MAAMC,KAAK,GAAG,IAAIC,KAAK,CAACJ,MAAM,EAAE;IAC9BK,GAAG,EAAEA,CAACC,MAAM,EAAEC,QAAQ,KAAK;MACzB,IAAID,MAAM,CAACL,MAAM,IAAI,IAAI,EAAE;QACzB;QACA;QACAK,MAAM,CAACL,MAAM,GAAGF,SAAS,CAAC,CAAY;MACxC;MACA,OAAOO,MAAM,CAACL,MAAM,CAACM,QAAQ,CAA+B;IAC9D;EACF,CAAC,CAAC;EACF,OAAOJ,KAAK;AACd,CAAC;AAACK,OAAA,CAAAV,iBAAA,GAAAA,iBAAA;AAEK,MAAMW,mCAAmC,SAASC,KAAK,CAAC;EAC7DC,WAAWA,CAACC,IAAY,EAAE;IACxB,KAAK,CAAE,GAAEA,IAAK,oBAAmB,CAAC;EACpC;AACF;AAACJ,OAAA,CAAAC,mCAAA,GAAAA,mCAAA"}
@@ -0,0 +1,3 @@
1
+ import type * as ReanimatedT from "react-native-reanimated";
2
+ declare const Reanimated: typeof ReanimatedT;
3
+ export default Reanimated;
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _ModuleProxy = require("../ModuleProxy");
8
+ const Reanimated = (0, _ModuleProxy.createModuleProxy)(() => {
9
+ try {
10
+ return require("react-native-reanimated");
11
+ } catch (e) {
12
+ throw new _ModuleProxy.OptionalDependencyNotInstalledError("react-native-reanimated");
13
+ }
14
+ });
15
+
16
+ // eslint-disable-next-line import/no-default-export
17
+ var _default = exports.default = Reanimated;
18
+ //# sourceMappingURL=ReanimatedProxy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_ModuleProxy","require","Reanimated","createModuleProxy","e","OptionalDependencyNotInstalledError","_default","exports","default"],"sources":["ReanimatedProxy.ts"],"sourcesContent":["import type * as ReanimatedT from \"react-native-reanimated\";\n\nimport {\n OptionalDependencyNotInstalledError,\n createModuleProxy,\n} from \"../ModuleProxy\";\ntype TReanimated = typeof ReanimatedT;\n\nconst Reanimated = createModuleProxy<TReanimated>(() => {\n try {\n return require(\"react-native-reanimated\");\n } catch (e) {\n throw new OptionalDependencyNotInstalledError(\"react-native-reanimated\");\n }\n});\n\n// eslint-disable-next-line import/no-default-export\nexport default Reanimated;\n"],"mappings":";;;;;;AAEA,IAAAA,YAAA,GAAAC,OAAA;AAMA,MAAMC,UAAU,GAAG,IAAAC,8BAAiB,EAAc,MAAM;EACtD,IAAI;IACF,OAAOF,OAAO,CAAC,yBAAyB,CAAC;EAC3C,CAAC,CAAC,OAAOG,CAAC,EAAE;IACV,MAAM,IAAIC,gDAAmC,CAAC,yBAAyB,CAAC;EAC1E;AACF,CAAC,CAAC;;AAEF;AAAA,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GACeN,UAAU"}
@@ -6,17 +6,20 @@ Object.defineProperty(exports, "__esModule", {
6
6
  exports.useRectBuffer = exports.useRSXformBuffer = exports.usePointBuffer = exports.useColorBuffer = void 0;
7
7
  var _react = require("react");
8
8
  var _skia = require("../../skia");
9
- var _moduleWrapper = require("./moduleWrapper");
10
9
  var _interpolators = require("./interpolators");
11
- const useBufferValue = (size, bufferInitializer) => (0, _react.useMemo)(() => (0, _moduleWrapper.makeMutable)(new Array(size).fill(0).map(bufferInitializer)),
12
- // eslint-disable-next-line react-hooks/exhaustive-deps
13
- [size]);
10
+ var _ReanimatedProxy = _interopRequireDefault(require("./ReanimatedProxy"));
11
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
12
+ const useBufferValue = (size, bufferInitializer) => {
13
+ return (0, _react.useMemo)(() => _ReanimatedProxy.default.makeMutable(new Array(size).fill(0).map(bufferInitializer)),
14
+ // eslint-disable-next-line react-hooks/exhaustive-deps
15
+ [size]);
16
+ };
14
17
  const useBuffer = (size, bufferInitializer, modifier) => {
15
18
  var _mod$__closure;
16
19
  const values = useBufferValue(size, bufferInitializer);
17
20
  const mod = modifier;
18
21
  const deps = [size, ...Object.values((_mod$__closure = mod.__closure) !== null && _mod$__closure !== void 0 ? _mod$__closure : {})];
19
- const mapperId = (0, _moduleWrapper.startMapper)(() => {
22
+ const mapperId = _ReanimatedProxy.default.startMapper(() => {
20
23
  "worklet";
21
24
 
22
25
  values.value.forEach((val, index) => {
@@ -26,7 +29,7 @@ const useBuffer = (size, bufferInitializer, modifier) => {
26
29
  }, deps);
27
30
  (0, _react.useEffect)(() => {
28
31
  return () => {
29
- (0, _moduleWrapper.stopMapper)(mapperId);
32
+ _ReanimatedProxy.default.stopMapper(mapperId);
30
33
  };
31
34
  }, [mapperId]);
32
35
  return values;