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