Android Camera原理之camx hal架构_libcamhal

libcamxncs              \
libstriping

LOCAL_WHOLE_STATIC_LIBRARIES :=
libcamxdspstreamer
libcamxhwlbps
libcamxgenerated
libcamxhal
libcamxhalutils
libcamxhwlfd
libcamxhwlife
libcamxhwlipe
libcamxhwliqmodule
libcamxswlfdmanager
libcamxswljpeg
libcamxhwljpeg
libcamxhwllrme
libcamxswlransac
libcamxhwltitan17x
libcamxiqsetting
libcamxosutils
libcamxstats
libcamxsensor
libcamxutils


camera.provider中如何实现到camera hal层的跳跃,camera service调用到camera provider中的接口方法,现在调用到 camera provider中的 **hardware/interfaces/camera/device/3.2/default/CameraDeviceSession.cpp 中的processCaptureRequest(...)方法,最终会调用到:**


status\_t ret = mDevice->ops->process\_capture\_request(mDevice, &halRequest);


**这个mDevice->ops 就是 hardware/libhardware/include/hardware/camera3.h 中的 camera3\_device\_ops 结构体:**


<https://www.jianshu.com/p/099cc3b0ab25>



typedef struct camera3_device_ops {
int (*initialize)(const struct camera3_device *,
const camera3_callback_ops_t *callback_ops);
int (*configure_streams)(const struct camera3_device *,
camera3_stream_configuration_t *stream_list);
int (*register_stream_buffers)(const struct camera3_device *,
const camera3_stream_buffer_set_t buffer_set);
const camera_metadata_t
(*construct_default_request_settings)(
const struct camera3_device *,
int type);
int (*process_capture_request)(const struct camera3_device *,
camera3_capture_request_t request);
void (get_metadata_vendor_tag_ops)(const struct camera3_device,
vendor_tag_query_ops_t
ops);
void (*dump)(const struct camera3_device *, int fd);
int (*flush)(const struct camera3_device *);

/* reserved for future use */
void *reserved[8];

} camera3_device_ops_t;


**这样找到在camera hal层的函数指针的映射关系。**


**映射到:vendor/qcom/proprietary/camx/src/core/hal/camxhal3entry.cpp 中的:**


// Global dispatch  
 static Dispatch g\_dispatchHAL3(&g\_jumpTableHAL3);


**看一下g\_jumpTableHAL3 变量:在 vendor/qcom/proprietary/camx/src/core/hal/camxhal3.cpp 中定义的:**



// Jump table for HAL3

JumpTableHAL3 g_jumpTableHAL3 =
{
open,
get_number_of_cameras,
get_camera_info,
set_callbacks,
get_vendor_tag_ops,
open_legacy,
set_torch_mode,
init,
parallelQuery,
setCallBack,
get_tag_count,
get_all_tags,
get_section_name,
get_tag_name,
get_tag_type,
close,
initialize,
configure_streams,
construct_default_request_settings,
process_capture_request,
dump,
flush,
camera_device_status_change,
torch_mode_status_change,
process_capture_result,
notify
};


***这儿直接构成了指针函数的映射关系。***


**vendor/qcom/proprietary/camx/src/core/chi/camxchitypes.h中定义了CHIAppCallbacks结构体,如下:**



