Refactor AImage/AImageReader

1/ Use BufferItemConsumer instead of CpuConsumer for AImageReader.
2/ Delay lock image in AImage until the first time getPlaneXXX functions
get called.
3/ Add libmedia_jni as dependency so that we can reuse existing code
from android_media_Utils.h

Bug: 35114769
Test: Ran the following CTS test case from CtsCameraTestCases:
      NativeCameraDeviceTest, NativeCameraManagerTest,
      NativeImageReaderTest, NativeStillCaptureTest

Change-Id: Ia8dc451ea873e8290592deacc7f8d40360382f86
diff --git a/include/ndk/NdkImage.h b/include/ndk/NdkImage.h
index 15eae40..40c1699 100644
--- a/include/ndk/NdkImage.h
+++ b/include/ndk/NdkImage.h
@@ -646,7 +646,9 @@
  *         <li>{@link AMEDIA_ERROR_UNSUPPORTED} if pixel stride is undefined for the format of input
  *                 image.</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
- *                 image has been deleted.</li></ul>
+ *                 image has been deleted.</li>
+ *         <li>{@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ *                 for CPU access.</li></ul>
  */
 media_status_t AImage_getPlanePixelStride(
         const AImage* image, int planeIdx, /*out*/int32_t* pixelStride);
@@ -671,7 +673,9 @@
  *         <li>{@link AMEDIA_ERROR_UNSUPPORTED} if row stride is undefined for the format of input
  *                 image.</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
- *                 image has been deleted.</li></ul>
+ *                 image has been deleted.</li>
+ *         <li>{@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ *                 for CPU access.</li></ul>
  */
 media_status_t AImage_getPlaneRowStride(
         const AImage* image, int planeIdx, /*out*/int32_t* rowStride);
@@ -693,7 +697,9 @@
  *         <li>{@link AMEDIA_ERROR_INVALID_PARAMETER} if image, data or dataLength is NULL, or
  *                 planeIdx is out of the range of [0, numOfPlanes - 1].</li>
  *         <li>{@link AMEDIA_ERROR_INVALID_OBJECT} if the {@link AImageReader} generated this
- *                 image has been deleted.</li></ul>
+ *                 image has been deleted.</li>
+ *         <li>{@link AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE} if the {@link AImage} cannot be locked
+ *                 for CPU access.</li></ul>
  */
 media_status_t AImage_getPlaneData(
         const AImage* image, int planeIdx,
diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h
index fb00b1d..9709a6f 100644
--- a/include/ndk/NdkMediaError.h
+++ b/include/ndk/NdkMediaError.h
@@ -60,6 +60,9 @@
     AMEDIA_IMGREADER_ERROR_BASE          = -30000,
     AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE = AMEDIA_IMGREADER_ERROR_BASE - 1,
     AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED = AMEDIA_IMGREADER_ERROR_BASE - 2,
+    AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE   = AMEDIA_IMGREADER_ERROR_BASE - 3,
+    AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE = AMEDIA_IMGREADER_ERROR_BASE - 4,
+    AMEDIA_IMGREADER_IMAGE_NOT_LOCKED    = AMEDIA_IMGREADER_ERROR_BASE - 5,
 
 } media_status_t;
 
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index 74729e4..67b0ab1 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -34,9 +34,12 @@
 
 LOCAL_C_INCLUDES := \
     bionic/libc/private \
+    external/piex \
     frameworks/base/core/jni \
+    frameworks/base/media/jni \
     frameworks/av/include/ndk \
-    system/media/camera/include
+    system/media/camera/include \
+    $(call include-path-for, libhardware)/hardware \
 
 LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
 
@@ -45,7 +48,9 @@
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
     libmedia \
+    libmedia_jni \
     libmediadrm \
+    libskia \
     libstagefright \
     libstagefright_foundation \
     liblog \
diff --git a/media/ndk/NdkImage.cpp b/media/ndk/NdkImage.cpp
index 40900ad..6c9a644 100644
--- a/media/ndk/NdkImage.cpp
+++ b/media/ndk/NdkImage.cpp
@@ -22,6 +22,8 @@
 #include "NdkImagePriv.h"
 #include "NdkImageReaderPriv.h"
 
+#include <android_media_Utils.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
 #include <utils/Log.h>
 #include "hardware/camera3.h"
 
@@ -29,11 +31,11 @@
 
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
-AImage::AImage(AImageReader* reader, int32_t format,
-        CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
+AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage,
+        BufferItem* buffer, int64_t timestamp,
         int32_t width, int32_t height, int32_t numPlanes) :
-        mReader(reader), mFormat(format),
-        mBuffer(buffer), mTimestamp(timestamp),
+        mReader(reader), mFormat(format), mUsage(usage),
+        mBuffer(buffer), mLockedBuffer(nullptr), mTimestamp(timestamp),
         mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
 }
 
@@ -66,6 +68,7 @@
     // Should have been set to nullptr in releaseImageLocked
     // Set to nullptr here for extra safety only
     mBuffer = nullptr;
+    mLockedBuffer = nullptr;
     mIsClosed = true;
 }
 
