YuvImage.java revision bca2d613e0d6d2630fedd302c0d779b7610adbcf
1bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen/*
2bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * Copyright (C) 2010 The Android Open Source Project
3bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen *
4bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License");
5bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * you may not use this file except in compliance with the License.
6bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * You may obtain a copy of the License at
7bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen *
8bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen *      http://www.apache.org/licenses/LICENSE-2.0
9bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen *
10bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * Unless required by applicable law or agreed to in writing, software
11bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS,
12bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * See the License for the specific language governing permissions and
14bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * limitations under the License.
15bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen */
16bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
17bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenpackage android.graphics;
18bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
19bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenimport java.io.OutputStream;
20bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
21bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen/**
22bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * @hide pending API council approval
23bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen *
24bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * YuvImage contains YUV data and provides a method that compresses a region of
25bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * the YUV data to a Jpeg. The YUV data should be provided as a single byte
26bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * array irrespective of the number of image planes in it. The stride of each
27bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * image plane should be provided as well.
28bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen *
29bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * To compress a rectangle region in the YUV data, users have to specify a
30bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * region by width, height and offsets, where each image plane has a
31bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * corresponding offset. All offsets are measured as a displacement in bytes
32bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen * from yuv[0], where yuv[0] is the beginning of the yuv data.
33bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen */
34bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chenpublic class YuvImage {
35bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
36bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
37bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * Number of bytes of temp storage we use for communicating between the
38bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * native compressor and the java OutputStream.
39bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
40bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    private final static int WORKING_COMPRESS_STORAGE = 4096;
41bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
42bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen   /**
43bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * The YUV format as defined in {@link PixelFormat}.
44bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
45bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    private int mFormat;
46bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
47bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
48bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * The raw YUV data.
49bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * In the case of more than one image plane, the image planes must be
50bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * concatenated into a single byte array.
51bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
52bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    private byte[] mData;
53bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
54bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
55bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * The number of row bytes in each image plane.
56bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
57bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    private int[] mStrides;
58bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
59bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
60bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * Construct an YuvImage.
61bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *
62bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param yuv The YUV data. In the case of more than one image plane, all the planes must be
63bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *            concatenated into a single byte array.
64bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param format The YUV data format as defined in {@link PixelFormat}.
65bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param strides Row bytes of each image plane.
66bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
67bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    public YuvImage(byte[] yuv, int format, int[] strides) {
68bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if ((yuv == null) || (strides == null)) {
69bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new IllegalArgumentException(
70bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                    "yuv or strides cannot be null");
71bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
72bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        mData = yuv;
73bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        mFormat = format;
74bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        mStrides = strides;
75bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
76bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
77bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
78bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * Compress a rectangle region in the YuvImage to a jpeg.
79bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I
80bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * are supported for now.
81bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *
82bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param width The width of the rectangle region.
83bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param height The height of the rectangle region.
84bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param offsets The offsets of the rectangle region in each image plane.
85bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *                The offsets are measured as a displacement in bytes from
86bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *                yuv[0], where yuv[0] is the beginning of the yuv data.
87bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
88bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *                 small size, 100 meaning compress for max quality.
89bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @param stream   The outputstream to write the compressed data.
90bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *
91bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @return true if successfully compressed to the specified stream.
92bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     *
93bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
94bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    public boolean compressToJpeg(int width, int height, int[] offsets, int quality,
95bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            OutputStream stream) {
96bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (!validate(mFormat, width, height, offsets)) {
97bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            return false;
98bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
99bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
100bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (quality < 0 || quality > 100) {
101bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new IllegalArgumentException("quality must be 0..100");
102bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
103bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
104bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (stream == null) {
105bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new NullPointerException();
106bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
107bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
108bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return nativeCompressToJpeg(mData, mFormat, width, height, offsets,
109bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                mStrides, quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
110bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
111bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
112bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
113bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @return the YUV data.
114bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
115bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    public byte[] getYuvData() {
116bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return mData;
117bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
118bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
119bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
120bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @return the YUV format as defined in {@link PixelFormat}.
121bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
122bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    public int getYuvFormat() {
123bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return mFormat;
124bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
125bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
126bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    /**
127bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     * @return the number of row bytes in each image plane.
128bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen     */
129bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    public int[] getStrides() {
130bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return mStrides;
131bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
132bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
133bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    protected boolean validate(int format, int width, int height, int[] offsets) {
134bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (format != PixelFormat.YCbCr_420_SP &&
135bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                format != PixelFormat.YCbCr_422_I) {
136bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new IllegalArgumentException(
137bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                    "only support PixelFormat.YCbCr_420_SP " +
138bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                    "and PixelFormat.YCbCr_422_I for now");
139bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
140bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
141bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (offsets.length != mStrides.length) {
142bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new IllegalArgumentException(
143bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                    "the number of image planes are mismatched");
144bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
145bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
146bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (width <= 0  || height <= 0) {
147bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new IllegalArgumentException(
148bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                    "width and height must large than 0");
149bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
150bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
151bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        int requiredSize;
152bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (format == PixelFormat.YCbCr_420_SP) {
153bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            requiredSize = height * mStrides[0] +(height >> 1) * mStrides[1];
154bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        } else {
155bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            requiredSize = height * mStrides[0];
156bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
157bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
158bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        if (requiredSize > mData.length) {
159bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            throw new IllegalArgumentException(
160bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen                    "width or/and height is larger than the yuv data");
161bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        }
162bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
163bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen        return true;
164bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    }
165bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
166bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    //////////// native methods
167bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen
168bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen    private static native boolean nativeCompressToJpeg(byte[] oriYuv,
169bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int format, int width, int height, int[] offsets, int[] strides,
170bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen            int quality, OutputStream stream, byte[] tempStorage);
171bca2d613e0d6d2630fedd302c0d779b7610adbcfWei-Ta Chen}
172