回顾这半年做的项目基本都跟Camera有关,从手势识别控制空调,到人脸识别的门禁,都是围绕相机的数据处理和渲染。这里相机不限于本地的相机,还包括远程的RTSP相机,要将数据流拉到本地进行渲染。
这两天好好读了一下Camera的源码,大概理清了整体架构,总结了一下,其实没多少东西,Android的各个模块都差不多,都是有个系统服务,然后Java封一层,Native封一层,Java层和Native层的对象互相绑定,上面的请求从Java层往下到Native层,然后跨进程丢到系统服务中处理,这里Binder是不可避免的,传接口或文件句柄之类的。对于大块内存就不能指望Binder了,这时候共享内存就出场了,打开设备获得描述符,各自映射到进程的用户空间,这里描述符通过Binder传递,不过要注意的是跨进程传递后描述符可能会变,不过没关系,内核空间还是对应着同一个文件对象。接着说系统服务,这里面很可能继续往下调到HAL层,这个就是定义的一套设备的标准接口,不同厂家实现好了so,这里直接加载,然后调用对应的设备操作函数就好了。底层拿到了数据,或者状态变化需要通知上层,则又一层层地回调回去。
有了这么一个大框架,读起源码来就顺多了。总的来说,Android有两个核心,一个是跨进程通信,一个是内存管理,其它的各系统服务诸如AMS、WMS、PMS或者相机蓝牙什么的都可以看做是架在上面的业务层。
好了,接下来我们从Camera的Java层调用入手,过一遍源码。
Camera的调用大致如下:
Camera camera = Camera.open(1);
camera.setPreviewTexture(surfaceTexture);
camera.setPreviewCallbackWithBuffer(callback);
camera.addCallbackBuffer(buffer);
camera.startPreview();
本文将重点分析以上几个函数,看看底层是如何实现的。
首先说说Camera.open,这是个静态函数。Camera有个系统服务,在系统启动的时候注册到ServiceManager,每次调用Camera.open都会创建一个Camera Java对象,然后调到Native层初始化,连接到CameraService,拿到对应的Binder句柄,生成Camera Native层的对象和上下文数据结构,然后绑定到Java层的Camera类中。
Camera的open会调到native_setup,传入cameraId,
// android_hardware_Camera.cpp
static jint android_hardware_Camera_native_setup(JNIEnv *env, ...) {
sp<Camera> camera = Camera::connect(cameraId, clientName, );
sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
camera->setListener(context);
env->SetLongField(thiz, fields.context, (jlong)context.get());
}
// Camera.cpp
sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName, ) {
return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
}
要注意的是Camera类继承自模板类CameraBase,如下:
// Camera.h
class Camera : public CameraBase<Camera>, public BnCameraClient
上面调用了CameraBaseT的connect函数,这是个静态函数,CameraBaseT定义在CameraBase中,
typedef CameraBase<TCam> CameraBaseT;
而对于Camera类来说就是CameraBase,再往下看connect的实现:
// CameraBase.cpp
template <typename TCam, typename TCamTraits>
sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId, ) {
sp<TCam> c = new TCam(cameraId);
sp<TCamCallbacks> cl = c;
const sp<::android::hardware::ICameraService> cs = getCameraService();
binder::Status ret;
if (cs != nullptr) {
TCamConnectService fnConnectService = TCamTraits::fnConnectService;
ret = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid, clientPid, &c->mCamera);
}
if (ret.isOk() && c->mCamera != nullptr) {
IInterface::asBinder(c->mCamera)->linkToDeath(c);
c->mStatus = NO_ERROR;
}
return c;
}
这里先获取CameraService