1 /* 2 * Copyright (C) 2011 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 #include "android/bitmap.h" 18 19 #include "jni/jni_native_frame.h" 20 #include "jni/jni_native_buffer.h" 21 #include "jni/jni_util.h" 22 23 #include "native/base/logging.h" 24 #include "native/core/gl_frame.h" 25 #include "native/core/native_frame.h" 26 27 using android::filterfw::NativeFrame; 28 using android::filterfw::GLFrame; 29 30 typedef union { 31 uint32_t value; 32 uint8_t rgba[4]; 33 } Pixel; 34 35 jboolean Java_android_filterfw_core_NativeFrame_nativeAllocate(JNIEnv* env, 36 jobject thiz, 37 jint size) { 38 std::unique_ptr<NativeFrame> frame(new NativeFrame(size)); 39 return ToJBool(WrapOwnedObjectInJava(std::move(frame), env, thiz, true)); 40 } 41 42 jboolean Java_android_filterfw_core_NativeFrame_nativeDeallocate(JNIEnv* env, jobject thiz) { 43 return ToJBool(DeleteNativeObject<NativeFrame>(env, thiz)); 44 } 45 46 jint Java_android_filterfw_core_NativeFrame_nativeIntSize(JNIEnv*, jclass) { 47 return sizeof(jint); 48 } 49 50 jint Java_android_filterfw_core_NativeFrame_nativeFloatSize(JNIEnv*, jclass) { 51 return sizeof(jfloat); 52 } 53 54 jboolean Java_android_filterfw_core_NativeFrame_setNativeData(JNIEnv* env, 55 jobject thiz, 56 jbyteArray data, 57 jint offset, 58 jint length) { 59 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 60 if (frame && data) { 61 jbyte* bytes = env->GetByteArrayElements(data, NULL); 62 if (bytes) { 63 const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(bytes + offset), 64 0, 65 length); 66 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT); 67 return ToJBool(success); 68 } 69 } 70 return JNI_FALSE; 71 } 72 73 jbyteArray Java_android_filterfw_core_NativeFrame_getNativeData(JNIEnv* env, 74 jobject thiz, 75 jint size) { 76 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 77 if (frame) { 78 const uint8_t* data = frame->Data(); 79 if (!data || size > frame->Size()) 80 return NULL; 81 jbyteArray result = env->NewByteArray(size); 82 env->SetByteArrayRegion(result, 0, size, reinterpret_cast<const jbyte*>(data)); 83 return result; 84 } 85 return NULL; 86 } 87 88 jboolean Java_android_filterfw_core_NativeFrame_getNativeBuffer(JNIEnv* env, 89 jobject thiz, 90 jobject buffer) { 91 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 92 if (frame) { 93 char* data = reinterpret_cast<char*>(frame->MutableData()); 94 return ToJBool(AttachDataToJBuffer(env, buffer, data, frame->Size())); 95 } 96 return JNI_FALSE; 97 } 98 99 jboolean Java_android_filterfw_core_NativeFrame_setNativeInts(JNIEnv* env, 100 jobject thiz, 101 jintArray ints) { 102 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 103 if (frame && ints) { 104 jint* int_ptr = env->GetIntArrayElements(ints, NULL); 105 const int length = env->GetArrayLength(ints); 106 if (int_ptr) { 107 const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(int_ptr), 108 0, 109 length * sizeof(jint)); 110 env->ReleaseIntArrayElements(ints, int_ptr, JNI_ABORT); 111 return ToJBool(success); 112 } 113 } 114 return JNI_FALSE; 115 } 116 117 jintArray Java_android_filterfw_core_NativeFrame_getNativeInts(JNIEnv* env, 118 jobject thiz, 119 jint size) { 120 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 121 if (frame) { 122 const uint8_t* data = frame->Data(); 123 if (!data || size > frame->Size() || (size % sizeof(jint)) != 0) 124 return NULL; 125 const int count = size / sizeof(jint); 126 jintArray result = env->NewIntArray(count); 127 env->SetIntArrayRegion(result, 0, count, reinterpret_cast<const jint*>(data)); 128 return result; 129 } 130 return NULL; 131 } 132 133 jboolean Java_android_filterfw_core_NativeFrame_setNativeFloats(JNIEnv* env, 134 jobject thiz, 135 jfloatArray floats) { 136 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 137 if (frame && floats) { 138 jfloat* float_ptr = env->GetFloatArrayElements(floats, NULL); 139 const int length = env->GetArrayLength(floats); 140 if (float_ptr) { 141 const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(float_ptr), 142 0, 143 length * sizeof(jfloat)); 144 env->ReleaseFloatArrayElements(floats, float_ptr, JNI_ABORT); 145 return ToJBool(success); 146 } 147 } 148 return JNI_FALSE; 149 } 150 151 jfloatArray Java_android_filterfw_core_NativeFrame_getNativeFloats(JNIEnv* env, 152 jobject thiz, 153 jint size) { 154 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 155 if (frame) { 156 const uint8_t* data = frame->Data(); 157 if (!data || size > frame->Size() || (size % sizeof(jfloat)) != 0) 158 return NULL; 159 const int count = size / sizeof(jfloat); 160 jfloatArray result = env->NewFloatArray(count); 161 env->SetFloatArrayRegion(result, 0, count, reinterpret_cast<const jfloat*>(data)); 162 return result; 163 } 164 return NULL; 165 } 166 167 jboolean Java_android_filterfw_core_NativeFrame_setNativeBitmap(JNIEnv* env, 168 jobject thiz, 169 jobject bitmap, 170 jint size, 171 jint bytes_per_sample) { 172 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 173 if (frame && bitmap) { 174 // Make sure frame size matches bitmap size 175 if ((size / 4) != (frame->Size() / bytes_per_sample)) { 176 ALOGE("Size mismatch in native setBitmap()!"); 177 return JNI_FALSE; 178 } 179 180 Pixel* src_ptr; 181 const int result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void**>(&src_ptr)); 182 if (result == ANDROID_BITMAP_RESULT_SUCCESS) { 183 // Create destination pointers 184 uint8_t* dst_ptr = reinterpret_cast<uint8_t*>(frame->MutableData()); 185 const uint8_t* end_ptr = dst_ptr + frame->Size(); 186 switch (bytes_per_sample) { 187 case 1: { // RGBA -> GRAY 188 while (dst_ptr < end_ptr) { 189 const Pixel pixel = *(src_ptr++); 190 *(dst_ptr++) = (pixel.rgba[0] + pixel.rgba[1] + pixel.rgba[2]) / 3; 191 } 192 break; 193 } 194 case 3: { // RGBA -> RGB 195 while (dst_ptr < end_ptr) { 196 const Pixel pixel = *(src_ptr++); 197 *(dst_ptr++) = pixel.rgba[0]; 198 *(dst_ptr++) = pixel.rgba[1]; 199 *(dst_ptr++) = pixel.rgba[2]; 200 } 201 break; 202 } 203 case 4: { // RGBA -> RGBA 204 memcpy(dst_ptr, src_ptr, frame->Size()); 205 break; 206 } 207 default: 208 ALOGE("Unsupported bytes-per-pixel %d in setBitmap!", bytes_per_sample); 209 break; 210 } 211 return (AndroidBitmap_unlockPixels(env, bitmap) == ANDROID_BITMAP_RESULT_SUCCESS); 212 } 213 } 214 return JNI_FALSE; 215 } 216 217 jboolean Java_android_filterfw_core_NativeFrame_getNativeBitmap(JNIEnv* env, 218 jobject thiz, 219 jobject bitmap, 220 jint size, 221 jint bytes_per_sample) { 222 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 223 if (frame && bitmap) { 224 Pixel* dst_ptr; 225 const int result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void**>(&dst_ptr)); 226 if (result == ANDROID_BITMAP_RESULT_SUCCESS) { 227 // Make sure frame size matches bitmap size 228 if ((size / 4) != (frame->Size() / bytes_per_sample)) { 229 ALOGE("Size mismatch in native getBitmap()!"); 230 return JNI_FALSE; 231 } 232 233 const uint8_t* src_ptr = frame->Data(); 234 const uint8_t* end_ptr = src_ptr + frame->Size(); 235 switch (bytes_per_sample) { 236 case 1: { // GRAY -> RGBA 237 while (src_ptr < end_ptr) { 238 const uint8_t value = *(src_ptr++); 239 dst_ptr->rgba[0] = dst_ptr->rgba[1] = dst_ptr->rgba[2] = value; 240 dst_ptr->rgba[3] = 255; 241 ++dst_ptr; 242 } 243 break; 244 } 245 case 3: { // RGB -> RGBA 246 while (src_ptr < end_ptr) { 247 dst_ptr->rgba[0] = *(src_ptr++); 248 dst_ptr->rgba[1] = *(src_ptr++); 249 dst_ptr->rgba[2] = *(src_ptr++); 250 dst_ptr->rgba[3] = 255; 251 ++dst_ptr; 252 } 253 break; 254 } 255 case 4: { // RGBA -> RGBA 256 memcpy(dst_ptr, src_ptr, frame->Size()); 257 break; 258 } 259 default: 260 ALOGE("Unsupported bytes-per-pixel %d in getBitmap!", bytes_per_sample); 261 break; 262 } 263 return (AndroidBitmap_unlockPixels(env, bitmap) == ANDROID_BITMAP_RESULT_SUCCESS); 264 } 265 } 266 return JNI_FALSE; 267 } 268 269 jint Java_android_filterfw_core_NativeFrame_getNativeCapacity(JNIEnv* env, jobject thiz) { 270 NativeFrame* frame = ConvertFromJava<NativeFrame>(env, thiz); 271 return frame ? frame->Capacity() : -1; 272 } 273 274 jboolean Java_android_filterfw_core_NativeFrame_nativeCopyFromNative(JNIEnv* env, 275 jobject thiz, 276 jobject frame) { 277 NativeFrame* this_frame = ConvertFromJava<NativeFrame>(env, thiz); 278 NativeFrame* other_frame = ConvertFromJava<NativeFrame>(env, frame); 279 if (this_frame && other_frame) { 280 return ToJBool(this_frame->WriteData(other_frame->Data(), 0, other_frame->Size())); 281 } 282 return JNI_FALSE; 283 } 284 285 jboolean Java_android_filterfw_core_NativeFrame_nativeCopyFromGL(JNIEnv* env, 286 jobject thiz, 287 jobject frame) { 288 NativeFrame* this_frame = ConvertFromJava<NativeFrame>(env, thiz); 289 GLFrame* other_frame = ConvertFromJava<GLFrame>(env, frame); 290 if (this_frame && other_frame) { 291 return ToJBool(other_frame->CopyDataTo(this_frame->MutableData(), this_frame->Size())); 292 } 293 return JNI_FALSE; 294 } 295