]> git.sesse.net Git - vlc/blobdiff - src/control/media_player.c
libvlc: nsobject is void *.
[vlc] / src / control / media_player.c
index 14c5e29b049f44a8419f429e9c2f6753df9eb6a2..512ed373d7bcb74fc7876e666dcedb502a3aeffb 100644 (file)
@@ -1,7 +1,7 @@
 /*****************************************************************************
  * media_player.c: Libvlc API Media Instance management functions
  *****************************************************************************
- * Copyright (C) 2005 the VideoLAN team
+ * Copyright (C) 2005-2009 the VideoLAN team
  * $Id$
  *
  * Authors: ClĂ©ment Stenac <zorglub@videolan.org>
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
  *****************************************************************************/
 
-#include "libvlc_internal.h"
+#include <assert.h>
 
 #include <vlc/libvlc.h>
+#include <vlc/libvlc_media.h>
+#include <vlc/libvlc_events.h>
+
 #include <vlc_demux.h>
 #include <vlc_input.h>
 #include <vlc_vout.h>
+
 #include "libvlc.h"
 
-static void
-input_state_changed( const vlc_event_t * event, void * p_userdata );
+#include "libvlc_internal.h"
+#include "media_internal.h" // libvlc_media_set_state()
+#include "media_player_internal.h"
 
 static int
 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
@@ -41,24 +46,19 @@ input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval,
                         void * p_userdata );
 static int
-input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
-                     vlc_value_t oldval, vlc_value_t newval,
-                     void * p_userdata );
-static int
-input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
+input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
                      vlc_value_t oldval, vlc_value_t newval,
                      void * p_userdata );
 
+static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data );
+
 static const libvlc_state_t vlc_to_libvlc_state_array[] =
 {
     [INIT_S]        = libvlc_NothingSpecial,
     [OPENING_S]     = libvlc_Opening,
-    [BUFFERING_S]   = libvlc_Buffering,
     [PLAYING_S]     = libvlc_Playing,
     [PAUSE_S]       = libvlc_Paused,
-    [STOP_S]        = libvlc_Stopped,
-    [FORWARD_S]     = libvlc_Forward,
-    [BACKWARD_S]    = libvlc_Backward,
     [END_S]         = libvlc_Ended,
     [ERROR_S]       = libvlc_Error,
 };
@@ -72,11 +72,11 @@ static inline libvlc_state_t vlc_to_libvlc_state( int vlc_state )
 }
 
 /*
- * Release the associated input thread
+ * Release the associated input thread.
  *
  * Object lock is NOT held.
  */
-static void release_input_thread( libvlc_media_player_t *p_mi )
+static void release_input_thread( libvlc_media_player_t *p_mi, bool b_input_abort )
 {
     input_thread_t * p_input_thread;
 
@@ -85,22 +85,20 @@ static void release_input_thread( libvlc_media_player_t *p_mi )
 
     p_input_thread = p_mi->p_input_thread;
 
-    /* No one is tracking this input_thread appart us. Destroy it */
-    if( p_mi->b_own_its_input_thread )
-    {
-        vlc_event_manager_t * p_em = input_get_event_manager( p_input_thread );
-        vlc_event_detach( p_em, vlc_InputStateChanged, input_state_changed, p_mi );
-        var_DelCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
-        var_DelCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
-        var_DelCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
-        var_DelCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
-
-        /* We owned this one */
-        input_StopThread( p_input_thread );
-        vlc_thread_join( p_input_thread );
-
-        var_Destroy( p_input_thread, "drawable" );
-    }
+    var_DelCallback( p_input_thread, "can-seek",
+                     input_seekable_changed, p_mi );
+    var_DelCallback( p_input_thread, "can-pause",
+                    input_pausable_changed, p_mi );
+    var_DelCallback( p_input_thread, "intf-event",
+                     input_event_changed, p_mi );
+
+    /* We owned this one */
+    input_Stop( p_input_thread, b_input_abort );
+    vlc_thread_join( p_input_thread );
+
+    var_Destroy( p_input_thread, "drawable-hwnd" );
+    var_Destroy( p_input_thread, "drawable-xid" );
+    var_Destroy( p_input_thread, "drawable-agl" );
 
     vlc_object_release( p_input_thread );
 
@@ -111,7 +109,7 @@ static void release_input_thread( libvlc_media_player_t *p_mi )
  * Retrieve the input thread. Be sure to release the object
  * once you are done with it. (libvlc Internal)
  *
- * Object lock is held.
+ * Function will lock the object.
  */
 input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
                                          libvlc_exception_t *p_e )
@@ -136,67 +134,6 @@ input_thread_t *libvlc_get_input_thread( libvlc_media_player_t *p_mi,
     return p_input_thread;
 }
 
