Camera 入门第一篇 openCamera

共 11923字,需浏览 24分钟

 ·

2020-07-29 19:50

和你一起终身学习,这里是程序员Android

本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:

一、openCamera 简单调用流程
二、CameraManager.getCameraCharacteristics 获取方法
三、supportsCamera2ApiLocked
四、CameraService.connectDevice
五、CameraManager.setRemoteDevice

一、openCamera 简单调用流程

打开相机是通过调用CameraManager.java (frameworks\base\core\java\android\hardware\camera2)的 openCamera 方法,根据指定的CameraId 打开。

1.1 CameraManager.openCamera 方法

  • cameraId 是一个标识,标识当前要打开的camera

  • callback 是一个状态回调,当前camera被打开的时候,这个状态回调会被触发的。

  • handler 是传入的一个执行耗时操作的handler

  • executor 操作线程池

    public void openCamera(@NonNull String cameraId...)
throws CameraAccessException {
// 通过Camera Id 打开Camera,调用1.2 openCameraForUid
openCameraForUid(cameraId, callback, CameraDeviceImpl.checkAndWrapHandler(handler),
USE_CALLING_UID);
}
public void openCamera(@NonNull String cameraId,
@NonNull @CallbackExecutor Executor executor,
@NonNull final CameraDevice.StateCallback callback)

1.2 CameraManager.openCameraForUid 方法

    public void openCameraForUid(@NonNull String cameraId,
.... ... )
throws CameraAccessException {
... ...
//调用异步 Camera 助手 打开Camera ,调用 1.3 openCameraDeviceUserAsync
openCameraDeviceUserAsync(cameraId, callback, executor, clientUid);
}

1.3 CameraManager.openCameraDeviceUserAsync 方法

  • 获取当前cameraId指定相机的设备信息

  • 利用获取相机的设备信息创建CameraDeviceImpl实例

  • 调用远程CameraService获取当前相机的远程服务

  • 将获取的远程服务设置到CameraDeviceImpl实例中

  • 返回CameraDeviceImpl实例

private CameraDevice openCameraDeviceUserAsync(String cameraId,... ...)
throws CameraAccessException {
//通过CamerService 获取CameraDevices的 Camera的设备信息 ,参考 二、getCameraCharacteristics 获取方法
CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
CameraDevice device = null;
... ...
// New 一个CameraDeviceImpl对象实例
android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
new android.hardware.camera2.impl.CameraDeviceImpl(
cameraId,
callback,
executor,
characteristics,
mContext.getApplicationInfo().targetSdkVersion);

ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();

try {
//判断是否支持 Camera2API
// 参考 三、supportsCamera2ApiLocked
if (supportsCamera2ApiLocked(cameraId)) {
// Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
if (cameraService == null) {
throw new ServiceSpecificException(
ICameraService.ERROR_DISCONNECTED,
"Camera service is currently unavailable");
}
//调用远程CameraService获取当前相机的远程服务
// 参考四、CameraService.connectDevice
cameraUser = cameraService.connectDevice(callbacks, cameraId,
mContext.getOpPackageName(), uid);
} else {
... ...
}
} catch (ServiceSpecificException e) {
... ...
} catch (RemoteException e) {
... ...
}

// TODO: factor out callback to be non-nested, then move setter to constructor
// For now, calling setRemoteDevice will fire initial
// onOpened/onUnconfigured callbacks.
// This function call may post onDisconnected and throw CAMERA_DISCONNECTED if
// cameraUser dies during setup.
//将获取的远程服务设置到CameraDeviceImpl实例中
// 参考 五、setRemoteDevice 方法
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;
}
//返回CameraDeviceImpl实例
return device;
}

1.4 Open Camera 大致时序图

Open Camera 时序图

二、CameraManager.getCameraCharacteristics 获取方法

