From ab92abb4187d456719c5209f86a768b832103558 Mon Sep 17 00:00:00 2001 From: Jim Chen Date: Fri, 26 Aug 2016 12:26:46 -0400 Subject: [PATCH] Bug 1296744 - Make cameraCallbackBridge use new native JNI bindings; r=snorp Make the GeckoAppShell.cameraCallbackBridge callback use the new native JNI bindings. Also refactor the relevant code in GeckoAppShell and CameraStreamImpl. --- .../java/org/mozilla/gecko/GeckoAppShell.java | 45 ++++++++----- netwerk/protocol/device/CameraStreamImpl.cpp | 66 ++++++++++++------- netwerk/protocol/device/CameraStreamImpl.h | 25 +++---- widget/android/AndroidBridge.cpp | 23 ------- widget/android/AndroidBridge.h | 2 - 5 files changed, 83 insertions(+), 78 deletions(-) diff --git a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java index 6180882607c6..c8a53589af22 100644 --- a/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java +++ b/mobile/android/geckoview/src/main/java/org/mozilla/gecko/GeckoAppShell.java @@ -70,6 +70,7 @@ import android.graphics.RectF; import android.graphics.SurfaceTexture; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; +import android.hardware.Camera; import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; @@ -1826,13 +1827,30 @@ public class GeckoAppShell sGeckoInterface = aGeckoInterface; } - public static android.hardware.Camera sCamera; + /* package */ static Camera sCamera; - static native void cameraCallbackBridge(byte[] data); + private static final int kPreferredFPS = 25; + private static byte[] sCameraBuffer; - static final int kPreferredFPS = 25; - static byte[] sCameraBuffer; + private static class CameraCallback implements Camera.PreviewCallback { + @WrapForJNI(calledFrom = "gecko") + private static native void onFrameData(int camera, byte[] data); + private final int mCamera; + + public CameraCallback(int camera) { + mCamera = camera; + } + + @Override + public void onPreviewFrame(byte[] data, Camera camera) { + onFrameData(mCamera, data); + + if (sCamera != null) { + sCamera.addCallbackBuffer(sCameraBuffer); + } + } + } @WrapForJNI(calledFrom = "gecko") static int[] initCamera(String aContentType, int aCamera, int aWidth, int aHeight) { @@ -1853,14 +1871,14 @@ public class GeckoAppShell int[] result = new int[4]; result[0] = 0; - if (android.hardware.Camera.getNumberOfCameras() == 0) { + if (Camera.getNumberOfCameras() == 0) { return result; } try { - sCamera = android.hardware.Camera.open(aCamera); + sCamera = Camera.open(aCamera); - android.hardware.Camera.Parameters params = sCamera.getParameters(); + Camera.Parameters params = sCamera.getParameters(); params.setPreviewFormat(ImageFormat.NV21); // use the preview fps closest to 25 fps. @@ -1879,11 +1897,11 @@ public class GeckoAppShell } // set up the closest preview size available - Iterator sit = params.getSupportedPreviewSizes().iterator(); + Iterator sit = params.getSupportedPreviewSizes().iterator(); int sizeDelta = 10000000; int bufferSize = 0; while (sit.hasNext()) { - android.hardware.Camera.Size size = sit.next(); + Camera.Size size = sit.next(); if (Math.abs(size.width * size.height - aWidth * aHeight) < sizeDelta) { sizeDelta = Math.abs(size.width * size.height - aWidth * aHeight); params.setPreviewSize(size.width, size.height); @@ -1907,14 +1925,7 @@ public class GeckoAppShell sCamera.setParameters(params); sCameraBuffer = new byte[(bufferSize * 12) / 8]; sCamera.addCallbackBuffer(sCameraBuffer); - sCamera.setPreviewCallbackWithBuffer(new android.hardware.Camera.PreviewCallback() { - @Override - public void onPreviewFrame(byte[] data, android.hardware.Camera camera) { - cameraCallbackBridge(data); - if (sCamera != null) - sCamera.addCallbackBuffer(sCameraBuffer); - } - }); + sCamera.setPreviewCallbackWithBuffer(new CameraCallback(aCamera)); sCamera.startPreview(); params = sCamera.getParameters(); result[0] = 1; diff --git a/netwerk/protocol/device/CameraStreamImpl.cpp b/netwerk/protocol/device/CameraStreamImpl.cpp index fc13a650a6b3..f4a2cf4a4fda 100644 --- a/netwerk/protocol/device/CameraStreamImpl.cpp +++ b/netwerk/protocol/device/CameraStreamImpl.cpp @@ -3,26 +3,12 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CameraStreamImpl.h" +#include "GeneratedJNINatives.h" #include "nsCRTGlue.h" #include "nsThreadUtils.h" #include "nsXULAppAPI.h" #include "mozilla/Monitor.h" -/** - * JNI part & helper runnable - */ - -extern "C" { - NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge(JNIEnv *, jclass, jbyteArray data); -} - -NS_EXPORT void JNICALL -Java_org_mozilla_gecko_GeckoAppShell_cameraCallbackBridge(JNIEnv *env, jclass, jbyteArray data) { - mozilla::net::CameraStreamImpl* impl = mozilla::net::CameraStreamImpl::GetInstance(0); - - impl->transmitFrame(env, &data); -} - using namespace mozilla; namespace mozilla { @@ -31,20 +17,40 @@ namespace net { static CameraStreamImpl* mCamera0 = nullptr; static CameraStreamImpl* mCamera1 = nullptr; +class CameraStreamImpl::Callback + : public java::GeckoAppShell::CameraCallback::Natives +{ +public: + static void OnFrameData(int32_t aCamera, jni::ByteArray::Param aData) + { + MOZ_ASSERT(NS_IsMainThread()); + + CameraStreamImpl* impl = GetInstance(uint32_t(aCamera)); + if (impl) { + impl->TransmitFrame(aData); + } + } +}; + /** * CameraStreamImpl */ -void CameraStreamImpl::transmitFrame(JNIEnv *env, jbyteArray *data) { - if (!mCallback) - return; - jboolean isCopy; - jbyte* jFrame = env->GetByteArrayElements(*data, &isCopy); - uint32_t length = env->GetArrayLength(*data); - if (length > 0) { - mCallback->ReceiveFrame((char*)jFrame, length); +void CameraStreamImpl::TransmitFrame(jni::ByteArray::Param aData) { + if (!mCallback) { + return; } - env->ReleaseByteArrayElements(*data, jFrame, 0); + + JNIEnv* const env = jni::GetGeckoThreadEnv(); + const size_t length = size_t(env->GetArrayLength(aData.Get())); + + if (!length) { + return; + } + + jbyte* const data = env->GetByteArrayElements(aData.Get(), nullptr); + mCallback->ReceiveFrame(reinterpret_cast(data), length); + env->ReleaseByteArrayElements(aData.Get(), data, JNI_ABORT); } CameraStreamImpl* CameraStreamImpl::GetInstance(uint32_t aCamera) { @@ -86,7 +92,17 @@ bool CameraStreamImpl::Init(const nsCString& contentType, const uint32_t& camera mCallback = aCallback; mWidth = width; mHeight = height; - return AndroidBridge::Bridge()->InitCamera(contentType, camera, &mWidth, &mHeight, &mFps); + + Callback::Init(); + jni::IntArray::LocalRef retArray = java::GeckoAppShell::InitCamera( + contentType, int32_t(camera), int32_t(width), int32_t(height)); + nsTArray ret = retArray->GetElements(); + + mWidth = uint32_t(ret[1]); + mHeight = uint32_t(ret[2]); + mFps = uint32_t(ret[3]); + + return !!ret[0]; } void CameraStreamImpl::Close() { diff --git a/netwerk/protocol/device/CameraStreamImpl.h b/netwerk/protocol/device/CameraStreamImpl.h index 1ce1b37ebede..f5ea97cb587e 100644 --- a/netwerk/protocol/device/CameraStreamImpl.h +++ b/netwerk/protocol/device/CameraStreamImpl.h @@ -5,8 +5,9 @@ #ifndef __CAMERASTREAMIMPL_H__ #define __CAMERASTREAMIMPL_H__ +#include "mozilla/jni/Refs.h" + #include "nsString.h" -#include "AndroidBridge.h" /** * This singleton class handles communication with the Android camera @@ -15,45 +16,47 @@ namespace mozilla { namespace net { - + class CameraStreamImpl { public: class FrameCallback { public: virtual void ReceiveFrame(char* frame, uint32_t length) = 0; }; - + /** * instance bound to a given camera */ static CameraStreamImpl* GetInstance(uint32_t aCamera); - + bool initNeeded() { return !mInit; } - + FrameCallback* GetFrameCallback() { return mCallback; } - + bool Init(const nsCString& contentType, const uint32_t& camera, const uint32_t& width, const uint32_t& height, FrameCallback* callback); void Close(); - + uint32_t GetWidth() { return mWidth; } uint32_t GetHeight() { return mHeight; } uint32_t GetFps() { return mFps; } - + void takePicture(const nsAString& aFileName); - - void transmitFrame(JNIEnv *env, jbyteArray *data); - + private: + class Callback; + CameraStreamImpl(uint32_t aCamera); CameraStreamImpl(const CameraStreamImpl&); CameraStreamImpl& operator=(const CameraStreamImpl&); ~CameraStreamImpl(); + void TransmitFrame(jni::ByteArray::Param aData); + bool mInit; uint32_t mCamera; uint32_t mWidth; diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 3d393564a4b7..0f115db6c1a9 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -682,29 +682,6 @@ namespace mozilla { } -bool -AndroidBridge::InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps) -{ - auto arr = GeckoAppShell::InitCamera - (NS_ConvertUTF8toUTF16(contentType), (int32_t) camera, (int32_t) *width, (int32_t) *height); - - if (!arr) - return false; - - JNIEnv* const env = arr.Env(); - jint *elements = env->GetIntArrayElements(arr.Get(), 0); - - *width = elements[1]; - *height = elements[2]; - *fps = elements[3]; - - bool res = elements[0] == 1; - - env->ReleaseIntArrayElements(arr.Get(), elements, 0); - - return res; -} - void AndroidBridge::GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo) { diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index f66724b28c42..60043d3e8a7c 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -192,8 +192,6 @@ public: void HandleGeckoMessage(JSContext* cx, JS::HandleObject message); - bool InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps); - void GetCurrentBatteryInformation(hal::BatteryInformation* aBatteryInfo); nsresult GetSegmentInfoForText(const nsAString& aText,