diff options
-rw-r--r-- | core/java/android/hardware/Camera.java | 98 | ||||
-rw-r--r-- | core/jni/android_hardware_Camera.cpp | 240 | ||||
-rw-r--r-- | include/camera/Camera.h | 23 | ||||
-rw-r--r-- | include/camera/ICamera.h | 12 | ||||
-rw-r--r-- | libs/camera/Camera.cpp | 6 | ||||
-rw-r--r-- | libs/camera/ICamera.cpp | 8 | ||||
-rw-r--r-- | media/libstagefright/CameraSourceTimeLapse.cpp | 2 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.cpp | 25 | ||||
-rw-r--r-- | services/camera/libcameraservice/CameraService.h | 2 |
9 files changed, 313 insertions, 103 deletions
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index c2f3ae7..d8a5b45 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -508,23 +508,86 @@ public class Camera { * finish processing the data in them. * * <p>The size of the buffer is determined by multiplying the preview - * image width, height, and bytes per pixel. The width and height can be - * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel + * image width, height, and bytes per pixel. The width and height can be + * read from {@link Camera.Parameters#getPreviewSize()}. Bytes per pixel * can be computed from * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8, * using the image format from {@link Camera.Parameters#getPreviewFormat()}. * * <p>This method is only necessary when - * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When + * {@link #setPreviewCallbackWithBuffer(PreviewCallback)} is used. When * {@link #setPreviewCallback(PreviewCallback)} or * {@link #setOneShotPreviewCallback(PreviewCallback)} are used, buffers - * are automatically allocated. + * are automatically allocated. When a supplied buffer is too small to + * hold the preview frame data, preview callback will return null and + * the buffer will be removed from the buffer queue. * * @param callbackBuffer the buffer to add to the queue. * The size should be width * height * bits_per_pixel / 8. * @see #setPreviewCallbackWithBuffer(PreviewCallback) */ - public native final void addCallbackBuffer(byte[] callbackBuffer); + public final void addCallbackBuffer(byte[] callbackBuffer) + { + _addCallbackBuffer(callbackBuffer, CAMERA_MSG_PREVIEW_FRAME); + } + + /** + * Adds a pre-allocated buffer to the raw image callback buffer queue. + * Applications can add one or more buffers to the queue. When a raw image + * frame arrives and there is still at least one available buffer, the + * buffer will be used to hold the raw image data and removed from the + * queue. Then raw image callback is invoked with the buffer. If a raw + * image frame arrives but there is no buffer left, the frame is + * discarded. Applications should add buffers back when they finish + * processing the data in them by calling this method again in order + * to avoid running out of raw image callback buffers. + * + * <p>The size of the buffer is determined by multiplying the raw image + * width, height, and bytes per pixel. The width and height can be + * read from {@link Camera.Parameters#getPictureSize()}. Bytes per pixel + * can be computed from + * {@link android.graphics.ImageFormat#getBitsPerPixel(int)} / 8, + * using the image format from {@link Camera.Parameters#getPreviewFormat()}. + * + * <p>This method is only necessary when the PictureCallbck for raw image + * is used while calling {@link #takePicture(Camera.ShutterCallback, + * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}. + * + * Please note that by calling this method, the mode for application-managed + * callback buffers is triggered. If this method has never been called, + * null will be returned by the raw image callback since there is + * no image callback buffer available. Furthermore, When a supplied buffer + * is too small to hold the raw image data, raw image callback will return + * null and the buffer will be removed from the buffer queue. + * + * @param callbackBuffer the buffer to add to the raw image callback buffer + * queue. The size should be width * height * (bits per pixel) / 8. An + * null callbackBuffer will be ignored and won't be added to the queue. + * + * @see #takePicture(Camera.ShutterCallback, + * Camera.PictureCallback, Camera.PictureCallback, Camera.PictureCallback)}. + * + * {@hide} + */ + public final void addRawImageCallbackBuffer(byte[] callbackBuffer) + { + addCallbackBuffer(callbackBuffer, CAMERA_MSG_RAW_IMAGE); + } + + private final void addCallbackBuffer(byte[] callbackBuffer, int msgType) + { + // CAMERA_MSG_VIDEO_FRAME may be allowed in the future. + if (msgType != CAMERA_MSG_PREVIEW_FRAME && + msgType != CAMERA_MSG_RAW_IMAGE) { + throw new IllegalArgumentException( + "Unsupported message type: " + msgType); + } + + _addCallbackBuffer(callbackBuffer, msgType); + } + + private native final void _addCallbackBuffer( + byte[] callbackBuffer, int msgType); private class EventHandler extends Handler { @@ -735,7 +798,7 @@ public class Camera { PictureCallback jpeg) { takePicture(shutter, raw, null, jpeg); } - private native final void native_takePicture(); + private native final void native_takePicture(int msgType); /** * Triggers an asynchronous image capture. The camera service will initiate @@ -743,7 +806,8 @@ public class Camera { * The shutter callback occurs after the image is captured. This can be used * to trigger a sound to let the user know that image has been captured. The * raw callback occurs when the raw image data is available (NOTE: the data - * may be null if the hardware does not have enough memory to make a copy). + * will be null if there is no raw image callback buffer available or the + * raw image callback buffer is not large enough to hold the raw image). * The postview callback occurs when a scaled, fully processed postview * image is available (NOTE: not all hardware supports this). The jpeg * callback occurs when the compressed image is available. If the @@ -762,6 +826,8 @@ public class Camera { * @param raw the callback for raw (uncompressed) image data, or null * @param postview callback with postview image data, may be null * @param jpeg the callback for JPEG image data, or null + * + * @see #addRawImageCallbackBuffer(byte[]) */ public final void takePicture(ShutterCallback shutter, PictureCallback raw, PictureCallback postview, PictureCallback jpeg) { @@ -769,7 +835,23 @@ public class Camera { mRawImageCallback = raw; mPostviewCallback = postview; mJpegCallback = jpeg; - native_takePicture(); + + // 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); } /** diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 9f70509..bfbfd37 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -53,25 +53,48 @@ public: virtual void notify(int32_t msgType, int32_t ext1, int32_t ext2); virtual void postData(int32_t msgType, const sp<IMemory>& dataPtr); virtual void postDataTimestamp(nsecs_t timestamp, int32_t msgType, const sp<IMemory>& dataPtr); - void addCallbackBuffer(JNIEnv *env, jbyteArray cbb); + void addCallbackBuffer(JNIEnv *env, jbyteArray cbb, int msgType); void setCallbackMode(JNIEnv *env, bool installed, bool manualMode); sp<Camera> getCamera() { Mutex::Autolock _l(mLock); return mCamera; } + bool isRawImageCallbackBufferAvailable() const; void release(); private: void copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType); + void clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers); void clearCallbackBuffers_l(JNIEnv *env); + jbyteArray getCallbackBuffer(JNIEnv *env, Vector<jbyteArray> *buffers, size_t bufferSize); jobject mCameraJObjectWeak; // weak reference to java object jclass mCameraJClass; // strong reference to java class sp<Camera> mCamera; // strong reference to native object 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<jbyteArray> mRawImageCallbackBuffers; + + /* + * Application-managed preview buffer queue and the flags + * associated with the usage of the preview buffer callback. + */ Vector<jbyteArray> 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. + bool mManualCameraCallbackSet; // Whether the callback has been set, used to + // reduce unnecessary calls to set the callback. }; +bool JNICameraContext::isRawImageCallbackBufferAvailable() const +{ + return !mRawImageCallbackBuffers.isEmpty(); +} + sp<Camera> get_native_camera(JNIEnv *env, jobject thiz, JNICameraContext** pContext) { sp<Camera> camera; @@ -128,10 +151,48 @@ void JNICameraContext::notify(int32_t msgType, int32_t ext1, int32_t ext2) return; } JNIEnv *env = AndroidRuntime::getJNIEnv(); + + /* + * If the notification or msgType is CAMERA_MSG_RAW_IMAGE_NOTIFY, change it + * to CAMERA_MSG_RAW_IMAGE since CAMERA_MSG_RAW_IMAGE_NOTIFY is not exposed + * to the Java app. + */ + if (msgType == CAMERA_MSG_RAW_IMAGE_NOTIFY) { + msgType = CAMERA_MSG_RAW_IMAGE; + } + env->CallStaticVoidMethod(mCameraJClass, fields.post_event, mCameraJObjectWeak, msgType, ext1, ext2, NULL); } +jbyteArray JNICameraContext::getCallbackBuffer( + JNIEnv* env, Vector<jbyteArray>* buffers, size_t bufferSize) +{ + jbyteArray obj = NULL; + + // Vector access should be protected by lock in postData() + if (!buffers->isEmpty()) { + LOGV("Using callback buffer from queue of length %d", buffers->size()); + jbyteArray globalBuffer = buffers->itemAt(0); + buffers->removeAt(0); + + obj = (jbyteArray)env->NewLocalRef(globalBuffer); + env->DeleteGlobalRef(globalBuffer); + + if (obj != NULL) { + jsize bufferLength = env->GetArrayLength(obj); + if ((int)bufferLength < (int)bufferSize) { + LOGE("Callback buffer was too small! Expected %d bytes, but got %d bytes!", + bufferSize, bufferLength); + env->DeleteLocalRef(obj); + return NULL; + } + } + } + + return obj; +} + void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int msgType) { jbyteArray obj = NULL; @@ -141,7 +202,7 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int ssize_t offset; size_t size; sp<IMemoryHeap> heap = dataPtr->getMemory(&offset, &size); - LOGV("postData: off=%d, size=%d", offset, size); + LOGV("copyAndPost: off=%ld, size=%d", offset, size); uint8_t *heapBase = (uint8_t*)heap->base(); if (heapBase != NULL) { @@ -151,32 +212,28 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int LOGV("Allocating callback buffer"); obj = env->NewByteArray(size); } else { - // Vector access should be protected by lock in postData() - if(!mCallbackBuffers.isEmpty()) { - LOGV("Using callback buffer from queue of length %d", mCallbackBuffers.size()); - jbyteArray globalBuffer = mCallbackBuffers.itemAt(0); - mCallbackBuffers.removeAt(0); - - obj = (jbyteArray)env->NewLocalRef(globalBuffer); - env->DeleteGlobalRef(globalBuffer); - - if (obj != NULL) { - jsize bufferLength = env->GetArrayLength(obj); - if ((int)bufferLength < (int)size) { - LOGE("Manually set buffer was too small! Expected %d bytes, but got %d!", - size, bufferLength); - env->DeleteLocalRef(obj); - return; + switch (msgType) { + case CAMERA_MSG_PREVIEW_FRAME: { + obj = getCallbackBuffer(env, &mCallbackBuffers, size); + + if (mCallbackBuffers.isEmpty()) { + LOGV("Out of buffers, clearing callback!"); + mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); + mManualCameraCallbackSet = false; + + if (obj == NULL) { + return; + } } + break; } - } - - if(mCallbackBuffers.isEmpty()) { - LOGV("Out of buffers, clearing callback!"); - mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); - mManualCameraCallbackSet = false; - - if (obj == NULL) { + case CAMERA_MSG_RAW_IMAGE: { + obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size); + break; + } + default: { + jniThrowException(env, + "java/lang/RuntimeException", "Unsupported message type"); return; } } @@ -212,21 +269,27 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) } // return data based on callback type - switch(msgType) { - case CAMERA_MSG_VIDEO_FRAME: - // should never happen - break; - // don't return raw data to Java - case CAMERA_MSG_RAW_IMAGE: - LOGV("rawCallback"); - env->CallStaticVoidMethod(mCameraJClass, fields.post_event, - mCameraJObjectWeak, msgType, 0, 0, NULL); - break; - default: - // TODO: Change to LOGV - LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); - copyAndPost(env, dataPtr, msgType); - break; + switch (msgType) { + 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, msgType, 0, 0, NULL); + } else { + copyAndPost(env, dataPtr, msgType); + } + break; + + default: + LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); + copyAndPost(env, dataPtr, msgType); + break; } } @@ -251,7 +314,7 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM if (!installed) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_NOOP); - clearCallbackBuffers_l(env); + clearCallbackBuffers_l(env, &mCallbackBuffers); } else if (mManualBufferMode) { if (!mCallbackBuffers.isEmpty()) { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); @@ -259,24 +322,44 @@ void JNICameraContext::setCallbackMode(JNIEnv *env, bool installed, bool manualM } } else { mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_BARCODE_SCANNER); - clearCallbackBuffers_l(env); + clearCallbackBuffers_l(env, &mCallbackBuffers); } } -void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) +void JNICameraContext::addCallbackBuffer( + JNIEnv *env, jbyteArray cbb, int msgType) { + LOGV("addCallbackBuffer: 0x%x", msgType); if (cbb != NULL) { Mutex::Autolock _l(mLock); - jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); - mCallbackBuffers.push(cbb); - - LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); - - // We want to make sure the camera knows we're ready for the next frame. - // This may have come unset had we not had a callbackbuffer ready for it last time. - if (mManualBufferMode && !mManualCameraCallbackSet) { - mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); - mManualCameraCallbackSet = true; + switch (msgType) { + case CAMERA_MSG_PREVIEW_FRAME: { + jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); + mCallbackBuffers.push(callbackBuffer); + + LOGV("Adding callback buffer to queue, %d total", + mCallbackBuffers.size()); + + // We want to make sure the camera knows we're ready for the + // next frame. This may have come unset had we not had a + // callbackbuffer ready for it last time. + if (mManualBufferMode && !mManualCameraCallbackSet) { + mCamera->setPreviewCallbackFlags(FRAME_CALLBACK_FLAG_CAMERA); + mManualCameraCallbackSet = true; + } + break; + } + case CAMERA_MSG_RAW_IMAGE: { + jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); + mRawImageCallbackBuffers.push(callbackBuffer); + break; + } + default: { + jniThrowException(env, + "java/lang/IllegalArgumentException", + "Unsupported message type"); + return; + } } } else { LOGE("Null byte array!"); @@ -285,10 +368,15 @@ void JNICameraContext::addCallbackBuffer(JNIEnv *env, jbyteArray cbb) void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env) { - LOGV("Clearing callback buffers, %d remained", mCallbackBuffers.size()); - while(!mCallbackBuffers.isEmpty()) { - env->DeleteGlobalRef(mCallbackBuffers.top()); - mCallbackBuffers.pop(); + clearCallbackBuffers_l(env, &mCallbackBuffers); + clearCallbackBuffers_l(env, &mRawImageCallbackBuffers); +} + +void JNICameraContext::clearCallbackBuffers_l(JNIEnv *env, Vector<jbyteArray> *buffers) { + LOGV("Clearing callback buffers, %d remained", buffers->size()); + while (!buffers->isEmpty()) { + env->DeleteGlobalRef(buffers->top()); + buffers->pop(); } } @@ -458,13 +546,13 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t context->setCallbackMode(env, installed, manualBuffer); } -static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes) { - LOGV("addCallbackBuffer"); +static void android_hardware_Camera_addCallbackBuffer(JNIEnv *env, jobject thiz, jbyteArray bytes, int msgType) { + LOGV("addCallbackBuffer: 0x%x", msgType); JNICameraContext* context = reinterpret_cast<JNICameraContext*>(env->GetIntField(thiz, fields.context)); if (context != NULL) { - context->addCallbackBuffer(env, bytes); + context->addCallbackBuffer(env, bytes, msgType); } } @@ -492,14 +580,32 @@ static void android_hardware_Camera_cancelAutoFocus(JNIEnv *env, jobject thiz) } } -static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) +static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz, int msgType) { LOGV("takePicture"); JNICameraContext* context; sp<Camera> camera = get_native_camera(env, thiz, &context); if (camera == 0) return; - if (camera->takePicture() != NO_ERROR) { + /* + * 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) { jniThrowException(env, "java/lang/RuntimeException", "takePicture failed"); return; } @@ -638,8 +744,8 @@ static JNINativeMethod camMethods[] = { { "setHasPreviewCallback", "(ZZ)V", (void *)android_hardware_Camera_setHasPreviewCallback }, - { "addCallbackBuffer", - "([B)V", + { "_addCallbackBuffer", + "([BI)V", (void *)android_hardware_Camera_addCallbackBuffer }, { "native_autoFocus", "()V", @@ -648,7 +754,7 @@ static JNINativeMethod camMethods[] = { "()V", (void *)android_hardware_Camera_cancelAutoFocus }, { "native_takePicture", - "()V", + "(I)V", (void *)android_hardware_Camera_takePicture }, { "native_setParameters", "(Ljava/lang/String;)V", diff --git a/include/camera/Camera.h b/include/camera/Camera.h index e5f7e62..f3c8f64 100644 --- a/include/camera/Camera.h +++ b/include/camera/Camera.h @@ -66,16 +66,17 @@ namespace android { // msgType in notifyCallback and dataCallback functions enum { - CAMERA_MSG_ERROR = 0x001, - CAMERA_MSG_SHUTTER = 0x002, - CAMERA_MSG_FOCUS = 0x004, - CAMERA_MSG_ZOOM = 0x008, - CAMERA_MSG_PREVIEW_FRAME = 0x010, - CAMERA_MSG_VIDEO_FRAME = 0x020, - CAMERA_MSG_POSTVIEW_FRAME = 0x040, - CAMERA_MSG_RAW_IMAGE = 0x080, - CAMERA_MSG_COMPRESSED_IMAGE = 0x100, - CAMERA_MSG_ALL_MSGS = 0x1FF + CAMERA_MSG_ERROR = 0x0001, + CAMERA_MSG_SHUTTER = 0x0002, + CAMERA_MSG_FOCUS = 0x0004, + CAMERA_MSG_ZOOM = 0x0008, + CAMERA_MSG_PREVIEW_FRAME = 0x0010, + CAMERA_MSG_VIDEO_FRAME = 0x0020, + CAMERA_MSG_POSTVIEW_FRAME = 0x0040, + CAMERA_MSG_RAW_IMAGE = 0x0080, + CAMERA_MSG_COMPRESSED_IMAGE = 0x0100, + CAMERA_MSG_RAW_IMAGE_NOTIFY = 0x0200, + CAMERA_MSG_ALL_MSGS = 0xFFFF }; // cmdType in sendCommand functions @@ -207,7 +208,7 @@ public: status_t cancelAutoFocus(); // take a picture - picture returned from callback - status_t takePicture(); + status_t takePicture(int msgType); // set preview/capture parameters - key/value pairs status_t setParameters(const String8& params); diff --git a/include/camera/ICamera.h b/include/camera/ICamera.h index b2310a6..2344b3f 100644 --- a/include/camera/ICamera.h +++ b/include/camera/ICamera.h @@ -70,7 +70,7 @@ public: virtual status_t startRecording() = 0; // stop recording mode - virtual void stopRecording() = 0; + virtual void stopRecording() = 0; // get recording state virtual bool recordingEnabled() = 0; @@ -84,8 +84,14 @@ public: // cancel auto focus virtual status_t cancelAutoFocus() = 0; - // take a picture - virtual status_t takePicture() = 0; + /* + * take a picture. + * @param msgType the message type an application selectively turn on/off + * on a photo-by-photo basis. The supported message types are: + * CAMERA_MSG_SHUTTER, CAMERA_MSG_RAW_IMAGE, CAMERA_MSG_COMPRESSED_IMAGE, + * and CAMERA_MSG_POSTVIEW_FRAME. Any other message types will be ignored. + */ + virtual status_t takePicture(int msgType) = 0; // set preview/capture parameters - key/value pairs virtual status_t setParameters(const String8& params) = 0; diff --git a/libs/camera/Camera.cpp b/libs/camera/Camera.cpp index 907f119..e288312 100644 --- a/libs/camera/Camera.cpp +++ b/libs/camera/Camera.cpp @@ -301,12 +301,12 @@ status_t Camera::cancelAutoFocus() } // take a picture -status_t Camera::takePicture() +status_t Camera::takePicture(int msgType) { - LOGV("takePicture"); + LOGV("takePicture: 0x%x", msgType); sp <ICamera> c = mCamera; if (c == 0) return NO_INIT; - return c->takePicture(); + return c->takePicture(msgType); } // set preview/capture parameters - key/value pairs diff --git a/libs/camera/ICamera.cpp b/libs/camera/ICamera.cpp index 0881d65..931b57d 100644 --- a/libs/camera/ICamera.cpp +++ b/libs/camera/ICamera.cpp @@ -223,11 +223,12 @@ public: } // take a picture - returns an IMemory (ref-counted mmap) - status_t takePicture() + status_t takePicture(int msgType) { - LOGV("takePicture"); + LOGV("takePicture: 0x%x", msgType); Parcel data, reply; data.writeInterfaceToken(ICamera::getInterfaceDescriptor()); + data.writeInt32(msgType); remote()->transact(TAKE_PICTURE, data, &reply); status_t ret = reply.readInt32(); return ret; @@ -401,7 +402,8 @@ status_t BnCamera::onTransact( case TAKE_PICTURE: { LOGV("TAKE_PICTURE"); CHECK_INTERFACE(ICamera, data, reply); - reply->writeInt32(takePicture()); + int msgType = data.readInt32(); + reply->writeInt32(takePicture(msgType)); return NO_ERROR; } break; case SET_PARAMETERS: { diff --git a/media/libstagefright/CameraSourceTimeLapse.cpp b/media/libstagefright/CameraSourceTimeLapse.cpp index e6fe618..3689557 100644 --- a/media/libstagefright/CameraSourceTimeLapse.cpp +++ b/media/libstagefright/CameraSourceTimeLapse.cpp @@ -277,7 +277,7 @@ void CameraSourceTimeLapse::threadTimeLapseEntry() { // this thread as read() will make a copy of this last frame and keep // returning it in the quick stop mode. Mutex::Autolock autoLock(mQuickStopLock); - CHECK_EQ(OK, mCamera->takePicture()); + CHECK_EQ(OK, mCamera->takePicture(CAMERA_MSG_RAW_IMAGE)); if (mQuickStop) { LOGV("threadTimeLapseEntry: Exiting due to mQuickStop = true"); return; diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp index 3d8ca7a..a09e16b 100644 --- a/services/camera/libcameraservice/CameraService.cpp +++ b/services/camera/libcameraservice/CameraService.cpp @@ -727,17 +727,30 @@ status_t CameraService::Client::cancelAutoFocus() { } // take a picture - image is returned in callback -status_t CameraService::Client::takePicture() { - LOG1("takePicture (pid %d)", getCallingPid()); +status_t CameraService::Client::takePicture(int msgType) { + LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType); Mutex::Autolock lock(mLock); status_t result = checkPidAndHardware(); if (result != NO_ERROR) return result; - enableMsgType(CAMERA_MSG_SHUTTER | - CAMERA_MSG_POSTVIEW_FRAME | - CAMERA_MSG_RAW_IMAGE | - CAMERA_MSG_COMPRESSED_IMAGE); + 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 | + CAMERA_MSG_RAW_IMAGE_NOTIFY | + CAMERA_MSG_COMPRESSED_IMAGE); + + enableMsgType(picMsgType); return mHardware->takePicture(); } diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h index ccb9cf7..1c43b00 100644 --- a/services/camera/libcameraservice/CameraService.h +++ b/services/camera/libcameraservice/CameraService.h @@ -108,7 +108,7 @@ private: virtual void releaseRecordingFrame(const sp<IMemory>& mem); virtual status_t autoFocus(); virtual status_t cancelAutoFocus(); - virtual status_t takePicture(); + virtual status_t takePicture(int msgType); virtual status_t setParameters(const String8& params); virtual String8 getParameters() const; virtual status_t sendCommand(int32_t cmd, int32_t arg1, int32_t arg2); |