Android Camera 打开预览流程分析--打开camera的SDK流程

Posted Give.Me.Five

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Camera 打开预览流程分析--打开camera的SDK流程相关的知识,希望对你有一定的参考价值。

	android系统应用场景中,Camera的使用场景变得越来越重要,在手机端不管是牌照美颜,还是拍小视频上传小视频平台。在其他领域,如车载,倒车视频,360全景影像也同样会用到Camera接口。那我们这个系列就拿Camera来分析了,我们主要就是android camera流程进行一个分析,对于照片美颜,视频上传这些就不在我们关注的范围了。那我们分析还是带着问题去分析吧,Camera就如何打开的,现在一个手机上少则2,3个摄像头,多着5~6个摄像头,那如何去打开想要的那个摄像头呢。另一方面的问题就是Camera预览窗口的图像是如何传到我们打开的那个窗口的,经过了那些流程呢。我们后续的分析文章就围绕着两个方面来展开分析。
	## Camera的分层框架  (等分析完这两个流程,应该就可以画出这个框图了)
	HAL层服务:frameworks/hardware/interfaces/cameraservice
	FW层服务: frameworks/av/services/camera/libcameraservice
	FW层SDK: frameworks/base/core/java/android/hardware/camera(2)

Camera的打开

我们就从android 标准的camera open接口开始撸:

open() ------framework/base/core/java/android/hardware/camera.java
    new Camera(int id)
        cameraInitVersion(int cameraId, int halVersion)
            native_setup(new WeakReference<Camera>(this), cameraId, halVersion, packageName)
                android_hardware_Camera_native_setup(..., jint cameraId, jint halVersion, jstring clientPackageName) -----framework/base/core/jni/android_hardware_camera.cpp

Camera从open接口开始分析,直接就调用到JNI中去了,我们接着从JNI中继续分析:

static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId, jint halVersion, jstring clientPackageName)
{
...
		//调用camera的connect接口 打开camera
        camera = Camera::connect(cameraId, clientName,
                Camera::USE_CALLING_UID, Camera::USE_CALLING_PID);
...
    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());

    // Update default display orientation in case the sensor is reverse-landscape
    CameraInfo cameraInfo;
    //获取camera的信息
    status_t rc = Camera::getCameraInfo(cameraId, &cameraInfo);         
...           

从JNI的native_setup中可以看到,调用了camera的connect接口,成功打开之后就可以获取camera的信息了. 再往下分析时,发现很多不对劲的地方,网上去百度了下,发现我们现在分析的camera 接口是Camera 最早的接口了,现在基本被弃用了,现在基本都是是使用Camera2的API接口,Camera2 与Camera 接口还是有挺大区别。Camera接口都被弃用了,我们就直接上手分析Camera2的接口吧。

Camera2 的接口

上面有说到camera 已经被弃用了,都推荐使用camera2的接口。我们就直接再从camera2 开始分析。camer2中有好些类:
CameraManager
相机系统服务,用于管理和连接相机设备
CameraDevice
相机设备类,和Camear1中的Camera类似
CameraCharacteristics
用于获取相机信息,内部携带大量的相机信息,包括摄像头的正反等,和Camear1中的Camera.Parameters同等功能。
CameraRequest
相机捕获图像的设置请求,包括sensor, flashlight等
CameraCaptureSession
请求抓去相机图像帧的会话,会话会创建一个通道,一个CameraDevice只能打开一个CameraCaptureSession.源头是Target, Target可以是Preview, 也可以是ImageReader

打开相机

public void Open(){
	CameraManager cameraManager = (CameraManager)getSystemService(Context.CAMERA_SERVICE);
	for(String cameraId: cameraManager.getCameraIdList()){
		CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(cameraId);
		//打开相机,第一个参数:哪个摄像头,第二个参数mStateCallback为相机打开的回调接口,第三个参数用来确定callback在哪个线程中执行,为null的话,在当前线程中执行
		cameraManager.openCamera(cameraId, mStateCallback, null)
	}
}

private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback(){
	public void onOpened(CameraDevice camera){
		mCameraDevice = camera;
		...
	}
	
	public void onDisconnected(CameraDevice camera){
		camera.close();
		mCameraDevice = null;
	}

	public void onError(){CameraDevice camera, int error}{
		camera.close();
		mCameraDevice = null;
	}
}

打开Camera时将CameraDevice.StateCallback对象传给openCamera当做参数,在OnOpened的回调中,再把Camera对象传给mCameraDevice, 后面就是用mCameraDevice 来操作。
那我们看看CameraManager.openCamera的流程吧。

    public void openCamera(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)
            throws CameraAccessException {

        openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
                USE_CALLING_UID);
    }
        public void openCameraForUid(@NonNull String cameraId,
            @NonNull final CameraDevice.StateCallback callback, @NonNull Executor executor,
            int clientUid)
            throws CameraAccessException {
		......
        openCameraDeviceUserAsync(cameraId, callback, executor, clientUid);
    }
private CameraDevice openCameraDeviceUserAsync(String cameraId,
            CameraDevice.StateCallback callback, Executor executor, final int uid)
            throws CameraAccessException {
        CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
        CameraDevice device = null;

        synchronized (mLock) {

            ICameraDeviceUser cameraUser = null;
            //初始化android.hardware.camera2.impl.CameraDeviceImpl
            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
                    new android.hardware.camera2.impl.CameraDeviceImpl(
                        cameraId,
                        callback,
                        executor,
                        characteristics,
                        mContext.getApplicationInfo().targetSdkVersion);
             ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
             
            		//初始化CameraService
					ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
					//CameraService 连接设备
                    cameraUser = cameraService.connectDevice(callbacks, cameraId,
                            mContext.getOpPackageName(), uid);    
            deviceImpl.setRemoteDevice(cameraUser);
            device = deviceImpl;
        }
        return device;
    }

这一步调用就直接调用到CameraService 里去了,与其他服务不同的是,其他服务直接是在SystemServer里的一个服务,CameraService是运行在CameraServer的一个独立进程中的。里面是使用cpp代码写的一个进程。下篇我们继续研究这个CameraService进程。

以上是关于Android Camera 打开预览流程分析--打开camera的SDK流程的主要内容,如果未能解决你的问题,请参考以下文章

Android Camera 打开预览流程分析--CameraService中的打开流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析--打开camera的SDK流程

Android Camera 打开预览流程分析-- Camera 连接到CameraService 过程分析