[vlc-devel] [PATCH 3/5] android: util: init ASurfaceTexture from Java

Louis Regnier louis.videolabs at gmail.com
Mon Apr 27 23:28:53 CEST 2020


When the native SurfaceTexture API is available, construct a SurfaceTexture
object from Java through JNI calls and store the producer side
(Surface/ANativeWindow) for the AWindowHandler clients.

The SurfaceTexture constructor is only available since API 26 but the NDK
API for ASurfaceTexture already require API 28
---
 modules/video_output/android/utils.c | 97 ++++++++++++++++++++++++++--
 1 file changed, 92 insertions(+), 5 deletions(-)

diff --git a/modules/video_output/android/utils.c b/modules/video_output/android/utils.c
index 8a300b05bb..62d5ba16b0 100644
--- a/modules/video_output/android/utils.c
+++ b/modules/video_output/android/utils.c
@@ -77,6 +77,7 @@ struct AWindowHandler
     native_window_api_t anw_api;
 
     struct ASurfaceTextureAPI ast_api;
+    bool b_has_ast_api;
 
     struct {
         awh_events_t cb;
@@ -100,6 +101,8 @@ static struct
         jmethodID setVideoLayout;
     } AndroidNativeWindow;
     struct {
+        jclass clazz;
+        jmethodID constructor;
         jmethodID attachToGLContext;
         jmethodID detachFromGLContext;
         jmethodID waitAndUpdateTexImage;
@@ -284,6 +287,30 @@ LoadNativeSurfaceAPI(AWindowHandler *p_awh)
  * Android ASurfaceTexture Android NDK
  */
 
+#define GET_CLASS(clazz, str, b_globlal) do { \
+    (clazz) = (*env)->FindClass(env, (str)); \
+    if (!(clazz)) { \
+        return -1; \
+    } \
+    if (b_globlal) { \
+        (clazz) = (jclass) (*env)->NewGlobalRef(env, (clazz)); \
+        if (!(clazz)) { \
+            return -1; \
+        } \
+    } \
+} while (0)
+
+static int JNI_getSurfaceTexture(JNIEnv *env)
+{
+    GET_CLASS(jfields.SurfaceTexture.clazz, "android/graphics/SurfaceTexture", true);
+
+    jfields.SurfaceTexture.constructor =
+        (*env)->GetMethodID(env, jfields.SurfaceTexture.clazz, "<init>", "(Z)V");
+    if (jfields.SurfaceTexture.constructor == NULL)
+        return -1;
+    return 0;
+}
+
 static int
 LoadSurfaceTextureAPI(AWindowHandler *p_awh, void *p_library)
 {
@@ -327,7 +354,7 @@ LoadSurfaceTextureAPI(AWindowHandler *p_awh, void *p_library)
  */
 
 static void
-LoadNativeWindowAPI(AWindowHandler *p_awh)
+LoadNativeWindowAPI(AWindowHandler *p_awh, JNIEnv *p_env)
 {
     void *p_library = dlopen("libandroid.so", RTLD_NOW);
     if (!p_library)
@@ -346,7 +373,9 @@ LoadNativeWindowAPI(AWindowHandler *p_awh)
      && p_awh->anw_api.winLock && p_awh->anw_api.unlockAndPost
      && p_awh->anw_api.setBuffersGeometry)
     {
-        LoadSurfaceTextureAPI(p_awh, p_library);
+        if (LoadSurfaceTextureAPI(p_awh, p_library) == VLC_SUCCESS)
+            JNI_getSurfaceTexture(p_env);
+        p_awh->b_has_ast_api = false;
         p_awh->p_anw_dl = p_library;
     }
     else
@@ -593,7 +622,7 @@ AWindowHandler_new(vout_window_t *wnd, awh_events_t *p_events)
         free(p_awh);
         return NULL;
     }
-    LoadNativeWindowAPI(p_awh);
+    LoadNativeWindowAPI(p_awh, p_env);
 
     p_awh->b_has_video_layout_listener =
         flags & AWINDOW_REGISTER_FLAGS_HAS_VIDEO_LAYOUT_LISTENER;
