Search in sources :

Example 1 with Plane

use of android.media.Image.Plane in project platform_frameworks_base by android.

the class ImageUtils method imageCopy.

/**
     * <p>
     * Copy source image data to destination Image.
     * </p>
     * <p>
     * Only support the copy between two non-{@link ImageFormat#PRIVATE PRIVATE} format
     * images with same properties (format, size, etc.). The data from the
     * source image will be copied to the byteBuffers from the destination Image
     * starting from position zero, and the destination image will be rewound to
     * zero after copy is done.
     * </p>
     *
     * @param src The source image to be copied from.
     * @param dst The destination image to be copied to.
     * @throws IllegalArgumentException If the source and destination images
     *             have different format, or one of the images is not copyable.
     */
public static void imageCopy(Image src, Image dst) {
    if (src == null || dst == null) {
        throw new IllegalArgumentException("Images should be non-null");
    }
    if (src.getFormat() != dst.getFormat()) {
        throw new IllegalArgumentException("Src and dst images should have the same format");
    }
    if (src.getFormat() == ImageFormat.PRIVATE || dst.getFormat() == ImageFormat.PRIVATE) {
        throw new IllegalArgumentException("PRIVATE format images are not copyable");
    }
    if (src.getFormat() == ImageFormat.RAW_PRIVATE) {
        throw new IllegalArgumentException("Copy of RAW_OPAQUE format has not been implemented");
    }
    if (!(dst.getOwner() instanceof ImageWriter)) {
        throw new IllegalArgumentException("Destination image is not from ImageWriter. Only" + " the images from ImageWriter are writable");
    }
    Size srcSize = new Size(src.getWidth(), src.getHeight());
    Size dstSize = new Size(dst.getWidth(), dst.getHeight());
    if (!srcSize.equals(dstSize)) {
        throw new IllegalArgumentException("source image size " + srcSize + " is different" + " with " + "destination image size " + dstSize);
    }
    Plane[] srcPlanes = src.getPlanes();
    Plane[] dstPlanes = dst.getPlanes();
    ByteBuffer srcBuffer = null;
    ByteBuffer dstBuffer = null;
    for (int i = 0; i < srcPlanes.length; i++) {
        int srcRowStride = srcPlanes[i].getRowStride();
        int dstRowStride = dstPlanes[i].getRowStride();
        srcBuffer = srcPlanes[i].getBuffer();
        dstBuffer = dstPlanes[i].getBuffer();
        if (!(srcBuffer.isDirect() && dstBuffer.isDirect())) {
            throw new IllegalArgumentException("Source and destination ByteBuffers must be" + " direct byteBuffer!");
        }
        if (srcPlanes[i].getPixelStride() != dstPlanes[i].getPixelStride()) {
            throw new IllegalArgumentException("Source plane image pixel stride " + srcPlanes[i].getPixelStride() + " must be same as destination image pixel stride " + dstPlanes[i].getPixelStride());
        }
        int srcPos = srcBuffer.position();
        srcBuffer.rewind();
        dstBuffer.rewind();
        if (srcRowStride == dstRowStride) {
            // Fast path, just copy the content if the byteBuffer all together.
            dstBuffer.put(srcBuffer);
        } else {
            // Source and destination images may have different alignment requirements,
            // therefore may have different strides. Copy row by row for such case.
            int srcOffset = srcBuffer.position();
            int dstOffset = dstBuffer.position();
            Size effectivePlaneSize = getEffectivePlaneSizeForImage(src, i);
            int srcByteCount = effectivePlaneSize.getWidth() * srcPlanes[i].getPixelStride();
            for (int row = 0; row < effectivePlaneSize.getHeight(); row++) {
                if (row == effectivePlaneSize.getHeight() - 1) {
                    // Special case for NV21 backed YUV420_888: need handle the last row
                    // carefully to avoid memory corruption. Check if we have enough bytes to
                    // copy.
                    int remainingBytes = srcBuffer.remaining() - srcOffset;
                    if (srcByteCount > remainingBytes) {
                        srcByteCount = remainingBytes;
                    }
                }
                directByteBufferCopy(srcBuffer, srcOffset, dstBuffer, dstOffset, srcByteCount);
                srcOffset += srcRowStride;
                dstOffset += dstRowStride;
            }
        }
        srcBuffer.position(srcPos);
        dstBuffer.rewind();
    }
}
Also used : Plane(android.media.Image.Plane) Size(android.util.Size) ByteBuffer(java.nio.ByteBuffer)

