Gralloc/Camera3: Support new HAL_PIXEL_FORMAT_YCbCr_420_888 format

Enable flexible YUV format buffers from the camera.

 - Add gralloc alloc support for YCbCr_420_888, mapped to NV21
 - Add gralloc lock_ycbcr method
 - Add new format to list supported by camera HAL
 - Fix minor compilation warnings

Bug: 8734880
Change-Id: I68a8cc126985c7d5ae100a87b31c60ee59074cd3
diff --git a/camera/EmulatedFakeCamera3.cpp b/camera/EmulatedFakeCamera3.cpp
index b82c4c0..2513c19 100644
--- a/camera/EmulatedFakeCamera3.cpp
+++ b/camera/EmulatedFakeCamera3.cpp
@@ -51,12 +51,15 @@
 const int64_t MSEC = USEC * 1000LL;
 const int64_t SEC = MSEC * 1000LL;
 
-const uint32_t EmulatedFakeCamera3::kAvailableFormats[4] = {
+const int32_t EmulatedFakeCamera3::kAvailableFormats[5] = {
         HAL_PIXEL_FORMAT_RAW_SENSOR,
         HAL_PIXEL_FORMAT_BLOB,
         HAL_PIXEL_FORMAT_RGBA_8888,
+        HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED,
+        // These are handled by YCbCr_420_888
         //        HAL_PIXEL_FORMAT_YV12,
-        HAL_PIXEL_FORMAT_YCrCb_420_SP
+        //        HAL_PIXEL_FORMAT_YCrCb_420_SP,
+        HAL_PIXEL_FORMAT_YCbCr_420_888
 };
 
 const uint32_t EmulatedFakeCamera3::kAvailableRawSizes[2] = {
@@ -294,6 +297,21 @@
             }
             inputStream = newStream;
         }
+
+        bool validFormat = false;
+        for (size_t f = 0;
+             f < sizeof(kAvailableFormats)/sizeof(kAvailableFormats[0]);
+             f++) {
+            if (newStream->format == kAvailableFormats[f]) {
+                validFormat = true;
+                break;
+            }
+        }
+        if (!validFormat) {
+            ALOGE("%s: Unsupported stream format 0x%x requested",
+                    __FUNCTION__, newStream->format);
+            return BAD_VALUE;
+        }
     }
     mInputStream = inputStream;
 
