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.
This commit is contained in:
Jim Chen 2016-08-26 12:26:46 -04:00
parent d924b1c615
commit ab92abb418
5 changed files with 83 additions and 78 deletions

View File

@ -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<android.hardware.Camera.Size> sit = params.getSupportedPreviewSizes().iterator();
Iterator<Camera.Size> 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;

View File

@ -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<Callback>
{
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<char*>(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<int32_t> ret = retArray->GetElements();
mWidth = uint32_t(ret[1]);
mHeight = uint32_t(ret[2]);
mFps = uint32_t(ret[3]);
return !!ret[0];
}
void CameraStreamImpl::Close() {

View File

@ -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;

View File

@ -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)
{

View File

@ -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,