+
+/* OSD menu commands */
+static int Menu( 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_data);
+ intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ playlist_t *p_playlist = NULL;
+ int i_error = VLC_SUCCESS;
+ vlc_value_t val;
+
+ if ( !*newval.psz_string )
+ {
+ msg_rc( _("Please provide one of the following parameters:") );
+ msg_rc( "[on|off|up|down|left|right|select]" );
+ return VLC_EGENERIC;
+ }
+
+ p_playlist = pl_Yield( p_this );
+
+ if( p_playlist->p_input )
+ {
+ var_Get( p_playlist->p_input, "state", &val );
+ if( ( ( val.i_int == PAUSE_S ) || ( val.i_int == PLAYLIST_PAUSED ) ) &&
+ ( strcmp( newval.psz_string, "select" ) != 0 ) )
+ {
+ msg_rc( _("Type 'menu select' or 'pause' to continue.") );
+ vlc_object_release( p_playlist );
+ return VLC_EGENERIC;
+ }
+ }
+ vlc_object_release( p_playlist );
+
+ val.psz_string = strdup( newval.psz_string );
+ if( !val.psz_string )
+ return VLC_ENOMEM;
+ if( !strcmp( val.psz_string, "on" ) || !strcmp( val.psz_string, "show" ))
+ osd_MenuShow( p_this );
+ else if( !strcmp( val.psz_string, "off" )
+ || !strcmp( val.psz_string, "hide" ) )
+ osd_MenuHide( p_this );
+ else if( !strcmp( val.psz_string, "up" ) )
+ osd_MenuUp( p_this );
+ else if( !strcmp( val.psz_string, "down" ) )
+ osd_MenuDown( p_this );
+ else if( !strcmp( val.psz_string, "left" ) )
+ osd_MenuPrev( p_this );
+ else if( !strcmp( val.psz_string, "right" ) )
+ osd_MenuNext( p_this );
+ else if( !strcmp( val.psz_string, "select" ) )
+ osd_MenuActivate( p_this );
+ else
+ {
+ msg_rc( _("Please provide one of the following parameters:") );
+ msg_rc( "[on|off|up|down|left|right|select]" );
+ i_error = VLC_EGENERIC;
+ }
+
+ free( val.psz_string );
+ return i_error;
+}
+
+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);
+ intf_thread_t *p_intf = (intf_thread_t*)p_this;
+ input_thread_t *p_input = NULL;
+ int i_error;
+
+ 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!") );
+ }
+
+ vlc_object_release( p_input );
+ i_error = VLC_SUCCESS;
+ return i_error;
+}
+
+static int updateStatistics( intf_thread_t *p_intf, input_item_t *p_item )
+{
+ if( !p_item ) return VLC_EGENERIC;
+
+ 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(_("| 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 bitrate : %6.0f kb/s"),
+ (float)(p_item->p_stats->f_demux_bitrate)*8000 );
+ msg_rc("|");
+ /* Video */
+ msg_rc(_("+-[Video Decoding]"));
+ msg_rc(_("| video decoded : %5i"),
+ p_item->p_stats->i_decoded_video );
+ msg_rc(_("| frames displayed : %5i"),
+ p_item->p_stats->i_displayed_pictures );
+ msg_rc(_("| frames lost : %5i"),
+ p_item->p_stats->i_lost_pictures );
+ msg_rc("|");
+ /* Audio*/
+ msg_rc(_("+-[Audio Decoding]"));
+ msg_rc(_("| audio decoded : %5i"),
+ p_item->p_stats->i_decoded_audio );
+ msg_rc(_("| buffers played : %5i"),
+ p_item->p_stats->i_played_abuffers );
+ msg_rc(_("| buffers lost : %5i"),
+ 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(_("| 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 );
+
+ return VLC_SUCCESS;
+}
+
+#ifdef WIN32
+bool ReadWin32( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
+{
+ INPUT_RECORD input_record;
+ DWORD i_dw;
+
+ /* On Win32, select() only works on socket descriptors */
+ while( WaitForSingleObject( p_intf->p_sys->hConsoleIn,
+ INTF_IDLE_SLEEP/1000 ) == WAIT_OBJECT_0 )
+ {
+ while( !intf_ShouldDie( p_intf ) && *pi_size < MAX_LINE_LENGTH &&
+ ReadConsoleInput( p_intf->p_sys->hConsoleIn, &input_record,
+ 1, &i_dw ) )
+ {
+ if( input_record.EventType != KEY_EVENT ||
+ !input_record.Event.KeyEvent.bKeyDown ||
+ input_record.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT ||
+ input_record.Event.KeyEvent.wVirtualKeyCode == VK_CONTROL||
+ input_record.Event.KeyEvent.wVirtualKeyCode == VK_MENU ||
+ input_record.Event.KeyEvent.wVirtualKeyCode == VK_CAPITAL )
+ {
+ /* nothing interesting */
+ continue;
+ }
+
+ p_buffer[ *pi_size ] = input_record.Event.KeyEvent.uChar.AsciiChar;
+
+ /* Echo out the command */
+ putc( p_buffer[ *pi_size ], stdout );
+
+ /* Handle special keys */
+ if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
+ {
+ putc( '\n', stdout );
+ break;
+ }
+ switch( p_buffer[ *pi_size ] )
+ {
+ case '\b':
+ if( *pi_size )
+ {
+ *pi_size -= 2;
+ putc( ' ', stdout );
+ putc( '\b', stdout );
+ }
+ break;
+ case '\r':
+ (*pi_size) --;
+ break;
+ }
+
+ (*pi_size)++;
+ }
+
+ if( *pi_size == MAX_LINE_LENGTH ||
+ p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
+ {
+ p_buffer[ *pi_size ] = 0;
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif
+
+bool ReadCommand( intf_thread_t *p_intf, char *p_buffer, int *pi_size )
+{
+ int i_read = 0;
+
+#ifdef WIN32
+ if( p_intf->p_sys->i_socket == -1 && !p_intf->p_sys->b_quiet )
+ return ReadWin32( p_intf, p_buffer, pi_size );
+ else if( p_intf->p_sys->i_socket == -1 )
+ {
+ msleep( INTF_IDLE_SLEEP );
+ return false;
+ }
+#endif
+
+ while( !intf_ShouldDie( p_intf ) && *pi_size < MAX_LINE_LENGTH &&
+ (i_read = net_Read( p_intf, p_intf->p_sys->i_socket == -1 ?
+ 0 /*STDIN_FILENO*/ : p_intf->p_sys->i_socket, NULL,
+ (uint8_t *)p_buffer + *pi_size, 1, false ) ) > 0 )
+ {
+ if( p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
+ break;
+
+ (*pi_size)++;
+ }
+
+ /* Connection closed */
+ if( i_read <= 0 )
+ {
+ if( p_intf->p_sys->i_socket != -1 )
+ {
+ net_Close( p_intf->p_sys->i_socket );
+ p_intf->p_sys->i_socket = -1;
+ }
+ else
+ {
+ /* Standard input closed: exit */
+ vlc_value_t empty;
+ Quit( VLC_OBJECT(p_intf), NULL, empty, empty, NULL );
+ }
+
+ p_buffer[ *pi_size ] = 0;
+ return true;
+ }
+
+ if( *pi_size == MAX_LINE_LENGTH ||
+ p_buffer[ *pi_size ] == '\r' || p_buffer[ *pi_size ] == '\n' )
+ {
+ p_buffer[ *pi_size ] = 0;
+ return true;
+ }
+
+ return false;
+}
+
+/*****************************************************************************
+ * parse_MRL: build a input item from a full mrl
+ *****************************************************************************
+ * MRL format: "simplified-mrl [:option-name[=option-value]]"
+ * We don't check for '"' or '\'', we just assume that a ':' that follows a
+ * space is a new option. Should be good enough for our purpose.
+ *****************************************************************************/
+static input_item_t *parse_MRL( intf_thread_t *p_intf, char *psz_mrl )
+{
+#define SKIPSPACE( p ) { while( *p == ' ' || *p == '\t' ) p++; }
+#define SKIPTRAILINGSPACE( p, d ) \
+ { char *e=d; while( e > p && (*(e-1)==' ' || *(e-1)=='\t') ){e--;*e=0;} }
+
+ input_item_t *p_item = NULL;
+ char *psz_item = NULL, *psz_item_mrl = NULL, *psz_orig;
+ char **ppsz_options = NULL;
+ int i, i_options = 0;
+
+ if( !psz_mrl ) return 0;
+
+ psz_mrl = psz_orig = strdup( psz_mrl );
+ while( *psz_mrl )
+ {
+ SKIPSPACE( psz_mrl );
+ psz_item = psz_mrl;
+
+ for( ; *psz_mrl; psz_mrl++ )
+ {
+ if( (*psz_mrl == ' ' || *psz_mrl == '\t') && psz_mrl[1] == ':' )
+ {
+ /* We have a complete item */
+ break;
+ }
+ if( (*psz_mrl == ' ' || *psz_mrl == '\t') &&
+ (psz_mrl[1] == '"' || psz_mrl[1] == '\'') && psz_mrl[2] == ':')
+ {
+ /* We have a complete item */
+ break;
+ }
+ }
+
+ if( *psz_mrl ) { *psz_mrl = 0; psz_mrl++; }
+ SKIPTRAILINGSPACE( psz_item, psz_item + strlen( psz_item ) );
+
+ /* Remove '"' and '\'' if necessary */
+ if( *psz_item == '"' && psz_item[strlen(psz_item)-1] == '"' )
+ { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
+ if( *psz_item == '\'' && psz_item[strlen(psz_item)-1] == '\'' )
+ { psz_item++; psz_item[strlen(psz_item)-1] = 0; }
+
+ if( !psz_item_mrl ) psz_item_mrl = psz_item;
+ else if( *psz_item )
+ {
+ i_options++;
+ ppsz_options = realloc( ppsz_options, i_options * sizeof(char *) );
+ ppsz_options[i_options - 1] = &psz_item[1];
+ }
+
+ if( *psz_mrl ) SKIPSPACE( psz_mrl );
+ }
+
+ /* Now create a playlist item */
+ if( psz_item_mrl )
+ {
+ p_item = input_ItemNew( p_intf, psz_item_mrl, NULL );
+ for( i = 0; i < i_options; i++ )
+ {
+ input_ItemAddOption( p_item, ppsz_options[i] );
+ }
+ }
+
+ if( i_options ) free( ppsz_options );
+ free( psz_orig );
+
+ return p_item;
+}