struct CHIAppCallbacks
{
/// @brief Called by the driver to get number of cameras
INT(CHIGetNumCameras)(
UINT32
pNumFwCameras,
UINT32* pNumLogicalCameras);

/// @brief Called by the driver to get the camera info for the camera id
CamxResult (*CHIGetCameraInfo)(
    UINT32      cameraId,
    CameraInfo* pCameraInfo);

/// @brief Defines the prototype for the device status change callback method from to the framework. Please refer to
///        the camera_device_status_change documentation in hardware/camera_common.h.
VOID (*CHIInitializeOverrideSession)(
    UINT32               cameraId,
    const Camera3Device* pCamera3Device,
    const HALCallbacks*  pHALCallbacks,
    Camera3StreamConfig* pStreamConfig,
    BOOL*                isOverrideEnabled,
    VOID**               ppPrivate);

/// @brief Defines the prototype for the torch mode status change callback method from to the framework. Please refer to
///        the torch_mode_status_change documentation in hardware/camera_common.h.
VOID (*CHIFinalizeOverrideSession)(
    const Camera3Device* pCamera3Device,
    UINT64*              pSession,
    VOID**               ppPrivate);

/// @brief Called by the driver to inform about session closing
VOID (*CHITeardownOverrideSession)(
    const Camera3Device* pCamera3Device,
    UINT64*              pSession,
    VOID*                pPrivate);

/// @brief Called by the driver to pass on capture request call to CHI
INT (*CHIOverrideProcessRequest)(
    const Camera3Device*    pCamera3Device,
    Camera3CaptureRequest*  pCaptureRequest,
    VOID*                   pPrivate);

/// @brief Called by the driver to allow for additional override processing during open()
INT(*CHIExtendOpen)(
    UINT32  cameraId,
    VOID*   pPrivateData);

/// @brief Called by the driver to allow for additional override processing during close()
INT(*CHIExtendClose)(
    UINT32  cameraId,
    VOID*   pPrivateData);

/// @brief Called by the driver to allow override to remap special camera IDs into logical camera IDs
UINT32(*CHIRemapCameraId)(
    UINT32              frameworkCameraId,
    CameraIdRemapMode   mode);

/// @brief Interface to allow various override-specific settings to be toggled.
UINT32(*CHIModifySettings)(
    VOID*   pPrivateData);

/// @brief Get any vendor tag specific request settings the override wants to get added to the default settings
VOID (*CHIGetDefaultRequestSettings)(
    UINT32           frameworkCameraId,
    INT              requestTemplate,
    const Metadata** pAdditionalMetadata);

/// @brief Called by the driver to allow for flush()
INT(*CHIOverrideFlush)(
    const Camera3Device*    pCamera3Device);
INT(*CHIParallelQuery) (INT num, char* list[]);
INT(*CHISetCallback) (void*);

};

typedef VOID(CHIHALOverrideEntry)(
CHIAppCallbacks
pCHIAppCallbacks);


这个结构体是函数指针,如何映射的,看看下面的关系:


vendor/qcom/proprietary/camx/src/core/hal/camxhal3module.h中定义的CHIAppCallbacks m\_ChiAppCallbacks;


CHIAppCallbacks m\_ChiAppCallbacks; ///< CHI HAL override entry


在 vendor/qcom/proprietary/camx/src/core/hal/camxhal3module.cpp中的 HAL3Module构造函数中,存在下面的执行语句:



CHIHALOverrideEntry funcCHIHALOverrideEntry =
reinterpret_cast(
CamX::OsUtils::LibGetAddr(m_hChiOverrideModuleHandle, “chi_hal_override_entry”));

if (NULL != funcCHIHALOverrideEntry)
{
funcCHIHALOverrideEntry(&m_ChiAppCallbacks);

CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIGetNumCameras);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIGetCameraInfo);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIFinalizeOverrideSession);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIInitializeOverrideSession);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIOverrideProcessRequest);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIOverrideFlush);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHITeardownOverrideSession);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIExtendOpen);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIExtendClose);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIRemapCameraId);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIModifySettings);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHIParallelQuery);
CAMX_ASSERT(NULL != m_ChiAppCallbacks.CHISetCallback);

if ((NULL != m_ChiAppCallbacks.CHIGetNumCameras)             &&
    (NULL != m_ChiAppCallbacks.CHIGetCameraInfo)             &&
    (NULL != m_ChiAppCallbacks.CHIFinalizeOverrideSession)   &&
    (NULL != m_ChiAppCallbacks.CHIInitializeOverrideSession) &&
    (NULL != m_ChiAppCallbacks.CHIOverrideProcessRequest)    &&
    (NULL != m_ChiAppCallbacks.CHIOverrideFlush)             &&
    (NULL != m_ChiAppCallbacks.CHITeardownOverrideSession)   &&
    (NULL != m_ChiAppCallbacks.CHIExtendOpen)                &&
    (NULL != m_ChiAppCallbacks.CHIExtendClose)               &&
    (NULL != m_ChiAppCallbacks.CHIRemapCameraId)             &&
    (NULL != m_ChiAppCallbacks.CHIModifySettings)            &&
    (NULL != m_ChiAppCallbacks.CHIParallelQuery)             &&
    (NULL != m_ChiAppCallbacks.CHISetCallback))
{
    CAMX_LOG_WARN(CamxLogGroupHAL, "CHI Module library function pointers exchanged");
}

}