getCameraCharacteristics 方法通过ICameraService.aidl 获取到 CameraService.cpp 中的getCameraCharacteristics 函数。

 public CameraCharacteristics getCameraCharacteristics(@NonNull String cameraId)
throws CameraAccessException {
CameraCharacteristics characteristics = null;

synchronized (mLock) {
/*
* Get the camera characteristics from the camera service directly if it supports it,
* otherwise get them from the legacy shim instead.
*/

//通过AIDL 调用CameraService.cpp中的函数
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();

try {
Size displaySize = getDisplaySize();

// First check isHiddenPhysicalCamera to avoid supportsCamera2ApiLocked throwing
// exception in case cameraId is a hidden physical camera.
if (!isHiddenPhysicalCamera(cameraId) && !supportsCamera2ApiLocked(cameraId)) {
// Legacy backwards compatibility path; build static info from the camera
// parameters
int id = Integer.parseInt(cameraId);

String parameters = cameraService.getLegacyParameters(id);

CameraInfo info = cameraService.getCameraInfo(id);

characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info,
id, displaySize);
} else {
// Camera2API 从 CameraService 中直接获取Camera设备信息 参考 2.1 cameraService.getCameraCharacteristics
CameraMetadataNative info = cameraService.getCameraCharacteristics(cameraId);
try {
info.setCameraId(Integer.parseInt(cameraId));
} catch (NumberFormatException e) {
Log.e(TAG, "Failed to parse camera Id " + cameraId + " to integer");
}
info.setDisplaySize(displaySize);
// new CameraCharacteristics 返回Camera设备信息
characteristics = new CameraCharacteristics(info);
}
} catch (ServiceSpecificException e) {
... ...
}
return characteristics;
}

2.1 CameraService::getCameraCharacteristics 函数

这里的CameraService.cpp(frameworks\av\services\camera\libcameraservice)

Status CameraService::getCameraCharacteristics(const String16& cameraId,
CameraMetadata* cameraInfo) {
ATRACE_CALL();
... ...
Status ret{};
// 通过 CameraProviderManger 获取Camera设备信息
// 参考2.2 CPM.getCameraCharacteristics 函数
status_t res = mCameraProviderManager->getCameraCharacteristics(
String8(cameraId).string(), cameraInfo);
... ...
int callingPid = CameraThreadState::getCallingPid();
int callingUid = CameraThreadState::getCallingUid();
std::vector<int32_t> tagsRemoved;
// If it's not calling from cameraserver, check the permission.
if ((callingPid != getpid()) &&
!checkPermission(String16("android.permission.CAMERA"), callingPid, callingUid)) {
res = cameraInfo->removePermissionEntries(
mCameraProviderManager->getProviderTagIdLocked(String8(cameraId).string()),
&tagsRemoved);
if (res != OK) {
cameraInfo->clear();
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to remove camera"
" characteristics needing camera permission for device %s: %s (%d)",
String8(cameraId).string(), strerror(-res), res);
}
}

if (!tagsRemoved.empty()) {
res = cameraInfo->update(ANDROID_REQUEST_CHARACTERISTIC_KEYS_NEEDING_PERMISSION,
tagsRemoved.data(), tagsRemoved.size());
if (res != OK) {
cameraInfo->clear();
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION, "Failed to insert camera "
"keys needing permission for device %s: %s (%d)", String8(cameraId).string(),
strerror(-res), res);
}
}

return ret;
}

2.2 CameraProviderManager::getCameraCharacteristics 函数

CameraProviderManager.cpp frameworks\av\services\camera\libcameraservice\common

status_t CameraProviderManager::getCameraCharacteristics(const std::string &id,
CameraMetadata* characteristics) const {
std::lock_guard<std::mutex> lock(mInterfaceMutex);
// 调用 CameraProviderManger 获取去Camera 设备信息方法
// 参考 2.3 CameraProviderManger.getCameraCharacteristicsLocked
return getCameraCharacteristicsLocked(id, characteristics);
}

