高通camera框架_流程浅析(1)

该文档主要浅析camera框架,后续会增加机制相关内容:

1.    Introduction

本文档主要讲解高通Camera整体框架。


部分内容或参考资料可参考个人博客Android开发栏目:http://blog.sina.com.cn/betterforlife 


2.   高通Camera框架简介
总体框图如下:




下面简要走一下流程,不涉及具体代码:


1、初始化CameraService


在frameworks/av/media/mediaserver/Main_mediaserver.cpp中会对CameraService进行初始化:


CameraService::instantiate();


CameraService的父类BinderService定义了instantiate()函数:


static void instantiate() { publish(); }


CameraService的启动发生在init.rc中:


service media /system/bin/mediaserver


class main


user media


group audio camerainet net_bt net_bt_admin net_bw_acct drmrpc


在CameraService初始化过程会从hal层获取一些基本信息,如支持的最大camera数目,如下图所示:




2、连接CameraService


如下图所示:




2.1 Hal 1.0版本框架分析
以设置camera sharpness(锐度)参数为例:


数据流app parameter->Java interface->jni->cameraclient->binder->camera service->hal->daemon->kernel


    如下图所示:




 


2.2 Hal v3与v1区别与过渡
2.2.1 简介
在Android 5.0上,Google正式的将Camera HAL 3.0作为一个标准配置进行了发行,当然Camera HALV1也是作为兼容标准可用。


HAL V3与V1本质区别是把帧的参数和帧的图像数据绑定到了一起,比如V1的时候一张preview上来的YUV帧,APP是不知道这个 YUV帧采用的Gain和曝光时间究竟是多少,但是在V3


里面,每一帧都有一个数据结构来描述,其中包括了帧的参数和帧的数据,当APP发送一个request的时候是需要指定使用什么样的参数,到request返回的时候,返回数据中就有图像数据和相关的参数配置。


2.2.2 HAL 1.0参数设置
A、V1增加设定参数:增加OIS光学防抖参数设置(ois参数一般不作为设置参数,在本文档仅作实验测试),仅作流程分析对比。


1)  添加接口函数,参考public void setSaturation(int saturation)设置


在code/frameworks/base/core/Java/android/hardware/Camera.java文件增加接口:


        publicvoid setOis(int saturation){


              …………


             set(KEY_QC_OIS, String.valueOf(OIS));


}


2)  App设置参数调用,假设设置ois值为1


参考packages/apps/SnapdragonCamera/src/com/android/camera/PhotoModule.java


mParameters.setSaturation(saturation);函数调用;


mParameters.setOis(ois);


由于HAL V1参数传递是通过字符串来完成的,最后传递到HAL层的字符串里面会有“ois=1”,在HAL层进行解析。


   B、Hal层相关修改:


1、    添加相关定义


1.1、 文件:hardware/qcom/camera/QCamera2/HAL/QCameraParameters.h


     static const char KEY_QC_SCE_FACTOR_STEP[];


+    static const char KEY_QC_OIS[];


     staticconst char KEY_QC_HISTOGRAM[] ;


 


     int32_tsetSharpness(const QCameraParameters& );


+    int32_t setOis(const QCameraParameters&);


     int32_tsetSaturation(const QCameraParameters& );


 


     int32_tsetSharpness(int sharpness);


+    int32_t setOis(int ois);


     int32_tsetSaturation(int saturation);


1.2、 文件:hardware/qcom/camera/QCamera2/stack/common/cam_types.h


            typedef enum {


                CAM_INTF_PARM_FLASH_BRACKETING,


                CAM_INTF_PARM_GET_IMG_PROP,


 


                    CAM_INTF_PARM_MAX


+    CAM_INTF_PARM_OIS


            }cam_intf_parm_type_t;


1.3、 文件:hardware/qcom/camera/QCamera2/stack/common/cam_intf.h


typedefstruct{


     cam_af_bracketing_t  mtf_af_bracketing_parm;


     /* Sensor type information */


     cam_sensor_type_t sensor_type;


+    /*ois default value*/


+   int32_t ois_default_value;


 } cam_capability_t;


2、    添加相关设置


文件:hardware/qcom/camera/QCamera2/HAL/QCameraParameters.cpp


const charQCameraParameters::KEY_QC_SCE_FACTOR_STEP[] = "sce-factor-step";


+const char QCameraParameters::KEY_QC_OIS[] = "ois";


 


//open camera时OIS默认值,该值在vendor中设置


int32_t QCameraParameters::initDefaultParameters()


{


       ………


+   // Set Ois


+   setOis(m_pCapability->ois_default_value);


+   ALOGE("the default_ois = %d",m_pCapability->ois_default_value);


     // Set Contrast


    set(KEY_QC_MIN_CONTRAST,m_pCapability->contrast_ctrl.min_value);


    set(KEY_QC_MAX_CONTRAST, m_pCapability->contrast_ctrl.max_value);


    ………


}


 


