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