android_hardware_camera2_legacy_LegacyCameraDevice.cpp revision 91b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0
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#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) 39 40/** 41 * Convert from RGB 888 to Y'CbCr using the conversion specified in ITU-R BT.601 for 42 * digital RGB with K_b = 0.114, and K_r = 0.299. 43 */ 44static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, uint8_t* yPlane, 45 uint8_t* uPlane, uint8_t* vPlane, size_t chromaStep, size_t yStride, size_t chromaStride) { 46 uint8_t R, G, B; 47 size_t index = 0; 48 49 int32_t cStrideDiff = chromaStride - width; 50 51 for (int32_t j = 0; j < height; j++) { 52 for (int32_t i = 0; i < width; i++) { 53 R = rgbBuf[index++]; 54 G = rgbBuf[index++]; 55 B = rgbBuf[index++]; 56 *(yPlane + i) = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16; 57 58 if (j % 2 == 0 && i % 2 == 0){ 59 *uPlane = (( -38 * R - 74 * G + 112 * B + 128) >> 8) + 128; 60 *vPlane = (( 112 * R - 94 * G - 18 * B + 128) >> 8) + 128; 61 uPlane += chromaStep; 62 vPlane += chromaStep; 63 } 64 // Skip alpha 65 index++; 66 } 67 yPlane += yStride; 68 if (j % 2 == 0) { 69 uPlane += cStrideDiff; 70 vPlane += cStrideDiff; 71 } 72 } 73} 74 75static void rgbToYuv420(uint8_t* rgbBuf, int32_t width, int32_t height, android_ycbcr* ycbcr) { 76 size_t cStep = ycbcr->chroma_step; 77 size_t cStride = ycbcr->cstride; 78 size_t yStride = ycbcr->ystride; 79 rgbToYuv420(rgbBuf, width, height, reinterpret_cast<uint8_t*>(ycbcr->y), 80 reinterpret_cast<uint8_t*>(ycbcr->cb), reinterpret_cast<uint8_t*>(ycbcr->cr), 81 cStep, yStride, cStride); 82} 83 84static status_t configureSurface(const sp<ANativeWindow>& anw, 85 int32_t width, 86 int32_t height, 87 int32_t pixelFmt, 88 int32_t maxBufferSlack) { 89 status_t err = NO_ERROR; 90 err = native_window_set_buffers_dimensions(anw.get(), width, height); 91 if (err != NO_ERROR) { 92 ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__, 93 strerror(-err), err); 94 return err; 95 } 96 97 err = native_window_set_buffers_format(anw.get(), pixelFmt); 98 if (err != NO_ERROR) { 99 ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__, 100 strerror(-err), err); 101 return err; 102 } 103 104 err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN); 105 if (err != NO_ERROR) { 106 ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__, 107 strerror(-err), err); 108 return err; 109 } 110 111 int minUndequeuedBuffers; 112 err = anw.get()->query(anw.get(), 113 NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, 114 &minUndequeuedBuffers); 115 if (err != NO_ERROR) { 116 ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).", 117 __FUNCTION__, strerror(-err), err); 118 return err; 119 } 120 121 ALOGV("%s: Setting buffer count to %d", __FUNCTION__, 122 maxBufferSlack + 1 + minUndequeuedBuffers); 123 err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers); 124 if (err != NO_ERROR) { 125 ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__, 126 strerror(-err), err); 127 return err; 128 } 129 return NO_ERROR; 130} 131 132/** 133 * Produce a frame in the given surface. 134 * 135 * Args: 136 * anw - a surface to produce a frame in. 137 * pixelBuffer - image buffer to generate a frame from. 138 * width - width of the pixelBuffer in pixels. 139 * height - height of the pixelBuffer in pixels. 140 * pixelFmt - format of the pixelBuffer, one of: 141 * HAL_PIXEL_FORMAT_YCrCb_420_SP, 142 * HAL_PIXEL_FORMAT_YCbCr_420_888, 143 * HAL_PIXEL_FORMAT_BLOB 144 * bufSize - the size of the pixelBuffer in bytes. 145 */ 146static status_t produceFrame(const sp<ANativeWindow>& anw, 147 uint8_t* pixelBuffer, 148 int32_t width, // Width of the pixelBuffer 149 int32_t height, // Height of the pixelBuffer 150 int32_t pixelFmt, // Format of the pixelBuffer 151 int64_t bufSize) { 152 ATRACE_CALL(); 153 status_t err = NO_ERROR; 154 ANativeWindowBuffer* anb; 155 ALOGV("%s: Dequeue buffer from %p",__FUNCTION__, anw.get()); 156 157 if (width < 0 || height < 0 || bufSize < 0) { 158 ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__); 159 return BAD_VALUE; 160 } 161 162 // TODO: Switch to using Surface::lock and Surface::unlockAndPost 163 err = native_window_dequeue_buffer_and_wait(anw.get(), &anb); 164 if (err != NO_ERROR) return err; 165 166 sp<GraphicBuffer> buf(new GraphicBuffer(anb, /*keepOwnership*/false)); 167 168 switch(pixelFmt) { 169 case HAL_PIXEL_FORMAT_YCrCb_420_SP: { 170 if (bufSize < width * height * 4) { 171 ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, 172 bufSize); 173 return BAD_VALUE; 174 } 175 uint8_t* img = NULL; 176 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 177 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 178 if (err != NO_ERROR) return err; 179 180 uint8_t* yPlane = img; 181 uint8_t* uPlane = img + height * width; 182 uint8_t* vPlane = uPlane + 1; 183 size_t chromaStep = 2; 184 size_t yStride = width; 185 size_t chromaStride = width; 186 187 rgbToYuv420(pixelBuffer, width, height, yPlane, 188 uPlane, vPlane, chromaStep, yStride, chromaStride); 189 break; 190 } 191 case HAL_PIXEL_FORMAT_YV12: { 192 if (bufSize < width * height * 4) { 193 ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, 194 bufSize); 195 return BAD_VALUE; 196 } 197 198 if ((width & 1) || (height & 1)) { 199 ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height); 200 return BAD_VALUE; 201 } 202 203 uint8_t* img = NULL; 204 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 205 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 206 if (err != NO_ERROR) { 207 ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__, 208 strerror(-err), err); 209 return err; 210 } 211 212 uint32_t stride = buf->getStride(); 213 LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride); 214 215 uint32_t cStride = ALIGN(stride / 2, 16); 216 size_t chromaStep = 1; 217 218 uint8_t* yPlane = img; 219 uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride; 220 uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2; 221 222 rgbToYuv420(pixelBuffer, width, height, yPlane, 223 crPlane, cbPlane, chromaStep, stride, cStride); 224 break; 225 } 226 case HAL_PIXEL_FORMAT_YCbCr_420_888: { 227 // Software writes with YCbCr_420_888 format are unsupported 228 // by the gralloc module for now 229 if (bufSize < width * height * 4) { 230 ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, 231 bufSize); 232 return BAD_VALUE; 233 } 234 android_ycbcr ycbcr = android_ycbcr(); 235 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 236 237 err = buf->lockYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr); 238 if (err != NO_ERROR) { 239 ALOGE("%s: Failed to lock ycbcr buffer, error %s (%d).", __FUNCTION__, 240 strerror(-err), err); 241 return err; 242 } 243 rgbToYuv420(pixelBuffer, width, height, &ycbcr); 244 break; 245 } 246 case HAL_PIXEL_FORMAT_BLOB: { 247 if (bufSize != width || height != 1) { 248 ALOGE("%s: Incorrect pixelBuffer size: %lld", __FUNCTION__, bufSize); 249 return BAD_VALUE; 250 } 251 int8_t* img = NULL; 252 253 ALOGV("%s: Lock buffer from %p for write", __FUNCTION__, anw.get()); 254 err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); 255 if (err != NO_ERROR) { 256 ALOGE("%s: Failed to lock buffer, error %s (%d).", __FUNCTION__, strerror(-err), 257 err); 258 return err; 259 } 260 memcpy(img, pixelBuffer, width); 261 break; 262 } 263 default: { 264 ALOGE("%s: Invalid pixel format in produceFrame: %x", __FUNCTION__, pixelFmt); 265 return BAD_VALUE; 266 } 267 } 268 269 ALOGV("%s: Unlock buffer from %p", __FUNCTION__, anw.get()); 270 err = buf->unlock(); 271 if (err != NO_ERROR) { 272 ALOGE("%s: Failed to unlock buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); 273 return err; 274 } 275 276 ALOGV("%s: Queue buffer to %p", __FUNCTION__, anw.get()); 277 err = anw->queueBuffer(anw.get(), buf->getNativeBuffer(), /*fenceFd*/-1); 278 if (err != NO_ERROR) { 279 ALOGE("%s: Failed to queue buffer, error %s (%d).", __FUNCTION__, strerror(-err), err); 280 return err; 281 } 282 return NO_ERROR; 283} 284 285static sp<ANativeWindow> getNativeWindow(JNIEnv* env, jobject surface) { 286 sp<ANativeWindow> anw; 287 if (surface) { 288 anw = android_view_Surface_getNativeWindow(env, surface); 289 if (env->ExceptionCheck()) { 290 return anw; 291 } 292 } else { 293 jniThrowNullPointerException(env, "surface"); 294 return anw; 295 } 296 if (anw == NULL) { 297 jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException", 298 "Surface had no valid native window."); 299 return anw; 300 } 301 return anw; 302} 303 304extern "C" { 305 306static jint LegacyCameraDevice_nativeDetectSurfaceType(JNIEnv* env, jobject thiz, jobject surface) { 307 ALOGV("nativeDetectSurfaceType"); 308 sp<ANativeWindow> anw; 309 if ((anw = getNativeWindow(env, surface)) == NULL) { 310 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 311 return 0; 312 } 313 int32_t fmt = 0; 314 status_t err = anw->query(anw.get(), NATIVE_WINDOW_FORMAT, &fmt); 315 if(err != NO_ERROR) { 316 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 317 "Error while querying surface pixel format (error code %d)", err); 318 return 0; 319 } 320 return fmt; 321} 322 323static void LegacyCameraDevice_nativeDetectSurfaceDimens(JNIEnv* env, jobject thiz, 324 jobject surface, jintArray dimens) { 325 ALOGV("nativeGetSurfaceDimens"); 326 sp<ANativeWindow> anw; 327 if ((anw = getNativeWindow(env, surface)) == NULL) { 328 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 329 return; 330 } 331 int32_t dimenBuf[2]; 332 status_t err = anw->query(anw.get(), NATIVE_WINDOW_WIDTH, dimenBuf); 333 if(err != NO_ERROR) { 334 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 335 "Error while querying surface width (error code %d)", err); 336 return; 337 } 338 err = anw->query(anw.get(), NATIVE_WINDOW_HEIGHT, dimenBuf + 1); 339 if(err != NO_ERROR) { 340 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 341 "Error while querying surface height (error code %d)", err); 342 return; 343 } 344 env->SetIntArrayRegion(dimens, /*start*/0, /*length*/ARRAY_SIZE(dimenBuf), dimenBuf); 345} 346 347static void LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface, 348 jint width, jint height, jint pixelFormat) { 349 ALOGV("nativeConfigureSurface"); 350 sp<ANativeWindow> anw; 351 if ((anw = getNativeWindow(env, surface)) == NULL) { 352 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 353 return; 354 } 355 status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK); 356 if (err != NO_ERROR) { 357 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 358 "Error while producing frame (error code %d)", err); 359 return; 360 } 361} 362 363static void LegacyCameraDevice_nativeProduceFrame(JNIEnv* env, jobject thiz, jobject surface, 364 jbyteArray pixelBuffer, jint width, jint height, jint pixelFormat) { 365 ALOGV("nativeProduceFrame"); 366 sp<ANativeWindow> anw; 367 368 if ((anw = getNativeWindow(env, surface)) == NULL) { 369 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 370 return; 371 } 372 373 if (pixelBuffer == NULL) { 374 jniThrowNullPointerException(env, "pixelBuffer"); 375 return; 376 } 377 378 int32_t bufSize = static_cast<int32_t>(env->GetArrayLength(pixelBuffer)); 379 jbyte* pixels = env->GetByteArrayElements(pixelBuffer, /*is_copy*/NULL); 380 381 if (pixels == NULL) { 382 jniThrowNullPointerException(env, "pixels"); 383 return; 384 } 385 386 status_t err = produceFrame(anw, reinterpret_cast<uint8_t*>(pixels), width, height, 387 pixelFormat, bufSize); 388 env->ReleaseByteArrayElements(pixelBuffer, pixels, JNI_ABORT); 389 390 if (err != NO_ERROR) { 391 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 392 "Error while producing frame (error code %d)", err); 393 return; 394 } 395} 396 397static void LegacyCameraDevice_nativeSetSurfaceFormat(JNIEnv* env, jobject thiz, jobject surface, 398 jint pixelFormat) { 399 ALOGV("nativeSetSurfaceType"); 400 sp<ANativeWindow> anw; 401 if ((anw = getNativeWindow(env, surface)) == NULL) { 402 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 403 return; 404 } 405 status_t err = native_window_set_buffers_format(anw.get(), pixelFormat); 406 if (err != NO_ERROR) { 407 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 408 "Error while setting surface format (error code %d)", err); 409 return; 410 } 411} 412 413static void LegacyCameraDevice_nativeSetSurfaceDimens(JNIEnv* env, jobject thiz, jobject surface, 414 jint width, jint height) { 415 ALOGV("nativeSetSurfaceDimens"); 416 sp<ANativeWindow> anw; 417 if ((anw = getNativeWindow(env, surface)) == NULL) { 418 ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__); 419 return; 420 } 421 status_t err = native_window_set_buffers_dimensions(anw.get(), width, height); 422 if (err != NO_ERROR) { 423 jniThrowExceptionFmt(env, "java/lang/IllegalStateException", 424 "Error while setting surface format (error code %d)", err); 425 return; 426 } 427} 428 429} // extern "C" 430 431static JNINativeMethod gCameraDeviceMethods[] = { 432 { "nativeDetectSurfaceType", 433 "(Landroid/view/Surface;)I", 434 (void *)LegacyCameraDevice_nativeDetectSurfaceType }, 435 { "nativeDetectSurfaceDimens", 436 "(Landroid/view/Surface;[I)V", 437 (void *)LegacyCameraDevice_nativeDetectSurfaceDimens }, 438 { "nativeConfigureSurface", 439 "(Landroid/view/Surface;III)V", 440 (void *)LegacyCameraDevice_nativeConfigureSurface }, 441 { "nativeProduceFrame", 442 "(Landroid/view/Surface;[BIII)V", 443 (void *)LegacyCameraDevice_nativeProduceFrame }, 444 { "nativeSetSurfaceFormat", 445 "(Landroid/view/Surface;I)V", 446 (void *)LegacyCameraDevice_nativeSetSurfaceFormat }, 447 { "nativeSetSurfaceDimens", 448 "(Landroid/view/Surface;II)V", 449 (void *)LegacyCameraDevice_nativeSetSurfaceDimens }, 450}; 451 452// Get all the required offsets in java class and register native functions 453int register_android_hardware_camera2_legacy_LegacyCameraDevice(JNIEnv* env) 454{ 455 // Register native functions 456 return AndroidRuntime::registerNativeMethods(env, 457 CAMERA_DEVICE_CLASS_NAME, 458 gCameraDeviceMethods, 459 NELEM(gCameraDeviceMethods)); 460} 461 462