m\_ChiAppCallbacks 通过 funcCHIHALOverrideEntry 映射到 chi\_hal\_override\_entry  
 这个 chi\_hal\_override\_entry 就是指 vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxextensioninterface.cpp 中的 chi\_hal\_override\_entry 函数,如下:



void chi_hal_override_entry(
chi_hal_callback_ops_t* callbacks)
{
ExtensionModule* pExtensionModule = ExtensionModule::GetInstance();

CHX_ASSERT(NULL != callbacks);

if (NULL != pExtensionModule)
{
    callbacks->chi_get_num_cameras              = chi_get_num_cameras;
    callbacks->chi_get_camera_info              = chi_get_camera_info;
    callbacks->chi_initialize_override_session  = chi_initialize_override_session;
    callbacks->chi_finalize_override_session    = chi_finalize_override_session;
    callbacks->chi_override_process_request     = chi_override_process_request;
    callbacks->chi_teardown_override_session    = chi_teardown_override_session;
    callbacks->chi_extend_open                  = chi_extend_open;
    callbacks->chi_extend_close                 = chi_extend_close;
    callbacks->chi_remap_camera_id              = chi_remap_camera_id;
    callbacks->chi_modify_settings              = chi_modify_settings;
    callbacks->chi_get_default_request_settings = chi_get_default_request_settings;
    callbacks->chi_override_flush               = chi_override_flush;
    callbacks->chi_parallelquery                = chi_parallelquery;
    callbacks->chi_setcallback                  = chi_setcallback;
}

}


这样就建立了 CHIAppCallbacks 中函数指针的一一映射关系。


 


![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8zNzY4MjgxLTkxYjBhMWM3ZTA3M2E1ZjAuanBnP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXAlN0NpbWFnZVZpZXcyLzIvdy82MjQvZm9ybWF0L3dlYnA?x-oss-process=image/format,png)


camx\_code.jpg


 


vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxextensionmodule.cpp 中的 ExtensionModule::OverrideProcessRequest 函数中执行了 m\_pUsecaseFactory->CreateUsecaseObject,如下:



m_pSelectedUsecase[logicalCameraId] =
m_pUsecaseFactory->CreateUsecaseObject(&m_logicalCameraInfo[logicalCameraId],
static_cast(m_SelectedUsecaseId[logicalCameraId]),
m_pStreamConfig[logicalCameraId]);


直接调用到: vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxusecaseutils.cpp 中的 UsecaseFactory::CreateUsecaseObject 函数:



Usecase* UsecaseFactory::CreateUsecaseObject(
LogicalCameraInfo* pLogicalCameraInfo, ///< camera info
UsecaseId usecaseId, ///< Usecase Id
camera3_stream_configuration_t* pStreamConfig) ///< Stream config
{
Usecase* pUsecase = NULL;
UINT camera0Id = pLogicalCameraInfo->ppDeviceInfo[0]->cameraId;
CHX_LOG_ERROR(“UsecaseFactory::CreateUsecaseObject id = %d”, usecaseId);
switch (usecaseId)
{
case UsecaseId::PreviewZSL:
pUsecase = AdvancedCameraUsecase::Create(pLogicalCameraInfo, pStreamConfig, usecaseId);
break;
case UsecaseId::MultiCamera:
pUsecase = UsecaseMultiCamera::Create(pLogicalCameraInfo, pStreamConfig);
break;
case UsecaseId::MultiCameraVR:
pUsecase = UsecaseMultiVRCamera::Create(pLogicalCameraInfo, pStreamConfig);
break;
case UsecaseId::MFNR:
pUsecase = UsecaseMFNR::Create(camera0Id, pStreamConfig);
break;
case UsecaseId::QuadCFA:
pUsecase = UsecaseQuadCFA::Create(pLogicalCameraInfo, pStreamConfig);
break;
case UsecaseId::Torch:
pUsecase = UsecaseTorch::Create(camera0Id, pStreamConfig);
break;
default:
pUsecase = AdvancedCameraUsecase::Create(pLogicalCameraInfo, pStreamConfig, usecaseId);
break;
}

return pUsecase;

}



