X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fgui%2Fqt4%2Finput_manager.cpp;h=ebcc032612391b0ac1282d2e62601586af2f0221;hb=d43b6be00d16cc30b3f33e5657d8860f4e59ec89;hp=880f8ce8057dbf79d0cd03f714823f54c1094ad9;hpb=cd4c4f1dadf2a9b595948da6d70ac2eaad93c990;p=vlc diff --git a/modules/gui/qt4/input_manager.cpp b/modules/gui/qt4/input_manager.cpp index 880f8ce805..ebcc032612 100644 --- a/modules/gui/qt4/input_manager.cpp +++ b/modules/gui/qt4/input_manager.cpp @@ -22,34 +22,49 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ + +#define __STDC_FORMAT_MACROS 1 + #ifdef HAVE_CONFIG_H # include "config.h" #endif -#include "qt4.hpp" #include "input_manager.hpp" -#include "dialogs_provider.hpp" +#include +#include -static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o, - vlc_value_t n, void *param ); +#include -static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o, - vlc_value_t n, void *param ); +#include static int ItemChanged( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); -static int PLItemChanged( vlc_object_t *, const char *, +static int LeafToParent( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); -static int InterfaceChanged( vlc_object_t *, const char *, - vlc_value_t, vlc_value_t, void * ); -static int ItemStateChanged( vlc_object_t *, const char *, +static int PLItemChanged( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); -static int ItemRateChanged( vlc_object_t *, const char *, +static int PLItemAppended( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); -static int ItemTitleChanged( vlc_object_t *, const char *, +static int PLItemRemoved( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); static int VolumeChanged( vlc_object_t *, const char *, vlc_value_t, vlc_value_t, void * ); +static int SoundMuteChanged( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); + +static int RandomChanged( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); +static int LoopChanged( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); +static int RepeatChanged( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); + + +static int InputEvent( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); +static int VbiEvent( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void * ); + /********************************************************************** * InputManager implementation @@ -62,12 +77,16 @@ InputManager::InputManager( QObject *parent, intf_thread_t *_p_intf) : QObject( parent ), p_intf( _p_intf ) { i_old_playing_status = END_S; - old_name = ""; + oldName = ""; artUrl = ""; p_input = NULL; - i_rate = 0; - i_input_id = 0; - b_transparentTelextext = false; + p_input_vbi = NULL; + f_rate = 0.; + p_item = NULL; + b_video = false; + timeA = 0; + timeB = 0; + f_cache = -1.; /* impossible initial value, different from all */ } InputManager::~InputManager() @@ -77,28 +96,32 @@ InputManager::~InputManager() /* Define the Input used. Add the callbacks on input - p_input is yield once here */ + p_input is held once here */ void InputManager::setInput( input_thread_t *_p_input ) { delInput(); p_input = _p_input; if( p_input && !( p_input->b_dead || !vlc_object_alive (p_input) ) ) { - vlc_object_yield( p_input ); - emit statusChanged( PLAYING_S ); - UpdateMeta(); + msg_Dbg( p_intf, "IM: Setting an input" ); + vlc_object_hold( p_input ); + addCallbacks(); + UpdateStatus(); + UpdateName(); UpdateArt(); - UpdateSPU(); UpdateTeletext(); UpdateNavigation(); - addCallbacks(); - i_input_id = input_GetItem( p_input )->i_id; + UpdateVout(); + + p_item = input_GetItem( p_input ); + emit rateChanged( var_GetFloat( p_input, "rate" ) ); } else { p_input = NULL; - i_input_id = 0; - emit rateChanged( INPUT_RATE_DEFAULT ); + p_item = NULL; + assert( !p_input_vbi ); + emit rateChanged( var_InheritFloat( p_intf, "rate" ) ); } } @@ -107,129 +130,279 @@ void InputManager::setInput( input_thread_t *_p_input ) p_input is released once here */ void InputManager::delInput() { - if( p_input ) + if( !p_input ) return; + msg_Dbg( p_intf, "IM: Deleting the input" ); + + delCallbacks(); + i_old_playing_status = END_S; + p_item = NULL; + oldName = ""; + artUrl = ""; + b_video = false; + timeA = 0; + timeB = 0; + f_rate = 0. ; + + if( p_input_vbi ) { - delCallbacks(); - i_old_playing_status = END_S; - i_input_id = 0; - old_name = ""; - artUrl = ""; - emit positionUpdated( 0.0, 0 ,0 ); - emit statusChanged( END_S ); - emit nameChanged( "" ); - emit artChanged( "" ); - emit rateChanged( INPUT_RATE_DEFAULT ); - vlc_object_release( p_input ); - p_input = NULL; - UpdateSPU(); - UpdateTeletext(); + vlc_object_release( p_input_vbi ); + p_input_vbi = NULL; } -} -/* Add the callbacks on Input. Self explanatory */ -void InputManager::addCallbacks() -{ - /* We don't care about: - - chapter - - programs - - audio-delay - - spu-delay - - bookmark - - position, time, length, because they are included in intf-change - */ - /* src/input/input.c:1629 */ - var_AddCallback( p_input, "state", ItemStateChanged, this ); - /* src/input/es-out.c:552 */ - var_AddCallback( p_input, "spu-es", ChangeSPU, this ); - /* src/input/es-out.c: */ - var_AddCallback( p_input, "teletext-es", ChangeTeletext, this ); - /* src/input/input.c:1765 */ - var_AddCallback( p_input, "rate-change", ItemRateChanged, this ); - /* src/input/input.c:2003 */ - var_AddCallback( p_input, "title", ItemTitleChanged, this ); - /* src/input/input.c:734 for timers update*/ - var_AddCallback( p_input, "intf-change", InterfaceChanged, this ); -} + vlc_object_release( p_input ); + p_input = NULL; -/* Delete the callbacks on Input. Self explanatory */ -void InputManager::delCallbacks() -{ - var_DelCallback( p_input, "spu-es", ChangeSPU, this ); - var_DelCallback( p_input, "teletext-es", ChangeTeletext, this ); - var_DelCallback( p_input, "state", ItemStateChanged, this ); - var_DelCallback( p_input, "rate-change", ItemRateChanged, this ); - var_DelCallback( p_input, "title", ItemTitleChanged, this ); - var_DelCallback( p_input, "intf-change", InterfaceChanged, this ); + emit positionUpdated( -1.0, 0 ,0 ); + emit rateChanged( var_InheritFloat( p_intf, "rate" ) ); + emit nameChanged( "" ); + emit chapterChanged( 0 ); + emit titleChanged( 0 ); + emit statusChanged( END_S ); + + emit teletextPossible( false ); + emit AtoBchanged( false, false ); + emit voutChanged( false ); + emit voutListChanged( NULL, 0 ); + + /* Reset all InfoPanels but stats */ + emit artChanged( NULL ); + emit infoChanged( NULL ); + emit currentMetaChanged( (input_item_t *)NULL ); + + emit encryptionChanged( false ); + emit recordingStateChanged( false ); + + emit cachingChanged( 1 ); } /* Convert the event from the callbacks in actions */ void InputManager::customEvent( QEvent *event ) { - int type = event->type(); + int i_type = event->type(); IMEvent *ple = static_cast(event); - if ( type != PositionUpdate_Type && - type != ItemChanged_Type && - type != ItemRateChanged_Type && - type != ItemTitleChanged_Type && - type != ItemSpuChanged_Type && - type != ItemTeletextChanged_Type && - type != ItemStateChanged_Type ) - return; - - if( !hasInput() ) return; + if( i_type == ItemChanged_Type ) + UpdateMeta( ple->p_item ); - if( ( type != PositionUpdate_Type && - type != ItemRateChanged_Type && - type != ItemSpuChanged_Type && - type != ItemTeletextChanged_Type && - type != ItemStateChanged_Type - ) - && ( i_input_id != ple->i_id ) ) + if( !hasInput() ) return; - if( type != PositionUpdate_Type ) - msg_Dbg( p_intf, "New Event: type %i", type ); - /* Actions */ - switch( type ) + switch( i_type ) { case PositionUpdate_Type: UpdatePosition(); break; + case StatisticsUpdate_Type: + UpdateStats(); + break; case ItemChanged_Type: - UpdateMeta(); - UpdateStatus(); - UpdateArt(); + /* Ignore ItemChanged_Type event that does not apply to our input */ + if( p_item == ple->p_item ) + { + UpdateStatus(); + // UpdateName(); + UpdateArt(); + /* Update duration of file */ + } break; case ItemStateChanged_Type: + // TODO: Fusion with above state UpdateStatus(); - UpdateNavigation(); + // UpdateName(); + // UpdateNavigation(); This shouldn't be useful now + // UpdateTeletext(); Same + break; + case NameChanged_Type: + UpdateName(); + break; + case MetaChanged_Type: UpdateMeta(); + UpdateName(); /* Needed for NowPlaying */ + UpdateArt(); /* Art is part of meta in the core */ + break; + case InfoChanged_Type: + UpdateInfo(); break; case ItemTitleChanged_Type: UpdateNavigation(); - UpdateMeta(); + UpdateName(); /* Display the name of the Chapter, if exists */ break; case ItemRateChanged_Type: UpdateRate(); break; - case ItemSpuChanged_Type: - UpdateSPU(); + case ItemEsChanged_Type: + UpdateTeletext(); + // We don't do anything ES related. Why ? break; case ItemTeletextChanged_Type: UpdateTeletext(); break; + case InterfaceVoutUpdate_Type: + UpdateVout(); + break; + case SynchroChanged_Type: + emit synchroChanged(); + break; + case CachingEvent_Type: + UpdateCaching(); + break; + case BookmarksChanged_Type: + emit bookmarksChanged(); + break; + case InterfaceAoutUpdate_Type: + UpdateAout(); + break; + case RecordingEvent_Type: + UpdateRecord(); + break; + case ProgramChanged_Type: + UpdateProgramEvent(); + break; + case EPGEvent_Type: + UpdateEPG(); + break; + default: + msg_Warn( p_intf, "This shouldn't happen: %i", i_type ); + assert(0); } } +/* Add the callbacks on Input. Self explanatory */ +inline void InputManager::addCallbacks() +{ + var_AddCallback( p_input, "intf-event", InputEvent, this ); +} + +/* Delete the callbacks on Input. Self explanatory */ +inline void InputManager::delCallbacks() +{ + var_DelCallback( p_input, "intf-event", InputEvent, this ); +} + +/* Static callbacks for IM */ +static int ItemChanged( vlc_object_t *p_this, const char *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *param ) +{ + InputManager *im = (InputManager*)param; + input_item_t *p_item = static_cast(newval.p_address); + + IMEvent *event = new IMEvent( ItemChanged_Type, p_item ); + QApplication::postEvent( im, event ); + return VLC_SUCCESS; +} + +static int InputEvent( vlc_object_t *p_this, const char *, + vlc_value_t, vlc_value_t newval, void *param ) +{ + InputManager *im = (InputManager*)param; + IMEvent *event; + + switch( newval.i_int ) + { + case INPUT_EVENT_STATE: + event = new IMEvent( ItemStateChanged_Type ); + break; + case INPUT_EVENT_RATE: + event = new IMEvent( ItemRateChanged_Type ); + break; + case INPUT_EVENT_POSITION: + //case INPUT_EVENT_LENGTH: + event = new IMEvent( PositionUpdate_Type ); + break; + + case INPUT_EVENT_TITLE: + case INPUT_EVENT_CHAPTER: + event = new IMEvent( ItemTitleChanged_Type ); + break; + + case INPUT_EVENT_ES: + event = new IMEvent( ItemEsChanged_Type ); + break; + case INPUT_EVENT_TELETEXT: + event = new IMEvent( ItemTeletextChanged_Type ); + break; + + case INPUT_EVENT_STATISTICS: + event = new IMEvent( StatisticsUpdate_Type ); + break; + + case INPUT_EVENT_VOUT: + event = new IMEvent( InterfaceVoutUpdate_Type ); + break; + case INPUT_EVENT_AOUT: + event = new IMEvent( InterfaceAoutUpdate_Type ); + break; + + case INPUT_EVENT_ITEM_META: /* Codec MetaData + Art */ + event = new IMEvent( MetaChanged_Type ); + break; + case INPUT_EVENT_ITEM_INFO: /* Codec Info */ + event = new IMEvent( InfoChanged_Type ); + break; + case INPUT_EVENT_ITEM_NAME: + event = new IMEvent( NameChanged_Type ); + break; + + case INPUT_EVENT_AUDIO_DELAY: + case INPUT_EVENT_SUBTITLE_DELAY: + event = new IMEvent( SynchroChanged_Type ); + break; + + case INPUT_EVENT_CACHE: + event = new IMEvent( CachingEvent_Type ); + break; + + case INPUT_EVENT_BOOKMARK: + event = new IMEvent( BookmarksChanged_Type ); + break; + + case INPUT_EVENT_RECORD: + event = new IMEvent( RecordingEvent_Type ); + break; + + case INPUT_EVENT_PROGRAM: + /* This is for PID changes */ + event = new IMEvent( ProgramChanged_Type ); + break; + + case INPUT_EVENT_ITEM_EPG: + /* EPG data changed */ + event = new IMEvent( EPGEvent_Type ); + break; + + case INPUT_EVENT_SIGNAL: + /* This is for capture-card signals */ + /* event = new IMEvent( SignalChanged_Type ); + break; */ + default: + event = NULL; + break; + } + + if( event ) + QApplication::postEvent( im, event ); + return VLC_SUCCESS; +} + +static int VbiEvent( vlc_object_t *, const char *, + vlc_value_t, vlc_value_t, void *param ) +{ + InputManager *im = (InputManager*)param; + IMEvent *event = new IMEvent( ItemTeletextChanged_Type ); + + QApplication::postEvent( im, event ); + return VLC_SUCCESS; +} + void InputManager::UpdatePosition() { /* Update position */ - int i_length, i_time; /* Int is enough, since we store seconds */ + int i_length; + int64_t i_time; float f_pos; i_length = var_GetTime( p_input , "length" ) / 1000000; - i_time = var_GetTime( p_input , "time") / 1000000; + i_time = var_GetTime( p_input , "time"); f_pos = var_GetFloat( p_input , "position" ); emit positionUpdated( f_pos, i_time, i_length ); } @@ -238,81 +411,90 @@ void InputManager::UpdateNavigation() { /* Update navigation status */ vlc_value_t val; val.i_int = 0; - var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL ); + vlc_value_t val2; val2.i_int = 0; + + if( hasInput() ) + var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &val, NULL ); + if( val.i_int > 0 ) { - val.i_int = 0; - var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val, NULL ); - emit navigationChanged( (val.i_int > 0) ? 1 : 2 ); + emit titleChanged( true ); + msg_Dbg( p_intf, "Title %"PRId64, val.i_int ); + /* p_input != NULL since val.i_int != 0 */ + var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &val2, NULL ); + emit chapterChanged( (val2.i_int > 1) || ( val2.i_int > 0 && val.i_int > 1 ) ); + msg_Dbg( p_intf, "Chapter: %"PRId64, val2.i_int ); } else - { - emit navigationChanged( 0 ); - } + emit titleChanged( false ); } void InputManager::UpdateStatus() { /* Update playing status */ - vlc_value_t val; val.i_int = 0; - var_Get( p_input, "state", &val ); - if( i_old_playing_status != val.i_int ) + int state = var_GetInteger( p_input, "state" ); + if( i_old_playing_status != state ) { - i_old_playing_status = val.i_int; - emit statusChanged( val.i_int ); + i_old_playing_status = state; + emit statusChanged( state ); } } void InputManager::UpdateRate() { /* Update Rate */ - int i_new_rate = var_GetInteger( p_input, "rate"); - if( i_new_rate != i_rate ) + float f_new_rate = var_GetFloat( p_input, "rate" ); + if( f_new_rate != f_rate ) { - i_rate = i_new_rate; + f_rate = f_new_rate; /* Update rate */ - emit rateChanged( i_rate ); + emit rateChanged( f_rate ); } } -void InputManager::UpdateMeta() +void InputManager::UpdateName() { /* Update text, name and nowplaying */ QString text; - char *psz_name = input_item_GetTitle( input_GetItem( p_input ) ); - if( EMPTY_STR( psz_name ) ) - { - free( psz_name ); - psz_name = input_item_GetName( input_GetItem( p_input ) ); - } + /* Try to get the Title, then the Name */ + char *psz_name = input_item_GetTitleFbName( input_GetItem( p_input ) ); + /* Try to get the nowplaying */ char *psz_nowplaying = input_item_GetNowPlaying( input_GetItem( p_input ) ); if( !EMPTY_STR( psz_nowplaying ) ) { text.sprintf( "%s - %s", psz_nowplaying, psz_name ); } - else + else /* Do it ourself */ { char *psz_artist = input_item_GetArtist( input_GetItem( p_input ) ); + if( !EMPTY_STR( psz_artist ) ) - { text.sprintf( "%s - %s", psz_artist, psz_name ); - } else - { text.sprintf( "%s", psz_name ); - } + free( psz_artist ); } + /* Free everything */ free( psz_name ); free( psz_nowplaying ); - if( old_name != text ) + /* If we have Nothing */ + if( text.isEmpty() ) + { + psz_name = input_item_GetURI( input_GetItem( p_input ) ); + text.sprintf( "%s", psz_name ); + text = text.remove( 0, text.lastIndexOf( DIR_SEP ) + 1 ); + free( psz_name ); + } + + if( oldName != text ) { emit nameChanged( text ); - old_name=text; + oldName = text; } } @@ -327,47 +509,196 @@ bool InputManager::hasAudio() return false; } -bool InputManager::hasVideo() +void InputManager::UpdateTeletext() { if( hasInput() ) { - vlc_value_t val; - var_Change( p_input, "video-es", VLC_VAR_CHOICESCOUNT, &val, NULL ); - return val.i_int > 0; + const bool b_enabled = var_CountChoices( p_input, "teletext-es" ) > 0; + const int i_teletext_es = var_GetInteger( p_input, "teletext-es" ); + + /* Teletext is possible. Show the buttons */ + emit teletextPossible( b_enabled ); + + /* If Teletext is selected */ + if( b_enabled && i_teletext_es >= 0 ) + { + /* Then, find the current page */ + int i_page = 100; + bool b_transparent = false; + + if( p_input_vbi ) + { + var_DelCallback( p_input_vbi, "vbi-page", VbiEvent, this ); + vlc_object_release( p_input_vbi ); + } + + if( input_GetEsObjects( p_input, i_teletext_es, &p_input_vbi, NULL, NULL ) ) + p_input_vbi = NULL; + + if( p_input_vbi ) + { + /* This callback is not remove explicitly, but interfaces + * are guaranted to outlive input */ + var_AddCallback( p_input_vbi, "vbi-page", VbiEvent, this ); + + i_page = var_GetInteger( p_input_vbi, "vbi-page" ); + b_transparent = !var_GetBool( p_input_vbi, "vbi-opaque" ); + } + emit newTelexPageSet( i_page ); + emit teletextTransparencyActivated( b_transparent ); + + } + emit teletextActivated( b_enabled && i_teletext_es >= 0 ); } - return false; + else + { + emit teletextActivated( false ); + emit teletextPossible( false ); + } +} +void InputManager::UpdateEPG() +{ + if( hasInput() ) + { + emit epgChanged(); + } } -void InputManager::UpdateSPU() +void InputManager::UpdateVout() { - UpdateTeletext(); + if( hasInput() ) + { + /* Get current vout lists from input */ + size_t i_vout; + vout_thread_t **pp_vout; + if( input_Control( p_input, INPUT_GET_VOUTS, &pp_vout, &i_vout ) ) + { + i_vout = 0; + pp_vout = NULL; + } + + /* */ + emit voutListChanged( pp_vout, i_vout ); + + /* */ + bool b_old_video = b_video; + b_video = i_vout > 0; + if( !!b_old_video != !!b_video ) + emit voutChanged( b_video ); + + /* Release the vout list */ + for( int i = 0; i < i_vout; i++ ) + vlc_object_release( (vlc_object_t*)pp_vout[i] ); + free( pp_vout ); + } } +void InputManager::UpdateAout() +{ + if( hasInput() ) + { + /* TODO */ + } +} +void InputManager::UpdateCaching() +{ + if(!hasInput()) return; -void InputManager::UpdateTeletext() + float f_newCache = var_GetFloat ( p_input, "cache" ); + if( f_newCache != f_cache ) + { + f_cache = f_newCache; + /* Update cache */ + emit cachingChanged( f_cache ); + } +} + +void InputManager::requestArtUpdate() { if( hasInput() ) - telexToggle( var_GetInteger( p_input, "teletext-es" ) >= 0 ); + { + playlist_AskForArtEnqueue( pl_Get(p_intf), input_GetItem( p_input ) ); + } else - telexToggle( false ); + { + /* No input will signal the cover art to update, + * let's do it ourself */ + UpdateArt(); + } } +const QString InputManager::decodeArtURL( input_item_t *p_item ) +{ + assert( p_item ); + + char *psz_art = input_item_GetArtURL( p_item ); + if( psz_art ) + { + char *psz = make_path( psz_art ); + free( psz_art ); + psz_art = psz; + } + +#if 0 + /* Taglib seems to define a attachment://, It won't work yet */ + url = url.replace( "attachment://", "" ); +#endif + QString path = qfu( psz_art ? psz_art : "" ); + free( psz_art ); + return path; +} void InputManager::UpdateArt() { - /* Update Art meta */ QString url; - char *psz_art = input_item_GetArtURL( input_GetItem( p_input ) ); - url.sprintf("%s", psz_art ); - free( psz_art ); - if( artUrl != url ) + + if( hasInput() ) + url = decodeArtURL( input_GetItem( p_input ) ); + + /* the art hasn't changed, no need to update */ + if(artUrl == url) + return; + + /* Update Art meta */ + artUrl = url; + emit artChanged( artUrl ); +} + +inline void InputManager::UpdateStats() +{ + emit statisticsUpdated( input_GetItem( p_input ) ); +} + +inline void InputManager::UpdateMeta( input_item_t *p_item ) +{ + emit metaChanged( p_item ); +} + +inline void InputManager::UpdateMeta() +{ + emit currentMetaChanged( input_GetItem( p_input ) ); +} + +inline void InputManager::UpdateInfo() +{ + emit infoChanged( input_GetItem( p_input ) ); +} + +void InputManager::UpdateRecord() +{ + if( hasInput() ) { - artUrl = url.replace( "file://",QString("" ) ); - /* Taglib seems to define a attachment://, It won't work yet */ - artUrl = url.replace( "attachment://",QString("" ) ); - emit artChanged( artUrl ); - msg_Dbg( p_intf, "Art: %s", qtu( artUrl ) ); + emit recordingStateChanged( var_GetBool( p_input, "record" ) ); + } +} + +void InputManager::UpdateProgramEvent() +{ + if( hasInput() ) + { + bool b_scrambled = var_GetBool( p_input, "program-scrambled" ); + emit encryptionChanged( b_scrambled ); } } @@ -376,16 +707,18 @@ void InputManager::sliderUpdate( float new_pos ) { if( hasInput() ) var_SetFloat( p_input, "position", new_pos ); + emit seekRequested( new_pos ); } /* User togglePlayPause */ void InputManager::togglePlayPause() { - vlc_value_t state; - var_Get( p_input, "state", &state ); - state.i_int = ( state.i_int != PLAYING_S ) ? PLAYING_S : PAUSE_S; - var_Set( p_input, "state", state ); - emit statusChanged( state.i_int ); + if( hasInput() ) + { + int state = var_GetInteger( p_input, "state" ); + state = ( state != PLAYING_S ) ? PLAYING_S : PAUSE_S; + var_SetInteger( p_input, "state", state ); + } } void InputManager::sectionPrev() @@ -393,9 +726,8 @@ void InputManager::sectionPrev() if( hasInput() ) { int i_type = var_Type( p_input, "next-chapter" ); - vlc_value_t val; val.b_bool = true; - var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ? - "prev-chapter":"prev-title", val ); + var_TriggerCallback( p_input, (i_type & VLC_VAR_TYPE) != 0 ? + "prev-chapter":"prev-title" ); } } @@ -404,9 +736,8 @@ void InputManager::sectionNext() if( hasInput() ) { int i_type = var_Type( p_input, "next-chapter" ); - vlc_value_t val; val.b_bool = true; - var_Set( p_input, (i_type & VLC_VAR_TYPE) != 0 ? - "next-chapter":"next-title", val ); + var_TriggerCallback( p_input, (i_type & VLC_VAR_TYPE) != 0 ? + "next-chapter":"next-title" ); } } @@ -414,118 +745,173 @@ void InputManager::sectionMenu() { if( hasInput() ) { - vlc_value_t val; val.i_int = 2; - var_Set( p_input, "title 0", val ); + vlc_value_t val, text; + + if( var_Change( p_input, "title 0", VLC_VAR_GETLIST, &val, &text ) < 0 ) + return; + + /* XXX is it "Root" or "Title" we want here ?" (set 0 by default) */ + int root = 0; + for( int i = 0; i < val.p_list->i_count; i++ ) + { + if( !strcmp( text.p_list->p_values[i].psz_string, "Title" ) ) + root = i; + } + var_FreeList( &val, &text ); + + var_SetInteger( p_input, "title 0", root ); } } -void InputManager::telexGotoPage( int page ) +/* + * Teletext Functions + */ + +/* Set a new Teletext Page */ +void InputManager::telexSetPage( int page ) { - if( hasInput() ) + if( hasInput() && p_input_vbi ) { const int i_teletext_es = var_GetInteger( p_input, "teletext-es" ); - const int i_spu_es = var_GetInteger( p_input, "spu-es" ); - if( i_teletext_es >= 0 && i_teletext_es == i_spu_es ) + if( i_teletext_es >= 0 ) { - vlc_object_t *p_vbi; - p_vbi = (vlc_object_t *) vlc_object_find_name( p_input, - "zvbi", FIND_ANYWHERE ); - if( p_vbi ) - { - var_SetInteger( p_vbi, "vbi-page", page ); - vlc_object_release( p_vbi ); - } + var_SetInteger( p_input_vbi, "vbi-page", page ); + emit newTelexPageSet( page ); } } - emit setNewTelexPage( page ); } -void InputManager::telexToggle( bool b_enabled ) +/* Set the transparency on teletext */ +void InputManager::telexSetTransparency( bool b_transparentTelextext ) { - if( hasInput() ) + if( hasInput() && p_input_vbi ) { - const int i_teletext_es = var_GetInteger( p_input, "teletext-es" ); - const int i_spu_es = var_GetInteger( p_input, "spu-es" ); - - b_enabled = (i_teletext_es >= 0); - emit teletextEnabled( b_enabled ); - if( b_enabled && (i_teletext_es == i_spu_es) ) - { - vlc_object_t *p_vbi; - int i_page = 100; - p_vbi = (vlc_object_t *) vlc_object_find_name( p_input, - "zvbi", FIND_ANYWHERE ); - if( p_vbi ) - { - i_page = var_GetInteger( p_vbi, "vbi-page" ); - vlc_object_release( p_vbi ); - i_page = b_enabled ? i_page : 0; - telexGotoPage( i_page ); - } - } + var_SetBool( p_input_vbi, "vbi-opaque", !b_transparentTelextext ); + emit teletextTransparencyActivated( b_transparentTelextext ); } - else emit teletextEnabled( b_enabled ); } -void InputManager::telexToggleButtons() +void InputManager::activateTeletext( bool b_enable ) { - if( hasInput() ) + vlc_value_t list; + vlc_value_t text; + if( hasInput() && !var_Change( p_input, "teletext-es", VLC_VAR_GETLIST, &list, &text ) ) { - const int i_teletext_es = var_GetInteger( p_input, "teletext-es" ); - if( i_teletext_es >= 0 ) + if( list.p_list->i_count > 0 ) { - const int i_spu_es = var_GetInteger( p_input, "spu-es" ); - - if( i_teletext_es == i_spu_es ) - var_SetInteger( p_input, "spu-es", -1 ); - else - var_SetInteger( p_input, "spu-es", i_teletext_es ); - - emit toggleTelexButtons(); + /* Prefer the page 100 if it is present */ + int i; + for( i = 0; i < text.p_list->i_count; i++ ) + { + /* The description is the page number as a string */ + const char *psz_page = text.p_list->p_values[i].psz_string; + if( psz_page && !strcmp( psz_page, "100" ) ) + break; + } + if( i >= list.p_list->i_count ) + i = 0; + var_SetInteger( p_input, "spu-es", b_enable ? list.p_list->p_values[i].i_int : -1 ); } + var_FreeList( &list, &text ); } } -void InputManager::telexSetTransparency() +void InputManager::reverse() { if( hasInput() ) { - vlc_object_t *p_vbi; - p_vbi = (vlc_object_t *) vlc_object_find_name( p_input, - "zvbi", FIND_ANYWHERE ); - if( p_vbi ) - { - var_SetBool( p_vbi, "vbi-opaque", b_transparentTelextext ); - b_transparentTelextext = !b_transparentTelextext; - vlc_object_release( p_vbi ); - } + float f_rate = var_GetFloat( p_input, "rate" ); + var_SetFloat( p_input, "rate", -f_rate ); } - emit toggleTelexTransparency(); } void InputManager::slower() { if( hasInput() ) - var_SetVoid( p_input, "rate-slower" ); + var_TriggerCallback( p_input, "rate-slower" ); } void InputManager::faster() { if( hasInput() ) - var_SetVoid( p_input, "rate-faster" ); + var_TriggerCallback( p_input, "rate-faster" ); +} + +void InputManager::littlefaster() +{ + var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_FASTER_FINE ); +} + +void InputManager::littleslower() +{ + var_SetInteger( p_intf->p_libvlc, "key-action", ACTIONID_RATE_SLOWER_FINE ); } void InputManager::normalRate() { if( hasInput() ) - var_SetInteger( p_input, "rate", INPUT_RATE_DEFAULT ); + var_SetFloat( p_input, "rate", 1. ); } void InputManager::setRate( int new_rate ) { if( hasInput() ) - var_SetInteger( p_input, "rate", new_rate ); + var_SetFloat( p_input, "rate", + (float)INPUT_RATE_DEFAULT / (float)new_rate ); +} + +void InputManager::jumpFwd() +{ + int i_interval = var_InheritInteger( p_input, "short-jump-size" ); + if( i_interval > 0 ) + { + mtime_t val = (mtime_t)(i_interval) * 1000000L; + var_SetTime( p_input, "time-offset", val ); + } +} + +void InputManager::jumpBwd() +{ + int i_interval = var_InheritInteger( p_input, "short-jump-size" ); + if( i_interval > 0 ) + { + mtime_t val = -1 *(mtime_t)(i_interval) * 1000000L; + var_SetTime( p_input, "time-offset", val ); + } +} + +void InputManager::setAtoB() +{ + if( !timeA ) + { + timeA = var_GetTime( THEMIM->getInput(), "time" ); + } + else if( !timeB ) + { + timeB = var_GetTime( THEMIM->getInput(), "time" ); + var_SetTime( THEMIM->getInput(), "time" , timeA ); + CONNECT( this, positionUpdated( float, int64_t, int ), + this, AtoBLoop( float, int64_t, int ) ); + } + else + { + timeA = 0; + timeB = 0; + disconnect( this, SIGNAL( positionUpdated( float, int64_t, int ) ), + this, SLOT( AtoBLoop( float, int64_t, int ) ) ); + } + emit AtoBchanged( (timeA != 0 ), (timeB != 0 ) ); +} + +/* Function called regularly when in an AtoB loop */ +void InputManager::AtoBLoop( float, int64_t i_time, int ) +{ + if( timeB ) + { + if( i_time >= timeB || i_time < timeA ) + var_SetTime( THEMIM->getInput(), "time" , timeA ); + } } /********************************************************************** @@ -541,97 +927,147 @@ MainInputManager::MainInputManager( intf_thread_t *_p_intf ) p_input = NULL; im = new InputManager( this, p_intf ); -// var_AddCallback( THEPL, "item-change", PLItemChanged, this ); var_AddCallback( THEPL, "item-change", ItemChanged, im ); - var_AddCallback( THEPL, "playlist-current", PLItemChanged, this ); + var_AddCallback( THEPL, "item-current", PLItemChanged, this ); var_AddCallback( THEPL, "activity", PLItemChanged, this ); + var_AddCallback( THEPL, "leaf-to-parent", LeafToParent, this ); + var_AddCallback( THEPL, "playlist-item-append", PLItemAppended, this ); + var_AddCallback( THEPL, "playlist-item-deleted", PLItemRemoved, this ); + var_AddCallback( THEPL, "random", RandomChanged, this ); + var_AddCallback( THEPL, "repeat", RepeatChanged, this ); + var_AddCallback( THEPL, "loop", LoopChanged, this ); - var_AddCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this ); - - // No necessary, I think TODO REMOVE ME at the end - //var_AddCallback( THEPL, "intf-change", ItemChanged, im ); + var_AddCallback( THEPL, "volume-change", VolumeChanged, this ); + var_AddCallback( THEPL, "volume-muted", SoundMuteChanged, this ); /* Warn our embedded IM about input changes */ - CONNECT( this, inputChanged( input_thread_t * ), - im, setInput( input_thread_t * ) ); - - /* emit check if playlist has allready started playing */ - vlc_value_t val; - var_Change( THEPL, "playlist-current", VLC_VAR_CHOICESCOUNT, &val, NULL ); - IMEvent *event = new IMEvent( ItemChanged_Type, val.i_int); - QApplication::postEvent( this, static_cast(event) ); + DCONNECT( this, inputChanged( input_thread_t * ), + im, setInput( input_thread_t * ) ); + /* emit check if playlist has already started playing */ + input_thread_t *p_input = playlist_CurrentInput( THEPL ); + if( p_input ) + { + input_item_t *p_item = input_GetItem( p_input ); + if( p_item ) + { + IMEvent *event = new IMEvent( ItemChanged_Type, p_item ); + customEvent( event ); + delete event; + } + vlc_object_release( p_input ); + } } MainInputManager::~MainInputManager() { if( p_input ) { + emit inputChanged( NULL ); var_DelCallback( p_input, "state", PLItemChanged, this ); vlc_object_release( p_input ); - emit inputChanged( NULL ); } - var_DelCallback( p_intf->p_libvlc, "volume-change", VolumeChanged, this ); + var_DelCallback( THEPL, "volume-change", VolumeChanged, this ); + var_DelCallback( THEPL, "volume-muted", SoundMuteChanged, this ); var_DelCallback( THEPL, "activity", PLItemChanged, this ); var_DelCallback( THEPL, "item-change", ItemChanged, im ); -// var_DelCallback( THEPL, "item-change", PLItemChanged, this ); + var_DelCallback( THEPL, "leaf-to-parent", LeafToParent, this ); - var_DelCallback( THEPL, "playlist-current", PLItemChanged, this ); + var_DelCallback( THEPL, "item-current", PLItemChanged, this ); + var_DelCallback( THEPL, "playlist-item-append", PLItemAppended, this ); + var_DelCallback( THEPL, "playlist-item-deleted", PLItemRemoved, this ); + var_DelCallback( THEPL, "random", RandomChanged, this ); + var_DelCallback( THEPL, "repeat", RepeatChanged, this ); + var_DelCallback( THEPL, "loop", LoopChanged, this ); + +} + +vout_thread_t* MainInputManager::getVout() +{ + return p_input ? input_GetVout( p_input ) : NULL; +} + +aout_instance_t * MainInputManager::getAout() +{ + return p_input ? input_GetAout( p_input ) : NULL; } void MainInputManager::customEvent( QEvent *event ) { int type = event->type(); - if ( type != ItemChanged_Type && type != VolumeChanged_Type ) - return; + + PLEvent *plEv; + IMEvent *imEv; // msg_Dbg( p_intf, "New MainIM Event of type: %i", type ); - if( type == VolumeChanged_Type ) + switch( type ) { + case VolumeChanged_Type: emit volumeChanged(); return; + case SoundMuteChanged_Type: + emit soundMuteChanged(); + return; + case PLItemAppended_Type: + plEv = static_cast( event ); + emit playlistItemAppended( plEv->i_item, plEv->i_parent ); + return; + case PLItemRemoved_Type: + plEv = static_cast( event ); + emit playlistItemRemoved( plEv->i_item ); + return; + case RandomChanged_Type: + emit randomChanged( var_GetBool( THEPL, "random" ) ); + return; + case LoopChanged_Type: + case RepeatChanged_Type: + notifyRepeatLoop(); + return; + case LeafToParent_Type: + imEv = static_cast( event ); + emit leafBecameParent( imEv->p_item ); + default: + if( type != ItemChanged_Type ) return; } /* Should be PLItemChanged Event */ - if( VLC_OBJECT_INTF == p_intf->i_object_type ) /* FIXME: don't use object type */ + if( !p_intf->p_sys->b_isDialogProvider ) { - vlc_mutex_lock( &p_intf->change_lock ); if( p_input && ( p_input->b_dead || !vlc_object_alive (p_input) ) ) { + emit inputChanged( p_input ); var_DelCallback( p_input, "state", PLItemChanged, this ); vlc_object_release( p_input ); - emit inputChanged( NULL ); p_input = NULL; - vlc_mutex_unlock( &p_intf->change_lock ); return; } if( !p_input ) { - QPL_LOCK; - p_input = THEPL->p_input; - if( p_input && !( !vlc_object_alive (p_input) || p_input->b_dead) ) + p_input = playlist_CurrentInput(THEPL); + if( p_input ) { - vlc_object_yield( p_input ); var_AddCallback( p_input, "state", PLItemChanged, this ); emit inputChanged( p_input ); } - else - p_input = NULL; - QPL_UNLOCK; } - vlc_mutex_unlock( &p_intf->change_lock ); } else { + /* remove previous stored p_input */ + if( p_input ) + { + vlc_object_release( p_input ); + p_input = NULL; + } /* we are working as a dialogs provider */ - playlist_t *p_playlist = pl_Yield( p_intf ); - p_input = playlist_CurrentInput( p_playlist ); - emit inputChanged( p_input ); - vlc_object_release( p_input ); - pl_Release( p_intf ); + p_input = playlist_CurrentInput( pl_Get(p_intf) ); + if( p_input ) + { + emit inputChanged( p_input ); + } } } @@ -653,121 +1089,159 @@ void MainInputManager::prev() void MainInputManager::togglePlayPause() { - if( p_input == NULL ) - { + /* No input, play */ + if( !p_input ) playlist_Play( THEPL ); - return; - } - getIM()->togglePlayPause(); + else + getIM()->togglePlayPause(); } -bool MainInputManager::teletextState() +void MainInputManager::play() { - im = getIM(); - if( im->hasInput() ) + /* No input, play */ + if( !p_input ) + playlist_Play( THEPL ); + else { - const int i_teletext_es = var_GetInteger( getInput(), "teletext-es" ); - const int i_spu_es = var_GetInteger( getInput(), "spu-es" ); + if( PLAYING_S != var_GetInteger( p_input, "state" ) ) + { + getIM()->togglePlayPause(); + } + } +} - return i_teletext_es >= 0 && i_teletext_es == i_spu_es; +void MainInputManager::pause() +{ + if(p_input && PLAYING_S == var_GetInteger( p_input, "state" ) ) + { + getIM()->togglePlayPause(); } - return false; } -/* Static callbacks */ +void MainInputManager::toggleRandom() +{ + var_ToggleBool( THEPL, "random" ); +} -/* IM */ -static int InterfaceChanged( vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *param ) +void MainInputManager::notifyRepeatLoop() { - static int counter = 0; - InputManager *im = (InputManager*)param; + int i_value = var_GetBool( THEPL, "loop" ) * REPEAT_ALL + + var_GetBool( THEPL, "repeat" ) * REPEAT_ONE; - counter = ++counter % 4; - if(!counter) - return VLC_SUCCESS; - IMEvent *event = new IMEvent( PositionUpdate_Type, 0 ); - QApplication::postEvent( im, static_cast(event) ); - return VLC_SUCCESS; + emit repeatLoopChanged( i_value ); } -static int ItemStateChanged( vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *param ) +void MainInputManager::loopRepeatLoopStatus() { - InputManager *im = (InputManager*)param; + /* Toggle Normal -> Loop -> Repeat -> Normal ... */ + if( var_GetBool( THEPL, "repeat" ) ) + var_SetBool( THEPL, "repeat", false ); + else if( var_GetBool( THEPL, "loop" ) ) + { + var_SetBool( THEPL, "loop", false ); + var_SetBool( THEPL, "repeat", true ); + } + else + var_SetBool( THEPL, "loop", true ); +} - IMEvent *event = new IMEvent( ItemStateChanged_Type, 0 ); - QApplication::postEvent( im, static_cast(event) ); - return VLC_SUCCESS; +void MainInputManager::activatePlayQuit( bool b_exit ) +{ + var_SetBool( THEPL, "play-and-exit", b_exit ); } -static int ItemRateChanged( vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *param ) + +/**************************** + * Static callbacks for MIM * + ****************************/ +static int PLItemChanged( vlc_object_t *p_this, const char *psz_var, + vlc_value_t oldval, vlc_value_t, void *param ) { - InputManager *im = (InputManager*)param; + MainInputManager *mim = (MainInputManager*)param; - IMEvent *event = new IMEvent( ItemRateChanged_Type, 0 ); - QApplication::postEvent( im, static_cast(event) ); + IMEvent *event = new IMEvent( ItemChanged_Type ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } -static int ItemTitleChanged( vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *param ) +static int LeafToParent( vlc_object_t *p_this, const char *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *param ) { - InputManager *im = (InputManager*)param; + MainInputManager *mim = (MainInputManager*)param; - IMEvent *event = new IMEvent( ItemTitleChanged_Type, 0 ); - QApplication::postEvent( im, static_cast(event) ); + IMEvent *event = new IMEvent( LeafToParent_Type, + static_cast( newval.p_address ) ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } -static int ItemChanged( vlc_object_t *p_this, const char *psz_var, +static int VolumeChanged( vlc_object_t *p_this, const char *psz_var, vlc_value_t oldval, vlc_value_t newval, void *param ) { - InputManager *im = (InputManager*)param; + MainInputManager *mim = (MainInputManager*)param; - IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int ); - QApplication::postEvent( im, static_cast(event) ); + IMEvent *event = new IMEvent( VolumeChanged_Type ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } -static int ChangeSPU( vlc_object_t *p_this, const char *var, vlc_value_t o, - vlc_value_t n, void *param ) +static int SoundMuteChanged( vlc_object_t *p_this, const char *psz_var, + vlc_value_t oldval, vlc_value_t newval, void *param ) { - InputManager *im = (InputManager*)param; - IMEvent *event = new IMEvent( ItemSpuChanged_Type, 0 ); - QApplication::postEvent( im, static_cast(event) ); + MainInputManager *mim = (MainInputManager*)param; + + IMEvent *event = new IMEvent( SoundMuteChanged_Type ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } -static int ChangeTeletext( vlc_object_t *p_this, const char *var, vlc_value_t o, - vlc_value_t n, void *param ) +static int PLItemAppended +( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data ) { + MainInputManager *mim = static_cast(data); + playlist_add_t *p_add = static_cast( cur.p_address ); - InputManager *im = (InputManager*)param; - IMEvent *event = new IMEvent( ItemTeletextChanged_Type, 0 ); - QApplication::postEvent( im, static_cast(event) ); + PLEvent *event = new PLEvent( PLItemAppended_Type, p_add->i_item, p_add->i_node ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } +static int PLItemRemoved +( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data ) +{ + MainInputManager *mim = static_cast(data); -/* MIM */ -static int PLItemChanged( vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *param ) + PLEvent *event = new PLEvent( PLItemRemoved_Type, cur.i_int, 0 ); + QApplication::postEvent( mim, event ); + return VLC_SUCCESS; +} + +static int RandomChanged +( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data ) { - MainInputManager *mim = (MainInputManager*)param; + MainInputManager *mim = static_cast(data); - IMEvent *event = new IMEvent( ItemChanged_Type, newval.i_int ); - QApplication::postEvent( mim, static_cast(event) ); + IMEvent *event = new IMEvent( RandomChanged_Type ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } -static int VolumeChanged( vlc_object_t *p_this, const char *psz_var, - vlc_value_t oldval, vlc_value_t newval, void *param ) +/* Probably could be merged with next callback */ +static int LoopChanged +( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data ) { - MainInputManager *mim = (MainInputManager*)param; + MainInputManager *mim = static_cast(data); - IMEvent *event = new IMEvent( VolumeChanged_Type, newval.i_int ); - QApplication::postEvent( mim, static_cast(event) ); + IMEvent *event = new IMEvent( LoopChanged_Type ); + QApplication::postEvent( mim, event ); return VLC_SUCCESS; } +static int RepeatChanged +( vlc_object_t * obj, const char *var, vlc_value_t old, vlc_value_t cur, void *data ) +{ + MainInputManager *mim = static_cast(data); + + IMEvent *event = new IMEvent( RepeatChanged_Type ); + QApplication::postEvent( mim, event ); + return VLC_SUCCESS; +}