• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
createJavaFrameSequence(JNIEnv * env,FrameSequence * frameSequence)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 
nativeDecodeByteArray(JNIEnv * env,jobject clazz,jbyteArray byteArray,jint offset,jint length)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 
nativeDecodeByteBuffer(JNIEnv * env,jobject clazz,jobject buf,jint offset,jint limit)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 
nativeDecodeStream(JNIEnv * env,jobject clazz,jobject istream,jbyteArray byteArray)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 
nativeDestroyFrameSequence(JNIEnv * env,jobject clazz,jlong frameSequenceLong)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 
nativeCreateState(JNIEnv * env,jobject clazz,jlong frameSequenceLong)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 
nativeDestroyState(JNIEnv * env,jobject clazz,jlong frameSequenceStateLong)104 static void nativeDestroyState(
105         JNIEnv* env, jobject clazz, jlong frameSequenceStateLong) {
106     FrameSequenceState* frameSequenceState =
107             reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
108     delete frameSequenceState;
109 }
110 
throwIae(JNIEnv * env,const char * message,int errorCode)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 
nativeGetFrame(JNIEnv * env,jobject clazz,jlong frameSequenceStateLong,jint frameNr,jobject bitmap,jint previousFrameNr)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 
FrameSequence_OnLoad(JNIEnv * env)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