Android 8.1 MTK Camera(api1+hal1.0)源码框架分析之Camera open流程

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

Android 8.1 MTK Camera(api1)源码框架分析

首先先看下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函数定义:
方式一:

    public static Camera open(int cameraId) {
   
        return new Camera(cameraId);
    }

方式二:

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

方式三:

    public static Camera openLegacy(int cameraId, int halVersion) {
   
        if (halVersion < CAMERA_HAL_API_VERSION_1_0) {
   
            throw new IllegalArgumentException("Invalid HAL version " + halVersion);
        }
        //new camera时,传入hal版本的参数
        return new Camera(cameraId, halVersion);
    }

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

    /** used by Camera#open, Camera#open(int) */
    Camera(int cameraId) {
   
        int err = cameraInitNormal(cameraId); //init
        if (checkInitErrors(err)) {
   
            if (err == -EACCES) {
   
                throw new RuntimeException("Fail to connect to camera service");
            } else if (err == -ENODEV) {
   
                throw new RuntimeException("Camera initialization failed");
            }
            // Should never hit this.
            throw new RuntimeException("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.
     */
    private Camera(int cameraId, int halVersion) {
   
        int err = cameraInitVersion(cameraId, halVersion);//init
        if (checkInitErrors(err)) {
   
            if (err == -EACCES) {
   
                throw new RuntimeException("Fail to connect to camera service");
            } else if (err == -ENODEV) {
   
                throw new RuntimeException("Camera initialization failed");
            } else if (err == -ENOSYS) {
   
                throw new RuntimeException("Camera initialization failed because some methods"
                        + " are not implemented");
            } else if (err == -EOPNOTSUPP) {
   
                throw new RuntimeException("Camera initialization failed because the hal"
                        + " version is not supported by this device");
            } else if (err == -EINVAL) {
   
                throw new RuntimeException("Camera initialization failed because the input"
                        + " arugments are invalid");
            } else if (err == -EBUSY) {
   
                throw new RuntimeException("Camera initialization failed because the camera"
                        + " device was already opened");
            } else if (err == -EUSERS) {
   
                throw new RuntimeException("Camera initialization failed because the max"
                        + " number of camera devices were already opened");
            }
            // Should never hit this.
            throw new RuntimeException("Unknown camera error");
        }
    }

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

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

    private int cameraInitNormal(int cameraId) {
   
        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
    }

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

    private int cameraInitVersion(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 = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
   
            mEventHandler = new EventHandler(this, looper);
        } else {
   
            mEventHandler = null;
        }

        return native_setup(new WeakReference<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()方法。

static const 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 service
static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
   
    // Convert jstring to String16
    const 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.h
    if (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 alive
    if (camera->getStatus() != NO_ERROR) {
   
        return NO_INIT;
    }

    jclass clazz = env->GetObjectClass(thiz);
    if (clazz == NULL) {
   
        // This should never happen
        jniThrowRuntimeException(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,赋值status
            case 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,
            /*ou
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值