enum class UsecaseId
{
NoMatch = 0,
Default = 1,
Preview = 2,
PreviewZSL = 3,
MFNR = 4,
MFSR = 5,
MultiCamera = 6,
QuadCFA = 7,
RawJPEG = 8,
MultiCameraVR = 9,
Torch = 10,
YUVInBlobOut = 11,
MaxUsecases = 12,
};


***前置摄像头的UsecaseId是 PreviewZSL,是单摄,后置摄像头的UsecaseId是 MultiCamera,是多摄。***


![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8zNzY4MjgxLWMyZDI1YmJhOTFmNDA3OTAuanBnP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXAlN0NpbWFnZVZpZXcyLzIvdy8xMDAwL2Zvcm1hdC93ZWJw?x-oss-process=image/format,png)


camx-usecase


 


![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8zNzY4MjgxLTJiN2U1N2NiNmY5YWI1MzguanBnP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXAlN0NpbWFnZVZpZXcyLzIvdy8xMDAwL2Zvcm1hdC93ZWJw?x-oss-process=image/format,png)


camx\_usecase.jpg


 


vendor/qcom/proprietary/camx/src/core/chi/camxchi.cpp中的 ChiEntry函数如下:



/// ChiEntry

CAMX_VISIBILITY_PUBLIC VOID ChiEntry(
ChiContextOps* pChiContextOps)
{
if (NULL != pChiContextOps)
{
pChiContextOps->size = sizeof(ChiContextOps);

    pChiContextOps->majorVersion               = CHI_API_MAJOR_VERSION;
    pChiContextOps->minorVersion               = CHI_API_MINOR_VERSION;
    pChiContextOps->pOpenContext               = CamX::ChiOpenContext;
    pChiContextOps->pCloseContext              = CamX::ChiCloseContext;
    pChiContextOps->pGetNumCameras             = CamX::ChiGetNumCameras;
    pChiContextOps->pGetCameraInfo             = CamX::ChiGetCameraInfo;
    pChiContextOps->pEnumerateSensorModes      = CamX::ChiEnumerateSensorModes;
    pChiContextOps->pCreatePipelineDescriptor  = CamX::ChiCreatePipelineDescriptor;
    pChiContextOps->pDestroyPipelineDescriptor = CamX::ChiDestroyPipelineDescriptor;
    pChiContextOps->pCreateSession             = CamX::ChiCreateSession;
    pChiContextOps->pDestroySession            = CamX::ChiDestroySession;
    pChiContextOps->pFlushSession              = CamX::ChiFlushSession;
    pChiContextOps->pActivatePipeline          = CamX::ChiActivatePipeline;
    pChiContextOps->pDeactivatePipeline        = CamX::ChiDeactivatePipeline;
    pChiContextOps->pSubmitPipelineRequest     = CamX::ChiSubmitPipelineRequest;
    pChiContextOps->pTagOps                    = CamX::ChiGetTagOps;
}

// This is the workaround for presil HAL3test on Windows
// On Device, set_camera_metadata_vendor_ops will be call the set the
// static vendor tag operation in camera_metadata.c
//
// On Windows side, theoretically hal3test should mimic what Android framework
// does and call the set_camera_metadata_vendor_ops function in libcamxext library
// However, in Windows, if both hal3test.exe and hal.dll link to libcamxext library,
// there are two different instance of static varibles sit in different memory location.
// Even if set_camera_metadata_vendor_ops is called in hal3test, when hal try to
// access to vendor tag ops, it is still not set.
//
// This is also a workaround to call vendor tag ops in Chi at GetNumCameras which happens to get called before
// GetVendorTagOps
CamX::g_vendorTagOps.get_all_tags     = CamX::ChiGetAllTags;
CamX::g_vendorTagOps.get_section_name = CamX::ChiGetSectionName;
CamX::g_vendorTagOps.get_tag_count    = CamX::ChiGetTagCount;
CamX::g_vendorTagOps.get_tag_name     = CamX::ChiGetTagName;
CamX::g_vendorTagOps.get_tag_type     = CamX::ChiGetTagType;

set_camera_metadata_vendor_ops(&(CamX::g_vendorTagOps));

}


