[Android] [PATCH] libvlc: replace static jni vout utils with java helpers

Thomas Guillem thomas at gllm.fr
Thu Jun 25 14:59:27 CEST 2015


IVLCVout: setup MediaPlayer Vout (Video, Subtitles surfaces).

IAWindowNativeHandler: used by native vlc.

AWindow: implements IAWindowNativeHandler and IVLCVout and owned by a
MediaPlayer.
---
 libvlc/jni/Android.mk                              |   2 +-
 libvlc/jni/libvlcjni-mediaplayer.c                 |  37 +-
 libvlc/jni/libvlcjni.c                             |  70 ++--
 libvlc/jni/vout.c                                  | 224 ----------
 libvlc/jni/vout.h                                  |  28 --
 libvlc/src/org/videolan/libvlc/AWindow.java        | 459 +++++++++++++++++++++
 .../org/videolan/libvlc/IAWindowNativeHandler.java |  97 +++++
 libvlc/src/org/videolan/libvlc/IVLCVout.java       | 123 ++++++
 libvlc/src/org/videolan/libvlc/IVideoPlayer.java   |  54 ---
 libvlc/src/org/videolan/libvlc/LibVLC.java         |  23 +-
 libvlc/src/org/videolan/libvlc/MediaPlayer.java    |  43 +-
 .../vlc/gui/video/VideoPlayerActivity.java         | 261 +++---------
 12 files changed, 863 insertions(+), 558 deletions(-)
 delete mode 100644 libvlc/jni/vout.c
 delete mode 100644 libvlc/jni/vout.h
 create mode 100644 libvlc/src/org/videolan/libvlc/AWindow.java
 create mode 100644 libvlc/src/org/videolan/libvlc/IAWindowNativeHandler.java
 create mode 100644 libvlc/src/org/videolan/libvlc/IVLCVout.java
 delete mode 100644 libvlc/src/org/videolan/libvlc/IVideoPlayer.java

diff --git a/libvlc/jni/Android.mk b/libvlc/jni/Android.mk
index 4337bad..a513010 100644
--- a/libvlc/jni/Android.mk
+++ b/libvlc/jni/Android.mk
@@ -9,7 +9,7 @@ LOCAL_SRC_FILES += libvlcjni-mediaplayer.c
 LOCAL_SRC_FILES += libvlcjni-equalizer.c
 LOCAL_SRC_FILES += libvlcjni-vlcobject.c
 LOCAL_SRC_FILES += libvlcjni-media.c libvlcjni-medialist.c libvlcjni-mediadiscoverer.c
-LOCAL_SRC_FILES += vout.c native_crash_handler.c thumbnailer.c
+LOCAL_SRC_FILES += native_crash_handler.c thumbnailer.c
 LOCAL_SRC_FILES += std_logger.c
 
 ifneq ($(APP_PLATFORM),android-21)
diff --git a/libvlc/jni/libvlcjni-mediaplayer.c b/libvlc/jni/libvlcjni-mediaplayer.c
index e3d7caf..f72a9d2 100644
--- a/libvlc/jni/libvlcjni-mediaplayer.c
+++ b/libvlc/jni/libvlcjni-mediaplayer.c
@@ -26,9 +26,15 @@
 
 #define THREAD_NAME "libvlcjni"
 JNIEnv *jni_get_env(const char *name);
+extern JavaVM *libvlc_get_jvm();
 
 extern jobject eventHandlerInstance;
 
+struct vlcjni_object_sys
+{
+    jobject jwindow;
+};
+
 /* TODO REMOVE */
 static void vlc_event_callback(const libvlc_event_t *ev, void *data)
 {
@@ -119,14 +125,26 @@ end:
 }
 
 static void
-MediaPlayer_newCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
+MediaPlayer_newCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj,
+                      jobject jwindow)
 {
-    if (!p_obj->u.p_mp)
+    p_obj->p_sys = calloc(1, sizeof(vlcjni_object_sys));
+
+    if (!p_obj->u.p_mp || !p_obj->p_sys)
+    {
+        VLCJniObject_release(env, thiz, p_obj);
+        throw_IllegalStateException(env, "can't create MediaPlayer instance");
+        return;
+    }
+    p_obj->p_sys->jwindow = (*env)->NewGlobalRef(env, jwindow);
+    if (!p_obj->p_sys->jwindow)
     {
         VLCJniObject_release(env, thiz, p_obj);
         throw_IllegalStateException(env, "can't create MediaPlayer instance");
         return;
     }
+    libvlc_media_player_set_android_context(p_obj->u.p_mp, libvlc_get_jvm(),
+                                            p_obj->p_sys->jwindow);
     /*
     VLCJniObject_attachEvents(p_obj, MediaPlayer_event_cb,
                               libvlc_media_event_manager(p_obj->u.p_mp),
@@ -156,7 +174,8 @@ MediaPlayer_newCommon(JNIEnv *env, jobject thiz, vlcjni_object *p_obj)
 void
 Java_org_videolan_libvlc_MediaPlayer_nativeNewFromLibVlc(JNIEnv *env,
                                                          jobject thiz,
-                                                         jobject libvlc)
+                                                         jobject libvlc,
+                                                         jobject jwindow)
 {
     vlcjni_object *p_obj = VLCJniObject_newFromJavaLibVlc(env, thiz, libvlc);
     if (!p_obj)
@@ -164,13 +183,14 @@ Java_org_videolan_libvlc_MediaPlayer_nativeNewFromLibVlc(JNIEnv *env,
 
     /* Create a media player playing environment */
     p_obj->u.p_mp = libvlc_media_player_new(p_obj->p_libvlc);
-    MediaPlayer_newCommon(env, thiz, p_obj);
+    MediaPlayer_newCommon(env, thiz, p_obj, jwindow);
 }
 
 void
 Java_org_videolan_libvlc_MediaPlayer_nativeNewFromMedia(JNIEnv *env,
                                                         jobject thiz,
-                                                        jobject jmedia)
+                                                        jobject jmedia,
+                                                        jobject jwindow)
 {
     vlcjni_object *p_obj;
     vlcjni_object *p_m_obj = VLCJniObject_getInstance(env, jmedia);
@@ -182,7 +202,7 @@ Java_org_videolan_libvlc_MediaPlayer_nativeNewFromMedia(JNIEnv *env,
     if (!p_obj)
         return;
     p_obj->u.p_mp = libvlc_media_player_new_from_media(p_m_obj->u.p_m);
-    MediaPlayer_newCommon(env, thiz, p_obj);
+    MediaPlayer_newCommon(env, thiz, p_obj, jwindow);
 }
 
 void
@@ -212,6 +232,11 @@ Java_org_videolan_libvlc_MediaPlayer_nativeRelease(JNIEnv *env, jobject thiz)
         libvlc_event_detach(ev, mp_events[i], vlc_event_callback, NULL);
     libvlc_media_player_release(p_obj->u.p_mp);
 
+    if (p_obj->p_sys && p_obj->p_sys->jwindow)
+        (*env)->DeleteGlobalRef(env, p_obj->p_sys->jwindow);
+
+    free(p_obj->p_sys);
+
     VLCJniObject_release(env, thiz, p_obj);
 }
 
diff --git a/libvlc/jni/libvlcjni.c b/libvlc/jni/libvlcjni.c
index 7970399..0e10204 100644
--- a/libvlc/jni/libvlcjni.c
+++ b/libvlc/jni/libvlcjni.c
@@ -36,7 +36,6 @@
 
 #include "libvlcjni-modules.h"
 #include "libvlcjni-vlcobject.h"
-#include "vout.h"
 #include "utils.h"
 #include "native_crash_handler.h"
 #include "std_logger.h"
@@ -55,6 +54,13 @@ jobject eventHandlerInstance = NULL;
  * can only be one instance of this shared library in a single VM
  */
 static JavaVM *myVm;
