OSDN Git Service

Application-managed callback buffer support for raw image
authorJames Dong <jdong@google.com>
Fri, 18 Feb 2011 00:38:06 +0000 (16:38 -0800)
committerJames Dong <jdong@google.com>
Wed, 23 Feb 2011 04:48:15 +0000 (20:48 -0800)
bug - 3292153

Change-Id: I9789f7c5cde3a3889d7375e881181e9152d95fc2

core/java/android/hardware/Camera.java
core/jni/android_hardware_Camera.cpp
include/camera/Camera.h
include/camera/ICamera.h
libs/camera/Camera.cpp
libs/camera/ICamera.cpp
media/libstagefright/CameraSourceTimeLapse.cpp
services/camera/libcameraservice/CameraService.cpp
services/camera/libcameraservice/CameraService.h

index c2f3ae7..d8a5b45 100644 (file)
@@ -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);
     }
 
     /**
index 9f70509..bfbfd37 100644 (file)
@@ -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",
index e5f7e62..f3c8f64 100644 (file)
@@ -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);
index b2310a6..2344b3f 100644 (file)
@@ -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;
index 907f119..e288312 100644 (file)
@@ -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
index 0881d65..931b57d 100644 (file)
@@ -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: {
index e6fe618..3689557 100644 (file)
@@ -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;
index 3d8ca7a..a09e16b 100644 (file)
@@ -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();
 }
index ccb9cf7..1c43b00 100644 (file)
@@ -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);