feat(android): add native bitmap utils
This commit is contained in:
		
							parent
							
								
									44bff1992a
								
							
						
					
					
						commit
						05d46111b7
					
				| @ -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<MotionData> datas = mDevice.getMotionDatas(); | ||||
|       if (mOnMotionDataReceiveListener != null) { | ||||
|         mOnMotionDataReceiveListener.onMotionDataReceive(datas, mBackgroundHandler); | ||||
|       } | ||||
|     } | ||||
|     */ | ||||
| 
 | ||||
|     if (mOpened) mBackgroundHandler.post(this); | ||||
|   } | ||||
|  | ||||
| @ -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<DeviceUsbInfo> infos = Device.query(); | ||||
|     if (infos.isEmpty()) { | ||||
|       alert("Warning", "There are no devices :("); | ||||
|     } else { | ||||
|       ArrayList<String> 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<StreamRequest> 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)); | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -39,6 +39,10 @@ class FrameImpl : public Frame { | ||||
|     return std::vector<uint8_t>(frame_->data(), frame_->data() + frame_->size()); | ||||
|   } | ||||
| 
 | ||||
|   frame_t RawFrame() const { | ||||
|     return frame_; | ||||
|   } | ||||
| 
 | ||||
|  private: | ||||
|   frame_t frame_; | ||||
| }; | ||||
|  | ||||
| @ -0,0 +1,117 @@ | ||||
| #include <android/bitmap.h> | ||||
| #include <android/log.h> | ||||
| #include <jni.h> | ||||
| 
 | ||||
| #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<mynteye_jni::FrameImpl>(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<rgba_t*>(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; | ||||
|   } | ||||
| } | ||||
| @ -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); | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user