[vlc-commits] android: vout: re-use the same SurfaceTexture

Thomas Guillem git at videolan.org
Fri Apr 21 16:32:57 CEST 2017


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Thu Apr 20 18:47:40 2017 +0200| [c547de6f215a6b98041f44d193ae3f2e432bb94c] | committer: Thomas Guillem

android: vout: re-use the same SurfaceTexture

Call attachToGLContext/detachFromGLContext on a same SurfaceTexture instance.
That way, we don't have to re-configure MediaCodec in order to setup the new
Surface when the video size change mid-stream (and when a new OpenGL vout is
created).

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c547de6f215a6b98041f44d193ae3f2e432bb94c
---

 modules/video_output/android/utils.c            | 217 ++++++++----------------
 modules/video_output/android/utils.h            |  36 ++--
 modules/video_output/opengl/converter_android.c |  26 +--
 3 files changed, 106 insertions(+), 173 deletions(-)

diff --git a/modules/video_output/android/utils.c b/modules/video_output/android/utils.c
index db462e0c16..d944e499ba 100644
--- a/modules/video_output/android/utils.c
+++ b/modules/video_output/android/utils.c
@@ -51,6 +51,11 @@ struct AWindowHandler
         awh_events_t cb;
     } event;
     bool b_has_video_layout_listener;
+
+    struct {
+        jfloatArray jtransform_mtx_array;
+        jfloat *jtransform_mtx;
+    } stex;
 };
 
 struct SurfaceTexture
@@ -65,8 +70,6 @@ struct SurfaceTexture
     jobject jsurface;
     ANativeWindow *p_anw;
 
-    jfloatArray jtransform_mtx_array;
-    jfloat *jtransform_mtx;
 };
 
 static struct