这个函数映射关系很重要,也在camx chi中比较常见,直接映射在此文件的CamxChi类中。都是从 vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxextensionmodule.cpp中调用过来的。


***下面是预览时capture request 处理流程图:***


![](https://imgconvert.csdnimg.cn/aHR0cHM6Ly91cGxvYWQtaW1hZ2VzLmppYW5zaHUuaW8vdXBsb2FkX2ltYWdlcy8zNzY4MjgxLWQ3MjhmMjlkNDFkODY1MTAuanBnP2ltYWdlTW9ncjIvYXV0by1vcmllbnQvc3RyaXAlN0NpbWFnZVZpZXcyLzIvdy8xMDAwL2Zvcm1hdC93ZWJw?x-oss-process=image/format,png)


camx\_pipeline流程.jpg


  
 check这段流程的时候我们最关注应该是5个重要的处理类型:


 


* 1.UseCase , vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxusecase.h 上面有介绍类图。UseCase在camx中很有很多衍生类,这是camx针对不同的stream来建立不同的usecase对象,用来管理选择feature,并且创建 pipeline以及session
* 2.ChiFeature, vendor/qcom/proprietary/chi-cdk/vendor/chioverride/default/chxfeature.h, usecase选择相应的feature,关联一组pipeline,收到request请求,根据request选择对应的feature


## 最后

今天关于面试的分享就到这里,还是那句话,有些东西你不仅要懂,而且要能够很好地表达出来,能够让面试官认可你的理解,例如Handler机制,这个是面试必问之题。有些晦涩的点,或许它只活在面试当中,实际工作当中你压根不会用到它,但是你要知道它是什么东西。

最后在这里小编分享一份自己收录整理上述技术体系图相关的几十套**腾讯、头条、阿里、美团等公司19年的面试题**,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含**知识脉络 + 诸多细节**,由于篇幅有限,这里以图片的形式给大家展示一部分。

还有 **高级架构技术进阶脑图、Android开发面试专题资料**,高级进阶架构资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。


**【Android核心高级技术PDF文档,BAT大厂面试真题解析】**

![](https://img-blog.csdnimg.cn/img_convert/9cf800e8e896983711b8cf9f8468aacc.webp?x-oss-process=image/format,png)

**【算法合集】**

![](https://img-blog.csdnimg.cn/img_convert/77a1a469cf3cabc9cec5dd500f2d8708.webp?x-oss-process=image/format,png)

**【延伸Android必备知识点】**

![](https://img-blog.csdnimg.cn/img_convert/414ec050264a7de58bed28315f97d65e.webp?x-oss-process=image/format,png)

**【Android部分高级架构视频学习资源】**

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

资料 帮助大家学习提升进阶,也节省大家在网上搜索资料的时间来学习,也可以分享给身边好友一起学习。


**【Android核心高级技术PDF文档,BAT大厂面试真题解析】**

[外链图片转存中...(img-KW84rL8C-1718767365487)]

**【算法合集】**

[外链图片转存中...(img-GQ9thjRK-1718767365488)]

**【延伸Android必备知识点】**

[外链图片转存中...(img-SS15lxaM-1718767365488)]

**【Android部分高级架构视频学习资源】**

**Android精讲视频领取学习后更加是如虎添翼!**进军BATJ大厂等(备战)!现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水,赶快领取吧!

  • 12
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值