+
+JavaVM *
+libvlc_get_jvm()
+{
+    return myVm;
+}
+
 static pthread_key_t jni_env_key;
 
 /* This function is called when a thread attached to the Java VM is canceled or
@@ -117,9 +123,6 @@ jint JNI_OnLoad(JavaVM *vm, void *reserved)
     if (pthread_key_create(&jni_env_key, jni_detach_thread) != 0)
         return -1;
 
-    pthread_mutex_init(&vout_android_lock, NULL);
-    pthread_cond_init(&vout_android_surf_attached, NULL);
-
 #ifndef NDEBUG
     p_std_logger = std_logger_Open("VLC-std");
 #endif
@@ -242,9 +245,6 @@ void JNI_OnUnload(JavaVM* vm, void* reserved)
 {
     JNIEnv* env = NULL;
 
-    pthread_mutex_destroy(&vout_android_lock);
-    pthread_cond_destroy(&vout_android_surf_attached);
-
     destroy_native_crash_handler();
 
     if ((*vm)->GetEnv(vm, (void**) &env, VLC_JNI_VERSION) != JNI_OK)
@@ -371,27 +371,6 @@ jstring Java_org_videolan_libvlc_LibVLC_changeset(JNIEnv* env, jobject thiz)
     return (*env)->NewStringUTF(env, libvlc_get_changeset());
 }
 
-// TODO: remove static variables
-static int i_window_width = 0;
-static int i_window_height = 0;
-
-void Java_org_videolan_libvlc_LibVLC_setWindowSize(JNIEnv *env, jobject thiz, jint width, jint height)
-{
-    pthread_mutex_lock(&vout_android_lock);
-    i_window_width = width;
-    i_window_height = height;
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-int jni_GetWindowSize(int *width, int *height)
-{
-    pthread_mutex_lock(&vout_android_lock);
-    *width = i_window_width;
-    *height = i_window_height;
-    pthread_mutex_unlock(&vout_android_lock);
-    return 0;
-}
-
 /* used by opensles module */
 int aout_get_native_sample_rate(void)
 {
@@ -403,3 +382,38 @@ int aout_get_native_sample_rate(void)
     int sample_rate = (*p_env)->CallStaticIntMethod (p_env, cls, method, 3); // AudioManager.STREAM_MUSIC
     return sample_rate;
 }
