[vlc-commits] [Git][videolan/vlc][master] 13 commits: vout: android: bypass canSetVideoLayout() if forced

Steve Lhomme (@robUx4) gitlab at videolan.org
Fri Mar 21 14:52:28 UTC 2025



Steve Lhomme pushed to branch master at VideoLAN / VLC


Commits:
a2acd45c by Thomas Guillem at 2025-03-21T14:21:27+00:00
vout: android: bypass canSetVideoLayout() if forced

- - - - -
c881d9e5 by Thomas Guillem at 2025-03-21T14:21:27+00:00
filter: egl_surfacetexture: add missing NULL check

- - - - -
f2294466 by Thomas Guillem at 2025-03-21T14:21:27+00:00
filter: egl_surfacetexture: fix leak on error

- - - - -
afa50f98 by Thomas Guillem at 2025-03-21T14:21:27+00:00
vout: android: utils: make jvm optional

jvm might be set to NULL in the next commit.

- - - - -
59414c6c by Thomas Guillem at 2025-03-21T14:21:27+00:00
vout: android: utils: rework capabilities

- - - - -
4982e2ea by Thomas Guillem at 2025-03-21T14:21:27+00:00
vout: android: utils: add SURFACE_VIEW capability

- - - - -
b67f72ee by Thomas Guillem at 2025-03-21T14:21:27+00:00
mediacodec: check AWH_CAPS_SURFACE_VIEW

Don't use a SurfaceTexture if not possible.

This will be used to force MediaCodec in direct rendering when a vout
callback is used (the capability will be off in that case).

- - - - -
75a2783a by Thomas Guillem at 2025-03-21T14:21:27+00:00
vout: android: utils: add AWindowHandler_newFromANWs()

This will be used for ANativeWindow support in
libvlc_video_set_output_callbacks().

- - - - -
a036c337 by Thomas Guillem at 2025-03-21T14:21:27+00:00
vout: android: window: add callback submodule

This will be used for libvlc_video_set_output_callbacks().

- - - - -
679210de by Thomas Guillem at 2025-03-21T14:21:27+00:00
libvlc: add libvlc_video_engine_anw

The ANativeWindow can com from a Java SurfaceView or a NDK
AImageReader. This allow to use libvlc on android without any Java/JNI
support.

- - - - -
17626834 by Thomas Guillem at 2025-03-21T14:21:27+00:00
libvlc: add libvlc_video_set_anw_callbacks helper

- - - - -
75bbeae1 by Thomas Guillem at 2025-03-21T14:21:27+00:00
egl: android: early return in case of error

- - - - -
61cbeec9 by Thomas Guillem at 2025-03-21T14:21:27+00:00
egl: android: call setBuffersGeometry() when needed

This allows to use libvlc_video_engine_anw callbacks with SW decoding.
We don't need to setBuffersGeometry() when using MediaCodec.

- - - - -


9 changed files:

- include/vlc/libvlc_media_player.h
- lib/media_player.c
- modules/codec/omxil/mediacodec.c
- modules/video_filter/egl_surfacetexture.c
- modules/video_output/android/display.c
- modules/video_output/android/utils.c
- modules/video_output/android/utils.h
- modules/video_output/android/window.c
- modules/video_output/opengl/egl.c


Changes:

=====================================
include/vlc/libvlc_media_player.h
=====================================
@@ -626,6 +626,14 @@ typedef struct libvlc_video_output_cfg_t
         int opengl_format;
         /** currently unused */
         void *p_surface;
+        struct {
+            /** Pointer to an ANativeWindow, used for video rendering */
+            void *video;
+            /** Pointer to an ANativeWindow, used for subtitles rendering, if
+             * blending subtitles into the video surface is not possible (when
+             * using MediaCodec with direct hw rendering) */
+            void *subtitle;
+        } anw;
     };
     /** Video is full range or studio/limited range. */
     bool full_range;
@@ -652,9 +660,9 @@ typedef struct libvlc_video_output_cfg_t
  *       uses to render. The host must set a Render target and call Present()
  *       when it needs the drawing from VLC to be done. This object is not valid
  *       anymore after Cleanup is called.