@@ -642,6 +671,18 @@ AWindowHandler_destroy(AWindowHandler *p_awh)
 
     if (p_env)
     {
+        if (p_awh->b_has_ast_api)
+        {
+            AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_SurfaceTexture);
+            (*p_env)->DeleteGlobalRef(p_env, p_awh->ast_api.surfacetexture);
+            if (p_awh->ast_api.p_ast != NULL)
+            {
+                p_awh->ast_api.pf_releaseAst(p_awh->ast_api.p_ast);
+                p_awh->ast_api.p_ast = NULL;
+            }
+            (*p_env)->DeleteGlobalRef(p_env, jfields.SurfaceTexture.clazz);
+        }
+
         JNI_ANWCALL(CallVoidMethod, unregisterNative);
         AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_Video);
         AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_Subtitles);
@@ -661,6 +702,46 @@ AWindowHandler_getANativeWindowAPI(AWindowHandler *p_awh)
     return &p_awh->anw_api;
 }
 
+static jobject InitSurfaceTextureNDK(AWindowHandler *p_awh, JNIEnv *p_env,
+        enum AWindow_ID id)
+{
+    jobject surfacetexture = (*p_env)->NewObject(p_env,
+            jfields.SurfaceTexture.clazz, jfields.SurfaceTexture.constructor, false);
+
+    if (surfacetexture == NULL)
+        goto error;
+
+    p_awh->ast_api.surfacetexture = (*p_env)->NewGlobalRef(p_env, surfacetexture);
+
+    p_awh->ast_api.p_ast = p_awh->ast_api.pf_astFromst(p_env,
+            p_awh->ast_api.surfacetexture);
+    if (p_awh->ast_api.p_ast == NULL)
+        goto error;
+
+    p_awh->views[id].p_anw = p_awh->ast_api.pf_acquireAnw(p_awh->ast_api.p_ast);
+    if (p_awh->views[id].p_anw == NULL)
+        goto error;
+
+    jobject jsurface = p_awh->ast_api.pf_anwToSurface(p_env, p_awh->views[id].p_anw);
+    if (jsurface == NULL)
+        goto error;
+    (*p_env)->DeleteLocalRef(p_env, surfacetexture);
+    return jsurface;
+
+error:
+    if (surfacetexture == NULL)
+        return NULL;
+    (*p_env)->DeleteLocalRef(p_env, surfacetexture);
+    p_awh->ast_api.surfacetexture = (*p_env)->NewGlobalRef(p_env, surfacetexture);
+    if (p_awh->ast_api.p_ast == NULL)
+        return NULL;
+    p_awh->ast_api.pf_releaseAst(p_awh->ast_api.p_ast);
+    if (p_awh->views[id].p_anw == NULL)
+        return NULL;
+    AWindowHandler_releaseANativeWindow(p_awh, id);
+    return NULL;
+}
+
 static int
 WindowHandler_NewSurfaceEnv(AWindowHandler *p_awh, JNIEnv *p_env,
                             enum AWindow_ID id)
@@ -676,8 +757,13 @@ WindowHandler_NewSurfaceEnv(AWindowHandler *p_awh, JNIEnv *p_env,
             jsurface = JNI_ANWCALL(CallObjectMethod, getSubtitlesSurface);
             break;
         case AWindow_SurfaceTexture:
-            jsurface = JNI_STEXCALL(CallObjectMethod, getSurface);
+        {
+            if (p_awh->b_has_ast_api)
+                jsurface = InitSurfaceTextureNDK(p_awh, p_env, id);
+            else
+                jsurface = JNI_STEXCALL(CallObjectMethod, getSurface);
             break;
+        }
         default:
             vlc_assert_unreachable();
     }
@@ -707,7 +793,8 @@ AWindowHandler_getANativeWindow(AWindowHandler *p_awh, enum AWindow_ID id)
         return NULL;
     assert(p_awh->views[id].jsurface != NULL);
 
-    p_awh->views[id].p_anw = p_awh->pf_winFromSurface(p_env,
+    if (!p_awh->b_has_ast_api || id != AWindow_SurfaceTexture)
+        p_awh->views[id].p_anw = p_awh->pf_winFromSurface(p_env,
                                                       p_awh->views[id].jsurface);
     return p_awh->views[id].p_anw;
 }
-- 
2.26.2



More information about the vlc-devel mailing list