@@ -169,8 +172,80 @@
     return AMEDIA_OK;
 }
 
+media_status_t AImage::lockImage() {
+    if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
+        LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    if ((mUsage & AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN) == 0) {
+        ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "",
+              __FUNCTION__, this, mUsage);
+        return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
+    }
+
+    if (mLockedBuffer != nullptr) {
+        // Return immediately if the image has already been locked.
+        return AMEDIA_OK;
+    }
+
+    auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>();
+
+    uint64_t producerUsage;
+    uint64_t consumerUsage;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+            &producerUsage, &consumerUsage, mUsage, 0);
+
+    status_t ret =
+            lockImageFromBuffer(mBuffer, consumerUsage, mBuffer->mFence->dup(), lockedBuffer.get());
+    if (ret != OK) {
+        ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret);
+        return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE;
+    }
+
+    ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this);
+    mLockedBuffer = std::move(lockedBuffer);
+
+    return AMEDIA_OK;
+}
+
+media_status_t AImage::unlockImageIfLocked(int* fenceFd) {
+    if (fenceFd == nullptr) {
+        LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
+    if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) {
+        LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this);
+        return AMEDIA_ERROR_INVALID_OBJECT;
+    }
+
+    if (mLockedBuffer == nullptr) {
+        // This image hasn't been locked yet, no need to unlock.
+        *fenceFd = -1;
+        return AMEDIA_OK;
+    }
+
+    // No fence by default.
+    int releaseFenceFd = -1;
+    status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd);
+    if (res != OK) {
+        ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this);
+        *fenceFd = -1;
+        return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE;
+    }
+
+    *fenceFd = releaseFenceFd;
+    return AMEDIA_OK;
+}
+
 media_status_t
 AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
+    if (mLockedBuffer == nullptr) {
+        ALOGE("%s: buffer not locked.", __FUNCTION__);
+        return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
+    }
+
     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
         ALOGE("Error: planeIdx %d out of bound [0,%d]",
                 planeIdx, mNumPlanes - 1);
@@ -183,10 +258,10 @@
         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    int32_t fmt = mBuffer->flexFormat;
+    int32_t fmt = mLockedBuffer->flexFormat;
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            *pixelStride = (planeIdx == 0) ? 1 : mBuffer->chromaStep;
+            *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
             *pixelStride = (planeIdx == 0) ? 1 : 2;
@@ -226,6 +301,11 @@
 
 media_status_t
 AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
+    if (mLockedBuffer == nullptr) {
+        ALOGE("%s: buffer not locked.", __FUNCTION__);
+        return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
+    }
+
     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
         ALOGE("Error: planeIdx %d out of bound [0,%d]",
                 planeIdx, mNumPlanes - 1);
@@ -238,54 +318,58 @@
         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
         return AMEDIA_ERROR_INVALID_OBJECT;
     }
-    int32_t fmt = mBuffer->flexFormat;
+    int32_t fmt = mLockedBuffer->flexFormat;
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            *rowStride = (planeIdx == 0) ? mBuffer->stride : mBuffer->chromaStride;
+            *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
+                                         : mLockedBuffer->chromaStride;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            *rowStride = mBuffer->width;
+            *rowStride = mLockedBuffer->width;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_YV12:
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            *rowStride = (planeIdx == 0) ? mBuffer->stride : ALIGN(mBuffer->stride / 2, 16);
+            *rowStride = (planeIdx == 0) ? mLockedBuffer->stride
+                                         : ALIGN(mLockedBuffer->stride / 2, 16);
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RAW10:
         case HAL_PIXEL_FORMAT_RAW12:
             // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
-            *rowStride = mBuffer->stride;
+            *rowStride = mLockedBuffer->stride;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_Y8:
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!",
+                      mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            *rowStride = mBuffer->stride;
+            *rowStride = mLockedBuffer->stride;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_Y16:
         case HAL_PIXEL_FORMAT_RAW16:
             // In native side, strides are specified in pixels, not in bytes.
             // Single plane 16bpp bayer data. even width/height,
             // row stride multiple of 16 pixels (32 bytes)
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!",
+                      mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            *rowStride = mBuffer->stride * 2;
+            *rowStride = mLockedBuffer->stride * 2;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RGB_565:
-            *rowStride = mBuffer->stride * 2;
+            *rowStride = mLockedBuffer->stride * 2;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
-            *rowStride = mBuffer->stride * 4;
+            *rowStride = mLockedBuffer->stride * 4;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_RGB_888:
             // Single plane, 24bpp.
