美文网首页Android camera
Media Module之Camera(二) 初始化

Media Module之Camera(二) 初始化

作者: Lemon_Home | 来源:发表于2017-05-31 19:04 被阅读2040次

    2. 初始化

    初始化主要分为几个部分,SM注册service,app层和framework层去打开相机操作,底层的服务的绑定,底层server端的初始化,HAL层去open。

    2.1 注册service

    手机开机后,会走init.rc流程,init.rc会启动MediaServer Service。
    system/core/rootdir/init.rc

    service media /system/bin/mediaserver
        class main
        user media
        group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc mediadrm qcom_diag
        ioprio rt 4
    

    在启动MediaServer之后会进入其main方法中:
    frameworks\av\media\mediaserver\main_mediaserver.cpp

    int main(int argc __unused, char** argv)
    {
        ... ...
        if (doLog && (childPid = fork()) != 0) {
            ... ...
        } else {
            CameraService::instantiate();
        }
    }
    

    对于CameraService::instantiate()方法来说,是CameraService的父类BinderService来实现的:
    frameworks\native\include\binder\BinderService.h

    namespace android {
    
    template<typename SERVICE>
    class BinderService
    {
    public:
        static status_t publish(bool allowIsolated = false) {
            sp<IServiceManager> sm(defaultServiceManager());
            return sm->addService(
                    String16(SERVICE::getServiceName()),
                    new SERVICE(), allowIsolated);
        }
    ... ...
        static void instantiate() { publish(); }
    ... ...
    

    可以发现在publish()函数中,CameraService完成服务的注册 。SERVICE是个模板,这里是注册CameraService,所以可用CameraService代替
    return sm->addService(String16(CameraService::getServiceName()), new CameraService());

    这样,Camera就在ServiceManager完成服务注册,提供给client随时使用。因为由init.rc在启动时调用,所以在设备开机的时候Camera就会注册一个服务,用作binder通信。

    2.2 从launcher进入相机

    主要流程

    在onCreate 可以看到从SharedPreferences 文件中获取初始化的模式,根据SharedPreferences文件中的filterMode的值决定初始化模式是普通还是全景还是特效模式;

    @Override
        public void onCreate(Bundle state) {
            super.onCreate(state);
            System.out.println(888);
    .................
    .................
    .................
    
    /**
    紧接着下面对其他应用访问相机根据其intent做了判断处理,如果拍照就进入拍照模式,录像就进入录像模式;
    **/
    int moduleIndex = -1;
            if (MediaStore.INTENT_ACTION_VIDEO_CAMERA.equals(getIntent().getAction())|| MediaStore.ACTION_VIDEO_CAPTURE.equals(getIntent().getAction())) {
                moduleIndex = ModuleSwitcher.VIDEO_MODULE_INDEX;
            } else if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(getIntent().getAction())
                    || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(getIntent()
    .getAction())) {
                moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
                SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
    if (prefs.getInt(CameraSettings.KEY_STARTUP_MODULE_INDEX, -1) == ModuleSwitcher.GCAM_MODULE_INDEX && GcamHelper.hasGcamCapture()) {
                    moduleIndex = ModuleSwitcher.GCAM_MODULE_INDEX;
                }
            } else if (MediaStore.ACTION_IMAGE_CAPTURE.equals(getIntent().getAction())
                    || MediaStore.ACTION_IMAGE_CAPTURE_SECURE.equals(getIntent().getAction())) {
                moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;//信息访问相机拍照(android.media.action.IMAGE_CAPTURE);
            } else {
                    moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
            }
    
    setModuleFromIndex(moduleIndex);
    mCurrentModule.init(this, mCameraModuleRootView) ;
    .................
    .................
    .................
    registerSDcardMountedReceiver();//注册SD卡挂载的监听,弹出提示是否保存到SD卡
    

    MediaStore这个类是android系统提供的一个多媒体数据库,android中多媒体信息都可以从这里提取。这个MediaStore包括了多媒体数据库的所有信息,包括音频,视频和图像,android把所有的多媒体数据库接口进行了封装,所有的数据库不用自己进行创建,直接调用利用ContentResolver去调用那些封装好的接口就可以进行数据库的操作了。

    oncreate中还注册了一些监听、观察者,动态注册SD卡是否挂载的广播;初始化一些服务;以及安全模式与非安全模式的查看已拍摄图片的一些处理;有兴趣自己可以查看;

    安全模式:有密码锁屏;非安全模式:无密码设置;

    初次进入默认的是moduleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;

    onCreate 调用setModuleFromIndex 方法, 根据传进来的ID进行模式初始化;

    private void setModuleFromIndex(int moduleIndex) {
            mCurrentModuleIndex = moduleIndex;
            switch (moduleIndex) {
                case ModuleSwitcher.VIDEO_MODULE_INDEX:
                    mCurrentModule = new VideoModule();
                    break;
    
                case ModuleSwitcher.PHOTO_MODULE_INDEX:
                    mCurrentModule = new PhotoModule();
                    break;
    
                .......
                .......
                .......
                default:
                    // Fall back to photo mode.
                    mCurrentModule = new PhotoModule();
                    mCurrentModuleIndex = ModuleSwitcher.PHOTO_MODULE_INDEX;
                    break;
            }
        }
    

    photoModule.java

    @Override
        public void init(CameraActivity activity, View parent) {
            System.out.println(151515);
            mActivity = activity;
          ...........
          ...........
          ...........
            if (mOpenCameraThread == null) {
                mOpenCameraThread = new OpenCameraThread();
                mOpenCameraThread.start();
            }
            mUI = new PhotoUI(activity, this, parent);
    
            initializeControlByIntent();//根据传进来的intent进行初始化
          ...........
          ...........
          ...........
            Storage.setSaveSDCard(
                mPreferences.getString(CameraSettings.KEY_CAMERA_SAVEPATH, "0").equals("1"));//根据设置菜单的参数判断保存的位置是SD卡还是本机
    
            mSoundPool = new SoundPool(1, AudioManager.STREAM_NOTIFICATION, 0);
            mRefocusSound = mSoundPool.load(mActivity, R.raw.camera_click_x5, 1);
        }
    

    photoModule.java

    private void initializeControlByIntent() {
            mUI.initializeControlByIntent();
            if (mIsImageCaptureIntent) {
                System.out.println("AAAA");
                setupCaptureParams();
            }
        }
    

    photoUI.java

    public void initializeControlByIntent() {
            System.out.println(171717);
            mBattery = (ImageView) mRootView.findViewById(R.id.battery_img);
            mBurstImg = (ImageView) mRootView.findViewById(R.id.burst_img);
            mThumbnail = (ImageView) mRootView.findViewById(R.id.preview_thumb);
            mThumbnail.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (!CameraControls.isAnimating()
                            && mController.getCameraState() != PhotoController.SNAPSHOT_IN_PROGRESS)
                        mActivity.gotoGallery();//点击缩略图进入到图库
                }
            });
            mMenuButton = mRootView.findViewById(R.id.menu);
            mMenuButton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if(mMenu != null){
                        System.out.println(212121);
                        mMenu.openFirstLevel();
                        mVideoMenu.openFirstLevel();
                    }
                }
            });
            if (mController.isImageCaptureIntent()) {//其他应用(信息)访问会走进这里
                System.out.println(181818);
                hideSwitcher();
                mMenuButton.setVisibility(View.VISIBLE);
                mTimerSwitcher.setVisibility(View.VISIBLE);
                showTimerPickers();
                //yanglei modify for bug 67085 20150708 start
    //            mSwitcher.setImageCaptureIntent(true);
                //yanglei modify for bug 67085 20150708 end
                ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls);
                mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
    
                mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
                mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
                mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake);
                mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
                mReviewCancelButton.setVisibility(View.VISIBLE);
                mVideoButton.setVisibility(View.GONE);
                mModelSwitcher.setVisibility(View.GONE);
    
                mReviewDoneButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mController.onCaptureDone();//拍照的监听
                    }
                });
                mReviewCancelButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mController.onCaptureCancelled();//取消拍照的监听
                    }
                });
    
                mReviewRetakeButton.setOnClickListener(new OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        mController.onCaptureRetake();//拍完之后不满意重新拍的监听
                    }
                });
            }
        }
    

    photoModule.java

    @Override
        public boolean isImageCaptureIntent() {
            String action = mActivity.getIntent().getAction();
            return (MediaStore.ACTION_IMAGE_CAPTURE.equals(action)
                    || CameraActivity.ACTION_IMAGE_CAPTURE_SECURE.equals(action));
        }
    

    photoModule.java

    private void setupCaptureParams() {
            Bundle myExtras = mActivity.getIntent().getExtras();
            if (myExtras != null) {
                mSaveUri = (Uri) myExtras.getParcelable(MediaStore.EXTRA_OUTPUT);
                mCropValue = myExtras.getString("crop");
            }
        }
    

    在onResume()方法中进入相应的模式
    CameraActivity.java

    @Override
        public void onResume() {
            ..............
            ..............
            ..............
            mCurrentModule.onResumeBeforeSuper();
            super.onResume();
            mCurrentModule.onResumeAfterSuper();
            setSwipingEnabled(true);
            if (mResetToPreviewOnResume) {
                // Go to the preview on resume.
                mFilmStripView.getController().goToFirstItem();
            }
            // Default is showing the preview, unless disabled by explicitly
            // starting an activity we want to return from to the filmstrip rather
            // than the preview.
            mResetToPreviewOnResume = true;
            ..............
            ..............
        }
    

    mFilmStripView胶片视图,可以看成用胶片录电影,最前面的是正在录制,后面的是已经录制完毕的; goToFirstItem()可以理解为到最开始录的胶片,即预览的界面;

    然后会进入photoModule.java中,注意在cameraActivity中的onResumeBeforeSuper()与onResumeAfterSuper()方法的实现是在相应的模式中;
    onResumeBeforeSuper()作用是做一些UI显示及动态注册广播,及判断SD卡是否存在可写,不可写则保存到内部存储,并将保存路径用sharedPreference保存起来;
    onResumeAfterSuper():主要启动onResumeTasks();方法,更新剩余内存的大小
    更新剩下可以拍摄的照片的数量

    @Override
        public void onResumeAfterSuper() {
            // Add delay on resume from lock screen only, in order to to speed up
            // the onResume --> onPause --> onResume cycle from lock screen.
            // Don't do always because letting go of thread can cause delay.
            String action = mActivity.getIntent().getAction();
            if (MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA.equals(action)
                    || MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE.equals(action)) {
                Log.v(TAG, "On resume, from lock screen.");
                // Note: onPauseAfterSuper() will delete this runnable, so we will
                // at most have 1 copy queued up.
                mHandler.postDelayed(new Runnable() {
                    public void run() {
                        onResumeTasks();
                    }
                }, ON_RESUME_TASKS_DELAY_MSEC);
            } else {
                Log.v(TAG, "On resume.");
                onResumeTasks();
            }
            mHandler.post(new Runnable(){
                @Override
                public void run(){
                    mActivity.updateStorageSpaceAndHint();//更新剩余内存的大小
                    updateRemainingPhotos();//更新剩下可以拍摄的照片的数量
                }
            });}
    
        private void onResumeTasks() {
            Log.v(TAG, "Executing onResumeTasks.");
            System.out.println(333);
            if (mOpenCameraFail || mCameraDisabled) return;
    
            if (mOpenCameraThread == null) {
                mOpenCameraThread = new OpenCameraThread();
                mOpenCameraThread.start();
            }
    
            mJpegPictureCallbackTime = 0;
            mZoomValue = 0;
    
            // If first time initialization is not finished, put it in the
            // message queue.
            if (!mFirstTimeInitialized) {
                mHandler.sendEmptyMessage(FIRST_TIME_INIT);
            } else {
                initializeSecondTime();
       .............
       .............
       .............
    

    通过onResumeTasks()方法,打开相机,开启预览

    private class OpenCameraThread extends Thread {
            @Override
            public void run() {
                openCamera();// 第一步开启camera
                startPreview();// 第二部开始预览
            }
        }   
    private void openCamera() {
            // We need to check whether the activity is paused before long
            // operations to ensure that onPause() can be done ASAP.
            if (mPaused) {
                return;
            }
            Log.v(TAG, "Open camera device.");
            mCameraDevice = CameraUtil.openCamera(
                    mActivity, mCameraId, mHandler,
                    mActivity.getCameraOpenErrorCallback());
            if (mCameraDevice == null) {
                Log.e(TAG, "Failed to open camera:" + mCameraId);
                mHandler.sendEmptyMessage(OPEN_CAMERA_FAIL);
                return;
            }
           .......
           .......
           .......
        }
    

    mCameraDevice = CameraUtil.openCamera(
    mActivity, mCameraId, mHandler,
    mActivity.getCameraOpenErrorCallback())
    其中mCameraDevice是com.android.camera.CameraManager.CameraProxy;的实例。

    CameraUtil属于公共的API,用于给不同模块提供对Camera的不同操作。
    在它openCamera 方法里,执行:
    CameraHolder.instance().open(handler, cameraId, cb);
    其中CameraHolder.instance()单例模式。目的就是控制,相机开启的只有能是一个。再次开启前,要确认上次已经销毁。

    b、 在CameraManager系统服务,获得camera设备对象为Camera设备提供操作的方法。

    @Override
        public CameraManager.CameraProxy cameraOpen(
            Handler handler, int cameraId, CameraOpenErrorCallback callback) {
            mCameraHandler.obtainMessage(OPEN_CAMERA, cameraId, 0,
                    CameraOpenErrorCallbackForward.getNewInstance(
                            handler, callback)).sendToTarget();
            mCameraHandler.waitDone();
            if (mCamera != null) {
                return new AndroidCameraProxyImpl();// ----->这个就是丢给前台的mCameraDevice
    
            } else {
                return null;
            }
        }
    

    CameraProxy 里AndroidCameraProxyImpl类这个接口就是将对Camera 接受和发送的操作,送达到Camera设备。
    这个接口的实现类是AndroidCameraProxyImpl,这个类属于AndroidCameraManagerImpl的内部类。在AndroidCameraManagerImpl.java 里面还有一个内部类CameraHandler,这个类属于Handler。在CameraHandler的handleMessage方法里,就是根据不同的消息参数来对android.hardware.Camera 进行控制。比如打开,释放,对焦,变焦等等

    2.3 服务绑定

    Binder服务已经在系统中注册,下面分析服务的客户端和服务端是如何绑定的。首先在app层中,调用了framework Camera.java中的open(int cameraId)方法:

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

    调用了构造函数:

    Camera(int cameraId) {
        int err = cameraInitNormal(cameraId);
    ... ...
    }
    

    在构造函数中调用了cameraInitNormal方法:

    private int cameraInitNormal(int cameraId) {
        return cameraInitVersion(cameraId, CAMERA_HAL_API_VERSION_NORMAL_CONNECT);
        // 代表camera能够正常连接和打开的常量
    }
    

    接下来调用的是cameraInitVersion方法:

    private int cameraInitVersion(int cameraId, int halVersion) {
        mShutterCallback = null;
        // 将各种回调设置初始值
    ... ...
        // 新建looper进行消息循环
        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;
        }
    
        String packageName = ActivityThread.currentOpPackageName();
    
        // 强制使用HAL1的版本,如果存在 HAL2异常的情况
     ... ...
        //调用native方法native_setup
        return native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName);
    }
    

    可以看出,在构造方法的层级调用中,走到了native方法native_setup。下面分析此native方法:

    static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
        jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
    {
    ... ...
        sp<Camera> camera;
        if (halVersion == CAMERA_HAL_API_VERSION_NORMAL_CONNECT) {
            // Default path: hal version is don't care, do normal camera connect.
    //clientName是通过将clientPackageName从jstring转换为String16格式得到;
    //Camera::USE_CALLING_UID是定义在Camera.h中的枚举类型,其值为//ICameraService::USE_CALLING_UID(同样为枚举类型,值为-1)。
            camera = Camera::connect(cameraId, clientName,
                    Camera::USE_CALLING_UID);
        } 
    ... ...
        // We use a weak reference so the Camera object can be garbage collected.
        // The reference is only used as a proxy for callbacks.
        //JNICameraContext这个类是一个监听类,用于处理底层Camera回调函数传来的数据和消息
        sp<JNICameraContext> context = new JNICameraContext(env, weak_this, clazz, camera);
        context->incStrong((void*)android_hardware_Camera_native_setup);
        camera->setListener(context);
    
        // save context in opaque field
        env->SetLongField(thiz, fields.context, (jlong)context.get());
        return NO_ERROR;
    }
    

    可以看到,在判断HAL的版本之后就调用了native层Camera的connect方法:
    frameworks/av/camera/Camera.cpp

    sp<Camera> Camera::connect(int cameraId, const String16& clientPackageName,
            int clientUid)
    {
        return CameraBaseT::connect(cameraId, clientPackageName, clientUid);
    }
    

    在return返回的是CameraBaseT调用connect方法,Camera类继承模板类CameraBase,先找到CameraBaseT的头文件:
    /frameworks/av/include/camera/CameraBase.h

    static sp<TCam>      connect(int cameraId,
                                 const String16& clientPackageName,
                                 int clientUid);
    

    发现是强引用类型TCam调用的方法,接下来在CameraBase.cpp中查看此方法:
    frameworks/av/camera/CameraBase.cpp

    template <typename TCam, typename TCamTraits>
    sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                                   const String16& clientPackageName,
                                                   int clientUid)
    {
        ALOGV("%s: connect", __FUNCTION__);
        sp<TCam> c = new TCam(cameraId);
        sp<TCamCallbacks> cl = c;
        status_t status = NO_ERROR;
        // 获取到cameraservice
        const sp<ICameraService>& cs = getCameraService();
    
        if (cs != 0) {
            TCamConnectService fnConnectService = TCamTraits::fnConnectService;
            //强引用,调用ICameraService的connect方法
            status = (cs.get()->*fnConnectService)(cl, cameraId, clientPackageName, clientUid,
                                                 /*out*/ c->mCamera);
        }
        if (status == OK && c->mCamera != 0) {
            IInterface::asBinder(c->mCamera)->linkToDeath(c);
            c->mStatus = NO_ERROR;
        } else {
            ALOGW("An error occurred while connecting to camera: %d", cameraId);
            c.clear();
        }
        return c;
    }
    
    const sp<ICameraService>& CameraBase<TCam, TCamTraits>::getCameraService()
    {
        Mutex::Autolock _l(gLock);
        if (gCameraService.get() == 0) {
            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);
            //通过binder获取CameraService实例
            gCameraService = interface_cast<ICameraService>(binder);
        }
        ALOGE_IF(gCameraService == 0, "no CameraService!?");
        return gCameraService;
    }
    

    可以看出,在connect方法中获取了cameraservice的实例,然后connect()函数在BpCameraService和BnCameraService的父类ICameraService中声明为纯虚函数,在BpCameraService和CameraService中分别给出了实现,BpCameraService作为代理类,提供接口给客户端。
    fnConnectService方法在Camera.cpp作为强引用,指向ICameraService::connect方法。

    CameraTraits<Camera>::TCamConnectService CameraTraits<Camera>::fnConnectService =
            &ICameraService::connect;
    ... ...
    

    在ICameraService.cpp的connect方法中,首先将传递过来的Camera对象cameraClient转换成IBinder类型,将调用的参数写到Parcel中,通过BpBinder的transact()函数发送消息,然后由BnCameraService去响应该连接,最后就是等待服务端返回,如果成功则生成一个BpCamera实例。
    frameworks/av/camera/ICameraService.cpp

    // connect to camera service (android.hardware.Camera)
    virtual status_t connect(const sp<ICameraClient>& cameraClient, int cameraId,
                             const String16 &clientPackageName, int clientUid,
                             /*out*/
                             sp<ICamera>& device)
    {
        Parcel data, reply;
        data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
        data.writeStrongBinder(IInterface::asBinder(cameraClient));
        data.writeInt32(cameraId);
        data.writeString16(clientPackageName);
        data.writeInt32(clientUid);
    
        status_t status;
        status = remote()->transact(BnCameraService::CONNECT, data, &reply);
    //BpBinder的transact()函数向IPCThreadState实例发送消息,通知其有消息要发送给binder driver
    
        if (status != OK) return status;
    
        if (readExceptionCode(reply)) return -EPROTO;
        status = reply.readInt32();
        if (reply.readInt32() != 0) {
            // client端读出server返回的binder
            device = interface_cast<ICamera>(reply.readStrongBinder());
        }
        return status;
    }
    

    发送的消息在BnCameraService接收,其中onTransact()函数负责解包收到的Parcel并执行client端的请求的方法。服务端收到CONNECT命令之后,
    (1) 使用Camera的Binder对象生成Camera客户代理BpCameraClient实例;
    (2) 将生成的BpCameraClient对象作为参数传递到CameraService(/frameworks/av/services/camera/libcameraservice/CameraService.cpp)的connect()函数中,该函数会返回一个BpCamera实例;
    (3) 将在(2)中返回的实例对象以IBinder的形式打包到Parcel中返回。

    status_t BnCameraService::onTransact(
        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
    {
        switch(code) {
            ... ...
            case CONNECT: {
                CHECK_INTERFACE(ICameraService, data, reply);
                sp<ICameraClient> cameraClient =
                        interface_cast<ICameraClient>(data.readStrongBinder());
                int32_t cameraId = data.readInt32();
                const String16 clientName = data.readString16();
                int32_t clientUid = data.readInt32();
                sp<ICamera> camera;
                status_t status = connect(cameraClient, cameraId,
                        clientName, clientUid, /*out*/camera);
                reply->writeNoException();
                reply->writeInt32(status);
                if (camera != NULL) {
                    reply->writeInt32(1);
                    reply->writeStrongBinder(IInterface::asBinder(camera));
                } else {
                    reply->writeInt32(0);
                }
                return NO_ERROR;
            } break;
    }
    

    接下来看CameraService::connect()函数,该函数返回一个BpCamera实例。

    status_t CameraService::connect(
            const sp<ICameraClient>& cameraClient,
            int cameraId,
            const String16& clientPackageName,
            int clientUid,
            /*out*/
            sp<ICamera>& device) {
    
        ATRACE_CALL();
        status_t ret = NO_ERROR;
        String8 id = String8::format("%d", cameraId);
        sp<Client> client = nullptr;
        ret = connectHelper<ICameraClient,Client>(cameraClient, id,
                CAMERA_HAL_API_VERSION_UNSPECIFIED,
                clientPackageName, clientUid, API_1, false, false, /*out*/client);
    
        if(ret != NO_ERROR) {
            logRejected(id, getCallingPid(), String8(clientPackageName),
                    String8::format("%s (%d)", strerror(-ret), ret));
            return ret;
        }
        device = client;
        return NO_ERROR;
    }
    

    可以看到又调用了connectHelper去返回客户端实例。在CameraService.h中定义了此方法:

    template<class CALLBACK, class CLIENT>
    status_t CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
            int halVersion, const String16& clientPackageName, int clientUid,
            apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
            /*out*/sp<CLIENT>& device) {
        status_t ret = NO_ERROR;
        String8 clientName8(clientPackageName);
        int clientPid = getCallingPid();
    
        sp<CLIENT> client = nullptr;
        {
            // Acquire mServiceLock and prevent other clients from connecting
            std::unique_ptr<AutoConditionLock> lock =
                    AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);
    
            if (lock == nullptr) {
                ALOGE("CameraService::connect X (PID %d) rejected (too many other clients connecting)."
                        , clientPid);
                return -EBUSY;
            }
    
            // Enforce client permissions and do basic sanity checks
            if((ret = validateConnectLocked(cameraId, /*inout*/clientUid)) != NO_ERROR) {
                return ret;
            }
    
            // Check the shim parameters after acquiring lock, if they have already been updated and
            // we were doing a shim update, return immediately
            if (shimUpdateOnly) {
                auto cameraState = getCameraState(cameraId);
                if (cameraState != nullptr) {
                    if (!cameraState->getShimParams().isEmpty()) return NO_ERROR;
                }
            }
    
            sp<BasicClient> clientTmp = nullptr;
            std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
            if ((ret = handleEvictionsLocked(cameraId, clientPid, effectiveApiLevel,
                    IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,
                    /*out*/&partial)) != NO_ERROR) {
                return ret;
            }
    
            if (clientTmp.get() != nullptr) {
                // Handle special case for API1 MediaRecorder where the existing client is returned
                device = static_cast<CLIENT*>(clientTmp.get());
                return NO_ERROR;
            }
    
            // give flashlight a chance to close devices if necessary.
            mFlashlight->prepareDeviceOpen(cameraId);
    
            // TODO: Update getDeviceVersion + HAL interface to use strings for Camera IDs
            int id = cameraIdToInt(cameraId);
            if (id == -1) {
                ALOGE("%s: Invalid camera ID %s, cannot get device version from HAL.", __FUNCTION__,
                        cameraId.string());
                return BAD_VALUE;
            }
    
            int facing = -1;
            int deviceVersion = getDeviceVersion(id, /*out*/&facing);
            sp<BasicClient> tmp = nullptr;
            if((ret = makeClient(this, cameraCb, clientPackageName, cameraId, facing, clientPid,
                    clientUid, getpid(), legacyMode, halVersion, deviceVersion, effectiveApiLevel,
                    /*out*/&tmp)) != NO_ERROR) {
                return ret;
            }
            client = static_cast<CLIENT*>(tmp.get());
    
            LOG_ALWAYS_FATAL_IF(client.get() == nullptr, "%s: CameraService in invalid state",
                    __FUNCTION__);
    
            if ((ret = client->initialize(mModule)) != OK) {
                ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
                return ret;
            }
    
            // Update shim paremeters for legacy clients
            if (effectiveApiLevel == API_1) {
                // Assume we have always received a Client subclass for API1
                sp<Client> shimClient = reinterpret_cast<Client*>(client.get());
                String8 rawParams = shimClient->getParameters();
                CameraParameters params(rawParams);
    
                auto cameraState = getCameraState(cameraId);
                if (cameraState != nullptr) {
                    cameraState->setShimParams(params);
                } else {
                    ALOGE("%s: Cannot update shim parameters for camera %s, no such device exists.",
                            __FUNCTION__, cameraId.string());
                }
            }
    
            if (shimUpdateOnly) {
                // If only updating legacy shim parameters, immediately disconnect client
                mServiceLock.unlock();
                client->disconnect();
                mServiceLock.lock();
            } else {
                // Otherwise, add client to active clients list
                finishConnectLocked(client, partial);
            }
        } // lock is destroyed, allow further connect calls
    
        // Important: release the mutex here so the client can call back into the service from its
        // destructor (can be at the end of the call)
        device = client;
        return NO_ERROR;
    }
    

    makeClient方法在CameraService.cpp中实现:

    status_t CameraService::makeClient(const sp<CameraService>& cameraService,
            const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
            int facing, int clientPid, uid_t clientUid, int servicePid, bool legacyMode,
            int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
            /*out*/sp<BasicClient>* client) {
    
        // TODO: Update CameraClients + HAL interface to use strings for Camera IDs
        int id = cameraIdToInt(cameraId);
        if (id == -1) {
            ALOGE("%s: Invalid camera ID %s, cannot convert to integer.", __FUNCTION__,
                    cameraId.string());
            return BAD_VALUE;
        }
    
        if (halVersion < 0 || halVersion == deviceVersion) {
            // Default path: HAL version is unspecified by caller, create CameraClient
            // based on device version reported by the HAL.
            switch(deviceVersion) {
              case CAMERA_DEVICE_API_VERSION_1_0:
                if (effectiveApiLevel == API_1) {  // Camera1 API route
                    sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                    *client = new CameraClient(cameraService, tmp, packageName, id, facing,
                            clientPid, clientUid, getpid(), legacyMode);
                } else { // Camera2 API route
                    ALOGW("Camera using old HAL version: %d", deviceVersion);
                    return -EOPNOTSUPP;
                }
                break;
              case CAMERA_DEVICE_API_VERSION_2_0:
              case CAMERA_DEVICE_API_VERSION_2_1:
              case CAMERA_DEVICE_API_VERSION_3_0:
              case CAMERA_DEVICE_API_VERSION_3_1:
              case CAMERA_DEVICE_API_VERSION_3_2:
              case CAMERA_DEVICE_API_VERSION_3_3:
                if (effectiveApiLevel == API_1) { // Camera1 API route
                    sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                    *client = new Camera2Client(cameraService, tmp, packageName, id, facing,
                            clientPid, clientUid, servicePid, legacyMode);
                } else { // Camera2 API route
                    sp<ICameraDeviceCallbacks> tmp =
                            static_cast<ICameraDeviceCallbacks*>(cameraCb.get());
                    *client = new CameraDeviceClient(cameraService, tmp, packageName, id,
                            facing, clientPid, clientUid, servicePid);
                }
                break;
              default:
                // Should not be reachable
                ALOGE("Unknown camera device HAL version: %d", deviceVersion);
                return INVALID_OPERATION;
            }
        } else {
            // A particular HAL version is requested by caller. Create CameraClient
            // based on the requested HAL version.
            if (deviceVersion > CAMERA_DEVICE_API_VERSION_1_0 &&
                halVersion == CAMERA_DEVICE_API_VERSION_1_0) {
                // Only support higher HAL version device opened as HAL1.0 device.
                sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
                *client = new CameraClient(cameraService, tmp, packageName, id, facing,
                        clientPid, clientUid, servicePid, legacyMode);
            } else {
                // Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
                ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
                        " opened as HAL %x device", halVersion, deviceVersion,
                        CAMERA_DEVICE_API_VERSION_1_0);
                return INVALID_OPERATION;
            }
        }
        return NO_ERROR;
    }
    

    由此,初始化了服务端的CameraClient实例,之后在客户端的操作都是调用了此实例。这样每一次客户端调用preview/takepicture,就直接调用的是CameraClient中的相关函数。

    返回到CameraService::connect()函数中,处理完成之后的client实例赋值给了device,而这个device,就是在客户端CameraBase.cpp中c->mCamera,
    status = (cs.get()->fnConnectService)(cl, cameraId, clientPackageName, clientUid,
    /
    out*/ c->mCamera);

    这样就真正建立了客户端和服务端的关系。如Camera.cpp中的startPreview

    status_t Camera::startPreview()
    {
        ALOGV("startPreview");
        sp <ICamera> c = mCamera;
        if (c == 0) return NO_INIT;
        return c->startPreview();
    }
    

    其实直接就会调用到CameraService中CameraClient.cpp中

    status_t CameraClient::startPreview() {
        LOG1("startPreview (pid %d)", getCallingPid());
        return startCameraMode(CAMERA_PREVIEW_MODE);
    }
    

    至此,对于camera的客户端如何连接到server端的已经介绍完毕。

    2.4 server端的初始化

    camera客户端与服务端的调用关系,就是camera.cpp中的函数,对应到CameraClient中的函数。下面我们再看看CameraClient的初始化过程。

    在客户端连接过程中,connectHelper方法里,调用了方法:

    if ((ret = client->initialize(mModule)) != OK) {
        ALOGE("%s: Could not initialize client from HAL module.", __FUNCTION__);
        return ret;
    }
    

    此方法调用了CameraClient的initialize函数:

    status_t CameraClient::initialize(CameraModule *module) {
        int callingPid = getCallingPid();
        status_t res;
    
        // Verify ops permissions
        res = startCameraOps();
        if (res != OK) {
            return res;
        }
    
        char camera_device_name[10];
        snprintf(camera_device_name, sizeof(camera_device_name), "%d", mCameraId);
        //先实例化camera HAL的CameraHardwareInterface接口
        mHardware = new CameraHardwareInterface(camera_device_name);
        //调用initialize进入HAL层,打开camera底层驱动
        res = mHardware->initialize(module);
        if (res != OK) {
            ALOGE("%s: Camera %d: unable to initialize device: %s (%d)",
                    __FUNCTION__, mCameraId, strerror(-res), res);
            mHardware.clear();
            return res;
        }
    
        mHardware->setCallbacks(notifyCallback,
                dataCallback,
                dataCallbackTimestamp,
                (void *)(uintptr_t)mCameraId);
    
        // Enable zoom, error, focus, and metadata messages by default
        enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
                      CAMERA_MSG_PREVIEW_METADATA | CAMERA_MSG_FOCUS_MOVE);
        return OK;
    }
    

    在上面的方法中,mHardware->initialize(module)中的module是一个结构体camera_module_t,接下来分析它的初始化过程。

    在客户端发起连接的时候,在CameraBase中的connect方法中,调用了getCameraService方法,

    sp<TCam> CameraBase<TCam, TCamTraits>::connect(int cameraId,
                                                   const String16& clientPackageName,
                                                   int clientUid)
    {
        ALOGV("%s: connect", __FUNCTION__);
        sp<TCam> c = new TCam(cameraId);
        sp<TCamCallbacks> cl = c;
        status_t status = NO_ERROR;
        const sp<ICameraService>& cs = getCameraService();
        ... ...
    

    这个时候初始化了一个CameraService实例,且用Sp包装,这个时候sp将新增计数,相应的CameraService实例里面onFirstRef()函数完成调用。该函数在强引用sp新增引用计数时调用。就是当有sp包装的类初始化的时候调用。

    void CameraService::onFirstRef()
    {
        BnCameraService::onFirstRef();
        // Update battery life tracking if service is restarting
        BatteryNotifier& notifier(BatteryNotifier::getInstance());
        notifier.noteResetCamera();
        notifier.noteResetFlashlight();
        camera_module_t *rawModule;
        int err = hw_get_module(CAMERA_HARDWARE_MODULE_ID,
                (const hw_module_t **)&rawModule);
        mModule = new CameraModule(rawModule);
        ... ...
    

    CAMERA_HARDWARE_MODULE_ID 获取Camera Hal层的代理stub,并赋值给mModule,后面就可通过操作mModule完成对Camera模块的控制。

    至此,服务端的初始化也分析完毕。整个流程的总结如下:
    ->先是系统注册CameraService的服务
    ->AP层调用Camera.open()
    ->Camera.java调用JNI native_setup()
    ->JNI层调用 android_hardware_Camera_native_setup
    -> HAL 客户端(Camera.cpp)调用connect与服务端(CameraService.cpp)连接,并得到CameraService中的CameraClient的一个实例
    ->服务端CameraClient的初始化,实例化Camera Hal接口 CameraHardwareInterface
    ->CameraHardwareInterface 打开Camera驱动,初始化完毕
    对应的代码层次:
    App--->framework-java--->jni--->framework-c++(Camera)--->binder---> framework-c++(CameraService)-->framework-c++(CameraService::Client)---> framework-c++(CameraClient) --->(CameraHardwareInterface) ---> HAL

    2.5 HAL层openCamera

    首先在CameraService中的onFirstRef()方法里实例化了HAL层的对象,然后调用了相关的方法,下面就从HAL层去分析是如何启动camera的。

    mModule = new CameraModule(rawModule);
    mNumberOfCameras = mModule->getNumberOfCameras();
    

    可以看出,先是调用了HAL层的getNumberOfCameras()方法,返回支持的摄像头数量。

    在HAL层,其调用到了QCamera2Factory.cpp中。在构造函数时调用了get_num_of_cameras()方法,然后getNumberOfCameras()方法返回这个成员变量。

    QCamera2Factory::QCamera2Factory()
    {
        mNumOfCameras = get_num_of_cameras();
    }
    int QCamera2Factory::getNumberOfCameras()
    {
        return mNumOfCameras;
    }
    

    get_num_of_cameras()方法在mm_camera_interface.c中实现,在while循环中不断访问驱动,然后不满足条件之后跳出循环,返回camera数量。

    之后通过HAL开启camera,在HAL层中,具体的实现是在QCamera2HWI.cpp中:

    int QCamera2HardwareInterface::openCamera(struct hw_device_t **hw_device)
    {
        ATRACE_CALL();
        int rc = NO_ERROR;
    
        if (!check_cam_access(mCameraId)) {
            ALOGE("%s: multiple simultaneous camera instance not supported", __func__);
            return -EUSERS;
        }
    
        if (mCameraOpened) {
            *hw_device = NULL;
            return PERMISSION_DENIED;
        }
        CDBG_HIGH("[KPI Perf] %s: E PROFILE_OPEN_CAMERA camera id %d", __func__,mCameraId);
        rc = openCamera();
        if (rc == NO_ERROR){
            *hw_device = &mCameraDevice.common;
            if (m_thermalAdapter.init(this) != 0) {
              ALOGE("Init thermal adapter failed");
            }
        }
        else
            *hw_device = NULL;
        return rc;
    }
    

    继续调用openCamera()方法,

    int QCamera2HardwareInterface::openCamera()
    {
        int32_t l_curr_width = 0;
        int32_t l_curr_height = 0;
        m_max_pic_width = 0;
        m_max_pic_height = 0;
        char value[PROPERTY_VALUE_MAX];
        int enable_4k2k;
        size_t i;
    
        if (mCameraHandle) {
            ALOGE("Failure: Camera already opened");
            return ALREADY_EXISTS;
        }
        mCameraHandle = camera_open((uint8_t)mCameraId);
        ... ...
        mCameraHandle->ops->register_event_notify(mCameraHandle->camera_handle,
                                              camEvtHandle,
                                              (void *) this);
        ... ...
        }
    

    之后调用camera_open方法,此方法在mm_camera_interface.c中实现:

    mm_camera_vtbl_t * camera_open(uint8_t camera_idx)
    {
        int32_t rc = 0;
        mm_camera_obj_t* cam_obj = NULL;
    
        CDBG("%s: E camera_idx = %d\n", __func__, camera_idx);
        if (camera_idx >= g_cam_ctrl.num_cam) {
            CDBG_ERROR("%s: Invalid camera_idx (%d)", __func__, camera_idx);
            return NULL;
        }
    
        pthread_mutex_lock(&g_intf_lock);
        /* opened already */
        if(NULL != g_cam_ctrl.cam_obj[camera_idx]) {
            /* Add reference */
            g_cam_ctrl.cam_obj[camera_idx]->ref_count++;
            pthread_mutex_unlock(&g_intf_lock);
            CDBG("%s:  opened alreadyn", __func__);
            return &g_cam_ctrl.cam_obj[camera_idx]->vtbl;
        }
    
        cam_obj = (mm_camera_obj_t *)malloc(sizeof(mm_camera_obj_t));
        if(NULL == cam_obj) {
            pthread_mutex_unlock(&g_intf_lock);
            CDBG("%s:  no mem", __func__);
            return NULL;
        }
    
        /* initialize camera obj */
        memset(cam_obj, 0, sizeof(mm_camera_obj_t));
        cam_obj->ref_count++;
        cam_obj->my_hdl = mm_camera_util_generate_handler(camera_idx);
        cam_obj->vtbl.camera_handle = cam_obj->my_hdl; /* set handler */
        cam_obj->vtbl.ops = &mm_camera_ops;
        pthread_mutex_init(&cam_obj->cam_lock, NULL);
    
        rc = mm_camera_open(cam_obj);
        if(rc != 0) {
            CDBG_ERROR("%s: mm_camera_open err = %d", __func__, rc);
            pthread_mutex_destroy(&cam_obj->cam_lock);
            g_cam_ctrl.cam_obj[camera_idx] = NULL;
            free(cam_obj);
            cam_obj = NULL;
            pthread_mutex_unlock(&g_intf_lock);
            return NULL;
        }else{
            CDBG("%s: Open succeded\n", __func__);
            g_cam_ctrl.cam_obj[camera_idx] = cam_obj;
            pthread_mutex_unlock(&g_intf_lock);
            return &cam_obj->vtbl;
        }
    }
    

    之后继续调用mm_camera_open方法,此方法在mm_camera.c中实现:

    int32_t mm_camera_open(mm_camera_obj_t *my_obj)
    {
        char dev_name[MM_CAMERA_DEV_NAME_LEN];
        int32_t rc = 0;
        int8_t n_try=MM_CAMERA_DEV_OPEN_TRIES;
        uint8_t sleep_msec=MM_CAMERA_DEV_OPEN_RETRY_SLEEP;
        int cam_idx = 0;
        char t_devname[MM_CAMERA_DEV_NAME_LEN];
        const char *temp_dev_name = mm_camera_util_get_dev_name(my_obj->my_hdl);
    
        CDBG("%s:  begin\n", __func__);
    
        if (temp_dev_name == NULL) {
            CDBG_ERROR("%s: dev name is NULL",__func__);
            rc= -1;
            goto on_error;
        }
        strlcpy(t_devname, temp_dev_name, sizeof(t_devname));
        snprintf(dev_name, sizeof(dev_name), "/dev/%s",t_devname );
        sscanf(dev_name, "/dev/video%d", &cam_idx);
        CDBG_ERROR("%s: dev name = %s, cam_idx = %d", __func__, dev_name, cam_idx);
    
        do{
            n_try--;
            my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);
            CDBG("%s:  ctrl_fd = %d, errno == %d", __func__, my_obj->ctrl_fd, errno);
            if((my_obj->ctrl_fd > 0) || (errno != EIO) || (n_try <= 0 )) {
                CDBG_ERROR("%s:  opened, break out while loop", __func__);
                break;
            }
            CDBG("%s:failed with I/O error retrying after %d milli-seconds",
                 __func__, sleep_msec);
            usleep(sleep_msec * 1000U);
        }while (n_try > 0);
    
        if (my_obj->ctrl_fd <= 0) {
            CDBG_ERROR("%s: cannot open control fd of '%s' (%s)\n",
                     __func__, dev_name, strerror(errno));
            rc = -1;
            goto on_error;
        }
    
        /* open domain socket*/
        n_try = MM_CAMERA_DEV_OPEN_TRIES;
        do {
            n_try--;
            my_obj->ds_fd = mm_camera_socket_create(cam_idx, MM_CAMERA_SOCK_TYPE_UDP);
            CDBG("%s:  ds_fd = %d, errno = %d", __func__, my_obj->ds_fd, errno);
            if((my_obj->ds_fd > 0) || (n_try <= 0 )) {
                CDBG("%s:  opened, break out while loop", __func__);
                break;
            }
            CDBG("%s:failed with I/O error retrying after %d milli-seconds",
                 __func__, sleep_msec);
            usleep(sleep_msec * 1000U);
        } while (n_try > 0);
    
        if (my_obj->ds_fd <= 0) {
            CDBG_ERROR("%s: cannot open domain socket fd of '%s'(%s)\n",
                     __func__, dev_name, strerror(errno));
            rc = -1;
            goto on_error;
        }
        pthread_mutex_init(&my_obj->msg_lock, NULL);
    
        pthread_mutex_init(&my_obj->cb_lock, NULL);
        pthread_mutex_init(&my_obj->evt_lock, NULL);
        pthread_cond_init(&my_obj->evt_cond, NULL);
    
        CDBG("%s : Launch evt Thread in Cam Open",__func__);
        snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Dispatch");
        mm_camera_cmd_thread_launch(&my_obj->evt_thread,
                                    mm_camera_dispatch_app_event,
                                    (void *)my_obj);
    
        /* launch event poll thread
         * we will add evt fd into event poll thread upon user first register for evt */
        CDBG("%s : Launch evt Poll Thread in Cam Open", __func__);
        snprintf(my_obj->evt_thread.threadName, THREAD_NAME_SIZE, "CAM_Poll");
        mm_camera_poll_thread_launch(&my_obj->evt_poll_thread,
                                     MM_CAMERA_POLL_TYPE_EVT);
        mm_camera_evt_sub(my_obj, TRUE);
    
        CDBG("%s:  end (rc = %d)\n", __func__, rc);
        /* we do not need to unlock cam_lock here before return
         * because for open, it's done within intf_lock */
        return rc;
    
    on_error:
        if (my_obj->ctrl_fd > 0) {
            close(my_obj->ctrl_fd);
            my_obj->ctrl_fd = 0;
        }
        if (my_obj->ds_fd > 0) {
            mm_camera_socket_close(my_obj->ds_fd);
           my_obj->ds_fd = 0;
        }
    
        /* we do not need to unlock cam_lock here before return
         * because for open, it's done within intf_lock */
        return rc;
    }
    

    可以看出,在此方法中,打开了视频节点,创建了Socket,Launch相关的线程。

    接着,回到QCamera2HWI.cpp中的openCamera()方法中,ops->register_event_notify去调用了mm_camera_interface.c中的方法:

    static int32_t mm_camera_intf_register_event_notify(uint32_t camera_handle,
                                                        mm_camera_event_notify_t evt_cb,
                                                        void * user_data)
    {
        int32_t rc = -1;
        mm_camera_obj_t * my_obj = NULL;
    
        CDBG("%s :E ", __func__);
        pthread_mutex_lock(&g_intf_lock);
        //获取camera对象
        my_obj = mm_camera_util_get_camera_by_handler(camera_handle);
    
        if(my_obj) {
            pthread_mutex_lock(&my_obj->cam_lock);
            pthread_mutex_unlock(&g_intf_lock);
            //真正去注册
            rc = mm_camera_register_event_notify(my_obj, evt_cb, user_data);
        } else {
            pthread_mutex_unlock(&g_intf_lock);
        }
        CDBG("%s :E rc = %d", __func__, rc);
        return rc;
    }
    

    可以看出,此方法是注册事件通知的,然后真正实现注册的位置是mm_camera.c中的mm_camera_register_event_notify方法:

    int32_t mm_camera_register_event_notify(mm_camera_obj_t *my_obj,
                                            mm_camera_event_notify_t evt_cb,
                                            void * user_data)
    {
        int rc = -1;
        rc = mm_camera_register_event_notify_internal(my_obj,
                                                      evt_cb,
                                                      user_data);
        pthread_mutex_unlock(&my_obj->cam_lock);
        return rc;
    }
    

    接下来,调用了mm_camera_register_event_notify_internal方法。

    int32_t mm_camera_register_event_notify_internal(mm_camera_obj_t *my_obj,
                                                     mm_camera_event_notify_t evt_cb,
                                                     void * user_data)
    {
        int i;
        int rc = -1;
        mm_camera_evt_obj_t *evt_array = NULL;
    
        pthread_mutex_lock(&my_obj->cb_lock);
        evt_array = &my_obj->evt;
        if(evt_cb) {
            /* this is reg case */
            for(i = 0; i < MM_CAMERA_EVT_ENTRY_MAX; i++) {
                if(evt_array->evt[i].user_data == NULL) {
                    evt_array->evt[i].evt_cb = evt_cb;
                    evt_array->evt[i].user_data = user_data;
                    evt_array->reg_count++;
                    rc = 0;
                    break;
                }
            }
        } else {
            /* this is unreg case */
            for(i = 0; i < MM_CAMERA_EVT_ENTRY_MAX; i++) {
                if(evt_array->evt[i].user_data == user_data) {
                    evt_array->evt[i].evt_cb = NULL;
                    evt_array->evt[i].user_data = NULL;
                    evt_array->reg_count--;
                    rc = 0;
                    break;
                }
            }
        }
    
        pthread_mutex_unlock(&my_obj->cb_lock);
        return rc;
    }
    

    此处将事件的回调注册完成。接着回到QCamera2HWI.cpp里,继续初始化、配置相关参数。
    至此,打开camera的过程已经分析完成。

    2.6 流程图

    底层Camera初始化流程图

    相关文章

      网友评论

        本文标题:Media Module之Camera(二) 初始化

        本文链接:https://www.haomeiwen.com/subject/zfyjfxtx.html