Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2387208c authored by Android (Google) Code Review's avatar Android (Google) Code Review Committed by The Android Open Source Project
Browse files

am 3d7b8d1a: Merge change 5158 into donut

Merge commit '3d7b8d1a'

* commit '3d7b8d1a':
  Use a ref-counted callback interface for Camera.
parents ffcdad9f 3d7b8d1a
Loading
Loading
Loading
Loading
+156 −182
Original line number Original line Diff line number Diff line
@@ -53,19 +53,33 @@ struct fields_t {
static fields_t fields;
static fields_t fields;
static Mutex sLock;
static Mutex sLock;


struct camera_context_t {
// provides persistent context for calls from native code to Java
class JNICameraContext: public CameraListener
{
public:
    JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera);
    ~JNICameraContext() { release(); }
    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2);
    virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr);
    sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; }
    void release();

private:
    void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType);

    jobject     mCameraJObjectWeak;     // weak reference to java object
    jobject     mCameraJObjectWeak;     // weak reference to java object
    jclass      mCameraJClass;          // strong reference to java class
    jclass      mCameraJClass;          // strong reference to java class
    sp<Camera>  mCamera;                // strong reference to native object 
    sp<Camera>  mCamera;                // strong reference to native object 
    Mutex       mLock;
};
};


sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext)
sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext)
{
{
    sp<Camera> camera;
    sp<Camera> camera;
    Mutex::Autolock _l(sLock);
    Mutex::Autolock _l(sLock);
    camera_context_t* context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
    JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));
    if (context != NULL) {
    if (context != NULL) {
        camera = context->mCamera;
        camera = context->getCamera();
    }
    }
    LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
    LOGV("get_native_camera: context=%p, camera=%p", context, camera.get());
    if (camera == 0) {
    if (camera == 0) {
@@ -76,15 +90,48 @@ sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pCont
    return camera;
    return camera;
}
}


static void err_callback(status_t err, void *cookie)
JNICameraContext::JNICameraContext(JNIEnv* env, jobject weak_this, jclass clazz, const sp<Camera>& camera)
{
{
    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
    mCameraJObjectWeak = env->NewGlobalRef(weak_this);
    if ((context == NULL) || (context->mCamera == 0)) return;
    mCameraJClass = (jclass)env->NewGlobalRef(clazz);
    mCamera = camera;
}


    LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get());
void JNICameraContext::release()
{
    LOGV("release");
    Mutex::Autolock _l(mLock);
    JNIEnv *env = AndroidRuntime::getJNIEnv();


    if (mCameraJObjectWeak != NULL) {
        env->DeleteGlobalRef(mCameraJObjectWeak);
        mCameraJObjectWeak = NULL;
    }
    if (mCameraJClass != NULL) {
        env->DeleteGlobalRef(mCameraJClass);
        mCameraJClass = NULL;
    }
    mCamera.clear();
}

void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2)
{
    LOGV("notify");

    // VM pointer will be NULL if object is released
    Mutex::Autolock _l(mLock);
    if (mCameraJObjectWeak == NULL) {
        LOGW("callback on dead camera object");
        return;
    }
    JNIEnv *env = AndroidRuntime::getJNIEnv();

    // parse message
    switch (msgType) {
    case CAMERA_MSG_ERROR:
        LOGV("errorCallback");
        int error;
        int error;
    switch (err) {
        switch (ext1) {
            case DEAD_OBJECT:
            case DEAD_OBJECT:
                error = kCameraErrorMediaServer;
                error = kCameraErrorMediaServer;
                break;
                break;
@@ -92,14 +139,91 @@ static void err_callback(status_t err, void *cookie)
                error = kCameraErrorUnknown;
                error = kCameraErrorUnknown;
                break;
                break;
        }
        }
        env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
                mCameraJObjectWeak, kErrorCallback, error, 0, NULL);
        break;
    case CAMERA_MSG_FOCUS:
        LOGV("autoFocusCallback");
        env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
                mCameraJObjectWeak, kAutoFocusCallback, ext1, 0, NULL);
        break;
    case CAMERA_MSG_SHUTTER:
        LOGV("shutterCallback");
        env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
                mCameraJObjectWeak, kShutterCallback, 0, 0, NULL);
        break;
    default:
        LOGV("notifyCallback(%d, %d, %d)", msgType, ext1, ext2);
        break;
    }
}


