You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
193 lines
6.6 KiB
193 lines
6.6 KiB
/*
|
|
* 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<jlong>(frameSequence),
|
|
frameSequence->getWidth(),
|
|
frameSequence->getHeight(),
|
|
frameSequence->isOpaque(),
|
|
frameSequence->getFrameCount(),
|
|
frameSequence->getDefaultLoopCount());
|
|
}
|
|
|
|
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;
|
|
}
|
|
MemoryStream stream(bytes + offset, length, NULL);
|
|
FrameSequence* frameSequence = FrameSequence::create(&stream);
|
|
env->ReleasePrimitiveArrayCritical(byteArray, bytes, 0);
|
|
return createJavaFrameSequence(env, frameSequence);
|
|
}
|
|
|
|
static jobject nativeDecodeByteBuffer(JNIEnv* env, jobject clazz,
|
|
jobject buf, jint offset, jint limit) {
|
|
jobject globalBuf = env->NewGlobalRef(buf);
|
|
JavaVM* vm;
|
|
env->GetJavaVM(&vm);
|
|
MemoryStream stream(
|
|
(reinterpret_cast<uint8_t*>(
|
|
env->GetDirectBufferAddress(globalBuf))) + offset,
|
|
limit,
|
|
globalBuf);
|
|
FrameSequence* frameSequence = FrameSequence::create(&stream);
|
|
jobject finalSequence = createJavaFrameSequence(env, frameSequence);
|
|
return finalSequence;
|
|
}
|
|
|
|
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,
|
|
jlong frameSequenceLong) {
|
|
FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
|
|
jobject buf = frameSequence->getRawByteBuffer();
|
|
if (buf != NULL) {
|
|
env->DeleteGlobalRef(buf);
|
|
}
|
|
delete frameSequence;
|
|
}
|
|
|
|
static jlong nativeCreateState(JNIEnv* env, jobject clazz, jlong frameSequenceLong) {
|
|
FrameSequence* frameSequence = reinterpret_cast<FrameSequence*>(frameSequenceLong);
|
|
FrameSequenceState* state = frameSequence->createState();
|
|
return reinterpret_cast<jlong>(state);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Frame sequence state
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
static void nativeDestroyState(
|
|
JNIEnv* env, jobject clazz, jlong frameSequenceStateLong) {
|
|
FrameSequenceState* frameSequenceState =
|
|
reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
|
|
delete frameSequenceState;
|
|
}
|
|
|
|
void throwIae(JNIEnv* env, const char* message, int errorCode) {
|
|
char buf[256];
|
|
snprintf(buf, sizeof(buf), "%s, error %d", message, errorCode);
|
|
jniThrowException(env, ILLEGAL_STATE_EXEPTION, buf);
|
|
}
|
|
|
|
static jlong JNICALL nativeGetFrame(
|
|
JNIEnv* env, jobject clazz, jlong frameSequenceStateLong, jint frameNr,
|
|
jobject bitmap, jint previousFrameNr) {
|
|
FrameSequenceState* frameSequenceState =
|
|
reinterpret_cast<FrameSequenceState*>(frameSequenceStateLong);
|
|
int ret;
|
|
AndroidBitmapInfo info;
|
|
void* pixels;
|
|
|
|
if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) {
|
|
throwIae(env, "Couldn't get info from Bitmap", ret);
|
|
return 0;
|
|
}
|
|
|
|
if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) {
|
|
throwIae(env, "Bitmap pixels couldn't be locked", ret);
|
|
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
|
|
},
|
|
{ "nativeDecodeByteBuffer",
|
|
"(Ljava/nio/ByteBuffer;II)L" JNI_PACKAGE "/FrameSequence;",
|
|
(void*) nativeDecodeByteBuffer
|
|
},
|
|
{ "nativeDecodeStream",
|
|
"(Ljava/io/InputStream;[B)L" JNI_PACKAGE "/FrameSequence;",
|
|
(void*) nativeDecodeStream
|
|
},
|
|
{ "nativeDestroyFrameSequence",
|
|
"(J)V",
|
|
(void*) nativeDestroyFrameSequence
|
|
},
|
|
{ "nativeCreateState",
|
|
"(J)J",
|
|
(void*) nativeCreateState
|
|
},
|
|
{ "nativeGetFrame",
|
|
"(JILandroid/graphics/Bitmap;I)J",
|
|
(void*) nativeGetFrame
|
|
},
|
|
{ "nativeDestroyState",
|
|
"(J)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>", "(JIIZII)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));
|
|
}
|