接着上一篇:
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 service static 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 use status_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平台的实现去分析。