Home | History | Annotate | Download | only in ndk
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <inttypes.h>
     18 
     19 //#define LOG_NDEBUG 0
     20 #define LOG_TAG "NdkImageReader"
     21 
     22 #include "NdkImagePriv.h"
     23 #include "NdkImageReaderPriv.h"
     24 
     25 #include <cutils/atomic.h>
     26 #include <utils/Log.h>
     27 #include <android_media_Utils.h>
     28 #include <android_runtime/android_view_Surface.h>
     29 #include <android_runtime/android_hardware_HardwareBuffer.h>
     30 #include <grallocusage/GrallocUsageConversion.h>
     31 
     32 using namespace android;
     33 
     34 namespace {
     35     // Get an ID that's unique within this process.
     36     static int32_t createProcessUniqueId() {
     37         static volatile int32_t globalCounter = 0;
     38         return android_atomic_inc(&globalCounter);
     39     }
     40 }
     41 
     42 const char* AImageReader::kCallbackFpKey = "Callback";
     43 const char* AImageReader::kContextKey    = "Context";
     44 const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
     45 
     46 bool
     47 AImageReader::isSupportedFormatAndUsage(int32_t format, uint64_t usage) {
     48     // Check whether usage has either CPU_READ_OFTEN or CPU_READ set. Note that check against
     49     // AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN (0x6) is sufficient as it implies
     50     // AHARDWAREBUFFER_USAGE_CPU_READ (0x2).
     51     bool hasCpuUsage = usage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
     52     switch (format) {
     53         case AIMAGE_FORMAT_RGBA_8888:
     54         case AIMAGE_FORMAT_RGBX_8888:
     55         case AIMAGE_FORMAT_RGB_888:
     56         case AIMAGE_FORMAT_RGB_565:
     57         case AIMAGE_FORMAT_RGBA_FP16:
     58         case AIMAGE_FORMAT_YUV_420_888:
     59         case AIMAGE_FORMAT_JPEG:
     60         case AIMAGE_FORMAT_RAW16:
     61         case AIMAGE_FORMAT_RAW_PRIVATE:
     62         case AIMAGE_FORMAT_RAW10:
     63         case AIMAGE_FORMAT_RAW12:
     64         case AIMAGE_FORMAT_DEPTH16:
     65         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
     66             return true;
     67         case AIMAGE_FORMAT_PRIVATE:
     68             // For private format, cpu usage is prohibited.
     69             return !hasCpuUsage;
     70         default:
     71             return false;
     72     }
     73 }
     74 
     75 int
     76 AImageReader::getNumPlanesForFormat(int32_t format) {
     77     switch (format) {
     78         case AIMAGE_FORMAT_YUV_420_888:
     79             return 3;
     80         case AIMAGE_FORMAT_RGBA_8888:
     81         case AIMAGE_FORMAT_RGBX_8888:
     82         case AIMAGE_FORMAT_RGB_888:
     83         case AIMAGE_FORMAT_RGB_565:
     84         case AIMAGE_FORMAT_RGBA_FP16:
     85         case AIMAGE_FORMAT_JPEG:
     86         case AIMAGE_FORMAT_RAW16:
     87         case AIMAGE_FORMAT_RAW_PRIVATE:
     88         case AIMAGE_FORMAT_RAW10:
     89         case AIMAGE_FORMAT_RAW12:
     90         case AIMAGE_FORMAT_DEPTH16:
     91         case AIMAGE_FORMAT_DEPTH_POINT_CLOUD:
     92             return 1;
     93         case AIMAGE_FORMAT_PRIVATE:
     94             return 0;
     95         default:
     96             return -1;
     97     }
     98 }
     99 
    100 void
    101 AImageReader::FrameListener::onFrameAvailable(const BufferItem& /*item*/) {
    102     Mutex::Autolock _l(mLock);
    103     sp<AImageReader> reader = mReader.promote();
    104     if (reader == nullptr) {
    105         ALOGW("A frame is available after AImageReader closed!");
    106         return; // reader has been closed
    107     }
    108     if (mListener.onImageAvailable == nullptr) {
    109         return; // No callback registered
    110     }
    111 
    112     sp<AMessage> msg = new AMessage(AImageReader::kWhatImageAvailable, reader->mHandler);
    113     msg->setPointer(AImageReader::kCallbackFpKey, (void *) mListener.onImageAvailable);
    114     msg->setPointer(AImageReader::kContextKey, mListener.context);
    115     msg->post();
    116 }
    117 
    118 media_status_t
    119 AImageReader::FrameListener::setImageListener(AImageReader_ImageListener* listener) {
    120     Mutex::Autolock _l(mLock);
    121     if (listener == nullptr) {
    122         mListener.context = nullptr;
    123         mListener.onImageAvailable = nullptr;
    124     } else {
    125         mListener = *listener;
    126     }
    127     return AMEDIA_OK;
    128 }
    129 
    130 void
    131 AImageReader::BufferRemovedListener::onBufferFreed(const wp<GraphicBuffer>& graphicBuffer) {
    132     Mutex::Autolock _l(mLock);
    133     sp<AImageReader> reader = mReader.promote();
    134     if (reader == nullptr) {
    135         ALOGW("A frame is available after AImageReader closed!");
    136         return; // reader has been closed
    137     }
    138     if (mListener.onBufferRemoved == nullptr) {
    139         return; // No callback registered
    140     }
    141 
    142     sp<GraphicBuffer> gBuffer = graphicBuffer.promote();
    143     if (gBuffer == nullptr) {
    144         ALOGW("A buffer being freed has gone away!");
    145         return; // buffer is already destroyed
    146     }
    147 
    148     sp<AMessage> msg = new AMessage(AImageReader::kWhatBufferRemoved, reader->mHandler);
    149     msg->setPointer(
    150         AImageReader::kCallbackFpKey, (void*) mListener.onBufferRemoved);
    151     msg->setPointer(AImageReader::kContextKey, mListener.context);
    152     msg->setObject(AImageReader::kGraphicBufferKey, gBuffer);
    153     msg->post();
    154 }
    155 
    156 media_status_t
    157 AImageReader::BufferRemovedListener::setBufferRemovedListener(
    158     AImageReader_BufferRemovedListener* listener) {
    159     Mutex::Autolock _l(mLock);
    160     if (listener == nullptr) {
    161         mListener.context = nullptr;
    162         mListener.onBufferRemoved = nullptr;
    163     } else {
    164         mListener = *listener;
    165     }
    166     return AMEDIA_OK;
    167 }
    168 
    169 media_status_t
    170 AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
    171     return mFrameListener->setImageListener(listener);
    172 }
    173 
    174 media_status_t
    175 AImageReader::setImageListener(AImageReader_ImageListener* listener) {
    176     Mutex::Autolock _l(mLock);
    177     return setImageListenerLocked(listener);
    178 }
    179 
    180 media_status_t
    181 AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
    182     return mBufferRemovedListener->setBufferRemovedListener(listener);
    183 }
    184 
    185 media_status_t
    186 AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
    187     Mutex::Autolock _l(mLock);
    188     return setBufferRemovedListenerLocked(listener);
    189 }
    190 
    191 void AImageReader::CallbackHandler::onMessageReceived(
    192         const sp<AMessage> &msg) {
    193     switch (msg->what()) {
    194         case kWhatBufferRemoved:
    195         {
    196             AImageReader_BufferRemovedCallback onBufferRemoved;
    197             void* context;
    198             bool found = msg->findPointer(kCallbackFpKey, (void**) &onBufferRemoved);
    199             if (!found || onBufferRemoved == nullptr) {
    200                 ALOGE("%s: Cannot find onBufferRemoved callback fp!", __FUNCTION__);
    201                 return;
    202             }
    203             found = msg->findPointer(kContextKey, &context);
    204             if (!found) {
    205                 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
    206                 return;
    207             }
    208             sp<RefBase> bufferToFree;
    209             found = msg->findObject(kGraphicBufferKey, &bufferToFree);
    210             if (!found || bufferToFree == nullptr) {
    211                 ALOGE("%s: Cannot find the buffer to free!", __FUNCTION__);
    212                 return;
    213             }
    214 
    215             // TODO(jwcai) Someone from Android graphics team stating this should just be a
    216             // static_cast.
    217             AHardwareBuffer* outBuffer = reinterpret_cast<AHardwareBuffer*>(bufferToFree.get());
    218 
    219             // At this point, bufferToFree holds the last reference to the GraphicBuffer owned by
    220             // this AImageReader, and the reference will be gone once this function returns.
    221             (*onBufferRemoved)(context, mReader, outBuffer);
    222             break;
    223         }
    224         case kWhatImageAvailable:
    225         {
    226             AImageReader_ImageCallback onImageAvailable;
    227             void* context;
    228             bool found = msg->findPointer(kCallbackFpKey, (void**) &onImageAvailable);
    229             if (!found || onImageAvailable == nullptr) {
    230                 ALOGE("%s: Cannot find onImageAvailable callback fp!", __FUNCTION__);
    231                 return;
    232             }
    233             found = msg->findPointer(kContextKey, &context);
    234             if (!found) {
    235                 ALOGE("%s: Cannot find callback context!", __FUNCTION__);
    236                 return;
    237             }
    238             (*onImageAvailable)(context, mReader);
    239             break;
    240         }
    241         default:
    242             ALOGE("%s: unknown message type %d", __FUNCTION__, msg->what());
    243             break;
    244     }
    245 }
    246 
    247 AImageReader::AImageReader(int32_t width,
    248                            int32_t height,
    249                            int32_t format,
    250                            uint64_t usage,
    251                            int32_t maxImages)
    252     : mWidth(width),
    253       mHeight(height),
    254       mFormat(format),
    255       mUsage(usage),
    256       mMaxImages(maxImages),
    257       mNumPlanes(getNumPlanesForFormat(format)),
    258       mFrameListener(new FrameListener(this)),
    259       mBufferRemovedListener(new BufferRemovedListener(this)) {}
    260 
    261 media_status_t
    262 AImageReader::init() {
    263     PublicFormat publicFormat = static_cast<PublicFormat>(mFormat);
    264     mHalFormat = android_view_Surface_mapPublicFormatToHalFormat(publicFormat);
    265     mHalDataSpace = android_view_Surface_mapPublicFormatToHalDataspace(publicFormat);
    266     mHalUsage = android_hardware_HardwareBuffer_convertToGrallocUsageBits(mUsage);
    267 
    268     sp<IGraphicBufferProducer> gbProducer;
    269     sp<IGraphicBufferConsumer> gbConsumer;
    270     BufferQueue::createBufferQueue(&gbProducer, &gbConsumer);
    271 
    272     String8 consumerName = String8::format("ImageReader-%dx%df%xu%" PRIu64 "m%d-%d-%d",
    273             mWidth, mHeight, mFormat, mUsage, mMaxImages, getpid(),
    274             createProcessUniqueId());
    275 
    276     mBufferItemConsumer =
    277             new BufferItemConsumer(gbConsumer, mHalUsage, mMaxImages, /*controlledByApp*/ true);
    278     if (mBufferItemConsumer == nullptr) {
    279         ALOGE("Failed to allocate BufferItemConsumer");
    280         return AMEDIA_ERROR_UNKNOWN;
    281     }
    282 
    283     mProducer = gbProducer;
    284     mBufferItemConsumer->setName(consumerName);
    285     mBufferItemConsumer->setFrameAvailableListener(mFrameListener);
    286     mBufferItemConsumer->setBufferFreedListener(mBufferRemovedListener);
    287 
    288     status_t res;
    289     res = mBufferItemConsumer->setDefaultBufferSize(mWidth, mHeight);
    290     if (res != OK) {
    291         ALOGE("Failed to set BufferItemConsumer buffer size");
    292         return AMEDIA_ERROR_UNKNOWN;
    293     }
    294     res = mBufferItemConsumer->setDefaultBufferFormat(mHalFormat);
    295     if (res != OK) {
    296         ALOGE("Failed to set BufferItemConsumer buffer format");
    297         return AMEDIA_ERROR_UNKNOWN;
    298     }
    299     res = mBufferItemConsumer->setDefaultBufferDataSpace(mHalDataSpace);
    300     if (res != OK) {
    301         ALOGE("Failed to set BufferItemConsumer buffer dataSpace");
    302         return AMEDIA_ERROR_UNKNOWN;
    303     }
    304 
    305     mSurface = new Surface(mProducer, /*controlledByApp*/true);
    306     if (mSurface == nullptr) {
    307         ALOGE("Failed to create surface");
    308         return AMEDIA_ERROR_UNKNOWN;
    309     }
    310     mWindow = static_cast<ANativeWindow*>(mSurface.get());
    311 
    312     for (int i = 0; i < mMaxImages; i++) {
    313         BufferItem* buffer = new BufferItem;
    314         mBuffers.push_back(buffer);
    315     }
    316 
    317     mCbLooper = new ALooper;
    318     mCbLooper->setName(consumerName.string());
    319     res = mCbLooper->start(
    320             /*runOnCallingThread*/false,
    321             /*canCallJava*/       true,
    322             PRIORITY_DEFAULT);
    323     if (res != OK) {
    324         ALOGE("Failed to start the looper");
    325         return AMEDIA_ERROR_UNKNOWN;
    326     }
    327     mHandler = new CallbackHandler(this);
    328     mCbLooper->registerHandler(mHandler);
    329 
    330     return AMEDIA_OK;
    331 }
    332 
    333 AImageReader::~AImageReader() {
    334     Mutex::Autolock _l(mLock);
    335     AImageReader_ImageListener nullListener = {nullptr, nullptr};
    336     setImageListenerLocked(&nullListener);
    337 
    338     AImageReader_BufferRemovedListener nullBufferRemovedListener = {nullptr, nullptr};
    339     setBufferRemovedListenerLocked(&nullBufferRemovedListener);
    340 
    341     if (mCbLooper != nullptr) {
    342         mCbLooper->unregisterHandler(mHandler->id());
    343         mCbLooper->stop();
    344     }
    345     mCbLooper.clear();
    346     mHandler.clear();
    347 
    348     // Close all previously acquired images
    349     for (auto it = mAcquiredImages.begin();
    350               it != mAcquiredImages.end(); it++) {
    351         AImage* image = *it;
    352         Mutex::Autolock _l(image->mLock);
    353         releaseImageLocked(image, /*releaseFenceFd*/-1);
    354     }
    355 
    356     // Delete Buffer Items
    357     for (auto it = mBuffers.begin();
    358               it != mBuffers.end(); it++) {
    359         delete *it;
    360     }
    361 
    362     if (mBufferItemConsumer != nullptr) {
    363         mBufferItemConsumer->abandon();
    364         mBufferItemConsumer->setFrameAvailableListener(nullptr);
    365     }
    366 }
    367 
    368 media_status_t
    369 AImageReader::acquireImageLocked(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
    370     *image = nullptr;
    371     BufferItem* buffer = getBufferItemLocked();
    372     if (buffer == nullptr) {
    373         ALOGW("Unable to acquire a lockedBuffer, very likely client tries to lock more than"
    374             " maxImages buffers");
    375         return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
    376     }
    377 
    378     // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
    379     bool waitForFence = acquireFenceFd == nullptr;
    380     status_t res = mBufferItemConsumer->acquireBuffer(buffer, 0, waitForFence);
    381 
    382     if (res != NO_ERROR) {
    383         returnBufferItemLocked(buffer);
    384         if (res != BufferQueue::NO_BUFFER_AVAILABLE) {
    385             if (res == INVALID_OPERATION) {
    386                 return AMEDIA_IMGREADER_MAX_IMAGES_ACQUIRED;
    387             } else {
    388                 ALOGE("%s: Acquire image failed with some unknown error: %s (%d)",
    389                       __FUNCTION__, strerror(-res), res);
    390                 return AMEDIA_ERROR_UNKNOWN;
    391             }
    392         }
    393         return AMEDIA_IMGREADER_NO_BUFFER_AVAILABLE;
    394     }
    395 
    396     const int bufferWidth = getBufferWidth(buffer);
    397     const int bufferHeight = getBufferHeight(buffer);
    398     const int bufferFmt = buffer->mGraphicBuffer->getPixelFormat();
    399     const int bufferUsage = buffer->mGraphicBuffer->getUsage();
    400 
    401     const int readerWidth = mWidth;
    402     const int readerHeight = mHeight;
    403     const int readerFmt = mHalFormat;
    404     const int readerUsage = mHalUsage;
    405 
    406     // Check if the producer buffer configurations match what AImageReader configured. Add some
    407     // extra checks for non-opaque formats.
    408     if (!isFormatOpaque(readerFmt)) {
    409         // Check if the left-top corner of the crop rect is origin, we currently assume this point
    410         // is zero, will revisit this once this assumption turns out problematic.
    411         Point lt = buffer->mCrop.leftTop();
    412         if (lt.x != 0 || lt.y != 0) {
    413             ALOGE("Crop left top corner [%d, %d] not at origin", lt.x, lt.y);
    414             return AMEDIA_ERROR_UNKNOWN;
    415         }
    416 
    417         // Check if the producer buffer configurations match what ImageReader configured.
    418         ALOGV_IF(readerWidth != bufferWidth || readerHeight != bufferHeight,
    419                 "%s: Buffer size: %dx%d, doesn't match AImageReader configured size: %dx%d",
    420                 __FUNCTION__, bufferWidth, bufferHeight, readerWidth, readerHeight);
    421 
    422         // Check if the buffer usage is a super set of reader's usage bits, aka all usage bits that
    423         // ImageReader requested has been supported from the producer side.
    424         ALOGD_IF((readerUsage | bufferUsage) != bufferUsage,
    425                 "%s: Producer buffer usage: %x, doesn't cover all usage bits AImageReader "
    426                 "configured: %x",
    427                 __FUNCTION__, bufferUsage, readerUsage);
    428 
    429         if (readerFmt != bufferFmt) {
    430             if (readerFmt == HAL_PIXEL_FORMAT_YCbCr_420_888 && isPossiblyYUV(bufferFmt)) {
    431                 // Special casing for when producer switches to a format compatible with flexible
    432                 // YUV.
    433                 mHalFormat = bufferFmt;
    434                 ALOGD("%s: Overriding buffer format YUV_420_888 to 0x%x.", __FUNCTION__, bufferFmt);
    435             } else {
    436                 // Return the buffer to the queue. No need to provide fence, as this buffer wasn't
    437                 // used anywhere yet.
    438                 mBufferItemConsumer->releaseBuffer(*buffer);
    439                 returnBufferItemLocked(buffer);
    440 
    441                 ALOGE("%s: Output buffer format: 0x%x, ImageReader configured format: 0x%x",
    442                         __FUNCTION__, bufferFmt, readerFmt);
    443 
    444                 return AMEDIA_ERROR_UNKNOWN;
    445             }
    446         }
    447     }
    448 
    449     if (mHalFormat == HAL_PIXEL_FORMAT_BLOB) {
    450         *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
    451                 readerWidth, readerHeight, mNumPlanes);
    452     } else {
    453         *image = new AImage(this, mFormat, mUsage, buffer, buffer->mTimestamp,
    454                 bufferWidth, bufferHeight, mNumPlanes);
    455     }
    456     mAcquiredImages.push_back(*image);
    457 
    458     // When the output paramter fence is not NULL, we are acquiring the image asynchronously.
    459     if (acquireFenceFd != nullptr) {
    460         *acquireFenceFd = buffer->mFence->dup();
    461     }
    462 
    463     return AMEDIA_OK;
    464 }
    465 
    466 BufferItem*
    467 AImageReader::getBufferItemLocked() {
    468     if (mBuffers.empty()) {
    469         return nullptr;
    470     }
    471     // Return a BufferItem pointer and remove it from the list
    472     auto it = mBuffers.begin();
    473     BufferItem* buffer = *it;
    474     mBuffers.erase(it);
    475     return buffer;
    476 }
    477 
    478 void
    479 AImageReader::returnBufferItemLocked(BufferItem* buffer) {
    480     mBuffers.push_back(buffer);
    481 }
    482 
    483 void
    484 AImageReader::releaseImageLocked(AImage* image, int releaseFenceFd) {
    485     BufferItem* buffer = image->mBuffer;
    486     if (buffer == nullptr) {
    487         // This should not happen, but is not fatal
    488         ALOGW("AImage %p has no buffer!", image);
    489         return;
    490     }
    491 
    492     int unlockFenceFd = -1;
    493     media_status_t ret = image->unlockImageIfLocked(&unlockFenceFd);
    494     if (ret < 0) {
    495         ALOGW("%s: AImage %p is cannot be unlocked.", __FUNCTION__, image);
    496         return;
    497     }
    498 
    499     sp<Fence> unlockFence = unlockFenceFd > 0 ? new Fence(unlockFenceFd) : Fence::NO_FENCE;
    500     sp<Fence> releaseFence = releaseFenceFd > 0 ? new Fence(releaseFenceFd) : Fence::NO_FENCE;
    501     sp<Fence> bufferFence = Fence::merge("AImageReader", unlockFence, releaseFence);
    502     mBufferItemConsumer->releaseBuffer(*buffer, bufferFence);
    503     returnBufferItemLocked(buffer);
    504     image->mBuffer = nullptr;
    505     image->mLockedBuffer = nullptr;
    506     image->mIsClosed = true;
    507 
    508     bool found = false;
    509     // cleanup acquired image list
    510     for (auto it = mAcquiredImages.begin();
    511               it != mAcquiredImages.end(); it++) {
    512         AImage* readerCopy = *it;
    513         if (readerCopy == image) {
    514             found = true;
    515             mAcquiredImages.erase(it);
    516             break;
    517         }
    518     }
    519     if (!found) {
    520         ALOGE("Error: AImage %p is not generated by AImageReader %p",
    521                 image, this);
    522     }
    523 }
    524 
    525 int
    526 AImageReader::getBufferWidth(BufferItem* buffer) {
    527     if (buffer == NULL) return -1;
    528 
    529     if (!buffer->mCrop.isEmpty()) {
    530         return buffer->mCrop.getWidth();
    531     }
    532 
    533     return buffer->mGraphicBuffer->getWidth();
    534 }
    535 
    536 int
    537 AImageReader::getBufferHeight(BufferItem* buffer) {
    538     if (buffer == NULL) return -1;
    539 
    540     if (!buffer->mCrop.isEmpty()) {
    541         return buffer->mCrop.getHeight();
    542     }
    543 
    544     return buffer->mGraphicBuffer->getHeight();
    545 }
    546 
    547 media_status_t
    548 AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
    549     Mutex::Autolock _l(mLock);
    550     return acquireImageLocked(image, acquireFenceFd);
    551 }
    552 
    553 media_status_t
    554 AImageReader::acquireLatestImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
    555     if (image == nullptr) {
    556         return AMEDIA_ERROR_INVALID_PARAMETER;
    557     }
    558     Mutex::Autolock _l(mLock);
    559     *image = nullptr;
    560     AImage* prevImage = nullptr;
    561     AImage* nextImage = nullptr;
    562     media_status_t ret = acquireImageLocked(&prevImage, acquireFenceFd);
    563     if (prevImage == nullptr) {
    564         return ret;
    565     }
    566     for (;;) {
    567         ret = acquireImageLocked(&nextImage, acquireFenceFd);
    568         if (nextImage == nullptr) {
    569             *image = prevImage;
    570             return AMEDIA_OK;
    571         }
    572 
    573         if (acquireFenceFd == nullptr) {
    574             // No need for release fence here since the prevImage is unused and acquireImageLocked
    575             // has already waited for acquired fence to be signaled.
    576             prevImage->close();
    577         } else {
    578             // Use the acquire fence as release fence, so that producer can wait before trying to
    579             // refill the buffer.
    580             prevImage->close(*acquireFenceFd);
    581         }
    582         prevImage->free();
    583         prevImage = nextImage;
    584         nextImage = nullptr;
    585     }
    586 }
    587 
    588 EXPORT
    589 media_status_t AImageReader_new(
    590         int32_t width, int32_t height, int32_t format, int32_t maxImages,
    591         /*out*/AImageReader** reader) {
    592     ALOGV("%s", __FUNCTION__);
    593     return AImageReader_newWithUsage(
    594             width, height, format, AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN, maxImages, reader);
    595 }
    596 
    597 EXPORT
    598 media_status_t AImageReader_newWithUsage(
    599         int32_t width, int32_t height, int32_t format, uint64_t usage,
    600         int32_t maxImages, /*out*/ AImageReader** reader) {
    601     ALOGV("%s", __FUNCTION__);
    602 
    603     if (width < 1 || height < 1) {
    604         ALOGE("%s: image dimension must be positive: w:%d h:%d",
    605                 __FUNCTION__, width, height);
    606         return AMEDIA_ERROR_INVALID_PARAMETER;
    607     }
    608 
    609     if (maxImages < 1) {
    610         ALOGE("%s: max outstanding image count must be at least 1 (%d)",
    611                 __FUNCTION__, maxImages);
    612         return AMEDIA_ERROR_INVALID_PARAMETER;
    613     }
    614 
    615     if (maxImages > BufferQueueDefs::NUM_BUFFER_SLOTS) {
    616         ALOGE("%s: max outstanding image count (%d) cannot be larget than %d.",
    617               __FUNCTION__, maxImages, BufferQueueDefs::NUM_BUFFER_SLOTS);
    618         return AMEDIA_ERROR_INVALID_PARAMETER;
    619     }
    620 
    621     if (!AImageReader::isSupportedFormatAndUsage(format, usage)) {
    622         ALOGE("%s: format %d is not supported with usage 0x%" PRIx64 " by AImageReader",
    623                 __FUNCTION__, format, usage);
    624         return AMEDIA_ERROR_INVALID_PARAMETER;
    625     }
    626 
    627     if (reader == nullptr) {
    628         ALOGE("%s: reader argument is null", __FUNCTION__);
    629         return AMEDIA_ERROR_INVALID_PARAMETER;
    630     }
    631 
    632     AImageReader* tmpReader = new AImageReader(
    633         width, height, format, usage, maxImages);
    634     if (tmpReader == nullptr) {
    635         ALOGE("%s: AImageReader allocation failed", __FUNCTION__);
    636         return AMEDIA_ERROR_UNKNOWN;
    637     }
    638     media_status_t ret = tmpReader->init();
    639     if (ret != AMEDIA_OK) {
    640         ALOGE("%s: AImageReader initialization failed!", __FUNCTION__);
    641         delete tmpReader;
    642         return ret;
    643     }
    644     *reader = tmpReader;
    645     (*reader)->incStrong((void*) AImageReader_new);
    646     return AMEDIA_OK;
    647 }
    648 
    649 EXPORT
    650 void AImageReader_delete(AImageReader* reader) {
    651     ALOGV("%s", __FUNCTION__);
    652     if (reader != nullptr) {
    653         reader->decStrong((void*) AImageReader_delete);
    654     }
    655     return;
    656 }
    657 
    658 EXPORT
    659 media_status_t AImageReader_getWindow(AImageReader* reader, /*out*/ANativeWindow** window) {
    660     ALOGV("%s", __FUNCTION__);
    661     if (reader == nullptr || window == nullptr) {
    662         ALOGE("%s: invalid argument. reader %p, window %p",
    663                 __FUNCTION__, reader, window);
    664         return AMEDIA_ERROR_INVALID_PARAMETER;
    665     }
    666     *window = reader->getWindow();
    667     return AMEDIA_OK;
    668 }
    669 
    670 EXPORT
    671 media_status_t AImageReader_getWidth(const AImageReader* reader, /*out*/int32_t* width) {
    672     ALOGV("%s", __FUNCTION__);
    673     if (reader == nullptr || width == nullptr) {
    674         ALOGE("%s: invalid argument. reader %p, width %p",
    675                 __FUNCTION__, reader, width);
    676         return AMEDIA_ERROR_INVALID_PARAMETER;
    677     }
    678     *width = reader->getWidth();
    679     return AMEDIA_OK;
    680 }
    681 
    682 EXPORT
    683 media_status_t AImageReader_getHeight(const AImageReader* reader, /*out*/int32_t* height) {
    684     ALOGV("%s", __FUNCTION__);
    685     if (reader == nullptr || height == nullptr) {
    686         ALOGE("%s: invalid argument. reader %p, height %p",
    687                 __FUNCTION__, reader, height);
    688         return AMEDIA_ERROR_INVALID_PARAMETER;
    689     }
    690     *height = reader->getHeight();
    691     return AMEDIA_OK;
    692 }
    693 
    694 EXPORT
    695 media_status_t AImageReader_getFormat(const AImageReader* reader, /*out*/int32_t* format) {
    696     ALOGV("%s", __FUNCTION__);
    697     if (reader == nullptr || format == nullptr) {
    698         ALOGE("%s: invalid argument. reader %p, format %p",
    699                 __FUNCTION__, reader, format);
    700         return AMEDIA_ERROR_INVALID_PARAMETER;
    701     }
    702     *format = reader->getFormat();
    703     return AMEDIA_OK;
    704 }
    705 
    706 EXPORT
    707 media_status_t AImageReader_getMaxImages(const AImageReader* reader, /*out*/int32_t* maxImages) {
    708     ALOGV("%s", __FUNCTION__);
    709     if (reader == nullptr || maxImages == nullptr) {
    710         ALOGE("%s: invalid argument. reader %p, maxImages %p",
    711                 __FUNCTION__, reader, maxImages);
    712         return AMEDIA_ERROR_INVALID_PARAMETER;
    713     }
    714     *maxImages = reader->getMaxImages();
    715     return AMEDIA_OK;
    716 }
    717 
    718 EXPORT
    719 media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
    720     ALOGV("%s", __FUNCTION__);
    721     return AImageReader_acquireNextImageAsync(reader, image, nullptr);
    722 }
    723 
    724 EXPORT
    725 media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
    726     ALOGV("%s", __FUNCTION__);
    727     return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
    728 }
    729 
    730 EXPORT
    731 media_status_t AImageReader_acquireNextImageAsync(
    732     AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
    733     ALOGV("%s", __FUNCTION__);
    734     if (reader == nullptr || image == nullptr) {
    735         ALOGE("%s: invalid argument. reader %p, image %p",
    736                 __FUNCTION__, reader, image);
    737         return AMEDIA_ERROR_INVALID_PARAMETER;
    738     }
    739     return reader->acquireNextImage(image, acquireFenceFd);
    740 }
    741 
    742 EXPORT
    743 media_status_t AImageReader_acquireLatestImageAsync(
    744     AImageReader* reader, /*out*/AImage** image, /*out*/int* acquireFenceFd) {
    745     ALOGV("%s", __FUNCTION__);
    746     if (reader == nullptr || image == nullptr) {
    747         ALOGE("%s: invalid argument. reader %p, image %p",
    748                 __FUNCTION__, reader, image);
    749         return AMEDIA_ERROR_INVALID_PARAMETER;
    750     }
    751     return reader->acquireLatestImage(image, acquireFenceFd);
    752 }
    753 
    754 EXPORT
    755 media_status_t AImageReader_setImageListener(
    756         AImageReader* reader, AImageReader_ImageListener* listener) {
    757     ALOGV("%s", __FUNCTION__);
    758     if (reader == nullptr) {
    759         ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
    760         return AMEDIA_ERROR_INVALID_PARAMETER;
    761     }
    762 
    763     reader->setImageListener(listener);
    764     return AMEDIA_OK;
    765 }
    766 
    767 EXPORT
    768 media_status_t AImageReader_setBufferRemovedListener(
    769     AImageReader* reader, AImageReader_BufferRemovedListener* listener) {
    770     ALOGV("%s", __FUNCTION__);
    771     if (reader == nullptr) {
    772         ALOGE("%s: invalid argument! reader %p", __FUNCTION__, reader);
    773         return AMEDIA_ERROR_INVALID_PARAMETER;
    774     }
    775 
    776     reader->setBufferRemovedListener(listener);
    777     return AMEDIA_OK;
    778 }
    779