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
这些回调的执行过程:
Step1,CameraManager调用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,在Step1的onOpened方法中,又会回调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,在Step2的onCameraOpened中,会调用oneCameraImpl的startPreview方法,这个过程中会以异步的方式创建一个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.java的open方法中就调用了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 device的internal pipelines,还要分配内存缓冲区以便发送images到指定的目标。所以这个创建的完成是异步的,createCaptureSession和createReprocessableCaptureSession会发送一个ready-to-use CaptureSessionde回调给它的监听者,这个调用是在CameraCaptureSession.StateCallback的onConfigured回调中处理的,它的监听者就是CaptureReadyCallback,如果配置失败,就会回调CameraCaptureSession.StateCallback#的onConfigureFailed。这个过程的实例:CaptureModule中,通过mCamera(OneCameraImpl)调用startview,同时设置了CaptureReadyCallback回调,并重写了其onReadyForCapture方法,在startview的过程中会通过调用CameraDevice的createCaptureSession创建一个capturesession,同时设置了CameraCaptureSession.StateCallback的回调,并重写其onConfigured,这样在session配置成功后,就会回调onConfigured,进而在onConfigured中回调CaptureReadyCallback的onReadyForCapture方法。
任何在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#createCaptureSession和CameraDevice#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 {
}