高通camera框架:初理解之三_HAL3.0简介_整理

HAL3.0  Frameworks层总体框架

v3将更多的工作集中在了Framework去完成,将更多的控制权掌握在自己的手里,从而与HAL的交互的数据信息更少,也进一步减轻了一些在旧版本中HAL层所需要做的事情,也更加模块化。

下面以initialize为起点进行分析:

Camera2Client后会进行initialize操作,完成各个处理模块的创建:

代码目录:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp

 

依次分别创建了:

1、StreamingProcessor并启动一个它所属的thread,该模块主要负责处理previews与record两种视频流的处理,用于从hal层获取原始的视频数据

2、FrameProcessor并启动一个thread,该模块专门用于处理回调回来的每一帧的3A等信息,即每一帧视频除去原始视频数据外,还应该有其他附加的数据信息,如3A值。

3、CaptureSequencer并启动一个thread,该模块需要和其他模块配合使用,主要用于向APP层告知capture到的picture。

4、JpegProcessor并启动一个thread,该模块和streamprocessor类似,他启动一个拍照流,一般用于从HAL层获取jpeg编码后的图像照片数据。

5另外ZslProcessor模块称之为0秒快拍,其本质是直接从原始的Preview流中获取预存着的最近的几帧,直接编码后返回给APP,而不 需要再经过take picture去请求获取jpeg数据。0秒快拍技术得意于当下处理器CSI2 MIPI性能的提升以及Sensor支持全像素高帧率的实时输出。一般手机拍照在按下快门后都会有一定的延时,是因为需要切换底层Camera以及ISP 等的工作模式,并重新设置参数以及重新对焦等等,都需要花一定时间后才抓取一帧用于编码为jpeg图像。

以上5个模块整合在一起基本上实现了Camera应用开发所需的基本业务功能。

2.3.2 Preview模式下的控制流

代码目录,直接以Camera2Client::startPreview()作为入口来分析整个Framework层中Preview相关的数据流

   1、调用Camera2Client::startPreview函数

代码目录-1:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp

 

startPreview通过startPreviewL提取参数后真正的开始执行Preview相关的控制流。该函数看上去内容虽然较多,但基本采用了同一种处理方式:

  • 2、  调用Camera2Client::startPreviewL函数

代码目录-1:frameworks/av/services/camera/libcameraservice/api1/Camera2Client.cpp

后面会详细介绍2.1-2.6粗体标注部分;

 

2.1、调用mStreamingProcessor->updatePreviewStream函数

   代码目录-2:

frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp

 

该函数首先是查看当前StreamingProcessor模块下是否存在Stream,没有的话,则交由Camera3Device创建一个 stream。显然,一个StreamingProcessor只能拥有一个PreviewStream,而一个Camera3Device显然控制着所 有的Stream。

注意:在Camera2Client中,5大模块的数据交互均以stream作为基础。

下面我们来重点关注Camera3Device的接口createStream,他是5个模块创建stream的基础:

      代码目录-3:

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

 

该函数重点是关注一个new Camera3OutputStream,在Camera3Device主要存在Camera3OutputStream和Camera3InputStream,两种stream,前者主要作为HAL的输出,是请求HAL填充数据的OutPutStream,后者是由Framework将Stream进行填充。无论是Preview、record还是capture均是从HAL层获取数据,故都会以OutPutStream的形式存在,是我们关注的重点,后面在描述Preview的数据流时还会进一步的阐述。

每当创建一个OutPutStream后,相关的stream信息被push维护在一个mOutputStreams的KeyedVector表中,分别是该stream在Camera3Device中创建时的ID以及Camera3OutputStream的sp值。同时对mNextStreamId记录下一个Stream的ID号。

上述过程完成StreamingProcessor模块中一个PreviewStream的创建,其中Camera3OutputStream创建时的ID值被返回记录作为mPreviewStreamId的值,此外每个Stream都会有一个对应的ANativeWindow,这里称之为Consumer。

2.2、调用updateProcessorStream(mJpegProcessor, params)函数

代码目录-2:

frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp

 

