Android 4.x_Camera新架构分析

本文探讨了Android 4.x版本中Camera架构的重大变化,包括新增Camera HAL模块以替代原有的设计,以及CameraHardwareInterface从抽象类转变为实体类。文章详细分析了Camera开机流程,并解释了Binder机制下Client和服务之间的交互。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

起源

        Camera 在android framework 设计中是遵循着 Binder 机制所设计的. 详细设计分析在网络上很多高手有在讨论, 在这里只是点出在android4.x 之后, camera 的架构流程有了哪些变化? 在这里就以 Camera的开机流程来做说明.

一般要android app要开始使用 camera都会由 android.hardware. Camera 对象中的 open函数来会得一个instance (实体).然后再用这个实体来控制相机已达到我们的需求. (ex预览,拍照,录像等).

        现在就从android.hardware. Camera 对象中的 open函数开始分析:

//Camera.java
public static Camera open(int cameraId) {
        return new Camera(cameraId);  //自从android 2.3以来, android 装置
                                   //就有分前后镜头, 所以在此需要指
                                   //定一个id来表示前后镜头.
}
 
Camera(int cameraId) {
        mShutterCallback = null;
        mRawImageCallback = null;
        mJpegCallback = null;
        mPreviewCallback = null;
        mPostviewCallback = null;
        mZoomListener = null;
       
        //用来接收来自底层的讯息
        Looper looper;
        if ((looper = Looper.myLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else if ((looper = Looper.getMainLooper()) != null) {
            mEventHandler = new EventHandler(this, looper);
        } else {
            mEventHandler = null;
        }
 
        native_setup(new WeakReference<Camera>(this), cameraId);
}


Google在android的framework设计中有分为javalayer跟native layer. 最主要是因为java 拥有一个特点, 就是开发效率会比用 nativecode来开发还快. 所以Google在android的 framework 设计就希望可以藉由java这项特点让开发app的程序员, 可以很方便也很快速的开发出一套app. 而javalayer 跟 native layer的沟通接口就是 JNI, 这是一条将 nativelayer (c/c++) 中的函数/变量转化给javalayer看得懂的接口, 当然也是一条将 javalayer 中的函数/变量转化给 nativelayer 看得懂的界面. 转化过程不是这里的重点, 因此不在这里做分析. 在androidframework中的source code 只要有 native相关字眼的函数名, 就属于 jni layer. 由上面的程序代码可以知道native_setup 函数是一个JNI的函数.

// android_hardware_Camera.cpp
// connect to camera service
static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz,
    jobject weak_this, jint cameraId)
{
    // 与Camera service 做联机.
    sp<Camera> camera = Camera::connect(cameraId);
 
    // 检查是否联机成功
    // 检查 Camera Hardware 的状态是否可用
    // 检查 java layer 呼叫者 Camera 对象是否存在
    // register listener for callback function
    sp<JNICameraContext> context = new JNICameraContext(env, weak_this,
                               clazz, camera);
    context->incStrong(thiz);
    camera->setListener(context);
}
由上面的程序代码一开始就可以发现, 要启动Camera 就要先跟CameraService联机. 理由是一开始说的Binder机制.Binder机制是简单的一个 Client 和Service的架构. 要做任何需求前,Client 是要先跟 Service 做联机. 继续分析与CameraService的联机流程.

// Camera.cpp
sp<Camera> Camera::connect(int cameraId)
{
    ALOGV("connect");
    // 1. new 一个 camera 的物件.
    sp<Camera> c = new Camera();
    // 2. 跟 system service 要一个 Camera Service 的 proxy handler.
    const sp<ICameraService>& cs = getCameraService();
    if (cs != 0) {
        //3. 利用 Camera service 的 proxy handler 将 camera 对象跟由
        // 上层传下来的id 一起往下传.
        c->mCamera = cs->connect(c, cameraId);
    }
    if (c->mCamera != 0) {
        //4. 用来注册IBinder.DeathRecipient物件.
        c->mCamera->asBinder()->linkToDeath(c);
        c->mStatus = NO_ERROR;
    } else {
        c.clear();
    }
    return c;
}
由上面的程序代码可以发现, 藉由 getCameraService 函数可以得到一个cameraservice的hanlder proxy, 这个proxy 就是一个代理人的意思. 在androidframework的设计中, 很多控制硬件的process都会由一个service的process来控制,Camera Service 正是其中之一. 在一开机的时候, ServiceManager就会去注册 android 每一个 service 以便之后统一管理. 等到需要用到某个系统的service时, 就可以藉由ServiceManger去要某个特定的service. ServiceManager在注册每一个service时, 都会有Handlerid, 这个handler id 就会对应到Handler proxy. 继续往下分析到了第三步就利用 Camera service Handler proxy 去做连结的动作. 到了第四步就去注册 IBinder.DeathRecipient物件. 这一步是属于errorhandler的动作. 类似对象里提到的例外机制.凡事都需要例外处理,Google 在设计 android framework时考虑还蛮周到的.Google 在设计 Binder 这个机制便加了例外处理. 一旦Client 跟Service之间的 Binder联机时, 只要有注册 IBinder.DeathRecipient物件. 会有一个callback函数 binderDied 会被触发. 触发流程不在这个范围. 所以点到为止. 回到第三步继续分析. 刚刚有说到是利用 CameraService handler proxy来做连结的动作, 这个链接的动作 connect函数到底是在哪个类别中定义的呢? 在这里只是介绍如何去tarcecode, 其原理是跟Binder机制有关, 哪是属于binder的原理, 所以不在这里分析. 由第三步会发现 connect函数是由 cs 带出来的. 这个cs 对象的宣告在上一行程序.

const sp<ICameraService>& cs = getCameraService();


const sp<ICameraService>& cs = getCameraService();

这一行程序代码的解读如下, 宣告一个为ICameraService数据型态strongpointer,这个strong pointer是一个指向常数的参考对象指针. 这里的strongpointer 跟 c++里的smartpointer有异曲同工之妙, 都是具有资源回收的效果. 其结构详细分析也不在这个范围内, 所以也是点到为止. 这行程序代码在这里的重点是ICameraService这个数据型态. 在android framework中,Binder的类别定义分为BnXXX, BpXXX这两个类别, 只要看到有对象是IXXX数据型态宣告, 就去找跟BnXXX类别相关的数据定义. 实作则会出现在衍生自BnXXX类别的衍生类别.所以会发现BnCameraService类别的衍生类别就是 CameraService 类别.而被呼叫的connect函数便实作在 CameraService 类别中.

// CameraService.cpp
sp<ICamera> CameraService::connect(
        const sp<ICameraClient>& cameraClient, int cameraId) {
        int callingPid = getCallingPid();
 
        LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
 
        if (!mModule) {
           ALOGE("Camera HAL module not loaded");
           return NULL;
        }
 
        sp<Client> client;
        if (cameraId < 0 || cameraId >= mNumberOfCameras) {
           ALOGE("CameraService::connect X (pid %d) rejected (invalid cameraId   
           %d).", callingPid, cameraId);
           return NULL;
        }
 
    char value[PROPERTY_VALUE_MAX];
    property_get("sys.secpolicy.camera.disabled", value, "0");
    if (strcmp(value, "1") == 0) {
        // Camera is disabled by DevicePolicyManager.
        ALOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
        return NULL;
    }
 
    Mutex::Autolock lock(mServiceLock);
    if (mClient[cameraId] != 0) {
        client = mClient[cameraId].promote();
        if (client != 0) {
            if (cameraClient->asBinder() ==
              client->getCameraClient()->asBinder()) {
                LOG1("CameraService::connect X (pid %d) (the same client)",
                     callingPid);
                return client;
            } else {
                ALOGW("CameraService::connect X (pid %d) rejected (existing
                client).",
                      callingPid);
                return NULL;
            }
        }
        mClient[cameraId].clear();
    }
 
    if (mBusy[cameraId]) {
        ALOGW("CameraService::connect X (pid %d) rejected"
                " (camera %d is still busy).", callingPid, cameraId);
        return NULL;
    }
 
    struct camera_info info;
    if (mModule->get_camera_info(cameraId, &info) != OK) {
        ALOGE("Invalid camera id %d", cameraId);
        return NULL;
    }
    //检查 Hal module api version
    int deviceVersion;
    if (mModule->common.module_api_version ==
        CAMERA_MODULE_API_VERSION_2_0) {
        deviceVersion = info.device_version;
    } else {
        deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
    }
 
    switch(deviceVersion) {
      case CAMERA_DEVICE_API_VERSION_1_0:
        client = new CameraClient(this, cameraClient, cameraId,
                info.facing, callingPid, getpid());
        break;
      case CAMERA_DEVICE_API_VERSION_2_0:
        client = new Camera2Client(this, cameraClient, cameraId,
                info.facing, callingPid, getpid());
        break;
      default:
        ALOGE("Unknown camera device HAL version: %d", deviceVersion);
        return NULL;
    }
    //初始化Camera device driver
    if (client->initialize(mModule) != OK) {
        return NULL;
    }
    //注册IBinder.DeathRecipient物件.
    cameraClient->asBinder()->linkToDeath(this);
 
    mClient[cameraId] = client;
    LOG1("CameraService::connect X (id %d, this pid is %d)", cameraId, getpid());
    return client;
}
在函数一开头便判断 mModule对象是否存在, 这个 mModule对象到底是甚么东西呢, 为何一开头就需要去做判断. 代表是一个很重要的对象. 搜寻了一下整个程序代码, 发现在 onFirstRef 函数有 mModule 的足迹.

