1 /*****************************************************************************
2 * hotkeys.c: Hotkey handling for vlc
3 *****************************************************************************
4 * Copyright (C) 2005-2009 the VideoLAN team
7 * Authors: Sigmund Augdal Helberg <dnumgis@videolan.org>
8 * Jean-Paul Saman <jpsaman #_at_# m2x.nl>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
33 #define VLC_MODULE_LICENSE VLC_LICENSE_GPL_2_PLUS
34 #include <vlc_common.h>
35 #include <vlc_plugin.h>
36 #include <vlc_interface.h>
37 #include <vlc_input.h>
39 #include <vlc_viewpoint.h>
40 #include <vlc_vout_osd.h>
41 #include <vlc_playlist.h>
42 #include <vlc_actions.h>
47 /*****************************************************************************
48 * intf_sys_t: description and status of FB interface
49 *****************************************************************************/
53 vout_thread_t
*p_vout
;
54 input_thread_t
*p_input
;
57 /*subtitle_delaybookmarks: placeholder for storing subtitle sync timestamps*/
60 int64_t i_time_subtitle
;
62 } subtitle_delaybookmarks
;
67 bool b_button_pressed
;
72 /*****************************************************************************
74 *****************************************************************************/
75 static int Open ( vlc_object_t
* );
76 static void Close ( vlc_object_t
* );
77 static int ActionEvent( vlc_object_t
*, char const *,
78 vlc_value_t
, vlc_value_t
, void * );
79 static void PlayBookmark( intf_thread_t
*, int );
80 static void SetBookmark ( intf_thread_t
*, int );
81 static void DisplayPosition( vout_thread_t
*, int, input_thread_t
* );
82 static void DisplayVolume( vout_thread_t
*, int, float );
83 static void DisplayRate ( vout_thread_t
*, float );
84 static float AdjustRateFine( vlc_object_t
*, const int );
85 static void ClearChannels ( vout_thread_t
*, int );
87 #define DisplayMessage(vout, ...) \
90 vout_OSDMessage(vout, VOUT_SPU_CHANNEL_OSD, __VA_ARGS__); \
92 #define DisplayIcon(vout, icon) \
93 do { if(vout) vout_OSDIcon(vout, VOUT_SPU_CHANNEL_OSD, icon); } while(0)
95 /*****************************************************************************
97 *****************************************************************************/
100 set_shortname( N_("Hotkeys") )
101 set_description( N_("Hotkeys management interface") )
102 set_capability( "interface", 0 )
103 set_callbacks( Open
, Close
)
104 set_category( CAT_INTERFACE
)
105 set_subcategory( SUBCAT_INTERFACE_HOTKEYS
)
109 static int MovedEvent( vlc_object_t
*p_this
, char const *psz_var
,
110 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
112 intf_thread_t
*p_intf
= (intf_thread_t
*)p_data
;
113 intf_sys_t
*p_sys
= p_intf
->p_sys
;
115 (void) p_this
; (void) psz_var
; (void) oldval
;
117 if( p_sys
->vrnav
.b_button_pressed
)
119 int i_horizontal
= newval
.coords
.x
- p_sys
->vrnav
.x
;
120 int i_vertical
= newval
.coords
.y
- p_sys
->vrnav
.y
;
122 vlc_viewpoint_t viewpoint
= {
123 .yaw
= -i_horizontal
* 0.05f
,
124 .pitch
= -i_vertical
* 0.05f
,
127 input_UpdateViewpoint( p_sys
->p_input
, &viewpoint
, false );
129 p_sys
->vrnav
.x
= newval
.coords
.x
;
130 p_sys
->vrnav
.y
= newval
.coords
.y
;
136 static int ViewpointMovedEvent( vlc_object_t
*p_this
, char const *psz_var
,
137 vlc_value_t oldval
, vlc_value_t newval
,
140 intf_thread_t
*p_intf
= (intf_thread_t
*)p_data
;
141 intf_sys_t
*p_sys
= p_intf
->p_sys
;
143 (void) p_this
; (void) psz_var
; (void) oldval
;
145 input_UpdateViewpoint( p_sys
->p_input
, newval
.p_address
, false );
150 static int ButtonEvent( vlc_object_t
*p_this
, char const *psz_var
,
151 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
153 intf_thread_t
*p_intf
= p_data
;
154 intf_sys_t
*p_sys
= p_intf
->p_sys
;
156 (void) psz_var
; (void) oldval
;
158 if( newval
.i_int
& 0x01 )
160 if( !p_sys
->vrnav
.b_button_pressed
)
162 p_sys
->vrnav
.b_button_pressed
= true;
163 var_GetCoords( p_this
, "mouse-moved",
164 &p_sys
->vrnav
.x
, &p_sys
->vrnav
.y
);
168 p_sys
->vrnav
.b_button_pressed
= false;
173 static void ChangeVout( intf_thread_t
*p_intf
, vout_thread_t
*p_vout
)
175 intf_sys_t
*p_sys
= p_intf
->p_sys
;
178 bool b_vrnav_can_change
;
181 slider_chan
= vout_RegisterSubpictureChannel( p_vout
);
182 b_vrnav_can_change
= var_GetBool( p_vout
, "viewpoint-changeable" );
185 vlc_mutex_lock( &p_sys
->lock
);
186 vout_thread_t
*p_old_vout
= p_sys
->p_vout
;
187 bool b_vrnav_could_change
= p_sys
->vrnav
.b_can_change
;
188 p_sys
->p_vout
= p_vout
;
191 p_sys
->slider_chan
= slider_chan
;
192 p_sys
->vrnav
.b_can_change
= b_vrnav_can_change
;
195 p_sys
->vrnav
.b_can_change
= false;
196 vlc_mutex_unlock( &p_sys
->lock
);
198 if( p_old_vout
!= NULL
)
200 if( b_vrnav_could_change
)
202 var_DelCallback( p_old_vout
, "mouse-moved", MovedEvent
,
204 var_DelCallback( p_old_vout
, "mouse-button-down", ButtonEvent
,
206 var_DelCallback( p_old_vout
, "viewpoint-moved", ViewpointMovedEvent
,
209 vlc_object_release( p_old_vout
);
212 if( p_sys
->vrnav
.b_can_change
)
214 assert( p_sys
->p_vout
!= NULL
);
215 var_AddCallback( p_sys
->p_vout
, "mouse-moved", MovedEvent
,
217 var_AddCallback( p_sys
->p_vout
, "mouse-button-down", ButtonEvent
,
219 var_AddCallback( p_sys
->p_vout
, "viewpoint-moved", ViewpointMovedEvent
,
224 static int InputEvent( vlc_object_t
*p_this
, char const *psz_var
,
225 vlc_value_t oldval
, vlc_value_t val
, void *p_data
)
227 input_thread_t
*p_input
= (input_thread_t
*)p_this
;
228 intf_thread_t
*p_intf
= p_data
;
230 (void) psz_var
; (void) oldval
;
232 if( val
.i_int
== INPUT_EVENT_VOUT
)
233 ChangeVout( p_intf
, input_GetVout( p_input
) );
238 static void ChangeInput( intf_thread_t
*p_intf
, input_thread_t
*p_input
)
240 intf_sys_t
*p_sys
= p_intf
->p_sys
;
242 input_thread_t
*p_old_input
= p_sys
->p_input
;
243 vout_thread_t
*p_old_vout
= NULL
;
244 if( p_old_input
!= NULL
)
246 /* First, remove callbacks from previous input. It's safe to access it
247 * unlocked, since it's written from this thread */
248 var_DelCallback( p_old_input
, "intf-event", InputEvent
, p_intf
);
250 p_old_vout
= p_sys
->p_vout
;
251 /* Remove mouse events before setting new input, since callbacks may
253 if( p_old_vout
!= NULL
&& p_sys
->vrnav
.b_can_change
)
255 var_DelCallback( p_old_vout
, "mouse-moved", MovedEvent
,
257 var_DelCallback( p_old_vout
, "mouse-button-down", ButtonEvent
,
259 var_DelCallback( p_old_vout
, "viewpoint-moved", ViewpointMovedEvent
,
264 /* Replace input and vout locked */
265 vlc_mutex_lock( &p_sys
->lock
);
266 p_sys
->p_input
= p_input
? vlc_object_hold( p_input
) : NULL
;
267 p_sys
->p_vout
= NULL
;
268 p_sys
->vrnav
.b_can_change
= false;
269 vlc_mutex_unlock( &p_sys
->lock
);
271 /* Release old input and vout objects unlocked */
272 if( p_old_input
!= NULL
)
274 if( p_old_vout
!= NULL
)
275 vlc_object_release( p_old_vout
);
276 vlc_object_release( p_old_input
);
279 /* Register input events */
280 if( p_input
!= NULL
)
281 var_AddCallback( p_input
, "intf-event", InputEvent
, p_intf
);
284 static int PlaylistEvent( vlc_object_t
*p_this
, char const *psz_var
,
285 vlc_value_t oldval
, vlc_value_t val
, void *p_data
)
287 intf_thread_t
*p_intf
= p_data
;
289 (void) p_this
; (void) psz_var
; (void) oldval
;
291 ChangeInput( p_intf
, val
.p_address
);
296 /*****************************************************************************
297 * Open: initialize interface
298 *****************************************************************************/
299 static int Open( vlc_object_t
*p_this
)
301 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
303 p_sys
= malloc( sizeof( intf_sys_t
) );
307 p_intf
->p_sys
= p_sys
;
309 p_sys
->p_vout
= NULL
;
310 p_sys
->p_input
= NULL
;
311 p_sys
->vrnav
.b_can_change
= false;
312 p_sys
->vrnav
.b_button_pressed
= false;
313 p_sys
->subtitle_delaybookmarks
.i_time_audio
= 0;
314 p_sys
->subtitle_delaybookmarks
.i_time_subtitle
= 0;
316 vlc_mutex_init( &p_sys
->lock
);
318 var_AddCallback( p_intf
->obj
.libvlc
, "key-action", ActionEvent
, p_intf
);
320 var_AddCallback( pl_Get(p_intf
), "input-current", PlaylistEvent
, p_intf
);
325 /*****************************************************************************
326 * Close: destroy interface
327 *****************************************************************************/
328 static void Close( vlc_object_t
*p_this
)
330 intf_thread_t
*p_intf
= (intf_thread_t
*)p_this
;
331 intf_sys_t
*p_sys
= p_intf
->p_sys
;
333 var_DelCallback( pl_Get(p_intf
), "input-current", PlaylistEvent
, p_intf
);
335 var_DelCallback( p_intf
->obj
.libvlc
, "key-action", ActionEvent
, p_intf
);
337 ChangeInput( p_intf
, NULL
);
339 vlc_mutex_destroy( &p_sys
->lock
);
341 /* Destroy structure */
345 static int PutAction( intf_thread_t
*p_intf
, input_thread_t
*p_input
,
346 vout_thread_t
*p_vout
, int slider_chan
, bool b_vrnav
,
349 #define DO_ACTION(x) PutAction( p_intf, p_input, p_vout, slider_chan, b_vrnav, x)
350 intf_sys_t
*p_sys
= p_intf
->p_sys
;
351 playlist_t
*p_playlist
= pl_Get( p_intf
);
356 /* Libvlc / interface actions */
358 libvlc_Quit( p_intf
->obj
.libvlc
);
360 ClearChannels( p_vout
, slider_chan
);
361 DisplayMessage( p_vout
, _( "Quit" ) );
364 case ACTIONID_INTF_TOGGLE_FSC
:
365 case ACTIONID_INTF_HIDE
:
366 var_TriggerCallback( p_intf
->obj
.libvlc
, "intf-toggle-fscontrol" );
368 case ACTIONID_INTF_BOSS
:
369 var_TriggerCallback( p_intf
->obj
.libvlc
, "intf-boss" );
371 case ACTIONID_INTF_POPUP_MENU
:
372 var_TriggerCallback( p_intf
->obj
.libvlc
, "intf-popupmenu" );
375 /* Playlist actions (including audio) */
378 /* Toggle Normal -> Loop -> Repeat -> Normal ... */
380 if( var_GetBool( p_playlist
, "repeat" ) )
382 var_SetBool( p_playlist
, "repeat", false );
386 if( var_GetBool( p_playlist
, "loop" ) )
387 { /* FIXME: this is not atomic, we should use a real tristate */
388 var_SetBool( p_playlist
, "loop", false );
389 var_SetBool( p_playlist
, "repeat", true );
394 var_SetBool( p_playlist
, "loop", true );
397 DisplayMessage( p_vout
, _("Loop: %s"), vlc_gettext(mode
) );
401 case ACTIONID_RANDOM
:
403 const bool state
= var_ToggleBool( p_playlist
, "random" );
404 DisplayMessage( p_vout
, _("Random: %s"),
405 vlc_gettext( state
? N_("On") : N_("Off") ) );
410 DisplayMessage( p_vout
, _("Next") );
411 playlist_Next( p_playlist
);
414 DisplayMessage( p_vout
, _("Previous") );
415 playlist_Prev( p_playlist
);
419 playlist_Stop( p_playlist
);
422 case ACTIONID_RATE_NORMAL
:
423 var_SetFloat( p_playlist
, "rate", 1.f
);
424 DisplayRate( p_vout
, 1.f
);
426 case ACTIONID_FASTER
:
427 var_TriggerCallback( p_playlist
, "rate-faster" );
428 DisplayRate( p_vout
, var_GetFloat( p_playlist
, "rate" ) );
430 case ACTIONID_SLOWER
:
431 var_TriggerCallback( p_playlist
, "rate-slower" );
432 DisplayRate( p_vout
, var_GetFloat( p_playlist
, "rate" ) );
434 case ACTIONID_RATE_FASTER_FINE
:
435 case ACTIONID_RATE_SLOWER_FINE
:
437 const int i_dir
= i_action
== ACTIONID_RATE_FASTER_FINE
? 1 : -1;
438 float rate
= AdjustRateFine( VLC_OBJECT(p_playlist
), i_dir
);
440 var_SetFloat( p_playlist
, "rate", rate
);
441 DisplayRate( p_vout
, rate
);
445 case ACTIONID_PLAY_BOOKMARK1
:
446 case ACTIONID_PLAY_BOOKMARK2
:
447 case ACTIONID_PLAY_BOOKMARK3
:
448 case ACTIONID_PLAY_BOOKMARK4
:
449 case ACTIONID_PLAY_BOOKMARK5
:
450 case ACTIONID_PLAY_BOOKMARK6
:
451 case ACTIONID_PLAY_BOOKMARK7
:
452 case ACTIONID_PLAY_BOOKMARK8
:
453 case ACTIONID_PLAY_BOOKMARK9
:
454 case ACTIONID_PLAY_BOOKMARK10
:
455 PlayBookmark( p_intf
, i_action
- ACTIONID_PLAY_BOOKMARK1
+ 1 );
458 case ACTIONID_SET_BOOKMARK1
:
459 case ACTIONID_SET_BOOKMARK2
:
460 case ACTIONID_SET_BOOKMARK3
:
461 case ACTIONID_SET_BOOKMARK4
:
462 case ACTIONID_SET_BOOKMARK5
:
463 case ACTIONID_SET_BOOKMARK6
:
464 case ACTIONID_SET_BOOKMARK7
:
465 case ACTIONID_SET_BOOKMARK8
:
466 case ACTIONID_SET_BOOKMARK9
:
467 case ACTIONID_SET_BOOKMARK10
:
468 SetBookmark( p_intf
, i_action
- ACTIONID_SET_BOOKMARK1
+ 1 );
470 case ACTIONID_PLAY_CLEAR
:
471 playlist_Clear( p_playlist
, pl_Unlocked
);
473 case ACTIONID_VOL_UP
:
476 if( playlist_VolumeUp( p_playlist
, 1, &vol
) == 0 )
477 DisplayVolume( p_vout
, slider_chan
, vol
);
480 case ACTIONID_VOL_DOWN
:
483 if( playlist_VolumeDown( p_playlist
, 1, &vol
) == 0 )
484 DisplayVolume( p_vout
, slider_chan
, vol
);
487 case ACTIONID_VOL_MUTE
:
489 int mute
= playlist_MuteGet( p_playlist
);
493 if( playlist_MuteSet( p_playlist
, mute
) )
496 float vol
= playlist_VolumeGet( p_playlist
);
497 if( mute
|| vol
== 0.f
)
499 ClearChannels( p_vout
, slider_chan
);
500 DisplayIcon( p_vout
, OSD_MUTE_ICON
);
503 DisplayVolume( p_vout
, slider_chan
, vol
);
507 case ACTIONID_AUDIODEVICE_CYCLE
:
509 audio_output_t
*p_aout
= playlist_GetAout( p_playlist
);
514 int n
= aout_DevicesList( p_aout
, &ids
, &names
);
518 char *dev
= aout_DeviceGet( p_aout
);
519 const char *devstr
= (dev
!= NULL
) ? dev
: "";
522 for( int i
= 0; i
< n
; i
++ )
524 if( !strcmp(devstr
, ids
[i
]) )
529 if( !aout_DeviceSet( p_aout
, ids
[idx
] ) )
530 DisplayMessage( p_vout
, _("Audio Device: %s"), names
[idx
] );
531 vlc_object_release( p_aout
);
533 for( int i
= 0; i
< n
; i
++ )
543 /* Playlist + input actions */
544 case ACTIONID_PLAY_PAUSE
:
547 ClearChannels( p_vout
, slider_chan
);
549 int state
= var_GetInteger( p_input
, "state" );
550 DisplayIcon( p_vout
, state
!= PAUSE_S
? OSD_PAUSE_ICON
: OSD_PLAY_ICON
);
552 playlist_TogglePause( p_playlist
);
556 if( p_input
&& var_GetFloat( p_input
, "rate" ) != 1.f
)
557 /* Return to normal speed */
558 var_SetFloat( p_input
, "rate", 1.f
);
561 ClearChannels( p_vout
, slider_chan
);
562 DisplayIcon( p_vout
, OSD_PLAY_ICON
);
563 playlist_Play( p_playlist
);
567 /* Playlist + video output actions */
568 case ACTIONID_WALLPAPER
:
570 bool wp
= var_ToggleBool( p_playlist
, "video-wallpaper" );
572 var_SetBool( p_vout
, "video-wallpaper", wp
);
578 if( p_input
&& var_GetInteger( p_input
, "state" ) != PAUSE_S
)
580 ClearChannels( p_vout
, slider_chan
);
581 DisplayIcon( p_vout
, OSD_PAUSE_ICON
);
582 var_SetInteger( p_input
, "state", PAUSE_S
);
586 case ACTIONID_RECORD
:
587 if( p_input
&& var_GetBool( p_input
, "can-record" ) )
589 const bool on
= var_ToggleBool( p_input
, "record" );
590 DisplayMessage( p_vout
, vlc_gettext(on
591 ? N_("Recording") : N_("Recording done")) );
595 case ACTIONID_FRAME_NEXT
:
598 var_TriggerCallback( p_input
, "frame-next" );
599 DisplayMessage( p_vout
, _("Next frame") );
603 case ACTIONID_SUBSYNC_MARKAUDIO
:
605 p_sys
->subtitle_delaybookmarks
.i_time_audio
= mdate();
606 DisplayMessage( p_vout
, _("Sub sync: bookmarked audio time"));
609 case ACTIONID_SUBSYNC_MARKSUB
:
612 vlc_value_t val
, list
, list2
;
614 var_Get( p_input
, "spu-es", &val
);
616 var_Change( p_input
, "spu-es", VLC_VAR_GETCHOICES
,
618 i_count
= list
.p_list
->i_count
;
619 if( i_count
< 1 || val
.i_int
< 0 )
621 DisplayMessage( p_vout
, _("No active subtitle") );
622 var_FreeList( &list
, &list2
);
625 p_sys
->subtitle_delaybookmarks
.i_time_subtitle
= mdate();
626 DisplayMessage( p_vout
,
627 _("Sub sync: bookmarked subtitle time"));
628 var_FreeList( &list
, &list2
);
631 case ACTIONID_SUBSYNC_APPLY
:
633 /* Warning! Can yield a pause in the playback.
634 * For example, the following succession of actions will yield a 5 second delay :
635 * - Pressing Shift-H (ACTIONID_SUBSYNC_MARKAUDIO)
637 * - Press Shift-J (ACTIONID_SUBSYNC_MARKSUB)
638 * - Press Shift-K (ACTIONID_SUBSYNC_APPLY)
639 * --> 5 seconds pause
640 * This is due to var_SetTime() (and ultimately UpdatePtsDelay())
641 * which causes the video to pause for an equivalent duration
642 * (This problem is also present in the "Track synchronization" window) */
645 if ( (p_sys
->subtitle_delaybookmarks
.i_time_audio
== 0) || (p_sys
->subtitle_delaybookmarks
.i_time_subtitle
== 0) )
647 DisplayMessage( p_vout
, _( "Sub sync: set bookmarks first!" ) );
651 int64_t i_current_subdelay
= var_GetInteger( p_input
, "spu-delay" );
652 int64_t i_additional_subdelay
= p_sys
->subtitle_delaybookmarks
.i_time_audio
- p_sys
->subtitle_delaybookmarks
.i_time_subtitle
;
653 int64_t i_total_subdelay
= i_current_subdelay
+ i_additional_subdelay
;
654 var_SetInteger( p_input
, "spu-delay", i_total_subdelay
);
655 ClearChannels( p_vout
, slider_chan
);
656 DisplayMessage( p_vout
, _( "Sub sync: corrected %i ms (total delay = %i ms)" ),
657 (int)(i_additional_subdelay
/ 1000),
658 (int)(i_total_subdelay
/ 1000) );
659 p_sys
->subtitle_delaybookmarks
.i_time_audio
= 0;
660 p_sys
->subtitle_delaybookmarks
.i_time_subtitle
= 0;
665 case ACTIONID_SUBSYNC_RESET
:
667 var_SetInteger( p_input
, "spu-delay", 0);
668 ClearChannels( p_vout
, slider_chan
);
669 DisplayMessage( p_vout
, _( "Sub sync: delay reset" ) );
670 p_sys
->subtitle_delaybookmarks
.i_time_audio
= 0;
671 p_sys
->subtitle_delaybookmarks
.i_time_subtitle
= 0;
675 case ACTIONID_SUBDELAY_DOWN
:
676 case ACTIONID_SUBDELAY_UP
:
678 int diff
= (i_action
== ACTIONID_SUBDELAY_UP
) ? 50000 : -50000;
681 vlc_value_t val
, list
, list2
;
683 var_Get( p_input
, "spu-es", &val
);
685 var_Change( p_input
, "spu-es", VLC_VAR_GETCHOICES
,
687 i_count
= list
.p_list
->i_count
;
688 if( i_count
< 1 || val
.i_int
< 0 )
690 DisplayMessage( p_vout
, _("No active subtitle") );
691 var_FreeList( &list
, &list2
);
694 int64_t i_delay
= var_GetInteger( p_input
, "spu-delay" ) + diff
;
696 var_SetInteger( p_input
, "spu-delay", i_delay
);
697 ClearChannels( p_vout
, slider_chan
);
698 DisplayMessage( p_vout
, _( "Subtitle delay %i ms" ),
699 (int)(i_delay
/1000) );
700 var_FreeList( &list
, &list2
);
704 case ACTIONID_AUDIODELAY_DOWN
:
705 case ACTIONID_AUDIODELAY_UP
:
707 int diff
= (i_action
== ACTIONID_AUDIODELAY_UP
) ? 50000 : -50000;
710 int64_t i_delay
= var_GetInteger( p_input
, "audio-delay" )
713 var_SetInteger( p_input
, "audio-delay", i_delay
);
714 ClearChannels( p_vout
, slider_chan
);
715 DisplayMessage( p_vout
, _( "Audio delay %i ms" ),
716 (int)(i_delay
/1000) );
721 case ACTIONID_AUDIO_TRACK
:
724 vlc_value_t val
, list
, list2
;
726 var_Get( p_input
, "audio-es", &val
);
727 var_Change( p_input
, "audio-es", VLC_VAR_GETCHOICES
,
729 i_count
= list
.p_list
->i_count
;
732 for( i
= 0; i
< i_count
; i
++ )
734 if( val
.i_int
== list
.p_list
->p_values
[i
].i_int
)
739 /* value of audio-es was not in choices list */
743 "invalid current audio track, selecting 0" );
746 else if( i
== i_count
- 1 )
750 var_Set( p_input
, "audio-es", list
.p_list
->p_values
[i
] );
751 DisplayMessage( p_vout
, _("Audio track: %s"),
752 list2
.p_list
->p_values
[i
].psz_string
);
754 var_FreeList( &list
, &list2
);
758 case ACTIONID_SUBTITLE_TRACK
:
759 case ACTIONID_SUBTITLE_REVERSE_TRACK
:
762 vlc_value_t val
, list
, list2
;
764 var_Get( p_input
, "spu-es", &val
);
766 var_Change( p_input
, "spu-es", VLC_VAR_GETCHOICES
,
768 i_count
= list
.p_list
->i_count
;
771 DisplayMessage( p_vout
, _("Subtitle track: %s"),
773 var_FreeList( &list
, &list2
);
776 for( i
= 0; i
< i_count
; i
++ )
778 if( val
.i_int
== list
.p_list
->p_values
[i
].i_int
)
783 /* value of spu-es was not in choices list */
787 "invalid current subtitle track, selecting 0" );
790 else if ((i
== i_count
- 1) && (i_action
== ACTIONID_SUBTITLE_TRACK
))
792 else if ((i
== 0) && (i_action
== ACTIONID_SUBTITLE_REVERSE_TRACK
))
795 i
= (i_action
== ACTIONID_SUBTITLE_TRACK
) ? i
+1 : i
-1;
796 var_SetInteger( p_input
, "spu-es", list
.p_list
->p_values
[i
].i_int
);
797 var_SetInteger( p_input
, "spu-choice", list
.p_list
->p_values
[i
].i_int
);
798 DisplayMessage( p_vout
, _("Subtitle track: %s"),
799 list2
.p_list
->p_values
[i
].psz_string
);
800 var_FreeList( &list
, &list2
);
803 case ACTIONID_SUBTITLE_TOGGLE
:
806 vlc_value_t list
, list2
;
807 int i_count
, i_sel_index
, i_sel_id
, i_old_id
, i_new_index
;
808 i_old_id
= var_GetInteger( p_input
, "spu-es" );
809 i_sel_id
= var_GetInteger( p_input
, "spu-choice" );
811 var_Change( p_input
, "spu-es", VLC_VAR_GETCHOICES
,
813 i_count
= list
.p_list
->i_count
;
816 DisplayMessage( p_vout
, _("Subtitle track: %s"),
818 var_FreeList( &list
, &list2
);
821 for( i_sel_index
= 0; i_sel_index
< i_count
; i_sel_index
++ )
823 if( i_sel_id
== list
.p_list
->p_values
[i_sel_index
].i_int
)
828 /* if there is nothing to toggle choose the first track */
831 i_sel_id
= list
.p_list
->p_values
[1].i_int
;
832 var_SetInteger( p_input
, "spu-choice", i_sel_id
);
836 if( i_old_id
!= i_sel_id
)
838 if( i_sel_index
>= i_count
)
840 var_SetInteger( p_input
, "spu-choice", list
.p_list
->p_values
[0].i_int
);
844 i_new_index
= i_sel_index
;
847 var_SetInteger( p_input
, "spu-es", list
.p_list
->p_values
[i_new_index
].i_int
);
848 DisplayMessage( p_vout
, _("Subtitle track: %s"),
849 list2
.p_list
->p_values
[i_new_index
].psz_string
);
850 var_FreeList( &list
, &list2
);
853 case ACTIONID_PROGRAM_SID_NEXT
:
854 case ACTIONID_PROGRAM_SID_PREV
:
857 vlc_value_t val
, list
, list2
;
859 var_Get( p_input
, "program", &val
);
861 var_Change( p_input
, "program", VLC_VAR_GETCHOICES
,
863 i_count
= list
.p_list
->i_count
;
866 DisplayMessage( p_vout
, _("Program Service ID: %s"),
868 var_FreeList( &list
, &list2
);
871 for( i
= 0; i
< i_count
; i
++ )
873 if( val
.i_int
== list
.p_list
->p_values
[i
].i_int
)
878 /* value of program sid was not in choices list */
882 "invalid current program SID, selecting 0" );
885 else if( i_action
== ACTIONID_PROGRAM_SID_NEXT
) {
886 if( i
== i_count
- 1 )
891 else { /* ACTIONID_PROGRAM_SID_PREV */
897 var_Set( p_input
, "program", list
.p_list
->p_values
[i
] );
898 DisplayMessage( p_vout
, _("Program Service ID: %s"),
899 list2
.p_list
->p_values
[i
].psz_string
);
900 var_FreeList( &list
, &list2
);
904 case ACTIONID_JUMP_BACKWARD_EXTRASHORT
:
905 case ACTIONID_JUMP_FORWARD_EXTRASHORT
:
906 case ACTIONID_JUMP_BACKWARD_SHORT
:
907 case ACTIONID_JUMP_FORWARD_SHORT
:
908 case ACTIONID_JUMP_BACKWARD_MEDIUM
:
909 case ACTIONID_JUMP_FORWARD_MEDIUM
:
910 case ACTIONID_JUMP_BACKWARD_LONG
:
911 case ACTIONID_JUMP_FORWARD_LONG
:
913 if( p_input
== NULL
|| !var_GetBool( p_input
, "can-seek" ) )
920 case ACTIONID_JUMP_BACKWARD_EXTRASHORT
:
923 case ACTIONID_JUMP_FORWARD_EXTRASHORT
:
924 varname
= "extrashort-jump-size";
926 case ACTIONID_JUMP_BACKWARD_SHORT
:
929 case ACTIONID_JUMP_FORWARD_SHORT
:
930 varname
= "short-jump-size";
932 case ACTIONID_JUMP_BACKWARD_MEDIUM
:
935 case ACTIONID_JUMP_FORWARD_MEDIUM
:
936 varname
= "medium-jump-size";
938 case ACTIONID_JUMP_BACKWARD_LONG
:
941 case ACTIONID_JUMP_FORWARD_LONG
:
942 varname
= "long-jump-size";
946 mtime_t it
= var_InheritInteger( p_input
, varname
);
949 var_SetInteger( p_input
, "time-offset", it
* sign
* CLOCK_FREQ
);
950 DisplayPosition( p_vout
, slider_chan
, p_input
);
954 /* Input navigation */
955 case ACTIONID_TITLE_PREV
:
957 var_TriggerCallback( p_input
, "prev-title" );
959 case ACTIONID_TITLE_NEXT
:
961 var_TriggerCallback( p_input
, "next-title" );
963 case ACTIONID_CHAPTER_PREV
:
965 var_TriggerCallback( p_input
, "prev-chapter" );
967 case ACTIONID_CHAPTER_NEXT
:
969 var_TriggerCallback( p_input
, "next-chapter" );
971 case ACTIONID_DISC_MENU
:
973 var_SetInteger( p_input
, "title 0", 2 );
975 case ACTIONID_NAV_ACTIVATE
:
977 input_Control( p_input
, INPUT_NAV_ACTIVATE
, NULL
);
979 case ACTIONID_NAV_UP
:
981 input_Control( p_input
, INPUT_NAV_UP
, NULL
);
983 case ACTIONID_NAV_DOWN
:
985 input_Control( p_input
, INPUT_NAV_DOWN
, NULL
);
987 case ACTIONID_NAV_LEFT
:
989 input_Control( p_input
, INPUT_NAV_LEFT
, NULL
);
991 case ACTIONID_NAV_RIGHT
:
993 input_Control( p_input
, INPUT_NAV_RIGHT
, NULL
);
996 /* Video Output actions */
997 case ACTIONID_SNAPSHOT
:
999 var_TriggerCallback( p_vout
, "video-snapshot" );
1002 case ACTIONID_TOGGLE_FULLSCREEN
:
1006 bool fs
= var_ToggleBool( p_vout
, "fullscreen" );
1007 var_SetBool( p_playlist
, "fullscreen", fs
);
1010 var_ToggleBool( p_playlist
, "fullscreen" );
1014 case ACTIONID_LEAVE_FULLSCREEN
:
1016 var_SetBool( p_vout
, "fullscreen", false );
1017 var_SetBool( p_playlist
, "fullscreen", false );
1020 case ACTIONID_ASPECT_RATIO
:
1023 vlc_value_t val
={0}, val_list
, text_list
;
1024 var_Get( p_vout
, "aspect-ratio", &val
);
1025 if( var_Change( p_vout
, "aspect-ratio", VLC_VAR_GETCHOICES
,
1026 &val_list
, &text_list
) >= 0 )
1029 for( i
= 0; i
< val_list
.p_list
->i_count
; i
++ )
1031 if( !strcmp( val_list
.p_list
->p_values
[i
].psz_string
,
1038 if( i
== val_list
.p_list
->i_count
) i
= 0;
1039 var_SetString( p_vout
, "aspect-ratio",
1040 val_list
.p_list
->p_values
[i
].psz_string
);
1041 DisplayMessage( p_vout
, _("Aspect ratio: %s"),
1042 text_list
.p_list
->p_values
[i
].psz_string
);
1044 var_FreeList( &val_list
, &text_list
);
1046 free( val
.psz_string
);
1053 vlc_value_t val
={0}, val_list
, text_list
;
1054 var_Get( p_vout
, "crop", &val
);
1055 if( var_Change( p_vout
, "crop", VLC_VAR_GETCHOICES
,
1056 &val_list
, &text_list
) >= 0 )
1059 for( i
= 0; i
< val_list
.p_list
->i_count
; i
++ )
1061 if( !strcmp( val_list
.p_list
->p_values
[i
].psz_string
,
1068 if( i
== val_list
.p_list
->i_count
) i
= 0;
1069 var_SetString( p_vout
, "crop",
1070 val_list
.p_list
->p_values
[i
].psz_string
);
1071 DisplayMessage( p_vout
, _("Crop: %s"),
1072 text_list
.p_list
->p_values
[i
].psz_string
);
1074 var_FreeList( &val_list
, &text_list
);
1076 free( val
.psz_string
);
1079 case ACTIONID_CROP_TOP
:
1081 var_IncInteger( p_vout
, "crop-top" );
1083 case ACTIONID_UNCROP_TOP
:
1085 var_DecInteger( p_vout
, "crop-top" );
1087 case ACTIONID_CROP_BOTTOM
:
1089 var_IncInteger( p_vout
, "crop-bottom" );
1091 case ACTIONID_UNCROP_BOTTOM
:
1093 var_DecInteger( p_vout
, "crop-bottom" );
1095 case ACTIONID_CROP_LEFT
:
1097 var_IncInteger( p_vout
, "crop-left" );
1099 case ACTIONID_UNCROP_LEFT
:
1101 var_DecInteger( p_vout
, "crop-left" );
1103 case ACTIONID_CROP_RIGHT
:
1105 var_IncInteger( p_vout
, "crop-right" );
1107 case ACTIONID_UNCROP_RIGHT
:
1109 var_DecInteger( p_vout
, "crop-right" );
1112 case ACTIONID_VIEWPOINT_FOV_IN
:
1114 input_UpdateViewpoint( p_input
,
1115 &(vlc_viewpoint_t
) { .fov
= -1.f
},
1118 case ACTIONID_VIEWPOINT_FOV_OUT
:
1120 input_UpdateViewpoint( p_input
,
1121 &(vlc_viewpoint_t
) { .fov
= 1.f
},
1125 case ACTIONID_VIEWPOINT_ROLL_CLOCK
:
1127 input_UpdateViewpoint( p_input
,
1128 &(vlc_viewpoint_t
) { .roll
= -1.f
},
1131 case ACTIONID_VIEWPOINT_ROLL_ANTICLOCK
:
1133 input_UpdateViewpoint( p_input
,
1134 &(vlc_viewpoint_t
) { .roll
= 1.f
},
1138 case ACTIONID_TOGGLE_AUTOSCALE
:
1141 float f_scalefactor
= var_GetFloat( p_vout
, "zoom" );
1142 if ( f_scalefactor
!= 1.f
)
1144 var_SetFloat( p_vout
, "zoom", 1.f
);
1145 DisplayMessage( p_vout
, _("Zooming reset") );
1149 bool b_autoscale
= !var_GetBool( p_vout
, "autoscale" );
1150 var_SetBool( p_vout
, "autoscale", b_autoscale
);
1152 DisplayMessage( p_vout
, _("Scaled to screen") );
1154 DisplayMessage( p_vout
, _("Original Size") );
1158 case ACTIONID_SCALE_UP
:
1161 float f_scalefactor
= var_GetFloat( p_vout
, "zoom" );
1163 if( f_scalefactor
< 10.f
)
1164 f_scalefactor
+= .1f
;
1165 var_SetFloat( p_vout
, "zoom", f_scalefactor
);
1168 case ACTIONID_SCALE_DOWN
:
1171 float f_scalefactor
= var_GetFloat( p_vout
, "zoom" );
1173 if( f_scalefactor
> .3f
)
1174 f_scalefactor
-= .1f
;
1175 var_SetFloat( p_vout
, "zoom", f_scalefactor
);
1179 case ACTIONID_ZOOM_QUARTER
:
1180 case ACTIONID_ZOOM_HALF
:
1181 case ACTIONID_ZOOM_ORIGINAL
:
1182 case ACTIONID_ZOOM_DOUBLE
:
1188 case ACTIONID_ZOOM_QUARTER
: f
= 0.25; break;
1189 case ACTIONID_ZOOM_HALF
: f
= 0.5; break;
1190 case ACTIONID_ZOOM_ORIGINAL
: f
= 1.; break;
1191 /*case ACTIONID_ZOOM_DOUBLE:*/
1192 default: f
= 2.; break;
1194 var_SetFloat( p_vout
, "zoom", f
);
1198 case ACTIONID_UNZOOM
:
1201 vlc_value_t val
={0}, val_list
, text_list
;
1202 var_Get( p_vout
, "zoom", &val
);
1203 if( var_Change( p_vout
, "zoom", VLC_VAR_GETCHOICES
,
1204 &val_list
, &text_list
) >= 0 )
1207 for( i
= 0; i
< val_list
.p_list
->i_count
; i
++ )
1209 if( val_list
.p_list
->p_values
[i
].f_float
1212 if( i_action
== ACTIONID_ZOOM
)
1214 else /* ACTIONID_UNZOOM */
1219 if( i
== val_list
.p_list
->i_count
) i
= 0;
1220 if( i
== -1 ) i
= val_list
.p_list
->i_count
-1;
1221 var_SetFloat( p_vout
, "zoom",
1222 val_list
.p_list
->p_values
[i
].f_float
);
1223 DisplayMessage( p_vout
, _("Zoom mode: %s"),
1224 text_list
.p_list
->p_values
[i
].psz_string
);
1226 var_FreeList( &val_list
, &text_list
);
1231 case ACTIONID_DEINTERLACE
:
1234 int i_deinterlace
= var_GetInteger( p_vout
, "deinterlace" );
1235 if( i_deinterlace
!= 0 )
1237 var_SetInteger( p_vout
, "deinterlace", 0 );
1238 DisplayMessage( p_vout
, _("Deinterlace off") );
1242 var_SetInteger( p_vout
, "deinterlace", 1 );
1244 char *psz_mode
= var_GetString( p_vout
, "deinterlace-mode" );
1245 vlc_value_t vlist
, tlist
;
1246 if( psz_mode
&& !var_Change( p_vout
, "deinterlace-mode", VLC_VAR_GETCHOICES
, &vlist
, &tlist
) )
1248 const char *psz_text
= NULL
;
1249 for( int i
= 0; i
< vlist
.p_list
->i_count
; i
++ )
1251 if( !strcmp( vlist
.p_list
->p_values
[i
].psz_string
, psz_mode
) )
1253 psz_text
= tlist
.p_list
->p_values
[i
].psz_string
;
1257 DisplayMessage( p_vout
, "%s (%s)", _("Deinterlace on"),
1258 psz_text
? psz_text
: psz_mode
);
1260 var_FreeList( &vlist
, &tlist
);
1266 case ACTIONID_DEINTERLACE_MODE
:
1269 char *psz_mode
= var_GetString( p_vout
, "deinterlace-mode" );
1270 vlc_value_t vlist
, tlist
;
1271 if( psz_mode
&& !var_Change( p_vout
, "deinterlace-mode", VLC_VAR_GETCHOICES
, &vlist
, &tlist
))
1273 const char *psz_text
= NULL
;
1275 for( i
= 0; i
< vlist
.p_list
->i_count
; i
++ )
1277 if( !strcmp( vlist
.p_list
->p_values
[i
].psz_string
, psz_mode
) )
1283 if( i
== vlist
.p_list
->i_count
) i
= 0;
1284 psz_text
= tlist
.p_list
->p_values
[i
].psz_string
;
1285 var_SetString( p_vout
, "deinterlace-mode", vlist
.p_list
->p_values
[i
].psz_string
);
1287 int i_deinterlace
= var_GetInteger( p_vout
, "deinterlace" );
1288 if( i_deinterlace
!= 0 )
1290 DisplayMessage( p_vout
, "%s (%s)", _("Deinterlace on"),
1291 psz_text
? psz_text
: psz_mode
);
1295 DisplayMessage( p_vout
, "%s (%s)", _("Deinterlace off"),
1296 psz_text
? psz_text
: psz_mode
);
1299 var_FreeList( &vlist
, &tlist
);
1305 case ACTIONID_SUBPOS_DOWN
:
1306 case ACTIONID_SUBPOS_UP
:
1310 vlc_value_t val
, list
, list2
;
1312 var_Get( p_input
, "spu-es", &val
);
1314 var_Change( p_input
, "spu-es", VLC_VAR_GETCHOICES
,
1316 i_count
= list
.p_list
->i_count
;
1317 if( i_count
< 1 || val
.i_int
< 0 )
1319 DisplayMessage( p_vout
,
1320 _("Subtitle position: no active subtitle") );
1321 var_FreeList( &list
, &list2
);
1326 if( i_action
== ACTIONID_SUBPOS_DOWN
)
1327 i_pos
= var_DecInteger( p_vout
, "sub-margin" );
1329 i_pos
= var_IncInteger( p_vout
, "sub-margin" );
1331 ClearChannels( p_vout
, slider_chan
);
1332 DisplayMessage( p_vout
, _( "Subtitle position %d px" ), i_pos
);
1333 var_FreeList( &list
, &list2
);
1338 case ACTIONID_SUBTITLE_TEXT_SCALE_DOWN
:
1339 case ACTIONID_SUBTITLE_TEXT_SCALE_UP
:
1340 case ACTIONID_SUBTITLE_TEXT_SCALE_NORMAL
:
1344 if( i_action
== ACTIONID_SUBTITLE_TEXT_SCALE_NORMAL
)
1350 i_scale
= var_GetInteger( p_playlist
, "sub-text-scale" );
1351 i_scale
+= ((i_action
== ACTIONID_SUBTITLE_TEXT_SCALE_UP
) ? 1 : -1) * 25;
1352 i_scale
= VLC_CLIP( i_scale
, 10, 500 );
1354 var_SetInteger( p_playlist
, "sub-text-scale", i_scale
);
1355 DisplayMessage( p_vout
, _( "Subtitle text scale %d%%" ), i_scale
);
1359 /* Input + video output */
1360 case ACTIONID_POSITION
:
1361 if( p_vout
&& vout_OSDEpg( p_vout
, input_GetItem( p_input
) ) )
1362 DisplayPosition( p_vout
, slider_chan
, p_input
);
1365 case ACTIONID_COMBO_VOL_FOV_UP
:
1367 DO_ACTION( ACTIONID_VIEWPOINT_FOV_IN
);
1369 DO_ACTION( ACTIONID_VOL_UP
);
1371 case ACTIONID_COMBO_VOL_FOV_DOWN
:
1373 DO_ACTION( ACTIONID_VIEWPOINT_FOV_OUT
);
1375 DO_ACTION( ACTIONID_VOL_DOWN
);
1382 /*****************************************************************************
1383 * ActionEvent: callback for hotkey actions
1384 *****************************************************************************/
1385 static int ActionEvent( vlc_object_t
*libvlc
, char const *psz_var
,
1386 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
1388 intf_thread_t
*p_intf
= (intf_thread_t
*)p_data
;
1389 intf_sys_t
*p_sys
= p_intf
->p_sys
;
1395 vlc_mutex_lock( &p_intf
->p_sys
->lock
);
1396 input_thread_t
*p_input
= p_sys
->p_input
? vlc_object_hold( p_sys
->p_input
)
1398 vout_thread_t
*p_vout
= p_sys
->p_vout
? vlc_object_hold( p_sys
->p_vout
)
1400 int slider_chan
= p_sys
->slider_chan
;
1401 bool b_vrnav
= p_sys
->vrnav
.b_can_change
;
1402 vlc_mutex_unlock( &p_intf
->p_sys
->lock
);
1404 int i_ret
= PutAction( p_intf
, p_input
, p_vout
, slider_chan
, b_vrnav
,
1407 if( p_input
!= NULL
)
1408 vlc_object_release( p_input
);
1409 if( p_vout
!= NULL
)
1410 vlc_object_release( p_vout
);
1415 static void PlayBookmark( intf_thread_t
*p_intf
, int i_num
)
1417 char *psz_bookmark_name
;
1418 if( asprintf( &psz_bookmark_name
, "bookmark%i", i_num
) == -1 )
1421 playlist_t
*p_playlist
= pl_Get( p_intf
);
1422 char *psz_bookmark
= var_CreateGetString( p_intf
, psz_bookmark_name
);
1425 FOREACH_ARRAY( playlist_item_t
*p_item
, p_playlist
->items
)
1426 char *psz_uri
= input_item_GetURI( p_item
->p_input
);
1427 if( !strcmp( psz_bookmark
, psz_uri
) )
1430 playlist_ViewPlay( p_playlist
, NULL
, p_item
);
1438 free( psz_bookmark
);
1439 free( psz_bookmark_name
);
1442 static void SetBookmark( intf_thread_t
*p_intf
, int i_num
)
1444 char *psz_bookmark_name
;
1445 char *psz_uri
= NULL
;
1446 if( asprintf( &psz_bookmark_name
, "bookmark%i", i_num
) == -1 )
1449 playlist_t
*p_playlist
= pl_Get( p_intf
);
1450 var_Create( p_intf
, psz_bookmark_name
,
1451 VLC_VAR_STRING
|VLC_VAR_DOINHERIT
);
1454 playlist_item_t
* p_item
= playlist_CurrentPlayingItem( p_playlist
);
1455 if( p_item
) psz_uri
= input_item_GetURI( p_item
->p_input
);
1460 config_PutPsz( psz_bookmark_name
, psz_uri
);
1461 msg_Info( p_intf
, "setting playlist bookmark %i to %s", i_num
, psz_uri
);
1465 free( psz_bookmark_name
);
1468 static void DisplayPosition( vout_thread_t
*p_vout
, int slider_chan
,
1469 input_thread_t
*p_input
)
1471 char psz_duration
[MSTRTIME_MAX_SIZE
];
1472 char psz_time
[MSTRTIME_MAX_SIZE
];
1474 if( p_vout
== NULL
) return;
1476 ClearChannels( p_vout
, slider_chan
);
1478 int64_t t
= var_GetInteger( p_input
, "time" ) / CLOCK_FREQ
;
1479 int64_t l
= var_GetInteger( p_input
, "length" ) / CLOCK_FREQ
;
1481 secstotimestr( psz_time
, t
);
1485 secstotimestr( psz_duration
, l
);
1486 DisplayMessage( p_vout
, "%s / %s", psz_time
, psz_duration
);
1490 DisplayMessage( p_vout
, "%s", psz_time
);
1493 if( var_GetBool( p_vout
, "fullscreen" ) )
1496 var_Get( p_input
, "position", &pos
);
1497 vout_OSDSlider( p_vout
, slider_chan
,
1498 pos
.f_float
* 100, OSD_HOR_SLIDER
);
1502 static void DisplayVolume( vout_thread_t
*p_vout
, int slider_chan
, float vol
)
1504 if( p_vout
== NULL
)
1506 ClearChannels( p_vout
, slider_chan
);
1508 if( var_GetBool( p_vout
, "fullscreen" ) )
1509 vout_OSDSlider( p_vout
, slider_chan
,
1510 lroundf(vol
* 100.f
), OSD_VERT_SLIDER
);
1511 DisplayMessage( p_vout
, _( "Volume %ld%%" ), lroundf(vol
* 100.f
) );
1514 static void DisplayRate( vout_thread_t
*p_vout
, float f_rate
)
1516 DisplayMessage( p_vout
, _("Speed: %.2fx"), (double) f_rate
);
1519 static float AdjustRateFine( vlc_object_t
*p_obj
, const int i_dir
)
1521 const float f_rate_min
= (float)INPUT_RATE_DEFAULT
/ INPUT_RATE_MAX
;
1522 const float f_rate_max
= (float)INPUT_RATE_DEFAULT
/ INPUT_RATE_MIN
;
1523 float f_rate
= var_GetFloat( p_obj
, "rate" );
1525 int i_sign
= f_rate
< 0 ? -1 : 1;
1527 f_rate
= floor( fabs(f_rate
) / 0.1 + i_dir
+ 0.05 ) * 0.1;
1529 if( f_rate
< f_rate_min
)
1530 f_rate
= f_rate_min
;
1531 else if( f_rate
> f_rate_max
)
1532 f_rate
= f_rate_max
;
1538 static void ClearChannels( vout_thread_t
*p_vout
, int slider_chan
)
1542 vout_FlushSubpictureChannel( p_vout
, VOUT_SPU_CHANNEL_OSD
);
1543 vout_FlushSubpictureChannel( p_vout
, slider_chan
);