diff options
Diffstat (limited to 'framesequence/jni/FrameSequenceJNI.cpp')
-rw-r--r-- | framesequence/jni/FrameSequenceJNI.cpp | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/framesequence/jni/FrameSequenceJNI.cpp b/framesequence/jni/FrameSequenceJNI.cpp new file mode 100644 index 0000000..90d0465 --- /dev/null +++ b/framesequence/jni/FrameSequenceJNI.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <android/bitmap.h> +#include "JNIHelpers.h" +#include "utils/log.h" +#include "FrameSequence.h" + +#include "FrameSequenceJNI.h" + +#define JNI_PACKAGE "android/support/rastermill" + +static struct { + jclass clazz; + jmethodID ctor; +} gFrameSequenceClassInfo; + +//////////////////////////////////////////////////////////////////////////////// +// Frame sequence +//////////////////////////////////////////////////////////////////////////////// + +static jobject createJavaFrameSequence(JNIEnv* env, FrameSequence* frameSequence) { + if (!frameSequence) { + return NULL; + } + return env->NewObject(gFrameSequenceClassInfo.clazz, gFrameSequenceClassInfo.ctor, + reinterpret_cast<jint>(frameSequence), + frameSequence->getWidth(), + frameSequence->getHeight(), + frameSequence->getFrameCount(), + frameSequence->isOpaque()); +} + +static jobject nativeDecodeByteArray(JNIEnv* env, jobject clazz, + jbyteArray byteArray, jint offset, jint length) { + jbyte* bytes = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(byteArray, NULL)); + if (bytes == NULL) { + jniThrowException(env, ILLEGAL_STATE_EXEPTION, + "couldn't read array bytes"); + return NULL; + } + bytes += offset; + MemoryStream stream(bytes, length); + FrameSequence* frameSequence = FrameSequence::create(&stream); + env->ReleasePrimitiveArrayCritical(byteArray, bytes, 0); + return createJavaFrameSequence(env, frameSequence); +} + +static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, + jobject istream, jbyteArray byteArray) { + JavaInputStream stream(env, istream, byteArray); + FrameSequence* frameSequence = FrameSequence::create(&stream); + return createJavaFrameSequence(env, frameSequence); +} + +static void nativeDestroyFrameSequence(JNIEnv* env, jobject clazz, + jint frameSequenceInt) { + FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceInt); + delete frameSequence; +} + +static jint nativeCreateState(JNIEnv* env, jobject clazz, jint frameSequenceInt) { + FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceInt); + FrameSequenceState* state = frameSequence->createState(); + return reinterpret_cast<jint>(state); +} + +//////////////////////////////////////////////////////////////////////////////// +// Frame sequence state +//////////////////////////////////////////////////////////////////////////////// + +static void nativeDestroyState( + JNIEnv* env, jobject clazz, jint frameSequenceStateInt) { + FrameSequenceState* frameSequenceState = + reinterpret_cast<FrameSequenceState*>(frameSequenceStateInt); + delete frameSequenceState; +} + +static jlong JNICALL nativeGetFrame( + JNIEnv* env, jobject clazz, jint frameSequenceStateInt, jint frameNr, + jobject bitmap, jint previousFrameNr) { + FrameSequenceState* frameSequenceState = + reinterpret_cast<FrameSequenceState*>(frameSequenceStateInt); + int ret; + AndroidBitmapInfo info; + void* pixels; + if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { + + jniThrowException(env, ILLEGAL_STATE_EXEPTION, + "Couldn't get info from Bitmap "); + return 0; + } + + if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { + jniThrowException(env, ILLEGAL_STATE_EXEPTION, + "Bitmap pixels couldn't be locked"); + return 0; + } + + int pixelStride = info.stride >> 2; + jlong delayMs = frameSequenceState->drawFrame(frameNr, + (Color8888*) pixels, pixelStride, previousFrameNr); + + AndroidBitmap_unlockPixels(env, bitmap); + return delayMs; +} + +static JNINativeMethod gMethods[] = { + { "nativeDecodeByteArray", + "([BII)L" JNI_PACKAGE "/FrameSequence;", + (void*) nativeDecodeByteArray + }, + { "nativeDecodeStream", + "(Ljava/io/InputStream;[B)L" JNI_PACKAGE "/FrameSequence;", + (void*) nativeDecodeStream + }, + { "nativeDestroyFrameSequence", + "(I)V", + (void*) nativeDestroyFrameSequence + }, + { "nativeCreateState", + "(I)I", + (void*) nativeCreateState + }, + { "nativeGetFrame", + "(IILandroid/graphics/Bitmap;I)J", + (void*) nativeGetFrame + }, + { "nativeDestroyFrameSequence", + "(I)V", + (void*) nativeDestroyState + }, +}; + +jint FrameSequence_OnLoad(JNIEnv* env) { + // Get jclass with env->FindClass. + // Register methods with env->RegisterNatives. + gFrameSequenceClassInfo.clazz = env->FindClass(JNI_PACKAGE "/FrameSequence"); + if (!gFrameSequenceClassInfo.clazz) { + ALOGW("Failed to find " JNI_PACKAGE "/FrameSequence"); + return -1; + } + gFrameSequenceClassInfo.clazz = (jclass)env->NewGlobalRef(gFrameSequenceClassInfo.clazz); + + gFrameSequenceClassInfo.ctor = env->GetMethodID(gFrameSequenceClassInfo.clazz, "<init>", "(IIIIZ)V"); + if (!gFrameSequenceClassInfo.ctor) { + ALOGW("Failed to find constructor for FrameSequence - was it stripped?"); + return -1; + } + + return env->RegisterNatives(gFrameSequenceClassInfo.clazz, gMethods, METHOD_COUNT(gMethods)); +} |