Add support for HAL_PIXEL_FORMAT_YCbCr_420_888

- Add fields to CpuConsumer::LockedBuffer for new information
- New lock methods for GraphicBuffer and GraphicBufferMapper for
  the format

Bug: 8734880
Change-Id: If31f82c62d64b6942cf4cc6e5715585c03273f12
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 4b956c7..bf9918e 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -53,6 +53,14 @@
         uint32_t    scalingMode;
         int64_t     timestamp;
         uint64_t    frameNumber;
+        // Values below are only valid when using
+        // HAL_PIXEL_FORMAT_YCbCr_420_888, in which case LockedBuffer::data
+        // contains the Y channel, and stride is the Y channel stride. For other
+        // formats, these will all be 0.
+        uint8_t    *dataCb;
+        uint8_t    *dataCr;
+        uint32_t    chromaStride;
+        uint32_t    chromaStep;
     };
 
     // Create a new CPU consumer. The maxLockedBuffers parameter specifies
diff --git a/include/ui/GraphicBuffer.h b/include/ui/GraphicBuffer.h
index ea9368d..e5ad1e0 100644
--- a/include/ui/GraphicBuffer.h
+++ b/include/ui/GraphicBuffer.h
@@ -92,6 +92,9 @@
 
     status_t lock(uint32_t usage, void** vaddr);
     status_t lock(uint32_t usage, const Rect& rect, void** vaddr);
+    // For HAL_PIXEL_FORMAT_YCbCr_420_888
+    status_t lockYCbCr(uint32_t usage, android_ycbcr *ycbcr);
+    status_t lockYCbCr(uint32_t usage, const Rect& rect, android_ycbcr *ycbcr);
     status_t unlock();
 
     ANativeWindowBuffer* getNativeBuffer() const;
diff --git a/include/ui/GraphicBufferMapper.h b/include/ui/GraphicBufferMapper.h
index 697a02a..99d8723 100644
--- a/include/ui/GraphicBufferMapper.h
+++ b/include/ui/GraphicBufferMapper.h
@@ -45,6 +45,9 @@
     status_t lock(buffer_handle_t handle,
             int usage, const Rect& bounds, void** vaddr);
 
+    status_t lockYCbCr(buffer_handle_t handle,
+            int usage, const Rect& bounds, android_ycbcr *ycbcr);
+
     status_t unlock(buffer_handle_t handle);
     
     // dumps information about the mapping of this handle
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index a638cfa..91af78d 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -89,16 +89,34 @@
     }
 
     void *bufferPointer = NULL;
-    err = mSlots[buf].mGraphicBuffer->lock(
-        GraphicBuffer::USAGE_SW_READ_OFTEN,
-        b.mCrop,
-        &bufferPointer);
+    android_ycbcr ycbcr = android_ycbcr();
 
-    if (bufferPointer != NULL && err != OK) {
-        CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err),
-                err);
-        return err;
+    if (mSlots[buf].mGraphicBuffer->getPixelFormat() ==
+            HAL_PIXEL_FORMAT_YCbCr_420_888) {
+        err = mSlots[buf].mGraphicBuffer->lockYCbCr(
+            GraphicBuffer::USAGE_SW_READ_OFTEN,
+            b.mCrop,
+            &ycbcr);
+
+        if (err != OK) {
+            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
+        bufferPointer = ycbcr.y;
+    } else {
+        err = mSlots[buf].mGraphicBuffer->lock(
+            GraphicBuffer::USAGE_SW_READ_OFTEN,
+            b.mCrop,
+            &bufferPointer);
+
+        if (err != OK) {
+            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)",
+                    strerror(-err), err);
+            return err;
+        }
     }
+
     size_t lockedIdx = 0;
     for (; lockedIdx < mMaxLockedBuffers; lockedIdx++) {
         if (mAcquiredBuffers[lockedIdx].mSlot ==
@@ -118,7 +136,9 @@
     nativeBuffer->width  = mSlots[buf].mGraphicBuffer->getWidth();
     nativeBuffer->height = mSlots[buf].mGraphicBuffer->getHeight();
     nativeBuffer->format = mSlots[buf].mGraphicBuffer->getPixelFormat();
-    nativeBuffer->stride = mSlots[buf].mGraphicBuffer->getStride();
+    nativeBuffer->stride = (ycbcr.y != NULL) ?
+            ycbcr.ystride :
+            mSlots[buf].mGraphicBuffer->getStride();
 
     nativeBuffer->crop        = b.mCrop;
     nativeBuffer->transform   = b.mTransform;
@@ -126,6 +146,11 @@
     nativeBuffer->timestamp   = b.mTimestamp;
     nativeBuffer->frameNumber = b.mFrameNumber;
 
+    nativeBuffer->dataCb       = reinterpret_cast<uint8_t*>(ycbcr.cb);
+    nativeBuffer->dataCr       = reinterpret_cast<uint8_t*>(ycbcr.cr);
+    nativeBuffer->chromaStride = ycbcr.cstride;
+    nativeBuffer->chromaStep   = ycbcr.chroma_step;
+
     mCurrentLockedBuffers++;
 
     return OK;
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index b9cab85..580788d 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -174,6 +174,27 @@
     return res;
 }
 
+status_t GraphicBuffer::lockYCbCr(uint32_t usage, android_ycbcr *ycbcr)
+{
+    const Rect lockBounds(width, height);
+    status_t res = lockYCbCr(usage, lockBounds, ycbcr);
+    return res;
+}
+
+status_t GraphicBuffer::lockYCbCr(uint32_t usage, const Rect& rect,
+        android_ycbcr *ycbcr)
+{
+    if (rect.left < 0 || rect.right  > this->width ||
+        rect.top  < 0 || rect.bottom > this->height) {
+        ALOGE("locking pixels (%d,%d,%d,%d) outside of buffer (w=%d, h=%d)",
+                rect.left, rect.top, rect.right, rect.bottom,
+                this->width, this->height);
+        return BAD_VALUE;
+    }
+    status_t res = getBufferMapper().lockYCbCr(handle, usage, rect, ycbcr);
+    return res;
+}
+
 status_t GraphicBuffer::unlock()
 {
     status_t res = getBufferMapper().unlock(handle);
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index 967da98..a4cfce2 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -84,6 +84,20 @@
     return err;
 }
 
+status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle,
+        int usage, const Rect& bounds, android_ycbcr *ycbcr)
+{
+    ATRACE_CALL();
+    status_t err;
+
+    err = mAllocMod->lock_ycbcr(mAllocMod, handle, usage,
+            bounds.left, bounds.top, bounds.width(), bounds.height(),
+            ycbcr);
+
+    ALOGW_IF(err, "lock(...) failed %d (%s)", err, strerror(-err));
+    return err;
+}
+
 status_t GraphicBufferMapper::unlock(buffer_handle_t handle)
 {
     ATRACE_CALL();