@@ -81,11 +84,11 @@ static struct
         jmethodID setVideoLayout;
     } AndroidNativeWindow;
     struct {
-        jmethodID create;
-        jmethodID release;
+        jmethodID attachToGLContext;
+        jmethodID detachFromGLContext;
         jmethodID waitAndUpdateTexImage;
         jmethodID getSurface;
-    } SurfaceTextureThread;
+    } SurfaceTexture;
 } jfields;
 
 /*
@@ -441,10 +444,6 @@ InitJNIFields(JNIEnv *env, vlc_object_t *p_obj, jobject *jobj)
     jfields.id = (*env)->GetMethodID(env, clazz, (str), (args)); \
     CHECK_EXCEPTION("GetMethodID("str")", critical); \
 } while( 0 )
-#define GET_SMETHOD(id, str, args, critical) do { \
-    jfields.id = (*env)->GetStaticMethodID(env, clazz, (str), (args)); \
-    CHECK_EXCEPTION("GetMethodID("str")", critical); \
-} while( 0 )
 
     clazz = (*env)->GetObjectClass(env, jobj);
     CHECK_EXCEPTION("AndroidNativeWindow clazz", true);
@@ -461,21 +460,15 @@ InitJNIFields(JNIEnv *env, vlc_object_t *p_obj, jobject *jobj)
     GET_METHOD(AndroidNativeWindow.setVideoLayout,
                "setVideoLayout", "(IIIIII)V", true);
 
-    GET_SMETHOD(SurfaceTextureThread.create,
-                "SurfaceTextureThread_create",
-                "(I)Lorg/videolan/libvlc/AWindow$SurfaceTextureThread;", true);
-    GET_SMETHOD(SurfaceTextureThread.release,
-                "SurfaceTextureThread_release",
-                "(Lorg/videolan/libvlc/AWindow$SurfaceTextureThread;)V",
-                true);
-    GET_SMETHOD(SurfaceTextureThread.waitAndUpdateTexImage,
-                "SurfaceTextureThread_waitAndUpdateTexImage",
-                "(Lorg/videolan/libvlc/AWindow$SurfaceTextureThread;[F)Z",
-                true);
-    GET_SMETHOD(SurfaceTextureThread.getSurface,
-                "SurfaceTextureThread_getSurface",
-                "(Lorg/videolan/libvlc/AWindow$SurfaceTextureThread;)"
-                "Landroid/view/Surface;", true);
+    GET_METHOD(SurfaceTexture.attachToGLContext,
+               "SurfaceTexture_attachToGLContext", "(I)Z", true);
+    GET_METHOD(SurfaceTexture.detachFromGLContext,
+               "SurfaceTexture_detachFromGLContext", "()V", true);
+    GET_METHOD(SurfaceTexture.waitAndUpdateTexImage,
+               "SurfaceTexture_waitAndUpdateTexImage", "([F)Z",
+               true);
+    GET_METHOD(SurfaceTexture.getSurface,
+               "SurfaceTexture_getSurface", "()Landroid/view/Surface;", true);
 
     if ((*env)->RegisterNatives(env, clazz, jni_callbacks, 2) < 0)
     {
@@ -503,7 +496,7 @@ end:
 #define JNI_ANWCALL(what, method, ...) \
     (*p_env)->what(p_env, p_awh->jobj, jfields.AndroidNativeWindow.method, ##__VA_ARGS__)
 #define JNI_STEXCALL(what, method, ...) \
-    (*p_env)->what(p_env, jfields.AndroidNativeWindow.clazz, jfields.SurfaceTextureThread.method, ##__VA_ARGS__)
+    (*p_env)->what(p_env, p_awh->jobj, jfields.SurfaceTexture.method, ##__VA_ARGS__)
 
 static JNIEnv*
 AWindowHandler_getEnv(AWindowHandler *p_awh)
@@ -552,12 +545,24 @@ AWindowHandler_new(vout_window_t *wnd, awh_events_t *p_events)
     p_awh->wnd = wnd;
     p_awh->event.cb = *p_events;
 
+    jfloatArray jarray = (*p_env)->NewFloatArray(p_env, 16);
+    if ((*p_env)->ExceptionCheck(p_env))
+    {
+        (*p_env)->ExceptionClear(p_env);
+        free(p_awh);
+        return NULL;
+    }
+    p_awh->stex.jtransform_mtx_array = (*p_env)->NewGlobalRef(p_env, jarray);
+    (*p_env)->DeleteLocalRef(p_env, jarray);
+    p_awh->stex.jtransform_mtx = NULL;
+
     const jint flags = JNI_ANWCALL(CallIntMethod, registerNative,
                                    (jlong)(intptr_t)p_awh);
     if ((flags & AWINDOW_REGISTER_FLAGS_SUCCESS) == 0)
     {
         msg_Err(wnd, "AWindow already registered");
         (*p_env)->DeleteGlobalRef(p_env, p_awh->jobj);
+        (*p_env)->DeleteGlobalRef(p_env, p_awh->stex.jtransform_mtx_array);
         free(p_awh);
         return NULL;
     }
@@ -604,6 +609,7 @@ AWindowHandler_destroy(AWindowHandler *p_awh)
     if (p_awh->p_anw_dl)
         dlclose(p_awh->p_anw_dl);
 
+    (*p_env)->DeleteGlobalRef(p_env, p_awh->stex.jtransform_mtx_array);
     free(p_awh);
 }
 
@@ -619,10 +625,18 @@ WindowHandler_NewSurfaceEnv(AWindowHandler *p_awh, JNIEnv *p_env,
 {
     jobject jsurface;
 
-    if (id == AWindow_Video)
-        jsurface = JNI_ANWCALL(CallObjectMethod, getVideoSurface);
-    else
-        jsurface = JNI_ANWCALL(CallObjectMethod, getSubtitlesSurface);
+    switch (id)
+    {
+        case AWindow_Video:
+            jsurface = JNI_ANWCALL(CallObjectMethod, getVideoSurface);
+            break;
+        case AWindow_Subtitles:
+            jsurface = JNI_ANWCALL(CallObjectMethod, getSubtitlesSurface);
+            break;
+        case AWindow_SurfaceTexture:
+            jsurface = JNI_STEXCALL(CallObjectMethod, getSurface);
+            break;
+    }
     if (!jsurface)
         return VLC_EGENERIC;
 
@@ -742,155 +756,62 @@ AWindowHandler_setVideoLayout(AWindowHandler *p_awh,
     return VLC_SUCCESS;
 }
 
-SurfaceTexture *
-SurfaceTexture_create(vlc_object_t *p_obj, int i_tex_name)
+int
+SurfaceTexture_attachToGLContext(AWindowHandler *p_awh, int tex_name)
 {
-    if (jfields.SurfaceTextureThread.create == NULL)
-        return NULL;
-
-    JavaVM *p_jvm = var_InheritAddress(p_obj, "android-jvm");
-    if (p_jvm == NULL)
-        return NULL;
-
-    JNIEnv *p_env = android_getEnvCommon(NULL, p_jvm, "SurfaceTexture");
+    JNIEnv *p_env = android_getEnvCommon(NULL, p_awh->p_jvm, "SurfaceTexture");
     if (!p_env)
-        return NULL;
-
-    SurfaceTexture *p_stex = malloc(sizeof(SurfaceTexture));
-    if (p_stex == NULL)
-        return NULL;
-
-    void *p_library = dlopen("libandroid.so", RTLD_NOW);
-    if (!p_library)
-        goto error;
-
-    p_stex->pf_winFromSurface = dlsym(p_library, "ANativeWindow_fromSurface");
-    p_stex->pf_winRelease = dlsym(p_library, "ANativeWindow_release");
-    if (p_stex->pf_winFromSurface == NULL || p_stex->pf_winRelease == NULL)
-        goto error;
-    p_stex->p_anw_dl = p_library;
-    p_stex->p_jvm = p_jvm;
-    p_stex->p_anw = NULL;
-    p_stex->jsurface = NULL;
-
-    jfloatArray jarray = (*p_env)->NewFloatArray(p_env, 16);
-    if ((*p_env)->ExceptionCheck(p_env))
-    {
-        (*p_env)->ExceptionClear(p_env);
-        goto error;
-    }
-    p_stex->jtransform_mtx_array = (*p_env)->NewGlobalRef(p_env, jarray);
-    (*p_env)->DeleteLocalRef(p_env, jarray);
-    p_stex->jtransform_mtx = NULL;
-
-    jobject thiz = JNI_STEXCALL(CallStaticObjectMethod, create, i_tex_name);
-    if ((*p_env)->ExceptionCheck(p_env))
-    {
-        (*p_env)->ExceptionClear(p_env);
-        (*p_env)->DeleteGlobalRef(p_env, p_stex->jtransform_mtx_array);
-        goto error;
-    }
-    p_stex->thiz = (*p_env)->NewGlobalRef(p_env, thiz);
-    (*p_env)->DeleteLocalRef(p_env, thiz);
-
-    return p_stex;
+        return VLC_EGENERIC;
 
-error:
-    free(p_stex);
-    if (p_library != NULL)
-        dlclose(p_library);
-    return NULL;
+    return JNI_STEXCALL(CallBooleanMethod, attachToGLContext, tex_name) ?
+           VLC_SUCCESS : VLC_EGENERIC;
 }
 
 void
-SurfaceTexture_release(SurfaceTexture *p_stex)
+SurfaceTexture_detachFromGLContext(AWindowHandler *p_awh)
 {
-    JNIEnv *p_env = android_getEnvCommon(NULL, p_stex->p_jvm, "SurfaceTexture");
+    JNIEnv *p_env = android_getEnvCommon(NULL, p_awh->p_jvm, "SurfaceTexture");
     if (!p_env)
         return;
 
-    if (p_stex->p_anw != NULL)
-        p_stex->pf_winRelease(p_stex->p_anw);
-
-    if (p_stex->jsurface != NULL)
-        (*p_env)->DeleteGlobalRef(p_env, p_stex->jsurface);
-
-    JNI_STEXCALL(CallStaticVoidMethod, release, p_stex->thiz);
-    (*p_env)->DeleteGlobalRef(p_env, p_stex->thiz);
-
-    if (p_stex->jtransform_mtx != NULL)
-        (*p_env)->ReleaseFloatArrayElements(p_env, p_stex->jtransform_mtx_array,
-                                            p_stex->jtransform_mtx,
-                                            JNI_ABORT);
-    (*p_env)->DeleteGlobalRef(p_env, p_stex->jtransform_mtx_array);
-
-    dlclose(p_stex->p_anw_dl);
-    free(p_stex);
-}
-
-jobject
-SurfaceTexture_getSurface(SurfaceTexture *p_stex)
-{
-    JNIEnv *p_env = android_getEnvCommon(NULL, p_stex->p_jvm, "SurfaceTexture");
-    if (!p_env)
-        return NULL;
-
-    if (p_stex->jsurface == NULL)
-    {
-        jobject jsurface =
-            JNI_STEXCALL(CallStaticObjectMethod, getSurface, p_stex->thiz);
-        if ((*p_env)->ExceptionCheck(p_env))
-        {
-            (*p_env)->ExceptionClear(p_env);
-            return NULL;
-        }
-        p_stex->jsurface = (*p_env)->NewGlobalRef(p_env, jsurface);
-        (*p_env)->DeleteLocalRef(p_env, jsurface);
-    }
-    return p_stex->jsurface;
-}
+    JNI_STEXCALL(CallVoidMethod, detachFromGLContext);
 
-ANativeWindow *
-SurfaceTexture_getANativeWindow(SurfaceTexture *p_stex)
-{
-    JNIEnv *p_env = android_getEnvCommon(NULL, p_stex->p_jvm, "SurfaceTexture");
-    if (!p_env)
-        return NULL;
+    AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_SurfaceTexture);
 
-    if (p_stex->p_anw == NULL)
+    if (p_awh->stex.jtransform_mtx != NULL)
     {
-        jobject jsurface = SurfaceTexture_getSurface(p_stex);
-        if (jsurface != NULL)
-            p_stex->p_anw = p_stex->pf_winFromSurface(p_env, jsurface);
+        (*p_env)->ReleaseFloatArrayElements(p_env, p_awh->stex.jtransform_mtx_array,
+                                            p_awh->stex.jtransform_mtx,
+                                            JNI_ABORT);
+        p_awh->stex.jtransform_mtx = NULL;
     }
-    return p_stex->p_anw;
 }
 
 int
-SurfaceTexture_waitAndUpdateTexImage(SurfaceTexture *p_stex,
+SurfaceTexture_waitAndUpdateTexImage(AWindowHandler *p_awh,
                                      const float **pp_transform_mtx)
 {
-    JNIEnv *p_env = android_getEnvCommon(NULL, p_stex->p_jvm, "SurfaceTexture");
+    JNIEnv *p_env = android_getEnvCommon(NULL, p_awh->p_jvm, "SurfaceTexture");
     if (!p_env)
         return VLC_EGENERIC;
 
-    if (p_stex->jtransform_mtx != NULL)
-        (*p_env)->ReleaseFloatArrayElements(p_env, p_stex->jtransform_mtx_array,
-                                            p_stex->jtransform_mtx,
+    if (p_awh->stex.jtransform_mtx != NULL)
+        (*p_env)->ReleaseFloatArrayElements(p_env, p_awh->stex.jtransform_mtx_array,
+                                            p_awh->stex.jtransform_mtx,
                                             JNI_ABORT);
 
-    bool ret = JNI_STEXCALL(CallStaticBooleanMethod, waitAndUpdateTexImage,
-                            p_stex->thiz, p_stex->jtransform_mtx_array);
+    bool ret = JNI_STEXCALL(CallBooleanMethod, waitAndUpdateTexImage,
+                            p_awh->stex.jtransform_mtx_array);
     if (ret)
     {
-        p_stex->jtransform_mtx = (*p_env)->GetFloatArrayElements(p_env,
-                                            p_stex->jtransform_mtx_array, NULL);
-        *pp_transform_mtx = p_stex->jtransform_mtx;
+        p_awh->stex.jtransform_mtx = (*p_env)->GetFloatArrayElements(p_env,
+                                            p_awh->stex.jtransform_mtx_array, NULL);
+        *pp_transform_mtx = p_awh->stex.jtransform_mtx;
         return VLC_SUCCESS;
     }
     else
     {
-        p_stex->jtransform_mtx = NULL;
+        p_awh->stex.jtransform_mtx = NULL;
         return VLC_EGENERIC;
     }
 }
diff --git a/modules/video_output/android/utils.h b/modules/video_output/android/utils.h
index 704755da44..87b0d9cc67 100644
--- a/modules/video_output/android/utils.h
+++ b/modules/video_output/android/utils.h
@@ -34,11 +34,11 @@
 #include <vlc_common.h>
 
 typedef struct AWindowHandler AWindowHandler;
-typedef struct SurfaceTexture SurfaceTexture;
 
 enum AWindow_ID {
     AWindow_Video,
     AWindow_Subtitles,
+    AWindow_SurfaceTexture,
     AWindow_Max,
 };
 
@@ -177,35 +177,43 @@ int AWindowHandler_setVideoLayout(AWindowHandler *p_awh,
                                   int i_sar_num, int i_sar_den);
 
 /**
- * Construct a new Java SurfaceTexture to stream images to a given OpenGL
- * texture
+ * Attach a SurfaceTexture to the OpenGL ES context that is current on the
+ * calling thread.
  *
  * See SurfaceTexture Android documentation.
+ * \return 0 on success, -1 on error.
  */
