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   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