-            *rowStride = mBuffer->stride * 3;
+            *rowStride = mLockedBuffer->stride * 3;
             return AMEDIA_OK;
         case HAL_PIXEL_FORMAT_BLOB:
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
@@ -300,13 +384,13 @@
 
 uint32_t
 AImage::getJpegSize() const {
-    if (mBuffer == nullptr) {
+    if (mLockedBuffer == nullptr) {
         LOG_ALWAYS_FATAL("Error: buffer is null");
     }
 
     uint32_t size = 0;
-    uint32_t width = mBuffer->width;
-    uint8_t* jpegBuffer = mBuffer->data;
+    uint32_t width = mLockedBuffer->width;
+    uint8_t* jpegBuffer = mLockedBuffer->data;
 
     // First check for JPEG transport header at the end of the buffer
     uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
@@ -334,6 +418,11 @@
 
 media_status_t
 AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
+    if (mLockedBuffer == nullptr) {
+        ALOGE("%s: buffer not locked.", __FUNCTION__);
+        return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED;
+    }
+
     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
         ALOGE("Error: planeIdx %d out of bound [0,%d]",
                 planeIdx, mNumPlanes - 1);
@@ -352,140 +441,154 @@
     uint8_t* cr = nullptr;
     uint8_t* pData = nullptr;
     int bytesPerPixel = 0;
-    int32_t fmt = mBuffer->flexFormat;
+    int32_t fmt = mLockedBuffer->flexFormat;
 
     switch (fmt) {
         case HAL_PIXEL_FORMAT_YCbCr_420_888:
-            pData = (planeIdx == 0) ? mBuffer->data :
-                    (planeIdx == 1) ? mBuffer->dataCb : mBuffer->dataCr;
+            pData = (planeIdx == 0) ? mLockedBuffer->data
+                                    : (planeIdx == 1) ? mLockedBuffer->dataCb
+                                                      : mLockedBuffer->dataCr;
             // only map until last pixel
             if (planeIdx == 0) {
-                dataSize = mBuffer->stride * (mBuffer->height - 1) + mBuffer->width;
+                dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) +
+                           mLockedBuffer->width;
             } else {
-                dataSize = mBuffer->chromaStride * (mBuffer->height / 2 - 1) +
-                        mBuffer->chromaStep * (mBuffer->width / 2 - 1) + 1;
+                dataSize =
+                    mLockedBuffer->chromaStride *
+                        (mLockedBuffer->height / 2 - 1) +
+                    mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) +
+                    1;
             }
             break;
         // NV21
         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-            cr = mBuffer->data + (mBuffer->stride * mBuffer->height);
+            cr = mLockedBuffer->data +
+                 (mLockedBuffer->stride * mLockedBuffer->height);
             cb = cr + 1;
             // only map until last pixel
-            ySize = mBuffer->width * (mBuffer->height - 1) + mBuffer->width;
-            cSize = mBuffer->width * (mBuffer->height / 2 - 1) + mBuffer->width - 1;
-
-            pData = (planeIdx == 0) ? mBuffer->data :
-                    (planeIdx == 1) ? cb : cr;
+            ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) +
+                    mLockedBuffer->width;
+            cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) +
+                    mLockedBuffer->width - 1;
+            pData = (planeIdx == 0) ? mLockedBuffer->data
+                                    : (planeIdx == 1) ? cb : cr;
             dataSize = (planeIdx == 0) ? ySize : cSize;
             break;
         case HAL_PIXEL_FORMAT_YV12:
             // Y and C stride need to be 16 pixel aligned.
