Home | History | Annotate | Download | only in jni
      1 /*
      2  * Copyright (C) 2013 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 #include "JNIHelpers.h"
     19 #include "utils/log.h"
     20 #include "FrameSequence.h"
     21 
     22 #include "FrameSequenceJNI.h"
     23 
     24 #define JNI_PACKAGE "android/support/rastermill"
     25 
     26 static struct {
     27     jclass clazz;
     28     jmethodID ctor;
     29 } gFrameSequenceClassInfo;
     30 
     31 ////////////////////////////////////////////////////////////////////////////////
     32 // Frame sequence
     33 ////////////////////////////////////////////////////////////////////////////////
     34 
     35 static jobject createJavaFrameSequence(JNIEnv* env, FrameSequence* frameSequence) {
     36     if (!frameSequence) {
     37         return NULL;
     38     }
     39     return env->NewObject(gFrameSequenceClassInfo.clazz, gFrameSequenceClassInfo.ctor,
     40             reinterpret_cast<jlong>(frameSequence),
     41             frameSequence->getWidth(),
     42             frameSequence->getHeight(),
     43             frameSequence->isOpaque(),
     44             frameSequence->getFrameCount(),
     45             frameSequence->getDefaultLoopCount());
     46 }
     47 
     48 static jobject nativeDecodeByteArray(JNIEnv* env, jobject clazz,
     49         jbyteArray byteArray, jint offset, jint length) {
     50     jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(byteArray, NULL));
     51     if (bytes == NULL) {
     52         jniThrowException(env, ILLEGAL_STATE_EXEPTION,
     53                 "couldn't read array bytes");
     54         return NULL;
     55     }
     56     MemoryStream stream(bytes + offset, length, NULL);
     57     FrameSequence* frameSequence = FrameSequence::create(&stream);
     58     env->ReleasePrimitiveArrayCritical(byteArray, bytes, 0);
     59     return createJavaFrameSequence(env, frameSequence);
     60 }
     61 
     62 static jobject nativeDecodeByteBuffer(JNIEnv* env, jobject clazz,
     63         jobject buf, jint offset, jint limit) {
     64     jobject globalBuf = env->NewGlobalRef(buf);
     65     JavaVM* vm;
     66     env->GetJavaVM(&vm);
     67     MemoryStream stream(
     68         (reinterpret_cast<uint8_t*>(
     69             env->GetDirectBufferAddress(globalBuf))) + offset,
     70         limit,
     71         globalBuf);
     72     FrameSequence* frameSequence = FrameSequence::create(&stream);
     73     jobject finalSequence = createJavaFrameSequence(env, frameSequence);
     74     return finalSequence;
     75 }
     76 
     77 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
     78         jobject istream, jbyteArray byteArray) {
     79     JavaInputStream stream(env, istream, byteArray);
     80     FrameSequence* frameSequence = FrameSequence::create(&stream);
     81     return createJavaFrameSequence(env, frameSequence);
     82 }
     83 
     84 static void nativeDestroyFrameSequence(JNIEnv* env, jobject clazz,
     85         jlong frameSequenceLong) {
     86     FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
     87     jobject buf = frameSequence->getRawByteBuffer();
     88     if (buf != NULL) {
     89         env->DeleteGlobalRef(buf);
     90     }
     91     delete frameSequence;
     92 }
     93 
     94 static jlong nativeCreateState(JNIEnv* env, jobject clazz, jlong frameSequenceLong) {
     95     FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
     96     FrameSequenceState* state = frameSequence->createState();
     97     return reinterpret_cast<jlong>(state);
     98 }
     99 
    100 ////////////////////////////////////////////////////////////////////////////////
    101 // Frame sequence state
    102 ////////////////////////////////////////////////////////////////////////////////
    103 
    104 static void nativeDestroyState(
    105         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong) {
    106     FrameSequenceState* frameSequenceState =
    107             reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
    108     delete frameSequenceState;
    109 }
    110 
    111 static jlong JNICALL nativeGetFrame(
    112         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong, jint frameNr,
    113         jobject bitmap, jint previousFrameNr) {
    114     FrameSequenceState* frameSequenceState =
    115             reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
    116     int ret;
    117     AndroidBitmapInfo info;
    118     void* pixels;
    119     if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
    120 
    121         jniThrowException(env, ILLEGAL_STATE_EXEPTION,
    122                 "Couldn't get info from Bitmap ");
    123         return 0;
    124     }
    125 
    126     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
    127         jniThrowException(env, ILLEGAL_STATE_EXEPTION,
    128                 "Bitmap pixels couldn't be locked");
    129         return 0;
    130     }
    131 
    132     int pixelStride = info.stride >> 2;
    133     jlong delayMs = frameSequenceState->drawFrame(frameNr,
    134             (Color8888*) pixels, pixelStride, previousFrameNr);
    135 
    136     AndroidBitmap_unlockPixels(env, bitmap);
    137     return delayMs;
    138 }
    139 
    140 static JNINativeMethod gMethods[] = {
    141     {   "nativeDecodeByteArray",
    142         "([BII)L" JNI_PACKAGE "/FrameSequence;",
    143         (void*) nativeDecodeByteArray
    144     },
    145     {   "nativeDecodeByteBuffer",
    146         "(Ljava/nio/ByteBuffer;II)L" JNI_PACKAGE "/FrameSequence;",
    147         (void*) nativeDecodeByteBuffer
    148     },
    149     {   "nativeDecodeStream",
    150         "(Ljava/io/InputStream;[B)L" JNI_PACKAGE "/FrameSequence;",
    151         (void*) nativeDecodeStream
    152     },
    153     {   "nativeDestroyFrameSequence",
    154         "(J)V",
    155         (void*) nativeDestroyFrameSequence
    156     },
    157     {   "nativeCreateState",
    158         "(J)J",
    159         (void*) nativeCreateState
    160     },
    161     {   "nativeGetFrame",
    162         "(JILandroid/graphics/Bitmap;I)J",
    163         (void*) nativeGetFrame
    164     },
    165     {   "nativeDestroyState",
    166         "(J)V",
    167         (void*) nativeDestroyState
    168     },
    169 };
    170 
    171 jint FrameSequence_OnLoad(JNIEnv* env) {
    172     // Get jclass with env->FindClass.
    173     // Register methods with env->RegisterNatives.
    174     gFrameSequenceClassInfo.clazz = env->FindClass(JNI_PACKAGE "/FrameSequence");
    175     if (!gFrameSequenceClassInfo.clazz) {
    176         ALOGW("Failed to find " JNI_PACKAGE "/FrameSequence");
    177         return -1;
    178     }
    179     gFrameSequenceClassInfo.clazz = (jclass)env->NewGlobalRef(gFrameSequenceClassInfo.clazz);
    180 
    181     gFrameSequenceClassInfo.ctor = env->GetMethodID(gFrameSequenceClassInfo.clazz, "<init>", "(JIIZII)V");
    182     if (!gFrameSequenceClassInfo.ctor) {
    183         ALOGW("Failed to find constructor for FrameSequence - was it stripped?");
    184         return -1;
    185     }
    186 
    187     return env->RegisterNatives(gFrameSequenceClassInfo.clazz, gMethods, METHOD_COUNT(gMethods));
    188 }
    189