该模板函数处理过程最终通过非显示实例到显示实例调用JpegProcessor::updateStream,该函数处理的逻辑基本和Callback 模块处理一致,创建的一个OutPutStream和CaptureWindow相互绑定,同时Stream的ID保存在 mCaptureStreamId中。

此外需要说明一点:

在preview模式下,就去创建一个jpeg处理的stream,目的在于启动takepicture时,可以更快的进行capture操作,是通过牺牲内存空间来提升效率。

2.3、调用mCallbackProcessor->updateStream函数

代码目录-2:

frameworks/av/services/camera/libcameraservice/api1/client2/CallbackProcessor.cpp

对比StreamingProcessor模块创建previewstream的过程,很容易定位到Callback模块是需要建立一个 callback流,同样需要创建一个Camera3OutputStream来接收HAL返回的每一帧帧数据,是否需要callback可以通过 callbackenable来控制。一般但预览阶段可能不需要回调每一帧的数据到APP,但涉及到相应的其他业务如视频处理时,就需要进行 callback的enable。

 

2.4、整合startPreviewL中所有的stream 到Vector outputStreams

outputStreams.push(getPreviewStreamId());//预览stream

outputStreams.push(getCallbackStreamId())//Callback stream

目前一次Preview构建的stream数目至少为两个。

2.5、调用mStreamingProcessor->updatePreviewRequest函数

代码目录-2:

frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp

在创建好多路stream后,由StreamingProcessor模块来将所有的stream信息交由Camera3Device去打包成Request请求。

注意:

Camera HAL2/3的特点是:将所有stream的请求都转化为几个典型的Request请求,而这些Request需要由HAL去解析,进而处理所需的业务,这也是Camera3数据处理复杂化的原因所在。

 

a mPreviewRequest是一个CameraMetadata类型数据,用于封装当前previewRequest;

b 调用device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW, &mPreviewRequest)函数

代码目录-3:

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

 

最终是由hal来实现构建一个rawrequest,即对于Preview,而言是构建了一个CAMERA3_TEMPLATE_PREVIEW类型的 Request。其实对HAL而言,rawrequest本质是用于操作一个camera_metadata_t类型的数据:

 

该数据结构可以存储多种数据,且可以根据entry tag的不同类型来存储数据,同时数据量的大小也可以自动调整;

c mPreviewRequest.update(ANDROID_REQUEST_ID,&mPreviewRequestId, 1)

将当前的PreviewRequest相应的ID保存到camera metadata。

2.6、调用mStreamingProcessor->startStream函数启动整个预览的stream流

代码目录-2:

frameworks/av/services/camera/libcameraservice/api1/client2/StreamingProcessor.cpp

该函数的处理过程较为复杂,可以说是整个Preview正常工作的核心控制:

 

该函数首先是根据当前工作模式来确定StreamingProcessor需要处理的Request,该模块负责Preview和Record两个Request。

以PreviewRequest就是之前createDefaultRequest构建的,这里先是将这个Request所需要操作的Outputstream打包到一个tag叫ANDROID_REQUEST_OUTPUT_STREAMS的entry当中。

      a 调用setStreamingRequest函数

      代码目录:

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

真正的请求Camera3Device去处理这个带有多路stream的PreviewRequest。

a.1

 

该函数将mPreviewRequest push到一个list,调用setStreamingRequestList

a.2

 

a.3

 

a.4 convertMetadataListToRequestListLocked

这个函数是需要将Requestlist中保存的CameraMetadata数据转换为List;

 

这里是对List进行迭代解析处理,如当前模式下仅存在PreviewRequest这一个CameraMetadata,通过setUpRequestLocked将其转换为一个CaptureRequest。

a.5 setUpRequestLocked

          

 

configureStreamsLocked函数主要是将Camera3Device侧建立的所有Stream包括Output与InPut格式 的交由HAL3层的Device去实现处理的核心接口是configure_streamsregister_stream_buffer

createCaptureRequest函数是将一个CameraMetadata格式的数据如PreviewRequest转换为一个CaptureRequest:

a.6

 

该函数主要处理指定的这个CameraMetadata mPreviewRequest下对应所拥有的Output与Input Stream,对于Preview而言,至少存在OutPutStream包括一路StreamProcessor与一路可选的 CallbackProcessor。