-SurfaceTexture *
-SurfaceTexture_create(vlc_object_t *p_obj, int tex_name);
+int
+SurfaceTexture_attachToGLContext(AWindowHandler *p_awh, int tex_name);
 
 /**
- * Release a SurfaceTexture
+ * Detach a SurfaceTexture from the OpenGL ES context that owns the OpenGL ES
+ * texture object.
  */
 void
-SurfaceTexture_release(SurfaceTexture *p_stex);
+SurfaceTexture_detachFromGLContext(AWindowHandler *p_awh);
 
 /**
- * Get a Java Surface from the SurfaceTexture
+ * Get a Java Surface from the attached SurfaceTexture
  *
  * This object can be used with mediacodec_jni.
  */
-jobject
-SurfaceTexture_getSurface(SurfaceTexture *p_stex);
+static inline jobject
+SurfaceTexture_getSurface(AWindowHandler *p_awh)
+{
+    return AWindowHandler_getSurface(p_awh, AWindow_SurfaceTexture);
+}
 
 /**
- * Get a ANativeWindow from the SurfaceTexture
+ * Get a ANativeWindow from the attached SurfaceTexture
  *
  * This pointer can be used with mediacodec_ndk.
  */
-ANativeWindow *
-SurfaceTexture_getANativeWindow(SurfaceTexture *p_stex);
+static inline ANativeWindow *
+SurfaceTexture_getANativeWindow(AWindowHandler *p_awh)
+{
+    return AWindowHandler_getANativeWindow(p_awh, AWindow_SurfaceTexture);
+}
 
 /**
  * Wait for a new frame and update it
@@ -221,5 +229,5 @@ SurfaceTexture_getANativeWindow(SurfaceTexture *p_stex);
  * \return VLC_SUCCESS or a VLC error
  */
 int