-            if (mBuffer->stride % 16) {
-                ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
+            if (mLockedBuffer->stride % 16) {
+                ALOGE("Stride %d is not 16 pixel aligned!",
+                      mLockedBuffer->stride);
                 return AMEDIA_ERROR_UNKNOWN;
             }
 
-            ySize = mBuffer->stride * mBuffer->height;
-            cStride = ALIGN(mBuffer->stride / 2, 16);
-            cr = mBuffer->data + ySize;
-            cSize = cStride * mBuffer->height / 2;
+            ySize = mLockedBuffer->stride * mLockedBuffer->height;
+            cStride = ALIGN(mLockedBuffer->stride / 2, 16);
+            cr = mLockedBuffer->data + ySize;
+            cSize = cStride * mLockedBuffer->height / 2;
             cb = cr + cSize;
 
-            pData = (planeIdx == 0) ? mBuffer->data :
-                    (planeIdx == 1) ? cb : cr;
+            pData = (planeIdx == 0) ? mLockedBuffer->data
+                                    : (planeIdx == 1) ? cb : cr;
             dataSize = (planeIdx == 0) ? ySize : cSize;
             break;
         case HAL_PIXEL_FORMAT_Y8:
             // Single plane, 8bpp.
 
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height;
             break;
         case HAL_PIXEL_FORMAT_Y16:
             bytesPerPixel = 2;
 
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_BLOB:
             // Used for JPEG data, height must be 1, width == size, single plane.
-            if (mBuffer->height != 1) {
-                ALOGE("Jpeg should have height value one but got %d", mBuffer->height);
+            if (mLockedBuffer->height != 1) {
+                ALOGE("Jpeg should have height value one but got %d",
+                      mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
 
-            pData = mBuffer->data;
+            pData = mLockedBuffer->data;
             dataSize = getJpegSize();
             break;
         case HAL_PIXEL_FORMAT_RAW16:
             // Single plane 16bpp bayer data.
             bytesPerPixel = 2;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
             // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
-            if (mBuffer->height != 1) {
-                ALOGE("RAW_OPAQUE should have height value one but got %d", mBuffer->height);
+            if (mLockedBuffer->height != 1) {
+                ALOGE("RAW_OPAQUE should have height value one but got %d",
+                      mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            pData = mBuffer->data;
-            dataSize = mBuffer->width;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->width;
             break;
         case HAL_PIXEL_FORMAT_RAW10:
             // Single plane 10bpp bayer data.
-            if (mBuffer->width % 4) {
-                ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+            if (mLockedBuffer->width % 4) {
+                ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->height % 2) {
-                ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+            if (mLockedBuffer->height % 2) {
+                ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->stride < (mBuffer->width * 10 / 8)) {
+            if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) {
                 ALOGE("stride (%d) should be at least %d",
-                        mBuffer->stride, mBuffer->width * 10 / 8);
+                        mLockedBuffer->stride, mLockedBuffer->width * 10 / 8);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height;
             break;
         case HAL_PIXEL_FORMAT_RAW12:
             // Single plane 10bpp bayer data.
-            if (mBuffer->width % 4) {
-                ALOGE("Width is not multiple of 4 %d", mBuffer->width);
+            if (mLockedBuffer->width % 4) {
+                ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->height % 2) {
-                ALOGE("Height is not multiple of 2 %d", mBuffer->height);
+            if (mLockedBuffer->height % 2) {
+                ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            if (mBuffer->stride < (mBuffer->width * 12 / 8)) {
+            if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) {
                 ALOGE("stride (%d) should be at least %d",
-                        mBuffer->stride, mBuffer->width * 12 / 8);
+                        mLockedBuffer->stride, mLockedBuffer->width * 12 / 8);
                 return AMEDIA_ERROR_UNKNOWN;
             }
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height;
             break;
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
             // Single plane, 32bpp.
             bytesPerPixel = 4;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_RGB_565:
             // Single plane, 16bpp.
             bytesPerPixel = 2;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize =
+                mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         case HAL_PIXEL_FORMAT_RGB_888:
             // Single plane, 24bpp.
             bytesPerPixel = 3;
-            pData = mBuffer->data;
-            dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
+            pData = mLockedBuffer->data;
+            dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel;
             break;
         default:
             ALOGE("Pixel format: 0x%x is unsupported", fmt);
@@ -602,6 +705,12 @@
                 __FUNCTION__, image, pixelStride);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
+    media_status_t ret = const_cast<AImage*>(image)->lockImage();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
+              __FUNCTION__, image, ret);
+        return ret;
+    }
     return image->getPlanePixelStride(planeIdx, pixelStride);
 }
 
@@ -614,6 +723,12 @@
                 __FUNCTION__, image, rowStride);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
+    media_status_t ret = const_cast<AImage*>(image)->lockImage();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
+              __FUNCTION__, image, ret);
+        return ret;
+    }
     return image->getPlaneRowStride(planeIdx, rowStride);
 }
 
@@ -627,5 +742,11 @@
                 __FUNCTION__, image, data, dataLength);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
+    media_status_t ret = const_cast<AImage*>(image)->lockImage();
+    if (ret != AMEDIA_OK) {
+        ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.",
+              __FUNCTION__, image, ret);
+        return ret;
+    }
     return image->getPlaneData(planeIdx, data, dataLength);
 }
diff --git a/media/ndk/NdkImagePriv.h b/media/ndk/NdkImagePriv.h
index 89d2b7c..e01dcc7 100644
--- a/media/ndk/NdkImagePriv.h
+++ b/media/ndk/NdkImagePriv.h
@@ -21,6 +21,7 @@
 #include <utils/Log.h>
 #include <utils/StrongPointer.h>
 
+#include <gui/BufferItem.h>
 #include <gui/CpuConsumer.h>
 
 #include "NdkImageReaderPriv.h"
@@ -31,9 +32,9 @@
 
 // TODO: this only supports ImageReader
 struct AImage {
-    AImage(AImageReader* reader, int32_t format,
-            CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
-            int32_t width, int32_t height, int32_t numPlanes);
+    AImage(AImageReader* reader, int32_t format, uint64_t usage,
+           BufferItem* buffer, int64_t timestamp,
+           int32_t width, int32_t height, int32_t numPlanes);
 
     // free all resources while keeping object alive. Caller must obtain reader lock
     void close();
@@ -54,6 +55,9 @@
     media_status_t getNumPlanes(/*out*/int32_t* numPlanes) const;
     media_status_t getTimestamp(/*out*/int64_t* timestamp) const;
 
+    media_status_t lockImage();
+    media_status_t unlockImageIfLocked(/*out*/int* fenceFd);
+
     media_status_t getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const;
     media_status_t getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const;
     media_status_t getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const;
@@ -69,7 +73,9 @@
     // When reader is close, AImage will only accept close API call
     wp<AImageReader>           mReader;
     const int32_t              mFormat;
-    CpuConsumer::LockedBuffer* mBuffer;
+    const uint64_t             mUsage;  // AHARDWAREBUFFER_USAGE0* flags.
+    BufferItem*                mBuffer;
+    std::unique_ptr<CpuConsumer::LockedBuffer> mLockedBuffer;
     const int64_t              mTimestamp;
     const int32_t              mWidth;
     const int32_t              mHeight;
diff --git a/media/ndk/NdkImageReader.cpp b/media/ndk/NdkImageReader.cpp
index ab3829e..e580dae 100644
--- a/media/ndk/NdkImageReader.cpp
+++ b/media/ndk/NdkImageReader.cpp
@@ -24,7 +24,9 @@
 
 #include <cutils/atomic.h>
 #include <utils/Log.h>
+#include <android_media_Utils.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
 
 using namespace android;
 
@@ -36,6 +38,7 @@
     }
 }
 
