Camera服务之--JNI部分

这一部分主要在/frameworks/base/core/java/android/hardware/Camera.java和/frameworks/base/core/jni/android_hardware_Camera.cpp中实现的。

在Camera.java中声明了很多native的方法,这些方法都是在android_hardware_Camera.cpp,通过JNI的方式来调用。


1.Camera.java分析

Camera.java主要的功能就是提供一个对Camera操作的java入口,并且定义一些回调接口。

先看一下成员变量:

    private int mNativeContext; // accessed by native methods
    private EventHandler mEventHandler;
    private ShutterCallback mShutterCallback;
    private PictureCallback mRawImageCallback;
    private PictureCallback mJpegCallback;
    private PreviewCallback mPreviewCallback;
    private PictureCallback mPostviewCallback;
    private AutoFocusCallback mAutoFocusCallback;
    private OnZoomChangeListener mZoomListener;
    private ErrorCallback mErrorCallback;

除了mNativeContext都是上一篇文章提到的一些回调接口。这个mNativeContext实际上是给android_hardware_Camera.cpp使用的,在JNI部分会分析到。


再看一下open方法:

public static Camera open(int cameraId) {
        return new Camera(cameraId);
}

open是对Camera操作的入口方法,根据cameraID打开前置或后置摄像头。


再看看Camera的构造方法都做了什么:

Camera(int cameraId) {
        mShutterCallback = null;
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mZoomListener = null;

        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }

        native_setup(new WeakReference<Camera>(this), cameraId);
    }

也很简单,初始化关于回调接口的成员变量,然后调用native_setup(new WeakReference<Camera>(this), cameraId);,把自己和cameraID传进去,在JNI层进行初始化。

完成了以上初始化,就可以对Camera进行各种操作了,比如setPreviewDisplay, startPreview等。


2.android_hardware_Camera.cpp分析

(1)首先来看JNI的注册函数。

int register_android_hardware_Camera(JNIEnv *env)
{
    field fields_to_find[] = {
        { "android/hardware/Camera", "mNativeContext",   "I", &fields.context },
        { "android/view/Surface",    ANDROID_VIEW_SURFACE_JNI_ID, "I", &fields.surface },
        { "android/hardware/Camera$CameraInfo", "facing",   "I", &fields.facing },
        { "android/hardware/Camera$CameraInfo", "orientation",   "I", &fields.orientation },
    };

    if (find_fields(env, fields_to_find, NELEM(fields_to_find)) < 0)
        return -1;

    jclass clazz = env->FindClass("android/hardware/Camera");
    fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative",
                                               "(Ljava/lang/Object;IIILjava/lang/Object;)V");
    if (fields.post_event == NULL) {
        LOGE("Can't find android/hardware/Camera.postEventFromNative");
        return -1;
    }


    // Register native functions
    return AndroidRuntime::registerNativeMethods(env, "android/hardware/Camera",
                                              camMethods, NELEM(camMethods));
}

这个函数中主要做了两件事:第一,也就是JNI的基本任务,注册JNINativeMethod camMethods[]函数数组,使得java层可以调用。第二, 通过env->GetStaticMethodID获取到java层中postEventFromNative方法的ID,这样就可以将camera service的一些通知信息传递给java层。这也回答了上一篇《Camera服务之--Camera应用部分》的一个疑问,就是camera 色让vice是怎么通知上层应用的,就是通过这个postEventFromNative方法。

(2)android_hardware_Camera_native_setup分析

这个函数是java层向下调用的入口,如果需要对camera进行操作,这个是必须首先调用的。

// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId)
{
    sp<Camera> camera = Camera::connect(cameraId);
   .......
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
    context->incStrong(thiz);
    camera->setListener(context);

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

首先调用camera service的connect函数,获得一个camera service的对象(代理),然后创建一个JNICameraContext对象,并把service对象保存在其中,最后再把回调接口设置到camera service中。因为JNICameraContext实现了回调接口CameraListener,所以也就是把JNICameraContext设置到camera service中。


(3)其他JNI函数分析

通过JNI注册的其他函数,都是static的函数,这些函数基本上可以总结为两种实现方式:

一个是对camera service的对象(代理)的调用,比如

static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz)
{
    LOGV("stopPreview");
    sp<Camera> c = get_native_camera(env, thiz, NULL);
    if (c == 0) return;

    c->stopPreview();
}

另一个是对JNICameraContext对象的调用,比如:

static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) {
    LOGV("addCallbackBuffer");

    JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context));

    if (context != NULL) {
        context->addCallbackBuffer(env, bytes);
    }
}