+
+/* TODO REMOVE */
+static jobject error_obj = NULL;
+pthread_mutex_t error_obj_lock;
+
+void Java_org_videolan_libvlc_LibVLC_nativeSetOnHardwareAccelerationError(JNIEnv *env, jobject thiz, jobject error_obj_)
+{
+    pthread_mutex_lock(&error_obj_lock);
+
+    if (error_obj != NULL)
+        (*env)->DeleteGlobalRef(env, error_obj);
+    error_obj = error_obj_ ? (*env)->NewGlobalRef(env, error_obj_) : NULL;
+    pthread_mutex_unlock(&error_obj_lock);
+}
+
+void jni_EventHardwareAccelerationError()
+{
+    JNIEnv *env;
+
+    if (!(env = jni_get_env(THREAD_NAME)))
+        return;
+
+    pthread_mutex_lock(&error_obj_lock);
+    if (error_obj == NULL) {
+        pthread_mutex_unlock(&error_obj_lock);
+        return;
+    }
+
+    jclass cls = (*env)->GetObjectClass(env, error_obj);
+    jmethodID methodId = (*env)->GetMethodID(env, cls, "eventHardwareAccelerationError", "()V");
+    (*env)->CallVoidMethod(env, error_obj, methodId);
+
+    (*env)->DeleteLocalRef(env, cls);
+    pthread_mutex_unlock(&error_obj_lock);
+}
diff --git a/libvlc/jni/vout.c b/libvlc/jni/vout.c
deleted file mode 100644
index ee50463..0000000
--- a/libvlc/jni/vout.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*****************************************************************************
- * vout.c
- *****************************************************************************
- * Copyright © 2010-2013 VLC authors and VideoLAN
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#include <vlc/vlc.h>
-#include <vlc_common.h>
-
-#include <jni.h>
-
-#define THREAD_NAME "jni_vout"
-extern JNIEnv *jni_get_env(const char *name);
-
-pthread_mutex_t vout_android_lock;
-static void *vout_android_gui = NULL;
-static jobject vout_android_java_surf = NULL;
-static jobject vout_android_subtitles_surf = NULL;
-
-void *jni_LockAndGetSubtitlesSurface() {
-    pthread_mutex_lock(&vout_android_lock);
-    if (!vout_android_subtitles_surf) {
-        pthread_mutex_unlock(&vout_android_lock);
-        return NULL;
-    }
-    return vout_android_subtitles_surf;
-}
-
-jobject jni_LockAndGetAndroidJavaSurface() {
-    pthread_mutex_lock(&vout_android_lock);
-    if (!vout_android_java_surf) {
-        pthread_mutex_unlock(&vout_android_lock);
-        return NULL;
-    }
-    return vout_android_java_surf;
-}
-
-void jni_UnlockAndroidSurface() {
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-void jni_EventHardwareAccelerationError()
-{
-    JNIEnv *env;
-
-    if (!(env = jni_get_env(THREAD_NAME)))
-        return;
-
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui == NULL) {
-        pthread_mutex_unlock(&vout_android_lock);
-        return;
-    }
-
-    jclass cls = (*env)->GetObjectClass(env, vout_android_gui);
-    jmethodID methodId = (*env)->GetMethodID(env, cls, "eventHardwareAccelerationError", "()V");
-    (*env)->CallVoidMethod(env, vout_android_gui, methodId);
-
-    (*env)->DeleteLocalRef(env, cls);
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-static void jni_SetSurfaceLayoutEnv(JNIEnv *p_env, int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
-{
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui == NULL) {
-        pthread_mutex_unlock(&vout_android_lock);
-        return;
-    }
-
-    jclass cls = (*p_env)->GetObjectClass (p_env, vout_android_gui);
-    jmethodID methodId = (*p_env)->GetMethodID (p_env, cls, "setSurfaceLayout", "(IIIIII)V");
-
-    (*p_env)->CallVoidMethod (p_env, vout_android_gui, methodId, width, height, visible_width, visible_height, sar_num, sar_den);
-
-    (*p_env)->DeleteLocalRef(p_env, cls);
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-void jni_SetSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den)
-{
-    JNIEnv *p_env;
-
-    if (!(p_env = jni_get_env(THREAD_NAME)))
-        return;
-
-    jni_SetSurfaceLayoutEnv(p_env, width, height, visible_width, visible_height, sar_num, sar_den);
-}
-
-void *jni_AndroidJavaSurfaceToNativeSurface(jobject surf)
-{
-    JNIEnv *p_env;
-    jclass clz;
-    jfieldID fid;
-    void *native_surface = NULL;
-
-    if (!(p_env = jni_get_env(THREAD_NAME)))
-        return NULL;
-
-    clz = (*p_env)->GetObjectClass(p_env, surf);
-    fid = (*p_env)->GetFieldID(p_env, clz, "mSurface", "I");
-    if (fid == NULL) {
-        jthrowable exp = (*p_env)->ExceptionOccurred(p_env);
-        if (exp) {
-            (*p_env)->DeleteLocalRef(p_env, exp);
-            (*p_env)->ExceptionClear(p_env);
-        }
-        fid = (*p_env)->GetFieldID(p_env, clz, "mNativeSurface", "I");
-        if (fid == NULL) {
-            jthrowable exp = (*p_env)->ExceptionOccurred(p_env);
-            if (exp) {
-                (*p_env)->DeleteLocalRef(p_env, exp);
-                (*p_env)->ExceptionClear(p_env);
-            }
-        }
-    }
-    if (fid != NULL)
-        native_surface = (void*)(*p_env)->GetIntField(p_env, surf, fid);
-    (*p_env)->DeleteLocalRef(p_env, clz);
-
-    return native_surface;
-}
-
-int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *configured)
-{
-    JNIEnv *p_env;
-    int ret;
-
-    if (!(p_env = jni_get_env(THREAD_NAME)))
-        return -1;
-
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui == NULL) {
-        pthread_mutex_unlock(&vout_android_lock);
-        return -1;
-    }
-
-    jclass clz = (*p_env)->GetObjectClass (p_env, vout_android_gui);
-    jmethodID methodId = (*p_env)->GetMethodID (p_env, clz, "configureSurface", "(Landroid/view/Surface;III)I");
-    ret = (*p_env)->CallIntMethod (p_env, vout_android_gui, methodId, jsurf, width, height, hal);
-    if (ret >= 0 && configured)
-        *configured = ret == 1;
-
-    (*p_env)->DeleteLocalRef(p_env, clz);
-
-    pthread_mutex_unlock(&vout_android_lock);
-    return ret == -1 ? -1 : 0;
-}
-
-void Java_org_videolan_libvlc_LibVLC_attachSurface(JNIEnv *env, jobject thiz, jobject surf, jobject gui) {
-    pthread_mutex_lock(&vout_android_lock);
-
-    if (vout_android_gui != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_gui);
-    if (vout_android_java_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_java_surf);
-    vout_android_gui = (*env)->NewGlobalRef(env, gui);
-    vout_android_java_surf = (*env)->NewGlobalRef(env, surf);
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-void Java_org_videolan_libvlc_LibVLC_detachSurface(JNIEnv *env, jobject thiz) {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_gui != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_gui);
-    if (vout_android_java_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_java_surf);
-    vout_android_gui = NULL;
-    vout_android_java_surf = NULL;
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-void Java_org_videolan_libvlc_LibVLC_attachSubtitlesSurface(JNIEnv *env, jobject thiz, jobject surf) {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_subtitles_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_subtitles_surf);
-    vout_android_subtitles_surf = (*env)->NewGlobalRef(env, surf);
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-void Java_org_videolan_libvlc_LibVLC_detachSubtitlesSurface(JNIEnv *env, jobject thiz) {
-    pthread_mutex_lock(&vout_android_lock);
-    if (vout_android_subtitles_surf != NULL)
-        (*env)->DeleteGlobalRef(env, vout_android_subtitles_surf);
-    vout_android_subtitles_surf = NULL;
-    pthread_mutex_unlock(&vout_android_lock);
-}
-
-static int mouse_x = -1;
-static int mouse_y = -1;
-static int mouse_button = -1;
-static int mouse_action = -1;
-
-void Java_org_videolan_libvlc_LibVLC_sendMouseEvent(JNIEnv* env, jobject thiz, jint action, jint button, jint x, jint y)
-{
-    mouse_x = x;
-    mouse_y = y;
-    mouse_button = button;
-    mouse_action = action;
-}
-
-void jni_getMouseCoordinates(int *action, int *button, int *x, int *y)
-{
-    *x = mouse_x;
-    *y = mouse_y;
-    *button = mouse_button;
-    *action = mouse_action;
-
-    mouse_button = mouse_action = mouse_x = mouse_y = -1;
-}
diff --git a/libvlc/jni/vout.h b/libvlc/jni/vout.h
deleted file mode 100644
index c3d4fd7..0000000
--- a/libvlc/jni/vout.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*****************************************************************************
- * vout.h
- *****************************************************************************
- * Copyright © 2011-2013 VLC authors and VideoLAN
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-#ifndef LIBVLCJNI_VOUT_H
-#define LIBVLCJNI_VOUT_H
-
-/* vout lock initialized in vout.c */
-pthread_mutex_t vout_android_lock;
-pthread_cond_t vout_android_surf_attached;
-
-#endif // LIBVLCJNI_VOUT_H
diff --git a/libvlc/src/org/videolan/libvlc/AWindow.java b/libvlc/src/org/videolan/libvlc/AWindow.java
new file mode 100644
index 0000000..b041e76
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/AWindow.java
@@ -0,0 +1,459 @@
+/*****************************************************************************
+ * class AWindow.java
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+package org.videolan.libvlc;
+
+import android.annotation.TargetApi;
+import android.graphics.PixelFormat;
+import android.graphics.SurfaceTexture;
+import android.os.Build;
+import android.os.Handler;
+import android.os.Looper;
+import android.support.annotation.MainThread;
+import android.util.Log;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.TextureView;
+
+import org.videolan.libvlc.util.AndroidUtil;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+class AWindow implements IAWindowNativeHandler, IVLCVout {
+    private static final int ID_VIDEO = 0;
+    private static final int ID_SUBTITLES = 1;
+    private static final int ID_MAX = 2;
+    private final String TAG = "AWindow";
+
+    protected interface SurfaceCallback {
+        @MainThread
+        void onSurfacesCreated(AWindow vout);
+        @MainThread
+        void onSurfacesDestroyed(AWindow vout);
+    }
+
+    private class SurfaceHelper {
+        private final int mId;
+        private final SurfaceView mSurfaceView;
+        private final TextureView mTextureView;
+        private final SurfaceHolder mSurfaceHolder;
+        private Surface mSurface;
+
+        private SurfaceHelper(int id, SurfaceView surfaceView) {
+            mId = id;
+            mTextureView = null;
+            mSurfaceView = surfaceView;
+            mSurfaceHolder = mSurfaceView != null ? mSurfaceView.getHolder() : null;
+            if (mId == ID_SUBTITLES) {
+                mSurfaceView.setZOrderMediaOverlay(true);
+                mSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
+            }
+        }
+
+        private SurfaceHelper(int id, TextureView textureView) {
+            mId = id;
+            mSurfaceView = null;
+            mSurfaceHolder = null;
+            mTextureView = textureView;
+            if (mId == ID_SUBTITLES) {
+                //TODO
+            }
+        }
+
+        private void setSurface(Surface surface) {
+            boolean surfaceValid = surface.isValid();
+            if (surfaceValid && mSurface == null) {
+                mSurface = surface;
+                setNativeSurface(mId, mSurface);
+                onSurfaceCreated();
+            }
+        }
+
+        private void attachSurfaceView() {
+            mSurfaceHolder.addCallback(mSurfaceHolderCallback);
+            setSurface(mSurfaceHolder.getSurface());
+        }
+
+        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+        private void attachTextureView() {
+            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
+            setSurface(new Surface(mTextureView.getSurfaceTexture()));
+        }
+
+        public void attach() {
+            if (mSurfaceView != null) {
+                attachSurfaceView();
+            } else {
+                attachTextureView();
+            }
+        }
+
+        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+        private void releaseSurfaceTexture() {
+            if (mTextureView != null)
+                mTextureView.setSurfaceTextureListener(null);
+        }
+
+        public void release() {
+            mSurface = null;
+            setNativeSurface(mId, null);
+            if (mSurfaceHolder != null)
+                mSurfaceHolder.removeCallback(mSurfaceHolderCallback);
+            releaseSurfaceTexture();
+        }
+
+        public boolean isReady() {
+            return mSurfaceView == null || mSurface != null;
+        }
+
+        public Surface getSurface() {
+            return mSurface;
+        }
+
+        public SurfaceHolder getSurfaceHolder() {
+            return mSurfaceHolder;
+        }
+
+        private final SurfaceHolder.Callback mSurfaceHolderCallback = new SurfaceHolder.Callback() {
+            @Override
+            public void surfaceCreated(SurfaceHolder holder) {
+                if (holder != mSurfaceHolder)
+                    throw new IllegalStateException("holders are different");
+                setSurface(holder.getSurface());
+            }
+
+            @Override
+            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            }
+
+            @Override
+            public void surfaceDestroyed(SurfaceHolder holder) {
+                onSurfaceDestroyed();
+            }
+        };
+
+        @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+        private TextureView.SurfaceTextureListener createSurfaceTextureListener() {
+            return new TextureView.SurfaceTextureListener() {
+                @Override
+                public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int width, int height) {
+                    setSurface(new Surface(surfaceTexture));
+                }
+
+                @Override
+                public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
+
+                }
+
+                @Override
+                public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
+                    onSurfaceDestroyed();
+                    return true;
+                }
+
+                @Override
+                public void onSurfaceTextureUpdated(SurfaceTexture surface) {
+                }
+            };
+        }
+
+        private final TextureView.SurfaceTextureListener mSurfaceTextureListener =
+                AndroidUtil.isICSOrLater() ? createSurfaceTextureListener() : null;
+    }
+
+    private final SurfaceHelper[] mSurfaceHelpers;
+
+    private final SurfaceCallback mSurfaceCallback;
+    private final AtomicBoolean mSurfacesReady = new AtomicBoolean(false);
+    private boolean mViewsAttached = false;
+    private IVLCVout.Callback mIAndroidWindowCallback = null;
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private Object mNativeLock = new Object();
+    /* synchronized Surfaces accessed by an other thread from JNI */
+    private final Surface[] mSurfaces;
+    private long mCallbackNativeHandle = 0;
+    private int mMouseAction = -1, mMouseButton = -1, mMouseX = -1, mMouseY = -1;
+    private int mWindowWidth = -1, mWindowHeight = -1;
+
+    protected AWindow(SurfaceCallback surfaceCallback) {
+        mSurfaceCallback = surfaceCallback;
+        mSurfaceHelpers = new SurfaceHelper[ID_MAX];
+        mSurfaceHelpers[ID_VIDEO] = null;
+        mSurfaceHelpers[ID_SUBTITLES] = null;
+        mSurfaces = new Surface[ID_MAX];
+        mSurfaces[ID_VIDEO] = null;
+        mSurfaces[ID_SUBTITLES] = null;
+    }
+
+    private void setView(int id, SurfaceView view) {
+        if (mViewsAttached)
+            throw new IllegalStateException("Can't set view when already attached");
+        if (view == null)
+            throw new NullPointerException("view is null");
+        final SurfaceHelper surfaceHelper = mSurfaceHelpers[id];
+        if (surfaceHelper != null)
+            surfaceHelper.release();
+
+        mSurfaceHelpers[id] = new SurfaceHelper(id, view);
+    }
+
+    private void setView(int id, TextureView view) {
+        if (!AndroidUtil.isICSOrLater())
+            throw new IllegalArgumentException("TextureView not implemented in this android version");
+        if (mViewsAttached)
+            throw new IllegalStateException("Can't set view when already attached");
+        if (view == null)
+            throw new NullPointerException("view is null");
+        final SurfaceHelper surfaceHelper = mSurfaceHelpers[id];
+        if (surfaceHelper != null)
+            surfaceHelper.release();
+
+        mSurfaceHelpers[id] = new SurfaceHelper(id, view);
+    }
+
+    @Override
+    @MainThread
+    public void setVideoView(SurfaceView videoSurface) {
+        setView(ID_VIDEO, videoSurface);
+    }
+
+    @Override
+    @MainThread
+    public void setVideoView(TextureView videoTexture) {
+        setView(ID_VIDEO, videoTexture);
+    }
+
+    @Override
+    @MainThread
+    public void setSubtitlesView(SurfaceView videoSurface) {
+        setView(ID_SUBTITLES, videoSurface);
+    }
+
+    @Override
+    @MainThread
+    public void setSubtitlesView(TextureView videoTexture) {
+        setView(ID_SUBTITLES, videoTexture);
+    }
+
+    @Override
+    @MainThread
+    public void attachViews() {
+        if (mViewsAttached || mSurfaceHelpers[ID_VIDEO] == null)
+            throw new IllegalStateException("already attached or video view not configured");
+        for (int id = 0; id < ID_MAX; ++id) {
+            final SurfaceHelper surfaceHelper = mSurfaceHelpers[id];
+            if (surfaceHelper != null)
+                surfaceHelper.attach();
+        }
+        mViewsAttached = true;
+    }
+
+    @Override
+    @MainThread
+    public void detachViews() {
+        if (!mViewsAttached)
+            return;
+        mSurfacesReady.set(false);
+        for (int id = 0; id < ID_MAX; ++id) {
+            final SurfaceHelper surfaceHelper = mSurfaceHelpers[id];
+            if (surfaceHelper != null)
+                surfaceHelper.release();
+            mSurfaceHelpers[id] = null;
+        }
+        mViewsAttached = false;
+        if (mSurfaceCallback != null)
+            mSurfaceCallback.onSurfacesDestroyed(this);
+    }
+
+    @Override
+    @MainThread
+    public boolean areViewsAttached() {
+        return mViewsAttached;
+    }
+
+    @MainThread
+    private void onSurfaceCreated() {
+        if (mSurfacesReady.get())
+            throw new IllegalArgumentException("callback already called");
+
+        final SurfaceHelper videoHelper = mSurfaceHelpers[ID_VIDEO];
+        final SurfaceHelper subtitlesHelper = mSurfaceHelpers[ID_SUBTITLES];
+        if (videoHelper == null)
+            throw new NullPointerException("videoHelper shouldn't be null here");
+
+        boolean ready = false;
+        if (videoHelper.isReady() && (subtitlesHelper == null || subtitlesHelper.isReady()))
+            ready = true;
+        mSurfacesReady.set(ready);
+        if (mSurfaceCallback != null && ready)
+            mSurfaceCallback.onSurfacesCreated(this);
+    }
+
+    @MainThread
+    private void onSurfaceDestroyed() {
+        detachViews();
+    }
+
+    protected boolean areSurfacesWaiting() {
+        return !mSurfacesReady.get();
+    }
+
+    @Override
+    public void sendMouseEvent(int action, int button, int x, int y) {
+        synchronized (mNativeLock) {
+            if (mCallbackNativeHandle != 0)
+                nativeOnMouseEvent(mCallbackNativeHandle, action, button, x, y);
+            else {
+                mMouseAction = action;
+                mMouseButton = button;
+                mMouseX = x;
+                mMouseY = y;
+            }
+        }
+    }
+
+    @Override
+    public void setWindowSize(int width, int height) {
+        synchronized (mNativeLock) {
+            if (mCallbackNativeHandle != 0)
+                nativeOnWindowSize(mCallbackNativeHandle, width, height);
+            else {
+                mWindowWidth = width;
+                mWindowHeight = height;
+            }
+        }
+    }
+
+    @Override
+    public boolean setCallback(long nativeHandle) {
+        synchronized (mNativeLock) {
+            if (mCallbackNativeHandle != 0 && nativeHandle != 0)
+                return false;
+            mCallbackNativeHandle = nativeHandle;
+            if (mCallbackNativeHandle != 0) {
+                if (mMouseAction != -1)
+                    nativeOnMouseEvent(mCallbackNativeHandle, mMouseAction, mMouseButton, mMouseX, mMouseY);
+                if (mWindowWidth != -1 && mWindowHeight != -1)
+                    nativeOnWindowSize(mCallbackNativeHandle, mWindowWidth, mWindowHeight);
+            }
+            mMouseAction = mMouseButton = mMouseX = mMouseY = -1;
+            mWindowWidth = mWindowHeight = -1;
+        }
+        return true;
+    }
+
+    private void setNativeSurface(int id, Surface surface) {
+        synchronized (mNativeLock) {
+            mSurfaces[id] = surface;
+        }
+    }
+
+    private Surface getNativeSurface(int id) {
+        synchronized (mNativeLock) {
+            return mSurfaces[id];
+        }
+    }
+
+    @Override
+    public Surface getVideoSurface() {
+        return getNativeSurface(ID_VIDEO);
+    }
+
+    @Override
+    public Surface getSubtitlesSurface() {
+        return getNativeSurface(ID_SUBTITLES);
+    }
+
+    @Override
+    public boolean setBuffersGeometry(final Surface surface, final int width, final int height, final int format) {
+        if (AndroidUtil.isICSOrLater())
+            return false;
+        if (width * height == 0)
+            return false;
+        Log.d(TAG, "configureSurface: " + width + "x" + height);
+
+        class Cond {
+            private boolean configured;
+        }
+        final Cond cond = new Cond();
+
+        final Handler handler = new Handler(Looper.getMainLooper());
+        handler.post(new Runnable() {
+
+            private SurfaceHelper getSurfaceHelper(Surface surface) {
+                for (int id = 0; id < ID_MAX; ++id) {
+                    final SurfaceHelper surfaceHelper = mSurfaceHelpers[id];
+                    if (surfaceHelper != null && surfaceHelper.getSurface() == surface)
+                        return surfaceHelper;
+                }
+                return null;
+            }
+
+            @Override
+            public void run() {
+                final SurfaceHelper surfaceHelper = getSurfaceHelper(surface);
+                final SurfaceHolder surfaceHolder = surfaceHelper != null ? surfaceHelper.getSurfaceHolder() : null;
+
+                if (surfaceHolder != null) {
+                    if (surfaceHolder.getSurface().isValid()) {
+                        if (format != 0)
+                            surfaceHolder.setFormat(format);
+                        surfaceHolder.setFixedSize(width, height);
+                    }
+                }
+
+                synchronized (cond) {
+                    cond.configured = true;
+                    cond.notifyAll();
+                }
+            }
+        });
+
+        try {
+            synchronized (cond) {
+                while (!cond.configured)
+                    cond.wait();
+            }
+        } catch (InterruptedException e) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public void setCallback(IVLCVout.Callback callback) {
+        mIAndroidWindowCallback = callback;
+    }
+
+    @Override
+    public void setWindowLayout(final int width, final int height, final int visibleWidth, final int visibleHeight, final int sarNum, final int sarDen) {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                if (mIAndroidWindowCallback != null)
+                    mIAndroidWindowCallback.onNewLayout(AWindow.this, width, height, visibleWidth, visibleHeight, sarNum, sarDen);
+            }
+        });
+    }
+    public native void nativeOnMouseEvent(long nativeHandle, int action, int button, int x, int y);
+    public native void nativeOnWindowSize(long nativeHandle, int width, int height);
+    public native void nativeOnSurfacesReleased(long nativeHandle);
+}
\ No newline at end of file
diff --git a/libvlc/src/org/videolan/libvlc/IAWindowNativeHandler.java b/libvlc/src/org/videolan/libvlc/IAWindowNativeHandler.java
new file mode 100644
index 0000000..51c25ee
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/IAWindowNativeHandler.java
@@ -0,0 +1,97 @@
+/*****************************************************************************
+ * public class IAWindowNativeHandler.java
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+package org.videolan.libvlc;
+
+import android.view.Surface;
+
+interface IAWindowNativeHandler {
+    /**
+     * Callback called from {@link IVLCVout#sendMouseEvent}.
+     *
+     * @param nativeHandle handle passed by {@link #setCallback}.
+     * @param action see ACTION_* in {@link android.view.MotionEvent}.
+     * @param button see BUTTON_* in {@link android.view.MotionEvent}.
+     * @param x x coordinate.
+     * @param y y coordinate.
+     */
+    void nativeOnMouseEvent(long nativeHandle, int action, int button, int x, int y);
+
+    /**
+     * Callback called from {@link IVLCVout#setWindowSize}.
+     *
+     * @param nativeHandle handle passed by {@link #setCallback}.
+     * @param width width of the window.
+     * @param height height of the window.
+     */
+    void nativeOnWindowSize(long nativeHandle, int width, int height);
+
+    /**
+     * Get the valid Video surface.
+     *
+     * @return can be null if the surface was destroyed.
+     */
+    @SuppressWarnings("unused") /* Used by JNI */
+    Surface getVideoSurface();
+
+    /**
+     * Get the valid Subtitles surface.
+     *
+     * @return can be null if the surface was destroyed.
+     */
+    @SuppressWarnings("unused") /* Used by JNI */
+    Surface getSubtitlesSurface();
+
+    /**
+     * Set a callback in order to receive {@link #nativeOnMouseEvent} and {@link #nativeOnWindowSize} events.
+     *
+     * @param nativeHandle native Handle passed by {@link #nativeOnMouseEvent} and {@link #nativeOnWindowSize}
+     * @return true if callback was successfully registered
+     */
+    @SuppressWarnings("unused") /* Used by JNI */
+    boolean setCallback(long nativeHandle);
+
+    /**
+     * This method is only used for ICS and before since ANativeWindow_setBuffersGeometry doesn't work before.
+     * It is synchronous.
+     *
+     * @param surface surface returned by getVideoSurface or getSubtitlesSurface
+     * @param width surface width
+     * @param height surface height
+     * @param format color format (or PixelFormat)
+     * @return true if buffersGeometry were set (only before ICS)
+     */
+    @SuppressWarnings("unused") /* Used by JNI */
+    boolean setBuffersGeometry(Surface surface, int width, int height, int format);
+
+    /**
+     * Set the window Layout.
+     * This call will result of {@link IVLCVout.Callback#onNewLayout} being called from the main thread.
+     *
+     * @param width Frame width
+     * @param height Frame height
+     * @param visibleWidth Visible frame width
+     * @param visibleHeight Visible frame height
+     * @param sarNum Surface aspect ratio numerator
+     * @param sarDen Surface aspect ratio denominator
+     */
+    @SuppressWarnings("unused") /* Used by JNI */
+    void setWindowLayout(int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen);
+}
\ No newline at end of file
diff --git a/libvlc/src/org/videolan/libvlc/IVLCVout.java b/libvlc/src/org/videolan/libvlc/IVLCVout.java
new file mode 100644
index 0000000..61a475a
--- /dev/null
+++ b/libvlc/src/org/videolan/libvlc/IVLCVout.java
@@ -0,0 +1,123 @@
+/*****************************************************************************
+ * public class IVLCVout.java
+ *****************************************************************************
+ * Copyright © 2015 VLC authors, VideoLAN and VideoLabs
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation; either version 2.1 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+package org.videolan.libvlc;
+
+import android.annotation.TargetApi;
+import android.os.Build;
+import android.support.annotation.MainThread;
+import android.view.SurfaceView;
+import android.view.TextureView;
+
+ at SuppressWarnings("unused")
+public interface IVLCVout {
+    interface Callback {
+        /**
+         * This callback is called when the native vout call request a new Layout.
+         *
+         * @param vlcVout vlcVout
+         * @param width Frame width
+         * @param height Frame height
+         * @param visibleWidth Visible frame width
+         * @param visibleHeight Visible frame height
+         * @param sarNum Surface aspect ratio numerator
+         * @param sarDen Surface aspect ratio denominator
+         */
+        @MainThread
+        void onNewLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen);
+    }
+
+    /**
+     * Set a surfaceView used for video out.
+     * @see #attachViews()
+     */
+    @MainThread
+    void setVideoView(SurfaceView videoSurface);
+
+    /**
+     * Set a TextureView used for video out.
+     * @see #attachViews()
+     */
+    @MainThread
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+    void setVideoView(TextureView videoTexture);
+
+    /**
+     * Set a surfaceView used for subtitles out.
+     * @see #attachViews()
+     */
+    @MainThread
+    void setSubtitlesView(SurfaceView subtitlesSurface);
+
+    /**
+     * Set a TextureView used for subtitles out.
+     * @see #attachViews()
+     */
+    @MainThread
+    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
+    void setSubtitlesView(TextureView subtitlesSurface);
+
+    /**
+     * Attach views previously set by setVideoView and setSubtitlesView.
+     * @see #setVideoView(SurfaceView)
+     * @see #setVideoView(TextureView)
+     * @see #setSubtitlesView(SurfaceView)
+     * @see #setSubtitlesView(TextureView)
+     */
+    @MainThread
+    void attachViews();
+
+    /**
+     * Detach views previously attached.
+     * This will be called automatically when surfaces are destroyed.
+     */
+    @MainThread
+    void detachViews();
+
+    /**
+     * Return true if views are attached. If surfaces were destroyed, this will return false.
+     */
+    @MainThread
+    boolean areViewsAttached();
+
+    /**
+     * Set a callback to receive {@link Callback#onNewLayout} events.
+     */
+    @MainThread
+    void setCallback(Callback callback);
+
+    /**
+     * Send a mouse event to the native vout.
+     * @param action see ACTION_* in {@link android.view.MotionEvent}.
+     * @param button see BUTTON_* in {@link android.view.MotionEvent}.
+     * @param x x coordinate.
+     * @param y y coordinate.
+     */
+    @MainThread
+    void sendMouseEvent(int action, int button, int x, int y);
+
+    /**
+     * Send the the window size to the native vout.
+     * @param width width of the window.
+     * @param height height of the window.
+     */
+    @MainThread
+    void setWindowSize(int width, int height);
+}
diff --git a/libvlc/src/org/videolan/libvlc/IVideoPlayer.java b/libvlc/src/org/videolan/libvlc/IVideoPlayer.java
deleted file mode 100644
index 08ac9ed..0000000
--- a/libvlc/src/org/videolan/libvlc/IVideoPlayer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*****************************************************************************
- * IVideoPlayer.java
- *****************************************************************************
- * Copyright © 2010-2013 VLC authors and VideoLAN
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
- *****************************************************************************/
-
-package org.videolan.libvlc;
-
-import android.view.Surface;
-
-public interface IVideoPlayer {
-    /**
-     * This method is called by native vout to request a new layout.
-     * @param width Frame width
-     * @param height Frame height
-     * @param visible_width Visible frame width
-     * @param visible_height Visible frame height
-     * @param sar_num Surface aspect ratio numerator
-     * @param sar_den Surface aspect ratio denominator
-     */
-    void setSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den);
-
-    /**
-     * This method is only used for Gingerbread and before.
-     * It is called by native vout to request a surface size and hal.
-     * It is synchronous.
-     * @param surface
-     * @param width surface width
-     * @param height surface height
-     * @param hal color format (or PixelFormat)
-     * @return -1 if you should'nt not use this call, 1 if surface size is changed, 0 otherwise
-     */
-    int configureSurface(Surface surface, int width, int height, int hal);
-
-
-    /**
-     * Called in case of hardware acceleration error
-     */
-    public void eventHardwareAccelerationError();
-}
diff --git a/libvlc/src/org/videolan/libvlc/LibVLC.java b/libvlc/src/org/videolan/libvlc/LibVLC.java
index db64267..1f6d85d 100644
--- a/libvlc/src/org/videolan/libvlc/LibVLC.java
+++ b/libvlc/src/org/videolan/libvlc/LibVLC.java
@@ -40,13 +40,9 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
     /** Native crash handler */
     private static OnNativeCrashListener sOnNativeCrashListener;
 
