高通 Camera API: Camera.getNumberOfCameras()分析
背景
最近调试的高通设备 有前摄 后摄 扫描头 三个camera设备
但是app 使用接口 Camera.getNumberOfCameras()的返回值为2. 出于好奇 看了一下接口源码实现
接口实现分析
/**
* Returns the number of physical cameras available on this device.
* The return value of this method might change dynamically if the device
* supports external cameras and an external camera is connected or
* disconnected.
*
* If there is a
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
* logical multi-camera} in the system, to maintain app backward compatibility, this method will
* only expose one camera per facing for all logical camera and physical camera groups.
* Use camera2 API to see all cameras.
*
* @return total number of accessible camera devices, or 0 if there are no
* cameras or an error was encountered enumerating them.
*/
public static int getNumberOfCameras() {
boolean exposeAuxCamera = false;
String packageName = ActivityThread.currentOpPackageName();
/* Force to expose only two cameras
* if the package name does not falls in this bucket
*/
String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
if (packageList.length() > 0) {
TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
splitter.setString(packageList);
for (String str : splitter) {
if (packageName.equals(str)) {
exposeAuxCamera = true;
break;
}
}
}
int numberOfCameras = _getNumberOfCameras();
if (exposeAuxCamera == false && (numberOfCameras > 2)) {
numberOfCameras = 2;
}
return numberOfCameras;
}
/**
* Returns the number of physical cameras available on this device.
*/
/** @hide */
public native static int _getNumberOfCameras();
作为对比 AOSP的代码如下:
/**
* Returns the number of physical cameras available on this device.
* The return value of this method might change dynamically if the device
* supports external cameras and an external camera is connected or
* disconnected.
*
* If there is a
* {@link android.hardware.camera2.CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES_LOGICAL_MULTI_CAMERA
* logical multi-camera} in the system, to maintain app backward compatibility, this method will
* only expose one camera per facing for all logical camera and physical camera groups.
* Use camera2 API to see all cameras.
*
* @return total number of accessible camera devices, or 0 if there are no
* cameras or an error was encountered enumerating them.
*/
public native static int getNumberOfCameras();
我们可以看到 高通的实现做了一层简单的封装
AOSP中获取物理设备的接口加入了_前缀变为隐藏起开
对app开放的是高通封装后的实现
在这个封装中 加入了一个属性 “vendor.camera.aux.packagelist”
只有在这个属性中定义的应用才能获得超过2个的摄像头
默认这个属性只有高通的骁龙相机
#Expose aux camera for below packages
vendor.camera.aux.packagelist=org.codeaurora.snapcam
其他app,当设备camera设备超过3个的时候,只能获得2个的结果
为什么?
拙以为 这个接口是针对手机的物理形态适配的 一个前摄 一个后摄。 多余三个的情况多余的情况大概率是后摄的多镜头 可以看做一个设备
如何处理?
如果想单独使用扫描头作为物理设备:
可以如下尝试操作来打开
try {
Method openMethod = Class.forName("android.hardware.Camera").getMethod(
"openLegacy", int.class, int.class);
mCamera = (android.hardware.Camera) openMethod.invoke(
null, 2, CAMERA_HAL_API_VERSION_1_0);
mCamera.setDisplayOrientation(oritationAdjust);
} catch (Exception e) {
/* Retry with open if openLegacy doesn't exist/fails */
Log.v(TAG, "openLegacy failed due to " + e.getMessage()
+ ", using open instead");
mCamera = android.hardware.Camera.open(2);
}
拓展
类似的接口还有
CameraManager.getCameraIdList()
/**
* Get a list of all camera IDs that are at least PRESENT; ignore devices that are
* NOT_PRESENT or ENUMERATING, since they cannot be used by anyone.
*/
public String[] getCameraIdList() {
String[] cameraIds = null;
synchronized(mLock) {
// Try to make sure we have an up-to-date list of camera devices.
connectCameraServiceLocked();
boolean exposeAuxCamera = false;
String packageName = ActivityThread.currentOpPackageName();
String packageList = SystemProperties.get("vendor.camera.aux.packagelist");
if (packageList.length() > 0) {
TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
splitter.setString(packageList);
for (String str : splitter) {
if (packageName.equals(str)) {
exposeAuxCamera = true;
break;
}
}
}
int idCount = 0;
for (int i = 0; i < mDeviceStatus.size(); i++) {
if(!exposeAuxCamera && (i == 2)) break;
int status = mDeviceStatus.valueAt(i);
if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
status == ICameraServiceListener.STATUS_ENUMERATING) continue;
idCount++;
}
cameraIds = new String[idCount];
idCount = 0;
for (int i = 0; i < mDeviceStatus.size(); i++) {
if(!exposeAuxCamera && (i == 2)) break;
int status = mDeviceStatus.valueAt(i);
if (status == ICameraServiceListener.STATUS_NOT_PRESENT ||
status == ICameraServiceListener.STATUS_ENUMERATING) continue;
cameraIds[idCount] = mDeviceStatus.keyAt(i);
idCount++;
}
}
// The sort logic must match the logic in
// libcameraservice/common/CameraProviderManager.cpp::getAPI1CompatibleCameraDeviceIds
Arrays.sort(cameraIds, new Comparator<String>() {
@Override
public int compare(String s1, String s2) {
int s1Int = 0, s2Int = 0;
try {
s1Int = Integer.parseInt(s1);
} catch (NumberFormatException e) {
s1Int = -1;
}
try {
s2Int = Integer.parseInt(s2);
} catch (NumberFormatException e) {
s2Int = -1;
}
// Uint device IDs first
if (s1Int >= 0 && s2Int >= 0) {
return s1Int - s2Int;
} else if (s1Int >= 0) {
return -1;
} else if (s2Int >= 0) {
return 1;
} else {
// Simple string compare if both id are not uint
return s1.compareTo(s2);
}
}});
return cameraIds;
}