// CameraService.cpp
void CameraService::onFirstRef()
{
    BnCameraService::onFirstRef();
 
    if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
                (const hw_module_t **)&mModule) < 0) {
        ALOGE("Could not load camera HAL module");
        mNumberOfCameras = 0;
    }
    else {
        mNumberOfCameras = mModule->get_number_of_cameras();
        if (mNumberOfCameras > MAX_CAMERAS) {
            ALOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
                    mNumberOfCameras, MAX_CAMERAS);
            mNumberOfCameras = MAX_CAMERAS;
        }
        for (int i = 0; i < mNumberOfCameras; i++) {
            setCameraFree(i);
        }
    }
}
这个onFirstRef函数算是overwrite函数, 只要有继承RefBase 类别的衍生类别都会去 overwrite onFirstRef函数来做初始化的动作. 这个onFirstRef函数初始化的动作会比建构子的初始化还更前面. 这算是strongpointer设计的功能之一. 从一开头会发现 mModule 的信息是由 hw_get_module函数提供的. 由此可知, 在camera这一块, 从android4.x开始终于有了自己的HAL module了. 在android 2.3的时候, 仍然是由一个抽象类 CameraHardwareInterface 去衍生出CameraHAL 类别. 这两个差别在于前者只要利用一个HALmodule ID CAMERA_HARDWARE_MODULE_ID 就可以跟cameradriver 沟通了, 无需要跟driverlayer 的 function 绑在一起. 后者则是还需要利用衍生的CameraHAL类别去跟 driver layer的function绑在一起才能运作, 无法达到抽换更新的流程. 而原本的抽象类 CameraHardwareInterface 在android4.x之后就变成一般的类别了.

