[vlc-commits] androidsurface: Use the ANativeWindow API where available

Martin Storsjö git at videolan.org
Fri Jul 26 11:54:36 CEST 2013


vlc | branch: master | Martin Storsjö <martin at martin.st> | Thu Jul 25 16:05:36 2013 +0300| [59e4f588117bc27b85686f5e3b678457806f4fd8] | committer: Martin Storsjö

androidsurface: Use the ANativeWindow API where available

This makes the android vout work on Android 4.3.

This API is available since Android 2.3/Gingerbread (api level 9).
It's a public, official API, contrary to the earlier hacking by
accessing the internal C++ Surface class directly. In most cases,
the ANativeWindow API is a very thin wrapper doing pretty much
the same as the existing Surface class entry points we've been using.

In Android 4.3, the C++ Surface class lock function we've been using
was renamed again, but using the new corresponding function as
we've done before doesn't work any longer.

Therefore, use the public API where possible (loading it dynamically,
to not break compatibility with pre-2.3 devices).

The only non-public API used in the vout is now the YV12
pixel format, which doesn't work on all devices.

Signed-off-by: Martin Storsjö <martin at martin.st>

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

 modules/video_output/androidsurface.c |   99 +++++++++++++++++++++++++++++----
 1 file changed, 89 insertions(+), 10 deletions(-)

diff --git a/modules/video_output/androidsurface.c b/modules/video_output/androidsurface.c
index 848591f..ae70bc3 100644
--- a/modules/video_output/androidsurface.c
+++ b/modules/video_output/androidsurface.c
@@ -32,6 +32,9 @@
 #include <vlc_picture_pool.h>
 
 #include <dlfcn.h>
+#include <android/native_window.h>
+#include <jni.h>
+#include <android/native_window_jni.h>
 
 #ifndef ANDROID_SYM_S_LOCK
 # define ANDROID_SYM_S_LOCK "_ZN7android7Surface4lockEPNS0_11SurfaceInfoEb"
@@ -70,7 +73,9 @@ vlc_module_end()
  * JNI prototypes
  *****************************************************************************/
 
+extern JavaVM *myVm;
 extern void *jni_LockAndGetAndroidSurface();
+extern jobject jni_LockAndGetAndroidJavaSurface();
 extern void  jni_UnlockAndroidSurface();
 extern void  jni_SetAndroidSurfaceSize(int width, int height, int sar_num, int sar_den);
 
@@ -81,6 +86,11 @@ typedef void (*Surface_lock2)(void *, void *, void *);
 // _ZN7android7Surface13unlockAndPostEv
 typedef void (*Surface_unlockAndPost)(void *);
 
+typedef ANativeWindow* (*ptr_ANativeWindow_fromSurface)(JNIEnv*, jobject);
+typedef void (*ptr_ANativeWindow_release)(ANativeWindow*);
+typedef int32_t (*ptr_ANativeWindow_lock)(ANativeWindow*, ANativeWindow_Buffer*, ARect*);
+// Just using the normal Surface_unlockAndPost as prototype for ANativeWindow_unlockAndPost
+
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
@@ -107,6 +117,12 @@ struct vout_display_sys_t {
     Surface_lock s_lock;
     Surface_lock2 s_lock2;
     Surface_unlockAndPost s_unlockAndPost;
+    ptr_ANativeWindow_fromSurface s_winFromSurface;
+    ptr_ANativeWindow_release s_winRelease;
+    ptr_ANativeWindow_lock s_winLock;
+
+    jobject jsurf;
+    ANativeWindow *window;
 
     /* density */
     int i_sar_num;
@@ -158,6 +174,33 @@ static void *InitLibrary(vout_display_sys_t *sys)
     return NULL;
 }
 
