精华内容
下载资源
问答
  • 此patch为将raw12数据流传输给上层,高通平台默认支持raw10和raw16,按照基础框架将raw12添加进camera HAL3代码中即可。
  • camera HAL

    2015-02-02 01:26:57
    camera HAL 层Log详细打印分析,仅供参考 camera
  • 这篇文章主要讲camerahal接口调用流程和使用方法 Camera3.h 注释自我笔记 1.Camerahal 的版本号: Hal接口camera_module_t.get_camera_info camera_module_t.common.module_api_version 实现接口 CameraHWInfo::...

    这篇文章主要讲camerahal接口调用流程和使用方法
    如果是写camerhal的厂家,这个应该是必看的,对于想学习camerahal有绝对的指导意义。甚至于是基于camerahal也能开发apk

    Camera3.h 注释自我笔记
    1.Camerahal 的版本号:
    Hal接口camera_module_t.get_camera_info camera_module_t.common.module_api_version
    实现接口
    CameraHWInfo::CameraHWInfo() :
    mMainDevicePathName(DEFAULT_MAIN_DEVICE),
    mHasMediaController(false)
    {
    mBoardName = “”;
    mProductName = “<not_set>”;
    mManufacturerName = “”;
    mCameraDeviceAPIVersion = CAMERA_DEVICE_API_VERSION_3_3;
    说明是hal3.3
    2调用流程
    2.1 framework调用camera_module_t->common.open,返回hardware_device_t
    2.2 检查hal的版本号,并实例化对应的handler,比如是3.0版本,那么可以将其强制转换成camera3_device_t
    2.3 调用camera3_device_t->ops->initialize(),设置回调函数。
    2.4 调用camera3_device_t->ops->configure_streams(),配置一系列输入输出流到hal
    2.5 如果小于或等于3.1版本,要分配gralloc buffers,调用camera3_device_t->ops->register_stream_buffers至少配置一个输出,同样的stream只能注册一次
    大于3.1版本camera3_device_t->ops->register_stream_buffers()不需要调用。
    因为当前的3.3 所以该函数不用调用
    2.6对一些用可以使用默认的设置,camera3_device_t->ops->construct_default_request_settings(),可以在第三部之后任何地方调用
    2.7 基于一组默认设置,发送一个capture 请求,必须至少包含一个输出stream,这个是之前注册过的(应该是第四步做的),调用camera3_device_t->ops->process_capture_request()。这个请求必须在hal能接受下一个请求之后返回(或者说返回之后,hal就可以接受下一个请求)。
    注意当版本大于3.2时,camera3_stream_buffer_t,可以是之前没注册过的
    2.8 连续提交请求,并调用construct_default_request_settings以获取其他用例的默认设置缓冲区(就是camera_metadata_t结构)。
    在3.1及以下版本可能会调用为没有注册的stream 调用register_stream_buffers函数
    2.9 当捕获请求开始时(曝光开始)或者重处理时,hal需要调用camera3_callback_ops_t->notify()报告SHUTTER事件,里面包含帧号和曝光时间戳。对于重处理请求,时间戳是可以在输入画面调用process_capture_request时候传入的camera3_capture_request_t.settings的android.sensor.timestamp查找
    小于等于3.1版本,这个调用必须在process_capture_result调用之前,他会使用帧号。
    大于3.1,hal必须尽早调用这个notify因为framework将没办法将gralloc buffers传递到应用层,直到有这个开始曝光的时间戳(或者输入图像的开始曝光用于重新处理请求)。
    部分metadata结果和gralloc buffer 会在SHUTTER事件前后的任何时候返回到framework层。
    2.10 一些pipeline延时之后(应该是数据在硬件上流转时间),hal使用amera3_callback_ops_t->process_capture_result()开始返回完整的捕获数据到framework,返回是按照请求下发顺序来的,根据pipeline的深度,可以同时执行多个请求。
    在大于3.1版本,一旦buffer作为camera3_stream_buffer_t的一部分通过process_capture_result返回,并且release_fence被标记(-1表示不允许操作),这个buffer的所有权将被视为转回framework,之后hal将不再保留这个特定buffer,framework将立即为它清理内存
    对于单帧,process_capture_result可能被多次调用,每次返回部分新的metadata或者(和)gralloc buffers,framework将积累这些metadata到一个结果
    下列特殊情况可以调用process_capture_result
    同时N帧和N+1帧,只要规则适用于gralloc buffer(是一个返回对应多个帧?)
    2.11 一段时间后,framework会停止下发新的request,等待完成现有的captures(buffer 填充,结果返回),然后再调用configure_streams(),这是为新的输入输出stream复位(配置)camera hardware和pipeline。一些stream可能被之前的配置重用。如果这些streams的buffer已经被hal注册,他们不会再次register,如果至少有一个output stream存在,framework会继续步骤7,否则还是要步骤5注册。
    2.12 framewrok可以调用camera3_device_t->common->close()去结束camera回话。当framwwork没有其他调用为active状态时(也就是poll状态也可以),可以随时调用。尽管这个调用可能会阻塞直到所有in-flight captures完成(所有result返回,所有buffer被填充) 。这个colse调用返回后,不允许hal调用camera3_callback_ops_t函数。一旦close开始,frame也不可以调用任何hal的函数。
    2.13 如果发生错误或其他异步事件,HAL必须调用camera3_callback_ops_t->notify()包含适当的错误/事件信息。当设备错误信息返回后,hal要像close被调用一样操作。然而,hal必须在调用notify()之前取消或完成所有未完成的capture.因此一旦notify被调用返回错误信息,framework将不会受到进一步的callbacks。除了close()之外的方法应在notify()返回错误之后返回-ENODEV或NULL。

    3 操作模式
    camera 3 HAL设备可以实现两种可能的操作模式之一:有限模式和满模式。新的高端设备有望提供全面支持。有限模式对硬件的要求大致与相机HAL设备v1实现的要求一致,一般是旧的或便宜的设备。Full是limited的严格父集,它们共享相同的基本操作流程,如上面所述。
    hal必须用android.info.supportedHardwareLevel静态metadata entry,0表示有限模式,1表示完全模式支持。
    所以 rk在camera3_profiles定义的是 <info.supportedHardwareLevel value=“LIMITED”/>
    粗略地说,limited模式设备不允许应用程序控制捕获设置(仅3A控制),高分辨率时候高速捕获图像,读取rawdata,或支持YUV输出流高于最大录像分辨率(JPEG只针对大型图像)。感觉rk应该可以做FULL.
    Limited细节表现
    有限模式设备不需要在捕获请求设置和捕获的实际图像数据之间实现精确同步, 相反,对设置的更改可能会在将来的某个时间生效,并且可能不会对每个设置项的同一输出帧生效, 快速的设置更改可能会导致某些设置从未用于捕获(就是设置下去被冲掉了), 但是,包含高分辨率output buffer(>1080p)的捕获必须使用指定的设置(但有关处理速率,请参见下文)。
    Limited模式设备不需要支持大多数setting/result/static metadata信息。具体地说,只有以下设置可能被消耗或者处理(使用到):

    • android.control.aeAntibandingMode (controls and dynamic)
    • android.control.aeExposureCompensation (controls and dynamic)
    • android.control.aeLock (controls and dynamic)
    • android.control.aeMode (controls and dynamic)
    • android.control.aeRegions (controls and dynamic)
    • android.control.aeTargetFpsRange (controls and dynamic)
    • android.control.aePrecaptureTrigger (controls and dynamic)
    • android.control.afMode (controls and dynamic)
    • android.control.afRegions (controls and dynamic)
    • android.control.awbLock (controls and dynamic)
    • android.control.awbMode (controls and dynamic)
    • android.control.awbRegions (controls and dynamic)
    • android.control.captureIntent (controls and dynamic)
    • android.control.effectMode (controls and dynamic)
    • android.control.mode (controls and dynamic)
    • android.control.sceneMode (controls and dynamic)
    • android.control.videoStabilizationMode (controls and dynamic)
    • android.control.aeAvailableAntibandingModes (static)
    • android.control.aeAvailableModes (static)
    • android.control.aeAvailableTargetFpsRanges (static)
    • android.control.aeCompensationRange (static)
    • android.control.aeCompensationStep (static)
    • android.control.afAvailableModes (static)
    • android.control.availableEffects (static)
    • android.control.availableSceneModes (static)
    • android.control.availableVideoStabilizationModes (static)
    • android.control.awbAvailableModes (static)
    • android.control.maxRegions (static)
    • android.control.sceneModeOverrides (static)
    • android.control.aeState (dynamic)
    • android.control.afState (dynamic)
    • android.control.awbState (dynamic)
    • android.flash.mode (controls and dynamic)
    • android.flash.info.available (static)
    • android.info.supportedHardwareLevel (static)
    • android.jpeg.gpsCoordinates (controls and dynamic)
    • android.jpeg.gpsProcessingMethod (controls and dynamic)
    • android.jpeg.gpsTimestamp (controls and dynamic)
    • android.jpeg.orientation (controls and dynamic)
    • android.jpeg.quality (controls and dynamic)
    • android.jpeg.thumbnailQuality (controls and dynamic)
    • android.jpeg.thumbnailSize (controls and dynamic)
    • android.jpeg.availableThumbnailSizes (static)
    • android.jpeg.maxSize (static)
    • android.lens.info.minimumFocusDistance (static)
    • android.request.id (controls and dynamic)
    • android.scaler.cropRegion (controls and dynamic)
    • android.scaler.availableStreamConfigurations (static)
    • android.scaler.availableMinFrameDurations (static)
    • android.scaler.availableStallDurations (static)
    • android.scaler.availableMaxDigitalZoom (static)
    • android.scaler.maxDigitalZoom (static)
    • android.scaler.croppingType (static)
    • android.sensor.orientation (static)
    • android.sensor.timestamp (dynamic)
    • android.statistics.faceDetectMode (controls and dynamic)
    • android.statistics.info.availableFaceDetectModes (static)
    • android.statistics.faceIds (dynamic)
    • android.statistics.faceLandmarks (dynamic)
    • android.statistics.faceRectangles (dynamic)
    • android.statistics.faceScores (dynamic)
    • android.sync.frameNumber (dynamic)
    • android.sync.maxLatency (static)
      在camera3_profiles.xml中发现部分动态的也会被预置值
      request.availableResultKeys 表示返回的resultkey
      request.availableRequestKeys 表示下发的RequestKeys
      以上两个都没有默认值,里面的应该是支持的key吧?那就没实现这里的全部
      在Limited模式包含大于1080p的 output buffers可能会被process_capture_request()阻塞,直到所有buffer被填充。Full模式的设备必须以static metadata定义的速率处理高分辨率request,hal仍然要调用process_capture_result()提供结果,framework必须简单地准备好让process_capture_request()阻塞,直到该请求的process_capture_result()完成有限模式设备的高分辨率捕获???
      FULL模式设备必须支持以下附加功能:
      最大分辨率能达到30帧最好,需要20帧以上
      每帧控制 (android.sync.maxLatency == PER_FRAME_CONTROL).rk也有配置
      手动控制metadata,查看定义在android.request.availableCapabilities 的MANUAL_SENSOR
      Post手动处理metadata 查看定义在android.request.availableCapabilities的
      MANUAL_POST_PROCESSING
      这两个rk没有

    4 3a模式和状态机:
    3A算法取决于HAL实现, HAL接口定义了高级状态机描述,以允许HAL设备和框架就3A的当前状态进行通信,并触发3A事件
    当设备打开时,所有单独的3A状态必须非活动状态。Stream配置没有重置3A。例如,必须在调用configure()中锁定焦点。
    触发3A操作只需在下一个请求的设置中设置相关的触发器条目,以指示触发器的启动
    例如,启动自动对焦扫描的触发器是将一个请求的entry ANDROID_CONTROL_AF_TRIGGER设置成ANDROID_CONTROL_AF_TRIGGER_START
    取消自动对焦设置ANDROID_CONTROL_AF_TRIGGER成ANDROID_CONTRL_AF_TRIGGER_CANCEL
    否则,这个entry会不存在,或者设置成ANDROID_CONTROL_AF_TRIGGER_IDLE,每个将触发器项设置为非idle值的请求将被视为独立触发事件
    3A由ANDROID_CONTROL_模式设置为总控制开关,RK用做request和result 的key
    ANDROID_CONTROL_MODE_OFF关闭3a
    ANDROID_CONTROL_MODE_AUTO 正常自动模式
    ANDROID_CONTROL_USE_SCENE_MODE 为情景模式
    在OFF模式下,每个单独的AE/AF/AWB模式有效关闭,并且任何捕获控件都不能被3A例程重写
    在自动模式下,自动对焦、自动曝光和自动白平衡都运行各自独立的算法,并具有自己的模式、状态和触发metadata entry,如下一节所列
    情景模式ANDROID_CONTROL_SCENE_MODE的值决定3a例程,在SCENE_MODEs而不是FACE_PRIORITY(SCENE_MODE的一种,就是face优先,3a值应该得保存,我理解是这样),hal必须重写ANDROID_CONTROL_AE/AWB/AF_MODE的值,也就是特定的场景写不同的值,有不同效果。比如,SCENE_MODE_NIGHT,使用连续对焦模式,任何用户的选择AE/AWB/AF模式都会被忽略。这个举例是不是有点欠妥
    SCENE_MODE_FACE_PRIORITY 3a的参数按照CONTROL_MODE_AUTO来。但是3a程序必须偏向于测量和聚焦在检测到的人脸上。
    4.1 自动对焦设置和result entries
    主要entries
    ANDROID_CONTROL_AF_MODE 选择当前对焦模式,framework发送request设置
    ANDROID_CONTROL_AF_STATE 动态metadata描述当前af算法状态,作为结果返回
    ANDROID_CONTROL_AF_TRIGGER 相关触发3a开启关闭和idle,发送request设置
    4.2 4.3AE和AWB都是差不多,AWB没有TRIGGER。每种mode state和trigger都有很多枚举值。
    4.4 通用状态机转换说明
    在AF、AE或AWB模式之间切换总是将算法的状态重置为inactive状态。同样在切换CONTORL_MODE或是使用CONTROL_MODE == USE_SCENE_MODE,将会置所有3a算法状态为INACTIVE状态
    4.5 4.6 af/ae/awb 状态机的切换 //todo

    5 裁剪
    ANDROID_SCALER_CROP_REGION可以设置全分辨率裁剪(数字变焦和小视场),这是pre-request(???),对于实现平滑的数字边角比较重要。
    简单说下这里:(x, y, width, height)矩形范围,x和y为(0,0)表示左上角最大有效像素,因此,width和height不能大于ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY静态,允许的最小值由ANDROID_SCALER_MAX_DIGITAL_ZOOM来决定,它也描述了最大的zoom因子,因此最小裁剪的范围宽高为

    • {width, height} =
      { floor(ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY[0] /
      ANDROID_SCALER_MAX_DIGITAL_ZOOM),
      floor(ANDROID_SENSOR_ACTIVE_PIXEL_ARRAY[1] /
      ANDROID_SCALER_MAX_DIGITAL_ZOOM) }
      如果裁剪区域需要满足特定要求(例如,它需要从偶数坐标开始,宽度/高度需要偶数),HAL必须进行必要的舍入,并写出输出结果metadata中使用的最终裁剪区域。类似的,如果HAL实现video固定(分辨率),则它必须调整结果裁剪区域以匹配固定的video区域。一般来说,使用应用程序的相机必须能够根据裁剪区域、图像传感器的尺寸和镜头焦距确定其接收的视野。

    假设裁剪是在将原始颜色应用到其他颜色空间之后进行的转换。原始流(RAW16和Raw_OPAQUE)没有这个转换阶段,不可裁剪。因此,HAL必须忽略raw stream。

    Crop只针对非raw stream,相比crop区域有很多不同的比例,实际sensor区域能会小于crop区域,具体地说,每个stream都应该维持他的宽高比例。如果stream的长宽比比crop区宽,则stream应垂直crop,如果stream的长宽比比作物区窄,stream水平crop。
    Crop必须在full crop区域的中心,每个stream只能是水平或者垂直crop
    后面例子不说,crop应该都清楚

    6 错误管理
    如果发生严重错误,具有返回值的Camera HAL device ops函数都将返回-ENODEV/NULL。这意味着设备无法继续运行,必须由框架关闭。一旦某个方法返回此错误,或者调用notify()通知ERROR_DEVICE,则只能成功调用close()方法。所有其他方法都将返回-ENODEV/NULL.
    如果操作错误的时序,例如framewrok调用config_streams在initialize,设备必须返回-ENOSYS.
    图像捕获中的暂时错误必须通过notify()报告,如下所示:
    整个捕获失败必须由HAL调用notify报告ERROR_REQUEST时间,在这种情况下,不能报告metadata个别错误或outputbuffer。
    如果capture的metadata不能处理,但是image buffers已经被填充,hal必须要调用notify 报告ERROR_RESULT信息
    如果output image buffer填充不了,但是metadata被处理或者一些其他buffer被填充,hal调用notify报告ERROR_BUFFER
    在这些暂时的故障情况中,HAL必须仍然调用process_capture_result,并使用有效的输出和输入(如果提交了输入缓冲区)buffer_handle_t。如果无法生成结果metadata,则应为空. 如果无法填充某些buffer,他们必须用process_capture_result返回错误状态
    Release fences必须通过framework设置为acquire fences,或者如果他已经在被hal等待,将被设置成-1。
    无效的输入参数导致-EINVAL,在这种情况下,framework必须像从未发出过那样
    7. Key Performance Indicator (KPI) 词汇
    Pipeline Latency:管道时延
    对于给定的capture request,从框架调用process_capture_request到HAL发送捕获结果以及process_capture_result调用返回的所有缓冲区的持续时间。为了使管道延迟的测量独立于帧速率,它是通过帧计数来测量的。
    例如,当帧速率为30(fps)时,帧持续时间(相邻帧捕获时间之间的时间间隔)为33(ms),如果框架需要5帧才能得到request结果和返回buffers,则管道延迟为5(帧),而不是5 x 33=165(ms)
    管道延迟由android.request.pipelineDepth和

    android.request.pipelineMaxDepth,请参阅它们的定义以了解更多详细信息。

    8 使用例子
    包含了hal支持的典型使用例子
    8.1 0秒快拍,使用CAMERA3_STREAM_BIDIRECTIONAL类型的stream
    使用这个双向stream将被framework做如下使用:
    @1 framework包含一个output buffer的普通stream的request
    @2 一旦hal返回一个填充的output buffer,framework将对这个buffer做两者之一
    @2.a framework使用填充的buffer,返回now-uesd buffer队列重用(这是什么?可能是得到buffer的正常使用),这和output 类型stream一样。
    @2.b framework处理这个填充的buffer,把这个buffer作为输入buffer做一个request,一旦hal处理了这个buffer,然后返回到framework,他会返回now-used buffer到stream 队列重用。
    @3 HAL设备将在将来的某个时刻再次被赋予这个buffer作为request的output buffer
    对于ZSL用例,在android.scaler.availableInputOutputFormatsMap中有支持的话。双向流的像素格式将是HAL_pixel_format_RAW_OPAQUE或HAL_pixel_format_IMPLEMENTATION,当使用HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED时,gralloc的usage编制将被设置成GRALLOC_USAGE_HW_CAMERA_ZSL。具有BIDIRECTIONAL stream作为输入,通常也具有不同的outputstream以获取重新处理的数据。例如 zsl用例:Stream将被这样配置:
    一个HAL_PIXEL_FORMAT_RAW_OPAQUE bidirectional stream作为输入
    HAL_PIXEL_FORMAT_BLOB作为输出
    8.2 zsl 被作为CAMERA3_STREAM_INPUT处理。
    当摄像机设备支持OPAQUE_REPROCESSING,input stream可以被APP/framework实现ZSL。这种stream将被framework做如下使用:
    @1 app/framework 配置opaque(基于raw或者yuv)格式输出stream用作生成ZSL的output buffers,stream的pixel格式为HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED。APP/framework配置opaque格式input stream,他发送处理zsl buffer到hal。这个pixel 格式也同样是HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED
    @2 APP/framework配置yuv/jpeg output stream,用他来接收处理好的数据,这个stream的pixle format 会是YCbCr_420/HAL_PIXEL_FORMAT_BLOB.
    @3 当应用程序发出ZSL捕获时,APP/framework 从output stream收取 zsl buffer,并在重新处理请求中将数据作为input buffer发送回HAL进行重新处理
    @4 Hal将output yuv/jpeg数据作为结果发送到framework
    Hal可以基于HAL_PIXEL_format_IMPLEMENTATION_DEFINED format和gralloc usage flag gralloc_usage_HW_CAMERA_ZSL去选择实际opaque buffer格式和配置适当的isp pipeline
    8.3 YUV 使用CAMERA3_STREAM_INPUT stream重处理
    当hal支持yuv数据重处理时,input stream可以用做lucky-shot和图像拼接。这种stream将会被Framework这样使用
    @1 APP/framework配置一个YCbCr_420 格式output stream,用他产生一个output buffer
    @2 APP/framework配置一个YCbCr_420 格式input stream,用他发送重处理yuv buffer到hal
    @3 APP/framework配置一个YUV/JPEG output stream用作接受重处理好的数据,stream 的pixl 格式会是YCbCr_420/HAL_PIXEL_FORMAT_BLOB
    @4 APP/framework当一个capture发送,从output stream处理output buffers(也可能简单的直接接收 output buffer),然后发送回这个data作为一个input buffer 重处理request,然后发送到hal重处理
    @5 Hal将output yuv/jpeg数据作为结果发送到framework
    9 关于control和metadata的说明
    这个片段包含各种metadata tags的理解和使用
    9.1 HIGH_QUALITY 和 FAST 模式
    许多camera有一些类似HIGH_QUALITY,FAST, 和 OFF 操作模式的后处理块,这些处理模块通常还有一个’可用模式’tag,表示在给定社保上哪些操作模式可用,实现这些模式一般策略如下:
    @1. 操作模式control硬件模块不能disable,相应的’可用模式’不能off状态
    @2. 如果可以关闭那个硬件block他的’可用模式’tag将被设置为OFF
    @3. 对于设备上支持的所有后处理块,FAST必须始终包含在“可用模式”标记中。如果后处理块还具有速度较慢且质量较高的操作模式,而该操作模式不满足快速模式的帧速率要求,则HIGH_QUALITY应该包含在“可用模式”标签中以表示此操作模式
    10. 重处理 flow 和 controls
    本节介绍OPAQUE和YUV 处理folw和controls。OPAQUE处理使用应用不能可视的opaque格式,app只能选择一些output buffer发送到hal做重处理,当YUV重处理给应用机会处理buffer(也就是选转换为yuv),然后再处理。
    第8节说明了stream的电影处理配置,这节对buffer flow和controls做更小细节的说明
    10.1 OPAQUE(通常用于zsl)重处理flow和controls
    OPAQUE重处理例子(例如zsl),app创建制定的output和input stream,运行buffer flow和controls制定如下:
    @1. app通过为得到output opaque buffer和预览发送repeat request启动output stream,buffer 由一组固定的环形buffer保存。这个request基于CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG capture 模版,该模板应具有所有必要的设置,以确保输出帧速率不会相对于sensor(摄像头)输出帧速率减慢。
    @2. app基于应用程序buffer的选择逻辑(例如 good ae 和af 统计)选择一个output buffer, 发送capture消息。然后基于capture 返回选定的buffer创建一个新的处理请求,这个选定的output buffer,现在作为input buffer添加到此重新处理请求,此重新处理请求的output buffer应为JPEG或者yuv outputbuffer,或者都有,具体取决于app的选择
    @3. App更改重新处理设置以获得最佳图像质量。如果HAL支持OPAQUE_REPROCESSING属性,HAL必须支持且仅支持以下控制:
    -android.jpeg.*(如果输出中包含jpeg缓冲区)
    -android.noiseReduction.mode(如果支持,则更改为高质量)
    *-android.edge.mode(如果支持,则更改为高质量)
    HAL必须忽略所有其他controls
    @4. HAL处理了input buffer并在capture results中返回utput buffers像平常一样
    10.2 YUV重处理flow和controls
    Yuv处理buffer flow和OPAQUE 处理相似,有以下不同:
    @1. app可能需要对中间YUV图像进行更精细的像素控制(在重新处理之前)。例如,应用程序可以选择android.noiseReduction.mode == MINIMAL,为了保证输出的YUV buffer 减少噪声,可以对其进行先进的降噪处理。对于OPAQUE 的情况,没有关系,只要最后处理的图像有最好的质量
    @2. 应用程序可以修改YUV输出缓冲区数据。例如,对于图像融合用例,将多个输出图像合并在一起以提高信噪比比率(SNR),app可以从多个buffer区(多个合成一个)生成input buffer。为了避免对input buffer应用过多的噪声降低和不足的边缘增强,app可以提示HAL应用程序已经完成了多少有效的曝光时间提升,然后,HAL可以调整去噪和边缘增强参数,以获得最佳的后处理图像质量
    以下标签可用于此目的:
    -android.reproces.effectiveExposureFactor系统
    该值是应用于原始输出图像的曝光时间增加因子,例如,如果有N个图像合并,则曝光时间增加因子将高达sqrt(N)。有关更多详细信息,请参阅此标记规范。
    10.3 Reprocessing pipeline 特性
    后处理管道与正常输出管道相比具有以下不同的特性:
    @1.重新处理结果可以在挂起的正常输出结果之前返回。但是,对于所有的后处理结果,必须保持FIFO顺序。例如,HAL正在处理以下请求(A代表输出请求,B代表重新处理请求):
    A1, A2, A3, A4, B1, A5, B2, A6…
    B1可以在A1-A4之前返回,但是B2必须B1之后返回
    @2.单一输入规则:对于给定的重新处理请求,所有output buffer必须来自input buffer,而不是传感器输出。例如,如果重新处理请求同时包含JPEG和preview buffers,所有output buffer 都必须从重新处理请求所包含的input buffer生成,而不是从sensor生成,hal不能从传感输出 preview buffers,而从input buffer输出jpeg buffer(怎么这么多废话)
    @3. Input buffer将直接从camera output(zsl 情况)或间接(图像合成)。对于修改buffer的情况,大小保持不变,如果发送来自未知源的buffer,HAL可以notify CAMERA3_MSG_ERROR_请求
    @4. 作为重新处理请求的结果:HAL可以期望重新处理请求是一个输出结果的副本,其中包含允许的少量设置更改。如果是未知源的请求,则hal可以通知如果发出CAMERA3_MSG_ERROR_REQUEST。
    @5. Output buffers不能用做跨配置流边界(cross the configure stream boundary)的input,这是因为像ZSL output stream这样的opaque stream在ZSL缓冲区内可能具有不同的实际图像大小,以节省用于较小分辨率JPEG捕获的功率和带宽,如果发生这种情况,HAL可以notify CAMERA3_MSG_ERROR_请求
    @6. HAL在FLUSH期间重新处理请求错误报告应遵循flush()方法指定的相同规则.

    展开全文
  • Android CameraCamera HAL 分析

    千次阅读 2019-03-27 19:10:54
    Android Camera 一 源码路径 Android Camera 二 JNI ...Android CameraCameraService 和 Client 链接到 HAL Android CameraCamera HAL 分析 Android CameraCamera HAL v1 Linux v4l2 一 应用层 Lin...

    Android Camera 一 源码路径

    Android Camera 二 JNI JAVA和C/CPP图像数据传输流程分析

    Android Camera 三 CameraService 和 Client 链接到 HAL

    Android Camera 四 Camera HAL 分析

    Android Camera 五 Camera HAL v1

    Linux v4l2 一 应用层

    Linux v4l2 二 驱动和 usb 摄像头

     

    frameworks/av/services/camera/libcameraservice/common/CameraModule.cpp
    frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
    frameworks/av/services/camera/libcameraservice/common/CameraModule.cpp
    hardware/libhardware/include/hardware/camera_common.h
    hardware/libhardware/include/hardware/hardware.h
    hardware/qcom/camera/QCamera2/QCamera2Hal.cpp
    hardware/qcom/camera/QCamera2/QCamera2Factory.cpp
    hardware/qcom/camera/QCamera2/HAL/QCameraMuxer.cpp
    hardware/qcom/camera/QCamera2/HAL/QCamera2HWI.cpp
    hardware/qcom/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
    hardware/qcom/camera/QCamera2/stack/mm-camera-interface/src/mm_camera.h
    hardware/qcom/camera/QCamera2/stack/mm-camera-interface/src/mm_camera.c
     

    在上一节讲到Camera3Device::initialize( CameraModule *module) 进入 HAL 层。

    接下来从分析 CameraModule 的open() 成员函数开始分析。

    关于 Android 中的 HAL 模块的注册机制,不做展开。

    // frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp
    //  该函数中 module->open() ,调用HAL层注册的相机模块 open 函数
    status_t Camera3Device::initialize(CameraModule *module)
    {
     ......
     
        /** Open HAL device */
     
        status_t res;
        String8 deviceName = String8::format("%d", mId);
     
        camera3_device_t *device;
     
        ATRACE_BEGIN("camera3->open");
        res = module->open(deviceName.string(),
                reinterpret_cast<hw_device_t**>(&device));  // 打开相机设备
    
        ATRACE_END();
     ......
    }

    各厂商遵从 Android HAL 规则,编写驱动代码,适配 Android系统。

    CameraModule::open() 成员函数根据 HAL 规则,调用各厂商适配的相机驱动打开对应的相机设备。

    // frameworks/av/services/camera/libcameraservice/common/CameraModule.cpp
    // camera_module_t *mModule
    int CameraModule::open(const char* id, struct hw_device_t** device) {
        int res;
        ATRACE_BEGIN("camera_module->open");
        res = filterOpenErrorCode(mModule->common.methods->open(&mModule->common, id, device));
        ATRACE_END();
        return res;
    }
    

     

    来看看 camera_module_t 结构体,该结构体定义的指针函数成员,类似 CPP 的抽象类封装。

    这种方式把各厂商的相机驱动和 HAL 层衔接起来,让 Android 适配更多的相机设备。

    // hardware/libhardware/include/hardware/camera_common.h
    typedef struct camera_module {
        /**
    	 * 相机模块的常用方法。该结构体必须是 camera_module 模块的第一个成员,
    	 * 因为该结构的用户将在已知 hw_module_t 模块引用 camera_module 模块的上下文中,
         *
         * The return values for common.methods->open for camera_module are:
         *
         * 0:           On a successful open of the camera device.
         *
         * -ENODEV:     The camera device cannot be opened due to an internal
         *              error.
         *
         * -EINVAL:     The input arguments are invalid, i.e. the id is invalid,
         *              and/or the module is invalid.
         *
         * -EBUSY:      The camera device was already opened for this camera id
         *              (by using this method or open_legacy),
         *              regardless of the device HAL version it was opened as.
         *
         * -EUSERS:     The maximal number of camera devices that can be
         *              opened concurrently were opened already, either by
         *              this method or the open_legacy method.
         *
         * All other return values from common.methods->open will be treated as
         * -ENODEV.
         */
        hw_module_t common;
    
        /**
         * get_number_of_cameras:
         *
         * 返回可通过相机模块访问的相机设备数量。摄像机设备编号为0到 N-1,其中 N 是此调用返回的值。
    	 * The name of the camera device for open() is
         * simply the number converted to a string. That is, "0" for camera ID 0,
         * "1" for camera ID 1.
         */
        int (*get_number_of_cameras)(void);
    
    
        int (*get_camera_info)(int camera_id, struct camera_info *info);
    
        int (*set_callbacks)(const camera_module_callbacks_t *callbacks);
    
    
        void (*get_vendor_tag_ops)(vendor_tag_ops_t* ops);
    
        int (*open_legacy)(const struct hw_module_t* module, const char* id,
                uint32_t halVersion, struct hw_device_t** device);
    
        int (*set_torch_mode)(const char* camera_id, bool enabled);
    
        int (*init)();
    
        /* reserved for future use */
        void* reserved[5];
    } camera_module_t;

    hw_module_t common 结构体是保存设备驱动在 HAL 注册的信息。

    // hardware/libhardware/include/hardware/hardware.h
    typedef struct hw_module_t
    {
        /** tag must be initialized to HARDWARE_MODULE_TAG */
        uint32_t tag;
    
        uint16_t module_api_version;
    
    #define version_major module_api_version
        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 */
        /** 结构体中定义模块指针函数 open() */
        struct hw_module_methods_t* methods;
    
        /** module's dso */
        void* dso;
    
    #ifdef __LP64__
        uint64_t reserved[32-7];
    #else
        /** padding to 128 bytes, reserved for future use */
        uint32_t reserved[32-7];
    #endif
    
    } hw_module_t;
    
    
    // struct hw_module_methods_t* methods
    // mModule->common.methods->open(&mModule->common, id, device) 的 open() 函数
    typedef struct hw_module_methods_t {
        /** Open a specific device */
        int (*open)(const struct hw_module_t* module, const char* id,
                struct hw_device_t** device);
    
    } hw_module_methods_t;

    通过上述代码知道 CameraModule::open() 方法是调用 hw_module_methods_t 结构体中的成员指针函数 method->open()

    搜索关键字 hw_module_methods_t  查找哪里定义并注册  hw_module_methods_t  指针函数  method->open() 。

    grep -R "hw_module_t" hardware/qcom/camera/

    打开文件  QCamera2Hal.cpp 

    QCamera2Hal.cpp 声明并初始化了 hw_module_t 和 camera_module_t 结构体变量。 

    静态变量 camera_common 中注册了 指针函数 method->open() , 

    methods  = &qcamera::QCamera2Factory::mModuleMethods;   开始顺藤摸瓜,找到真正打开 camera 设备的函数。

    // hardware/qcom/camera/QCamera2/QCamera2Hal.cpp
    #include "QCamera2Factory.h"
    #include "HAL3/QCamera3VendorTags.h"
    
    static hw_module_t camera_common = {
        .tag                    = HARDWARE_MODULE_TAG,
        .module_api_version     = CAMERA_MODULE_API_VERSION_2_4,
        .hal_api_version        = HARDWARE_HAL_API_VERSION,
        .id                     = CAMERA_HARDWARE_MODULE_ID,
        .name                   = "QCamera Module",
        .author                 = "Qualcomm Innovation Center Inc",
        .methods                = &qcamera::QCamera2Factory::mModuleMethods,  // 打开相机的方法
        .dso                    = NULL,
        .reserved               = {0}
    };
    
    camera_module_t HAL_MODULE_INFO_SYM = {
        .common                 = camera_common,
        .get_number_of_cameras  = qcamera::QCamera2Factory::get_number_of_cameras,
        .get_camera_info        = qcamera::QCamera2Factory::get_camera_info,
        .set_callbacks          = qcamera::QCamera2Factory::set_callbacks,
        .get_vendor_tag_ops     = qcamera::QCamera3VendorTags::get_vendor_tag_ops,
        .open_legacy            = qcamera::QCamera2Factory::open_legacy,
        .set_torch_mode         = qcamera::QCamera2Factory::set_torch_mode,
        .init                   = NULL,
        .reserved               = {0}
    };
    

     

    从 QCamera2Factory::mModuleMethods 定位到  QCamera2Factory 类

    // hardware/qcom/camera/QCamera2/QCamera2Factory.cpp
    struct hw_module_methods_t QCamera2Factory::mModuleMethods = 
    {
        .open = QCamera2Factory::camera_device_open,
    };
    
    
    int QCamera2Factory::camera_device_open(
        const struct hw_module_t *module, const char *id,
        struct hw_device_t **hw_device)
    {
        int rc = NO_ERROR;
        if(module != &HAL_MODULE_INFO_SYM.common)
        {
            LOGE("Invalid module. Trying to open %p, expect %p",
                 module, &HAL_MODULE_INFO_SYM.common);
            return INVALID_OPERATION;
        }
        if(!id)
        {
            LOGE("Invalid camera id");
            return BAD_VALUE;
        }
    #ifdef QCAMERA_HAL1_SUPPORT
        if(gQCameraMuxer)
            rc =  gQCameraMuxer->camera_device_open(module, id, hw_device);
        else
    #endif
            rc = gQCamera2Factory->cameraDeviceOpen(atoi(id), hw_device);
        return rc;
    }

    两个分支的调用流程:

    • QCamera2Factory::cameraDeviceOpen() → QCamera2HardwareInterface::openCamera() → camera_open()  
    • QCameraMuxer::camera_device_open() → QCameraMuxer::cameraDeviceOpen() → QCamera2HardwareInterface::openCamera() → camera_open()

    两个分支经过不同的路径调用函数 camera_open()  。

    mm_camera_interface.c 的函数 camera_open() 调用 

    • mm_camera_open() → open(dev_name, O_RDWR | O_NONBLOCK); 

    打开相机设备

    // hardware/qcom/camera/QCamera2/stack/mm-camera-interface/src/mm_camera_interface.c
    int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl)
    {
        ......
    
        rc = mm_camera_open(cam_obj);
    
        ......
    
    }

     

    mm_camera.c 中函数 mm_camera_open() → open()  真正的打开了 camera 设备。

    在执行 open() 后,从 HAL 层进入 Linux kernel 。即将离开 Android ,进入 Linux 的世界。

    Linux的思想:一切皆文件,对文件的操作分为三个步骤:

    1. 打开设备 open();
    2. 读写设备 read()/write();
    3. 关闭设备 close()。

    如下代码所示, 调用 open() 打开了 camera 设备。 read()/write()/close() 不做叙述。

    // hardware/qcom/camera/QCamera2/stack/mm-camera-interface/src/mm_camera.c
    int32_t mm_camera_open(mm_camera_obj_t *my_obj)
    {
        ......
        do
        {
            n_try--;
            errno = 0;
            my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);
            l_errno = errno;
            LOGD("ctrl_fd = %d, errno == %d", my_obj->ctrl_fd, l_errno);
            if((my_obj->ctrl_fd >= 0) || (errno != EIO && errno != ETIMEDOUT) || (n_try <= 0))
            {
                break;
            }
            LOGE("Failed with %s error, retrying after %d milli-seconds",
                 strerror(errno), sleep_msec);
            usleep(sleep_msec * 1000U);
        }
        while(n_try > 0);
        ......
    }

    打开设备之后,如何获取图像呢?    v4l2 是 Linux的视频框架,Android 也是使用类似的方式获取视频图像。

    这里给出 mm_camera.h 和 Linux V4L2 类似的接口函数声明,简化对 camera 底层框架理解。

    // hardware/qcom/camera/QCamera2/stack/mm-camera-interface/src/mm_camera.h
    
    extern int32_t mm_camera_open(mm_camera_obj_t *my_obj);
    extern int32_t mm_camera_close(mm_camera_obj_t *my_obj);
    extern int32_t mm_camera_register_event_notify(mm_camera_obj_t *my_obj,
                                                   mm_camera_event_notify_t evt_cb,
                                                   void * user_data);
    extern int32_t mm_camera_qbuf(mm_camera_obj_t *my_obj,
                                  uint32_t ch_id,
                                  mm_camera_buf_def_t *buf);
    extern int32_t mm_camera_get_queued_buf_count(mm_camera_obj_t *my_obj,
            uint32_t ch_id, uint32_t stream_id);
    extern int32_t mm_camera_query_capability(mm_camera_obj_t *my_obj);
    extern int32_t mm_camera_set_parms(mm_camera_obj_t *my_obj,
                                       parm_buffer_t *parms);
    extern int32_t mm_camera_get_parms(mm_camera_obj_t *my_obj,
                                       parm_buffer_t *parms);
    extern int32_t mm_camera_map_buf(mm_camera_obj_t *my_obj,
                                     uint8_t buf_type,
                                     int fd,
                                     size_t size,
                                     void *buffer);
    extern int32_t mm_camera_map_bufs(mm_camera_obj_t *my_obj,
                                      const cam_buf_map_type_list *buf_map_list);
    extern int32_t mm_camera_unmap_buf(mm_camera_obj_t *my_obj,
                                       uint8_t buf_type);

    通过跟踪 Android 7.1 源码 “open camera ”的流程分析完成:

    •  framework层的JNI → hardware → Linux  

    感兴趣的朋友继续分析 Camera 的 read()/write()/close()的流程,加深理解 Camera 框架。

     

     

     

     

     

    展开全文
  • Android camera HAL框架

    千次阅读 2019-09-29 13:43:49
    接下来将会了解Android HAL是如何与相机设备、Framework进行交互的,为了简单起见,我们使用androidP代码中的谷歌实例代码进行学习,代码路径为:android/hardware/libhardware/modules/camera/3_4。 一般的,各个...

    接下来将会了解Android HAL是如何与相机设备、Framework进行交互的,为了简单起见,我们使用androidP代码中的谷歌实例代码进行学习,代码路径为:android/hardware/libhardware/modules/camera/3_4。

    一般的,各个平台的camera HAL将会有个 v4l2_camera_hal.cpp 文件。在这里,将是HAL对外的接口,该文件将会通过 HAL_MODULE_INFO_SYM 修饰一个 camera_module_t 结构体。camera Provider服务就是通过 HAL_MODULE_INFO_SYM 找到 camera_module_t,从而操作HAL。

    全局静态对象 V4L2CameraHAL

    在 v4l2_camera_hal.cpp 中定义了一个 V4L2CameraHAL 类的全局静态对象 gCameraHAL,所以在加载 HAL.so 时,将会调用 V4L2CameraHAL 类的构造函数。在构造函数中,主要是探测 /dev 目录下有多少个 video 节点且支持V4L2 video capture,并将探测结果保存在 V4L2CameraHAL.mCameras 容器中。

    get_number_of_cameras()

    最终将返回全局静态对象 gCameraHAL 的 mCameras 成员大小。

    get_camera_info()

    最终根据传递进来的 id 将调用到全局静态对象 gCameraHAL 的 mCameras[id]->getInfo(info),此时将调用到 Camera::getInfo()。注意,mCameras[id]在全局静态变量 gCameraHAL 的构造函数中已经创建 V4L2Camera 对象。

    为了支持Android框架保存原始图像文件,需要有关传感器特性的大量元数据。这包括诸如色彩空间和镜头阴影功能之类的信息。这些信息大部分都是相机子系统的静态属性,可以在配置输出管道或者提交请求之前进行查询。

    set_callbacks()

    设置回调函数,保存在 gCameraHAL.mCallbacks。mCallbacks为 camera_module_callbacks_t 类型,其中包含两个回调,一个是相机设备状态改变时的回调;一个是闪光灯状态改变时的回调。

    hw_module_methods_t 变量

    在 camera_module_t 的comon成员中,通过 methods 指向了一个 hw_module_methods_t 类型变量。通过 hw_module_methods_t->open() ,我们最终调用到 Camera::openDevice() 函数(V4L2Camera是Camera的派生类,V4L2Camera没有覆盖openDevice()函数),从而和相机设备连接起来,该函数的参数 module 指向 HAL_MODULE_INFO_SYM.common,而 device 则是将返回给 Framework 的 camera device,device 指向 hw_device_t 类型对象。

    Camera::openDevice()

    在该函数中,将会通过调用 connect() 函数完成与相机设备的连接,接着将填充device,返回Framework。

    而 connect() 将是调用到 V4L2Camera::connect()。V4L2Camera::connect() 则是创建一个 V4L2Wrapper::Connection 实例对象,在 V4L2Wrapper::Connection 的构造函数中,又将调用 V4L2Wrapper::Connect() 函数。

    这一切,就这样就到了V4L2Wrapper::Connect() 。而在 V4L2Wrapper::Connect() 中,将会 open video节点,进行查询支持的格式以及分辨率等操作。

    看完 v4l2_camera_hal.cpp 中的接口后,似乎上面就已经介绍完了,就没有其他接口控制设备了,那么 camera Provider服务进程又是如何多样操作相机设备的呢?下面继续看。

    我们回头看 Camera::openDevice() 函数的实现:

    int Camera::openDevice(const hw_module_t *module, hw_device_t **device)
    {
        ALOGI("%s:%d: Opening camera device", __func__, mId);
        ATRACE_CALL();
        android::Mutex::Autolock al(mDeviceLock);
    
        if (mBusy) {
            ALOGE("%s:%d: Error! Camera device already opened", __func__, mId);
            return -EBUSY;
        }
    
        int connectResult = connect();
        if (connectResult != 0) {
          return connectResult;
        }
        mBusy = true;
        mDevice.common.module = const_cast<hw_module_t*>(module);
        /* 这里,是我们返回给Framework的 hw_device_t,那么这个
         * mDevice 是什么呢,看 Camera 的构造函数
         */
        *device = &mDevice.common;
        return 0;
    }
    
    Camera::Camera(int id)
      : mId(id),
        mSettingsSet(false),
        mBusy(false),
        mCallbackOps(NULL),
        mInFlightTracker(new RequestTracker)
    {
        memset(&mTemplates, 0, sizeof(mTemplates));
    	/* 在Camera 的构造函数中,初始化 common 成员的部分变量之后,
    	 * 赋值了 ops 操作集,接下来再看看 ops 的类型
    	 */
        memset(&mDevice, 0, sizeof(mDevice));
        mDevice.common.tag    = HARDWARE_DEVICE_TAG;
        mDevice.common.version = CAMERA_DEVICE_API_VERSION_3_4;
        mDevice.common.close  = close_device;
        mDevice.ops           = const_cast<camera3_device_ops_t*>(&sOps);
        mDevice.priv          = this;
    }
    
    /* 从 mDevice.ops 的定义类型来看,很像就是操作相机设备的一些接口函数,
     * 我们怎么确认我们的猜测是否正确呢,看 camera Provider 服务进程的调用
     */
    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);
    
        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 *);
    
        void *reserved[8];
    } camera3_device_ops_t;
    
    /* camera Provider 服务进程的调用 */
    /* 通过查看 CameraDeviceSession 类的实现,可以了解到,
     * 在创建流、处理Framework请求等操作,都是通过 Camera::openDevice()
     * 返回的 device 进行操作的,一般以以下的方式进行调用:
     */
    mDevice->ops->initialize(mDevice, this);
    mDevice->ops->dump(mDevice, fd->data[0]);
    mDevice->ops->construct_default_request_settings(mDevice, (int) type);
    mDevice->ops->configure_streams(mDevice, &stream_list);
    mDevice->ops->process_capture_request(mDevice, &halRequest);
    mDevice->ops->flush(mDevice);
    

    所以通过以上分析得知,camera Provider 服务通过返回的 device 得到 camera3_device_ops_t 操作集,所以可以操作配置相机设备。下面再分析,这些操作集函数都进行了什么操作。

    camera3_device_ops_t

    const camera3_device_ops_t Camera::sOps = {
        .initialize = default_camera_hal::initialize,
        .configure_streams = default_camera_hal::configure_streams,
        .register_stream_buffers = nullptr,
        .construct_default_request_settings
            = default_camera_hal::construct_default_request_settings,
        .process_capture_request = default_camera_hal::process_capture_request,
        .get_metadata_vendor_tag_ops = nullptr,
        .dump = default_camera_hal::dump,
        .flush = default_camera_hal::flush,
        .reserved = {0},
    };
    
    initialize()

    从上面我们了解到 initialize() 函数指针赋值为 default_camera_hal::initialize()。

    namespace default_camera_hal {
    extern "C" {
    // Get handle to camera from device priv data
    static Camera *camdev_to_camera(const camera3_device_t *dev)
    {
    	/* 实际上通过转换为 camera3_device_t 类型,
    	 * 再获取 priv 成员转换为 Camera 类型指针,可
    	 * 回头查看 Camera 的构造函数以及 openDevice()
    	 */
        return reinterpret_cast<Camera*>(dev->priv);
    }
    
    static int initialize(const camera3_device_t *dev,
            const camera3_callback_ops_t *callback_ops)
    {
        /* 调用到 Camera::initialize() */
        return camdev_to_camera(dev)->initialize(callback_ops);
    }
    } // extern "C"
    } // namespace default_camera_hal
    
    int Camera::initialize(const camera3_callback_ops_t *callback_ops)
    {
        int res;
    
        ALOGV("%s:%d: callback_ops=%p", __func__, mId, callback_ops);
        /* 在Framework层,调用 initialize() 函数时,传递了
         * CameraDeviceSession 类对象的this指针,所以这里的
         * callback_ops 指向 CameraDeviceSession实例对象地
         * 址,而 CameraDeviceSession 类继承于 camera3_callback_ops,
         * 所以这里就可以对接起来了
         */
        mCallbackOps = callback_ops;
        // per-device specific initialization
        /* Camera类的 initDevice() 函数是纯虚函数,将会调用
         * V4L2Camera::initDevice(),接着创建
         * V4L2Camera::enqueueRequestBuffers() 线程和
         * V4L2Camera::dequeueRequestBuffers() 线程
         */
        res = initDevice();
        if (res != 0) {
            ALOGE("%s:%d: Failed to initialize device!", __func__, mId);
            return res;
        }
        return 0;
    }
    

    如上介绍,在camera HAL,将会通过 mCallbackOps 将状态等信息反馈到 Framework。我们可以查看,在 CameraDeviceSession 类的构造函数可以看到以下信息:

    /* camera3_callback_ops 对象将初始化为以下值 */
    camera3_callback_ops({&sProcessCaptureResult, &sNotify})
    
    typedef struct camera3_callback_ops {
        void (*process_capture_result)(const struct camera3_callback_ops *,
                const camera3_capture_result_t *result);
    
        void (*notify)(const struct camera3_callback_ops *,
                const camera3_notify_msg_t *msg);
    
    } camera3_callback_ops_t;
    

    而在 V4L2Camera::initDevice() 函数中,则是创建处理Framework 请求的线程。

    configure_streams()

    与 initialize() 类似,将会调用至 Camera::configureStreams(camera3_stream_configuration_t *stream_config)。这个调用将使用stream_list中定义的数据流信息来代替之前的数据流配置。在initialize()之后,使用process_capture_request()提交请求之前,这个函数至少被调用一次。在了解 configureStreams() 的具体操作前,我们先看看,函数参数的具体定义是怎样的。

    typedef struct camera3_stream_configuration {
        /* Framework请求的stream总数,至少为1,而且至少有一个具有输出能力的流 */
        uint32_t num_streams;
    
        /* 指向Framework配置的stream */
        camera3_stream_t **streams;
    
        uint32_t operation_mode;
    
        const camera_metadata_t *session_parameters;
    } camera3_stream_configuration_t;
    
    typedef struct camera3_stream {
    
        int stream_type;
    
        uint32_t width;
    
        uint32_t height;
    
        int format;
    
        uint32_t usage;
    
        uint32_t max_buffers;
    
        void *priv;
    
        android_dataspace_t data_space;
    
        int rotation;
    
        const char* physical_camera_id;
    
        /* reserved for future use */
        void *reserved[6];
    
    } camera3_stream_t;
    

    从 camera3_stream_configuration_t 的定义我们可以了解到,主要就是配置相机硬件输出的格式、分辨率、buf数量、以及stream的类型等。

    而 configureStreams() 进行了什么操作呢?

    int Camera::configureStreams(camera3_stream_configuration_t *stream_config)
    {
    	/* 检查参数是否正确、有效 */
        int res = validateStreamConfiguration(stream_config);
        if (res) {
            ALOGE("%s:%d: Failed to validate stream set", __func__, mId);
        } else {
            /* 设置stream */
            res = setupStreams(stream_config);
            if (res) {
                ALOGE("%s:%d: Failed to setup stream set", __func__, mId);
            }
        }
    
        if (!res) {
            /* 保存相应的配置 */
            mInFlightTracker->SetStreamConfiguration(*stream_config);
            // Must provide new settings for the new configuration.
            mSettingsSet = false;
        } else if (res != -EINVAL) {
            // Fatal error, the old configuration is invalid.
            mInFlightTracker->ClearStreamConfiguration();
        }
        // On a non-fatal error the old configuration, if any, remains valid.
        return res;
    }
    

    在 setupStreams() 函数又进行了什么操作呢,检查当前的多个stream的格式、分辨率等参数是否一致,然后设置格式、申请buf等。

    简单总结 configureStreams() 进行了什么操作:

    1. 检查多个stream参数是否正确有效;
    2. 确认stream的格式和分辨率一致,然后 VIDIOC_S_FMT、VIDIOC_REQBUFS,并根据返回值填充 stream 信息;
    3. 保存 stream 信息到 buffers_in_flight_;
    construct_default_request_settings()

    该函数将调用至 Camera::constructDefaultRequestSettings(),上面有提到过,Framework将会通过一些请求操作camera HAL,但是可能各个平台的HAL有个别差异,所以需要Framework在提交请求前,先获取默认请求的设置模板(实质是 CameraMetadata),从而再精确化设置具体的参数,该函数就是构造默认请求设置的。

    constructDefaultRequestSettings() 函数主要进行以下操作:

    • 在 Camera 类中,有个 mTemplates 指针数据指向了各中请求类型的 CameraMetadata,所以在检查请求类型的有效性之后,将会确认 mTemplates 是否已经保存了相应类型的数据,如果是,直接返回相应的数据;
    • 如果没有相应类型的 CameraMetadata,将通过 initTemplate() 初始化相应的数据并保存;
    process_capture_request()

    显然的,从该函数名我们就知道,它是负责处理Framework发过来的请求的,下面我们来看看,调用至 Camera::processCaptureRequest() 后又是怎么处理的?

    Camera::processCaptureRequest() 主要进行以下操作:

    • 检查输入参数的有效性;
    • 在 preprocessCaptureBuffer() 函数中,获取 output_buffers 同步防护,防止HAL操作该buffer时Framework在读取;
    • 将该请求信息添加到 mInFlightTracker;
    • 通过 enqueueRequest() 函数,添加请求到 request_queue_ 队列中,同时通过条件变量 requests_available_ 通知到 V4L2Camera::enqueueRequestBuffers() 线程进行相应的处理;
    V4L2Camera::enqueueRequestBuffers() 操作了什么?

    上面我们说到,当HAL接收到Framework请求操作时,将会把请求信息添加到 request_queue_ 队列再通过条件变量通知到 V4L2Camera::enqueueRequestBuffers() 函数(在 Camera::initialize() 中已经创建线程运行该函数了)。

    enqueueRequestBuffers() 操作如下:

    1. 通过 dequeueRequest() 函数,从 request_queue_ 队列中获取一个请求操作;
    2. 通过 SetRequestSettings() 函数设置请求中的参数;
    3. 通过 V4L2Wrapper::EnqueueRequest() 函数查询buf信息保存在 buffers_ 以及将buf添加到相机设备驱动;
    4. 接下来通过 V4L2Wrapper::StreamOn() 函数开启流传输;
    5. 最后将会通过条件变量通知到 V4L2Camera::dequeueRequestBuffers() 线程(buffer_dequeuer_线程);
    6. 在 dequeueRequestBuffers() 线程中,通过 DequeueRequest() 拿到图像数据之后,将会调用 completeRequest() 函数;
    7. 在 Camera::completeRequest() 中,处理该请求,而后从 mInFlightTracker 中移除,设置请求的时间戳,接着通过 Camera::notifyShutter() 函数调用了 mCallbackOps->notify() 函数,从而通知Framework;
    8. 最后还会通过 Camera::sendResult() 函数调用 mCallbackOps->process_capture_result() 从而Framework处理该请求信息;

    以上,HAL与Framework完成了交互。

    dump()、flush()

    dump() 函数则是dump各种设置参数等操作,而 flush() 则是进行清除 mInFlightTracker 中保存的各个请求以及通过 V4L2Wrapper::StreamOff() 函数关闭相机设备流传输以及清除buffer等。

    疑问:

    这个 CameraMetadata 是怎么初始化的?

    在 V4L2Camera::initStaticInfo() 中,将会初始化一些配置信息,就是在这里进行初始化操作的。详细可参考 天才2012 的:Android Camera API2中采用CameraMetadata用于从APP到HAL的参数交互

    参考

    Android Camera

    展开全文
  • Hello Camera2是播放预览的Android Camera2示例。 它通过NDK camera2 API控制相机设备,该设备成为Android N中的之一。 先决条件 带有 (> = r12)捆绑包的Android Studio 2.1+。 屏幕截图 触摸屏幕时,会切换一个...
  • android8.1 mtk camera hal各种操作流程

    千次阅读 2020-08-03 22:16:14
    最近一年,一直在做android上的视频编解码和录相、以及camera hal和系统框架这一块。随着做的慢慢的深入,越发觉得mtk的camera hal这一块,有其独到之处。偏偏网上相关的资料却是极少,对新入手的人而言,很难从上到...

            最近一年,一直在做android上的视频编解码和录相、以及camera hal和系统框架这一块。随着做的慢慢的深入,越发觉得mtk的camera hal这一块,有其独到之处。偏偏网上相关的资料却是极少,对新入手的人而言,很难从上到下吃透。今天闲来无事,把最近一年来,对mtk camera hal层的理解,从上到下梳理了下。现在记录下来,希望能帮到更多的有志于mtk camera hal模块的人。

            强调下,这篇博客,在自己理解的基础上,也大量参照了https://blog.csdn.net/luozirong/article/details/52244031这篇文章,有兴趣的,可以去参考一下。另外说明一下,我是家里抽了半天写的这篇文章,手头没有源代码,有些函数和文件,可能描述的不太准确,但大致思路是清晰的。

            对mtk camera hal的分析,我是从open、display、preview、previewcallback、recorder、takepicture以及hal层的buff流转来着手的。虽然写的很简单,只是从上到下的调用堆栈,但是大伙只要顺着这几条线看下去,mtk camera hal 的pass2以及往上的部份,就都能理得明白了。大伙可以再配合我前几篇camera的文章来看,对mtk camera hal应该就有个比较好的把握了。好了,下面开讲了。

    IImgBufProviderClient是用来管理IImgBufProvider,即让CamAdapter通过ImgBufProvidersManager管理DisplayClient的IImgBufProvider

    这里的IImgBufProvider是我们DiaplayClient数据队列的管理者ImgBufQueue的父类。管理着mTodoImgBufQue和mDoneImgBufQue

    上面说了ImgBufQueue继承了Provider和Process,并实现了他们的函数,其中Provider是提供给外部的类提出数据包和插入数据包,而Process是用来给内部整理和读取数据包。就如我们的DisplayClient的ImgBufQueue,DisplayClient内部生成和读取Buf通过Process系列函数,而DisplayClient把Provider系列函数提供给了CamAdapter操作数据包

    CamAdapter管理了ImageSensor,ISP等硬件的初始化和调度,3A,数据的分配流向和处理等,虽然CamAdapter没有去执行Preview,Capture,Record等操作,但却管理到了他们的数据的来源和数据的动向,最后Camadapter里还包含了Buf manager和整个Camera的状态。例如在CamAdapter中Preview的管理就包括了PreviewCmdQueThread和PreviewBufMgr,PreviewCmdQueThread的线程里接收到通知后,从Sensor取数据并交由ISP处理,3A等处理后把Buf交给PreviewBufMgr进行分配到相应的操作。如果PreviewBufMgr收到的Buf需要显示,则通过ImgBufProvidersManager找到DisplayClient里的ImgBufQueue,再把Buf插入到队列里,由ImgBufQueue进行通知显示

    1.       camera的打开的过程:

    1.) app上通过Camera.open(0);

    2.)frameworks\base\core\java\android\hardware\Camera.java里open->cameraInitNormal(cameraId)->cameraInitVersion->native_setup

    3.)frameworks\base\core\jni\android_hardware_Camera.cppandroid_hardware_Camera_native_setup

    4.)frameworks\av\camera\CameraBase.cpp 里connect

    5.)frameworks\av\services\camera\libcameraservice\CameraService.cpp里的connectHelper

    6.)CameraService::makeClient

    7.)new CameraClient

    8.)CameraClient::initialize

    9.)new CameraHardwareInterface->initialize

    10.)CameraHardwareInterface::initialize

    11.)CameraDevice::open

    12.)CameraDevice1Base::open->CameraDeviceManagerBase->startOpenDevice  在这个open函数里还调用了initHalPreviewWindow();它主要是将app上传进来的surface,传给hal层。它的定义如下

    void CameraDevice1Base::initHalPreviewWindow()

    {

        mHalPreviewWindow.cancel_buffer = sCancelBuffer;

        mHalPreviewWindow.lock_buffer = sLockBuffer;

        mHalPreviewWindow.dequeue_buffer = sDequeueBuffer;

        mHalPreviewWindow.enqueue_buffer = sEnqueueBuffer;

        mHalPreviewWindow.set_buffer_count = sSetBufferCount;

        mHalPreviewWindow.set_buffers_geometry = sSetBuffersGeometry;

        mHalPreviewWindow.set_crop = sSetCrop;

        mHalPreviewWindow.set_timestamp = sSetTimestamp;

        mHalPreviewWindow.set_usage = sSetUsage;

        mHalPreviewWindow.set_swap_interval = sSetSwapInterval;

     

        mHalPreviewWindow.get_min_undequeued_buffer_count =

                sGetMinUndequeuedBufferCount;

    }

     

    1. camera设置preview窗口的过程
    1. )app上调用camera.setPreviewDisplay(SurfaceHolder);
    2. )frameworks/base/core/java/android/hardware/Camera.java里setPreviewDisplay

    3.) Camera.java里setPreviewSurface(holder.getSurface());

    4.) frameworks\base\core\jni\android_hardware_Camera.cppandroid_hardware_Camera_setPreviewSurface

    5.) frameworks/av/camera/Camera.cpp里Camera::setPreviewTarget(const sp<IGraphicBufferProducer>& bufferProducer)

    6.) CameraClient::setPreviewTarget( const sp<IGraphicBufferProducer>& bufferProducer)

    7.)CameraClient::setPreviewWindow(const sp<IBinder>& binder, const sp<ANativeWindow>& window)

    8.)CameraHardwareInterface::setPreviewWindow(const sp<ANativeWindow>& buf)

    9.)CameraDevice.cpp::setPreviewWindow

    10.)CameraDevice1Base.cpp::setPreviewWindow

    11.)CameraDevice1Base.cpp::initDisplayClient

    12.)DisplayClient::setWindow()

    13.)DisplayClient:: set_preview_stream_ops() ----> mpStreamOps = window

     

    1. 预览的过程
    1. )紧跟着上面一部份,在)CameraDevice1Base.cpp::initDisplayClient
    2. )IDisplayClient::createInstance() 
    3. )DisplayClient::init()
    4. )createDisplayThread()&& createImgBufQueue()
    5. )cameraDevice1Base::enableDisplayClient()
    6. )DisplayClient::enableDisplay()
    7. )DisplayClient::enableDisplay()-
    8. ) mpDisplayThread-> postCommand(Command(Command::eID_WAKEUP)) 
    9. )DisplayThread::threadLoop() 
    10. )DisplayClient::onThreadLoop()
    11. )DisplayClient::waitAndHandleReturnBuffers
    12. )rpBufQueue->dequeProcessor(vQueNode)
    13. )DisplayClient::handleReturnBuffers()
    14. )enquePrvOps() 
    15. )mpStreamOps->enqueue_buffer(mpStreamOps,rpImgBuf->getBufHndlPtr())  (mpStreamOps这个就是app上传下来的surface)

    如果把上面enqueue_buffer这一部份给删除,则预览界面无显示. 所以总体来说是在DisplayClient的init的时候创建了一个线程:

    mpDisplayThread =IDisplayThread::createInstance(this)

    一个队列:

    mpImgBufQueue = newImgBufQueue(IImgBufProvider::eID_DISPLAY, "CameraDisplay@ImgBufQue");

    然后mpDisplayThread等待ImgBufQueue有数据的时候通过dequeProcessor取到要渲染的数据,交给mpStreamOps也就是preview_stream_ops对象,其实preview_stream_ops只是对ANativeWindow的简单封装,最后调用的其实是ANativeWindow的queueBuffer函数

     

    1. 录相的过程
    1. )CameraClient::startRecordingMode
    2. )CameraHardwareInterface::startRecording()

    3.)vendor\mediatek\proprietary\hardware\mtkcam\main\hal\device\1.x\device\CameraDevice.cpp

    mpDevice->startRecording();

    4.)CameraDevice1Base::startRecording()->mpCamClient->startRecording

    5.)vendor\mediatek\proprietary\hardware\mtkcam\middleware\v1\client\CamClient\CamClient::startRecording()->mpRecordClient->startRecording()

    6.)vendor\mediatek\proprietary\hardware\mtkcam\middleware\v1\client\CamClient\Record\RecordClient.cpp  


    RecordClient::startRecording()

     

    7.) RecordClient::
    onStateChanged()->postCommand(Command(Command::eID_WAKEUP)); 

    8.)RecordClient.Thread.cpp里的
    threadLoop()

    9.)RecordClient.Thread.cpp里的onClientThreadLoop, prepareAllTodoBuffers->pBufQueue->startProcessor()->waitAndHandleReturnBuffers(pBufQueue, blocking)

    在onClientThreadLoop函数里,通过prepareAllTodoBuffers去准备好接收收据的buff,prepareAllTodoBuffers的第一个参数就是在init里初始化的mpImgBufQueue, 在这里赋值给了pBufQueue,在prepareAllTodoBuffers里, 通过enqueProcessor将当前的帧放到了mpImgBufQueue 里。

     再在onClientThreadLoop里, 调用pBufQueue->startProcessor() 去通知处理。      然后再通过waitAndHandleReturnBuffers去处理这些buff.这个函数里,通过rpBufQueue->dequeProcessor(vQueNode);来取刚刚得到的帧buff,最后丢给handleReturnBuffers处理理。     waitAndHandleReturnBuffers定义在vendor\mediatek\proprietary\hardware\mtkcam\middleware\v1\client\CamClient\Record\RecordClient.BufOps.cpp里. 在waitAndHandleReturnBuffers中,通过rpBufQueue->dequeProcessor(vQueNode);,去获取当前帧,然后通过handleReturnBuffers去处理, 最后取到帧后,会丢给performRecordCallback去回调给app

    1.  

     

     IImgBufProvider的设置过程:

    DisplayClient::enableDisplay ()---->DisplayClient::setImgBufProviderClient (mpCamAdapter)----> IImgBufProviderClient::onImgBufProviderCreated(mpImgBufQueue) ---->BaseCamAdapter::

    onImgBufProviderCreated(sp<IImgBufProvider>const&rpProvider) ----> ImgBufProvidersManager::setProvider()

             Camera的数据来源

             DefaultCam1Device::onStartPreview()----> Cam1DeviceBase::initCameraAdapter() ----> CamAdapter::init() ---->IPreviewCmdQueThread::createInstance() ----> CamAdapter::startPreview() ---->StateIdle::onStartPreview() ----> CamAdapter::onHandleStartPreview() ---->mpPreviewCmdQueThread->postCommand(PrvCmdCookie::eUpdate, PrvCmdCookie::eSemBefore)----> PreviewCmdQueThread::threadLoop()----> PreviewCmdQueThread::update()----> PreviewCmdQueThread::updateOne() ----> PreviewBufMgr::enqueBuffer()----> IImgBufProvider:: enqueProvider()

    5.Camera预览数据回调流程

    api1去预览,并且在app上通过setPreviewCallBack设置预览回调,想获取预览数据的流程如下:

    1. )app调用Camera.java的startPreview, setPreviewCallback
    2. )android_hardware_Camera.cpp里的android_hardware_Camera_startPreview
    3. )Camera.cpp Camera::startPreview()
    4. )CameraClient::startPreview()
    5. CameraClient::startCameraMode
    6. CameraClient::startPreviewMode()
    7. CameraHardwareInterface::startPreview
    8. )CameraDevice::startPreview

    {

    //(1) 此函数在其子类DefaultCam1Device中实现

    //仅是初始化了CameraAdapter

    onStartPreview();

     

    //(2) 初始化DisplayClient,重要,稍后研究

    enableDisplayClient();

    //(3)

    mpCamClient->startPreview();

    //(4) 我们通过(3)和(4)开始研究,再返回去看(1)(2)

    mpCamAdapter->startPreview();

     

    enableMsgType(CAMERA_MSG_PREVIEW_METADATA);

    //

    mIsPreviewEnabled = true;

    }

    1. )CamClient::startPreview()里的mpCamclient->startPreview()
    2. )PreviewClient::startPreview(),这个里面会去调用initBuffers();

    PreviewClient::startPreview()

    {

    //获得预览参数,这里参数为800*480,yuv420sp

    ms8PrvTgtFmt = mpParamsMgr->getPreviewFormat();

    mpParamsMgr->getPreviewSize(&mi4PrvWidth, &mi4PrvHeight);

    //初始化预览Buf

    initBuffers();

    //

    return onStateChanged();

    }

     

    PreviewClient::initBuffers()

    {

    //预览数据的Buf

    mpImgBufMgr = ImgBufManager::alloc(ms8PrvTgtFmt, mi4PrvWidth,

    mi4PrvHeight, eMAX_PREVIEW_BUFFER_NUM, 

    "PreviewClientCb", mpCamMsgCbInfo->mRequestMemory,

    0, 0);

     

    //预览数据的处理类,这里只是保留了一个处理接口

    //里面并没有什么东西,可自行填充

    mpExtImgProc = ExtImgProc::createInstance(); 

    mpExtImgProc->init();

    }

     

    PreviewClient::onStateChanged()

    { //发送了一个eID_WAKEUP的消息

    postCommand(Command(Command::eID_WAKEUP)); 

    }

     

    //接收eID_WAKEUP消息

    PreviewClient::threadLoop()

    {

    Command cmd;

    if ( getCommand(cmd) )

    {

    switch (cmd.eId)

    {

    case Command::eID_WAKEUP:

    case Command::eID_PREVIEW_FRAME:

    case Command::eID_POSTVIEW_FRAME:

    onClientThreadLoop(cmd);

    break;

    //

    case Command::eID_EXIT:

    //...

    }

    }

    1. )PreviewClient::onClientThreadLoop开始处理数据Buf
    2. )PreviewClient::waitAndHandleReturnBuffers(sp<IImgBufQueue>const& rpBufQueue)
    3. )PreviewClient::handleReturnBuffers(Vector<ImgBufQueNode>const& rvQueNode). 这个函数会调用到performPreviewCallback
    4. )PreviewClient::performPreviewCallback(sp<ICameraImgBuf>const& pCameraImgBuf, int32_t const msgType)。这个函数里,会调用到pCamMsgCbInfo->mDataCb函数。这个函数,就是在CameraClient.cpp的initialize()函数里,通过mHardware->setCallbacks(notifyCallback, dataCallback, dataCallbackTimestamp, (void *)mCameraId);这句话其中的dataCallback,设置的mDataCb函数。也就是app上调用这句话其中的dataCallback,设置了mDataCb函数传下来的回调函数。这里会将数据传到app层上去。

    6.拍照的流程:

    CamAdapter::takePicture()-> IState::onCapture() ->IStateHandler::onHandleCapture() ->CamAdapter::onHandleCapture()CamAdapter::onHandleCapture() ->CaptureCmdQueThread::onCapture() -> CaptureCmdQueThread::threadLoop() ->CamAdapter::onCaptureThreadLoop()->CapBufShot::sendCommand()->CapBufShot::onCmd_capture()-> SingleShot::startOne()在这里组装IImgBuffer

    7.拍照回调的流程:

    SingleShot::startOne() --> CamShotImp::handleDataCallback() --> CamShotImp::onDataCallback--> CapBufShot::fgCamShotDataCb --> CapBufShot::handleJpegData  -->CamAdapter::onCB_RawImage -->mpCamMsgCbInfo->mDataCb

    ##注意两个两个标红的和标蓝的,他们这样就头尾对起来了。

     

    1.所谓的Camera主要就是从摄像头取一点数据放到LCD上显示,所以打蛇打七寸,我们首先介绍HAL层的Window对象是mpStrwamOps。而这个对象被设置的流程是:

    Cam1DeviceBase::setPreviewWindow()  --->  initDisplayClient()  ---> DisplayClient::setWindow()  ---> set_preview_stream_ops()  ---> mpStreamOps = window

    2.另一个面我们看下数据的获取流程,Camera HAL层数据主要通过ImgBufQueue对象传递,而这个对象最开始的赋值过程如下:

    CamAdapter::takePicture() -> IState::onCapture() ->IStateHandler::onHandleCapture() -> CamAdapter::onHandleCapture()CamAdapter::onHandleCapture() -> CaptureCmdQueThread::onCapture() -> CaptureCmdQueThread::threadLoop() -> CamAdapter::onCaptureThreadLoop()->CapBufShot::sendCommand()->CapBufShot::onCmd_capture() -> SingleShot::startOne()在这里组装IImgBuffer

     

    1.  

     

     

    8.)CamAdapter, pass1分发到pass2的过程

    1.)我们从DefaultCam1Device.cpp开始看起, DefaultCam1Device::onStartPreview()

    2.)Cam1DeviceBase::initCameraAdapter()

    {

    ....

    mpCamAdapter = ICamAdapter::createInstance(mDevName, mi4OpenId, mpParamsMgr);

    ....

    // (.4) [DisplayClient] set Image Buffer Provider Client if needed.

    mpDisplayClient->setImgBufProviderClient(mpCamAdapter);

    // (.5) [CamClient] set Image Buffer Provider Client if needed.

    mpCamClient->setImgBufProviderClient(mpCamAdapter);

    }

    3.)ICamAdapter::createInstance会调到MtkDefaultCamAdapter.cpp里的

    CamAdapter::init()

    {

    //PreviewBufMgr

    mpPreviewBufMgr = IPreviewBufMgr::createInstance(mpImgBufProvidersMgr);

    //PreviewCmdQueThread,注意第一个参数为PreviewBufMgr

    mpPreviewCmdQueThread = IPreviewCmdQueThread::createInstance(mpPreviewBufMgr, getOpenId(), mpParamsMgr);

    mpPreviewCmdQueThread->run();

     

    //CaptureCmdQueThread

    mpCaptureCmdQueThread = ICaptureCmdQueThread::createInstance(this);

    mpCaptureCmdQueThread->run();

     

    //就是相机的3个Auto,自动曝光,自动对焦,自动白平衡

    init3A();

    }

    4.)CamAdapter::startPreview()

    5.)state.cpp里的StateIdle::onStartPreview(IStateHandler* pHandler)

    6.)CamAdapter::onHandleStartPreview()里会调用mpPreviewCmdQueThread->postCommand(PrvCmdCookie::eStart, PrvCmdCookie::eSemAfter); ”

    7.)PreviewCmdQueThread.cpp PreviewCmdQueThread::threadLoop()

    {

    ....

    case PrvCmdCookie::eStart:

    isvalid = start();

    break;

    ....

    }

    8.)PreviewCmdQueThread::start()

    {

    ....

    for (int32_t i = 0; i < PASS1BUFCNT; i++)

    {

    //取出刚才创建的Buf

    mspPreviewBufHandler->dequeBuffer(eID_Pass1Out, Pass1Node);

    //获取bufinfo

    mapNode2BufInfo(eID_Pass1Out, Pass1Node, BufInfo);

    //收集bufinfo

    vBufPass1Out.push_back(BufInfo);

    }

    ......

    预览

    if (flag & eID_Pass2DISPO)

    {

    dispNode.getImgBuf()->setTimestamp(pass1LatestTimeStamp);

    //通知Client的接收队列,进行接收处理

    mspPreviewBufHandler->enqueBuffer(dispNode);

    }

    //录相

    if (flag & eID_Pass2VIDO)

    {

    vidoNode.getImgBuf()->setTimestamp(pass1LatestTimeStamp);

    mspPreviewBufHandler->enqueBuffer(vidoNode);

    }

    }

    9.)PreviewBufMgr::enqueBuffer(ImgBufQueNode const& node)

    {

    ....

    //这里将从pass1取出来的数据分发给pass2

    case eBuf_Disp:

    {

    //从Provider的队列中找到Id为eID_DISPLAY的Provider,

    sp<IImgBufProvider> bufProvider = mspImgBufProvidersMgr->getDisplayPvdr();

    /**

    在DisplayClient::waitAndHandleReturnBuffers()中,调用了ImgBufQueue.cpp dequeProcessor()

    dequeProcessor()里mDoneImgBufQueCond.wait()会一直在等待。直到下面的函数被调用了

    就会把buf传进去,并 mDoneImgBufQueCond.broadcast();通知接收buf

    **/

    bufProvider->enqueProvider(node);

    }

    break;

    //...

    case eBuf_Rec:

    ....

    }

    看到这里验证了我们之前的猜想,CamAdapter管理了ImageSensor,ISP等硬件的初始化和调度,3A,数据的分配流向和处理等,虽然CamAdapter没有去执行Preview,Capture,Record等操作,但却管理到了他们的数据的来源和数据的动向,最后Camdapter里还包含了Buf manager和整个Camera的状态。例如在CamAdapter中Preview的管理就包括了PreviewCmdQueThread和PreviewBufMgr,PreviewCmdQueThread的线程里接收到通知后,从Sensor取数据并交由ISP处理,3A等处理后把Buf交给PreviewBufMgr进行分配到相应的操作。如果PreviewBufMgr收到的Buf需要显示,则通过ImgBufProvidersManager找到DisplayClient里的ImgBufQueue,再把Buf插入到队列里,由ImgBufQueue进行通知显示

     

                本人建了个android camera系统 微信群,不过现在群成员超200了,不能通过二维码扫码加入,有兴趣的,可以加我微信号:xuhui_7810,到时拉你们入群。

     

    展开全文
  • camera HAL3 架构

    2019-11-02 11:53:30
    Android Camera整体框架主要包括三个进程:app进程、camera server进程、hal进程。进程之间的通信都是通过binder实现,其中app和camera server通信使用aidl,camera server和hal通信使用hidl。Android Camera2整体...
  • Camera HAL1&HAL3的区别

    2021-09-16 22:30:02
    1.HAL 1 概述 由于相机 HAL1 已弃用,建议在搭载 Android 9 或更高版本的设备上使用相机 HAL3. 相机子系统的第 1 个版本被设计为具有高级控件和以下三种运行模式的黑盒子: 预览 视频录制 静态拍摄 三种模式...
  • Hal需要实现的接口就是libhardware\include\hardware\camera3.h typedef struct camera3_device { /** * common.version must equal CAMERA_DEVICE_API_VERSION_3_0 to identify this * device as implementing ...
  • Android Camera HAL3-metadata

    千次阅读 2020-03-28 11:31:47
    Metadata 是整个 Android camera 中类似于高楼大厦中的管道系统一样,贯穿了整个 Camera 的 Framework 和 vendor HAL,Metadata 里面几乎包含了所有的控制、参数、返回值等等,总线型的设计使得这个玩意儿承担的任务...
  • Android Camera HAL3 - 框架流程预览

    千次阅读 2019-09-22 11:32:58
    前面说了 HAL3 是一个总线型的设计结构,本文就先对 HAL3 的控制流进行一个提纲挈领式的概述,主要理解整个 HAL3 的主干框架,以便对后续深入各个细节。 主干流程 以下全部都是摘抄 Google 官方网站上面介绍的 ...
  • camera hal学习

    2020-04-09 20:11:47
    转载https://www.cnblogs.com/blogs-of-lxl/p/10668554.html
  • */ eImgFmt_CAMERA_OPAQUE = HAL_PIXEL_FORMAT_CAMERA_OPAQUE, /*!, RAW10 + Metadata */ eImgFmt_YUV_P010 = HAL_PIXEL_FORMAT_YCBCR_P010, /*!, 16bit, 2 plane (Y),(UV) = P010 */ //... } 需要在JpegNode.cpp...
  • Camera HAL 3 & HAL 1

    千次阅读 2019-10-28 12:00:00
    和你一起终身学习,这里是程序员 Android本篇文章主要介绍Android开发中的部分知识点,通过阅读本篇文章,您将收获以下内容:一、HAL 3 简介一、HAL 3...
  • camera hal

    2020-05-12 16:49:39
    https://www.cnblogs.com/blogs-of-lxl/p/10651611.html
  • android camera hal3 新增vendor tag

    千次阅读 热门讨论 2020-09-07 15:55:24
    前段时间,我在android8.1的系统层上,新增了一个usbcamera hal,和一个虚拟摄像头hal。在实际使用的过程中,遇到了一个问题——客户app在用camera api接口调用usbcamera或virtual camera时,希望能够知道当前调用的...
  • Camera HAL3 内存优化

    2021-06-06 15:02:57
    总有些项目的内存优化落到Camera头上,从Hal1到Hal3,永不停歇...以下适用于HAL3(Android P).总所周知,内存与Performance在某些条件下,是无法调和的矛盾,请大家根据各项目状态酌情选用.解决方案内存用量概要:adb...
  • Android Camera HAL浅析

    2020-03-30 20:01:13
    Android Camera框架 Android的Camera子系统提供一个拍照和录制视频的框架。 它将Camera的上层应用与Application Framework、用户库串接...Camera HAL层部分 源码平台:rk3288 代码存放目录:hardware/rockchip/ca...
  • Camera HAL3学习

    2019-05-23 16:22:29
    转自:Camera HAL3学习 Android Camera System Android Camera硬件抽象层(HAL,Hardware Abstraction Layer)主要用于把底层camera drive与硬件和位于android.hardware中的framework APIs连接起来。Camera子系统...
  • Camera hal 之 CameraProvider 一、CameraProvider的作用二、CameraProvider的启动、初始化 一、CameraProvider的作用 cameraProvider的主要作用就是向下调用CameraModule,通过CameraModule 来和 Camera driver ...
  • Camera HAL3 简介

    千次阅读 2018-12-21 14:20:50
    Android 的相机硬件抽象层 (HAL) ...Android 8.0 引入了 Treble,用于将 CameraHal API 切换到由 HAL 接口描述语言 (HIDL) 定义的稳定接口。如果您之前为旧版 Android 开发过相机 HAL 模块和驱动程序,请注意相机管...
  • Camera HAL3的整体架构和流程(二)

    千次阅读 多人点赞 2020-09-12 23:49:01
    这是Google官方的Camera架构,Google封装了HAL层接口:ICameraProvider, ICameraDevice, ICameraDeviceSession。 这几个接口的作用如下: ICameraProvider:用于枚举单个设备并管理其状态。 ICameraDevice:相机...
  • Android Q 之MTK代码分析(一)--Camera Hal3 Service

    千次阅读 多人点赞 2020-06-16 18:34:53
    先简单看一下MTK Camera HAL层的框架,大概了解关联部分有camea service、camera provider、camera hal service、 camera device manager、camera device这五部分。 再了解下Android框架启动过程 参考链接:...
  • 说明:转载自 Android Camera,不定期添加自己的...Android’s camera Hardware Abstraction Layer (HAL) connects the higher level camera framework APIs in android.hardware.camera2 to your underlying camera...
  • 1. Android系统中Camera模块版本号的历史演变进度 .../** * All module versions * as CAMERA_MODULE_API_VERSION_1_0 */ #define CAMERA_MODULE_API_VERSION_1_0 HARDWARE_MODULE_API_VE
  • 本文参考: ...Session Parameter 是用于在 configure_streams 阶段就进行初始化配置的选项,类似于之前的 setParameters 的作用,自 camera 的架构改成全部参数使用 metadata 来传递之后,在 configure
  • Camera HAL3的整体架构和流程(一)

    千次阅读 2020-08-24 00:08:12
    本文基于Android P的Camera HAL3架构,以MTK平台为例,分析Camera HAL3的体系结构和调用流程。本文是描述关于MTK平台如何重写Android所定义的ICameraProvider, ICameraDevice, ICameraDeviceSession HIDL interfaces...
  • 本地写了几篇之后发现不把camera server和hal的初始化写完,直接开始写API调用流程的话不太好写。还是从服务的初始化开始写吧。 代码流程分析 我就按照自己习惯的学习一个新的模块的思路来写。 先通过ps命令看一下...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 8,882
精华内容 3,552
关键字:

camerahal