在构建这个PreviewRequest时,已经将ANDROID_REQUEST_OUTPUT_STREAMS这个Tag进行了初始化,相应的内容为Vector &outputStreams,包含着属于PreviewRequest这个Request所需要的输出stream的ID值,通过这个ID index值,可以遍历到Camera3Device下所createstream创造的Camera3OutputStream,即说明不同类型的 Request在Camera3Device端存在多个Stream,而每次不同业务下所需要Request的对应的Stream又仅是其中的个别而已。

idx = mOutputStreams.indexOfKey(streams.data.i32[i])是通过属于PreviewRequest中包含的一个 stream的ID值来查找到mOutputStreams这个KeyedVector中对应的标定值index。注意:两个索引值不一定是一致的。

mOutputStreams.editValueAt(idx)是获取一个与该ID值(如Previewstream ID、Callback Stream ID等等)相对应的Camera3OutputStream。

在找到了当前Request中所有的Camera3OutputStream后,将其维护在CaptureRequest中:

 

mSettings是保存CameraMetadata PreviewRequest,vector mOutPutStreams保存着当前Request提取出来的Camera3OutputStream,至此构建了一个CaptureRequest。

回到a.4:convertMetadataListToRequestListLocked

返回到convertMetadataListToRequestListLocked中,现在已经完成了一个CameraMetadata Request的处理,生产的是一个CaptureRequest。我们将这个ANDROID_REQUEST_ID的ID值,保留在newRequest->mResultExtras.requestId = it->find(ANDROID_REQUEST_ID).data.i32[0]。

这个值在整个Camera3的架构中,仅存在3大种Request类型,说明了整个和HAL层交互的Request类型是不多的:

预览Request mPreviewRequest

 

拍照Request mCaptureRequest

 

录像Request mRecordingRequest

 

 

回到a.3:mRequestThread->setRepeatingRequests(requestList)

对于Preview来说,一次Preview后底层硬件就该可以连续的工作,而不需要进行过多的切换,故Framework每次向HAL发送的Request均是一种repeat的操作模式,故调用了一个重复的RequestQueue来循环处理每次的Request。

 

将Preview线程提交的Request加入到mRepeatingRequests中后,唤醒RequestThread线程去处理当前新的Request。

2.7、经过2.6步骤将开启RequestThread 请求处理线程

RequestThread::threadLoop()函数主要用于响应并处理新加入到Request队列中的请求。

代码目录-2:

frameworks/av/services/camera/libcameraservice/device3/Camera3Device.cpp

 

a.1 waitForNextRequest()

   

 

该函数是响应RequestList的核心,通过不断的轮训休眠等待一旦mRepeatingRequests有Request可处理时,就将他内部所有 的CaptureRequest加入到mRequestQueue 中去,理论来说每一个CaptureRequest对应着一帧的请求处理,每次响应时可能会出现mRequestQueue包含了多个 CaptureRequest。

通过nextRequest->mResultExtras.frameNumber = mFrameNumber++表示当前CaptureRequest在处理的一帧图像号。

对于mRepeatingRequests而言,只有其非空,在执行完一次queue操作后,在循环进入执行时,会自动对 mRequestQueue进行erase操作,是的mRequestQueue变为empty后再次重新加载mRepeatingRequests中的 内容,从而形成一个队repeatRequest的重复响应过程。

a.2

 

提取该CaptureRequest对应的 Request 类型值;

a.3 getBuffer操作

a.4

 

这里的request是已经由一个CaptureRequest转换为和HAL3.0交互的camera3_capture_request_t结构。

  • 3、  总结

 

至此已经完成了一次向HAL3.0 Device发送一次完整的Request的请求。从最初Preview启动建立多个OutPutStream,再是将这些Stream打包成一个 mPreviewRequest来启动stream,随后将这个Request又转变为一个CaptureRequest,直到转为Capture list后交由RequestThread来处理这些请求。每一次的Request简单可以说是Camera3Device向HAL3.0请求一帧数据, 当然每一次Request也可以包含各种控制操作,如AutoFocus等内容。

微信扫码打赏

作者: RESSRC

个人资源站

发表评论

电子邮件地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据