vlc | branch: master | Martin Storsjö <[email protected]> | 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ö <[email protected]>

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

_______________________________________________
vlc-commits mailing list
[email protected]
http://mailman.videolan.org/listinfo/vlc-commits

Reply via email to