@@ -877,8 +895,26 @@
         if (res == OK) {
             // Lock buffer for writing
             const Rect rect(destBuf.width, destBuf.height);
-            res = GraphicBufferMapper::get().lock(*(destBuf.buffer),
-                    GRALLOC_USAGE_HW_CAMERA_WRITE, rect, (void**)&(destBuf.img));
+            if (srcBuf.stream->format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                if (privBuffer->format == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
+                    android_ycbcr ycbcr = android_ycbcr();
+                    res = GraphicBufferMapper::get().lockYCbCr(
+                        *(destBuf.buffer),
+                        GRALLOC_USAGE_HW_CAMERA_WRITE, rect,
+                        &ycbcr);
+                    // This is only valid because we know that emulator's
+                    // YCbCr_420_888 is really contiguous NV21 under the hood
+                    destBuf.img = static_cast<uint8_t*>(ycbcr.y);
+                } else {
+                    ALOGE("Unexpected private format for flexible YUV: 0x%x",
+                            privBuffer->format);
+                    res = INVALID_OPERATION;
+                }
+            } else {
+                res = GraphicBufferMapper::get().lock(*(destBuf.buffer),
+                        GRALLOC_USAGE_HW_CAMERA_WRITE, rect,
+                        (void**)&(destBuf.img));
+            }
             if (res != OK) {
                 ALOGE("%s: Request %d: Buffer %d: Unable to lock buffer",
                         __FUNCTION__, frameNumber, i);
@@ -886,7 +922,8 @@
         }
 
         if (res != OK) {
-            // Either waiting or locking failed. Unlock locked buffers and bail out.
+            // Either waiting or locking failed. Unlock locked buffers and bail
+            // out.
             for (size_t j = 0; j < i; j++) {
                 GraphicBufferMapper::get().unlock(
                         *(request->output_buffers[i].buffer));
@@ -1111,8 +1148,8 @@
     // android.scaler
 
     info.update(ANDROID_SCALER_AVAILABLE_FORMATS,
-            (int32_t*)kAvailableFormats,
-            sizeof(kAvailableFormats)/sizeof(uint32_t));
+            kAvailableFormats,
+            sizeof(kAvailableFormats)/sizeof(int32_t));
 
     info.update(ANDROID_SCALER_AVAILABLE_RAW_SIZES,
             (int32_t*)kAvailableRawSizes,
diff --git a/camera/EmulatedFakeCamera3.h b/camera/EmulatedFakeCamera3.h
index 0b3e2db..e9ef184 100644
--- a/camera/EmulatedFakeCamera3.h
+++ b/camera/EmulatedFakeCamera3.h
@@ -135,7 +135,7 @@
     // sensor-generated buffers which use a nonpositive ID. Otherwise, HAL3 has
     // no concept of a stream id.
     static const uint32_t kGenericStreamId = 1;
-    static const uint32_t kAvailableFormats[];
+    static const int32_t  kAvailableFormats[];
     static const uint32_t kAvailableRawSizes[];
     static const uint64_t kAvailableRawMinDurations[];
     static const uint32_t kAvailableProcessedSizesBack[];
diff --git a/opengl/system/OpenglSystemCommon/gralloc_cb.h b/opengl/system/OpenglSystemCommon/gralloc_cb.h
index a207401..fd35473 100644
--- a/opengl/system/OpenglSystemCommon/gralloc_cb.h
+++ b/opengl/system/OpenglSystemCommon/gralloc_cb.h
@@ -30,13 +30,14 @@
 struct cb_handle_t : public native_handle {
 
     cb_handle_t(int p_fd, int p_ashmemSize, int p_usage,
-                int p_width, int p_height, int p_format,
-                int p_glFormat, int p_glType) :
+                int p_width, int p_height, int p_frameworkFormat,
+                int p_format, int p_glFormat, int p_glType) :
         fd(p_fd),
         magic(BUFFER_HANDLE_MAGIC),
         usage(p_usage),
         width(p_width),
         height(p_height),
+        frameworkFormat(p_frameworkFormat),
         format(p_format),
         glFormat(p_glFormat),
         glType(p_glType),
@@ -89,6 +90,7 @@
     int usage;              // usage bits the buffer was created with
     int width;              // buffer width
     int height;             // buffer height
+    int frameworkFormat;    // format requested by the Android framework
     int format;             // real internal pixel format format
     int glFormat;           // OpenGL format enum used for host h/w color buffer
     int glType;             // OpenGL type enum used when uploading to host
diff --git a/opengl/system/gralloc/gralloc.cpp b/opengl/system/gralloc/gralloc.cpp
index 311146f..ed5d05f 100644
--- a/opengl/system/gralloc/gralloc.cpp
+++ b/opengl/system/gralloc/gralloc.cpp
@@ -154,6 +154,8 @@
     bool hw_cam_read = usage & GRALLOC_USAGE_HW_CAMERA_READ;
     bool hw_vid_enc_read = usage & GRALLOC_USAGE_HW_VIDEO_ENCODER;
 
+    // Keep around original requested format for later validation
+    int frameworkFormat = format;
     // Pick the right concrete pixel format given the endpoints as encoded in
     // the usage bits.  Every end-point pair needs explicit listing here.
     if (format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) {
@@ -178,8 +180,17 @@
                     w, h, usage);
             return -EINVAL;
         }
+    } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        // Flexible framework-accessible YUV format; map to NV21 for now
+        if (usage & GRALLOC_USAGE_HW_CAMERA_WRITE) {
+            format = HAL_PIXEL_FORMAT_YCrCb_420_SP;
+        }
+        if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            ALOGE("gralloc_alloc: Requested YCbCr_420_888, but no known "
+                    "specific format for this usage: %d x %d, usage %x",
+                    w, h, usage);
+        }
     }
-
     bool yuv_format = false;
 
     int ashmem_size = 0;
@@ -297,7 +308,8 @@
     }
 
     cb_handle_t *cb = new cb_handle_t(fd, ashmem_size, usage,
-                                      w, h, format, glFormat, glType);
+                                      w, h, frameworkFormat, format,
+                                      glFormat, glType);
 
     if (ashmem_size > 0) {
         //
@@ -350,7 +362,11 @@
     pthread_mutex_unlock(&grdev->lock);
 
     *pHandle = cb;
-    *pStride = stride;
+    if (frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        *pStride = 0;
+    } else {
+        *pStride = stride;
+    }
     return 0;
 }
 
@@ -580,7 +596,7 @@
             ERR("gralloc_unregister_buffer(%p): unmap failed", cb);
             return -EINVAL;
         }
-        cb->ashmemBase = NULL;
+        cb->ashmemBase = 0;
         cb->mappedPid = 0;
     }
 
@@ -605,6 +621,12 @@
         return -EINVAL;
     }
 
+    // validate format
+    if (cb->frameworkFormat == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGE("gralloc_lock can't be used with YCbCr_420_888 format");
+        return -EINVAL;
+    }
+
     // Validate usage,
     //   1. cannot be locked for hw access
     //   2. lock for either sw read or write.
@@ -759,6 +781,109 @@
     return 0;
 }
 
