| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include <inttypes.h> |
| |
| //#define LOG_NDEBUG 0 |
| #define LOG_TAG "NdkImage" |
| |
| #include "NdkImagePriv.h" |
| #include "NdkImageReaderPriv.h" |
| |
| #include <android_media_Utils.h> |
| #include <private/android/AHardwareBufferHelpers.h> |
| #include <ui/PublicFormat.h> |
| #include <utils/Log.h> |
| |
| using namespace android; |
| |
| #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) ) |
| |
| AImage::AImage(AImageReader* reader, int32_t format, uint64_t usage, BufferItem* buffer, |
| int64_t timestamp, int32_t width, int32_t height, int32_t numPlanes) : |
| mReader(reader), mFormat(format), mUsage(usage), mBuffer(buffer), mLockedBuffer(nullptr), |
| mTimestamp(timestamp), mWidth(width), mHeight(height), mNumPlanes(numPlanes) { |
| PublicFormat publicFormat = static_cast<PublicFormat>(format); |
| mHalDataSpace = mapPublicFormatToHalDataspace(publicFormat); |
| LOG_FATAL_IF(reader == nullptr, "AImageReader shouldn't be null while creating AImage"); |
| } |
| |
| AImage::~AImage() { |
| Mutex::Autolock _l(mLock); |
| if (!mIsClosed) { |
| LOG_ALWAYS_FATAL( |
| "Error: AImage %p is deleted before returning buffer to AImageReader!", this); |
| } |
| } |
| |
| bool |
| AImage::isClosed() const { |
| Mutex::Autolock _l(mLock); |
| return mIsClosed; |
| } |
| |
| void |
| AImage::close(int releaseFenceFd) { |
| Mutex::Autolock _l(mLock); |
| if (mIsClosed) { |
| return; |
| } |
| if (mReader->mIsOpen) { |
| mReader->releaseImageLocked(this, releaseFenceFd); |
| } |
| // Should have been set to nullptr in releaseImageLocked |
| // Set to nullptr here for extra safety only |
| mBuffer = nullptr; |
| mLockedBuffer = nullptr; |
| mIsClosed = true; |
| } |
| |
| void |
| AImage::free() { |
| if (!isClosed()) { |
| ALOGE("Cannot free AImage before close!"); |
| return; |
| } |
| delete this; |
| } |
| |
| void |
| AImage::lockReader() const { |
| mReader->mLock.lock(); |
| } |
| |
| void |
| AImage::unlockReader() const { |
| mReader->mLock.unlock(); |
| } |
| |
| media_status_t |
| AImage::getWidth(int32_t* width) const { |
| if (width == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| *width = -1; |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| *width = mWidth; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getHeight(int32_t* height) const { |
| if (height == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| *height = -1; |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| *height = mHeight; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getFormat(int32_t* format) const { |
| if (format == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| *format = -1; |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| *format = mFormat; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getNumPlanes(int32_t* numPlanes) const { |
| if (numPlanes == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| *numPlanes = -1; |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| *numPlanes = mNumPlanes; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getTimestamp(int64_t* timestamp) const { |
| if (timestamp == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| *timestamp = -1; |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| *timestamp = mTimestamp; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getDataSpace(android_dataspace* dataSpace) const { |
| if (dataSpace == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| *dataSpace = static_cast<android_dataspace>(-1); |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| *dataSpace = mHalDataSpace; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t AImage::lockImage() { |
| if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) { |
| LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| |
| if ((mUsage & AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN) == 0) { |
| ALOGE("%s: AImage %p does not have any software read usage bits set, usage=%" PRIu64 "", |
| __FUNCTION__, this, mUsage); |
| return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE; |
| } |
| |
| if (mLockedBuffer != nullptr) { |
| // Return immediately if the image has already been locked. |
| return AMEDIA_OK; |
| } |
| |
| auto lockedBuffer = std::make_unique<CpuConsumer::LockedBuffer>(); |
| |
| uint64_t grallocUsage = AHardwareBuffer_convertToGrallocUsageBits(mUsage); |
| |
| status_t ret = |
| lockImageFromBuffer(mBuffer, grallocUsage, mBuffer->mFence->dup(), lockedBuffer.get()); |
| if (ret != OK) { |
| ALOGE("%s: AImage %p failed to lock, error=%d", __FUNCTION__, this, ret); |
| return AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE; |
| } |
| |
| ALOGV("%s: Successfully locked the image %p.", __FUNCTION__, this); |
| mLockedBuffer = std::move(lockedBuffer); |
| |
| return AMEDIA_OK; |
| } |
| |
| media_status_t AImage::unlockImageIfLocked(int* fenceFd) { |
| if (fenceFd == nullptr) { |
| LOG_ALWAYS_FATAL("%s: fenceFd cannot be null.", __FUNCTION__); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| |
| if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) { |
| LOG_ALWAYS_FATAL("%s: AImage %p has no buffer.", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| |
| if (mLockedBuffer == nullptr) { |
| // This image hasn't been locked yet, no need to unlock. |
| *fenceFd = -1; |
| return AMEDIA_OK; |
| } |
| |
| // No fence by default. |
| int releaseFenceFd = -1; |
| status_t res = mBuffer->mGraphicBuffer->unlockAsync(&releaseFenceFd); |
| if (res != OK) { |
| ALOGE("%s unlock buffer failed on iamge %p.", __FUNCTION__, this); |
| *fenceFd = -1; |
| return AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE; |
| } |
| |
| *fenceFd = releaseFenceFd; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getPlanePixelStride(int planeIdx, /*out*/int32_t* pixelStride) const { |
| if (mLockedBuffer == nullptr) { |
| ALOGE("%s: buffer not locked.", __FUNCTION__); |
| return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED; |
| } |
| |
| if (planeIdx < 0 || planeIdx >= mNumPlanes) { |
| ALOGE("Error: planeIdx %d out of bound [0,%d]", |
| planeIdx, mNumPlanes - 1); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| if (pixelStride == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| int32_t fmt = mLockedBuffer->flexFormat; |
| switch (fmt) { |
| case HAL_PIXEL_FORMAT_YCbCr_420_888: |
| *pixelStride = (planeIdx == 0) ? 1 : mLockedBuffer->chromaStep; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
| *pixelStride = (planeIdx == 0) ? 1 : 2; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_YCBCR_P010: |
| if (mLockedBuffer->dataCb && mLockedBuffer->dataCr) { |
| *pixelStride = (planeIdx == 0) ? 2 : mLockedBuffer->chromaStep; |
| } else { |
| *pixelStride = (planeIdx == 0) ? 2 : 4; |
| } |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_Y8: |
| *pixelStride = 1; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_YV12: |
| *pixelStride = 1; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_Y16: |
| case HAL_PIXEL_FORMAT_RAW16: |
| case HAL_PIXEL_FORMAT_RGB_565: |
| // Single plane 16bpp data. |
| *pixelStride = 2; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_RGBA_8888: |
| case HAL_PIXEL_FORMAT_RGBX_8888: |
| *pixelStride = 4; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_RGB_888: |
| // Single plane, 24bpp. |
| *pixelStride = 3; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_BLOB: |
| case HAL_PIXEL_FORMAT_RAW10: |
| case HAL_PIXEL_FORMAT_RAW12: |
| case HAL_PIXEL_FORMAT_RAW_OPAQUE: |
| // Blob is used for JPEG data, RAW10 and RAW12 is used for 10-bit and 12-bit raw data, |
| // those are single plane data without pixel stride defined |
| return AMEDIA_ERROR_UNSUPPORTED; |
| default: |
| ALOGE("Pixel format: 0x%x is unsupported", fmt); |
| return AMEDIA_ERROR_UNSUPPORTED; |
| } |
| } |
| |
| media_status_t |
| AImage::getPlaneRowStride(int planeIdx, /*out*/int32_t* rowStride) const { |
| if (mLockedBuffer == nullptr) { |
| ALOGE("%s: buffer not locked.", __FUNCTION__); |
| return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED; |
| } |
| |
| if (planeIdx < 0 || planeIdx >= mNumPlanes) { |
| ALOGE("Error: planeIdx %d out of bound [0,%d]", |
| planeIdx, mNumPlanes - 1); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| if (rowStride == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| int32_t fmt = mLockedBuffer->flexFormat; |
| switch (fmt) { |
| case HAL_PIXEL_FORMAT_YCbCr_420_888: |
| *rowStride = (planeIdx == 0) ? mLockedBuffer->stride |
| : mLockedBuffer->chromaStride; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
| *rowStride = mLockedBuffer->width; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_YV12: |
| if (mLockedBuffer->stride % 16) { |
| ALOGE("Stride %d is not 16 pixel aligned!", mLockedBuffer->stride); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| *rowStride = (planeIdx == 0) ? mLockedBuffer->stride |
| : ALIGN(mLockedBuffer->stride / 2, 16); |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_YCBCR_P010: |
| if (mLockedBuffer->dataCb && mLockedBuffer->dataCr) { |
| *rowStride = (planeIdx == 0) ? mLockedBuffer->stride : mLockedBuffer->chromaStride; |
| } else { |
| *rowStride = mLockedBuffer->stride * 2; |
| } |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_RAW10: |
| case HAL_PIXEL_FORMAT_RAW12: |
| // RAW10 and RAW12 are used for 10-bit and 12-bit raw data, they are single plane |
| *rowStride = mLockedBuffer->stride; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_Y8: |
| if (mLockedBuffer->stride % 16) { |
| ALOGE("Stride %d is not 16 pixel aligned!", |
| mLockedBuffer->stride); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| *rowStride = mLockedBuffer->stride; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_Y16: |
| case HAL_PIXEL_FORMAT_RAW16: |
| // In native side, strides are specified in pixels, not in bytes. |
| // Single plane 16bpp bayer data. even width/height, |
| // row stride multiple of 16 pixels (32 bytes) |
| if (mLockedBuffer->stride % 16) { |
| ALOGE("Stride %d is not 16 pixel aligned!", |
| mLockedBuffer->stride); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| *rowStride = mLockedBuffer->stride * 2; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_RGB_565: |
| *rowStride = mLockedBuffer->stride * 2; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_RGBA_8888: |
| case HAL_PIXEL_FORMAT_RGBX_8888: |
| *rowStride = mLockedBuffer->stride * 4; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_RGB_888: |
| // Single plane, 24bpp. |
| *rowStride = mLockedBuffer->stride * 3; |
| return AMEDIA_OK; |
| case HAL_PIXEL_FORMAT_BLOB: |
| case HAL_PIXEL_FORMAT_RAW_OPAQUE: |
| // Blob is used for JPEG/Raw opaque data. It is single plane and has 0 row stride and |
| // no row stride defined |
| return AMEDIA_ERROR_UNSUPPORTED; |
| default: |
| ALOGE("%s Pixel format: 0x%x is unsupported", __FUNCTION__, fmt); |
| return AMEDIA_ERROR_UNSUPPORTED; |
| } |
| } |
| |
| uint32_t |
| AImage::getJpegSize() const { |
| if (mLockedBuffer == nullptr) { |
| LOG_ALWAYS_FATAL("Error: buffer is null"); |
| } |
| |
| uint32_t size = 0; |
| uint32_t width = mLockedBuffer->width; |
| uint8_t* jpegBuffer = mLockedBuffer->data; |
| |
| // First check for JPEG transport header at the end of the buffer |
| uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob_v2)); |
| struct camera3_jpeg_blob_v2* blob = (struct camera3_jpeg_blob_v2*)(header); |
| if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) { |
| size = blob->jpeg_size; |
| ALOGV("%s: Jpeg size = %d", __FUNCTION__, size); |
| } |
| |
| // failed to find size, default to whole buffer |
| if (size == 0) { |
| /* |
| * This is a problem because not including the JPEG header |
| * means that in certain rare situations a regular JPEG blob |
| * will be misidentified as having a header, in which case |
| * we will get a garbage size value. |
| */ |
| ALOGW("%s: No JPEG header detected, defaulting to size=width=%d", |
| __FUNCTION__, width); |
| size = width; |
| } |
| |
| return size; |
| } |
| |
| media_status_t |
| AImage::getPlaneData(int planeIdx,/*out*/uint8_t** data, /*out*/int* dataLength) const { |
| if (mLockedBuffer == nullptr) { |
| ALOGE("%s: buffer not locked.", __FUNCTION__); |
| return AMEDIA_IMGREADER_IMAGE_NOT_LOCKED; |
| } |
| |
| if (planeIdx < 0 || planeIdx >= mNumPlanes) { |
| ALOGE("Error: planeIdx %d out of bound [0,%d]", |
| planeIdx, mNumPlanes - 1); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| if (data == nullptr || dataLength == nullptr) { |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| if (isClosed()) { |
| ALOGE("%s: image %p has been closed!", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| |
| uint32_t dataSize, ySize, cSize, cStride; |
| uint8_t* cb = nullptr; |
| uint8_t* cr = nullptr; |
| uint8_t* pData = nullptr; |
| int bytesPerPixel = 0; |
| int32_t fmt = mLockedBuffer->flexFormat; |
| |
| switch (fmt) { |
| case HAL_PIXEL_FORMAT_YCbCr_420_888: |
| pData = (planeIdx == 0) ? mLockedBuffer->data |
| : (planeIdx == 1) ? mLockedBuffer->dataCb |
| : mLockedBuffer->dataCr; |
| // only map until last pixel |
| if (planeIdx == 0) { |
| dataSize = mLockedBuffer->stride * (mLockedBuffer->height - 1) + |
| mLockedBuffer->width; |
| } else { |
| dataSize = |
| mLockedBuffer->chromaStride * |
| (mLockedBuffer->height / 2 - 1) + |
| mLockedBuffer->chromaStep * (mLockedBuffer->width / 2 - 1) + |
| 1; |
| } |
| break; |
| // NV21 |
| case HAL_PIXEL_FORMAT_YCrCb_420_SP: |
| cr = mLockedBuffer->data + |
| (mLockedBuffer->stride * mLockedBuffer->height); |
| cb = cr + 1; |
| // only map until last pixel |
| ySize = mLockedBuffer->width * (mLockedBuffer->height - 1) + |
| mLockedBuffer->width; |
| cSize = mLockedBuffer->width * (mLockedBuffer->height / 2 - 1) + |
| mLockedBuffer->width - 1; |
| pData = (planeIdx == 0) ? mLockedBuffer->data |
| : (planeIdx == 1) ? cb : cr; |
| dataSize = (planeIdx == 0) ? ySize : cSize; |
| break; |
| case HAL_PIXEL_FORMAT_YV12: |
| // Y and C stride need to be 16 pixel aligned. |
| if (mLockedBuffer->stride % 16) { |
| ALOGE("Stride %d is not 16 pixel aligned!", |
| mLockedBuffer->stride); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| ySize = mLockedBuffer->stride * mLockedBuffer->height; |
| cStride = ALIGN(mLockedBuffer->stride / 2, 16); |
| cr = mLockedBuffer->data + ySize; |
| cSize = cStride * mLockedBuffer->height / 2; |
| cb = cr + cSize; |
| |
| pData = (planeIdx == 0) ? mLockedBuffer->data |
| : (planeIdx == 1) ? cb : cr; |
| dataSize = (planeIdx == 0) ? ySize : cSize; |
| break; |
| case HAL_PIXEL_FORMAT_YCBCR_P010: |
| if (mLockedBuffer->height % 2 != 0) { |
| ALOGE("YCBCR_P010: height (%d) should be a multiple of 2", mLockedBuffer->height); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| if (mLockedBuffer->width <= 0) { |
| ALOGE("YCBCR_P010: width (%d) should be a > 0", mLockedBuffer->width); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| if (mLockedBuffer->height <= 0) { |
| ALOGE("YCBCR_P010: height (%d) should be a > 0", mLockedBuffer->height); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| if (mLockedBuffer->dataCb && mLockedBuffer->dataCr) { |
| pData = (planeIdx == 0) ? mLockedBuffer->data : |
| (planeIdx == 1) ? mLockedBuffer->dataCb : mLockedBuffer->dataCr; |
| // only map until last pixel |
| if (planeIdx == 0) { |
| cStride = mLockedBuffer->stride; |
| dataSize = cStride * (mLockedBuffer->height - 1) + mLockedBuffer->width * 2; |
| } else { |
| bytesPerPixel = mLockedBuffer->chromaStep; |
| cStride = mLockedBuffer->chromaStride; |
| dataSize = cStride * (mLockedBuffer->height / 2 - 1) + |
| bytesPerPixel * (mLockedBuffer->width / 2); |
| } |
| break; |
| } |
| |
| cStride = mLockedBuffer->stride * 2; |
| ySize = cStride * mLockedBuffer->height; |
| cSize = ySize / 2; |
| cb = mLockedBuffer->data + ySize; |
| cr = cb + 2; |
| |
| pData = (planeIdx == 0) ? mLockedBuffer->data : (planeIdx == 1) ? cb : cr; |
| dataSize = (planeIdx == 0) ? ySize : cSize; |
| break; |
| case HAL_PIXEL_FORMAT_Y8: |
| // Single plane, 8bpp. |
| |
| pData = mLockedBuffer->data; |
| dataSize = mLockedBuffer->stride * mLockedBuffer->height; |
| break; |
| case HAL_PIXEL_FORMAT_Y16: |
| bytesPerPixel = 2; |
| |
| pData = mLockedBuffer->data; |
| dataSize = |
| mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel; |
| break; |
| case HAL_PIXEL_FORMAT_BLOB: |
| // Used for JPEG data, height must be 1, width == size, single plane. |
| if (mLockedBuffer->height != 1) { |
| ALOGE("Jpeg should have height value one but got %d", |
| mLockedBuffer->height); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| |
| pData = mLockedBuffer->data; |
| dataSize = getJpegSize(); |
| break; |
| case HAL_PIXEL_FORMAT_RAW16: |
| // Single plane 16bpp bayer data. |
| bytesPerPixel = 2; |
| pData = mLockedBuffer->data; |
| dataSize = |
| mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel; |
| break; |
| case HAL_PIXEL_FORMAT_RAW_OPAQUE: |
| // Used for RAW_OPAQUE data, height must be 1, width == size, single plane. |
| if (mLockedBuffer->height != 1) { |
| ALOGE("RAW_OPAQUE should have height value one but got %d", |
| mLockedBuffer->height); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| pData = mLockedBuffer->data; |
| dataSize = mLockedBuffer->width; |
| break; |
| case HAL_PIXEL_FORMAT_RAW10: |
| // Single plane 10bpp bayer data. |
| if (mLockedBuffer->width % 4) { |
| ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| if (mLockedBuffer->height % 2) { |
| ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| if (mLockedBuffer->stride < (mLockedBuffer->width * 10 / 8)) { |
| ALOGE("stride (%d) should be at least %d", |
| mLockedBuffer->stride, mLockedBuffer->width * 10 / 8); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| pData = mLockedBuffer->data; |
| dataSize = mLockedBuffer->stride * mLockedBuffer->height; |
| break; |
| case HAL_PIXEL_FORMAT_RAW12: |
| // Single plane 10bpp bayer data. |
| if (mLockedBuffer->width % 4) { |
| ALOGE("Width is not multiple of 4 %d", mLockedBuffer->width); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| if (mLockedBuffer->height % 2) { |
| ALOGE("Height is not multiple of 2 %d", mLockedBuffer->height); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| if (mLockedBuffer->stride < (mLockedBuffer->width * 12 / 8)) { |
| ALOGE("stride (%d) should be at least %d", |
| mLockedBuffer->stride, mLockedBuffer->width * 12 / 8); |
| return AMEDIA_ERROR_UNKNOWN; |
| } |
| pData = mLockedBuffer->data; |
| dataSize = mLockedBuffer->stride * mLockedBuffer->height; |
| break; |
| case HAL_PIXEL_FORMAT_RGBA_8888: |
| case HAL_PIXEL_FORMAT_RGBX_8888: |
| // Single plane, 32bpp. |
| bytesPerPixel = 4; |
| pData = mLockedBuffer->data; |
| dataSize = |
| mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel; |
| break; |
| case HAL_PIXEL_FORMAT_RGB_565: |
| // Single plane, 16bpp. |
| bytesPerPixel = 2; |
| pData = mLockedBuffer->data; |
| dataSize = |
| mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel; |
| break; |
| case HAL_PIXEL_FORMAT_RGB_888: |
| // Single plane, 24bpp. |
| bytesPerPixel = 3; |
| pData = mLockedBuffer->data; |
| dataSize = mLockedBuffer->stride * mLockedBuffer->height * bytesPerPixel; |
| break; |
| default: |
| ALOGE("Pixel format: 0x%x is unsupported", fmt); |
| return AMEDIA_ERROR_UNSUPPORTED; |
| } |
| |
| *data = pData; |
| *dataLength = dataSize; |
| return AMEDIA_OK; |
| } |
| |
| media_status_t |
| AImage::getHardwareBuffer(/*out*/AHardwareBuffer** buffer) const { |
| if (mBuffer == nullptr || mBuffer->mGraphicBuffer == nullptr) { |
| ALOGE("%s: AImage %p has no buffer.", __FUNCTION__, this); |
| return AMEDIA_ERROR_INVALID_OBJECT; |
| } |
| |
| // TODO(jwcai) Someone from Android graphics team stating this should just be a static_cast. |
| *buffer = reinterpret_cast<AHardwareBuffer*>(mBuffer->mGraphicBuffer.get()); |
| return AMEDIA_OK; |
| } |
| |
| EXPORT |
| void AImage_delete(AImage* image) { |
| ALOGV("%s", __FUNCTION__); |
| AImage_deleteAsync(image, -1); |
| return; |
| } |
| |
| EXPORT |
| void AImage_deleteAsync(AImage* image, int releaseFenceFd) { |
| ALOGV("%s", __FUNCTION__); |
| if (image != nullptr) { |
| image->lockReader(); |
| image->close(releaseFenceFd); |
| image->unlockReader(); |
| if (!image->isClosed()) { |
| LOG_ALWAYS_FATAL("Image close failed!"); |
| } |
| image->free(); |
| } |
| return; |
| } |
| |
| EXPORT |
| media_status_t AImage_getWidth(const AImage* image, /*out*/int32_t* width) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || width == nullptr) { |
| ALOGE("%s: bad argument. image %p width %p", |
| __FUNCTION__, image, width); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getWidth(width); |
| } |
| |
| EXPORT |
| media_status_t AImage_getHeight(const AImage* image, /*out*/int32_t* height) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || height == nullptr) { |
| ALOGE("%s: bad argument. image %p height %p", |
| __FUNCTION__, image, height); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getHeight(height); |
| } |
| |
| EXPORT |
| media_status_t AImage_getFormat(const AImage* image, /*out*/int32_t* format) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || format == nullptr) { |
| ALOGE("%s: bad argument. image %p format %p", |
| __FUNCTION__, image, format); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getFormat(format); |
| } |
| |
| EXPORT |
| media_status_t AImage_getCropRect(const AImage* image, /*out*/AImageCropRect* rect) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || rect == nullptr) { |
| ALOGE("%s: bad argument. image %p rect %p", |
| __FUNCTION__, image, rect); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| // For now AImage only supports camera outputs where cropRect is always full window |
| int32_t width = -1; |
| media_status_t ret = image->getWidth(&width); |
| if (ret != AMEDIA_OK) { |
| return ret; |
| } |
| int32_t height = -1; |
| ret = image->getHeight(&height); |
| if (ret != AMEDIA_OK) { |
| return ret; |
| } |
| rect->left = 0; |
| rect->top = 0; |
| rect->right = width; |
| rect->bottom = height; |
| return AMEDIA_OK; |
| } |
| |
| EXPORT |
| media_status_t AImage_getTimestamp(const AImage* image, /*out*/int64_t* timestampNs) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || timestampNs == nullptr) { |
| ALOGE("%s: bad argument. image %p timestampNs %p", |
| __FUNCTION__, image, timestampNs); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getTimestamp(timestampNs); |
| } |
| |
| EXPORT |
| media_status_t AImage_getNumberOfPlanes(const AImage* image, /*out*/int32_t* numPlanes) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || numPlanes == nullptr) { |
| ALOGE("%s: bad argument. image %p numPlanes %p", |
| __FUNCTION__, image, numPlanes); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getNumPlanes(numPlanes); |
| } |
| |
| EXPORT |
| media_status_t AImage_getPlanePixelStride( |
| const AImage* image, int planeIdx, /*out*/int32_t* pixelStride) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || pixelStride == nullptr) { |
| ALOGE("%s: bad argument. image %p pixelStride %p", |
| __FUNCTION__, image, pixelStride); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| media_status_t ret = const_cast<AImage*>(image)->lockImage(); |
| if (ret != AMEDIA_OK) { |
| ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.", |
| __FUNCTION__, image, ret); |
| return ret; |
| } |
| return image->getPlanePixelStride(planeIdx, pixelStride); |
| } |
| |
| EXPORT |
| media_status_t AImage_getPlaneRowStride( |
| const AImage* image, int planeIdx, /*out*/int32_t* rowStride) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || rowStride == nullptr) { |
| ALOGE("%s: bad argument. image %p rowStride %p", |
| __FUNCTION__, image, rowStride); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| media_status_t ret = const_cast<AImage*>(image)->lockImage(); |
| if (ret != AMEDIA_OK) { |
| ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.", |
| __FUNCTION__, image, ret); |
| return ret; |
| } |
| return image->getPlaneRowStride(planeIdx, rowStride); |
| } |
| |
| EXPORT |
| media_status_t AImage_getPlaneData( |
| const AImage* image, int planeIdx, |
| /*out*/uint8_t** data, /*out*/int* dataLength) { |
| ALOGV("%s", __FUNCTION__); |
| if (image == nullptr || data == nullptr || dataLength == nullptr) { |
| ALOGE("%s: bad argument. image %p data %p dataLength %p", |
| __FUNCTION__, image, data, dataLength); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| media_status_t ret = const_cast<AImage*>(image)->lockImage(); |
| if (ret != AMEDIA_OK) { |
| ALOGE("%s: failed to lock buffer for CPU access. image %p, error=%d.", |
| __FUNCTION__, image, ret); |
| return ret; |
| } |
| return image->getPlaneData(planeIdx, data, dataLength); |
| } |
| |
| EXPORT |
| media_status_t AImage_getHardwareBuffer( |
| const AImage* image, /*out*/AHardwareBuffer** buffer) { |
| ALOGV("%s", __FUNCTION__); |
| |
| if (image == nullptr || buffer == nullptr) { |
| ALOGE("%s: bad argument. image %p buffer %p", __FUNCTION__, image, buffer); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getHardwareBuffer(buffer); |
| } |
| |
| EXPORT |
| media_status_t AImage_getDataSpace( |
| const AImage* image, /*out*/int32_t* dataSpace) { |
| ALOGV("%s", __FUNCTION__); |
| |
| if (image == nullptr || dataSpace == nullptr) { |
| ALOGE("%s: bad argument. image %p dataSpace %p", __FUNCTION__, image, dataSpace); |
| return AMEDIA_ERROR_INVALID_PARAMETER; |
| } |
| return image->getDataSpace((android_dataspace*)(dataSpace)); |
| } |