(4)JNICameraContext分析

这个类实现了CameraListener接口,也就是实现了camera service的回调接口。这个类的主要作用就是这个,对camera service回调event的一个中转站,将回调event处理后调用java层的回调实现。

### UVCCamera JNI 使用方法及相关问题 在 Android 开发中,使用 UVCCameraJNI 技术可以实现对 USB 摄像头的支持以及更高效的图像处理功能。以下是关于 UVCCamera JNI 的具体用法及其可能涉及的问题。 #### 1. UVCCamera JNI 基本概念 UVCCamera 是一种用于支持 UVC (USB Video Class) 协议摄像头的库,在 Android 平台上可以通过 JNI 调用来访问底层硬件资源并获取视频流数据。JNI(Java Native Interface)允许 Java 程序调用本地 C/C++ 函数来执行性能敏感的操作[^1]。 为了使 UVCCamera 正常工作,开发者通常需要完成以下几个部分的工作: - **加载本地库**:通过 `System.loadLibrary` 方法加载预编译好的 `.so` 文件。 - **定义本地函数接口**:在 Java 层声明 native 方法并与 C/C++ 实现绑定。 - **初始化设备连接**:通过 JNI 接口打开指定的 USB 设备并配置其参数。 #### 2. 加载本地库示例 下面是一段典型的代码片段展示如何加载 UVCCamera 所需的本地库: ```java static { System.loadLibrary("uvc_camera"); // 替换为实际使用的 so 库名称 } ``` 此代码应放置在一个静态块中以确保仅被加载一次,并且应在应用启动初期尽早执行以便后续逻辑能够正常调用相关功能。 #### 3. 配置时区文件的重要性 如果应用程序依赖于精确的时间戳计算或者涉及到跨区域时间转换,则需要注意 JRE 中的核心组件——即 `[JRE]\lib\tzmappings` 文件的存在与否会对最终结果造成显著影响[^2]。即使是在嵌入式环境中部署精简版 JDK 或者自定义构建 AOSP 系统镜像时也应当保留此类必要资产以免引发潜在错误。 #### 4. 解决常见问题 ##### a. 图像显示异常 当观察到捕获的画面存在色彩失真或其他视觉瑕疵时,可能是由于未正确设置像素格式所致。建议检查当前选定模式下的帧描述符是否匹配目标平台需求;另外还需确认驱动层面上是否有足够的缓冲区分配给每一帧传输过程以防丢包现象发生。 ##### b. 性能瓶颈优化 对于实时性强的应用场景来说降低延迟尤为关键。一方面可以从算法层面着手改进比如采用多线程机制分离采集与渲染任务减少相互干扰;另一方面则考虑利用 GPU 加速技术卸载部分运算负载从而提升整体流畅度体验。 ##### c. 兼容性考量 不同厂商生产的UVC兼容型摄像机之间可能存在细微差异甚至个别特性缺失情况。因此最好事先查阅官方文档了解所选型号的具体规格限制条件再据此调整开发策略适应各种可能性变化。 --- ### 示例代码:简单的 UVCCamera 初始化流程 以下提供了一个简化版本的例子说明如何基于 JNI 构建基本框架来进行初步探索尝试: ```c #include <jni.h> #include "android/log.h" #define LOG_TAG "NativeLib" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__) extern "C"JNIEXPORT void JNICALL Java_com_example_uvc_UVCHelper_initCamera(JNIEnv *env,jobject thiz){ LOGI("Initializing camera..."); // TODO: Add actual initialization code here. } extern "C"JNIEXPORT jbyteArray JNICALL Java_com_example_uvc_UVCHelper_captureFrame(JNIEnv *env,jobject thiz){ LOGI("Capturing frame..."); const int FRAME_SIZE=640*480*3; // Assuming YUV format with resolution of 640x480 pixels unsigned char buffer[FRAME_SIZE]; memset(buffer,0,sizeof(buffer)); // Simulate capturing process by filling dummy data into the array. for(int i=0;i<sizeof(buffer);i++)buffer[i]=rand()%256; jbyteArray result=env->NewByteArray(FRAME_SIZE); env->SetByteArrayRegion(result,0,FRAME_SIZE,(jbyte*)buffer); return result; } ``` 上述代码展示了两个主要的功能点分别是相机初始化(`initCamera`)以及单张图片抓取(`captureFrame`)。注意这只是一个非常基础的概念验证模型还需要进一步完善才能满足真实项目的要求。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值