+int32_t QCameraParameters::setOis(constQCameraParameters& params)


+{


+    int ois = params.getInt(KEY_QC_OIS);


+    int prev_ois = getInt(KEY_QC_OIS);


+    if(params.get(KEY_QC_OIS) == NULL) {


+       CDBG_HIGH("%s: Ois not set by App",__func__);


+       return NO_ERROR;


+    }


+    ALOGE("haljay ois=%dprev_ois=%d",ois, prev_ois);


+    if (prev_ois !=  ois) {


+        if((ois >= 0) && (ois <=2)) {


+            CDBG(" new ois value : %d", ois);


+            return setOis(ois);


+        } else {


+            ALOGE("%s: invalid value%d",__func__, ois);


+            return BAD_VALUE;


+        }


+    } else {


+        ALOGE("haljay no valuechange");


+        CDBG("%s: No value change inois", __func__);


+        return NO_ERROR;


+    }


+}


 


+int32_t QCameraParameters::setOis(intois)


+{


+    charval[16];


+   sprintf(val, "%d", ois);


+   updateParamEntry(KEY_QC_OIS, val);


+   CDBG("%s: Setting ois %s", __func__, val);


+    ALOGE("haljay%s set ois=%s OIS=%d", __func__, val, CAM_INTF_PARM_OIS);


+    int32_tvalue = ois;


+    returnAddSetParmEntryToBatch(m_pParamBuf,


+                                 CAM_INTF_PARM_OIS,


+                                 sizeof(value),


+                                  &value);


+}


 


函数int32_tQCameraParameters::updateParameters添加setOis:


     if ((rc =setBrightness(params)))                  final_rc = rc;


     if ((rc =setZoom(params)))                        final_rc = rc;


     if ((rc = setSharpness(params)))                    final_rc = rc;


+    if ((rc = setOis(params)))                          final_rc = rc;


     if ((rc =setSaturation(params)))                   final_rc = rc;


   C、Vendor层相关修改:


1、    添加相关定义


1.1、 文件:kernel/include/media/msm_cam_sensor.h


enum msm_actuator_cfg_type_t {


  CFG_SET_POSITION,


  CFG_ACTUATOR_POWERDOWN,


  CFG_ACTUATOR_POWERUP,


+ CFG_ACTUATOR_OIS,


 };


struct msm_actuator_cfg_data {


      struct msm_actuator_get_info_t get_info;


      struct msm_actuator_set_position_t setpos;


      enum af_camera_name cam_name;


+      void*setting;


  } cfg;


1.2、 文件:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/mct/pipeline/mct_pipeline.c


      在函数boolean mct_pipeline_populate_query_cap_buffer(mct_pipeline_t*pipeline)中添加:


                hal_data->sharpness_ctrl.min_value= 0;


                hal_data->sharpness_ctrl.step= 6;


 


+  hal_data->ois_default_value= 1;


                hal_data->contrast_ctrl.def_value= 5;


                hal_data->contrast_ctrl.max_value= 10;


1.3、 文件:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/module/sensor_common.h


typedefenum {


   /* End of CSID enums*/


   /* video hdr enums */


   SENSOR_SET_AWB_UPDATE, /*sensor_set_awb_data_t * */


+ ACTUATOR_SET_OIS


 } sensor_submodule_event_type_t;


2、    添加相关设置


文件:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/module/module_sensor.c


2.1、 获取hal层参数


在函数static boolean module_sensor_event_control_set_parm中增加:


+  case CAM_INTF_PARM_OIS:{


+    if (!event_control->parm_data) {


+        SERR("failed parm_dataNULL");


+        ret = FALSE;


+        break;


+      }


+    module_sensor_params_t        *ois_module_params = NULL;


+    ois_module_params =s_bundle->module_sensor_params[SUB_MODULE_ACTUATOR];


+    if (ois_module_params->func_tbl.process != NULL) {


+      rc =ois_module_params->func_tbl.process(


+        ois_module_params->sub_module_private,


+        ACTUATOR_SET_OIS,event_control->parm_data);


+    }


+    if (rc < 0) {


+      SERR("failed");


+      ret = FALSE;


+    }


+     break;


+  }


文件:vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/actuators/actuator.c


2.2、在函数int32_t actuator_process中增加:


       case ACTUATOR_SET_POSITION:


            rc =actuator_set_position(actuator_ctrl, data);


            break;


+  /*set ois*/


+   case ACTUATOR_SET_OIS:


+   rc = actuator_set_ois(actuator_ctrl,data);


+   break;