总结

        由此可以做个总结,Android 4.x 的camera 架构跟Android2.3的camera架构有以下的差异:

1. 新增了一个 CameraHAL module来取代原本的架构.

2. 原本的 CameraHardwareInterface 抽象类演变成实体类别, 是给 CAMERA_DEVICE_API_VERSION_1_0的CameraClient 对象使用.CAMERA_DEVICE_API_VERSION_1_0 CAMERA_DEVICE_API_VERSION_2_0 的差别在于前者算是过渡期..CAMERA_DEVICE_API_VERSION_1_0 CAMERA_DEVICE_API_VERSION_2_0的定义如下:

// camera_common.h
#define CAMERA_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VERSION(1, 0)
#define CAMERA_MODULE_API_VERSION_2_0 HARDWARE_MODULE_API_VERSION(2, 0)
 

3. HAL 的结构进板, 这算是属于在HALmodule design的范围内, 不过既然CameraService的connect 函数有用到Hal module,

// CameraService.cpp
    int deviceVersion;
    if (mModule->common.module_api_version ==
        CAMERA_MODULE_API_VERSION_2_0) {
        deviceVersion = info.device_version;
    } else {
        deviceVersion = CAMERA_DEVICE_API_VERSION_1_0;
    }

所以这里就把进板的新数据型态贴出来.

