]> git.sesse.net Git - vlc/blobdiff - modules/control/rc.c
Use var_InheritString for --decklink-video-connection.
[vlc] / modules / control / rc.c
index b2134cb79dc3d65fe8c87160917e0423dcdba6cc..dbab111df25fba783f6c0ccdc5532f2d3dadadda 100644 (file)
@@ -34,7 +34,6 @@
 #include <vlc_plugin.h>
 
 #include <errno.h>                                                 /* ENOMEM */
-#include <ctype.h>
 #include <signal.h>
 #include <assert.h>
 
 #include <vlc_vout.h>
 #include <vlc_osd.h>
 #include <vlc_playlist.h>
+#include <vlc_keys.h>
 
 #ifdef HAVE_UNISTD_H
 #    include <unistd.h>
 #endif
-
-#ifdef HAVE_SYS_TIME_H
-#    include <sys/time.h>
-#endif
 #include <sys/types.h>
 
 #include <vlc_network.h>
-#include "vlc_url.h"
+#include <vlc_url.h>
 
 #include <vlc_charset.h>
 
-#if defined(AF_UNIX) && !defined(AF_LOCAL)
-#    define AF_LOCAL AF_UNIX
+#if defined(PF_UNIX) && !defined(PF_LOCAL)
+#    define PF_LOCAL PF_UNIX
 #endif
 
 #if defined(AF_LOCAL) && ! defined(WIN32)
