1 /* 2 * Copyright 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.media.cts; 18 19 import android.graphics.Bitmap; 20 import android.graphics.Color; 21 import android.graphics.Rect; 22 import android.media.Image; 23 import android.os.Environment; 24 import android.util.Log; 25 26 import java.io.File; 27 import java.io.FileOutputStream; 28 import java.nio.ByteBuffer; 29 30 public class CodecUtils { 31 private static final String TAG = "CodecUtils"; 32 33 /** Load jni on initialization */ 34 static { Log.i(TAG, "before loadlibrary")35 Log.i(TAG, "before loadlibrary"); 36 System.loadLibrary("ctscodecutils_jni"); Log.i(TAG, "after loadlibrary")37 Log.i(TAG, "after loadlibrary"); 38 } 39 40 private static class ImageWrapper extends CodecImage { 41 private final Image mImage; 42 private final Plane[] mPlanes; 43 ImageWrapper(Image image)44 private ImageWrapper(Image image) { 45 mImage = image; 46 Image.Plane[] planes = mImage.getPlanes(); 47 48 mPlanes = new Plane[planes.length]; 49 for (int i = 0; i < planes.length; i++) { 50 mPlanes[i] = new PlaneWrapper(planes[i]); 51 } 52 53 setCropRect(image.getCropRect()); 54 } 55 createFromImage(Image image)56 public static ImageWrapper createFromImage(Image image) { 57 return new ImageWrapper(image); 58 } 59 60 @Override getFormat()61 public int getFormat() { 62 return mImage.getFormat(); 63 } 64 65 @Override getWidth()66 public int getWidth() { 67 return mImage.getWidth(); 68 } 69 70 @Override getHeight()71 public int getHeight() { 72 return mImage.getHeight(); 73 } 74 75 @Override getTimestamp()76 public long getTimestamp() { 77 return mImage.getTimestamp(); 78 } 79 80 @Override getPlanes()81 public Plane[] getPlanes() { 82 return mPlanes; 83 } 84 85 @Override close()86 public void close() { 87 mImage.close(); 88 } 89 90 private static class PlaneWrapper extends CodecImage.Plane { 91 private final Image.Plane mPlane; 92 PlaneWrapper(Image.Plane plane)93 PlaneWrapper(Image.Plane plane) { 94 mPlane = plane; 95 } 96 97 @Override getRowStride()98 public int getRowStride() { 99 return mPlane.getRowStride(); 100 } 101 102 @Override getPixelStride()103 public int getPixelStride() { 104 return mPlane.getPixelStride(); 105 } 106 107 @Override getBuffer()108 public ByteBuffer getBuffer() { 109 return mPlane.getBuffer(); 110 } 111 } 112 } 113 114 /* two native image checksum functions */ getImageChecksumAdler32(CodecImage image)115 public native static int getImageChecksumAdler32(CodecImage image); getImageChecksumMD5(CodecImage image)116 public native static String getImageChecksumMD5(CodecImage image); 117 copyFlexYUVImage(CodecImage target, CodecImage source)118 public native static void copyFlexYUVImage(CodecImage target, CodecImage source); 119 copyFlexYUVImage(Image target, CodecImage source)120 public static void copyFlexYUVImage(Image target, CodecImage source) { 121 copyFlexYUVImage(ImageWrapper.createFromImage(target), source); 122 } copyFlexYUVImage(Image target, Image source)123 public static void copyFlexYUVImage(Image target, Image source) { 124 copyFlexYUVImage( 125 ImageWrapper.createFromImage(target), 126 ImageWrapper.createFromImage(source)); 127 } 128 fillImageRectWithYUV( CodecImage image, Rect area, int y, int u, int v)129 public native static void fillImageRectWithYUV( 130 CodecImage image, Rect area, int y, int u, int v); 131 fillImageRectWithYUV(Image image, Rect area, int y, int u, int v)132 public static void fillImageRectWithYUV(Image image, Rect area, int y, int u, int v) { 133 fillImageRectWithYUV(ImageWrapper.createFromImage(image), area, y, u, v); 134 } 135 getRawStats(CodecImage image, Rect area)136 public native static long[] getRawStats(CodecImage image, Rect area); 137 getRawStats(Image image, Rect area)138 public static long[] getRawStats(Image image, Rect area) { 139 return getRawStats(ImageWrapper.createFromImage(image), area); 140 } 141 getYUVStats(CodecImage image, Rect area)142 public native static float[] getYUVStats(CodecImage image, Rect area); 143 getYUVStats(Image image, Rect area)144 public static float[] getYUVStats(Image image, Rect area) { 145 return getYUVStats(ImageWrapper.createFromImage(image), area); 146 } 147 Raw2YUVStats(long[] rawStats)148 public native static float[] Raw2YUVStats(long[] rawStats); 149 150 /** 151 * This method reads the binarybar code on the top row of a bitmap. Each 16x16 152 * block is one digit, with black=0 and white=1. LSB is on the left. 153 */ readBinaryCounterFromBitmap(Bitmap bitmap)154 public static int readBinaryCounterFromBitmap(Bitmap bitmap) { 155 int numDigits = bitmap.getWidth() / 16; 156 int counter = 0; 157 for (int i = 0; i < numDigits; i++) { 158 int rgb = bitmap.getPixel(i * 16 + 8, 8); 159 if (Color.red(rgb) > 128) { 160 counter |= (1 << i); 161 } 162 } 163 return counter; 164 } 165 166 /** 167 * This method verifies the rotation degrees of a bitmap by reading the colors on its corners. 168 * The bitmap without rotation (rotation degree == 0) looks like 169 * red | green 170 * ----------------- 171 * blue | white 172 * with resolution equals to 320x240. 173 */ VerifyFrameRotationFromBitmap(Bitmap bitmap, int targetRotation)174 public static boolean VerifyFrameRotationFromBitmap(Bitmap bitmap, int targetRotation) { 175 if (targetRotation == 0 || targetRotation == 180) { 176 if (bitmap.getWidth() != 320 || bitmap.getHeight() != 240) { 177 return false; 178 } 179 Color left_top = Color.valueOf(bitmap.getPixel(10, 10)); 180 Color right_top = Color.valueOf(bitmap.getPixel(310, 10)); 181 Color left_bottom = Color.valueOf(bitmap.getPixel(10, 230)); 182 Color right_bottom = Color.valueOf(bitmap.getPixel(310, 230)); 183 if (targetRotation == 0) { 184 if (!isRed(left_top) || !isGreen(right_top) 185 || !isBlue(left_bottom) || !isWhite(right_bottom)) { 186 return false; 187 } 188 } else { 189 if (!isWhite(left_top) || !isBlue(right_top) 190 || !isGreen(left_bottom) || !isRed(right_bottom)) { 191 return false; 192 } 193 } 194 } else if (targetRotation == 90 || targetRotation == 270) { 195 if (bitmap.getWidth() != 240 || bitmap.getHeight() != 320) { 196 return false; 197 } 198 Color left_top = Color.valueOf(bitmap.getPixel(10, 10)); 199 Color right_top = Color.valueOf(bitmap.getPixel(230, 10)); 200 Color left_bottom = Color.valueOf(bitmap.getPixel(10, 310)); 201 Color right_bottom = Color.valueOf(bitmap.getPixel(230, 310)); 202 if (targetRotation == 90) { 203 if (!isBlue(left_top) || !isRed(right_top) 204 || !isWhite(left_bottom) || !isGreen(right_bottom)) { 205 return false; 206 } 207 } else { 208 if (!isGreen(left_top) || !isWhite(right_top) 209 || !isRed(left_bottom) || !isBlue(right_bottom)) { 210 return false; 211 } 212 } 213 } 214 return true; 215 } 216 isRed(Color color)217 private static boolean isRed(Color color) { 218 return color.red() > 0.95 && color.green() < 0.05 && color.blue() < 0.05; 219 } 220 isGreen(Color color)221 private static boolean isGreen(Color color) { 222 return color.red() < 0.05 && color.green() > 0.95 && color.blue() < 0.05; 223 } 224 isBlue(Color color)225 private static boolean isBlue(Color color) { 226 return color.red() < 0.05 && color.green() < 0.05 && color.blue() > 0.95; 227 } 228 isWhite(Color color)229 private static boolean isWhite(Color color) { 230 return color.red() > 0.95 && color.green() > 0.95 && color.blue() > 0.95; 231 } 232 saveBitmapToFile(Bitmap bitmap, String filename)233 public static void saveBitmapToFile(Bitmap bitmap, String filename) { 234 try { 235 File outputFile = new File(Environment.getExternalStorageDirectory(), filename); 236 237 Log.d(TAG, "Saving bitmap to: " + outputFile); 238 FileOutputStream outputStream = new FileOutputStream(outputFile); 239 bitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream); 240 outputStream.flush(); 241 outputStream.close(); 242 } catch(Exception e) { 243 Log.e(TAG, "Failed to save to file: " + e); 244 } 245 } 246 } 247 248