diff options
author | Ruben Brunk <rubenbrunk@google.com> | 2014-06-20 00:24:56 -0700 |
---|---|---|
committer | Ruben Brunk <rubenbrunk@google.com> | 2014-06-20 15:59:00 -0700 |
commit | 91b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0 (patch) | |
tree | 7dcc48c4f6af7f6defa76a23558b095d37ca177b | |
parent | 5776aafc7e70c0b79c4bee2bc50f44121b37c962 (diff) |
camera2: Switch to using YV12 for ImageReader.
Bug: 15116722
- Also fixes incorrect frame number for single captures.
Change-Id: I8552124d18ad176e6724f089a1e3a3f49a5eeec4
7 files changed, 64 insertions, 12 deletions
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index 50515a2927a6..cb951b320b6a 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -174,13 +174,17 @@ public class LegacyCameraDevice implements AutoCloseable { private final RequestThreadManager mRequestThreadManager; /** - * Check if a given surface uses {@link ImageFormat#YUV_420_888} format. + * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily + * converted to this; YV12 and NV21 are the two currently supported formats. * * @param s the surface to check. - * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888}. + * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible + * format. */ static boolean needsConversion(Surface s) { - return LegacyCameraDevice.nativeDetectSurfaceType(s) == ImageFormat.YUV_420_888; + int nativeType = LegacyCameraDevice.nativeDetectSurfaceType(s); + return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 || + nativeType == ImageFormat.NV21; } /** diff --git a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java index 6fa2134571fb..7f23561d6dcb 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java +++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java @@ -49,7 +49,7 @@ public class LegacyMetadataMapper { private static final int HAL_PIXEL_FORMAT_BLOB = 0x21; private static final long APPROXIMATE_CAPTURE_DELAY_MS = 200; // ms - private static final long APPROXIMATE_SENSOR_AREA = (1 << 20); // 8mp + private static final long APPROXIMATE_SENSOR_AREA = (1 << 23); // 8mp private static final long APPROXIMATE_JPEG_ENCODE_TIME = 600; // ms private static final long NS_PER_MS = 1000000; diff --git a/core/java/android/hardware/camera2/legacy/RequestQueue.java b/core/java/android/hardware/camera2/legacy/RequestQueue.java index 5c6830372b10..6bedc48aaa8b 100644 --- a/core/java/android/hardware/camera2/legacy/RequestQueue.java +++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java @@ -122,7 +122,7 @@ public class RequestQueue { for (BurstHolder b : mRequestQueue) { total += b.getNumberOfRequests(); if (b.getRequestId() == requestId) { - return total; + return total - 1; } } throw new IllegalStateException( diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java index e0f3429d8bec..a4b10997125d 100644 --- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java +++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java @@ -239,6 +239,9 @@ public class RequestThreadManager { mGLThreadManager.queueNewFrame(holder.getHolderTargets()); } + /** + * TODO: Get timestamp from GL thread after buffer update. + */ mLastPreviewTimestamp = surfaceTexture.getTimestamp(); mReceivedPreview.open(); } @@ -495,7 +498,6 @@ public class RequestThreadManager { if (holder.hasJpegTargets()) { mReceivedJpeg.close(); doJpegCapture(holder); - mReceivedJpeg.block(); if (!mReceivedJpeg.block(JPEG_FRAME_TIMEOUT)) { // TODO: report error to CameraDevice Log.e(TAG, "Hit timeout for jpeg callback!"); @@ -507,6 +509,9 @@ public class RequestThreadManager { // TODO: err handling throw new IOError(e); } + if (timestamp == 0) { + timestamp = SystemClock.elapsedRealtimeNanos(); + } CameraMetadataNative result = LegacyMetadataMapper.convertResultMetadata(mParams, request, timestamp); mDeviceState.setCaptureResult(holder, result); diff --git a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java index e9d32f0caa34..bbc700583981 100644 --- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java +++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java @@ -439,7 +439,7 @@ public class SurfaceTextureRenderer { for (Surface s : surfaces) { // If pixel conversions aren't handled by egl, use a pbuffer if (LegacyCameraDevice.needsConversion(s)) { - LegacyCameraDevice.nativeSetSurfaceFormat(s, ImageFormat.NV21); + LegacyCameraDevice.nativeSetSurfaceFormat(s, ImageFormat.YV12); EGLSurfaceHolder holder = new EGLSurfaceHolder(); holder.surface = s; mConversionSurfaces.add(holder); diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp index 40e95447a41f..004842649788 100644 --- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp +++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp @@ -35,6 +35,8 @@ using namespace android; #define ARRAY_SIZE(a) (sizeof(a)/sizeof(*(a))) +#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) + /** * 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. @@ -152,6 +154,11 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, ANativeWindowBuffer* anb; ALOGV("%s: Dequeue buffer from %p",__FUNCTION__, anw.get()); + if (width < 0 || height < 0 || bufSize < 0) { + ALOGE("%s: Illegal argument, negative dimension passed to produceFrame", __FUNCTION__); + return BAD_VALUE; + } + // 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; @@ -181,6 +188,41 @@ static status_t produceFrame(const sp<ANativeWindow>& anw, uPlane, vPlane, chromaStep, yStride, chromaStride); break; } + case HAL_PIXEL_FORMAT_YV12: { + if (bufSize < width * height * 4) { + ALOGE("%s: PixelBuffer size %lld to small for given dimensions", __FUNCTION__, + bufSize); + return BAD_VALUE; + } + + if ((width & 1) || (height & 1)) { + ALOGE("%s: Dimens %dx%d are not divisible by 2.", __FUNCTION__, width, height); + 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) { + ALOGE("%s: Error %s (%d) while locking gralloc buffer for write.", __FUNCTION__, + strerror(-err), err); + return err; + } + + uint32_t stride = buf->getStride(); + LOG_ALWAYS_FATAL_IF(stride % 16, "Stride is not 16 pixel aligned %d", stride); + + uint32_t cStride = ALIGN(stride / 2, 16); + size_t chromaStep = 1; + + uint8_t* yPlane = img; + uint8_t* crPlane = img + static_cast<uint32_t>(height) * stride; + uint8_t* cbPlane = crPlane + cStride * static_cast<uint32_t>(height) / 2; + + rgbToYuv420(pixelBuffer, width, height, yPlane, + crPlane, cbPlane, chromaStep, stride, cStride); + break; + } case HAL_PIXEL_FORMAT_YCbCr_420_888: { // Software writes with YCbCr_420_888 format are unsupported // by the gralloc module for now diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp index 36cfb0fe4bee..41ed9e133706 100644 --- a/media/jni/android_media_ImageReader.cpp +++ b/media/jni/android_media_ImageReader.cpp @@ -767,11 +767,12 @@ static jint ImageReader_imageSetup(JNIEnv* env, jobject thiz, int imgReaderFmt = ctx->getBufferFormat(); int bufFmt = buffer->format; if (imgReaderFmt != bufFmt) { - // Special casing for when producer switches format - if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && bufFmt == - HAL_PIXEL_FORMAT_YCrCb_420_SP) { - ctx->setBufferFormat(HAL_PIXEL_FORMAT_YCrCb_420_SP); - ALOGV("%s: Overriding NV21 to YUV_420_888.", __FUNCTION__); + // Special casing for when producer switches to a format compatible with flexible YUV + // (HAL_PIXEL_FORMAT_YCbCr_420_888). + if (imgReaderFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt == + HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) { + ctx->setBufferFormat(bufFmt); + ALOGV("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt); } else { // Return the buffer to the queue. consumer->unlockBuffer(*buffer); |