Chinaunix首页 | 论坛 | 博客
  • 博客访问: 76053
  • 博文数量: 12
  • 博客积分: 307
  • 博客等级: 二等列兵
  • 技术积分: 110
  • 用 户 组: 普通用户
  • 注册时间: 2011-04-12 17:16
文章分类
文章存档

2012年(3)

2011年(9)

我的朋友

分类: 嵌入式

2012-05-24 16:18:49

首先,Package层的Camera.java会调用Framework层的Camera.java的open函数,传入camera id。这个函数是个static函数,它只是new了一个Camera对象并返回。在Camera的构造函数中,最主要的就是调用JNI层的native_setup函数,传入两个参数:对象自身的weak引用,以及camera id。使用weak reference的目的是不影响Camera对象的垃圾回收,因为JNI层保存这个对象主要是用于回调。

接下来再来看JNI的对应函数。第一步,调用Camera::connect(cameraId)函数生成一个native的Camera对象。在这个函数内会通过binder向CameraService请求服务,如下:
sp Camera::connect(int cameraId)
{
    LOGV("connect");
    sp c = new Camera();
    const sp& cs = getCameraService();
    if (cs != 0) {
        c->mCamera = cs->connect(c, cameraId);
    }
    if (c->mCamera != 0) {
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        c.clear();
    }
    return c;
}
可以看到先是new了一个native Camera对象,然后把调用CameraService connect函数,传入刚new出来的Camera对象并把返回值保存在mCamera变量中,此变量为ICamera类型,看代码就知道ICamera这个接口类提供了很多操作Camera的接口,以后拍照、preview等操作就要靠它来完成啦。

那CameraService的connect函数都做了些什么呢?代码如下:
sp CameraService::connect(
        const sp& cameraClient, int cameraId) {
    int callingPid = getCallingPid();
    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);

    sp client;

    Mutex::Autolock lock(mServiceLock);
    if (mClient[cameraId] != 0) {
        client = mClient[cameraId].promote();
        if (client != 0) {
            if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
                LOG1("CameraService::connect X (pid %d) (the same client)",
                    callingPid);
                return client;
            } else {
                LOGW("CameraService::connect X (pid %d) rejected (existing client).",
                    callingPid);
                return NULL;
            }
        }
        mClient[cameraId].clear();
    }

    sp hardware = HAL_openCameraHardware(cameraId);
    if (hardware == NULL) {
        LOGE("Fail to open camera hardware (id=%d)", cameraId);
        return NULL;
    }
    CameraInfo info;
    HAL_getCameraInfo(cameraId, &info);
    client = new Client(this, cameraClient, hardware, cameraId, info.facing,
                        callingPid);
    mClient[cameraId] = client;
    LOG1("CameraService::connect X");
    return client;
}
删去了一些无关紧要的代码。可以看到CameraService里居然还有一个Client!首先试着从mClient里取对应于camera id的client对象,如果找到并且请求的来源相同,就直接返回这个对象,但如果client对象存在但来自另一个不同的请求进程,那CameraService就会拒绝,因为一个Camera只能被一个native Camera对象所拥有,可见用完Camera一定要及时释放。如果mClient中找不到,那就先通过HAL_openCameraHardware函数拿到一个CameraHardwareInterface对象,通过它就获得了与厂商自行实现的Camera HAL交流的渠道。接着new一个Client对象,传入请求者对象、hardware HAL对象、camera id等,然后把这个对象返回,以后的具体操作就靠它啦。

一开始,我还对为什么CameraService里还有Client感到疑惑,后来想明白是因为系统可能不只有一个Camera,而CameraService只有一份,因此需要多个对象来对应多个Camera。至此,我们把请求进程与CameraService、Camera HAL连接了起来。总结下来,就是请求进程中得到了远端CameraService中的Client对象,CameraService得到了请求进程的native Camera对象,并把它与Client联系起来,Client又跟Camera HAL联系起来,通过它获得操作具体Camera的能力,当得到数据时可以通过保存的请求进程的native Camera对象进行回调。

JNI中第一步connect说完了,接下来的主要代码如下:
    // We use a weak reference so the Camera object can be garbage collected.
    // The reference is only used as a proxy for callbacks.
    sp 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());
new了一个JNICameraContext对象,把它设为native Camera的listener,并把这个对象保存在java对象里。JNICameraContext的作用主要是回调java层的函数,把图像数据传过去。
阅读(8130) | 评论(0) | 转发(0) |
0

上一篇:Android Camera调用流程

下一篇:没有了

给主人留下些什么吧!~~