- *
- * Tone mapping, range and color conversion will be done depending on the values
- * set in the output structure.
+ * Tone mapping, range and color conversion will be done depending on the
+ * values set in the output structure. It can be ignored in the \ref
+ * libvlc_video_engine_anw case.
  */
 typedef bool (*libvlc_video_update_output_cb)(void* opaque, const libvlc_video_render_cfg_t *cfg,
                                               libvlc_video_output_cfg_t *output );
@@ -747,6 +755,23 @@ typedef enum libvlc_video_engine_t {
     libvlc_video_engine_d3d11,
     /** Direct3D9 rendering engine */
     libvlc_video_engine_d3d9,
+
+    /**
+     * Android ANativeWindow. It can be set in \ref libvlc_video_output_cfg_t
+     * from the \ref libvlc_video_update_output_cb callback. The ANativeWindow
+     * can be created via:
+     *  - 'ANativeWindow_fromSurface': from a JAVA SurfaceView
+     *  - 'AImageReader_getWindow()': from an 'AImageReader' created with the
+     *  following arguments: \verbatim
+     AImageReader_newWithUsage(1, 1 AIMAGE_FORMAT_PRIVATE,
+                               AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE,
+                               maxImages, &reader);
+     \endverbatim
+     * The width and height from \ref libvlc_video_render_cfg_t should be
+     * ignored as the video size is overridden by the producer (MediaCodec or
+     * EGL vout).
+     */
+    libvlc_video_engine_anw,
 } libvlc_video_engine_t;
 
 