-    /** Check in libVLC already initialized otherwise crash */
-    public native void attachSurface(Surface surface, IVideoPlayer player);
-
-    public native void detachSurface();
-
-    public native void attachSubtitlesSurface(Surface surface);
-    public native void detachSubtitlesSurface();
+    public interface HardwareAccelerationError {
+        void eventHardwareAccelerationError(); // TODO REMOVE
+    }
 
     /**
      * Create a LibVLC withs options
@@ -95,11 +91,10 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
         this(null);
     }
 
-    /**
-     * Give to LibVLC the surface to draw the video.
-     * @param f the surface to draw
-     */
-    public native void setSurface(Surface f);
+    public void setOnHardwareAccelerationError(HardwareAccelerationError error) {
+        nativeSetOnHardwareAccelerationError(error);
+    }
+    private native void nativeSetOnHardwareAccelerationError(HardwareAccelerationError error);
 
     /**
      * Get the libVLC version
@@ -119,8 +114,6 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
      */
     public native String changeset();
 
-    public native static void sendMouseEvent( int action, int button, int x, int y);
-
     private native void setEventHandler(EventHandler eventHandler);
 
     private native void detachEventHandler();
@@ -149,8 +142,6 @@ public class LibVLC extends VLCObject<LibVLC.Event> {
             sOnNativeCrashListener.onNativeCrash();
     }
 
