android camera API1调用camera HAL3流程学习总结

本文深入解析了Android系统中相机API1如何与HAL3版本的硬件抽象层兼容工作,详细介绍了从调用opencamera、startpreview、takepicture到设置和获取参数的整个流程,揭示了Camera2Client与Camera3Device在API1+HAL3环境下的角色与功能。

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

从AndroidP 开始,高通camera系统全面使用HAL3,之前的HAL1已经被移除,对应HAL3主流的相机开发接口是camera API2 ,但是依然存在大量的使用Camera API 1开发的相机应用,为此Android专门设计了一套兼容API1调用HAL3的中间转换接口,本门主要从几个方面简要介绍下这部分相关的知识。**

  • opencamera
  • startpreview
  • takepicture
  • setparameter、getparameter

1. opencamera

相机应用在调用

Camera open(int cameraId)

时, 经过Binder IPC进入CameraService.cpp,调用的接口是

CameraService::connectHelper(....){
    ALOGI("CameraService::connect call (PID %d \"%s\", camera ID %s) for HAL version %s and "
           "Camera API version %d");

ret = makeClient(......))

err <span class="token operator">=</span> client<span class="token operator">-&gt;</span><span class="token function">initialize</span><span class="token punctuation">(</span>mCameraProviderManager<span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token comment">//重点分析</span>

}

通过makeClient会创建相应的client

Status CameraService::makeClient(.....) {
         ......
        // Default path: HAL version is unspecified by caller, create CameraClient
        // based on device version reported by the HAL.
        switch(deviceVersion) {
             //Android P 之后不再存在CAMERA_DEVICE_API_VERSION_1_0
          case CAMERA_DEVICE_API_VERSION_1_0:
            if (effectiveApiLevel == API_1) {  // Camera1 API route 
                *client = new CameraClient(....),
            } else { // Camera2 API route
            }
            break;
          case CAMERA_DEVICE_API_VERSION_3_0:
          case CAMERA_DEVICE_API_VERSION_3_1:
          case CAMERA_DEVICE_API_VERSION_3_2:
          case CAMERA_DEVICE_API_VERSION_3_3:
          case CAMERA_DEVICE_API_VERSION_3_4:
            //API1+HAL3 对应的client
            if (effectiveApiLevel == API_1) { // Camera1 API route
                *client = new Camera2Client(.....);
            } else { // Camera2 API route
                //API2+HAL3 对应的client
                *client = new CameraDeviceClient(.....);
            }
            break;
          default:
            // Should not be reachable
            ALOGE("Unknown camera device HAL version: %d", deviceVersion);
            .....
        }
}

