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