+const int32_t AImageReader::kDefaultUsage = AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN;
 const char* AImageReader::kCallbackFpKey = "Callback";
 const char* AImageReader::kContextKey    = "Context";
 
@@ -151,10 +154,18 @@
     }
 }
 
-AImageReader::AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages) :
-        mWidth(width), mHeight(height), mFormat(format), mMaxImages(maxImages),
-        mNumPlanes(getNumPlanesForFormat(format)),
-        mFrameListener(new FrameListener(this)) {}
+AImageReader::AImageReader(int32_t width,
+                           int32_t height,
+                           int32_t format,
+                           uint64_t usage,
+                           int32_t maxImages)
+    : mWidth(width),
+      mHeight(height),
+      mFormat(format),
+      mUsage(usage),
+      mMaxImages(maxImages),
+      mNumPlanes(getNumPlanesForFormat(format)),
+      mFrameListener(new FrameListener(this)) {}
 
 media_status_t
 AImageReader::init() {
@@ -162,42 +173,44 @@
     mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
     mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
 
+    uint64_t producerUsage;
+    uint64_t consumerUsage;
+    android_hardware_HardwareBuffer_convertToGrallocUsageBits(
+            &producerUsage, &consumerUsage, mUsage, 0);
+
     sp<IGraphicBufferProducer> gbProducer;
     sp<IGraphicBufferConsumer> gbConsumer;
     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
 
-    sp<CpuConsumer> cpuConsumer;
-    String8 consumerName = String8::format("ImageReader-%dx%df%xm%d-%d-%d",
-            mWidth, mHeight, mFormat, mMaxImages, getpid(),
-            createProcessUniqueId());
+    String8 consumerName = String8::format(
+            "ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d", mWidth, mHeight, mFormat, mUsage,
+            mMaxImages, getpid(), createProcessUniqueId());
 
-    cpuConsumer = new CpuConsumer(gbConsumer, mMaxImages, /*controlledByApp*/true);
-    if (cpuConsumer == nullptr) {
-        ALOGE("Failed to allocate CpuConsumer");
+    mBufferItemConsumer =
+            new BufferItemConsumer(gbConsumer, consumerUsage, mMaxImages, /*controlledByApp*/ true);
+    if (mBufferItemConsumer == nullptr) {
+        ALOGE("Failed to allocate BufferItemConsumer");
         return AMEDIA_ERROR_UNKNOWN;
     }
 
-    mCpuConsumer = cpuConsumer;
-    mCpuConsumer->setName(consumerName);
     mProducer = gbProducer;
-
-    sp<ConsumerBase> consumer = cpuConsumer;
-    consumer->setFrameAvailableListener(mFrameListener);
+    mBufferItemConsumer->setName(consumerName);
+    mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
 
     status_t res;
-    res = cpuConsumer->setDefaultBufferSize(mWidth, mHeight);
+    res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
     if (res != OK) {
-        ALOGE("Failed to set CpuConsumer buffer size");
+        ALOGE("Failed to set BufferItemConsumer buffer size");
         return AMEDIA_ERROR_UNKNOWN;
     }
-    res = cpuConsumer->setDefaultBufferFormat(mHalFormat);
+    res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
     if (res != OK) {
-        ALOGE("Failed to set CpuConsumer buffer format");
+        ALOGE("Failed to set BufferItemConsumer buffer format");
         return AMEDIA_ERROR_UNKNOWN;
     }
-    res = cpuConsumer->setDefaultBufferDataSpace(mHalDataSpace);
+    res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
     if (res != OK) {
-        ALOGE("Failed to set CpuConsumer buffer dataSpace");
+        ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
         return AMEDIA_ERROR_UNKNOWN;
     }
 
@@ -209,7 +222,7 @@
     mWindow = static_cast<ANativeWindow*>(mSurface.get());
 
     for (int i = 0; i < mMaxImages; i++) {
-        CpuConsumer::LockedBuffer* buffer = new CpuConsumer::LockedBuffer;
+        BufferItem* buffer = new BufferItem;
         mBuffers.push_back(buffer);
     }
 
@@ -248,133 +261,136 @@
         image->close();
     }
 
-    // Delete LockedBuffers
+    // Delete Buffer Items
     for (auto it = mBuffers.begin();
               it != mBuffers.end(); it++) {
         delete *it;
     }
 
-    if (mCpuConsumer != nullptr) {
-        mCpuConsumer->abandon();
-        mCpuConsumer->setFrameAvailableListener(nullptr);
+    if (mBufferItemConsumer != nullptr) {
+        mBufferItemConsumer->abandon();
+        mBufferItemConsumer->setFrameAvailableListener(nullptr);
     }
 }
 
 media_status_t
-AImageReader::acquireCpuConsumerImageLocked(/*out*/AImage** image) {
+AImageReader::acquireImageLocked(/*out*/AImage** image) {
     *image = nullptr;
-    CpuConsumer::LockedBuffer* buffer = getLockedBufferLocked();
+    BufferItem* buffer = getBufferItemLocked();
     if (buffer == nullptr) {
         ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
             " maxImages buffers");
         return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
     }
 
-    status_t res = mCpuConsumer->lockNextBuffer(buffer);
+    status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0);
     if (res != NO_ERROR) {
-        returnLockedBufferLocked(buffer);
-        if (res != BAD_VALUE /*no buffers*/) {
-            if (res == NOT_ENOUGH_DATA) {
+        returnBufferItemLocked(buffer);
+        if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
+            if (res == INVALID_OPERATION) {
                 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
             } else {
-                ALOGE("%s Fail to lockNextBuffer with error: %d ",
-                      __FUNCTION__, res);
+                ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
+                      __FUNCTION__, strerror(-res), res);
                 return AMEDIA_ERROR_UNKNOWN;
             }
         }
         return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
     }
 
-    if (buffer->flexFormat == HAL_PIXEL_FORMAT_YCrCb_420_SP) {
-        ALOGE("NV21 format is not supported by AImageReader");
-        return AMEDIA_ERROR_UNSUPPORTED;
-    }
+    const int bufferWidth = getBufferWidth(buffer);
+    const int bufferHeight = getBufferHeight(buffer);
+    const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
 
-    // Check if the left-top corner of the crop rect is origin, we currently assume this point is
-    // zero, will revist this once this assumption turns out problematic.
-    Point lt = buffer->crop.leftTop();
-    if (lt.x != 0 || lt.y != 0) {
-        ALOGE("crop left top corner [%d, %d] need to be at origin", lt.x, lt.y);
-        return AMEDIA_ERROR_UNKNOWN;
-    }
+    const int readerWidth = mWidth;
+    const int readerHeight = mHeight;
+    const int readerFmt = mHalFormat;
 
-    // Check if the producer buffer configurations match what ImageReader configured.
-    int outputWidth = getBufferWidth(buffer);
-    int outputHeight = getBufferHeight(buffer);
-
-    int readerFmt = mHalFormat;
-    int readerWidth = mWidth;
-    int readerHeight = mHeight;
-
-    if ((buffer->format != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
-            (readerWidth != outputWidth || readerHeight != outputHeight)) {
-        ALOGW("%s: Producer buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
-                __FUNCTION__, outputWidth, outputHeight, readerWidth, readerHeight);
-    }
-
-    int bufFmt = buffer->format;
-    if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-        bufFmt = buffer->flexFormat;
-    }
-
-    if (readerFmt != bufFmt) {
-        if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && (bufFmt ==
-                HAL_PIXEL_FORMAT_YCrCb_420_SP || bufFmt == HAL_PIXEL_FORMAT_YV12)) {
-            // Special casing for when producer switches to a format compatible with flexible YUV
-            // (HAL_PIXEL_FORMAT_YCbCr_420_888).
-            mHalFormat = bufFmt;
-            ALOGD("%s: Overriding buffer format YUV_420_888 to %x.", __FUNCTION__, bufFmt);
-        } else {
-            // Return the buffer to the queue.
-            mCpuConsumer->unlockBuffer(*buffer);
-            returnLockedBufferLocked(buffer);
-
-            ALOGE("Producer output buffer format: 0x%x, ImageReader configured format: 0x%x",
-                    buffer->format, readerFmt);
-
+    // Check if the producer buffer configurations match what AImageReader configured. Add some
+    // extra checks for non-opaque formats.
+    if (!isFormatOpaque(readerFmt)) {
+        // Check if the left-top corner of the crop rect is origin, we currently assume this point
+        // is zero, will revisit this once this assumption turns out problematic.
+        Point lt = buffer->mCrop.leftTop();
+        if (lt.x != 0 || lt.y != 0) {
+            ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
             return AMEDIA_ERROR_UNKNOWN;
         }
+
+        // Check if the producer buffer configurations match what ImageReader configured.
+        if ((bufferFmt != HAL_PIXEL_FORMAT_BLOB) && (readerFmt != HAL_PIXEL_FORMAT_BLOB) &&
+                (readerWidth != bufferWidth || readerHeight != bufferHeight)) {
+            ALOGW("%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
+                    __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
+        }
+
+        if (readerFmt != bufferFmt) {
+            if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
+                // Special casing for when producer switches to a format compatible with flexible
+                // YUV.
+                mHalFormat = bufferFmt;
+                ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
+            } else {
+                // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
+                // used anywhere yet.
+                mBufferItemConsumer->releaseBuffer(*buffer);
+                returnBufferItemLocked(buffer);
+
+                ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
+                        __FUNCTION__, bufferFmt, readerFmt);
+
+                return AMEDIA_ERROR_UNKNOWN;
+            }
+        }
     }
 
     if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
-        *image = new AImage(this, mFormat, buffer, buffer->timestamp,
+        *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
                             readerWidth, readerHeight, mNumPlanes);
     } else {
-        *image = new AImage(this, mFormat, buffer, buffer->timestamp,
-                            outputWidth, outputHeight, mNumPlanes);
+        *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
+                            bufferWidth, bufferHeight, mNumPlanes);
     }
     mAcquiredImages.push_back(*image);
     return AMEDIA_OK;
 }
 
