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