@@ -117,14 +113,10 @@ static int  Statistics   ( vlc_object_t *, char const *,
 static int updateStatistics( intf_thread_t *, input_item_t *);
 
 /* Status Callbacks */
-static int TimeOffsetChanged( vlc_object_t *, char const *,
-                              vlc_value_t, vlc_value_t , void * );
-static int VolumeChanged    ( vlc_object_t *, char const *,
-                              vlc_value_t, vlc_value_t, void * );
-static int StateChanged     ( vlc_object_t *, char const *,
-                              vlc_value_t, vlc_value_t, void * );
-static int RateChanged      ( vlc_object_t *, char const *,
-                              vlc_value_t, vlc_value_t, void * );
+static int VolumeChanged( vlc_object_t *, char const *,
+                          vlc_value_t, vlc_value_t, void * );
+static int InputEvent( vlc_object_t *, char const *,
+                       vlc_value_t, vlc_value_t, void * );
 
 struct intf_sys_t
 {
@@ -134,7 +126,9 @@ struct intf_sys_t
 
     /* status changes */
     vlc_mutex_t       status_lock;
-    playlist_status_t i_last_state;
+    int               i_last_state;
+    playlist_t        *p_playlist;
+    bool              b_input_buffering;
 
 #ifdef WIN32
     HANDLE hConsoleIn;
@@ -192,17 +186,17 @@ vlc_module_begin ()
     set_category( CAT_INTERFACE )
     set_subcategory( SUBCAT_INTERFACE_MAIN )
     set_description( N_("Remote control interface") )
-    add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, true )
+    add_bool( "rc-show-pos", false, NULL, POS_TEXT, POS_LONGTEXT, true )
 
 #ifdef WIN32
-    add_bool( "rc-quiet", 0, NULL, QUIET_TEXT, QUIET_LONGTEXT, false )
+    add_bool( "rc-quiet", false, NULL, QUIET_TEXT, QUIET_LONGTEXT, false )
 #else
 #if defined (HAVE_ISATTY)
-    add_bool( "rc-fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, true )
+    add_bool( "rc-fake-tty", false, NULL, TTY_TEXT, TTY_LONGTEXT, true )
 #endif
-    add_string( "rc-unix", 0, NULL, UNIX_TEXT, UNIX_LONGTEXT, true )
+    add_string( "rc-unix", NULL, NULL, UNIX_TEXT, UNIX_LONGTEXT, true )
 #endif
-    add_string( "rc-host", 0, NULL, HOST_TEXT, HOST_LONGTEXT, true )
+    add_string( "rc-host", NULL, NULL, HOST_TEXT, HOST_LONGTEXT, true )
 
     set_capability( "interface", 20 )
 
@@ -221,14 +215,14 @@ static int Activate( vlc_object_t *p_this )
 #ifndef WIN32
 #if defined(HAVE_ISATTY)
     /* Check that stdin is a TTY */
-    if( !config_GetInt( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
+    if( !var_InheritBool( p_intf, "rc-fake-tty" ) && !isatty( 0 ) )
     {
         msg_Warn( p_intf, "fd 0 is not a TTY" );
         return VLC_EGENERIC;
     }
 #endif
 
-    psz_unix_path = config_GetPsz( p_intf, "rc-unix" );
+    psz_unix_path = var_InheritString( p_intf, "rc-unix" );
     if( psz_unix_path )
     {
         int i_socket;
@@ -244,7 +238,7 @@ static int Activate( vlc_object_t *p_this )
 
         msg_Dbg( p_intf, "trying UNIX socket" );
 
-        if( (i_socket = socket( AF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
+        if( (i_socket = socket( PF_LOCAL, SOCK_STREAM, 0 ) ) < 0 )
         {
             msg_Warn( p_intf, "can't open socket: %m" );
             free( psz_unix_path );
@@ -296,7 +290,7 @@ static int Activate( vlc_object_t *p_this )
 #endif /* !WIN32 */
 
     if( ( pi_socket == NULL ) &&
-        ( psz_host = config_GetPsz( p_intf, "rc-host" ) ) != NULL )
+        ( psz_host = var_InheritString( p_intf, "rc-host" ) ) != NULL )
     {
         vlc_url_t url;
 
@@ -327,6 +321,7 @@ static int Activate( vlc_object_t *p_this )
     p_intf->p_sys->psz_unix_path = psz_unix_path;
     vlc_mutex_init( &p_intf->p_sys->status_lock );
     p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
+    p_intf->p_sys->b_input_buffering = false;
 
     /* Non-buffered stdout */
     setvbuf( stdout, (char *)NULL, _IOLBF, 0 );
@@ -334,13 +329,13 @@ static int Activate( vlc_object_t *p_this )
     p_intf->pf_run = Run;
 
 #ifdef WIN32
-    p_intf->p_sys->b_quiet = config_GetInt( p_intf, "rc-quiet" );
+    p_intf->p_sys->b_quiet = var_InheritBool( p_intf, "rc-quiet" );
     if( !p_intf->p_sys->b_quiet ) { CONSOLE_INTRO_MSG; }
 #else
     CONSOLE_INTRO_MSG;
 #endif
 
-    msg_rc( _("Remote control interface initialized. Type `help' for help.") );
+    msg_rc( "%s", _("Remote control interface initialized. Type `help' for help.") );
     return VLC_SUCCESS;
 }
 
@@ -410,6 +405,7 @@ static void RegisterCallbacks( intf_thread_t *p_intf )
     ADD( "faster", VOID, Input )
     ADD( "slower", VOID, Input )
     ADD( "normal", VOID, Input )
+    ADD( "frame", VOID, Input )
 
     ADD( "atrack", STRING, Input )
     ADD( "vtrack", STRING, Input )
@@ -442,11 +438,11 @@ static void RegisterCallbacks( intf_thread_t *p_intf )
  *****************************************************************************/
 static void Run( intf_thread_t *p_intf )
 {
-    input_thread_t * p_input;
-    playlist_t *     p_playlist;
+    input_thread_t * p_input = NULL;
+    playlist_t *     p_playlist = pl_Get( p_intf );
 
     char p_buffer[ MAX_LINE_LENGTH + 1 ];
-    bool b_showpos = config_GetInt( p_intf, "rc-show-pos" );
+    bool b_showpos = var_InheritBool( p_intf, "rc-show-pos" );
     bool b_longhelp = false;
 
     int  i_size = 0;
@@ -455,15 +451,14 @@ static void Run( intf_thread_t *p_intf )
     int  canc = vlc_savecancel();
 
     p_buffer[0] = 0;
-    p_input = NULL;
-    p_playlist = NULL;
 
     /* Register commands that will be cleaned up upon object destruction */
+    p_intf->p_sys->p_playlist = p_playlist;
     RegisterCallbacks( p_intf );
 
     /* status callbacks */
     /* Listen to audio volume updates */
-    var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, p_intf );
+    var_AddCallback( p_playlist, "volume-change", VolumeChanged, p_intf );
 
 #ifdef WIN32
     /* Get the file descriptor of the console input */
@@ -484,8 +479,7 @@ static void Run( intf_thread_t *p_intf )
             p_intf->p_sys->i_socket == -1 )
         {
             p_intf->p_sys->i_socket =
-                net_Accept( p_intf, p_intf->p_sys->pi_socket_listen,
-                            INTF_IDLE_SLEEP );
+                net_Accept( p_intf, p_intf->p_sys->pi_socket_listen );
             if( p_intf->p_sys->i_socket == -1 ) continue;
         }
 
@@ -494,20 +488,7 @@ static void Run( intf_thread_t *p_intf )
         /* Manage the input part */
         if( p_input == NULL )
         {
-            if( p_playlist )
-            {
-                p_input = vlc_object_find( p_playlist, VLC_OBJECT_INPUT,
-                                                       FIND_CHILD );
-            }
-            else
-            {
-                p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT,
-                                                   FIND_ANYWHERE );
-                if( p_input )
-                {
-                    p_playlist = pl_Hold( p_input );
-                }
-            }
+            p_input = playlist_CurrentInput( p_playlist );
             /* New input has been registered */
             if( p_input )
             {
@@ -518,33 +499,21 @@ static void Run( intf_thread_t *p_intf )
                     msg_rc( STATUS_CHANGE "( new input: %s )", psz_uri );
                     free( psz_uri );
                     msg_rc( STATUS_CHANGE "( audio volume: %d )",
-                            config_GetInt( p_intf, "volume" ));
+                            (int)config_GetInt( p_intf, "volume" ));
                 }
-                var_AddCallback( p_input, "state", StateChanged, p_intf );
-                var_AddCallback( p_input, "rate-faster", RateChanged, p_intf );
-                var_AddCallback( p_input, "rate-slower", RateChanged, p_intf );
-                var_AddCallback( p_input, "rate", RateChanged, p_intf );
-                var_AddCallback( p_input, "time-offset", TimeOffsetChanged,
-                                 p_intf );
+                var_AddCallback( p_input, "intf-event", InputEvent, p_intf );
             }
         }
         else if( p_input->b_dead )
         {
-            var_DelCallback( p_input, "state", StateChanged, p_intf );
-            var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
-            var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
-            var_DelCallback( p_input, "rate", RateChanged, p_intf );
-            var_DelCallback( p_input, "time-offset", TimeOffsetChanged,
-                             p_intf );
+            var_DelCallback( p_input, "intf-event", InputEvent, p_intf );
             vlc_object_release( p_input );
             p_input = NULL;
 
             if( p_playlist )
             {
-                PL_LOCK;
-                p_intf->p_sys->i_last_state = (int) PLAYLIST_STOPPED;
+                p_intf->p_sys->i_last_state = PLAYLIST_STOPPED;
                 msg_rc( STATUS_CHANGE "( stop state: 0 )" );
-                PL_UNLOCK;
             }
         }
 
@@ -553,6 +522,8 @@ static void Run( intf_thread_t *p_intf )
         {
             PL_LOCK;
             int status = playlist_Status( p_playlist );
+            PL_UNLOCK;
+
             if( p_intf->p_sys->i_last_state != status )
             {
                 if( status == PLAYLIST_STOPPED )
@@ -571,7 +542,6 @@ static void Run( intf_thread_t *p_intf )
                     msg_rc( STATUS_CHANGE "( pause state: 4 )" );
                 }
             }
-            PL_UNLOCK;
         }
 
         if( p_input && b_showpos )
@@ -763,46 +733,34 @@ static void Run( intf_thread_t *p_intf )
         }
         else if( !strcmp( psz_cmd, "key" ) || !strcmp( psz_cmd, "hotkey" ) )
         {
-            var_SetInteger( p_intf->p_libvlc, "key-pressed",
-                            config_GetInt( p_intf, psz_arg ) );
+            var_SetInteger( p_intf->p_libvlc, "key-action",
+                            vlc_GetActionId( psz_arg ) );
         }
         else switch( psz_cmd[0] )
         {
         case 'f':
         case 'F':
+        {
+            bool fs;
+
+            if( !strncasecmp( psz_arg, "on", 2 ) )
+                var_SetBool( p_playlist, "fullscreen", fs = true );
+            else if( !strncasecmp( psz_arg, "off", 3 ) )
+                var_SetBool( p_playlist, "fullscreen", fs = false );
+            else
+                fs = var_ToggleBool( p_playlist, "fullscreen" );
+
             if( p_input )
             {
-                vout_thread_t *p_vout;
-                p_vout = vlc_object_find( p_input,
-                                          VLC_OBJECT_VOUT, FIND_CHILD );
-
+                vout_thread_t *p_vout = input_GetVout( p_input );
                 if( p_vout )
                 {
-                    vlc_value_t val;
-                    bool b_update = false;
-                    var_Get( p_vout, "fullscreen", &val );
-                    val.b_bool = !val.b_bool;
-                    if( !strncmp( psz_arg, "on", 2 )
-                        && ( val.b_bool == true ) )
-                    {
-                        b_update = true;
-                        val.b_bool = true;
-                    }
-                    else if( !strncmp( psz_arg, "off", 3 )
-                             && ( val.b_bool == false ) )
-                    {
-                        b_update = true;
-                        val.b_bool = false;
-                    }
-                    else if( strncmp( psz_arg, "off", 3 )
-                             && strncmp( psz_arg, "on", 2 ) )
-                        b_update = true;
-                    if( b_update ) var_Set( p_vout, "fullscreen", val );
+                    var_SetBool( p_vout, "fullscreen", fs );
                     vlc_object_release( p_vout );
                 }
             }
             break;
-
+        }
         case 's':
         case 'S':
             ;
@@ -826,144 +784,114 @@ static void Run( intf_thread_t *p_intf )
 
     if( p_input )
     {
-        var_DelCallback( p_input, "state", StateChanged, p_intf );
-        var_DelCallback( p_input, "rate-faster", RateChanged, p_intf );
-        var_DelCallback( p_input, "rate-slower", RateChanged, p_intf );
-        var_DelCallback( p_input, "rate", RateChanged, p_intf );
-        var_DelCallback( p_input, "time-offset", TimeOffsetChanged, p_intf );
+        var_DelCallback( p_input, "intf-event", InputEvent, p_intf );
         vlc_object_release( p_input );
-        p_input = NULL;
-    }
-
-    if( p_playlist )
-    {
-        vlc_object_release( p_playlist );
-        p_playlist = NULL;
     }
 
-    var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, p_intf );
+    var_DelCallback( p_playlist, "volume-change", VolumeChanged, p_intf );
     vlc_restorecancel( canc );
 }
 
 static void Help( intf_thread_t *p_intf, bool b_longhelp)
 {
-    msg_rc(_("+----[ Remote control commands ]"));
+    msg_rc("%s", _("+----[ Remote control commands ]"));
     msg_rc(  "| ");
-    msg_rc(_("| add XYZ  . . . . . . . . . . . . add XYZ to playlist"));
-    msg_rc(_("| enqueue XYZ  . . . . . . . . . queue XYZ to playlist"));
-    msg_rc(_("| playlist . . . . .  show items currently in playlist"));
-    msg_rc(_("| play . . . . . . . . . . . . . . . . . . play stream"));
-    msg_rc(_("| stop . . . . . . . . . . . . . . . . . . stop stream"));
-    msg_rc(_("| next . . . . . . . . . . . . . .  next playlist item"));
-    msg_rc(_("| prev . . . . . . . . . . . .  previous playlist item"));
-    msg_rc(_("| goto . . . . . . . . . . . . . .  goto item at index"));
-    msg_rc(_("| repeat [on|off] . . . .  toggle playlist item repeat"));
-    msg_rc(_("| loop [on|off] . . . . . . . . . toggle playlist loop"));
-    msg_rc(_("| random [on|off] . . . . . . .  toggle random jumping"));
-    msg_rc(_("| clear . . . . . . . . . . . . . . clear the playlist"));
-    msg_rc(_("| status . . . . . . . . . . . current playlist status"));
-    msg_rc(_("| title [X]  . . . . . . set/get title in current item"));
-    msg_rc(_("| title_n  . . . . . . . .  next title in current item"));
-    msg_rc(_("| title_p  . . . . . .  previous title in current item"));
-    msg_rc(_("| chapter [X]  . . . . set/get chapter in current item"));
-    msg_rc(_("| chapter_n  . . . . . .  next chapter in current item"));
-    msg_rc(_("| chapter_p  . . . .  previous chapter in current item"));
+    msg_rc("%s", _("| add XYZ  . . . . . . . . . . . . add XYZ to playlist"));
+    msg_rc("%s", _("| enqueue XYZ  . . . . . . . . . queue XYZ to playlist"));
+    msg_rc("%s", _("| playlist . . . . .  show items currently in playlist"));
+    msg_rc("%s", _("| play . . . . . . . . . . . . . . . . . . play stream"));
+    msg_rc("%s", _("| stop . . . . . . . . . . . . . . . . . . stop stream"));
+    msg_rc("%s", _("| next . . . . . . . . . . . . . .  next playlist item"));
+    msg_rc("%s", _("| prev . . . . . . . . . . . .  previous playlist item"));
+    msg_rc("%s", _("| goto . . . . . . . . . . . . . .  goto item at index"));
+    msg_rc("%s", _("| repeat [on|off] . . . .  toggle playlist item repeat"));
+    msg_rc("%s", _("| loop [on|off] . . . . . . . . . toggle playlist loop"));
+    msg_rc("%s", _("| random [on|off] . . . . . . .  toggle random jumping"));
+    msg_rc("%s", _("| clear . . . . . . . . . . . . . . clear the playlist"));
+    msg_rc("%s", _("| status . . . . . . . . . . . current playlist status"));
+    msg_rc("%s", _("| title [X]  . . . . . . set/get title in current item"));
+    msg_rc("%s", _("| title_n  . . . . . . . .  next title in current item"));
+    msg_rc("%s", _("| title_p  . . . . . .  previous title in current item"));
+    msg_rc("%s", _("| chapter [X]  . . . . set/get chapter in current item"));
+    msg_rc("%s", _("| chapter_n  . . . . . .  next chapter in current item"));
+    msg_rc("%s", _("| chapter_p  . . . .  previous chapter in current item"));
     msg_rc(  "| ");
-    msg_rc(_("| seek X . . . seek in seconds, for instance `seek 12'"));
-    msg_rc(_("| pause  . . . . . . . . . . . . . . . .  toggle pause"));
-    msg_rc(_("| fastforward  . . . . . . . .  .  set to maximum rate"));
-    msg_rc(_("| rewind  . . . . . . . . . . . .  set to minimum rate"));
-    msg_rc(_("| faster . . . . . . . . . .  faster playing of stream"));
-    msg_rc(_("| slower . . . . . . . . . .  slower playing of stream"));
-    msg_rc(_("| normal . . . . . . . . . .  normal playing of stream"));
-    msg_rc(_("| f [on|off] . . . . . . . . . . . . toggle fullscreen"));
-    msg_rc(_("| info . . . . .  information about the current stream"));
-    msg_rc(_("| stats  . . . . . . . .  show statistical information"));
-    msg_rc(_("| get_time . . seconds elapsed since stream's beginning"));
-    msg_rc(_("| is_playing . . . .  1 if a stream plays, 0 otherwise"));
-    msg_rc(_("| get_title . . . . .  the title of the current stream"));
-    msg_rc(_("| get_length . . . .  the length of the current stream"));
+    msg_rc("%s", _("| seek X . . . seek in seconds, for instance `seek 12'"));
+    msg_rc("%s", _("| pause  . . . . . . . . . . . . . . . .  toggle pause"));
+    msg_rc("%s", _("| fastforward  . . . . . . . .  .  set to maximum rate"));
+    msg_rc("%s", _("| rewind  . . . . . . . . . . . .  set to minimum rate"));
+    msg_rc("%s", _("| faster . . . . . . . . . .  faster playing of stream"));
+    msg_rc("%s", _("| slower . . . . . . . . . .  slower playing of stream"));
+    msg_rc("%s", _("| normal . . . . . . . . . .  normal playing of stream"));
+    msg_rc("%s", _("| frame. . . . . . . . . .  play frame by frame"));
+    msg_rc("%s", _("| f [on|off] . . . . . . . . . . . . toggle fullscreen"));
+    msg_rc("%s", _("| info . . . . .  information about the current stream"));
+    msg_rc("%s", _("| stats  . . . . . . . .  show statistical information"));
+    msg_rc("%s", _("| get_time . . seconds elapsed since stream's beginning"));
+    msg_rc("%s", _("| is_playing . . . .  1 if a stream plays, 0 otherwise"));
+    msg_rc("%s", _("| get_title . . . . .  the title of the current stream"));
+    msg_rc("%s", _("| get_length . . . .  the length of the current stream"));
     msg_rc(  "| ");
-    msg_rc(_("| volume [X] . . . . . . . . . .  set/get audio volume"));
-    msg_rc(_("| volup [X]  . . . . . . .  raise audio volume X steps"));
-    msg_rc(_("| voldown [X]  . . . . . .  lower audio volume X steps"));
-    msg_rc(_("| adev [X] . . . . . . . . . . .  set/get audio device"));
-    msg_rc(_("| achan [X]. . . . . . . . . .  set/get audio channels"));
-    msg_rc(_("| atrack [X] . . . . . . . . . . . set/get audio track"));
-    msg_rc(_("| vtrack [X] . . . . . . . . . . . set/get video track"));
-    msg_rc(_("| vratio [X]  . . . . . . . set/get video aspect ratio"));
-    msg_rc(_("| vcrop [X]  . . . . . . . . . . .  set/get video crop"));
-    msg_rc(_("| vzoom [X]  . . . . . . . . . . .  set/get video zoom"));
-    msg_rc(_("| snapshot . . . . . . . . . . . . take video snapshot"));
-    msg_rc(_("| strack [X] . . . . . . . . . set/get subtitles track"));
-    msg_rc(_("| key [hotkey name] . . . . . .  simulate hotkey press"));
-    msg_rc(_("| menu . . [on|off|up|down|left|right|select] use menu"));
+    msg_rc("%s", _("| volume [X] . . . . . . . . . .  set/get audio volume"));
+    msg_rc("%s", _("| volup [X]  . . . . . . .  raise audio volume X steps"));
+    msg_rc("%s", _("| voldown [X]  . . . . . .  lower audio volume X steps"));
+    msg_rc("%s", _("| adev [X] . . . . . . . . . . .  set/get audio device"));
+    msg_rc("%s", _("| achan [X]. . . . . . . . . .  set/get audio channels"));
+    msg_rc("%s", _("| atrack [X] . . . . . . . . . . . set/get audio track"));
+    msg_rc("%s", _("| vtrack [X] . . . . . . . . . . . set/get video track"));
+    msg_rc("%s", _("| vratio [X]  . . . . . . . set/get video aspect ratio"));
+    msg_rc("%s", _("| vcrop [X]  . . . . . . . . . . .  set/get video crop"));
+    msg_rc("%s", _("| vzoom [X]  . . . . . . . . . . .  set/get video zoom"));
+    msg_rc("%s", _("| snapshot . . . . . . . . . . . . take video snapshot"));
+    msg_rc("%s", _("| strack [X] . . . . . . . . . set/get subtitles track"));
+    msg_rc("%s", _("| key [hotkey name] . . . . . .  simulate hotkey press"));
+    msg_rc("%s", _("| menu . . [on|off|up|down|left|right|select] use menu"));
     msg_rc(  "| ");
 
     if (b_longhelp)
     {
-        msg_rc(_("| @name marq-marquee  STRING  . . overlay STRING in video"));
-        msg_rc(_("| @name marq-x X . . . . . . . . . . . .offset from left"));
-        msg_rc(_("| @name marq-y Y . . . . . . . . . . . . offset from top"));
-        msg_rc(_("| @name marq-position #. . .  .relative position control"));
-        msg_rc(_("| @name marq-color # . . . . . . . . . . font color, RGB"));
-        msg_rc(_("| @name marq-opacity # . . . . . . . . . . . . . opacity"));
-        msg_rc(_("| @name marq-timeout T. . . . . . . . . . timeout, in ms"));
-        msg_rc(_("| @name marq-size # . . . . . . . . font size, in pixels"));
+        msg_rc("%s", _("| @name marq-marquee  STRING  . . overlay STRING in video"));
+        msg_rc("%s", _("| @name marq-x X . . . . . . . . . . . .offset from left"));
+        msg_rc("%s", _("| @name marq-y Y . . . . . . . . . . . . offset from top"));
+        msg_rc("%s", _("| @name marq-position #. . .  .relative position control"));
+        msg_rc("%s", _("| @name marq-color # . . . . . . . . . . font color, RGB"));
+        msg_rc("%s", _("| @name marq-opacity # . . . . . . . . . . . . . opacity"));
+        msg_rc("%s", _("| @name marq-timeout T. . . . . . . . . . timeout, in ms"));
+        msg_rc("%s", _("| @name marq-size # . . . . . . . . font size, in pixels"));
         msg_rc(  "| ");
-        msg_rc(_("| @name logo-file STRING . . .the overlay file path/name"));
-        msg_rc(_("| @name logo-x X . . . . . . . . . . . .offset from left"));
-        msg_rc(_("| @name logo-y Y . . . . . . . . . . . . offset from top"));
-        msg_rc(_("| @name logo-position #. . . . . . . . relative position"));
-        msg_rc(_("| @name logo-transparency #. . . . . . . . .transparency"));
+        msg_rc("%s", _("| @name logo-file STRING . . .the overlay file path/name"));
+        msg_rc("%s", _("| @name logo-x X . . . . . . . . . . . .offset from left"));
+        msg_rc("%s", _("| @name logo-y Y . . . . . . . . . . . . offset from top"));
+        msg_rc("%s", _("| @name logo-position #. . . . . . . . relative position"));
+        msg_rc("%s", _("| @name logo-transparency #. . . . . . . . .transparency"));
         msg_rc(  "| ");
-        msg_rc(_("| @name mosaic-alpha # . . . . . . . . . . . . . . alpha"));
-        msg_rc(_("| @name mosaic-height #. . . . . . . . . . . . . .height"));
-        msg_rc(_("| @name mosaic-width # . . . . . . . . . . . . . . width"));
-        msg_rc(_("| @name mosaic-xoffset # . . . .top left corner position"));
-        msg_rc(_("| @name mosaic-yoffset # . . . .top left corner position"));
-        msg_rc(_("| @name mosaic-offsets x,y(,x,y)*. . . . list of offsets"));
-        msg_rc(_("| @name mosaic-align 0..2,4..6,8..10. . .mosaic alignment"));
-        msg_rc(_("| @name mosaic-vborder # . . . . . . . . vertical border"));
-        msg_rc(_("| @name mosaic-hborder # . . . . . . . horizontal border"));
-        msg_rc(_("| @name mosaic-position {0=auto,1=fixed} . . . .position"));
-        msg_rc(_("| @name mosaic-rows #. . . . . . . . . . .number of rows"));
-        msg_rc(_("| @name mosaic-cols #. . . . . . . . . . .number of cols"));
-        msg_rc(_("| @name mosaic-order id(,id)* . . . . order of pictures "));
-        msg_rc(_("| @name mosaic-keep-aspect-ratio {0,1} . . .aspect ratio"));
+        msg_rc("%s", _("| @name mosaic-alpha # . . . . . . . . . . . . . . alpha"));
+        msg_rc("%s", _("| @name mosaic-height #. . . . . . . . . . . . . .height"));
+        msg_rc("%s", _("| @name mosaic-width # . . . . . . . . . . . . . . width"));
+        msg_rc("%s", _("| @name mosaic-xoffset # . . . .top left corner position"));
+        msg_rc("%s", _("| @name mosaic-yoffset # . . . .top left corner position"));
+        msg_rc("%s", _("| @name mosaic-offsets x,y(,x,y)*. . . . list of offsets"));
+        msg_rc("%s", _("| @name mosaic-align 0..2,4..6,8..10. . .mosaic alignment"));
+        msg_rc("%s", _("| @name mosaic-vborder # . . . . . . . . vertical border"));
+        msg_rc("%s", _("| @name mosaic-hborder # . . . . . . . horizontal border"));
+        msg_rc("%s", _("| @name mosaic-position {0=auto,1=fixed} . . . .position"));
+        msg_rc("%s", _("| @name mosaic-rows #. . . . . . . . . . .number of rows"));
+        msg_rc("%s", _("| @name mosaic-cols #. . . . . . . . . . .number of cols"));
+        msg_rc("%s", _("| @name mosaic-order id(,id)* . . . . order of pictures "));
+        msg_rc("%s", _("| @name mosaic-keep-aspect-ratio {0,1} . . .aspect ratio"));
         msg_rc(  "| ");
     }
-    msg_rc(_("| help . . . . . . . . . . . . . . . this help message"));
-    msg_rc(_("| longhelp . . . . . . . . . . . a longer help message"));
-    msg_rc(_("| logout . . . . . . .  exit (if in socket connection)"));
-    msg_rc(_("| quit . . . . . . . . . . . . . . . . . . .  quit vlc"));
+    msg_rc("%s", _("| help . . . . . . . . . . . . . . . this help message"));
+    msg_rc("%s", _("| longhelp . . . . . . . . . . . a longer help message"));
+    msg_rc("%s", _("| logout . . . . . . .  exit (if in socket connection)"));
+    msg_rc("%s", _("| quit . . . . . . . . . . . . . . . . . . .  quit vlc"));
     msg_rc(  "| ");
-    msg_rc(_("+----[ end of help ]"));
+    msg_rc("%s", _("+----[ end of help ]"));
 }
 
 /********************************************************************
  * Status callback routines
  ********************************************************************/
-static int TimeOffsetChanged( vlc_object_t *p_this, char const *psz_cmd,
-    vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
-    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd);
-    VLC_UNUSED(oldval); VLC_UNUSED(newval);
-    intf_thread_t *p_intf = (intf_thread_t*)p_data;
-    input_thread_t *p_input = NULL;
-
-    vlc_mutex_lock( &p_intf->p_sys->status_lock );
-    p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
-    if( p_input )
-    {
-        msg_rc( STATUS_CHANGE "( time-offset: %"PRId64"s )",
-                (var_GetTime( p_input, "time-offset" )/1000000) );
-        vlc_object_release( p_input );
-    }
-    vlc_mutex_unlock( &p_intf->p_sys->status_lock );
-    return VLC_SUCCESS;
-}
-
 static int VolumeChanged( vlc_object_t *p_this, char const *psz_cmd,
     vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
@@ -972,64 +900,96 @@ static int VolumeChanged( vlc_object_t *p_this, char const *psz_cmd,
 
     vlc_mutex_lock( &p_intf->p_sys->status_lock );
     msg_rc( STATUS_CHANGE "( audio volume: %d )",
-            config_GetInt( p_this, "volume") );
+            (int)config_GetInt( p_this, "volume") );
     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
     return VLC_SUCCESS;
 }
 
