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