-/*
- * input_state_changed (Private) (vlc_InputStateChanged callback)
- */
-static void
-input_state_changed( const vlc_event_t * event, void * p_userdata )
-{
-    libvlc_media_player_t * p_mi = p_userdata;
-    libvlc_event_t forwarded_event;
-    libvlc_event_type_t type = event->u.input_state_changed.new_state;
-
-    switch ( type )
-    {
-        case INIT_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, NULL);
-            forwarded_event.type = libvlc_MediaPlayerNothingSpecial;
-            break;
-        case OPENING_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Opening, NULL);
-            forwarded_event.type = libvlc_MediaPlayerOpening;
-            break;
-        case BUFFERING_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Buffering, NULL);
-            forwarded_event.type = libvlc_MediaPlayerBuffering;
-            break;
-        case PLAYING_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Playing, NULL);
-            forwarded_event.type = libvlc_MediaPlayerPlaying;
-            break;
-        case PAUSE_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Paused, NULL);
-            forwarded_event.type = libvlc_MediaPlayerPaused;
-            break;
-        case STOP_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Stopped, NULL);
-            forwarded_event.type = libvlc_MediaPlayerStopped;
-            break;
-        case FORWARD_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Forward, NULL);
-            forwarded_event.type = libvlc_MediaPlayerForward;
-            break;
-        case BACKWARD_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Backward, NULL);
-            forwarded_event.type = libvlc_MediaPlayerBackward;
-            break;
-        case END_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Ended, NULL);
-            forwarded_event.type = libvlc_MediaPlayerEndReached;
-            break;
-        case ERROR_S:
-            libvlc_media_set_state( p_mi->p_md, libvlc_Error, NULL);
-            forwarded_event.type = libvlc_MediaPlayerEncounteredError;
-            break;
-
-        default:
-            return;
-    }
-
-    libvlc_event_send( p_mi->p_event_manager, &forwarded_event );
-    return;
-}
-
 static int
 input_seekable_changed( vlc_object_t * p_this, char const * psz_cmd,
                         vlc_value_t oldval, vlc_value_t newval,
@@ -235,73 +172,100 @@ input_pausable_changed( vlc_object_t * p_this, char const * psz_cmd,
     return VLC_SUCCESS;
 }
 
-/*
- * input_position_changed (Private) (input var "intf-change" Callback)
- */
 static int
-input_position_changed( vlc_object_t * p_this, char const * psz_cmd,
+input_event_changed( vlc_object_t * p_this, char const * psz_cmd,
                      vlc_value_t oldval, vlc_value_t newval,
                      void * p_userdata )
 {
     VLC_UNUSED(oldval);
+    input_thread_t * p_input = (input_thread_t *)p_this;
     libvlc_media_player_t * p_mi = p_userdata;
-    vlc_value_t val;
+    libvlc_event_t event;
 
-    if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
+    assert( !strcmp( psz_cmd, "intf-event" ) );
+
+    if( newval.i_int == INPUT_EVENT_STATE )
     {
-        input_thread_t * p_input = (input_thread_t *)p_this;
+        libvlc_state_t libvlc_state;
 
-        var_Get( p_input, "state", &val );
-        if( val.i_int != PLAYING_S )
-            return VLC_SUCCESS; /* Don't send the position while stopped */
+        switch ( var_GetInteger( p_input, "state" ) )
+        {
+            case INIT_S:
+                libvlc_state = libvlc_NothingSpecial;
+                event.type = libvlc_MediaPlayerNothingSpecial;
+                break;
+            case OPENING_S:
+                libvlc_state = libvlc_Opening;
+                event.type = libvlc_MediaPlayerOpening;
+                break;
+            case PLAYING_S:
+                libvlc_state = libvlc_Playing;
+                event.type = libvlc_MediaPlayerPlaying;
+                break;
+            case PAUSE_S:
+                libvlc_state = libvlc_Paused;
+                event.type = libvlc_MediaPlayerPaused;
+                break;
+            case END_S:
+                libvlc_state = libvlc_Ended;
+                event.type = libvlc_MediaPlayerEndReached;
+                break;
+            case ERROR_S:
+                libvlc_state = libvlc_Error;
+                event.type = libvlc_MediaPlayerEncounteredError;
+                break;
+
+            default:
+                return VLC_SUCCESS;
+        }
 
-        var_Get( p_input, "position", &val );
+        libvlc_media_set_state( p_mi->p_md, libvlc_state, NULL );
+        libvlc_event_send( p_mi->p_event_manager, &event );
     }
-    else
-        val.i_time = newval.i_time;
-
-    libvlc_event_t event;
-    event.type = libvlc_MediaPlayerPositionChanged;
-    event.u.media_player_position_changed.new_position = val.f_float;
-
-    libvlc_event_send( p_mi->p_event_manager, &event );
-    return VLC_SUCCESS;
-}
-
-/*
- * input_time_changed (Private) (input var "intf-change" Callback)
- */
-static int
-input_time_changed( vlc_object_t * p_this, char const * psz_cmd,
-                     vlc_value_t oldval, vlc_value_t newval,
-                     void * p_userdata )
-{
-    VLC_UNUSED(oldval);
-    libvlc_media_player_t * p_mi = p_userdata;
-    vlc_value_t val;
-
-    if (!strncmp(psz_cmd, "intf", 4 /* "-change" no need to go further */))
+    else if( newval.i_int == INPUT_EVENT_POSITION )
     {
-        input_thread_t * p_input = (input_thread_t *)p_this;
-
-        var_Get( p_input, "state", &val );
-        if( val.i_int != PLAYING_S )
+        if( var_GetInteger( p_input, "state" ) != PLAYING_S )
             return VLC_SUCCESS; /* Don't send the position while stopped */
 
-        var_Get( p_input, "time", &val );
+        /* */
+        event.type = libvlc_MediaPlayerPositionChanged;
+        event.u.media_player_position_changed.new_position =
+                                          var_GetFloat( p_input, "position" );
+        libvlc_event_send( p_mi->p_event_manager, &event );
+
+        /* */
+        event.type = libvlc_MediaPlayerTimeChanged;
+        event.u.media_player_time_changed.new_time =
+                                               var_GetTime( p_input, "time" );
+        libvlc_event_send( p_mi->p_event_manager, &event );
+    }
+    else if( newval.i_int == INPUT_EVENT_LENGTH )
+    {
+        event.type = libvlc_MediaPlayerLengthChanged;
+        event.u.media_player_length_changed.new_length =
+                                               var_GetTime( p_input, "length" );
+        libvlc_event_send( p_mi->p_event_manager, &event );
     }
-    else
-        val.i_time = newval.i_time;
 
-    libvlc_event_t event;
-    event.type = libvlc_MediaPlayerTimeChanged;
-    event.u.media_player_time_changed.new_time = val.i_time;
-    libvlc_event_send( p_mi->p_event_manager, &event );
     return VLC_SUCCESS;
+
 }
 
+static void libvlc_media_player_destroy( libvlc_media_player_t * );
+
 /**************************************************************************
- * Create a Media Instance object
+ * Create a Media Instance object.
+ *
+ * Refcount strategy:
+ * - All items created by _new start with a refcount set to 1.
+ * - Accessor _release decrease the refcount by 1, if after that
+ *   operation the refcount is 0, the object is destroyed.
+ * - Accessor _retain increase the refcount by 1 (XXX: to implement)
+ *
+ * Object locking strategy:
+ * - No lock held while in constructor.
+ * - When accessing any member variable this lock is held. (XXX who locks?)
+ * - When attempting to destroy the object the lock is also held.
  **************************************************************************/
 libvlc_media_player_t *
 libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
@@ -322,25 +286,19 @@ libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
         return NULL;
     }
     p_mi->p_md = NULL;
-    p_mi->drawable = 0;
+    p_mi->drawable.agl = 0;
+    p_mi->drawable.xid = 0;
+    p_mi->drawable.hwnd = NULL;
+    p_mi->drawable.nsobject = NULL;
     p_mi->p_libvlc_instance = p_libvlc_instance;
     p_mi->p_input_thread = NULL;
-    /* refcount strategy:
-     * - All items created by _new start with a refcount set to 1
-     * - Accessor _release decrease the refcount by 1, if after that
-     *   operation the refcount is 0, the object is destroyed.
-     * - Accessor _retain increase the refcount by 1 (XXX: to implement) */
     p_mi->i_refcount = 1;
-    p_mi->b_own_its_input_thread = true;
-    /* object_lock strategy:
-     * - No lock held in constructor
-     * - Lock when accessing all variable this lock is held
-     * - Lock when attempting to destroy the object the lock is also held */
     vlc_mutex_init( &p_mi->object_lock );
     p_mi->p_event_manager = libvlc_event_manager_new( p_mi,
             p_libvlc_instance, p_e );
     if( libvlc_exception_raised( p_e ) )
     {
+        vlc_mutex_destroy( &p_mi->object_lock );
         free( p_mi );
         return NULL;
     }
@@ -370,18 +328,33 @@ libvlc_media_player_new( libvlc_instance_t * p_libvlc_instance,
             libvlc_MediaPlayerPositionChanged, p_e );
     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
             libvlc_MediaPlayerTimeChanged, p_e );