-static int StateChanged( vlc_object_t *p_this, char const *psz_cmd,
-    vlc_value_t oldval, vlc_value_t newval, void *p_data )
+static void StateChanged( intf_thread_t *p_intf, input_thread_t *p_input )
 {
-    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
-    intf_thread_t *p_intf = (intf_thread_t*)p_data;
-    playlist_t    *p_playlist = NULL;
-    char cmd[6];
+    playlist_t *p_playlist = p_intf->p_sys->p_playlist;
 
-    vlc_mutex_lock( &p_intf->p_sys->status_lock );
-    p_playlist = pl_Hold( p_intf );
     PL_LOCK;
-    int i_status = playlist_Status( p_playlist );
+    const int i_status = playlist_Status( p_playlist );
     PL_UNLOCK;
-    pl_Release( p_intf );
 
+    /* */
+    const char *psz_cmd;
     switch( i_status )
     {
     case PLAYLIST_STOPPED:
-        strcpy( cmd, "stop" );
+        psz_cmd = "stop";
         break;
     case PLAYLIST_RUNNING:
-        strcpy( cmd, "play" );
+        psz_cmd = "play";
         break;
     case PLAYLIST_PAUSED:
-        strcpy( cmd, "pause" );
+        psz_cmd = "pause";
         break;
     default:
-        cmd[0] = '\0';
-    } /* var_GetInteger( p_input, "state" )  */
-    msg_rc( STATUS_CHANGE "( %s state: %d ): %s", cmd, newval.i_int,
-            ppsz_input_state[ newval.i_int ] );
+        psz_cmd = "";
+        break;
+    }
 
