admin管理员组

文章数量:1516870

之前已经写过一篇关于camera框架的文章,现在开始写camera相关的功能流程,总结一下常用的camera流程,算是对camera开发的一个回顾。

首先先看下camera open流程,基于mtk release代码,使用camera api1+hal1.0的组合。

1.应用层的open方式

api中定义的有两种open方式,分别是:

return Camera.open(cameraId);//指定打开某一个摄像头return Camera.open();//默认打开后置摄像头

open函数的参数cameraID,表示要访问的是哪一个硬件摄像头:介于0和getNumberOfCameras()-1之间。

而mtk的release代码中,新增了一种open方式,增加了指定hal版本的参数:

//指定hal api版本以及指定打开某个摄像头,如果当前设备不支持指定的hal版本,则抛出RuntimeException。return Camera.openLegacy(cameraId, halVersion);

这三种方式实际都是去new Camera(),只是构造函数中的参数不一样。都返回Camera句柄。

2.Camera.java api中的open函数

frameworks/base/core/java/android/hardware/Camera.java 中的open函数定义:
方式一:

publicstatic Camera open(int cameraId){
   
   returnnewCamera(cameraId);}

方式二:

publicstatic Camera open(){
   
   int numberOfCameras =getNumberOfCameras();
        CameraInfo cameraInfo =newCameraInfo();for(int i =0; i < numberOfCameras; i++){
   
   getCameraInfo(i, cameraInfo);//这里通过遍历到back camera时,就new Camera(i)if(cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK){
   
   returnnewCamera(i);}}return null;}

方式三:

publicstatic Camera openLegacy(int cameraId,int halVersion){
   
   if(halVersion < CAMERA_HAL_API_VERSION_1_0){
   
   thrownewIllegalArgumentException("Invalid HAL version "+ halVersion);}//new camera时,传入hal版本的参数returnnewCamera(cameraId, halVersion);}

三种方式都是去new Camera,所以看到Camera同名不同参的两个构造函数。
构造函数一:

/** used by Camera#open, Camera#open(int) */Camera(int cameraId){
   
   int err =cameraInitNormal(cameraId);//initif(checkInitErrors(err)){
   
   if(err ==-EACCES){
   
   thrownewRuntimeException("Fail to connect to camera service");}elseif(err ==-ENODEV){
   
   thrownewRuntimeException("Camera initialization failed");}// Should never hit this.thrownewRuntimeException("Unknown camera error");}}

构造函数二:

/**
     * Create a legacy camera object.
     *
     * @param cameraId The hardware camera to access, between 0 and
     * {@link #getNumberOfCameras()}-1.
     * @param halVersion The HAL API version this camera device to be opened as.
     */privateCamera(int cameraId,int halVersion){
   
   int err =cameraInitVersion(cameraId, halVersion);//initif(checkInitErrors(err)){
   
   if(err ==-EACCES){
   
   thrownewRuntimeException("Fail to connect to camera service");}elseif(err ==-ENODEV){
   
   thrownewRuntimeException("Camera initialization failed");}elseif(err ==-ENOSYS){
   
   thrownewRuntimeException("Camera initialization failed because some methods"+" are not implemented");}elseif(err ==-EOPNOTSUPP){
   
   thrownewRuntimeException("Camera initialization failed because the hal"+" version is not supported by this device");}elseif(err ==-EINVAL){
   
   thrownewRuntimeException("Camera initialization failed because the input"+" arugments are invalid");}elseif(err ==-EBUSY){
   
   thrownewRuntimeException("Camera initialization failed because the camera"+" device was already opened");}elseif(err ==-EUSERS){
   
   thrownewRuntimeException("Camera initialization failed because the max"+" number of camera devices were already opened");}// Should never hit this.thrownewRuntimeException("Unknown camera error");}}

构造函数中,都通过cameraInit函数的返回值来判断camera是否打开成功,如失败则抛出异常。真正的去执行open操作也是在cameraInit函数中调用jni函数native_setup。

-----cameraInitNormal中的参数指定为CAMERA_HAL_API_VERSION_NORMAL_CONNECT = -2;这个代表的是使用当前系统底层默认的hal版本。

privateintcameraInitNormal(int cameraId){
   
   returncameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);}

-----而cameraInitVersion中参数是由调用者设置的。一般设置CAMERA_HAL_API_VERSION_1_0 = 0x100; 表明Camera HAL device API version 1.0。

privateintcameraInitVersion(int cameraId,int halVersion){
   
   
        mShutterCallback = null;
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mUsingPreviewAllocation =false;
        mZoomListener = null;
        Looper looper;if((looper = Looper.myLooper())!= null){
   
   
            mEventHandler =newEventHandler(this, looper);}elseif((looper = Looper.getMainLooper())!= null){
   
   
            mEventHandler =newEventHandler(this, looper);}else{
   
   
            mEventHandler = null;}returnnative_setup(newWeakReference<Camera>(this), cameraId, halVersion,
                ActivityThread.currentOpPackageName());}

3.JNI函数

根据jni函数命名规则,可找到native_setup函数所在文件目录:frameworks\base\core\jni\android_hardware_Camera.cpp。

native_setup()被动态注册到JNI,指向android_hardware_Camera_native_setup()方法。

staticconst JNINativeMethod camMethods[]={
   
   ......{
   
   "native_setup","(Ljava/lang/Object;IILjava/lang/String;)I",(void*)android_hardware_Camera_native_setup },......

android_hardware_Camera_native_setup函数自带了两个原生参数JNIEnv *env, jobject thiz,而后面4个参数就是从camera.java中native_setup函数传下来的。

// connect to camera servicestatic jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName){
   
   // Convert jstring to String16const char16_t *rawClientName = reinterpret_cast<const char16_t*>(
        env->GetStringChars(clientPackageName,NULL));
    jsize rawClientNameLen = env->GetStringLength(clientPackageName);
    String16 clientName(rawClientName, rawClientNameLen);
    env->ReleaseStringChars(clientPackageName,
                            reinterpret_cast<const jchar*>(rawClientName));//根据halVersion来决定走哪一个connect函数
    sp<Camera> camera;//这里是指向Camera.cpp/Camera.hif(halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT){
   
   // Default path: hal version is don't care, do normal camera connect.
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);}else{
   
   
        jint status = Camera::connectLegacy(cameraId, halVersion, clientName,
                Camera::USE_CALLING_UID, camera);if(status != NO_ERROR){
   
   return status;}}//判断camera的相关状态,返回相关error信息if(camera ==NULL){
   
   return-EACCES;}// make sure camera hardware is aliveif(camera->getStatus()!= NO_ERROR){
   
   return NO_INIT;}
    jclass clazz = env->GetObjectClass(thiz);if(clazz ==NULL){
   
   // This should never happenjniThrowRuntimeException(env,"Can't find android/hardware/Camera");return INVALID_OPERATION;}......return NO_ERROR;}

通过将clientPackageName从jstring转换为String16格式得到clientName。
函数中根据halVersion来决定走哪一个connect函数,如是CAMERA_HAL_API_VERSION_NORMAL_CONNECT,则走的默认的;否则走指定的hal版本。
调用Camera::connect()/connectLegacy()方法去请求连接CameraService服务,这个camera指向的就是Camera.h/Camera.cpp了,有此进入到了camera client端。

4.Camera client

Camera.h头文件路径:\frameworks\av\camera\include\camera,函数声明:

static  sp<Camera>connect(int cameraId,const String16& clientPackageName,int clientUid,int clientPid);static  status_t  connectLegacy(int cameraId,int halVersion,const String16& clientPackageName,int clientUid, sp<Camera>& camera);

由于mtk在Android P之前hal层基本使用的hal1.0,所以这里就看connectLegacy函数。
在frameworks\av\camera\Camera.cpp文件中:

status_t Camera::connectLegacy(int cameraId,int halVersion,const String16& clientPackageName,int clientUid,
        sp<Camera>& camera){
   
   ALOGV("%s: connect legacy camera device", __FUNCTION__);
    sp<Camera> c = new Camera(cameraId);//拿到已经被打开的camera的,ICamera接口
    sp<::android::hardware::ICameraClient> cl = c;//拿到ICameraClient接口
    status_t status = NO_ERROR;//通过CameraBaseT::getCameraService()拿到ICameraService接口const sp<::android::hardware::ICameraService>& cs = CameraBaseT::getCameraService();
    binder::Status ret;if(cs != nullptr){
   
   //这里cs.get是拿到CameraService,并调用connectLegacy,传入参数
        ret = cs.get()->connectLegacy(cl, cameraId, halVersion, clientPackageName,
                clientUid,/*out*/&(c->mCamera));//c->mCamera指向的就是ICamera}if(ret.isOk()&& c->mCamera != nullptr){
   
   
        IInterface::asBinder(c->mCamera)->linkToDeath(c);//binder间通讯
        c->mStatus = NO_ERROR;
        camera = c;}else{
   
   switch(ret.serviceSpecificErrorCode()){
   
   //遍历error code,赋值statuscase hardware::ICameraService::ERROR_DISCONNECTED:
                status =-ENODEV;break;case hardware::ICameraService::ERROR_CAMERA_IN_USE:
                status =-EBUSY;break;case hardware::ICameraService::ERROR_INVALID_OPERATION:
                status =-EINVAL;break;case hardware::ICameraService::ERROR_MAX_CAMERAS_IN_USE:
                status =-EUSERS;break;case hardware::ICameraService::ERROR_ILLEGAL_ARGUMENT:
                status = BAD_VALUE;break;case hardware::ICameraService::ERROR_DEPRECATED_HAL:
                status =-EOPNOTSUPP;break;case hardware::ICameraService::ERROR_DISABLED:
                status =-EACCES;break;case hardware::ICameraService::ERROR_PERMISSION_DENIED:
                status = PERMISSION_DENIED;break;default:
                status =-EINVAL;ALOGW("An error occurred while connecting to camera %d: %s", cameraId,(cs != nullptr)?"Service not available": ret.toString8().string());break;}
        c.clear();}return status;}

connectLegacy函数中,先是拿到已经被打开的camera的ICamera接口,再获取ICameraClient接口,通过CameraBaseT::getCameraService()再拿到ICameraService接口,通过cs.get是拿到CameraService,并调用connectLegacy,传入ICameraClient cl、ICamera / out /&(c->mCamera)等参数。

CameraBaseT是CameraBase的模板类,CameraBaseT是定义在CameraBase.h中的变量。

typedef CameraBase<TCam>         CameraBaseT;

所以可以在CameraBase.cpp中看下CameraBaseT::getCameraService()函数,通过binder方式拿到ICameraService。

// establish binder interface to camera service
template <typename TCam, typename TCamTraits>const sp<::android::hardware::ICameraService> CameraBase<TCam, TCamTraits>::getCameraService(){
   
   
    Mutex::Autolock _l(gLock);if(gCameraService.get()==0){
   
   char value[PROPERTY_VALUE_MAX];property_get("config.disable_cameraservice", value,"0");if(strncmp(value,"0",2)!=0&&strncasecmp(value,"false",6)!=0){
   
   return gCameraService;}
        sp<IServiceManager> sm =defaultServiceManager();
        sp<IBinder> binder;do{
   
   
            binder = sm->getService(String16(kCameraServiceName));if(binder !=0){
   
   break;}ALOGW("CameraService not published, waiting...");usleep(kCameraServicePollDelay);}while(true);if(gDeathNotifier ==NULL){
   
   
            gDeathNotifier = new DeathNotifier();}
        binder->linkToDeath(gDeathNotifier);
        gCameraService = interface_cast<::android::hardware::ICameraService>(binder);}ALOGE_IF(gCameraService ==0,"no CameraService!?");return gCameraService;}

5.Camera service

文件路径:frameworks\av\services\camera\libcameraservice。
cs.get()->connectLegacy指向到CameraSerive中,看到CameraService.h头文件中声明:

    virtual binder::Status     connectLegacy(const sp<hardware::ICameraClient>& cameraClient,
            int32_t cameraId, int32_t halVersion,const String16& clientPackageName, int32_t clientUid,/*out*/
            sp<hardware::ICamera><

本文标签: 函数系统编程