1f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He/*
2f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Copyright 2015 The Android Open Source Project
3f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *
4f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Licensed under the Apache License, Version 2.0 (the "License");
5f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * you may not use this file except in compliance with the License.
6f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * You may obtain a copy of the License at
7f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *
8f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *      http://www.apache.org/licenses/LICENSE-2.0
9f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He *
10f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Unless required by applicable law or agreed to in writing, software
11f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * distributed under the License is distributed on an "AS IS" BASIS,
12f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * See the License for the specific language governing permissions and
14f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * limitations under the License.
15f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He */
16f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
17f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Hepackage android.media;
18f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
19f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.graphics.ImageFormat;
20f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.graphics.PixelFormat;
21f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.media.Image.Plane;
22f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport android.util.Size;
23f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
24bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun Heimport libcore.io.Memory;
25bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He
26f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heimport java.nio.ByteBuffer;
27f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
28f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He/**
29f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He * Package private utility class for hosting commonly used Image related methods.
30f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He */
31f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun Heclass ImageUtils {
32f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
33f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
34f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Only a subset of the formats defined in
35f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link android.graphics.ImageFormat ImageFormat} and
36f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link android.graphics.PixelFormat PixelFormat} are supported by
37f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * ImageReader. When reading RGB data from a surface, the formats defined in
38f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * {@link android.graphics.PixelFormat PixelFormat} can be used; when
39f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * reading YUV, JPEG or raw sensor data (for example, from the camera or video
40f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
41f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * are used.
42f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
43f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public static int getNumPlanesForFormat(int format) {
44f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        switch (format) {
45f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.YV12:
46f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.YUV_420_888:
47f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.NV21:
48f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return 3;
49f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.NV16:
50f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return 2;
51f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case PixelFormat.RGB_565:
52f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case PixelFormat.RGBA_8888:
53f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case PixelFormat.RGBX_8888:
54f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case PixelFormat.RGB_888:
55f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.JPEG:
56f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.YUY2:
57f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.Y8:
58f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.Y16:
59f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.RAW_SENSOR:
60f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            case ImageFormat.RAW10:
61f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return 1;
62d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He            case ImageFormat.PRIVATE:
63f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                return 0;
64f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            default:
65f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                throw new UnsupportedOperationException(
66f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                        String.format("Invalid format specified %d", format));
67f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
68f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
69f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
70f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    /**
71f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
72f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * Copy source image data to destination Image.
73f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
74f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * <p>
75d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * Only support the copy between two non-{@link ImageFormat#PRIVATE PRIVATE} format
76d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * images with same properties (format, size, etc.). The data from the
77d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * source image will be copied to the byteBuffers from the destination Image
78d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * starting from position zero, and the destination image will be rewound to
79d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He     * zero after copy is done.
80f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * </p>
81f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *
82f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param src The source image to be copied from.
83f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @param dst The destination image to be copied to.
84f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     * @throws IllegalArgumentException If the source and destination images
85f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     *             have different format, or one of the images is not copyable.
86f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He     */
87f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    public static void imageCopy(Image src, Image dst) {
88f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (src == null || dst == null) {
89f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("Images should be non-null");
90f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
91f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (src.getFormat() != dst.getFormat()) {
92f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("Src and dst images should have the same format");
93f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
94d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He        if (src.getFormat() == ImageFormat.PRIVATE ||
95d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He                dst.getFormat() == ImageFormat.PRIVATE) {
96d99dc329b9baefe3d722ccafc0c92461cfef42b1Zhijun He            throw new IllegalArgumentException("PRIVATE format images are not copyable");
97f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
98f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!(dst.getOwner() instanceof ImageWriter)) {
99f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("Destination image is not from ImageWriter. Only"
100f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    + " the images from ImageWriter are writable");
101f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
102f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Size srcSize = new Size(src.getWidth(), src.getHeight());
103f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Size dstSize = new Size(dst.getWidth(), dst.getHeight());
104f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        if (!srcSize.equals(dstSize)) {
105f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            throw new IllegalArgumentException("source image size " + srcSize + " is different"
106f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He                    + " with " + "destination image size " + dstSize);
107f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
108f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He
109f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Plane[] srcPlanes = src.getPlanes();
110f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        Plane[] dstPlanes = dst.getPlanes();
111f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ByteBuffer srcBuffer = null;
112f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        ByteBuffer dstBuffer = null;
113f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        for (int i = 0; i < srcPlanes.length; i++) {
114bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            int srcRowStride = srcPlanes[i].getRowStride();
115bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            int dstRowStride = dstPlanes[i].getRowStride();
116f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            srcBuffer = srcPlanes[i].getBuffer();
117bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            dstBuffer = dstPlanes[i].getBuffer();
118bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            if (!(srcBuffer.isDirect() && dstBuffer.isDirect())) {
119bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                throw new IllegalArgumentException("Source and destination ByteBuffers must be"
120bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        + " direct byteBuffer!");
121bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            }
122bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            if (srcPlanes[i].getPixelStride() != dstPlanes[i].getPixelStride()) {
123bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                throw new IllegalArgumentException("Source plane image pixel stride " +
124bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        srcPlanes[i].getPixelStride() +
125bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        " must be same as destination image pixel stride " +
126bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        dstPlanes[i].getPixelStride());
127bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            }
128bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He
129f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            int srcPos = srcBuffer.position();
130f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            srcBuffer.rewind();
131f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            dstBuffer.rewind();
132bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            if (srcRowStride == dstRowStride) {
133bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                // Fast path, just copy the content if the byteBuffer all together.
134bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                dstBuffer.put(srcBuffer);
135bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            } else {
136bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                // Source and destination images may have different alignment requirements,
137bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                // therefore may have different strides. Copy row by row for such case.
138bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                int srcOffset = srcBuffer.position();
139bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                int dstOffset = dstBuffer.position();
140bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                Size effectivePlaneSize = getEffectivePlaneSizeForImage(src, i);
141bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                int srcByteCount = effectivePlaneSize.getWidth() * srcPlanes[i].getPixelStride();
142bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                for (int row = 0; row < effectivePlaneSize.getHeight(); row++) {
143bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    if (row == effectivePlaneSize.getHeight() - 1) {
144bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        // Special case for NV21 backed YUV420_888: need handle the last row
145bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        // carefully to avoid memory corruption. Check if we have enough bytes to
146bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        // copy.
147bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        int remainingBytes = srcBuffer.remaining() - srcOffset;
148bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        if (srcByteCount > remainingBytes) {
149bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                            srcByteCount = remainingBytes;
150bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        }
151bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    }
152bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    directByteBufferCopy(srcBuffer, srcOffset, dstBuffer, dstOffset, srcByteCount);
153bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    srcOffset += srcRowStride;
154bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    dstOffset += dstRowStride;
155bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                }
156bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            }
157bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He
158f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            srcBuffer.position(srcPos);
159f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He            dstBuffer.rewind();
160f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He        }
161f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He    }
16211c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen
16311c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen    /**
16411c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * Return the estimated native allocation size in bytes based on width, height, format,
16511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * and number of images.
16611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     *
16711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * <p>This is a very rough estimation and should only be used for native allocation
16811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * registration in VM so it can be accounted for during GC.</p>
16911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     *
17011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * @param width The width of the images.
17111c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * @param height The height of the images.
17211c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * @param format The format of the images.
17311c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     * @param numImages The number of the images.
17411c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen     */
17511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen    public static int getEstimatedNativeAllocBytes(int width, int height, int format,
17611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            int numImages) {
17711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        double estimatedBytePerPixel;
17811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        switch (format) {
17911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            // 10x compression from RGB_888
18011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.JPEG:
18111c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.DEPTH_POINT_CLOUD:
18211c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 0.3;
18311c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
18411c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.Y8:
18511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 1.0;
18611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
18711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.RAW10:
18811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 1.25;
18911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
19011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.YV12:
19111c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.YUV_420_888:
19211c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.NV21:
19311c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.PRIVATE: // A really rough estimate because the real size is unknown.
19411c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 1.5;
19511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
19611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.NV16:
19711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case PixelFormat.RGB_565:
19811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.YUY2:
19911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.Y16:
20011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.RAW_SENSOR:
20111c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case ImageFormat.DEPTH16:
20211c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 2.0;
20311c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
20411c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case PixelFormat.RGB_888:
20511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 3.0;
20611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
20711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case PixelFormat.RGBA_8888:
20811c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            case PixelFormat.RGBX_8888:
20911c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                estimatedBytePerPixel = 4.0;
21011c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                break;
21111c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen            default:
21211c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                throw new UnsupportedOperationException(
21311c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen                        String.format("Invalid format specified %d", format));
21411c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        }
21511c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen
21611c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen        return (int)(width * height * estimatedBytePerPixel * numImages);
21711c5d0dd01cccc500796febf63aab404e8ae058bChien-Yu Chen    }
218bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He
219bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He    private static Size getEffectivePlaneSizeForImage(Image image, int planeIdx) {
220bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He        switch (image.getFormat()) {
221bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.YV12:
222bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.YUV_420_888:
223bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.NV21:
224bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                if (planeIdx == 0) {
225bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    return new Size(image.getWidth(), image.getHeight());
226bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                } else {
227bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    return new Size(image.getWidth() / 2, image.getHeight() / 2);
228bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                }
229bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.NV16:
230bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                if (planeIdx == 0) {
231bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    return new Size(image.getWidth(), image.getHeight());
232bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                } else {
233bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                    return new Size(image.getWidth(), image.getHeight() / 2);
234bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                }
235bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case PixelFormat.RGB_565:
236bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case PixelFormat.RGBA_8888:
237bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case PixelFormat.RGBX_8888:
238bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case PixelFormat.RGB_888:
239bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.JPEG:
240bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.YUY2:
241bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.Y8:
242bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.Y16:
243bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.RAW_SENSOR:
244bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.RAW10:
245bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                return new Size(image.getWidth(), image.getHeight());
246bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            case ImageFormat.PRIVATE:
247bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                return new Size(0, 0);
248bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            default:
249bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                throw new UnsupportedOperationException(
250bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He                        String.format("Invalid image format %d", image.getFormat()));
251bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He        }
252bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He    }
253bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He
254bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He    private static void directByteBufferCopy(ByteBuffer srcBuffer, int srcOffset,
255bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He            ByteBuffer dstBuffer, int dstOffset, int srcByteCount) {
256bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He        Memory.memmove(dstBuffer, dstOffset, srcBuffer, srcOffset, srcByteCount);
257bc0b63667960896929fdfcc0d95491ff8f1ef00aZhijun He    }
258f6a09e510649ae4701bb5ad4c40d102d59a5608cZhijun He}
259