2.3 CameraProviderManger::getCameraCharacteristicsLocked

status_t CameraProviderManager::getCameraCharacteristicsLocked(const std::string &id,
CameraMetadata* characteristics) const {
// 通过deviceinfo3 获取设备getCameraCharacteristics
// 参考 2.4 CPM.findDeviceInfoLocked函数
auto deviceInfo = findDeviceInfoLocked(id, /*minVersion*/ {3,0}, /*maxVersion*/ {5,0});
if (deviceInfo != nullptr) {
return deviceInfo->getCameraCharacteristics(characteristics);
}

// Find hidden physical camera characteristics
for (auto& provider : mProviders) {
for (auto& deviceInfo : provider->mDevices) {
status_t res = deviceInfo->getPhysicalCameraCharacteristics(id, characteristics);
if (res != NAME_NOT_FOUND) return res;
}
}

return NAME_NOT_FOUND;
}

2.4 CameraProviderManger::findDeviceInfoLocked

CameraProviderManager::ProviderInfo::DeviceInfo* CameraProviderManager::findDeviceInfoLocked(
const std::string& id,
hardware::hidl_version minVersion, hardware::hidl_version maxVersion) const {
// 通过 deviceinfo3 queryPhysicalCameraIds 查询对应id的Camera 信息
// 见 2.5 CMP.queryPhysicalCameraIds 函数
for (auto& provider : mProviders) {
for (auto& deviceInfo : provider->mDevices) {
if (deviceInfo->mId == id &&
minVersion <= deviceInfo->mVersion && maxVersion >= deviceInfo->mVersion) {
return deviceInfo.get();
}
}
}
return nullptr;
}

2.5 CameraProviderManger::queryPhysicalCameraIds 函数

void CameraProviderManager::ProviderInfo::DeviceInfo3::queryPhysicalCameraIds() {
camera_metadata_entry_t entryCap;

entryCap = mCameraCharacteristics.find(ANDROID_REQUEST_AVAILABLE_CAPABILITIES);
for (size_t i = 0; i < entryCap.count; ++i) {
uint8_t capability = entryCap.data.u8[i];
if (capability == ANDROID_REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA) {
mIsLogicalCamera = true;
break;
}
}
if (!mIsLogicalCamera) {
return;
}

camera_metadata_entry_t entryIds = mCameraCharacteristics.find(
ANDROID_LOGICAL_MULTI_CAMERA_PHYSICAL_IDS);
const uint8_t* ids = entryIds.data.u8;
size_t start = 0;
for (size_t i = 0; i < entryIds.count; ++i) {
if (ids[i] == '\0') {
if (start != i) {
mPhysicalIds.push_back((const char*)ids+start);
}
start = i+1;
}
}
}

2.6 getCameraCharacteristics 大致时序图

getCameraCharacteristics

三、supportsCamera2ApiLocked

当前CameraService 是否支持Camera2Api,如果支持,返回true,如果不支持,返回false。

supportsCamera2ApiLocked(cameraId)方法实现如下:

 private boolean supportsCamera2ApiLocked(String cameraId) {
// 参考 3.1 supportsCameraApiLocked
return supportsCameraApiLocked(cameraId, API_VERSION_2);
}

3.1 CameraManager.supportsCameraApiLocked

    private boolean supportsCameraApiLocked(String cameraId, int apiVersion) {
/*
* Possible return values:
* - NO_ERROR => CameraX API is supported
* - CAMERA_DEPRECATED_HAL => CameraX API is *not* supported (thrown as an exception)
* - Remote exception => If the camera service died
*
* Anything else is an unexpected error we don't want to recover from.
*/

try {
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
// If no camera service, no support
// 参考 3.2 CameraService supportsCameraApi 的方法
if (cameraService == null) return false;

return cameraService.supportsCameraApi(cameraId, apiVersion);
} catch (RemoteException e) {
// Camera service is now down, no support for any API level
}
return false;
}