Example 2 with Plane

use of android.media.Image.Plane in project platform_frameworks_base by android.

the class CameraTestUtils method getDataFromImage.

/**
     * <p>Read data from all planes of an Image into a contiguous unpadded, unpacked
     * 1-D linear byte array, such that it can be write into disk, or accessed by
     * software conveniently. It supports YUV_420_888/NV21/YV12 and JPEG input
     * Image format.</p>
     *
     * <p>For YUV_420_888/NV21/YV12/Y8/Y16, it returns a byte array that contains
     * the Y plane data first, followed by U(Cb), V(Cr) planes if there is any
     * (xstride = width, ystride = height for chroma and luma components).</p>
     *
     * <p>For JPEG, it returns a 1-D byte array contains a complete JPEG image.</p>
     */
public static byte[] getDataFromImage(Image image) {
    assertNotNull("Invalid image:", image);
    int format = image.getFormat();
    int width = image.getWidth();
    int height = image.getHeight();
    int rowStride, pixelStride;
    byte[] data = null;
    // Read image data
    Plane[] planes = image.getPlanes();
    assertTrue("Fail to get image planes", planes != null && planes.length > 0);
    // Check image validity
    checkAndroidImageFormat(image);
    ByteBuffer buffer = null;
    // Same goes for DEPTH_POINT_CLOUD
    if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD || format == ImageFormat.RAW_PRIVATE) {
        buffer = planes[0].getBuffer();
        assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
        data = new byte[buffer.remaining()];
        buffer.get(data);
        buffer.rewind();
        return data;
    }
    int offset = 0;
    data = new byte[width * height * ImageFormat.getBitsPerPixel(format) / 8];
    int maxRowSize = planes[0].getRowStride();
    for (int i = 0; i < planes.length; i++) {
        if (maxRowSize < planes[i].getRowStride()) {
            maxRowSize = planes[i].getRowStride();
        }
    }
    byte[] rowData = new byte[maxRowSize];
    if (VERBOSE)
        Log.v(TAG, "get data from " + planes.length + " planes");
    for (int i = 0; i < planes.length; i++) {
        buffer = planes[i].getBuffer();
        assertNotNull("Fail to get bytebuffer from plane", buffer);
        rowStride = planes[i].getRowStride();
        pixelStride = planes[i].getPixelStride();
        assertTrue("pixel stride " + pixelStride + " is invalid", pixelStride > 0);
        if (VERBOSE) {
            Log.v(TAG, "pixelStride " + pixelStride);
            Log.v(TAG, "rowStride " + rowStride);
            Log.v(TAG, "width " + width);
            Log.v(TAG, "height " + height);
        }
        // For multi-planar yuv images, assuming yuv420 with 2x2 chroma subsampling.
        int w = (i == 0) ? width : width / 2;
        int h = (i == 0) ? height : height / 2;
        assertTrue("rowStride " + rowStride + " should be >= width " + w, rowStride >= w);
        for (int row = 0; row < h; row++) {
            int bytesPerPixel = ImageFormat.getBitsPerPixel(format) / 8;
            int length;
            if (pixelStride == bytesPerPixel) {
                // Special case: optimized read of the entire row
                length = w * bytesPerPixel;
                buffer.get(data, offset, length);
                offset += length;
            } else {
                // Generic case: should work for any pixelStride but slower.
                // Use intermediate buffer to avoid read byte-by-byte from
                // DirectByteBuffer, which is very bad for performance
                length = (w - 1) * pixelStride + bytesPerPixel;
                buffer.get(rowData, 0, length);
                for (int col = 0; col < w; col++) {
                    data[offset++] = rowData[col * pixelStride];
                }
            }
            // Advance buffer the remainder of the row stride
            if (row < h - 1) {
                buffer.position(buffer.position() + rowStride - length);
            }
        }
        if (VERBOSE)
            Log.v(TAG, "Finished reading data from plane " + i);
        buffer.rewind();
    }
    return data;
}
Also used : Plane(android.media.Image.Plane) ByteBuffer(java.nio.ByteBuffer)

