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);
     57     FrameSequence* frameSequence = FrameSequence::create(&stream);
     58     env->ReleasePrimitiveArrayCritical(byteArray, bytes, 0);
     59     return createJavaFrameSequence(env, frameSequence);
     60 }
     61 
     62 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz,
     63         jobject istream, jbyteArray byteArray) {
     64     JavaInputStream stream(env, istream, byteArray);
     65     FrameSequence* frameSequence = FrameSequence::create(&stream);
     66     return createJavaFrameSequence(env, frameSequence);
     67 }
     68 
     69 static void nativeDestroyFrameSequence(JNIEnv* env, jobject clazz,
     70         jlong frameSequenceLong) {
     71     FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
     72     delete frameSequence;
     73 }
     74 
     75 static jlong nativeCreateState(JNIEnv* env, jobject clazz, jlong frameSequenceLong) {
     76     FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
     77     FrameSequenceState* state = frameSequence->createState();
     78     return reinterpret_cast<jlong>(state);
     79 }
     80 
     81 ////////////////////////////////////////////////////////////////////////////////
     82 // Frame sequence state
     83 ////////////////////////////////////////////////////////////////////////////////
     84 
     85 static void nativeDestroyState(
     86         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong) {
     87     FrameSequenceState* frameSequenceState =
     88             reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
     89     delete frameSequenceState;
     90 }
     91 
     92 static jlong JNICALL nativeGetFrame(
     93         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong, jint frameNr,
     94         jobject bitmap, jint previousFrameNr) {
     95     FrameSequenceState* frameSequenceState =
     96             reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
     97     int ret;
     98     AndroidBitmapInfo info;
     99     void* pixels;
    100     if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
    101 
    102         jniThrowException(env, ILLEGAL_STATE_EXEPTION,
    103                 "Couldn't get info from Bitmap ");
    104         return 0;
    105     }
    106 
    107     if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
    108         jniThrowException(env, ILLEGAL_STATE_EXEPTION,
    109                 "Bitmap pixels couldn't be locked");
    110         return 0;
    111     }
    112 
    113     int pixelStride = info.stride >> 2;
    114     jlong delayMs = frameSequenceState->drawFrame(frameNr,
    115             (Color8888*) pixels, pixelStride, previousFrameNr);
    116 
    117     AndroidBitmap_unlockPixels(env, bitmap);
    118     return delayMs;
    119 }
    120 
    121 static JNINativeMethod gMethods[] = {
    122     {   "nativeDecodeByteArray",
    123         "([BII)L" JNI_PACKAGE "/FrameSequence;",
    124         (void*) nativeDecodeByteArray
    125     },
    126     {   "nativeDecodeStream",
    127         "(Ljava/io/InputStream;[B)L" JNI_PACKAGE "/FrameSequence;",
    128         (void*) nativeDecodeStream
    129     },
    130     {   "nativeDestroyFrameSequence",
    131         "(J)V",
    132         (void*) nativeDestroyFrameSequence
    133     },
    134     {   "nativeCreateState",
    135         "(J)J",
    136         (void*) nativeCreateState
    137     },
    138     {   "nativeGetFrame",
    139         "(JILandroid/graphics/Bitmap;I)J",
    140         (void*) nativeGetFrame
    141     },
    142     {   "nativeDestroyState",
    143         "(J)V",
    144         (void*) nativeDestroyState
    145     },
    146 };
    147 
    148 jint FrameSequence_OnLoad(JNIEnv* env) {
    149     // Get jclass with env->FindClass.
    150     // Register methods with env->RegisterNatives.
    151     gFrameSequenceClassInfo.clazz = env->FindClass(JNI_PACKAGE "/FrameSequence");
    152     if (!gFrameSequenceClassInfo.clazz) {
    153         ALOGW("Failed to find " JNI_PACKAGE "/FrameSequence");
    154         return -1;
    155     }
    156     gFrameSequenceClassInfo.clazz = (jclass)env->NewGlobalRef(gFrameSequenceClassInfo.clazz);
    157 
    158     gFrameSequenceClassInfo.ctor = env->GetMethodID(gFrameSequenceClassInfo.clazz, "<init>", "(JIIZII)V");
    159     if (!gFrameSequenceClassInfo.ctor) {
    160         ALOGW("Failed to find constructor for FrameSequence - was it stripped?");
    161         return -1;
    162     }
    163 
    164     return env->RegisterNatives(gFrameSequenceClassInfo.clazz, gMethods, METHOD_COUNT(gMethods));
    165 }
    166