diff options
author | Ruben Brunk <rubenbrunk@google.com> | 2014-05-22 06:08:55 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-05-22 06:08:56 +0000 |
commit | 94520c74608bfcd61ff987410a8018d87b75d734 (patch) | |
tree | 57cbe1577329df9ccb0a20f26deada5f70952c8b /core/jni | |
parent | 521d8cdae0be5c7d33715e0fa7b5b85367c5de09 (diff) | |
parent | feb50af361e4305a25758966b6b5df2738c00259 (diff) | |
download | frameworks_base-94520c74608bfcd61ff987410a8018d87b75d734.zip frameworks_base-94520c74608bfcd61ff987410a8018d87b75d734.tar.gz frameworks_base-94520c74608bfcd61ff987410a8018d87b75d734.tar.bz2 |
Merge "camera2: Add HAL1 compatibility shim skeleton."
Diffstat (limited to 'core/jni')
-rw-r--r-- | core/jni/Android.mk | 1 | ||||
-rw-r--r-- | core/jni/AndroidRuntime.cpp | 2 | ||||
-rw-r--r-- | core/jni/android_hardware_Camera.cpp | 23 | ||||
-rw-r--r-- | core/jni/android_hardware_camera2_CameraMetadata.cpp | 4 | ||||
-rw-r--r-- | core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp | 419 |
5 files changed, 436 insertions, 13 deletions
diff --git a/core/jni/Android.mk b/core/jni/Android.mk index 83c26f6..835a648 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -137,6 +137,7 @@ LOCAL_SRC_FILES:= \ android_media_ToneGenerator.cpp \ android_hardware_Camera.cpp \ android_hardware_camera2_CameraMetadata.cpp \ + android_hardware_camera2_legacy_LegacyCameraDevice.cpp \ android_hardware_SensorManager.cpp \ android_hardware_SerialPort.cpp \ android_hardware_UsbDevice.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 948b51e..2d350e0 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -79,6 +79,7 @@ extern int register_android_opengl_jni_GLES31Ext(JNIEnv* env); extern int register_android_hardware_Camera(JNIEnv *env); extern int register_android_hardware_camera2_CameraMetadata(JNIEnv *env); +extern int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv *env); extern int register_android_hardware_SensorManager(JNIEnv *env); extern int register_android_hardware_SerialPort(JNIEnv *env); extern int register_android_hardware_UsbDevice(JNIEnv *env); @@ -1284,6 +1285,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_com_android_internal_util_VirtualRefBasePtr), REG_JNI(register_android_hardware_Camera), REG_JNI(register_android_hardware_camera2_CameraMetadata), + REG_JNI(register_android_hardware_camera2_legacy_LegacyCameraDevice), REG_JNI(register_android_hardware_SensorManager), REG_JNI(register_android_hardware_SerialPort), REG_JNI(register_android_hardware_UsbDevice), diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index 307293f..3a53331 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -27,6 +27,7 @@ #include <cutils/properties.h> #include <utils/Vector.h> +#include <utils/Errors.h> #include <gui/GLConsumer.h> #include <gui/Surface.h> @@ -464,7 +465,7 @@ static void android_hardware_Camera_getCameraInfo(JNIEnv *env, jobject thiz, } // connect to camera service -static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, +static jint android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this, jint cameraId, jstring clientPackageName) { // Convert jstring to String16 @@ -477,20 +478,19 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, Camera::USE_CALLING_UID); if (camera == NULL) { - jniThrowRuntimeException(env, "Fail to connect to camera service"); - return; + return -EACCES; } // make sure camera hardware is alive if (camera->getStatus() != NO_ERROR) { - jniThrowRuntimeException(env, "Camera initialization failed"); - return; + return NO_INIT; } jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { + // This should never happen jniThrowRuntimeException(env, "Can't find android/hardware/Camera"); - return; + return INVALID_OPERATION; } // We use a weak reference so the Camera object can be garbage collected. @@ -501,6 +501,7 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, // save context in opaque field env->SetLongField(thiz, fields.context, (jlong)context.get()); + return NO_ERROR; } // disconnect from camera service @@ -538,9 +539,9 @@ static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) } } -static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) +static void android_hardware_Camera_setPreviewSurface(JNIEnv *env, jobject thiz, jobject jSurface) { - ALOGV("setPreviewDisplay"); + ALOGV("setPreviewSurface"); sp<Camera> camera = get_native_camera(env, thiz, NULL); if (camera == 0) return; @@ -890,14 +891,14 @@ static JNINativeMethod camMethods[] = { "(ILandroid/hardware/Camera$CameraInfo;)V", (void*)android_hardware_Camera_getCameraInfo }, { "native_setup", - "(Ljava/lang/Object;ILjava/lang/String;)V", + "(Ljava/lang/Object;ILjava/lang/String;)I", (void*)android_hardware_Camera_native_setup }, { "native_release", "()V", (void*)android_hardware_Camera_release }, - { "setPreviewDisplay", + { "setPreviewSurface", "(Landroid/view/Surface;)V", - (void *)android_hardware_Camera_setPreviewDisplay }, + (void *)android_hardware_Camera_setPreviewSurface }, { "setPreviewTexture", "(Landroid/graphics/SurfaceTexture;)V", (void *)android_hardware_Camera_setPreviewTexture }, diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp index 3312109..0d2df80 100644 --- a/core/jni/android_hardware_camera2_CameraMetadata.cpp +++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp @@ -518,7 +518,7 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN SortedVector<String8> vendorSections; size_t vendorSectionCount = 0; - if (vTags != 0) { + if (vTags != NULL) { vendorSections = vTags->getAllSectionNames(); vendorSectionCount = vendorSections.size(); } @@ -592,7 +592,7 @@ static jint CameraMetadata_getTagFromKey(JNIEnv *env, jobject thiz, jstring keyN "Could not find tag name for key '%s')", key); return 0; } - } else if (vTags != 0) { + } else if (vTags != NULL) { // Match vendor tags (typically com.*) const String8 sectionName(section); const String8 tagName(keyTagName); diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp new file mode 100644 index 0000000..40e9544 --- /dev/null +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -0,0 +1,419 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "Legacy-CameraDevice-JNI" +#include <utils/Log.h> +#include <utils/Errors.h> +#include <utils/Trace.h> + +#include "jni.h" +#include "JNIHelp.h" +#include "android_runtime/AndroidRuntime.h" +#include "android_runtime/android_view_Surface.h" + +#include <ui/GraphicBuffer.h> +#include <system/window.h> + +using namespace android; + +// fully-qualified class name +#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice" +#define CAMERA_DEVICE_BUFFER_SLACK 3 + +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) + +/** + * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for + * digital RGB with K_b = 0.114, and K_r = 0.299. + */ +static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane, + uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) { + uint8_t R, G, B; + size_t index = 0; + + int32_t cStrideDiff = chromaStride - width; + + for (int32_t j = 0; j < height; j++) { + for (int32_t i = 0; i < width; i++) { + R = rgbBuf[index++]; + G = rgbBuf[index++]; + B = rgbBuf[index++]; + *(yPlane + i) = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; + + if (j % 2 == 0 && i % 2 == 0){ + *uPlane = (( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128; + *vPlane = (( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128; + uPlane += chromaStep; + vPlane += chromaStep; + } + // Skip alpha + index++; + } + yPlane += yStride; + if (j % 2 == 0) { + uPlane += cStrideDiff; + vPlane += cStrideDiff; + } + } +} + +static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) { + size_t cStep = ycbcr->chroma_step; + size_t cStride = ycbcr->cstride; + size_t yStride = ycbcr->ystride; + rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y), + reinterpret_cast<uint8_t*>(ycbcr->cb), reinterpret_cast<uint8_t*>(ycbcr->cr), + cStep, yStride, cStride); +} + +static status_t configureSurface(const sp<ANativeWindow>& anw, + int32_t width, + int32_t height, + int32_t pixelFmt, + int32_t maxBufferSlack) { + status_t err = NO_ERROR; + err = native_window_set_buffers_dimensions(anw.get(), width, height); + if (err != NO_ERROR) { + ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__, + strerror(-err), err); + return err; + } + + err = native_window_set_buffers_format(anw.get(), pixelFmt); + if (err != NO_ERROR) { + ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__, + strerror(-err), err); + return err; + } + + err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); + if (err != NO_ERROR) { + ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__, + strerror(-err), err); + return err; + } + + int minUndequeuedBuffers; + err = anw.get()->query(anw.get(), + NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, + &minUndequeuedBuffers); + if (err != NO_ERROR) { + ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).", + __FUNCTION__, strerror(-err), err); + return err; + } + + ALOGV("%s: Setting buffer count to %d", __FUNCTION__, + maxBufferSlack + 1 + minUndequeuedBuffers); + err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers); + if (err != NO_ERROR) { + ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__, + strerror(-err), err); + return err; + } + return NO_ERROR; +} + +/** + * Produce a frame in the given surface. + * + * Args: + * anw - a surface to produce a frame in. + * pixelBuffer - image buffer to generate a frame from. + * width - width of the pixelBuffer in pixels. + * height - height of the pixelBuffer in pixels. + * pixelFmt - format of the pixelBuffer, one of: + * HAL_PIXEL_FORMAT_YCrCb_420_SP, + * HAL_PIXEL_FORMAT_YCbCr_420_888, + * HAL_PIXEL_FORMAT_BLOB + * bufSize - the size of the pixelBuffer in bytes. + */ +static status_t produceFrame(const sp<ANativeWindow>& anw, + uint8_t* pixelBuffer, + int32_t width, // Width of the pixelBuffer + int32_t height, // Height of the pixelBuffer + int32_t pixelFmt, // Format of the pixelBuffer + int64_t bufSize) { + ATRACE_CALL(); + status_t err = NO_ERROR; + ANativeWindowBuffer* anb; + ALOGV("%s: Dequeue buffer from %p",__FUNCTION__, anw.get()); + + // TODO: Switch to using Surface::lock and Surface::unlockAndPost + err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); + if (err != NO_ERROR) return err; + + sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false)); + + switch(pixelFmt) { + case HAL_PIXEL_FORMAT_YCrCb_420_SP: { + if (bufSize < width * height * 4) { + ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, + bufSize); + return BAD_VALUE; + } + uint8_t* img = NULL; + ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); + err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + if (err != NO_ERROR) return err; + + uint8_t* yPlane = img; + uint8_t* uPlane = img + height * width; + uint8_t* vPlane = uPlane + 1; + size_t chromaStep = 2; + size_t yStride = width; + size_t chromaStride = width; + + rgbToYuv420(pixelBuffer, width, height, yPlane, + uPlane, vPlane, chromaStep, yStride, chromaStride); + break; + } + case HAL_PIXEL_FORMAT_YCbCr_420_888: { + // Software writes with YCbCr_420_888 format are unsupported + // by the gralloc module for now + if (bufSize < width * height * 4) { + ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, + bufSize); + return BAD_VALUE; + } + android_ycbcr ycbcr = android_ycbcr(); + ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); + + err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr); + if (err != NO_ERROR) { + ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__, + strerror(-err), err); + return err; + } + rgbToYuv420(pixelBuffer, width, height, &ycbcr); + break; + } + case HAL_PIXEL_FORMAT_BLOB: { + if (bufSize != width || height != 1) { + ALOGE("%s: Incorrect pixelBuffer size: %lld", __FUNCTION__, bufSize); + return BAD_VALUE; + } + int8_t* img = NULL; + + ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); + err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); + if (err != NO_ERROR) { + ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err), + err); + return err; + } + memcpy(img, pixelBuffer, width); + break; + } + default: { + ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt); + return BAD_VALUE; + } + } + + ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get()); + err = buf->unlock(); + if (err != NO_ERROR) { + ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); + return err; + } + + ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get()); + err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1); + if (err != NO_ERROR) { + ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); + return err; + } + return NO_ERROR; +} + +static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) { + sp<ANativeWindow> anw; + if (surface) { + anw = android_view_Surface_getNativeWindow(env, surface); + if (env->ExceptionCheck()) { + return anw; + } + } else { + jniThrowNullPointerException(env, "surface"); + return anw; + } + if (anw == NULL) { + jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", + "Surface had no valid native window."); + return anw; + } + return anw; +} + +extern "C" { + +static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) { + ALOGV("nativeDetectSurfaceType"); + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return 0; + } + int32_t fmt = 0; + status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt); + if(err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while querying surface pixel format (error code %d)", err); + return 0; + } + return fmt; +} + +static void LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, + jobject surface, jintArray dimens) { + ALOGV("nativeGetSurfaceDimens"); + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return; + } + int32_t dimenBuf[2]; + status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf); + if(err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while querying surface width (error code %d)", err); + return; + } + err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1); + if(err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while querying surface height (error code %d)", err); + return; + } + env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf); +} + +static void LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface, + jint width, jint height, jint pixelFormat) { + ALOGV("nativeConfigureSurface"); + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return; + } + status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK); + if (err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while producing frame (error code %d)", err); + return; + } +} + +static void LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface, + jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) { + ALOGV("nativeProduceFrame"); + sp<ANativeWindow> anw; + + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return; + } + + if (pixelBuffer == NULL) { + jniThrowNullPointerException(env, "pixelBuffer"); + return; + } + + int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer)); + jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL); + + if (pixels == NULL) { + jniThrowNullPointerException(env, "pixels"); + return; + } + + status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height, + pixelFormat, bufSize); + env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT); + + if (err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while producing frame (error code %d)", err); + return; + } +} + +static void LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface, + jint pixelFormat) { + ALOGV("nativeSetSurfaceType"); + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return; + } + status_t err = native_window_set_buffers_format(anw.get(), pixelFormat); + if (err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while setting surface format (error code %d)", err); + return; + } +} + +static void LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface, + jint width, jint height) { + ALOGV("nativeSetSurfaceDimens"); + sp<ANativeWindow> anw; + if ((anw = getNativeWindow(env, surface)) == NULL) { + ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); + return; + } + status_t err = native_window_set_buffers_dimensions(anw.get(), width, height); + if (err != NO_ERROR) { + jniThrowExceptionFmt(env, "java/lang/IllegalStateException", + "Error while setting surface format (error code %d)", err); + return; + } +} + +} // extern "C" + +static JNINativeMethod gCameraDeviceMethods[] = { + { "nativeDetectSurfaceType", + "(Landroid/view/Surface;)I", + (void *)LegacyCameraDevice_nativeDetectSurfaceType }, + { "nativeDetectSurfaceDimens", + "(Landroid/view/Surface;[I)V", + (void *)LegacyCameraDevice_nativeDetectSurfaceDimens }, + { "nativeConfigureSurface", + "(Landroid/view/Surface;III)V", + (void *)LegacyCameraDevice_nativeConfigureSurface }, + { "nativeProduceFrame", + "(Landroid/view/Surface;[BIII)V", + (void *)LegacyCameraDevice_nativeProduceFrame }, + { "nativeSetSurfaceFormat", + "(Landroid/view/Surface;I)V", + (void *)LegacyCameraDevice_nativeSetSurfaceFormat }, + { "nativeSetSurfaceDimens", + "(Landroid/view/Surface;II)V", + (void *)LegacyCameraDevice_nativeSetSurfaceDimens }, +}; + +// Get all the required offsets in java class and register native functions +int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env) +{ + // Register native functions + return AndroidRuntime::registerNativeMethods(env, + CAMERA_DEVICE_CLASS_NAME, + gCameraDeviceMethods, + NELEM(gCameraDeviceMethods)); +} + |