]> git.sesse.net Git - vlc/blob - src/input/control.c
Move/clean up input event code to its own file.
[vlc] / src / input / control.c
1 /*****************************************************************************
2  * control.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Gildas Bazin <gbazin@videolan.org>
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 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27
28 #include <vlc_common.h>
29
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 #include "input_internal.h"
34 #include "event.h"
35
36
37 static void UpdateBookmarksOption( input_thread_t * );
38
39 /****************************************************************************
40  * input_Control
41  ****************************************************************************/
42 /**
43  * Control function for inputs.
44  * \param p_input input handle
45  * \param i_query query type
46  * \return VLC_SUCCESS if ok
47  */
48 int input_Control( input_thread_t *p_input, int i_query, ...  )
49 {
50     va_list args;
51     int     i_result;
52
53     va_start( args, i_query );
54     i_result = input_vaControl( p_input, i_query, args );
55     va_end( args );
56
57     return i_result;
58 }
59
60 int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
61 {
62     seekpoint_t *p_bkmk, ***ppp_bkmk;
63     int i_bkmk = 0;
64     int *pi_bkmk;
65
66     int i_int, *pi_int;
67     bool b_bool, *pb_bool;
68     double f, *pf;
69     int64_t i_64, *pi_64;
70
71     char *psz;
72     vlc_value_t val;
73
74     switch( i_query )
75     {
76         case INPUT_GET_POSITION:
77             pf = (double*)va_arg( args, double * );
78             *pf = var_GetFloat( p_input, "position" );
79             return VLC_SUCCESS;
80
81         case INPUT_SET_POSITION:
82             f = (double)va_arg( args, double );
83             return var_SetFloat( p_input, "position", f );
84
85         case INPUT_GET_LENGTH:
86             pi_64 = (int64_t*)va_arg( args, int64_t * );
87             *pi_64 = var_GetTime( p_input, "length" );
88             return VLC_SUCCESS;
89
90         case INPUT_GET_TIME:
91             pi_64 = (int64_t*)va_arg( args, int64_t * );
92             *pi_64 = var_GetTime( p_input, "time" );
93             return VLC_SUCCESS;
94
95         case INPUT_SET_TIME:
96             i_64 = (int64_t)va_arg( args, int64_t );
97             return var_SetTime( p_input, "time", i_64 );
98
99         case INPUT_GET_RATE:
100             pi_int = (int*)va_arg( args, int * );
101             *pi_int = var_GetInteger( p_input, "rate" );
102             return VLC_SUCCESS;
103
104         case INPUT_SET_RATE:
105             i_int = (int)va_arg( args, int );
106             return var_SetInteger( p_input, "rate", i_int );
107
108         case INPUT_GET_STATE:
109             pi_int = (int*)va_arg( args, int * );
110             *pi_int = var_GetInteger( p_input, "state" );
111             return VLC_SUCCESS;
112
113         case INPUT_SET_STATE:
114             i_int = (int)va_arg( args, int );
115             return var_SetInteger( p_input, "state", i_int );
116
117         case INPUT_GET_AUDIO_DELAY:
118             pi_64 = (int64_t*)va_arg( args, int64_t * );
119             *pi_64 = var_GetTime( p_input, "audio-delay" );
120             return VLC_SUCCESS;
121
122         case INPUT_GET_SPU_DELAY:
123             pi_64 = (int64_t*)va_arg( args, int64_t * );
124             *pi_64 = var_GetTime( p_input, "spu-delay" );
125             return VLC_SUCCESS;
126
127         case INPUT_SET_AUDIO_DELAY:
128             i_64 = (int64_t)va_arg( args, int64_t );
129             return var_SetTime( p_input, "audio-delay", i_64 );
130
131         case INPUT_SET_SPU_DELAY:
132             i_64 = (int64_t)va_arg( args, int64_t );
133             return var_SetTime( p_input, "spu-delay", i_64 );
134
135         case INPUT_ADD_INFO:
136         {
137             /* FIXME : Impossible to use input_item_AddInfo because of
138              * the ... problem ? */
139             char *psz_cat = (char *)va_arg( args, char * );
140             char *psz_name = (char *)va_arg( args, char * );
141             char *psz_format = (char *)va_arg( args, char * );
142
143             char *psz_value;
144             
145             if( vasprintf( &psz_value, psz_format, args ) == -1 )
146                 return VLC_EGENERIC;
147
148             int i_ret = input_item_AddInfo( p_input->p->input.p_item,
149                                             psz_cat, psz_name, "%s", psz_value );
150
151             if( !p_input->b_preparsing && !i_ret )
152                 input_SendEventMetaInfo( p_input );
153             return i_ret;
154         }
155
156         case INPUT_DEL_INFO:
157         {
158             char *psz_cat = (char *)va_arg( args, char * );
159             char *psz_name = (char *)va_arg( args, char * );
160
161             int i_ret = input_item_DelInfo( p_input->p->input.p_item,
162                                             psz_cat, psz_name );
163
164             if( !p_input->b_preparsing && !i_ret )
165                 input_SendEventMetaInfo( p_input );
166             return i_ret;
167         }
168
169
170         case INPUT_GET_INFO:
171         {
172             char *psz_cat = (char *)va_arg( args, char * );
173             char *psz_name = (char *)va_arg( args, char * );
174             char **ppsz_value = (char **)va_arg( args, char ** );
175             int i_ret = VLC_EGENERIC;
176             *ppsz_value = NULL;
177
178             *ppsz_value = input_item_GetInfo( p_input->p->input.p_item,
179                                                   psz_cat, psz_name );
180             return i_ret;
181         }
182
183         case INPUT_SET_NAME:
184         {
185             char *psz_name = (char *)va_arg( args, char * );
186
187             if( !psz_name ) return VLC_EGENERIC;
188
189             vlc_mutex_lock( &p_input->p->input.p_item->lock );
190             if( p_input->p->input.p_item->psz_name )
191                 free( p_input->p->input.p_item->psz_name );
192             p_input->p->input.p_item->psz_name = strdup( psz_name );
193             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
194
195             if( !p_input->b_preparsing )
196                 input_SendEventMetaName( p_input, psz_name );
197             return VLC_SUCCESS;
198         }
199
200         case INPUT_ADD_BOOKMARK:
201             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
202             p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
203
204             vlc_mutex_lock( &p_input->p->input.p_item->lock );
205             if( !p_bkmk->psz_name )
206             {
207                  if( asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
208                                p_input->p->i_bookmark ) == -1 )
209                      p_bkmk->psz_name = NULL;
210             }
211
212             TAB_APPEND( p_input->p->i_bookmark, p_input->p->bookmark, p_bkmk );
213
214             /* Reflect the changes on the object var */
215             var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
216             {
217                 vlc_value_t val, text;
218                 int i;
219
220                 for( i = 0; i < p_input->p->i_bookmark; i++ )
221                 {
222                     val.i_int = i;
223                     text.psz_string = p_input->p->bookmark[i]->psz_name;
224                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
225                                 &val, &text );
226                 }
227             }
228             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
229
230             UpdateBookmarksOption( p_input );
231
232             return VLC_SUCCESS;
233
234         case INPUT_CHANGE_BOOKMARK:
235             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
236             i_bkmk = (int)va_arg( args, int );
237
238             vlc_mutex_lock( &p_input->p->input.p_item->lock );
239             if( i_bkmk < p_input->p->i_bookmark )
240             {
241                 vlc_value_t val, text;
242                 int i;
243
244                 p_input->p->bookmark[i_bkmk] = p_bkmk;
245
246                 /* Reflect the changes on the object var */
247                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
248                 for( i = 0; i < p_input->p->i_bookmark; i++ )
249                 {
250                     val.i_int = i;
251                     text.psz_string = p_input->p->bookmark[i]->psz_name;
252                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
253                                 &val, &text );
254                 }
255             }
256             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
257
258             UpdateBookmarksOption( p_input );
259
260             return VLC_SUCCESS;
261
262         case INPUT_DEL_BOOKMARK:
263             i_bkmk = (int)va_arg( args, int );
264
265             vlc_mutex_lock( &p_input->p->input.p_item->lock );
266             if( i_bkmk < p_input->p->i_bookmark )
267             {
268                 vlc_value_t val, text;
269                 int i;
270
271                 p_bkmk = p_input->p->bookmark[i_bkmk];
272                 TAB_REMOVE( p_input->p->i_bookmark, p_input->p->bookmark,
273                             p_bkmk );
274                 vlc_seekpoint_Delete( p_bkmk );
275
276                 /* Reflect the changes on the object var */
277                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
278                 for( i = 0; i < p_input->p->i_bookmark; i++ )
279                 {
280                     val.i_int = i;
281                     text.psz_string = p_input->p->bookmark[i]->psz_name;
282                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
283                                 &val, &text );
284                 }
285                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
286
287                 UpdateBookmarksOption( p_input );
288
289                 return VLC_SUCCESS;
290             }
291             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
292
293             return VLC_EGENERIC;
294
295         case INPUT_GET_BOOKMARKS:
296             ppp_bkmk = (seekpoint_t ***)va_arg( args, seekpoint_t *** );
297             pi_bkmk = (int *)va_arg( args, int * );
298
299             vlc_mutex_lock( &p_input->p->input.p_item->lock );
300             if( p_input->p->i_bookmark )
301             {
302                 int i;
303
304                 *pi_bkmk = p_input->p->i_bookmark;
305                 *ppp_bkmk = malloc( sizeof(seekpoint_t *) *
306                                     p_input->p->i_bookmark );
307                 for( i = 0; i < p_input->p->i_bookmark; i++ )
308                 {
309                     (*ppp_bkmk)[i] =
310                         vlc_seekpoint_Duplicate(p_input->p->bookmark[i]);
311                 }
312
313                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
314                 return VLC_SUCCESS;
315             }
316             else
317             {
318                 *ppp_bkmk = NULL;
319                 *pi_bkmk = 0;
320
321                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
322                 return VLC_EGENERIC;
323             }
324             break;
325
326         case INPUT_CLEAR_BOOKMARKS:
327
328             vlc_mutex_lock( &p_input->p->input.p_item->lock );
329             if( p_input->p->i_bookmark )
330             {
331                 int i;
332
333                 for( i = p_input->p->i_bookmark - 1; i >= 0; i-- )
334                 {
335                     p_bkmk = p_input->p->bookmark[i];
336                     TAB_REMOVE( p_input->p->i_bookmark, p_input->p->bookmark,
337                                 p_bkmk );
338                     vlc_seekpoint_Delete( p_bkmk );
339                 }
340                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
341             }
342             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
343
344             UpdateBookmarksOption( p_input );
345
346             return VLC_SUCCESS;
347
348         case INPUT_SET_BOOKMARK:
349             i_bkmk = (int)va_arg( args, int );
350
351             vlc_mutex_lock( &p_input->p->input.p_item->lock );
352             if( i_bkmk >= 0 && i_bkmk < p_input->p->i_bookmark )
353             {
354                 vlc_value_t pos;
355                 int i_ret;
356
357                 if( p_input->p->bookmark[i_bkmk]->i_time_offset != -1 )
358                 {
359                     pos.i_time = p_input->p->bookmark[i_bkmk]->i_time_offset;
360                     i_ret = var_Set( p_input, "time", pos );
361                 }
362                 else if( p_input->p->bookmark[i_bkmk]->i_byte_offset != -1 )
363                 {
364                     // don't crash on bookmarks in live streams
365                     if( stream_Size( p_input->p->input.p_stream ) == 0 )
366                     {
367                         vlc_mutex_unlock( &p_input->p->input.p_item->lock );
368                         return VLC_EGENERIC;
369                     }
370                     pos.f_float = !p_input->p->input.p_stream ? 0 :
371                         p_input->p->bookmark[i_bkmk]->i_byte_offset /
372                         stream_Size( p_input->p->input.p_stream );
373                     i_ret = var_Set( p_input, "position", pos );
374                 }
375                 else
376                 {
377                     pos.f_float = 0;
378                     i_ret = var_Set( p_input, "position", pos );
379                 }
380
381                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
382                 return i_ret;
383             }
384             else
385             {
386                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
387                 return VLC_EGENERIC;
388             }
389
390             break;
391
392         case INPUT_ADD_OPTION:
393         {
394             const char *psz_option = va_arg( args, const char * );
395             const char *psz_value = va_arg( args, const char * );
396             char *str;
397             int i;
398
399             if( asprintf( &str, "%s=%s", psz_option, psz_value ) == -1 )
400                 return VLC_ENOMEM;
401
402             i = input_item_AddOpt( p_input->p->input.p_item, str,
403                                   VLC_INPUT_OPTION_UNIQUE );
404             free( str );
405             return i;
406         }
407
408         case INPUT_GET_BYTE_POSITION:
409             pi_64 = (int64_t*)va_arg( args, int64_t * );
410             *pi_64 = !p_input->p->input.p_stream ? 0 :
411                 stream_Tell( p_input->p->input.p_stream );
412             return VLC_SUCCESS;
413
414         case INPUT_SET_BYTE_SIZE:
415             pi_64 = (int64_t*)va_arg( args, int64_t * );
416             *pi_64 = !p_input->p->input.p_stream ? 0 :
417                 stream_Size( p_input->p->input.p_stream );
418             return VLC_SUCCESS;
419
420         case INPUT_GET_VIDEO_FPS:
421         {
422             int i;
423             pf = (double*)va_arg( args, double * );
424             vlc_mutex_lock( &p_input->p->input.p_item->lock );
425             *pf = p_input->p->input.f_fps;
426             for( i = 0; i < p_input->p->i_slave && *pf <= 0.001; i++ )
427                 *pf = p_input->p->slave[i]->f_fps;
428             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
429             return VLC_SUCCESS;
430         }
431
432         case INPUT_ADD_SLAVE:
433             psz = (char*)va_arg( args, char * );
434             if( psz && *psz )
435             {
436                 val.psz_string = strdup( psz );
437                 input_ControlPush( p_input, INPUT_CONTROL_ADD_SLAVE, &val );
438             }
439             return VLC_SUCCESS;
440
441         case INPUT_GET_ATTACHMENTS: /* arg1=input_attachment_t***, arg2=int*  res=can fail */
442         {
443             input_attachment_t ***ppp_attachment = (input_attachment_t***)va_arg( args, input_attachment_t *** );
444             int *pi_attachment = (int*)va_arg( args, int * );
445             int i;
446
447             vlc_mutex_lock( &p_input->p->input.p_item->lock );
448             if( p_input->p->i_attachment <= 0 )
449             {
450                 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
451                 *ppp_attachment = NULL;
452                 *pi_attachment = 0;
453                 return VLC_EGENERIC;
454             }
455             *pi_attachment = p_input->p->i_attachment;
456             *ppp_attachment = malloc( sizeof(input_attachment_t**) * p_input->p->i_attachment );
457             for( i = 0; i < p_input->p->i_attachment; i++ )
458                 (*ppp_attachment)[i] = vlc_input_attachment_Duplicate( p_input->p->attachment[i] );
459
460             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
461             return VLC_SUCCESS;
462         }
463
464         case INPUT_GET_ATTACHMENT:  /* arg1=input_attachment_t**, arg2=char*  res=can fail */
465         {
466             input_attachment_t **pp_attachment = (input_attachment_t**)va_arg( args, input_attachment_t ** );
467             const char *psz_name = (const char*)va_arg( args, const char * );
468             int i;
469
470             vlc_mutex_lock( &p_input->p->input.p_item->lock );
471             for( i = 0; i < p_input->p->i_attachment; i++ )
472             {
473                 if( !strcmp( p_input->p->attachment[i]->psz_name, psz_name ) )
474                 {
475                     *pp_attachment = vlc_input_attachment_Duplicate( p_input->p->attachment[i] );
476                     vlc_mutex_unlock( &p_input->p->input.p_item->lock );
477                     return VLC_SUCCESS;
478                 }
479             }
480             *pp_attachment = NULL;
481             vlc_mutex_unlock( &p_input->p->input.p_item->lock );
482             return VLC_EGENERIC;
483         }
484
485         case INPUT_SET_RECORD_STATE:
486             b_bool = (bool)va_arg( args, int );
487             var_SetBool( p_input, "record", b_bool );
488             return VLC_SUCCESS;
489
490         case INPUT_GET_RECORD_STATE:
491             pb_bool = (bool*)va_arg( args, bool* );
492             *pb_bool = var_GetBool( p_input, "record" );
493             return VLC_SUCCESS;
494
495         case INPUT_RESTART_ES:
496             val.i_int = (int)va_arg( args, int );
497             input_ControlPush( p_input, INPUT_CONTROL_RESTART_ES, &val );
498             return VLC_SUCCESS;
499
500         default:
501             msg_Err( p_input, "unknown query in input_vaControl" );
502             return VLC_EGENERIC;
503     }
504 }
505
506 static void UpdateBookmarksOption( input_thread_t *p_input )
507 {
508     int i, i_len = 0;
509     char *psz_value = NULL, *psz_next = NULL;
510
511     vlc_mutex_lock( &p_input->p->input.p_item->lock );
512     if( p_input->p->i_bookmark > 0 )
513     {
514         for( i = 0; i < p_input->p->i_bookmark; i++ )
515         {
516             i_len += snprintf( NULL, 0, "{name=%s,bytes=%"PRId64",time=%"PRId64"}",
517                                p_input->p->bookmark[i]->psz_name,
518                                p_input->p->bookmark[i]->i_byte_offset,
519                                p_input->p->bookmark[i]->i_time_offset/1000000 );
520         }
521         psz_value = psz_next = malloc( i_len + p_input->p->i_bookmark );
522
523         for( i = 0; i < p_input->p->i_bookmark; i++ )
524         {
525             sprintf( psz_next, "{name=%s,bytes=%"PRId64",time=%"PRId64"}",
526                      p_input->p->bookmark[i]->psz_name,
527                      p_input->p->bookmark[i]->i_byte_offset,
528                      p_input->p->bookmark[i]->i_time_offset/1000000 );
529
530             psz_next += strlen( psz_next );
531             if( i < p_input->p->i_bookmark - 1)
532                 *psz_next = ','; psz_next++;
533         }
534     }
535     vlc_mutex_unlock( &p_input->p->input.p_item->lock );
536
537     input_Control( p_input, INPUT_ADD_OPTION, "bookmarks",
538                    psz_value ? psz_value : "" );
539     free( psz_value );
540 }
541