Example 3 with Plane

use of android.media.Image.Plane in project platform_frameworks_base by android.

the class CameraTestUtils method isImageStronglyEqual.

/**
     * <p>
     * Checks whether the two images are strongly equal.
     * </p>
     * <p>
     * Two images are strongly equal if and only if the data, formats, sizes,
     * and timestamps are same. For {@link ImageFormat#PRIVATE PRIVATE} format
     * images, the image data is not not accessible thus the data comparison is
     * effectively skipped as the number of planes is zero.
     * </p>
     * <p>
     * Note that this method compares the pixel data even outside of the crop
     * region, which may not be necessary for general use case.
     * </p>
     *
     * @param lhsImg First image to be compared with.
     * @param rhsImg Second image to be compared with.
     * @return true if the two images are equal, false otherwise.
     * @throws IllegalArgumentException If either of image is null.
     */
public static boolean isImageStronglyEqual(Image lhsImg, Image rhsImg) {
    if (lhsImg == null || rhsImg == null) {
        throw new IllegalArgumentException("Images should be non-null");
    }
    if (lhsImg.getFormat() != rhsImg.getFormat()) {
        Log.i(TAG, "lhsImg format " + lhsImg.getFormat() + " is different with rhsImg format " + rhsImg.getFormat());
        return false;
    }
    if (lhsImg.getWidth() != rhsImg.getWidth()) {
        Log.i(TAG, "lhsImg width " + lhsImg.getWidth() + " is different with rhsImg width " + rhsImg.getWidth());
        return false;
    }
    if (lhsImg.getHeight() != rhsImg.getHeight()) {
        Log.i(TAG, "lhsImg height " + lhsImg.getHeight() + " is different with rhsImg height " + rhsImg.getHeight());
        return false;
    }
    if (lhsImg.getTimestamp() != rhsImg.getTimestamp()) {
        Log.i(TAG, "lhsImg timestamp " + lhsImg.getTimestamp() + " is different with rhsImg timestamp " + rhsImg.getTimestamp());
        return false;
    }
    if (!lhsImg.getCropRect().equals(rhsImg.getCropRect())) {
        Log.i(TAG, "lhsImg crop rect " + lhsImg.getCropRect() + " is different with rhsImg crop rect " + rhsImg.getCropRect());
        return false;
    }
    // Compare data inside of the image.
    Plane[] lhsPlanes = lhsImg.getPlanes();
    Plane[] rhsPlanes = rhsImg.getPlanes();
    ByteBuffer lhsBuffer = null;
    ByteBuffer rhsBuffer = null;
    for (int i = 0; i < lhsPlanes.length; i++) {
        lhsBuffer = lhsPlanes[i].getBuffer();
        rhsBuffer = rhsPlanes[i].getBuffer();
        if (!lhsBuffer.equals(rhsBuffer)) {
            Log.i(TAG, "byte buffers for plane " + i + " don't matach.");
            return false;
        }
    }
    return true;
}
Also used : Plane(android.media.Image.Plane) ByteBuffer(java.nio.ByteBuffer)

Example 4 with Plane

use of android.media.Image.Plane in project android_frameworks_base by DirtyUnicorns.

the class ImageUtils method imageCopy.

/**
     * <p>
     * Copy source image data to destination Image.
     * </p>
     * <p>
     * Only support the copy between two non-{@link ImageFormat#PRIVATE PRIVATE} format
     * images with same properties (format, size, etc.). The data from the
     * source image will be copied to the byteBuffers from the destination Image
     * starting from position zero, and the destination image will be rewound to
     * zero after copy is done.
     * </p>
     *
     * @param src The source image to be copied from.
     * @param dst The destination image to be copied to.
     * @throws IllegalArgumentException If the source and destination images
     *             have different format, or one of the images is not copyable.
     */