2.3、将参数通过ioctl方法下至内核


        +staticint actuator_set_ois(void *ptr, void*data) {


+  int rc = 0;


+  int32_t *ois_level = (int32_t*)data;


+  actuator_data_t *ois_actuator_ptr =(actuator_data_t *)ptr;


+  struct msm_actuator_cfg_data cfg;


+  if (ois_actuator_ptr->fd <= 0)


+    return -EINVAL;


+  cfg.cfgtype = CFG_ACTUATOR_OIS;


+  cfg.cfg.setting = ois_level;


+  /* Invoke the IOCTL to set the ois */


+  rc = ioctl(ois_actuator_ptr->fd,VIDIOC_MSM_ACTUATOR_CFG, &cfg);


+  if (rc < 0) {


+    SERR("failed-errno:%s!!!",strerror(errno));


+  }


+  return rc;


+}


2.2.3 HAL 3.0参数设置
V3增加设定参数:对于HAL V3,从framework到HAL层的参数传递是通过metadata方式完成的,即每一个设置现在都变成了一个参数对,例如:设置AE mode为auto,V1版本参数可能是“AE mode=auto”字符串;V3版本假设AE mode功能序号是10,参数auto为1,传到HAL层的参数类似(10,1)这样的参数对,在HAL层需要通过10这个参数,获取设置值1;对于在V1版本对ois的设置需要在V3中添加新的处理来实现。


如何在V3中定义自己特定参数(如ois设置):谷歌考虑到厂商可能需要定义自己特定的参数,因此在metadata里面定义了vendor tag的数据范围来让vendor可以添加自己特定的操作,如ois设置,可以通过vendor tag来实现。


步骤:


1)  定义自己的vendor tag序号值


vim system/media/camera/include/system/camera_metadata_tags.h


          typedefenum camera_metadata_tag {


             ANDROID_SYNC_START,


             ANDROID_SYNC_MAX_LATENCY,


             ANDROID_SYNC_END,


+ VENDOR_TAG_OIS =


+ VENDOR_SECTION_START,  //由于参数少,没有重新定义section,使用默认section 0x8000


                ......................


           } camera_metadata_tag_t;


2)  所需支持配置


Vendor Tag都需要在VENDOR_SECTION_START后面添加,此处添加了VENDOR_TAG_OIS。在HAL里面如果需要处理 Vendor Tag,一个是需要camera module的版本是2.2以上,因为Google在这个版本之后才稳定支持vendor tag。一个是需要vendor tag的的operations函数。


vim ./hardware/libhardware/modules/camera/CameraHAL.cpp +186


版本和操作函数如下图所示:


vim ./hardware/qcom/camera/QCamera2/HAL3/QCamera3VendorTags.cpp +184


 


           get_tag_count:返回所有vendor tag的个数;


get_all_tags:把所有vendor tag依次放在service传下来的uint32_t * tag_array里面,这样上层就知道每一个tag对应的序号值了;


get_section_name:获取vendor tag的section对应的section名称,比如可以把某几个vendor tag放在一个section里面,其它的放在其它的section里面。查看metadata.h里面的定义很好理解,如果你想增加自己的section,就可以在VENDOR_SECTION = 0x8000后面添加自己的section。由于本次只设置ois参数,没有分类的必要,所以就使用默认的VENDOR_SECTION.


vim system/media/camera/include/system/camera_metadata_tags.h


 


get_tag_name:用于获取每一个vendor tag的名称,比如我们这个地方返回“VENDOR_TAG_OIS”就可以了;


get_tag_type:这个函数返回vendor tag对应的设置数据的类型,可以用TYPE_INT32, TYPE_FLOAT等多种数据格式,取决于需求,我们ois参数只要是INT32就行了。


3)  加载vendor tag


这样CameraService.cpp在启动的时候就会调用onFirstRef里面的下面代码来加载我们所写的vendor tag


if (mModule->common.module_api_version >= CAMERA_MODULE_API_VERSION_2_2) {


                       setUpVendorTags();


        }


4)  V1到V3参数转化


由于我们这个ois设置是在V1的APP里面使用,因此首先需要实现V1和V3参数的转换,Google在services/camera/libcameraservice/api1/client2/Parameters.cpp实现相应的转换,因此首先需要在如下函数里面获取V1 APP传下来的OIS的值,其中的paramString就是V1的参数设置的字符串


status_t Parameters::set(const String8& paramString)


{


    …………


    mOis = newParams.get(CameraParameters::KEY_OIS);


    …………


}


由于V3的参数都是在request frame的时候一起下发的,因此需要讲mSaturation的值在Parameters::updateRequest(CameraMetadata *request)里面下发到HAL,即


+  res = request->update(VENDOR_TAG_SATURATION,&mOis, 1);


 这样就将saturation的vendor tag和其设置值发送到了HAL V3。


5)  HAL V3获取设置的OIS参数


使用CameraMetadata::find(uint32_ttag)函数来获取参数:


oisMapMode =                frame_settings.find(VENDOR_TAG_OIS).data.i32[0];


通过ADD_SET_PARAM_ENTRY_TO_BATCH函数将设置下到vendor层:


