]> git.sesse.net Git - vlc/blob - src/input/var.c
Use var_Inherit* instead of var_CreateGet*.
[vlc] / src / input / var.c
1 /*****************************************************************************
2  * var.c: object variables for input thread
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <assert.h>
33 #include <math.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36
37 #include "input_internal.h"
38
39 /*****************************************************************************
40  * Callbacks
41  *****************************************************************************/
42 static int StateCallback   ( vlc_object_t *p_this, char const *psz_cmd,
43                              vlc_value_t oldval, vlc_value_t newval, void * );
44 static int RateCallback    ( vlc_object_t *p_this, char const *psz_cmd,
45                              vlc_value_t oldval, vlc_value_t newval, void * );
46 static int RateOffsetCallback( vlc_object_t *p_this, char const *psz_cmd,
47                              vlc_value_t oldval, vlc_value_t newval, void * );
48 static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
49                              vlc_value_t oldval, vlc_value_t newval, void * );
50 static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
51                              vlc_value_t oldval, vlc_value_t newval, void * );
52 static int ProgramCallback ( vlc_object_t *p_this, char const *psz_cmd,
53                              vlc_value_t oldval, vlc_value_t newval, void * );
54 static int TitleCallback   ( vlc_object_t *p_this, char const *psz_cmd,
55                              vlc_value_t oldval, vlc_value_t newval, void * );
56 static int SeekpointCallback( vlc_object_t *p_this, char const *psz_cmd,
57                              vlc_value_t oldval, vlc_value_t newval, void * );
58 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
59                              vlc_value_t oldval, vlc_value_t newval, void * );
60 static int ESCallback      ( vlc_object_t *p_this, char const *psz_cmd,
61                              vlc_value_t oldval, vlc_value_t newval, void * );
62 static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd,
63                              vlc_value_t oldval, vlc_value_t newval, void * );
64
65 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
66                              vlc_value_t oldval, vlc_value_t newval, void * );
67
68 static int RecordCallback( vlc_object_t *p_this, char const *psz_cmd,
69                            vlc_value_t oldval, vlc_value_t newval,
70                            void *p_data );
71 static int FrameNextCallback( vlc_object_t *p_this, char const *psz_cmd,
72                               vlc_value_t oldval, vlc_value_t newval,
73                               void *p_data );
74
75 typedef struct
76 {
77     const char *psz_name;
78     vlc_callback_t callback;
79 } vlc_input_callback_t;
80
81 static void InputAddCallbacks( input_thread_t *, const vlc_input_callback_t * );
82 static void InputDelCallbacks( input_thread_t *, const vlc_input_callback_t * );
83
84 #ifdef CALLBACK /* For windows */
85 # undef CALLBACK /* We don't care of this one here */
86 #endif
87 /* List all callbacks added by input */
88 #define CALLBACK(name,cb) { name, cb }
89 static const vlc_input_callback_t p_input_callbacks[] =
90 {
91     CALLBACK( "state", StateCallback ),
92     CALLBACK( "rate", RateCallback ),
93     CALLBACK( "rate-slower", RateOffsetCallback ),
94     CALLBACK( "rate-faster", RateOffsetCallback ),
95     CALLBACK( "position", PositionCallback ),
96     CALLBACK( "position-offset", PositionCallback ),
97     CALLBACK( "time", TimeCallback ),
98     CALLBACK( "time-offset", TimeCallback ),
99     CALLBACK( "bookmark", BookmarkCallback ),
100     CALLBACK( "program", ProgramCallback ),
101     CALLBACK( "title", TitleCallback ),
102     CALLBACK( "chapter", SeekpointCallback ),
103     CALLBACK( "audio-delay", EsDelayCallback ),
104     CALLBACK( "spu-delay", EsDelayCallback ),
105     CALLBACK( "video-es", ESCallback ),
106     CALLBACK( "audio-es", ESCallback ),
107     CALLBACK( "spu-es", ESCallback ),
108     CALLBACK( "record", RecordCallback ),
109     CALLBACK( "frame-next", FrameNextCallback ),
110
111     CALLBACK( NULL, NULL )
112 };
113 static const vlc_input_callback_t p_input_navigation_callbacks[] =
114 {
115     CALLBACK( "next-title", TitleCallback ),
116     CALLBACK( "prev-title", TitleCallback ),
117
118     CALLBACK( NULL, NULL )
119 };
120 static const vlc_input_callback_t p_input_title_callbacks[] =
121 {
122     CALLBACK( "next-chapter", SeekpointCallback ),
123     CALLBACK( "prev-chapter", SeekpointCallback ),
124
125     CALLBACK( NULL, NULL )
126 };
127 #undef CALLBACK
128
129 /*****************************************************************************
130  * input_ControlVarInit:
131  *  Create all control object variables with their callbacks
132  *****************************************************************************/
133 void input_ControlVarInit ( input_thread_t *p_input )
134 {
135     vlc_value_t val, text;
136
137     /* State */
138     var_Create( p_input, "state", VLC_VAR_INTEGER );
139     val.i_int = p_input->p->i_state;
140     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
141
142     /* Rate */
143     var_Create( p_input, "rate", VLC_VAR_FLOAT );
144     val.f_float = (float)INPUT_RATE_DEFAULT / (float)p_input->p->i_rate;
145     var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
146
147     var_Create( p_input, "rate-slower", VLC_VAR_VOID );
148
149     var_Create( p_input, "rate-faster", VLC_VAR_VOID );
150
151     var_Create( p_input, "frame-next", VLC_VAR_VOID );
152
153     /* Position */
154     var_Create( p_input, "position",  VLC_VAR_FLOAT );
155     var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );
156     val.f_float = 0.0;
157     var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
158
159     /* Time */
160     var_Create( p_input, "time",  VLC_VAR_TIME );
161     var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
162     val.i_time = 0;
163     var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
164
165     /* Bookmark */
166     var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
167                 VLC_VAR_ISCOMMAND );
168     val.psz_string = _("Bookmark");
169     var_Change( p_input, "bookmark", VLC_VAR_SETTEXT, &val, NULL );
170
171     /* Program */
172     var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
173                 VLC_VAR_DOINHERIT );
174     var_Get( p_input, "program", &val );
175     if( val.i_int <= 0 )
176         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
177     text.psz_string = _("Program");
178     var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
179
180     /* Programs */
181     var_Create( p_input, "programs", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
182     text.psz_string = _("Programs");
183     var_Change( p_input, "programs", VLC_VAR_SETTEXT, &text, NULL );
184
185     /* Title */
186     var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
187     text.psz_string = _("Title");
188     var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
189
190     /* Chapter */
191     var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
192     text.psz_string = _("Chapter");
193     var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
194
195     /* Navigation The callback is added after */
196     var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
197     text.psz_string = _("Navigation");
198     var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
199
200     /* Delay */
201     var_Create( p_input, "audio-delay", VLC_VAR_TIME );
202     val.i_time = INT64_C(1000) * var_GetInteger( p_input, "audio-desync" );
203     var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
204     var_Create( p_input, "spu-delay", VLC_VAR_TIME );
205     val.i_time = 0;
206     var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
207
208     /* Video ES */
209     var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
210     text.psz_string = _("Video Track");
211     var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
212
213     /* Audio ES */
214     var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
215     text.psz_string = _("Audio Track");
216     var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
217
218     /* Spu ES */
219     var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
220     text.psz_string = _("Subtitles Track");
221     var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
222
223     /* Special read only objects variables for intf */
224     var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
225
226     var_Create( p_input, "length",  VLC_VAR_TIME );
227     val.i_time = 0;
228     var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
229
230     var_Create( p_input, "bit-rate", VLC_VAR_INTEGER );
231     var_Create( p_input, "sample-rate", VLC_VAR_INTEGER );
232
233     if( !p_input->b_preparsing )
234     {
235         /* Special "intf-event" variable. */
236         var_Create( p_input, "intf-event", VLC_VAR_INTEGER );
237     }
238
239     /* Add all callbacks
240      * XXX we put callback only in non preparsing mode. We need to create the variable
241      * unless someone want to check all var_Get/var_Change return value ... */
242     if( !p_input->b_preparsing )
243         InputAddCallbacks( p_input, p_input_callbacks );
244 }
245
246 /*****************************************************************************
247  * input_ControlVarStop:
248  *****************************************************************************/
249 void input_ControlVarStop( input_thread_t *p_input )
250 {
251     if( !p_input->b_preparsing )
252         InputDelCallbacks( p_input, p_input_callbacks );
253
254     if( p_input->p->i_title > 0 )
255     {
256         char name[sizeof("title ") + 5 ];
257         int i;
258
259         InputDelCallbacks( p_input, p_input_navigation_callbacks );
260         InputDelCallbacks( p_input, p_input_title_callbacks );
261
262         for( i = 0; i < p_input->p->i_title; i++ )
263         {
264             snprintf( name, sizeof(name), "title %2i", i );
265             var_DelCallback( p_input, name, NavigationCallback, (void *)(intptr_t)i );
266         }
267     }
268 }
269
270 /*****************************************************************************
271  * input_ControlVarNavigation:
272  *  Create all remaining control object variables
273  *****************************************************************************/
274 void input_ControlVarNavigation( input_thread_t *p_input )
275 {
276     vlc_value_t val, text;
277     int  i;
278
279     /* Create more command variables */
280     if( p_input->p->i_title > 1 )
281     {
282         var_Create( p_input, "next-title", VLC_VAR_VOID );
283         text.psz_string = _("Next title");
284         var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
285         var_AddCallback( p_input, "next-title", TitleCallback, NULL );
286
287         var_Create( p_input, "prev-title", VLC_VAR_VOID );
288         text.psz_string = _("Previous title");
289         var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
290         var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
291     }
292
293     /* Create title and navigation */
294     val.psz_string = malloc( sizeof("title ") + 5 );
295     if( !val.psz_string )
296         return;
297
298     for( i = 0; i < p_input->p->i_title; i++ )
299     {
300         vlc_value_t val2, text2;
301         int j;
302
303         /* Add Navigation entries */
304         sprintf( val.psz_string,  "title %2i", i );
305         var_Destroy( p_input, val.psz_string );
306         var_Create( p_input, val.psz_string,
307                     VLC_VAR_INTEGER|VLC_VAR_HASCHOICE|VLC_VAR_ISCOMMAND );
308         var_AddCallback( p_input, val.psz_string,
309                          NavigationCallback, (void *)(intptr_t)i );
310
311         char psz_length[MSTRTIME_MAX_SIZE + sizeof(" []")] = "";
312         if( p_input->p->title[i]->i_length > 0 )
313         {
314             strcpy( psz_length, " [" );
315             secstotimestr( &psz_length[2], p_input->p->title[i]->i_length / CLOCK_FREQ );
316             strcat( psz_length, "]" );
317         }
318
319         if( p_input->p->title[i]->psz_name == NULL ||
320             *p_input->p->title[i]->psz_name == '\0' )
321         {
322             if( asprintf( &text.psz_string, _("Title %i%s"),
323                           i + p_input->p->i_title_offset, psz_length ) == -1 )
324                 continue;
325         }
326         else
327         {
328             if( asprintf( &text.psz_string, "%s%s",
329                           p_input->p->title[i]->psz_name, psz_length ) == -1 )
330                 continue;
331         }
332         var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, &text );
333
334         /* Add title choice */
335         val2.i_int = i;
336         var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val2, &text );
337
338         free( text.psz_string );
339
340         for( j = 0; j < p_input->p->title[i]->i_seekpoint; j++ )
341         {
342             val2.i_int = j;
343
344             if( p_input->p->title[i]->seekpoint[j]->psz_name == NULL ||
345                 *p_input->p->title[i]->seekpoint[j]->psz_name == '\0' )
346             {
347                 /* Default value */
348                 if( asprintf( &text2.psz_string, _("Chapter %i"),
349                           j + p_input->p->i_seekpoint_offset ) == -1 )
350                     continue;
351             }
352             else
353             {
354                 text2.psz_string =
355                     strdup( p_input->p->title[i]->seekpoint[j]->psz_name );
356             }
357
358             var_Change( p_input, val.psz_string, VLC_VAR_ADDCHOICE,
359                         &val2, &text2 );
360             free( text2.psz_string );
361         }
362
363     }
364     free( val.psz_string );
365 }
366
367 /*****************************************************************************
368  * input_ControlVarTitle:
369  *  Create all variables for a title
370  *****************************************************************************/
371 void input_ControlVarTitle( input_thread_t *p_input, int i_title )
372 {
373     input_title_t *t = p_input->p->title[i_title];
374     vlc_value_t text;
375     int  i;
376
377     /* Create/Destroy command variables */
378     if( t->i_seekpoint <= 1 )
379     {
380         var_Destroy( p_input, "next-chapter" );
381         var_Destroy( p_input, "prev-chapter" );
382     }
383     else if( var_Type( p_input, "next-chapter" ) == 0 )
384     {
385         var_Create( p_input, "next-chapter", VLC_VAR_VOID );
386         text.psz_string = _("Next chapter");
387         var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
388         var_AddCallback( p_input, "next-chapter", SeekpointCallback, NULL );
389
390         var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
391         text.psz_string = _("Previous chapter");
392         var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
393         var_AddCallback( p_input, "prev-chapter", SeekpointCallback, NULL );
394     }
395
396     /* Build chapter list */
397     var_Change( p_input, "chapter", VLC_VAR_CLEARCHOICES, NULL, NULL );
398     for( i = 0; i <  t->i_seekpoint; i++ )
399     {
400         vlc_value_t val;
401         val.i_int = i;
402
403         if( t->seekpoint[i]->psz_name == NULL ||
404             *t->seekpoint[i]->psz_name == '\0' )
405         {
406             /* Default value */
407             if( asprintf( &text.psz_string, _("Chapter %i"),
408                       i + p_input->p->i_seekpoint_offset ) == -1 )
409                 continue;
410         }
411         else
412         {
413             text.psz_string = strdup( t->seekpoint[i]->psz_name );
414         }
415
416         var_Change( p_input, "chapter", VLC_VAR_ADDCHOICE, &val, &text );
417         free( text.psz_string );
418     }
419 }
420
421 /*****************************************************************************
422  * input_ConfigVarInit:
423  *  Create all config object variables
424  *****************************************************************************/
425 void input_ConfigVarInit ( input_thread_t *p_input )
426 {
427     /* Create Object Variables for private use only */
428
429     if( !p_input->b_preparsing )
430     {
431         var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
432         var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
433         var_Create( p_input, "spu", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
434
435         var_Create( p_input, "audio-track", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
436         var_Create( p_input, "sub-track", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
437
438         var_Create( p_input, "audio-language",
439                     VLC_VAR_STRING|VLC_VAR_DOINHERIT );
440         var_Create( p_input, "sub-language",
441                     VLC_VAR_STRING|VLC_VAR_DOINHERIT );
442
443         var_Create( p_input, "audio-track-id",
444                     VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
445         var_Create( p_input, "sub-track-id",
446                     VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
447
448         var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
449         var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
450                     VLC_VAR_DOINHERIT );
451         var_Create( p_input, "sub-autodetect-path", VLC_VAR_STRING |
452                     VLC_VAR_DOINHERIT );
453         var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
454                     VLC_VAR_DOINHERIT );
455
456         var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
457         var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
458         var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
459         var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
460         var_Create( p_input, "sout-spu", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
461         var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
462
463         var_Create( p_input, "input-repeat",
464                     VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
465         var_Create( p_input, "start-time", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT );
466         var_Create( p_input, "stop-time", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT );
467         var_Create( p_input, "run-time", VLC_VAR_FLOAT|VLC_VAR_DOINHERIT );
468         var_Create( p_input, "input-fast-seek", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
469
470         var_Create( p_input, "input-slave",
471                     VLC_VAR_STRING | VLC_VAR_DOINHERIT );
472
473         var_Create( p_input, "audio-desync",
474                     VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
475         var_Create( p_input, "cr-average",
476                     VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
477         var_Create( p_input, "clock-synchro",
478                     VLC_VAR_INTEGER | VLC_VAR_DOINHERIT);
479     }
480
481     var_Create( p_input, "can-seek", VLC_VAR_BOOL );
482     var_SetBool( p_input, "can-seek", true ); /* Fixed later*/
483
484     var_Create( p_input, "can-pause", VLC_VAR_BOOL );
485     var_SetBool( p_input, "can-pause", true ); /* Fixed later*/
486
487     var_Create( p_input, "can-rate", VLC_VAR_BOOL );
488     var_SetBool( p_input, "can-rate", false );
489
490     var_Create( p_input, "can-rewind", VLC_VAR_BOOL );
491     var_SetBool( p_input, "can-rewind", false );
492
493     var_Create( p_input, "can-record", VLC_VAR_BOOL );
494     var_SetBool( p_input, "can-record", false ); /* Fixed later*/
495
496     var_Create( p_input, "record", VLC_VAR_BOOL );
497     var_SetBool( p_input, "record", false );
498
499     var_Create( p_input, "teletext-es", VLC_VAR_INTEGER );
500     var_SetInteger( p_input, "teletext-es", -1 );
501
502     var_Create( p_input, "signal-quality", VLC_VAR_FLOAT );
503     var_SetFloat( p_input, "signal-quality", -1 );
504
505     var_Create( p_input, "signal-strength", VLC_VAR_FLOAT );
506     var_SetFloat( p_input, "signal-strength", -1 );
507
508     var_Create( p_input, "program-scrambled", VLC_VAR_BOOL );
509     var_SetBool( p_input, "program-scrambled", false );
510
511     var_Create( p_input, "cache", VLC_VAR_FLOAT );
512     var_SetFloat( p_input, "cache", 0.0 );
513
514     /* */
515     var_Create( p_input, "input-record-native", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
516
517     /* */
518     var_Create( p_input, "access", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
519     var_Create( p_input, "demux", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
520     var_Create( p_input, "stream-filter", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
521
522     /* Meta */
523     var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
524     var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
525     var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
526     var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
527     var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
528     var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
529     var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
530     var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
531 }
532
533 /*****************************************************************************
534  * Callbacks managements:
535  *****************************************************************************/
536 static void InputAddCallbacks( input_thread_t *p_input,
537                                const vlc_input_callback_t *p_callbacks )
538 {
539     int i;
540     for( i = 0; p_callbacks[i].psz_name != NULL; i++ )
541         var_AddCallback( p_input,
542                          p_callbacks[i].psz_name,
543                          p_callbacks[i].callback, NULL );
544 }
545
546 static void InputDelCallbacks( input_thread_t *p_input,
547                                const vlc_input_callback_t *p_callbacks )
548 {
549     int i;
550     for( i = 0; p_callbacks[i].psz_name != NULL; i++ )
551         var_DelCallback( p_input,
552                          p_callbacks[i].psz_name,
553                          p_callbacks[i].callback, NULL );
554 }
555
556 /*****************************************************************************
557  * All Callbacks:
558  *****************************************************************************/
559 static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
560                           vlc_value_t oldval, vlc_value_t newval,
561                           void *p_data )
562 {
563     input_thread_t *p_input = (input_thread_t*)p_this;
564     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
565
566     if( newval.i_int == PLAYING_S || newval.i_int == PAUSE_S )
567     {
568         input_ControlPush( p_input, INPUT_CONTROL_SET_STATE, &newval );
569         return VLC_SUCCESS;
570     }
571
572     return VLC_EGENERIC;
573 }
574
575 static int RateCallback( vlc_object_t *p_this, char const *psz_cmd,
576                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
577 {
578     input_thread_t *p_input = (input_thread_t*)p_this;
579     VLC_UNUSED(oldval); VLC_UNUSED(p_data); VLC_UNUSED(psz_cmd);
580
581     newval.i_int = INPUT_RATE_DEFAULT / newval.f_float;
582     input_ControlPush( p_input, INPUT_CONTROL_SET_RATE, &newval );
583
584     return VLC_SUCCESS;
585 }
586
587 static int RateOffsetCallback( vlc_object_t *p_this, char const *psz_cmd,
588                                vlc_value_t oldval, vlc_value_t newval, void *p_data )
589 {
590     input_thread_t *p_input = (input_thread_t*)p_this;
591     VLC_UNUSED(oldval); VLC_UNUSED(p_data); VLC_UNUSED(newval);
592
593     static const float pf_rate[] = {
594         1.0/64, 1.0/32, 1.0/16, 1.0/8, 1.0/4, 1.0/3, 1.0/2, 2.0/3,
595         1.0/1,
596         3.0/2, 2.0/1, 3.0/1, 4.0/1, 8.0/1, 16.0/1, 32.0/1, 64.0/1,
597     };
598     const unsigned i_rate_count = sizeof(pf_rate)/sizeof(*pf_rate);
599
600     const float f_rate = var_GetFloat( p_input, "rate" );
601
602     /* Determine the factor closest to the current rate */
603     float f_error;
604     int i_idx;
605     for( unsigned i = 0; i < i_rate_count; i++ )
606     {
607         const float f_test_e = fabs( fabs( f_rate ) - pf_rate[i] );
608         if( i == 0 || f_test_e < f_error )
609         {
610             i_idx = i;
611             f_error = f_test_e;
612         }
613     }
614     assert( i_idx < (int)i_rate_count );
615
616     /* */
617     i_idx += strcmp( psz_cmd, "rate-faster" ) == 0 ? 1 : -1;
618     if( i_idx >= 0 && i_idx < (int)i_rate_count )
619     {
620         const float f_rate_min = (float)INPUT_RATE_DEFAULT / INPUT_RATE_MAX;
621         const float f_rate_max = (float)INPUT_RATE_DEFAULT / INPUT_RATE_MIN;
622         const float f_sign = f_rate >= 0 ? +1. : -1.;
623
624         var_SetFloat( p_input, "rate",
625                       f_sign * __MAX( __MIN( pf_rate[i_idx],
626                                              f_rate_max ),
627                                       f_rate_min ) );
628     }
629     return VLC_SUCCESS;
630 }
631
632 static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
633                              vlc_value_t oldval, vlc_value_t newval,
634                              void *p_data )
635 {
636     input_thread_t *p_input = (input_thread_t*)p_this;
637     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
638
639     if( !strcmp( psz_cmd, "position-offset" ) )
640     {
641         float f_position = var_GetFloat( p_input, "position" ) + newval.f_float;
642         if( f_position < 0.0 )
643             f_position = 0.0;
644         else if( f_position > 1.0 )
645             f_position = 1.0;
646         var_SetFloat( p_this, "position", f_position );
647     }
648     else
649     {
650         /* Update "length" for better intf behavour */
651         const mtime_t i_length = var_GetTime( p_input, "length" );
652         if( i_length > 0 && newval.f_float >= 0.0 && newval.f_float <= 1.0 )
653         {
654             vlc_value_t val;
655
656             val.i_time = i_length * newval.f_float;
657             var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
658         }
659
660         /* */
661         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &newval );
662     }
663     return VLC_SUCCESS;
664 }
665
666 static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
667                          vlc_value_t oldval, vlc_value_t newval, void *p_data )
668 {
669     input_thread_t *p_input = (input_thread_t*)p_this;
670     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
671
672     if( !strcmp( psz_cmd, "time-offset" ) )
673     {
674         mtime_t i_time = var_GetTime( p_input, "time" ) + newval.i_time;
675         if( i_time < 0 )
676             i_time = 0;
677         var_SetTime( p_this, "time", i_time );
678     }
679     else
680     {
681         /* Update "position" for better intf behavour */
682         const mtime_t i_length = var_GetTime( p_input, "length" );
683         if( i_length > 0 && newval.i_time >= 0 && newval.i_time <= i_length )
684         {
685             vlc_value_t val;
686
687             val.f_float = (double)newval.i_time/(double)i_length;
688             var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
689         }
690
691         /* */
692         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &newval );
693     }
694     return VLC_SUCCESS;
695 }
696
697 static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
698                             vlc_value_t oldval, vlc_value_t newval,
699                             void *p_data )
700 {
701     input_thread_t *p_input = (input_thread_t*)p_this;
702     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
703
704     input_ControlPush( p_input, INPUT_CONTROL_SET_PROGRAM, &newval );
705
706     return VLC_SUCCESS;
707 }
708
709 static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
710                           vlc_value_t oldval, vlc_value_t newval,
711                           void *p_data )
712 {
713     input_thread_t *p_input = (input_thread_t*)p_this;
714     vlc_value_t val, count;
715     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
716
717     if( !strcmp( psz_cmd, "next-title" ) )
718     {
719         input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE_NEXT, NULL );
720
721         val.i_int = var_GetInteger( p_input, "title" ) + 1;
722         var_Change( p_input, "title", VLC_VAR_CHOICESCOUNT, &count, NULL );
723         if( val.i_int < count.i_int )
724             var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
725     }
726     else if( !strcmp( psz_cmd, "prev-title" ) )
727     {
728         input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE_PREV, NULL );
729
730         val.i_int = var_GetInteger( p_input, "title" ) - 1;
731         if( val.i_int >= 0 )
732             var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
733     }
734     else
735     {
736         input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &newval );
737     }
738
739     return VLC_SUCCESS;
740 }
741
742 static int SeekpointCallback( vlc_object_t *p_this, char const *psz_cmd,
743                               vlc_value_t oldval, vlc_value_t newval,
744                               void *p_data )
745 {
746     input_thread_t *p_input = (input_thread_t*)p_this;
747     vlc_value_t val, count;
748     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
749
750     if( !strcmp( psz_cmd, "next-chapter" ) )
751     {
752         input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT_NEXT, NULL );
753
754         val.i_int = var_GetInteger( p_input, "chapter" ) + 1;
755         var_Change( p_input, "chapter", VLC_VAR_CHOICESCOUNT, &count, NULL );
756         if( val.i_int < count.i_int )
757             var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &val, NULL );
758     }
759     else if( !strcmp( psz_cmd, "prev-chapter" ) )
760     {
761         input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT_PREV, NULL );
762
763         val.i_int = var_GetInteger( p_input, "chapter" ) - 1;
764         if( val.i_int >= 0 )
765             var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &val, NULL );
766     }
767     else
768     {
769         input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &newval );
770     }
771
772     return VLC_SUCCESS;
773 }
774
775 static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
776                                vlc_value_t oldval, vlc_value_t newval,
777                                void *p_data )
778 {
779     input_thread_t *p_input = (input_thread_t*)p_this;
780     vlc_value_t     val;
781     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval);
782
783     /* Issue a title change */
784     val.i_int = (intptr_t)p_data;
785     input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
786
787     var_Change( p_input, "title", VLC_VAR_SETVALUE, &val, NULL );
788
789     /* And a chapter change */
790     input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &newval );
791
792     var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &newval, NULL );
793
794     return VLC_SUCCESS;
795 }
796
797 static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
798                        vlc_value_t oldval, vlc_value_t newval, void *p_data )
799 {
800     input_thread_t *p_input = (input_thread_t*)p_this;
801     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
802
803     if( newval.i_int < 0 )
804     {
805         vlc_value_t v;
806         /* Hack */
807         if( !strcmp( psz_cmd, "audio-es" ) )
808             v.i_int = -AUDIO_ES;
809         else if( !strcmp( psz_cmd, "video-es" ) )
810             v.i_int = -VIDEO_ES;
811         else if( !strcmp( psz_cmd, "spu-es" ) )
812             v.i_int = -SPU_ES;
813         else
814             v.i_int = 0;
815         if( v.i_int != 0 )
816             input_ControlPush( p_input, INPUT_CONTROL_SET_ES, &v );
817     }
818     else
819     {
820         input_ControlPush( p_input, INPUT_CONTROL_SET_ES, &newval );
821     }
822
823     return VLC_SUCCESS;
824 }
825
826 static int EsDelayCallback ( vlc_object_t *p_this, char const *psz_cmd,
827                              vlc_value_t oldval, vlc_value_t newval, void *p_data )
828 {
829     input_thread_t *p_input = (input_thread_t*)p_this;
830     VLC_UNUSED(oldval); VLC_UNUSED(p_data);
831
832     if( !strcmp( psz_cmd, "audio-delay" ) )
833     {
834         input_ControlPush( p_input, INPUT_CONTROL_SET_AUDIO_DELAY, &newval );
835     }
836     else if( !strcmp( psz_cmd, "spu-delay" ) )
837     {
838         input_ControlPush( p_input, INPUT_CONTROL_SET_SPU_DELAY, &newval );
839     }
840     return VLC_SUCCESS;
841 }
842
843 static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
844                              vlc_value_t oldval, vlc_value_t newval,
845                              void *p_data )
846 {
847     input_thread_t *p_input = (input_thread_t*)p_this;
848     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
849
850     input_ControlPush( p_input, INPUT_CONTROL_SET_BOOKMARK, &newval );
851
852     return VLC_SUCCESS;
853 }
854
855 static int RecordCallback( vlc_object_t *p_this, char const *psz_cmd,
856                            vlc_value_t oldval, vlc_value_t newval,
857                            void *p_data )
858 {
859     input_thread_t *p_input = (input_thread_t*)p_this;
860     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
861
862     input_ControlPush( p_input, INPUT_CONTROL_SET_RECORD_STATE, &newval );
863
864     return VLC_SUCCESS;
865 }
866
867 static int FrameNextCallback( vlc_object_t *p_this, char const *psz_cmd,
868                               vlc_value_t oldval, vlc_value_t newval,
869                               void *p_data )
870 {
871     input_thread_t *p_input = (input_thread_t*)p_this;
872     VLC_UNUSED(psz_cmd); VLC_UNUSED(oldval); VLC_UNUSED(p_data);
873     VLC_UNUSED(newval);
874
875     input_ControlPush( p_input, INPUT_CONTROL_SET_FRAME_NEXT, NULL );
876
877     return VLC_SUCCESS;
878 }
879