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