android_hardware_camera2_legacy_LegacyCameraDevice.cpp revision feb50af361e4305a25758966b6b5df2738c00259
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "Legacy-CameraDevice-JNI" 18#include <utils/Log.h> 19#include <utils/Errors.h> 20#include <utils/Trace.h> 21 22#include "jni.h" 23#include "JNIHelp.h" 24#include "android_runtime/AndroidRuntime.h" 25#include "android_runtime/android_view_Surface.h" 26 27#include <ui/GraphicBuffer.h> 28#include <system/window.h> 29 30using namespace android; 31 32// fully-qualified class name 33#define CAMERA_DEVICE_CLASS_NAME "android/hardware/camera2/legacy/LegacyCameraDevice" 34#define CAMERA_DEVICE_BUFFER_SLACK 3 35 36#define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) 37 38/** 39 * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for 40 * digital RGB with K_b = 0.114, and K_r = 0.299. 41 */ 42static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane, 43 uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) { 44 uint8_t R, G, B; 45 size_t index = 0; 46 47 int32_t cStrideDiff = chromaStride - width; 48 49 for (int32_t j = 0; j < height; j++) { 50 for (int32_t i = 0; i < width; i++) { 51 R = rgbBuf[index++]; 52 G = rgbBuf[index++]; 53 B = rgbBuf[index++]; 54 *(yPlane + i) = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; 55 56 if (j % 2 == 0 && i % 2 == 0){ 57 *uPlane = (( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128; 58 *vPlane = (( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128; 59 uPlane += chromaStep; 60 vPlane += chromaStep; 61 } 62 // Skip alpha 63 index++; 64 } 65 yPlane += yStride; 66 if (j % 2 == 0) { 67 uPlane += cStrideDiff; 68 vPlane += cStrideDiff; 69 } 70 } 71} 72 73static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) { 74 size_t cStep = ycbcr->chroma_step; 75 size_t cStride = ycbcr->cstride; 76 size_t yStride = ycbcr->ystride; 77 rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y), 78 reinterpret_cast<uint8_t*>(ycbcr->cb), reinterpret_cast<uint8_t*>(ycbcr->cr), 79 cStep, yStride, cStride); 80} 81 82static status_t configureSurface(const sp<ANativeWindow>& anw, 83 int32_t width, 84 int32_t height, 85 int32_t pixelFmt, 86 int32_t maxBufferSlack) { 87 status_t err = NO_ERROR; 88 err = native_window_set_buffers_dimensions(anw.get(), width, height); 89 if (err != NO_ERROR) { 90 ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__, 91 strerror(-err), err); 92 return err; 93 } 94 95 err = native_window_set_buffers_format(anw.get(), pixelFmt); 96 if (err != NO_ERROR) { 97 ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__, 98 strerror(-err), err); 99 return err; 100 } 101 102 err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); 103 if (err != NO_ERROR) { 104 ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__, 105 strerror(-err), err); 106 return err; 107 } 108 109 int minUndequeuedBuffers; 110 err = anw.get()->query(anw.get(), 111 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 112 &minUndequeuedBuffers); 113 if (err != NO_ERROR) { 114 ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).", 115 __FUNCTION__, strerror(-err), err); 116 return err; 117 } 118 119 ALOGV("%s: Setting buffer count to %d", __FUNCTION__, 120 maxBufferSlack + 1 + minUndequeuedBuffers); 121 err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers); 122 if (err != NO_ERROR) { 123 ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__, 124 strerror(-err), err); 125 return err; 126 } 127 return NO_ERROR; 128} 129 130/** 131 * Produce a frame in the given surface. 132 * 133 * Args: 134 * anw - a surface to produce a frame in. 135 * pixelBuffer - image buffer to generate a frame from. 136 * width - width of the pixelBuffer in pixels. 137 * height - height of the pixelBuffer in pixels. 138 * pixelFmt - format of the pixelBuffer, one of: 139 * HAL_PIXEL_FORMAT_YCrCb_420_SP, 140 * HAL_PIXEL_FORMAT_YCbCr_420_888, 141 * HAL_PIXEL_FORMAT_BLOB 142 * bufSize - the size of the pixelBuffer in bytes. 143 */ 144static status_t produceFrame(const sp<ANativeWindow>& anw, 145 uint8_t* pixelBuffer, 146 int32_t width, // Width of the pixelBuffer 147 int32_t height, // Height of the pixelBuffer 148 int32_t pixelFmt, // Format of the pixelBuffer 149 int64_t bufSize) { 150 ATRACE_CALL(); 151 status_t err = NO_ERROR; 152 ANativeWindowBuffer* anb; 153 ALOGV("%s: Dequeue buffer from %p",__FUNCTION__, anw.get()); 154 155 // TODO: Switch to using Surface::lock and Surface::unlockAndPost 156 err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); 157 if (err != NO_ERROR) return err; 158 159 sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false)); 160 161 switch(pixelFmt) { 162 case HAL_PIXEL_FORMAT_YCrCb_420_SP: { 163 if (bufSize < width * height * 4) { 164 ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, 165 bufSize); 166 return BAD_VALUE; 167 } 168 uint8_t* img = NULL; 169 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 170 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 171 if (err != NO_ERROR) return err; 172 173 uint8_t* yPlane = img; 174 uint8_t* uPlane = img + height * width; 175 uint8_t* vPlane = uPlane + 1; 176 size_t chromaStep = 2; 177 size_t yStride = width; 178 size_t chromaStride = width; 179 180 rgbToYuv420(pixelBuffer, width, height, yPlane, 181 uPlane, vPlane, chromaStep, yStride, chromaStride); 182 break; 183 } 184 case HAL_PIXEL_FORMAT_YCbCr_420_888: { 185 // Software writes with YCbCr_420_888 format are unsupported 186 // by the gralloc module for now 187 if (bufSize < width * height * 4) { 188 ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, 189 bufSize); 190 return BAD_VALUE; 191 } 192 android_ycbcr ycbcr = android_ycbcr(); 193 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 194 195 err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr); 196 if (err != NO_ERROR) { 197 ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__, 198 strerror(-err), err); 199 return err; 200 } 201 rgbToYuv420(pixelBuffer, width, height, &ycbcr); 202 break; 203 } 204 case HAL_PIXEL_FORMAT_BLOB: { 205 if (bufSize != width || height != 1) { 206 ALOGE("%s: Incorrect pixelBuffer size: %lld", __FUNCTION__, bufSize); 207 return BAD_VALUE; 208 } 209 int8_t* img = NULL; 210 211 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 212 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 213 if (err != NO_ERROR) { 214 ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err), 215 err); 216 return err; 217 } 218 memcpy(img, pixelBuffer, width); 219 break; 220 } 221 default: { 222 ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt); 223 return BAD_VALUE; 224 } 225 } 226 227 ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get()); 228 err = buf->unlock(); 229 if (err != NO_ERROR) { 230 ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); 231 return err; 232 } 233 234 ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get()); 235 err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1); 236 if (err != NO_ERROR) { 237 ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); 238 return err; 239 } 240 return NO_ERROR; 241} 242 243static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) { 244 sp<ANativeWindow> anw; 245 if (surface) { 246 anw = android_view_Surface_getNativeWindow(env, surface); 247 if (env->ExceptionCheck()) { 248 return anw; 249 } 250 } else { 251 jniThrowNullPointerException(env, "surface"); 252 return anw; 253 } 254 if (anw == NULL) { 255 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 256 "Surface had no valid native window."); 257 return anw; 258 } 259 return anw; 260} 261 262extern "C" { 263 264static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) { 265 ALOGV("nativeDetectSurfaceType"); 266 sp<ANativeWindow> anw; 267 if ((anw = getNativeWindow(env, surface)) == NULL) { 268 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 269 return 0; 270 } 271 int32_t fmt = 0; 272 status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt); 273 if(err != NO_ERROR) { 274 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 275 "Error while querying surface pixel format (error code %d)", err); 276 return 0; 277 } 278 return fmt; 279} 280 281static void LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, 282 jobject surface, jintArray dimens) { 283 ALOGV("nativeGetSurfaceDimens"); 284 sp<ANativeWindow> anw; 285 if ((anw = getNativeWindow(env, surface)) == NULL) { 286 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 287 return; 288 } 289 int32_t dimenBuf[2]; 290 status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf); 291 if(err != NO_ERROR) { 292 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 293 "Error while querying surface width (error code %d)", err); 294 return; 295 } 296 err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1); 297 if(err != NO_ERROR) { 298 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 299 "Error while querying surface height (error code %d)", err); 300 return; 301 } 302 env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf); 303} 304 305static void LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface, 306 jint width, jint height, jint pixelFormat) { 307 ALOGV("nativeConfigureSurface"); 308 sp<ANativeWindow> anw; 309 if ((anw = getNativeWindow(env, surface)) == NULL) { 310 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 311 return; 312 } 313 status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK); 314 if (err != NO_ERROR) { 315 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 316 "Error while producing frame (error code %d)", err); 317 return; 318 } 319} 320 321static void LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface, 322 jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) { 323 ALOGV("nativeProduceFrame"); 324 sp<ANativeWindow> anw; 325 326 if ((anw = getNativeWindow(env, surface)) == NULL) { 327 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 328 return; 329 } 330 331 if (pixelBuffer == NULL) { 332 jniThrowNullPointerException(env, "pixelBuffer"); 333 return; 334 } 335 336 int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer)); 337 jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL); 338 339 if (pixels == NULL) { 340 jniThrowNullPointerException(env, "pixels"); 341 return; 342 } 343 344 status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height, 345 pixelFormat, bufSize); 346 env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT); 347 348 if (err != NO_ERROR) { 349 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 350 "Error while producing frame (error code %d)", err); 351 return; 352 } 353} 354 355static void LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface, 356 jint pixelFormat) { 357 ALOGV("nativeSetSurfaceType"); 358 sp<ANativeWindow> anw; 359 if ((anw = getNativeWindow(env, surface)) == NULL) { 360 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 361 return; 362 } 363 status_t err = native_window_set_buffers_format(anw.get(), pixelFormat); 364 if (err != NO_ERROR) { 365 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 366 "Error while setting surface format (error code %d)", err); 367 return; 368 } 369} 370 371static void LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface, 372 jint width, jint height) { 373 ALOGV("nativeSetSurfaceDimens"); 374 sp<ANativeWindow> anw; 375 if ((anw = getNativeWindow(env, surface)) == NULL) { 376 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 377 return; 378 } 379 status_t err = native_window_set_buffers_dimensions(anw.get(), width, height); 380 if (err != NO_ERROR) { 381 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 382 "Error while setting surface format (error code %d)", err); 383 return; 384 } 385} 386 387} // extern "C" 388 389static JNINativeMethod gCameraDeviceMethods[] = { 390 { "nativeDetectSurfaceType", 391 "(Landroid/view/Surface;)I", 392 (void *)LegacyCameraDevice_nativeDetectSurfaceType }, 393 { "nativeDetectSurfaceDimens", 394 "(Landroid/view/Surface;[I)V", 395 (void *)LegacyCameraDevice_nativeDetectSurfaceDimens }, 396 { "nativeConfigureSurface", 397 "(Landroid/view/Surface;III)V", 398 (void *)LegacyCameraDevice_nativeConfigureSurface }, 399 { "nativeProduceFrame", 400 "(Landroid/view/Surface;[BIII)V", 401 (void *)LegacyCameraDevice_nativeProduceFrame }, 402 { "nativeSetSurfaceFormat", 403 "(Landroid/view/Surface;I)V", 404 (void *)LegacyCameraDevice_nativeSetSurfaceFormat }, 405 { "nativeSetSurfaceDimens", 406 "(Landroid/view/Surface;II)V", 407 (void *)LegacyCameraDevice_nativeSetSurfaceDimens }, 408}; 409 410// Get all the required offsets in java class and register native functions 411int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env) 412{ 413 // Register native functions 414 return AndroidRuntime::registerNativeMethods(env, 415 CAMERA_DEVICE_CLASS_NAME, 416 gCameraDeviceMethods, 417 NELEM(gCameraDeviceMethods)); 418} 419 420