]> git.sesse.net Git - vlc/blob - src/input/control.c
* src/input/control.c, include/ninput.h: Added INPUT_GET_INFO.
[vlc] / src / input / control.c
1 /*****************************************************************************
2  * control.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VideoLAN
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <vlc/vlc.h>
27 #include <vlc/input.h>
28
29 #include "vlc_playlist.h"
30
31 #include "ninput.h"
32 #include "../../modules/demux/util/sub.h"
33
34 struct input_thread_sys_t
35 {
36     /* subtitles */
37     int              i_sub;
38     subtitle_demux_t **sub;
39     int64_t          i_stop_time;
40 };
41
42 static void UpdateBookmarksOption( input_thread_t * );
43
44 /****************************************************************************
45  * input_Control
46  ****************************************************************************/
47 /**
48  * Control function for inputs.
49  * \param p_input input handle
50  * \param i_query query type
51  * \return VLC_SUCESS if ok
52  */
53 int input_Control( input_thread_t *p_input, int i_query, ...  )
54 {
55     va_list args;
56     int     i_result;
57
58     va_start( args, i_query );
59     i_result = input_vaControl( p_input, i_query, args );
60     va_end( args );
61
62     return i_result;
63 }
64
65 int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
66 {
67     int     i_ret;
68     seekpoint_t *p_bkmk, ***ppp_bkmk;
69     int i_bkmk, *pi_bkmk;
70     int i, *pi;
71     vlc_value_t val, text;
72     char *psz_option, *psz_value;
73
74     vlc_mutex_lock( &p_input->stream.stream_lock );
75     switch( i_query )
76     {
77         case INPUT_ADD_OPTION:
78         {
79             psz_option = (char *)va_arg( args, char * );
80             psz_value = (char *)va_arg( args, char * );
81             i_ret = VLC_EGENERIC;
82
83             vlc_mutex_lock( &p_input->p_item->lock );
84             /* Check if option already exists */            
85             for( i = 0; i < p_input->p_item->i_options; i++ )
86             {
87                 if( !strncmp( p_input->p_item->ppsz_options[i], psz_option,
88                               strlen( psz_option ) ) &&
89                     p_input->p_item->ppsz_options[i][strlen(psz_option)]
90                       == '=' )
91                 {
92                     free( p_input->p_item->ppsz_options[i] );
93                     break;
94                 }
95             }
96             if( i == p_input->p_item->i_options )
97             {
98                 p_input->p_item->i_options++;
99                 p_input->p_item->ppsz_options =
100                     realloc( p_input->p_item->ppsz_options,
101                              p_input->p_item->i_options * sizeof(char **) );
102             }
103
104             asprintf( &p_input->p_item->ppsz_options[i],
105                       "%s=%s", psz_option, psz_value ) ;
106             vlc_mutex_unlock( &p_input->p_item->lock );
107
108             i_ret = VLC_SUCCESS;
109             break;
110         }
111
112         case INPUT_SET_NAME:
113         {
114             char *psz_name = (char *)va_arg( args, char * );
115             i_ret = VLC_EGENERIC;
116             if( !psz_name ) break;
117             vlc_mutex_lock( &p_input->p_item->lock );
118             if( p_input->p_item->psz_name ) free( p_input->p_item->psz_name );
119             p_input->p_item->psz_name = strdup( psz_name );
120             vlc_mutex_unlock( &p_input->p_item->lock );
121             i_ret = VLC_SUCCESS;
122
123             /* Notify playlist */
124             {
125                 vlc_value_t val;
126                 playlist_t *p_playlist =
127                 (playlist_t *)vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
128                                                FIND_PARENT );
129                 if( p_playlist )
130                 {
131                     val.i_int = p_playlist->i_index;
132                     var_Set( p_playlist, "item-change", val );
133                     vlc_object_release( p_playlist );
134                 }
135             }
136             break;
137         }
138
139         case INPUT_ADD_INFO:
140         {
141             char *psz_cat = (char *)va_arg( args, char * );
142             char *psz_name = (char *)va_arg( args, char * );
143             char *psz_format = (char *)va_arg( args, char * );
144
145             info_category_t *p_cat;
146             info_t *p_info;
147             int i;
148
149             i_ret = VLC_EGENERIC;
150
151             vlc_mutex_lock( &p_input->p_item->lock );
152             for( i = 0; i < p_input->p_item->i_categories; i++ )
153             {
154                 if( !strcmp( p_input->p_item->pp_categories[i]->psz_name,
155                              psz_cat ) )
156                     break;
157             }
158
159             if( i == p_input->p_item->i_categories )
160             {
161                 p_cat = malloc( sizeof( info_category_t ) );
162                 if( !p_cat ) break;
163                 p_cat->psz_name = strdup( psz_cat );
164                 p_cat->i_infos = 0;
165                 p_cat->pp_infos = NULL;
166                 INSERT_ELEM( p_input->p_item->pp_categories,
167                              p_input->p_item->i_categories,
168                              p_input->p_item->i_categories, p_cat );
169             }
170
171             p_cat = p_input->p_item->pp_categories[i];
172
173             for( i = 0; i < p_cat->i_infos; i++ )
174             {
175                 if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
176                 {
177                     if( p_cat->pp_infos[i]->psz_value )
178                         free( p_cat->pp_infos[i]->psz_value );
179                     break;
180                 }
181             }
182
183             if( i == p_cat->i_infos )
184             {
185                 p_info = malloc( sizeof( info_t ) );
186                 if( !p_info ) break;
187                 INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos,
188                              p_cat->i_infos, p_info );
189                 p_info->psz_name = strdup( psz_name );
190             }
191
192             p_info = p_cat->pp_infos[i];
193             vasprintf( &p_info->psz_value, psz_format, args );
194
195             vlc_mutex_unlock( &p_input->p_item->lock );
196
197             i_ret = VLC_SUCCESS;
198
199             /* Notify playlist */
200             {
201                 vlc_value_t val;
202                 playlist_t *p_playlist =
203                 (playlist_t *)vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
204                                                FIND_PARENT );
205                 if( p_playlist )
206                 {
207                     val.i_int = p_playlist->i_index;
208                     var_Set( p_playlist, "item-change", val );
209                     vlc_object_release( p_playlist );
210                 }
211             }
212         }
213         break;
214
215         case INPUT_GET_INFO:
216         {
217             char *psz_cat = (char *)va_arg( args, char * );
218             char *psz_name = (char *)va_arg( args, char * );
219             char **ppsz_value = (char **)va_arg( args, char ** );
220             int i;
221
222             i_ret = VLC_EGENERIC;
223             *ppsz_value = NULL;
224
225             vlc_mutex_lock( &p_input->p_item->lock );
226             for( i = 0; i < p_input->p_item->i_categories; i++ )
227             {
228                 if( !strcmp( p_input->p_item->pp_categories[i]->psz_name,
229                              psz_cat ) )
230                     break;
231             }
232
233             if( i != p_input->p_item->i_categories )
234             {
235                 info_category_t *p_cat;
236                 p_cat = p_input->p_item->pp_categories[i];
237
238                 for( i = 0; i < p_cat->i_infos; i++ )
239                 {
240                     if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
241                     {
242                         if( p_cat->pp_infos[i]->psz_value )
243                         {
244                             *ppsz_value =strdup(p_cat->pp_infos[i]->psz_value);
245                             i_ret = VLC_SUCCESS;
246                         }
247                         break;
248                     }
249                 }
250             }
251             vlc_mutex_unlock( &p_input->p_item->lock );
252         }
253         break;
254
255         case INPUT_ADD_BOOKMARK:
256             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
257             p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
258             if( !p_bkmk->psz_name )
259             {
260                  asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
261                            p_input->i_bookmarks );
262             }
263             TAB_APPEND( p_input->i_bookmarks, p_input->pp_bookmarks, p_bkmk );
264
265             /* Reflect the changes on the object var */
266             var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
267             {
268                 int i;
269                 for( i = 0; i < p_input->i_bookmarks; i++ )
270                 {
271                     val.i_int = i;
272                     text.psz_string = p_input->pp_bookmarks[i]->psz_name;
273                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
274                                 &val, &text );
275                 }
276             }
277
278             UpdateBookmarksOption( p_input );
279
280             i_ret = VLC_SUCCESS;
281             break;
282
283         case INPUT_DEL_BOOKMARK:
284             i_bkmk = (int)va_arg( args, int );
285             if( i_bkmk < p_input->i_bookmarks )
286             {
287                 int i;
288                 p_bkmk = p_input->pp_bookmarks[i_bkmk];
289                 TAB_REMOVE( p_input->i_bookmarks, p_input->pp_bookmarks,
290                             p_bkmk );
291                 vlc_seekpoint_Delete( p_bkmk );
292
293                 /* Reflect the changes on the object var */
294                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
295                 for( i = 0; i < p_input->i_bookmarks; i++ )
296                 {
297                     val.i_int = i;
298                     text.psz_string = p_input->pp_bookmarks[i]->psz_name;
299                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
300                                 &val, &text );
301                 }
302
303                 UpdateBookmarksOption( p_input );
304
305                 i_ret = VLC_SUCCESS;
306             }
307             else i_ret = VLC_EGENERIC;
308             break;
309
310         case INPUT_GET_BOOKMARKS:
311             ppp_bkmk = (seekpoint_t ***)va_arg( args, seekpoint_t *** );
312             pi_bkmk = (int *)va_arg( args, int * );
313             if( p_input->i_bookmarks )
314             {
315                 int i;
316
317                 *pi_bkmk = p_input->i_bookmarks;
318                 *ppp_bkmk = malloc( sizeof(seekpoint_t *) *
319                               p_input->i_bookmarks );
320                 for( i = 0; i < p_input->i_bookmarks; i++ )
321                 {
322                     (*ppp_bkmk)[i] =
323                         vlc_seekpoint_Duplicate(p_input->pp_bookmarks[i]);
324                 }
325                 i_ret = VLC_SUCCESS;
326             }
327             else
328             {
329                 *ppp_bkmk = NULL;
330                 *pi_bkmk = 0;
331                 i_ret = VLC_EGENERIC;
332             }
333             break;
334
335         case INPUT_CLEAR_BOOKMARKS:
336             if( p_input->i_bookmarks )
337             {
338                 int i;
339
340                 for( i = p_input->i_bookmarks - 1; i >= 0; i-- )
341                 {
342                     p_bkmk = p_input->pp_bookmarks[i];
343                     TAB_REMOVE( p_input->i_bookmarks, p_input->pp_bookmarks,
344                                 p_bkmk );
345                     vlc_seekpoint_Delete( p_bkmk );
346                 }
347                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
348             }
349
350             UpdateBookmarksOption( p_input );
351
352             i_ret = VLC_SUCCESS;
353             break;
354
355         case INPUT_SET_BOOKMARK:
356             i_bkmk = (int)va_arg( args, int );
357             if( i_bkmk >= 0 && i_bkmk < p_input->i_bookmarks )
358             {
359                 vlc_value_t pos;
360                 vlc_mutex_unlock( &p_input->stream.stream_lock );
361                 if( p_input->pp_bookmarks[i_bkmk]->i_byte_offset ||
362                     ( !p_input->pp_bookmarks[i_bkmk]->i_byte_offset &&
363                       !p_input->pp_bookmarks[i_bkmk]->i_time_offset ) )
364                 {
365                     pos.f_float = p_input->pp_bookmarks[i_bkmk]->i_byte_offset/
366                         (double)p_input->stream.p_selected_area->i_size;
367                     i_ret = var_Set( p_input, "position", pos );
368                 }
369                 else if( p_input->pp_bookmarks[i_bkmk]->i_time_offset )
370                 {
371                     pos.i_time = p_input->pp_bookmarks[i_bkmk]->i_time_offset;
372                     i_ret = var_Set( p_input, "time", pos );
373                 }
374                 vlc_mutex_lock( &p_input->stream.stream_lock );
375             }
376             else
377             {
378                 i_ret = VLC_EGENERIC;
379             }
380             break;
381
382         case INPUT_GET_SUBDELAY:
383             pi = (int*)va_arg( args, int *);
384             /* We work on the first subtitle */
385             if( p_input->p_sys != NULL )
386             {
387                 if( p_input->p_sys->i_sub > 0 )
388                 {
389                     i_ret = var_Get( (vlc_object_t *)p_input->p_sys->sub[0],
390                                       "sub-delay", &val );
391                     *pi = val.i_int;
392                 }
393                 else
394                 {
395                     msg_Dbg( p_input,"no subtitle track");
396                     i_ret = VLC_EGENERIC;
397                 }
398             }
399             else
400             {
401                 i_ret = VLC_EGENERIC;
402             }
403             break;
404
405         case INPUT_SET_SUBDELAY:
406             i = (int)va_arg( args, int );
407             /* We work on the first subtitle */
408             if( p_input->p_sys )
409             {
410                 if( p_input->p_sys->i_sub > 0 )
411                 {
412                     val.i_int = i;
413                     i_ret = var_Set( (vlc_object_t *)p_input->p_sys->sub[0],
414                                       "sub-delay", val );
415                 }
416                 else
417                 {
418                     msg_Dbg( p_input,"no subtitle track");
419                     i_ret = VLC_EGENERIC;
420                 }
421             }
422             else
423             {
424                 i_ret = VLC_EGENERIC;
425             }
426             break;
427
428         default:
429             msg_Err( p_input, "unknown query in input_vaControl" );
430             i_ret = VLC_EGENERIC;
431             break;
432     }
433     vlc_mutex_unlock( &p_input->stream.stream_lock );
434
435     return i_ret;
436 }
437
438 static void UpdateBookmarksOption( input_thread_t *p_input )
439 {
440     int i, i_len = 0;
441     char *psz_value = NULL, *psz_next = NULL;
442
443     vlc_mutex_unlock( &p_input->stream.stream_lock );
444
445     for( i = 0; i < p_input->i_bookmarks; i++ )
446     {
447         asprintf( &psz_value, "{name=%s,bytes="I64Fd",time="I64Fd"}",
448                   p_input->pp_bookmarks[i]->psz_name,
449                   p_input->pp_bookmarks[i]->i_byte_offset,
450                   p_input->pp_bookmarks[i]->i_time_offset/1000000 );
451         i_len += strlen( psz_value );
452         free( psz_value );
453     }
454     for( i = 0; i < p_input->i_bookmarks; i++ )
455     {
456         if( !i ) psz_value = psz_next = malloc( i_len + p_input->i_bookmarks );
457
458         sprintf( psz_next, "{name=%s,bytes="I64Fd",time="I64Fd"}",
459                  p_input->pp_bookmarks[i]->psz_name,
460                  p_input->pp_bookmarks[i]->i_byte_offset,
461                  p_input->pp_bookmarks[i]->i_time_offset/1000000 );
462
463         psz_next += strlen( psz_next );
464         if( i < p_input->i_bookmarks - 1)
465         {
466             *psz_next = ','; psz_next++;
467         }
468     }
469     input_Control( p_input, INPUT_ADD_OPTION, "bookmarks",
470                    psz_value ? psz_value : "" );
471
472     vlc_mutex_lock( &p_input->stream.stream_lock );
473 }