📄 rc.c
字号:
/***************************************************************************** * rc.c : remote control stdin/stdout module for vlc ***************************************************************************** * Copyright (C) 2004 VideoLAN * $Id: rc.c,v 1.43 2004/01/25 20:40:59 gbazin Exp $ * * Author: Peter Surda <shurdeek@panorama.sth.ac.at> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. *****************************************************************************//***************************************************************************** * Preamble *****************************************************************************/#include <stdlib.h> /* malloc(), free() */#include <string.h>#include <errno.h> /* ENOMEM */#include <stdio.h>#include <ctype.h>#include <signal.h>#include <vlc/vlc.h>#include <vlc/intf.h>#include <vlc/aout.h>#include <vlc/vout.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_error.h"#define MAX_LINE_LENGTH 256/***************************************************************************** * Local prototypes *****************************************************************************/static int Activate ( vlc_object_t * );static void Run ( intf_thread_t *p_intf );static int Input ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int Playlist ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int Quit ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int Intf ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int Volume ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int VolumeMove ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );static int AudioConfig ( vlc_object_t *, char const *, vlc_value_t, vlc_value_t, void * );/***************************************************************************** * Module descriptor *****************************************************************************/#define POS_TEXT N_("Show stream position")#define POS_LONGTEXT N_("Show the current position in seconds within the stream from time to time.")#define TTY_TEXT N_("Fake TTY")#define TTY_LONGTEXT N_("Force the rc module to use stdin as if it was a TTY.")vlc_module_begin(); set_description( _("Remote control interface") ); add_bool( "rc-show-pos", 0, NULL, POS_TEXT, POS_LONGTEXT, VLC_TRUE );#ifdef HAVE_ISATTY add_bool( "fake-tty", 0, NULL, TTY_TEXT, TTY_LONGTEXT, VLC_TRUE );#endif set_capability( "interface", 20 ); set_callbacks( Activate, NULL );vlc_module_end();/***************************************************************************** * Activate: initialize and create stuff *****************************************************************************/static int Activate( vlc_object_t *p_this ){ intf_thread_t *p_intf = (intf_thread_t*)p_this;#if defined(HAVE_ISATTY) && !defined(WIN32) /* Check that stdin is a TTY */ if( !config_GetInt( p_intf, "fake-tty" ) && !isatty( 0 ) ) { msg_Warn( p_intf, "fd 0 is not a TTY" ); return VLC_EGENERIC; }#endif /* Non-buffered stdout */ setvbuf( stdout, (char *)NULL, _IOLBF, 0 ); p_intf->pf_run = Run; CONSOLE_INTRO_MSG; printf( "Remote control interface initialized, `h' for help\n" ); return VLC_SUCCESS;}/***************************************************************************** * Run: rc thread ***************************************************************************** * This part of the interface is in a separate thread so that we can call * exec() from within it without annoying the rest of the program. *****************************************************************************/static void Run( intf_thread_t *p_intf ){ input_thread_t * p_input; playlist_t * p_playlist; char p_buffer[ MAX_LINE_LENGTH + 1 ]; vlc_bool_t b_showpos = config_GetInt( p_intf, "rc-show-pos" ); input_info_category_t * p_category; input_info_t * p_info; int i_dummy; off_t i_oldpos = 0; off_t i_newpos; double f_ratio = 1.0;#ifdef WIN32 HANDLE hConsoleIn; INPUT_RECORD input_record; DWORD i_dummy2;#endif p_input = NULL; p_playlist = NULL; /* Register commands that will be cleaned up upon object destruction */ var_Create( p_intf, "quit", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "quit", Quit, NULL ); var_Create( p_intf, "intf", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "intf", Intf, NULL ); var_Create( p_intf, "add", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "add", Playlist, NULL ); var_Create( p_intf, "playlist", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "playlist", Playlist, NULL ); var_Create( p_intf, "play", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "play", Playlist, NULL ); var_Create( p_intf, "stop", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "stop", Playlist, NULL ); var_Create( p_intf, "prev", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "prev", Playlist, NULL ); var_Create( p_intf, "next", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "next", Playlist, NULL ); var_Create( p_intf, "pause", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "pause", Input, NULL ); var_Create( p_intf, "seek", VLC_VAR_INTEGER | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "seek", Input, NULL ); var_Create( p_intf, "title", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "title", Input, NULL ); var_Create( p_intf, "title_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "title_n", Input, NULL ); var_Create( p_intf, "title_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "title_p", Input, NULL ); var_Create( p_intf, "chapter", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "chapter", Input, NULL ); var_Create( p_intf, "chapter_n", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "chapter_n", Input, NULL ); var_Create( p_intf, "chapter_p", VLC_VAR_VOID | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "chapter_p", Input, NULL ); var_Create( p_intf, "volume", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "volume", Volume, NULL ); var_Create( p_intf, "volup", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "volup", VolumeMove, NULL ); var_Create( p_intf, "voldown", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "voldown", VolumeMove, NULL ); var_Create( p_intf, "adev", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "adev", AudioConfig, NULL ); var_Create( p_intf, "achan", VLC_VAR_STRING | VLC_VAR_ISCOMMAND ); var_AddCallback( p_intf, "achan", AudioConfig, NULL );#ifdef WIN32 /* Get the file descriptor of the console input */ hConsoleIn = GetStdHandle(STD_INPUT_HANDLE); if( hConsoleIn == INVALID_HANDLE_VALUE ) { msg_Err( p_intf, "Couldn't open STD_INPUT_HANDLE" ); p_intf->b_die = VLC_TRUE; }#endif while( !p_intf->b_die ) { vlc_bool_t b_complete = VLC_FALSE;#ifndef WIN32 fd_set fds; struct timeval tv; /* Check stdin */ tv.tv_sec = 0; tv.tv_usec = (long)INTF_IDLE_SLEEP; FD_ZERO( &fds ); FD_SET( STDIN_FILENO, &fds ); i_dummy = select( STDIN_FILENO + 1, &fds, NULL, NULL, &tv );#else /* On Win32, select() only works on socket descriptors */ i_dummy = ( WaitForSingleObject( hConsoleIn, INTF_IDLE_SLEEP/1000 ) == WAIT_OBJECT_0 );#endif if( i_dummy > 0 ) { int i_size = 0; while( !p_intf->b_die && i_size < MAX_LINE_LENGTH#ifndef WIN32 && read( STDIN_FILENO, p_buffer + i_size, 1 ) > 0#else && ReadConsoleInput( hConsoleIn, &input_record, 1, &i_dummy2 )#endif ) {#ifdef WIN32 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[ i_size ] = input_record.Event.KeyEvent.uChar.AsciiChar; /* Echo out the command */ putc( p_buffer[ i_size ], stdout ); /* Handle special keys */ if( p_buffer[ i_size ] == '\r' || p_buffer[ i_size ] == '\n' ) { putc( '\n', stdout ); break; } switch( p_buffer[ i_size ] ) { case '\b': if( i_size ) { i_size -= 2; putc( ' ', stdout ); putc( '\b', stdout ); } break; case '\r': i_size --; break; } i_size++;#else if( p_buffer[ i_size ] == '\r' || p_buffer[ i_size ] == '\n' ) { break; } i_size++;#endif } if( i_size == MAX_LINE_LENGTH || p_buffer[ i_size ] == '\r' || p_buffer[ i_size ] == '\n' ) { p_buffer[ i_size ] = 0; b_complete = VLC_TRUE; } } /* 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 = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_PARENT ); } } } else if( p_input->b_dead ) { vlc_object_release( p_input ); p_input = NULL; } if( p_input && b_showpos ) { /* Get position */ vlc_mutex_lock( &p_input->stream.stream_lock ); if( !p_input->b_die && p_input->stream.i_mux_rate ) {#define A p_input->stream.p_selected_area f_ratio = 1.0 / ( 50 * p_input->stream.i_mux_rate ); i_newpos = A->i_tell * f_ratio; if( i_oldpos != i_newpos ) { i_oldpos = i_newpos; printf( "pos: %li s / %li s\n", (long int)i_newpos, (long int)(f_ratio * A->i_size) ); }#undef S } vlc_mutex_unlock( &p_input->stream.stream_lock ); } /* Is there something to do? */ if( b_complete ) { char *psz_cmd, *psz_arg; /* Skip heading spaces */ psz_cmd = p_buffer; while( *psz_cmd == ' ' ) { psz_cmd++; } /* Split psz_cmd at the first space and make sure that * psz_arg is valid */ psz_arg = strchr( psz_cmd, ' ' ); if( psz_arg ) { *psz_arg++ = 0; while( *psz_arg == ' ' ) { psz_arg++; } } else { psz_arg = ""; } /* If the user typed a registered local command, try it */ if( var_Type( p_intf, psz_cmd ) & VLC_VAR_ISCOMMAND ) { vlc_value_t val; int i_ret; val.psz_string = psz_arg; i_ret = var_Set( p_intf, psz_cmd, val ); printf( "%s: returned %i (%s)\n", psz_cmd, i_ret, vlc_error( i_ret ) ); } /* Or maybe it's a global command */ else if( var_Type( p_intf->p_libvlc, psz_cmd ) & VLC_VAR_ISCOMMAND ) { vlc_value_t val; int i_ret; val.psz_string = psz_arg; /* FIXME: it's a global command, but we should pass the * local object as an argument, not p_intf->p_libvlc. */ i_ret = var_Set( p_intf->p_libvlc, psz_cmd, val ); printf( "%s: returned %i (%s)\n", psz_cmd, i_ret, vlc_error( i_ret ) ); } else if( !strcmp( psz_cmd, "info" ) ) { if ( p_input ) { vlc_mutex_lock( &p_input->stream.stream_lock ); p_category = p_input->stream.p_info; while ( p_category ) { printf( "+----[ %s ]\n", p_category->psz_name ); printf( "| \n" ); p_info = p_category->p_info; while ( p_info ) { printf( "| %s: %s\n", p_info->psz_name, p_info->psz_value ); p_info = p_info->p_next; } p_category = p_category->p_next; printf( "| \n" ); } printf( "+----[ end of stream info ]\n" ); vlc_mutex_unlock( &p_input->stream.stream_lock ); } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -