xref: /aosp_15_r20/cts/tests/tests/media/common/jni/codec-utils-jni.cpp (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
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