-     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
+    libvlc_event_manager_register_event_type( p_mi->p_event_manager,
+            libvlc_MediaPlayerLengthChanged, p_e );
+    libvlc_event_manager_register_event_type( p_mi->p_event_manager,
             libvlc_MediaPlayerTitleChanged, p_e );
     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
             libvlc_MediaPlayerSeekableChanged, p_e );
     libvlc_event_manager_register_event_type( p_mi->p_event_manager,
             libvlc_MediaPlayerPausableChanged, p_e );
 
+    /* Snapshot initialization */
+    libvlc_event_manager_register_event_type( p_mi->p_event_manager,
+           libvlc_MediaPlayerSnapshotTaken, p_e );
+
+    /* Attach a var callback to the global object to provide the glue between
+        vout_thread that generates the event and media_player that re-emits it
+        with its own event manager
+    */
+    var_Create( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
+                VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
+    var_AddCallback( p_libvlc_instance->p_libvlc_int, "vout-snapshottaken",
+                     SnapshotTakenCallback, p_mi );
+
     return p_mi;
 }
 
 /**************************************************************************
- * Create a Media Instance object with a media descriptor
+ * Create a Media Instance object with a media descriptor.
  **************************************************************************/
 libvlc_media_player_t *
 libvlc_media_player_new_from_media(
@@ -389,8 +362,8 @@ libvlc_media_player_new_from_media(
                                     libvlc_exception_t *p_e )
 {
     libvlc_media_player_t * p_mi;
-    p_mi = libvlc_media_player_new( p_md->p_libvlc_instance, p_e );
 
+    p_mi = libvlc_media_player_new( p_md->p_libvlc_instance, p_e );
     if( !p_mi )
         return NULL;
 
@@ -400,121 +373,73 @@ libvlc_media_player_new_from_media(
     return p_mi;
 }
 
-/**************************************************************************
- * Create a new media instance object from an input_thread (Libvlc Internal)
- **************************************************************************/
-libvlc_media_player_t * libvlc_media_player_new_from_input_thread(
-                                   struct libvlc_instance_t *p_libvlc_instance,
-                                   input_thread_t *p_input,
-                                   libvlc_exception_t *p_e )
-{
-    libvlc_media_player_t * p_mi;
-
-    if( !p_input )
-    {
-        libvlc_exception_raise( p_e, "invalid input thread" );
-        return NULL;
-    }
-
-    p_mi = libvlc_media_player_new( p_libvlc_instance, p_e );
-
-    if( !p_mi )
-        return NULL;
-
-    p_mi->p_md = libvlc_media_new_from_input_item(
-                    p_libvlc_instance,
-                    input_GetItem( p_input ), p_e );
-
-    if( !p_mi->p_md )
-    {
-        libvlc_media_player_destroy( p_mi );
-        return NULL;
-    }
-
-    /* will be released in media_player_release() */
-    vlc_object_hold( p_input );
-
-    p_mi->p_input_thread = p_input;
-    p_mi->b_own_its_input_thread = false;
-
-    return p_mi;
-}
-
 /**************************************************************************
  * Destroy a Media Instance object (libvlc internal)
  *
- * Warning: No lock held here, but hey, this is internal.
+ * Warning: No lock held here, but hey, this is internal. Caller must lock.
  **************************************************************************/
-void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
+static void libvlc_media_player_destroy( libvlc_media_player_t *p_mi )
 {
     input_thread_t *p_input_thread;
     libvlc_exception_t p_e;
 
-    libvlc_exception_init( &p_e );
+    assert( p_mi );
 
-    if( !p_mi )
-        return;
+    /* Detach Callback from the main libvlc object */
+    var_DelCallback( p_mi->p_libvlc_instance->p_libvlc_int,
+                     "vout-snapshottaken", SnapshotTakenCallback, p_mi );
 
+    libvlc_exception_init( &p_e );
     p_input_thread = libvlc_get_input_thread( p_mi, &p_e );
 
     if( libvlc_exception_raised( &p_e ) )
-    {
-        libvlc_event_manager_release( p_mi->p_event_manager );
+        /* no need to worry about no input thread */
         libvlc_exception_clear( &p_e );
-        free( p_mi );
-        return; /* no need to worry about no input thread */
-    }
-    vlc_mutex_destroy( &p_mi->object_lock );
-
-    vlc_object_release( p_input_thread );
+    else
+        release_input_thread( p_mi, true );
 
+    libvlc_event_manager_release( p_mi->p_event_manager );
     libvlc_media_release( p_mi->p_md );
-
+    vlc_mutex_destroy( &p_mi->object_lock );
     free( p_mi );
 }
 
 /**************************************************************************
- * Release a Media Instance object
+ * Release a Media Instance object.
+ *
+ * Function does the locking.
  **************************************************************************/
 void libvlc_media_player_release( libvlc_media_player_t *p_mi )
 {
-    if( !p_mi )
-        return;
+    bool destroy;
 
+    assert( p_mi );
     vlc_mutex_lock( &p_mi->object_lock );
-
-    p_mi->i_refcount--;
-
-    if( p_mi->i_refcount > 0 )
-    {
-        vlc_mutex_unlock( &p_mi->object_lock );
-        return;
-    }
+    destroy = !--p_mi->i_refcount;
     vlc_mutex_unlock( &p_mi->object_lock );
-    vlc_mutex_destroy( &p_mi->object_lock );
-
-    release_input_thread( p_mi );
-
-    libvlc_event_manager_release( p_mi->p_event_manager );
 
-    libvlc_media_release( p_mi->p_md );
-
-    free( p_mi );
+    if( destroy )
+        libvlc_media_player_destroy( p_mi );
 }
 
 /**************************************************************************
- * Retain a Media Instance object
+ * Retain a Media Instance object.
+ *
+ * Caller must hold the lock.
  **************************************************************************/
 void libvlc_media_player_retain( libvlc_media_player_t *p_mi )
 {
-    if( !p_mi )
-        return;
+    assert( p_mi );
 
+    vlc_mutex_lock( &p_mi->object_lock );
     p_mi->i_refcount++;
+    vlc_mutex_unlock( &p_mi->object_lock );
 }
 
 /**************************************************************************
- * Set the Media descriptor associated with the instance
+ * Set the Media descriptor associated with the instance.
+ *
+ * Enter without lock -- function will lock the object.
  **************************************************************************/
 void libvlc_media_player_set_media(
                             libvlc_media_player_t *p_mi,
@@ -528,7 +453,12 @@ void libvlc_media_player_set_media(
 
     vlc_mutex_lock( &p_mi->object_lock );
 
-    release_input_thread( p_mi );
+    /* FIXME I am not sure if it is a user request or on die(eof/error)
+     * request here */
+    release_input_thread( p_mi,
+                          p_mi->p_input_thread &&
+                          !p_mi->p_input_thread->b_eof &&
+                          !p_mi->p_input_thread->b_error );
 
     if( p_mi->p_md )
         libvlc_media_set_state( p_mi->p_md, libvlc_NothingSpecial, p_e );
@@ -553,7 +483,7 @@ void libvlc_media_player_set_media(
 }
 
 /**************************************************************************
- * Get the Media descriptor associated with the instance
+ * Get the Media descriptor associated with the instance.
  **************************************************************************/
 libvlc_media_t *
 libvlc_media_player_get_media(
@@ -570,7 +500,7 @@ libvlc_media_player_get_media(
 }
 
 /**************************************************************************
- * Get the event Manager
+ * Get the event Manager.
  **************************************************************************/
 libvlc_event_manager_t *
 libvlc_media_player_event_manager(
@@ -583,7 +513,30 @@ libvlc_media_player_event_manager(
 }
 
 /**************************************************************************
- * Play
+ * Trigger a snapshot Taken Event.
+ *************************************************************************/
+static int SnapshotTakenCallback( vlc_object_t *p_this, char const *psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
+{
+    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
+    VLC_UNUSED(p_this) ;
+
+    libvlc_media_player_t* p_mi = (libvlc_media_player_t*) p_data ;
+    libvlc_event_t event ;
+    event.type = libvlc_MediaPlayerSnapshotTaken ;
+    event.u.media_player_snapshot_taken.psz_filename = newval.psz_string ;
+    /* Snapshot psz data is a vlc_variable owned by libvlc object .
+         Its memmory management is taken care by the obj*/
+    msg_Dbg( p_this, "about to emit libvlc_snapshot_taken.make psz_str=0x%p"
+             " (%s)", event.u.media_player_snapshot_taken.psz_filename,
+             event.u.media_player_snapshot_taken.psz_filename );
+    libvlc_event_send( p_mi->p_event_manager, &event );
+
+    return VLC_SUCCESS;
+}
+
+/**************************************************************************
+ * Tell media player to start playing.
  **************************************************************************/
 void libvlc_media_player_play( libvlc_media_player_t *p_mi,
                                  libvlc_exception_t *p_e )
@@ -610,9 +563,8 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
         return;
     }
 
-    p_mi->p_input_thread = input_CreateThread( p_mi->p_libvlc_instance->p_libvlc_int,
-                      p_mi->p_md->p_input_item );
-
+    p_mi->p_input_thread = input_Create( p_mi->p_libvlc_instance->p_libvlc_int,
+                                         p_mi->p_md->p_input_item, NULL, NULL );
 
     if( !p_mi->p_input_thread )
     {
@@ -622,39 +574,53 @@ void libvlc_media_player_play( libvlc_media_player_t *p_mi,
 
     p_input_thread = p_mi->p_input_thread;
 
-    if( p_mi->drawable )
+    var_Create( p_input_thread, "drawable-agl", VLC_VAR_INTEGER );
+    if( p_mi->drawable.agl )
+        var_SetInteger( p_input_thread, "drawable-agl", p_mi->drawable.agl );
+
+    var_Create( p_input_thread, "drawable-xid", VLC_VAR_INTEGER );
+    if( p_mi->drawable.xid )
+        var_SetInteger( p_input_thread, "drawable-xid", p_mi->drawable.xid );
+
+    var_Create( p_input_thread, "drawable-hwnd", VLC_VAR_ADDRESS );
+    if( p_mi->drawable.hwnd != NULL )
     {
-        vlc_value_t val;
-        val.i_int = p_mi->drawable;
-        var_Create( p_input_thread, "drawable", VLC_VAR_DOINHERIT );
-        var_Set( p_input_thread, "drawable", val );
+        vlc_value_t val = { .p_address = p_mi->drawable.hwnd };
+        var_Set( p_input_thread, "drawable-hwnd", val );
     }
 
-    vlc_event_manager_t * p_em = input_get_event_manager( p_input_thread );
-    vlc_event_attach( p_em, vlc_InputStateChanged, input_state_changed, p_mi );
+       var_Create( p_input_thread, "drawable-nsobject", VLC_VAR_ADDRESS );
+    if( p_mi->drawable.nsobject != NULL )
+    {
+        vlc_value_t val = { .p_address = p_mi->drawable.nsobject };
+        var_Set( p_input_thread, "drawable-nsobject", val );
+    }
+       
+    var_AddCallback( p_input_thread, "can-seek", input_seekable_changed, p_mi );
+    var_AddCallback( p_input_thread, "can-pause", input_pausable_changed, p_mi );
+    var_AddCallback( p_input_thread, "intf-event", input_event_changed, p_mi );
 
-    var_AddCallback( p_input_thread, "seekable", input_seekable_changed, p_mi );
-    var_AddCallback( p_input_thread, "pausable", input_pausable_changed, p_mi );
-    var_AddCallback( p_input_thread, "intf-change", input_position_changed, p_mi );
-    var_AddCallback( p_input_thread, "intf-change", input_time_changed, p_mi );
+    if( input_Start( p_input_thread ) )
+    {
+        vlc_object_release( p_input_thread );
+        p_mi->p_input_thread = NULL;
+    }
 
     vlc_mutex_unlock( &p_mi->object_lock );
 }
 
 /**************************************************************************
- * Pause
+ * Pause.
  **************************************************************************/
 void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
                                   libvlc_exception_t *p_e )
 {
     input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
-
     if( !p_input_thread )
         return;
 
     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
-
-    if( state == libvlc_Playing )
+    if( state == libvlc_Playing || state == libvlc_Buffering )
     {
         if( libvlc_media_player_can_pause( p_mi, p_e ) )
             input_Control( p_input_thread, INPUT_SET_STATE, PAUSE_S );
@@ -668,40 +634,118 @@ void libvlc_media_player_pause( libvlc_media_player_t *p_mi,
 }
 
 /**************************************************************************
- * Stop
+ * Tells whether the media player is currently playing.
+ *
+ * Enter with lock held.
+ **************************************************************************/
+int libvlc_media_player_is_playing( libvlc_media_player_t *p_mi,
+                                     libvlc_exception_t *p_e )
+{
+    libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
+    return (libvlc_Playing == state) || (libvlc_Buffering == state);
+}
+
+/**************************************************************************
+ * Stop playing.
  **************************************************************************/
 void libvlc_media_player_stop( libvlc_media_player_t *p_mi,
                                  libvlc_exception_t *p_e )
 {
     libvlc_state_t state = libvlc_media_player_get_state( p_mi, p_e );
 
-    if( state == libvlc_Playing || state == libvlc_Paused )
+    if( state == libvlc_Playing ||
+        state == libvlc_Paused ||
+        state == libvlc_Buffering )
     {
-        /* Send a stop notification event only of we are in playing or paused states */
+        /* Send a stop notification event only if we are in playing,
+         * buffering or paused states */
         libvlc_media_set_state( p_mi->p_md, libvlc_Ended, p_e );
 
         /* Construct and send the event */
         libvlc_event_t event;
-        event.type = libvlc_MediaPlayerEndReached;
+        event.type = libvlc_MediaPlayerStopped;
         libvlc_event_send( p_mi->p_event_manager, &event );
     }
 
-    if( p_mi->b_own_its_input_thread )
-    {
-        vlc_mutex_lock( &p_mi->object_lock );
-        release_input_thread( p_mi ); /* This will stop the input thread */
-        vlc_mutex_unlock( &p_mi->object_lock );
-    }
-    else
-    {
-        input_thread_t * p_input_thread = libvlc_get_input_thread( p_mi, p_e );
+    vlc_mutex_lock( &p_mi->object_lock );
+    release_input_thread( p_mi, true ); /* This will stop the input thread */
+    vlc_mutex_unlock( &p_mi->object_lock );
+}
 
-        if( !p_input_thread )
-            return;
+/**************************************************************************
+ * set_nsobject
+ **************************************************************************/
+void libvlc_media_player_set_nsobject( libvlc_media_player_t *p_mi,
+                                        void * drawable,
+                                        libvlc_exception_t *p_e )
+{
+    (void) p_e;
+    p_mi->drawable.nsobject = drawable;
+}
 
-        input_StopThread( p_input_thread );
-        vlc_object_release( p_input_thread );
-    }
+/**************************************************************************
+ * get_nsobject
+ **************************************************************************/
+void * libvlc_media_player_get_nsobject( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.nsobject;
+}
+
+/**************************************************************************
+ * set_agl
+ **************************************************************************/
+void libvlc_media_player_set_agl( libvlc_media_player_t *p_mi,
+                                      uint32_t drawable,
+                                      libvlc_exception_t *p_e )
+{
+    (void) p_e;
+    p_mi->drawable.agl = drawable;
+}
+
+/**************************************************************************
+ * get_agl
+ **************************************************************************/
+uint32_t libvlc_media_player_get_agl( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.agl;
+}
+
+/**************************************************************************
+ * set_xwindow
+ **************************************************************************/
+void libvlc_media_player_set_xwindow( libvlc_media_player_t *p_mi,
+                                      uint32_t drawable,
+                                      libvlc_exception_t *p_e )
+{
+    (void) p_e;
+    p_mi->drawable.xid = drawable;
+}
+
+/**************************************************************************
+ * get_xwindow
+ **************************************************************************/
+uint32_t libvlc_media_player_get_xwindow( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.xid;
+}
+
+/**************************************************************************
+ * set_hwnd
+ **************************************************************************/
+void libvlc_media_player_set_hwnd( libvlc_media_player_t *p_mi,
+                                   void *drawable,
+                                   libvlc_exception_t *p_e )
+{
+    (void) p_e;
+    p_mi->drawable.hwnd = drawable;
+}
+
+/**************************************************************************
+ * get_hwnd
+ **************************************************************************/
+void *libvlc_media_player_get_hwnd( libvlc_media_player_t *p_mi )
+{
+    return p_mi->drawable.hwnd;
 }
 
 /**************************************************************************
@@ -711,39 +755,39 @@ void libvlc_media_player_set_drawable( libvlc_media_player_t *p_mi,
                                        libvlc_drawable_t drawable,
                                        libvlc_exception_t *p_e )
 {
-    input_thread_t *p_input_thread;
-    vout_thread_t *p_vout = NULL;
-
-    p_mi->drawable = drawable;
-
-    /* Allow on the fly drawable changing. This is tricky has this may
-     * not be supported by every vout. We though can't disable it
-     * because of some creepy drawable type that are not flexible enough
-     * (Win32 HWND for instance) */
-    p_input_thread = libvlc_get_input_thread( p_mi, p_e );
-    if( !p_input_thread ) {
-        /* No input, nothing more to do, we are fine */
-        libvlc_exception_clear( p_e );
-        return;
-    }
-
-    p_vout = vlc_object_find( p_input_thread, VLC_OBJECT_VOUT, FIND_CHILD );
-    if( p_vout )
-    {
-        vout_Control( p_vout , VOUT_REPARENT, drawable);
-        vlc_object_release( p_vout );
-    }
-    vlc_object_release( p_input_thread );
+#ifdef WIN32
+    if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
+        p_mi->drawable.hwnd = (HWND)drawable;
+    else
+        libvlc_exception_raise(p_e, "Operation not supported");
+#elif defined(__APPLE__)
+    p_mi->drawable.agl = drawable;
+    (void) p_e;
+#else
+    p_mi->drawable.xid = drawable;
+    (void) p_e;
+#endif
 }
 
 /**************************************************************************
  * Get Drawable
  **************************************************************************/
 libvlc_drawable_t
-libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi, libvlc_exception_t *p_e )
+libvlc_media_player_get_drawable ( libvlc_media_player_t *p_mi,
+                                   libvlc_exception_t *p_e )
 {
     VLC_UNUSED(p_e);
-    return p_mi->drawable;
+
+#ifdef WIN32
+    if (sizeof (HWND) <= sizeof (libvlc_drawable_t))
+        return (libvlc_drawable_t)p_mi->drawable.hwnd;
+    else
+        return 0;
+#elif defined(__APPLE__)
+    return p_mi->drawable.agl;
+#else
+    return p_mi->drawable.xid;
+#endif
 }
 
 /**************************************************************************
@@ -788,14 +832,12 @@ void libvlc_media_player_set_time(
                                  libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
-    vlc_value_t value;
 
     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
     if( !p_input_thread )
         return;
 
-    value.i_time = time*1000LL;
-    var_Set( p_input_thread, "time", value );
+    var_SetTime( p_input_thread, "time", time*1000LL );
     vlc_object_release( p_input_thread );
 }
 
@@ -805,14 +847,12 @@ void libvlc_media_player_set_position(
                                 libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
-    vlc_value_t val;
-    val.f_float = position;
 
     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
     if( !p_input_thread )
         return;
 
-    var_Set( p_input_thread, "position", val );
+    var_SetFloat( p_input_thread, "position", position );
     vlc_object_release( p_input_thread );
 }
 
@@ -839,14 +879,12 @@ void libvlc_media_player_set_chapter(
                                  libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
-    vlc_value_t val;
-    val.i_int = chapter;
 
     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
     if( !p_input_thread )
         return;
 
-    var_Set( p_input_thread, "chapter", val );
+    var_SetInteger( p_input_thread, "chapter", chapter );
     vlc_object_release( p_input_thread );
 }
 
@@ -915,14 +953,12 @@ void libvlc_media_player_set_title(
                                  libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
-    vlc_value_t val;
-    val.i_int = i_title;
 
     p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
     if( !p_input_thread )
         return;
 
-    var_Set( p_input_thread, "title", val );
+    var_SetInteger( p_input_thread, "title", i_title );
     vlc_object_release( p_input_thread );
 
     //send event
@@ -977,10 +1013,8 @@ void libvlc_media_player_next_chapter(
         return;
 
     int i_type = var_Type( p_input_thread, "next-chapter" );
-    vlc_value_t val;
-    val.b_bool = true;
-    var_Set( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
-                            "next-chapter":"next-title", val );
+    var_SetBool( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
+                            "next-chapter":"next-title", true );
 
     vlc_object_release( p_input_thread );
 }
@@ -996,10 +1030,8 @@ void libvlc_media_player_previous_chapter(
         return;
 
     int i_type = var_Type( p_input_thread, "next-chapter" );
-    vlc_value_t val;
-    val.b_bool = true;
-    var_Set( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
-                            "prev-chapter":"prev-title", val );
+    var_SetBool( p_input_thread, (i_type & VLC_VAR_TYPE) != 0 ?
+                            "prev-chapter":"prev-title", true );
 
     vlc_object_release( p_input_thread );
 }
@@ -1043,18 +1075,21 @@ void libvlc_media_player_set_rate(
                                  libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
-    vlc_value_t val;
-
-    if( rate <= 0 )
-        RAISEVOID( "Rate value is invalid" );
+    bool b_can_rewind;
 
-    val.i_int = 1000.0f/rate;
+    p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
+    if( !p_input_thread )
+        return;
 
-    p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
-    if ( !p_input_thread )
+    b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
+    if( (rate < 0.0) && !b_can_rewind )
+    {
+        vlc_object_release( p_input_thread );
+        libvlc_exception_raise( p_e, "Rate value is invalid" );
         return;
+    }
 
-    var_Set( p_input_thread, "rate", val );
+    var_SetInteger( p_input_thread, "rate", 1000.0f/rate );
     vlc_object_release( p_input_thread );
 }
 
@@ -1064,12 +1099,19 @@ float libvlc_media_player_get_rate(
 {
     input_thread_t *p_input_thread;
     vlc_value_t val;
+    bool b_can_rewind;
 
-    p_input_thread = libvlc_get_input_thread ( p_mi, p_e);
-    if ( !p_input_thread )
-        return -1.0;
+    p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
+    if( !p_input_thread )
+        return 0.0;  /* rate < 0 indicates rewind */
 
     var_Get( p_input_thread, "rate", &val );
+    b_can_rewind = var_GetBool( p_input_thread, "can-rewind" );
+    if( (val.i_int < 0) && !b_can_rewind )
+    {
+        libvlc_exception_raise( p_e, "invalid rate" );
+        return 0.0;
+    }
     vlc_object_release( p_input_thread );
 
     return (float)1000.0f/val.i_int;
@@ -1080,21 +1122,30 @@ libvlc_state_t libvlc_media_player_get_state(
                                  libvlc_exception_t *p_e )
 {
     input_thread_t *p_input_thread;
+    libvlc_state_t state = libvlc_Ended;
     vlc_value_t val;
 
     p_input_thread = libvlc_get_input_thread ( p_mi, p_e );
-    if ( !p_input_thread )
+    if( !p_input_thread )
     {
         /* We do return the right value, no need to throw an exception */
         if( libvlc_exception_raised( p_e ) )
             libvlc_exception_clear( p_e );
-        return libvlc_Ended;
+        return state;
     }
 
     var_Get( p_input_thread, "state", &val );
-    vlc_object_release( p_input_thread );
+    state = vlc_to_libvlc_state(val.i_int);
 
-    return vlc_to_libvlc_state(val.i_int);
+    if( state == libvlc_Playing )
+    {
+        float caching;
+        caching = var_GetFloat( p_input_thread, "cache" );
+        if( caching > 0.0 && caching < 1.0 )
+            state = libvlc_Buffering;
+    }
+    vlc_object_release( p_input_thread );
+    return state;
 }
 
 int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
@@ -1111,7 +1162,7 @@ int libvlc_media_player_is_seekable( libvlc_media_player_t *p_mi,
             libvlc_exception_clear( p_e );
         return false;
     }
-    var_Get( p_input_thread, "seekable", &val );
+    var_Get( p_input_thread, "can-seek", &val );
     vlc_object_release( p_input_thread );
 
     return val.b_bool;
@@ -1124,6 +1175,8 @@ libvlc_track_description_t *
                                       libvlc_exception_t *p_e )
 {
     input_thread_t *p_input = libvlc_get_input_thread( p_mi, p_e );
+    libvlc_track_description_t *p_track_description = NULL,
+                               *p_actual, *p_previous;
 
     if( !p_input )
         return NULL;
@@ -1131,18 +1184,16 @@ libvlc_track_description_t *
     vlc_value_t val_list, text_list;
     var_Change( p_input, psz_variable, VLC_VAR_GETLIST, &val_list, &text_list);
 
-    if( val_list.p_list->i_count <= 0 ) /* no tracks */
-        return NULL;
+    /* no tracks */
+    if( val_list.p_list->i_count <= 0 )
+        goto end;
 
-    libvlc_track_description_t *p_track_description, *p_actual, *p_previous;
     p_track_description = ( libvlc_track_description_t * )
         malloc( sizeof( libvlc_track_description_t ) );
     if ( !p_track_description )
     {
-        var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
-        vlc_object_release( p_input );
         libvlc_exception_raise( p_e, "no enough memory" );
-        return NULL;
+        goto end;
     }
     p_actual = p_track_description;
     p_previous = NULL;
@@ -1155,10 +1206,8 @@ libvlc_track_description_t *
             if ( !p_actual )
             {
                 libvlc_track_description_release( p_track_description );
-                var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
-                vlc_object_release( p_input );
                 libvlc_exception_raise( p_e, "no enough memory" );
-                return NULL;
+                goto end;
             }
         }
         p_actual->i_id = val_list.p_list->p_values[i].i_int;
@@ -1169,16 +1218,18 @@ libvlc_track_description_t *
         p_previous = p_actual;
         p_actual =  NULL;
     }
-    var_Change( p_input, psz_variable, VLC_VAR_FREELIST, &val_list, &text_list);
+
+end:
+    var_FreeList( &val_list, &text_list );
     vlc_object_release( p_input );
 
     return p_track_description;
 }
 
-void libvlc_track_description_release( libvlc_track_description_t *p_track_description )
+void libvlc_track_description_release( libvlc_track_description_t *p_td )
 {
     libvlc_track_description_t *p_actual, *p_before;
-    p_actual = p_track_description;
+    p_actual = p_td;
 
     while ( p_actual )
     {