3.2 CameraService::supportsCameraApi

Status CameraService::supportsCameraApi(const String16& cameraId, int apiVersion,
/*out*/ bool *isSupported) {
ATRACE_CALL();

const String8 id = String8(cameraId);

ALOGV("%s: for camera ID = %s", __FUNCTION__, id.string());

switch (apiVersion) {
case API_VERSION_1:
case API_VERSION_2:
break;
default:
String8 msg = String8::format("Unknown API version %d", apiVersion);
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}

int deviceVersion = getDeviceVersion(id);
switch (deviceVersion) {
case CAMERA_DEVICE_API_VERSION_1_0:
case CAMERA_DEVICE_API_VERSION_3_0:
case CAMERA_DEVICE_API_VERSION_3_1:
if (apiVersion == API_VERSION_2) {
ALOGV("%s: Camera id %s uses HAL version %d <3.2, doesn't support api2 without shim",
__FUNCTION__, id.string(), deviceVersion);
*isSupported = false;
} else { // if (apiVersion == API_VERSION_1) {
ALOGV("%s: Camera id %s uses older HAL before 3.2, but api1 is always supported",
__FUNCTION__, id.string());
*isSupported = true;
}
break;
case CAMERA_DEVICE_API_VERSION_3_2:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_5:
ALOGV("%s: Camera id %s uses HAL3.2 or newer, supports api1/api2 directly",
__FUNCTION__, id.string());
*isSupported = true;
break;
case -1: {
String8 msg = String8::format("Unknown camera ID %s", id.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_ILLEGAL_ARGUMENT, msg.string());
}
default: {
String8 msg = String8::format("Unknown device version %x for device %s",
deviceVersion, id.string());
ALOGE("%s: %s", __FUNCTION__, msg.string());
return STATUS_ERROR(ERROR_INVALID_OPERATION, msg.string());
}
}

return Status::ok();
}

四、CameraService.connectDevice

cameraService.connectDevice 会通过AIDL 调用到CameraService.cppframeworks\av\services\camera\libcameraservice

4.1 CameraService::connectDevice

连接当前的cameraDevice设备

Status CameraService::connectDevice(
const sp<hardware::camera2::ICameraDeviceCallbacks>& cameraCb,
const String16& cameraId,
const String16& clientPackageName,
int clientUid,
/*out*/
sp<hardware::camera2::ICameraDeviceUser>* device) {

ATRACE_CALL();
Status ret = Status::ok();
String8 id = String8(cameraId);
sp<CameraDeviceClient> client = nullptr;
String16 clientPackageNameAdj = clientPackageName;

if (getCurrentServingCall() == BinderCallType::HWBINDER) {
std::string vendorClient =
StringPrintf("vendor.client.pid<%d>", CameraThreadState::getCallingPid());
clientPackageNameAdj = String16(vendorClient.c_str());
}
// connectHelper 链接助手,处理连接的一些情况 比如Camera 独占,flash 预打开等
// 具体实现情况 4.2 CameraService::connectHelper
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageNameAdj,
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);

if(!ret.isOk()) {
logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageNameAdj),
ret.toString8());
return ret;
}

*device = client;
return ret;
}

4.2 CameraService::connectHelper

Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();

String8 clientName8(clientPackageName);

int originalClientPid = 0;



if (shouldRejectHiddenCameraConnection(cameraId)) {
ALOGW("Attempting to connect to system-only camera id %s, connection rejected",
cameraId.c_str());
return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
"No camera device with ID \"%s\" currently available",
cameraId.string());

}
sp<CLIENT> client = nullptr;
{
// Acquire mServiceLock and prevent other clients from connecting
std::unique_ptr<AutoConditionLock> lock =
AutoConditionLock::waitAndAcquire(mServiceLockWrapper, DEFAULT_CONNECT_TIMEOUT_NS);


// 检查当前的camera device是否可用,这儿的判断比较简单,只是简单判断当前设备是否存在
if(!(ret = validateConnectLocked(cameraId, clientName8,
/*inout*/clientUid, /*inout*/clientPid, /*out*/originalClientPid)).isOk()) {
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 ret;
}
}

