lin20080410的专栏

从站在巨人的肩上,向成为巨人迈进... 互相学习!

Camera2(api2) 打开过程(一)

C++层log的输出,如果不全,可以调整log的级别:

adb shell dumpsys media.camera -v 1 ,至少改成>=1。

 

Camera2 打开过程 

public void onCreateTasks(Bundle state)@ CameraActivity.java{

       mFirstRunDialog = new FirstRunDialog(this,

              getAndroidContext(),

              mResolutionSetting,

              mSettingsManager,

              mOneCameraManager,

              newFirstRunDialog.FirstRunDialogListener() {

           @Override

           public void onFirstRunStateReady() {

                // Run normal resume tasks.

                resume();

           }

}


private void resume()@CameraActivity.java{

         mCurrentModule.resume();

}


public void resume()@CaptureModule.java{

       if (texture != null) {

           initSurfaceTextureConsumer();

           guard.mark("initSurfaceTextureConsumer");

       }       

}


private void initSurfaceTextureConsumer()@CaptureModule.java{

         reopenCamera();

}


private void reopenCamera() @CaptureModule.java{

         openCameraAndStartPreview();

}


在打开Camera设备,预览,拍照的过程中有几个比较重要的回调:

1、  OneCamera.OpenCallback @OneCamera.java

2、  CameraDevice. StateCallback@ CameraDevice.java

3、  CameraCaptureSession. StateCallback@ CameraCaptureSession.java

4、  CameraCaptureSession.CaptureCallback @ CameraCaptureSession.java

5、  OneCamera.CaptureReadyCallback@ OneCamera.java

这些回调的执行过程:

Step1CameraManager调用openCamera后,会执行CameraDevice.StateCallback这个回调,重写其中的onOpened方法:

Camera2OneCameraOpenerImpl.java

mCameraManager.openCamera(cameraKey.getValue(), new CameraDevice.StateCallback() {
public void onOpened(CameraDevice device) {
OneCamera oneCamera = OneCameraCreator.create(
                                    device,
                                    characteristics,
                                    mFeatureConfig,
                                    captureSetting,
                                    mDisplayMetrics,
                                    mContext,
                                    mainThread,
                                    imageRotationCalculator,
                                    burstController,
                                    soundPlayer, fatalErrorHandler);

openCallback.onCameraOpened(oneCamera);
}
}

其中 OneCameraCreator.create会创建一个Camera实例,具体调用那个OneCameraFactory来生成实例,依赖于camera支持的level,最终生成的camera实例都是GenericOneCameraImpl类型的。


Step2,在Step1onOpened方法中,又会回调OpenCallback,执行其中重写的onCameraOpened方法。这里的openCallback变量是在CaptureModule.java中的openCameraAndStartPreview调用中传递过来的。

CaptureModule.java

mOneCameraOpener.open(cameraId,captureSetting, mCameraHandler, mainThread,

         imageRotationCalculator,mBurstController, mSoundPlayer,

         new OpenCallback() {

                   publicvoid onCameraOpened(@Nonnull final OneCamera camera) {

                            camera.startPreview(newSurface(getPreviewSurfaceTexture()),

                                     new CaptureReadyCallback() {

                                         public voidonReadyForCapture() {……}

                                    }

                  }

}

在camera打开成功后,调用camera实例的startPreview开启预览。


Step3,在Step2onCameraOpened中,会调用oneCameraImplstartPreview方法,这个过程中会以异步的方式创建一个capture session,然后createCaptureSession中如果成功配置了输入输出流,又回调了CameraCaptureSession.StateCallback中的onConfigured方法,同时把创建的CameraCaptureSession对象传了过来。

OneCameraImpl.java

public void startPreview(SurfacepreviewSurface, CaptureReadyCallback listener) {

mDevice.createCaptureSession(outputSurfaces,new CameraCaptureSession.StateCallback() {

         public void onConfigured(CameraCaptureSession session) {

                   boolean success =repeatingPreview(null);

                   listener.onReadyForCapture();

         }

}

值得一提的是调用stateCallback的onConfigured方法,是在CallbackProxies$SessionStateCallbackProxy中利用类似委托的模式调用了CameraCaptureSession.StateCallback.class的onConfigured方法,并携带参数CameraCaptureSession session。

    public static class SessionStateCallbackProxy
            extends CameraCaptureSession.StateCallback {
        public void onConfigured(CameraCaptureSession session) {
            mProxy.invoke("onConfigured", session);
        }
}


Step4,在上一步的onConfigured中,通过repeatingPreview调用setRepeatingRequest开启预览,这个过程会提交一个拍照的request到captureSession中,如果开启预览成功,会调用listener.onReadyForCapture();这里的listener是CaptureReadyCallback类型的,是在CaptureModule.java中的openCameraAndStartPreview中传递的实例(camera.startPreview(...new CaptureReadyCallback())),表示做好了拍照的准备。

还会回调CameraCaptureSession.CaptureCallback,调用其中的方法:onCaptureCompleted,这个调用也是利用委托的模式,具体是通过frameworks/base/core/java/android/hardware/camera2/impl/CallbackProxies$DeviceCaptureCallbackProxy.java实现。

CameraCaptureSession.CaptureCallback这个callback主要是对frame元数据的监听。

OneCameraImpl.java

private boolean repeatingPreview(Objecttag) {

//向相机设备发起获取图像的请求。

         mCaptureSession.setRepeatingRequest(builder.build(),mCaptureCallback,

                   mCameraHandler);

}

值得注意的这里回调了mCaptureCallback中的onCaptureCompleted,接着看这个函数的处理:

private finalCameraCaptureSession.CaptureCallback mCaptureCallback =

         newCameraCaptureSession.CaptureCallback() {

         publicvoid onCaptureCompleted(CameraCaptureSession session,

                   CaptureRequestrequest, TotalCaptureResult result) {

         if(mCaptureQueue.getFirst().setCaptureResult(result)

                   .isCaptureComplete()){

                   capture= mCaptureQueue.removeFirst();

         }

         OneCameraImpl.this.onCaptureCompleted(capture);

         }
};

根据sCaptureImageFormat,这里会获取到RAW数据,或者jpeg数据,原数据以dng文件的形式保存。

oneCameraImpl.java

private void onCaptureCompleted(InFlightCapture capture) {

         if(sCaptureImageFormat == ImageFormat.RAW_SENSOR) {

                   FiledngFile = new File(RAW_DIRECTORY, capture.session.getTitle() +".dng");

                   writeDngBytesAndClose(capture.image,capture.totalCaptureResult,

                            mCharacteristics,dngFile);

         }else {

                   saveJpegPicture(imageBytes,capture.parameters, capture.session,

                            capture.totalCaptureResult);

         }

----------------------------------------------------------------------------------------------------------------

private void openCameraAndStartPreview() @CaptureModule.java{

         mOneCameraOpener.open(…);

}

public void open(

           final CameraId cameraKey,

           final OneCameraCaptureSetting captureSetting,

           final Handler handler,

           final MainThread mainThread,

           final ImageRotationCalculator imageRotationCalculator,

           final BurstFacade burstController,

           final SoundPlayer soundPlayer,

           final OpenCallback openCallback,

           final FatalErrorHandler fatalErrorHandler)@Camera2OneCameraOpenerImpl.java{

 

         mCameraManager.openCamera(cameraKey.getValue(),new CameraDevice.StateCallback() {

                @Override

                public voidonDisconnected(CameraDevice device) {

                    if (isFirstCallback) {

                        isFirstCallback =false;

                        // If the camera isdisconnected before it is opened

                        // then we must callclose.

                        device.close();

                       openCallback.onCameraClosed();

                    }

                }

 

                @Override

                public void onClosed(CameraDevicedevice) {

                    if (isFirstCallback) {

                        isFirstCallback =false;

                       openCallback.onCameraClosed();

                    }

                }

 

                @Override

                public voidonOpened(CameraDevice device) {

                    if (isFirstCallback) {

                        isFirstCallback =false;

                        try {

                           CameraCharacteristics characteristics = mCameraManager

                                   .getCameraCharacteristics(device.getId());

                            // TODO: Setboolean based on whether HDR+ is

                            // enabled.

                            OneCamera oneCamera= OneCameraCreator.create(

                                    device,

                                   characteristics,

                                   mFeatureConfig,

                                   captureSetting,

                                    mDisplayMetrics,

                                    mContext,

                                    mainThread,

                                   imageRotationCalculator,

                                   burstController,

                                    soundPlayer, fatalErrorHandler);

 

                            if (oneCamera !=null) {

                               openCallback.onCameraOpened(oneCamera);

                            } else {

                                Log.d(TAG,"Could not construct a OneCamera object!");

                               openCallback.onFailure();

                            }

                        } catch(CameraAccessException e) {

                        } catch(OneCameraAccessException e) {

                        }

                    }

                }                

}

}

总结下几个回调接口的函数:

先说应用层的OneCamera.java中的:

OpenCallback,当一个Camera被打开或者打开失败时会调用其中的方法。具体实例是在CaptureModule中,通过mOneCameraOpener(Camera2OneCameraOpenerImpl)open方法,传入了这个OpenCallback的回调。

public static interface OpenCallback {

//camera成功打开时调用

         publicvoid onCameraOpened(@Nonnull OneCamera camera);

//打开camera失败时调用。

         publicvoid onFailure();

//在尝试打开camera时,如果camera被关闭或者断开连接了,会调用。

         publicvoid onCameraClosed();

}

这个回调是在Camera成功打开的前提下,才会回调,具体实例在CaptureModule中,onCameraOpened回调被执行时,通过mCamera(OneCameraImpl.java)调用startPreview设置了CaptureReadyCallback,然后在CameraCaptureSession.StateCallback()onConfigured回调被执行时,并且启动预览成功时,回调了其中的onReadyForCapture方法。

public static interfaceCaptureReadyCallback {

//系统准备发出拍照请求时调用。

         publicvoid onReadyForCapture();

//系统还没准备好发出拍照请求就出错了,比如camera配置失败等,这时会调用。

         publicvoid onSetupFailed();

}

然后看下Framework层的两个回调接口,

CameraDevice.java

一个Camera实例必须提供CameraManager#openCamera这个方法来打开camera设备,比如在Camera2OneCameraOpenerImpl.javaopen方法中就调用了mCameraManager.openCamera方法。

这个回调是状态更新,包括设备完成启动相关的通知(这里说的完成启动是指允许调用createCaptureSession方法),包括设备断开或者关闭,或者意想不到的设备错误。

public static abstract class StateCallback{

//这个方法是必须要实现的,在设备完成打开时调用。

         publicabstract void onOpened(@NonNull CameraDevice camera);
//在camera设备被关闭时调用,后面如果再尝试调用cameradevice的任何方法都会抛出异常,IllegalStateException

         publicvoid onClosed(@NonNull CameraDevice camera)

//这个方法必须要实现,当camera设备不再可用时调用。如果打开camera失败,调用onDisconnected,就不在调用onOpened了。在disconnected之后,再调用camera设备的其他方法都会抛出CameraAccessException,断开连接的原因有:安全策略或权限的改变,物理层的断开或移除了cameradevice,被更高优先级的cameraclient所需要。

         publicabstract void onDisconnected(@NonNull CameraDevice camera);

//这个方法必须实现,当cameradevice遇到严重错误时会调用。

         publicabstract void onError(@NonNull CameraDevice camera, @ErrorCode int error);

}

CameraCaptureSession.java

通过提供一组目标output Surfaces作为CameraDevice#createCaptureSession的参数,可以创建一个createCaptureSession;或者提供一个(android.hardware.camera2.params.InputConfiguration)和一组目标outputsurfaces作为CameraDevice#createReprocessableCaptureSession的参数,可以创建一个可重复处理的capture session,一旦创建,这个session就是active的,直到有一个新的session被这个camera device创建,或者camera device被关闭了。

所有的capture sessions都可以用来capturing images,但是只有reprocessable capture sessions可以在同一个session上重复的处理imagescaptured

创建一个session是一个很昂贵的操作,可能需要几百毫秒,因为需要配置camera deviceinternal pipelines,还要分配内存缓冲区以便发送images到指定的目标。所以这个创建的完成是异步的,createCaptureSessioncreateReprocessableCaptureSession会发送一个ready-to-use CaptureSessionde回调给它的监听者,这个调用是在CameraCaptureSession.StateCallbackonConfigured回调中处理的,它的监听者就是CaptureReadyCallback,如果配置失败,就会回调CameraCaptureSession.StateCallback#onConfigureFailed。这个过程的实例:CaptureModule中,通过mCamera(OneCameraImpl)调用startview,同时设置了CaptureReadyCallback回调,并重写了其onReadyForCapture方法,在startview的过程中会通过调用CameraDevicecreateCaptureSession创建一个capturesession,同时设置了CameraCaptureSession.StateCallback的回调,并重写其onConfigured,这样在session配置成功后,就会回调onConfigured,进而在onConfigured中回调CaptureReadyCallbackonReadyForCapture方法。

任何在session ready之前提交的capture requests都会入队,一旦session变为ready就开始capture,万一session没有配置成功,onConfigureFailed会被调用,同时所有入队的capture requests会被丢弃。

如果camera device创建了一个新的session,那么前一个session会关闭,相关的回调onClosed被调用,如果session被关闭了,再去调用它的方法就会抛出IllegalStateException

 

StateCallback 接收cameracapture session的状态更新。

public static abstract class StateCallback{

//当camera device完成了自身的配置,session可以开始处理capturerequests时,这个方法会被调用。

如果已经有capture requests已经在这个session上排队,一旦这个回调被调用就开始处理,在这个调用callback后,会去调用onActive。

如果还没有capture requests提交,在这个调用后,这个session会去调用onReady。

         publicabstract void onConfigured(@NonNull CameraCaptureSession session);

//如果session不能做为requested被配置,回调这个方法,可能的情况有:一组请求的outputs包含了不支持的大小,或者一次请求有太多的outputs。

         publicabstract void onConfigureFailed(@NonNull CameraCaptureSession session);

}

 

CaptureCallback 跟踪CaptureRequest提交到到cameraDevice的进度。

public static abstract class CaptureCallback {

//当cameradevice已经开始为请求捕获输出图像,在图像曝光的起点,或者当camerdevice已经开始为请求处理输入图像时,这个方法被调用。

对于一个正常的拍照请求,这个方法恰好是在开始捕获第一帧时被调用,所以最接近的时间是播放快门音,或者触发拍照UI的标识。

         publicvoid onCaptureStarted(@NonNull CameraCaptureSession session,

                   @NonNullCaptureRequest request, long timestamp, long frameNumber)

//当图像拍摄执行了部分进度,来自图像拍摄的一些结果数据(不是全部)是可用的,这时调用onCaptureProgressed,

其中的参数partialResult包含了完整结果字段的一些子集,在每次拍摄时,这个方法可能调用多次,给出的结果字段最多只会出现在一次的部分捕获中。最后,onCaptureCompleted调用时,result会包含所有字段(特别指出的是,所有字段的联合体是由所有的部分结果组合成的总的结果)

         publicvoid onCaptureProgressed(@NonNull CameraCaptureSession session,

                   @NonNullCaptureRequest request, @NonNull CaptureResult partialResult)

//当图片capture全部完成,并且所有的结果metadata数据可用时,调用这个方法

         publicvoid onCaptureCompleted(@NonNull CameraCaptureSession session,

                   @NonNullCaptureRequest request, @NonNull TotalCaptureResult result)

}


下面进入到Camera Framework层,CameraManager.java

通常情况下,如果一个前端的Activity运行在你的应用进程,你的进程有机会得到一个较高的优先级,当调用openCamera方法访问camera时是会成功的,即使这个camera设备正被另外的一个camera Client使用。任何低优先级的应用是可能失去对camera的控制的,然后收到回调:android.hardware.camera2.CameraDevice.StateCallback#onDisconnected

一旦camera成功打开,CameraDevice.StateCallback#onOpened这个回调随着新打开的设备会被调用,camera设备通过调用CameraDevice#createCaptureSessionCameraDevice#createCaptureRequest准备操作。

因为Camera设备的打开是异步的,任何异步的操作完成返回后,Camera实例会对他们排队,直到camera启动完成,启动完成会有回调:CameraDevice.StateCallback#onOpened onOpened,然后,那些pending的操作就会被顺序的执行。

如果camera在初始化时断开了,CameraDevice.StateCallback#onDisconnected会被调用,CameraDevice.StateCallback#onOpened会被跳过。

如果打开camera失败,会有CameraDevice.StateCallback#onError这个回调,后面再对这个camera设备的调用都会抛出异常:CameraAccessException

 

Framework/base/core/java/android/hardware/camera2/CameraManager.java

   public void openCamera(@NonNull String cameraId,

           @NonNull final CameraDevice.StateCallback callback, @Nullable Handler handler)

           throws CameraAccessException@ CameraManager.java {

         openCameraForUid(cameraId,callback, handler, USE_CALLING_UID);

}

public void openCameraForUid(@NonNullString cameraId,

           @NonNull final CameraDevice.StateCallback callback, @Nullable Handlerhandler,

           int clientUid)

           throws CameraAccessException@ CameraManager.java {

         openCameraDeviceUserAsync(cameraId,callback, handler, clientUid);

}

下面的代码进入到CameraService中,所以我们先看CameraService的启动:

CameraServer有自己的.rc文件:framework/av/camera/cameraserver/cameraserver.rc

service cameraserver/system/bin/cameraserver

   class main

   user cameraserver

   group audio camera input drmrpc

   ioprio rt 4

writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks

所以CameraService是通过cameraserver.rc启动的,它自己是一个单独的进程,这是android7.0的版本,在之前的版本可能是在mediaServer中启动的。

frameworks/av/camera/cameraserver/Main_cameraserver.cpp

main_cameraserver.cpp{

   sp<ProcessState> proc(ProcessState::self());

   sp<IServiceManager> sm = defaultServiceManager();

ALOGI("ServiceManager:%p", sm.get());

//这句调用会启动cameraService

CameraService::instantiate();

//这2句调用,使进程进入到类似Binder_loop的循环。

   ProcessState::self()->startThreadPool();

   IPCThreadState::self()->joinThreadPool();

}

instantiate()调用是CameraService的父类BinderService中的方法。从CameraService.h可以看到这个继承关系。

CameraService.h{

         classCameraService :

                   publicBinderService<CameraService>,

}

BinderService是一个模板类,这里的SERVICE就是CameraService,接下来完成CameraService的注册,具体是在publish方法中,调用了sm->addService(),其中的参数SERVICE::getServiceName()调用的CameraService.h中的:

// Implementation of BinderService<T>

static char const* getServiceName() {return "media.camera"; }

CameraService对应的服务名是media.camera。

 

template<typename SERVICE>

BinderService.h{

         staticvoid instantiate() { publish(); }

static status_tpublish(bool allowIsolated = false) {

       sp<IServiceManager> sm(defaultServiceManager());

       return sm->addService(

               String16(SERVICE::getServiceName()),

                new SERVICE(), allowIsolated);

    }       

}

下面就开始获取CameraService的句柄,调用CameraService中的connectDevice函数。

private CameraDevice openCameraDeviceUserAsync(String cameraId,

           CameraDevice.StateCallback callback, Handler handler, final int uid)

           throws CameraAccessException@ CameraManager.java {

}


续:camera2(api2)的打开预览过程

阅读更多
版权声明:笔记记录,互相学习,不足之处,欢迎指正! https://blog.csdn.net/lin20044140410/article/details/76585818
文章标签: camera2 api2
想对作者说点什么? 我来说一句

Camera API2拍照Demo

2016年09月30日 10.96MB 下载

没有更多推荐了,返回首页

不良信息举报

Camera2(api2) 打开过程(一)

最多只允许输入30个字

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