通过上述代码分析发现API1+HAL3对用的client是Camera2Client
其类图如下:
在这里插入图片描述
从上边看Camera2Client继承实现了ICamera定义的camera API1接口,但是其内部的成员变量mDevice是`Camera3Device 类型,其是针对HAL3设计的,其类的备注如下:

/**
 * CameraDevice for HAL devices with version CAMERA_DEVICE_API_VERSION_3_0 or higher.
 */
class Camera3Device :
            public CameraDeviceBase,
            virtual public hardware::camera::device::V3_2::ICameraDeviceCallback,
            private camera3_callback_ops

Camera3Device类图如下:

在这里插入图片描述
Camera3Device内部类HalInterface中的sp<hardware::camera::device::V3_2::ICameraDeviceSession>mHidlSession成员变量,是在opencamera是获取的对象,之后所有的constructDefaultRequestSettings,configureStreams等操作,都是通过该对象与HAL3进行通信完成的。
下边给出ICameraDeviceSession类图:
在这里插入图片描述
该类是定义在hardware\interfaces\camera\device中,是cameraservice与cameraprovider通信的接口。
下边分析 openCamera具体流程
在这里插入图片描述
从流程图上看,opencamera主要完成了两件事:

  • makeclient 创建camera2client对象及Camera3Device对象
  • 初始化camera2client,真正完成打开相机的地方

    从上述过程看,Camera2Client实现的是Camera API1的接口,在opencamera时,通过Camera3Device中的BpHwCameraDevice类型对象deviceInfo3->mInterface的open方法完成与HAL3通信来打开相机,并该方法返回结果为ICameraDeviceSession类型对象session,表示相机成功打开,之后所有的相机相关操作全是通过该对象完成。

2. startpreview

startPreview时序图如下:
在这里插入图片描述
从上述时序图看,startpreive过程主要有两个过程,

  • configureStreams
  • 将request插入到mRepeatingRequests队列中,并启动RequestThread,向HAL层不断发送processCaptureRequest申请

3. takepicture

开启相机后会启动一个拍照处理线程mCaptureSequencer:

template<typename TProviderPtr>
status_t Camera2Client::initializeImpl(TProviderPtr providerPtr)
{
    ATRACE_CALL();
    ALOGV("%s: Initializing client for camera %d", __FUNCTION__, mCameraId);
    status_t res;
res <span class="token operator">=</span> Camera2ClientBase<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">initialize</span><span class="token punctuation">(</span>providerPtr<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>

#ifdef USE_QTI_CAMERA2CLIENT
mQTICamera2Client = new QTICamera2Client(this);
#endif

mStreamingProcessor <span class="token operator">=</span> new <span class="token function">StreamingProcessor</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">;</span>
threadName <span class="token operator">=</span> String8<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"C2-%d-StreamProc"</span><span class="token punctuation">,</span>
        mCameraId<span class="token punctuation">)</span><span class="token punctuation">;</span>

mFrameProcessor <span class="token operator">=</span> new <span class="token function">FrameProcessor</span><span class="token punctuation">(</span>mDevice<span class="token punctuation">,</span> this<span class="token punctuation">)</span><span class="token punctuation">;</span>
threadName <span class="token operator">=</span> String8<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"C2-%d-FrameProc"</span><span class="token punctuation">,</span>
        mCameraId<span class="token punctuation">)</span><span class="token punctuation">;</span>
mFrameProcessor<span class="token operator">-&gt;</span><span class="token function">run</span><span class="token punctuation">(</span>threadName<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//创建拍照处理线程并启动</span>
mCaptureSequencer <span class="token operator">=</span> new <span class="token function">CaptureSequencer</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">;</span>
threadName <span class="token operator">=</span> String8<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"C2-%d-CaptureSeq"</span><span class="token punctuation">,</span>
        mCameraId<span class="token punctuation">)</span><span class="token punctuation">;</span>
mCaptureSequencer<span class="token operator">-&gt;</span><span class="token function">run</span><span class="token punctuation">(</span>threadName<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

mJpegProcessor <span class="token operator">=</span> new <span class="token function">JpegProcessor</span><span class="token punctuation">(</span>this<span class="token punctuation">,</span> mCaptureSequencer<span class="token punctuation">)</span><span class="token punctuation">;</span>
threadName <span class="token operator">=</span> String8<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"C2-%d-JpegProc"</span><span class="token punctuation">,</span>
        mCameraId<span class="token punctuation">)</span><span class="token punctuation">;</span>
mJpegProcessor<span class="token operator">-&gt;</span><span class="token function">run</span><span class="token punctuation">(</span>threadName<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

#ifdef USE_QTI_CAMERA2CLIENT
mRawProcessor = new RawProcessor(this, mCaptureSequencer);
threadName = String8::format(“C2-%d-RawProc”,
mCameraId);
mRawProcessor->run(threadName.string());
#endif

mZslProcessor <span class="token operator">=</span> new <span class="token function">ZslProcessor</span><span class="token punctuation">(</span>this<span class="token punctuation">,</span> mCaptureSequencer<span class="token punctuation">)</span><span class="token punctuation">;</span>

threadName <span class="token operator">=</span> String8<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"C2-%d-ZslProc"</span><span class="token punctuation">,</span>
        mCameraId<span class="token punctuation">)</span><span class="token punctuation">;</span>
mZslProcessor<span class="token operator">-&gt;</span><span class="token function">run</span><span class="token punctuation">(</span>threadName<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

mCallbackProcessor <span class="token operator">=</span> new <span class="token function">CallbackProcessor</span><span class="token punctuation">(</span>this<span class="token punctuation">)</span><span class="token punctuation">;</span>
threadName <span class="token operator">=</span> String8<span class="token punctuation">:</span><span class="token punctuation">:</span><span class="token function">format</span><span class="token punctuation">(</span><span class="token string">"C2-%d-CallbkProc"</span><span class="token punctuation">,</span>
        mCameraId<span class="token punctuation">)</span><span class="token punctuation">;</span>
mCallbackProcessor<span class="token operator">-&gt;</span><span class="token function">run</span><span class="token punctuation">(</span>threadName<span class="token punctuation">.</span><span class="token function">string</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span>
<span class="token keyword">return</span> OK<span class="token punctuation">;</span>

}

线程中包含有一个状态机,不断检测是否有拍照命令下发,
状态机状态定义如下:

    enum CaptureState {
        IDLE,
        START,
        ZSL_START,
        ZSL_WAITING,
        ZSL_REPROCESSING,
        STANDARD_START,
        STANDARD_PRECAPTURE_WAIT,
        STANDARD_CAPTURE,
        STANDARD_CAPTURE_WAIT,
        DONE,
        ERROR,
        NUM_CAPTURE_STATES
    } mCaptureState;

对应的状态处理函数定义如下:

const CaptureSequencer::StateManager
        CaptureSequencer::kStateManagers[CaptureSequencer::NUM_CAPTURE_STATES-1] = {
    &CaptureSequencer::manageIdle,
    &CaptureSequencer::manageStart,
    &CaptureSequencer::manageZslStart,
    &CaptureSequencer::manageZslWaiting,
    &CaptureSequencer::manageZslReprocessing,
    &CaptureSequencer::manageStandardStart,
    &CaptureSequencer::manageStandardPrecaptureWait,
    &CaptureSequencer::manageStandardCapture,
    &CaptureSequencer::manageStandardCaptureWait,
    &CaptureSequencer::manageDone,
};

在有拍照命令下发时,状态机进入下一状态START,否则一直停留在IDLE状态


bool CaptureSequencer::threadLoop() {
sp<span class="token operator">&lt;</span>Camera2Client<span class="token operator">&gt;</span> client <span class="token operator">=</span> mClient<span class="token punctuation">.</span><span class="token function">promote</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>client <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token keyword">return</span> false<span class="token punctuation">;</span>

CaptureState currentState<span class="token punctuation">;</span>
<span class="token punctuation">{</span>
    Mutex<span class="token punctuation">:</span><span class="token punctuation">:</span>Autolock <span class="token function">l</span><span class="token punctuation">(</span>mStateMutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
    currentState <span class="token operator">=</span> mCaptureState<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">//状态机处理流程</span>
currentState <span class="token operator">=</span> <span class="token punctuation">(</span>this<span class="token operator">-&gt;</span><span class="token operator">*</span>kStateManagers<span class="token punctuation">[</span>currentState<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">(</span>client<span class="token punctuation">)</span><span class="token punctuation">;</span>

Mutex<span class="token punctuation">:</span><span class="token punctuation">:</span>Autolock <span class="token function">l</span><span class="token punctuation">(</span>mStateMutex<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>currentState <span class="token operator">!=</span> mCaptureState<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>mCaptureState <span class="token operator">!=</span> IDLE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">ATRACE_ASYNC_END</span><span class="token punctuation">(</span>kStateNames<span class="token punctuation">[</span>mCaptureState<span class="token punctuation">]</span><span class="token punctuation">,</span> mStateTransitionCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    mCaptureState <span class="token operator">=</span> currentState<span class="token punctuation">;</span>
    mStateTransitionCount<span class="token operator">++</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>mCaptureState <span class="token operator">!=</span> IDLE<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">ATRACE_ASYNC_BEGIN</span><span class="token punctuation">(</span>kStateNames<span class="token punctuation">[</span>mCaptureState<span class="token punctuation">]</span><span class="token punctuation">,</span> mStateTransitionCount<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
    <span class="token function">ALOGV</span><span class="token punctuation">(</span><span class="token string">"Camera %d: New capture state %s"</span><span class="token punctuation">,</span>
            client<span class="token operator">-&gt;</span><span class="token function">getCameraId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> kStateNames<span class="token punctuation">[</span>mCaptureState<span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    mStateChanged<span class="token punctuation">.</span><span class="token function">signal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">if</span> <span class="token punctuation">(</span>mCaptureState <span class="token operator">==</span> ERRORmanageStart<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token function">ALOGE</span><span class="token punctuation">(</span><span class="token string">"Camera %d: Stopping capture sequencer due to error"</span><span class="token punctuation">,</span>
            client<span class="token operator">-&gt;</span><span class="token function">getCameraId</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">return</span> false<span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token keyword">return</span> true<span class="token punctuation">;</span>

}

状态图如下:
在这里插入图片描述

4. setparameter、getparameter

待续。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值