+static void *InitLibrary2(vout_display_sys_t *sys)
+{
+    void *p_library = dlopen("libandroid.so", RTLD_NOW);
+    if (!p_library)
+        return NULL;
+
+    sys->s_winFromSurface =
+        (ptr_ANativeWindow_fromSurface)(dlsym(p_library, "ANativeWindow_fromSurface"));
+    sys->s_winRelease =
+        (ptr_ANativeWindow_release)(dlsym(p_library, "ANativeWindow_release"));
+    sys->s_winLock =
+        (ptr_ANativeWindow_lock)(dlsym(p_library, "ANativeWindow_lock"));
+    sys->s_unlockAndPost =
+        (Surface_unlockAndPost)(dlsym(p_library, "ANativeWindow_unlockAndPost"));
+
+    if (sys->s_winFromSurface && sys->s_winRelease && sys->s_winLock && sys->s_unlockAndPost)
+        return p_library;
+
+    sys->s_winFromSurface = NULL;
+    sys->s_winRelease = NULL;
+    sys->s_winLock = NULL;
+    sys->s_unlockAndPost = NULL;
+
+    dlclose(p_library);
+    return NULL;
+}
+
 static int Open(vlc_object_t *p_this)
 {
     vout_display_t *vd = (vout_display_t *)p_this;
@@ -176,10 +219,12 @@ static int Open(vlc_object_t *p_this)
     }
 
     /* */
-    sys->p_library = InitLibrary(sys);
+    sys->p_library = InitLibrary2(sys);
+    if (!sys->p_library)
+        sys->p_library = InitLibrary(sys);
     if (!sys->p_library) {
         free(sys);
-        msg_Err(vd, "Could not initialize libui.so/libgui.so/libsurfaceflinger_client.so!");
+        msg_Err(vd, "Could not initialize libandroid.so/libui.so/libgui.so/libsurfaceflinger_client.so!");
         vlc_mutex_unlock(&single_instance);
         return VLC_EGENERIC;
     }
@@ -279,6 +324,8 @@ static void Close(vlc_object_t *p_this)
 
     picture_pool_Delete(sys->pool);
     dlclose(sys->p_library);
+    if (sys->window)
+        sys->s_winRelease(sys->window);
     free(sys);
     vlc_mutex_unlock(&single_instance);
 }
@@ -329,15 +376,44 @@ static int  AndroidLockSurface(picture_t *picture)
     sw = picture->p[0].i_visible_pitch / picture->p[0].i_pixel_pitch;
     sh = picture->p[0].i_visible_lines;
 
-    picsys->surf = surf = jni_LockAndGetAndroidSurface();
-    info = &(picsys->info);
-
-    if (unlikely(!surf)) {
-        jni_UnlockAndroidSurface();
-        return VLC_EGENERIC;
+    if (sys->s_winFromSurface) {
+        jobject jsurf = jni_LockAndGetAndroidJavaSurface();
+        if (unlikely(!jsurf)) {
+            jni_UnlockAndroidSurface();
+            return VLC_EGENERIC;
+        }
+        if (sys->window && jsurf != sys->jsurf) {
+            sys->s_winRelease(sys->window);
+            sys->window = NULL;
+        }
+        sys->jsurf = jsurf;
+        if (!sys->window) {
+            JNIEnv *p_env;
+            (*myVm)->AttachCurrentThread(myVm, &p_env, NULL);
+            sys->window = sys->s_winFromSurface(p_env, jsurf);
+            (*myVm)->DetachCurrentThread(myVm);
+        }
+        // Using sys->window instead of the native surface object
+        // as parameter to the unlock function
+        picsys->surf = surf = sys->window;
+    } else {
+        picsys->surf = surf = jni_LockAndGetAndroidSurface();
+        if (unlikely(!surf)) {
+            jni_UnlockAndroidSurface();
+            return VLC_EGENERIC;
+        }
     }
-
-    if (sys->s_lock)
+    info = &picsys->info;
+
+    if (sys->s_winLock) {
+        ANativeWindow_Buffer buf = { 0 };
+        sys->s_winLock(sys->window, &buf, NULL);
+        info->w      = buf.width;
+        info->h      = buf.height;
+        info->bits   = buf.bits;
+        info->s      = buf.stride;
+        info->format = buf.format;
+    } else if (sys->s_lock)
         sys->s_lock(surf, info, 1);
     else
         sys->s_lock2(surf, info, NULL);
@@ -349,6 +425,9 @@ static int  AndroidLockSurface(picture_t *picture)
     if (info->w != aligned_width || info->h != sh) {
         // input size doesn't match the surface size -> request a resize
         jni_SetAndroidSurfaceSize(sw, sh, sys->i_sar_num, sys->i_sar_den);
+        // When using ANativeWindow, one should use ANativeWindow_setBuffersGeometry
+        // to set the size and format. In our case, these are set via the SurfaceHolder
+        // in Java, so we seem to manage without calling this ANativeWindow function.
         sys->s_unlockAndPost(surf);
         jni_UnlockAndroidSurface();
         return VLC_EGENERIC;



More information about the vlc-commits mailing list