+    /* */
+    const int i_state = var_GetInteger( p_input, "state" );
+
+    vlc_mutex_lock( &p_intf->p_sys->status_lock );
+    msg_rc( STATUS_CHANGE "( %s state: %d ): %s", psz_cmd,
+            i_state, ppsz_input_state[i_state] );
+    vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+}
+static void RateChanged( intf_thread_t *p_intf,
+                         input_thread_t *p_input )
+{
+    vlc_mutex_lock( &p_intf->p_sys->status_lock );
+    msg_rc( STATUS_CHANGE "( new rate: %.3f )",
+            var_GetFloat( p_input, "rate" ) );
+    vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+}
+static void PositionChanged( intf_thread_t *p_intf,
+                             input_thread_t *p_input )
+{
+    vlc_mutex_lock( &p_intf->p_sys->status_lock );
+    if( p_intf->p_sys->b_input_buffering )
+        msg_rc( STATUS_CHANGE "( time: %"PRId64"s )",
+                (var_GetTime( p_input, "time" )/1000000) );
+    p_intf->p_sys->b_input_buffering = false;
+    vlc_mutex_unlock( &p_intf->p_sys->status_lock );
+}
+static void CacheChanged( intf_thread_t *p_intf )
+{
+    vlc_mutex_lock( &p_intf->p_sys->status_lock );
+    p_intf->p_sys->b_input_buffering = true;
     vlc_mutex_unlock( &p_intf->p_sys->status_lock );
-    return VLC_SUCCESS;
 }
 
