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