精华内容
下载资源
问答
  • 高通平台camera框架分析,详细的camera hal和驱动之间的关系。
  • 高通camera框架_流程浅析(1)

    千次阅读 2016-11-17 15:41:16
    该文档主要浅析camera框架,后续会增加机制相关内容: 1. Introduction 本文档主要讲解高通Camera整体框架。...2. 高通Camera框架简介 总体框图如下: 下面简要走一下流程,不涉及具

    该文档主要浅析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层参数设置如下图所示:
    展开全文
  • 高通Camera整体框架

    千次阅读 2017-11-07 14:33:08
    1. Introduction 本文档主要讲解高通Camera整体框架。 部分内容或参考资料可...2. 高通Camera框架简介 总体框图如下: 下面简要走一下流程,不涉及具体代码: 1、初始化CameraService 在fra

    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_streamsregister_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层参数设置如下图所示:

     


    camera相关优秀 博客 http://www.cnblogs.com/whw19818/p/5766027.html
    展开全文
  • 高通Camera框架--数据流浅谈01

    千次阅读 2015-11-15 16:25:09
    // When the encoder fails to be created, we need // release the camera source due to the camera's lock // and unlock mechanism. cameraSource->stop(); return UNKNOWN_ERROR; } mVideoSourceNode = ...

        本文重点:stagefrightRecorder.cpp    OMXCodec.cpp   MPEG4Writer.cpp  CameraSource.cpp 之间的调用关系

    ===============================================================================

         最初看的时候,有些地方还是不清楚,关于编码和文件的读写之间的关系不是很了解。只是知道底层回调的数据会经过CameraSource.cpp回调,只是知道数据会在OMXCodec.cpp 中完成编码,只是知道在MPEG4Writer.cpp 会有读写线程和轨迹线程,只是知道在stagefrightRecorder.cpp 中会将OMXCodex.cpp、MPEG4Writer.cpp和CameraSource.cpp 做相互的配合调用。之前一直纠结的是MPEG4Writer.cpp是直接读CameraSource.cpp 的数据,那和编码之间又是怎样的联系呢?

         是自己知识面不广,了解的不多,读代码能力也还得加强。

         这次看源码,总算是理清了上面的疑点。

        OMXCodec.cpp 的read函数,直接读的是CameraSource.cpp 中数据,然后MPEG4Writer.cpp 中的轨迹线程的mSource->read()调用的则是OMXCodec.cpp 中数据。那也就是说,底层数据经过CameraSource.cpp回调的时候,是先经过编码,然后在将数据写入文件。

       >>>>>>>>这里直接从stagefrightRecorder.cpp 的start函数开始了,会在start()函数中调用startMPEG4Recording()函数

    stagefrightRecorder.cpp

    status_t StagefrightRecorder::start() {
          ......
        switch (mOutputFormat) {
            case OUTPUT_FORMAT_DEFAULT:
            case OUTPUT_FORMAT_THREE_GPP:
            case OUTPUT_FORMAT_MPEG_4:
                status = startMPEG4Recording();
               
         ......
    }

          >>>>>>>>在startMPEG4Recording()方法中过,调用的重要方法已经标红

    status_t StagefrightRecorder::startMPEG4Recording() {
       ......

          status_t err = setupMPEG4Recording(
                mOutputFd, mVideoWidth, mVideoHeight,
                mVideoBitRate, &totalBitRate, &mWriter);

        sp<MetaData> meta = new MetaData;


        setupMPEG4MetaData(startTimeUs, totalBitRate, &meta);


        err = mWriter->start(meta.get());
      ......
    }

     

         >>>>>>>>在setupMPEG4Recording()方法中,我们看到 sp<MediaWriter> writer = new MPEG4Writer(outputFd); 这个是完成writer的初始化,那我们现在就知道这个writer是MPEG4Writer了,这个还是蛮重要的。在这个方法中,会调用setupMediaSource(),完成source的初始化,而这个source就是CameraSource,还会继续调用setupVideoEncoder()方法,完成coder的初始化,而这个coder则是OMXCodex。还得注意下的就是writer->addSource(encoder); 这里是把编码的数据交给了writer,这样MPEG4Writer.cpp和OMXCodec.cpp直接就连续起来了

     

    status_t StagefrightRecorder::setupMPEG4Recording(
          ......
            sp<MediaWriter> *mediaWriter) {
        mediaWriter->clear();

      
        sp<MediaWriter> writer = new MPEG4Writer(outputFd);


        if (mVideoSource < VIDEO_SOURCE_LIST_END) {


            sp<MediaSource> mediaSource;       
            err = setupMediaSource(&mediaSource);
            if (err != OK) {
                return err;
            }


            sp<MediaSource> encoder;
            err = setupVideoEncoder(mediaSource, videoBitRate, &encoder);
            if (err != OK) {
                return err;
            }


            writer->addSource(encoder);
            *totalBitRate += videoBitRate;
        }


        // Audio source is added at the end if it exists.
        // This help make sure that the "recoding" sound is suppressed for
        // camcorder applications in the recorded files.
        if (!mCaptureTimeLapse && (mAudioSource != AUDIO_SOURCE_CNT)) {
            err = setupAudioEncoder(writer);
            if (err != OK) return err;
            *totalBitRate += mAudioBitRate;
        }


        if (mInterleaveDurationUs > 0) {
            reinterpret_cast<MPEG4Writer *>(writer.get())->
                setInterleaveDuration(mInterleaveDurationUs);
        }
        if (mLongitudex10000 > -3600000 && mLatitudex10000 > -3600000) {
            reinterpret_cast<MPEG4Writer *>(writer.get())->
                setGeoData(mLatitudex10000, mLongitudex10000);
        }
        if (mMaxFileDurationUs != 0) {
            writer->setMaxFileDuration(mMaxFileDurationUs);
        }
        if (mMaxFileSizeBytes != 0) {
            writer->setMaxFileSize(mMaxFileSizeBytes);
        }


        mStartTimeOffsetMs = mEncoderProfiles->getStartTimeOffsetMs(mCameraId);
        if (mStartTimeOffsetMs > 0) {
            reinterpret_cast<MPEG4Writer *>(writer.get())->
                setStartTimeOffsetMs(mStartTimeOffsetMs);
        }


        writer->setListener(mListener);
        *mediaWriter = writer;
        return OK;
    }

      >>>>>>>>在setupMediaSource()方法中是完成了cameraSource的初始化

     

    status_t StagefrightRecorder::setupMediaSource(
                          sp<MediaSource> *mediaSource) {
        if (mVideoSource == VIDEO_SOURCE_DEFAULT
                || mVideoSource == VIDEO_SOURCE_CAMERA) {
            sp<CameraSource> cameraSource;
            status_t err = setupCameraSource(&cameraSource);

            if (err != OK) {
                return err;
            }
            *mediaSource = cameraSource;
        } else if (mVideoSource == VIDEO_SOURCE_GRALLOC_BUFFER) {
            // If using GRAlloc buffers, setup surfacemediasource.
            // Later a handle to that will be passed
            // to the client side when queried
            status_t err = setupSurfaceMediaSource();
            if (err != OK) {
                return err;
            }
            *mediaSource = mSurfaceMediaSource;
        } else {
            return INVALID_OPERATION;
        }
        return OK;
    }

          >>>>>>>在setupVideoEncoder()方法中是完成了OMXCodec的初始化,这里注意下OMXCodec::create(...,camerasource,...,...);我们看到create的时候,传进入的参数中,那个source是cameraSource,所以后面在OMXCodec.cpp 中调用的mSoure->read();直接调用的就是CameraSoure.cpp中的read()方法

     

    status_t StagefrightRecorder::setupVideoEncoder(
            ......
        sp<MediaSource> encoder = OMXCodec::Create(
                client.interface(), enc_meta,
                true /* createEncoder */, cameraSource,
                NULL, encoder_flags);


        if (encoder == NULL) {
            ALOGW("Failed to create the encoder");
            // When the encoder fails to be created, we need
            // release the camera source due to the camera's lock
            // and unlock mechanism.
            cameraSource->stop();
            return UNKNOWN_ERROR;
        }


        mVideoSourceNode = cameraSource;
        mVideoEncoderOMX = encoder;


        *source = encoder;


        return OK;
    }

     

    -----------------------------

        >>>>>上面有说到在stagefrigheRecorder.cpp中有调用到MPEG4Writer.cpp中addSource()方法 [writer->addSource(encoder);],而addSource中传进来的参数是编码码的数据,这样MPEG4Writer.cpp和OMXCodec.cpp之间就有了联系,MPEG4Writer.cpp 读写的就是OMXCodec.cpp 中编码后的数据。

    MPEG4Writer.cpp 

     

        >>>>>> 在MPEG4Writer.cpp 的addSource()方法中,注意看下Track *track = new Track(this, source, 1 + mTracks.size());  我们看到new Track(...,source,...)的时候,是传进去了source,而这个source,从上面的分析,我们已经知道它是编码后的数据

     

    status_t MPEG4Writer::addSource(const sp<MediaSource> &source) {
        Mutex::Autolock l(mLock);
        if (mStarted) {
            ALOGE("Attempt to add source AFTER recording is started");
            return UNKNOWN_ERROR;
        }


        // At most 2 tracks can be supported.
        if (mTracks.size() >= 2) {
            ALOGE("Too many tracks (%d) to add", mTracks.size());
            return ERROR_UNSUPPORTED;
        }


        CHECK(source.get() != NULL);


        // A track of type other than video or audio is not supported.
        const char *mime;
        sp<MetaData> meta = source->getFormat();
        CHECK(meta->findCString(kKeyMIMEType, &mime));
        bool isAudio = !strncasecmp(mime, "audio/", 6);
        bool isVideo = !strncasecmp(mime, "video/", 6);
        if (!isAudio && !isVideo) {
            ALOGE("Track (%s) other than video or audio is not supported",
                mime);
            return ERROR_UNSUPPORTED;
        }


        // At this point, we know the track to be added is either
        // video or audio. Thus, we only need to check whether it
        // is an audio track or not (if it is not, then it must be
        // a video track).


        // No more than one video or one audio track is supported.
        for (List<Track*>::iterator it = mTracks.begin();
             it != mTracks.end(); ++it) {
            if ((*it)->isAudio() == isAudio) {
                ALOGE("%s track already exists", isAudio? "Audio": "Video");
                return ERROR_UNSUPPORTED;
            }
        }


        // This is the first track of either audio or video.
        // Go ahead to add the track.
        Track *track = new Track(this, source, 1 + mTracks.size());       -------------------------------
        mTracks.push_back(track);                                                                                               |
                                                                                                                                                   |
                                                                                                                                                   |
        mHFRRatio = ExtendedUtils::HFR::getHFRRatio(meta);                                                   |
                                                                                                                                                   |
                                                                                                                                                   |
        return OK;                                                                                                                           |
    }                                                                                                                                               |

                                                                                                                                                    |

    MPEG4Writer::Track::Track(       --------------------------------------------------------------------------- |
            MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
        : mOwner(owner),
          mMeta(source->getFormat()),
          mSource(source),
          mDone(false),
          mPaused(false),
          mResumed(false),
          mStarted(false),
          mTrackId(trackId),
          mTrackDurationUs(0),
          mEstimatedTrackSizeBytes(0),
          mSamplesHaveSameSize(true),
          mStszTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
          mStcoTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
          mCo64TableEntries(new ListTableEntries<off64_t>(1000, 1)),
          mStscTableEntries(new ListTableEntries<uint32_t>(1000, 3)),
          mStssTableEntries(new ListTableEntries<uint32_t>(1000, 1)),
          mSttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
          mCttsTableEntries(new ListTableEntries<uint32_t>(1000, 2)),
          mCodecSpecificData(NULL),
          mCodecSpecificDataSize(0),
          mGotAllCodecSpecificData(false),
          mReachedEOS(false),
          mRotation(0),
          mHFRRatio(1) {
        getCodecSpecificDataFromInputFormatIfPossible();


        const char *mime;
        mMeta->findCString(kKeyMIMEType, &mime);
        mIsAvc = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC);
        mIsAudio = !strncasecmp(mime, "audio/", 6);
        mIsMPEG4 = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_MPEG4) ||
                   !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC);


        setTimeScale();
    }

      >>>>>> theradEntry()是轨迹线程真正执行的方法,在这个方法中会通过mSource->read(&buffer)去不断的读取数据,那我们想知道,它是read的哪里的数据,所以就需要找到mSource是在哪里初始化的,我们搜索下,会发现是在

        MPEG4Writer::Track::Track(  )
            MPEG4Writer *owner, const sp<MediaSource> &source, size_t trackId)
        : mOwner(owner),
       
          mSource(source),

      这里进行了初始化。直接看上面,已经连线标出来的方法,就知道,这个source就是编码后的数据了

     

    status_t MPEG4Writer::Track::threadEntry() {

        while (!mDone && (err = mSource->read(&buffer)) == OK) {

           ......

        }
    }

    --------------------

         >>>>>>在上面的分析中,我们知道在stagefrightRecorder.cpp中会完成OMXCodec的初始化,而且在初始化中,就将CameraSource传进来,这里只是想说 下面的source就是CameraSource,这样CameraSource.cpp和OMXCodec.cpp之间就联系起来了

    OMXCodec.cpp

    OMXCodec::OMXCodec(
            const sp<IOMX> &omx, IOMX::node_id node,
            uint32_t quirks, uint32_t flags,
            bool isEncoder,
            const char *mime,
            const char *componentName,
            const sp<MediaSource> &source,
            const sp<ANativeWindow> &nativeWindow)
        : mOMX(omx),
          mOMXLivesLocally(omx->livesLocally(node, getpid())),
          mNode(node),
          mQuirks(quirks),
          mFlags(flags),
          mIsEncoder(isEncoder),
          mIsVideo(!strncasecmp("video/", mime, 6)),
          mMIME(strdup(mime)),
          mComponentName(strdup(componentName)),
          mSource(source),
          mCodecSpecificDataIndex(0),
          mState(LOADED),
          mInitialBufferSubmit(true),
          mSignalledEOS(false),
          mNoMoreOutputData(false),
          mOutputPortSettingsHaveChanged(false),
          mSeekTimeUs(-1),
          mSeekMode(ReadOptions::SEEK_CLOSEST_SYNC),
          mTargetTimeUs(-1),
          mOutputPortSettingsChangedPending(false),
          mSkipCutBuffer(NULL),
          mLeftOverBuffer(NULL),
          mPaused(false),
          mNativeWindow(
                  (!strncmp(componentName, "OMX.google.", 11))
                            ? NULL : nativeWindow),
          mNumBFrames(0),
          mInSmoothStreamingMode(false),
          mOutputCropChanged(false),
          mSignalledReadTryAgain(false),
          mReturnedRetry(false),
          mLastSeekTimeUs(-1),
          mLastSeekMode(ReadOptions::SEEK_CLOSEST) {
        mPortStatus[kPortIndexInput] = ENABLING;
        mPortStatus[kPortIndexOutput] = ENABLING;


        setComponentRole();
    }

        >>>>>>这里的read()方法,会被MPEG4Writer.cpp的mSourcr->read()调用,至于编码的过程,还没有详细看

    status_t OMXCodec::read(
            MediaBuffer **buffer, const ReadOptions *options) { 

          .......

    }

    ==============================================================================================

    欢迎关注我的个人微信公众号,公众号会记录自己开发的点滴,还有日常的生活,希望和更多的小伙伴一起交流~~

     

     

    展开全文
  • 高通camera架构讲解

    千次阅读 2018-03-09 15:21:05
    转自:http://www.cnblogs.com/thjfk/p/4086001.html Camera原理:外部光线穿过lens后,经过color filter滤波后照射到sensor面上,sensor将从lens上传到过来的光线转换成电信号,再通过内部的AD转换为数字信号,如果...

    转自:http://www.cnblogs.com/thjfk/p/4086001.html  

    Camera原理:外部光线穿过lens后,经过color filter滤波后照射到sensor面上,sensor将从lens上传到过来的光线转换成电信号,再通过内部的AD转换为数字信号,如果sensor没有集成DSP,则通过DVP的方式传输到baseband,此时的数据格式是RAW DATA。必须通过平台的isp来处理。如果集成了DSP,这RAW DATA数据经过AWB,color matrix,lens shading,gamma,sharpness,AE和de-noise处理后输出YUV或者RGB格式的数据。最后会由CPU送到framebuffer中进行显示。

    1、首先对照原理图,检查camera module的pin脚连接是否正确。

     

    2、用示波器量Camera的MCLK管脚,看是否正确,如果MCLK正常,通常情况下PCLK也应该有波形;

          (1)MCLK 为camera提供时钟,给模组内部的pll使用。qualcomm平台是24MHZ。broadcom平台是26MHZ。

    3、用万用表测量Camera的电源管脚,查看Camera的供电是否正常;     

        (2)AVDD 模拟电路电源 2.8V ,正常情况下,AVDD需要单独供电,电源纹波<=30mV.

              IOVDD/DOVDD/VIF:  Power support for IO circuits   1.8V

              DVDD 数字电路供电电源 1.2V,如果IOVDD是1.8V的话,推荐使用sensor internal DVDD.硬件上就不要做external DVDD,否则将会导致竖条纹问题的出现。

    如果IOVDD是使用2.8V的话,则使用external DVDD,上电时序将改变。

    3、查看Camera的Spec文档,检查PWDN和RESET的管脚触发是否正常;检查代码中camera power up时序是否与datasheet的一致。   

      (3)RESET/XSHUTDOWN/XCLR:用来reset sensor;RESET一般是低有效,当脉冲为低时,reset sensor,而正常工作时,应该为高。注意reset的时间要求

      (4)PWDN/standby:power down引脚,切断供电。即powerdown 有效时,camera 为不工作模式。PWDN一般是高有效,当脉冲为高时,进入省电模式,而正常工作时为低。、powe rdown 有效极性。pwdn高有效就是说pwdn为高电平的时候进入power down模式,所以在进入预览界面的时候就要把pwdn拉低。这样camera才能进入正常工作状态

     (5) XCLR is reset input signal and power OFF of internal  core, camera become standby situation.(Low active)

          XCLR=”H”:Usually situation    XCLR=”L”:Reset situation   

    (6) XSHUTDOWN:reset and power down(active low with internal pull down resistor) hardware reset

    (7) sony sensor has the build in power on reset function.It automatically initializes the internal circuit by itself  when XCLR pin is open and the power supplies are brought up.In addition,if XCLR pin is set to low and the power supplies are bring up.The sensor will skip executing the power on reset function.

    4、在Camera的Datasheet中找出该设备的I2C地址,检查I2C配置是否正确;通常Camera Sensor的Spec上所写的I2C ID号,还包含了最后一位读写方向位。而这一位在I2C总线的定义中,严格来说,不属于ID的一部分,所以Linux I2C的驱动API中的调用参数里的ID号,通常是不考虑这一位的,读写方向位会在具体的读写操作中,在寄存器中进行设置。

    5、查看I2C通信是否正常,是否能正常进行读写,用示波器量出I2C的SCL和SDA的波形是否正常,未通信时都为高电平,通信时SCL为I2C时钟信号,SDA为I2C数据通路信号; 

    6、让Sensor FAE检查Camera的寄存器列表的配置是否正确。


     

        高通平台对于camera的代码组织,大体上还是遵循Android的框架:即上层应用和HAL层交互,高通平台在HAL层里面实现自己的一套管理策略;在kernel中实现sensor的底层驱动。对于最核心的sensor端的底层设置、ISP效果相关等代码则是单独进行了抽离,放在了一个daemon进程中进行管理。

     

     

    图1 kernel层camera主要代码简图

     

    如上图,camera在kernel层的主文件为msm.c,负责设备的具体注册及相关方法的填充;在msm_sensor.c文件中,主要维护高通自己的一个sensor相关结构体—msm_sensor_ctrl_t,同时把dts文件中的配置信息读取出来;kernel层对于不同的sensor对应自己的一个驱动文件— xxsensor.c,主要是把power setting的设定填充到msm_sensor_ctrl_t中。    

        在vendor目录下,高通把各个sensor实质性的代码放置在此。一部分代码是高通自己实现的daemon进程和kernel层及HAL层进行通讯的框架代码;另一部分则是和sensor相关的chromatix效果代码和sensor lib部分代码(init setting、lens info、output info)。

     

    图2 vendor下主要camera代码简图

     

    如上图,高通平台通过一个函数指针数组sub_module_init来管理sensor相关的组件;其中重要的是sensor_sub_module_init和chromatix_sub_module_init模块,对于sensor模块需要对应填充sensor_lib_t下的接口,对于chromatix模块则是通过高通的chromatix工具生成。

        从更高的层次来看,sensor部分的代码只是camera子系统的一部分。打开高通vendor下面关于camera的源码也可以看到,/mm-camera2/media-controller/modules目录下面,sensors只是modules文件下面其中的一个子目录。

    2  主要移植步骤

    2.1  kernel层代码移植

    1.  在./kernel/arch/arm/boot/dts/msm8226-camera-sensor-qrd.dtsi中新增camera节点,重点关注节点中的IIC地址、sensro的ID信息、电压设定信息:

    qcom,camera@21 { //21 is the I2C slave Id of the imx214 

      compatible = "qcom,imx214"; //same as the sensor name used in the project

      reg = <0x21>;
      qcom,slave-id = <0x20 0x0016 0x0214>; //sensor id
      qcom,csiphy-sd-index = <0>;
      qcom,csid-sd-index = <0>;
      qcom,actuator-src = <&actuator1>;
      qcom,led-flash-src = <&led_flash0>;
      qcom,eeprom-src = <&eeprom4>;
      qcom,mount-angle = <90>; // 90 for rear camera and 270 for front camera
      qcom,sensor-name = "imx214";//
     unique sensor name to differentiate from other sensor

      cam_vdig-supply = <&pm8226_l5>;// defined in ./kernel/arch/arm/boot/dts/msm8226-regulator.dtsi
      cam_vana-supply = <&pm8226_l15>;
      cam_vio-supply = <&pm8226_lvs1>;
      cam_vaf-supply = <&pm8226_l18>;
      qcom,cam-vreg-name = "cam_vdig", "cam_vio", "cam_vana","cam_vaf";
      qcom,cam-vreg-type = <0 1 0 0>; // 0 for LDO and 1 for LVS
      qcom,cam-vreg-min-voltage = <1100000 1800000 2800000 2950000>;
      qcom,cam-vreg-max-voltage = <1100000 1800000 2800000 2950000>;
      qcom,cam-vreg-op-mode = <120000 0 200000 600000>;
      qcom,gpio-no-mux = <0>;
      gpios = <&msmgpio 26 0>,
          <&msmgpio 37 0>,
          <&msmgpio 36 0>,
          <&msmgpio 15 0>;
      qcom,gpio-reset = <1>;
      qcom,gpio-standby = <2>;
      qcom,gpio-af-pwdm = <3>;
      qcom,gpio-req-tbl-num = <0 1 2 3>;
      qcom,gpio-req-tbl-flags = <1 0 0 0>;
      qcom,gpio-req-tbl-label = "CAMIF_MCLK",
                    "CAM_RESET1",
                    "CAM_STANDBY",
                    "CAM_AF_PWDM";
      qcom,csi-lane-assign = <0x4320>;
      qcom,csi-lane-mask = <0x1f>;
      qcom,sensor-position = <0>; // 0 for rear camea and 1 for front camera
      qcom,sensor-mode = <0>; // 0 for bayer format and 1 for yuv format
      qcom,cci-master = <0>;
      status = "ok";
      }; 

    详细的文档请参考 ./kernel/Documentation/devicetree/bindings/media/video/目录。

    2.增加以下文件./kernel/drivers/media/platform/msm/camera_v2/sensor/imx214.c

     

    +static struct msm_sensor_power_setting imx214_power_setting[] = {
    + {
    + .seq_type = SENSOR_VREG,
    + .seq_val = CAM_VIO,
    + .config_val = 0,
    + .delay = 1,
    + },
    + {
    + .seq_type = SENSOR_VREG,
    + .seq_val = CAM_VANA,
    + .config_val = 0,
    + .delay = 1,
    + },
    + {
    + .seq_type = SENSOR_VREG,
    + .seq_val = CAM_VDIG,
    + .config_val = 0,
    + .delay = 1,
    + },
    + {
    + .seq_type = SENSOR_VREG,
    + .seq_val = CAM_VAF,
    + .config_val = 0,
    + .delay = 5,
    + },
    + {
    + .seq_type = SENSOR_GPIO,
    + .seq_val = SENSOR_GPIO_STANDBY,
    + .config_val = GPIO_OUT_LOW,
    + .delay = 1,
    + },
    + {
    + .seq_type = SENSOR_GPIO,
    + .seq_val = SENSOR_GPIO_RESET,
    + .config_val = GPIO_OUT_LOW,
    + .delay = 5,
    + },
    + {
    + .seq_type = SENSOR_GPIO,
    + .seq_val = SENSOR_GPIO_AF_PWDM,
    + .config_val = GPIO_OUT_LOW,
    + .delay = 5,
    + },
    + {
    + .seq_type = SENSOR_GPIO,
    + .seq_val = SENSOR_GPIO_STANDBY,
    + .config_val = GPIO_OUT_HIGH,
    + .delay = 5,
    + },
    + {
    + .seq_type = SENSOR_GPIO,
    + .seq_val = SENSOR_GPIO_RESET,
    + .config_val = GPIO_OUT_HIGH,
    + .delay = 10,
    + },
    + {
    + .seq_type = SENSOR_GPIO,
    + .seq_val = SENSOR_GPIO_AF_PWDM,
    + .config_val = GPIO_OUT_HIGH,
    + .delay = 5,
    + },
    + {
    + .seq_type = SENSOR_CLK,
    + .seq_val = SENSOR_CAM_MCLK,
    + .config_val = 24000000,
    + .delay = 10,
    + },
    + {
    + .seq_type = SENSOR_I2C_MUX,
    + .seq_val = 0,
    + .config_val = 0,
    + .delay = 0,
    + },
    +};

    3.在以下文件中添加对imx214的支持

     ./kernel/arch/arm/configs/msm8226_defconfig

    +CONFIG_IMX214=y

    4./kernel/drivers/media/platform/msm/camera_v2/Kconfig

    +config IMX214
    + bool "Sensor IMX214 (BAYER 13M)"
    + depends on MSMB_CAMERA
    + ---help---
    + Sony 12 MP Bayer Sensor with auto focus, uses
    + 4 mipi lanes, preview config = 2104 x 1560 at 49 fps,
    + snapshot config = 4208 x 3120 at 24 fps,
    + Video HDR support.

    5、./kernel/drivers/media/platform/msm/camera_v2/sensor/Makefile

    +obj-$(CONFIG_IMX214) += imx214.o

    6、注册时钟./kernel/arch/arm/mach-msm/clock-8226.c 

    @@ -3421,6 +3421,11 @@ static struct clk_lookup msm_clocks_8226[] = {
    CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "0.qcom,camera"),
    CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "1.qcom,camera"),

    + CLK_LOOKUP("cam_clk", camss_mclk0_clk.c, "21.qcom,camera"),
    + CLK_LOOKUP("cam_src_clk", mclk0_clk_src.c, "21.qcom,camera"),

    2.2  vendor下代码移植

        Vendor下面的代码主要是两部分,一个是sensor_libs目录下的sensor具体设定、配置文件,另一个是chromatix下面的ISP效果文件。具体为:

    1. ./vendor/qcom/proprietary/mm-camera/mm-camera2/media-controller/modules/sensors/sensor_libs/imx214/imx214_lib.c

    +/*===========================================================================
    + * FUNCTION - imx214_open_lib -
    + *
    + * DESCRIPTION:
    + *==========================================================================*/
    +void *imx214_open_lib(void)
    +{
    + return &sensor_lib_ptr;
    +}

    This lib will be loaded when camera deamon process is started, kernel will find the handle based on the sensor name in dtb(device tree binary file), so please make sure the file name and function name follow the request for your sensor. 

    <your_sensor_name>/<your_sensor_name>_lib.c 
    void *<your_sensor_name>_open_lib(void)

    sensor输出设置

    static struct sensor_lib_out_info_t sensor_out_info[] = { 

    /* vt_pixel_clk = .line_length_pclk* frame_length_lines*frame rate */
    /* op_pixel_clk = VFE working clk */

    ....

    }

     

     

    2.  chromatix目录下相关文件,在对应sensor目录下包含4个目录和一个Android文件,总共13个文件,这些文件都会由chromatix调试工具生成。

    图8  vendor下chromatix相关文件示例图

    3. vendor下还有eeprom文件,模组自带的eeprom数据处理相关;AF相关文件,调试工具生成的关于AF的效果文件;配置文件,把需要编译的模块填进配置文件中。

    Acuator porting 

    ./kernel/drivers/media/video/msm/actuators/actuator.c

    msm_actuator_ctrl_t contains all the information about the actuator setting related to sensors like 
    i2c addr, set_info, focal length, etc. All the info is loaded from the chromatix file for the sensor.

    In af header file, the driver engineer should take care of the structure of actuator_params_t, which contains the af drive ic address, register patten, etc. It is important for AF working.

    3  调试常见问题

    3.1  kernel和vendor下命名匹配

        在参考其他代码移植调试一个新sensor的过程中,要注意在对应的dts文件中给sensor配置节点信息的过程中,“qcom,sensor-name”字段的配置要和vendor下面的sensor lib代码中的“xxx_open_lib”函数名以及对应的Android.mk中的“LOCAL_MODULE”名称匹配,否则相应sensor的vendor下库文件无法调用,这时打开camera会出现闪退现象。具体可参考平台代码sensor.c中的sensor_load_library()函数。

     

    图10  camera name匹配详图

     

    3.2  sensor lib中的sensor_lib_out_info_t填充

     

        一般来说,每个sensor可以配置输出不同大小的图像。此时,除了进行对应的sensor setting来改变sensor自身的输出及相关配置外;还需要将相关的输出大小、帧率等信息通知平台端,即填充struct sensor_lib_out_info_t结构体。

     

    图11 高通平台获取sensor信息框图

     

    填充的这个sensor_lib_out_info_t中的成员,最终会作为sensor基本信息的一部分被HAL层获取到,上图为高通平台获取sensor信息的一个简单框图。

        在调试过程中,需要注意的是这个结构体的成员max_fps需要填写至少大于等于30;否则会因为在获取capability时无法得到有效的previewsize、video size而无法进入预览。具体可参考平台代码mct_pipeline.c中的mct_pipeline_populate_query_cap_buffer()函数。

    3.3  sensorlib中的exposure_table_size填写

        对于sensor端输出RAW数据,平台端进行ISP处理的情形来说,sensor端除了基本的init配置外,另外一个就是根据平台端AEC计算出来的数据来对应调整sensor的曝光。在高通平台上将平台端的AEC和具体的sensor曝光设置联系起来的是chromatix文件中的一个Exposure Table和sensor lib文件中的exposure对应接口。

        这里的exposure_table_size对应着sensor lib中sensor_fill_exposure_array()接口写入的sensor寄存器的个数,平台代码中需要根据这个exposure_table_size来动态分配内存大小。如果这个值的填写和sensor_fill_exposure_array()中实际写入的值大小不一致,就会造成内存方面的crash。具体可参考平台代码sensor.c中的sensor_apply_exposure()函数。

     

    3.4  kernel 层非常规设定

        对于一些sensor来说,对于电压的设定或是MCLK的设定有非常规要求的时候,可能就需要修改平台上相关的默认设定。

        对于sensor的几路工作电压 (AVDD、DVDD、IOVDD),平台端一般都是通过PMIC的相应regulator供电,而硬件上regulator的输出能力一般都有限制,代码上也会有体现。如果有sensor需要的电压超过代码上相应regulator的限制值,可以查看PMIC上的说明,如果代码上的限制值并不是硬件的真正极限,可以修改平台代码解决。

        对于MCLK的设定,高通平台有一些常规的值设定。如果sensor有特殊要求,而这个MCLK不能被平台识别,这时候可以在平台的clock相关代码中,通过配置平台的PLL参数来生成特定的MCLK时钟给sensor使用。

    展开全文
  • 高通camera代码框架

    2018-01-17 13:25:23
    高通平台camera层代码初始化的框架流程图,对于ISP工程师等了解camera的运行流程有帮助
  • 接触高通平台camera不长时间,了解的不够深入,下面个人所了解内容的是基于高通平台的camera,有的地方能描述不一定会很清楚,以后会慢慢补充! 一 框架介绍 Package -> Framwork -> JNI -> Camera.cpp -...
  • 许久未更新博客,今天再次重磅推出鄙人的浅显的一些总结,以供参考,该文主要是基于camera一个小功能来详细讲解java层接口如何步步调用至hardware层接口,涉及到一些机制的简单介绍,希望可以为您提供更多的参考,...
  • 此patch为将raw12数据流传输给上层,高通平台默认支持raw10和raw16,按照基础框架将raw12添加进camera HAL3代码中即可。
  • 高通camera基本代码架构

    千次阅读 2017-11-28 17:22:03
    Camera原理:外部光线穿过lens后,经过color filter滤波后照射到sensor面上,sensor将从lens上传到过来的光线转换成电信号,再通过内部的AD转换为数字信号,如果sensor没有集成DSP,则通过DVP的方式传输到baseband,...
  • 高通camera驱动分析

    千次阅读 2018-11-27 11:56:25
    高通camera驱动分析 ./qcom/proprietary/mm-still/codec_v1/omx/jpeg_encoder/Android.mk:15:CHROMATIX_VERSION := 0309 这个定义用那个版本,这个就是用0309的版本 在调试的时候发现不能点亮,发现是pdaf关掉就...
  • 高通camera调试步骤

    千次阅读 2018-11-27 11:44:47
    项目比较紧,3周内把一个带有外置ISP,MIPI数据通信,800万像素的camera从无驱动到实现客户全部需求。 1日 搭平台,建环境,编译内核,烧写代码。 我是一直在Window下搭...2日 编写camera驱动大致框架,配置GPIO...
  • 高通Camera功耗优化

    2019-12-16 10:16:33
    一、随便说说 功耗优化一直是一个令人头大的东西,毕竟单枪匹马,没人指导,真的很... 不知道有没有大神通过改Camera框架,进行这种级别的功耗优化! 功耗优化的2个层面: 1.硬件 2.软件 平台:高通8909 二、知...
  • 高通camera hal3学习

    2021-07-27 10:06:59
    高通camera camx-chi框架 配流 open request
  • 高通camera基本代码架构

    万次阅读 2015-08-24 18:07:14
    Camera原理:外部光线穿过lens后,经过color filter滤波后照射到sensor面上,sensor将从lens上传到过来的光线转换成电信号,再通过内部的AD转换为数字信号,如果sensor没有集成DSP,则通过DVP的方式传输到baseband,...
  • Android 高通平台 Camera C/S init 流程
  • 高通Camera基本架构及Sensor移植

    千次阅读 2019-07-08 09:22:55
    camera基本代码架构   Camera原理:外部光线穿过lens后,经过color filter滤波后照射到sensor面上,sensor将从lens上传到过来的光线转换成电信号,再通过内部的AD转换为数字信号,如果sensor没有集成DSP,...
  • 高通camera结构(摄像头基础介绍)

    千次阅读 2019-06-19 10:15:10
    2.3 Camera框架的client部分: 代码位置:/android/frameworks/base/libs/camera/下5个文件。 Camera.cpp CameraParameters.cpp ICamera.cpp ICameraClient.cpp ICameraService.cpp 它们的...
  • 本文转载自:... 1.总体架构 AndroidCamera 框架从整体上看是一个 client/service 的架构, 有两个进程: client 进程,可以看成是 AP 端,主要包括Java代码与一些 native c/c++代码; service ...
  • 高通camera整体架构分析之端口模块篇
  • 高通camera模块驱动指南资料介绍

    千次阅读 2018-10-15 14:41:33
    本资料提供了摄像机传感器和相关模块的驱动程序开发指南,并描述了...摄像机传感器框架包括以下组件的配置: Sensor CSIPHY CSID Camera Control Interface (CCI) Actuator Flash EEPROM Chromatix™ 本资料中的大...
  • Android Camera HAL3 - 框架流程预览

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

    千次阅读 多人点赞 2019-05-18 18:18:05
    想写一份关于qualcomm 平台 的camera driver 的文档 ,想讲清楚 camera 各个 module 和 camera sensor的各个sub module。 无论是 camx 还是 mm-camera 结构, 无论是android O 还是 N 东西就那么多,就不同的写法...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,560
精华内容 624
关键字:

高通camera框架