android: add AWindowHandler and android_getEnv
authorThomas Guillem <thomas@gllm.fr>
Thu, 25 Jun 2015 11:52:54 +0000 (13:52 +0200)
committerThomas Guillem <thomas@gllm.fr>
Thu, 25 Jun 2015 17:08:26 +0000 (19:08 +0200)
android_getEnv: get a JNIEnv* from the Java VM passed via the "android-jvm"
option.

AWindowHandler: utility class that provide a way to get the Video / Subtitles
Java Surface or ANativeWindow.

14 files changed:
modules/audio_output/Makefile.am
modules/audio_output/audiotrack.c
modules/codec/Makefile.am
modules/codec/omxil/mediacodec.c
modules/codec/omxil/mediacodec.h
modules/codec/omxil/mediacodec_jni.c
modules/codec/omxil/mediacodec_ndk.c
modules/codec/omxil/omxil.c
modules/codec/omxil/omxil.h
modules/video_output/Makefile.am
modules/video_output/android/android_window.c
modules/video_output/android/nativewindow.c
modules/video_output/android/utils.c
modules/video_output/android/utils.h

index 589e5fe..366193b 100644 (file)
@@ -4,7 +4,8 @@ aout_LTLIBRARIES =
 libopensles_android_plugin_la_SOURCES = audio_output/opensles_android.c
 libopensles_android_plugin_la_LIBADD = $(LIBDL) $(LIBM)
 
-libandroid_audiotrack_plugin_la_SOURCES = audio_output/audiotrack.c
+libandroid_audiotrack_plugin_la_SOURCES = audio_output/audiotrack.c \
+       video_output/android/utils.c video_output/android/utils.h
 libandroid_audiotrack_plugin_la_CFLAGS = $(AM_CFLAGS)
 
 if HAVE_ANDROID
index 34e65c4..9dc4b9d 100644 (file)
@@ -33,6 +33,7 @@
 #include <vlc_common.h>
 #include <vlc_plugin.h>
 #include <vlc_aout.h>
+#include "../video_output/android/utils.h"
 
 #define MIN_AUDIOTRACK_BUFFER_US INT64_C(250000)  // 250ms
 #define MAX_AUDIOTRACK_BUFFER_US INT64_C(1000000) // 1000ms
@@ -131,7 +132,7 @@ vlc_module_begin ()
 vlc_module_end ()
 
 #define THREAD_NAME "android_audiotrack"