-CpuConsumer::LockedBuffer*
-AImageReader::getLockedBufferLocked() {
+BufferItem*
+AImageReader::getBufferItemLocked() {
     if (mBuffers.empty()) {
         return nullptr;
     }
-    // Return a LockedBuffer pointer and remove it from the list
+    // Return a BufferItem pointer and remove it from the list
     auto it = mBuffers.begin();
-    CpuConsumer::LockedBuffer* buffer = *it;
+    BufferItem* buffer = *it;
     mBuffers.erase(it);
     return buffer;
 }
 
 void
-AImageReader::returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer) {
+AImageReader::returnBufferItemLocked(BufferItem* buffer) {
     mBuffers.push_back(buffer);
 }
 
 void
 AImageReader::releaseImageLocked(AImage* image) {
-    CpuConsumer::LockedBuffer* buffer = image->mBuffer;
+    BufferItem* buffer = image->mBuffer;
     if (buffer == nullptr) {
         // This should not happen, but is not fatal
         ALOGW("AImage %p has no buffer!", image);
         return;
     }
 
-    mCpuConsumer->unlockBuffer(*buffer);
-    returnLockedBufferLocked(buffer);
+    int fenceFd = -1;
+    media_status_t ret = image->unlockImageIfLocked(&fenceFd);
+    if (ret < 0) {
+        ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
+        return;
+    }
+
+    sp<Fence> releaseFence = fenceFd > 0 ? new Fence(fenceFd) : Fence::NO_FENCE;
+    mBufferItemConsumer->releaseBuffer(*buffer, releaseFence);
+    returnBufferItemLocked(buffer);
     image->mBuffer = nullptr;
 
     bool found = false;
@@ -395,29 +411,31 @@
 }
 
 int
-AImageReader::getBufferWidth(CpuConsumer::LockedBuffer* buffer) {
-    if (buffer == nullptr) return -1;
+AImageReader::getBufferWidth(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
 
-    if (!buffer->crop.isEmpty()) {
-        return buffer->crop.getWidth();
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getWidth();
     }
-    return buffer->width;
+
+    return buffer->mGraphicBuffer->getWidth();
 }
 
 int
-AImageReader::getBufferHeight(CpuConsumer::LockedBuffer* buffer) {
-    if (buffer == nullptr) return -1;
+AImageReader::getBufferHeight(BufferItem* buffer) {
+    if (buffer == NULL) return -1;
 
-    if (!buffer->crop.isEmpty()) {
-        return buffer->crop.getHeight();
+    if (!buffer->mCrop.isEmpty()) {
+        return buffer->mCrop.getHeight();
     }
-    return buffer->height;
+
+    return buffer->mGraphicBuffer->getHeight();
 }
 
 media_status_t
 AImageReader::acquireNextImage(/*out*/AImage** image) {
     Mutex::Autolock _l(mLock);
-    return acquireCpuConsumerImageLocked(image);
+    return acquireImageLocked(image);
 }
 
 media_status_t
@@ -429,12 +447,12 @@
     *image = nullptr;
     AImage* prevImage = nullptr;
     AImage* nextImage = nullptr;
-    media_status_t ret = acquireCpuConsumerImageLocked(&prevImage);
+    media_status_t ret = acquireImageLocked(&prevImage);
     if (prevImage == nullptr) {
         return ret;
     }
     for (;;) {
-        ret = acquireCpuConsumerImageLocked(&nextImage);
+        ret = acquireImageLocked(&nextImage);
         if (nextImage == nullptr) {
             *image = prevImage;
             return AMEDIA_OK;
@@ -464,6 +482,12 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
+    if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+        ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
+              __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
+        return AMEDIA_ERROR_INVALID_PARAMETER;
+    }
+
     if (!AImageReader::isSupportedFormat(format)) {
         ALOGE("%s: format %d is not supported by AImageReader",
                 __FUNCTION__, format);
@@ -475,8 +499,10 @@
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
 
-    //*reader = new AImageReader(width, height, format, maxImages);
-    AImageReader* tmpReader = new AImageReader(width, height, format, maxImages);
+    // Set consumer usage to AHARDWAREBUFFER_USAGE0_CPU_READ_OFTEN by default so that
+    // AImageReader_new behaves as if it's backed by CpuConsumer.
+    AImageReader* tmpReader = new AImageReader(
+        width, height, format, AImageReader::kDefaultUsage, maxImages);
     if (tmpReader == nullptr) {
         ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
         return AMEDIA_ERROR_UNKNOWN;
@@ -565,7 +591,7 @@
 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
     ALOGV("%s", __FUNCTION__);
     if (reader == nullptr || image == nullptr) {
-        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+        ALOGE("%s: invalid argument. reader %p, image %p",
                 __FUNCTION__, reader, image);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
@@ -576,7 +602,7 @@
 media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
     ALOGV("%s", __FUNCTION__);
     if (reader == nullptr || image == nullptr) {
-        ALOGE("%s: invalid argument. reader %p, maxImages %p",
+        ALOGE("%s: invalid argument. reader %p, image %p",
                 __FUNCTION__, reader, image);
         return AMEDIA_ERROR_INVALID_PARAMETER;
     }
diff --git a/media/ndk/NdkImageReaderPriv.h b/media/ndk/NdkImageReaderPriv.h
index 8b540fa..8becb1d 100644
--- a/media/ndk/NdkImageReaderPriv.h
+++ b/media/ndk/NdkImageReaderPriv.h
@@ -25,7 +25,8 @@
 #include <utils/Mutex.h>
 #include <utils/StrongPointer.h>
 
-#include <gui/CpuConsumer.h>
+#include <gui/BufferItem.h>
+#include <gui/BufferItemConsumer.h>
 #include <gui/Surface.h>
 
 #include <media/stagefright/foundation/ALooper.h>
@@ -48,11 +49,16 @@
 
 struct AImageReader : public RefBase {
   public:
+    static const int32_t kDefaultUsage;
 
     static bool isSupportedFormat(int32_t format);
     static int getNumPlanesForFormat(int32_t format);
 
-    AImageReader(int32_t width, int32_t height, int32_t format, int32_t maxImages);
+    AImageReader(int32_t width,
+                 int32_t height,
+                 int32_t format,
+                 uint64_t usage,
+                 int32_t maxImages);
     ~AImageReader();
 
     // Inintialize AImageReader, uninitialized or failed to initialize AImageReader
@@ -68,22 +74,24 @@
     int32_t        getWidth()     const { return mWidth; };
     int32_t        getHeight()    const { return mHeight; };
     int32_t        getFormat()    const { return mFormat; };
+    uint64_t       getUsage()     const { return mUsage; };
     int32_t        getMaxImages() const { return mMaxImages; };
 
-
   private:
 
     friend struct AImage; // for grabing reader lock
 
-    media_status_t acquireCpuConsumerImageLocked(/*out*/AImage** image);
-    CpuConsumer::LockedBuffer* getLockedBufferLocked();
-    void returnLockedBufferLocked(CpuConsumer::LockedBuffer* buffer);
+    BufferItem* getBufferItemLocked();
+    void returnBufferItemLocked(BufferItem* buffer);
+
+    // Called by AImageReader_acquireXXX to acquire a Buffer and setup AImage.
+    media_status_t acquireImageLocked(/*out*/AImage** image);
 
     // Called by AImage to close image
     void releaseImageLocked(AImage* image);
 
-    static int getBufferWidth(CpuConsumer::LockedBuffer* buffer);
-    static int getBufferHeight(CpuConsumer::LockedBuffer* buffer);
+    static int getBufferWidth(BufferItem* buffer);
+    static int getBufferHeight(BufferItem* buffer);
 
     media_status_t setImageListenerLocked(AImageReader_ImageListener* listener);
 
@@ -102,12 +110,15 @@
     };
     sp<CallbackHandler> mHandler;
     sp<ALooper>         mCbLooper; // Looper thread where callbacks actually happen on
+    List<BufferItem*>   mBuffers;
 
-    List<CpuConsumer::LockedBuffer*> mBuffers;
     const int32_t mWidth;
     const int32_t mHeight;
     const int32_t mFormat;
+    const uint64_t mUsage;
     const int32_t mMaxImages;
+
+    // TODO(jwcai) Seems completely unused in AImageReader class.
     const int32_t mNumPlanes;
 
     struct FrameListener : public ConsumerBase::FrameAvailableListener {
@@ -130,7 +141,7 @@
 
     sp<IGraphicBufferProducer> mProducer;
     sp<Surface>                mSurface;
-    sp<CpuConsumer>            mCpuConsumer;
+    sp<BufferItemConsumer>     mBufferItemConsumer;
     sp<ANativeWindow>          mWindow;
 
     List<AImage*>              mAcquiredImages;