ADD_SET_PARAM_ENTRY_TO_BATCH(hal_metadata, CAM_INTF_META_OIS,


oisMapMode);


 


2.3 Hal 3.0版本框架分析
2.3.1 Frameworks层总体框架
Frameworks之CameraService部分架构图如下图所示:


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


Camera2Client建立与初始化过程如下图所示:


 


由上图可知建立好Camera2Client后会进行initialize操作,完成各个处理模块的创建:


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


status_tCamera2Client::initialize(CameraModule *module)


{


    ………


    mStreamingProcessor = new StreamingProcessor(this);//preview和recorder


    threadName =String8::format(C2-%d-StreamProc, mCameraId);


   mStreamingProcessor->run(threadName.string());//预览与录像


 


    mFrameProcessor = new FrameProcessor(mDevice, this);// 3A


    threadName = String8::format(C2-%d-FrameProc,mCameraId);


   mFrameProcessor->run(threadName.string()); //3A


 


    mCaptureSequencer = new CaptureSequencer(this);


    threadName =String8::format(C2-%d-CaptureSeq, mCameraId);


   mCaptureSequencer->run(threadName.string());//录像,拍照


 


   mJpegProcessor = new JpegProcessor(this,mCaptureSequencer);


    threadName =String8::format(C2-%d-JpegProc, mCameraId);


   mJpegProcessor->run(threadName.string());


………


    mCallbackProcessor = new CallbackProcessor(this);//回调处理


    threadName = String8::format(C2-%d-CallbkProc,mCameraId);


   mCallbackProcessor->run(threadName.string());


    ………


}


依次分别创建了:


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


status_t Camera2Client::startPreview() {


    ATRACE_CALL();


    ALOGV(%s: E, __FUNCTION__);


    Mutex::Autolockicl(mBinderSerializationLock);


    status_t res;


    if ( (res = checkPid(__FUNCTION__) ) != OK)return res;


    SharedParameters::Lock l(mParameters);


    return startPreviewL(l.mParameters,false);


}


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


2、    调用Camera2Client::startPreviewL函数


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


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


status_tCamera2Client::startPreviewL(Parameters &params, bool restart){


......


//获取上一层Preview stream id


intlastPreviewStreamId = mStreamingProcessor->getPreviewStreamId();


//2.1创建camera3device stream, Camera3OutputStream


    res =mStreamingProcessor->updatePreviewStream(params);


.....


intlastJpegStreamId = mJpegProcessor->getStreamId();


//2.2预览启动时就建立一个jpeg的outstream


res= updateProcessorStream(mJpegProcessor,params);


.....


//2.3回调处理建立一个Camera3outputstream


res= mCallbackProcessor->updateStream(params);


………


//2.4


outputStreams.push(getCallbackStreamId());


......


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


......


if(!params.recordingHint) {


   if (!restart) {


      //2.5 request处理,更新了mPreviewrequest


      res = mStreamingProcessor->updatePreviewRequest(params); 


......


    }


        //2.6


        res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW,


                outputStreams);//启动stream,传入outputStreams即stream 的id


    }


......


}


2.1、调用mStreamingProcessor->updatePreviewStream函数


   代码目录-2:


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


status_t StreamingProcessor::updatePreviewStream (constParameters &params) {


......


    sp<cameradevicebase> device =mDevice.promote();//Camera3Device


......


    if (mPreviewStreamId != NO_STREAM) {


        // Check if stream parameters have tochange


       uint32_t currentWidth, currentHeight;


        res =device->getStreamInfo(mPreviewStreamId,


                &tWidth, &tHeight, 0);


    ......


        if (currentWidth !=(uint32_t)params.previewWidth ||


                currentHeight != (uint32_t)params.previewHeight){


        ......    


            res =device->waitUntilDrained();


        ......   


            res =device->deleteStream(mPreviewStreamId);


            ......


            mPreviewStreamId = NO_STREAM;


        }


    }


if (mPreviewStreamId == NO_STREAM) {//首次create stream


        //创建一个Camera3OutputStream


        res = device->createStream(mPreviewWindow,


                params.previewWidth,params.previewHeight,


               CAMERA2_HAL_PIXEL_FORMAT_OPAQUE, &mPreviewStreamId);


        ......


        }


    }


    res =device->setStreamTransform(mPreviewStreamId,


            params.previewTransform);


    ......


}


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


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


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


      代码目录-3:


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


