camera2: Switch to using YV12 for ImageReader.

Bug: 15116722

- Also fixes incorrect frame number for single captures.

Change-Id: I8552124d18ad176e6724f089a1e3a3f49a5eeec4
diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
index 50515a2..cb951b3 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
@@ -174,13 +174,17 @@
     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 6fa2134..7f23561 100644
--- a/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
+++ b/core/java/android/hardware/camera2/legacy/LegacyMetadataMapper.java
@@ -49,7 +49,7 @@
     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 5c68303..6bedc48 100644
--- a/core/java/android/hardware/camera2/legacy/RequestQueue.java
+++ b/core/java/android/hardware/camera2/legacy/RequestQueue.java
@@ -122,7 +122,7 @@
         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 e0f3429..a4b1099 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -239,6 +239,9 @@
                         mGLThreadManager.queueNewFrame(holder.getHolderTargets());
                     }
 
+                    /**
+                     * TODO: Get timestamp from GL thread after buffer update.
+                     */
                     mLastPreviewTimestamp = surfaceTexture.getTimestamp();
                     mReceivedPreview.open();
                 }
@@ -495,7 +498,6 @@
                             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 @@
                             // 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 e9d32f0..bbc7005 100644
--- a/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
+++ b/core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
@@ -439,7 +439,7 @@
         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 40e9544..0048426 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -35,6 +35,8 @@
 
 #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 @@
     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 @@
                     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 36cfb0f..41ed9e1 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -767,11 +767,12 @@
     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);