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