From 05d46111b76688255a8d4190a106cc83f6262142 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Mon, 18 Feb 2019 14:11:14 +0800 Subject: [PATCH] feat(android): add native bitmap utils --- .../mynteye/demo/camera/Mynteye.java | 7 +- .../mynteye/demo/ui/MainActivity.java | 64 +--------- .../android/mynteye/libmynteye/CMakeLists.txt | 7 +- .../src/main/cpp/mynteye/impl/frame_impl.hpp | 4 + .../main/cpp/mynteye/impl/util/jni_util.cpp | 117 ++++++++++++++++++ .../slightech/mynteye/util/BitmapUtils.java | 10 ++ 6 files changed, 147 insertions(+), 62 deletions(-) create mode 100644 wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp create mode 100644 wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BitmapUtils.java diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java index 7c3031d..bfff986 100644 --- a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/camera/Mynteye.java @@ -56,8 +56,9 @@ public final class Mynteye implements Runnable { startBackgroundThread(); mDevice.configStreamRequest(request); - mDevice.enableMotionDatas(Integer.MAX_VALUE); - mDevice.start(Source.ALL); + //mDevice.enableMotionDatas(Integer.MAX_VALUE); + //mDevice.start(Source.ALL); + mDevice.start(Source.VIDEO_STREAMING); mBackgroundHandler.post(this); } @@ -91,12 +92,14 @@ public final class Mynteye implements Runnable { } //Timber.i("get motions"); + /* { ArrayList datas = mDevice.getMotionDatas(); if (mOnMotionDataReceiveListener != null) { mOnMotionDataReceiveListener.onMotionDataReceive(datas, mBackgroundHandler); } } + */ if (mOpened) mBackgroundHandler.post(this); } diff --git a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java index cfa4742..2072c9a 100644 --- a/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java +++ b/wrappers/android/mynteye/app/src/main/java/com/slightech/mynteye/demo/ui/MainActivity.java @@ -32,6 +32,7 @@ import com.slightech.mynteye.usb.CameraDialog; import com.slightech.mynteye.usb.USBMonitor; import com.slightech.mynteye.usb.USBMonitor.OnDeviceConnectListener; import com.slightech.mynteye.usb.USBMonitor.UsbControlBlock; +import com.slightech.mynteye.util.BitmapUtils; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Locale; @@ -166,51 +167,8 @@ public class MainActivity extends BaseActivity implements CameraDialog.CameraDia private void actionOpen(final Runnable completeEvent) { if (completeEvent != null) completeEvent.run(); CameraDialog.showDialog(this); - /* - if (!RootUtils.isRooted()) { - if (completeEvent != null) completeEvent.run(); - alert("Warning", "Root denied :("); - return; - } - RootUtils.requestAccessible(ok -> { - if (completeEvent != null) completeEvent.run(); - if (ok) { - toast("Root granted :)"); - showDevices(); - } else { - alert("Warning", "There are no devices accessible."); - } - }); - */ } - /* - private void showDevices() { - ArrayList infos = Device.query(); - if (infos.isEmpty()) { - alert("Warning", "There are no devices :("); - } else { - ArrayList items = new ArrayList<>(); - for (DeviceUsbInfo info : infos) { - items.add(String.format(Locale.getDefault(), "%d, %s, SN: %s", - info.getIndex(), info.getName(), info.getSn())); - } - - AlertDialog dialog = new AlertDialog.Builder(this) - .setTitle("Devices") - .create(); - ListView listView = new ListView(this); - listView.setAdapter(new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, items)); - listView.setOnItemClickListener((parent, view, position, id) -> { - dialog.dismiss(); - openDevice(infos.get(position)); - }); - dialog.setView(listView); - dialog.show(); - } - } - */ - private void openDevice(DeviceUsbInfo info) { mMynteye = new Mynteye(info); ArrayList requests = mMynteye.getStreamRequests(); @@ -256,15 +214,9 @@ public class MainActivity extends BaseActivity implements CameraDialog.CameraDia //Timber.i("onStreamLeftReceive"); Frame frame = data.frame(); if (mLeftBitmap == null) { - Bitmap.Config config; - switch (frame.format()) { - case GREY: config = Bitmap.Config.ALPHA_8; break; - case RGB888: config = Bitmap.Config.ARGB_8888; break; - default: Timber.e("Unaccepted stream format"); return; - } - mLeftBitmap = Bitmap.createBitmap(frame.width(), frame.height(), config); + mLeftBitmap = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888); } - mLeftBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(frame.data())); + BitmapUtils.copyPixels(frame, mLeftBitmap); mLeftImageView.post(() -> mLeftImageView.setImageBitmap(mLeftBitmap)); } @@ -273,15 +225,9 @@ public class MainActivity extends BaseActivity implements CameraDialog.CameraDia //Timber.i("onStreamRightReceive"); Frame frame = data.frame(); if (mRightBitmap == null) { - Bitmap.Config config; - switch (frame.format()) { - case GREY: config = Bitmap.Config.ALPHA_8; break; - case RGB888: config = Bitmap.Config.ARGB_8888; break; - default: Timber.e("Unaccepted stream format"); return; - } - mRightBitmap = Bitmap.createBitmap(frame.width(), frame.height(), config); + mRightBitmap = Bitmap.createBitmap(frame.width(), frame.height(), Bitmap.Config.ARGB_8888); } - mRightBitmap.copyPixelsFromBuffer(ByteBuffer.wrap(frame.data())); + BitmapUtils.copyPixels(frame, mRightBitmap); mRightImageView.post(() -> mRightImageView.setImageBitmap(mRightBitmap)); } diff --git a/wrappers/android/mynteye/libmynteye/CMakeLists.txt b/wrappers/android/mynteye/libmynteye/CMakeLists.txt index eefcdad..59b7d14 100644 --- a/wrappers/android/mynteye/libmynteye/CMakeLists.txt +++ b/wrappers/android/mynteye/libmynteye/CMakeLists.txt @@ -28,6 +28,10 @@ endif() find_library(log-lib log) +## jnigraphics + +find_library(jnigraphics-lib jnigraphics) + ## djinni_jni include_directories( @@ -115,6 +119,7 @@ endforeach() add_library(mynteye_jni SHARED ${DJINNI_DIR}/support-lib/jni/djinni_main.cpp + ${CPP_DIR}/mynteye/impl/util/jni_util.cpp ${MYNTEYE_JNI_SRCS} ) -target_link_libraries(mynteye_jni ${log-lib} djinni_jni mynteye mynteye_internal) +target_link_libraries(mynteye_jni ${log-lib} ${jnigraphics-lib} djinni_jni mynteye mynteye_internal) diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp index 01225b6..2e88380 100644 --- a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/frame_impl.hpp @@ -39,6 +39,10 @@ class FrameImpl : public Frame { return std::vector(frame_->data(), frame_->data() + frame_->size()); } + frame_t RawFrame() const { + return frame_; + } + private: frame_t frame_; }; diff --git a/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp new file mode 100644 index 0000000..5a46c09 --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/cpp/mynteye/impl/util/jni_util.cpp @@ -0,0 +1,117 @@ +#include +#include +#include + +#ifndef LOG_TAG +#define LOG_TAG "native" +#endif + +#define LOGI(...) \ + ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)) +#define LOGW(...) \ + ((void)__android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__)) +#define LOGE(...) \ + ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) + +#include "NativeFrame.hpp" + +#include "frame_impl.hpp" + +// BitmapUtils + +// RGBA +typedef struct { + uint8_t r; + uint8_t g; + uint8_t b; + uint8_t a; +} rgba_t; + +void copyPixelsGray(std::uint8_t *from, rgba_t *to, uint32_t n); +void copyPixelsBGR3(std::uint8_t *from, rgba_t *to, uint32_t n); +void copyPixelsRGB3(std::uint8_t *from, rgba_t *to, uint32_t n); + +void copyPixels(mynteye_jni::FrameImpl::frame_t from, rgba_t *to, + const AndroidBitmapInfo &info) { + if (info.width != from->width() || info.height != from->height()) { + LOGE("Frame size is not same"); + return; + } + uint32_t n = info.width * info.height; + switch (from->format()) { + case MYNTEYE_NAMESPACE::Format::GREY: + copyPixelsGray(from->data(), to, n); + return; + case MYNTEYE_NAMESPACE::Format::BGR888: + copyPixelsBGR3(from->data(), to, n); + return; + case MYNTEYE_NAMESPACE::Format::RGB888: + copyPixelsRGB3(from->data(), to, n); + return; + case MYNTEYE_NAMESPACE::Format::YUYV: + default: + LOGE("Frame format is not supported"); + return; + } +} + +CJNIEXPORT void JNICALL Java_com_slightech_mynteye_util_BitmapUtils_copyPixels( + JNIEnv *env, jclass clazz, jobject j_frame, jobject bitmap) { + auto frame = ::djinni_generated::NativeFrame::toCpp(env, j_frame); + // LOGI("frame format: %dx%d", frame->Width(), frame->Height()); + auto frame_raw = std::dynamic_pointer_cast(frame)->RawFrame(); + + AndroidBitmapInfo info; + int result; + if ((result = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { + LOGE("AndroidBitmap_getInfo() failed, error=%d", result); + return; + } + if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) { + LOGE("Bitmap format is not RGBA_8888!"); + return; + } + + void *pixels; + if ((result = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { + LOGE("AndroidBitmap_lockPixels() failed, error=%d", result); + } + rgba_t *rgba_pixels = static_cast(pixels); + + copyPixels(frame_raw, rgba_pixels, info); + + AndroidBitmap_unlockPixels(env, bitmap); +} + +void copyPixelsGray(std::uint8_t *from, rgba_t *to, uint32_t n) { + for (uint32_t i = 0; i < n; ++i) { + std::uint8_t &gray = from[i]; + rgba_t &rgba = to[i]; + rgba.r = gray; + rgba.g = gray; + rgba.b = gray; + rgba.a = 255; + } +} + +void copyPixelsBGR3(std::uint8_t *from, rgba_t *to, uint32_t n) { + for (uint32_t i = 0; i < n; ++i) { + std::uint8_t *bgr = from + (i*3); + rgba_t &rgba = to[i]; + rgba.r = *(bgr + 2); + rgba.g = *(bgr + 1); + rgba.b = *(bgr); + rgba.a = 255; + } +} + +void copyPixelsRGB3(std::uint8_t *from, rgba_t *to, uint32_t n) { + for (uint32_t i = 0; i < n; ++i) { + std::uint8_t *rgb = from + (i*3); + rgba_t &rgba = to[i]; + rgba.r = *(rgb); + rgba.g = *(rgb + 1); + rgba.b = *(rgb + 2); + rgba.a = 255; + } +} diff --git a/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BitmapUtils.java b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BitmapUtils.java new file mode 100644 index 0000000..377407c --- /dev/null +++ b/wrappers/android/mynteye/libmynteye/src/main/java/com/slightech/mynteye/util/BitmapUtils.java @@ -0,0 +1,10 @@ +package com.slightech.mynteye.util; + +import android.graphics.Bitmap; +import com.slightech.mynteye.Frame; + +public class BitmapUtils { + + public static native void copyPixels(Frame from, Bitmap to); + +}