-extern JNIEnv *jni_get_env(const char *name);
+#define GET_ENV() android_getEnv( VLC_OBJECT(p_aout), THREAD_NAME )
 
 static struct
 {
@@ -200,26 +201,19 @@ static struct
 /* init all jni fields.
  * Done only one time during the first initialisation */
 static bool
-InitJNIFields( audio_output_t *p_aout )
+InitJNIFields( audio_output_t *p_aout, JNIEnv* env )
 {
     static vlc_mutex_t lock = VLC_STATIC_MUTEX;
     static int i_init_state = -1;
     bool ret;
     jclass clazz;
     jfieldID field;
-    JNIEnv* env = NULL;
 
     vlc_mutex_lock( &lock );
 
     if( i_init_state != -1 )
         goto end;
 
-    if (!(env = jni_get_env(THREAD_NAME)))
-    {
-        i_init_state = 0;
-        goto end;
-    }
-
 #define CHECK_EXCEPTION( what, critical ) do { \
     if( (*env)->ExceptionOccurred( env ) ) \
     { \
@@ -650,7 +644,7 @@ TimeGet( audio_output_t *p_aout, mtime_t *restrict p_delay )
     mtime_t i_audiotrack_us;
     JNIEnv *env;
 
-    if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+    if( p_sys->b_error || !( env = GET_ENV() ) )
         return -1;
 
     if( p_sys->b_spdif )
@@ -848,7 +842,7 @@ Start( audio_output_t *p_aout, audio_sample_format_t *restrict p_fmt )
     b_spdif = var_InheritBool( p_aout, "spdif" );
     i_max_channels = var_InheritInteger( p_aout, "audiotrack-audio-channels" );
 
-    if( !( env = jni_get_env( THREAD_NAME ) ) )
+    if( !( env = GET_ENV() ) )
         return VLC_EGENERIC;
 
     p_sys->fmt = *p_fmt;
@@ -1043,7 +1037,7 @@ Stop( audio_output_t *p_aout )
     aout_sys_t *p_sys = p_aout->sys;
     JNIEnv *env;
 
-    if( !( env = jni_get_env( THREAD_NAME ) ) )
+    if( !( env = GET_ENV() ) )
         return;
 
     if( p_sys->p_audiotrack )
@@ -1326,7 +1320,7 @@ Play( audio_output_t *p_aout, block_t *p_buffer )
     mtime_t i_play_wait = 0;
     aout_sys_t *p_sys = p_aout->sys;
 
-    if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+    if( p_sys->b_error || !( env = GET_ENV() ) )
         goto bailout;
 
     p_sys->b_error = AudioTrack_PreparePlay( env, p_aout, p_buffer )
@@ -1368,7 +1362,7 @@ Pause( audio_output_t *p_aout, bool b_pause, mtime_t i_date )
     JNIEnv *env;
     VLC_UNUSED( i_date );
 
-    if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+    if( p_sys->b_error || !( env = GET_ENV() ) )
         return;
 
     if( b_pause )
@@ -1389,7 +1383,7 @@ Flush( audio_output_t *p_aout, bool b_wait )
     aout_sys_t *p_sys = p_aout->sys;
     JNIEnv *env;
 
-    if( p_sys->b_error || !( env = jni_get_env( THREAD_NAME ) ) )
+    if( p_sys->b_error || !( env = GET_ENV() ) )
         return;
 
     /* Android doc:
@@ -1434,8 +1428,9 @@ Open( vlc_object_t *obj )
 {
     audio_output_t *p_aout = (audio_output_t *) obj;
     aout_sys_t *p_sys;
+    JNIEnv *env = GET_ENV();
 
-    if( !InitJNIFields( p_aout ) )
+    if( !env || !InitJNIFields( p_aout, env ) )
         return VLC_EGENERIC;
 
     p_sys = calloc( 1, sizeof (aout_sys_t) );
@@ -1463,7 +1458,7 @@ Close( vlc_object_t *obj )
     aout_sys_t *p_sys = p_aout->sys;
     JNIEnv *env;
 
-    if( ( env = jni_get_env( THREAD_NAME ) ) )
+    if( ( env = GET_ENV() ) )
     {
         if( p_sys->p_bytearray )
             (*env)->DeleteGlobalRef( env, p_sys->p_bytearray );
index 770c117..a53d2e1 100644 (file)
@@ -391,6 +391,9 @@ libomxil_plugin_la_SOURCES = \
        codec/omxil/qcom.c codec/omxil/qcom.h \
        codec/omxil/omxil.c codec/omxil/omxil.h codec/omxil/omxil_core.c codec/omxil/omxil_core.h \
        video_chroma/copy.c
+if HAVE_ANDROID
+libomxil_plugin_la_SOURCES += video_output/android/utils.c video_output/android/utils.h
+endif
 libomxil_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/codec/omxil $(CFLAGS_omxil)
 libomxil_plugin_la_LIBADD = $(LIBDL)
 libomxil_plugin_la_LDFLAGS = $(AM_LDFLAGS) -rpath '$(codecdir)'
@@ -408,6 +411,7 @@ libmediacodec_plugin_la_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)/codec/omxil
 libmediacodec_plugin_la_SOURCES = codec/omxil/mediacodec.c codec/omxil/mediacodec.h \
        codec/omxil/mediacodec_jni.c codec/omxil/mediacodec_ndk.c codec/omxil/utils.c \
        video_chroma/copy.c codec/omxil/android_opaque.c codec/omxil/android_opaque.h \
+       video_output/android/utils.c video_output/android/utils.h
        packetizer/h264_nal.c packetizer/h264_nal.h
        packetizer/hevc_nal.c packetizer/hevc_nal.h
 
index 28e41ea..fab53a3 100644 (file)
@@ -48,9 +48,7 @@
 #include "../../video_output/android/android_window.h"
 
 /* JNI functions to get/set an Android Surface object. */
-extern jobject jni_LockAndGetAndroidJavaSurface();
-extern void jni_UnlockAndroidSurface();
-extern void jni_EventHardwareAccelerationError();
+extern void jni_EventHardwareAccelerationError(); // TODO REMOVE
 
 /* Implementation of a circular buffer of timestamps with overwriting
  * of older values. MediaCodec has only one type of timestamp, if a
@@ -136,6 +134,7 @@ struct csd
 struct decoder_sys_t
 {
     mc_api *api;
+    AWindowHandler *p_awh;
     char *psz_name;
     uint32_t nal_size;
 
@@ -341,7 +340,6 @@ static int StartMediaCodec(decoder_t *p_dec)
     int i_angle = 0, i_ret;
     size_t h264_profile = 0;
     char *psz_name = NULL;
-    jobject jsurface = NULL;
 
     if (p_dec->fmt_in.i_extra && !p_sys->p_csd)
     {
@@ -424,12 +422,10 @@ static int StartMediaCodec(decoder_t *p_dec)
     if (!psz_name)
         return VLC_EGENERIC;
 
-    if (var_InheritBool(p_dec, CFG_PREFIX "dr"))
-        jsurface = jni_LockAndGetAndroidJavaSurface();
-    i_ret = p_sys->api->start(p_sys->api, jsurface, psz_name, p_sys->mime,
+    if (!p_sys->p_awh && var_InheritBool(p_dec, CFG_PREFIX "dr"))
+        p_sys->p_awh = AWindowHandler_new(VLC_OBJECT(p_dec));
+    i_ret = p_sys->api->start(p_sys->api, p_sys->p_awh, psz_name, p_sys->mime,
                               p_sys->i_width, p_sys->i_height, i_angle);
-    if (jsurface)
-        jni_UnlockAndroidSurface();
 
     if (i_ret == VLC_SUCCESS)
     {
@@ -462,6 +458,11 @@ static void StopMediaCodec(decoder_t *p_dec)
     p_sys->psz_name = NULL;
 
     p_sys->api->stop(p_sys->api);
+    if (p_sys->p_awh)
+    {
+        AWindowHandler_releaseANativeWindow(p_sys->p_awh, AWindow_Video);
+        AWindowHandler_releaseSurface(p_sys->p_awh, AWindow_Video);
+    }
 }
 
 /*****************************************************************************
@@ -592,6 +593,8 @@ static void CloseDecoder(vlc_object_t *p_this)
         timestamp_FifoRelease(p_sys->timestamp_fifo);
     p_sys->api->clean(p_sys->api);
     free(p_sys->api);
+    if (p_sys->p_awh)
+        AWindowHandler_destroy(p_sys->p_awh);
     free(p_sys);
 }
 
index 90d7676..592bc3c 100644 (file)
@@ -22,6 +22,7 @@
 #define VLC_MEDIACODEC_H
 
 #include <vlc_common.h>
+#include "../../video_output/android/utils.h"
 
 typedef struct mc_api mc_api;
 typedef struct mc_api_sys mc_api_sys;
@@ -74,7 +75,7 @@ struct mc_api
     bool b_support_interlaced;
 
     void (*clean)(mc_api *);
-    int (*start)(mc_api *, jobject jsurface, const char *psz_name,
+    int (*start)(mc_api *, AWindowHandler *p_awh, const char *psz_name,
                  const char *psz_mime, int i_width, int i_height, int i_angle);
     int (*stop)(mc_api *);
     int (*flush)(mc_api *);
index 38c5f91..71318a0 100644 (file)
@@ -38,7 +38,6 @@
 #include "mediacodec.h"
 
 #define THREAD_NAME "mediacodec_jni"
-extern JNIEnv *jni_get_env(const char *name);
 
 #define BUFFER_FLAG_CODEC_CONFIG  2
 #define INFO_OUTPUT_BUFFERS_CHANGED -3
@@ -174,7 +173,7 @@ static inline bool check_exception(JNIEnv *env)
         return false;
 }
 #define CHECK_EXCEPTION() check_exception( env )
-#define GET_ENV() if (!(env = jni_get_env(THREAD_NAME))) return VLC_EGENERIC;
+#define GET_ENV() if (!(env = android_getEnv(api->p_obj, THREAD_NAME))) return VLC_EGENERIC;
 
 /* Initialize all jni fields.
  * Done only one time during the first initialisation */
@@ -283,7 +282,7 @@ char* MediaCodec_GetName(vlc_object_t *p_obj, const char *psz_mime,
     jstring jmime;
     char *psz_name = NULL;
 
-    if (!(env = jni_get_env(THREAD_NAME)))
+    if (!(env = android_getEnv(p_obj, THREAD_NAME)))
         return NULL;
 
     if (!InitJNIFields(p_obj, env))
@@ -459,7 +458,7 @@ static int Stop(mc_api *api)
 /*****************************************************************************
  * Start
  *****************************************************************************/
-static int Start(mc_api *api, jobject jsurface, const char *psz_name,
+static int Start(mc_api *api, AWindowHandler *p_awh, const char *psz_name,
                  const char *psz_mime, int i_width, int i_height, int i_angle)
 {
     mc_api_sys *p_sys = api->p_sys;
@@ -474,6 +473,7 @@ static int Start(mc_api *api, jobject jsurface, const char *psz_name,
     jobject jinput_buffers = NULL;
     jobject joutput_buffers = NULL;
     jobject jbuffer_info = NULL;
+    jobject jsurface = NULL;
 
     GET_ENV();
 
@@ -499,6 +499,8 @@ static int Start(mc_api *api, jobject jsurface, const char *psz_name,
                                              jfields.create_video_format, jmime,
                                              i_width, i_height);
 
+    if (p_awh)
+        jsurface = AWindowHandler_getSurface(p_awh, AWindow_Video);
     b_direct_rendering = !!jsurface;
 
     /* There is no way to rotate the video using direct rendering (and using a
@@ -825,7 +827,7 @@ static void Clean(mc_api *api)
  *****************************************************************************/
 int MediaCodecJni_Init(mc_api *api)
 {
-    JNIEnv* env = NULL;
+    JNIEnv *env;
 
     GET_ENV();
 
index a16c657..31ea3fa 100644 (file)
 #include "omxil_utils.h"
 
 #include "mediacodec.h"
-#include "../../video_output/android/utils.h"
 
 #define THREAD_NAME "mediacodec_ndk"
-extern JNIEnv *jni_get_env(const char *name);
 
 /* Not in NdkMedia API but we need it since we send config data via input
  * buffers and not via "csd-*" buffers from AMediaFormat */
@@ -180,7 +178,6 @@ struct syms
     } AMediaFormat;
 };
 static struct syms syms;
-static native_window_api_t anw_syms;
 
 struct members
 {
@@ -246,12 +243,6 @@ InitSymbols(mc_api *api)
         }
         *(void **)((uint8_t*)&syms + members[i].offset) = sym;
     }
-    void *anw_handle = LoadNativeWindowAPI(&anw_syms);
-    if (!anw_handle)
-    {
-        dlclose(ndk_handle);
-        goto end;
-    }
 
     i_init_state = 1;
 end:
@@ -271,7 +262,6 @@ struct mc_api_sys
 {
     AMediaCodec* p_codec;
     AMediaFormat* p_format;
-    ANativeWindow* p_anw;
 };
 
 /*****************************************************************************
@@ -299,11 +289,6 @@ static int Stop(mc_api *api)
         syms.AMediaFormat.delete(p_sys->p_format);
         p_sys->p_format = NULL;
     }
-    if (p_sys->p_anw)
-    {
-        anw_syms.winRelease(p_sys->p_anw);
-        p_sys->p_anw = NULL;
-    }
 
     msg_Dbg(api->p_obj, "MediaCodec via NDK closed");
     return VLC_SUCCESS;
@@ -312,11 +297,12 @@ static int Stop(mc_api *api)
 /*****************************************************************************
  * Start
  *****************************************************************************/
-static int Start(mc_api *api, jobject jsurface, const char *psz_name,
+static int Start(mc_api *api, AWindowHandler *p_awh, const char *psz_name,
                  const char *psz_mime, int i_width, int i_height, int i_angle)
 {
     mc_api_sys *p_sys = api->p_sys;
     int i_ret = VLC_EGENERIC;
+    ANativeWindow *p_anw = NULL;
 
     p_sys->p_codec = syms.AMediaCodec.createCodecByName(psz_name);
     if (!p_sys->p_codec)
@@ -338,17 +324,11 @@ static int Start(mc_api *api, jobject jsurface, const char *psz_name,
     syms.AMediaFormat.setInt32(p_sys->p_format, "rotation-degrees", i_angle);
     syms.AMediaFormat.setInt32(p_sys->p_format, "encoder", 0);
 
-    if (jsurface)
-    {
-        JNIEnv *env;
-
-        if (!(env = jni_get_env(THREAD_NAME)))
-            goto error;
-        p_sys->p_anw = anw_syms.winFromSurface(env, jsurface);
-    }
+    if (p_awh)
+        p_anw = AWindowHandler_getANativeWindow(p_awh, AWindow_Video);
 
     if (syms.AMediaCodec.configure(p_sys->p_codec, p_sys->p_format,
-                                   p_sys->p_anw, NULL, 0) != AMEDIA_OK)
+                                   p_anw, NULL, 0) != AMEDIA_OK)
     {
         msg_Err(api->p_obj, "AMediaCodec.configure failed");
         goto error;
@@ -360,7 +340,7 @@ static int Start(mc_api *api, jobject jsurface, const char *psz_name,
     }
 
     api->b_started = true;
-    api->b_direct_rendering = !!p_sys->p_anw;
+    api->b_direct_rendering = !!p_anw;
     api->b_support_interlaced = true;
     i_ret = VLC_SUCCESS;
 
index 1418340..cecd3e3 100644 (file)
@@ -68,9 +68,6 @@
 #if defined(USE_IOMX)
 /* JNI functions to get/set an Android Surface object. */
 #define THREAD_NAME "omxil"
-extern JNIEnv *jni_get_env(const char *name);
-extern jobject jni_LockAndGetAndroidJavaSurface();
-extern void jni_UnlockAndroidSurface();
 #endif
 
 /*****************************************************************************
@@ -2020,8 +2017,7 @@ static void HwBuffer_ChangeState( decoder_t *p_dec, OmxPort *p_port,
 static void HwBuffer_Init( decoder_t *p_dec, OmxPort *p_port )
 {
     VLC_UNUSED( p_dec );
-    void *surf;
-    JNIEnv *p_env;
+    ANativeWindow *p_anw;
     OMX_ERRORTYPE omx_error;
 
     if( !p_port->b_direct || p_port->definition.eDir != OMX_DirOutput ||
@@ -2045,38 +2041,30 @@ static void HwBuffer_Init( decoder_t *p_dec, OmxPort *p_port )
         goto error;
     }
     vlc_cond_init (&p_port->p_hwbuf->wait);
-    p_port->p_hwbuf->p_library = LoadNativeWindowAPI( &p_port->p_hwbuf->native_window );
-    if( !p_port->p_hwbuf->p_library )
+
+    p_port->p_hwbuf->p_awh = AWindowHandler_new( VLC_OBJECT( p_dec ) );
+    if( !p_port->p_hwbuf->p_awh )
     {
-        msg_Warn( p_dec, "LoadNativeWindowAPI failed" );
+        msg_Warn( p_dec, "AWindowHandler_new failed" );
         goto error;
     }
-    if( LoadNativeWindowPrivAPI( &p_port->p_hwbuf->anwpriv ) != 0 )
+    p_port->p_hwbuf->anwpriv = AWindowHandler_getANativeWindowPrivAPI( p_port->p_hwbuf->p_awh );
+    if( !p_port->p_hwbuf->anwpriv )
     {
-        msg_Warn( p_dec, "LoadNativeWindowPrivAPI failed" );
+        msg_Warn( p_dec, "AWindowHandler_getANativeWindowPrivAPI failed" );
         goto error;
     }
-
-    surf = jni_LockAndGetAndroidJavaSurface();
-    if( !surf ) {
-        msg_Warn( p_dec, "jni_LockAndGetAndroidJavaSurface failed" );
+    p_anw = AWindowHandler_getANativeWindow( p_port->p_hwbuf->p_awh,
+                                             AWindow_Video );
+    if( !p_anw )
+    {
+        msg_Warn( p_dec, "AWindowHandler_getVideoANativeWindow failed" );
         goto error;
     }
 
-    if ((p_env = jni_get_env(THREAD_NAME)))
-        p_port->p_hwbuf->window = p_port->p_hwbuf->native_window.winFromSurface( p_env, surf );
-
-    jni_UnlockAndroidSurface();
-    if( !p_port->p_hwbuf->window ) {
-        msg_Warn( p_dec, "winFromSurface failed" );
-        goto error;
-    }
-    p_port->p_hwbuf->window_priv =
-        p_port->p_hwbuf->anwpriv.connect( p_port->p_hwbuf->window );
+    p_port->p_hwbuf->window_priv = p_port->p_hwbuf->anwpriv->connect( p_anw );
     if( !p_port->p_hwbuf->window_priv ) {
         msg_Warn( p_dec, "connect failed" );
-        p_port->p_hwbuf->native_window.winRelease( p_port->p_hwbuf->window );
-        p_port->p_hwbuf->window = NULL;
         goto error;
     }
 
@@ -2106,19 +2094,19 @@ static void HwBuffer_Destroy( decoder_t *p_dec, OmxPort *p_port )
 {
     if( p_port->p_hwbuf )
     {
-        if( p_port->p_hwbuf->p_library )
+        if( p_port->p_hwbuf->window_priv )
         {
-            if( p_port->p_hwbuf->window )
-            {
-                HwBuffer_Stop( p_dec, p_port );
-                HwBuffer_FreeBuffers( p_dec, p_port );
-                HwBuffer_Join( p_dec, p_port );
-                p_port->p_hwbuf->anwpriv.disconnect( p_port->p_hwbuf->window_priv );
-                pf_enable_graphic_buffers( p_port->omx_handle,
-                                           p_port->i_port_index, OMX_FALSE );
-                p_port->p_hwbuf->native_window.winRelease( p_port->p_hwbuf->window );
-            }
-            dlclose( p_port->p_hwbuf->p_library );
+            HwBuffer_Stop( p_dec, p_port );
+            HwBuffer_FreeBuffers( p_dec, p_port );
+            HwBuffer_Join( p_dec, p_port );
+            p_port->p_hwbuf->anwpriv->disconnect( p_port->p_hwbuf->window_priv );
+            pf_enable_graphic_buffers( p_port->omx_handle,
+                                       p_port->i_port_index, OMX_FALSE );
+        }
+        if( p_port->p_hwbuf->p_awh )
+        {
+            AWindowHandler_destroy( p_port->p_hwbuf->p_awh );
+            p_port->p_hwbuf->p_awh = NULL;
         }
 
         vlc_cond_destroy( &p_port->p_hwbuf->wait );
@@ -2177,17 +2165,17 @@ static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
             default:
                 i_angle = 0;
         }
-        p_port->p_hwbuf->anwpriv.setOrientation( p_port->p_hwbuf->window_priv,
+        p_port->p_hwbuf->anwpriv->setOrientation( p_port->p_hwbuf->window_priv,
                                                  i_angle );
     }
 
-    if( p_port->p_hwbuf->anwpriv.setUsage( p_port->p_hwbuf->window_priv,
+    if( p_port->p_hwbuf->anwpriv->setUsage( p_port->p_hwbuf->window_priv,
                                            true, (int) i_hw_usage ) != 0 )
     {
         msg_Err( p_dec, "can't set usage" );
         goto error;
     }
-    if( p_port->p_hwbuf->anwpriv.setBuffersGeometry( p_port->p_hwbuf->window_priv,
+    if( p_port->p_hwbuf->anwpriv->setBuffersGeometry( p_port->p_hwbuf->window_priv,
                                                      def->format.video.nFrameWidth,
                                                      def->format.video.nFrameHeight,
                                                      colorFormat ) != 0 )
@@ -2196,7 +2184,7 @@ static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
         goto error;
     }
 
-    if( p_port->p_hwbuf->anwpriv.getMinUndequeued( p_port->p_hwbuf->window_priv,
+    if( p_port->p_hwbuf->anwpriv->getMinUndequeued( p_port->p_hwbuf->window_priv,
                                                    &min_undequeued ) != 0 )
     {
         msg_Err( p_dec, "can't get min_undequeued" );
@@ -2218,7 +2206,7 @@ static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
                      omx_error, ErrorToString(omx_error) );
     }
 
-    if( p_port->p_hwbuf->anwpriv.setBufferCount( p_port->p_hwbuf->window_priv,
+    if( p_port->p_hwbuf->anwpriv->setBufferCount( p_port->p_hwbuf->window_priv,
                                                  def->nBufferCountActual ) != 0 )
     {
         msg_Err( p_dec, "can't set buffer_count" );
@@ -2246,7 +2234,7 @@ static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
     {
         void *p_handle = NULL;
 
-        if( p_port->p_hwbuf->anwpriv.dequeue( p_port->p_hwbuf->window_priv,
+        if( p_port->p_hwbuf->anwpriv->dequeue( p_port->p_hwbuf->window_priv,
                                               &p_handle ) != 0 )
         {
             msg_Err( p_dec, "OMXHWBuffer_dequeue Fail" );
@@ -2259,7 +2247,7 @@ static int HwBuffer_AllocateBuffers( decoder_t *p_dec, OmxPort *p_port )
     for(; i < p_port->p_hwbuf->i_buffers; i++)
     {
         OMX_DBG( "canceling buffer(%d)", i );
-        p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv,
+        p_port->p_hwbuf->anwpriv->cancel( p_port->p_hwbuf->window_priv,
                                          p_port->p_hwbuf->pp_handles[i] );
     }
 
@@ -2290,7 +2278,7 @@ static int HwBuffer_FreeBuffers( decoder_t *p_dec, OmxPort *p_port )
 
             if( p_handle && p_port->p_hwbuf->i_states[i] == BUF_STATE_OWNED )
             {
-                p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
+                p_port->p_hwbuf->anwpriv->cancel( p_port->p_hwbuf->window_priv, p_handle );
                 HwBuffer_ChangeState( p_dec, p_port, i, BUF_STATE_NOT_OWNED );
             }
         }
@@ -2330,7 +2318,7 @@ static int HwBuffer_Start( decoder_t *p_dec, OmxPort *p_port )
 
         if( p_header && p_port->p_hwbuf->i_states[i] == BUF_STATE_OWNED )
         {
-            if( p_port->p_hwbuf->anwpriv.lock( p_port->p_hwbuf->window_priv,
+            if( p_port->p_hwbuf->anwpriv->lock( p_port->p_hwbuf->window_priv,
                                                p_header->pBuffer ) != 0 )
             {
                 msg_Err( p_dec, "lock failed" );
@@ -2380,7 +2368,7 @@ static int HwBuffer_Stop( decoder_t *p_dec, OmxPort *p_port )
                     void *p_handle = p_port->pp_buffers[p_picsys->priv.hw.i_index]->pBuffer;
                     if( p_handle )
                     {
-                        p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
+                        p_port->p_hwbuf->anwpriv->cancel( p_port->p_hwbuf->window_priv, p_handle );
                         HwBuffer_ChangeState( p_dec, p_port, p_picsys->priv.hw.i_index,
                                               BUF_STATE_NOT_OWNED );
                     }
@@ -2475,7 +2463,7 @@ static void HwBuffer_SetCrop( decoder_t *p_dec, OmxPort *p_port,
 {
     VLC_UNUSED( p_dec );
 
-    p_port->p_hwbuf->anwpriv.setCrop( p_port->p_hwbuf->window_priv,
+    p_port->p_hwbuf->anwpriv->setCrop( p_port->p_hwbuf->window_priv,
                                       p_rect->nLeft, p_rect->nTop,
                                       p_rect->nWidth, p_rect->nHeight );
 }
@@ -2510,9 +2498,9 @@ static void *DequeueThread( void *data )
         /* The thread can be stuck here. It shouldn't happen since we make sure
          * we call the dequeue function if there is at least one buffer
          * available. */
-        err = p_port->p_hwbuf->anwpriv.dequeue( p_port->p_hwbuf->window_priv, &p_handle );
+        err = p_port->p_hwbuf->anwpriv->dequeue( p_port->p_hwbuf->window_priv, &p_handle );
         if( err == 0 )
-            err = p_port->p_hwbuf->anwpriv.lock( p_port->p_hwbuf->window_priv, p_handle );
+            err = p_port->p_hwbuf->anwpriv->lock( p_port->p_hwbuf->window_priv, p_handle );
 
         HWBUFFER_LOCK();
 
@@ -2524,7 +2512,7 @@ static void *DequeueThread( void *data )
 
         if( !p_port->p_hwbuf->b_run )
         {
-            p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
+            p_port->p_hwbuf->anwpriv->cancel( p_port->p_hwbuf->window_priv, p_handle );
             continue;
         }
 
@@ -2539,7 +2527,7 @@ static void *DequeueThread( void *data )
         }
         if( i_index == -1 )
         {
-            msg_Err( p_dec, "p_port->p_hwbuf->anwpriv.dequeue returned unknown handle" );
+            msg_Err( p_dec, "p_port->p_hwbuf->anwpriv->dequeue returned unknown handle" );
             continue;
         }
 
@@ -2589,9 +2577,9 @@ static void UnlockPicture( picture_t* p_pic, bool b_render )
     }
 
     if( b_render )
-        p_port->p_hwbuf->anwpriv.queue( p_port->p_hwbuf->window_priv, p_handle );
+        p_port->p_hwbuf->anwpriv->queue( p_port->p_hwbuf->window_priv, p_handle );
     else
-        p_port->p_hwbuf->anwpriv.cancel( p_port->p_hwbuf->window_priv, p_handle );
+        p_port->p_hwbuf->anwpriv->cancel( p_port->p_hwbuf->window_priv, p_handle );
 
     HwBuffer_ChangeState( p_dec, p_port, p_picsys->priv.hw.i_index, BUF_STATE_NOT_OWNED );
     HWBUFFER_BROADCAST( p_port );
index 911f5f6..ba97418 100644 (file)
@@ -74,11 +74,9 @@ typedef struct HwBuffer
     unsigned int    i_max_owned;
     unsigned int    i_owned;
 
-    void            *p_library;
-    void            *window;
 #if defined(USE_IOMX)
-    native_window_api_t native_window;
-    native_window_priv_api_t anwpriv;
+    AWindowHandler *p_awh;
+    native_window_priv_api_t *anwpriv;
     native_window_priv *window_priv;
 #endif
 
index f918773..40213c6 100644 (file)
@@ -266,7 +266,8 @@ libegl_android_plugin_la_SOURCES = video_output/egl.c
 libegl_android_plugin_la_CFLAGS = $(AM_CFLAGS) $(EGL_CFLAGS) -DUSE_PLATFORM_ANDROID=1
 libegl_android_plugin_la_LIBADD = $(EGL_LIBS)
 
-libandroid_native_window_plugin_la_SOURCES = video_output/android/nativewindow.c video_output/android/utils.c
+libandroid_native_window_plugin_la_SOURCES = video_output/android/nativewindow.c \
+       video_output/android/utils.c video_output/android/utils.h
 libandroid_native_window_plugin_la_CFLAGS = $(AM_CFLAGS)
 libandroid_native_window_plugin_la_LIBADD = $(LIBDL)
 
index 2d264e0..8e2a9c7 100644 (file)
@@ -67,16 +67,6 @@ vlc_module_end()
  *****************************************************************************/
 
 #define THREAD_NAME "android_window"
-extern JNIEnv *jni_get_env(const char *name);
-
-extern jobject jni_LockAndGetAndroidJavaSurface();
-extern jobject jni_LockAndGetSubtitlesSurface();
-extern void  jni_UnlockAndroidSurface();
-
-extern void  jni_SetSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den);
-extern int jni_ConfigureSurface(jobject jsurf, int width, int height, int hal, bool *configured);
-extern int jni_GetWindowSize(int *width, int *height);
-extern void jni_getMouseCoordinates(int *, int *, int *, int *);
 
 static const vlc_fourcc_t subpicture_chromas[] =
 {
@@ -101,7 +91,7 @@ struct android_window
     bool b_use_priv;
     bool b_opaque;
 
-    jobject jsurf;
+    enum AWindow_ID id;
     ANativeWindow *p_handle;
     native_window_priv *p_handle_priv;
 };
@@ -120,10 +110,9 @@ struct vout_display_sys_t
     int i_display_width;
     int i_display_height;
 
-    void *p_library;
-    native_window_api_t anw;
-    native_window_priv_api_t anwp;
-    bool b_has_anwp;
+    AWindowHandler *p_awh;
+    native_window_api_t *anw;
+    native_window_priv_api_t *anwp;
 
     android_window *p_window;
     android_window *p_sub_window;
@@ -159,7 +148,8 @@ static inline int ChromaToAndroidHal(vlc_fourcc_t i_chroma)
     }
 }
 
-static int UpdateWindowSize(video_format_t *p_fmt, bool b_cropped)
+static int UpdateWindowSize(vout_display_sys_t *sys, video_format_t *p_fmt,
+                            bool b_cropped)
 {
     unsigned int i_width, i_height;
     unsigned int i_sar_num = 1, i_sar_den = 1;
@@ -179,11 +169,10 @@ static int UpdateWindowSize(video_format_t *p_fmt, bool b_cropped)
         i_height = rot_fmt.i_height;
     }
 
-    jni_SetSurfaceLayout(i_width, i_height,
-                         rot_fmt.i_visible_width,
-                         rot_fmt.i_visible_height,
-                         i_sar_num,
-                         i_sar_den);
+    AWindowHandler_setWindowLayout(sys->p_awh, i_width, i_height,
+                                   rot_fmt.i_visible_width,
+                                   rot_fmt.i_visible_height,
+                                   i_sar_num, i_sar_den);
     return 0;
 }
 
@@ -310,30 +299,25 @@ static void SetupPictureYV12(picture_t *p_picture, uint32_t i_in_stride)
     }
 }
 
