Camera显示之app实现简单camera" />
当前位置: 代码迷 >> .NET Framework >> Camera显示之app实现简单camera
  详细解决方案

Camera显示之app实现简单camera

热度:92   发布时间:2016-05-01 23:38:44.0
Camera显示之Framework层设置显示窗口

接着上一篇:

Camera显示之app实现简单camera

mCamera.setPreviewDisplay(mSurfaceHolder);函数往下分析。 


一.调用关系图:



二.1.mCamera为:android.hardware.Camera。

最终:

 public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {        if (holder != null) {            setPreviewDisplay(holder.getSurface());        } else {            setPreviewDisplay((Surface)null);        }    }   private native final void setPreviewDisplay(Surface surface) throws IOException;


2.调用到jni层:

static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface){    ALOGV("setPreviewDisplay");    sp<Camera> camera = get_native_camera(env, thiz, NULL);//这里是拿到一个和CameraService通信的客户端。目的是和CameraService进行通信    if (camera == 0) return;    sp<Surface> surface = NULL;    if (jSurface != NULL) {        surface = reinterpret_cast<Surface*>(env->GetIntField(jSurface, fields.surface));//将java层的Surface转化成native的Surface对象指针。    }       if (camera->setPreviewDisplay(surface) != NO_ERROR) {//通过CameraService的客户端最终和CameraService进行通信。        jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed");    }    }}


我们来关注下:camera->setPreviewDisplay(surface)中的camera是如何获取的?

1).jni层

// connect to camera servicestatic void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,    jobject weak_this, jint cameraId)//在Cameraopen的时候会调用{    sp<Camera> camera = Camera::connect(cameraId); //调用Camera的静态方法连接获取的。    if (camera == NULL) {        jniThrowRuntimeException(env, "Fail to connect to camera service");        return;    }    // make sure camera hardware is alive    if (camera->getStatus() != NO_ERROR) {        jniThrowRuntimeException(env, "Camera initialization failed");        return;    }    jclass clazz = env->GetObjectClass(thiz);    if (clazz == NULL) {        jniThrowRuntimeException(env, "Can't find android/hardware/Camera");        return;    }    // We use a weak reference so the Camera object can be garbage collected.    // The reference is only used as a proxy for callbacks.//!++#ifdef  MTK_CAMERA_BSP_SUPPORT    sp<JNICameraContext> context = new MtkJNICameraContext(env, weak_this, clazz, camera);//将camera通过MtkJNICameraContext保存到这个实例, 要用的时候直接通过这个类实例获取。#else    sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);//Android原生的也是这个涉及思路。



2).Camera.cpp

继续1)中:sp<Camera> camera = Camera::connect(cameraId);

sp<Camera> Camera::connect(int cameraId){    ALOGV("connect");    sp<Camera> c = new Camera();    const sp<ICameraService>& cs = getCameraService();//获取CameraService实例指针:    if (cs != 0) {        c->mCamera = cs->connect(c, cameraId);//调用CameraService的connect的方法。    }    if (c->mCamera != 0) {        c->mCamera->asBinder()->linkToDeath(c);        c->mStatus = NO_ERROR;    } else {        c.clear();    }    return c;}


3). CameraService.cpp


由于此方法代码较多, 我们只关注部分关键点:

sp<ICamera> CameraService::connect(        const sp<ICameraClient>& cameraClient, int cameraId) {#ifdef  MTK_CAMERAPROFILE_SUPPORT    initCameraProfile();    AutoCPTLog cptlog(Event_CS_connect);#endif    int callingPid = getCallingPid();    LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);......................................................... int deviceVersion;    if (mModule->common.module_api_version == CAMERA_MODULE_API_VERSION_2_0) {        deviceVersion = info.device_version;    } else {        deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;    }    switch(deviceVersion) {//从这个里面可以看到client是CameraClient      case CAMERA_DEVICE_API_VERSION_1_0:        client = new CameraClient(this, cameraClient, cameraId,                info.facing, callingPid, getpid());//Android原生设计。        break;      case CAMERA_DEVICE_API_VERSION_2_0://这里应该是MTK自己进行了扩展。        client = new Camera2Client(this, cameraClient, cameraId,                info.facing, callingPid, getpid());        break;      default:        ALOGE("Unknown camera device HAL version: %d", deviceVersion);        return NULL;    }.........................................................................................................    mClient[cameraId] = client;    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());    return client;//最终返回的是client, 也即是CameraClient。}



通过以上的调用关系, 可以知道camera->setPreviewDisplay(surface)调用到了CameraClient中的对应的方法, 注意这里已经是两个不同的进程了(一个是app进程, 一个是CameraService所在的mediaserver进程), 在jni层通过Camera.cpp里面实现的客户端通过Binder机制连接到CameraService端, 后面的通信都是通过Binder来进行,而不是直接调用。


3.CameraService端:

继续2中的camera->setPreviewDisplay(surface):

可以知道最终会通过Binder调用到CameraClient端。

// set the Surface that the preview will usestatus_t CameraClient::setPreviewDisplay(const sp<Surface>& surface) {#ifdef  MTK_CAMERAPROFILE_SUPPORT    AutoCPTLog cptlog(Event_CS_setPreviewDisplay);#endif    LOG1("setPreviewDisplay(%p) (pid %d)", surface.get(), getCallingPid());    sp<IBinder> binder(surface != 0 ? surface->asBinder() : 0);    sp<ANativeWindow> window(surface);//将Surface么与ANativeWindow绑定。    return setPreviewWindow(binder, window);}status_t CameraClient::setPreviewWindow(const sp<IBinder>& binder,        const sp<ANativeWindow>& window) {    Mutex::Autolock lock(mLock);    status_t result = checkPidAndHardware();    if (result != NO_ERROR) return result;    // return if no change in surface.    if (binder == mSurface) {        return NO_ERROR;    }    if (window != 0) {        result = native_window_api_connect(window.get(), NATIVE_WINDOW_API_CAMERA);        if (result != NO_ERROR) {            ALOGE("native_window_api_connect failed: %s (%d)", strerror(-result),                    result);            return result;        }    }    // If preview has been already started, register preview buffers now.    if (mHardware->previewEnabled()) {        if (window != 0) {            native_window_set_scaling_mode(window.get(),                    NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);            native_window_set_buffers_transform(window.get(), mOrientation);            result = mHardware->setPreviewWindow(window);        }    }    //!++    else if ( window == 0 ) {        result = mHardware->setPreviewWindow(window);//将window设置到hal层, Android代码架构真正的实现就止于此,hal层的东西就看具体厂家根据自身情况进行实现了。    }    //!--    if (result == NO_ERROR) {        // Everything has succeeded.  Disconnect the old window and remember the        // new window.        disconnectWindow(mPreviewWindow);        mSurface = binder;        mPreviewWindow = window;    } else {        // Something went wrong after we connected to the new window, so        // disconnect here.        disconnectWindow(window);    }    return result;}


三. 关键点, 这里jni层后涉及到camera所在的app进程和CameraService所在mediaserver两个不同的进程, 他们之间会通过Binder进行通信。 对于这部分, 后面会继续和大家分享。

在CameraService的下一层就是hal层了, 这部分是各个厂家根据自己芯片的特色进行设计构建的。 所以这下面的实现肯定多种多样, 但是可以从去学习代码架构, 看看一帧数据是如何一步一步的进行显示的。


通过上面我们可以看到, 对于显示部分, 我们其实只是设置了一个surface, 在中间层, 又和 ANativeWindow的绑定, 最后完全交个hal层去实现。

后面的分析, 我会以ktm平台的实现去分析。



  相关解决方案