Android Camera TakePicture過程分析
接著上一篇文章,繼續講解camera拍照等具體功能實行流程
Camera子系統采用C/S架構,客戶端和服務端在兩個不同的進程當中,它們使用android中的binder機制進行通信,
本系列文章將從Android Camera應用程序到硬件抽象的實現一步一步對照相機系統進行分析,首先從CameraService初始化過程著手,然後從上層APP打開照相機->進行preview->拍照以及聚焦等功能的實現全面的學習照相機子系統
1、CameraService初始化過程
frameworks\base\media\mediaserver\Main_MediaServer.cpp
CameraService在MediaServer中初始化,代碼是MediaServer的main函數,在該函數中初始化照相機服務,已在上一篇文章中講述
CameraService中的instantiate方法用來創建CameraService實例,並進行相應的初始化,這個函數定義在它的父類BinderService中:frameworks/base/include/binder/BinderService.h
相機服務的初始化過程首先是創建CameraService實例,然後將其注冊到ServiceManager中,關於它的啟動是發生在init.rc中,通過media_server來啟動CameraService,具體代碼如下:
system/core/rootdir/init.rc
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
service media /system/bin/mediaserver
class main
user media
group audio camera inet net_bt net_bt_admin net_bw_acct drmrpc
ioprio rt 4
在cameraService注冊以及啟動過程中cameraService自身會執行一些初始化的工作,主要涉及到如下工作
frameworks/base/services/camera/libcameraservice/CameraService.cpp
- CameraService::CameraService()
- :mSoundRef(0), mModule(0)
- {
- LOGI("CameraService started (pid=%d)", getpid());
- gCameraService = this;
- }
- void CameraService::onFirstRef()
- {
- BnCameraService::onFirstRef();
- if (hw_get_module(CAMERA_HARDWARE_MODULE_ID,
- (const hw_module_t **)&mModule) < 0) {
- LOGE("Could not load camera HAL module");
- mNumberOfCameras = 0;
- }
- else {
- mNumberOfCameras = mModule->get_number_of_cameras();
- if (mNumberOfCameras > MAX_CAMERAS) {
- LOGE("Number of cameras(%d) > MAX_CAMERAS(%d).",
- mNumberOfCameras, MAX_CAMERAS);
- mNumberOfCameras = MAX_CAMERAS;
- }
- for (int i = 0; i < mNumberOfCameras; i++) {
- setCameraFree(i);
- }
- }
- }
在上述初始化代碼中,先通過調用HAL硬件抽象層庫load camera HAL module,獲取支持的攝像頭個數並保存到mNumberOfCameras
2、應用程序鏈接相機服務過程
在camera應用程序啟動的時候首先會和CameraService建立連接,camera應用程序代碼就不分析了,上一篇文章已經說過,下面這副圖是一個簡單的流程圖
從上面的流程圖我們可以看出在請求服務的過程中多出用到了應用框架層的camera類,該類定義在 frameworks/base/core/java/android/hardware/Camera.java文件當中,這一個類正是Camera子系統中APP層和JNI層交換的接口,它對上為應用程序提供了各種操作Camera的方法,向下訪問JNI實現它自身的接口Camera類定義如下:
- public class Camera {
- public static Camera open(int cameraId) {
- return new Camera(cameraId);
- }
-
- .................
-
- Camera(int cameraId) {
- Looper looper;
- if ((looper = Looper.myLooper()) != null) {
- mEventHandler = new EventHandler(this, looper);
- } else if ((looper = Looper.getMainLooper()) != null) {
- mEventHandler = new EventHandler(this, looper);
- } else {
- mEventHandler = null;
- }
- native_setup(new WeakReference(this), cameraId);
- }
- }
下面就開始從app的takepicture逐步分析camera takepicture整個過程
在app中,takepicture是在capture方法中被調用的:packages/apps/OMAPCamera/src/com/ti/omap4/android/camera/Camera.java(apk)
- @Override
- public boolean capture() {
- synchronized (mCameraStateLock) {
- // If we are already in the
middle of taking a snapshot then ignore.
- if (mCameraState == SNAPSHOT_IN_PROGRESS || mCameraDevice == null) {
- return false;
- }
- mCaptureStartTime = System.currentTimeMillis();
- mPostViewPictureCallbackTime = 0;
- mJpegImageData = null;
- // Set rotation and gps
data.
- Util.setRotationParameter(mParameters, mCameraId, mOrientation);
- Location loc = mLocationManager.getCurrentLocation();
- Util.setGpsParameters(mParameters, loc);
- if (canSetParameters()) {
- mCameraDevice.setParameters(mParameters);
- }
- try {
- mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
- mPostViewPictureCallback, new
JpegPictureCallback(loc));
- } catch (RuntimeException e ) {
- e.printStackTrace();
- return false;
- }
- mFaceDetectionStarted = false;
- setCameraState(SNAPSHOT_IN_PROGRESS);
- return true;
- }
- }
這裡調用的takePicture是在framework層中定義:frameworks/base/core/java/android/hardware/Camera.java
- public final void takePicture(ShutterCallback
shutter, PictureCallback raw,
- PictureCallback postview, PictureCallback jpeg) {
- mShutterCallback = shutter;
- mRawImageCallback = raw;
- mPostviewCallback = postview;
- mJpegCallback = jpeg;
- // If callback is not set, do not send
me callbacks.
- int msgType = 0;
- if (mShutterCallback != null) {
- msgType |= CAMERA_MSG_SHUTTER;
- }
- if (mRawImageCallback != null) {
- msgType |= CAMERA_MSG_RAW_IMAGE;
- }
- if (mPostviewCallback != null) {
- msgType |= CAMERA_MSG_POSTVIEW_FRAME;
- }
- if (mJpegCallback != null) {
- msgType |= CAMERA_MSG_COMPRESSED_IMAGE;
- }
- native_takePicture(msgType);
- }
在這裡設置callback函數,並調用通過JNI調用takepicture方法:frameworks/base/core/jni/android_hardware_Camera.cpp
- static void android_hardware_Camera_takePicture(JNIEnv *env, jobject
thiz, int msgType)
- {
- LOGV("takePicture");
- JNICameraContext* context;
- sp camera = get_native_camera(env, thiz, &context);
- if (camera == 0) return;
- /*
- * When CAMERA_MSG_RAW_IMAGE is requested, if the
raw image callback
- * buffer is available, CAMERA_MSG_RAW_IMAGE is enabled to get the
- * notification _and_ the data; otherwise, CAMERA_MSG_RAW_IMAGE_NOTIFY
- * is enabled to receive the callback
notification but no data.
- *
- * Note that CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed to the
- * Java application.
- */
- if (msgType & CAMERA_MSG_RAW_IMAGE) {
- LOGV("Enable raw image callback buffer");
- if (!context->isRawImageCallbackBufferAvailable()) {
- LOGV("Enable raw image notification, since no callback buffer exists");
- msgType &= ~CAMERA_MSG_RAW_IMAGE;
- msgType |= CAMERA_MSG_RAW_IMAGE_NOTIFY;
- }
- }
- if (camera->takePicture(msgType) != NO_ERROR) {
- jniThrowRuntimeException(env, "takePicture
failed");
- return;
- }
- }
這裡調用camera 的takepicture,即camera client 的takepicture方法:frameworks/base/libs/camera/Camera.cpp
- status_t Camera::takePicture(int msgType, const String8& params)
- {
- LOGV("takePicture: 0x%x", msgType);
- sp c = mCamera;
- if (c == 0) return
NO_INIT;
- return c->takePicture(msgType, params);
- }
這裡client 端的takepicture又調用到camera server端的takepicture:frameworks/base/services/camera/libcameraservice/CameraService.cpp
- // take a picture - image is returned in callback
- #ifdef OMAP_ENHANCEMENT_CPCAM
- status_t CameraService::Client::takePicture(int msgType, const String8& params) {
- #else
- status_t CameraService::Client::takePicture(int msgType) {
- #endif
- LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
- Mutex::Autolock lock(mLock);
- status_t result = checkPidAndHardware();
- if (result != NO_ERROR) return
result;
- if ((msgType & CAMERA_MSG_RAW_IMAGE) &&
- (msgType & CAMERA_MSG_RAW_IMAGE_NOTIFY)) {
- LOGE("CAMERA_MSG_RAW_IMAGE and CAMERA_MSG_RAW_IMAGE_NOTIFY"
- " cannot be both enabled");
- return BAD_VALUE;
- }
- // We only accept picture related message types
- // and ignore other types of messages for takePicture().
- int picMsgType = msgType
- & (CAMERA_MSG_SHUTTER |
- CAMERA_MSG_POSTVIEW_FRAME |
- CAMERA_MSG_RAW_IMAGE |
- #ifdef OMAP_ENHANCEMENT
- CAMERA_MSG_RAW_BURST |
- #endif
- CAMERA_MSG_RAW_IMAGE_NOTIFY |
- CAMERA_MSG_COMPRESSED_IMAGE);
- #ifdef OMAP_ENHANCEMENT
- picMsgType |= CAMERA_MSG_COMPRESSED_BURST_IMAGE;
- #endif
- enableMsgType(picMsgType);
- #ifdef OMAP_ENHANCEMENT
- // make sure the other capture messages are disabled
- picMsgType = ~picMsgType &
- (CAMERA_MSG_SHUTTER |
- CAMERA_MSG_POSTVIEW_FRAME |
- CAMERA_MSG_RAW_IMAGE |
- CAMERA_MSG_RAW_BURST |
- CAMERA_MSG_RAW_IMAGE_NOTIFY |
- CAMERA_MSG_COMPRESSED_IMAGE |
- CAMERA_MSG_COMPRESSED_BURST_IMAGE);
- disableMsgType(picMsgType);
- #endif
- #ifdef OMAP_ENHANCEMENT_CPCAM
- return mHardware->takePicture(params);
- #else
- return mHardware->takePicture();
- #endif
- }
一些初始化之後,最終server端的takepicture方法會調用HAL層(硬件接口層)的takepicture方法:frameworks/base/services/camera/libcameraservice/CameraHardwareInterface.h
- /**
- * Take a picture.
- */
- #ifdef OMAP_ENHANCEMENT_CPCAM
- status_t takePicture(const ShotParameters ¶ms)
- {
- LOGV("%s(%s)", __FUNCTION__, mName.string());
- if (mDevice->ops->take_picture)
- return mDevice->ops->take_picture(mDevice,
- params.flatten().string());
- return INVALID_OPERATION;
- }
- #else
- status_t takePicture()
- {
- LOGV("%s(%s)", __FUNCTION__, mName.string());
- if (mDevice->ops->take_picture)
- return mDevice->ops->take_picture(mDevice);//從這裡開始通過V4L2子系統調用到kerner
driver的設備,以後針對這個部分做詳細學習
- return INVALID_OPERATION;
- }
- #endif
下面的重點是分析數據回調過程,這個過程是camera的最重點,在我看來也是最難點理解的地方,要多花點時間,努把力了,現在就開始
首先還是必須先追溯到Camera客戶端與服務端連接的時候,由我的上一遍初始化的文章知道,Camera客戶端與服務端連接的時候,首先調用的是client端的connect方法,
client的connect方法首先getservice,然後調用server端的connect方法,為了方便理解我再次把這部分代碼貼出:
server的connect()函數定義在以下路徑:frameworks/base/services/camera/libcameraservice/CameraService.cpp
- sp CameraService::connect(
- const sp& cameraClient, int cameraId) {
- int callingPid = getCallingPid();
- sp hardware = NULL;
- LOG1("CameraService::connect E (pid %d, id %d)", callingPid, cameraId);
- if (!mModule) {
- LOGE("Camera HAL module not loaded");
- return NULL;
- }
- sp client;
- if (cameraId < 0 || cameraId >= mNumberOfCameras) {
- LOGE("CameraService::connect X (pid %d) rejected (invalid cameraId %d).",
- callingPid, cameraId);
- return NULL;
- }
- char value[PROPERTY_VALUE_MAX];
- property_get("sys.secpolicy.camera.disabled", value, "0");
- if (strcmp(value, "1") == 0) {
- // Camera is disabled by DevicePolicyManager.
- LOGI("Camera is disabled. connect X (pid %d) rejected", callingPid);
- return NULL;
- }
- Mutex::Autolock lock(mServiceLock);
- if (mClient[cameraId] != 0) {
- client = mClient[cameraId].promote();
- if (client != 0) {
- if (cameraClient->asBinder() == client->getCameraClient()->asBinder()) {
- LOG1("CameraService::connect X (pid %d) (the same client)",
- callingPid);
- return client;
- } else {
- LOGW("CameraService::connect X (pid %d) rejected (existing client).",
- callingPid);
- return NULL;
- }
- }
- mClient[cameraId].clear();
- }
- if (mBusy[cameraId]) {
- LOGW("CameraService::connect X (pid %d) rejected"
- " (camera %d is still busy).", callingPid, cameraId);
- return NULL;
- }
- struct camera_info info;
- if (mModule->get_camera_info(cameraId, &info) != OK) {
- LOGE("Invalid camera id %d", cameraId);
- return NULL;
- }
- char camera_device_name[10];
- snprintf(camera_device_name, sizeof(camera_device_name), "%d", cameraId);
- hardware = new CameraHardwareInterface(camera_device_name);
- if (hardware->initialize(&mModule->common) != OK) {
- hardware.clear();
- return NULL;
- }
- client = new
Client(this, cameraClient, hardware, cameraId, info.facing, callingPid);
- mClient[cameraId] = client;
- LOG1("CameraService::connect X");
- return client;
- }
最重要的地方在上面標注的綠色部分,這裡在connect成功之後會new一個client,這個Client是CamereService類的內部類,
這個時候便會調用client這個內部類的client構造函數,而我們的回調函數也正是在這個時候被設置,看看代碼:
- CameraService::Client::Client(const sp& cameraService,
- const sp& cameraClient,
- const sp& hardware,
- int cameraId, int cameraFacing, int clientPid) {
- int callingPid = getCallingPid();
- LOG1("Client::Client E (pid %d)", callingPid);
- mCameraService = cameraService;
- mCameraClient = cameraClient;
- mHardware = hardware;
- mCameraId = cameraId;
- mCameraFacing = cameraFacing;
- mClientPid = clientPid;
- mMsgEnabled = 0;
- mSurface = 0;
- mPreviewWindow = 0;
- #ifdef OMAP_ENHANCEMENT_CPCAM
- mTapin = 0;
- mTapinClient = 0;
- mTapout = 0;
- mTapoutClient = 0;
- #endif
- mHardware->setCallbacks(notifyCallback,
- dataCallback,
- dataCallbackTimestamp,
- (void *)cameraId);
- // Enable zoom, error, focus, and metadata
messages by default
- enableMsgType(CAMERA_MSG_ERROR | CAMERA_MSG_ZOOM | CAMERA_MSG_FOCUS |
- CAMERA_MSG_PREVIEW_METADATA);
- // Callback is disabled by default
- mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
- mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
- mPlayShutterSound = true;
- cameraService->setCameraBusy(cameraId);
- cameraService->loadSound();
- LOG1("Client::Client X (pid %d)", callingPid);
- }
上面就對camera設置了notifyCallback、dataCallback、dataCallbackTimestamp三個回調函數,用於返回底層數據用於處理,看下它的處理方法:
這裡先針對其中的dataCallback回調方法做介紹,其他的回調方法以此類推,所以我們就先看一下dataCallback方法中都做了些什麼事情:
這裡的回調函數是camera server層的回調函數:frameworks/base/services/camera/libcameraservice/CameraService.cpp
- void CameraService::Client::dataCallback(int32_t
msgType,
- const sp& dataPtr, camera_frame_metadata_t *metadata, void* user) {
- LOG2("dataCallback(%d)", msgType);
- sp client = getClientFromCookie(user);
- if (client == 0) return;
- if (!client->lockIfMessageWanted(msgType)) return;
- if (dataPtr == 0 && metadata == NULL) {
- LOGE("Null data returned in data callback");
- client->handleGenericNotify(CAMERA_MSG_ERROR, UNKNOWN_ERROR, 0);
- return;
- }
- switch (msgType & ~CAMERA_MSG_PREVIEW_METADATA) {
- case CAMERA_MSG_PREVIEW_FRAME:
- client->handlePreviewData(msgType, dataPtr, metadata);
- break;
- case CAMERA_MSG_POSTVIEW_FRAME:
- client->handlePostview(dataPtr);
- break;
- case CAMERA_MSG_RAW_IMAGE:
- client->handleRawPicture(dataPtr);
- break;
- case CAMERA_MSG_COMPRESSED_IMAGE:
- client->handleCompressedPicture(dataPtr);
- break;
- #ifdef OMAP_ENHANCEMENT
- case CAMERA_MSG_COMPRESSED_BURST_IMAGE:
- client->handleCompressedBurstPicture(dataPtr);
- break;
- #endif
- default:
- client->handleGenericData(msgType, dataPtr, metadata);
- break;
- }
- }
這裡進行分類處理,因為preview過程需要大量數據傳輸,而且容易大家理解,這裡就針對preview數據回調過程進行分析:
- // preview callback - frame
buffer update
- void CameraService::Client::handlePreviewData(int32_t
msgType,
- const sp& mem,
- camera_frame_metadata_t *metadata) {
- ssize_t offset;
- size_t size;
- sp heap = mem->getMemory(&offset, &size);
- // local copy of the callback flags
- int flags = mPreviewCallbackFlag;
- // is callback enabled?
- if (!(flags & CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK)) {
- // If the enable bit is off, the
copy-out and one-shot bits are ignored
- LOG2("frame callback is disabled");
- mLock.unlock();
- return;
- }
- // hold a strong pointer to the client
- sp c = mCameraClient;
- // clear callback flags if no client or one-shot
mode
- if (c == 0 || (mPreviewCallbackFlag & CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK)) {
- LOG2("Disable preview callback");
- mPreviewCallbackFlag &= ~(CAMERA_FRAME_CALLBACK_FLAG_ONE_SHOT_MASK |
- CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK |
- CAMERA_FRAME_CALLBACK_FLAG_ENABLE_MASK);
- disableMsgType(CAMERA_MSG_PREVIEW_FRAME);
- }
- if (c != 0) {
- // Is the received frame copied
out or not?
- if (flags & CAMERA_FRAME_CALLBACK_FLAG_COPY_OUT_MASK) {
- LOG2("frame is copied");
- copyFrameAndPostCopiedFrame(msgType, c, heap, offset, size, metadata);
- } else {
- LOG2("frame is forwarded");
- mLock.unlock();
- c->dataCallback(msgType, mem, metadata);
- }
- } else {
- mLock.unlock();
- }
- }
這裡有兩個方向
copyFrameAndPostCopiedFrame這個函數執行兩個buff區preview數據的投遞,通過它的具體實現過程,可以知道最終他也要調用dataCallback方法繼續調用客戶端client的回調函數
所以這裡直接分析copyFrameAndPostCopiedFrame:
- void CameraService::Client::copyFrameAndPostCopiedFrame(
- int32_t msgType, const sp& client,
- const sp& heap, size_t
offset, size_t size,
- camera_frame_metadata_t *metadata) {
- LOG2("copyFrameAndPostCopiedFrame");
- // It is necessary to copy
out of pmem before sending this to
- // the callback. For efficiency, reuse
the same MemoryHeapBase
- // provided it's big enough. Don't
allocate the memory or
- // perform the copy if there's
no callback.
- // hold the preview lock while we grab
a reference to the preview buffer
- sp previewBuffer;
- if (mPreviewBuffer == 0) {
- mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
- } else if (size > mPreviewBuffer->virtualSize()) {
- mPreviewBuffer.clear();
- mPreviewBuffer = new MemoryHeapBase(size, 0, NULL);
- }
- if (mPreviewBuffer == 0) {
- LOGE("failed to allocate space for preview buffer");
- mLock.unlock();
- return;
- }
- previewBuffer = mPreviewBuffer;
- memcpy(previewBuffer->base(), (uint8_t *)heap->base() + offset, size);
- sp frame = new MemoryBase(previewBuffer, 0, size);
- if (frame == 0) {
- LOGE("failed to allocate space for frame callback");
- mLock.unlock();
- return;
- }
- mLock.unlock();
- client->dataCallback(msgType, frame, metadata);
- }
從這裡開始,回調函數進入到camera client的回調函數:frameworks/base/libs/camera/Camera.cpp
- // callback from camera service when frame or image is ready
- void Camera::dataCallback(int32_t msgType, const sp& dataPtr,
- camera_frame_metadata_t *metadata)
- {
- sp listener;
- {
- Mutex::Autolock _l(mLock);
- listener = mListener;
- }
- if (listener != NULL) {
- listener->postData(msgType, dataPtr, metadata);
- }
- }
這裡的listener到底是什麼,還記得初始化的時候,在jni裡面有設置listenerm嗎?我們還是從新再看一下吧:frameworks/base/core/jni/android_hardware_Camera.cpp
- // connect to camera
service
- static void android_hardware_Camera_native_setup(JNIEnv *env, jobject
thiz,
- jobject weak_this, jint cameraId)
- {
- sp camera = Camera::connect(cameraId);
- if (camera == NULL) {
- jniThrowRuntimeException(env, "Fail to
connect to camera service");
- return;
- }
- // make sure camera hardware is alive
- if (camera->getStatus() != NO_ERROR) {
- jniThrowRuntimeException(env, "Camera
initialization failed");
- return;
- }
- jclass clazz = env->GetObjectClass(thiz);
- if (clazz == NULL) {
- jniThrowRuntimeException(env, "Can't find
android/hardware/Camera");
- return;
- }
- // We use a weak reference so the Camera object can be garbage collected.
- // The reference is only used as a proxy for callbacks.
- sp context = new
JNICameraContext(env, weak_this, clazz, camera);
- context->incStrong(thiz);
- camera->setListener(context);
- // save context in opaque field
- env->SetIntField(thiz, fields.context, (int)context.get());
- }
由上面可以看出JNICameraContext是個監聽類,同時set這個監聽類,這個類的定義在:frameworks/base/core/jni/android_hardware_Camera.cpp
- // provides persistent context for calls
from native code to Java
- class JNICameraContext: public CameraListener
- {
- public:
- JNICameraContext(JNIEnv* env, jobject
weak_this, jclass clazz, const sp& camera);
- ~JNICameraContext() { release(); }
- virtual void notify(int32_t msgType, int32_t ext1, int32_t
ext2);
- virtual void postData(int32_t
msgType, const sp& dataPtr,
- camera_frame_metadata_t *metadata);
- virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp& dataPtr);
- void postMetadata(JNIEnv *env, int32_t
msgType, camera_frame_metadata_t *metadata);
- void addCallbackBuffer(JNIEnv *env, jbyteArray
cbb, int msgType);
- void setCallbackMode(JNIEnv *env, bool
installed, bool manualMode);
- sp getCamera() { Mutex::Autolock
_l(mLock); return mCamera; }
- bool isRawImageCallbackBufferAvailable() const;
- void release();
- private:
- void copyAndPost(JNIEnv* env, const sp& dataPtr, int msgType);
- void clearCallbackBuffers_l(JNIEnv *env, Vector *buffers);
- void clearCallbackBuffers_l(JNIEnv *env);
- jbyteArray getCallbackBuffer(JNIEnv *env, Vector *buffers, size_t
bufferSize);
- jobject mCameraJObjectWeak; // weak
reference to java object
- jclass mCameraJClass; // strong reference to java class
- sp mCamera; // strong
reference to native object
- jclass mFaceClass; // strong reference to Face class
- jclass mRectClass; // strong reference to Rect class
- Mutex mLock;
- /*
- * Global reference application-managed raw image buffer queue.
- *
- * Manual-only mode is supported for raw
image callbacks, which is
- * set whenever method addCallbackBuffer() with
msgType =
- * CAMERA_MSG_RAW_IMAGE is called; otherwise, null is returned
- * with raw image callbacks.
- */
- Vector mRawImageCallbackBuffers;
- /*
- * Application-managed preview buffer queue and the
flags
- * associated with the usage of the preview buffer callback.
- */
- Vector mCallbackBuffers; // Global
reference application managed byte[]
- bool mManualBufferMode; // Whether to use
application managed buffers.
- bool mManualCameraCallbackSet; // Whether
the callback has been set, used to
- // reduce unnecessary calls to set the
callback.
- };
標注部分是我們在上面用到的postData,我們看一看postData的實現過程:
- void JNICameraContext::postData(int32_t
msgType, const sp& dataPtr,
- camera_frame_metadata_t *metadata)
- {
- // VM pointer will be NULL if object is released
- Mutex::Autolock _l(mLock);
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- if (mCameraJObjectWeak == NULL) {
- LOGW("callback on dead camera object");
- return;
- }
- int32_t dataMsgType = msgType & ~CAMERA_MSG_PREVIEW_METADATA;
- // return data based on callback type
- switch (dataMsgType) {
- case CAMERA_MSG_VIDEO_FRAME:
- // should never happen
- break;
- // For backward-compatibility
purpose, if there is no callback
- // buffer for raw image, the
callback returns null.
- case CAMERA_MSG_RAW_IMAGE:
- LOGV("rawCallback");
- if (mRawImageCallbackBuffers.isEmpty()) {
- env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
- mCameraJObjectWeak, dataMsgType, 0, 0, NULL);
- } else {
- copyAndPost(env, dataPtr, dataMsgType);
- }
- break;
- // There is no data.
- case 0:
- break;
- default:
- LOGV("dataCallback(%d, %p)", dataMsgType, dataPtr.get());
- copyAndPost(env, dataPtr, dataMsgType);
- break;
- }
- // post frame metadata to Java
- if (metadata && (msgType & CAMERA_MSG_PREVIEW_METADATA)) {
- postMetadata(env, CAMERA_MSG_PREVIEW_METADATA, metadata);
- }
- }
我們接著看看這個copyAndPost方法:
- void JNICameraContext::copyAndPost(JNIEnv* env, const sp& dataPtr, int msgType)
- {
- jbyteArray obj = NULL;
- // allocate Java byte array and copy
data
- if (dataPtr != NULL) {
- ssize_t offset;
- size_t size;
- sp heap = dataPtr->getMemory(&offset, &size);
- LOGV("copyAndPost: off=%ld, size=%d", offset, size);
- uint8_t *heapBase = (uint8_t*)heap->base();
- if (heapBase != NULL) {
- const jbyte* data = reinterpret_cast(heapBase + offset);
- if (msgType == CAMERA_MSG_RAW_IMAGE) {
- obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size);
- } else if (msgType == CAMERA_MSG_PREVIEW_FRAME && mManualBufferMode) {
- obj = getCallbackBuffer(env, &mCallbackBuffers, size);
- if (mCallbackBuffers.isEmpty()) {
- LOGV("Out of buffers, clearing callback!");
- mCamera->setPreviewCallbackFlags(CAMERA_FRAME_CALLBACK_FLAG_NOOP);
- mManualCameraCallbackSet = false;
- if (obj == NULL) {
- return;
- }
- }
- } else {
- LOGV("Allocating callback buffer");
- obj = env->NewByteArray(size);
- }
- if (obj == NULL) {
- LOGE("Couldn't allocate byte array for JPEG data");
- env->ExceptionClear();
- } else {
- env->SetByteArrayRegion(obj, 0, size, data);
- }
- } else {
- LOGE("image heap is NULL");
- }
- }
- // post image data to Java
- env->CallStaticVoidMethod(mCameraJClass, fields.post_event,
- mCameraJObjectWeak, msgType, 0, 0, obj);
- if (obj) {
- env->DeleteLocalRef(obj);
- }
- }
以上先建立一個byte數組obj,將data緩存數據存儲進obj數組,CallStaticVoidMethod是C調用java函數,最後執行實在Camera.java(框架)的postEventFromNative()
從這裡開始,回調函數進入到camera framework層
frameworks/base/core/java/android/hardware/Camera.java
- private static void postEventFromNative(Object
camera_ref,
- int what, int arg1, int arg2, Object
obj)
- {
- Camera c = (Camera)((WeakReference)camera_ref).get();
- if (c == null)
- return;
- if (c.mEventHandler != null) {
- Message m = c.mEventHandler.obtainMessage(what, arg1, arg2, obj);
- c.mEventHandler.sendMessage(m);
- }
- }
sendMessage之後由handle進行處理,定義同樣在framework層
- private class EventHandler extends Handler
- {
- private Camera mCamera;
- public EventHandler(Camera c, Looper
looper) {
- super(looper);
- mCamera = c;
- }
- @Override
- public void handleMessage(Message msg) {
- switch(msg.what) {
- case CAMERA_MSG_SHUTTER:
- if (mShutterCallback != null) {
- mShutterCallback.onShutter();
- }
- return;
- case CAMERA_MSG_RAW_IMAGE:
- if (mRawImageCallback != null) {
- mRawImageCallback.onPictureTaken((byte[])msg.obj, mCamera);
- }
- return;
- case CAMERA_MSG_COMPRESSED_IMAGE:
- if (mJpegCallback != null) {
- mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
- }
- return;
- case CAMERA_MSG_PREVIEW_FRAME:
- if (mPreviewCallback != null) {
- PreviewCallback cb = mPreviewCallback;
- if (mOneShot) {
- // Clear
the callback variable before the callback
- // in case the
app calls setPreviewCallback from
- // the
callback function
- mPreviewCallback = null;
- } else if (!mWithBuffer) {
- // We're
faking the camera preview mode to prevent
- // the
app from being flooded with preview frames.
- // Set to oneshot
mode again.
- setHasPreviewCallback(true, false);
- }
- cb.onPreviewFrame((byte[])msg.obj, mCamera);
- }
- return;
- case CAMERA_MSG_POSTVIEW_FRAME:
- if (mPostviewCallback != null) {
- mPostviewCallback.onPictureTaken((byte[])msg.obj, mCamera);
- }
- return;
- case CAMERA_MSG_FOCUS:
- if (mAutoFocusCallback != null) {
- mAutoFocusCallback.onAutoFocus(msg.arg1 == 0 ? false : true, mCamera);
- }
- return;
- case CAMERA_MSG_ZOOM:
- if (mZoomListener != null) {
- mZoomListener.onZoomChange(msg.arg1, msg.arg2 != 0, mCamera);
- }
- return;
- case CAMERA_MSG_PREVIEW_METADATA:
- if (mFaceListener != null) {
- mFaceListener.onFaceDetection((Face[])msg.obj, mCamera);
- }
- return;
- case CAMERA_MSG_ERROR :
- Log.e(TAG, "Error
" + msg.arg1);
- if (mErrorCallback != null) {
- mErrorCallback.onError(msg.arg1, mCamera);
- }
- return;
- default:
- Log.e(TAG, "Unknown
message type " + msg.what);
- return;
- }
- }
- }
上面可以看出,這裡處理了所有的回調,快門回調mShutterCallback.onShutter(),RawImageCallback.onPictureTaken()拍照數據回調,自動對焦回調等。。
默認是沒有previewcallback這個回調的,除非你的app設置了setPreviewCallback,可以看出preview的數據還是可以向上層回調,只是系統默認不回調,這裡再說深一些:
由上面綠色標注的地方可以看出,我們需要做以下事情,檢查PreviewCallback 這個在framework中定義的接口有沒有設置了setPreviewCallback,設置則調用,這裡接口中
的onPreviewFrame方法需要開發者自己實現,這裡默認是沒有實現的,需要特殊使用的要自己添加,這裡是自己的理解,看一下PreviewCallback 接口的定義:frameworks/base/core/java/android/hardware/Camera.java
- /**
- * Callback interface used to deliver copies of preview frames as
- * they are displayed.
- *
- * @see #setPreviewCallback(Camera.PreviewCallback)
- * @see #setOneShotPreviewCallback(Camera.PreviewCallback)
- * @see #setPreviewCallbackWithBuffer(Camera.PreviewCallback)
- * @see #startPreview()
- */
- public interface PreviewCallback
- {
- /**
- * Called as preview frames are displayed. This callback is invoked
- * on the event thread {@link #open(int)} was
called from.
- *
- * @param data the contents of the preview frame in the format defined
- * by {@link android.graphics.ImageFormat}, which
can be queried
- * with {@link android.hardware.Camera.Parameters#getPreviewFormat()}.
- * If {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}
- * is never called, the default
will be the YCbCr_420_SP
- * (NV21) format.
- * @param camera the Camera service object.
- */
- void onPreviewFrame(byte[] data, Camera
camera);
- };
另數據采集區與顯示區兩個緩存區buffer preview數據的投遞,以完成preview實時顯示是在HAL層完成的。
takePicture()處理過程跟preview差不多,只是增加了回調函數返回時候存儲圖像的動作,這裡分析一下takepicture的處理過程:
- case CAMERA_MSG_COMPRESSED_IMAGE:
- if (mJpegCallback != null) {
- mJpegCallback.onPictureTaken((byte[])msg.obj, mCamera);
- }
- return;
mJpegCallback的定義
private PictureCallback mJpegCallback;
走到這裡我們又不得不回頭看看最起初在調用takepicture的時候是怎麼調用的
- try {
- mCameraDevice.takePicture(mShutterCallback, mRawPictureCallback,
- mPostViewPictureCallback, new JpegPictureCallback(loc));
- } catch (RuntimeException e ) {
- e.printStackTrace();
- return false;
- }
這裡大家看到了標准部分就是要使用的mJpegCallback,但是這個callback是JpegPictureCallback類,我們定義的mJpegCallback確是PictureCallback 類,不是同一個類
所以這個還是必須得說清楚一點,看看JpegPictureCallback類的定義吧
- private final class JpegPictureCallback
implements PictureCallback {
- Location mLocation;
- public JpegPictureCallback(Location loc) {
- mLocation = loc;
- }
- public void onPictureTaken(
- final byte [] jpegData, final
android.hardware.Camera camera) {
- if (mPausing) {
- if (mBurstImages > 0) {
- resetBurst();
- mBurstImages = 0;
- mHandler.sendEmptyMessageDelayed(RELEASE_CAMERA,
- CAMERA_RELEASE_DELAY);
- }
- return;
- }
- FocusManager.TempBracketingStates tempState = mFocusManager.getTempBracketingState();
- mJpegPictureCallbackTime = System.currentTimeMillis();
- // If postview callback has
arrived, the captured image is displayed
- // in postview callback. If not, the
captured image is displayed in
- // raw picture callback.
- if (mPostViewPictureCallbackTime != 0) {
- mShutterToPictureDisplayedTime =
- mPostViewPictureCallbackTime - mShutterCallbackTime;
- mPictureDisplayedToJpegCallbackTime =
- mJpegPictureCallbackTime - mPostViewPictureCallbackTime;
- } else {
- mShutterToPictureDisplayedTime =
- mRawPictureCallbackTime - mShutterCallbackTime;
- mPictureDisplayedToJpegCallbackTime =
- mJpegPictureCallbackTime - mRawPictureCallbackTime;
- }
- Log.v(TAG, "mPictureDisplayedToJpegCallbackTime
= "
- + mPictureDisplayedToJpegCallbackTime + "ms");
- if (!mIsImageCaptureIntent) {
- enableCameraControls(true);
- if (( tempState != FocusManager.TempBracketingStates.RUNNING ) &&
- !mCaptureMode.equals(mExposureBracketing) &&
- !mCaptureMode.equals(mZoomBracketing) &&
- !mBurstRunning == true) {
- // We want to show the taken
picture for a while, so we wait
- // for at least 0.5 second before
restarting the preview.
- long delay = 500 - mPictureDisplayedToJpegCallbackTime;
- if (delay < 0) {
- startPreview(true);
- startFaceDetection();
- } else {
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, delay);
- }
- }
- }
- if (!mIsImageCaptureIntent) {
- Size s = mParameters.getPictureSize();
- mImageSaver.addImage(jpegData, mLocation, s.width, s.height);
- } else {
- mJpegImageData = jpegData;
- if (!mQuickCapture) {
- showPostCaptureAlert();
- } else {
- doAttach();
- }
- }
- // Check this in advance of each shot
so we don't add to shutter
- // latency. It's true that
someone else could write to the SD card in
- // the mean time and fill
it, but that could have happened between the
- // shutter press and saving
the JPEG too.
- checkStorage();
- if (!mHandler.hasMessages(RESTART_PREVIEW)) {
- long now = System.currentTimeMillis();
- mJpegCallbackFinishTime = now - mJpegPictureCallbackTime;
- Log.v(TAG, "mJpegCallbackFinishTime
= "
- + mJpegCallbackFinishTime + "ms");
- mJpegPictureCallbackTime = 0;
- }
- if (mCaptureMode.equals(mExposureBracketing) ) {
- mBurstImages --;
- if (mBurstImages == 0 ) {
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, 0);
- }
- }
- //reset burst in case of
exposure bracketing
- if (mCaptureMode.equals(mExposureBracketing) && mBurstImages == 0) {
- mBurstImages = EXPOSURE_BRACKETING_COUNT;
- mParameters.set(PARM_BURST, mBurstImages);
- mCameraDevice.setParameters(mParameters);
- }
- if (mCaptureMode.equals(mZoomBracketing) ) {
- mBurstImages --;
- if (mBurstImages == 0 ) {
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, 0);
- }
- }
- //reset burst in case of
zoom bracketing
- if (mCaptureMode.equals(mZoomBracketing) && mBurstImages == 0) {
- mBurstImages = ZOOM_BRACKETING_COUNT;
- mParameters.set(PARM_BURST, mBurstImages);
- mCameraDevice.setParameters(mParameters);
- }
- if ( tempState == FocusManager.TempBracketingStates.RUNNING ) {
- mBurstImages --;
- if (mBurstImages == 0 ) {
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, 0);
- mTempBracketingEnabled = true;
- stopTemporalBracketing();
- }
- }
- if (mBurstRunning) {
- mBurstImages --;
- if (mBurstImages == 0) {
- resetBurst();
- mBurstRunning = false;
- mHandler.sendEmptyMessageDelayed(RESTART_PREVIEW, 0);
- }
- }
- }
- }
原來他們是父子類之間的關系,那麼自然父類可以可以轉換為子類的形式,但是子類就不能向父類轉換了,這個不懂就沒辦法了,面向對象的知識
而且這裡子類重新實現了父類的方法onPictureTaken
這裡這個函數不就是handle裡面調用的函數了嘛,可以看到上面onPictureTaken的實現過程,其實與preview最大的不同就是我上面標注的部分,
takepicture最終將圖片保存下來了
好了,takepicture的過程就說到這裡了,下一步要進底層了,HAL和driver之間的那些事,driver做的那些事