-static int AndroidWindow_SetSurface(vout_display_sys_t *sys,
-                                    android_window *p_window,
-                                    jobject jsurf)
+static void AndroidWindow_DisconnectSurface(vout_display_sys_t *sys,
+                                            android_window *p_window)
 {
-    if (jsurf != p_window->jsurf) {
-        if (p_window->p_handle_priv) {
-            sys->anwp.disconnect(p_window->p_handle_priv);
-            p_window->p_handle_priv = NULL;
-        }
-        if (p_window->p_handle) {
-            sys->anw.winRelease(p_window->p_handle);
-            p_window->p_handle = NULL;
-        }
+    if (p_window->p_handle_priv) {
+        sys->anwp->disconnect(p_window->p_handle_priv);
+        p_window->p_handle_priv = NULL;
+    }
+    if (p_window->p_handle) {
+        AWindowHandler_releaseANativeWindow(sys->p_awh, p_window->id);
+        p_window->p_handle = NULL;
     }
+}
 
-    p_window->jsurf = jsurf;
-    if (!p_window->jsurf )
-        return -1;
+static int AndroidWindow_ConnectSurface(vout_display_sys_t *sys,
+                                        android_window *p_window)
+{
     if (!p_window->p_handle && !p_window->b_opaque) {
-        JNIEnv *p_env;
-
-        if (!(p_env = jni_get_env(THREAD_NAME)))
-            return -1;
-        p_window->p_handle = sys->anw.winFromSurface(p_env, p_window->jsurf);
+        p_window->p_handle = AWindowHandler_getANativeWindow(sys->p_awh,
+                                                             p_window->id);
         if (!p_window->p_handle)
             return -1;
     }
@@ -341,25 +325,26 @@ static int AndroidWindow_SetSurface(vout_display_sys_t *sys,
     return 0;
 }
 
-static android_window *AndroidWindow_New(vout_display_sys_t *sys,
+static android_window *AndroidWindow_New(vout_display_t *vd,
                                          video_format_t *p_fmt,
-                                         jobject jsurf,
+                                         enum AWindow_ID id,
                                          bool b_use_priv)
 {
-    android_window *p_window = calloc(1, sizeof(android_window));
+    vout_display_sys_t *sys = vd->sys;
+    android_window *p_window = NULL;
 
+    p_window = calloc(1, sizeof(android_window));
     if (!p_window)
-        return NULL;
+        goto error;
 
+    p_window->id = id;
     p_window->b_opaque = p_fmt->i_chroma == VLC_CODEC_ANDROID_OPAQUE;
     if (!p_window->b_opaque) {
-        p_window->b_use_priv = sys->b_has_anwp && b_use_priv;
+        p_window->b_use_priv = sys->anwp && b_use_priv;
 
         p_window->i_android_hal = ChromaToAndroidHal(p_fmt->i_chroma);
-        if (p_window->i_android_hal == -1) {
-            free(p_window);
-            return NULL;
-        }
+        if (p_window->i_android_hal == -1)
+            goto error;
     }
 
     switch (p_fmt->orientation)
@@ -382,18 +367,23 @@ static android_window *AndroidWindow_New(vout_display_sys_t *sys,
         video_format_ApplyRotation(&p_window->fmt, p_fmt);
     p_window->i_pic_count = 1;
 
-    if (AndroidWindow_SetSurface(sys, p_window, jsurf) != 0) {
-        free(p_window);
-        return NULL;
+    if (AndroidWindow_ConnectSurface(sys, p_window) != 0)
+    {
+        if (id == AWindow_Video)
+            msg_Err(vd, "can't get Video Surface");
+        goto error;
     }
 
     return p_window;
+error:
+    free(p_window);
+    return NULL;
 }
 
-static void AndroidWindow_Destroy(vout_display_sys_t *sys,
+static void AndroidWindow_Destroy(vout_display_t *vd,
                                   android_window *p_window)
 {
-    AndroidWindow_SetSurface(sys, p_window, NULL);
+    AndroidWindow_DisconnectSurface(vd->sys, p_window);
     free(p_window);
 }
 
@@ -403,11 +393,11 @@ static int AndroidWindow_UpdateCrop(vout_display_sys_t *sys,
     if (!p_window->p_handle_priv)
         return -1;
 
-    return sys->anwp.setCrop(p_window->p_handle_priv,
-                             p_window->fmt.i_x_offset,
-                             p_window->fmt.i_y_offset,
-                             p_window->fmt.i_visible_width,
-                             p_window->fmt.i_visible_height);
+    return sys->anwp->setCrop(p_window->p_handle_priv,
+                              p_window->fmt.i_x_offset,
+                              p_window->fmt.i_y_offset,
+                              p_window->fmt.i_visible_width,
+                              p_window->fmt.i_visible_height);
 }
 
 static int AndroidWindow_SetupANWP(vout_display_sys_t *sys,
@@ -417,37 +407,37 @@ static int AndroidWindow_SetupANWP(vout_display_sys_t *sys,
     unsigned int i_max_buffer_count = 0;
 
     if (!p_window->p_handle_priv)
-        p_window->p_handle_priv = sys->anwp.connect(p_window->p_handle);
+        p_window->p_handle_priv = sys->anwp->connect(p_window->p_handle);
 
     if (!p_window->p_handle_priv)
         goto error;
 
-    if (sys->anwp.setUsage(p_window->p_handle_priv, false, 0) != 0)
+    if (sys->anwp->setUsage(p_window->p_handle_priv, false, 0) != 0)
         goto error;
 
     if (!b_java_configured
-        && sys->anwp.setBuffersGeometry(p_window->p_handle_priv,
-                                        p_window->fmt.i_width,
-                                        p_window->fmt.i_height,
-                                        p_window->i_android_hal) != 0)
+        && sys->anwp->setBuffersGeometry(p_window->p_handle_priv,
+                                         p_window->fmt.i_width,
+                                         p_window->fmt.i_height,
+                                         p_window->i_android_hal) != 0)
         goto error;
 
-    sys->anwp.getMinUndequeued(p_window->p_handle_priv,
-                               &p_window->i_min_undequeued);
+    sys->anwp->getMinUndequeued(p_window->p_handle_priv,
+                                &p_window->i_min_undequeued);
 
-    sys->anwp.getMaxBufferCount(p_window->p_handle_priv, &i_max_buffer_count);
+    sys->anwp->getMaxBufferCount(p_window->p_handle_priv, &i_max_buffer_count);
 
     if ((p_window->i_min_undequeued + p_window->i_pic_count) >
          i_max_buffer_count)
         p_window->i_pic_count = i_max_buffer_count - p_window->i_min_undequeued;
 
-    if (sys->anwp.setBufferCount(p_window->p_handle_priv,
-                                 p_window->i_pic_count +
-                                 p_window->i_min_undequeued) != 0)
+    if (sys->anwp->setBufferCount(p_window->p_handle_priv,
+                                  p_window->i_pic_count +
+                                  p_window->i_min_undequeued) != 0)
         goto error;
 
-    if (sys->anwp.setOrientation(p_window->p_handle_priv,
-                                 p_window->i_angle) != 0)
+    if (sys->anwp->setOrientation(p_window->p_handle_priv,
+                                  p_window->i_angle) != 0)
         goto error;
 
     AndroidWindow_UpdateCrop(sys, p_window);
@@ -455,7 +445,7 @@ static int AndroidWindow_SetupANWP(vout_display_sys_t *sys,
     return 0;
 error:
     if (p_window->p_handle_priv) {
-        sys->anwp.disconnect(p_window->p_handle_priv);
+        sys->anwp->disconnect(p_window->p_handle_priv);
         p_window->p_handle_priv = NULL;
     }
     p_window->b_use_priv = false;
@@ -468,29 +458,24 @@ static int AndroidWindow_ConfigureJavaSurface(vout_display_sys_t *sys,
                                               android_window *p_window,
                                               bool *p_java_configured)
 {
-    int err;
-    bool configured = false;
-
-    /* setBuffersGeometry is broken before ics. Use jni_ConfigureSurface to
-     * configure the surface on the java side synchronously.
-     * jni_ConfigureSurface return -1 when you don't need to call it (ie, after
-     * ics). if jni_ConfigureSurface succeed, you need to get a new surface
-     * handle. That's why AndroidWindow_SetSurface is called again here. */
-    err = jni_ConfigureSurface(p_window->jsurf,
-                               p_window->fmt.i_width,
-                               p_window->fmt.i_height,
-                               p_window->i_android_hal,
-                               &configured);
-    if (err == 0) {
-        if (configured) {
-            jobject jsurf = p_window->jsurf;
-            p_window->jsurf = NULL;
-            if (AndroidWindow_SetSurface(sys, p_window, jsurf) != 0)
-                return -1;
-        } else
+    /* setBuffersGeometry is broken before ics. Use
+     * AJavaWindow_setBuffersGeometry to configure the surface on the java side
+     * synchronously.  AJavaWindow_setBuffersGeometry return en error when you
+     * don't need to call it (ie, after ics). if this call succeed, you need to
+     * get a new surface handle. That's why AndroidWindow_DisconnectSurface is
+     * called here. */
+    if (AWindowHandler_setBuffersGeometry(sys->p_awh, p_window->id,
+                                          p_window->fmt.i_width,
+                                          p_window->fmt.i_height,
+                                          p_window->i_android_hal) == VLC_SUCCESS)
+    {
+        *p_java_configured = true;
+        AndroidWindow_DisconnectSurface(sys, p_window);
+        if (AndroidWindow_ConnectSurface(sys, p_window) != 0)
             return -1;
-    }
-    *p_java_configured = configured;
+    } else
+        *p_java_configured = false;
+
     return 0;
 }
 
@@ -501,18 +486,18 @@ static int AndroidWindow_SetupANW(vout_display_sys_t *sys,
     p_window->i_pic_count = 1;
     p_window->i_min_undequeued = 0;
 
-    if (!b_java_configured && sys->anw.setBuffersGeometry)
-        return sys->anw.setBuffersGeometry(p_window->p_handle,
-                                           p_window->fmt.i_width,
-                                           p_window->fmt.i_height,
-                                           p_window->i_android_hal);
+    if (!b_java_configured && sys->anw->setBuffersGeometry)
+        return sys->anw->setBuffersGeometry(p_window->p_handle,
+                                            p_window->fmt.i_width,
+                                            p_window->fmt.i_height,
+                                            p_window->i_android_hal);
     else
         return 0;
 }
 
 static int AndroidWindow_Setup(vout_display_sys_t *sys,
-                                    android_window *p_window,
-                                    unsigned int i_pic_count)
+                               android_window *p_window,
+                               unsigned int i_pic_count)
 {
     bool b_java_configured = false;
 
@@ -562,9 +547,9 @@ static void AndroidWindow_UnlockPicture(vout_display_sys_t *sys,
         if (p_handle == NULL)
             return;
 
-        sys->anwp.unlockData(p_window->p_handle_priv, p_handle, b_render);
+        sys->anwp->unlockData(p_window->p_handle_priv, p_handle, b_render);
     } else
-        sys->anw.unlockAndPost(p_window->p_handle);
+        sys->anw->unlockAndPost(p_window->p_handle);
 }
 
 static int AndroidWindow_LockPicture(vout_display_sys_t *sys,
@@ -577,15 +562,15 @@ static int AndroidWindow_LockPicture(vout_display_sys_t *sys,
         void *p_handle;
         int err;
 
-        err = sys->anwp.lockData(p_window->p_handle_priv,
-                                 &p_handle,
-                                 &p_picsys->priv.sw.buf);
+        err = sys->anwp->lockData(p_window->p_handle_priv,
+                                  &p_handle,
+                                  &p_picsys->priv.sw.buf);
         if (err != 0)
             return -1;
         p_picsys->priv.sw.p_handle = p_handle;
     } else {
-        if (sys->anw.winLock(p_window->p_handle,
-                             &p_picsys->priv.sw.buf, NULL) != 0)
+        if (sys->anw->winLock(p_window->p_handle,
+                              &p_picsys->priv.sw.buf, NULL) != 0)
             return -1;
     }
     if (p_picsys->priv.sw.buf.width < 0 ||
@@ -629,7 +614,7 @@ static void SendEventDisplaySize(vout_display_t *vd)
     vout_display_sys_t *sys = vd->sys;
     int i_display_width, i_display_height;
 
-    if (jni_GetWindowSize(&i_display_width, &i_display_height) == 0
+    if (AWindowHandler_getWindowSize(sys->p_awh, &i_display_width, &i_display_height)
         && i_display_width != 0 && i_display_height != 0
         && (i_display_width != sys->i_display_width
          || i_display_height != sys->i_display_height))
@@ -642,7 +627,6 @@ static int Open(vlc_object_t *p_this)
     vout_display_t *vd = (vout_display_t*)p_this;
     vout_display_sys_t *sys;
     video_format_t sub_fmt;
-    jobject jsurf;
 
     if (vout_display_IsWindowed(vd))
         return VLC_EGENERIC;
@@ -652,17 +636,18 @@ static int Open(vlc_object_t *p_this)
     if (!sys)
         return VLC_ENOMEM;
 
-    sys->p_library = LoadNativeWindowAPI(&sys->anw);
-    if (!sys->p_library)
+    sys->p_awh = AWindowHandler_new(p_this);
+    if (!sys->p_awh)
     {
-        msg_Warn(vd, "Using old Android Surface");
-        LoadNativeSurfaceAPI(&sys->anw);
+        free(sys);
+        msg_Err(vd, "AWindowHandler_new failed");
+        return VLC_EGENERIC;
     }
+    sys->anw = AWindowHandler_getANativeWindowAPI(sys->p_awh);
 
 #ifdef USE_ANWP
-    if (LoadNativeWindowPrivAPI(&sys->anwp) == 0)
-        sys->b_has_anwp = true;
-    else
+    sys->anwp = AWindowHandler_getANativeWindowPrivAPI(sys->p_awh);
+    if (!sys->anwp)
         msg_Warn(vd, "Could not initialize NativeWindow Priv API.");
 #endif
 
@@ -696,11 +681,7 @@ static int Open(vlc_object_t *p_this)
         }
     }
 
-    jsurf = jni_LockAndGetAndroidJavaSurface();
-    if (!jsurf)
-        goto error;
-    sys->p_window = AndroidWindow_New(sys, &vd->fmt, jsurf, true);
-    jni_UnlockAndroidSurface();
+    sys->p_window = AndroidWindow_New(vd, &vd->fmt, AWindow_Video, true);
     if (!sys->p_window)
         goto error;
 
@@ -714,17 +695,12 @@ static int Open(vlc_object_t *p_this)
     msg_Dbg(vd, "using %s", sys->p_window->b_opaque ? "opaque" :
             (sys->p_window->b_use_priv ? "ANWP" : "ANW"));
 
-    jsurf = jni_LockAndGetSubtitlesSurface();
-    if (jsurf) {
-        video_format_ApplyRotation(&sub_fmt, &vd->fmt);
-        sub_fmt.i_chroma = subpicture_chromas[0];
-        SetRGBMask(&sub_fmt);
-        video_format_FixRgb(&sub_fmt);
-
-        sys->p_sub_window = AndroidWindow_New(sys, &sub_fmt, jsurf, false);
-        jni_UnlockAndroidSurface();
-        if (!sys->p_sub_window)
-            goto error;
+    video_format_ApplyRotation(&sub_fmt, &vd->fmt);
+    sub_fmt.i_chroma = subpicture_chromas[0];
+    SetRGBMask(&sub_fmt);
+    video_format_FixRgb(&sub_fmt);
+    sys->p_sub_window = AndroidWindow_New(vd, &sub_fmt, AWindow_Subtitles, false);
+    if (sys->p_sub_window) {
 
         FixSubtitleFormat(sys);
         sys->i_sub_last_order = -1;
@@ -762,7 +738,7 @@ static void Close(vlc_object_t *p_this)
     if (sys->pool)
         picture_pool_Release(sys->pool);
     if (sys->p_window)
-        AndroidWindow_Destroy(sys, sys->p_window);
+        AndroidWindow_Destroy(vd, sys->p_window);
 
     if (sys->p_sub_pic)
         picture_Release(sys->p_sub_pic);
@@ -770,10 +746,10 @@ static void Close(vlc_object_t *p_this)
         filter_DeleteBlend(sys->p_spu_blend);
     free(sys->p_sub_buffer_bounds);
     if (sys->p_sub_window)
-        AndroidWindow_Destroy(sys, sys->p_sub_window);
+        AndroidWindow_Destroy(vd, sys->p_sub_window);
 
-    if (sys->p_library)
-        dlclose(sys->p_library);
+    if (sys->p_awh)
+        AWindowHandler_destroy(sys->p_awh);
 
     free(sys);
 }
@@ -832,7 +808,7 @@ static picture_pool_t *PoolAlloc(vout_display_t *vd, unsigned requested_count)
     requested_count = sys->p_window->i_pic_count;
     msg_Dbg(vd, "PoolAlloc: got %d frames", requested_count);
 
-    UpdateWindowSize(&sys->p_window->fmt, sys->p_window->b_use_priv);
+    UpdateWindowSize(sys, &sys->p_window->fmt, sys->p_window->b_use_priv);
 
     pp_pics = calloc(requested_count, sizeof(picture_t));
 
@@ -1104,7 +1080,8 @@ static int Control(vout_display_t *vd, int query, va_list args)
             } else
                 CopySourceAspect(&sys->p_window->fmt, source);
 
-            UpdateWindowSize(&sys->p_window->fmt, sys->p_window->b_use_priv);
+            UpdateWindowSize(sys, &sys->p_window->fmt,
+                             sys->p_window->b_use_priv);
         } else {
             const vout_display_cfg_t *cfg;
 
@@ -1129,9 +1106,11 @@ static int Control(vout_display_t *vd, int query, va_list args)
 
 static void Manage(vout_display_t *vd)
 {
+    vout_display_sys_t *sys = vd->sys;
     int x, y, button, action;
-    jni_getMouseCoordinates(&action, &button, &x, &y);
-    if (x >= 0 && y >= 0)
+
+    if (AWindowHandler_getMouseCoordinates(sys->p_awh,
+                                           &action, &button, &x, &y))
     {
         switch( action )
         {
index ac8d62c..85a33c6 100644 (file)
 #include "utils.h"
 
 #define THREAD_NAME "ANativeWindow"
-extern JNIEnv *jni_get_env(const char *name);
-extern jobject jni_LockAndGetAndroidJavaSurface();
-extern void jni_UnlockAndroidSurface();
-extern void  jni_SetSurfaceLayout(int width, int height, int visible_width, int visible_height, int sar_num, int sar_den);
 
 static int Open(vout_window_t *, const vout_window_cfg_t *);
 static void Close(vout_window_t *);
@@ -62,10 +58,7 @@ vlc_module_end()
 
 struct vout_window_sys_t
 {
-    void *p_library;
-    native_window_api_t native_window;
-
-    ANativeWindow *window;
+    AWindowHandler *p_awh;
 };
 
 /**
@@ -73,6 +66,8 @@ struct vout_window_sys_t
  */
 static int Open(vout_window_t *wnd, const vout_window_cfg_t *cfg)
 {
+    ANativeWindow *p_anw;
+
     if (cfg->type != VOUT_WINDOW_TYPE_INVALID
      && cfg->type != VOUT_WINDOW_TYPE_ANDROID_NATIVE)
         return VLC_EGENERIC;
@@ -81,40 +76,27 @@ static int Open(vout_window_t *wnd, const vout_window_cfg_t *cfg)
     if (p_sys == NULL)
         return VLC_ENOMEM;
 
-    p_sys->p_library = LoadNativeWindowAPI(&p_sys->native_window);
-    if (p_sys->p_library == NULL)
-    {
-        free(p_sys);
-        return VLC_EGENERIC;
-    }
-
-    // Create the native window by first getting the Java surface.
-    jobject javaSurface = jni_LockAndGetAndroidJavaSurface();
-    if (javaSurface == NULL)
-        goto error;
-
-    JNIEnv *p_env;
-    if (!(p_env = jni_get_env(THREAD_NAME)))
+    p_sys->p_awh = AWindowHandler_new(VLC_OBJECT(wnd));
+    if (!p_sys->p_awh)
         goto error;
-    p_sys->window = p_sys->native_window.winFromSurface(p_env, javaSurface); // ANativeWindow_fromSurface call.
-
-    jni_UnlockAndroidSurface();
-
-    if (p_sys->window == NULL)
+    p_anw = AWindowHandler_getANativeWindow(p_sys->p_awh, AWindow_Video);
+    if (!p_anw)
         goto error;
 
     wnd->type = VOUT_WINDOW_TYPE_ANDROID_NATIVE;
-    wnd->handle.anativewindow = p_sys->window;
+    wnd->handle.anativewindow = p_anw;
     wnd->control = Control;
     wnd->sys = p_sys;
 
     // Set the Java surface size.
-    jni_SetSurfaceLayout(cfg->width, cfg->height, cfg->width, cfg->height, 1, 1);
+    AWindowHandler_setWindowLayout(p_sys->p_awh, cfg->width, cfg->height,
+                                   cfg->width, cfg->height, 1, 1);
 
     return VLC_SUCCESS;
 
 error:
-    dlclose(p_sys->p_library);
+    if (p_sys->p_awh)
+        AWindowHandler_destroy(p_sys->p_awh);
     free(p_sys);
     return VLC_EGENERIC;
 }
@@ -126,8 +108,7 @@ error:
 static void Close(vout_window_t *wnd)
 {
     vout_window_sys_t *p_sys = wnd->sys;
-    p_sys->native_window.winRelease(p_sys->window); // Release the native window.
-    dlclose(p_sys->p_library); // Close the library.
+    AWindowHandler_destroy(p_sys->p_awh);
     free (p_sys);
 }
 
@@ -143,7 +124,8 @@ static int Control(vout_window_t *wnd, int cmd, va_list ap)
         {
             unsigned width = va_arg(ap, unsigned);
             unsigned height = va_arg(ap, unsigned);
-            jni_SetSurfaceLayout(width, height, width, height, 1, 1);
+            AWindowHandler_setWindowLayout(wnd->sys->p_awh, width, height,
+                                           width, height, 1, 1);
             break;
         }
         case VOUT_WINDOW_SET_STATE:
index a2dbf99..69d3eed 100644 (file)
@@ -1,9 +1,10 @@
 /*****************************************************************************
  * utils.c: shared code between Android vout modules.
  *****************************************************************************
- * Copyright (C) 2014 VLC authors and VideoLAN
+ * Copyright (C) 2014-2015 VLC authors and VideoLAN
  *
  * Authors: Felix Abecassis <felix.abecassis@gmail.com>
+ *          Thomas Guillem <thomas@gllm.fr>
  *
  * 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
  *****************************************************************************/
 #include "utils.h"
 #include <dlfcn.h>
+#include <jni.h>
+#include <pthread.h>
+#include <assert.h>
+
+typedef ANativeWindow* (*ptr_ANativeWindow_fromSurface)(JNIEnv*, jobject);
+typedef void (*ptr_ANativeWindow_release)(ANativeWindow*);
+
+struct AWindowHandler
+{
+    JavaVM *p_jvm;
+    jobject jobj;
+
+    struct {
+        jobject jsurface;
+        ANativeWindow *p_anw;
+    } views[AWindow_Max];
+
+    void *p_anw_dl;
+    ptr_ANativeWindow_fromSurface pf_winFromSurface;
+    ptr_ANativeWindow_release pf_winRelease;
+    native_window_api_t anw_api;
+    native_window_priv_api_t anwpriv_api;
+
+    pthread_mutex_t lock;
+    struct {
+        bool b_registered;
+        struct {
+            int i_action, i_button, i_x, i_y;
+        } mouse;
+        struct {
+            int i_width, i_height;
+        } window;
+    } event;
+};
+
+static struct
+{
+    struct {
+        jmethodID getVideoSurface;
+        jmethodID getSubtitlesSurface;
+        jmethodID setCallback;
+        jmethodID setBuffersGeometry;
+        jmethodID setWindowLayout;
+    } AndroidNativeWindow;
+} jfields;
 
 /*
  * Android Surface (pre android 2.3)
@@ -67,11 +113,50 @@ NativeSurface_Load(const char *psz_lib, NativeSurface *p_ns)
     return NULL;
 }
 
+static void *
+NativeSurface_getHandle(JNIEnv *p_env, jobject jsurf)
+{
+    jclass clz;
+    jfieldID fid;
+    intptr_t p_surface_handle = NULL;
+
+    clz = (*p_env)->GetObjectClass(p_env, jsurf);
+    if ((*p_env)->ExceptionOccurred(p_env))
+    {
+        (*p_env)->ExceptionClear(p_env);
+        return NULL;
+    }
+    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)
+        p_surface_handle = (intptr_t)(*p_env)->GetIntField(p_env, jsurf, fid);
+    (*p_env)->DeleteLocalRef(p_env, clz);
+
+    return (void *)p_surface_handle;
+}
+
 
 static ANativeWindow*
-NativeSurface_fromSurface(JNIEnv *env, jobject jsurf)
+NativeSurface_fromSurface(JNIEnv *p_env, jobject jsurf)
 {
-    (void) env;
     void *p_surface_handle;
     NativeSurface *p_ns;
 
@@ -80,7 +165,7 @@ NativeSurface_fromSurface(JNIEnv *env, jobject jsurf)
         "libgui.so",
         "libui.so"
     };
-    p_surface_handle = jni_AndroidJavaSurfaceToNativeSurface(jsurf);
+    p_surface_handle = NativeSurface_getHandle(p_env, jsurf);
     if (!p_surface_handle)
         return NULL;
     p_ns = malloc(sizeof(NativeSurface));
@@ -154,55 +239,60 @@ NativeSurface_unlockAndPost(ANativeWindow *p_anw)
     p_ns->pf_unlockAndPost(p_ns->p_surface_handle);
 }
 
-void LoadNativeSurfaceAPI(native_window_api_t *native)
+static void
+LoadNativeSurfaceAPI(AWindowHandler *p_awh)
 {
-    native->winFromSurface = NativeSurface_fromSurface;
-    native->winRelease = NativeSurface_release;
-    native->winLock = NativeSurface_lock;
-    native->unlockAndPost = NativeSurface_unlockAndPost;
-    native->setBuffersGeometry = NULL;
+    p_awh->pf_winFromSurface = NativeSurface_fromSurface;
+    p_awh->pf_winRelease = NativeSurface_release;
+    p_awh->anw_api.winLock = NativeSurface_lock;
+    p_awh->anw_api.unlockAndPost = NativeSurface_unlockAndPost;
+    p_awh->anw_api.setBuffersGeometry = NULL;
 }
 
 /*
  * Android NativeWindow (post android 2.3)
  */
 
-void *LoadNativeWindowAPI(native_window_api_t *native)
+static void
+LoadNativeWindowAPI(AWindowHandler *p_awh)
 {
     void *p_library = dlopen("libandroid.so", RTLD_NOW);
     if (!p_library)
-        return NULL;
+    {
+        LoadNativeSurfaceAPI(p_awh);
+        return;
+    }
 
-    native->winFromSurface =
+    p_awh->pf_winFromSurface =
         (ptr_ANativeWindow_fromSurface)(dlsym(p_library, "ANativeWindow_fromSurface"));
-    native->winRelease =
+    p_awh->pf_winRelease =
         (ptr_ANativeWindow_release)(dlsym(p_library, "ANativeWindow_release"));
-    native->winLock =
+    p_awh->anw_api.winLock =
         (ptr_ANativeWindow_lock)(dlsym(p_library, "ANativeWindow_lock"));
-    native->unlockAndPost =
+    p_awh->anw_api.unlockAndPost =
         (ptr_ANativeWindow_unlockAndPost)(dlsym(p_library, "ANativeWindow_unlockAndPost"));
-    native->setBuffersGeometry =
+    p_awh->anw_api.setBuffersGeometry =
         (ptr_ANativeWindow_setBuffersGeometry)(dlsym(p_library, "ANativeWindow_setBuffersGeometry"));
 
-    if (native->winFromSurface && native->winRelease && native->winLock
-        && native->unlockAndPost && native->setBuffersGeometry)
-        return p_library;
-
-    native->winFromSurface = NULL;
-    native->winRelease = NULL;
-    native->winLock = NULL;
-    native->unlockAndPost = NULL;
-    native->setBuffersGeometry = NULL;
-
-    dlclose(p_library);
-    return NULL;
+    if (p_awh->pf_winFromSurface && p_awh->pf_winRelease
+     && p_awh->anw_api.winLock && p_awh->anw_api.unlockAndPost
+     && p_awh->anw_api.setBuffersGeometry)
+    {
+        p_awh->p_anw_dl = p_library;
+    }
+    else
+    {
+        dlclose(p_library);
+        LoadNativeSurfaceAPI(p_awh);
+    }
 }
 
 /*
  * Android private NativeWindow (post android 2.3)
  */
 
-int LoadNativeWindowPrivAPI(native_window_priv_api_t *native)
+static int
+LoadNativeWindowPrivAPI(native_window_priv_api_t *native)
 {
     native->connect = dlsym(RTLD_DEFAULT, "ANativeWindowPriv_connect");
     native->disconnect = dlsym(RTLD_DEFAULT, "ANativeWindowPriv_disconnect");
@@ -226,3 +316,444 @@ int LoadNativeWindowPrivAPI(native_window_priv_api_t *native)
         native->dequeue && native->lock && native->lockData && native->unlockData &&
         native->queue && native->cancel && native->setOrientation ? 0 : -1;
 }
+
+/*
+ * Andoid JNIEnv helper
+ */
+
+static pthread_key_t jni_env_key;
+static pthread_once_t jni_env_key_once = PTHREAD_ONCE_INIT;
+
+/* This function is called when a thread attached to the Java VM is canceled or
+ * exited */
+static void
+jni_detach_thread(void *data)
+{
+    JNIEnv *env = data;
+    JavaVM *jvm;
+
+    (*env)->GetJavaVM(env, &jvm);
+    assert(jvm);
+    (*jvm)->DetachCurrentThread(jvm);
+}
+
+static void jni_env_key_create()
+{
+    /* Create a TSD area and setup a destroy callback when a thread that
+     * previously set the jni_env_key is canceled or exited */
+    pthread_key_create(&jni_env_key, jni_detach_thread);
+}
+
+static JNIEnv *
+android_getEnvCommon(vlc_object_t *p_obj, JavaVM *jvm, const char *psz_name)
+{
+    assert((p_obj && !jvm) || (!p_obj && jvm));
+
+    JNIEnv *env;
+
+    pthread_once(&jni_env_key_once, jni_env_key_create);
+    env = pthread_getspecific(jni_env_key);
+    if (env == NULL)
+    {
+        if (!jvm)
+            jvm = var_InheritAddress(p_obj, "android-jvm");
+
+        if (!jvm)
+            return NULL;
+
+        /* if GetEnv returns JNI_OK, the thread is already attached to the
+         * JavaVM, so we are already in a java thread, and we don't have to
+         * setup any destroy callbacks */
+        if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_2) != JNI_OK)
+        {
+            /* attach the thread to the Java VM */
+            JavaVMAttachArgs args;
+
+            args.version = JNI_VERSION_1_2;
+            args.name = psz_name;
+            args.group = NULL;
+
+            if ((*jvm)->AttachCurrentThread(jvm, &env, &args) != JNI_OK)
+                return NULL;
+
+            /* Set the attached env to the thread-specific data area (TSD) */
+            if (pthread_setspecific(jni_env_key, env) != 0)
+            {
+                (*jvm)->DetachCurrentThread(jvm);
+                return NULL;
+            }
+        }
+    }
+
+    return env;
+}
+
+JNIEnv *
+android_getEnv(vlc_object_t *p_obj, const char *psz_name)
+{
+    return android_getEnvCommon(p_obj, NULL, psz_name);
+}
+
+static void
+AndroidNativeWindow_onMouseEvent(JNIEnv*, jobject, jlong, jint, jint, jint, jint);
+static void
+AndroidNativeWindow_onWindowSize(JNIEnv*, jobject, jlong, jint, jint );
+
+const JNINativeMethod jni_callbacks[] = {
+    { "nativeOnMouseEvent", "(JIIII)V",
+        (void *)AndroidNativeWindow_onMouseEvent },
+    { "nativeOnWindowSize", "(JII)V",
+        (void *)AndroidNativeWindow_onWindowSize },
+};
+
+static int
+InitJNIFields(JNIEnv *env, vlc_object_t *p_obj, AWindowHandler *p_awh)
+{
+    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
+    static int i_init_state = -1;
+    int ret;
+    jclass clazz;
+
+    vlc_mutex_lock(&lock);
+
+    if (i_init_state != -1)
+        goto end;
+
+#define CHECK_EXCEPTION(what) do { \
+    if( (*env)->ExceptionOccurred(env) ) \
+    { \
+        msg_Err(p_obj, "%s failed", what); \
+        (*env)->ExceptionClear(env); \
+        i_init_state = 0; \
+        goto end; \
+    } \
+} while( 0 )
+#define GET_METHOD(id, str, args) do { \
+    jfields.AndroidNativeWindow.id = (*env)->GetMethodID(env, clazz, (str), (args)); \
+    CHECK_EXCEPTION("GetMethodID("str")"); \
+} while( 0 )
+
+    clazz = (*env)->GetObjectClass(env, p_awh);
+    CHECK_EXCEPTION("AndroidNativeWindow clazz");
+    GET_METHOD(getVideoSurface, "getVideoSurface", "()Landroid/view/Surface;");
+    GET_METHOD(getSubtitlesSurface, "getSubtitlesSurface", "()Landroid/view/Surface;");
+    GET_METHOD(setCallback, "setCallback", "(J)Z");
+    GET_METHOD(setBuffersGeometry, "setBuffersGeometry", "(Landroid/view/Surface;III)Z");
+    GET_METHOD(setWindowLayout, "setWindowLayout", "(IIIIII)V");
+#undef CHECK_EXCEPTION
+#undef GET_METHOD
+
+    if ((*env)->RegisterNatives(env, clazz, jni_callbacks, 2) < 0)
+    {
+        msg_Err(p_obj, "RegisterNatives failed");
+        i_init_state = 0;
+        goto end;
+    }
+    (*env)->DeleteLocalRef(env, clazz);
+
+    i_init_state = 1;
+    msg_Dbg(p_obj, "InitJNIFields success");
+end:
+    ret = i_init_state == 1 ? VLC_SUCCESS : VLC_EGENERIC;
+    if (ret)
+        msg_Err(p_obj, "AndroidNativeWindow jni init failed" );
+    vlc_mutex_unlock(&lock);
+    return ret;
+}
+
+#define JNI_CALL(what, method, ...) \
+    (*p_env)->what(p_env, p_awh->jobj, jfields.AndroidNativeWindow.method, ##__VA_ARGS__)
+
+static JNIEnv*
+AWindowHandler_getEnv(AWindowHandler *p_awh)
+{
+    return android_getEnvCommon(NULL, p_awh->p_jvm, "AWindowHandler");
+}
+
+AWindowHandler *
+AWindowHandler_new(vlc_object_t *p_obj)
+{
+    AWindowHandler *p_awh;
+    JNIEnv *p_env;
+    JavaVM *p_jvm = var_InheritAddress(p_obj, "android-jvm");
+    jobject jobj = var_InheritAddress(p_obj, "drawable-androidwindow");
+
+    if (!p_jvm || !jobj)
+    {
+        msg_Err(p_obj, "libvlc_media_player options not set");
+        return NULL;
+    }
+
+    p_env = android_getEnvCommon(NULL, p_jvm, "AWindowHandler");
+    if (!p_env)
+    {
+        msg_Err(p_obj, "can't get JNIEnv");
+        return NULL;
+    }
+
+    if (InitJNIFields(p_env, p_obj, jobj) != VLC_SUCCESS)
+    {
+        msg_Err(p_obj, "InitJNIFields failed");
+        return NULL;
+    }
+    p_awh = calloc(1, sizeof(AWindowHandler));
+    if (!p_awh)
+        return NULL;
+    p_awh->p_jvm = p_jvm;
+    p_awh->jobj = (*p_env)->NewGlobalRef(p_env, jobj);
+    LoadNativeWindowAPI(p_awh);
+    pthread_mutex_init(&p_awh->lock, NULL);
+    p_awh->event.mouse.i_action = p_awh->event.mouse.i_button =
+    p_awh->event.mouse.i_x = p_awh->event.mouse.i_y = -1;
+    p_awh->event.window.i_width = p_awh->event.window.i_height = -1;
+
+    return p_awh;
+}
+
+static void
+AWindowHandler_releaseSurfaceEnv(AWindowHandler *p_awh, JNIEnv *p_env,
+                                 enum AWindow_ID id)
+{
+    if (p_awh->views[id].jsurface)
+    {
+        (*p_env)->DeleteGlobalRef(p_env, p_awh->views[id].jsurface);
+        p_awh->views[id].jsurface = NULL;
+    }
+}
+
+void
+AWindowHandler_destroy(AWindowHandler *p_awh)
+{
+    JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
+
+    AWindowHandler_releaseANativeWindow(p_awh, AWindow_Video);
+    AWindowHandler_releaseANativeWindow(p_awh, AWindow_Subtitles);
+
+    if (p_env)
+    {
+        if (p_awh->event.b_registered)
+            JNI_CALL(CallBooleanMethod, setCallback, (jlong)0LL);
+        AWindowHandler_releaseSurfaceEnv(p_awh, p_env, AWindow_Video);
+        AWindowHandler_releaseSurfaceEnv(p_awh, p_env, AWindow_Subtitles);
+        (*p_env)->DeleteGlobalRef(p_env, p_awh->jobj);
+    }
+
+    pthread_mutex_destroy(&p_awh->lock);
+
+    if (p_awh->p_anw_dl)
+        dlclose(p_awh->p_anw_dl);
+
+    free(p_awh);
+}
+
+native_window_api_t *
+AWindowHandler_getANativeWindowAPI(AWindowHandler *p_awh)
+{
+    return &p_awh->anw_api;
+}
+
+native_window_priv_api_t *
+AWindowHandler_getANativeWindowPrivAPI(AWindowHandler *p_awh)
+{
+    if (LoadNativeWindowPrivAPI(&p_awh->anwpriv_api) != 0)
+        return NULL;
+    else
+        return &p_awh->anwpriv_api;
+}
+
+jobject
+AWindowHandler_getSurface(AWindowHandler *p_awh, enum AWindow_ID id)
+{
+    assert(id < AWindow_Max);
+
+    jobject jsurface;
+    JNIEnv *p_env;
+
+    if (p_awh->views[id].jsurface)
+        return p_awh->views[id].jsurface;
+
+    p_env = AWindowHandler_getEnv(p_awh);
+    if (!p_env)
+        return NULL;
+
+    if (id == AWindow_Video)
+        jsurface = JNI_CALL(CallObjectMethod, getVideoSurface);
+    else
+        jsurface = JNI_CALL(CallObjectMethod, getSubtitlesSurface);
+    if (!jsurface)
+        return NULL;
+
+    p_awh->views[id].jsurface = (*p_env)->NewGlobalRef(p_env, jsurface);
+    (*p_env)->DeleteLocalRef(p_env, jsurface);
+    return p_awh->views[id].jsurface;
+}
+
+void
+AWindowHandler_releaseSurface(AWindowHandler *p_awh, enum AWindow_ID id)
+{
+    assert(id < AWindow_Max);
+
+    JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
+    if (p_env)
+        AWindowHandler_releaseSurfaceEnv(p_awh, p_env, id);
+}
+
+ANativeWindow *
+AWindowHandler_getANativeWindow(AWindowHandler *p_awh, enum AWindow_ID id)
+{
+    assert(id < AWindow_Max);
+
+    jobject jsurf;
+    JNIEnv *p_env;
+
+    if (p_awh->views[id].p_anw)
+        return p_awh->views[id].p_anw;
+
+    p_env = AWindowHandler_getEnv(p_awh);
+    if (!p_env)
+        return NULL;
+
+    jsurf = AWindowHandler_getSurface(p_awh, id);
+    if (!jsurf)
+        return NULL;
+
+    p_awh->views[id].p_anw = p_awh->pf_winFromSurface(p_env, jsurf);
+    return p_awh->views[id].p_anw;
+}
+
+void AWindowHandler_releaseANativeWindow(AWindowHandler *p_awh,
+                                         enum AWindow_ID id)
+{
+    assert(id < AWindow_Max);
+
+    if (p_awh->views[id].p_anw)
+    {
+        p_awh->pf_winRelease(p_awh->views[id].p_anw);
+        p_awh->views[id].p_anw = NULL;
+    }
+}
+
+static inline AWindowHandler *jlong_AWindowHandler(jlong handle)
+{
+    return (AWindowHandler *)(intptr_t) handle;
+}
+
+static void
+AndroidNativeWindow_onMouseEvent(JNIEnv* env, jobject clazz, jlong handle,
+                                 jint action, jint button, jint x, jint y)
+{
+    (void) env; (void) clazz;
+    AWindowHandler *p_awh = jlong_AWindowHandler(handle);
+
+    pthread_mutex_lock(&p_awh->lock);
+    p_awh->event.mouse.i_action = action;
+    p_awh->event.mouse.i_button = button;
+    p_awh->event.mouse.i_x = x;
+    p_awh->event.mouse.i_y = y;
+    pthread_mutex_unlock(&p_awh->lock);
+}
+
+static void
+AndroidNativeWindow_onWindowSize(JNIEnv* env, jobject clazz, jlong handle,
+                                 jint width, jint height)
+{
+    (void) env; (void) clazz;
+    AWindowHandler *p_awh = jlong_AWindowHandler(handle);
+
+    pthread_mutex_lock(&p_awh->lock);
+    p_awh->event.window.i_width = width;
+    p_awh->event.window.i_height = height;
+    pthread_mutex_unlock(&p_awh->lock);
+}
+
+static bool
+AWindowHandler_registerCallback(AWindowHandler *p_awh)
+{
+    if (!p_awh->event.b_registered)
+    {
+        JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
+        if (!p_env)
+            return false;
+        p_awh->event.b_registered = JNI_CALL(CallBooleanMethod,
+                                             setCallback,
+                                             (jlong)(intptr_t)p_awh);
+    }
+    return p_awh->event.b_registered;
+}
+
+bool
+AWindowHandler_getMouseCoordinates(AWindowHandler *p_awh,
+                                   int *p_action, int *p_button,
+                                   int *p_x, int *p_y)
+{
+    if (!AWindowHandler_registerCallback(p_awh))
+        return false;
+
+    pthread_mutex_lock(&p_awh->lock);
+    if (p_awh->event.mouse.i_action == -1
+     || p_awh->event.mouse.i_button == -1
+     || p_awh->event.mouse.i_x <= 0 || p_awh->event.mouse.i_y <= 0)
+    {
+        pthread_mutex_unlock(&p_awh->lock);
+        return false;
+    }
+    *p_action = p_awh->event.mouse.i_action;
+    *p_button = p_awh->event.mouse.i_button;
+    *p_x = p_awh->event.mouse.i_x;
+    *p_y = p_awh->event.mouse.i_y;
+    pthread_mutex_unlock(&p_awh->lock);
+    return true;
+}
+
+bool
+AWindowHandler_getWindowSize(AWindowHandler *p_awh,
+                             int *p_width, int *p_height)
+{
+    if (!AWindowHandler_registerCallback(p_awh))
+        return false;
+
+    pthread_mutex_lock(&p_awh->lock);
+    if (p_awh->event.window.i_width <= 0
+     || p_awh->event.window.i_height <= 0)
+    {
+        pthread_mutex_unlock(&p_awh->lock);
+        return false;
+    }
+    *p_width = p_awh->event.window.i_width;
+    *p_height = p_awh->event.window.i_height;
+    pthread_mutex_unlock(&p_awh->lock);
+    return true;
+}
+
+int
+AWindowHandler_setBuffersGeometry(AWindowHandler *p_awh, enum AWindow_ID id,
+                                  int i_width, int i_height, int i_format)
+{
+    jobject jsurf;
+    JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
+    if (!p_env)
+        return VLC_EGENERIC;
+
+    jsurf = AWindowHandler_getSurface(p_awh, id);
+    if (!jsurf)
+        return VLC_EGENERIC;
+
+    return JNI_CALL(CallBooleanMethod, setBuffersGeometry,
+                    jsurf, i_width, i_height, i_format) ? VLC_SUCCESS
+                                                        : VLC_EGENERIC;
+}
+
+int
+AWindowHandler_setWindowLayout(AWindowHandler *p_awh,
+                               int i_width, int i_height,
+                               int i_visible_width, int i_visible_height,
+                               int i_sar_num, int i_sar_den)
+{
+    JNIEnv *p_env = AWindowHandler_getEnv(p_awh);
+    if (!p_env)
+        return VLC_EGENERIC;
+
+    JNI_CALL(CallVoidMethod, setWindowLayout, i_width, i_height,
+             i_visible_width,i_visible_height, i_sar_num, i_sar_den);
+    return VLC_SUCCESS;
+}
index 91a7909..8de2235 100644 (file)
@@ -1,9 +1,10 @@
 /*****************************************************************************
  * utils.h: shared code between Android vout modules.
  *****************************************************************************
- * Copyright (C) 2014 VLC authors and VideoLAN
+ * Copyright (C) 2014-2015 VLC authors and VideoLAN
  *
  * Authors: Felix Abecassis <felix.abecassis@gmail.com>
+ *          Thomas Guillem <thomas@gllm.fr>
  *
  * 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
 # include "config.h"
 #endif
 
-#include <android/native_window.h>
 #include <jni.h>
+#include <android/native_window.h>
 #include <android/native_window_jni.h>
 #include <android/input.h>
 
 #include <vlc_vout_display.h>
+#include <vlc_common.h>
+
+typedef struct AWindowHandler AWindowHandler;
+
+enum AWindow_ID {
+    AWindow_Video,
+    AWindow_Subtitles,
+    AWindow_Max,
+};
+
+/**
+ * native_window_api_t. See android/native_window.h in NDK
+ */
 
-typedef ANativeWindow* (*ptr_ANativeWindow_fromSurface)(JNIEnv*, jobject);
-typedef void (*ptr_ANativeWindow_release)(ANativeWindow*);
 typedef int32_t (*ptr_ANativeWindow_lock)(ANativeWindow*, ANativeWindow_Buffer*, ARect*);
 typedef void (*ptr_ANativeWindow_unlockAndPost)(ANativeWindow*);
 typedef int32_t (*ptr_ANativeWindow_setBuffersGeometry)(ANativeWindow*, int32_t, int32_t, int32_t);
 
 typedef struct
 {
-    ptr_ANativeWindow_fromSurface winFromSurface;
-    ptr_ANativeWindow_release winRelease;
     ptr_ANativeWindow_lock winLock;
     ptr_ANativeWindow_unlockAndPost unlockAndPost;
     ptr_ANativeWindow_setBuffersGeometry setBuffersGeometry; /* can be NULL */
 } native_window_api_t;
 
-/* Fill the structure passed as parameter and return a library handle
-   that should be destroyed with dlclose. */
-void *LoadNativeWindowAPI(native_window_api_t *native);
-
-/* Pre Android 2.3 NativeSurface, no need to free a handle,
- * native->sys->anwp.setBuffersGeometry will be NULL. */
-void LoadNativeSurfaceAPI(native_window_api_t *native);
+/**
+ * native_window_priv_api_t. See system/core/include/system/window.h in AOSP.
+ */
 
 typedef struct native_window_priv native_window_priv;
-typedef native_window_priv *(*ptr_ANativeWindowPriv_connect) (void *);
+typedef native_window_priv *(*ptr_ANativeWindowPriv_connect) (ANativeWindow *);
 typedef int (*ptr_ANativeWindowPriv_disconnect) (native_window_priv *);
 typedef int (*ptr_ANativeWindowPriv_setUsage) (native_window_priv *, bool, int );
 typedef int (*ptr_ANativeWindowPriv_setBuffersGeometry) (native_window_priv *, int, int, int );
@@ -90,6 +96,77 @@ typedef struct
     ptr_ANativeWindowPriv_setOrientation setOrientation;
 } native_window_priv_api_t;
 
-/* Fill the structure passed as parameter and return 0 if all symbols are
-   found. Don't need to call dlclose, the lib is already loaded. */
-int LoadNativeWindowPrivAPI(native_window_priv_api_t *native);
+/**
+ * This function returns a JNIEnv* created from the android JavaVM attached to
+ * the VLC object var. it doesn't need to be released.
+ */
+JNIEnv *android_getEnv(vlc_object_t *p_obj, const char *psz_thread_name);
+
+/**
+ * This function return a new AWindowHandler created from a
+ * IAWindowNativeHandler jobject attached to the VLC object var. It must be
+ * released with AWindowHandler_destroy.
+ */
+AWindowHandler *AWindowHandler_new(vlc_object_t *p_obj);
+void AWindowHandler_destroy(AWindowHandler *p_awh);
+
+/**
+ * This functions returns a native_window_api_t that can be used to access the
+ * public ANativeWindow API. It can't be NULL and shouldn't be released
+ */
+native_window_api_t *AWindowHandler_getANativeWindowAPI(AWindowHandler *p_awh);
+
+/**
+ * This function returns a native_window_priv_api_t that can be used to access
+ * the private ANativeWindow API. It can be NULL and shouldn't be released
+ */
+native_window_priv_api_t *AWindowHandler_getANativeWindowPrivAPI(AWindowHandler *p_awh);
+
+/**
+ * This function retrieves the mouse coordinates sent by the Android
+ * MediaPlayer. It returns true if the coordinates are valid.
+ */
+bool AWindowHandler_getMouseCoordinates(AWindowHandler *p_awh,
+                                        int *p_action, int *p_button,
+                                        int *p_x, int *p_y);
+
+/**
+ * This function retrieves the window size sent by the Android MediaPlayer.  It
+ * returns true if the size is valid.
+ */
+bool AWindowHandler_getWindowSize(AWindowHandler *p_awh,
+                                  int *p_width, int *p_height);
+
+/**
+ * This function returns the Video or the Subtitles Android Surface attached to
+ * the MediaPlayer. It can be released with AWindowHandler_releaseSurface or by
+ * AWindowHandler_destroy.
+ */
+jobject AWindowHandler_getSurface(AWindowHandler *p_awh, enum AWindow_ID id);
+void AWindowHandler_releaseSurface(AWindowHandler *p_awh, enum AWindow_ID id);
+
+/**
+ * This function returns the Video or the Subtitles ANativeWindow attached to
+ * the Android Surface. It can be released with
+ * AWindowHandler_releaseANativeWindow or by AWindowHandler_destroy.
+ */
+ANativeWindow *AWindowHandler_getANativeWindow(AWindowHandler *p_awh,
+                                               enum AWindow_ID id);
+void AWindowHandler_releaseANativeWindow(AWindowHandler *p_awh,
+                                         enum AWindow_ID id);
+/**
+ * This function is a fix up of ANativeWindow_setBuffersGeometry that doesn't
+ * work before Android ICS. It configures the Surface from the Android
+ * MainThread via a SurfaceHolder. It returns VLC_SUCCESS if the Surface was
+ * configured (it returns VLC_EGENERIC after Android ICS).
+ */
+int AWindowHandler_setBuffersGeometry(AWindowHandler *p_awh, enum AWindow_ID id,
+                                      int i_width, int i_height, int i_format);
+
+/**
+ * This function set the window layout.
+ */
+int AWindowHandler_setWindowLayout(AWindowHandler *p_awh,
+                                   int i_width, int i_height,
+                                   int i_visible_width, int i_visible_height,
+                                   int i_sar_num, int i_sar_den);