OSDN Git Service

Added jpeg streaming classes.
[android-x86/packages-apps-Gallery2.git] / jni_jpegstream / src / jpegstream.cpp
diff --git a/jni_jpegstream/src/jpegstream.cpp b/jni_jpegstream/src/jpegstream.cpp
new file mode 100644 (file)
index 0000000..3b9a683
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * 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 "error_codes.h"
+#include "jni_defines.h"
+#include "jpeg_writer.h"
+#include "jpeg_reader.h"
+#include "jpeg_config.h"
+#include "outputstream_wrapper.h"
+#include "inputstream_wrapper.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static jint OutputStream_setup(JNIEnv* env, jobject thiz, jobject out,
+        jint width, jint height, jint format, jint quality) {
+    // Get a reference to this object's class
+    jclass thisClass = env->GetObjectClass(thiz);
+    if (env->ExceptionCheck() || thisClass == NULL) {
+        return J_EXCEPTION;
+    }
+    // Get field for storing C pointer
+    jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+    if (NULL == fidNumber || env->ExceptionCheck()) {
+        return J_EXCEPTION;
+    }
+
+    // Check size
+    if (width <= 0 || height <= 0) {
+        return J_ERROR_BAD_ARGS;
+    }
+    Jpeg_Config::Format fmt = static_cast<Jpeg_Config::Format>(format);
+    // Check format
+    switch (fmt) {
+    case Jpeg_Config::FORMAT_GRAYSCALE:
+    case Jpeg_Config::FORMAT_RGB:
+    case Jpeg_Config::FORMAT_RGBA:
+    case Jpeg_Config::FORMAT_ABGR:
+        break;
+    default:
+        return J_ERROR_BAD_ARGS;
+    }
+
+    uint32_t w = static_cast<uint32_t>(width);
+    uint32_t h = static_cast<uint32_t>(height);
+    int32_t q = static_cast<int32_t>(quality);
+    // Clamp quality to (0, 100]
+    q = (q > 100) ? 100 : ((q < 1) ? 1 : q);
+
+    JpegWriter* w_ptr = new JpegWriter();
+
+    // Do JpegWriter setup.
+    int32_t errorFlag = w_ptr->setup(env, out, w, h, fmt, q);
+    if (env->ExceptionCheck() || errorFlag != J_SUCCESS) {
+        delete w_ptr;
+        return errorFlag;
+    }
+
+    // Store C pointer for writer
+    env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(w_ptr));
+    if (env->ExceptionCheck()) {
+        delete w_ptr;
+        return J_EXCEPTION;
+    }
+    return J_SUCCESS;
+}
+
+static jint InputStream_setup(JNIEnv* env, jobject thiz, jobject dimens,
+        jobject in, jint format) {
+    // Get a reference to this object's class
+    jclass thisClass = env->GetObjectClass(thiz);
+    if (env->ExceptionCheck() || thisClass == NULL) {
+        return J_EXCEPTION;
+    }
+    jmethodID setMethod = NULL;
+
+    // Get dimensions object setter method
+    if (dimens != NULL) {
+        jclass pointClass = env->GetObjectClass(dimens);
+        if (env->ExceptionCheck() || pointClass == NULL) {
+            return J_EXCEPTION;
+        }
+        setMethod = env->GetMethodID(pointClass, "set", "(II)V");
+        if (env->ExceptionCheck() || setMethod == NULL) {
+            return J_EXCEPTION;
+        }
+    }
+    // Get field for storing C pointer
+    jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+    if (NULL == fidNumber || env->ExceptionCheck()) {
+        return J_EXCEPTION;
+    }
+    Jpeg_Config::Format fmt = static_cast<Jpeg_Config::Format>(format);
+    // Check format
+    switch (fmt) {
+    case Jpeg_Config::FORMAT_GRAYSCALE:
+    case Jpeg_Config::FORMAT_RGB:
+    case Jpeg_Config::FORMAT_RGBA:
+    case Jpeg_Config::FORMAT_ABGR:
+        break;
+    default:
+        return J_ERROR_BAD_ARGS;
+    }
+
+    JpegReader* r_ptr = new JpegReader();
+    int32_t w = 0, h = 0;
+    // Do JpegReader setup.
+    int32_t errorFlag = r_ptr->setup(env, in, &w, &h, fmt);
+    if (env->ExceptionCheck() || errorFlag != J_SUCCESS) {
+        delete r_ptr;
+        return errorFlag;
+    }
+
+    // Set dimensions to return
+    if (dimens != NULL) {
+        env->CallVoidMethod(dimens, setMethod, static_cast<jint>(w),
+                static_cast<jint>(h));
+        if (env->ExceptionCheck()) {
+            delete r_ptr;
+            return J_EXCEPTION;
+        }
+    }
+    // Store C pointer for reader
+    env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(r_ptr));
+    if (env->ExceptionCheck()) {
+        delete r_ptr;
+        return J_EXCEPTION;
+    }
+    return J_SUCCESS;
+}
+
+static JpegWriter* getWPtr(JNIEnv* env, jobject thiz, jfieldID* fid) {
+    jclass thisClass = env->GetObjectClass(thiz);
+    if (env->ExceptionCheck() || thisClass == NULL) {
+        return NULL;
+    }
+    jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+    if (NULL == fidNumber || env->ExceptionCheck()) {
+        return NULL;
+    }
+    jlong ptr = env->GetLongField(thiz, fidNumber);
+    if (env->ExceptionCheck()) {
+        return NULL;
+    }
+    // Get writer C pointer out of java field.
+    JpegWriter* w_ptr = reinterpret_cast<JpegWriter*>(ptr);
+    if (fid != NULL) {
+        *fid = fidNumber;
+    }
+    return w_ptr;
+}
+
+static JpegReader* getRPtr(JNIEnv* env, jobject thiz, jfieldID* fid) {
+    jclass thisClass = env->GetObjectClass(thiz);
+    if (env->ExceptionCheck() || thisClass == NULL) {
+        return NULL;
+    }
+    jfieldID fidNumber = env->GetFieldID(thisClass, "JNIPointer", "J");
+    if (NULL == fidNumber || env->ExceptionCheck()) {
+        return NULL;
+    }
+    jlong ptr = env->GetLongField(thiz, fidNumber);
+    if (env->ExceptionCheck()) {
+        return NULL;
+    }
+    // Get reader C pointer out of java field.
+    JpegReader* r_ptr = reinterpret_cast<JpegReader*>(ptr);
+    if (fid != NULL) {
+        *fid = fidNumber;
+    }
+    return r_ptr;
+}
+
+static void OutputStream_cleanup(JNIEnv* env, jobject thiz) {
+    jfieldID fidNumber = NULL;
+    JpegWriter* w_ptr = getWPtr(env, thiz, &fidNumber);
+    if (w_ptr == NULL) {
+        return;
+    }
+    // Update environment
+    w_ptr->updateEnv(env);
+    // Destroy writer object
+    delete w_ptr;
+    w_ptr = NULL;
+    // Set the java field to null
+    env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(w_ptr));
+}
+
+static void InputStream_cleanup(JNIEnv* env, jobject thiz) {
+    jfieldID fidNumber = NULL;
+    JpegReader* r_ptr = getRPtr(env, thiz, &fidNumber);
+    if (r_ptr == NULL) {
+        return;
+    }
+    // Update environment
+    r_ptr->updateEnv(env);
+    // Destroy the reader object
+    delete r_ptr;
+    r_ptr = NULL;
+    // Set the java field to null
+    env->SetLongField(thiz, fidNumber, reinterpret_cast<jlong>(r_ptr));
+}
+
+static jint OutputStream_writeInputBytes(JNIEnv* env, jobject thiz,
+        jbyteArray inBuffer, jint offset, jint inCount) {
+    JpegWriter* w_ptr = getWPtr(env, thiz, NULL);
+    if (w_ptr == NULL) {
+        return J_EXCEPTION;
+    }
+    // Pin input buffer
+    jbyte* in_buf = (jbyte*) env->GetByteArrayElements(inBuffer, 0);
+    if (env->ExceptionCheck() || in_buf == NULL) {
+        return J_EXCEPTION;
+    }
+
+    int8_t* in_bytes = static_cast<int8_t*>(in_buf);
+    int32_t in_len = static_cast<int32_t>(inCount);
+    int32_t off = static_cast<int32_t>(offset);
+    in_bytes += off;
+    int32_t written = 0;
+
+    // Update environment
+    w_ptr->updateEnv(env);
+    // Write out and unpin buffer.
+    written = w_ptr->write(in_bytes, in_len);
+    env->ReleaseByteArrayElements(inBuffer, in_buf, JNI_ABORT);
+    return written;
+}
+
+static jint InputStream_readDecodedBytes(JNIEnv* env, jobject thiz,
+        jbyteArray inBuffer, jint offset, jint inCount) {
+    JpegReader* r_ptr = getRPtr(env, thiz, NULL);
+    if (r_ptr == NULL) {
+        return J_EXCEPTION;
+    }
+    // Pin input buffer
+    jbyte* in_buf = (jbyte*) env->GetByteArrayElements(inBuffer, 0);
+    if (env->ExceptionCheck() || in_buf == NULL) {
+        return J_EXCEPTION;
+    }
+    int8_t* in_bytes = static_cast<int8_t*>(in_buf);
+    int32_t in_len = static_cast<int32_t>(inCount);
+    int32_t off = static_cast<int32_t>(offset);
+    int32_t read = 0;
+
+    // Update environment
+    r_ptr->updateEnv(env);
+    // Read into buffer
+    read = r_ptr->read(in_bytes, off, in_len);
+
+    // Unpin buffer
+    if (read < 0) {
+        env->ReleaseByteArrayElements(inBuffer, in_buf, JNI_ABORT);
+    } else {
+        env->ReleaseByteArrayElements(inBuffer, in_buf, JNI_COMMIT);
+    }
+    return read;
+}
+
+static jint InputStream_skipDecodedBytes(JNIEnv* env, jobject thiz,
+        jint bytes) {
+    if (bytes <= 0) {
+        return J_ERROR_BAD_ARGS;
+    }
+    JpegReader* r_ptr = getRPtr(env, thiz, NULL);
+    if (r_ptr == NULL) {
+        return J_EXCEPTION;
+    }
+
+    // Update environment
+    r_ptr->updateEnv(env);
+    int32_t skip = 0;
+    // Read with null buffer to skip
+    skip = r_ptr->read(NULL, 0, bytes);
+    return skip;
+}
+
+static const char *outClassPathName =
+        "com/android/gallery3d/jpegstream/JPEGOutputStream";
+static const char *inClassPathName =
+        "com/android/gallery3d/jpegstream/JPEGInputStream";
+
+static JNINativeMethod writeMethods[] = { { "setup",
+        "(Ljava/io/OutputStream;IIII)I", (void*) OutputStream_setup }, {
+        "cleanup", "()V", (void*) OutputStream_cleanup }, { "writeInputBytes",
+        "([BII)I", (void*) OutputStream_writeInputBytes } };
+
+static JNINativeMethod readMethods[] = { { "setup",
+        "(Landroid/graphics/Point;Ljava/io/InputStream;I)I",
+        (void*) InputStream_setup }, { "cleanup", "()V",
+        (void*) InputStream_cleanup }, { "readDecodedBytes", "([BII)I",
+        (void*) InputStream_readDecodedBytes }, { "skipDecodedBytes", "(I)I",
+        (void*) InputStream_skipDecodedBytes } };
+
+static int registerNativeMethods(JNIEnv* env, const char* className,
+        JNINativeMethod* gMethods, int numMethods) {
+    jclass clazz;
+    clazz = env->FindClass(className);
+    if (clazz == NULL) {
+        LOGE("Native registration unable to find class '%s'", className);
+        return JNI_FALSE;
+    }
+    if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
+        LOGE("RegisterNatives failed for '%s'", className);
+        return JNI_FALSE;
+    }
+    return JNI_TRUE;
+}
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
+        LOGE("Error: GetEnv failed in JNI_OnLoad");
+        return -1;
+    }
+    if (!registerNativeMethods(env, outClassPathName, writeMethods,
+            sizeof(writeMethods) / sizeof(writeMethods[0]))) {
+        LOGE("Error: could not register native methods for JPEGOutputStream");
+        return -1;
+    }
+    if (!registerNativeMethods(env, inClassPathName, readMethods,
+            sizeof(readMethods) / sizeof(readMethods[0]))) {
+        LOGE("Error: could not register native methods for JPEGInputStream");
+        return -1;
+    }
+    // cache method IDs for OutputStream
+    jclass outCls = env->FindClass("java/io/OutputStream");
+    if (outCls == NULL) {
+        LOGE("Unable to find class 'OutputStream'");
+        return -1;
+    }
+    jmethodID cachedWriteFun = env->GetMethodID(outCls, "write", "([BII)V");
+    if (cachedWriteFun == NULL) {
+        LOGE("Unable to find write function in class 'OutputStream'");
+        return -1;
+    }
+    OutputStreamWrapper::setWriteMethodID(cachedWriteFun);
+
+    // cache method IDs for InputStream
+    jclass inCls = env->FindClass("java/io/InputStream");
+    if (inCls == NULL) {
+        LOGE("Unable to find class 'InputStream'");
+        return -1;
+    }
+    jmethodID cachedReadFun = env->GetMethodID(inCls, "read", "([BII)I");
+    if (cachedReadFun == NULL) {
+        LOGE("Unable to find read function in class 'InputStream'");
+        return -1;
+    }
+    jmethodID cachedSkipFun = env->GetMethodID(inCls, "skip", "(J)J");
+    if (cachedSkipFun == NULL) {
+        LOGE("Unable to find skip function in class 'InputStream'");
+        return -1;
+    }
+    InputStreamWrapper::setReadSkipMethodIDs(cachedReadFun, cachedSkipFun);
+    return JNI_VERSION_1_6;
+}
+
+#ifdef __cplusplus
+}
+#endif