void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType)
{
    jbyteArray obj = NULL;

    // allocate Java byte array and copy data
    if (dataPtr != NULL) {
        ssize_t offset;
        size_t size;
        sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size);
        LOGV("postData: off=%d, size=%d", offset, size);
        uint8_t *heapBase = (uint8_t*)heap->base();

        if (heapBase != NULL) {
            uint8_t *data = heapBase + offset;
            obj = env->NewByteArray(size);
            if (obj == NULL) {
                LOGE("Couldn't allocate byte array for JPEG data");
                env->ExceptionClear();
            } else {
                jbyte *bytes = env->GetByteArrayElements(obj, NULL);
                memcpy(bytes, data, size);
                env->ReleaseByteArrayElements(obj, bytes, 0);

            }
        } else {
            LOGE("image heap is NULL");
        }
    }

    // post image data to Java
    env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
            mCameraJObjectWeak, msgType, 0, 0, obj);
    if (obj) {
        env->DeleteLocalRef(obj);
    }
}

void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr)
{
    // VM pointer will be NULL if object is released
    Mutex::Autolock _l(mLock);
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {

        LOGE("err_callback on dead VM");
    // return data based on callback type
        return;
    switch(msgType) {
    case CAMERA_MSG_PREVIEW_FRAME:
        LOGV("previewCallback");
        copyAndPost(env, dataPtr, kPreviewCallback);
        break;
    case CAMERA_MSG_VIDEO_FRAME:
        LOGV("recordingCallback");
        break;
    case CAMERA_MSG_RAW_IMAGE:
        LOGV("rawCallback");
        env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
                mCameraJObjectWeak, kRawCallback, 0, 0, NULL);
        break;
    case CAMERA_MSG_COMPRESSED_IMAGE:
        LOGV("jpegCallback");
        copyAndPost(env, dataPtr, kJpegCallback);
        break;
    default:
        LOGV("dataCallback(%d, %p)", msgType, dataPtr.get());
        break;
    }
    }
    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,

            context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL);
}
}


// connect to camera service
// connect to camera service
@@ -127,19 +251,12 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj


    // We use a weak reference so the Camera object can be garbage collected.
    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    // The reference is only used as a proxy for callbacks.
    camera_context_t* context = new camera_context_t;
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->mCameraJObjectWeak = env->NewGlobalRef(weak_this);
    context->incStrong(thiz);
    context->mCameraJClass = (jclass)env->NewGlobalRef(clazz);
    camera->setListener(context);
    context->mCamera = camera;


    // save context in opaque field
    // save context in opaque field
    env->SetIntField(thiz, fields.context, (int)context);
    env->SetIntField(thiz, fields.context, (int)context.get());

    LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p",
            (int)context->mCameraJObjectWeak, (int)thiz, context);

    // set error callback
    camera->setErrorCallback(err_callback, context);
}
}


// disconnect from camera service
// disconnect from camera service
@@ -148,11 +265,11 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj
// finalizer is invoked later.
// finalizer is invoked later.
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)
{
{
    camera_context_t* context = NULL;
    JNICameraContext* context = NULL;
    sp<Camera> camera;
    sp<Camera> camera;
    {
    {
        Mutex::Autolock _l(sLock);
        Mutex::Autolock _l(sLock);
        context = reinterpret_cast<camera_context_t*>(env->GetIntField(thiz, fields.context));
        context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));


        // Make sure we do not attempt to callback on a deleted Java object.
        // Make sure we do not attempt to callback on a deleted Java object.
        env->SetIntField(thiz, fields.context, 0);
        env->SetIntField(thiz, fields.context, 0);
@@ -160,21 +277,18 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz)


    // clean up if release has not been called before
    // clean up if release has not been called before
    if (context != NULL) {
    if (context != NULL) {
        camera = context->mCamera;
        camera = context->getCamera();
        context->mCamera.clear();
        context->release();
        LOGV("native_release: context=%p camera=%p", context, camera.get());
        LOGV("native_release: context=%p camera=%p", context, camera.get());


        // clear callbacks
        // clear callbacks
        if (camera != NULL) {
        if (camera != NULL) {
            camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP);
            camera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP);
            camera->setErrorCallback(NULL, NULL);
            camera->disconnect();
            camera->disconnect();
            env->DeleteGlobalRef(context->mCameraJObjectWeak);
            env->DeleteGlobalRef(context->mCameraJClass);
        }
        }


        // remove context to prevent further Java access
        // remove context to prevent further Java access
        delete context;
        context->decStrong(thiz);
    }
    }
}
}


@@ -190,48 +304,6 @@ static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz,
    }
    }
}
}


