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_gl_frame.h" 20 #include "jni/jni_util.h" 21 22 #include "native/core/gl_env.h" 23 #include "native/core/gl_frame.h" 24 #include "native/core/native_frame.h" 25 26 using android::filterfw::GLEnv; 27 using android::filterfw::GLFrame; 28 using android::filterfw::NativeFrame; 29 30 // Helper functions //////////////////////////////////////////////////////////////////////////////// 31 void ConvertFloatsToRGBA(const float* floats, int length, uint8_t* result) { 32 for (int i = 0; i < length; ++i) { 33 result[i] = static_cast<uint8_t>(floats[i] * 255.0); 34 } 35 } 36 37 void ConvertRGBAToFloats(const uint8_t* rgba, int length, float* result) { 38 for (int i = 0; i < length; ++i) { 39 result[i] = rgba[i] / 255.0; 40 } 41 } 42 43 // GLFrame JNI implementation ////////////////////////////////////////////////////////////////////// 44 jboolean Java_android_filterfw_core_GLFrame_nativeAllocate(JNIEnv* env, 45 jobject thiz, 46 jobject gl_env, 47 jint width, 48 jint height) { 49 GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env); 50 if (!gl_env_ptr) return JNI_FALSE; 51 GLFrame* frame = new GLFrame(gl_env_ptr); 52 if (frame->Init(width, height)) { 53 return ToJBool(WrapObjectInJava(frame, env, thiz, true)); 54 } else { 55 delete frame; 56 return JNI_FALSE; 57 } 58 } 59 60 jboolean Java_android_filterfw_core_GLFrame_nativeAllocateWithTexture(JNIEnv* env, 61 jobject thiz, 62 jobject gl_env, 63 jint tex_id, 64 jint width, 65 jint height) { 66 GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env); 67 if (!gl_env_ptr) return JNI_FALSE; 68 GLFrame* frame = new GLFrame(gl_env_ptr); 69 if (frame->InitWithTexture(tex_id, width, height)) { 70 return ToJBool(WrapObjectInJava(frame, env, thiz, true)); 71 } else { 72 delete frame; 73 return JNI_FALSE; 74 } 75 } 76 77 jboolean Java_android_filterfw_core_GLFrame_nativeAllocateWithFbo(JNIEnv* env, 78 jobject thiz, 79 jobject gl_env, 80 jint fbo_id, 81 jint width, 82 jint height) { 83 GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env); 84 if (!gl_env_ptr) return JNI_FALSE; 85 GLFrame* frame = new GLFrame(gl_env_ptr); 86 if (frame->InitWithFbo(fbo_id, width, height)) { 87 return ToJBool(WrapObjectInJava(frame, env, thiz, true)); 88 } else { 89 delete frame; 90 return JNI_FALSE; 91 } 92 } 93 94 jboolean Java_android_filterfw_core_GLFrame_nativeAllocateExternal(JNIEnv* env, 95 jobject thiz, 96 jobject gl_env) { 97 GLEnv* gl_env_ptr = ConvertFromJava<GLEnv>(env, gl_env); 98 if (!gl_env_ptr) return JNI_FALSE; 99 GLFrame* frame = new GLFrame(gl_env_ptr); 100 if (frame->InitWithExternalTexture()) { 101 return ToJBool(WrapObjectInJava(frame, env, thiz, true)); 102 } else { 103 delete frame; 104 return JNI_FALSE; 105 } 106 } 107 108 jboolean Java_android_filterfw_core_GLFrame_nativeDeallocate(JNIEnv* env, jobject thiz) { 109 return ToJBool(DeleteNativeObject<GLFrame>(env, thiz)); 110 } 111 112 jboolean Java_android_filterfw_core_GLFrame_setNativeData(JNIEnv* env, 113 jobject thiz, 114 jbyteArray data, 115 jint offset, 116 jint length) { 117 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 118 if (frame && data) { 119 jbyte* bytes = env->GetByteArrayElements(data, NULL); 120 if (bytes) { 121 const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(bytes + offset), length); 122 env->ReleaseByteArrayElements(data, bytes, JNI_ABORT); 123 return ToJBool(success); 124 } 125 } 126 return JNI_FALSE; 127 } 128 129 jbyteArray Java_android_filterfw_core_GLFrame_getNativeData(JNIEnv* env, jobject thiz) { 130 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 131 if (frame && frame->Size() > 0) { 132 jbyteArray result = env->NewByteArray(frame->Size()); 133 jbyte* data = env->GetByteArrayElements(result, NULL); 134 frame->CopyDataTo(reinterpret_cast<uint8_t*>(data), frame->Size()); 135 env->ReleaseByteArrayElements(result, data, 0); 136 return result; 137 } 138 return NULL; 139 } 140 141 jboolean Java_android_filterfw_core_GLFrame_setNativeInts(JNIEnv* env, 142 jobject thiz, 143 jintArray ints) { 144 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 145 if (frame && ints) { 146 jint* int_ptr = env->GetIntArrayElements(ints, NULL); 147 const int length = env->GetArrayLength(ints); 148 if (int_ptr) { 149 const bool success = frame->WriteData(reinterpret_cast<const uint8_t*>(int_ptr), 150 length * sizeof(jint)); 151 env->ReleaseIntArrayElements(ints, int_ptr, JNI_ABORT); 152 return ToJBool(success); 153 } 154 } 155 return JNI_FALSE; 156 } 157 158 jintArray Java_android_filterfw_core_GLFrame_getNativeInts(JNIEnv* env, jobject thiz) { 159 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 160 if (frame && frame->Size() > 0 && (frame->Size() % sizeof(jint) == 0)) { 161 jintArray result = env->NewIntArray(frame->Size() / sizeof(jint)); 162 jint* data = env->GetIntArrayElements(result, NULL); 163 frame->CopyDataTo(reinterpret_cast<uint8_t*>(data), frame->Size()); 164 env->ReleaseIntArrayElements(result, data, 0); 165 return result; 166 } 167 return NULL; 168 } 169 170 jboolean Java_android_filterfw_core_GLFrame_setNativeFloats(JNIEnv* env, 171 jobject thiz, 172 jfloatArray floats) { 173 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 174 if (frame && floats) { 175 jfloat* float_ptr = env->GetFloatArrayElements(floats, NULL); 176 const int length = env->GetArrayLength(floats); 177 if (float_ptr) { 178 // Convert floats to RGBA buffer 179 uint8_t* rgba_buffer = new uint8_t[length]; 180 ConvertFloatsToRGBA(float_ptr, length, rgba_buffer); 181 env->ReleaseFloatArrayElements(floats, float_ptr, JNI_ABORT); 182 183 // Write RGBA buffer to frame 184 const bool success = frame->WriteData(rgba_buffer, length); 185 186 // Clean-up 187 delete[] rgba_buffer; 188 return ToJBool(success); 189 } 190 } 191 return JNI_FALSE; 192 } 193 194 jfloatArray Java_android_filterfw_core_GLFrame_getNativeFloats(JNIEnv* env, jobject thiz) { 195 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 196 if (frame && frame->Size() > 0) { 197 // Create the result array 198 jfloatArray result = env->NewFloatArray(frame->Size()); 199 jfloat* float_array = env->GetFloatArrayElements(result, NULL); 200 201 // Read the frame pixels 202 uint8_t* pixels = new uint8_t[frame->Size()]; 203 frame->CopyDataTo(pixels, frame->Size()); 204 205 // Convert them to floats 206 ConvertRGBAToFloats(pixels, frame->Size(), float_array); 207 208 // Clean-up 209 delete[] pixels; 210 env->ReleaseFloatArrayElements(result, float_array, 0); 211 return result; 212 } 213 return NULL; 214 } 215 216 jboolean Java_android_filterfw_core_GLFrame_setNativeBitmap(JNIEnv* env, 217 jobject thiz, 218 jobject bitmap, 219 jint size) { 220 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 221 if (frame && bitmap) { 222 uint8_t* pixels; 223 const int result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void**>(&pixels)); 224 if (result == ANDROID_BITMAP_RESULT_SUCCESS) { 225 const bool success = frame->WriteData(pixels, size); 226 return ToJBool(success && 227 AndroidBitmap_unlockPixels(env, bitmap) == ANDROID_BITMAP_RESULT_SUCCESS); 228 } 229 } 230 return JNI_FALSE; 231 } 232 233 jboolean Java_android_filterfw_core_GLFrame_getNativeBitmap(JNIEnv* env, 234 jobject thiz, 235 jobject bitmap) { 236 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 237 if (frame && bitmap) { 238 uint8_t* pixels; 239 const int result = AndroidBitmap_lockPixels(env, bitmap, reinterpret_cast<void**>(&pixels)); 240 if (result == ANDROID_BITMAP_RESULT_SUCCESS) { 241 frame->CopyDataTo(pixels, frame->Size()); 242 return (AndroidBitmap_unlockPixels(env, bitmap) == ANDROID_BITMAP_RESULT_SUCCESS); 243 } 244 } 245 return JNI_FALSE; 246 } 247 248 jboolean Java_android_filterfw_core_GLFrame_setNativeViewport(JNIEnv* env, 249 jobject thiz, 250 jint x, 251 jint y, 252 jint width, 253 jint height) { 254 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 255 return frame ? ToJBool(frame->SetViewport(x, y, width, height)) : JNI_FALSE; 256 } 257 258 jint Java_android_filterfw_core_GLFrame_getNativeTextureId(JNIEnv* env, jobject thiz) { 259 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 260 return frame ? frame->GetTextureId() : -1; 261 } 262 263 jint Java_android_filterfw_core_GLFrame_getNativeFboId(JNIEnv* env, jobject thiz) { 264 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 265 return frame ? frame->GetFboId() : -1; 266 } 267 268 jboolean Java_android_filterfw_core_GLFrame_generateNativeMipMap(JNIEnv* env, jobject thiz) { 269 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 270 return frame ? ToJBool(frame->GenerateMipMap()) : JNI_FALSE; 271 } 272 273 jboolean Java_android_filterfw_core_GLFrame_setNativeTextureParam(JNIEnv* env, 274 jobject thiz, 275 jint param, 276 jint value) { 277 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 278 return frame ? ToJBool(frame->SetTextureParameter(param, value)) : JNI_FALSE; 279 } 280 281 jboolean Java_android_filterfw_core_GLFrame_nativeResetParams(JNIEnv* env, jobject thiz) { 282 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 283 return frame ? ToJBool(frame->ResetTexParameters()) : JNI_FALSE; 284 } 285 286 jboolean Java_android_filterfw_core_GLFrame_nativeCopyFromNative(JNIEnv* env, 287 jobject thiz, 288 jobject frame) { 289 GLFrame* this_frame = ConvertFromJava<GLFrame>(env, thiz); 290 NativeFrame* other_frame = ConvertFromJava<NativeFrame>(env, frame); 291 if (this_frame && other_frame) { 292 return ToJBool(this_frame->WriteData(other_frame->Data(), other_frame->Size())); 293 } 294 return JNI_FALSE; 295 } 296 297 jboolean Java_android_filterfw_core_GLFrame_nativeCopyFromGL(JNIEnv* env, 298 jobject thiz, 299 jobject frame) { 300 GLFrame* this_frame = ConvertFromJava<GLFrame>(env, thiz); 301 GLFrame* other_frame = ConvertFromJava<GLFrame>(env, frame); 302 if (this_frame && other_frame) { 303 return ToJBool(this_frame->CopyPixelsFrom(other_frame)); 304 } 305 return JNI_FALSE; 306 } 307 308 jboolean Java_android_filterfw_core_GLFrame_nativeFocus(JNIEnv* env, jobject thiz) { 309 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 310 return ToJBool(frame && frame->FocusFrameBuffer()); 311 } 312 313 jboolean Java_android_filterfw_core_GLFrame_nativeReattachTexToFbo(JNIEnv* env, jobject thiz) { 314 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 315 return ToJBool(frame && frame->ReattachTextureToFbo()); 316 } 317 318 jboolean Java_android_filterfw_core_GLFrame_nativeDetachTexFromFbo(JNIEnv* env, jobject thiz) { 319 GLFrame* frame = ConvertFromJava<GLFrame>(env, thiz); 320 return ToJBool(frame && frame->DetachTextureFromFbo()); 321 } 322 323