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.ImageFormat; 20 import android.graphics.Rect; 21 import android.media.cts.CodecImage; 22 import android.media.Image; 23 import android.media.MediaCodecInfo; 24 import android.media.MediaCodecInfo.CodecCapabilities; 25 import android.media.MediaCodecList; 26 import android.util.Log; 27 28 import java.nio.ByteBuffer; 29 import java.security.MessageDigest; 30 import java.util.ArrayList; 31 32 public class CodecUtils { 33 private static final String TAG = "CodecUtils"; 34 35 /** Load jni on initialization */ 36 static { Log.i(TAG, "before loadlibrary")37 Log.i(TAG, "before loadlibrary"); 38 System.loadLibrary("ctsmediacodec_jni"); Log.i(TAG, "after loadlibrary")39 Log.i(TAG, "after loadlibrary"); 40 } 41 42 private static class ImageWrapper extends CodecImage { 43 private final Image mImage; 44 private final Plane[] mPlanes; 45 ImageWrapper(Image image)46 private ImageWrapper(Image image) { 47 mImage = image; 48 Image.Plane[] planes = mImage.getPlanes(); 49 50 mPlanes = new Plane[planes.length]; 51 for (int i = 0; i < planes.length; i++) { 52 mPlanes[i] = new PlaneWrapper(planes[i]); 53 } 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 getImageMD5Checksum(Image image)150 public static String getImageMD5Checksum(Image image) throws Exception { 151 int format = image.getFormat(); 152 if (ImageFormat.YUV_420_888 != format) { 153 Log.w(TAG, "unsupported image format"); 154 return ""; 155 } 156 157 MessageDigest md = MessageDigest.getInstance("MD5"); 158 159 int imageWidth = image.getWidth(); 160 int imageHeight = image.getHeight(); 161 162 Image.Plane[] planes = image.getPlanes(); 163 for (int i = 0; i < planes.length; ++i) { 164 ByteBuffer buf = planes[i].getBuffer(); 165 166 int width, height, rowStride, pixelStride, x, y; 167 rowStride = planes[i].getRowStride(); 168 pixelStride = planes[i].getPixelStride(); 169 if (i == 0) { 170 width = imageWidth; 171 height = imageHeight; 172 } else { 173 width = imageWidth / 2; 174 height = imageHeight /2; 175 } 176 // local contiguous pixel buffer 177 byte[] bb = new byte[width * height]; 178 if (buf.hasArray()) { 179 byte b[] = buf.array(); 180 int offs = buf.arrayOffset(); 181 if (pixelStride == 1) { 182 for (y = 0; y < height; ++y) { 183 System.arraycopy(bb, y * width, b, y * rowStride + offs, width); 184 } 185 } else { 186 // do it pixel-by-pixel 187 for (y = 0; y < height; ++y) { 188 int lineOffset = offs + y * rowStride; 189 for (x = 0; x < width; ++x) { 190 bb[y * width + x] = b[lineOffset + x * pixelStride]; 191 } 192 } 193 } 194 } else { // almost always ends up here due to direct buffers 195 int pos = buf.position(); 196 if (pixelStride == 1) { 197 for (y = 0; y < height; ++y) { 198 buf.position(pos + y * rowStride); 199 buf.get(bb, y * width, width); 200 } 201 } else { 202 // local line buffer 203 byte[] lb = new byte[rowStride]; 204 // do it pixel-by-pixel 205 for (y = 0; y < height; ++y) { 206 buf.position(pos + y * rowStride); 207 // we're only guaranteed to have pixelStride * (width - 1) + 1 bytes 208 buf.get(lb, 0, pixelStride * (width - 1) + 1); 209 for (x = 0; x < width; ++x) { 210 bb[y * width + x] = lb[x * pixelStride]; 211 } 212 } 213 } 214 buf.position(pos); 215 } 216 md.update(bb, 0, width * height); 217 } 218 219 return convertByteArrayToHEXString(md.digest()); 220 } 221 convertByteArrayToHEXString(byte[] ba)222 private static String convertByteArrayToHEXString(byte[] ba) throws Exception { 223 StringBuilder result = new StringBuilder(); 224 for (int i = 0; i < ba.length; i++) { 225 result.append(Integer.toString((ba[i] & 0xff) + 0x100, 16).substring(1)); 226 } 227 return result.toString(); 228 } 229 } 230 231