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