summaryrefslogtreecommitdiffstats
path: root/graphics/java/android/graphics/YuvImage.java
blob: 09b4bf4473a9eca5fb0b81561810e114b87f6682 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
/*
 * Copyright (C) 2010 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.
 */

package android.graphics;

import java.io.OutputStream;

/**
 * YuvImage contains YUV data and provides a method that compresses a region of
 * the YUV data to a Jpeg. The YUV data should be provided as a single byte
 * array irrespective of the number of image planes in it. The stride of each
 * image plane should be provided as well.
 *
 * To compress a rectangle region in the YUV data, users have to specify a
 * region by width, height and offsets, where each image plane has a
 * corresponding offset. All offsets are measured as a displacement in bytes
 * from yuv[0], where yuv[0] is the beginning of the yuv data.
 */
public class YuvImage {

    /**
     * Number of bytes of temp storage we use for communicating between the
     * native compressor and the java OutputStream.
     */
    private final static int WORKING_COMPRESS_STORAGE = 4096;

   /**
     * The YUV format as defined in {@link PixelFormat}.
     */
    private int mFormat;

    /**
     * The raw YUV data.
     * In the case of more than one image plane, the image planes must be
     * concatenated into a single byte array.
     */
    private byte[] mData;

    /**
     * The number of row bytes in each image plane.
     */
    private int[] mStrides;

    /**
     * Construct an YuvImage.
     *
     * @param yuv The YUV data. In the case of more than one image plane, all the planes must be
     *            concatenated into a single byte array.
     * @param format The YUV data format as defined in {@link PixelFormat}.
     * @param strides Row bytes of each image plane.
     */
    public YuvImage(byte[] yuv, int format, int[] strides) {
        if ((yuv == null) || (strides == null)) {
            throw new IllegalArgumentException(
                    "yuv or strides cannot be null");
        }
        mData = yuv;
        mFormat = format;
        mStrides = strides;
    }

    /**
     * Compress a rectangle region in the YuvImage to a jpeg.
     * Only PixelFormat.YCbCr_420_SP and PixelFormat.YCbCr_422_I
     * are supported for now.
     *
     * @param width The width of the rectangle region.
     * @param height The height of the rectangle region.
     * @param offsets The offsets of the rectangle region in each image plane.
     *                The offsets are measured as a displacement in bytes from
     *                yuv[0], where yuv[0] is the beginning of the yuv data.
     * @param quality  Hint to the compressor, 0-100. 0 meaning compress for
     *                 small size, 100 meaning compress for max quality.
     * @param stream   The outputstream to write the compressed data.
     *
     * @return true if successfully compressed to the specified stream.
     *
     */
    public boolean compressToJpeg(int width, int height, int[] offsets, int quality,
            OutputStream stream) {
        if (!validate(mFormat, width, height, offsets)) {
            return false;
        }

        if (quality < 0 || quality > 100) {
            throw new IllegalArgumentException("quality must be 0..100");
        }

        if (stream == null) {
            throw new NullPointerException();
        }

        return nativeCompressToJpeg(mData, mFormat, width, height, offsets,
                mStrides, quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
    }

    /**
     * @return the YUV data.
     */
    public byte[] getYuvData() {
        return mData;
    }

    /**
     * @return the YUV format as defined in {@link PixelFormat}.
     */
    public int getYuvFormat() {
        return mFormat;
    }

    /**
     * @return the number of row bytes in each image plane.
     */
    public int[] getStrides() {
        return mStrides;
    }

    protected boolean validate(int format, int width, int height, int[] offsets) {
        if (format != PixelFormat.YCbCr_420_SP &&
                format != PixelFormat.YCbCr_422_I) {
            throw new IllegalArgumentException(
                    "only support PixelFormat.YCbCr_420_SP " +
                    "and PixelFormat.YCbCr_422_I for now");
        }

        if (offsets.length != mStrides.length) {
            throw new IllegalArgumentException(
                    "the number of image planes are mismatched");
        }

        if (width <= 0  || height <= 0) {
            throw new IllegalArgumentException(
                    "width and height must large than 0");
        }

        int requiredSize;
        if (format == PixelFormat.YCbCr_420_SP) {
            requiredSize = height * mStrides[0] +(height >> 1) * mStrides[1];
        } else {
            requiredSize = height * mStrides[0];
        }

        if (requiredSize > mData.length) {
            throw new IllegalArgumentException(
                    "width or/and height is larger than the yuv data");
        }

        return true;
    }

    //////////// native methods

    private static native boolean nativeCompressToJpeg(byte[] oriYuv,
            int format, int width, int height, int[] offsets, int[] strides,
            int quality, OutputStream stream, byte[] tempStorage);
}