@@ -876,9 +901,12 @@ typedef bool( *libvlc_video_output_select_plane_cb )( void *opaque, size_t plane
  * \param cleanup_cb callback called to clean up user data
  * \param window_cb callback called to setup the window
  * \param update_output_cb callback to get the rendering format of the host (cannot be NULL)
- * \param swap_cb callback called after rendering a video frame (cannot be NULL)
- * \param makeCurrent_cb callback called to enter/leave the rendering context (cannot be NULL)
- * \param getProcAddress_cb opengl function loading callback (cannot be NULL for \ref libvlc_video_engine_opengl and for \ref libvlc_video_engine_gles2)
+ * \param swap_cb callback called after rendering a video frame (can only be
+ * NULL when using \ref libvlc_video_engine_anw)
+ * \param makeCurrent_cb callback called to enter/leave the rendering context
+ * (can only be NULL when using \ref libvlc_video_engine_anw)
+ * \param getProcAddress_cb opengl function loading callback (cannot be NULL 
+ * for \ref libvlc_video_engine_opengl and for \ref libvlc_video_engine_gles2)
  * \param metadata_cb callback to provide frame metadata (D3D11 only)
  * \param select_plane_cb callback to select different D3D11 rendering targets
  * \param opaque private pointer passed to callbacks
@@ -904,6 +932,22 @@ bool libvlc_video_set_output_callbacks( libvlc_media_player_t *mp,
                                         libvlc_video_output_select_plane_cb select_plane_cb,
                                         void* opaque );
 
+/**
+ * Helper to setup output_callbacks for \ref libvlc_video_engine_anw
+ */
+static inline bool
+libvlc_video_set_anw_callbacks( libvlc_media_player_t *mp,
+                                libvlc_video_output_setup_cb setup_cb,
+                                libvlc_video_output_cleanup_cb cleanup_cb,
+                                libvlc_video_update_output_cb update_output_cb,
+                                void *opaque )
+{
+    return libvlc_video_set_output_callbacks( mp, libvlc_video_engine_anw,
+                                              setup_cb, cleanup_cb, NULL,
+                                              update_output_cb, NULL, NULL,
+                                              NULL, NULL, NULL, opaque );
+}
+
 /**
  * Set the handler where the media player should display its video output.
  *


=====================================
lib/media_player.c
=====================================
@@ -1136,6 +1136,13 @@ bool libvlc_video_set_output_callbacks(libvlc_media_player_t *mp,
         var_SetString ( mp, "vout", "direct3d9" );
         var_SetString ( mp, "dec-dev", "d3d9" );
     }
+    else if ( engine == libvlc_video_engine_anw )
+    {
+        /* Force android-display is using MediaCodec or fallback to GL (any) */
+        var_SetString ( mp, "vout", "android-display,any" );
+        var_SetString ( mp, "dec-dev", "android" );
+        var_SetString( mp, "window", "android");
+    }
     else if ( engine == libvlc_video_engine_disable )
     {
         // use the default display module


=====================================
modules/codec/omxil/mediacodec.c
=====================================
@@ -720,10 +720,14 @@ CreateVideoContext(decoder_t *p_dec)
      * to modify its layout. */
 
     p_sys->video.surfacetexture = NULL;
-    bool use_surfacetexture =
-        p_dec->fmt_out.video.projection_mode != PROJECTION_MODE_RECTANGULAR
-     || (!p_sys->api.b_support_rotation && p_dec->fmt_out.video.orientation != ORIENT_NORMAL)
-     || !AWindowHandler_canSetVideoLayout(awh);
+    int awh_caps = AWindowHandler_getCapabilities(awh);
+    bool can_set_video_layout = awh_caps & AWH_CAPS_SET_VIDEO_LAYOUT;
+    bool can_use_surfacetexture = awh_caps & AWH_CAPS_SURFACE_VIEW;
+
+    bool use_surfacetexture = can_use_surfacetexture
+     && (p_dec->fmt_out.video.projection_mode != PROJECTION_MODE_RECTANGULAR
+      || (!p_sys->api.b_support_rotation && p_dec->fmt_out.video.orientation != ORIENT_NORMAL)
+      || !can_set_video_layout);
 
     if (!use_surfacetexture)
     {


=====================================
modules/video_filter/egl_surfacetexture.c
=====================================
@@ -129,6 +129,8 @@ static picture_context_t *CreatePictureContext(vlc_gl_t *gl)
     struct video_ctx *vctx = GetVCtx(gl);
 
     ctx->texture = vlc_asurfacetexture_New(gl->device->opaque, false);
+    if (ctx->texture == NULL)
+        goto error;
 
     struct ANativeWindow *window = ctx->texture->window;
     native_window_api_t *api =
@@ -142,6 +144,7 @@ static picture_context_t *CreatePictureContext(vlc_gl_t *gl)
     if (ctx->surface == EGL_NO_SURFACE)
     {
         msg_Err(gl, "cannot create EGL window surface");
+        vlc_asurfacetexture_Delete(ctx->texture);
         goto error;
     }
 


=====================================
modules/video_output/android/display.c
=====================================
@@ -62,6 +62,7 @@ struct subpicture
 struct sys
 {
     AWindowHandler *awh;
+    bool can_set_video_layout;
     android_video_context_t *avctx;
     struct subpicture sub;
 };
@@ -380,6 +381,8 @@ static void Display(vout_display_t *vd, picture_t *picture)
 static void SetVideoLayout(vout_display_t *vd)
 {
     struct sys *sys = vd->sys;
+    if (!sys->can_set_video_layout)
+        return;
 
     video_format_t rot_fmt;
     video_format_ApplyRotation(&rot_fmt, vd->source);
@@ -428,7 +431,8 @@ static void Close(vout_display_t *vd)
 {
     struct sys *sys = vd->sys;
 
-    AWindowHandler_setVideoLayout(sys->awh, 0, 0, 0, 0, 0, 0);
+    if (sys->can_set_video_layout)
+        AWindowHandler_setVideoLayout(sys->awh, 0, 0, 0, 0, 0, 0);
 
     if (sys->sub.window != NULL)
         subpicture_CloseDisplay(vd);
@@ -444,11 +448,14 @@ static int Open(vout_display_t *vd,
 
     if (embed->type != VLC_WINDOW_TYPE_ANDROID_NATIVE
      || fmtp->i_chroma != VLC_CODEC_ANDROID_OPAQUE
-     || context == NULL
-     || !AWindowHandler_canSetVideoLayout(awh))
+     || context == NULL)
         return VLC_EGENERIC;
 
-    if (!vd->obj.force && fmtp->projection_mode != PROJECTION_MODE_RECTANGULAR)
+    bool can_set_video_layout = AWindowHandler_getCapabilities(awh)
+                                & AWH_CAPS_SET_VIDEO_LAYOUT;
+    if (!vd->obj.force
+     && (fmtp->projection_mode != PROJECTION_MODE_RECTANGULAR
+      || !can_set_video_layout))
     {
         /* Let the gles2 vout handle projection */
         return VLC_EGENERIC;
@@ -460,6 +467,7 @@ static int Open(vout_display_t *vd,
         return VLC_ENOMEM;
 
     sys->awh = awh;
+    sys->can_set_video_layout = can_set_video_layout;
     sys->avctx = vlc_video_context_GetPrivate(context, VLC_VIDEO_CONTEXT_AWINDOW);
     assert(sys->avctx);
     if (sys->avctx->texture != NULL)


=====================================
modules/video_output/android/utils.c
=====================================
@@ -40,6 +40,7 @@
 
 typedef ANativeWindow* (*ptr_ANativeWindow_fromSurface)(JNIEnv*, jobject);
 typedef ANativeWindow* (*ptr_ANativeWindow_fromSurfaceTexture)(JNIEnv*, jobject);
+typedef void (*ptr_ANativeWindow_acquire)(ANativeWindow*);
 typedef void (*ptr_ANativeWindow_release)(ANativeWindow*);
 
 typedef void (*ptr_ASurfaceTexture_getTransformMatrix)
@@ -130,6 +131,7 @@ struct AWindowHandler
 
     void *p_anw_dl;
     ptr_ANativeWindow_fromSurface pf_winFromSurface;
+    ptr_ANativeWindow_acquire pf_winAcquire;
     ptr_ANativeWindow_release pf_winRelease;
     native_window_api_t anw_api;
 
@@ -139,7 +141,7 @@ struct AWindowHandler
     struct {
         awh_events_t cb;
     } event;
-    bool b_has_video_layout_listener;
+    int capabilities;
 
     struct {
         jfloatArray jtransform_mtx_array;
@@ -321,6 +323,7 @@ static void
 LoadNativeSurfaceAPI(AWindowHandler *p_awh)
 {
     p_awh->pf_winFromSurface = NativeSurface_fromSurface;
+    p_awh->pf_winAcquire = NULL;
     p_awh->pf_winRelease = NativeSurface_release;
     p_awh->anw_api.winLock = NativeSurface_lock;
     p_awh->anw_api.unlockAndPost = NativeSurface_unlockAndPost;
@@ -574,12 +577,13 @@ LoadNativeWindowAPI(AWindowHandler *p_awh)
     }
 
     p_awh->pf_winFromSurface = dlsym(p_library, "ANativeWindow_fromSurface");
+    p_awh->pf_winAcquire = dlsym(p_library, "ANativeWindow_acquire");
     p_awh->pf_winRelease = dlsym(p_library, "ANativeWindow_release");
     p_awh->anw_api.winLock = dlsym(p_library, "ANativeWindow_lock");
     p_awh->anw_api.unlockAndPost = dlsym(p_library, "ANativeWindow_unlockAndPost");
     p_awh->anw_api.setBuffersGeometry = dlsym(p_library, "ANativeWindow_setBuffersGeometry");
 
-    if (p_awh->pf_winFromSurface && p_awh->pf_winRelease
+    if (p_awh->pf_winFromSurface && p_awh->pf_winAcquire && p_awh->pf_winRelease
      && p_awh->anw_api.winLock && p_awh->anw_api.unlockAndPost
      && p_awh->anw_api.setBuffersGeometry)
     {
@@ -744,6 +748,8 @@ error:
 static JNIEnv*
 AWindowHandler_getEnv(AWindowHandler *p_awh)
 {
+    if (p_awh->p_jvm == NULL)
+        return NULL;
     return android_getEnvCommon(NULL, p_awh->p_jvm, "AWindowHandler");
 }
 
@@ -820,10 +826,12 @@ AWindowHandler_new(vlc_object_t *obj, vlc_window_t *wnd, awh_events_t *p_events)
     }
     LoadNativeWindowAPI(p_awh);
 
-    p_awh->b_has_video_layout_listener =
-        wnd && flags & AWINDOW_REGISTER_FLAGS_HAS_VIDEO_LAYOUT_LISTENER;
+    p_awh->capabilities = 0;
+
+    if (wnd && flags & AWINDOW_REGISTER_FLAGS_HAS_VIDEO_LAYOUT_LISTENER)
+        p_awh->capabilities |= AWH_CAPS_SET_VIDEO_LAYOUT;
 
-    if (p_awh->b_has_video_layout_listener && p_events != NULL)
+    if (p_awh->capabilities & AWH_CAPS_SET_VIDEO_LAYOUT && p_events != NULL)
     {
         /* XXX: HACK: force mediacodec to setup an OpenGL surface when the vout
          * is forced to gles2. Indeed, setting b_has_video_layout_listener to
@@ -833,13 +841,47 @@ AWindowHandler_new(vlc_object_t *obj, vlc_window_t *wnd, awh_events_t *p_events)
         if (vout_modules
          && (strncmp(vout_modules, "gles2", sizeof("gles2") - 1) == 0
           || strncmp(vout_modules, "opengles2", sizeof("opengles2") - 1) == 0))
-            p_awh->b_has_video_layout_listener = false;
+            p_awh->capabilities &= ~AWH_CAPS_SET_VIDEO_LAYOUT;
         free(vout_modules);
     }
 
+    p_awh->capabilities |= AWH_CAPS_SURFACE_VIEW;
+
     return p_awh;
 }
 
+AWindowHandler *
+AWindowHandler_newFromANWs(vlc_object_t *obj, ANativeWindow *video,
+                           ANativeWindow *subtitle)
+{
+    (void) obj;
+    AWindowHandler *awh = calloc(1, sizeof(AWindowHandler));
+    if (!awh)
+        return NULL;
+
+    awh->p_jvm = NULL;
+    awh->jobj = NULL;
+    awh->jfields = (struct vlc_android_jfields) { .AWindow.clazz = NULL };
+    awh->wnd = NULL;
+
+    LoadNativeWindowAPI(awh);
+    if (awh->pf_winAcquire == NULL)
+    {
+        free(awh);
+        return NULL;
+    }
+
+    awh->views[AWindow_Video].p_anw = video;
+    awh->pf_winAcquire(video);
+    awh->capabilities = 0;
+
+    awh->views[AWindow_Subtitles].p_anw = subtitle;
+    if (subtitle != NULL)
+        awh->pf_winAcquire(subtitle);
+
+    return awh;
+}
+
 static void
 AWindowHandler_releaseANativeWindowEnv(AWindowHandler *p_awh, JNIEnv *p_env,
                                        enum AWindow_ID id)
@@ -852,7 +894,7 @@ AWindowHandler_releaseANativeWindowEnv(AWindowHandler *p_awh, JNIEnv *p_env,
         p_awh->views[id].p_anw = NULL;
     }
 
-    if (p_awh->views[id].jsurface)
+    if (p_env != NULL && p_awh->views[id].jsurface)
     {
         (*p_env)->DeleteGlobalRef(p_env, p_awh->views[id].jsurface);
         p_awh->views[id].jsurface = NULL;
@@ -874,16 +916,20 @@ AWindowHandler_destroy(AWindowHandler *p_awh)
 
         if (p_awh->jobj)
             JNI_ANWCALL(CallVoidMethod, unregisterNative);
-        AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_Video);
-        AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_Subtitles);
+    }
+
+    AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_Video);
+    AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, AWindow_Subtitles);
+
+    if (p_env != NULL)
+    {
         if (p_awh->jobj)
             (*p_env)->DeleteGlobalRef(p_env, p_awh->jobj);
+        (*p_env)->DeleteGlobalRef(p_env, p_awh->stex.jtransform_mtx_array);
     }
 
     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);
 }
 
@@ -1108,6 +1154,8 @@ error:
 struct vlc_asurfacetexture *
 vlc_asurfacetexture_New(AWindowHandler *p_awh, bool single_buffer)
 {
+    if (p_awh->p_jvm == NULL)
+        return NULL;
     JNIEnv *p_env = android_getEnvCommon(NULL, p_awh->p_jvm, "SurfaceTexture");
     struct vlc_asurfacetexture_priv *surfacetexture =
         CreateSurfaceTexture(p_awh, p_env, single_buffer);
@@ -1150,12 +1198,10 @@ AWindowHandler_getANativeWindow(AWindowHandler *p_awh, enum AWindow_ID id)
 {
     assert(id < AWindow_Max);
 
-    JNIEnv *p_env;
-
     if (p_awh->views[id].p_anw)
         return p_awh->views[id].p_anw;
 
-    p_env = AWindowHandler_getEnv(p_awh);
+    JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
     if (!p_env)
         return NULL;
 
@@ -1187,8 +1233,7 @@ void AWindowHandler_releaseANativeWindow(AWindowHandler *p_awh,
                                          enum AWindow_ID id)
 {
     JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
-    if (p_env)
-        AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, id);
+    AWindowHandler_releaseANativeWindowEnv(p_awh, p_env, id);
 }
 
 static inline AWindowHandler *jlong_AWindowHandler(jlong handle)
@@ -1218,10 +1263,10 @@ AndroidNativeWindow_onWindowSize(JNIEnv* env, jobject clazz, jlong handle,
         p_awh->event.cb.on_new_window_size(p_awh->wnd, width, height);
 }
 
-bool
-AWindowHandler_canSetVideoLayout(AWindowHandler *p_awh)
+int
+AWindowHandler_getCapabilities(AWindowHandler *p_awh)
 {
-    return p_awh->b_has_video_layout_listener && p_awh->wnd != NULL;
+    return p_awh->capabilities;
 }
 
 int
@@ -1230,7 +1275,7 @@ AWindowHandler_setVideoLayout(AWindowHandler *p_awh,
                               int i_visible_width, int i_visible_height,
                               int i_sar_num, int i_sar_den)
 {
-    assert(p_awh->b_has_video_layout_listener);
+    assert(p_awh->capabilities & AWH_CAPS_SET_VIDEO_LAYOUT);
     JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
     if (!p_env)
         return VLC_EGENERIC;


=====================================
modules/video_output/android/utils.h
=====================================
@@ -33,6 +33,11 @@
 #include <vlc_vout_display.h>
 #include <vlc_common.h>
 
+/* AWH using a VideoLAN AWindow helpers */
+#define AWH_CAPS_SET_VIDEO_LAYOUT 0x1
+/* AWH backed by a Android SurfaceView */
+#define AWH_CAPS_SURFACE_VIEW 0x2
+
 typedef struct AWindowHandler AWindowHandler;
 typedef struct ASurfaceTexture ASurfaceTexture;
 
@@ -125,6 +130,10 @@ struct vlc_asurfacetexture_operations
 AWindowHandler *AWindowHandler_new(vlc_object_t *obj, vlc_window_t *wnd, awh_events_t *p_events);
 void AWindowHandler_destroy(AWindowHandler *p_awh);
 
+AWindowHandler *
+AWindowHandler_newFromANWs(vlc_object_t *obj, ANativeWindow *video,
+                           ANativeWindow *subtitle);
+
 /**
  * Get the public native window API
  *
@@ -156,15 +165,12 @@ ANativeWindow *AWindowHandler_getANativeWindow(AWindowHandler *p_awh,
 void AWindowHandler_releaseANativeWindow(AWindowHandler *p_awh,
                                          enum AWindow_ID id);
 
-/**
- * Returns true if the video layout can be changed
- */
-bool AWindowHandler_canSetVideoLayout(AWindowHandler *p_awh);
+int AWindowHandler_getCapabilities(AWindowHandler *p_awh);
 
 /**
  * Set the video layout
  *
- * Should be called only if AWindowHandler_canSetVideoLayout() returned true
+ * Should be called only if AWindowHandler_getCapabilities() has AWH_CAPS_SET_VIDEO_LAYOUT
  */
 int AWindowHandler_setVideoLayout(AWindowHandler *p_awh,
                                   int i_width, int i_height,


=====================================
modules/video_output/android/window.c
=====================================
@@ -33,6 +33,9 @@
 #include <vlc_window.h>
 #include <vlc_codec.h>
 
+#include <vlc/libvlc.h>
+#include <vlc/libvlc_media_player.h>
+
 #include <dlfcn.h>
 #include <jni.h>
 
@@ -44,6 +47,12 @@ typedef struct
     vlc_wasync_resize_compressor_t compressor;
 } vout_window_sys_t;
 
+struct vout_window_sys_cb
+{
+    void *opaque;
+    libvlc_video_output_cleanup_cb cleanup_cb;
+};
+
 static void OnNewWindowSize(vlc_window_t *wnd,
                             unsigned i_width, unsigned i_height)
 {
@@ -108,6 +117,76 @@ static int Open(vlc_window_t *wnd)
     return VLC_SUCCESS;
 }
 
+static void DestroyCallback(vlc_window_t *wnd)
+{
+    struct vout_window_sys_cb *sys = wnd->sys;
+    if (sys->cleanup_cb != NULL)
+        sys->cleanup_cb(sys->opaque);
+}
+
+static int OpenCallback(vlc_window_t *wnd)
+{
+    static const struct vlc_window_operations ops = {
+        .destroy = DestroyCallback,
+    };
+
+    libvlc_video_engine_t engine = var_InheritInteger(wnd, "vout-cb-type");
+    if (engine != libvlc_video_engine_anw)
+        return VLC_EGENERIC;
+
+    struct vout_window_sys_cb *sys = vlc_obj_malloc(VLC_OBJECT(wnd), sizeof (*sys));
+    if (sys == NULL)
+        return VLC_ENOMEM;
+
+    sys->opaque = var_InheritAddress(wnd, "vout-cb-opaque");
+    libvlc_video_output_setup_cb setup_cb = var_InheritAddress(wnd, "vout-cb-setup");
+    libvlc_video_update_output_cb update_cb = var_InheritAddress(wnd, "vout-cb-update-output");
+    sys->cleanup_cb = var_InheritAddress(wnd, "vout-cb-cleanup");
+
+    if (update_cb == NULL)
+        return VLC_EGENERIC;
+
+    if (setup_cb != NULL)
+    {
+        const libvlc_video_setup_device_cfg_t cfg = {
+            .hardware_decoding = true,
+        };
+        libvlc_video_setup_device_info_t out;
+        bool success = setup_cb(&sys->opaque, &cfg, &out);
+        if (!success)
+            return VLC_EGENERIC;
+        (void) out; /* Ignored on Android */
+    }
+
+    /* Default values, parameters are overridden by the producer */
+    const libvlc_video_render_cfg_t render_cfg = {
+        .width = 1,
+        .height = 1,
+    };
+    libvlc_video_output_cfg_t out = { .anw = { NULL, NULL } };
+    bool success = update_cb(sys->opaque, &render_cfg, &out);
+    if (!success)
+        goto error;
+    assert(out.anw.video != NULL);
+
+    AWindowHandler *awh =
+        AWindowHandler_newFromANWs(VLC_OBJECT(wnd), out.anw.video, out.anw.subtitle);
+    if (awh == NULL)
+        goto error;
+
+    wnd->sys = sys;
+    wnd->type = VLC_WINDOW_TYPE_ANDROID_NATIVE;
+    wnd->display.anativewindow = awh;
+    wnd->handle.android_id = AWindow_Video;
+    wnd->ops = &ops;
+
+    return VLC_SUCCESS;
+error:
+    if (sys->cleanup_cb != NULL)
+        sys->cleanup_cb(sys->opaque);
+    return VLC_EGENERIC;
+}
+
 static int
 OpenDecDevice(vlc_decoder_device *device, vlc_window_t *window)
 {
@@ -140,6 +219,9 @@ vlc_module_begin()
     set_subcategory(SUBCAT_VIDEO_VOUT)
     set_capability("vout window", 10)
     set_callback(Open)
+    add_submodule ()
+        set_capability("vout window", 11)
+        set_callback(OpenCallback)
     add_submodule ()
         set_callback_dec_device(OpenDecDevice, 1)
         add_shortcut("android")


=====================================
modules/video_output/opengl/egl.c
=====================================
@@ -521,9 +521,18 @@ static EGLSurface CreateSurface(vlc_gl_t *gl, EGLDisplay dpy, EGLConfig config,
         AWindowHandler_getANativeWindow(gl->surface->display.anativewindow,
                                         gl->surface->handle.android_id);
 
-    (void) width; (void) height;
-    return (anw != NULL) ? eglCreateWindowSurface(dpy, config, anw, NULL)
-                         : EGL_NO_SURFACE;
+    if (anw == NULL)
+        return EGL_NO_SURFACE;
+
+    int awh_caps = AWindowHandler_getCapabilities(gl->surface->display.anativewindow);
+    if ((awh_caps & AWH_CAPS_SURFACE_VIEW) == 0)
+    {
+        native_window_api_t *api =
+            AWindowHandler_getANativeWindowAPI(gl->surface->display.anativewindow);
+        api->setBuffersGeometry(anw, width, height, AHARDWAREBUFFER_FORMAT_BLOB);
+    }
+
+    return eglCreateWindowSurface(dpy, config, anw, NULL);
 }
 
 static void ReleaseDisplay(vlc_gl_t *gl)



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f1f05aa2b98901f77f947f5aed39ee79eba3fcaa...61cbeec966d2220929d80f3df9d3b444f9593cf8

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/f1f05aa2b98901f77f947f5aed39ee79eba3fcaa...61cbeec966d2220929d80f3df9d3b444f9593cf8
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list