status_tCamera3Device::createStream(spconsumer,


        uint32_t width, uint32_t height, intformat, int *id) {


    ......


    assert(mStatus != STATUS_ACTIVE);


    sp<camera3outputstream> newStream;


    if (format == HAL_PIXEL_FORMAT_BLOB) {//图片


        ssize_t jpegBufferSize =getJpegBufferSize(width, height);


       ......


        newStream = new Camera3OutputStream(mNextStreamId, consumer,


                width, height, jpegBufferSize,format);//jpeg 缓存的大小


    } else {


        newStream = new Camera3OutputStream(mNextStreamId, consumer,


                width, height, format);//Camera3OutputStream


    }


newStream->setStatusTracker(mStatusTracker);


//一个streamid与Camera3OutputStream绑定


    res = mOutputStreams.add(mNextStreamId,newStream);


    ......


    *id = mNextStreamId++;//至少一个previewstream 一般还有CallbackStream


    mNeedConfig = true;


    // Continue captures if active at start


    if (wasActive) {


        ALOGV(%s: Restarting activity toreconfigure streams, __FUNCTION__);


        res = configureStreamsLocked();


       ......


        internalResumeLocked();


    }


    ALOGV(Camera %d: Created new stream, mId);


    return OK;


}


该函数重点是关注一个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


       status_tCamera2Client::updateProcessorStream(sp<processort> processor,


                                             camera2::Parameters params) {


            //No default template arguments until C++11, so we need this overload


             return updateProcessorStream<processort,processort::updatestream="">(


                processor,params);


}


template <typename const="" parameters=""status_t="">


status_tCamera2Client::updateProcessorStream(sp<processort> processor,


                                             Parameters params) {


            status_tres;


            //Get raw pointer since sp<t> doesn't have operator->*


            ProcessorT*processorPtr = processor.get();


            res= (processorPtr->*updateStreamF)(params);


.......


}


该模板函数处理过程最终通过非显示实例到显示实例调用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。


status_t CallbackProcessor::updateStream(constParameters &params) {


    ………


    sp<cameradevicebase> device =mDevice.promote();


    ………


    // If possible, use the flexible YUV format


    int32_t callbackFormat =params.previewFormat;


    if (mCallbackToApp) {


        // TODO: etalvala: This should use theflexible YUV format as well, but


        // need to reconcile HAL2/HAL3requirements.


        callbackFormat = HAL_PIXEL_FORMAT_YV12;


    } else if(params.fastInfo.useFlexibleYuv&&


            (params.previewFormat ==HAL_PIXEL_FORMAT_YCrCb_420_SP ||


             params.previewFormat ==HAL_PIXEL_FORMAT_YV12) ) {


        callbackFormat =HAL_PIXEL_FORMAT_YCbCr_420_888;


    }


    if (!mCallbackToApp &&mCallbackConsumer == 0) {


        // Create CPU buffer queue endpoint,since app hasn't given us one


        // Make it async to avoid disconnectdeadlocks


        sp<igraphicbufferproducer>producer;


        sp<igraphicbufferconsumer>consumer;


       //BufferQueueProducer与BufferQueueConsumer


        BufferQueue::createBufferQueue(&producer, &consumer);


        mCallbackConsumer = new CpuConsumer(consumer,kCallbackHeapCount);


//当前CallbackProcessor继承于CpuConsumer::FrameAvailableListener


        mCallbackConsumer->setFrameAvailableListener(this);


       mCallbackConsumer->setName(String8(Camera2Client::CallbackConsumer));


//用于queue操作,这里直接进行本地的buffer操作


        mCallbackWindow = new Surface(producer);


    }


    if (mCallbackStreamId != NO_STREAM) {


        // Check if stream parameters have tochange


        uint32_t currentWidth, currentHeight,currentFormat;


        res =device->getStreamInfo(mCallbackStreamId,


                &tWidth, &tHeight, &tFormat);


       ………


    }


    if (mCallbackStreamId == NO_STREAM) {


        ALOGV(Creating callback stream: %d x%d, format 0x%x, API format 0x%x,


                params.previewWidth,params.previewHeight,


                callbackFormat,params.previewFormat);


        res = device->createStream(mCallbackWindow,


               params.previewWidth, params.previewHeight,


                callbackFormat,&mCallbackStreamId);//Creating callback stream


        ………


    }


    return OK;


}


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数据处理复杂化的原因所在。