status_t err;

sp<BasicClient> clientTmp = nullptr;
std::shared_ptr<resource_policy::ClientDescriptor<String8, sp<BasicClient>>> partial;
// 处理camera独占情况
if ((err = handleEvictionsLocked(cameraId, originalClientPid, effectiveApiLevel,
IInterface::asBinder(cameraCb), clientName8, /*out*/&clientTmp,
/*out*/&partial)) != NO_ERROR) {
switch (err) {
case -ENODEV:
return STATUS_ERROR_FMT(ERROR_DISCONNECTED,
"No camera device with ID \"%s\" currently available",
cameraId.string());
case -EBUSY:
return STATUS_ERROR_FMT(ERROR_CAMERA_IN_USE,
"Higher-priority client using camera, ID \"%s\" currently unavailable",
cameraId.string());
default:
return STATUS_ERROR_FMT(ERROR_INVALID_OPERATION,
"Unexpected error %s (%d) opening camera \"%s\"",
strerror(-err), err, cameraId.string());
}
}

if (clientTmp.get() != nullptr) {
// Handle special case for API1 MediaRecorder where the existing client is returned
device = static_cast<CLIENT*>(clientTmp.get());
return ret;
}

// 预备链接CameraDevices 必要时给手电筒关闭设备的机会.
mFlashlight->prepareDeviceOpen(cameraId);

int facing = -1;
//获取当前的camera device的version 版本
int deviceVersion = getDeviceVersion(cameraId, /*out*/&facing);


sp<BasicClient> tmp = nullptr;
// 我们采用的client都是CameraDeviceClient
if(!(ret = makeClient(this, cameraCb, clientPackageName,
cameraId, api1CameraId, facing,
clientPid, clientUid, getpid(),
halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
}
client = static_cast<CLIENT*>(tmp.get());

... ...

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 ret;
}

4.3 connectDevices 调用流程


connectdevices.jpg

五、CameraManager.setRemoteDevice 方法

// 参考 5.1 CameraDeviceImpl.setRemoteDevice
deviceImpl.setRemoteDevice(cameraUser);
device = deviceImpl;

5.1 CameraDeviceImpl.setRemoteDevice

CameraDeviceImpl.javaframeworks\base\core\java\android\hardware\camera2\impl
这个mRemoteDevice是应用程序进程和android camera service端之间链接的桥梁,上层操作camera的方法会通过调用mRemoteDevice来调用到camera service端来实现操作底层camera驱动的目的

    public void setRemoteDevice(ICameraDeviceUser remoteDevice) throws CameraAccessException {
synchronized(mInterfaceLock) {
// TODO: Move from decorator to direct binder-mediated exceptions
// If setRemoteFailure already called, do nothing
if (mInError) return;

mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);

IBinder remoteDeviceBinder = remoteDevice.asBinder();
// For legacy camera device, remoteDevice is in the same process, and
// asBinder returns NULL.
if (remoteDeviceBinder != null) {
try {
remoteDeviceBinder.linkToDeath(this, /*flag*/ 0);
} catch (RemoteException e) {
CameraDeviceImpl.this.mDeviceExecutor.execute(mCallOnDisconnected);

throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
"The camera device has encountered a serious error");
}
}

mDeviceExecutor.execute(mCallOnOpened);
mDeviceExecutor.execute(mCallOnUnconfigured);
}
}


相关文章友情推荐 

1. Android开发干货分享

至此,本篇已结束,如有不对的地方,欢迎您的建议与指正。同时期待您的关注,感谢您的阅读,谢谢!

点个在看,方便您使用时快速查看!

浏览 20
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报