static void preview_callback(const sp<IMemory>& mem, void *cookie)
{
    LOGV("preview_callback");
    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        LOGE("preview_callback on dead VM");
        return;
    }
    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);
    if ((context == NULL) || (context->mCamera == 0)) {
        LOGW("context or camera is NULL in preview_callback");
        return;
    }
    LOGV("native_release: context=%p camera=%p", context, context->mCamera.get());

    int arg1 = 0, arg2 = 0;
    jobject obj = NULL;

    ssize_t offset;
    size_t size;
    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);

    uint8_t *data = ((uint8_t *)heap->base()) + offset;

    jbyteArray array = env->NewByteArray(size);
    if (array == NULL) {
        LOGE("Couldn't allocate byte array for YUV data");
        env->ExceptionClear();
        return;
    }

    jbyte *bytes = env->GetByteArrayElements(array, NULL);
    memcpy(bytes, data, size);
    env->ReleaseByteArrayElements(array, bytes, 0);

    obj = array;

    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
            context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj);
    env->DeleteLocalRef(array);
}

static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz)
{
{
    LOGV("startPreview");
    LOGV("startPreview");
@@ -267,7 +339,7 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
    // Important: Only install preview_callback if the Java code has called
    // Important: Only install preview_callback if the Java code has called
    // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
    // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy
    // each preview frame for nothing.
    // each preview frame for nothing.
    camera_context_t* context;
    JNICameraContext* context;
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    if (camera == 0) return;
    if (camera == 0) return;


@@ -277,130 +349,32 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t
    } else {
    } else {
        callback_flag = FRAME_CALLBACK_FLAG_NOOP;
        callback_flag = FRAME_CALLBACK_FLAG_NOOP;
    }
    }
    camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag);
    camera->setPreviewCallbackFlags(callback_flag);
}

static void autofocus_callback_impl(bool success, void *cookie)
{
    LOGV("autoFocusCallback");
    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);

    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        LOGE("autofocus_callback on dead VM");
        return;
    }
    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
            context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL);
}
}


static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz)
{
{
    LOGV("autoFocus");
    LOGV("autoFocus");
    camera_context_t* context;
    JNICameraContext* context;
    sp<Camera> c = get_native_camera(env, thiz, &context);
    sp<Camera> c = get_native_camera(env, thiz, &context);
    if (c == 0) return;
    if (c == 0) return;


    c->setAutoFocusCallback(autofocus_callback_impl, context);
    if (c->autoFocus() != NO_ERROR) {
    if (c->autoFocus() != NO_ERROR) {
        jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed");
        jniThrowException(env, "java/lang/RuntimeException", "autoFocus failed");
    }
    }
}
}


static void jpeg_callback(const sp<IMemory>& mem, void *cookie)
{
    LOGV("jpegCallback");
    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);

    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        LOGE("jpeg`_callback on dead VM");
        return;
    }
    int arg1 = 0, arg2 = 0;
    jobject obj = NULL;

    if (mem == NULL) {
        env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
                                  context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL);
        return;
    }
    ssize_t offset;
    size_t size;
    sp<IMemoryHeap> heap = mem->getMemory(&offset, &size);
    LOGV("jpeg_callback: mem off=%d, size=%d", offset, size);

    uint8_t *heap_base = (uint8_t *)heap->base();
    if (heap_base == NULL) {
        LOGE("YUV heap is NULL");
        return;
    }

    uint8_t *data = heap_base + offset;

    jbyteArray array = env->NewByteArray(size);
    if (array == NULL) {
        LOGE("Couldn't allocate byte array for JPEG data");
        env->ExceptionClear();
        return;
    }

    jbyte *bytes = env->GetByteArrayElements(array, NULL);
    memcpy(bytes, data, size);
    env->ReleaseByteArrayElements(array, bytes, 0);

    obj = array;

    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
                              context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj);
    env->DeleteLocalRef(array);
}

static void shutter_callback_impl(void *cookie)
{
    LOGV("shutterCallback");
    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);

    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        LOGE("shutter_callback on dead VM");
        return;
    }
    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
                              context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL);
}

static void raw_callback(const sp<IMemory>& mem __attribute__((unused)),
                         void *cookie)
{
    LOGV("rawCallback");
    camera_context_t* context = reinterpret_cast<camera_context_t*>(cookie);

    JNIEnv *env = AndroidRuntime::getJNIEnv();
    if (env == NULL) {
        LOGE("raw_callback on dead VM");
        return;
    }
    env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event,
                              context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL);
}

static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz)
{
{
    LOGV("takePicture");
    LOGV("takePicture");
    camera_context_t* context;
    JNICameraContext* context;
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    sp<Camera> camera = get_native_camera(env, thiz, &context);
    if (camera == 0) return;
    if (camera == 0) return;


    camera->setShutterCallback(shutter_callback_impl, context);
    camera->setRawCallback(raw_callback, context);
    camera->setJpegCallback(jpeg_callback, context);
    if (camera->takePicture() != NO_ERROR) {
    if (camera->takePicture() != NO_ERROR) {
        jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
        jniThrowException(env, "java/lang/RuntimeException", "takePicture failed");
        return;
        return;
    }
    }

    return;
}
}


