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