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 void throwIae(JNIEnv* env, const char* message, int errorCode) {
    112     char buf[256];
    113     snprintf(buf, sizeof(buf), "%s, error %d", message, errorCode);
    114     jniThrowException(env, ILLEGAL_STATE_EXEPTION, buf);
    115 }
    116 
    117 static jlong JNICALL nativeGetFrame(
    118         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong, jint frameNr,
    119         jobject bitmap, jint previousFrameNr) {
    120     FrameSequenceState* frameSequenceState =
    121             reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
    122     int ret;
    123     AndroidBitmapInfo info;
    124     void* pixels;
    125 
    126     if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
    127         throwIae(env, "Couldn't get info from Bitmap", ret);
    128         return 0;
    129     }
    130 
    131     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
    132         throwIae(env, "Bitmap pixels couldn't be locked", ret);
    133         return 0;
    134     }
    135 
    136     int pixelStride = info.stride >> 2;
    137     jlong delayMs = frameSequenceState->drawFrame(frameNr,
    138             (Color8888*) pixels, pixelStride, previousFrameNr);
    139 
    140     AndroidBitmap_unlockPixels(env, bitmap);
    141     return delayMs;
    142 }
    143 
    144 static JNINativeMethod gMethods[] = {
    145     {   "nativeDecodeByteArray",
    146         "([BII)L" JNI_PACKAGE "/FrameSequence;",
    147         (void*) nativeDecodeByteArray
    148     },
    149     {   "nativeDecodeByteBuffer",
    150         "(Ljava/nio/ByteBuffer;II)L" JNI_PACKAGE "/FrameSequence;",
    151         (void*) nativeDecodeByteBuffer
    152     },
    153     {   "nativeDecodeStream",
    154         "(Ljava/io/InputStream;[B)L" JNI_PACKAGE "/FrameSequence;",
    155         (void*) nativeDecodeStream
    156     },
    157     {   "nativeDestroyFrameSequence",
    158         "(J)V",
    159         (void*) nativeDestroyFrameSequence
    160     },
    161     {   "nativeCreateState",
    162         "(J)J",
    163         (void*) nativeCreateState
    164     },
    165     {   "nativeGetFrame",
    166         "(JILandroid/graphics/Bitmap;I)J",
    167         (void*) nativeGetFrame
    168     },
    169     {   "nativeDestroyState",
    170         "(J)V",
    171         (void*) nativeDestroyState
    172     },
    173 };
    174 
    175 jint FrameSequence_OnLoad(JNIEnv* env) {
    176     // Get jclass with env->FindClass.
    177     // Register methods with env->RegisterNatives.
    178     gFrameSequenceClassInfo.clazz = env->FindClass(JNI_PACKAGE "/FrameSequence");
    179     if (!gFrameSequenceClassInfo.clazz) {
    180         ALOGW("Failed to find " JNI_PACKAGE "/FrameSequence");
    181         return -1;
    182     }
    183     gFrameSequenceClassInfo.clazz = (jclass)env->NewGlobalRef(gFrameSequenceClassInfo.clazz);
    184 
    185     gFrameSequenceClassInfo.ctor = env->GetMethodID(gFrameSequenceClassInfo.clazz, "<init>", "(JIIZII)V");
    186     if (!gFrameSequenceClassInfo.ctor) {
    187         ALOGW("Failed to find constructor for FrameSequence - was it stripped?");
    188         return -1;
    189     }
    190 
    191     return env->RegisterNatives(gFrameSequenceClassInfo.clazz, gMethods, METHOD_COUNT(gMethods));
    192 }
    193