[vlc-devel] [PATCH v2 7/7] android: utils: synchronize on updateTexImage

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


Create SurfaceTextureListener for new SurfaceTexture to synchronize
them in the opengl interop. It synchronizes the rendering of the picture
from MediaCodec with the call to UpdateTexImage(). This is not used for
Android devices with API < 21 for now.

Since the wait is blocking and decoder can kill the producer side, the
wait is taking into account the interruption state and will gracefully
fail if it has been interrupted because we'd need to kill the display.

Fixes #25361.
---
 modules/video_output/android/utils.c | 68 ++++++++++++++++++++++++++++
 1 file changed, 68 insertions(+)

diff --git a/modules/video_output/android/utils.c b/modules/video_output/android/utils.c
index c2e678bdb9..4aab3a8f76 100644
--- a/modules/video_output/android/utils.c
+++ b/modules/video_output/android/utils.c
@@ -35,6 +35,8 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 
+#include <vlc_interrupt.h>
+
 typedef ANativeWindow* (*ptr_ANativeWindow_fromSurface)(JNIEnv*, jobject);
 typedef ANativeWindow* (*ptr_ANativeWindow_fromSurfaceTexture)(JNIEnv*, jobject);
 typedef void (*ptr_ANativeWindow_release)(ANativeWindow*);
@@ -69,6 +71,11 @@ struct vlc_asurfacetexture_priv {
 
     /* Android API are loaded into an AWindowHandler instance. */
     struct AWindowHandler *awh;
+
+    /* Semaphore resyncing updateTexImage on OnFrameAvailableListener. */
+    vlc_sem_t sem_frame;
+    jobject jlistener;
+    struct vlc_asurfacetexture_listener listener;
 };
 
 struct ASurfaceTextureAPI
@@ -463,6 +470,16 @@ NDKSurfaceTexture_updateTexImage(
     struct vlc_asurfacetexture_priv *handle =
         container_of(surface, struct vlc_asurfacetexture_priv, surface);
 
+    if (vlc_killed())
+        return VLC_EGENERIC;
+
+    /* Sync SurfaceTexture. */
+    if (handle->listener.on_frame_available && handle->jlistener)
+    {
+        if (vlc_sem_wait_i11e(&handle->sem_frame) == EINTR)
+            return VLC_EGENERIC;
+    }
+
     /* ASurfaceTexture_updateTexImage can fail, for example if calling it
      * before having produced a new image. */
     if (handle->awh->ndk_ast_api.pf_updateTexImage(handle->texture))
@@ -493,6 +510,9 @@ static void NDKSurfaceTexture_destroy(
     handle->awh->ndk_ast_api.pf_releaseAst(handle->texture);
     (*p_env)->DeleteGlobalRef(p_env, handle->jtexture);
 
+    if (handle->jlistener)
+        (*p_env)->DeleteGlobalRef(p_env, handle->jlistener);
+
     free(handle);
 }
 
@@ -559,6 +579,16 @@ JNISurfaceTexture_updateTexImage(
     struct vlc_asurfacetexture_priv *handle =
         container_of(surface, struct vlc_asurfacetexture_priv, surface);
 
+    if (vlc_killed())
+        return VLC_EGENERIC;
+
+    /* Sync SurfaceTexture. */
+    if (handle->listener.on_frame_available && handle->jlistener)
+    {
+        if (vlc_sem_wait_i11e(&handle->sem_frame) == EINTR)
+            return VLC_EGENERIC;
+    }
+
     AWindowHandler *p_awh = handle->awh;
     JNIEnv *p_env = android_getEnvCommon(NULL, p_awh->p_jvm, "SurfaceTexture");
     if (!p_env)
@@ -612,6 +642,9 @@ static void JNISurfaceTexture_destroy(
     if (handle->surface.jsurface)
         (*p_env)->DeleteGlobalRef(p_env, handle->surface.jsurface);
 
+    if (handle->jlistener)
+        (*p_env)->DeleteGlobalRef(p_env, handle->jlistener);
+
     free(handle);
 }
 
@@ -1412,6 +1445,14 @@ error:
     return NULL;
 }
 
+static void OnFrameAvailable(struct vlc_asurfacetexture_listener *listener)
+{
+    struct vlc_asurfacetexture_priv *priv =
+        container_of(listener, struct vlc_asurfacetexture_priv, listener);
+
+    vlc_sem_post(&priv->sem_frame);
+}
+
 struct vlc_asurfacetexture *
 vlc_asurfacetexture_New(AWindowHandler *p_awh, bool single_buffer)
 {
@@ -1420,6 +1461,33 @@ vlc_asurfacetexture_New(AWindowHandler *p_awh, bool single_buffer)
         CreateSurfaceTexture(p_awh, p_env, single_buffer);
     if (surfacetexture == NULL)
         return NULL;
+
+    surfacetexture->listener.on_frame_available = NULL;
+    surfacetexture->jlistener = NULL;
+    vlc_sem_init(&surfacetexture->sem_frame, 0);
+
+#ifdef __ANDROID_API__ < 21
+    if (android_get_device_api_level() < 21)
+        goto end;
+#endif
+    if (p_awh->jfields.SurfaceTextureListener.clazz && !single_buffer)
+    {
+        surfacetexture->listener.on_frame_available = OnFrameAvailable;
+
+        jobject listener = (*p_env)->NewObject(p_env, p_awh->jfields.SurfaceTextureListener.clazz,
+                                               p_awh->jfields.SurfaceTextureListener.init,
+                                               (jlong)(intptr_t)&surfacetexture->listener);
+        surfacetexture->jlistener = (*p_env)->NewGlobalRef(p_env, listener);
+        (*p_env)->DeleteLocalRef(p_env, listener);
+
+        assert(surfacetexture->jlistener != NULL && surfacetexture->jtexture != NULL);
+
+        (*p_env)->CallVoidMethod(p_env, surfacetexture->jtexture,
+                                 p_awh->jfields.SurfaceTexture.setOnFrameAvailableListener,
+                                 surfacetexture->jlistener, p_awh->handler.handler);
+    }
+
+end:
     return &surfacetexture->surface;
 }
 
-- 
2.30.1



More information about the vlc-devel mailing list