前言:做了7年的camera app开发,给自己一个总结,算是对camera的一次告白吧。Camera被大家誉为手机的眼睛,是现在各大手机厂商的卖点,也是各大厂商重点发力的地方。Camera的重要性我就不在这里赘述了,让我们进入正题。
先来一张官方的流程图,让我们更加清晰的了解Camera的架构。
一、申请权限
Manifest.permission.CAMERA
如果只要拍照功能,不需要录像的功能,只申请Camera的权限就可以了。
参考代码:参考Camera2 原码
1. Manifest.permission.RECORD_AUDIO
如果camera app中需要有录像的功能
参考代码:参考Camera2 原码
2. Manifest.permission.ACCESS_COARSE_LOCATION
3. Manifest.permission.ACCESS_FINE_LOCATION
如果需要拍照生成的照片带gps的信息,需要申请这两个权限。
参考代码:参考Camera2 原码
二、准备SurfaceView或者SurfaceTexture 或 TextureView
在Camera app启动的时候,onCreate的时候创建surface,可以选择SurfaceView或者SurfaceTexture,这里是根据业务选择的,各有优缺点。
- SurfaceView:SurfaceView的核心在于提供了两个线程:UI线程和渲染线程,两个线程通过“双缓冲”机制来达到高效的界面刷新效果。
- SurfaceTexture: 和SurfaceView不同的是,它对图像流的处理并不直接显示,而是转为GL外部纹理,因此可用于图像流数据的二次处理(如Camera滤镜,桌面特效等)。比如Camera的预览数据,变成纹理后可以交给GLSurfaceView直接显示,也可以通过SurfaceTexture交给TextureView作为View heirachy中的一个硬件加速层来显示。
- TextureView: 它可以将内容流直接投影到View中,可以用于实现Live preview等功能。和SurfaceView不同,它不会在WMS中单独创建窗口,而是作为View hierachy中的一个普通View,因此可以和其它普通View一样进行移动,旋转,缩放,动画等变化。
- SurfaceView和TextureView对比:
参考代码:Camera2 代码中用的是SurefaceTexture
三、准备打开camera和预览
Surface准备好了,收到onSurfaceTextureAvailable后,app就可以打开camera和预览了。
参考代码:reopenCamera
1. 获取camera id
首先要确定app要打开的是哪个Camera id,把这个id确定好,app就可以通过openCamera来打开正确的camera sensor了。
参见camera2代码:获取cameraid
2. openCamera
CameraManager调用openCamera方法打开camera,参见api文档:openCamera
对应到Camera2 的原码位置:open —> 真正调用openCamera的位置 -->framework中CameraManager调用openCamera的位置–>openCameraForUid -->openCameraDeviceUserAsync–>connectDevice–>connectHelper–>CameraService.cpp中的方法connectHelper–>makeClient
1060 if (effectiveApiLevel == API_1) {
// Camera1 API route
1061 sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
1062 *client = new Camera2Client(cameraService, tmp, cameraService->mCameraServiceProxyWrapper,
1063 packageName, featureId, cameraId, api1CameraId, facing, sensorOrientation,
1064 clientPid, clientUid, servicePid, overrideForPerfClass, overrideToPortrait,
1065 forceSlowJpegMode);
1066 ALOGI("%s: Camera1 API (legacy), override to portrait %d, forceSlowJpegMode %d",
1067 __FUNCTION__, overrideToPortrait, forceSlowJpegMode);
1068 } else {
// Camera2 API route
1069 sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
1070 static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
1071 *client = new CameraDeviceClient(cameraService, tmp,
1072 cameraService->mCameraServiceProxyWrapper, packageName, systemNativeClient,
1073 featureId, cameraId, facing, sensorOrientation, clientPid, clientUid, servicePid,
1074 overrideForPerfClass, overrideToPortrait);
1075 ALOGI("%s: Camera2 API, override to portrait %d", __FUNCTION__, overrideToPortrait);
1076 }
几种常见的camera连接的错误,这些错误是客户端调用initialize,调用到服务端,服务端返回的错误信息。
1858 String8 monitorTags = isClientWatched(client.get()) ? mMonitorTags : String8("");
1859 err = client->initialize(mCameraProviderManager, monitorTags);
1860 if (err != OK) {
1861 ALOGE("%s: Could not initialize client from HAL.", __FUNCTION__);
1862 // Errors could be from the HAL module open call or from AppOpsManager
1863 switch(err) {
1864 case BAD_VALUE:
1865 return STATUS_ERROR_FMT(ERROR_ILLEGAL_ARGUMENT,
1866 "Illegal argument to HAL module for camera \"%s\"", cameraId.string());
1867 case -EBUSY:
1868 return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
1869 "Camera \"%s\" is already open", cameraId.string());
1870 case -EUSERS:
1871 return STATUS_ERROR_FMT(ERROR_MAX_CAMERAS_IN_USE,
1872 "Too many cameras already open, cannot open camera \"%s\"",
1873 cameraId.string());
1874 case PERMISSION_DENIED:
1875 return STATUS_ERROR_FMT(ERROR_PERMISSION_DENIED,
1876 "No permission to open camera \"%s\"", cameraId.string());
1877 case -EACCES:
1878 return STATUS_ERROR_FMT(ERROR_DISABLED,
1879 "Camera \"%s\" disabled by policy", cameraId.string());
1880 case -ENODEV:
1881 default:
1882 return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
1883 "Failed to initialize camera \"%s\": %s (%d)", cameraId.string(),
1884 strerror(-err), err);
1885 }
1886 }
–>调用camera2的CameraDeviceClient -->Camera2ClientBase.
- 从CameraService.cpp 中的connectHelper中调用initialize --> initialize–>initializeImpl–>CameraDeviceClient.cpp中的方法 initialize --> initializeImpl --> Camera2ClientBase.cpp initialize --> initializeImpl --> 创建Camera3Device
switch (providerTransport) {
116 case IPCTransport::HIDL:
117 mDevice =
118 new HidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
119 mLegacyClient);
120 break;
121 case IPCTransport::AIDL:
122 mDevice =
123 new AidlCamera3Device(TClientBase::mCameraIdStr, mOverrideForPerfClass,
124 mLegacyClient);
125 break;
126 default:
127 ALOGE("%s Invalid transport for camera id %s", __FUNCTION__,
128 TClientBase::mCameraIdStr.string());
129 return NO_INIT;
130 }
–>Camera2ClientBase.cpp 中的方法 initialize --> HidlCamera3Device.cpp 中的方法initialize -->openHidlSession --> open
714 status_t CameraProviderManager::openHidlSession(const std::string &id,
715 const sp<device::V3_2::ICameraDeviceCallback>& callback,
716 /*out*/
717 sp<device::V3_2::ICameraDeviceSession> *session) {
718
719 std::lock_guard<std::mutex> lock(mInterfaceMutex);
720
721 ... ...
723
724 auto *hidlDeviceInfo3 = static_cast<HidlProviderInfo::HidlDeviceInfo3*>(deviceInfo);
725 sp<ProviderInfo> parentProvider = deviceInfo->mParentProvider.promote();
726 if (parentProvider == nullptr) {