status_t StreamingProcessor::updatePreviewRequest(constParameters &params) {


    ………


    if (mPreviewRequest.entryCount()== 0) {


        sp<camera2client> client =mClient.promote();


        if (client == 0) {


            ALOGE(%s: Camera %d: Client doesnot exist, __FUNCTION__, mId);


            return INVALID_OPERATION;


        }


        // UseCAMERA3_TEMPLATE_ZERO_SHUTTER_LAG for ZSL streaming case.


        if (client->getCameraDeviceVersion()>= CAMERA_DEVICE_API_VERSION_3_0) {


            if (params.zslMode &&!params.recordingHint) {


                res = device->createDefaultRequest(CAMERA3_TEMPLATE_ZERO_SHUTTER_LAG,


                        &mPreviewRequest);


            } else {


                res = device->createDefaultRequest(CAMERA3_TEMPLATE_PREVIEW,


                        &mPreviewRequest);


            }


        } else {


          //创建一个Preview相关的request,由底层的hal来完成default创建


            res =device->createDefaultRequest(CAMERA2_TEMPLATE_PREVIEW,


                    &mPreviewRequest);


        ………


}


//根据参数来更新CameraMetadatarequest,用于app设置参数,如antibanding设置


res= params.updateRequest(&mPreviewRequest);  


    ………


    res = mPreviewRequest.update(ANDROID_REQUEST_ID,


            &mPreviewRequestId,1);//mPreviewRequest的ANDROID_REQUEST_ID


    ………


}


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


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


代码目录-3:


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


status_t Camera3Device::createDefaultRequest(int templateId, CameraMetadata*request) {


    ………


const camera_metadata_t *rawRequest;


 ATRACE_BEGIN(camera3->construct_default_request_settings);


 rawRequest = mHal3Device->ops->construct_default_request_settings(


    mHal3Device, templateId);


 ATRACE_END();


 if (rawRequest == NULL) {


    SET_ERR_L(HAL is unable to construct default settings for template %d,


             templateId);


    return DEAD_OBJECT;


 }


 *request = rawRequest;


 mRequestTemplateCache[templateId] =rawRequest;


………


}


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


struct camera_metadata {


    metadata_size_t          size;


    uint32_t                 version;


    uint32_t                 flags;


    metadata_size_t          entry_count;


    metadata_size_t          entry_capacity;


    metadata_uptrdiff_t      entries_start; // Offset fromcamera_metadata


    metadata_size_t          data_count;


    metadata_size_t          data_capacity;


    metadata_uptrdiff_t      data_start; // Offset fromcamera_metadata


    uint8_t                 reserved[];


};


该数据结构可以存储多种数据,且可以根据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正常工作的核心控制:


tatus_tStreamingProcessor::startStream(StreamType type,


        const Vector<int32_t>&outputStreams) {


.....


CameraMetadata&request = (type == PREVIEW) ?


            mPreviewRequest :mRecordingRequest;//取preview的CameraMetadata request


//CameraMetadata中添加outputStreams


res = request.update(ANDROID_REQUEST_OUTPUT_STREAMS,outputStreams);


res= device->setStreamingRequest(request);//向hal发送request


.....


}


该函数首先是根据当前工作模式来确定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 status_t Camera3Device::setStreamingRequest(constCameraMetadata &request,


                                           int64_t* /*lastFrameNumber*/) {


    ATRACE_CALL();


    List<constcamerametadata=""> requests;


    requests.push_back(request);


    return setStreamingRequestList(requests,/*lastFrameNumber*/NULL);


}


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


a.2 status_t Camera3Device::setStreamingRequestList(constList<const camerametadata=""> &requests, int64_t*lastFrameNumber) {


        ATRACE_CALL();


        returnsubmitRequestsHelper(requests,/*repeating*/true, lastFrameNumber);


}


a.3 status_t Camera3Device::submitRequestsHelper(


       const List<const camerametadata=""> &requests, boolrepeating,


       /*out*/


       int64_t *lastFrameNumber) {//repeating = 1;lastFrameNumber = NULL


   ………


   status_t res = checkStatusOkToCaptureLocked();


   ………


    RequestList requestList;


//返回的是CaptureRequest RequestList


res = convertMetadataListToRequestListLocked(requests,/*out*/&requestList);   


………


   if (repeating) {


//重复的request存入到RequestThread


res = mRequestThread->setRepeatingRequests(requestList, lastFrameNumber); 


}  else {


//capture模式,拍照单词


       res = mRequestThread->queueRequestList(requestList,lastFrameNumber);  


 }


   if (res == OK) {


       waitUntilStateThenRelock(/*active*/true, kActiveTimeout);


       if (res != OK) {


            SET_ERR_L(Can't transition toactive in %f seconds!,


                    kActiveTimeout/1e9);


       }


       ALOGV(Camera %d: Capture request % PRId32  enqueued, mId,


             (*(requestList.begin()))->mResultExtras.requestId);


   } else {


       CLOGE(Cannot queue request. Impossible.);


       return BAD_VALUE;


   }


   return res;


}


a.4 convertMetadataListToRequestListLocked


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


status_tCamera3Device::convertMetadataListToRequestListLocked(


const List<constcamerametadata=""> &metadataList, RequestList *requestList) {


   ………


   for (List<const camerametadata="">::const_iterator it =metadataList.begin();//CameraMetadata, mPreviewRequest


            it != metadataList.end(); ++it) {


        //新建CaptureRequest由CameraMetadata转化而来


       sp<capturerequest>newRequest = setUpRequestLocked(*it);       


        ………


       // Setup burst Id and request Id


       newRequest->mResultExtras.burstId = burstId++;


       if (it->exists(ANDROID_REQUEST_ID)) {


            if(it->find(ANDROID_REQUEST_ID).count == 0) {


                CLOGE(RequestID entry exists;but must not be empty in metadata);


                return BAD_VALUE;


            }


        //设置该request对应的id


        newRequest->mResultExtras.requestId =it->find(ANDROID_REQUEST_ID).data.i32[0];


       } else {


            CLOGE(RequestID does not exist inmetadata);


            return BAD_VALUE;


       }


       requestList->push_back(newRequest);


        ………


   }


   return OK;


}


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


        a.5 setUpRequestLocked


           sp<camera3device::capturerequest>Camera3Device::setUpRequestLocked(


                constCameraMetadata &request) {//mPreviewRequest


                status_tres;


                if(mStatus == STATUS_UNCONFIGURED || mNeedConfig) {


                res= configureStreamsLocked();


                ......


    //CameraMetadata转为CaptureRequest,包含mOutputStreams


   </strong>sp<capturerequest> newRequest = createCaptureRequest(request);


                return newRequest;


}


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


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


           a.6 sp<camera3device::capturerequest>Camera3Device::createCaptureRequest(


                constCameraMetadata &request) {//mPreviewRequest


                ………


                sp<capturerequest>newRequest = new CaptureRequest;


                newRequest->mSettings= request;//CameraMetadata


                camera_metadata_entry_tinputStreams =


                    newRequest->mSettings.find(ANDROID_REQUEST_INPUT_STREAMS);


                if(inputStreams.count > 0) {


                    if(mInputStream == NULL ||


                        mInputStream->getId() != inputStreams.data.i32[0]) {


                        CLOGE(Requestreferences unknown input stream %d,


                        inputStreams.data.u8[0]);


                        returnNULL;


                    }


                ………


                    newRequest->mInputStream= mInputStream;


                    newRequest->mSettings.erase(ANDROID_REQUEST_INPUT_STREAMS);


                }


//读取存储在CameraMetadata的stream id信息


                camera_metadata_entry_tstreams =


                    newRequest->mSettings.find(ANDROID_REQUEST_OUTPUT_STREAMS);


                    ………


for (size_t i = 0; i < streams.count; i++) {


                    //Camera3OutputStream的id在mOutputStreams中


                    intidx = mOutputStreams.indexOfKey(streams.data.i32[i]);


                    ………


                 }


                //返回的是Camera3OutputStream,preview/callback等stream


                sp<camera3outputstreaminterface>stream =


                     mOutputStreams.editValueAt(idx);


                ………


//Camera3OutputStream添加到CaptureRequest的mOutputStreams


                newRequest->mOutputStreams.push(stream);


    }


                newRequest->mSettings.erase(ANDROID_REQUEST_OUTPUT_STREAMS);


                returnnewRequest;


}


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


在构建这个PreviewRequest时,已经将ANDROID_REQUEST_OUTPUT_STREAMS这个Tag进行了初始化,相应的内容为Vector &outputStreams,包含着属于PreviewRequest这个Request所需要的输出stream的ID值,通过这个IDindex值,可以遍历到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、CallbackStream ID等等)相对应的Camera3OutputStream。


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