-SurfaceTexture_waitAndUpdateTexImage(SurfaceTexture *p_stex,
+SurfaceTexture_waitAndUpdateTexImage(AWindowHandler *p_awh,
                                      const float **pp_transform_mtx);
diff --git a/modules/video_output/opengl/converter_android.c b/modules/video_output/opengl/converter_android.c
index db55cf03ef..3e0f03c0da 100644
--- a/modules/video_output/opengl/converter_android.c
+++ b/modules/video_output/opengl/converter_android.c
@@ -33,8 +33,9 @@
 
 struct priv
 {
-    SurfaceTexture *stex;
+    AWindowHandler *awh;
     const float *transform_mtx;
+    bool stex_attached;
 
     struct {
         GLint uSTMatrix;
@@ -68,12 +69,12 @@ tc_anop_allocate_textures(const opengl_tex_converter_t *tc, GLuint *textures,
     (void) tex_width; (void) tex_height;
     struct priv *priv = tc->priv;
     assert(textures[0] != 0);
-    priv->stex = SurfaceTexture_create(VLC_OBJECT(tc->gl), textures[0]);
-    if (priv->stex == NULL)
+    if (SurfaceTexture_attachToGLContext(priv->awh, textures[0]) != 0)
     {
-        msg_Err(tc->gl, "tc_anop_get_pool: SurfaceTexture_create failed");
+        msg_Err(tc->gl, "SurfaceTexture_attachToGLContext failed");
         return VLC_EGENERIC;
     }
+    priv->stex_attached = true;
     return VLC_SUCCESS;
 }
 
@@ -98,8 +99,8 @@ tc_anop_get_pool(const opengl_tex_converter_t *tc, const video_format_t *fmt,
         };
 
         p_picsys->hw.b_vd_ref = true;
-        p_picsys->hw.p_surface = SurfaceTexture_getANativeWindow(priv->stex);
-        p_picsys->hw.p_jsurface = SurfaceTexture_getSurface(priv->stex);
+        p_picsys->hw.p_surface = SurfaceTexture_getANativeWindow(priv->awh);
+        p_picsys->hw.p_jsurface = SurfaceTexture_getSurface(priv->awh);
         p_picsys->hw.i_index = -1;
         vlc_mutex_init(&p_picsys->hw.lock);
 
@@ -147,7 +148,7 @@ tc_anop_update(const opengl_tex_converter_t *tc, GLuint *textures,
 
     AndroidOpaquePicture_Release(pic->p_sys, true);
 
-    if (SurfaceTexture_waitAndUpdateTexImage(priv->stex, &priv->transform_mtx)
+    if (SurfaceTexture_waitAndUpdateTexImage(priv->awh, &priv->transform_mtx)
         != VLC_SUCCESS)
     {
         priv->transform_mtx = NULL;
@@ -184,8 +185,9 @@ static void
 tc_anop_release(const opengl_tex_converter_t *tc)
 {
     struct priv *priv = tc->priv;
-    if (priv->stex != NULL)
-        SurfaceTexture_release(priv->stex);
+
+    if (priv->stex_attached)
+        SurfaceTexture_detachFromGLContext(priv->awh);
 
     free(priv);
 }
@@ -194,7 +196,8 @@ GLuint
 opengl_tex_converter_anop_init(const video_format_t *fmt,
                                opengl_tex_converter_t *tc)
 {
-    if (fmt->i_chroma != VLC_CODEC_ANDROID_OPAQUE)
+    if (fmt->i_chroma != VLC_CODEC_ANDROID_OPAQUE
+     || !tc->gl->surface->handle.anativewindow)
         return 0;
 
     tc->priv = malloc(sizeof(struct priv));
@@ -202,8 +205,9 @@ opengl_tex_converter_anop_init(const video_format_t *fmt,
         return 0;
 
     struct priv *priv = tc->priv;
-    priv->stex = NULL;
+    priv->awh = tc->gl->surface->handle.anativewindow;
     priv->transform_mtx = NULL;
+    priv->stex_attached = false;
 
     tc->pf_allocate_textures = tc_anop_allocate_textures;
     tc->pf_get_pool       = tc_anop_get_pool;



More information about the vlc-commits mailing list