feat: Replace *NativeMap and *NativeArray with Map<K,V> and List<T> for faster JSI -> JNI calls (#1720)

Replaces `ReadableNativeMap`/`WritableNativeMap` with `Map<String, Object>` and `ReadableNativeArray`/`WritableNativeArray` with `List<Object>`, making the JSI -> JNI conversion a bit faster and more logical.
Also, we could now convert Array Buffers or HostObjects if we wanted to.
This commit is contained in:
Marc Rousavy 2023-08-25 12:22:44 +02:00 committed by GitHub
parent f87bc74de1
commit dfb86e174b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 125 additions and 167 deletions

View File

@ -24,18 +24,19 @@ add_library(
${PACKAGE_NAME} ${PACKAGE_NAME}
SHARED SHARED
../cpp/JSITypedArray.cpp ../cpp/JSITypedArray.cpp
src/main/cpp/FrameHostObject.cpp
src/main/cpp/FrameProcessorPluginHostObject.cpp
src/main/cpp/JSIJNIConversion.cpp
src/main/cpp/VisionCamera.cpp src/main/cpp/VisionCamera.cpp
src/main/cpp/VisionCameraProxy.cpp # Frame Processor
src/main/cpp/frameprocessor/FrameHostObject.cpp
src/main/cpp/frameprocessor/FrameProcessorPluginHostObject.cpp
src/main/cpp/frameprocessor/JSIJNIConversion.cpp
src/main/cpp/frameprocessor/VisionCameraProxy.cpp
src/main/cpp/frameprocessor/java-bindings/JFrame.cpp
src/main/cpp/frameprocessor/java-bindings/JFrameProcessor.cpp
src/main/cpp/frameprocessor/java-bindings/JFrameProcessorPlugin.cpp
src/main/cpp/frameprocessor/java-bindings/JVisionCameraProxy.cpp
src/main/cpp/frameprocessor/java-bindings/JVisionCameraScheduler.cpp
# Skia Frame Processor
src/main/cpp/skia/SkiaRenderer.cpp src/main/cpp/skia/SkiaRenderer.cpp
src/main/cpp/java-bindings/JFrame.cpp
src/main/cpp/java-bindings/JFrameProcessor.cpp
src/main/cpp/java-bindings/JFrameProcessorPlugin.cpp
src/main/cpp/java-bindings/JHashMap.cpp
src/main/cpp/java-bindings/JVisionCameraProxy.cpp
src/main/cpp/java-bindings/JVisionCameraScheduler.cpp
) )
# Header Search Paths (includes) # Header Search Paths (includes)
@ -44,6 +45,9 @@ target_include_directories(
PRIVATE PRIVATE
"../cpp" "../cpp"
"src/main/cpp" "src/main/cpp"
"src/main/cpp/frameprocessor"
"src/main/cpp/frameprocessor/java-bindings"
"src/main/cpp/skia"
"${NODE_MODULES_DIR}/react-native/ReactCommon" "${NODE_MODULES_DIR}/react-native/ReactCommon"
"${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker" "${NODE_MODULES_DIR}/react-native/ReactCommon/callinvoker"
"${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/react/turbomodule" # <-- CallInvokerHolder JNI wrapper "${NODE_MODULES_DIR}/react-native/ReactAndroid/src/main/jni/react/turbomodule" # <-- CallInvokerHolder JNI wrapper

View File

@ -1,10 +1,10 @@
#include <jni.h> #include <jni.h>
#include <fbjni/fbjni.h> #include <fbjni/fbjni.h>
#include "java-bindings/JVisionCameraScheduler.h" #include "JVisionCameraScheduler.h"
#include "java-bindings/JFrameProcessor.h" #include "JFrameProcessor.h"
#include "java-bindings/JVisionCameraProxy.h" #include "JVisionCameraProxy.h"
#include "VisionCameraProxy.h" #include "VisionCameraProxy.h"
#include "skia/SkiaRenderer.h" #include "SkiaRenderer.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) { JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] { return facebook::jni::initialize(vm, [] {

View File

@ -10,7 +10,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include "java-bindings/JFrame.h" #include "JFrame.h"
namespace vision { namespace vision {

View File

@ -34,7 +34,7 @@ jsi::Value FrameProcessorPluginHostObject::get(jsi::Runtime& runtime, const jsi:
auto frame = frameHostObject->frame; auto frame = frameHostObject->frame;
// Options are second argument (possibly undefined) // Options are second argument (possibly undefined)
local_ref<react::ReadableNativeMap::javaobject> options = nullptr; local_ref<JMap<jstring, jobject>> options = nullptr;
if (count > 1) { if (count > 1) {
options = JSIJNIConversion::convertJSIObjectToJNIMap(runtime, arguments[1].asObject(runtime)); options = JSIJNIConversion::convertJSIObjectToJNIMap(runtime, arguments[1].asObject(runtime));
} }

View File

@ -5,7 +5,7 @@
#pragma once #pragma once
#include <jsi/jsi.h> #include <jsi/jsi.h>
#include "java-bindings/JFrameProcessorPlugin.h" #include "JFrameProcessorPlugin.h"
#include <memory> #include <memory>
#include <fbjni/fbjni.h> #include <fbjni/fbjni.h>
#include <vector> #include <vector>

View File

@ -13,25 +13,71 @@
#include <utility> #include <utility>
#include <memory> #include <memory>
#include <react/jni/NativeMap.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/jni/WritableNativeMap.h>
#include <jsi/JSIDynamic.h>
#include <folly/dynamic.h>
#include "FrameHostObject.h" #include "FrameHostObject.h"
#include "java-bindings/JFrame.h" #include "JFrame.h"
#include "java-bindings/JArrayList.h"
#include "java-bindings/JHashMap.h"
namespace vision { namespace vision {
using namespace facebook; using namespace facebook;
jni::local_ref<react::ReadableNativeMap::javaobject> JSIJNIConversion::convertJSIObjectToJNIMap(jsi::Runtime& runtime, const jsi::Object& object) { jni::local_ref<jni::JMap<jstring, jobject>> JSIJNIConversion::convertJSIObjectToJNIMap(jsi::Runtime& runtime, const jsi::Object& object) {
auto dynamic = jsi::dynamicFromValue(runtime, jsi::Value(runtime, object)); auto propertyNames = object.getPropertyNames(runtime);
return react::ReadableNativeMap::createWithContents(std::move(dynamic)); auto size = propertyNames.size(runtime);
auto hashMap = jni::JHashMap<jstring, jobject>::create();
for (size_t i = 0; i < size; i++) {
auto propName = propertyNames.getValueAtIndex(runtime, i).asString(runtime);
auto key = jni::make_jstring(propName.utf8(runtime));
auto value = object.getProperty(runtime, propName);
if (value.isNull() || value.isUndefined()) {
// null
hashMap->put(key, nullptr);
} else if (value.isBool()) {
// Boolean
auto boolean = value.getBool();
hashMap->put(key, jni::JBoolean::valueOf(boolean));
} else if (value.isNumber()) {
// Double
auto number = value.getNumber();
hashMap->put(key, jni::JDouble::valueOf(number));
} else if (value.isString()) {
// String
auto str = value.getString(runtime).utf8(runtime);
hashMap->put(key, jni::make_jstring(str));
} else if (value.isObject()) {
// Object
auto valueAsObject = value.getObject(runtime);
if (valueAsObject.isArray(runtime)) {
// List<Object>
} else if (valueAsObject.isHostObject(runtime)) {
throw std::runtime_error("You can't pass HostObjects here.");
} else {
// Map<String, Object>
auto map = convertJSIObjectToJNIMap(runtime, valueAsObject);
hashMap->put(key, map);
}
} else {
auto stringRepresentation = value.toString(runtime).utf8(runtime);
throw std::runtime_error("Failed to convert jsi::Value to JNI value - unsupported type!" + stringRepresentation);
}
}
return hashMap;
} }
jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime &runtime, const jni::local_ref<jobject>& object) { jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime &runtime, const jni::local_ref<jobject>& object) {
@ -66,10 +112,10 @@ jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime &runtime, c
return jsi::String::createFromUtf8(runtime, object->toString()); return jsi::String::createFromUtf8(runtime, object->toString());
} else if (object->isInstanceOf(JArrayList<jobject>::javaClassStatic())) { } else if (object->isInstanceOf(JList<jobject>::javaClassStatic())) {
// ArrayList<E> // List<E>
auto arrayList = static_ref_cast<JArrayList<jobject>>(object); auto arrayList = static_ref_cast<JList<jobject>>(object);
auto size = arrayList->size(); auto size = arrayList->size();
auto result = jsi::Array(runtime, size); auto result = jsi::Array(runtime, size);
@ -80,19 +126,10 @@ jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime &runtime, c
} }
return result; return result;
} else if (object->isInstanceOf(react::ReadableArray::javaClassStatic())) { } else if (object->isInstanceOf(JMap<jstring, jobject>::javaClassStatic())) {
// ReadableArray // Map<K, V>
static const auto toArrayListFunc = react::ReadableArray::javaClassLocal()->getMethod<JArrayList<jobject>()>("toArrayList"); auto map = static_ref_cast<JMap<jstring, jobject>>(object);
// call recursive, this time ArrayList<E>
auto array = toArrayListFunc(object.get());
return convertJNIObjectToJSIValue(runtime, array);
} else if (object->isInstanceOf(JHashMap<jstring, jobject>::javaClassStatic())) {
// HashMap<K, V>
auto map = static_ref_cast<JHashMap<jstring, jobject>>(object);
auto result = jsi::Object(runtime); auto result = jsi::Object(runtime);
for (const auto& entry : *map) { for (const auto& entry : *map) {
@ -103,16 +140,7 @@ jsi::Value JSIJNIConversion::convertJNIObjectToJSIValue(jsi::Runtime &runtime, c
} }
return result; return result;
} else if (object->isInstanceOf(react::ReadableMap::javaClassStatic())) { } if (object->isInstanceOf(JFrame::javaClassStatic())) {
// ReadableMap
static const auto toHashMapFunc = react::ReadableMap::javaClassLocal()->getMethod<JHashMap<jstring, jobject>()>("toHashMap");
// call recursive, this time HashMap<K, V>
auto hashMap = toHashMapFunc(object.get());
return convertJNIObjectToJSIValue(runtime, hashMap);
} else if (object->isInstanceOf(JFrame::javaClassStatic())) {
// Frame // Frame
auto frame = static_ref_cast<JFrame>(object); auto frame = static_ref_cast<JFrame>(object);

View File

@ -7,7 +7,6 @@
#include <jsi/jsi.h> #include <jsi/jsi.h>
#include <jni.h> #include <jni.h>
#include <fbjni/fbjni.h> #include <fbjni/fbjni.h>
#include <react/jni/ReadableNativeMap.h>
namespace vision { namespace vision {
@ -15,7 +14,7 @@ namespace JSIJNIConversion {
using namespace facebook; using namespace facebook;
jni::local_ref<react::ReadableNativeMap::javaobject> convertJSIObjectToJNIMap(jsi::Runtime& runtime, const jsi::Object& object); jni::local_ref<jni::JMap<jstring, jobject>> convertJSIObjectToJNIMap(jsi::Runtime& runtime, const jsi::Object& object);
jsi::Value convertJNIObjectToJSIValue(jsi::Runtime& runtime, const jni::local_ref<jobject>& object); jsi::Value convertJNIObjectToJSIValue(jsi::Runtime& runtime, const jni::local_ref<jobject>& object);

View File

@ -5,8 +5,8 @@
#include "VisionCameraProxy.h" #include "VisionCameraProxy.h"
#include <jsi/jsi.h> #include <jsi/jsi.h>
#include "java-bindings/JFrameProcessor.h" #include "JFrameProcessor.h"
#include "java-bindings/JFrameProcessorPlugin.h" #include "JFrameProcessorPlugin.h"
#include "JSIJNIConversion.h" #include "JSIJNIConversion.h"
#include <android/log.h> #include <android/log.h>

View File

@ -6,8 +6,8 @@
#include <jsi/jsi.h> #include <jsi/jsi.h>
#include "java-bindings/JVisionCameraScheduler.h" #include "JVisionCameraScheduler.h"
#include "java-bindings/JVisionCameraProxy.h" #include "JVisionCameraProxy.h"
#include <vector> #include <vector>
#include <string> #include <string>

View File

@ -12,10 +12,10 @@ namespace vision {
using namespace facebook; using namespace facebook;
using namespace jni; using namespace jni;
using TCallback = jobject(alias_ref<JFrame::javaobject>, alias_ref<react::ReadableNativeMap::javaobject> params); using TCallback = jobject(alias_ref<JFrame::javaobject>, alias_ref<JMap<jstring, jobject>> params);
local_ref<jobject> JFrameProcessorPlugin::callback(const alias_ref<JFrame::javaobject>& frame, local_ref<jobject> JFrameProcessorPlugin::callback(const alias_ref<JFrame::javaobject>& frame,
const alias_ref<react::ReadableNativeMap::javaobject>& params) const { const alias_ref<JMap<jstring, jobject>>& params) const {
auto callbackMethod = getClass()->getMethod<TCallback>("callback"); auto callbackMethod = getClass()->getMethod<TCallback>("callback");
auto result = callbackMethod(self(), frame, params); auto result = callbackMethod(self(), frame, params);

View File

@ -7,7 +7,6 @@
#include <jni.h> #include <jni.h>
#include <fbjni/fbjni.h> #include <fbjni/fbjni.h>
#include <string> #include <string>
#include <react/jni/ReadableNativeMap.h>
#include "JFrame.h" #include "JFrame.h"
@ -24,7 +23,7 @@ struct JFrameProcessorPlugin : public JavaClass<JFrameProcessorPlugin> {
* Call the plugin. * Call the plugin.
*/ */
local_ref<jobject> callback(const alias_ref<JFrame::javaobject>& frame, local_ref<jobject> callback(const alias_ref<JFrame::javaobject>& frame,
const alias_ref<react::ReadableNativeMap::javaobject>& params) const; const alias_ref<JMap<jstring, jobject>>& params) const;
}; };
} // namespace vision } // namespace vision

View File

@ -9,7 +9,6 @@
#include <string> #include <string>
#include <jsi/jsi.h> #include <jsi/jsi.h>
#include <react/jni/ReadableNativeMap.h>
#include "FrameProcessorPluginHostObject.h" #include "FrameProcessorPluginHostObject.h"
#include "JSITypedArray.h" #include "JSITypedArray.h"
@ -24,7 +23,7 @@ namespace vision {
using TSelf = local_ref<HybridClass<JVisionCameraProxy>::jhybriddata>; using TSelf = local_ref<HybridClass<JVisionCameraProxy>::jhybriddata>;
using TJSCallInvokerHolder = jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>; using TJSCallInvokerHolder = jni::alias_ref<facebook::react::CallInvokerHolder::javaobject>;
using TScheduler = jni::alias_ref<JVisionCameraScheduler::javaobject>; using TScheduler = jni::alias_ref<JVisionCameraScheduler::javaobject>;
using TOptions = jni::local_ref<react::ReadableNativeMap::javaobject>; using TOptions = jni::local_ref<JMap<jstring, jobject>>;
JVisionCameraProxy::JVisionCameraProxy(const jni::alias_ref<JVisionCameraProxy::jhybridobject>& javaThis, JVisionCameraProxy::JVisionCameraProxy(const jni::alias_ref<JVisionCameraProxy::jhybridobject>& javaThis,
jsi::Runtime* runtime, jsi::Runtime* runtime,

View File

@ -6,7 +6,6 @@
#include <fbjni/fbjni.h> #include <fbjni/fbjni.h>
#include <jsi/jsi.h> #include <jsi/jsi.h>
#include <react/jni/ReadableNativeMap.h>
#include <ReactCommon/CallInvokerHolder.h> #include <ReactCommon/CallInvokerHolder.h>
#include "JFrameProcessorPlugin.h" #include "JFrameProcessorPlugin.h"
@ -34,7 +33,7 @@ class JVisionCameraProxy : public jni::HybridClass<JVisionCameraProxy> {
const jsi::Object& frameProcessor); const jsi::Object& frameProcessor);
void removeFrameProcessor(int viewTag); void removeFrameProcessor(int viewTag);
jni::local_ref<JFrameProcessorPlugin::javaobject> getFrameProcessorPlugin(const std::string& name, jni::local_ref<JFrameProcessorPlugin::javaobject> getFrameProcessorPlugin(const std::string& name,
jni::local_ref<react::ReadableNativeMap::javaobject> options); jni::local_ref<JMap<jstring, jobject>> options);
jsi::Runtime* getJSRuntime() { return _runtime; } jsi::Runtime* getJSRuntime() { return _runtime; }

View File

@ -1,21 +0,0 @@
//
// Created by Marc Rousavy on 24.06.21.
//
#pragma once
#include <jni.h>
#include <fbjni/fbjni.h>
namespace vision {
using namespace facebook;
using namespace jni;
// TODO: Remove when fbjni 0.2.3 releases.
template <typename E = jobject>
struct JArrayList : JavaClass<JArrayList<E>, JList<E>> {
constexpr static auto kJavaDescriptor = "Ljava/util/ArrayList;";
};
} // namespace vision

View File

@ -1,20 +0,0 @@
//
// Created by Marc Rousavy on 25.06.21.
//
#include "JHashMap.h"
#include <jni.h>
#include <fbjni/fbjni.h>
namespace vision {
using namespace facebook;
using namespace jni;
template <typename K, typename V>
local_ref<JHashMap<K, V>> JHashMap<K, V>::create() {
return JHashMap<K, V>::newInstance();
}
} // namespace vision

View File

@ -1,23 +0,0 @@
//
// Created by Marc Rousavy on 25.06.21.
//
#pragma once
#include <jni.h>
#include <fbjni/fbjni.h>
namespace vision {
using namespace facebook;
using namespace jni;
// TODO: Remove when fbjni 0.2.3 releases.
template <typename K = jobject, typename V = jobject>
struct JHashMap : JavaClass<JHashMap<K, V>, JMap<K, V>> {
constexpr static auto kJavaDescriptor = "Ljava/util/HashMap;";
static local_ref<JHashMap<K, V>> create();
};
} // namespace vision

View File

@ -4,7 +4,7 @@ import androidx.annotation.Keep;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReadableNativeMap; import java.util.Map;
/** /**
* Declares a Frame Processor Plugin. * Declares a Frame Processor Plugin.
@ -21,5 +21,5 @@ public abstract class FrameProcessorPlugin {
*/ */
@DoNotStrip @DoNotStrip
@Keep @Keep
public abstract @Nullable Object callback(@NonNull Frame frame, @Nullable ReadableNativeMap params); public abstract @Nullable Object callback(@NonNull Frame frame, @Nullable Map<String, Object> params);
} }

View File

@ -2,12 +2,9 @@ package com.mrousavy.camera.frameprocessor;
import androidx.annotation.Keep; import androidx.annotation.Keep;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import com.facebook.proguard.annotations.DoNotStrip; import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.ReadableNativeMap;
import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.HashMap;
@DoNotStrip @DoNotStrip
@Keep @Keep
@ -24,7 +21,7 @@ public class FrameProcessorPluginRegistry {
@DoNotStrip @DoNotStrip
@Keep @Keep
public static FrameProcessorPlugin getPlugin(String name, ReadableNativeMap options) { public static FrameProcessorPlugin getPlugin(String name, Map<String, Object> options) {
PluginInitializer initializer = Plugins.get(name); PluginInitializer initializer = Plugins.get(name);
if (initializer == null) { if (initializer == null) {
return null; return null;
@ -33,6 +30,6 @@ public class FrameProcessorPluginRegistry {
} }
public interface PluginInitializer { public interface PluginInitializer {
FrameProcessorPlugin initializePlugin(@Nullable ReadableNativeMap options); FrameProcessorPlugin initializePlugin(@Nullable Map<String, Object> options);
} }
} }

View File

@ -6,7 +6,6 @@ import androidx.annotation.UiThread
import com.facebook.jni.HybridData import com.facebook.jni.HybridData
import com.facebook.proguard.annotations.DoNotStrip import com.facebook.proguard.annotations.DoNotStrip
import com.facebook.react.bridge.ReactApplicationContext import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.bridge.ReadableNativeMap
import com.facebook.react.bridge.UiThreadUtil import com.facebook.react.bridge.UiThreadUtil
import com.facebook.react.turbomodule.core.CallInvokerHolderImpl import com.facebook.react.turbomodule.core.CallInvokerHolderImpl
import com.facebook.react.uimanager.UIManagerHelper import com.facebook.react.uimanager.UIManagerHelper
@ -14,7 +13,6 @@ import com.mrousavy.camera.CameraView
import com.mrousavy.camera.ViewNotFoundError import com.mrousavy.camera.ViewNotFoundError
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
@Suppress("KotlinJniMissingFunction") // we use fbjni. @Suppress("KotlinJniMissingFunction") // we use fbjni.
class VisionCameraProxy(context: ReactApplicationContext) { class VisionCameraProxy(context: ReactApplicationContext) {
companion object { companion object {
@ -71,7 +69,7 @@ class VisionCameraProxy(context: ReactApplicationContext) {
@DoNotStrip @DoNotStrip
@Keep @Keep
fun getFrameProcessorPlugin(name: String, options: ReadableNativeMap): FrameProcessorPlugin { fun getFrameProcessorPlugin(name: String, options: Map<String, Any>): FrameProcessorPlugin {
return FrameProcessorPluginRegistry.getPlugin(name, options) return FrameProcessorPluginRegistry.getPlugin(name, options)
} }

View File

@ -39,8 +39,8 @@ Similar to a TurboModule, the Frame Processor Plugin Registry API automatically
| `number` | `NSNumber*` (double) | `Double` | | `number` | `NSNumber*` (double) | `Double` |
| `boolean` | `NSNumber*` (boolean) | `Boolean` | | `boolean` | `NSNumber*` (boolean) | `Boolean` |
| `string` | `NSString*` | `String` | | `string` | `NSString*` | `String` |
| `[]` | `NSArray*` | `ReadableNativeArray` | | `[]` | `NSArray*` | `List<Object>` |
| `{}` | `NSDictionary*` | `ReadableNativeMap` | | `{}` | `NSDictionary*` | `Map<String, Object>` |
| `undefined` / `null` | `nil` | `null` | | `undefined` / `null` | `nil` | `null` |
| `(any, any) => void` | [`RCTResponseSenderBlock`][4] | `(Object, Object) -> void` | | `(any, any) => void` | [`RCTResponseSenderBlock`][4] | `(Object, Object) -> void` |
| [`Frame`][1] | [`Frame*`][2] | [`Frame`][3] | | [`Frame`][1] | [`Frame*`][2] | [`Frame`][3] |

View File

@ -61,7 +61,7 @@ import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin;
public class FaceDetectorFrameProcessorPlugin extends FrameProcessorPlugin { public class FaceDetectorFrameProcessorPlugin extends FrameProcessorPlugin {
@Override @Override
public Object callback(Frame frame, ReadableNativeMap arguments) { public Object callback(Frame frame, Map<String, Object> arguments) {
// code goes here // code goes here
return null; return null;
} }
@ -126,7 +126,7 @@ import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin
class FaceDetectorFrameProcessorPlugin: FrameProcessorPlugin() { class FaceDetectorFrameProcessorPlugin: FrameProcessorPlugin() {
override fun callback(frame: Frame, arguments: ReadableNativeMap): Any? { override fun callback(frame: Frame, arguments: Map<String, Object>): Any? {
// code goes here // code goes here
return null return null
} }

View File

@ -3,40 +3,40 @@ package com.mrousavy.camera.example;
import android.media.Image; import android.media.Image;
import android.util.Log; import android.util.Log;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.mrousavy.camera.frameprocessor.Frame; import com.mrousavy.camera.frameprocessor.Frame;
import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin; import com.mrousavy.camera.frameprocessor.FrameProcessorPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class ExampleFrameProcessorPlugin extends FrameProcessorPlugin { public class ExampleFrameProcessorPlugin extends FrameProcessorPlugin {
@Override @Override
public Object callback(@NotNull Frame frame, @Nullable ReadableNativeMap params) { public Object callback(@NotNull Frame frame, @Nullable Map<String, Object> params) {
HashMap<String, Object> hashMap = params != null ? params.toHashMap() : new HashMap<>(); if (params == null) return null;
Image image = frame.getImage(); Image image = frame.getImage();
Log.d("ExamplePlugin", image.getWidth() + " x " + image.getHeight() + " Image with format #" + image.getFormat() + ". Logging " + hashMap.size() + " parameters:"); Log.d("ExamplePlugin", image.getWidth() + " x " + image.getHeight() + " Image with format #" + image.getFormat() + ". Logging " + params.size() + " parameters:");
for (String key : hashMap.keySet()) { for (String key : params.keySet()) {
Object value = hashMap.get(key); Object value = params.get(key);
Log.d("ExamplePlugin", " -> " + (value == null ? "(null)" : value.toString() + " (" + value.getClass().getName() + ")")); Log.d("ExamplePlugin", " -> " + (value == null ? "(null)" : value + " (" + value.getClass().getName() + ")"));
} }
WritableNativeMap map = new WritableNativeMap(); Map<String, Object> map = new HashMap<>();
map.putString("example_str", "Test"); map.put("example_str", "Test");
map.putBoolean("example_bool", true); map.put("example_bool", true);
map.putDouble("example_double", 5.3); map.put("example_double", 5.3);
WritableNativeArray array = new WritableNativeArray(); List<Object> array = new ArrayList<>();
array.pushString("Hello!"); array.add("Hello!");
array.pushBoolean(true); array.add(true);
array.pushDouble(17.38); array.add(17.38);
map.putArray("example_array", array); map.put("example_array", array);
return map; return map;
} }

View File

@ -8,7 +8,6 @@ import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication; import com.facebook.react.ReactApplication;
import com.facebook.react.ReactNativeHost; import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage; import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.ReadableNativeMap;
import com.facebook.soloader.SoLoader; import com.facebook.soloader.SoLoader;
import java.util.List; import java.util.List;
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint; import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint;