Camera HAL(Camera Preview)

看看Android系统,高通camera hal(camera3)当中camera preview数据是怎么从kernel一层一层传递,最终发给SurfaceView的。
高通的Camera HAL的module在QualcommCamera.cpp[android/hardware/qcom/camera/qcamera2/hal/wrapper]
这个Camera HAL被加载是在CameraServer里,加载流程如下:
这里写图片描述

Camera2Client创建的XXProcessor。这几个Processor的说明如下:
1. StreamingProcessor并启动一个他所属的thread,该模块主要负责处理previews与record两种视频流的处理,用于从hal层获取原始的视频数据
2. FrameProcessor并启动一个thread,该模块专门用于处理回调回来的每一帧的3A等信息,即每一帧视频除去原始视频数据外,还应该有其他附加的数据信息,如3A值。
3. CaptureSequencer并启动一个thread,该模块需要和其他模块配合使用,主要用于向APP层告知capture到的picture。
4. pegProcessor并启动一个thread,该模块和streamprocessor类似,他启动一个拍照流,一般用于从HAL层获取jpeg编码后的图像照片数据
5. 此外ZslProcessor模块称之为0秒快拍,其本质是直接从原始的Preview流中获取预存着的最近的几帧,直接编码后返回给APP,而不需要再经过take picture去请求获取jpeg数据。0秒快拍技术得意于当下处理器CSI2 MIPI性能的提升以及Sensor支持全像素高帧率的实时输出。一般手机拍照在按下快门后都会有一定的延时,是因为需要切换底层Camera以及ISP等的工作模式,并重新设置参数以及重新对焦等等,都需要花一定时间后才抓取一帧用于编码为jpeg图像。

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

CameraServer启动,HAL加载完之后,就可以从上层APP调用相关的接口打开camera并进行preview了。
1.第一步当然是打开camera了,也就是camera_device_open()函数。这个函数被调用之后的调用栈如下(中间的JNI等等忽略了~):

camera_device_open()[QualcommCamera.cpp]
    ->camera_device_open()[QCamera2Factory.cpp]
        ->cameraDeviceOpen()[QCamera2Factory.cpp]
            ->openCamera()[QCamera3HWI.cpp]
                ->camera_open()[mm_camera_interface.c]  
                    ->mm_camera_open()[mm_camera.c]

mm_camera_open()[mm_camera.c]这里主要做的工作就是打开/dev/videoXX这个节点了。
还有就是创建一个socket,这个还不知道干嘛~~

int32_t camera_open(uint8_t camera_idx, mm_camera_vtbl_t **camera_vtbl){
    ...
    sscanf(dev_name, "/dev/video%d", &cam_idx);
    my_obj->ctrl_fd = open(dev_name, O_RDWR | O_NONBLOCK);
    ...
    mm_camera_socket_create(cam_idx, MM_CAMERA_SOCK_TYPE_UDP);
    ...
}

2.第二步,要进行preview当然要设置一个surfaceview给camera hal。这样才可以在得到frame数据之后在surfaceview中刷。这一步是APP调用setPreviewDisplay(SurfaceHolder holder)来完成的。
调用栈如下:

android_hardware_Camera_setPreviewSurface()
    ->setPreviewTarget()[camera.cpp]
        ->经过Binder
            ->setPreviewTarget()[CameraClient2.cpp]
                ->setPreviewWindow()[StreamingProcess.cpp]
                最后保存在mPreviewWindow

3.第三步就是调用StartPreview来开始camera preview了。

status_t CameraClient::startPreview()
-> status_t CameraClient::startCameraMode(camera_mode mode)
 ->CameraClient::startPreviewMode()
  ->QCamera2HardwareInterface::setPreviewWindow(mPreviewWindow)
   ->QCamera2HardwareInterface::startPreview()[QCamera2HWI.cpp]

startPreview()函数设置Preview channel的回调函数

int QCamera2HardwareInterface::startPreview(){
    ...
    rc = startChannel(QCAMERA_CH_TYPE_PREVIEW);
    ...
}
QCamera2HardwareInterface::startChannel()
    -> QCameraChannel::config()
        -> QCameraStream::configStream()
        这里设置stream_config.stream_cb = dataNotifyCB。
    -> QCameraChannel::start()
        -> mm_camera_intf_start_channel()
            -> mm_camera_start_channel()
                -> mm_channel_start() [mm_camera_channel.c]
                    -> mm_stream_fsm_reg()
                        ->mm_camera_cmd_thread_launch()
                            ->启动线程,回调函数是mm_camera_cmd_thread()
                               //这个函数处理从kernel得到buffer等之后的操作,
                               //比如mm_stream_handle_rcvd_buf函数发的
                               //MM_CAMERA_CMD_TYPE_DATA_CB命令    
                            ->mm_stream_dispatch_app_data()//mm_camera_cmd_threa()又会调用这个函数
                              //最后buf_cb[0].cb是QCameraStream::dataNotifyCB()函数,这个又调用
                              //QCamera3Stream::processDataNotify把frame加到mDataQ,之后发
                              //CAMERA_CMD_TYPE_DO_NEXT_JOB。
                            //QCamera3Stream::dataProcRoutine()处理CAMERA_CMD_TYPE_DO_NEXT_JOB。
                            //调用pme->mDataCB()
                            //这个mDataCB()是在addPreviewChannel()->addStreamToChannel()的时候
                            //加的回调函数preview_stream_cb_routine !!!
                            //这个函数应该是处理并显示用的
                        ->mm_stream_streamon()

那camera的数据在哪里监听? 又传给mm_camera_cmd_thread()线程的呢?

mm_stream_qbuf()
    -> mm_camera_poll_thread_add_poll_fd(&my_obj->ch_obj->poll_thread[0],
            my_obj->my_hdl, my_obj->fd, mm_stream_data_notify, (void*)my_obj,
            mm_camera_async_call);
        -> notify_cb就是mm_stream_data_notify()
mm_channel_init()
    -> mm_camera_poll_thread_launch()
        -> pthread_create(&poll_cb->pid, NULL, mm_camera_poll_thread, (void *)poll_cb);
            -> mm_camera_poll_thread()
                -> mm_camera_poll_fn()
                    -> 在调用poll,然后有返回就去调用notify_cb()了,也就是mm_stream_data_notify

mm_stream_data_notify()又会去调用mm_stream_handle_rcvd_buf()把数据发过去!!

参考:
http://blog.chinaunix.net/uid-2630593-id-3307179.html

qualcomm camera hal
http://my.oschina.net/jerikc/blog/215653

http://www.linuxidc.com/Linux/2011-09/42501p4.htm

http://www.2cto.com/kf/201510/445484.html

http://www.2cto.com/kf/201510/445484.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章