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 "NdkImage"
     21 
     22 #include "NdkImagePriv.h"
     23 #include "NdkImageReaderPriv.h"
     24 
     25 #include <utils/Log.h>
     26 #include "hardware/camera3.h"
     27 
     28 using namespace android;
     29 
     30 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
     31 
     32 AImage::AImage(AImageReader* reader, int32_t format,
     33         CpuConsumer::LockedBuffer* buffer, int64_t timestamp,
     34         int32_t width, int32_t height, int32_t numPlanes) :
     35         mReader(reader), mFormat(format),
     36         mBuffer(buffer), mTimestamp(timestamp),
     37         mWidth(width), mHeight(height), mNumPlanes(numPlanes) {
     38 }
     39 
     40 // Can only be called by free() with mLock hold
     41 AImage::~AImage() {
     42     if (!mIsClosed) {
     43         LOG_ALWAYS_FATAL(
     44                 "Error: AImage %p is deleted before returning buffer to AImageReader!", this);
     45     }
     46 }
     47 
     48 bool
     49 AImage::isClosed() const {
     50     Mutex::Autolock _l(mLock);
     51     return mIsClosed;
     52 }
     53 
     54 void
     55 AImage::close() {
     56     Mutex::Autolock _l(mLock);
     57     if (mIsClosed) {
     58         return;
     59     }
     60     sp<AImageReader> reader = mReader.promote();
     61     if (reader == nullptr) {
     62         LOG_ALWAYS_FATAL("Error: AImage not closed before AImageReader close!");
     63         return;
     64     }
     65     reader->releaseImageLocked(this);
     66     // Should have been set to nullptr in releaseImageLocked
     67     // Set to nullptr here for extra safety only
     68     mBuffer = nullptr;
     69     mIsClosed = true;
     70 }
     71 
     72 void
     73 AImage::free() {
     74     if (!isClosed()) {
     75         ALOGE("Cannot free AImage before close!");
     76         return;
     77     }
     78     Mutex::Autolock _l(mLock);
     79     delete this;
     80 }
     81 
     82 void
     83 AImage::lockReader() const {
     84     sp<AImageReader> reader = mReader.promote();
     85     if (reader == nullptr) {
     86         // Reader has been closed
     87         return;
     88     }
     89     reader->mLock.lock();
     90 }
     91 
     92 void
     93 AImage::unlockReader() const {
     94     sp<AImageReader> reader = mReader.promote();
     95     if (reader == nullptr) {
     96         // Reader has been closed
     97         return;
     98     }
     99     reader->mLock.unlock();
    100 }
    101 
    102 media_status_t
    103 AImage::getWidth(int32_t* width) const {
    104     if (width == nullptr) {
    105         return AMEDIA_ERROR_INVALID_PARAMETER;
    106     }
    107     *width = -1;
    108     if (isClosed()) {
    109         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    110         return AMEDIA_ERROR_INVALID_OBJECT;
    111     }
    112     *width = mWidth;
    113     return AMEDIA_OK;
    114 }
    115 
    116 media_status_t
    117 AImage::getHeight(int32_t* height) const {
    118     if (height == nullptr) {
    119         return AMEDIA_ERROR_INVALID_PARAMETER;
    120     }
    121     *height = -1;
    122     if (isClosed()) {
    123         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    124         return AMEDIA_ERROR_INVALID_OBJECT;
    125     }
    126     *height = mHeight;
    127     return AMEDIA_OK;
    128 }
    129 
    130 media_status_t
    131 AImage::getFormat(int32_t* format) const {
    132     if (format == nullptr) {
    133         return AMEDIA_ERROR_INVALID_PARAMETER;
    134     }
    135     *format = -1;
    136     if (isClosed()) {
    137         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    138         return AMEDIA_ERROR_INVALID_OBJECT;
    139     }
    140     *format = mFormat;
    141     return AMEDIA_OK;
    142 }
    143 
    144 media_status_t
    145 AImage::getNumPlanes(int32_t* numPlanes) const {
    146     if (numPlanes == nullptr) {
    147         return AMEDIA_ERROR_INVALID_PARAMETER;
    148     }
    149     *numPlanes = -1;
    150     if (isClosed()) {
    151         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    152         return AMEDIA_ERROR_INVALID_OBJECT;
    153     }
    154     *numPlanes = mNumPlanes;
    155     return AMEDIA_OK;
    156 }
    157 
    158 media_status_t
    159 AImage::getTimestamp(int64_t* timestamp) const {
    160     if (timestamp == nullptr) {
    161         return AMEDIA_ERROR_INVALID_PARAMETER;
    162     }
    163     *timestamp = -1;
    164     if (isClosed()) {
    165         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    166         return AMEDIA_ERROR_INVALID_OBJECT;
    167     }
    168     *timestamp = mTimestamp;
    169     return AMEDIA_OK;
    170 }
    171 
    172 media_status_t
    173 AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const {
    174     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
    175         ALOGE("Error: planeIdx %d out of bound [0,%d]",
    176                 planeIdx, mNumPlanes - 1);
    177         return AMEDIA_ERROR_INVALID_PARAMETER;
    178     }
    179     if (pixelStride == nullptr) {
    180         return AMEDIA_ERROR_INVALID_PARAMETER;
    181     }
    182     if (isClosed()) {
    183         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    184         return AMEDIA_ERROR_INVALID_OBJECT;
    185     }
    186     int32_t fmt = mBuffer->flexFormat;
    187     switch (fmt) {
    188         case HAL_PIXEL_FORMAT_YCbCr_420_888:
    189             *pixelStride = (planeIdx == 0) ? 1 : mBuffer->chromaStep;
    190             return AMEDIA_OK;
    191         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
    192             *pixelStride = (planeIdx == 0) ? 1 : 2;
    193             return AMEDIA_OK;
    194         case HAL_PIXEL_FORMAT_Y8:
    195             *pixelStride = 1;
    196             return AMEDIA_OK;
    197         case HAL_PIXEL_FORMAT_YV12:
    198             *pixelStride = 1;
    199             return AMEDIA_OK;
    200         case HAL_PIXEL_FORMAT_Y16:
    201         case HAL_PIXEL_FORMAT_RAW16:
    202         case HAL_PIXEL_FORMAT_RGB_565:
    203             // Single plane 16bpp data.
    204             *pixelStride = 2;
    205             return AMEDIA_OK;
    206         case HAL_PIXEL_FORMAT_RGBA_8888:
    207         case HAL_PIXEL_FORMAT_RGBX_8888:
    208             *pixelStride = 4;
    209             return AMEDIA_OK;
    210         case HAL_PIXEL_FORMAT_RGB_888:
    211             // Single plane, 24bpp.
    212             *pixelStride = 3;
    213             return AMEDIA_OK;
    214         case HAL_PIXEL_FORMAT_BLOB:
    215         case HAL_PIXEL_FORMAT_RAW10:
    216         case HAL_PIXEL_FORMAT_RAW12:
    217         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
    218             // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data,
    219             // those are single plane data without pixel stride defined
    220             return AMEDIA_ERROR_UNSUPPORTED;
    221         default:
    222             ALOGE("Pixel format: 0x%x is unsupported", fmt);
    223             return AMEDIA_ERROR_UNSUPPORTED;
    224     }
    225 }
    226 
    227 media_status_t
    228 AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const {
    229     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
    230         ALOGE("Error: planeIdx %d out of bound [0,%d]",
    231                 planeIdx, mNumPlanes - 1);
    232         return AMEDIA_ERROR_INVALID_PARAMETER;
    233     }
    234     if (rowStride == nullptr) {
    235         return AMEDIA_ERROR_INVALID_PARAMETER;
    236     }
    237     if (isClosed()) {
    238         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    239         return AMEDIA_ERROR_INVALID_OBJECT;
    240     }
    241     int32_t fmt = mBuffer->flexFormat;
    242     switch (fmt) {
    243         case HAL_PIXEL_FORMAT_YCbCr_420_888:
    244             *rowStride = (planeIdx == 0) ? mBuffer->stride : mBuffer->chromaStride;
    245             return AMEDIA_OK;
    246         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
    247             *rowStride = mBuffer->width;
    248             return AMEDIA_OK;
    249         case HAL_PIXEL_FORMAT_YV12:
    250             if (mBuffer->stride % 16) {
    251                 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
    252                 return AMEDIA_ERROR_UNKNOWN;
    253             }
    254             *rowStride = (planeIdx == 0) ? mBuffer->stride : ALIGN(mBuffer->stride / 2, 16);
    255             return AMEDIA_OK;
    256         case HAL_PIXEL_FORMAT_RAW10:
    257         case HAL_PIXEL_FORMAT_RAW12:
    258             // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane
    259             *rowStride = mBuffer->stride;
    260             return AMEDIA_OK;
    261         case HAL_PIXEL_FORMAT_Y8:
    262             if (mBuffer->stride % 16) {
    263                 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
    264                 return AMEDIA_ERROR_UNKNOWN;
    265             }
    266             *rowStride = mBuffer->stride;
    267             return AMEDIA_OK;
    268         case HAL_PIXEL_FORMAT_Y16:
    269         case HAL_PIXEL_FORMAT_RAW16:
    270             // In native side, strides are specified in pixels, not in bytes.
    271             // Single plane 16bpp bayer data. even width/height,
    272             // row stride multiple of 16 pixels (32 bytes)
    273             if (mBuffer->stride % 16) {
    274                 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
    275                 return AMEDIA_ERROR_UNKNOWN;
    276             }
    277             *rowStride = mBuffer->stride * 2;
    278             return AMEDIA_OK;
    279         case HAL_PIXEL_FORMAT_RGB_565:
    280             *rowStride = mBuffer->stride * 2;
    281             return AMEDIA_OK;
    282         case HAL_PIXEL_FORMAT_RGBA_8888:
    283         case HAL_PIXEL_FORMAT_RGBX_8888:
    284             *rowStride = mBuffer->stride * 4;
    285             return AMEDIA_OK;
    286         case HAL_PIXEL_FORMAT_RGB_888:
    287             // Single plane, 24bpp.
    288             *rowStride = mBuffer->stride * 3;
    289             return AMEDIA_OK;
    290         case HAL_PIXEL_FORMAT_BLOB:
    291         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
    292             // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and
    293             // no row stride defined
    294             return AMEDIA_ERROR_UNSUPPORTED;
    295         default:
    296             ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt);
    297           return AMEDIA_ERROR_UNSUPPORTED;
    298     }
    299 }
    300 
    301 uint32_t
    302 AImage::getJpegSize() const {
    303     if (mBuffer == nullptr) {
    304         LOG_ALWAYS_FATAL("Error: buffer is null");
    305     }
    306 
    307     uint32_t size = 0;
    308     uint32_t width = mBuffer->width;
    309     uint8_t* jpegBuffer = mBuffer->data;
    310 
    311     // First check for JPEG transport header at the end of the buffer
    312     uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
    313     struct camera3_jpeg_blob* blob = (struct camera3_jpeg_blob*)(header);
    314     if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
    315         size = blob->jpeg_size;
    316         ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
    317     }
    318 
    319     // failed to find size, default to whole buffer
    320     if (size == 0) {
    321         /*
    322          * This is a problem because not including the JPEG header
    323          * means that in certain rare situations a regular JPEG blob
    324          * will be misidentified as having a header, in which case
    325          * we will get a garbage size value.
    326          */
    327         ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
    328                 __FUNCTION__, width);
    329         size = width;
    330     }
    331 
    332     return size;
    333 }
    334 
    335 media_status_t
    336 AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const {
    337     if (planeIdx < 0 || planeIdx >= mNumPlanes) {
    338         ALOGE("Error: planeIdx %d out of bound [0,%d]",
    339                 planeIdx, mNumPlanes - 1);
    340         return AMEDIA_ERROR_INVALID_PARAMETER;
    341     }
    342     if (data == nullptr || dataLength == nullptr) {
    343         return AMEDIA_ERROR_INVALID_PARAMETER;
    344     }
    345     if (isClosed()) {
    346         ALOGE("%s: image %p has been closed!", __FUNCTION__, this);
    347         return AMEDIA_ERROR_INVALID_OBJECT;
    348     }
    349 
    350     uint32_t dataSize, ySize, cSize, cStride;
    351     uint8_t* cb = nullptr;
    352     uint8_t* cr = nullptr;
    353     uint8_t* pData = nullptr;
    354     int bytesPerPixel = 0;
    355     int32_t fmt = mBuffer->flexFormat;
    356 
    357     switch (fmt) {
    358         case HAL_PIXEL_FORMAT_YCbCr_420_888:
    359             pData = (planeIdx == 0) ? mBuffer->data :
    360                     (planeIdx == 1) ? mBuffer->dataCb : mBuffer->dataCr;
    361             // only map until last pixel
    362             if (planeIdx == 0) {
    363                 dataSize = mBuffer->stride * (mBuffer->height - 1) + mBuffer->width;
    364             } else {
    365                 dataSize = mBuffer->chromaStride * (mBuffer->height / 2 - 1) +
    366                         mBuffer->chromaStep * (mBuffer->width / 2 - 1) + 1;
    367             }
    368             break;
    369         // NV21
    370         case HAL_PIXEL_FORMAT_YCrCb_420_SP:
    371             cr = mBuffer->data + (mBuffer->stride * mBuffer->height);
    372             cb = cr + 1;
    373             // only map until last pixel
    374             ySize = mBuffer->width * (mBuffer->height - 1) + mBuffer->width;
    375             cSize = mBuffer->width * (mBuffer->height / 2 - 1) + mBuffer->width - 1;
    376 
    377             pData = (planeIdx == 0) ? mBuffer->data :
    378                     (planeIdx == 1) ? cb : cr;
    379             dataSize = (planeIdx == 0) ? ySize : cSize;
    380             break;
    381         case HAL_PIXEL_FORMAT_YV12:
    382             // Y and C stride need to be 16 pixel aligned.
    383             if (mBuffer->stride % 16) {
    384                 ALOGE("Stride %d is not 16 pixel aligned!", mBuffer->stride);
    385                 return AMEDIA_ERROR_UNKNOWN;
    386             }
    387 
    388             ySize = mBuffer->stride * mBuffer->height;
    389             cStride = ALIGN(mBuffer->stride / 2, 16);
    390             cr = mBuffer->data + ySize;
    391             cSize = cStride * mBuffer->height / 2;
    392             cb = cr + cSize;
    393 
    394             pData = (planeIdx == 0) ? mBuffer->data :
    395                     (planeIdx == 1) ? cb : cr;
    396             dataSize = (planeIdx == 0) ? ySize : cSize;
    397             break;
    398         case HAL_PIXEL_FORMAT_Y8:
    399             // Single plane, 8bpp.
    400 
    401             pData = mBuffer->data;
    402             dataSize = mBuffer->stride * mBuffer->height;
    403             break;
    404         case HAL_PIXEL_FORMAT_Y16:
    405             bytesPerPixel = 2;
    406 
    407             pData = mBuffer->data;
    408             dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
    409             break;
    410         case HAL_PIXEL_FORMAT_BLOB:
    411             // Used for JPEG data, height must be 1, width == size, single plane.
    412             if (mBuffer->height != 1) {
    413                 ALOGE("Jpeg should have height value one but got %d", mBuffer->height);
    414                 return AMEDIA_ERROR_UNKNOWN;
    415             }
    416 
    417             pData = mBuffer->data;
    418             dataSize = getJpegSize();
    419             break;
    420         case HAL_PIXEL_FORMAT_RAW16:
    421             // Single plane 16bpp bayer data.
    422             bytesPerPixel = 2;
    423             pData = mBuffer->data;
    424             dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
    425             break;
    426         case HAL_PIXEL_FORMAT_RAW_OPAQUE:
    427             // Used for RAW_OPAQUE data, height must be 1, width == size, single plane.
    428             if (mBuffer->height != 1) {
    429                 ALOGE("RAW_OPAQUE should have height value one but got %d", mBuffer->height);
    430                 return AMEDIA_ERROR_UNKNOWN;
    431             }
    432             pData = mBuffer->data;
    433             dataSize = mBuffer->width;
    434             break;
    435         case HAL_PIXEL_FORMAT_RAW10:
    436             // Single plane 10bpp bayer data.
    437             if (mBuffer->width % 4) {
    438                 ALOGE("Width is not multiple of 4 %d", mBuffer->width);
    439                 return AMEDIA_ERROR_UNKNOWN;
    440             }
    441             if (mBuffer->height % 2) {
    442                 ALOGE("Height is not multiple of 2 %d", mBuffer->height);
    443                 return AMEDIA_ERROR_UNKNOWN;
    444             }
    445             if (mBuffer->stride < (mBuffer->width * 10 / 8)) {
    446                 ALOGE("stride (%d) should be at least %d",
    447                         mBuffer->stride, mBuffer->width * 10 / 8);
    448                 return AMEDIA_ERROR_UNKNOWN;
    449             }
    450             pData = mBuffer->data;
    451             dataSize = mBuffer->stride * mBuffer->height;
    452             break;
    453         case HAL_PIXEL_FORMAT_RAW12:
    454             // Single plane 10bpp bayer data.
    455             if (mBuffer->width % 4) {
    456                 ALOGE("Width is not multiple of 4 %d", mBuffer->width);
    457                 return AMEDIA_ERROR_UNKNOWN;
    458             }
    459             if (mBuffer->height % 2) {
    460                 ALOGE("Height is not multiple of 2 %d", mBuffer->height);
    461                 return AMEDIA_ERROR_UNKNOWN;
    462             }
    463             if (mBuffer->stride < (mBuffer->width * 12 / 8)) {
    464                 ALOGE("stride (%d) should be at least %d",
    465                         mBuffer->stride, mBuffer->width * 12 / 8);
    466                 return AMEDIA_ERROR_UNKNOWN;
    467             }
    468             pData = mBuffer->data;
    469             dataSize = mBuffer->stride * mBuffer->height;
    470             break;
    471         case HAL_PIXEL_FORMAT_RGBA_8888:
    472         case HAL_PIXEL_FORMAT_RGBX_8888:
    473             // Single plane, 32bpp.
    474             bytesPerPixel = 4;
    475             pData = mBuffer->data;
    476             dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
    477             break;
    478         case HAL_PIXEL_FORMAT_RGB_565:
    479             // Single plane, 16bpp.
    480             bytesPerPixel = 2;
    481             pData = mBuffer->data;
    482             dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
    483             break;
    484         case HAL_PIXEL_FORMAT_RGB_888:
    485             // Single plane, 24bpp.
    486             bytesPerPixel = 3;
    487             pData = mBuffer->data;
    488             dataSize = mBuffer->stride * mBuffer->height * bytesPerPixel;
    489             break;
    490         default:
    491             ALOGE("Pixel format: 0x%x is unsupported", fmt);
    492             return AMEDIA_ERROR_UNSUPPORTED;
    493     }
    494 
    495     *data = pData;
    496     *dataLength = dataSize;
    497     return AMEDIA_OK;
    498 }
    499 
    500 EXPORT
    501 void AImage_delete(AImage* image) {
    502     ALOGV("%s", __FUNCTION__);
    503     if (image != nullptr) {
    504         image->lockReader();
    505         image->close();
    506         image->unlockReader();
    507         if (!image->isClosed()) {
    508             LOG_ALWAYS_FATAL("Image close failed!");
    509         }
    510         image->free();
    511     }
    512     return;
    513 }
    514 
    515 EXPORT
    516 media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) {
    517     ALOGV("%s", __FUNCTION__);
    518     if (image == nullptr || width == nullptr) {
    519         ALOGE("%s: bad argument. image %p width %p",
    520                 __FUNCTION__, image, width);
    521         return AMEDIA_ERROR_INVALID_PARAMETER;
    522     }
    523     return image->getWidth(width);
    524 }
    525 
    526 EXPORT
    527 media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) {
    528     ALOGV("%s", __FUNCTION__);
    529     if (image == nullptr || height == nullptr) {
    530         ALOGE("%s: bad argument. image %p height %p",
    531                 __FUNCTION__, image, height);
    532         return AMEDIA_ERROR_INVALID_PARAMETER;
    533     }
    534     return image->getHeight(height);
    535 }
    536 
    537 EXPORT
    538 media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) {
    539     ALOGV("%s", __FUNCTION__);
    540     if (image == nullptr || format == nullptr) {
    541         ALOGE("%s: bad argument. image %p format %p",
    542                 __FUNCTION__, image, format);
    543         return AMEDIA_ERROR_INVALID_PARAMETER;
    544     }
    545     return image->getFormat(format);
    546 }
    547 
    548 EXPORT
    549 media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) {
    550     ALOGV("%s", __FUNCTION__);
    551     if (image == nullptr || rect == nullptr) {
    552         ALOGE("%s: bad argument. image %p rect %p",
    553                 __FUNCTION__, image, rect);
    554         return AMEDIA_ERROR_INVALID_PARAMETER;
    555     }
    556     // For now AImage only supports camera outputs where cropRect is always full window
    557     int32_t width = -1;
    558     media_status_t ret = image->getWidth(&width);
    559     if (ret != AMEDIA_OK) {
    560         return ret;
    561     }
    562     int32_t height = -1;
    563     ret = image->getHeight(&height);
    564     if (ret != AMEDIA_OK) {
    565         return ret;
    566     }
    567     rect->left = 0;
    568     rect->top = 0;
    569     rect->right = width;
    570     rect->bottom = height;
    571     return AMEDIA_OK;
    572 }
    573 
    574 EXPORT
    575 media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) {
    576     ALOGV("%s", __FUNCTION__);
    577     if (image == nullptr || timestampNs == nullptr) {
    578         ALOGE("%s: bad argument. image %p timestampNs %p",
    579                 __FUNCTION__, image, timestampNs);
    580         return AMEDIA_ERROR_INVALID_PARAMETER;
    581     }
    582     return image->getTimestamp(timestampNs);
    583 }
    584 
    585 EXPORT
    586 media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) {
    587     ALOGV("%s", __FUNCTION__);
    588     if (image == nullptr || numPlanes == nullptr) {
    589         ALOGE("%s: bad argument. image %p numPlanes %p",
    590                 __FUNCTION__, image, numPlanes);
    591         return AMEDIA_ERROR_INVALID_PARAMETER;
    592     }
    593     return image->getNumPlanes(numPlanes);
    594 }
    595 
    596 EXPORT
    597 media_status_t AImage_getPlanePixelStride(
    598         const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) {
    599     ALOGV("%s", __FUNCTION__);
    600     if (image == nullptr || pixelStride == nullptr) {
    601         ALOGE("%s: bad argument. image %p pixelStride %p",
    602                 __FUNCTION__, image, pixelStride);
    603         return AMEDIA_ERROR_INVALID_PARAMETER;
    604     }
    605     return image->getPlanePixelStride(planeIdx, pixelStride);
    606 }
    607 
    608 EXPORT
    609 media_status_t AImage_getPlaneRowStride(
    610         const AImage* image, int planeIdx, /*out*/int32_t* rowStride) {
    611     ALOGV("%s", __FUNCTION__);
    612     if (image == nullptr || rowStride == nullptr) {
    613         ALOGE("%s: bad argument. image %p rowStride %p",
    614                 __FUNCTION__, image, rowStride);
    615         return AMEDIA_ERROR_INVALID_PARAMETER;
    616     }
    617     return image->getPlaneRowStride(planeIdx, rowStride);
    618 }
    619 
    620 EXPORT
    621 media_status_t AImage_getPlaneData(
    622         const AImage* image, int planeIdx,
    623         /*out*/uint8_t** data, /*out*/int* dataLength) {
    624     ALOGV("%s", __FUNCTION__);
    625     if (image == nullptr || data == nullptr || dataLength == nullptr) {
    626         ALOGE("%s: bad argument. image %p data %p dataLength %p",
    627                 __FUNCTION__, image, data, dataLength);
    628         return AMEDIA_ERROR_INVALID_PARAMETER;
    629     }
    630     return image->getPlaneData(planeIdx, data, dataLength);
    631 }
    632