public static void imageCopy(Image src, Image dst) {
    if (src == null || dst == null) {
        throw new IllegalArgumentException("Images should be non-null");
    }
    if (src.getFormat() != dst.getFormat()) {
        throw new IllegalArgumentException("Src and dst images should have the same format");
    }
    if (src.getFormat() == ImageFormat.PRIVATE || dst.getFormat() == ImageFormat.PRIVATE) {
        throw new IllegalArgumentException("PRIVATE format images are not copyable");
    }
    if (src.getFormat() == ImageFormat.RAW_PRIVATE) {
        throw new IllegalArgumentException("Copy of RAW_OPAQUE format has not been implemented");
    }
    if (!(dst.getOwner() instanceof ImageWriter)) {
        throw new IllegalArgumentException("Destination image is not from ImageWriter. Only" + " the images from ImageWriter are writable");
    }
    Size srcSize = new Size(src.getWidth(), src.getHeight());
    Size dstSize = new Size(dst.getWidth(), dst.getHeight());
    if (!srcSize.equals(dstSize)) {
        throw new IllegalArgumentException("source image size " + srcSize + " is different" + " with " + "destination image size " + dstSize);
    }
    Plane[] srcPlanes = src.getPlanes();
    Plane[] dstPlanes = dst.getPlanes();
    ByteBuffer srcBuffer = null;
    ByteBuffer dstBuffer = null;
    for (int i = 0; i < srcPlanes.length; i++) {
        int srcRowStride = srcPlanes[i].getRowStride();
        int dstRowStride = dstPlanes[i].getRowStride();
        srcBuffer = srcPlanes[i].getBuffer();
        dstBuffer = dstPlanes[i].getBuffer();
        if (!(srcBuffer.isDirect() && dstBuffer.isDirect())) {
            throw new IllegalArgumentException("Source and destination ByteBuffers must be" + " direct byteBuffer!");
        }
        if (srcPlanes[i].getPixelStride() != dstPlanes[i].getPixelStride()) {
            throw new IllegalArgumentException("Source plane image pixel stride " + srcPlanes[i].getPixelStride() + " must be same as destination image pixel stride " + dstPlanes[i].getPixelStride());
        }
        int srcPos = srcBuffer.position();
        srcBuffer.rewind();
        dstBuffer.rewind();
        if (srcRowStride == dstRowStride) {
            // Fast path, just copy the content if the byteBuffer all together.
            dstBuffer.put(srcBuffer);
        } else {
            // Source and destination images may have different alignment requirements,
            // therefore may have different strides. Copy row by row for such case.
            int srcOffset = srcBuffer.position();
            int dstOffset = dstBuffer.position();
            Size effectivePlaneSize = getEffectivePlaneSizeForImage(src, i);
            int srcByteCount = effectivePlaneSize.getWidth() * srcPlanes[i].getPixelStride();
            for (int row = 0; row < effectivePlaneSize.getHeight(); row++) {
                if (row == effectivePlaneSize.getHeight() - 1) {
                    // Special case for NV21 backed YUV420_888: need handle the last row
                    // carefully to avoid memory corruption. Check if we have enough bytes to
                    // copy.
                    int remainingBytes = srcBuffer.remaining() - srcOffset;
                    if (srcByteCount > remainingBytes) {
                        srcByteCount = remainingBytes;
                    }
                }
                directByteBufferCopy(srcBuffer, srcOffset, dstBuffer, dstOffset, srcByteCount);
                srcOffset += srcRowStride;
                dstOffset += dstRowStride;
            }
        }
        srcBuffer.position(srcPos);
        dstBuffer.rewind();
    }
}
Also used : Plane(android.media.Image.Plane) Size(android.util.Size) ByteBuffer(java.nio.ByteBuffer)

Example 5 with Plane

use of android.media.Image.Plane in project android_frameworks_base by DirtyUnicorns.

the class CameraTestUtils method getDataFromImage.