-static int RateChanged( vlc_object_t *p_this, char const *psz_cmd,
-    vlc_value_t oldval, vlc_value_t newval, void *p_data )
+static int InputEvent( vlc_object_t *p_this, char const *psz_cmd,
+                       vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
-    VLC_UNUSED(p_this); VLC_UNUSED(psz_cmd);
-    VLC_UNUSED(oldval); VLC_UNUSED(newval);
-    intf_thread_t *p_intf = (intf_thread_t*)p_data;
-    input_thread_t *p_input = NULL;
+    VLC_UNUSED(psz_cmd);
+    VLC_UNUSED(oldval);
+    input_thread_t *p_input = (input_thread_t*)p_this;
+    intf_thread_t *p_intf = p_data;
 
-    vlc_mutex_lock( &p_intf->p_sys->status_lock );
-    p_input = vlc_object_find( p_intf, VLC_OBJECT_INPUT, FIND_ANYWHERE );
-    if( p_input )
+    switch( newval.i_int )
     {
-        msg_rc( STATUS_CHANGE "( new rate: %d )",
-                var_GetInteger( p_input, "rate" ) );
-        vlc_object_release( p_input );
+    case INPUT_EVENT_STATE:
+    case INPUT_EVENT_DEAD:
+        StateChanged( p_intf, p_input );
+        break;
+    case INPUT_EVENT_RATE:
+        RateChanged( p_intf, p_input );
+        break;
+    case INPUT_EVENT_POSITION:
+        PositionChanged( p_intf, p_input );
+        break;
+    case INPUT_EVENT_CACHE:
+        CacheChanged( p_intf );
+        break;
+    default:
+        break;
     }
-    vlc_mutex_unlock( &p_intf->p_sys->status_lock );
     return VLC_SUCCESS;
 }
 
