Camera應用是android多媒體系統中典型的採用C/S架構設計的應用,Client和Server在兩個獨立的線程間通過Binder機制通信。下面是Camera的總體構架圖。
從應用層的Camera.java(packages\app\Camera),到framework java部分的Camera.java(framework\base\core\java\android\hardware),再到JNI層的android_hardware_camera(framework\base\core),接着轉到framework C++部分的Camera.cpp和CameraService.cpp,Camera2Client.cpp。其中Framework C++部分的Binder數據通信結構如下:
下面大致分兩個部分來介紹Camera:Camera的初始化以及Camera Preview流程。
Camera的初始化
由於Camera是通過Binder通信的,所以必然會在ServiceManager註冊它的service。對應的路徑是frameworks\av\media\mediaserver\Main_MediaServer.cpp下有個main函數, 其中CameraService::instantiate()就是註冊CameraService服務的。接下來,我們回過頭來,從CameraApp的初始化來看這個流程。
點開Camera應用圖標後,Camera應用會在Activity的onCreate()方法中啓動一個線程叫CameraStartUpThread。在該線程中,按照從啓動到預覽,分爲幾個步驟:
1、Open Camera
2、applyXXXCallbacks
3、applyParameters
4、startPreview
註冊回調函數主要和Camera預覽窗口的圖標的點擊有關,applyParameter主要和Camera的參數設置相關(如是否開啓flash,picture size是多少等等)。這兩個後面有機會再展開,這裏主要分析openCamera和startPreview。
Util.openCamera(cameraId)
-->CameraHolder.instance().open(cameraId)
-->CameraManager.instance().cameraOpen(cameraId)
-->FrameworksClassFactory.openCamera(cameraId)
-->Camera.open(cameraId)
這裏的Camera就是framework java部分的camera了,即framework\base\core\java\android\hardware下的Camera.java。這裏的open動作會創建一個Camera實例,實例初始化調用native_setup(newWeakReference<Camera>(this), cameraId, packageName)。從函數名可以看出,調用轉到JNI層了,通過JNI的命名規則,我們在android_hardware_Camera.cpp中找到android_hardware_Camera_native_setup()。調用關係:
Camera.open(cameraId)
-->new Camera(cameraId)
-->native_setup(…);
-->sp<Camera> camera = Camera::connect(…)
-->CameraBaseT::connect(…)
-->const sp<ICameraService>& cs =getCameraService();
-->(cs.get()->*fnConnectService)(…)
再注意到Camera.cpp中fnConnectService的賦值CameraTraits<Camera>::TCamConnectServiceCameraTraits<Camera>::fnConnectService = &ICameraService::connect;從上面的圖標我們瞭解到ICameraService也是按照Binder通信的,從其中成員BpCameraService(Client端),BnCameraService(Server端),BpCameraService::connectà BnCameraService:: onTransact,switch語句中走CONNECT分支。注意其中兩條語句:
sp<ICameraClient>cameraClient =
interface_cast<ICameraClient>(data.readStrongBinder());
status_tstatus = connect(cameraClient, cameraId,
clientName, clientUid,/*out*/ camera);
由Binder知識,connect轉到CameraService中的connect,在其中創建了cameraClient爲Camera2Client。服務端CameraService在創建時,即在Camera.cpp在從IServiceManager中獲取server對象時創建,constsp<ICameraService>& cs = getCameraService();前面提到在CameraService初始化時會創建實例,其中調用到onFirstRef()。hw_get_module函數就是用來獲取模塊的Hal stub,這裏是通過CAMERA_HARDWARE_MODULE_ID 獲取Camera Hal層的代理stub,並賦值給mModule,後面就可通過操作mModule完成對Camera模塊的控制。以上基本上就完成了對Camera的初始化了。下面再瞭解一下Camera的預覽流程。
CameraPreview流程
應用層的Camera一般不設置previewcallback回調,除非你的app設置了 setPreviewCallback,可以看出preview的數據還是可以向上層回調,只是系統默認不回調,另數據採集區與顯示區兩個緩存區 buffer preview數據的投遞,以完成preview實時顯示是在HAL層完成的。下面我們還是從應用上層開始逐步跟蹤代碼流程,詳細介紹一下。
Camera.java(Camera Application)
-->Camera.java(FrameworokJava)
-->android_hardware_camera.cpp(JNI)
-->Camera.cpp(Client)
-->CameraService.cpp(Server)
-->CameraHarwareInterface(HALinterface)
上層從startPreview開始到JNI層的代碼流程大致如下:
startPreview()
1)--> mCamera.getCameraDevice().startPreviewAsync()
2)-->startPreviewAsync()
3)-->mCamera.startPreview()(Framework android_hardware_camera)
4)-->android_hardware_Camera_startPreview(…)
稍作解釋,2)中mCamera.getCameraDevice就是上面介紹的Camera初始化時返回的Util.openCamera(),得到CameraManager.CameraProxy實例,調用startPreviewAsync()實際上就是發了一個消息START_PREVIEW_ASYNC。在收到消息後,3)中調用ICamera的startPreview,這裏對應frameworkjava部分的android_hardware_camera的startPreview轉到JNI層處理。如同上面分析camera的open接口一樣,大致流程如下:
ICamera::startPreview()
-->ICamera::BpCamerastartPreview()
-->ICamera::BnCameraonTransact()START_PREVIEW case分支
在Camera2Client裏將處理preview的請求並進入HAL層
status_t Camera2Client::startPreview() {
……
return startPreviewL(l.mParameters, false);
}
Camera2Client的數據處理和StreamingProcessor相關。
status_t Camera2Client::startPreviewL(Parameters ¶ms,bool restart) {
……
if (!mStreamingProcessor->haveValidPreviewWindow()){
……
}
res =mStreamingProcessor->updatePreviewStream(params);
……
if (!params.recordingHint) {
……
res =mStreamingProcessor->updatePreviewRequest(params);
res = mStreamingProcessor->startStream(StreamingProcessor::PREVIEW, outputStreams);
} else {
……
res =mStreamingProcessor->updateRecordingRequest(params);
res =mStreamingProcessor->startStream(StreamingProcessor::RECORD, outputStreams);
}
}
上層應用如果想獲取Preview數據,則需要調用setPreviewDisplay(SurfaceHolder), 數據將傳給上層設置的SurfaceView。在以上函數中紅色部分,在mStreamingProcessor->updatePreviewStream(params)中會將上層的SurfaceView轉換成IGraphicBufferProducer類型,在Camera2Client中再轉換成底層能識別的Surface,並傳入StreamingProcessor,以mPreviewWindow指向它。後面的預覽數據也就指定傳給該Surface了。
最後在updatePreviewRequest(params)中創建一個previewRequest,然後開始向outputStreams中update stream。