/**
 * Every hardware module must have a data structure named
 * HAL_MODULE_INFO_SYM
 * and the fields of this data structure must begin with hw_module_t
 * followed by module specific information.
 */
typedef struct hw_module_t {
    /** tag must be initialized to HARDWARE_MODULE_TAG */
    uint32_t tag;
 
    /**
     * The API version of the implemented module. The module owner is
     * responsible for updating the version when a module interface has
     * changed.
     *
     * The derived modules such as gralloc and audio own and manage this field.
     * The module user must interpret the version field to decide whether or
     * not to inter-operate with the supplied module implementation.
     * For example, SurfaceFlinger is responsible for making sure that
     * it knows how to manage different versions of the gralloc-module API,
     * and AudioFlinger must know how to do the same for audio-module API.
     *
     * The module API version should include a major and a minor component.
     * For example, version 1.0 could be represented as 0x0100. This format
     * implies that versions 0x0100-0x01ff are all API-compatible.
     *
     * In the future, libhardware will expose a hw_get_module_version()
     * (or equivalent) function that will take minimum/maximum supported
     * versions as arguments and would be able to reject modules with
     * versions outside of the supplied range.
     */
    uint16_t module_api_version;
#define version_major module_api_version
    /**
     * version_major/version_minor defines are supplied here for temporary
     * source code compatibility. They will be removed in the next version.
     * ALL clients must convert to the new version format.
     */
 
    /**
     * The API version of the HAL module interface. This is meant to
     * version the hw_module_t, hw_module_methods_t, and hw_device_t
     * structures and definitions.
     *
     * The HAL interface owns this field. Module users/implementations
     * must NOT rely on this value for version information.
     *
     * Presently, 0 is the only valid value.
     */
    uint16_t hal_api_version;
#define version_minor hal_api_version
 
    /** Identifier of module */
    const char *id;
 
    /** Name of this module */
    const char *name;
 
    /** Author/owner/implementor of the module */
    const char *author;
 
    /** Modules methods */
    struct hw_module_methods_t* methods;
 
    /** module's dso */
    void* dso;
 
    /** padding to 128 bytes, reserved for future use */
    uint32_t reserved[32-7];
 
} hw_module_t;