static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params)
+13 −0
Original line number Original line Diff line number Diff line
@@ -86,6 +86,14 @@ class Surface;
class Mutex;
class Mutex;
class String8;
class String8;


// ref-counted object for callbacks
class CameraListener: virtual public RefBase
{
public:
    virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2) = 0;
    virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr) = 0;
};

typedef void (*shutter_callback)(void *cookie);
typedef void (*shutter_callback)(void *cookie);
typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
typedef void (*frame_callback)(const sp<IMemory>& mem, void *cookie);
typedef void (*autofocus_callback)(bool focused, void *cookie);
typedef void (*autofocus_callback)(bool focused, void *cookie);
@@ -152,6 +160,9 @@ public:
            void        setErrorCallback(error_callback cb, void *cookie);
            void        setErrorCallback(error_callback cb, void *cookie);
            void        setAutoFocusCallback(autofocus_callback cb, void *cookie);
            void        setAutoFocusCallback(autofocus_callback cb, void *cookie);


            void        setListener(const sp<CameraListener>& listener);
            void        setPreviewCallbackFlags(int preview_callback_flag);

    // ICameraClient interface
    // ICameraClient interface
    virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
    virtual void        notifyCallback(int32_t msgType, int32_t ext, int32_t ext2);
    virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
    virtual void        dataCallback(int32_t msgType, const sp<IMemory>& dataPtr);
@@ -194,6 +205,8 @@ private:
            autofocus_callback  mAutoFocusCallback;
            autofocus_callback  mAutoFocusCallback;
            void                *mAutoFocusCallbackCookie;
            void                *mAutoFocusCallbackCookie;


            sp<CameraListener>  mListener;

            friend class DeathNotifier;
            friend class DeathNotifier;


            static  Mutex               mLock;
            static  Mutex               mLock;
+33 −0
Original line number Original line Diff line number Diff line
@@ -337,9 +337,32 @@ void Camera::setErrorCallback(error_callback cb, void *cookie)
    mErrorCallbackCookie = cookie;
    mErrorCallbackCookie = cookie;
}
}


void Camera::setListener(const sp<CameraListener>& listener)
{
    Mutex::Autolock _l(mLock);
    mListener = listener;
}

void Camera::setPreviewCallbackFlags(int flag)
{
    LOGV("setPreviewCallbackFlags");
    sp <ICamera> c = mCamera;
    if (c == 0) return;
    mCamera->setPreviewCallbackFlag(flag);
}

// callback from camera service
// callback from camera service
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
{
{
    sp<CameraListener> listener;
    {
        Mutex::Autolock _l(mLock);
        listener = mListener;
    }
    if (listener != NULL) {
        listener->notify(msgType, ext1, ext2);
    }

    switch(msgType) {
    switch(msgType) {
    case CAMERA_MSG_ERROR:
    case CAMERA_MSG_ERROR:
        LOGV("errorCallback");
        LOGV("errorCallback");
@@ -368,6 +391,15 @@ void Camera::notifyCallback(int32_t msgType, int32_t ext1, int32_t ext2)
// callback from camera service when frame or image is ready
// callback from camera service when frame or image is ready
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)
{
{
    sp<CameraListener> listener;
    {
        Mutex::Autolock _l(mLock);
        listener = mListener;
    }
    if (listener != NULL) {
        listener->postData(msgType, dataPtr);
    }

    switch(msgType) {
    switch(msgType) {
    case CAMERA_MSG_PREVIEW_FRAME:
    case CAMERA_MSG_PREVIEW_FRAME:
        LOGV("previewCallback");
        LOGV("previewCallback");
@@ -401,6 +433,7 @@ void Camera::dataCallback(int32_t msgType, const sp<IMemory>& dataPtr)


void Camera::binderDied(const wp<IBinder>& who) {
void Camera::binderDied(const wp<IBinder>& who) {
    LOGW("ICamera died");
    LOGW("ICamera died");
    notifyCallback(CAMERA_MSG_ERROR, DEAD_OBJECT, 0);
    if (mErrorCallback) {
    if (mErrorCallback) {
        mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
        mErrorCallback(DEAD_OBJECT, mErrorCallbackCookie);
    }
    }
+1 −1
Original line number Original line Diff line number Diff line
@@ -41,7 +41,7 @@ using namespace android;
// ----------------------------------------------------------------------------
// ----------------------------------------------------------------------------


// helper function to extract a native Camera object from a Camera Java object
// helper function to extract a native Camera object from a Camera Java object
extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct camera_context_t** context);
extern sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, struct JNICameraContext** context);


struct fields_t {
struct fields_t {
    jfieldID    context;
    jfieldID    context;