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
32using namespace android;
33
34namespace {
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
42const char* AImageReader::kCallbackFpKey = "Callback";
43const char* AImageReader::kContextKey    = "Context";
44const char* AImageReader::kGraphicBufferKey = "GraphicBuffer";
45
46bool
47AImageReader::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
68int
69AImageReader::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
91void
92AImageReader::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
109media_status_t
110AImageReader::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
121void
122AImageReader::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
147media_status_t
148AImageReader::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
160media_status_t
161AImageReader::setImageListenerLocked(AImageReader_ImageListener* listener) {
162    return mFrameListener->setImageListener(listener);
163}
164
165media_status_t
166AImageReader::setImageListener(AImageReader_ImageListener* listener) {
167    Mutex::Autolock _l(mLock);
168    return setImageListenerLocked(listener);
169}
170
171media_status_t
172AImageReader::setBufferRemovedListenerLocked(AImageReader_BufferRemovedListener* listener) {
173    return mBufferRemovedListener->setBufferRemovedListener(listener);
174}
175
176media_status_t
177AImageReader::setBufferRemovedListener(AImageReader_BufferRemovedListener* listener) {
178    Mutex::Autolock _l(mLock);
179    return setBufferRemovedListenerLocked(listener);
180}
181
182void 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
238AImageReader::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
252media_status_t
253AImageReader::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
324AImageReader::~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
358media_status_t
359AImageReader::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
456BufferItem*
457AImageReader::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
468void
469AImageReader::returnBufferItemLocked(BufferItem* buffer) {
470    mBuffers.push_back(buffer);
471}
472
473void
474AImageReader::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
513int
514AImageReader::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
524int
525AImageReader::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
535media_status_t
536AImageReader::acquireNextImage(/*out*/AImage** image, /*out*/int* acquireFenceFd) {
537    Mutex::Autolock _l(mLock);
538    return acquireImageLocked(image, acquireFenceFd);
539}
540
541media_status_t
542AImageReader::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
576EXPORT
577media_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
585EXPORT
586media_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
637EXPORT
638void AImageReader_delete(AImageReader* reader) {
639    ALOGV("%s", __FUNCTION__);
640    if (reader != nullptr) {
641        reader->decStrong((void*) AImageReader_delete);
642    }
643    return;
644}
645
646EXPORT
647media_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
658EXPORT
659media_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
670EXPORT
671media_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
682EXPORT
683media_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
694EXPORT
695media_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
706EXPORT
707media_status_t AImageReader_acquireNextImage(AImageReader* reader, /*out*/AImage** image) {
708    ALOGV("%s", __FUNCTION__);
709    return AImageReader_acquireNextImageAsync(reader, image, nullptr);
710}
711
712EXPORT
713media_status_t AImageReader_acquireLatestImage(AImageReader* reader, /*out*/AImage** image) {
714    ALOGV("%s", __FUNCTION__);
715    return AImageReader_acquireLatestImageAsync(reader, image, nullptr);
716}
717
718EXPORT
719media_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
730EXPORT
731media_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
742EXPORT
743media_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
755EXPORT
756media_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