<think>好的,用户现在想用CameraX库实现USB摄像头的预览访问,需要最简单的示例代码。我之前已经提供了关于UVCCamera兼容性问题和解决方案的回答,现在需要结合用户提供的引用内容来给出具体实现步骤。 首先,用户引用了[3],里面提到了CameraX的依赖项,所以第一步应该是添加正确的依赖。需要确认用户的项目中已经包含了CameraX的核心库、Camera2实现以及USB扩展库。用户可能容易忽略USB扩展库,所以要特别指出。 接下来,用户提到要使用USB摄像头,这意味着需要处理USB权限。根据之前的回答,引用[1]中提到了CameraSelector来选择前后摄像头,但USB摄像头可能需要不同的处理方式。可能需要动态请求USB权限,类似用户之前提到的USB设备权限获取代码。但CameraX可能有更简化的方式,比如自动检测USB设备,但可能需要用户确认权限。 然后,CameraX的架构通常包括ProcessCameraProvider,绑定生命周期到LifecycleOwner。这里需要配置CameraSelector,但普通的选择器可能无法识别USB摄像头。根据引用[3],可能需要使用CameraX的扩展库,比如camera-usb扩展,来支持外接设备。用户需要正确配置CameraSelector,可能通过设备ID或类型来指定USB摄像头。 在预览方面,用户需要创建Preview用例,并绑定到视图,比如TextureView或PreviewView。这里可能需要设置SurfaceProvider,将预览画面显示出来。同时,需要处理摄像头可用性,比如在设备连接或断开时的回调。 用户可能遇到的问题包括USB设备未正确识别、权限未获取、视图未正确绑定等。需要在示例代码中包含错误处理和日志输出,方便调试。例如,在枚举摄像头设备时,过滤出USB类型,并检查是否有支持的摄像头。 另外,参考用户之前的问题,他们提到UVCCamera的兼容性问题,所以可能需要比较CameraX和UVCCamera的不同,指出CameraX的优势,比如更好的兼容性和生命周期管理。 最后,确保代码示例简洁,步骤明确,覆盖权限声明、依赖添加、摄像头选择、预览绑定等关键点。同时,提醒用户在实际应用中的注意事项,比如Android版本差异、设备兼容性测试等。</think>以下是使用CameraX实现USB摄像头预览访问的完整示例方案,综合引用内容和Android实践: ### 一、基础配置 1. **Gradle依赖配置**(引用[3]扩展) ```gradle dependencies { def camerax_version = "1.3.0" implementation "androidx.camera:camera-core:${camerax_version}" implementation "androidx.camera:camera-camera2:${camerax_version}" implementation "androidx.camera:camera-lifecycle:${camerax_version}" implementation "androidx.camera:camera-view:${camerax_version}" implementation "androidx.camera:camera-extensions:${camerax_version}" implementation "androidx.camera:camera-usb:${camerax_version}" // USB扩展库 } ``` ### 二、核心实现代码 ```kotlin class USBCameraActivity : AppCompatActivity() { private lateinit var cameraProvider: ProcessCameraProvider private val executor = Executors.newSingleThreadExecutor() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_camera) val previewView: PreviewView = findViewById(R.id.preview_view) // 异步初始化CameraProvider val cameraProviderFuture = ProcessCameraProvider.getInstance(this) cameraProviderFuture.addListener({ cameraProvider = cameraProviderFuture.get() // 检测USB摄像头(引用[4]设备枚举原理) val cameraSelector = getUSBCameraSelector() ?: return@addListener // 配置预览用例 val preview = Preview.Builder() .setTargetResolution(Size(1280, 720)) .build() .also { it.setSurfaceProvider(previewView.surfaceProvider) } try { cameraProvider.unbindAll() cameraProvider.bindToLifecycle( this, cameraSelector, preview ) } catch(exc: Exception) { Log.e("CameraX", "Use case binding failed", exc) } }, ContextCompat.getMainExecutor(this)) } private fun getUSBCameraSelector(): CameraSelector? { return cameraProvider.availableCameraInfos .firstOrNull { // 检测USB接口设备(引用[4]硬件特征) (it as Camera2CameraInfo).cameraCharacteristics[CameraCharacteristics.LENS_FACING] == CameraMetadata.LENS_FACING_EXTERNAL }?.let { CameraSelector.Builder().addCameraFilter { listOf(it) }.build() } } } ``` ### 三、布局文件 ```xml <!-- res/layout/activity_camera.xml --> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <androidx.camera.view.PreviewView android:id="@+id/preview_view" android:layout_width="match_parent" android:layout_height="match_parent" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> ``` ### 四、关键配置补充 1. **AndroidManifest权限声明**(引用[2]基础配置) ```xml <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.USB_PERMISSION" /> <uses-feature android:name="android.hardware.camera.any" /> <uses-feature android:name="android.hardware.usb.host" /> ``` 2. **USB设备检测增强**(结合引用[4]硬件特征) ```kotlin private fun checkUSBCameraSupport(): Boolean { val usbManager = getSystemService(Context.USB_SERVICE) as UsbManager return usbManager.deviceList.values.any { it.deviceClass == UsbConstants.USB_CLASS_VIDEO } } ``` ### 五、功能特性说明 1. **自动分辨率适配**(引用[4]分辨率配置原理) - 通过`setTargetResolution()`指定期望分辨率 - 系统自动选择最接近的可用分辨率 2. **多设备兼容**(引用[1]选择器机制) - 自动检测`LENS_FACING_EXTERNAL`类型设备 - 支持通过VID/PID过滤特定设备 3. **生命周期管理**(引用[3]生命周期绑定) - 自动处理Activity/Fragment生命周期 - 设备断开时自动释放资源 建议调试时使用`adb shell dumpsys usb`命令确认USB摄像头连接状态,并通过CameraX的`CameraInfo`接口获取设备详细信息。若需更高级控制,可参考Camera2 API的扩展实现(引用[2]示例项目)[^3][^4]。 --相关问题-- 1. 如何实现USB摄像头与内置摄像头的快速切换? 2. CameraX如何处理多个外接USB摄像头的情况? 3. 怎样在CameraX中实现USB摄像头的参数自定义配置?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值