[FFmpeg-devel] [PATCH 1/5] lavu: add JNI support

Hendrik Leppkes h.leppkes at gmail.com
Mon Feb 15 18:56:51 CET 2016


On Mon, Feb 15, 2016 at 6:52 PM, Matthieu Bouron
<matthieu.bouron at gmail.com> wrote:
> From: Matthieu Bouron <matthieu.bouron at stupeflix.com>
>
> ---
>  configure                |   4 +
>  libavutil/Makefile       |   4 +
>  libavutil/jni.c          |  55 +++++++
>  libavutil/jni.h          |  42 +++++
>  libavutil/jni_internal.c | 391 +++++++++++++++++++++++++++++++++++++++++++++++
>  libavutil/jni_internal.h | 147 ++++++++++++++++++
>  6 files changed, 643 insertions(+)
>  create mode 100644 libavutil/jni.c
>  create mode 100644 libavutil/jni.h
>  create mode 100644 libavutil/jni_internal.c
>  create mode 100644 libavutil/jni_internal.h
>
> diff --git a/configure b/configure
> index 2148f11..d05ae4d 100755
> --- a/configure
> +++ b/configure
> @@ -206,6 +206,7 @@ External library support:
>    --enable-gnutls          enable gnutls, needed for https support
>                             if openssl is not used [no]
>    --disable-iconv          disable iconv [autodetect]
> +  --enable-jni             enable JNI support [no]
>    --enable-ladspa          enable LADSPA audio filtering [no]
>    --enable-libass          enable libass subtitles rendering,
>                             needed for subtitles and ass filter [no]
> @@ -1432,6 +1433,7 @@ EXTERNAL_LIBRARY_LIST="
>      gmp
>      gnutls
>      iconv
> +    jni
>      ladspa
>      libass
>      libbluray
> @@ -5455,6 +5457,7 @@ enabled decklink          && { check_header DeckLinkAPI.h || die "ERROR: DeckLin
>  enabled frei0r            && { check_header frei0r.h || die "ERROR: frei0r.h header not found"; }
>  enabled gmp               && require2 gmp gmp.h mpz_export -lgmp
>  enabled gnutls            && require_pkg_config gnutls gnutls/gnutls.h gnutls_global_init
> +enabled jni               && { check_header jni.h && enabled pthreads; }
>  enabled ladspa            && { check_header ladspa.h || die "ERROR: ladspa.h header not found"; }
>  enabled libiec61883       && require libiec61883 libiec61883/iec61883.h iec61883_cmp_connect -lraw1394 -lavc1394 -lrom1394 -liec61883
>  enabled libass            && require_pkg_config libass ass/ass.h ass_library_init
> @@ -6222,6 +6225,7 @@ echo "threading support         ${thread_type-no}"
>  echo "safe bitstream reader     ${safe_bitstream_reader-no}"
>  echo "SDL support               ${sdl-no}"
>  echo "opencl enabled            ${opencl-no}"
> +echo "JNI support               ${jni-no}"
>  echo "texi2html enabled         ${texi2html-no}"
>  echo "perl enabled              ${perl-no}"
>  echo "pod2man enabled           ${pod2man-no}"
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index 65b2d25..ab39d41 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -72,6 +72,8 @@ HEADERS-$(CONFIG_LZO)                   += lzo.h
>
>  HEADERS-$(CONFIG_OPENCL)                += opencl.h
>
> +HEADERS-$(CONFIG_JNI)                   += jni.h
> +
>  ARCH_HEADERS = bswap.h                                                  \
>                 intmath.h                                                \
>                 intreadwrite.h                                           \
> @@ -148,6 +150,7 @@ OBJS-$(!HAVE_ATOMICS_NATIVE)            += atomic.o                     \
>
>  OBJS-$(CONFIG_LZO)                      += lzo.o
>  OBJS-$(CONFIG_OPENCL)                   += opencl.o opencl_internal.o
> +OBJS-$(CONFIG_JNI)                      += jni.o jni_internal.o
>
>  OBJS += $(COMPAT_OBJS:%=../compat/%)
>
> @@ -158,6 +161,7 @@ SKIPHEADERS-$(HAVE_ATOMICS_GCC)        += atomic_gcc.h
>  SKIPHEADERS-$(HAVE_ATOMICS_SUNCC)      += atomic_suncc.h
>  SKIPHEADERS-$(HAVE_ATOMICS_WIN32)      += atomic_win32.h
>  SKIPHEADERS-$(CONFIG_OPENCL)           += opencl.h
> +SKIPHEADERS-$(CONFIG_JNI)              += jni_internal.h
>
>  TESTPROGS = adler32                                                     \
>              aes                                                         \
> diff --git a/libavutil/jni.c b/libavutil/jni.c
> new file mode 100644
> index 0000000..fb89426
> --- /dev/null
> +++ b/libavutil/jni.c
> @@ -0,0 +1,55 @@
> +/*
> + * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "config.h"
> +#include "jni.h"
> +#include "log.h"
> +
> +#include <jni.h>
> +#include <stdlib.h>
> +#include <pthread.h>
> +
> +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
> +
> +JavaVM *java_vm = NULL;
> +
> +void av_jni_register_java_vm(JavaVM *vm)
> +{
> +    pthread_mutex_lock(&lock);
> +    if (java_vm) {
> +        av_log(NULL, AV_LOG_INFO, "The Java VM has already been registered\n");
> +        goto done;
> +    }
> +
> +    java_vm = vm;
> +done:
> +    pthread_mutex_unlock(&lock);
> +}
> +
> +JavaVM *av_jni_get_java_vm(void)
> +{
> +    JavaVM *vm;
> +
> +    pthread_mutex_lock(&lock);
> +    vm = java_vm;
> +    pthread_mutex_unlock(&lock);
> +
> +    return vm;
> +}
> diff --git a/libavutil/jni.h b/libavutil/jni.h
> new file mode 100644
> index 0000000..a6c5c16
> --- /dev/null
> +++ b/libavutil/jni.h
> @@ -0,0 +1,42 @@
> +/*
> + * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVUTIL_JNI_H
> +#define AVUTIL_JNI_H
> +
> +#include <jni.h>
> +
> +/*
> + * Register a java virtual machine that will be used to manage the JNI
> + * environment.
> + *
> + * @param vm java virtual machine
> + */
> +void av_jni_register_java_vm(JavaVM *vm);
> +
> +/*
> + * Get the registered java virtual machine.
> + *
> + * @return the java virtual machine, NULL if no java virtual machine has been
> + * registered
> + */
> +JavaVM *av_jni_get_java_vm(void);
> +
> +#endif /* AVUTIL_JNI_H */
> diff --git a/libavutil/jni_internal.c b/libavutil/jni_internal.c
> new file mode 100644
> index 0000000..f095469
> --- /dev/null
> +++ b/libavutil/jni_internal.c
> @@ -0,0 +1,391 @@
> +/*
> + * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#include "bprint.h"
> +#include "config.h"
> +#include "jni.h"
> +#include "jni_internal.h"
> +#include "log.h"
> +
> +#include <jni.h>
> +#include <stdlib.h>
> +
> +extern JavaVM *java_vm;
> +
> +JNIEnv *avpriv_jni_attach_env(int *attached, void *log_ctx)
> +{
> +    int ret = 0;
> +    JNIEnv *env = NULL;
> +
> +    *attached = 0;
> +
> +    if (java_vm == NULL) {
> +        av_log(log_ctx, AV_LOG_ERROR, "No java virtual machine has been registered\n");
> +        return NULL;
> +    }
> +
> +    ret = (*java_vm)->GetEnv(java_vm, (void **)&env, JNI_VERSION_1_6);
> +    switch(ret) {
> +    case JNI_EDETACHED:
> +        if ((*java_vm)->AttachCurrentThread(java_vm, &env, NULL) != 0) {
> +            av_log(log_ctx, AV_LOG_ERROR, "Failed to attach the JNI environment to the current thread\n");
> +            env = NULL;
> +        } else {
> +            *attached = 1;
> +        }
> +        break;
> +    case JNI_OK:
> +        break;
> +    case JNI_EVERSION:
> +        av_log(log_ctx, AV_LOG_ERROR, "The specified JNI version is not supported\n");
> +        break;
> +    default:
> +        av_log(log_ctx, AV_LOG_ERROR, "Failed to get the JNI environment attached to this thread");
> +        break;
> +    }
> +
> +    return env;
> +}
> +
> +int avpriv_jni_detach_env(void *log_ctx)
> +{
> +    if (java_vm == NULL) {
> +        av_log(log_ctx, AV_LOG_ERROR, "No java virtual machine has been registered\n");
> +        return AVERROR(EINVAL);
> +    }
> +
> +    return (*java_vm)->DetachCurrentThread(java_vm);
> +}
> +
> +char *avpriv_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx)
> +{
> +    char *ret = NULL;
> +    const char *utf_chars = NULL;
> +
> +    jboolean copy = 0;
> +
> +    if (!string) {
> +        return NULL;
> +    }
> +
> +    utf_chars = (*env)->GetStringUTFChars(env, string, &copy);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "String.getStringUTFChars() threw an exception\n");
> +        return NULL;
> +    }
> +
> +    ret = av_strdup(utf_chars);
> +
> +    (*env)->ReleaseStringUTFChars(env, string, utf_chars);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "String.releaseStringUTFChars() threw an exception\n");
> +        return NULL;;
> +    }
> +
> +    return ret;
> +}
> +
> +jstring avpriv_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx)
> +{
> +    jstring ret;
> +
> +    ret = (*env)->NewStringUTF(env, utf_chars);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "NewStringUTF() threw an exception\n");
> +        return NULL;
> +    }
> +
> +    return ret;
> +}
> +
> +int avpriv_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx)
> +{
> +    int ret = 0;
> +
> +    AVBPrint bp;
> +
> +    char *name = NULL;
> +    char *message = NULL;
> +
> +    jclass class_class = NULL;
> +    jmethodID get_name_id = NULL;
> +
> +    jclass exception_class = NULL;
> +    jmethodID get_message_id = NULL;
> +
> +    jstring string;
> +
> +    av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC);
> +
> +    exception_class = (*env)->GetObjectClass(env, exception);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "Could not find Throwable class\n");
> +        ret = AVERROR_EXTERNAL;
> +        goto done;
> +    }
> +
> +    class_class = (*env)->GetObjectClass(env, exception_class);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "Could not find Throwable class's class\n");
> +        ret = AVERROR_EXTERNAL;
> +        goto done;
> +    }
> +
> +    get_name_id = (*env)->GetMethodID(env, class_class, "getName", "()Ljava/lang/String;");
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "Could not find method Class.getName()\n");
> +        ret = AVERROR_EXTERNAL;
> +        goto done;
> +    }
> +
> +    string = (*env)->CallObjectMethod(env, exception_class, get_name_id);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "Class.getName() threw an exception\n");
> +        ret = AVERROR_EXTERNAL;
> +        goto done;
> +    }
> +
> +    if (string) {
> +        name = avpriv_jni_jstring_to_utf_chars(env, string, log_ctx);
> +        (*env)->DeleteLocalRef(env, string);
> +        string = NULL;
> +    }
> +
> +    get_message_id = (*env)->GetMethodID(env, exception_class, "getMessage", "()Ljava/lang/String;");
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "Could not find method java/lang/Throwable.getMessage()\n");
> +        ret = AVERROR_EXTERNAL;
> +        goto done;
> +    }
> +
> +    string = (*env)->CallObjectMethod(env, exception, get_message_id);
> +    if ((*env)->ExceptionCheck(env)) {
> +        (*env)->ExceptionClear(env);
> +        av_log(log_ctx, AV_LOG_ERROR, "Throwable.getMessage() threw an exception\n");
> +        ret = AVERROR_EXTERNAL;
> +        goto done;
> +    }
> +
> +    if (string) {
> +        message = avpriv_jni_jstring_to_utf_chars(env, string, log_ctx);
> +        (*env)->DeleteLocalRef(env, string);
> +        string = NULL;
> +    }
> +
> +    if (name && message) {
> +        av_bprintf(&bp, "%s: %s", name, message);
> +    } else if (name && !message) {
> +        av_bprintf(&bp, "%s occured", name);
> +    } else if (!name && message) {
> +        av_bprintf(&bp, "Exception: %s", message);
> +    } else {
> +        av_log(log_ctx, AV_LOG_WARNING, "Could not retreive exception name and message\n");
> +        av_bprintf(&bp, "Exception occured");
> +    }
> +
> +    ret = av_bprint_finalize(&bp, error);
> +done:
> +
> +    av_free(name);
> +    av_free(message);
> +
> +    if (class_class) {
> +        (*env)->DeleteLocalRef(env, class_class);
> +    }
> +
> +    if (exception_class) {
> +        (*env)->DeleteLocalRef(env, exception_class);
> +    }
> +
> +    if (string) {
> +        (*env)->DeleteLocalRef(env, string);
> +    }
> +
> +    return ret;
> +}
> +
> +int avpriv_jni_exception_check(JNIEnv *env, int log, void *log_ctx)
> +{
> +    int ret;
> +
> +    jthrowable exception;
> +
> +    char *message = NULL;
> +
> +    if (!(*(env))->ExceptionCheck((env))) {
> +        return 0;
> +    }
> +
> +    if (!log) {
> +        (*(env))->ExceptionClear((env));
> +        return -1;
> +    }
> +
> +    exception = (*env)->ExceptionOccurred(env);
> +    (*(env))->ExceptionClear((env));
> +
> +    if ((ret = avpriv_jni_exception_get_summary(env, exception, &message, log_ctx)) < 0) {
> +        (*env)->DeleteLocalRef(env, exception);
> +        return ret;
> +    }
> +
> +    (*env)->DeleteLocalRef(env, exception);
> +
> +    av_log(log_ctx, AV_LOG_ERROR, "%s\n", message);
> +    av_free(message);
> +
> +    return -1;
> +}
> +
> +int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
> +{
> +    int i, ret = 0;
> +    jclass last_clazz = NULL;
> +
> +    for (i = 0; jfields_mapping[i].name; i++) {
> +        int mandatory = jfields_mapping[i].mandatory;
> +        enum FFJniFieldType type = jfields_mapping[i].type;
> +
> +        if (type == FF_JNI_CLASS) {
> +            jclass clazz;
> +
> +            last_clazz = NULL;
> +
> +            clazz = (*env)->FindClass(env, jfields_mapping[i].name);
> +            if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx) && mandatory) < 0) {
> +                goto done;
> +            }
> +
> +            last_clazz = *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset) =
> +                    global ? (*env)->NewGlobalRef(env, clazz) : clazz;
> +        } else {
> +
> +            if (!last_clazz) {
> +                ret = AVERROR_EXTERNAL;
> +                break;
> +            }
> +
> +            switch(type) {
> +            case (FF_JNI_FIELD): {
> +                jfieldID field_id = (*env)->GetFieldID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
> +                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
> +                    goto done;
> +                }
> +
> +                *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = field_id;
> +                break;
> +            }
> +            case (FF_JNI_STATIC_FIELD): {
> +                jfieldID field_id = (*env)->GetStaticFieldID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
> +                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
> +                    goto done;
> +                }
> +
> +                *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = field_id;
> +                break;
> +            }
> +            case (FF_JNI_METHOD): {
> +                jmethodID method_id = (*env)->GetMethodID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
> +                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
> +                    goto done;
> +                }
> +
> +                *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = method_id;
> +                break;
> +            }
> +            case (FF_JNI_STATIC_METHOD): {
> +                jmethodID method_id = (*env)->GetStaticMethodID(env, last_clazz, jfields_mapping[i].method, jfields_mapping[i].signature);
> +                if ((ret = avpriv_jni_exception_check(env, mandatory, log_ctx)) < 0 && mandatory) {
> +                    goto done;
> +                }
> +
> +                *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = method_id;
> +                break;
> +            }
> +            default:
> +                av_log(log_ctx, AV_LOG_ERROR, "Unknown JNI field type\n");
> +                ret = AVERROR(EINVAL);
> +                goto done;
> +            }
> +        }
> +    }
> +
> +done:
> +    if (ret < 0) {
> +        /* reset jfields in case of failure so it does not leak references */
> +        avpriv_jni_reset_jfields(env, jfields, jfields_mapping, global, log_ctx);
> +    }
> +
> +    return ret;
> +}
> +
> +int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx)
> +{
> +    int i;
> +
> +    for (i = 0; jfields_mapping[i].name; i++) {
> +        enum FFJniFieldType type = jfields_mapping[i].type;
> +
> +        switch(type) {
> +        case (FF_JNI_CLASS): {
> +            jclass clazz = *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset);
> +            if (!clazz)
> +                continue;
> +
> +            if (global) {
> +                (*env)->DeleteGlobalRef(env, clazz);
> +            } else {
> +                (*env)->DeleteLocalRef(env, clazz);
> +            }
> +
> +            *(jclass*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
> +            break;
> +        }
> +        case (FF_JNI_FIELD): {
> +            *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
> +            break;
> +        }
> +        case (FF_JNI_STATIC_FIELD): {
> +            *(jfieldID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
> +            break;
> +        }
> +        case (FF_JNI_METHOD): {
> +            *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
> +            break;
> +        }
> +        case (FF_JNI_STATIC_METHOD): {
> +            *(jmethodID*)((uint8_t*)jfields + jfields_mapping[i].offset) = NULL;
> +            break;
> +        }
> +        default:
> +            av_log(log_ctx, AV_LOG_ERROR, "Unknown JNI field type\n");
> +        }
> +    }
> +
> +    return 0;
> +}
> diff --git a/libavutil/jni_internal.h b/libavutil/jni_internal.h
> new file mode 100644
> index 0000000..6e66cc2
> --- /dev/null
> +++ b/libavutil/jni_internal.h
> @@ -0,0 +1,147 @@
> +/*
> + * Copyright (c) 2015-2016 Matthieu Bouron <matthieu.bouron stupeflix.com>
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + */
> +
> +#ifndef AVUTIL_JNI_INTERNAL_H
> +#define AVUTIL_JNI_INTERNAL_H
> +
> +#include <jni.h>
> +
> +/*
> + * Attach a JNI environment to the current thread.
> + *
> + * @param attached pointer to an integer that will be set to 1 if the
> + * environment has been attached to the current thread or 0 if it is
> + * already attached.
> + * @param log_ctx context used for logging, can be NULL
> + * @return the JNI environment on success, NULL otherwise
> + */
> +JNIEnv *avpriv_jni_attach_env(int *attached, void *log_ctx);
> +
> +/*
> + * Detach the JNI environment from the current thread.
> + *
> + * @param log_ctx context used for logging, can be NULL
> + * @return 0 on success, < 0 otherwise
> + */
> +int avpriv_jni_detach_env(void *log_ctx);
> +
> +/*
> + * Convert a jstring to its utf characters equivalent.
> + *
> + * @param env JNI environment
> + * @param string java string to convert
> + * @param log_ctx context used for logging, can be NULL
> + * @return a pointer to an array of unicode caracters on success, NULL
> + * otherwise
> + */
> +char *avpriv_jni_jstring_to_utf_chars(JNIEnv *env, jstring string, void *log_ctx);
> +
> +/*
> + * Convert utf chars to its jstring equivalent.
> + *
> + * @param env JNI environment
> + * @param utf_chars a pointer to an array of unicode caracters
> + * @param log_ctx context used for logging, can be NULL
> + * @return a java string object on success, NULL otherwise
> + */
> +jstring avpriv_jni_utf_chars_to_jstring(JNIEnv *env, const char *utf_chars, void *log_ctx);
> +
> +/*
> + * Extract the error summary from a jthrowable in the form of "className: errorMesage"
> + *
> + * @param env JNI environment
> + * @param exception exception to get the summary from
> + * @param error address pointing to the error, the value is updated if a
> + * summary can be extracted
> + * @param log_ctx context used for logging, can be NULL
> + * @return 0 on success, < 0 otherwise
> + */
> +int avpriv_jni_exception_get_summary(JNIEnv *env, jthrowable exception, char **error, void *log_ctx);
> +
> +/*
> + * Check if an exception has occurred,log it using av_log and clear it.
> + *
> + * @param env JNI environment
> + * @param log value used to enable logging if an exception has occured,
> + * 0 disables logging, != 0 enables logging
> + * @param log_ctx context used for logging, can be NULL
> + */
> +int avpriv_jni_exception_check(JNIEnv *env, int log, void *log_ctx);
> +
> +/*
> + * Jni field type.
> + */
> +enum FFJniFieldType {
> +
> +    FF_JNI_CLASS,
> +    FF_JNI_FIELD,
> +    FF_JNI_STATIC_FIELD,
> +    FF_JNI_METHOD,
> +    FF_JNI_STATIC_METHOD
> +
> +} MemberType;
> +
> +/*
> + * Jni field describing a class, a field or a method to be retrived using
> + * the avpriv_jni_init_jfields method.
> + */
> +struct FFJniField {
> +
> +    const char *name;
> +    const char *method;
> +    const char *signature;
> +    enum FFJniFieldType type;
> +    int offset;
> +    int mandatory;
> +
> +};
> +
> +/*
> + * Retreive class references, field ids and method ids to an arbitrary structure.
> + *
> + * @param env JNI environment
> + * @param jfields a pointer to an arbitrary structure where the different
> + * fields are declared and where the FFJNIField mapping table offsets are
> + * pointing to
> + * @param jfields_mapping null terminated array of FFJNIFields describing
> + * the class/field/method to be retrived
> + * @param global, wheter or not to make the classes reference global, it is
> + * the caller responsability to properly release global references.
> + * @param log_ctx context used for logging, can be NULL
> + * @return 0 on success, < 0 otherwise
> + */
> +int avpriv_jni_init_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
> +
> +/*
> + * Delete class references, field ids and method ids of an arbitrary structure.
> + *
> + * @param env JNI environment
> + * @param jfields a pointer to an arbitrary structure where the different
> + * fields are declared and where the FFJNIField mapping table offsets are
> + * pointing to
> + * @param jfields_mapping null terminated array of FFJNIFields describing
> + * the class/field/method to be deleted
> + * @param global, wheter or not the classes reference are global
> + * @param log_ctx context used for logging, can be NULL
> + * @return 0 on success, < 0 otherwise
> + */
> +int avpriv_jni_reset_jfields(JNIEnv *env, void *jfields, const struct FFJniField *jfields_mapping, int global, void *log_ctx);
> +
> +#endif /* AVUTIL_JNI_INTERNAL_H */
> --

avpriv API is evil, either something is worth sharing and it should be
public, or its not, and it should be entirely private (inside the
library that uses it).
Using avutil as a dump of code for other av* libraries isn't quite the
right way.

- Hendrik


More information about the ffmpeg-devel mailing list