Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79f135dc authored by Zhijun He's avatar Zhijun He Committed by android-build-merger
Browse files

Merge "ImageReader/Writer: refactor and cleanup" into nyc-dev

am: 924dd555

* commit '924dd555':
  ImageReader/Writer: refactor and cleanup
parents 6ecfd615 924dd555
Loading
Loading
Loading
Loading
+24 −28
Original line number Diff line number Diff line
@@ -335,7 +335,6 @@ public class ImageReader implements AutoCloseable {

            switch (status) {
                case ACQUIRE_SUCCESS:
                    si.createSurfacePlanes();
                    si.mIsImageValid = true;
                case ACQUIRE_NO_BUFS:
                case ACQUIRE_MAX_IMAGES:
@@ -693,7 +692,7 @@ public class ImageReader implements AutoCloseable {
                    width = ImageReader.this.getWidth();
                    break;
                default:
                    width = nativeGetWidth(mFormat);
                    width = nativeGetWidth();
            }
            return width;
        }
@@ -709,7 +708,7 @@ public class ImageReader implements AutoCloseable {
                    height = ImageReader.this.getHeight();
                    break;
                default:
                    height = nativeGetHeight(mFormat);
                    height = nativeGetHeight();
            }
            return height;
        }
@@ -729,6 +728,10 @@ public class ImageReader implements AutoCloseable {
        @Override
        public Plane[] getPlanes() {
            throwISEIfImageIsInvalid();

            if (mPlanes == null) {
                mPlanes = nativeCreatePlanes(ImageReader.this.mNumPlanes, ImageReader.this.mFormat);
            }
            // Shallow copy is fine.
            return mPlanes.clone();
        }
@@ -766,7 +769,8 @@ public class ImageReader implements AutoCloseable {
        }

        private void clearSurfacePlanes() {
            if (mIsImageValid) {
            // Image#getPlanes may not be called before the image is closed.
            if (mIsImageValid && mPlanes != null) {
                for (int i = 0; i < mPlanes.length; i++) {
                    if (mPlanes[i] != null) {
                        mPlanes[i].clearBuffer();
@@ -776,32 +780,25 @@ public class ImageReader implements AutoCloseable {
            }
        }

        private void createSurfacePlanes() {
            mPlanes = new SurfacePlane[ImageReader.this.mNumPlanes];
            for (int i = 0; i < ImageReader.this.mNumPlanes; i++) {
                mPlanes[i] = nativeCreatePlane(i, ImageReader.this.mFormat);
            }
        }
        private class SurfacePlane extends android.media.Image.Plane {
            // SurfacePlane instance is created by native code when a new SurfaceImage is created
            private SurfacePlane(int index, int rowStride, int pixelStride) {
                mIndex = index;
            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
            // called
            private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
                mRowStride = rowStride;
                mPixelStride = pixelStride;
                mBuffer = buffer;
                /**
                 * Set the byteBuffer order according to host endianness (native
                 * order), otherwise, the byteBuffer order defaults to
                 * ByteOrder.BIG_ENDIAN.
                 */
                mBuffer.order(ByteOrder.nativeOrder());
            }

            @Override
            public ByteBuffer getBuffer() {
                SurfaceImage.this.throwISEIfImageIsInvalid();
                if (mBuffer != null) {
                throwISEIfImageIsInvalid();
                return mBuffer;
                } else {
                    mBuffer = SurfaceImage.this.nativeImageGetBuffer(mIndex,
                            ImageReader.this.mFormat);
                    // Set the byteBuffer order according to host endianness (native order),
                    // otherwise, the byteBuffer order defaults to ByteOrder.BIG_ENDIAN.
                    return mBuffer.order(ByteOrder.nativeOrder());
                }
            }

            @Override
@@ -837,7 +834,6 @@ public class ImageReader implements AutoCloseable {
                mBuffer = null;
            }

            final private int mIndex;
            final private int mPixelStride;
            final private int mRowStride;

@@ -860,10 +856,10 @@ public class ImageReader implements AutoCloseable {
        // If this image is detached from the ImageReader.
        private AtomicBoolean mIsDetached = new AtomicBoolean(false);

        private synchronized native ByteBuffer nativeImageGetBuffer(int idx, int readerFormat);
        private synchronized native SurfacePlane nativeCreatePlane(int idx, int readerFormat);
        private synchronized native int nativeGetWidth(int format);
        private synchronized native int nativeGetHeight(int format);
        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes,
                int readerFormat);
        private synchronized native int nativeGetWidth();
        private synchronized native int nativeGetHeight();
        private synchronized native int nativeGetFormat(int readerFormat);
    }

+3 −3
Original line number Diff line number Diff line
@@ -748,8 +748,8 @@ public class ImageWriter implements AutoCloseable {
            final private int mPixelStride;
            final private int mRowStride;

            // SurfacePlane instance is created by native code when a new
            // SurfaceImage is created
            // SurfacePlane instance is created by native code when SurfaceImage#getPlanes() is
            // called
            private SurfacePlane(int rowStride, int pixelStride, ByteBuffer buffer) {
                mRowStride = rowStride;
                mPixelStride = pixelStride;
@@ -795,7 +795,7 @@ public class ImageWriter implements AutoCloseable {

        }

        // this will create the SurfacePlane object and fill the information
        // Create the SurfacePlane object and fill the information
        private synchronized native SurfacePlane[] nativeCreatePlanes(int numPlanes, int writerFmt);

        private synchronized native int nativeGetWidth();
+291 −809

File changed.

Preview size limit exceeded, changes collapsed.

+26 −325
Original line number Diff line number Diff line
@@ -16,34 +16,28 @@

//#define LOG_NDEBUG 0
#define LOG_TAG "ImageWriter_JNI"
#include "android_media_Utils.h"

#include <utils/Log.h>
#include <utils/String8.h>

#include <gui/IProducerListener.h>
#include <gui/Surface.h>
#include <gui/CpuConsumer.h>
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/android_view_Surface.h>
#include <camera3.h>

#include <jni.h>
#include <JNIHelp.h>

#include <stdint.h>
#include <inttypes.h>

#define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )

#define IMAGE_BUFFER_JNI_ID           "mNativeBuffer"

// ----------------------------------------------------------------------------

using namespace android;

enum {
    IMAGE_WRITER_MAX_NUM_PLANES = 3,
};

static struct {
    jmethodID postEventFromNative;
    jfieldID mWriterFormat;
@@ -60,8 +54,6 @@ static struct {
    jmethodID ctor;
} gSurfacePlaneClassInfo;

typedef CpuConsumer::LockedBuffer LockedImage;

// ----------------------------------------------------------------------------

class JNIImageWriterContext : public BnProducerListener {
@@ -181,13 +173,11 @@ extern "C" {

// -------------------------------Private method declarations--------------

static bool isPossiblyYUV(PixelFormat format);
static void Image_setNativeContext(JNIEnv* env, jobject thiz,
        sp<GraphicBuffer> buffer, int fenceFd);
static void Image_getNativeContext(JNIEnv* env, jobject thiz,
        GraphicBuffer** buffer, int* fenceFd);
static void Image_unlockIfLocked(JNIEnv* env, jobject thiz);
static bool isFormatOpaque(int format);

// --------------------------ImageWriter methods---------------------------------------

@@ -672,28 +662,6 @@ static jint Image_getHeight(JNIEnv* env, jobject thiz) {
    return buffer->getHeight();
}

// Some formats like JPEG defined with different values between android.graphics.ImageFormat and
// graphics.h, need convert to the one defined in graphics.h here.
static int Image_getPixelFormat(JNIEnv* env, int format) {
    int jpegFormat;
    jfieldID fid;

    ALOGV("%s: format = 0x%x", __FUNCTION__, format);

    jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
    ALOG_ASSERT(imageFormatClazz != NULL);

    fid = env->GetStaticFieldID(imageFormatClazz, "JPEG", "I");
    jpegFormat = env->GetStaticIntField(imageFormatClazz, fid);

    // Translate the JPEG to BLOB for camera purpose.
    if (format == jpegFormat) {
        format = HAL_PIXEL_FORMAT_BLOB;
    }

    return format;
}

static jint Image_getFormat(JNIEnv* env, jobject thiz) {
    ALOGV("%s", __FUNCTION__);
    GraphicBuffer* buffer;
@@ -704,7 +672,10 @@ static jint Image_getFormat(JNIEnv* env, jobject thiz) {
        return 0;
    }

    return Image_getPixelFormat(env, buffer->getPixelFormat());
    // ImageWriter doesn't support data space yet, assuming it is unknown.
    PublicFormat publicFmt = android_view_Surface_mapHalFormatDataspaceToPublicFormat(
            buffer->getPixelFormat(), HAL_DATASPACE_UNKNOWN);
    return static_cast<jint>(publicFmt);
}

static void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
@@ -723,272 +694,34 @@ static void Image_getLockedImage(JNIEnv* env, jobject thiz, LockedImage *image)
        return;
    }

    void* pData = NULL;
    android_ycbcr ycbcr = android_ycbcr();
    status_t res;
    int format = Image_getFormat(env, thiz);
    int flexFormat = format;
    if (isPossiblyYUV(format)) {
    // ImageWriter doesn't use crop by itself, app sets it, use the no crop version.
        res = buffer->lockAsyncYCbCr(GRALLOC_USAGE_SW_WRITE_OFTEN, &ycbcr, fenceFd);
    const Rect noCrop(buffer->width, buffer->height);
    status_t res = lockImageFromBuffer(
            buffer, GRALLOC_USAGE_SW_WRITE_OFTEN, noCrop, fenceFd, image);
    // Clear the fenceFd as it is already consumed by lock call.
    Image_setFenceFd(env, thiz, /*fenceFd*/-1);
    if (res != OK) {
            jniThrowRuntimeException(env, "lockAsyncYCbCr failed for YUV buffer");
        jniThrowExceptionFmt(env, "java/lang/RuntimeException",
                "lock buffer failed for format 0x%x",
                buffer->getPixelFormat());
        return;
    }
        pData = ycbcr.y;
        flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
    }

    // lockAsyncYCbCr for YUV is unsuccessful.
    if (pData == NULL) {
        res = buffer->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, &pData, fenceFd);
        if (res != OK) {
            jniThrowRuntimeException(env, "lockAsync failed");
            return;
        }
    }

    image->data = reinterpret_cast<uint8_t*>(pData);
    image->width = buffer->getWidth();
    image->height = buffer->getHeight();
    image->format = format;
    image->flexFormat = flexFormat;
    image->stride = (ycbcr.y != NULL) ? static_cast<uint32_t>(ycbcr.ystride) : buffer->getStride();

    image->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
    image->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
    image->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
    image->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
    ALOGV("Successfully locked the image");
    ALOGV("%s: Successfully locked the image", __FUNCTION__);
    // crop, transform, scalingMode, timestamp, and frameNumber should be set by producer,
    // and we don't set them here.
}

static bool usingRGBAToJpegOverride(int32_t bufferFormat, int32_t writerCtxFormat) {
    return writerCtxFormat == HAL_PIXEL_FORMAT_BLOB && bufferFormat == HAL_PIXEL_FORMAT_RGBA_8888;
}

static int32_t applyFormatOverrides(int32_t bufferFormat, int32_t writerCtxFormat)
{
    // Using HAL_PIXEL_FORMAT_RGBA_8888 gralloc buffers containing JPEGs to get around SW
    // write limitations for some platforms (b/17379185).
    if (usingRGBAToJpegOverride(bufferFormat, writerCtxFormat)) {
        return HAL_PIXEL_FORMAT_BLOB;
    }
    return bufferFormat;
}

static uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride) {
    ALOGV("%s", __FUNCTION__);
    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
    uint32_t size = 0;
    uint32_t width = buffer->width;
    uint8_t* jpegBuffer = buffer->data;

    if (usingRGBAOverride) {
        width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
    }

    // First check for JPEG transport header at the end of the buffer
    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
    struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(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;
}

static void Image_getLockedImageInfo(JNIEnv* env, LockedImage* buffer, int idx,
        int32_t writerFormat, uint8_t **base, uint32_t *size, int *pixelStride, int *rowStride) {
    ALOGV("%s", __FUNCTION__);
    ALOG_ASSERT(buffer != NULL, "Input buffer is NULL!!!");
    ALOG_ASSERT(base != NULL, "base is NULL!!!");
    ALOG_ASSERT(size != NULL, "size is NULL!!!");
    ALOG_ASSERT(pixelStride != NULL, "pixelStride is NULL!!!");
    ALOG_ASSERT(rowStride != NULL, "rowStride is NULL!!!");
    ALOG_ASSERT((idx < IMAGE_WRITER_MAX_NUM_PLANES) && (idx >= 0));

    ALOGV("%s: buffer: %p", __FUNCTION__, buffer);

    uint32_t dataSize, ySize, cSize, cStride;
    uint32_t pStride = 0, rStride = 0;
    uint8_t *cb, *cr;
    uint8_t *pData = NULL;
    int bytesPerPixel = 0;

    dataSize = ySize = cSize = cStride = 0;
    int32_t fmt = buffer->flexFormat;

    bool usingRGBAOverride = usingRGBAToJpegOverride(fmt, writerFormat);
    fmt = applyFormatOverrides(fmt, writerFormat);
    switch (fmt) {
        case HAL_PIXEL_FORMAT_YCbCr_420_888:
            pData =
                (idx == 0) ?
                    buffer->data :
                (idx == 1) ?
                    buffer->dataCb :
                buffer->dataCr;
            // only map until last pixel
            if (idx == 0) {
                pStride = 1;
                rStride = buffer->stride;
                dataSize = buffer->stride * (buffer->height - 1) + buffer->width;
            } else {
                pStride = buffer->chromaStep;
                rStride = buffer->chromaStride;
                dataSize = buffer->chromaStride * (buffer->height / 2 - 1) +
                        buffer->chromaStep * (buffer->width / 2 - 1) + 1;
            }
            break;
        // NV21
        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
            cr = buffer->data + (buffer->stride * buffer->height);
            cb = cr + 1;
            // only map until last pixel
            ySize = buffer->width * (buffer->height - 1) + buffer->width;
            cSize = buffer->width * (buffer->height / 2 - 1) + buffer->width - 1;

            pData =
                (idx == 0) ?
                    buffer->data :
                (idx == 1) ?
                    cb:
                cr;

            dataSize = (idx == 0) ? ySize : cSize;
            pStride = (idx == 0) ? 1 : 2;
            rStride = buffer->width;
            break;
        case HAL_PIXEL_FORMAT_YV12:
            // Y and C stride need to be 16 pixel aligned.
            LOG_ALWAYS_FATAL_IF(buffer->stride % 16,
                                "Stride is not 16 pixel aligned %d", buffer->stride);

            ySize = buffer->stride * buffer->height;
            cStride = ALIGN(buffer->stride / 2, 16);
            cr = buffer->data + ySize;
            cSize = cStride * buffer->height / 2;
            cb = cr + cSize;

            pData =
                (idx == 0) ?
                    buffer->data :
                (idx == 1) ?
                    cb :
                cr;
            dataSize = (idx == 0) ? ySize : cSize;
            pStride = 1;
            rStride = (idx == 0) ? buffer->stride : ALIGN(buffer->stride / 2, 16);
            break;
        case HAL_PIXEL_FORMAT_Y8:
            // Single plane, 8bpp.
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);

            pData = buffer->data;
            dataSize = buffer->stride * buffer->height;
            pStride = 1;
            rStride = buffer->stride;
            break;
        case HAL_PIXEL_FORMAT_Y16:
            bytesPerPixel = 2;
            // Single plane, 16bpp, strides are specified in pixels, not in bytes
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);

            pData = buffer->data;
            dataSize = buffer->stride * buffer->height * bytesPerPixel;
            pStride = bytesPerPixel;
            rStride = buffer->stride * 2;
            break;
        case HAL_PIXEL_FORMAT_BLOB:
            // Used for JPEG data, height must be 1, width == size, single plane.
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
            ALOG_ASSERT(buffer->height == 1, "JPEG should has height value %d", buffer->height);

            pData = buffer->data;
            dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
            pStride = bytesPerPixel;
            rowStride = 0;
            break;
        case HAL_PIXEL_FORMAT_RAW16:
            // Single plane 16bpp bayer data.
            bytesPerPixel = 2;
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
            pData = buffer->data;
            dataSize = buffer->stride * buffer->height * bytesPerPixel;
            pStride = bytesPerPixel;
            rStride = buffer->stride * 2;
            break;
        case HAL_PIXEL_FORMAT_RAW10:
            // Single plane 10bpp bayer data.
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
            LOG_ALWAYS_FATAL_IF(buffer->width % 4,
                                "Width is not multiple of 4 %d", buffer->width);
            LOG_ALWAYS_FATAL_IF(buffer->height % 2,
                                "Height is not even %d", buffer->height);
            LOG_ALWAYS_FATAL_IF(buffer->stride < (buffer->width * 10 / 8),
                                "stride (%d) should be at least %d",
                                buffer->stride, buffer->width * 10 / 8);
            pData = buffer->data;
            dataSize = buffer->stride * buffer->height;
            pStride = 0;
            rStride = buffer->stride;
            break;
        case HAL_PIXEL_FORMAT_RGBA_8888:
        case HAL_PIXEL_FORMAT_RGBX_8888:
            // Single plane, 32bpp.
            bytesPerPixel = 4;
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
            pData = buffer->data;
            dataSize = buffer->stride * buffer->height * bytesPerPixel;
            pStride = bytesPerPixel;
            rStride = buffer->stride * 4;
            break;
        case HAL_PIXEL_FORMAT_RGB_565:
            // Single plane, 16bpp.
            bytesPerPixel = 2;
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
            pData = buffer->data;
            dataSize = buffer->stride * buffer->height * bytesPerPixel;
            pStride = bytesPerPixel;
            rStride = buffer->stride * 2;
            break;
        case HAL_PIXEL_FORMAT_RGB_888:
            // Single plane, 24bpp.
            bytesPerPixel = 3;
            ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
            pData = buffer->data;
            dataSize = buffer->stride * buffer->height * bytesPerPixel;
            pStride = bytesPerPixel;
            rStride = buffer->stride * 3;
            break;
        default:

    status_t res = getLockedImageInfo(buffer, idx, writerFormat, base, size,
            pixelStride, rowStride);
    if (res != OK) {
        jniThrowExceptionFmt(env, "java/lang/UnsupportedOperationException",
                                 "Pixel format: 0x%x is unsupported", fmt);
            break;
                             "Pixel format: 0x%x is unsupported", buffer->flexFormat);
    }

    *base = pData;
    *size = dataSize;
    *pixelStride = pStride;
    *rowStride = rStride;
}

static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
@@ -1024,7 +757,8 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
    Image_getLockedImage(env, thiz, &lockedImg);

    // Create all SurfacePlanes
    writerFormat = Image_getPixelFormat(env, writerFormat);
    PublicFormat publicWriterFormat = static_cast<PublicFormat>(writerFormat);
    writerFormat = android_view_Surface_mapPublicFormatToHalFormat(publicWriterFormat);
    for (int i = 0; i < numPlanes; i++) {
        Image_getLockedImageInfo(env, &lockedImg, i, writerFormat,
                &pData, &dataSize, &pixelStride, &rowStride);
@@ -1044,39 +778,6 @@ static jobjectArray Image_createSurfacePlanes(JNIEnv* env, jobject thiz,
    return surfacePlanes;
}

// -------------------------------Private convenience methods--------------------

static bool isFormatOpaque(int format) {
    // Only treat IMPLEMENTATION_DEFINED as an opaque format for now.
    return format == HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED;
}

static bool isPossiblyYUV(PixelFormat format) {
    switch (static_cast<int>(format)) {
        case HAL_PIXEL_FORMAT_RGBA_8888:
        case HAL_PIXEL_FORMAT_RGBX_8888:
        case HAL_PIXEL_FORMAT_RGB_888:
        case HAL_PIXEL_FORMAT_RGB_565:
        case HAL_PIXEL_FORMAT_BGRA_8888:
        case HAL_PIXEL_FORMAT_Y8:
        case HAL_PIXEL_FORMAT_Y16:
        case HAL_PIXEL_FORMAT_RAW16:
        case HAL_PIXEL_FORMAT_RAW10:
        case HAL_PIXEL_FORMAT_RAW_OPAQUE:
        case HAL_PIXEL_FORMAT_BLOB:
        case HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED:
            return false;

        case HAL_PIXEL_FORMAT_YV12:
        case HAL_PIXEL_FORMAT_YCbCr_420_888:
        case HAL_PIXEL_FORMAT_YCbCr_422_SP:
        case HAL_PIXEL_FORMAT_YCrCb_420_SP:
        case HAL_PIXEL_FORMAT_YCbCr_422_I:
        default:
            return true;
    }
}

} // extern "C"

// ----------------------------------------------------------------------------
+388 −0

File changed.

Preview size limit exceeded, changes collapsed.

Loading