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

Thomas Guillem thomas at gllm.fr
Tue Apr 28 12:57:09 CEST 2020



On Mon, Apr 27, 2020, at 23:28, Louis Regnier wrote:
> 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;

This variable name is confusing. It seem to be used to identify if the NDK API is present. Why not adding ndk in the var name ?
Also, when is this variable set to true ?

>  
>      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;

This is misleading but it is my fault.
The methods from the SurfaceTexture struct are methods of the AWindow class.
The methods from the AndroidNativeWindow struct are methods of the AWindow class.
Therefore, both struct should be first merged and name AWindow.

Then you could add clazz and constructor on the SurfaceTexture struct that will be methods/class of the SurfaceTexture class.

> @@ -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)); \

You leak a local ref, you should call (*env)->DeleteLocalRef(env, clazz); after getting the global ref (and use an other class var).


> +        if (!(clazz)) { \
> +            return -1; \
> +        } \
> +    } \
> +} while (0)

THis macro is used only one time, and could be removed.

> +
> +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;

I think you could put direcly the content of this function in LoadSurfaceTextureAPI().

> +}
> +
>  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);

You leak a local ref, you should call (*env)->DeleteLocalRef(env, surfacetexture); after getting the global ref.

> +
> +    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
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list