@@ -1041,92 +1001,88 @@ static int Input( vlc_object_t *p_this, char const *psz_cmd,
 {
     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    input_thread_t *p_input;
-    vlc_value_t     val;
+    input_thread_t *p_input =
+        playlist_CurrentInput( p_intf->p_sys->p_playlist );
+    int i_error = VLC_EGENERIC;
 
-    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
-    if( !p_input ) return VLC_ENOOBJ;
+    if( !p_input )
+        return VLC_ENOOBJ;
 
-    var_Get( p_input, "state", &val );
-    if( ( val.i_int == PAUSE_S ) &&
-        ( strcmp( psz_cmd, "pause" ) != 0 ) )
+    int state = var_GetInteger( p_input, "state" );
+    if( ( state == PAUSE_S ) &&
+        ( strcmp( psz_cmd, "pause" ) != 0 ) && (strcmp( psz_cmd,"frame") != 0 ) )
     {
-        msg_rc( _("Press menu select or pause to continue.") );
-        vlc_object_release( p_input );
-        return VLC_EGENERIC;
+        msg_rc( "%s", _("Press menu select or pause to continue.") );
     }
-
+    else
     /* Parse commands that only require an input */
     if( !strcmp( psz_cmd, "pause" ) )
     {
-        var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_PLAY_PAUSE );
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        playlist_Pause( p_intf->p_sys->p_playlist );
+        i_error = VLC_SUCCESS;
     }
     else if( !strcmp( psz_cmd, "seek" ) )
     {
         if( strlen( newval.psz_string ) > 0 &&
             newval.psz_string[strlen( newval.psz_string ) - 1] == '%' )
         {
-            val.f_float = (float)atof( newval.psz_string ) / 100.0;
-            var_Set( p_input, "position", val );
+            float f = atof( newval.psz_string ) / 100.0;
+            var_SetFloat( p_input, "position", f );
         }
         else
         {
-            val.i_time = ((int64_t)atoi( newval.psz_string )) * 1000000;
-            var_Set( p_input, "time", val );
+            mtime_t t = ((int64_t)atoi( newval.psz_string )) * CLOCK_FREQ;
+            var_SetTime( p_input, "time", t );
         }
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        i_error = VLC_SUCCESS;
     }
     else if ( !strcmp( psz_cmd, "fastforward" ) )
     {
         if( var_GetBool( p_input, "can-rate" ) )
         {
-            int i_rate = var_GetInteger( p_input, "rate" );
-            i_rate = (i_rate < 0) ? -i_rate : i_rate * 2;
-            var_SetInteger( p_input, "rate", i_rate );
+            float f_rate = var_GetFloat( p_input, "rate" );
+            f_rate = (f_rate < 0) ? -f_rate : f_rate * 2;
+            var_SetFloat( p_input, "rate", f_rate );
         }
         else
         {
             var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_FORWARD_EXTRASHORT );
         }
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        i_error = VLC_SUCCESS;
     }
     else if ( !strcmp( psz_cmd, "rewind" ) )
     {
         if( var_GetBool( p_input, "can-rewind" ) )
         {
-            int i_rate = var_GetInteger( p_input, "rate" );
-            i_rate = (i_rate > 0) ? -i_rate : i_rate / 2;
-            var_SetInteger( p_input, "rate", i_rate );
+            float f_rate = var_GetFloat( p_input, "rate" );
+            f_rate = (f_rate > 0) ? -f_rate : f_rate * 2;
+            var_SetFloat( p_input, "rate", f_rate );
         }
         else
         {
             var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_JUMP_BACKWARD_EXTRASHORT );
         }
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        i_error = VLC_SUCCESS;
     }
     else if ( !strcmp( psz_cmd, "faster" ) )
     {
-        var_Set( p_input, "rate-faster", val );
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        var_TriggerCallback( p_input, "rate-faster" );
+        i_error = VLC_SUCCESS;
     }
     else if ( !strcmp( psz_cmd, "slower" ) )
     {
-        var_Set( p_input, "rate-slower", val );
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        var_TriggerCallback( p_input, "rate-slower" );
+        i_error = VLC_SUCCESS;
     }
     else if ( !strcmp( psz_cmd, "normal" ) )
     {
-        val.i_int = INPUT_RATE_DEFAULT;
-        var_Set( p_input, "rate", val );
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        var_SetFloat( p_input, "rate", 1. );
+        i_error = VLC_SUCCESS;
+    }
+    else if ( !strcmp( psz_cmd, "frame" ) )
+    {
+       var_TriggerCallback( p_input, "frame-next" );
+        i_error = VLC_SUCCESS;
     }
     else if( !strcmp( psz_cmd, "chapter" ) ||
              !strcmp( psz_cmd, "chapter_n" ) ||
@@ -1137,24 +1093,22 @@ static int Input( vlc_object_t *p_this, char const *psz_cmd,
             if ( *newval.psz_string )
             {
                 /* Set. */
-                val.i_int = atoi( newval.psz_string );
-                var_Set( p_input, "chapter", val );
+                var_SetInteger( p_input, "chapter", atoi( newval.psz_string ) );
             }
             else
             {
                 /* Get. */
-                var_Get( p_input, "chapter", &val );
+                int i_chap = var_GetInteger( p_input, "chapter" );
                 int i_chapter_count = var_CountChoices( p_input, "chapter" );
-                msg_rc( "Currently playing chapter %d/%d.", val.i_int,
+                msg_rc( "Currently playing chapter %d/%d.", i_chap,
                         i_chapter_count );
             }
         }
         else if( !strcmp( psz_cmd, "chapter_n" ) )
-            var_SetVoid( p_input, "next-chapter" );
+            var_TriggerCallback( p_input, "next-chapter" );
         else if( !strcmp( psz_cmd, "chapter_p" ) )
-            var_SetVoid( p_input, "prev-chapter" );
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+            var_TriggerCallback( p_input, "prev-chapter" );
+        i_error = VLC_SUCCESS;
     }
     else if( !strcmp( psz_cmd, "title" ) ||
              !strcmp( psz_cmd, "title_n" ) ||
@@ -1163,27 +1117,23 @@ static int Input( vlc_object_t *p_this, char const *psz_cmd,
         if( !strcmp( psz_cmd, "title" ) )
         {
             if ( *newval.psz_string )
-            {
                 /* Set. */
-                val.i_int = atoi( newval.psz_string );
-                var_Set( p_input, "title", val );
-            }
+                var_SetInteger( p_input, "title", atoi( newval.psz_string ) );
             else
             {
                 /* Get. */
-                var_Get( p_input, "title", &val );
+                int i_title = var_GetInteger( p_input, "title" );
                 int i_title_count = var_CountChoices( p_input, "title" );
-                msg_rc( "Currently playing title %d/%d.", val.i_int,
+                msg_rc( "Currently playing title %d/%d.", i_title,
                         i_title_count );
             }
         }
         else if( !strcmp( psz_cmd, "title_n" ) )
-            var_SetVoid( p_input, "next-title" );
+            var_TriggerCallback( p_input, "next-title" );
         else if( !strcmp( psz_cmd, "title_p" ) )
-            var_SetVoid( p_input, "prev-title" );
+            var_TriggerCallback( p_input, "prev-title" );
 
-        vlc_object_release( p_input );
-        return VLC_SUCCESS;
+        i_error = VLC_SUCCESS;
     }
     else if(    !strcmp( psz_cmd, "atrack" )
              || !strcmp( psz_cmd, "vtrack" )
@@ -1191,7 +1141,6 @@ static int Input( vlc_object_t *p_this, char const *psz_cmd,
     {
         const char *psz_variable;
         vlc_value_t val_name;
-        int i_error;
 
         if( !strcmp( psz_cmd, "atrack" ) )
         {
@@ -1214,10 +1163,8 @@ static int Input( vlc_object_t *p_this, char const *psz_cmd,
         if( newval.psz_string && *newval.psz_string )
         {
             /* set */
-            vlc_value_t val;
-            val.i_int = atoi( newval.psz_string );
-
-            i_error = var_Set( p_input, psz_variable, val );
+            i_error = var_SetInteger( p_input, psz_variable,
+                                      atoi( newval.psz_string ) );
         }
         else
         {
@@ -1226,43 +1173,34 @@ static int Input( vlc_object_t *p_this, char const *psz_cmd,
             int i, i_value;
 
             if ( var_Get( p_input, psz_variable, &val ) < 0 )
-            {
-                vlc_object_release( p_input );
-                return VLC_EGENERIC;
-            }
+                goto out;
             i_value = val.i_int;
 
             if ( var_Change( p_input, psz_variable,
                              VLC_VAR_GETLIST, &val, &text ) < 0 )
-            {
-                vlc_object_release( p_input );
-                return VLC_EGENERIC;
-            }
+                goto out;
 
             msg_rc( "+----[ %s ]", val_name.psz_string );
             for ( i = 0; i < val.p_list->i_count; i++ )
             {
                 if ( i_value == val.p_list->p_values[i].i_int )
-                    msg_rc( "| %i - %s *", val.p_list->p_values[i].i_int,
+                    msg_rc( "| %"PRId64" - %s *",
+                            val.p_list->p_values[i].i_int,
                             text.p_list->p_values[i].psz_string );
                 else
-                    msg_rc( "| %i - %s", val.p_list->p_values[i].i_int,
+                    msg_rc( "| %"PRId64" - %s",
+                            val.p_list->p_values[i].i_int,
                             text.p_list->p_values[i].psz_string );
             }
             var_FreeList( &val, &text );
             msg_rc( "+----[ end of %s ]", val_name.psz_string );
 
             free( val_name.psz_string );
-
-            i_error = VLC_SUCCESS;
         }
-        vlc_object_release( p_input );
-        return i_error;
     }
-
-    /* Never reached. */
+out:
     vlc_object_release( p_input );
-    return VLC_EGENERIC;
+    return i_error;
 }
 
 static void print_playlist( intf_thread_t *p_intf, playlist_item_t *p_item, int i_level )
@@ -1291,18 +1229,17 @@ static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
     vlc_value_t val;
 
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    playlist_t *p_playlist = pl_Hold( p_this );
+    playlist_t *p_playlist = p_intf->p_sys->p_playlist;
     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
 
     if( p_input )
     {
-        var_Get( p_input, "state", &val );
+        int state = var_GetInteger( p_input, "state" );
         vlc_object_release( p_input );
 
-        if( val.i_int == PAUSE_S )
+        if( state == PAUSE_S )
         {
-            msg_rc( _("Type 'menu select' or 'pause' to continue.") );
-            pl_Release( p_this );
+            msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
             return VLC_EGENERIC;
         }
     }
@@ -1389,23 +1326,25 @@ static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
     }
     else if (!strcmp( psz_cmd, "goto" ) )
     {
+        PL_LOCK;
         int i_pos = atoi( newval.psz_string );
         /* The playlist stores 2 times the same item: onelevel & category */
         int i_size = p_playlist->items.i_size / 2;
 
         if( i_pos <= 0 )
-            msg_rc( _("Error: `goto' needs an argument greater than zero.") );
+            msg_rc( "%s", _("Error: `goto' needs an argument greater than zero.") );
         else if( i_pos <= i_size )
         {
             playlist_item_t *p_item, *p_parent;
             p_item = p_parent = p_playlist->items.p_elems[i_pos*2-1];
             while( p_parent->p_parent )
                 p_parent = p_parent->p_parent;
-            playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Unlocked,
+            playlist_Control( p_playlist, PLAYLIST_VIEWPLAY, pl_Locked,
                     p_parent, p_item );
         }
         else
             msg_rc( _("Playlist has only %d elements"), i_size );
+        PL_UNLOCK;
     }
     else if( !strcmp( psz_cmd, "stop" ) )
     {
@@ -1459,8 +1398,10 @@ static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
 
     else if( !strcmp( psz_cmd, "sort" ))
     {
+        PL_LOCK;
         playlist_RecursiveNodeSort( p_playlist, p_playlist->p_root_onelevel,
                                     SORT_ARTIST, ORDER_NORMAL );
+        PL_UNLOCK;
     }
     else if( !strcmp( psz_cmd, "status" ) )
     {
@@ -1473,10 +1414,12 @@ static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
             msg_rc( STATUS_CHANGE "( new input: %s )", psz_uri );
             free( psz_uri );
             msg_rc( STATUS_CHANGE "( audio volume: %d )",
-                    config_GetInt( p_intf, "volume" ));
+                    (int)config_GetInt( p_intf, "volume" ));
 
             PL_LOCK;
-            switch( playlist_Status(p_playlist) )
+            int status = playlist_Status(p_playlist);
+            PL_UNLOCK;
+            switch( status )
             {
                 case PLAYLIST_STOPPED:
                     msg_rc( STATUS_CHANGE "( stop state: 5 )" );
@@ -1491,7 +1434,6 @@ static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
                     msg_rc( STATUS_CHANGE "( unknown state: -1 )" );
                     break;
             }
-            PL_UNLOCK;
             vlc_object_release( p_input );
         }
     }
@@ -1504,7 +1446,6 @@ static int Playlist( vlc_object_t *p_this, char const *psz_cmd,
         msg_rc( "unknown command!" );
     }
 
-    pl_Release( p_this );
     return VLC_SUCCESS;
 }
 
@@ -1531,25 +1472,22 @@ static int Volume( vlc_object_t *p_this, char const *psz_cmd,
 {
     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    input_thread_t *p_input = NULL;
+    playlist_t *p_playlist = p_intf->p_sys->p_playlist;
+    input_thread_t *p_input = playlist_CurrentInput( p_playlist );
     int i_error = VLC_EGENERIC;
 
-    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
     if( !p_input )
         return VLC_ENOOBJ;
 
     if( p_input )
     {
-        vlc_value_t val;
-
-        var_Get( p_input, "state", &val );
-        if( val.i_int == PAUSE_S )
+        int state = var_GetInteger( p_input, "state" );
+        vlc_object_release( p_input );
+        if( state == PAUSE_S )
         {
-            msg_rc( _("Type 'menu select' or 'pause' to continue.") );
-            vlc_object_release( p_input );
+            msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
             return VLC_EGENERIC;
         }
-        vlc_object_release( p_input );
     }
 
     if ( *newval.psz_string )
@@ -1565,10 +1503,9 @@ static int Volume( vlc_object_t *p_this, char const *psz_cmd,
         else
         {
             if( i_volume == AOUT_VOLUME_MIN )
-            {
-                var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_VOL_MUTE );
-            }
-            i_error = aout_VolumeSet( p_this, i_volume );
+                aout_ToggleMute( p_playlist, NULL );
+            if( !aout_VolumeSet( p_playlist, i_volume ) )
+                i_error = VLC_SUCCESS;
             osd_Volume( p_this );
             msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
         }
@@ -1577,11 +1514,7 @@ static int Volume( vlc_object_t *p_this, char const *psz_cmd,
     {
         /* Get. */
         audio_volume_t i_volume;
-        if ( aout_VolumeGet( p_this, &i_volume ) < 0 )
-        {
-            i_error = VLC_EGENERIC;
-        }
-        else
+        if ( !aout_VolumeGet( p_playlist, &i_volume ) )
         {
             msg_rc( STATUS_CHANGE "( audio volume: %d )", i_volume );
             i_error = VLC_SUCCESS;
@@ -1597,27 +1530,21 @@ static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
     audio_volume_t i_volume;
-    input_thread_t *p_input = NULL;
+    input_thread_t *p_input =
+        playlist_CurrentInput( p_intf->p_sys->p_playlist );
     int i_nb_steps = atoi(newval.psz_string);
     int i_error = VLC_SUCCESS;
     int i_volume_step = 0;
 
-    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
     if( !p_input )
         return VLC_ENOOBJ;
 
-    if( p_input )
+    int state = var_GetInteger( p_input, "state" );
+    vlc_object_release( p_input );
+    if( state == PAUSE_S )
     {
-        vlc_value_t val;
-
-        var_Get( p_input, "state", &val );
-        if( val.i_int == PAUSE_S )
-        {
-            msg_rc( _("Type 'menu select' or 'pause' to continue.") );
-            vlc_object_release( p_input );
-            return VLC_EGENERIC;
-        }
-        vlc_object_release( p_input );
+        msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
+        return VLC_EGENERIC;
     }
 
     i_volume_step = config_GetInt( p_intf->p_libvlc, "volume-step" );
@@ -1628,12 +1555,12 @@ static int VolumeMove( vlc_object_t *p_this, char const *psz_cmd,
 
     if ( !strcmp(psz_cmd, "volup") )
     {
-        if ( aout_VolumeUp( p_this, i_nb_steps, &i_volume ) < 0 )
+        if ( aout_VolumeUp( p_intf->p_sys->p_playlist, i_nb_steps, &i_volume ) < 0 )
             i_error = VLC_EGENERIC;
     }
     else
     {
-        if ( aout_VolumeDown( p_this, i_nb_steps, &i_volume ) < 0 )
+        if ( aout_VolumeDown( p_intf->p_sys->p_playlist, i_nb_steps, &i_volume ) < 0 )
             i_error = VLC_EGENERIC;
     }
     osd_Volume( p_this );
@@ -1648,16 +1575,16 @@ static int VideoConfig( vlc_object_t *p_this, char const *psz_cmd,
 {
     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    input_thread_t *p_input = NULL;
+    input_thread_t *p_input =
+        playlist_CurrentInput( p_intf->p_sys->p_playlist );
     vout_thread_t * p_vout;
     const char * psz_variable = NULL;
-    int i_error;
+    int i_error = VLC_SUCCESS;
 
-    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
     if( !p_input )
         return VLC_ENOOBJ;
 
-    p_vout = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD );
+    p_vout = input_GetVout( p_input );
     vlc_object_release( p_input );
     if( !p_vout )
         return VLC_ENOOBJ;
@@ -1698,9 +1625,7 @@ static int VideoConfig( vlc_object_t *p_this, char const *psz_cmd,
     }
     else if( !strcmp( psz_cmd, "snapshot" ) )
     {
-        vlc_value_t val;
-        val.b_bool = true;
-        i_error = var_Set( p_vout, psz_variable, val );
+        var_TriggerCallback( p_vout, psz_variable );
     }
     else
     {
@@ -1722,7 +1647,7 @@ static int VideoConfig( vlc_object_t *p_this, char const *psz_cmd,
         }
         else
         {
-            psz_value = strdup( val.psz_string );
+            psz_value = val.psz_string;
         }
 
         if ( var_Change( p_vout, psz_variable,
@@ -1768,8 +1693,6 @@ static int VideoConfig( vlc_object_t *p_this, char const *psz_cmd,
         msg_rc( "+----[ end of %s ]", val_name.psz_string );
 
         free( val_name.psz_string );
-
-        i_error = VLC_SUCCESS;
     }
     vlc_object_release( p_vout );
     return i_error;
@@ -1780,32 +1703,27 @@ static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
 {
     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    input_thread_t *p_input = NULL;
+    input_thread_t *p_input =
+        playlist_CurrentInput( p_intf->p_sys->p_playlist );
     aout_instance_t * p_aout;
     const char * psz_variable;
     vlc_value_t val_name;
     int i_error;
 
-    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
     if( !p_input )
         return VLC_ENOOBJ;
 
-    if( p_input )
+    int state = var_GetInteger( p_input, "state" );
+    if( state == PAUSE_S )
     {
-        vlc_value_t val;
-
-        var_Get( p_input, "state", &val );
-        if( val.i_int == PAUSE_S )
-        {
-            msg_rc( _("Type 'menu select' or 'pause' to continue.") );
-            vlc_object_release( p_input );
-            return VLC_EGENERIC;
-        }
-        vlc_object_release( p_input );
+        msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
+        return VLC_EGENERIC;
     }
 
-    p_aout = vlc_object_find( p_this, VLC_OBJECT_AOUT, FIND_ANYWHERE );
-    if ( p_aout == NULL ) return VLC_ENOOBJ;
+    p_aout = input_GetAout( p_input );
+    vlc_object_release( p_input );
+    if ( p_aout == NULL )
+         return VLC_ENOOBJ;
 
     if ( !strcmp( psz_cmd, "adev" ) )
     {
@@ -1845,10 +1763,10 @@ static int AudioConfig( vlc_object_t *p_this, char const *psz_cmd,
         for ( i = 0; i < val.p_list->i_count; i++ )
         {
             if ( i_value == val.p_list->p_values[i].i_int )
-                msg_rc( "| %i - %s *", val.p_list->p_values[i].i_int,
+                msg_rc( "| %"PRId64" - %s *", val.p_list->p_values[i].i_int,
                         text.p_list->p_values[i].psz_string );
             else
-                msg_rc( "| %i - %s", val.p_list->p_values[i].i_int,
+                msg_rc( "| %"PRId64" - %s", val.p_list->p_values[i].i_int,
                         text.p_list->p_values[i].psz_string );
         }
         var_FreeList( &val, &text );
@@ -1875,18 +1793,17 @@ static int Menu( vlc_object_t *p_this, char const *psz_cmd,
 {
     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    playlist_t    *p_playlist = NULL;
+    playlist_t    *p_playlist = p_intf->p_sys->p_playlist;
     int i_error = VLC_SUCCESS;
     vlc_value_t val;
 
     if ( !*newval.psz_string )
     {
-        msg_rc( _("Please provide one of the following parameters:") );
+        msg_rc( "%s", _("Please provide one of the following parameters:") );
         msg_rc( "[on|off|up|down|left|right|select]" );
         return VLC_EGENERIC;
     }
 
-    p_playlist = pl_Hold( p_this );
     input_thread_t * p_input = playlist_CurrentInput( p_playlist );
 
     if( p_input )
@@ -1897,12 +1814,10 @@ static int Menu( vlc_object_t *p_this, char const *psz_cmd,
         if( ( val.i_int == PAUSE_S ) &&
             ( strcmp( newval.psz_string, "select" ) != 0 ) )
         {
-            msg_rc( _("Type 'menu select' or 'pause' to continue.") );
-            pl_Release( p_this );
+            msg_rc( "%s", _("Type 'menu select' or 'pause' to continue.") );
             return VLC_EGENERIC;
         }
     }
-    pl_Release( p_this );
 
     val.psz_string = strdup( newval.psz_string );
     if( !val.psz_string )
@@ -1924,7 +1839,7 @@ static int Menu( vlc_object_t *p_this, char const *psz_cmd,
         osd_MenuActivate( p_this );
     else
     {
-        msg_rc( _("Please provide one of the following parameters:") );
+        msg_rc( "%s", _("Please provide one of the following parameters:") );
         msg_rc( "[on|off|up|down|left|right|select]" );
         i_error = VLC_EGENERIC;
     }
@@ -1936,80 +1851,72 @@ static int Menu( vlc_object_t *p_this, char const *psz_cmd,
 static int Statistics ( vlc_object_t *p_this, char const *psz_cmd,
     vlc_value_t oldval, vlc_value_t newval, void *p_data )
 {
-    VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data);
+    VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(newval); VLC_UNUSED(p_data);
     intf_thread_t *p_intf = (intf_thread_t*)p_this;
-    input_thread_t *p_input = NULL;
-    int i_error;
+    input_thread_t *p_input =
+        playlist_CurrentInput( p_intf->p_sys->p_playlist );
 
-    p_input = vlc_object_find( p_this, VLC_OBJECT_INPUT, FIND_ANYWHERE );
     if( !p_input )
         return VLC_ENOOBJ;
 
-    if( !strcmp( psz_cmd, "stats" ) )
-    {
-        vlc_mutex_lock( &input_GetItem(p_input)->lock );
-        updateStatistics( p_intf, input_GetItem(p_input) );
-        vlc_mutex_unlock( &input_GetItem(p_input)->lock );
-    }
-    /*
-     * sanity check
-     */
-    else
-    {
-        msg_rc(_("Unknown command!") );
-    }
-
+    updateStatistics( p_intf, input_GetItem(p_input) );
     vlc_object_release( p_input );
-    i_error = VLC_SUCCESS;
-    return i_error;
+    return VLC_SUCCESS;
 }
 
 static int updateStatistics( intf_thread_t *p_intf, input_item_t *p_item )
 {
     if( !p_item ) return VLC_EGENERIC;
 
+    vlc_mutex_lock( &p_item->lock );
     vlc_mutex_lock( &p_item->p_stats->lock );
     msg_rc( "+----[ begin of statistical info ]" );
 
     /* Input */
-    msg_rc(_("+-[Incoming]"));
-    msg_rc(_("| input bytes read : %8.0f kB"),
-            (float)(p_item->p_stats->i_read_bytes)/1000 );
+    msg_rc("%s", _("+-[Incoming]"));
+    msg_rc(_("| input bytes read : %8.0f KiB"),
+            (float)(p_item->p_stats->i_read_bytes)/1024 );
     msg_rc(_("| input bitrate    :   %6.0f kb/s"),
             (float)(p_item->p_stats->f_input_bitrate)*8000 );
-    msg_rc(_("| demux bytes read : %8.0f kB"),
-            (float)(p_item->p_stats->i_demux_read_bytes)/1000 );
+    msg_rc(_("| demux bytes read : %8.0f KiB"),
+            (float)(p_item->p_stats->i_demux_read_bytes)/1024 );
     msg_rc(_("| demux bitrate    :   %6.0f kb/s"),
             (float)(p_item->p_stats->f_demux_bitrate)*8000 );
+    msg_rc(_("| demux corrupted  :    %5"PRIi64),
+            p_item->p_stats->i_demux_corrupted );
+    msg_rc(_("| discontinuities  :    %5"PRIi64),
+            p_item->p_stats->i_demux_discontinuity );
     msg_rc("|");
     /* Video */
-    msg_rc(_("+-[Video Decoding]"));
-    msg_rc(_("| video decoded    :    %5i"),
+    msg_rc("%s", _("+-[Video Decoding]"));
+    msg_rc(_("| video decoded    :    %5"PRIi64),
             p_item->p_stats->i_decoded_video );
-    msg_rc(_("| frames displayed :    %5i"),
+    msg_rc(_("| frames displayed :    %5"PRIi64),
             p_item->p_stats->i_displayed_pictures );
-    msg_rc(_("| frames lost      :    %5i"),
+    msg_rc(_("| frames lost      :    %5"PRIi64),
             p_item->p_stats->i_lost_pictures );
     msg_rc("|");
     /* Audio*/
-    msg_rc(_("+-[Audio Decoding]"));
-    msg_rc(_("| audio decoded    :    %5i"),
+    msg_rc("%s", _("+-[Audio Decoding]"));
+    msg_rc(_("| audio decoded    :    %5"PRIi64),
             p_item->p_stats->i_decoded_audio );
-    msg_rc(_("| buffers played   :    %5i"),
+    msg_rc(_("| buffers played   :    %5"PRIi64),
             p_item->p_stats->i_played_abuffers );
-    msg_rc(_("| buffers lost     :    %5i"),
+    msg_rc(_("| buffers lost     :    %5"PRIi64),
             p_item->p_stats->i_lost_abuffers );
     msg_rc("|");
     /* Sout */
-    msg_rc(_("+-[Streaming]"));
-    msg_rc(_("| packets sent     :    %5i"), p_item->p_stats->i_sent_packets );
-    msg_rc(_("| bytes sent       : %8.0f kB"),
-            (float)(p_item->p_stats->i_sent_bytes)/1000 );
+    msg_rc("%s", _("+-[Streaming]"));
+    msg_rc(_("| packets sent     :    %5"PRIi64),
+           p_item->p_stats->i_sent_packets );
+    msg_rc(_("| bytes sent       : %8.0f KiB"),
+            (float)(p_item->p_stats->i_sent_bytes)/1024 );
     msg_rc(_("| sending bitrate  :   %6.0f kb/s"),
             (float)(p_item->p_stats->f_send_bitrate*8)*1000 );
     msg_rc("|");
     msg_rc( "+----[ end of statistical info ]" );
     vlc_mutex_unlock( &p_item->p_stats->lock );
+    vlc_mutex_unlock( &p_item->lock );
 
     return VLC_SUCCESS;
 }
@@ -2188,7 +2095,7 @@ static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
         else if( *psz_item )
         {
             i_options++;
-            ppsz_options = realloc( ppsz_options, i_options * sizeof(char *) );
+            ppsz_options = xrealloc( ppsz_options, i_options * sizeof(char *) );
             ppsz_options[i_options - 1] = &psz_item[1];
         }