diff --git a/libmpv/src/main/cpp/event.cpp b/libmpv/src/main/cpp/event.cpp index 549f3e3..f4d4f91 100644 --- a/libmpv/src/main/cpp/event.cpp +++ b/libmpv/src/main/cpp/event.cpp @@ -6,25 +6,26 @@ #include "jni_utils.h" #include "log.h" -static void sendPropertyUpdateToJava(JNIEnv *env, mpv_event_property *prop) { + +static void sendPropertyUpdateToJava(JNIEnv *env, MPVInstance* instance, mpv_event_property *prop) { jstring jprop = env->NewStringUTF(prop->name); jstring jvalue = nullptr; switch (prop->format) { case MPV_FORMAT_NONE: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_S, jprop); + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_eventProperty_S, jprop); break; case MPV_FORMAT_FLAG: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_Sb, jprop, *(int*)prop->data); + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_eventProperty_Sb, jprop, *(int*)prop->data); break; case MPV_FORMAT_INT64: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_Sl, jprop, *(int64_t*)prop->data); + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_eventProperty_Sl, jprop, *(int64_t*)prop->data); break; case MPV_FORMAT_DOUBLE: - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_Sd, jprop, *(double*)prop->data); + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_eventProperty_Sd, jprop, *(double*)prop->data); break; case MPV_FORMAT_STRING: jvalue = env->NewStringUTF(*(const char**)prop->data); - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_eventProperty_SS, jprop, jvalue); + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_eventProperty_SS, jprop, jvalue); break; default: ALOGV("sendPropertyUpdateToJava: Unknown property update format received in callback: %d!", prop->format); @@ -36,15 +37,15 @@ static void sendPropertyUpdateToJava(JNIEnv *env, mpv_event_property *prop) { env->DeleteLocalRef(jvalue); } -static void sendEventToJava(JNIEnv *env, int event) { - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_event, event); +static void sendEventToJava(JNIEnv *env, MPVInstance* instance, int event) { + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_event, event); } static inline bool invalid_utf8(unsigned char c) { return c == 0xc0 || c == 0xc1 || c >= 0xf5; } -static void sendLogMessageToJava(JNIEnv *env, mpv_event_log_message *msg) { +static void sendLogMessageToJava(JNIEnv *env, MPVInstance* instance, mpv_event_log_message *msg) { // filter the most obvious cases of invalid utf-8 int invalid = 0; for (int i = 0; msg->text[i]; i++) @@ -55,7 +56,7 @@ static void sendLogMessageToJava(JNIEnv *env, mpv_event_log_message *msg) { jstring jprefix = env->NewStringUTF(msg->prefix); jstring jtext = env->NewStringUTF(msg->text); - env->CallStaticVoidMethod(mpv_MPVLib, mpv_MPVLib_logMessage_SiS, + env->CallVoidMethod(instance->javaObject, mpv_MPVLib_logMessage_SiS, jprefix, (jint) msg->log_level, jtext); if (jprefix) @@ -65,8 +66,9 @@ static void sendLogMessageToJava(JNIEnv *env, mpv_event_log_message *msg) { } void *event_thread(void *arg) { + auto instance = static_cast(arg); JNIEnv *env = nullptr; - acquire_jni_env(g_vm, &env); + acquire_jni_env(instance->vm, &env); if (!env) die("failed to acquire java env"); @@ -75,9 +77,9 @@ void *event_thread(void *arg) { mpv_event_property *mp_property; mpv_event_log_message *msg; - mp_event = mpv_wait_event(g_mpv, -1.0); + mp_event = mpv_wait_event(instance->mpv, -1.0); - if (g_event_thread_request_exit) + if (instance->event_thread_request_exit) break; if (mp_event->event_id == MPV_EVENT_NONE) @@ -87,20 +89,20 @@ void *event_thread(void *arg) { case MPV_EVENT_LOG_MESSAGE: msg = (mpv_event_log_message*)mp_event->data; ALOGV("[%s:%s] %s", msg->prefix, msg->level, msg->text); - sendLogMessageToJava(env, msg); + sendLogMessageToJava(env, instance, msg); break; case MPV_EVENT_PROPERTY_CHANGE: mp_property = (mpv_event_property*)mp_event->data; - sendPropertyUpdateToJava(env, mp_property); + sendPropertyUpdateToJava(env, instance, mp_property); break; default: ALOGV("event: %s\n", mpv_event_name(mp_event->event_id)); - sendEventToJava(env, mp_event->event_id); + sendEventToJava(env, instance, mp_event->event_id); break; } } - g_vm->DetachCurrentThread(); + instance->vm->DetachCurrentThread(); return nullptr; } diff --git a/libmpv/src/main/cpp/globals.h b/libmpv/src/main/cpp/globals.h index e2427b8..574d0cf 100644 --- a/libmpv/src/main/cpp/globals.h +++ b/libmpv/src/main/cpp/globals.h @@ -2,6 +2,13 @@ #include -extern JavaVM *g_vm; -extern mpv_handle *g_mpv; -extern std::atomic g_event_thread_request_exit; +// create a new struct to hold the mpv_handle and other related data +struct MPVInstance { + mpv_handle *mpv; + JavaVM *vm; + pthread_t event_thread_id; + std::atomic event_thread_request_exit; + jobject javaObject; + bool methods_initialized; + jobject surface; +}; diff --git a/libmpv/src/main/cpp/jni_utils.cpp b/libmpv/src/main/cpp/jni_utils.cpp index ebd519b..1b67de2 100644 --- a/libmpv/src/main/cpp/jni_utils.cpp +++ b/libmpv/src/main/cpp/jni_utils.cpp @@ -21,11 +21,7 @@ jmethodID java_GLSurfaceView_requestRender; jclass mpv_MPVLib; jmethodID mpv_MPVLib_eventProperty_S, mpv_MPVLib_eventProperty_Sb, mpv_MPVLib_eventProperty_Sl, mpv_MPVLib_eventProperty_Sd, mpv_MPVLib_eventProperty_SS, mpv_MPVLib_event, mpv_MPVLib_logMessage_SiS; -void init_methods_cache(JNIEnv *env) { - static bool methods_initialized = false; - if (methods_initialized) - return; - +bool init_methods_cache(JNIEnv *env, jobject instance) { #define FIND_CLASS(name) reinterpret_cast(env->NewGlobalRef(env->FindClass(name))) java_Integer = FIND_CLASS("java/lang/Integer"); java_Integer_init = env->GetMethodID(java_Integer, "", "(I)V"); @@ -37,15 +33,15 @@ void init_methods_cache(JNIEnv *env) { java_Boolean_init = env->GetMethodID(java_Boolean, "", "(Z)V"); java_Boolean_booleanValue = env->GetMethodID(java_Boolean, "booleanValue", "()Z"); - mpv_MPVLib = FIND_CLASS("dev/jdtech/mpv/MPVLib"); - mpv_MPVLib_eventProperty_S = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;)V"); // eventProperty(String) - mpv_MPVLib_eventProperty_Sb = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;Z)V"); // eventProperty(String, boolean) - mpv_MPVLib_eventProperty_Sl = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;J)V"); // eventProperty(String, long) - mpv_MPVLib_eventProperty_Sd = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;D)V"); // eventProperty(String, double) - mpv_MPVLib_eventProperty_SS = env->GetStaticMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;Ljava/lang/String;)V"); // eventProperty(String, String) - mpv_MPVLib_event = env->GetStaticMethodID(mpv_MPVLib, "event", "(I)V"); // event(int) - mpv_MPVLib_logMessage_SiS = env->GetStaticMethodID(mpv_MPVLib, "logMessage", "(Ljava/lang/String;ILjava/lang/String;)V"); // logMessage(String, int, String) + mpv_MPVLib = env->GetObjectClass(instance); + mpv_MPVLib_eventProperty_S = env->GetMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;)V"); // eventProperty(String) + mpv_MPVLib_eventProperty_Sb = env->GetMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;Z)V"); // eventProperty(String, boolean) + mpv_MPVLib_eventProperty_Sl = env->GetMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;J)V"); // eventProperty(String, long) + mpv_MPVLib_eventProperty_Sd = env->GetMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;D)V"); // eventProperty(String, double) + mpv_MPVLib_eventProperty_SS = env->GetMethodID(mpv_MPVLib, "eventProperty", "(Ljava/lang/String;Ljava/lang/String;)V"); // eventProperty(String, String) + mpv_MPVLib_event = env->GetMethodID(mpv_MPVLib, "event", "(I)V"); // event(int) + mpv_MPVLib_logMessage_SiS = env->GetMethodID(mpv_MPVLib, "logMessage", "(Ljava/lang/String;ILjava/lang/String;)V"); // logMessage(String, int, String) #undef FIND_CLASS - methods_initialized = true; + return true; } diff --git a/libmpv/src/main/cpp/jni_utils.h b/libmpv/src/main/cpp/jni_utils.h index af0b08f..a877ad5 100644 --- a/libmpv/src/main/cpp/jni_utils.h +++ b/libmpv/src/main/cpp/jni_utils.h @@ -6,7 +6,7 @@ #define jni_func(return_type, name, ...) JNIEXPORT return_type JNICALL jni_func_name(name) (JNIEnv *env, jobject obj, ##__VA_ARGS__) bool acquire_jni_env(JavaVM *vm, JNIEnv **env); -void init_methods_cache(JNIEnv *env); +bool init_methods_cache(JNIEnv *env, jobject instance); extern jclass java_Integer, java_Double, java_Boolean; extern jmethodID java_Integer_init, java_Integer_intValue, java_Double_init, java_Double_doubleValue, java_Boolean_init, java_Boolean_booleanValue; diff --git a/libmpv/src/main/cpp/main.cpp b/libmpv/src/main/cpp/main.cpp index a61df51..e36b355 100644 --- a/libmpv/src/main/cpp/main.cpp +++ b/libmpv/src/main/cpp/main.cpp @@ -16,72 +16,76 @@ extern "C" { #include "log.h" #include "jni_utils.h" #include "event.h" +#include "globals.h" #define ARRAYLEN(a) (sizeof(a)/sizeof(a[0])) +// Update the JNI functions to accept a jlong parameter, which will be a +// pointer to the MPVInstance extern "C" { - jni_func(void, create, jobject appctx); - jni_func(void, init); - jni_func(void, destroy); - - jni_func(void, command, jobjectArray jarray); + jni_func(jlong, nativeCreate, jobject thiz, jobject appctx); + jni_func(void, nativeInit, jlong instance); + jni_func(void, nativeDestroy, jlong instance); + jni_func(void, nativeCommand, jlong instance, jobjectArray jarray); }; -JavaVM *g_vm; -mpv_handle *g_mpv; -std::atomic g_event_thread_request_exit(false); - -static pthread_t event_thread_id; - -static void prepare_environment(JNIEnv *env, jobject appctx) { +static void prepare_environment(JNIEnv *env, jobject appctx, MPVInstance* instance) { setlocale(LC_NUMERIC, "C"); - if (!env->GetJavaVM(&g_vm) && g_vm) - av_jni_set_java_vm(g_vm, nullptr); - init_methods_cache(env); + if (!env->GetJavaVM(&instance->vm) && instance->vm) + av_jni_set_java_vm(instance->vm, nullptr); + if (!instance->methods_initialized) { + instance->methods_initialized = init_methods_cache(env, instance->javaObject); + } } -jni_func(void, create, jobject appctx) { - prepare_environment(env, appctx); - - if (g_mpv) - die("mpv is already initialized"); +jni_func(jlong, nativeCreate, jobject thiz, jobject appctx) { + auto instance = new MPVInstance(); + instance->event_thread_request_exit = false; + instance->javaObject = env->NewGlobalRef(thiz); + prepare_environment(env, appctx, instance); - g_mpv = mpv_create(); - if (!g_mpv) + instance->mpv = mpv_create(); + if (!instance->mpv) { + delete instance; die("context init failed"); + } - mpv_request_log_messages(g_mpv, "v"); + mpv_request_log_messages(instance->mpv, "v"); + return reinterpret_cast(instance); } -jni_func(void, init) { - if (!g_mpv) +jni_func(void, nativeInit, jlong instance) { + auto mpv_instance = reinterpret_cast(instance); + if (!mpv_instance->mpv) die("mpv is not created"); - if (mpv_initialize(g_mpv) < 0) + if (mpv_initialize(mpv_instance->mpv) < 0) die("mpv init failed"); - g_event_thread_request_exit = false; - pthread_create(&event_thread_id, nullptr, event_thread, nullptr); + mpv_instance->event_thread_request_exit = false; + pthread_create(&mpv_instance->event_thread_id, nullptr, event_thread, mpv_instance); } -jni_func(void, destroy) { - if (!g_mpv) +jni_func(void, nativeDestroy, jlong instance) { + auto mpv_instance = reinterpret_cast(instance); + if (!mpv_instance->mpv) die("mpv destroy called but it's already destroyed"); - // poke event thread and wait for it to exit - g_event_thread_request_exit = true; - mpv_wakeup(g_mpv); - pthread_join(event_thread_id, nullptr); + mpv_instance->event_thread_request_exit = true; + mpv_wakeup(mpv_instance->mpv); + pthread_join(mpv_instance->event_thread_id, nullptr); - mpv_terminate_destroy(g_mpv); - g_mpv = nullptr; + mpv_terminate_destroy(mpv_instance->mpv); + env->DeleteGlobalRef(mpv_instance->javaObject); + delete mpv_instance; } -jni_func(void, command, jobjectArray jarray) { +jni_func(void, nativeCommand, jlong instance, jobjectArray jarray) { + auto mpv_instance = reinterpret_cast(instance); const char *arguments[128] = { 0 }; int len = env->GetArrayLength(jarray); - if (!g_mpv) + if (!mpv_instance->mpv) die("Cannot run command: mpv is not initialized"); if (len >= ARRAYLEN(arguments)) die("Cannot run command: too many arguments"); @@ -89,7 +93,7 @@ jni_func(void, command, jobjectArray jarray) { for (int i = 0; i < len; ++i) arguments[i] = env->GetStringUTFChars((jstring)env->GetObjectArrayElement(jarray, i), nullptr); - mpv_command(g_mpv, arguments); + mpv_command(mpv_instance->mpv, arguments); for (int i = 0; i < len; ++i) env->ReleaseStringUTFChars((jstring)env->GetObjectArrayElement(jarray, i), arguments[i]); diff --git a/libmpv/src/main/cpp/property.cpp b/libmpv/src/main/cpp/property.cpp index 5d52c04..201fa9b 100644 --- a/libmpv/src/main/cpp/property.cpp +++ b/libmpv/src/main/cpp/property.cpp @@ -8,28 +8,29 @@ #include "globals.h" extern "C" { - jni_func(jint, setOptionString, jstring option, jstring value); - - jni_func(jobject, getPropertyInt, jstring property); - jni_func(void, setPropertyInt, jstring property, jobject value); - jni_func(jobject, getPropertyDouble, jstring property); - jni_func(void, setPropertyDouble, jstring property, jobject value); - jni_func(jobject, getPropertyBoolean, jstring property); - jni_func(void, setPropertyBoolean, jstring property, jobject value); - jni_func(jstring, getPropertyString, jstring jproperty); - jni_func(void, setPropertyString, jstring jproperty, jstring jvalue); - - jni_func(void, observeProperty, jstring property, jint format); + jni_func(jint, nativeSetOptionString, jlong instance, jstring option, jstring value); + + jni_func(jobject, nativeGetPropertyInt, jlong instance, jstring property); + jni_func(void, nativeSetPropertyInt, jlong instance, jstring property, jobject value); + jni_func(jobject, nativeGetPropertyDouble, jlong instance, jstring property); + jni_func(void, nativeSetPropertyDouble, jlong instance, jstring property, jobject value); + jni_func(jobject, nativeGetPropertyBoolean, jlong instance, jstring property); + jni_func(void, nativeSetPropertyBoolean, jlong instance, jstring property, jobject value); + jni_func(jstring, nativeGetPropertyString, jlong instance, jstring jproperty); + jni_func(void, nativeSetPropertyString, jlong instance, jstring jproperty, jstring jvalue); + + jni_func(void, observeProperty, jlong instance, jstring property, jint format); } -jni_func(jint, setOptionString, jstring joption, jstring jvalue) { - if (!g_mpv) +jni_func(jint, nativeSetOptionString, jlong instance, jstring joption, jstring jvalue) { + auto mpv_instance = reinterpret_cast(instance); + if (!mpv_instance->mpv) die("mpv is not initialized"); const char *option = env->GetStringUTFChars(joption, nullptr); const char *value = env->GetStringUTFChars(jvalue, nullptr); - int result = mpv_set_option_string(g_mpv, option, value); + int result = mpv_set_option_string(mpv_instance->mpv, option, value); env->ReleaseStringUTFChars(joption, option); env->ReleaseStringUTFChars(jvalue, value); @@ -37,12 +38,12 @@ jni_func(jint, setOptionString, jstring joption, jstring jvalue) { return result; } -static int common_get_property(JNIEnv *env, jstring jproperty, mpv_format format, void *output) { - if (!g_mpv) +static int common_get_property(JNIEnv *env, mpv_handle* mpv, jstring jproperty, mpv_format format, void *output) { + if (!mpv) die("get_property called but mpv is not initialized"); const char *prop = env->GetStringUTFChars(jproperty, nullptr); - int result = mpv_get_property(g_mpv, prop, format, output); + int result = mpv_get_property(mpv, prop, format, output); if (result < 0) ALOGE("mpv_get_property(%s) format %d returned error %s", prop, format, mpv_error_string(result)); env->ReleaseStringUTFChars(jproperty, prop); @@ -50,12 +51,12 @@ static int common_get_property(JNIEnv *env, jstring jproperty, mpv_format format return result; } -static int common_set_property(JNIEnv *env, jstring jproperty, mpv_format format, void *value) { - if (!g_mpv) +static int common_set_property(JNIEnv *env, mpv_handle* mpv, jstring jproperty, mpv_format format, void *value) { + if (!mpv) die("set_property called but mpv is not initialized"); const char *prop = env->GetStringUTFChars(jproperty, nullptr); - int result = mpv_set_property(g_mpv, prop, format, value); + int result = mpv_set_property(mpv, prop, format, value); if (result < 0) ALOGE("mpv_set_property(%s, %p) format %d returned error %s", prop, value, format, mpv_error_string(result)); env->ReleaseStringUTFChars(jproperty, prop); @@ -63,61 +64,70 @@ static int common_set_property(JNIEnv *env, jstring jproperty, mpv_format format return result; } -jni_func(jobject, getPropertyInt, jstring jproperty) { +jni_func(jobject, nativeGetPropertyInt, jlong instance, jstring jproperty) { + auto mpv_instance = reinterpret_cast(instance); int64_t value = 0; - if (common_get_property(env, jproperty, MPV_FORMAT_INT64, &value) < 0) + if (common_get_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_INT64, &value) < 0) return nullptr; return env->NewObject(java_Integer, java_Integer_init, (jint)value); } -jni_func(jobject, getPropertyDouble, jstring jproperty) { +jni_func(jobject, nativeGetPropertyDouble, jlong instance, jstring jproperty) { + auto mpv_instance = reinterpret_cast(instance); double value = 0; - if (common_get_property(env, jproperty, MPV_FORMAT_DOUBLE, &value) < 0) + if (common_get_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_DOUBLE, &value) < 0) return nullptr; return env->NewObject(java_Double, java_Double_init, (jdouble)value); } -jni_func(jobject, getPropertyBoolean, jstring jproperty) { +jni_func(jobject, nativeGetPropertyBoolean, jlong instance, jstring jproperty) { + auto mpv_instance = reinterpret_cast(instance); int value = 0; - if (common_get_property(env, jproperty, MPV_FORMAT_FLAG, &value) < 0) + if (common_get_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_FLAG, &value) < 0) return nullptr; return env->NewObject(java_Boolean, java_Boolean_init, (jboolean)value); } -jni_func(jstring, getPropertyString, jstring jproperty) { +jni_func(jstring, nativeGetPropertyString, jlong instance, jstring jproperty) { + auto mpv_instance = reinterpret_cast(instance); char *value; - if (common_get_property(env, jproperty, MPV_FORMAT_STRING, &value) < 0) + if (common_get_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_STRING, &value) < 0) return nullptr; jstring jvalue = env->NewStringUTF(value); mpv_free(value); return jvalue; } -jni_func(void, setPropertyInt, jstring jproperty, jobject jvalue) { +jni_func(void, nativeSetPropertyInt, jlong instance, jstring jproperty, jobject jvalue) { + auto mpv_instance = reinterpret_cast(instance); int64_t value = env->CallIntMethod(jvalue, java_Integer_intValue); - common_set_property(env, jproperty, MPV_FORMAT_INT64, &value); + common_set_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_INT64, &value); } -jni_func(void, setPropertyDouble, jstring jproperty, jobject jvalue) { +jni_func(void, nativeSetPropertyDouble, jlong instance, jstring jproperty, jobject jvalue) { + auto mpv_instance = reinterpret_cast(instance); double value = env->CallDoubleMethod(jvalue, java_Double_doubleValue); - common_set_property(env, jproperty, MPV_FORMAT_DOUBLE, &value); + common_set_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_DOUBLE, &value); } -jni_func(void, setPropertyBoolean, jstring jproperty, jobject jvalue) { +jni_func(void, nativeSetPropertyBoolean, jlong instance, jstring jproperty, jobject jvalue) { + auto mpv_instance = reinterpret_cast(instance); int value = env->CallBooleanMethod(jvalue, java_Boolean_booleanValue); - common_set_property(env, jproperty, MPV_FORMAT_FLAG, &value); + common_set_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_FLAG, &value); } -jni_func(void, setPropertyString, jstring jproperty, jstring jvalue) { +jni_func(void, nativeSetPropertyString, jlong instance, jstring jproperty, jstring jvalue) { + auto mpv_instance = reinterpret_cast(instance); const char *value = env->GetStringUTFChars(jvalue, nullptr); - common_set_property(env, jproperty, MPV_FORMAT_STRING, &value); + common_set_property(env, mpv_instance->mpv, jproperty, MPV_FORMAT_STRING, &value); env->ReleaseStringUTFChars(jvalue, value); } -jni_func(void, observeProperty, jstring property, jint format) { - if (!g_mpv) +jni_func(void, nativeObserveProperty, jlong instance, jstring property, jint format) { + auto mpv_instance = reinterpret_cast(instance); + if (!mpv_instance->mpv) die("mpv is not initialized"); const char *prop = env->GetStringUTFChars(property, nullptr); - mpv_observe_property(g_mpv, 0, prop, (mpv_format)format); + mpv_observe_property(mpv_instance->mpv, 0, prop, (mpv_format)format); env->ReleaseStringUTFChars(property, prop); } diff --git a/libmpv/src/main/cpp/render.cpp b/libmpv/src/main/cpp/render.cpp index 061df84..cb7eace 100644 --- a/libmpv/src/main/cpp/render.cpp +++ b/libmpv/src/main/cpp/render.cpp @@ -6,22 +6,22 @@ #include "globals.h" extern "C" { - jni_func(void, attachSurface, jobject surface_); - jni_func(void, detachSurface); -}; - -static jobject surface; + jni_func(void, nativeAttachSurface, jlong instance, jobject surface); + jni_func(void, nativeDetachSurface, jlong instance); +} -jni_func(void, attachSurface, jobject surface_) { - surface = env->NewGlobalRef(surface_); - int64_t wid = (int64_t)(intptr_t) surface; - mpv_set_option(g_mpv, "wid", MPV_FORMAT_INT64, (void*) &wid); +jni_func(void, nativeAttachSurface, jlong instance, jobject surface) { + auto mpv_instance = reinterpret_cast(instance); + mpv_instance->surface = env->NewGlobalRef(surface); + int64_t wid = (int64_t)(intptr_t) mpv_instance->surface; + mpv_set_option(mpv_instance->mpv, "wid", MPV_FORMAT_INT64, (void*) &wid); } -jni_func(void, detachSurface) { +jni_func(void, nativeDetachSurface, jlong instance) { + auto mpv_instance = reinterpret_cast(instance); int64_t wid = 0; - mpv_set_option(g_mpv, "wid", MPV_FORMAT_INT64, (void*) &wid); + mpv_set_option(mpv_instance->mpv, "wid", MPV_FORMAT_INT64, (void*) &wid); - env->DeleteGlobalRef(surface); - surface = nullptr; + env->DeleteGlobalRef(mpv_instance->surface); + mpv_instance->surface = nullptr; } diff --git a/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java b/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java index fb91913..ed131ca 100644 --- a/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java +++ b/libmpv/src/main/java/dev/jdtech/mpv/MPVLib.java @@ -15,6 +15,9 @@ @SuppressWarnings("unused") public class MPVLib { + private long nativeInstance; + private final List observers = new ArrayList<>(); + private final List log_observers = new ArrayList<>(); static { String[] libs = {"mpv", "player"}; @@ -23,109 +26,158 @@ public class MPVLib { } } - public static native void create(Context appctx); + public MPVLib() { + nativeInstance = 0; + } - public static native void init(); + public void create(Context appctx) { + nativeInstance = nativeCreate(this, appctx); + } + private native long nativeCreate(MPVLib thiz, Context appctx); - public static native void destroy(); + public void init() { + nativeInit(nativeInstance); + } + private native void nativeInit(long instance); - public static native void attachSurface(Surface surface); + public void destroy() { + nativeDestroy(nativeInstance); + nativeInstance = 0; + } + private native void nativeDestroy(long instance); - public static native void detachSurface(); + public void attachSurface(Surface surface) { + nativeAttachSurface(nativeInstance, surface); + } + private native void nativeAttachSurface(long instance, Surface surface); - public static native void command(@NonNull String[] cmd); + public void detachSurface() { + nativeDetachSurface(nativeInstance); + } + private native void nativeDetachSurface(long instance); - public static native int setOptionString(@NonNull String name, @NonNull String value); + public void command(@NonNull String[] cmd) { + nativeCommand(nativeInstance, cmd); + } + private native void nativeCommand(long instance, @NonNull String[] cmd); - public static native Integer getPropertyInt(@NonNull String property); + public int setOptionString(@NonNull String name, @NonNull String value) { + return nativeSetOptionString(nativeInstance, name, value); + } + private native int nativeSetOptionString(long instance, @NonNull String name, @NonNull String value); - public static native void setPropertyInt(@NonNull String property, @NonNull Integer value); + public Integer getPropertyInt(@NonNull String property) { + return nativeGetPropertyInt(nativeInstance, property); + } + private native int nativeGetPropertyInt(long instance, @NonNull String property); - public static native Double getPropertyDouble(@NonNull String property); + public void setPropertyInt(@NonNull String property, @NonNull Integer value) { + nativeSetPropertyInt(nativeInstance, property, value); + } + private native int nativeSetPropertyInt(long instance, @NonNull String property, @NonNull Integer value); - public static native void setPropertyDouble(@NonNull String property, @NonNull Double value); + public Double getPropertyDouble(@NonNull String property) { + return nativeGetPropertyDouble(nativeInstance, property); + } + private native Double nativeGetPropertyDouble(long instance, @NonNull String property); - public static native Boolean getPropertyBoolean(@NonNull String property); + public void setPropertyDouble(@NonNull String property, @NonNull Double value) { + nativeSetPropertyDouble(nativeInstance, property, value); + } + private native void nativeSetPropertyDouble(long instance, @NonNull String property, @NonNull Double value); - public static native void setPropertyBoolean(@NonNull String property, @NonNull Boolean value); + public Boolean getPropertyBoolean(@NonNull String property) { + return nativeGetPropertyBoolean(nativeInstance, property); + } + private native Boolean nativeGetPropertyBoolean(long instance, @NonNull String property); - public static native String getPropertyString(@NonNull String property); + public void setPropertyBoolean(@NonNull String property, @NonNull Boolean value) { + nativeSetPropertyBoolean(nativeInstance, property, value); + } + private native void nativeSetPropertyBoolean(long instance, @NonNull String property, @NonNull Boolean value); - public static native void setPropertyString(@NonNull String property, @NonNull String value); + public String getPropertyString(@NonNull String property) { + return nativeGetPropertyString(nativeInstance, property); + } + private native String nativeGetPropertyString(long instance, @NonNull String property); - public static native void observeProperty(@NonNull String property, @Format int format); + public void setPropertyString(@NonNull String property, @NonNull String value) { + nativeSetPropertyString(nativeInstance, property, value); + } + private native void nativeSetPropertyString(long instance, @NonNull String property, @NonNull String value); - private static final List observers = new ArrayList<>(); + public void observeProperty(@NonNull String property, @Format int format) { + nativeObserveProperty(nativeInstance, property, format); + } + private native void nativeObserveProperty(long instance, @NonNull String property, @Format int format); - public static void addObserver(EventObserver o) { + public void addObserver(EventObserver o) { synchronized (observers) { observers.add(o); } } - public static void removeObserver(EventObserver o) { + public void removeObserver(EventObserver o) { synchronized (observers) { observers.remove(o); } } - public static void eventProperty(String property, long value) { + public void eventProperty(String property, long value) { synchronized (observers) { for (EventObserver o : observers) o.eventProperty(property, value); } } - public static void eventProperty(String property, double value) { + public void eventProperty(String property, double value) { synchronized (observers) { for (EventObserver o : observers) o.eventProperty(property, value); } } - public static void eventProperty(String property, boolean value) { + public void eventProperty(String property, boolean value) { synchronized (observers) { for (EventObserver o : observers) o.eventProperty(property, value); } } - public static void eventProperty(String property, String value) { + public void eventProperty(String property, String value) { synchronized (observers) { for (EventObserver o : observers) o.eventProperty(property, value); } } - public static void eventProperty(String property) { + public void eventProperty(String property) { synchronized (observers) { for (EventObserver o : observers) o.eventProperty(property); } } - public static void event(@Event int eventId) { + public void event(@Event int eventId) { synchronized (observers) { for (EventObserver o : observers) o.event(eventId); } } - private static final List log_observers = new ArrayList<>(); - - public static void addLogObserver(LogObserver o) { + public void addLogObserver(LogObserver o) { synchronized (log_observers) { log_observers.add(o); } } - public static void removeLogObserver(LogObserver o) { + public void removeLogObserver(LogObserver o) { synchronized (log_observers) { log_observers.remove(o); } } - public static void logMessage(String prefix, @LogLevel int level, String text) { + public void logMessage(String prefix, @LogLevel int level, String text) { synchronized (log_observers) { for (LogObserver o : log_observers) o.logMessage(prefix, level, text);