android 获取当前设备有多少个摄像头 android 获取摄像头 ID
获取 CameraId 列表通过调用 CameraManager 类 getCameraIdList() 实现。
getCameraIdList() 按标识符返回当前连接的摄像头设备列表,包括其他 camera API 客户端可能正在使用的摄像头。
不可移动摄像头的标识符使用以 0 开头的整数,而可移动摄像头即使是同一型号,也为每个设备都分配唯一的标识符。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......
@NonNull
public String[] getCameraIdList() throws CameraAccessException {
synchronized (mLock) {
// 创建 ID 列表可处理设备枚举中的各种已知故障,
// 因此只有它抛出的异常是意外的,并且应该向上传播。
return getOrCreateDeviceIdListLocked().toArray(new String[0]);
}
}
......
}
getOrCreateDeviceIdListLocked() 返回或创建当前连接的相机设备列表。如果连接到相机服务出现错误,将返回一个空列表。
- 获取 CameraService 服务代理
- 获取 Camera 个数
- 获取描述每个 Camera 的元信息
- 将 Camera 从 0 开始的整数标识符添加到设备 ID 列表
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......
private ArrayList<String> mDeviceIdList;
......
private ArrayList<String> getOrCreateDeviceIdListLocked() throws CameraAccessException {
if (mDeviceIdList == null) {
int numCameras = 0;
// 1. 获取 CameraService
ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
ArrayList<String> deviceIdList = new ArrayList<>();
// 如果 CameraService 为 null,返回空列表
if (cameraService == null) {
return deviceIdList;
}
try {
// 2. 获取 Camera 个数
numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
} catch(CameraRuntimeException e) {
throw e.asChecked();
} catch (RemoteException e) {
// camera service just died - if no camera service, then no devices
return deviceIdList;
}
CameraMetadataNative info = new CameraMetadataNative();
for (int i = 0; i < numCameras; ++i) {
// 不可移动摄像头使用从 0 开始的整数作为标识符
boolean isDeviceSupported = false;
try {
// 3. 获取描述 Camera 元信息
cameraService.getCameraCharacteristics(i, info);
if (!info.isEmpty()) {
isDeviceSupported = true;
} else {
throw new AssertionError("Expected to get non-empty characteristics");
}
} catch(IllegalArgumentException e) {
// 从服务获得 BAD_VALUE,表示不支持此设备。
} catch(CameraRuntimeException e) {
// DISCONNECTED 意味着 HAL 在获取设备信息时报告了一个底层错误;
// 跳过设备。其他错误,继续传播异常。
if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
throw e.asChecked();
}
} catch(RemoteException e) {
// 相机服务死亡,没有设备列出
deviceIdList.clear();
return deviceIdList;
}
if (isDeviceSupported) {
// 4. 将 Camera 从 0 开始的整数标识符添加到设备 ID 列表
deviceIdList.add(String.valueOf(i));
} else {
Log.w(TAG, "Error querying camera device " + i + " for listing.");
}
}
mDeviceIdList = deviceIdList;
}
return mDeviceIdList;
}
......
}
获取 CameraService,首先调用了 CameraManager 类内部静态类 CameraManagerGlobal 的 get() 方法获取 CameraManagerGlobal 单例对象。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......
private static final class CameraManagerGlobal extends ICameraServiceListener.Stub
implements IBinder.DeathRecipient {
......
// Singleton instance
private static final CameraManagerGlobal gCameraManager =
new CameraManagerGlobal();
......
// Singleton, don't allow construction
private CameraManagerGlobal() {
}
public static CameraManagerGlobal get() {
return gCameraManager;
}
......
}
......
}
然后调用 CameraManagerGlobal 对象的 getCameraService() 方法获取 CameraService(实现了 ICameraService 接口)。getCameraService() 方法内部调用 connectCameraServiceLocked() 处理。如果相机服务当前不可用,则为 null。如果自上次使用相机服务以来相机服务已失效,则将尝试重新连接该服务。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......
private static final class CameraManagerGlobal extends ICameraServiceListener.Stub
implements IBinder.DeathRecipient {
......
public ICameraService getCameraService() {
synchronized(mLock) {
connectCameraServiceLocked();
if (mCameraService == null) {
Log.e(TAG, "Camera service is unavailable");
}
return mCameraService;
}
}
......
}
......
}
连接到 CameraService(如果有),并设置侦听器。 如果服务已经连接,则什么也不做。将 mCameraService 设置为有效的指针;如果连接失败,则将其设置为 null。
frameworks/base/core/java/android/hardware/camera2/CameraManager.java
public final class CameraManager {
......
private static final class CameraManagerGlobal extends ICameraServiceListener.Stub
implements IBinder.DeathRecipient {
......
private void connectCameraServiceLocked() {
// 只有在必要时才重新连接
if (mCameraService != null) return;
Log.i(TAG, "Connecting to camera service");
// 从 ServiceManager 中查询并获取 CameraService Binder 对象
IBinder cameraServiceBinder = ServiceManager.getService(CAMERA_SERVICE_BINDER_NAME);
if (cameraServiceBinder == null) {
// CameraService 现在已经关闭,将 mCameraService 设置为 null
return;
}
try {
// 为 Binder 对象设置死亡代理
cameraServiceBinder.linkToDeath(this, /*flags*/ 0);
} catch (RemoteException e) {
// CameraService 现在已经关闭,将 mCameraService 设置为 null
return;
}
// 将 Binder 对象转化为 CameraService
ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
/**
* 将 CameraService 包装在装饰器中,该装饰器会自动将返回码转换为异常。
*/
ICameraService cameraService =
CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
try {
// 设置供应商标签
CameraServiceBinderDecorator.throwOnError(
CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
} catch (CameraRuntimeException e) {
handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
}
try {
// 添加监听器
cameraService.addListener(this);
mCameraService = cameraService;
} catch(CameraRuntimeException e) {
// 意外故障
throw new IllegalStateException("Failed to register a camera service listener",
e.asChecked());
} catch (RemoteException e) {
// CameraService 现在已经关闭,将 mCameraService 设置为 null
}
}
......
}
......
}
mediaserver 中运行的本地摄像头服务的 Binder 接口。
frameworks/base/core/java/android/hardware/ICameraService.aidl
interface ICameraService
{
/**
* Keep up-to-date with frameworks/av/include/camera/ICameraService.h
*/
int getNumberOfCameras(int type);
......
int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
......
// 确定是否支持特定的 API 版本;参见 ICameraService.h 了解版本定义
int supportsCameraApi(int cameraId, int apiVersion);
......
}
接下来研究一下设置供应商标签。nativeSetupGlobalVendorTagDescriptor() 是个 jni 方法。它设置全局客户端供应商标签描述符,以允许在相机应用程序中使用供应商标签。
frameworks/base/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
public class CameraMetadataNative implements Parcelable {
......
public static native int nativeSetupGlobalVendorTagDescriptor();
......
}
- 获取 CameraService 服务代理
- 获取 VendorTagDescriptor
- 调用 VendorTagDescriptor setAsGlobalVendorTagDescriptor(…) 设置供应商标签
frameworks/base/core/jni/android_hardware_camera2_CameraMetadata.cpp
static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
const String16 NAME("media.camera");
sp<ICameraService> cameraService;
// 1. 获取 CameraService
status_t err = getService(NAME, /*out*/&cameraService);
if (err != OK) {
ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
strerror(-err), err);
return err;
}
sp<VendorTagDescriptor> desc;
// 2. 获取 VendorTagDescriptor
err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
if (err == -EOPNOTSUPP) {
// Camera HAL 太旧了,不支持供应商标签
ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
VendorTagDescriptor::clearGlobalVendorTagDescriptor();
return OK;
} else if (err != OK) {
ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
__FUNCTION__, strerror(-err), err);
return err;
}
// 3. 设置供应商标签
err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
return err;
}
getNumberOfCameras(…)、getCameraCharacteristics(…) 和 getCameraVendorTagDescriptor(…) 三个方法都调用了远端实现。现在拿 getNumberOfCameras(…) 方法作为例子分析一下。结合前面 Native CameraService 启动过程,不难知道入口点在 BpCameraService 中。
frameworks/av/camera/ICameraService.cpp
class BpCameraService: public BpInterface<ICameraService>
{
public:
BpCameraService(const sp<IBinder>& impl)
: BpInterface<ICameraService>(impl)
{
}
// get number of cameras available that support standard camera operations
virtual int32_t getNumberOfCameras()
{
// CAMERA_TYPE_BACKWARD_COMPATIBLE 代表向后兼容的类型
return getNumberOfCameras(CAMERA_TYPE_BACKWARD_COMPATIBLE);
}
// get number of cameras available of a given type
virtual int32_t getNumberOfCameras(int type)
{
Parcel data, reply;
data.writeInterfaceToken(ICameraService::getInterfaceDescriptor());
data.writeInt32(type);
remote()->transact(BnCameraService::GET_NUMBER_OF_CAMERAS, data, &reply);
if (readExceptionCode(reply)) return 0;
return reply.readInt32();
}
......
}
BpCameraService 类中的 getNumberOfCameras() 方法最终调用了其重载版本的方法 getNumberOfCameras(int type)。最终会在 BnCameraService 类得到处理,CameraService 继承了 BnCameraService 类,实际是在 CameraService 中得到处理的。首先在 BnCameraService 类 onTransact 方法中收到写过来的数据。然后在其中调用了 getNumberOfCameras(…) 作为返回值又给客户端写了回去。
frameworks/av/camera/ICameraService.cpp
status_t BnCameraService::onTransact(
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
switch(code) {
case GET_NUMBER_OF_CAMERAS: {
CHECK_INTERFACE(ICameraService, data, reply);
reply->writeNoException();
reply->writeInt32(getNumberOfCameras(data.readInt32()));
return NO_ERROR;
} break;
......
}
}
CameraService 类 getNumberOfCameras(…) 只是简单的返回了 mNumberOfNormalCameras 成员变量的值。这个值是在 CameraService 类 onFirstRef() 方法中赋值的,具体可以参见《Android 源码 Camera2 CameraService 启动》一节。
frameworks/av/services/camera/libcameraservice/CameraService.cpp
int32_t CameraService::getNumberOfCameras(int type) {
ATRACE_CALL();
switch (type) {
case CAMERA_TYPE_BACKWARD_COMPATIBLE:
return mNumberOfNormalCameras;
case CAMERA_TYPE_ALL:
return mNumberOfCameras;
default:
ALOGW("%s: Unknown camera type %d, returning 0",
__FUNCTION__, type);
return 0;
}
}
上一篇: 电阻式触摸屏原理简介
下一篇: DLNA 和 UPnP 开发说明 (2)