[vlc-devel] [PATCH v2 5/7] android: utils: load SurfaceTextureListener wrapper

Alexandre Janniaux ajanni at videolabs.io
Thu Feb 11 08:34:07 UTC 2021


The SurfaceTextureListener is currently meant to be implemented outside
of libvlccore since libvlccore doesn't ship java compiled code, so it is
loaded through the ClassLoader stored from JNI_OnLoad.

The wrapper implements what's required for the SurfaceTexture's
OnFrameAvailableListener interface and redirect it to C callbacks.

It will be used to implement the proper SurfaceTexture synchronization.
---
 modules/video_output/android/utils.c | 81 ++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

diff --git a/modules/video_output/android/utils.c b/modules/video_output/android/utils.c
index 96832ad2b3..44f3c94a77 100644
--- a/modules/video_output/android/utils.c
+++ b/modules/video_output/android/utils.c
@@ -53,6 +53,10 @@ typedef int (*ptr_ASurfaceTexture_updateTexImage)(ASurfaceTexture* st);
 typedef int (*ptr_ASurfaceTexture_detachFromGLContext)(ASurfaceTexture *st);
 typedef void (*ptr_ASurfaceTexture_release)(ASurfaceTexture *st);
 
+struct vlc_asurfacetexture_listener {
+    void (*on_frame_available)(struct vlc_asurfacetexture_listener *listener);
+};
+
 /*
  * Android SurfaceTexture handle
  */
@@ -104,6 +108,7 @@ struct vlc_android_jfields
           jmethodID getTransformMatrix;
           jmethodID detachFromGLContext;
           jmethodID attachToGLContext;
+          jmethodID setOnFrameAvailableListener;
     } SurfaceTexture;
     struct {
         jclass clazz;
@@ -113,6 +118,10 @@ struct vlc_android_jfields
         jobject instance;
         jmethodID findClass;
     } ClassLoader;
+    struct {
+        jclass clazz;
+        jmethodID init;
+    } SurfaceTextureListener;
 };
 
 struct AWindowHandler
@@ -678,6 +687,37 @@ const JNINativeMethod jni_callbacks[] = {
         (void *)AndroidNativeWindow_onWindowSize },
 };
 
+static void SurfaceTextureListener_nativeNew(
+        JNIEnv *env, jobject thiz, jlong listener)
+{
+    jclass clazz = (*env)->GetObjectClass(env, thiz);
+    jfieldID mListener = (*env)->GetFieldID(env, clazz, "mListener", "J");
+    (*env)->SetLongField(env, thiz, mListener, listener);
+}
+
+static void SurfaceTextureListener_onFrameAvailable(
+        JNIEnv *env, jobject thiz, jobject surfaceTexture)
+{
+    jclass clazz = (*env)->GetObjectClass(env, thiz);
+    jclass gclazz = (*env)->NewGlobalRef(env, clazz);
+    (*env)->DeleteLocalRef(env, clazz);
+
+    jfieldID mListener = (*env)->GetFieldID(env, gclazz, "mListener", "J");
+    jlong listener_ptr = (*env)->GetLongField(env, thiz, mListener);
+
+    struct vlc_asurfacetexture_listener * listener = (void *)(intptr_t)listener_ptr;
+
+    listener->on_frame_available(listener);
+
+    (*env)->DeleteGlobalRef(env, gclazz);
+}
+
+const JNINativeMethod SurfaceTextureListener_jni_callbacks[] = {
+    { "nativeNew", "(J)V",
+        (void *)SurfaceTextureListener_nativeNew },
+    { "nativeOnFrameAvailable", "(Landroid/graphics/SurfaceTexture;)V",
+        (void *) SurfaceTextureListener_onFrameAvailable },
+};
 static int
 InitJNIFields(JNIEnv *env, vlc_object_t *p_obj, jobject *jobj, AWindowHandler *awh)
 {
@@ -766,6 +806,10 @@ InitJNIFields(JNIEnv *env, vlc_object_t *p_obj, jobject *jobj, AWindowHandler *a
     GET_METHOD(SurfaceTexture, detachFromGLContext,
                "detachFromGLContext", "()V", true);
 
+    GET_METHOD(SurfaceTexture, setOnFrameAvailableListener,
+              "setOnFrameAvailableListener",
+              "(Landroid/graphics/SurfaceTexture$OnFrameAvailableListener;Landroid/os/Handler;)V",
+              true);
 
     /* We cannot create any SurfaceTexture if we cannot load the SurfaceTexture
      * methods. */
@@ -785,6 +829,38 @@ InitJNIFields(JNIEnv *env, vlc_object_t *p_obj, jobject *jobj, AWindowHandler *a
     GET_METHOD(Surface, init_st, "<init>",
                "(Landroid/graphics/SurfaceTexture;)V", true);
 
+    /* Beware! Java ClassLoader requires a binary name, like org.example.me and
+     * not org/example/me like the JNI ClassLoader interface. */
+    const char *classname = "org.videolan.libvlc.util.SurfaceTextureListener";
+    jstring jclass_name = (*env)->NewStringUTF(env, classname);
+    CHECK_EXCEPTION("org/videolan/libvlc/util/SurfaceTextureListener string allocation", false);
+
+    clazz = (*env)->CallObjectMethod(env,
+            awh->jfields.ClassLoader.instance,
+            awh->jfields.ClassLoader.findClass,
+            jclass_name);
+    (*env)->DeleteLocalRef(env, jclass_name);
+    CHECK_EXCEPTION("org/videolan/libvlc/util/SurfaceTextureListener class", false);
+
+    if (clazz != NULL)
+    {
+        awh->jfields.SurfaceTextureListener.clazz = (*env)->NewGlobalRef(env, clazz);
+        (*env)->DeleteLocalRef(env, clazz);
+    }
+    if (awh->jfields.SurfaceTextureListener.clazz != NULL)
+    {
+        GET_METHOD(SurfaceTextureListener, init, "<init>", "(J)V", true);
+        ret = (*env)->RegisterNatives(env, awh->jfields.SurfaceTextureListener.clazz,
+                SurfaceTextureListener_jni_callbacks,
+                ARRAY_SIZE(SurfaceTextureListener_jni_callbacks));
+
+        if (ret < 0)
+        {
+            msg_Err(p_obj, "RegisterNatives for SurfaceTextureListener failed");
+            goto error;
+        }
+    }
+
 #undef GET_METHOD
 #undef CHECK_EXCEPTION
 
@@ -798,6 +874,8 @@ end:
 
 error:
     i_init_state = 0;
+    if (awh->jfields.SurfaceTextureListener.clazz)
+        (*env)->DeleteGlobalRef(env, awh->jfields.SurfaceTextureListener.clazz);
     if (awh->jfields.SurfaceTexture.clazz)
         (*env)->DeleteGlobalRef(env, awh->jfields.SurfaceTexture.clazz);
     awh->jfields.SurfaceTexture.clazz = NULL;
@@ -955,6 +1033,9 @@ AWindowHandler_destroy(AWindowHandler *p_awh)
 
     if (p_env)
     {
+        if (p_awh->jfields.SurfaceTextureListener.clazz)
+            (*p_env)->DeleteGlobalRef(p_env, p_awh->jfields.SurfaceTextureListener.clazz);
+
         if (p_awh->jfields.SurfaceTexture.clazz)
             (*p_env)->DeleteGlobalRef(p_env, p_awh->jfields.SurfaceTexture.clazz);
 
-- 
2.30.1



More information about the vlc-devel mailing list