1*b7c941bbSAndroid Build Coastguard Worker /*
2*b7c941bbSAndroid Build Coastguard Worker * Copyright 2014 The Android Open Source Project
3*b7c941bbSAndroid Build Coastguard Worker *
4*b7c941bbSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*b7c941bbSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*b7c941bbSAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*b7c941bbSAndroid Build Coastguard Worker *
8*b7c941bbSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*b7c941bbSAndroid Build Coastguard Worker *
10*b7c941bbSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*b7c941bbSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*b7c941bbSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b7c941bbSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*b7c941bbSAndroid Build Coastguard Worker * limitations under the License.
15*b7c941bbSAndroid Build Coastguard Worker */
16*b7c941bbSAndroid Build Coastguard Worker
17*b7c941bbSAndroid Build Coastguard Worker /* Original code copied from NDK Native-media sample code */
18*b7c941bbSAndroid Build Coastguard Worker
19*b7c941bbSAndroid Build Coastguard Worker //#define LOG_NDEBUG 0
20*b7c941bbSAndroid Build Coastguard Worker #define TAG "CodecUtilsJNI"
21*b7c941bbSAndroid Build Coastguard Worker #include <log/log.h>
22*b7c941bbSAndroid Build Coastguard Worker
23*b7c941bbSAndroid Build Coastguard Worker #include <stdint.h>
24*b7c941bbSAndroid Build Coastguard Worker #include <sys/types.h>
25*b7c941bbSAndroid Build Coastguard Worker #include <jni.h>
26*b7c941bbSAndroid Build Coastguard Worker
27*b7c941bbSAndroid Build Coastguard Worker #include <memory>
28*b7c941bbSAndroid Build Coastguard Worker
29*b7c941bbSAndroid Build Coastguard Worker // workaround for using ScopedLocalRef with system runtime
30*b7c941bbSAndroid Build Coastguard Worker // TODO: Remove this after b/74632104 is fixed
31*b7c941bbSAndroid Build Coastguard Worker namespace std
32*b7c941bbSAndroid Build Coastguard Worker {
33*b7c941bbSAndroid Build Coastguard Worker typedef decltype(nullptr) nullptr_t;
34*b7c941bbSAndroid Build Coastguard Worker }
35*b7c941bbSAndroid Build Coastguard Worker
36*b7c941bbSAndroid Build Coastguard Worker #include <nativehelper/JNIHelp.h>
37*b7c941bbSAndroid Build Coastguard Worker #include <nativehelper/ScopedLocalRef.h>
38*b7c941bbSAndroid Build Coastguard Worker
39*b7c941bbSAndroid Build Coastguard Worker #include <math.h>
40*b7c941bbSAndroid Build Coastguard Worker
41*b7c941bbSAndroid Build Coastguard Worker #include "md5_utils.h"
42*b7c941bbSAndroid Build Coastguard Worker
43*b7c941bbSAndroid Build Coastguard Worker // ImageFormat.YCBCR_P010 was defined in API31.
44*b7c941bbSAndroid Build Coastguard Worker #define __YCBCR_P010_MIN_API__ 31
45*b7c941bbSAndroid Build Coastguard Worker
46*b7c941bbSAndroid Build Coastguard Worker typedef ssize_t offs_t;
47*b7c941bbSAndroid Build Coastguard Worker
48*b7c941bbSAndroid Build Coastguard Worker struct NativeImage {
49*b7c941bbSAndroid Build Coastguard Worker struct crop {
50*b7c941bbSAndroid Build Coastguard Worker int left;
51*b7c941bbSAndroid Build Coastguard Worker int top;
52*b7c941bbSAndroid Build Coastguard Worker int right;
53*b7c941bbSAndroid Build Coastguard Worker int bottom;
54*b7c941bbSAndroid Build Coastguard Worker } crop;
55*b7c941bbSAndroid Build Coastguard Worker struct plane {
56*b7c941bbSAndroid Build Coastguard Worker const uint8_t *buffer;
57*b7c941bbSAndroid Build Coastguard Worker size_t size;
58*b7c941bbSAndroid Build Coastguard Worker ssize_t colInc;
59*b7c941bbSAndroid Build Coastguard Worker ssize_t rowInc;
60*b7c941bbSAndroid Build Coastguard Worker offs_t cropOffs;
61*b7c941bbSAndroid Build Coastguard Worker size_t cropWidth;
62*b7c941bbSAndroid Build Coastguard Worker size_t cropHeight;
63*b7c941bbSAndroid Build Coastguard Worker } plane[3];
64*b7c941bbSAndroid Build Coastguard Worker int width;
65*b7c941bbSAndroid Build Coastguard Worker int height;
66*b7c941bbSAndroid Build Coastguard Worker int format;
67*b7c941bbSAndroid Build Coastguard Worker long timestamp;
68*b7c941bbSAndroid Build Coastguard Worker size_t numPlanes;
69*b7c941bbSAndroid Build Coastguard Worker };
70*b7c941bbSAndroid Build Coastguard Worker
71*b7c941bbSAndroid Build Coastguard Worker struct ChecksumAlg {
72*b7c941bbSAndroid Build Coastguard Worker virtual void init() = 0;
73*b7c941bbSAndroid Build Coastguard Worker virtual void update(uint8_t c) = 0;
74*b7c941bbSAndroid Build Coastguard Worker virtual uint32_t checksum() = 0;
75*b7c941bbSAndroid Build Coastguard Worker virtual size_t length() = 0;
76*b7c941bbSAndroid Build Coastguard Worker protected:
~ChecksumAlgChecksumAlg77*b7c941bbSAndroid Build Coastguard Worker virtual ~ChecksumAlg() {}
78*b7c941bbSAndroid Build Coastguard Worker };
79*b7c941bbSAndroid Build Coastguard Worker
80*b7c941bbSAndroid Build Coastguard Worker struct Adler32 : ChecksumAlg {
Adler32Adler3281*b7c941bbSAndroid Build Coastguard Worker Adler32() {
82*b7c941bbSAndroid Build Coastguard Worker init();
83*b7c941bbSAndroid Build Coastguard Worker }
initAdler3284*b7c941bbSAndroid Build Coastguard Worker void init() {
85*b7c941bbSAndroid Build Coastguard Worker a = 1;
86*b7c941bbSAndroid Build Coastguard Worker len = b = 0;
87*b7c941bbSAndroid Build Coastguard Worker }
updateAdler3288*b7c941bbSAndroid Build Coastguard Worker void update(uint8_t c) {
89*b7c941bbSAndroid Build Coastguard Worker a += c;
90*b7c941bbSAndroid Build Coastguard Worker b += a;
91*b7c941bbSAndroid Build Coastguard Worker ++len;
92*b7c941bbSAndroid Build Coastguard Worker }
checksumAdler3293*b7c941bbSAndroid Build Coastguard Worker uint32_t checksum() {
94*b7c941bbSAndroid Build Coastguard Worker return (a % 65521) + ((b % 65521) << 16);
95*b7c941bbSAndroid Build Coastguard Worker }
lengthAdler3296*b7c941bbSAndroid Build Coastguard Worker size_t length() {
97*b7c941bbSAndroid Build Coastguard Worker return len;
98*b7c941bbSAndroid Build Coastguard Worker }
99*b7c941bbSAndroid Build Coastguard Worker private:
100*b7c941bbSAndroid Build Coastguard Worker uint32_t a, b;
101*b7c941bbSAndroid Build Coastguard Worker size_t len;
102*b7c941bbSAndroid Build Coastguard Worker };
103*b7c941bbSAndroid Build Coastguard Worker
104*b7c941bbSAndroid Build Coastguard Worker static struct ImageFieldsAndMethods {
105*b7c941bbSAndroid Build Coastguard Worker // android.graphics.ImageFormat
106*b7c941bbSAndroid Build Coastguard Worker int YUV_420_888;
107*b7c941bbSAndroid Build Coastguard Worker int YCBCR_P010;
108*b7c941bbSAndroid Build Coastguard Worker // android.media.Image
109*b7c941bbSAndroid Build Coastguard Worker jmethodID methodWidth;
110*b7c941bbSAndroid Build Coastguard Worker jmethodID methodHeight;
111*b7c941bbSAndroid Build Coastguard Worker jmethodID methodFormat;
112*b7c941bbSAndroid Build Coastguard Worker jmethodID methodTimestamp;
113*b7c941bbSAndroid Build Coastguard Worker jmethodID methodPlanes;
114*b7c941bbSAndroid Build Coastguard Worker jmethodID methodCrop;
115*b7c941bbSAndroid Build Coastguard Worker // android.media.Image.Plane
116*b7c941bbSAndroid Build Coastguard Worker jmethodID methodBuffer;
117*b7c941bbSAndroid Build Coastguard Worker jmethodID methodPixelStride;
118*b7c941bbSAndroid Build Coastguard Worker jmethodID methodRowStride;
119*b7c941bbSAndroid Build Coastguard Worker // android.graphics.Rect
120*b7c941bbSAndroid Build Coastguard Worker jfieldID fieldLeft;
121*b7c941bbSAndroid Build Coastguard Worker jfieldID fieldTop;
122*b7c941bbSAndroid Build Coastguard Worker jfieldID fieldRight;
123*b7c941bbSAndroid Build Coastguard Worker jfieldID fieldBottom;
124*b7c941bbSAndroid Build Coastguard Worker } gFields;
125*b7c941bbSAndroid Build Coastguard Worker static bool gFieldsInitialized = false;
126*b7c941bbSAndroid Build Coastguard Worker
initializeGlobalFields(JNIEnv * env)127*b7c941bbSAndroid Build Coastguard Worker void initializeGlobalFields(JNIEnv *env) {
128*b7c941bbSAndroid Build Coastguard Worker if (gFieldsInitialized) {
129*b7c941bbSAndroid Build Coastguard Worker return;
130*b7c941bbSAndroid Build Coastguard Worker }
131*b7c941bbSAndroid Build Coastguard Worker { // ImageFormat
132*b7c941bbSAndroid Build Coastguard Worker jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
133*b7c941bbSAndroid Build Coastguard Worker const jfieldID fieldYUV420888 = env->GetStaticFieldID(imageFormatClazz, "YUV_420_888", "I");
134*b7c941bbSAndroid Build Coastguard Worker gFields.YUV_420_888 = env->GetStaticIntField(imageFormatClazz, fieldYUV420888);
135*b7c941bbSAndroid Build Coastguard Worker if (__builtin_available(android __YCBCR_P010_MIN_API__, *)) {
136*b7c941bbSAndroid Build Coastguard Worker const jfieldID fieldYCBCRP010 = env->GetStaticFieldID(imageFormatClazz,
137*b7c941bbSAndroid Build Coastguard Worker "YCBCR_P010", "I");
138*b7c941bbSAndroid Build Coastguard Worker gFields.YCBCR_P010 = env->GetStaticIntField(imageFormatClazz, fieldYCBCRP010);
139*b7c941bbSAndroid Build Coastguard Worker } else {
140*b7c941bbSAndroid Build Coastguard Worker // Set this to -1 to ensure it doesn't get equated to any valid color format
141*b7c941bbSAndroid Build Coastguard Worker gFields.YCBCR_P010 = -1;
142*b7c941bbSAndroid Build Coastguard Worker }
143*b7c941bbSAndroid Build Coastguard Worker env->DeleteLocalRef(imageFormatClazz);
144*b7c941bbSAndroid Build Coastguard Worker imageFormatClazz = NULL;
145*b7c941bbSAndroid Build Coastguard Worker }
146*b7c941bbSAndroid Build Coastguard Worker
147*b7c941bbSAndroid Build Coastguard Worker { // Image
148*b7c941bbSAndroid Build Coastguard Worker jclass imageClazz = env->FindClass("android/media/cts/CodecImage");
149*b7c941bbSAndroid Build Coastguard Worker gFields.methodWidth = env->GetMethodID(imageClazz, "getWidth", "()I");
150*b7c941bbSAndroid Build Coastguard Worker gFields.methodHeight = env->GetMethodID(imageClazz, "getHeight", "()I");
151*b7c941bbSAndroid Build Coastguard Worker gFields.methodFormat = env->GetMethodID(imageClazz, "getFormat", "()I");
152*b7c941bbSAndroid Build Coastguard Worker gFields.methodTimestamp = env->GetMethodID(imageClazz, "getTimestamp", "()J");
153*b7c941bbSAndroid Build Coastguard Worker gFields.methodPlanes = env->GetMethodID(
154*b7c941bbSAndroid Build Coastguard Worker imageClazz, "getPlanes", "()[Landroid/media/cts/CodecImage$Plane;");
155*b7c941bbSAndroid Build Coastguard Worker gFields.methodCrop = env->GetMethodID(
156*b7c941bbSAndroid Build Coastguard Worker imageClazz, "getCropRect", "()Landroid/graphics/Rect;");
157*b7c941bbSAndroid Build Coastguard Worker env->DeleteLocalRef(imageClazz);
158*b7c941bbSAndroid Build Coastguard Worker imageClazz = NULL;
159*b7c941bbSAndroid Build Coastguard Worker }
160*b7c941bbSAndroid Build Coastguard Worker
161*b7c941bbSAndroid Build Coastguard Worker { // Image.Plane
162*b7c941bbSAndroid Build Coastguard Worker jclass planeClazz = env->FindClass("android/media/cts/CodecImage$Plane");
163*b7c941bbSAndroid Build Coastguard Worker gFields.methodBuffer = env->GetMethodID(planeClazz, "getBuffer", "()Ljava/nio/ByteBuffer;");
164*b7c941bbSAndroid Build Coastguard Worker gFields.methodPixelStride = env->GetMethodID(planeClazz, "getPixelStride", "()I");
165*b7c941bbSAndroid Build Coastguard Worker gFields.methodRowStride = env->GetMethodID(planeClazz, "getRowStride", "()I");
166*b7c941bbSAndroid Build Coastguard Worker env->DeleteLocalRef(planeClazz);
167*b7c941bbSAndroid Build Coastguard Worker planeClazz = NULL;
168*b7c941bbSAndroid Build Coastguard Worker }
169*b7c941bbSAndroid Build Coastguard Worker
170*b7c941bbSAndroid Build Coastguard Worker { // Rect
171*b7c941bbSAndroid Build Coastguard Worker jclass rectClazz = env->FindClass("android/graphics/Rect");
172*b7c941bbSAndroid Build Coastguard Worker gFields.fieldLeft = env->GetFieldID(rectClazz, "left", "I");
173*b7c941bbSAndroid Build Coastguard Worker gFields.fieldTop = env->GetFieldID(rectClazz, "top", "I");
174*b7c941bbSAndroid Build Coastguard Worker gFields.fieldRight = env->GetFieldID(rectClazz, "right", "I");
175*b7c941bbSAndroid Build Coastguard Worker gFields.fieldBottom = env->GetFieldID(rectClazz, "bottom", "I");
176*b7c941bbSAndroid Build Coastguard Worker env->DeleteLocalRef(rectClazz);
177*b7c941bbSAndroid Build Coastguard Worker rectClazz = NULL;
178*b7c941bbSAndroid Build Coastguard Worker }
179*b7c941bbSAndroid Build Coastguard Worker gFieldsInitialized = true;
180*b7c941bbSAndroid Build Coastguard Worker }
181*b7c941bbSAndroid Build Coastguard Worker
getNativeImage(JNIEnv * env,jobject image,jobject area=NULL)182*b7c941bbSAndroid Build Coastguard Worker static std::unique_ptr<NativeImage> getNativeImage(JNIEnv *env, jobject image, jobject area = NULL) {
183*b7c941bbSAndroid Build Coastguard Worker if (image == NULL) {
184*b7c941bbSAndroid Build Coastguard Worker jniThrowNullPointerException(env, "image is null");
185*b7c941bbSAndroid Build Coastguard Worker return NULL;
186*b7c941bbSAndroid Build Coastguard Worker }
187*b7c941bbSAndroid Build Coastguard Worker
188*b7c941bbSAndroid Build Coastguard Worker initializeGlobalFields(env);
189*b7c941bbSAndroid Build Coastguard Worker
190*b7c941bbSAndroid Build Coastguard Worker std::unique_ptr<NativeImage> img(new NativeImage);
191*b7c941bbSAndroid Build Coastguard Worker img->format = env->CallIntMethod(image, gFields.methodFormat);
192*b7c941bbSAndroid Build Coastguard Worker img->width = env->CallIntMethod(image, gFields.methodWidth);
193*b7c941bbSAndroid Build Coastguard Worker img->height = env->CallIntMethod(image, gFields.methodHeight);
194*b7c941bbSAndroid Build Coastguard Worker img->timestamp = env->CallLongMethod(image, gFields.methodTimestamp);
195*b7c941bbSAndroid Build Coastguard Worker
196*b7c941bbSAndroid Build Coastguard Worker jobject cropRect = NULL;
197*b7c941bbSAndroid Build Coastguard Worker if (area == NULL) {
198*b7c941bbSAndroid Build Coastguard Worker cropRect = env->CallObjectMethod(image, gFields.methodCrop);
199*b7c941bbSAndroid Build Coastguard Worker area = cropRect;
200*b7c941bbSAndroid Build Coastguard Worker }
201*b7c941bbSAndroid Build Coastguard Worker
202*b7c941bbSAndroid Build Coastguard Worker img->crop.left = env->GetIntField(area, gFields.fieldLeft);
203*b7c941bbSAndroid Build Coastguard Worker img->crop.top = env->GetIntField(area, gFields.fieldTop);
204*b7c941bbSAndroid Build Coastguard Worker img->crop.right = env->GetIntField(area, gFields.fieldRight);
205*b7c941bbSAndroid Build Coastguard Worker img->crop.bottom = env->GetIntField(area, gFields.fieldBottom);
206*b7c941bbSAndroid Build Coastguard Worker if (img->crop.right == 0 && img->crop.bottom == 0) {
207*b7c941bbSAndroid Build Coastguard Worker img->crop.right = img->width;
208*b7c941bbSAndroid Build Coastguard Worker img->crop.bottom = img->height;
209*b7c941bbSAndroid Build Coastguard Worker }
210*b7c941bbSAndroid Build Coastguard Worker
211*b7c941bbSAndroid Build Coastguard Worker if (cropRect != NULL) {
212*b7c941bbSAndroid Build Coastguard Worker env->DeleteLocalRef(cropRect);
213*b7c941bbSAndroid Build Coastguard Worker cropRect = NULL;
214*b7c941bbSAndroid Build Coastguard Worker }
215*b7c941bbSAndroid Build Coastguard Worker
216*b7c941bbSAndroid Build Coastguard Worker if (img->format != gFields.YUV_420_888 && img->format != gFields.YCBCR_P010) {
217*b7c941bbSAndroid Build Coastguard Worker jniThrowException(
218*b7c941bbSAndroid Build Coastguard Worker env, "java/lang/UnsupportedOperationException",
219*b7c941bbSAndroid Build Coastguard Worker "only support YUV_420_888 and YCBCR_P010 images");
220*b7c941bbSAndroid Build Coastguard Worker img.reset();
221*b7c941bbSAndroid Build Coastguard Worker return img;
222*b7c941bbSAndroid Build Coastguard Worker }
223*b7c941bbSAndroid Build Coastguard Worker img->numPlanes = 3;
224*b7c941bbSAndroid Build Coastguard Worker
225*b7c941bbSAndroid Build Coastguard Worker ScopedLocalRef<jobjectArray> planesArray(
226*b7c941bbSAndroid Build Coastguard Worker env, (jobjectArray)env->CallObjectMethod(image, gFields.methodPlanes));
227*b7c941bbSAndroid Build Coastguard Worker int xDecim = 0;
228*b7c941bbSAndroid Build Coastguard Worker int yDecim = 0;
229*b7c941bbSAndroid Build Coastguard Worker for (size_t ix = 0; ix < img->numPlanes; ++ix) {
230*b7c941bbSAndroid Build Coastguard Worker ScopedLocalRef<jobject> plane(
231*b7c941bbSAndroid Build Coastguard Worker env, env->GetObjectArrayElement(planesArray.get(), (jsize)ix));
232*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].colInc = env->CallIntMethod(plane.get(), gFields.methodPixelStride);
233*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].rowInc = env->CallIntMethod(plane.get(), gFields.methodRowStride);
234*b7c941bbSAndroid Build Coastguard Worker ScopedLocalRef<jobject> buffer(
235*b7c941bbSAndroid Build Coastguard Worker env, env->CallObjectMethod(plane.get(), gFields.methodBuffer));
236*b7c941bbSAndroid Build Coastguard Worker
237*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].buffer = (const uint8_t *)env->GetDirectBufferAddress(buffer.get());
238*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].size = env->GetDirectBufferCapacity(buffer.get());
239*b7c941bbSAndroid Build Coastguard Worker
240*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].cropOffs =
241*b7c941bbSAndroid Build Coastguard Worker (img->crop.left >> xDecim) * img->plane[ix].colInc
242*b7c941bbSAndroid Build Coastguard Worker + (img->crop.top >> yDecim) * img->plane[ix].rowInc;
243*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].cropHeight =
244*b7c941bbSAndroid Build Coastguard Worker ((img->crop.bottom + (1 << yDecim) - 1) >> yDecim) - (img->crop.top >> yDecim);
245*b7c941bbSAndroid Build Coastguard Worker img->plane[ix].cropWidth =
246*b7c941bbSAndroid Build Coastguard Worker ((img->crop.right + (1 << xDecim) - 1) >> xDecim) - (img->crop.left >> xDecim);
247*b7c941bbSAndroid Build Coastguard Worker
248*b7c941bbSAndroid Build Coastguard Worker // validate increments
249*b7c941bbSAndroid Build Coastguard Worker ssize_t widthOffs =
250*b7c941bbSAndroid Build Coastguard Worker (((img->width + (1 << xDecim) - 1) >> xDecim) - 1) * img->plane[ix].colInc;
251*b7c941bbSAndroid Build Coastguard Worker ssize_t heightOffs =
252*b7c941bbSAndroid Build Coastguard Worker (((img->height + (1 << yDecim) - 1) >> yDecim) - 1) * img->plane[ix].rowInc;
253*b7c941bbSAndroid Build Coastguard Worker if (widthOffs < 0 || heightOffs < 0
254*b7c941bbSAndroid Build Coastguard Worker || widthOffs + heightOffs >= (ssize_t)img->plane[ix].size) {
255*b7c941bbSAndroid Build Coastguard Worker jniThrowException(
256*b7c941bbSAndroid Build Coastguard Worker env, "java/lang/IndexOutOfBoundsException", "plane exceeds bytearray");
257*b7c941bbSAndroid Build Coastguard Worker img.reset();
258*b7c941bbSAndroid Build Coastguard Worker return img;
259*b7c941bbSAndroid Build Coastguard Worker }
260*b7c941bbSAndroid Build Coastguard Worker xDecim = yDecim = 1;
261*b7c941bbSAndroid Build Coastguard Worker }
262*b7c941bbSAndroid Build Coastguard Worker return img;
263*b7c941bbSAndroid Build Coastguard Worker }
264*b7c941bbSAndroid Build Coastguard Worker
Java_android_media_cts_CodecUtils_getImageChecksumAlder32(JNIEnv * env,jclass,jobject image)265*b7c941bbSAndroid Build Coastguard Worker extern "C" jint Java_android_media_cts_CodecUtils_getImageChecksumAlder32(JNIEnv *env,
266*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject image)
267*b7c941bbSAndroid Build Coastguard Worker {
268*b7c941bbSAndroid Build Coastguard Worker auto img = getNativeImage(env, image);
269*b7c941bbSAndroid Build Coastguard Worker if (!img) {
270*b7c941bbSAndroid Build Coastguard Worker return 0;
271*b7c941bbSAndroid Build Coastguard Worker }
272*b7c941bbSAndroid Build Coastguard Worker
273*b7c941bbSAndroid Build Coastguard Worker Adler32 adler;
274*b7c941bbSAndroid Build Coastguard Worker for (size_t ix = 0; ix < img->numPlanes; ++ix) {
275*b7c941bbSAndroid Build Coastguard Worker const uint8_t *row = img->plane[ix].buffer + img->plane[ix].cropOffs;
276*b7c941bbSAndroid Build Coastguard Worker for (size_t y = img->plane[ix].cropHeight; y > 0; --y) {
277*b7c941bbSAndroid Build Coastguard Worker const uint8_t *col = row;
278*b7c941bbSAndroid Build Coastguard Worker ssize_t colInc = img->plane[ix].colInc;
279*b7c941bbSAndroid Build Coastguard Worker for (size_t x = img->plane[ix].cropWidth; x > 0; --x) {
280*b7c941bbSAndroid Build Coastguard Worker adler.update(*col);
281*b7c941bbSAndroid Build Coastguard Worker col += colInc;
282*b7c941bbSAndroid Build Coastguard Worker }
283*b7c941bbSAndroid Build Coastguard Worker row += img->plane[ix].rowInc;
284*b7c941bbSAndroid Build Coastguard Worker }
285*b7c941bbSAndroid Build Coastguard Worker }
286*b7c941bbSAndroid Build Coastguard Worker ALOGV("adler %zu/%u", adler.length(), adler.checksum());
287*b7c941bbSAndroid Build Coastguard Worker return adler.checksum();
288*b7c941bbSAndroid Build Coastguard Worker }
289*b7c941bbSAndroid Build Coastguard Worker
Java_android_media_cts_CodecUtils_getImageChecksumMD5(JNIEnv * env,jclass,jobject image)290*b7c941bbSAndroid Build Coastguard Worker extern "C" jstring Java_android_media_cts_CodecUtils_getImageChecksumMD5(JNIEnv *env,
291*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject image)
292*b7c941bbSAndroid Build Coastguard Worker {
293*b7c941bbSAndroid Build Coastguard Worker auto img = getNativeImage(env, image);
294*b7c941bbSAndroid Build Coastguard Worker if (!img) {
295*b7c941bbSAndroid Build Coastguard Worker return 0;
296*b7c941bbSAndroid Build Coastguard Worker }
297*b7c941bbSAndroid Build Coastguard Worker
298*b7c941bbSAndroid Build Coastguard Worker MD5Context md5;
299*b7c941bbSAndroid Build Coastguard Worker char res[33];
300*b7c941bbSAndroid Build Coastguard Worker MD5Init(&md5);
301*b7c941bbSAndroid Build Coastguard Worker
302*b7c941bbSAndroid Build Coastguard Worker for (size_t ix = 0; ix < img->numPlanes; ++ix) {
303*b7c941bbSAndroid Build Coastguard Worker const uint8_t *row = img->plane[ix].buffer + img->plane[ix].cropOffs;
304*b7c941bbSAndroid Build Coastguard Worker for (size_t y = img->plane[ix].cropHeight; y > 0; --y) {
305*b7c941bbSAndroid Build Coastguard Worker const uint8_t *col = row;
306*b7c941bbSAndroid Build Coastguard Worker ssize_t colInc = img->plane[ix].colInc;
307*b7c941bbSAndroid Build Coastguard Worker for (size_t x = img->plane[ix].cropWidth; x > 0; --x) {
308*b7c941bbSAndroid Build Coastguard Worker MD5Update(&md5, col, 1);
309*b7c941bbSAndroid Build Coastguard Worker col += colInc;
310*b7c941bbSAndroid Build Coastguard Worker }
311*b7c941bbSAndroid Build Coastguard Worker row += img->plane[ix].rowInc;
312*b7c941bbSAndroid Build Coastguard Worker }
313*b7c941bbSAndroid Build Coastguard Worker }
314*b7c941bbSAndroid Build Coastguard Worker
315*b7c941bbSAndroid Build Coastguard Worker static const char hex[16] = {
316*b7c941bbSAndroid Build Coastguard Worker '0', '1', '2', '3', '4', '5', '6', '7',
317*b7c941bbSAndroid Build Coastguard Worker '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
318*b7c941bbSAndroid Build Coastguard Worker };
319*b7c941bbSAndroid Build Coastguard Worker uint8_t tmp[16];
320*b7c941bbSAndroid Build Coastguard Worker
321*b7c941bbSAndroid Build Coastguard Worker MD5Final(tmp, &md5);
322*b7c941bbSAndroid Build Coastguard Worker for (int i = 0; i < 16; i++) {
323*b7c941bbSAndroid Build Coastguard Worker res[i * 2 + 0] = hex[tmp[i] >> 4];
324*b7c941bbSAndroid Build Coastguard Worker res[i * 2 + 1] = hex[tmp[i] & 0xf];
325*b7c941bbSAndroid Build Coastguard Worker }
326*b7c941bbSAndroid Build Coastguard Worker res[32] = 0;
327*b7c941bbSAndroid Build Coastguard Worker
328*b7c941bbSAndroid Build Coastguard Worker return env->NewStringUTF(res);
329*b7c941bbSAndroid Build Coastguard Worker }
330*b7c941bbSAndroid Build Coastguard Worker
331*b7c941bbSAndroid Build Coastguard Worker /* tiled copy that loops around source image boundary */
Java_android_media_cts_CodecUtils_copyFlexYUVImage(JNIEnv * env,jclass,jobject target,jobject source)332*b7c941bbSAndroid Build Coastguard Worker extern "C" void Java_android_media_cts_CodecUtils_copyFlexYUVImage(JNIEnv *env,
333*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject target, jobject source)
334*b7c941bbSAndroid Build Coastguard Worker {
335*b7c941bbSAndroid Build Coastguard Worker auto tgt = getNativeImage(env, target);
336*b7c941bbSAndroid Build Coastguard Worker auto src = getNativeImage(env, source);
337*b7c941bbSAndroid Build Coastguard Worker if (tgt != NULL && src != NULL) {
338*b7c941bbSAndroid Build Coastguard Worker ALOGV("copyFlexYUVImage %dx%d (%d,%d..%d,%d) (%zux%zu) %+zd%+zd %+zd%+zd %+zd%+zd <= "
339*b7c941bbSAndroid Build Coastguard Worker "%dx%d (%d, %d..%d, %d) (%zux%zu) %+zd%+zd %+zd%+zd %+zd%+zd",
340*b7c941bbSAndroid Build Coastguard Worker tgt->width, tgt->height,
341*b7c941bbSAndroid Build Coastguard Worker tgt->crop.left, tgt->crop.top, tgt->crop.right, tgt->crop.bottom,
342*b7c941bbSAndroid Build Coastguard Worker tgt->plane[0].cropWidth, tgt->plane[0].cropHeight,
343*b7c941bbSAndroid Build Coastguard Worker tgt->plane[0].rowInc, tgt->plane[0].colInc,
344*b7c941bbSAndroid Build Coastguard Worker tgt->plane[1].rowInc, tgt->plane[1].colInc,
345*b7c941bbSAndroid Build Coastguard Worker tgt->plane[2].rowInc, tgt->plane[2].colInc,
346*b7c941bbSAndroid Build Coastguard Worker src->width, src->height,
347*b7c941bbSAndroid Build Coastguard Worker src->crop.left, src->crop.top, src->crop.right, src->crop.bottom,
348*b7c941bbSAndroid Build Coastguard Worker src->plane[0].cropWidth, src->plane[0].cropHeight,
349*b7c941bbSAndroid Build Coastguard Worker src->plane[0].rowInc, src->plane[0].colInc,
350*b7c941bbSAndroid Build Coastguard Worker src->plane[1].rowInc, src->plane[1].colInc,
351*b7c941bbSAndroid Build Coastguard Worker src->plane[2].rowInc, src->plane[2].colInc);
352*b7c941bbSAndroid Build Coastguard Worker for (size_t ix = 0; ix < tgt->numPlanes; ++ix) {
353*b7c941bbSAndroid Build Coastguard Worker uint8_t *row = const_cast<uint8_t *>(tgt->plane[ix].buffer) + tgt->plane[ix].cropOffs;
354*b7c941bbSAndroid Build Coastguard Worker for (size_t y = 0; y < tgt->plane[ix].cropHeight; ++y) {
355*b7c941bbSAndroid Build Coastguard Worker uint8_t *col = row;
356*b7c941bbSAndroid Build Coastguard Worker ssize_t colInc = tgt->plane[ix].colInc;
357*b7c941bbSAndroid Build Coastguard Worker const uint8_t *srcRow = (src->plane[ix].buffer + src->plane[ix].cropOffs
358*b7c941bbSAndroid Build Coastguard Worker + src->plane[ix].rowInc * (y % src->plane[ix].cropHeight));
359*b7c941bbSAndroid Build Coastguard Worker for (size_t x = 0; x < tgt->plane[ix].cropWidth; ++x) {
360*b7c941bbSAndroid Build Coastguard Worker *col = srcRow[src->plane[ix].colInc * (x % src->plane[ix].cropWidth)];
361*b7c941bbSAndroid Build Coastguard Worker col += colInc;
362*b7c941bbSAndroid Build Coastguard Worker }
363*b7c941bbSAndroid Build Coastguard Worker row += tgt->plane[ix].rowInc;
364*b7c941bbSAndroid Build Coastguard Worker }
365*b7c941bbSAndroid Build Coastguard Worker }
366*b7c941bbSAndroid Build Coastguard Worker }
367*b7c941bbSAndroid Build Coastguard Worker }
368*b7c941bbSAndroid Build Coastguard Worker
Java_android_media_cts_CodecUtils_fillImageRectWithYUV(JNIEnv * env,jclass,jobject image,jobject area,jint y,jint u,jint v)369*b7c941bbSAndroid Build Coastguard Worker extern "C" void Java_android_media_cts_CodecUtils_fillImageRectWithYUV(JNIEnv *env,
370*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject image, jobject area, jint y, jint u, jint v)
371*b7c941bbSAndroid Build Coastguard Worker {
372*b7c941bbSAndroid Build Coastguard Worker auto img = getNativeImage(env, image, area);
373*b7c941bbSAndroid Build Coastguard Worker if (!img) {
374*b7c941bbSAndroid Build Coastguard Worker return;
375*b7c941bbSAndroid Build Coastguard Worker }
376*b7c941bbSAndroid Build Coastguard Worker
377*b7c941bbSAndroid Build Coastguard Worker for (size_t ix = 0; ix < img->numPlanes; ++ix) {
378*b7c941bbSAndroid Build Coastguard Worker const uint8_t *row = img->plane[ix].buffer + img->plane[ix].cropOffs;
379*b7c941bbSAndroid Build Coastguard Worker uint8_t val = ix == 0 ? y : ix == 1 ? u : v;
380*b7c941bbSAndroid Build Coastguard Worker for (size_t y = img->plane[ix].cropHeight; y > 0; --y) {
381*b7c941bbSAndroid Build Coastguard Worker uint8_t *col = (uint8_t *)row;
382*b7c941bbSAndroid Build Coastguard Worker ssize_t colInc = img->plane[ix].colInc;
383*b7c941bbSAndroid Build Coastguard Worker for (size_t x = img->plane[ix].cropWidth; x > 0; --x) {
384*b7c941bbSAndroid Build Coastguard Worker *col = val;
385*b7c941bbSAndroid Build Coastguard Worker col += colInc;
386*b7c941bbSAndroid Build Coastguard Worker }
387*b7c941bbSAndroid Build Coastguard Worker row += img->plane[ix].rowInc;
388*b7c941bbSAndroid Build Coastguard Worker }
389*b7c941bbSAndroid Build Coastguard Worker }
390*b7c941bbSAndroid Build Coastguard Worker }
391*b7c941bbSAndroid Build Coastguard Worker
getRawStats(std::unique_ptr<NativeImage> & img,jlong rawStats[10])392*b7c941bbSAndroid Build Coastguard Worker void getRawStats(std::unique_ptr<NativeImage> &img, jlong rawStats[10])
393*b7c941bbSAndroid Build Coastguard Worker {
394*b7c941bbSAndroid Build Coastguard Worker // this works best if crop area is even
395*b7c941bbSAndroid Build Coastguard Worker
396*b7c941bbSAndroid Build Coastguard Worker uint64_t sum_x[3] = { 0, 0, 0 }; // Y, U, V
397*b7c941bbSAndroid Build Coastguard Worker uint64_t sum_xx[3] = { 0, 0, 0 }; // YY, UU, VV
398*b7c941bbSAndroid Build Coastguard Worker uint64_t sum_xy[3] = { 0, 0, 0 }; // YU, YV, UV
399*b7c941bbSAndroid Build Coastguard Worker
400*b7c941bbSAndroid Build Coastguard Worker const uint8_t *yrow = img->plane[0].buffer + img->plane[0].cropOffs;
401*b7c941bbSAndroid Build Coastguard Worker const uint8_t *urow = img->plane[1].buffer + img->plane[1].cropOffs;
402*b7c941bbSAndroid Build Coastguard Worker const uint8_t *vrow = img->plane[2].buffer + img->plane[2].cropOffs;
403*b7c941bbSAndroid Build Coastguard Worker
404*b7c941bbSAndroid Build Coastguard Worker ssize_t ycolInc = img->plane[0].colInc;
405*b7c941bbSAndroid Build Coastguard Worker ssize_t ucolInc = img->plane[1].colInc;
406*b7c941bbSAndroid Build Coastguard Worker ssize_t vcolInc = img->plane[2].colInc;
407*b7c941bbSAndroid Build Coastguard Worker
408*b7c941bbSAndroid Build Coastguard Worker ssize_t yrowInc = img->plane[0].rowInc;
409*b7c941bbSAndroid Build Coastguard Worker ssize_t urowInc = img->plane[1].rowInc;
410*b7c941bbSAndroid Build Coastguard Worker ssize_t vrowInc = img->plane[2].rowInc;
411*b7c941bbSAndroid Build Coastguard Worker
412*b7c941bbSAndroid Build Coastguard Worker size_t rightOdd = img->crop.right & 1;
413*b7c941bbSAndroid Build Coastguard Worker size_t bottomOdd = img->crop.bottom & 1;
414*b7c941bbSAndroid Build Coastguard Worker
415*b7c941bbSAndroid Build Coastguard Worker for (size_t y = img->plane[0].cropHeight; y; --y) {
416*b7c941bbSAndroid Build Coastguard Worker uint8_t *ycol = (uint8_t *)yrow;
417*b7c941bbSAndroid Build Coastguard Worker uint8_t *ucol = (uint8_t *)urow;
418*b7c941bbSAndroid Build Coastguard Worker uint8_t *vcol = (uint8_t *)vrow;
419*b7c941bbSAndroid Build Coastguard Worker
420*b7c941bbSAndroid Build Coastguard Worker for (size_t x = img->plane[0].cropWidth; x; --x) {
421*b7c941bbSAndroid Build Coastguard Worker uint64_t Y = 0, U = 0, V = 0;
422*b7c941bbSAndroid Build Coastguard Worker if (img->format == gFields.YCBCR_P010) {
423*b7c941bbSAndroid Build Coastguard Worker // Only most significant 8 bits are used for statistics as rest of the analysis
424*b7c941bbSAndroid Build Coastguard Worker // is based on 8-bit data
425*b7c941bbSAndroid Build Coastguard Worker Y = *(ycol + 1);
426*b7c941bbSAndroid Build Coastguard Worker U = *(ucol + 1);
427*b7c941bbSAndroid Build Coastguard Worker V = *(vcol + 1);
428*b7c941bbSAndroid Build Coastguard Worker } else {
429*b7c941bbSAndroid Build Coastguard Worker Y = *ycol;
430*b7c941bbSAndroid Build Coastguard Worker U = *ucol;
431*b7c941bbSAndroid Build Coastguard Worker V = *vcol;
432*b7c941bbSAndroid Build Coastguard Worker }
433*b7c941bbSAndroid Build Coastguard Worker
434*b7c941bbSAndroid Build Coastguard Worker sum_x[0] += Y;
435*b7c941bbSAndroid Build Coastguard Worker sum_x[1] += U;
436*b7c941bbSAndroid Build Coastguard Worker sum_x[2] += V;
437*b7c941bbSAndroid Build Coastguard Worker sum_xx[0] += Y * Y;
438*b7c941bbSAndroid Build Coastguard Worker sum_xx[1] += U * U;
439*b7c941bbSAndroid Build Coastguard Worker sum_xx[2] += V * V;
440*b7c941bbSAndroid Build Coastguard Worker sum_xy[0] += Y * U;
441*b7c941bbSAndroid Build Coastguard Worker sum_xy[1] += Y * V;
442*b7c941bbSAndroid Build Coastguard Worker sum_xy[2] += U * V;
443*b7c941bbSAndroid Build Coastguard Worker
444*b7c941bbSAndroid Build Coastguard Worker ycol += ycolInc;
445*b7c941bbSAndroid Build Coastguard Worker if (rightOdd ^ (x & 1)) {
446*b7c941bbSAndroid Build Coastguard Worker ucol += ucolInc;
447*b7c941bbSAndroid Build Coastguard Worker vcol += vcolInc;
448*b7c941bbSAndroid Build Coastguard Worker }
449*b7c941bbSAndroid Build Coastguard Worker }
450*b7c941bbSAndroid Build Coastguard Worker
451*b7c941bbSAndroid Build Coastguard Worker yrow += yrowInc;
452*b7c941bbSAndroid Build Coastguard Worker if (bottomOdd ^ (y & 1)) {
453*b7c941bbSAndroid Build Coastguard Worker urow += urowInc;
454*b7c941bbSAndroid Build Coastguard Worker vrow += vrowInc;
455*b7c941bbSAndroid Build Coastguard Worker }
456*b7c941bbSAndroid Build Coastguard Worker }
457*b7c941bbSAndroid Build Coastguard Worker
458*b7c941bbSAndroid Build Coastguard Worker rawStats[0] = img->plane[0].cropWidth * (uint64_t)img->plane[0].cropHeight;
459*b7c941bbSAndroid Build Coastguard Worker for (size_t i = 0; i < 3; i++) {
460*b7c941bbSAndroid Build Coastguard Worker rawStats[i + 1] = sum_x[i];
461*b7c941bbSAndroid Build Coastguard Worker rawStats[i + 4] = sum_xx[i];
462*b7c941bbSAndroid Build Coastguard Worker rawStats[i + 7] = sum_xy[i];
463*b7c941bbSAndroid Build Coastguard Worker }
464*b7c941bbSAndroid Build Coastguard Worker }
465*b7c941bbSAndroid Build Coastguard Worker
Raw2YUVStats(jlong rawStats[10],jfloat stats[9])466*b7c941bbSAndroid Build Coastguard Worker bool Raw2YUVStats(jlong rawStats[10], jfloat stats[9]) {
467*b7c941bbSAndroid Build Coastguard Worker int64_t sum_x[3], sum_xx[3]; // Y, U, V
468*b7c941bbSAndroid Build Coastguard Worker int64_t sum_xy[3]; // YU, YV, UV
469*b7c941bbSAndroid Build Coastguard Worker
470*b7c941bbSAndroid Build Coastguard Worker int64_t num = rawStats[0]; // #Y,U,V
471*b7c941bbSAndroid Build Coastguard Worker for (size_t i = 0; i < 3; i++) {
472*b7c941bbSAndroid Build Coastguard Worker sum_x[i] = rawStats[i + 1];
473*b7c941bbSAndroid Build Coastguard Worker sum_xx[i] = rawStats[i + 4];
474*b7c941bbSAndroid Build Coastguard Worker sum_xy[i] = rawStats[i + 7];
475*b7c941bbSAndroid Build Coastguard Worker }
476*b7c941bbSAndroid Build Coastguard Worker
477*b7c941bbSAndroid Build Coastguard Worker if (num > 0) {
478*b7c941bbSAndroid Build Coastguard Worker stats[0] = sum_x[0] / (float)num; // y average
479*b7c941bbSAndroid Build Coastguard Worker stats[1] = sum_x[1] / (float)num; // u average
480*b7c941bbSAndroid Build Coastguard Worker stats[2] = sum_x[2] / (float)num; // v average
481*b7c941bbSAndroid Build Coastguard Worker
482*b7c941bbSAndroid Build Coastguard Worker // 60 bits for 4Mpixel image
483*b7c941bbSAndroid Build Coastguard Worker // adding 1 to avoid degenerate case when deviation is 0
484*b7c941bbSAndroid Build Coastguard Worker stats[3] = sqrtf((sum_xx[0] + 1) * num - sum_x[0] * sum_x[0]) / num; // y stdev
485*b7c941bbSAndroid Build Coastguard Worker stats[4] = sqrtf((sum_xx[1] + 1) * num - sum_x[1] * sum_x[1]) / num; // u stdev
486*b7c941bbSAndroid Build Coastguard Worker stats[5] = sqrtf((sum_xx[2] + 1) * num - sum_x[2] * sum_x[2]) / num; // v stdev
487*b7c941bbSAndroid Build Coastguard Worker
488*b7c941bbSAndroid Build Coastguard Worker // yu covar
489*b7c941bbSAndroid Build Coastguard Worker stats[6] = (float)(sum_xy[0] + 1 - sum_x[0] * sum_x[1] / num) / num / stats[3] / stats[4];
490*b7c941bbSAndroid Build Coastguard Worker // yv covar
491*b7c941bbSAndroid Build Coastguard Worker stats[7] = (float)(sum_xy[1] + 1 - sum_x[0] * sum_x[2] / num) / num / stats[3] / stats[5];
492*b7c941bbSAndroid Build Coastguard Worker // uv covar
493*b7c941bbSAndroid Build Coastguard Worker stats[8] = (float)(sum_xy[2] + 1 - sum_x[1] * sum_x[2] / num) / num / stats[4] / stats[5];
494*b7c941bbSAndroid Build Coastguard Worker return true;
495*b7c941bbSAndroid Build Coastguard Worker } else {
496*b7c941bbSAndroid Build Coastguard Worker return false;
497*b7c941bbSAndroid Build Coastguard Worker }
498*b7c941bbSAndroid Build Coastguard Worker }
499*b7c941bbSAndroid Build Coastguard Worker
Java_android_media_cts_CodecUtils_getRawStats(JNIEnv * env,jclass,jobject image,jobject area)500*b7c941bbSAndroid Build Coastguard Worker extern "C" jobject Java_android_media_cts_CodecUtils_getRawStats(JNIEnv *env,
501*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject image, jobject area)
502*b7c941bbSAndroid Build Coastguard Worker {
503*b7c941bbSAndroid Build Coastguard Worker auto img = getNativeImage(env, image, area);
504*b7c941bbSAndroid Build Coastguard Worker if (!img) {
505*b7c941bbSAndroid Build Coastguard Worker return NULL;
506*b7c941bbSAndroid Build Coastguard Worker }
507*b7c941bbSAndroid Build Coastguard Worker
508*b7c941bbSAndroid Build Coastguard Worker jlong rawStats[10];
509*b7c941bbSAndroid Build Coastguard Worker getRawStats(img, rawStats);
510*b7c941bbSAndroid Build Coastguard Worker jlongArray jstats = env->NewLongArray(10);
511*b7c941bbSAndroid Build Coastguard Worker if (jstats != NULL) {
512*b7c941bbSAndroid Build Coastguard Worker env->SetLongArrayRegion(jstats, 0, 10, rawStats);
513*b7c941bbSAndroid Build Coastguard Worker }
514*b7c941bbSAndroid Build Coastguard Worker return jstats;
515*b7c941bbSAndroid Build Coastguard Worker }
516*b7c941bbSAndroid Build Coastguard Worker
Java_android_media_cts_CodecUtils_getYUVStats(JNIEnv * env,jclass,jobject image,jobject area)517*b7c941bbSAndroid Build Coastguard Worker extern "C" jobject Java_android_media_cts_CodecUtils_getYUVStats(JNIEnv *env,
518*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject image, jobject area)
519*b7c941bbSAndroid Build Coastguard Worker {
520*b7c941bbSAndroid Build Coastguard Worker auto img = getNativeImage(env, image, area);
521*b7c941bbSAndroid Build Coastguard Worker if (!img) {
522*b7c941bbSAndroid Build Coastguard Worker return NULL;
523*b7c941bbSAndroid Build Coastguard Worker }
524*b7c941bbSAndroid Build Coastguard Worker
525*b7c941bbSAndroid Build Coastguard Worker jlong rawStats[10];
526*b7c941bbSAndroid Build Coastguard Worker getRawStats(img, rawStats);
527*b7c941bbSAndroid Build Coastguard Worker jfloat stats[9];
528*b7c941bbSAndroid Build Coastguard Worker jfloatArray jstats = NULL;
529*b7c941bbSAndroid Build Coastguard Worker if (Raw2YUVStats(rawStats, stats)) {
530*b7c941bbSAndroid Build Coastguard Worker jstats = env->NewFloatArray(9);
531*b7c941bbSAndroid Build Coastguard Worker if (jstats != NULL) {
532*b7c941bbSAndroid Build Coastguard Worker env->SetFloatArrayRegion(jstats, 0, 9, stats);
533*b7c941bbSAndroid Build Coastguard Worker }
534*b7c941bbSAndroid Build Coastguard Worker } else {
535*b7c941bbSAndroid Build Coastguard Worker jniThrowRuntimeException(env, "empty area");
536*b7c941bbSAndroid Build Coastguard Worker }
537*b7c941bbSAndroid Build Coastguard Worker
538*b7c941bbSAndroid Build Coastguard Worker return jstats;
539*b7c941bbSAndroid Build Coastguard Worker }
540*b7c941bbSAndroid Build Coastguard Worker
Java_android_media_cts_CodecUtils_Raw2YUVStats(JNIEnv * env,jclass,jobject jrawStats)541*b7c941bbSAndroid Build Coastguard Worker extern "C" jobject Java_android_media_cts_CodecUtils_Raw2YUVStats(JNIEnv *env,
542*b7c941bbSAndroid Build Coastguard Worker jclass /*clazz*/, jobject jrawStats)
543*b7c941bbSAndroid Build Coastguard Worker {
544*b7c941bbSAndroid Build Coastguard Worker jfloatArray jstats = NULL;
545*b7c941bbSAndroid Build Coastguard Worker jlong rawStats[10];
546*b7c941bbSAndroid Build Coastguard Worker env->GetLongArrayRegion((jlongArray)jrawStats, 0, 10, rawStats);
547*b7c941bbSAndroid Build Coastguard Worker if (!env->ExceptionCheck()) {
548*b7c941bbSAndroid Build Coastguard Worker jfloat stats[9];
549*b7c941bbSAndroid Build Coastguard Worker if (Raw2YUVStats(rawStats, stats)) {
550*b7c941bbSAndroid Build Coastguard Worker jstats = env->NewFloatArray(9);
551*b7c941bbSAndroid Build Coastguard Worker if (jstats != NULL) {
552*b7c941bbSAndroid Build Coastguard Worker env->SetFloatArrayRegion(jstats, 0, 9, stats);
553*b7c941bbSAndroid Build Coastguard Worker }
554*b7c941bbSAndroid Build Coastguard Worker } else {
555*b7c941bbSAndroid Build Coastguard Worker jniThrowRuntimeException(env, "no raw statistics");
556*b7c941bbSAndroid Build Coastguard Worker }
557*b7c941bbSAndroid Build Coastguard Worker }
558*b7c941bbSAndroid Build Coastguard Worker return jstats;
559*b7c941bbSAndroid Build Coastguard Worker }
560