]> git.sesse.net Git - vlc/blob - src/input/control.c
Hopefully fix locking issues with wx
[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                     vlc_mutex_unlock( &p_input->stream.stream_lock );
133                     var_Set( p_playlist, "item-change", val );
134                     vlc_mutex_lock( &p_input->stream.stream_lock );
135                     vlc_object_release( p_playlist );
136                 }
137             }
138             break;
139         }
140
141         case INPUT_ADD_INFO:
142         {
143             char *psz_cat = (char *)va_arg( args, char * );
144             char *psz_name = (char *)va_arg( args, char * );
145             char *psz_format = (char *)va_arg( args, char * );
146
147             info_category_t *p_cat;
148             info_t *p_info;
149             int i;
150
151             i_ret = VLC_EGENERIC;
152
153             vlc_mutex_lock( &p_input->p_item->lock );
154             for( i = 0; i < p_input->p_item->i_categories; i++ )
155             {
156                 if( !strcmp( p_input->p_item->pp_categories[i]->psz_name,
157                              psz_cat ) )
158                     break;
159             }
160
161             if( i == p_input->p_item->i_categories )
162             {
163                 p_cat = malloc( sizeof( info_category_t ) );
164                 if( !p_cat ) break;
165                 p_cat->psz_name = strdup( psz_cat );
166                 p_cat->i_infos = 0;
167                 p_cat->pp_infos = NULL;
168                 INSERT_ELEM( p_input->p_item->pp_categories,
169                              p_input->p_item->i_categories,
170                              p_input->p_item->i_categories, p_cat );
171             }
172
173             p_cat = p_input->p_item->pp_categories[i];
174
175             for( i = 0; i < p_cat->i_infos; i++ )
176             {
177                 if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
178                 {
179                     if( p_cat->pp_infos[i]->psz_value )
180                         free( p_cat->pp_infos[i]->psz_value );
181                     break;
182                 }
183             }
184
185             if( i == p_cat->i_infos )
186             {
187                 p_info = malloc( sizeof( info_t ) );
188                 if( !p_info ) break;
189                 INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos,
190                              p_cat->i_infos, p_info );
191                 p_info->psz_name = strdup( psz_name );
192             }
193
194             p_info = p_cat->pp_infos[i];
195             vasprintf( &p_info->psz_value, psz_format, args );
196
197             vlc_mutex_unlock( &p_input->p_item->lock );
198
199             i_ret = VLC_SUCCESS;
200
201             /* Notify playlist */
202             {
203                 vlc_value_t val;
204                 playlist_t *p_playlist =
205                 (playlist_t *)vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
206                                                FIND_PARENT );
207                 if( p_playlist )
208                 {
209                     val.i_int = p_playlist->i_index;
210                     vlc_mutex_unlock( &p_input->stream.stream_lock );
211                     var_Set( p_playlist, "item-change", val );
212                     vlc_mutex_lock( &p_input->stream.stream_lock );
213                     vlc_object_release( p_playlist );
214                 }
215             }
216         }
217         break;
218
219         case INPUT_GET_INFO:
220         {
221             char *psz_cat = (char *)va_arg( args, char * );
222             char *psz_name = (char *)va_arg( args, char * );
223             char **ppsz_value = (char **)va_arg( args, char ** );
224             int i;
225
226             i_ret = VLC_EGENERIC;
227             *ppsz_value = NULL;
228
229             vlc_mutex_lock( &p_input->p_item->lock );
230             for( i = 0; i < p_input->p_item->i_categories; i++ )
231             {
232                 if( !strcmp( p_input->p_item->pp_categories[i]->psz_name,
233                              psz_cat ) )
234                     break;
235             }
236
237             if( i != p_input->p_item->i_categories )
238             {
239                 info_category_t *p_cat;
240                 p_cat = p_input->p_item->pp_categories[i];
241
242                 for( i = 0; i < p_cat->i_infos; i++ )
243                 {
244                     if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
245                     {
246                         if( p_cat->pp_infos[i]->psz_value )
247                         {
248                             *ppsz_value =strdup(p_cat->pp_infos[i]->psz_value);
249                             i_ret = VLC_SUCCESS;
250                         }
251                         break;
252                     }
253                 }
254             }
255             vlc_mutex_unlock( &p_input->p_item->lock );
256         }
257         break;
258
259         case INPUT_ADD_BOOKMARK:
260             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
261             p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
262             if( !p_bkmk->psz_name )
263             {
264                  asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
265                            p_input->i_bookmarks );
266             }
267             TAB_APPEND( p_input->i_bookmarks, p_input->pp_bookmarks, p_bkmk );
268
269             /* Reflect the changes on the object var */
270             var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
271             {
272                 int i;
273                 for( i = 0; i < p_input->i_bookmarks; i++ )
274                 {
275                     val.i_int = i;
276                     text.psz_string = p_input->pp_bookmarks[i]->psz_name;
277                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
278                                 &val, &text );
279                 }
280             }
281
282             UpdateBookmarksOption( p_input );
283
284             i_ret = VLC_SUCCESS;
285             break;
286
287         case INPUT_DEL_BOOKMARK:
288             i_bkmk = (int)va_arg( args, int );
289             if( i_bkmk < p_input->i_bookmarks )
290             {
291                 int i;
292                 p_bkmk = p_input->pp_bookmarks[i_bkmk];
293                 TAB_REMOVE( p_input->i_bookmarks, p_input->pp_bookmarks,
294                             p_bkmk );
295                 vlc_seekpoint_Delete( p_bkmk );
296
297                 /* Reflect the changes on the object var */
298                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
299                 for( i = 0; i < p_input->i_bookmarks; i++ )
300                 {
301                     val.i_int = i;
302                     text.psz_string = p_input->pp_bookmarks[i]->psz_name;
303                     var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
304                                 &val, &text );
305                 }
306
307                 UpdateBookmarksOption( p_input );
308
309                 i_ret = VLC_SUCCESS;
310             }
311             else i_ret = VLC_EGENERIC;
312             break;
313
314         case INPUT_GET_BOOKMARKS:
315             ppp_bkmk = (seekpoint_t ***)va_arg( args, seekpoint_t *** );
316             pi_bkmk = (int *)va_arg( args, int * );
317             if( p_input->i_bookmarks )
318             {
319                 int i;
320
321                 *pi_bkmk = p_input->i_bookmarks;
322                 *ppp_bkmk = malloc( sizeof(seekpoint_t *) *
323                               p_input->i_bookmarks );
324                 for( i = 0; i < p_input->i_bookmarks; i++ )
325                 {
326                     (*ppp_bkmk)[i] =
327                         vlc_seekpoint_Duplicate(p_input->pp_bookmarks[i]);
328                 }
329                 i_ret = VLC_SUCCESS;
330             }
331             else
332             {
333                 *ppp_bkmk = NULL;
334                 *pi_bkmk = 0;
335                 i_ret = VLC_EGENERIC;
336             }
337             break;
338
339         case INPUT_CLEAR_BOOKMARKS:
340             if( p_input->i_bookmarks )
341             {
342                 int i;
343
344                 for( i = p_input->i_bookmarks - 1; i >= 0; i-- )
345                 {
346                     p_bkmk = p_input->pp_bookmarks[i];
347                     TAB_REMOVE( p_input->i_bookmarks, p_input->pp_bookmarks,
348                                 p_bkmk );
349                     vlc_seekpoint_Delete( p_bkmk );
350                 }
351                 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
352             }
353
354             UpdateBookmarksOption( p_input );
355
356             i_ret = VLC_SUCCESS;
357             break;
358
359         case INPUT_SET_BOOKMARK:
360             i_bkmk = (int)va_arg( args, int );
361             if( i_bkmk >= 0 && i_bkmk < p_input->i_bookmarks )
362             {
363                 vlc_value_t pos;
364                 vlc_mutex_unlock( &p_input->stream.stream_lock );
365                 if( p_input->pp_bookmarks[i_bkmk]->i_byte_offset ||
366                     ( !p_input->pp_bookmarks[i_bkmk]->i_byte_offset &&
367                       !p_input->pp_bookmarks[i_bkmk]->i_time_offset ) )
368                 {
369                     pos.f_float = p_input->pp_bookmarks[i_bkmk]->i_byte_offset/
370                         (double)p_input->stream.p_selected_area->i_size;
371                     i_ret = var_Set( p_input, "position", pos );
372                 }
373                 else if( p_input->pp_bookmarks[i_bkmk]->i_time_offset )
374                 {
375                     pos.i_time = p_input->pp_bookmarks[i_bkmk]->i_time_offset;
376                     i_ret = var_Set( p_input, "time", pos );
377                 }
378                 vlc_mutex_lock( &p_input->stream.stream_lock );
379             }
380             else
381             {
382                 i_ret = VLC_EGENERIC;
383             }
384             break;
385
386         case INPUT_GET_SUBDELAY:
387             pi = (int*)va_arg( args, int *);
388             /* We work on the first subtitle */
389             if( p_input->p_sys != NULL )
390             {
391                 if( p_input->p_sys->i_sub > 0 )
392                 {
393                     i_ret = var_Get( (vlc_object_t *)p_input->p_sys->sub[0],
394                                       "sub-delay", &val );
395                     *pi = val.i_int;
396                 }
397                 else
398                 {
399                     msg_Dbg( p_input,"no subtitle track");
400                     i_ret = VLC_EGENERIC;
401                 }
402             }
403             else
404             {
405                 i_ret = VLC_EGENERIC;
406             }
407             break;
408
409         case INPUT_SET_SUBDELAY:
410             i = (int)va_arg( args, int );
411             /* We work on the first subtitle */
412             if( p_input->p_sys )
413             {
414                 if( p_input->p_sys->i_sub > 0 )
415                 {
416                     val.i_int = i;
417                     i_ret = var_Set( (vlc_object_t *)p_input->p_sys->sub[0],
418                                       "sub-delay", val );
419                 }
420                 else
421                 {
422                     msg_Dbg( p_input,"no subtitle track");
423                     i_ret = VLC_EGENERIC;
424                 }
425             }
426             else
427             {
428                 i_ret = VLC_EGENERIC;
429             }
430             break;
431
432         default:
433             msg_Err( p_input, "unknown query in input_vaControl" );
434             i_ret = VLC_EGENERIC;
435             break;
436     }
437     vlc_mutex_unlock( &p_input->stream.stream_lock );
438
439     return i_ret;
440 }
441
442 static void UpdateBookmarksOption( input_thread_t *p_input )
443 {
444     int i, i_len = 0;
445     char *psz_value = NULL, *psz_next = NULL;
446
447     vlc_mutex_unlock( &p_input->stream.stream_lock );
448
449     for( i = 0; i < p_input->i_bookmarks; i++ )
450     {
451         asprintf( &psz_value, "{name=%s,bytes="I64Fd",time="I64Fd"}",
452                   p_input->pp_bookmarks[i]->psz_name,
453                   p_input->pp_bookmarks[i]->i_byte_offset,
454                   p_input->pp_bookmarks[i]->i_time_offset/1000000 );
455         i_len += strlen( psz_value );
456         free( psz_value );
457     }
458     for( i = 0; i < p_input->i_bookmarks; i++ )
459     {
460         if( !i ) psz_value = psz_next = malloc( i_len + p_input->i_bookmarks );
461
462         sprintf( psz_next, "{name=%s,bytes="I64Fd",time="I64Fd"}",
463                  p_input->pp_bookmarks[i]->psz_name,
464                  p_input->pp_bookmarks[i]->i_byte_offset,
465                  p_input->pp_bookmarks[i]->i_time_offset/1000000 );
466
467         psz_next += strlen( psz_next );
468         if( i < p_input->i_bookmarks - 1)
469         {
470             *psz_next = ','; psz_next++;
471         }
472     }
473     input_Control( p_input, INPUT_ADD_OPTION, "bookmarks",
474                    psz_value ? psz_value : "" );
475
476     vlc_mutex_lock( &p_input->stream.stream_lock );
477 }