+static int gralloc_lock_ycbcr(gralloc_module_t const* module,
+                        buffer_handle_t handle, int usage,
+                        int l, int t, int w, int h,
+                        android_ycbcr *ycbcr)
+{
+    // Not supporting fallback module for YCbCr
+    if (sFallback != NULL) {
+        return -EINVAL;
+    }
+
+    if (!ycbcr) {
+        ALOGE("gralloc_lock_ycbcr got NULL ycbcr struct");
+        return -EINVAL;
+    }
+
+    private_module_t *gr = (private_module_t *)module;
+    cb_handle_t *cb = (cb_handle_t *)handle;
+    if (!gr || !cb_handle_t::validate(cb)) {
+        ALOGE("gralloc_lock_ycbcr bad handle\n");
+        return -EINVAL;
+    }
+
+    if (cb->frameworkFormat != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        ALOGE("gralloc_lock_ycbcr can only be used with "
+                "HAL_PIXEL_FORMAT_YCbCr_420_888, got %x instead",
+                cb->frameworkFormat);
+        return -EINVAL;
+    }
+
+    // Validate usage
+    // For now, only allow camera write, software read.
+    bool sw_read = (0 != (usage & GRALLOC_USAGE_SW_READ_MASK));
+    bool hw_cam_write = (usage & GRALLOC_USAGE_HW_CAMERA_WRITE);
+    bool sw_read_allowed = (0 != (cb->usage & GRALLOC_USAGE_SW_READ_MASK));
+
+    if ( (!hw_cam_write && !sw_read) ||
+            (sw_read && !sw_read_allowed) ) {
+        ALOGE("gralloc_lock_ycbcr usage mismatch usage:0x%x cb->usage:0x%x\n",
+                usage, cb->usage);
+        return -EINVAL;
+    }
+
+    // Make sure memory is mapped, get address
+    if (cb->ashmemBasePid != getpid() || !cb->ashmemBase) {
+        return -EACCES;
+    }
+
+    uint8_t *cpu_addr = NULL;
+
+    if (cb->canBePosted()) {
+        cpu_addr = (uint8_t *)(cb->ashmemBase + sizeof(int));
+    }
+    else {
+        cpu_addr = (uint8_t *)(cb->ashmemBase);
+    }
+
+    // Calculate offsets to underlying YUV data
+    size_t yStride;
+    size_t cStride;
+    size_t yOffset;
+    size_t uOffset;
+    size_t vOffset;
+    size_t cStep;
+    switch (cb->format) {
+        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
+            yStride = cb->width;
+            cStride = cb->width;
+            yOffset = 0;
+            vOffset = yStride * cb->height;
+            uOffset = vOffset + 1;
+            cStep = 2;
+            break;
+        default:
+            ALOGE("gralloc_lock_ycbcr unexpected internal format %x",
+                    cb->format);
+            return -EINVAL;
+    }
+
+    ycbcr->y = cpu_addr + yOffset;
+    ycbcr->cb = cpu_addr + uOffset;
+    ycbcr->cr = cpu_addr + vOffset;
+    ycbcr->ystride = yStride;
+    ycbcr->cstride = cStride;
+    ycbcr->chroma_step = cStep;
+
+    // Zero out reserved fields
+    memset(ycbcr->reserved, 0, sizeof(ycbcr->reserved));
+
+    //
+    // Keep locked region if locked for s/w write access.
+    //
+    cb->lockedLeft = l;
+    cb->lockedTop = t;
+    cb->lockedWidth = w;
+    cb->lockedHeight = h;
+
+    DD("gralloc_lock_ycbcr success. usage: %x, ycbcr.y: %p, .cb: %p, .cr: %p, "
+            ".ystride: %d , .cstride: %d, .chroma_step: %d", usage,
+            ycbcr->y, ycbcr->cb, ycbcr->cr, ycbcr->ystride, ycbcr->cstride,
+            ycbcr->chroma_step);
+
+    return 0;
+}
 
 static int gralloc_device_open(const hw_module_t* module,
                                const char* name,
@@ -881,8 +1006,8 @@
     base: {
         common: {
             tag: HARDWARE_MODULE_TAG,
-            version_major: 1,
-            version_minor: 0,
+            module_api_version: GRALLOC_MODULE_API_VERSION_0_2,
+            hal_api_version: 0,
             id: GRALLOC_HARDWARE_MODULE_ID,
             name: "Graphics Memory Allocator Module",
             author: "The Android Open Source Project",
@@ -894,7 +1019,9 @@
         unregisterBuffer: gralloc_unregister_buffer,
         lock: gralloc_lock,
         unlock: gralloc_unlock,
-        perform: NULL
+        perform: NULL,
+        lock_ycbcr: gralloc_lock_ycbcr,
+        reserved_proc: {0, }
     }
 };