class CaptureRequest : public LightRefBase<capturerequest> {


      public:


        CameraMetadata                      mSettings;


        sp<camera3::camera3stream>          mInputStream;


       Vector<sp<camera3::camera3outputstreaminterface> >


                                            mOutputStreams;


        CaptureResultExtras                 mResultExtras;


    };


mSettings是保存CameraMetadata PreviewRequest,vectormOutPutStreams保存着当前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类型是不多的:


预览RequestmPreviewRequest:mPreviewRequestId(Camera2Client::kPreviewRequestIdStart),


拍照RequestmCaptureRequest:mCaptureId(Camera2Client::kCaptureRequestIdStart),


录像RequestmRecordingRequest: mRecordingRequestId(Camera2Client::kRecordingRequestIdStart);


staticconst int32_t kPreviewRequestIdStart = 10000000;


staticconst int32_t kPreviewRequestIdEnd   =20000000;


staticconst int32_t kRecordingRequestIdStart  =20000000;


staticconst int32_t kRecordingRequestIdEnd    =30000000;


staticconst int32_t kCaptureRequestIdStart = 30000000;


staticconst int32_t kCaptureRequestIdEnd   =40000000;


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


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


status_tCamera3Device::RequestThread::setRepeatingRequests(


        const RequestList &requests,


        /*out*/


        int64_t *lastFrameNumber) {


    Mutex::Autolock l(mRequestLock);


    if (lastFrameNumber != NULL) {//第一次进来为null


        *lastFrameNumber =mRepeatingLastFrameNumber;


    }


    mRepeatingRequests.clear();


    mRepeatingRequests.insert(mRepeatingRequests.begin(),


            requests.begin(), requests.end());


   unpauseForNewRequests();//signal request_thread in waitfornextrequest


    mRepeatingLastFrameNumber =NO_IN_FLIGHT_REPEATING_FRAMES;


    return OK;


}


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


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


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


