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

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