-    public native int setWindowSize(int width, int height);
-
     /* JNI */
     private native void nativeNew(String[] options);
     private native void nativeRelease();
diff --git a/libvlc/src/org/videolan/libvlc/MediaPlayer.java b/libvlc/src/org/videolan/libvlc/MediaPlayer.java
index c4c40f5..92478d7 100644
--- a/libvlc/src/org/videolan/libvlc/MediaPlayer.java
+++ b/libvlc/src/org/videolan/libvlc/MediaPlayer.java
@@ -24,8 +24,7 @@ package org.videolan.libvlc;
 
 import java.util.Map;
 
-
-public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
+public class MediaPlayer extends VLCObject<MediaPlayer.Event> implements AWindow.SurfaceCallback {
 
     public static class Event extends VLCEvent {
         //public static final int MediaChanged         = 0x100;
@@ -77,6 +76,9 @@ public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
     }
 
     private Media mMedia = null;
+    private boolean mPlaying = false;
+    private boolean mPlayRequested = false;
+    private final AWindow mWindow = new AWindow(this);
 
     /**
      * Create an empty MediaPlayer
@@ -84,7 +86,7 @@ public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
      * @param libVLC
      */
     public MediaPlayer(LibVLC libVLC) {
-        nativeNewFromLibVlc(libVLC);
+        nativeNewFromLibVlc(libVLC, mWindow);
     }
 
     /**
@@ -97,7 +99,15 @@ public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
             throw new IllegalArgumentException("Media is null or released");
         mMedia = media;
         mMedia.retain();
-        nativeNewFromMedia(mMedia);
+        nativeNewFromMedia(mMedia, mWindow);
+    }
+
+    /**
+     *
+     * @return
+     */
+    public IVLCVout getVLCVout() {
+        return mWindow;
     }
 
     /**
@@ -134,6 +144,12 @@ public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
      *
      */
     public synchronized void play() {
+        if (!mPlaying) {
+            mPlayRequested = true;
+            if (mWindow.areSurfacesWaiting())
+                return;
+        }
+        mPlaying = true;
         nativePlay();
     }
 
@@ -142,9 +158,24 @@ public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
      *
      */
     public synchronized void stop() {
+        mPlayRequested = false;
+        mPlaying = false;
         nativeStop();
     }
 
+
+    @Override
+    public synchronized void onSurfacesCreated(AWindow vout) {
+        if (!mPlaying && mPlayRequested)
+            play();
+    }
+
+    @Override
+    public synchronized void onSurfacesDestroyed(AWindow vout) {
+        if (mPlaying)
+            setVideoTrackEnabled(false);
+    }
+
     /**
      * Set if, and how, the video title will be shown when media is played
      *
@@ -305,8 +336,8 @@ public class MediaPlayer extends VLCObject<MediaPlayer.Event> {
     }
 
     /* JNI */
-    private native void nativeNewFromLibVlc(LibVLC libVLC);
-    private native void nativeNewFromMedia(Media media);
+    private native void nativeNewFromLibVlc(LibVLC libVLC, IAWindowNativeHandler window);
+    private native void nativeNewFromMedia(Media media, IAWindowNativeHandler window);
     private native void nativeRelease();
     private native void nativeSetMedia(Media media);
     private native void nativePlay();
diff --git a/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java b/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
index 9f558c3..abedfe0 100644
--- a/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
+++ b/vlc-android/src/org/videolan/vlc/gui/video/VideoPlayerActivity.java
@@ -36,7 +36,6 @@ import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.database.Cursor;
 import android.graphics.Color;
-import android.graphics.PixelFormat;
 import android.media.AudioManager;
 import android.media.AudioManager.OnAudioFocusChangeListener;
 import android.media.MediaRouter;
@@ -44,7 +43,6 @@ import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
-import android.os.Looper;
 import android.os.Message;
 import android.os.ParcelFileDescriptor;
 import android.preference.PreferenceManager;
@@ -71,8 +69,6 @@ import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.Surface;
-import android.view.SurfaceHolder;
-import android.view.SurfaceHolder.Callback;
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -96,12 +92,11 @@ import android.widget.TextView;
 import android.widget.Toast;
 
 import org.videolan.libvlc.EventHandler;
-import org.videolan.libvlc.IVideoPlayer;
+import org.videolan.libvlc.IVLCVout;
 import org.videolan.libvlc.LibVLC;
 import org.videolan.libvlc.Media;
 import org.videolan.libvlc.MediaPlayer;
 import org.videolan.libvlc.util.AndroidUtil;
-import org.videolan.libvlc.util.HWDecoderUtil;
 import org.videolan.vlc.BuildConfig;
 import org.videolan.vlc.MediaDatabase;
 import org.videolan.vlc.MediaWrapper;
@@ -138,7 +133,8 @@ import java.util.ArrayList;
 import java.util.Date;
 import java.util.Map;
 
-public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlayer, GestureDetector.OnDoubleTapListener, IDelayController {
+public class VideoPlayerActivity extends AppCompatActivity implements IVLCVout.Callback,
+        GestureDetector.OnDoubleTapListener, IDelayController, LibVLC.HardwareAccelerationError {
 
     public final static String TAG = "VLC/VideoPlayerActivity";
 
@@ -161,12 +157,8 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     public final static int RESULT_VIDEO_TRACK_LOST = RESULT_FIRST_USER + 4;
 
     private PlaybackServiceClient mClient;
-    private SurfaceView mSurfaceView;
-    private SurfaceView mSubtitlesSurfaceView;
-    private SurfaceHolder mSurfaceHolder;
-    private SurfaceHolder mSubtitlesSurfaceHolder;
-    private Surface mSurface = null;
-    private Surface mSubtitleSurface = null;
+    private SurfaceView mSurfaceView = null;
+    private SurfaceView mSubtitlesSurfaceView = null;
     private FrameLayout mSurfaceFrame;
     private MediaRouter mMediaRouter;
     private MediaRouter.SimpleCallback mMediaRouterCallback;
@@ -197,12 +189,11 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     private static final int OVERLAY_INFINITE = -1;
     private static final int FADE_OUT = 1;
     private static final int SHOW_PROGRESS = 2;
-    private static final int SURFACE_LAYOUT = 3;
-    private static final int FADE_OUT_INFO = 4;
-    private static final int START_PLAYBACK = 5;
-    private static final int AUDIO_SERVICE_CONNECTION_FAILED = 6;
-    private static final int RESET_BACK_LOCK = 7;
-    private static final int CHECK_VIDEO_TRACKS = 8;
+    private static final int FADE_OUT_INFO = 3;
+    private static final int START_PLAYBACK = 4;
+    private static final int AUDIO_SERVICE_CONNECTION_FAILED = 5;
+    private static final int RESET_BACK_LOCK = 6;
+    private static final int CHECK_VIDEO_TRACKS = 7;
     private boolean mDragging;
     private boolean mShowing;
     private DelayState mDelay = DelayState.OFF;
@@ -319,10 +310,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     private OnLayoutChangeListener mOnLayoutChangeListener;
     private AlertDialog mAlertDialog;
 
-    private boolean mPlaybackServiceReady = false;
-    private boolean mSurfaceReady = false;
-    private boolean mSubtitleSurfaceReady = false;
-
     private boolean mHasHdmiAudio = false;
 
     private static LibVLC LibVLC() {
@@ -445,22 +432,9 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         mMediaListPlayer = MediaWrapperListPlayer.getInstance();
 
         mSurfaceView = (SurfaceView) findViewById(R.id.player_surface);
-        mSurfaceHolder = mSurfaceView.getHolder();
-        mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);
-
         mSubtitlesSurfaceView = (SurfaceView) findViewById(R.id.subtitles_surface);
-        mSubtitlesSurfaceHolder = mSubtitlesSurfaceView.getHolder();
-        mSubtitlesSurfaceView.setZOrderMediaOverlay(true);
-        mSubtitlesSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
 
-        if (!HWDecoderUtil.HAS_SUBTITLES_SURFACE) {
-            mSubtitlesSurfaceView.setVisibility(View.GONE);
-            mSubtitleSurfaceReady = true;
-        }
-        if (mPresentation == null) {
-            mSurfaceHolder.addCallback(mSurfaceCallback);
-            mSubtitlesSurfaceHolder.addCallback(mSubtitlesSurfaceCallback);
-        }
+        mSurfaceFrame = (FrameLayout) findViewById(R.id.player_surface_frame);
 
         mSeekbar = (SeekBar) findViewById(R.id.player_overlay_seekbar);
 
@@ -583,7 +557,7 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     @Override
     public void onConfigurationChanged(Configuration newConfig) {
         if (!AndroidUtil.isHoneycombOrLater())
-            setSurfaceLayout(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
+            changeSurfaceLayout();
         super.onConfigurationChanged(newConfig);
         resetHudLayout();
     }
@@ -674,9 +648,21 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     @TargetApi(Build.VERSION_CODES.HONEYCOMB)
     private void startPlayback() {
         /* start playback only when audio service and both surfaces are ready */
-        if (mPlaybackStarted || !mPlaybackServiceReady || !mSurfaceReady || !mSubtitleSurfaceReady)
+        if (mPlaybackStarted || !mClient.isConnected())
             return;
 
+        LibVLC().setOnHardwareAccelerationError(this);
+        final IVLCVout vlcVout = MediaPlayer().getVLCVout();
+        if (mPresentation == null) {
+            vlcVout.setVideoView(mSurfaceView);
+            vlcVout.setSubtitlesView(mSubtitlesSurfaceView);
+        } else {
+            vlcVout.setVideoView(mPresentation.mSurfaceView);
+            vlcVout.setSubtitlesView(mPresentation.mSubtitlesSurfaceView);
+        }
+        vlcVout.setCallback(this);
+        vlcVout.attachViews();
+
         mPlaybackStarted = true;
 
         if (AndroidUtil.isHoneycombOrLater()) {
@@ -686,13 +672,13 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
                     public void onLayoutChange(View v, int left, int top, int right,
                                                int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
                         if (left != oldLeft || top != oldTop || right != oldRight || bottom != oldBottom)
-                            setSurfaceLayout(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
+                            changeSurfaceLayout();
                     }
                 };
             }
             mSurfaceFrame.addOnLayoutChangeListener(mOnLayoutChangeListener);
         }
-        setSurfaceLayout(mVideoWidth, mVideoHeight, mVideoVisibleWidth, mVideoVisibleHeight, mSarNum, mSarDen);
+        changeSurfaceLayout();
 
         if (mMediaRouter != null) {
             // Listen for changes to media routes.
@@ -724,6 +710,8 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         if (!mPlaybackStarted)
             return;
 
+        LibVLC().setOnHardwareAccelerationError(null);
+
         mPlaybackStarted = false;
 
         if(mSwitchingView) {
@@ -757,6 +745,10 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
             time -= 5000; // go back 5 seconds, to compensate loading time
         MediaPlayer().stop();
 
+        final IVLCVout vlcVout = MediaPlayer().getVLCVout();
+        vlcVout.detachViews();
+        vlcVout.setCallback(null);
+
         SharedPreferences.Editor editor = mSettings.edit();
         // Save position
         if (time >= 0 && mCanSeek) {
@@ -1081,22 +1073,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     }
 
     @Override
-    public void setSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den) {
-        if (width * height == 0)
-            return;
-
-        // store video size
-        mVideoHeight = height;
-        mVideoWidth = width;
-        mVideoVisibleHeight = visible_height;
-        mVideoVisibleWidth  = visible_width;
-        mSarNum = sar_num;
-        mSarDen = sar_den;
-        Message msg = mHandler.obtainMessage(SURFACE_LAYOUT);
-        mHandler.sendMessage(msg);
-    }
-
-    @Override
     public void showAudioDelaySetting() {
         mDelay = DelayState.AUDIO;
         showDelayControls();
@@ -1190,57 +1166,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         }
     }
 
-    private static class ConfigureSurfaceHolder {
-        private final Surface surface;
-        private boolean configured;
-
-        private ConfigureSurfaceHolder(Surface surface) {
-            this.surface = surface;
-        }
-    }
-
-    @Override
-    public int configureSurface(Surface surface, final int width, final int height, final int hal) {
-        if (AndroidUtil.isICSOrLater() || surface == null)
-            return -1;
-        if (width * height == 0)
-            return 0;
-        Log.d(TAG, "configureSurface: " + width +"x"+height);
-
-        final ConfigureSurfaceHolder holder = new ConfigureSurfaceHolder(surface);
-
-        final Handler handler = new Handler(Looper.getMainLooper());
-        handler.post(new Runnable() {
-            @Override
-            public void run() {
-                if (mSurface == holder.surface && mSurfaceHolder != null) {
-                    if (hal != 0)
-                        mSurfaceHolder.setFormat(hal);
-                    mSurfaceHolder.setFixedSize(width, height);
-                } else if (mSubtitleSurface == holder.surface && mSubtitlesSurfaceHolder != null) {
-                    if (hal != 0)
-                        mSubtitlesSurfaceHolder.setFormat(hal);
-                    mSubtitlesSurfaceHolder.setFixedSize(width, height);
-                }
-
-                synchronized (holder) {
-                    holder.configured = true;
-                    holder.notifyAll();
-                }
-            }
-        });
-
-        try {
-            synchronized (holder) {
-                while (!holder.configured)
-                    holder.wait();
-            }
-        } catch (InterruptedException e) {
-            return 0;
-        }
-        return 1;
-    }
-
     /**
      * Lock screen rotation
      */
@@ -1536,9 +1461,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
                         sendMessageDelayed(msg, 1000 - (pos % 1000));
                     }
                     break;
-                case SURFACE_LAYOUT:
-                    activity.changeSurfaceLayout();
-                    break;
                 case FADE_OUT_INFO:
                     activity.fadeOutInfo();
                     break;
@@ -1607,6 +1529,7 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         mAlertDialog.show();
     }
 
+    @Override
     public void eventHardwareAccelerationError() {
         EventHandler em = EventHandler.getInstance();
         em.callback(EventHandler.HardwareAccelerationError, new Bundle());
@@ -1645,7 +1568,8 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     }
 
     private void handleVout(Message msg) {
-        if (msg.getData().getInt("data") == 0 && !mEndReached) {
+        final IVLCVout vlcVout = MediaPlayer().getVLCVout();
+        if (vlcVout.areViewsAttached() && msg.getData().getInt("data") == 0 && !mEndReached) {
             /* Video track lost, open in audio mode */
             Log.i(TAG, "Video track lost, switching to audio");
             mSwitchingView = true;
@@ -1687,8 +1611,8 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
             sw = mPresentation.getWindow().getDecorView().getWidth();
             sh = mPresentation.getWindow().getDecorView().getHeight();
         }
-        if (LibVLC() != null)
-            LibVLC().setWindowSize(sw, sh);
+        final IVLCVout vlcVout = MediaPlayer().getVLCVout();
+        vlcVout.setWindowSize(sw, sh);
 
         double dw = sw, dh = sh;
         boolean isPortrait;
@@ -1780,7 +1704,8 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         lp.width  = (int) Math.ceil(dw * mVideoWidth / mVideoVisibleWidth);
         lp.height = (int) Math.ceil(dh * mVideoHeight / mVideoVisibleHeight);
         surface.setLayoutParams(lp);
-        subtitlesSurface.setLayoutParams(lp);
+        if (subtitlesSurface != null)
+            subtitlesSurface.setLayoutParams(lp);
 
         // set frame size (crop if necessary)
         lp = surfaceFrame.getLayoutParams();
@@ -1789,7 +1714,13 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         surfaceFrame.setLayoutParams(lp);
 
         surface.invalidate();
-        subtitlesSurface.invalidate();
+        if (subtitlesSurface != null)
+            subtitlesSurface.invalidate();
+    }
+
+    private void sendMouseEvent(int action, int button, int x, int y) {
+        final IVLCVout vlcVout = MediaPlayer().getVLCVout();
+        vlcVout.sendMouseEvent(action, button, x, y);
     }
 
     /**
@@ -1853,12 +1784,12 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
             // Seek
             mTouchX = event.getRawX();
             // Mouse events for the core
-            LibVLC.sendMouseEvent(MotionEvent.ACTION_DOWN, 0, xTouch, yTouch);
+            sendMouseEvent(MotionEvent.ACTION_DOWN, 0, xTouch, yTouch);
             break;
 
         case MotionEvent.ACTION_MOVE:
             // Mouse events for the core
-            LibVLC.sendMouseEvent(MotionEvent.ACTION_MOVE, 0, xTouch, yTouch);
+            sendMouseEvent(MotionEvent.ACTION_MOVE, 0, xTouch, yTouch);
 
             // No volume/brightness action if coef < 2 or a secondary display is connected
             //TODO : Volume action when a secondary display is connected
@@ -1885,7 +1816,7 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
 
         case MotionEvent.ACTION_UP:
             // Mouse events for the core
-            LibVLC.sendMouseEvent(MotionEvent.ACTION_UP, 0, xTouch, yTouch);
+            sendMouseEvent(MotionEvent.ACTION_UP, 0, xTouch, yTouch);
 
             if (mTouchAction == TOUCH_NONE) {
                 if (!mShowing) {
@@ -2325,67 +2256,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
     };
 
     /**
-     * attach and disattach surface to the lib
-     */
-    private final SurfaceHolder.Callback mSurfaceCallback = new Callback() {
-        @Override
-        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-            if(MediaPlayer() != null) {
-                final Surface newSurface = holder.getSurface();
-                if (mSurface != newSurface) {
-                    mSurface = newSurface;
-                    Log.d(TAG, "surfaceChanged: " + mSurface);
-                    LibVLC().attachSurface(mSurface, VideoPlayerActivity.this);
-                    mSurfaceReady = true;
-                    mHandler.sendEmptyMessage(START_PLAYBACK);
-                }
-            }
-        }
-
-        @Override
-        public void surfaceCreated(SurfaceHolder holder) {
-        }
-
-        @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {
-            Log.d(TAG, "surfaceDestroyed");
-            if(MediaPlayer() != null) {
-                mSurface = null;
-                LibVLC().detachSurface();
-                mSurfaceReady = false;
-            }
-        }
-    };
-
-    private final SurfaceHolder.Callback mSubtitlesSurfaceCallback = new Callback() {
-        @Override
-        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
-            if(MediaPlayer() != null) {
-                final Surface newSurface = holder.getSurface();
-                if (mSubtitleSurface != newSurface) {
-                    mSubtitleSurface = newSurface;
-                    LibVLC().attachSubtitlesSurface(mSubtitleSurface);
-                    mSubtitleSurfaceReady = true;
-                    mHandler.sendEmptyMessage(START_PLAYBACK);
-                }
-            }
-        }
-
-        @Override
-        public void surfaceCreated(SurfaceHolder holder) {
-        }
-
-        @Override
-        public void surfaceDestroyed(SurfaceHolder holder) {
-            if(MediaPlayer() != null) {
-                mSubtitleSurface = null;
-                LibVLC().detachSubtitlesSurface();
-                mSubtitleSurfaceReady = false;
-            }
-        }
-    };
-
-    /**
      * show overlay
      * @param forceCheck: adjust the timeout in function of playing state
      */
@@ -3045,8 +2915,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
 
         private SurfaceView mSurfaceView;
         private SurfaceView mSubtitlesSurfaceView;
-        private SurfaceHolder mSurfaceHolder;
-        private SurfaceHolder mSubtitlesSurfaceHolder;
         private FrameLayout mSurfaceFrame;
 
         public SecondaryDisplay(Context context, LibVLC libVLC, Display display) {
@@ -3062,7 +2930,7 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
             setContentView(R.layout.player_remote);
 
             mSurfaceView = (SurfaceView) findViewById(R.id.remote_player_surface);
-            mSurfaceHolder = mSurfaceView.getHolder();
+            mSubtitlesSurfaceView = (SurfaceView) findViewById(R.id.remote_subtitles_surface);
             mSurfaceFrame = (FrameLayout) findViewById(R.id.remote_player_surface_frame);
 
             VideoPlayerActivity activity = (VideoPlayerActivity)getOwnerActivity();
@@ -3071,16 +2939,6 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
                 return;
             }
 
-            mSurfaceHolder.addCallback(activity.mSurfaceCallback);
-
-            mSubtitlesSurfaceView = (SurfaceView) findViewById(R.id.remote_subtitles_surface);
-            mSubtitlesSurfaceHolder = mSubtitlesSurfaceView.getHolder();
-            mSubtitlesSurfaceView.setZOrderMediaOverlay(true);
-            mSubtitlesSurfaceHolder.setFormat(PixelFormat.TRANSLUCENT);
-            mSubtitlesSurfaceHolder.addCallback(activity.mSubtitlesSurfaceCallback);
-
-            if (!HWDecoderUtil.HAS_SUBTITLES_SURFACE)
-                mSubtitlesSurfaceView.setVisibility(View.GONE);
             Log.i(TAG, "Secondary display created");
         }
     }
@@ -3176,13 +3034,11 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
 
         @Override
         public void onConnected() {
-            mPlaybackServiceReady = true;
             mHandler.sendEmptyMessage(START_PLAYBACK);
         }
 
         @Override
         public void onDisconnected() {
-            mPlaybackServiceReady = false;
             mHandler.sendEmptyMessage(AUDIO_SERVICE_CONNECTION_FAILED);
         }
 
@@ -3202,4 +3058,19 @@ public class VideoPlayerActivity extends AppCompatActivity implements IVideoPlay
         public void onMediaPlayedRemoved(int index) {
         }
     };
+
+    @Override
+    public void onNewLayout(IVLCVout vlcVout, int width, int height, int visibleWidth, int visibleHeight, int sarNum, int sarDen) {
+        if (width * height == 0)
+            return;
+
+        // store video size
+        mVideoWidth = width;
+        mVideoHeight = height;
+        mVideoVisibleWidth  = visibleWidth;
+        mVideoVisibleHeight = visibleHeight;
+        mSarNum = sarNum;
+        mSarDen = sarDen;
+        changeSurfaceLayout();
+    }
 }
-- 
2.1.4



More information about the Android mailing list