代码目录-2:


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


boolCamera3Device::RequestThread::threadLoop(){


....


//返回的是mRepeatingRequests,mPreviewRequest


 sp<capturerequest> nextRequest = waitForNextRequest();  


………


    // Create request to HAL


//CaptureRequest转为给HAL3.0的camera3_capture_request_t


camera3_capture_request_t request =camera3_capture_request_t();   request.frame_number = nextRequest->mResultExtras.frameNumber;//当前帧号


    Vector<camera3_stream_buffer_t>outputBuffers;


    // Get the request ID, if any


    int requestId;


    camera_metadata_entry_t requestIdEntry =


            nextRequest->mSettings.find(ANDROID_REQUEST_ID);


    if (requestIdEntry.count > 0) {


//获取requestid,这里是mPreviewRequest的id


        requestId = requestIdEntry.data.i32[0];


    }


         .....


   for (size_t i = 0; i <nextRequest->mOutputStreams.size(); i++) {


         res =nextRequest->mOutputStreams.editItemAt(i)->


                 getBuffer(&outputBuffers.editItemAt(i));


.....


    // Submit request and block until ready fornext one


    ATRACE_ASYNC_BEGIN(frame capture,request.frame_number);


   ATRACE_BEGIN(camera3->process_capture_request);


   //调用底层hal的process_capture_request,如antibanding参数设置


res = mHal3Device->ops->process_capture_request(mHal3Device,&request);    ATRACE_END();


     .......


}


a.1 waitForNextRequest()


    Camera3Device::RequestThread::waitForNextRequest() {


   ………


    while (mRequestQueue.empty()) {


        if (!mRepeatingRequests.empty()) {


            // Always atomically enqueue allrequests in a repeating request


            // list. Guarantees a completein-sequence set of captures to


            // application.


            const RequestList &requests =mRepeatingRequests;


            RequestList::const_iteratorfirstRequest =


                    requests.begin();


            nextRequest = *firstRequest;


            //把当前的mRepeatingRequests插入到mRequestQueue


           mRequestQueue.insert(mRequestQueue.end(),


                    ++firstRequest,


                    requests.end());


            // No need to wait any longer


            mRepeatingLastFrameNumber = mFrameNumber+ requests.size() - 1;


            break;


        }


        //等待下一个request


        res =mRequestSignal.waitRelative(mRequestLock, kRequestTimeout);


       if ((mRequestQueue.empty() && mRepeatingRequests.empty()) ||


                exitPending()) {


            Mutex::Autolock pl(mPauseLock);


            if (mPaused == false) {


                ALOGV(%s: RequestThread: Goingidle, __FUNCTION__);


                mPaused = true;


                // Let the tracker know


                sp<statustracker>statusTracker = mStatusTracker.promote();


                if (statusTracker != 0) {


                   statusTracker->markComponentIdle(mStatusId, Fence::NO_FENCE);


                }


            }


            // Stop waiting for now and letthread management happen


            return NULL;


        }


    }


    if (nextRequest == NULL) {


        // Don't have a repeating requestalready in hand, so queue


        // must have an entry now.


        RequestList::iterator firstRequest =


                mRequestQueue.begin();


        nextRequest = *firstRequest;


//取一根mRequestQueue中的CaptureRequest,来自于mRepeatingRequests的next


        mRequestQueue.erase(firstRequest);


    }


    ………


    if (nextRequest != NULL) {


        //对每一个非空的request需要帧号++


nextRequest->mResultExtras.frameNumber= mFrameNumber++;       nextRequest->mResultExtras.afTriggerId = mCurrentAfTriggerId;


       nextRequest->mResultExtras.precaptureTriggerId = mCurrentPreCaptureTriggerId;


    }


    return nextRequest;


}


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


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


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


a.2


camera_metadata_entry_t requestIdEntry =nextRequest->mSettings.find(ANDROID_REQUEST_ID);提取该CaptureRequest对应的 Request 类型值;


a.3 getBuffer操作


a.4 mHal3Device->ops->process_capture_request(mHal3Device,&request)


这里的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等内容。


2.3.3 opencamera过程调用device3 initialize函数
    App至framework流程上面章节已做简要分析,frameworks -> hal初始化框图如下:


 


2.3.4 frameworks层设置参数流程
    设置参数setParameters流程图如下所示:


    Frameworks层:


 


2.3.5设置参数下至hal层流程
由2.3.2节可知,开启并在request线程中--Camera3Device::RequestThread::threadLoop调用hal层接口函数mHal3Device->ops->process_capture_request(mHal3Device, &request),接口函数中会完成参数设置相关工作,如antibanding的设置。


根据2.3.6节可知,antibanding等相关参数已经更新到requestlist中,hal层参数设置如下图所示:
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值