Android 源码 Camera2 获取 CameraId 列表

获取 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() 返回或创建当前连接的相机设备列表。如果连接到相机服务出现错误,将返回一个空列表。

  1. 获取 CameraService 服务代理
  2. 获取 Camera 个数
  3. 获取描述每个 Camera 的元信息
  4. 将 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();    
    ......
}
  1. 获取 CameraService 服务代理
  2. 获取 VendorTagDescriptor
  3. 调用 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;
    }
}
tyyj90 CSDN认证博客专家 安卓全栈开发
Android高级开发工程师,熟悉App开发,熟悉Framework定制开发,略了解Linux内核。开发使用的语言涉及Java、Kotlin、C/C++、Python和汇编NEON指令集。
©️2020 CSDN 皮肤主题: 像素格子 设计师:CSDN官方博客 返回首页
实付 9.90元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值