Android中Camera的調用流程可分爲以下幾個層次:
Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camera HAL->Camera Driver
以拍照流程爲例:
1. 各個參數設置完成,對焦完成後,位於Package的Camera.java會調用Framework中Camera.java的takePicture函數,如下:
此函數保存Package層傳下的callback函數,同時調用JNI層的native_takePicture
2. JNI層的native_takePicture自己並沒有做太多事情,僅僅是通過./base/core/jni/android_hardware_Camera.cpp中的android_hardware_Camera_takePicture,簡單地調用./av/camera/Camera.cpp中的takePicture函數。此前已經把JNI中的一個對象註冊成了Camera.cpp的listener
3. 位於frameworks/base/libs/camera是向CameraService請求服務的客戶端,但它本身也繼承了一個BnCameraClient類,用於CameraService回調自己。
從上面的接口定義可以看到,這個類就是用於回調。
Camera.cpp的takePicture函數是利用open Camera時得到的ICamera對象來繼續調用takePicture
4. 接下來通過binder轉到另一個進程CameraService中的處理。CameraService中之前已經實例化了一個HAL層的 CameraHardware,並把自己的data callback傳遞給了CameraHardware,這些工作都是由CameraService的內部類Client來完成的,這個Client類繼承自BnCamera,是真正提供Camera操作API的類
5. 然後自然是調用HAL層CameraHardware的takePicture函數。從HAL層向下就不是Android的標準代碼了,各個廠商有自己不同的實現。但思路應該都是相同的:Camera遵循V4L2架構,利用ioctl發送VIDIOC_DQBUF命令得到有效的圖像數據,接着回調HAL層的data callback接口以通知CameraService,CameraService會通過binder通知Camera.cpp,如下:
6. Camera.cpp會繼續通知它的listener:
7. 而這個listener就是我們的JNI層的JNICameraContext對象了:
8. 可以看到JNI層最終都會調用來自java層的函數postEventFromNative,這個函數會發送對應的消息給自己的 eventhandler,收到消息後就會根據消息的類型回調Package層Camera.java最初傳下來的callback函數。至此,我們就在最上層拿到了圖像數據。
Package->Framework->JNI->Camera(cpp)--(binder)-->CameraService->Camera HAL->Camera Driver
以拍照流程爲例:
1. 各個參數設置完成,對焦完成後,位於Package的Camera.java會調用Framework中Camera.java的takePicture函數,如下:
1 |
public final void takePicture(ShutterCallback
shutter, PictureCallback raw, |
2 |
PictureCallback
postview, PictureCallback jpeg) { |
3 |
mShutterCallback
= shutter; |
4 |
mRawImageCallback
= raw; |
5 |
mPostviewCallback
= postview; |
6 |
mJpegCallback
= jpeg; |
7 |
native_takePicture(); |
8 |
} |
此函數保存Package層傳下的callback函數,同時調用JNI層的native_takePicture
2. JNI層的native_takePicture自己並沒有做太多事情,僅僅是通過./base/core/jni/android_hardware_Camera.cpp中的android_hardware_Camera_takePicture,簡單地調用./av/camera/Camera.cpp中的takePicture函數。此前已經把JNI中的一個對象註冊成了Camera.cpp的listener
3. 位於frameworks/base/libs/camera是向CameraService請求服務的客戶端,但它本身也繼承了一個BnCameraClient類,用於CameraService回調自己。
1 |
class ICameraClient: public IInterface |
2 |
{ |
3 |
public : |
4 |
DECLARE_META_INTERFACE(CameraClient); |
5 |
6 |
virtual void notifyCallback(int32_t
msgType, int32_t ext1, int32_t ext2) = 0 ; |
7 |
virtual void dataCallback(int32_t
msgType, const sp<IMemory>&
data) = 0 ; |
8 |
virtual void dataCallbackTimestamp(nsecs_t
timestamp, int32_t msgType, const sp<IMemory>&
data) = 0 ; |
9 |
}; |
從上面的接口定義可以看到,這個類就是用於回調。
Camera.cpp的takePicture函數是利用open Camera時得到的ICamera對象來繼續調用takePicture
4. 接下來通過binder轉到另一個進程CameraService中的處理。CameraService中之前已經實例化了一個HAL層的 CameraHardware,並把自己的data callback傳遞給了CameraHardware,這些工作都是由CameraService的內部類Client來完成的,這個Client類繼承自BnCamera,是真正提供Camera操作API的類
5. 然後自然是調用HAL層CameraHardware的takePicture函數。從HAL層向下就不是Android的標準代碼了,各個廠商有自己不同的實現。但思路應該都是相同的:Camera遵循V4L2架構,利用ioctl發送VIDIOC_DQBUF命令得到有效的圖像數據,接着回調HAL層的data callback接口以通知CameraService,CameraService會通過binder通知Camera.cpp,如下:
01 |
void CameraService::Client::dataCallback(int32_t
msgType, |
02 |
const sp<IMemory>&
dataPtr, void *
user) { |
03 |
LOG2( "dataCallback(%d)" ,
msgType); |
04 |
05 |
sp<Client>
client = getClientFromCookie(user); |
06 |
if (client
== 0) return ; |
07 |
if (!client->lockIfMessageWanted(msgType)) return ; |
08 |
09 |
if (dataPtr
== 0) { |
10 |
LOGE( "Null
data returned in data callback" ); |
11 |
client->handleGenericNotify(CAMERA_MSG_ERROR,
UNKNOWN_ERROR, 0); |
12 |
return ; |
13 |
} |
14 |
15 |
switch (msgType)
{ |
16 |
case CAMERA_MSG_PREVIEW_FRAME: |
17 |
client->handlePreviewData(dataPtr); |
18 |
break ; |
19 |
case CAMERA_MSG_POSTVIEW_FRAME: |
20 |
client->handlePostview(dataPtr); |
21 |
break ; |
22 |
case CAMERA_MSG_RAW_IMAGE: |
23 |
client->handleRawPicture(dataPtr); |
24 |
break ; |
25 |
case CAMERA_MSG_COMPRESSED_IMAGE: |
26 |
client->handleCompressedPicture(dataPtr); |
27 |
break ; |
28 |
default : |
29 |
client->handleGenericData(msgType,
dataPtr); |
30 |
break ; |
31 |
} |
32 |
} |
33 |
//
picture callback - compressed picture ready |
34 |
void CameraService::Client::handleCompressedPicture( const sp<IMemory>&
mem) { |
35 |
int restPictures
= mHardware->getPictureRestCount(); |
36 |
if (!restPictures) |
37 |
{ |
38 |
disableMsgType(CAMERA_MSG_COMPRESSED_IMAGE); |
39 |
} |
40 |
41 |
sp<ICameraClient>
c = mCameraClient; |
42 |
mLock.unlock(); |
43 |
if (c
!= 0) { |
44 |
c->dataCallback(CAMERA_MSG_COMPRESSED_IMAGE,
mem); |
45 |
} |
46 |
} |
6. Camera.cpp會繼續通知它的listener:
01 |
//
callback from camera service when frame or image is ready |
02 |
void Camera::dataCallback(int32_t
msgType, const sp<IMemory>&
dataPtr) |
03 |
{ |
04 |
sp<CameraListener>
listener; |
05 |
{ |
06 |
Mutex::Autolock
_l(mLock); |
07 |
listener
= mListener; |
08 |
} |
09 |
if (listener
!= NULL) { |
10 |
listener->postData(msgType,
dataPtr); |
11 |
} |
12 |
} |
7. 而這個listener就是我們的JNI層的JNICameraContext對象了:
01 |
void JNICameraContext::postData(int32_t
msgType, const sp<IMemory>&
dataPtr) |
02 |
{ |
03 |
//
VM pointer will be NULL if object is released |
04 |
Mutex::Autolock
_l(mLock); |
05 |
JNIEnv
*env = AndroidRuntime::getJNIEnv(); |
06 |
if (mCameraJObjectWeak
== NULL) { |
07 |
LOGW( "callback
on dead camera object" ); |
08 |
return ; |
09 |
} |
10 |
11 |
//
return data based on callback type |
12 |
switch (msgType)
{ |
13 |
case CAMERA_MSG_VIDEO_FRAME: |
14 |
//
should never happen |
15 |
break ; |
16 |
//
don't return raw data to Java |
17 |
case CAMERA_MSG_RAW_IMAGE: |
18 |
LOGV( "rawCallback" ); |
19 |
env->CallStaticVoidMethod(mCameraJClass,
fields.post_event, |
20 |
mCameraJObjectWeak,
msgType, 0, 0, NULL); |
21 |
break ; |
22 |
default : |
23 |
//
TODO: Change to LOGV |
24 |
LOGV( "dataCallback(%d,
%p)" ,
msgType, dataPtr.get()); |
25 |
copyAndPost(env,
dataPtr, msgType); |
26 |
break ; |
27 |
} |
28 |
} |
8. 可以看到JNI層最終都會調用來自java層的函數postEventFromNative,這個函數會發送對應的消息給自己的 eventhandler,收到消息後就會根據消息的類型回調Package層Camera.java最初傳下來的callback函數。至此,我們就在最上層拿到了圖像數據。