/**
     * <p>Read data from all planes of an Image into a contiguous unpadded, unpacked
     * 1-D linear byte array, such that it can be write into disk, or accessed by
     * software conveniently. It supports YUV_420_888/NV21/YV12 and JPEG input
     * Image format.</p>
     *
     * <p>For YUV_420_888/NV21/YV12/Y8/Y16, it returns a byte array that contains
     * the Y plane data first, followed by U(Cb), V(Cr) planes if there is any
     * (xstride = width, ystride = height for chroma and luma components).</p>
     *
     * <p>For JPEG, it returns a 1-D byte array contains a complete JPEG image.</p>
     */
public static byte[] getDataFromImage(Image image) {
    assertNotNull("Invalid image:", image);
    int format = image.getFormat();
    int width = image.getWidth();
    int height = image.getHeight();
    int rowStride, pixelStride;
    byte[] data = null;
    // Read image data
    Plane[] planes = image.getPlanes();
    assertTrue("Fail to get image planes", planes != null && planes.length > 0);
    // Check image validity
    checkAndroidImageFormat(image);
    ByteBuffer buffer = null;
    // Same goes for DEPTH_POINT_CLOUD
    if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD || format == ImageFormat.RAW_PRIVATE) {
        buffer = planes[0].getBuffer();
        assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
        data = new byte[buffer.remaining()];
        buffer.get(data);
        buffer.rewind();
        return data;
    }
    int offset = 0;
    data = new byte[width * height * ImageFormat.getBitsPerPixel(format) / 8];
    int maxRowSize = planes[0].getRowStride();
    for (int i = 0; i < planes.length; i++) {
        if (maxRowSize < planes[i].getRowStride()) {
            maxRowSize = planes[i].getRowStride();
        }
    }
    byte[] rowData = new byte[maxRowSize];
    if (VERBOSE)
        Log.v(TAG, "get data from " + planes.length + " planes");
    for (int i = 0; i < planes.length; i++) {
        buffer = planes[i].getBuffer();
        assertNotNull("Fail to get bytebuffer from plane", buffer);
        rowStride = planes[i].getRowStride();
        pixelStride = planes[i].getPixelStride();
        assertTrue("pixel stride " + pixelStride + " is invalid", pixelStride > 0);
        if (VERBOSE) {
            Log.v(TAG, "pixelStride " + pixelStride);
            Log.v(TAG, "rowStride " + rowStride);
            Log.v(TAG, "width " + width);
            Log.v(TAG, "height " + height);
        }
        // For multi-planar yuv images, assuming yuv420 with 2x2 chroma subsampling.
        int w = (i == 0) ? width : width / 2;
        int h = (i == 0) ? height : height / 2;
        assertTrue("rowStride " + rowStride + " should be >= width " + w, rowStride >= w);
        for (int row = 0; row < h; row++) {
            int bytesPerPixel = ImageFormat.getBitsPerPixel(format) / 8;
            int length;
            if (pixelStride == bytesPerPixel) {
                // Special case: optimized read of the entire row
                length = w * bytesPerPixel;
                buffer.get(data, offset, length);
                offset += length;
            } else {
                // Generic case: should work for any pixelStride but slower.
                // Use intermediate buffer to avoid read byte-by-byte from
                // DirectByteBuffer, which is very bad for performance
                length = (w - 1) * pixelStride + bytesPerPixel;
                buffer.get(rowData, 0, length);
                for (int col = 0; col < w; col++) {
                    data[offset++] = rowData[col * pixelStride];
                }
            }
            // Advance buffer the remainder of the row stride
            if (row < h - 1) {
                buffer.position(buffer.position() + rowStride - length);
            }
        }
        if (VERBOSE)
            Log.v(TAG, "Finished reading data from plane " + i);
        buffer.rewind();
    }
    return data;
}
Also used : Plane(android.media.Image.Plane) ByteBuffer(java.nio.ByteBuffer)

Aggregations

Plane (android.media.Image.Plane)20 ByteBuffer (java.nio.ByteBuffer)20 Size (android.util.Size)5