Loading core/java/android/hardware/Camera.java +90 −8 Original line number Diff line number Diff line Loading @@ -518,13 +518,76 @@ public class Camera { * {@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 { Loading Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading @@ -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); } /** Loading core/jni/android_hardware_Camera.cpp +173 −67 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) { Loading @@ -151,25 +212,9 @@ 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!"); Loading @@ -180,6 +225,18 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int return; } } break; } case CAMERA_MSG_RAW_IMAGE: { obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size); break; } default: { jniThrowException(env, "java/lang/RuntimeException", "Unsupported message type"); return; } } } if (obj == NULL) { Loading Loading @@ -216,14 +273,20 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) case CAMERA_MSG_VIDEO_FRAME: // should never happen break; // don't return raw data to Java // 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: // TODO: Change to LOGV LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); copyAndPost(env, dataPtr, msgType); break; Loading Loading @@ -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); Loading @@ -259,25 +322,45 @@ 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); switch (msgType) { case CAMERA_MSG_PREVIEW_FRAME: { jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); mCallbackBuffers.push(cbb); mCallbackBuffers.push(callbackBuffer); LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); 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. // 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!"); } Loading @@ -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(); } } Loading Loading @@ -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); } } Loading Loading @@ -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; } Loading Loading @@ -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", Loading @@ -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", Loading include/camera/Camera.h +12 −11 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading include/camera/ICamera.h +9 −3 Original line number Diff line number Diff line Loading @@ -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; Loading libs/camera/Camera.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading
core/java/android/hardware/Camera.java +90 −8 Original line number Diff line number Diff line Loading @@ -518,13 +518,76 @@ public class Camera { * {@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 { Loading Loading @@ -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 Loading @@ -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 Loading @@ -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) { Loading @@ -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); } /** Loading
core/jni/android_hardware_Camera.cpp +173 −67 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading @@ -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) { Loading @@ -151,25 +212,9 @@ 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!"); Loading @@ -180,6 +225,18 @@ void JNICameraContext::copyAndPost(JNIEnv* env, const sp<IMemory>& dataPtr, int return; } } break; } case CAMERA_MSG_RAW_IMAGE: { obj = getCallbackBuffer(env, &mRawImageCallbackBuffers, size); break; } default: { jniThrowException(env, "java/lang/RuntimeException", "Unsupported message type"); return; } } } if (obj == NULL) { Loading Loading @@ -216,14 +273,20 @@ void JNICameraContext::postData(int32_t msgType, const sp<IMemory>& dataPtr) case CAMERA_MSG_VIDEO_FRAME: // should never happen break; // don't return raw data to Java // 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: // TODO: Change to LOGV LOGV("dataCallback(%d, %p)", msgType, dataPtr.get()); copyAndPost(env, dataPtr, msgType); break; Loading Loading @@ -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); Loading @@ -259,25 +322,45 @@ 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); switch (msgType) { case CAMERA_MSG_PREVIEW_FRAME: { jbyteArray callbackBuffer = (jbyteArray)env->NewGlobalRef(cbb); mCallbackBuffers.push(cbb); mCallbackBuffers.push(callbackBuffer); LOGV("Adding callback buffer to queue, %d total", mCallbackBuffers.size()); 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. // 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!"); } Loading @@ -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(); } } Loading Loading @@ -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); } } Loading Loading @@ -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; } Loading Loading @@ -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", Loading @@ -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", Loading
include/camera/Camera.h +12 −11 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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); Loading
include/camera/ICamera.h +9 −3 Original line number Diff line number Diff line Loading @@ -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; Loading
libs/camera/Camera.cpp +3 −3 Original line number Diff line number Diff line Loading @@ -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 Loading