]> git.sesse.net Git - vlc/blob - src/input/control.c
input core: add status field per elementary stream
[vlc] / src / input / control.c
1 /*****************************************************************************
2  * control.c
3  *****************************************************************************
4  * Copyright (C) 1999-2004 VLC authors and 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 it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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 #include <assert.h>
33
34 #include "input_internal.h"
35 #include "event.h"
36 #include "resource.h"
37 #include "es_out.h"
38
39 typedef enum input_es_state_e input_es_state_e;
40
41 static void UpdateBookmarksOption( input_thread_t * );
42
43 /****************************************************************************
44  * input_Control
45  ****************************************************************************/
46 /**
47  * Control function for inputs.
48  * \param p_input input handle
49  * \param i_query query type
50  * \return VLC_SUCCESS if ok
51  */
52 int input_Control( input_thread_t *p_input, int i_query, ...  )
53 {
54     va_list args;
55     int     i_result;
56
57     va_start( args, i_query );
58     i_result = input_vaControl( p_input, i_query, args );
59     va_end( args );
60
61     return i_result;
62 }
63
64 int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
65 {
66     seekpoint_t *p_bkmk, ***ppp_bkmk;
67     int i_bkmk = 0;
68     int *pi_bkmk;
69
70     int i_int, *pi_int;
71     bool b_bool, *pb_bool;
72     double f, *pf;
73     int64_t i_64, *pi_64;
74
75     char *psz;
76     vlc_value_t val;
77
78     switch( i_query )
79     {
80         case INPUT_GET_POSITION:
81             pf = (double*)va_arg( args, double * );
82             *pf = var_GetFloat( p_input, "position" );
83             return VLC_SUCCESS;
84
85         case INPUT_SET_POSITION:
86             f = (double)va_arg( args, double );
87             return var_SetFloat( p_input, "position", f );
88
89         case INPUT_GET_LENGTH:
90             pi_64 = (int64_t*)va_arg( args, int64_t * );
91             *pi_64 = var_GetTime( p_input, "length" );
92             return VLC_SUCCESS;
93
94         case INPUT_GET_TIME:
95             pi_64 = (int64_t*)va_arg( args, int64_t * );
96             *pi_64 = var_GetTime( p_input, "time" );
97             return VLC_SUCCESS;
98
99         case INPUT_SET_TIME:
100             i_64 = (int64_t)va_arg( args, int64_t );
101             return var_SetTime( p_input, "time", i_64 );
102
103         case INPUT_GET_RATE:
104             pi_int = (int*)va_arg( args, int * );
105             *pi_int = INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" );
106             return VLC_SUCCESS;
107
108         case INPUT_SET_RATE:
109             i_int = (int)va_arg( args, int );
110             return var_SetFloat( p_input, "rate",
111                                  (float)INPUT_RATE_DEFAULT / (float)i_int );
112
113         case INPUT_GET_STATE:
114             pi_int = (int*)va_arg( args, int * );
115             *pi_int = var_GetInteger( p_input, "state" );
116             return VLC_SUCCESS;
117
118         case INPUT_SET_STATE:
119             i_int = (int)va_arg( args, int );
120             return var_SetInteger( p_input, "state", i_int );
121
122         case INPUT_GET_AUDIO_DELAY:
123             pi_64 = (int64_t*)va_arg( args, int64_t * );
124             *pi_64 = var_GetTime( p_input, "audio-delay" );
125             return VLC_SUCCESS;
126
127         case INPUT_GET_SPU_DELAY:
128             pi_64 = (int64_t*)va_arg( args, int64_t * );
129             *pi_64 = var_GetTime( p_input, "spu-delay" );
130             return VLC_SUCCESS;
131
132         case INPUT_SET_AUDIO_DELAY:
133             i_64 = (int64_t)va_arg( args, int64_t );
134             return var_SetTime( p_input, "audio-delay", i_64 );
135
136         case INPUT_SET_SPU_DELAY:
137             i_64 = (int64_t)va_arg( args, int64_t );
138             return var_SetTime( p_input, "spu-delay", i_64 );
139
140         case INPUT_NAV_ACTIVATE:
141         case INPUT_NAV_UP:
142         case INPUT_NAV_DOWN:
143         case INPUT_NAV_LEFT:
144         case INPUT_NAV_RIGHT:
145             input_ControlPush( p_input, i_query - INPUT_NAV_ACTIVATE
146                                + INPUT_CONTROL_NAV_ACTIVATE, NULL );
147             return VLC_SUCCESS;
148
149         case INPUT_ADD_INFO:
150         {
151             char *psz_cat = (char *)va_arg( args, char * );
152             char *psz_name = (char *)va_arg( args, char * );
153             char *psz_format = (char *)va_arg( args, char * );
154
155             char *psz_value;
156
157             if( vasprintf( &psz_value, psz_format, args ) == -1 )
158                 return VLC_EGENERIC;
159
160             int i_ret = input_item_AddInfo( p_input->p->p_item,
161                                             psz_cat, psz_name, "%s", psz_value );
162             free( psz_value );
163
164             if( !p_input->b_preparsing && !i_ret )
165                 input_SendEventMetaInfo( p_input );
166             return i_ret;
167         }
168         case INPUT_REPLACE_INFOS:
169         case INPUT_MERGE_INFOS:
170         {
171             info_category_t *p_cat = va_arg( args, info_category_t * );
172
173             if( i_query == INPUT_REPLACE_INFOS )
174                 input_item_ReplaceInfos( p_input->p->p_item, p_cat );
175             else
176                 input_item_MergeInfos( p_input->p->p_item, p_cat );
177
178             if( !p_input->b_preparsing )
179                 input_SendEventMetaInfo( p_input );
180             return VLC_SUCCESS;
181         }
182         case INPUT_DEL_INFO:
183         {
184             char *psz_cat = (char *)va_arg( args, char * );
185             char *psz_name = (char *)va_arg( args, char * );
186
187             int i_ret = input_item_DelInfo( p_input->p->p_item,
188                                             psz_cat, psz_name );
189
190             if( !p_input->b_preparsing && !i_ret )
191                 input_SendEventMetaInfo( p_input );
192             return i_ret;
193         }
194         case INPUT_GET_INFO:
195         {
196             char *psz_cat = (char *)va_arg( args, char * );
197             char *psz_name = (char *)va_arg( args, char * );
198             char **ppsz_value = (char **)va_arg( args, char ** );
199             int i_ret = VLC_EGENERIC;
200             *ppsz_value = NULL;
201
202             *ppsz_value = input_item_GetInfo( p_input->p->p_item,
203                                                   psz_cat, psz_name );
204             return i_ret;
205         }
206
207         case INPUT_SET_NAME:
208         {
209             char *psz_name = (char *)va_arg( args, char * );
210
211             if( !psz_name ) return VLC_EGENERIC;
212
213             input_item_SetName( p_input->p->p_item, psz_name );
214
215             if( !p_input->b_preparsing )
216                 input_SendEventMetaName( p_input, psz_name );
217             return VLC_SUCCESS;
218         }
219
220         case INPUT_ADD_BOOKMARK:
221             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
222             p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
223
224             vlc_mutex_lock( &p_input->p->p_item->lock );
225             if( !p_bkmk->psz_name )
226             {
227                  if( asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
228                                p_input->p->i_bookmark ) == -1 )
229                      p_bkmk->psz_name = NULL;
230             }
231
232             TAB_APPEND( p_input->p->i_bookmark, p_input->p->pp_bookmark, p_bkmk );
233             vlc_mutex_unlock( &p_input->p->p_item->lock );
234
235             UpdateBookmarksOption( p_input );
236
237             return VLC_SUCCESS;
238
239         case INPUT_CHANGE_BOOKMARK:
240             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
241             i_bkmk = (int)va_arg( args, int );
242
243             vlc_mutex_lock( &p_input->p->p_item->lock );
244             if( i_bkmk < p_input->p->i_bookmark )
245             {
246                 vlc_seekpoint_Delete( p_input->p->pp_bookmark[i_bkmk] );
247                 p_input->p->pp_bookmark[i_bkmk] = vlc_seekpoint_Duplicate( p_bkmk );
248             }
249             vlc_mutex_unlock( &p_input->p->p_item->lock );
250
251             UpdateBookmarksOption( p_input );
252
253             return VLC_SUCCESS;
254
255         case INPUT_DEL_BOOKMARK:
256             i_bkmk = (int)va_arg( args, int );
257
258             vlc_mutex_lock( &p_input->p->p_item->lock );
259             if( i_bkmk < p_input->p->i_bookmark )
260             {
261                 p_bkmk = p_input->p->pp_bookmark[i_bkmk];
262                 TAB_REMOVE( p_input->p->i_bookmark, p_input->p->pp_bookmark, p_bkmk );
263                 vlc_seekpoint_Delete( p_bkmk );
264
265                 vlc_mutex_unlock( &p_input->p->p_item->lock );
266
267                 UpdateBookmarksOption( p_input );
268
269                 return VLC_SUCCESS;
270             }
271             vlc_mutex_unlock( &p_input->p->p_item->lock );
272
273             return VLC_EGENERIC;
274
275         case INPUT_GET_BOOKMARKS:
276             ppp_bkmk = (seekpoint_t ***)va_arg( args, seekpoint_t *** );
277             pi_bkmk = (int *)va_arg( args, int * );
278
279             vlc_mutex_lock( &p_input->p->p_item->lock );
280             if( p_input->p->i_bookmark )
281             {
282                 int i;
283
284                 *pi_bkmk = p_input->p->i_bookmark;
285                 *ppp_bkmk = malloc( sizeof(seekpoint_t *) *
286                                     p_input->p->i_bookmark );
287                 for( i = 0; i < p_input->p->i_bookmark; i++ )
288                 {
289                     (*ppp_bkmk)[i] =
290                         vlc_seekpoint_Duplicate( p_input->p->pp_bookmark[i] );
291                 }
292
293                 vlc_mutex_unlock( &p_input->p->p_item->lock );
294                 return VLC_SUCCESS;
295             }
296             else
297             {
298                 *ppp_bkmk = NULL;
299                 *pi_bkmk = 0;
300
301                 vlc_mutex_unlock( &p_input->p->p_item->lock );
302                 return VLC_EGENERIC;
303             }
304             break;
305
306         case INPUT_CLEAR_BOOKMARKS:
307
308             vlc_mutex_lock( &p_input->p->p_item->lock );
309             while( p_input->p->i_bookmark > 0 )
310             {
311                 p_bkmk = p_input->p->pp_bookmark[p_input->p->i_bookmark-1];
312
313                 TAB_REMOVE( p_input->p->i_bookmark, p_input->p->pp_bookmark,
314                             p_bkmk );
315                 vlc_seekpoint_Delete( p_bkmk );
316             }
317             vlc_mutex_unlock( &p_input->p->p_item->lock );
318
319             UpdateBookmarksOption( p_input );
320             return VLC_SUCCESS;
321
322         case INPUT_SET_BOOKMARK:
323             i_bkmk = (int)va_arg( args, int );
324
325             val.i_int = i_bkmk;
326             input_ControlPush( p_input, INPUT_CONTROL_SET_BOOKMARK, &val );
327
328             return VLC_SUCCESS;
329
330         case INPUT_GET_BOOKMARK:
331             p_bkmk = (seekpoint_t *)va_arg( args, seekpoint_t * );
332
333             vlc_mutex_lock( &p_input->p->p_item->lock );
334             *p_bkmk = p_input->p->bookmark;
335             vlc_mutex_unlock( &p_input->p->p_item->lock );
336             return VLC_SUCCESS;
337
338         case INPUT_GET_TITLE_INFO:
339         {
340             input_title_t **p_title = (input_title_t **)va_arg( args, input_title_t ** );
341             int *pi_req_title_offset = (int *) va_arg( args, int * );
342
343             vlc_mutex_lock( &p_input->p->p_item->lock );
344
345             int i_current_title = var_GetInteger( p_input, "title" );
346             if ( *pi_req_title_offset < 0 ) /* return current title if -1 */
347                 *pi_req_title_offset = i_current_title;
348
349             if( p_input->p->i_title && p_input->p->i_title > *pi_req_title_offset )
350             {
351                 *p_title = vlc_input_title_Duplicate( p_input->p->title[*pi_req_title_offset] );
352                 vlc_mutex_unlock( &p_input->p->p_item->lock );
353                 return VLC_SUCCESS;
354             }
355             else
356             {
357                 vlc_mutex_unlock( &p_input->p->p_item->lock );
358                 return VLC_EGENERIC;
359             }
360         }
361
362         case INPUT_GET_VIDEO_FPS:
363             pf = (double*)va_arg( args, double * );
364
365             vlc_mutex_lock( &p_input->p->p_item->lock );
366             *pf = p_input->p->f_fps;
367             vlc_mutex_unlock( &p_input->p->p_item->lock );
368             return VLC_SUCCESS;
369
370         case INPUT_ADD_SLAVE:
371             psz = (char*)va_arg( args, char * );
372             if( psz && *psz )
373             {
374                 val.psz_string = strdup( psz );
375                 input_ControlPush( p_input, INPUT_CONTROL_ADD_SLAVE, &val );
376             }
377             return VLC_SUCCESS;
378
379         case INPUT_ADD_SUBTITLE:
380             psz = (char*)va_arg( args, char * );
381             b_bool = (bool)va_arg( args, int );
382
383             if( !psz || *psz == '\0' )
384                 return VLC_EGENERIC;
385             if( b_bool && !subtitles_Filter( psz ) )
386                 return VLC_EGENERIC;
387
388             val.psz_string = strdup( psz );
389             input_ControlPush( p_input, INPUT_CONTROL_ADD_SUBTITLE, &val );
390             return VLC_SUCCESS;
391
392         case INPUT_GET_ATTACHMENTS: /* arg1=input_attachment_t***, arg2=int*  res=can fail */
393         {
394             input_attachment_t ***ppp_attachment = (input_attachment_t***)va_arg( args, input_attachment_t *** );
395             int *pi_attachment = (int*)va_arg( args, int * );
396             int i;
397
398             vlc_mutex_lock( &p_input->p->p_item->lock );
399             if( p_input->p->i_attachment <= 0 )
400             {
401                 vlc_mutex_unlock( &p_input->p->p_item->lock );
402                 *ppp_attachment = NULL;
403                 *pi_attachment = 0;
404                 return VLC_EGENERIC;
405             }
406             *pi_attachment = p_input->p->i_attachment;
407             *ppp_attachment = malloc( sizeof(input_attachment_t*) * p_input->p->i_attachment );
408             for( i = 0; i < p_input->p->i_attachment; i++ )
409                 (*ppp_attachment)[i] = vlc_input_attachment_Duplicate( p_input->p->attachment[i] );
410
411             vlc_mutex_unlock( &p_input->p->p_item->lock );
412             return VLC_SUCCESS;
413         }
414
415         case INPUT_GET_ATTACHMENT:  /* arg1=input_attachment_t**, arg2=char*  res=can fail */
416         {
417             input_attachment_t **pp_attachment = (input_attachment_t**)va_arg( args, input_attachment_t ** );
418             const char *psz_name = (const char*)va_arg( args, const char * );
419             int i;
420
421             vlc_mutex_lock( &p_input->p->p_item->lock );
422             for( i = 0; i < p_input->p->i_attachment; i++ )
423             {
424                 if( !strcmp( p_input->p->attachment[i]->psz_name, psz_name ) )
425                 {
426                     *pp_attachment = vlc_input_attachment_Duplicate( p_input->p->attachment[i] );
427                     vlc_mutex_unlock( &p_input->p->p_item->lock );
428                     return VLC_SUCCESS;
429                 }
430             }
431             *pp_attachment = NULL;
432             vlc_mutex_unlock( &p_input->p->p_item->lock );
433             return VLC_EGENERIC;
434         }
435
436         case INPUT_SET_RECORD_STATE:
437             b_bool = (bool)va_arg( args, int );
438             var_SetBool( p_input, "record", b_bool );
439             return VLC_SUCCESS;
440
441         case INPUT_GET_RECORD_STATE:
442             pb_bool = (bool*)va_arg( args, bool* );
443             *pb_bool = var_GetBool( p_input, "record" );
444             return VLC_SUCCESS;
445
446         case INPUT_RESTART_ES:
447             val.i_int = (int)va_arg( args, int );
448             input_ControlPush( p_input, INPUT_CONTROL_RESTART_ES, &val );
449             return VLC_SUCCESS;
450
451         case INPUT_GET_AOUT:
452         {
453             audio_output_t *p_aout = input_resource_HoldAout( p_input->p->p_resource );
454             if( !p_aout )
455                 return VLC_EGENERIC;
456
457             audio_output_t **pp_aout = (audio_output_t**)va_arg( args, audio_output_t** );
458             *pp_aout = p_aout;
459             return VLC_SUCCESS;
460         }
461
462         case INPUT_GET_VOUTS:
463         {
464             vout_thread_t ***ppp_vout = (vout_thread_t***)va_arg( args, vout_thread_t*** );
465             size_t        *pi_vout = va_arg( args, size_t * );
466
467             input_resource_HoldVouts( p_input->p->p_resource, ppp_vout, pi_vout );
468             if( *pi_vout <= 0 )
469                 return VLC_EGENERIC;
470             return VLC_SUCCESS;
471         }
472
473         case INPUT_GET_ES_OBJECTS:
474         {
475             const int i_id = va_arg( args, int );
476             vlc_object_t    **pp_decoder = va_arg( args, vlc_object_t ** );
477             vout_thread_t   **pp_vout    = va_arg( args, vout_thread_t ** );
478             audio_output_t **pp_aout    = va_arg( args, audio_output_t ** );
479
480             return es_out_Control( p_input->p->p_es_out_display, ES_OUT_GET_ES_OBJECTS_BY_ID, i_id,
481                                    pp_decoder, pp_vout, pp_aout );
482         }
483
484         case INPUT_GET_PCR_SYSTEM:
485         {
486             mtime_t *pi_system = va_arg( args, mtime_t * );
487             mtime_t *pi_delay  = va_arg( args, mtime_t * );
488             return es_out_ControlGetPcrSystem( p_input->p->p_es_out_display, pi_system, pi_delay );
489         }
490
491         case INPUT_MODIFY_PCR_SYSTEM:
492         {
493             bool b_absolute = va_arg( args, int );
494             mtime_t i_system = va_arg( args, mtime_t );
495             return es_out_ControlModifyPcrSystem( p_input->p->p_es_out_display, b_absolute, i_system );
496         }
497
498         case INPUT_GET_ES_STATE:
499         {
500             int i_cat = (int)va_arg( args, int );
501             input_es_state_e *pi_state = (input_es_state_e *)va_arg( args, input_es_state_e* );
502
503             bool b_selected = false, b_error = false;
504             int ret = es_out_GetEsState( p_input->p->p_es_out_display, i_cat, &b_selected, &b_error);
505             if (ret != VLC_SUCCESS)
506             {
507                 *pi_state = INPUT_ES_STATE_DISABLED;
508                 return VLC_EGENERIC;
509             }
510
511             *pi_state = b_error ? INPUT_ES_STATE_ERROR :
512                                ( b_selected ? INPUT_ES_STATE_ENABLED : INPUT_ES_STATE_DISABLED );
513             return ret;
514         }
515
516         default:
517             msg_Err( p_input, "unknown query in input_vaControl" );
518             return VLC_EGENERIC;
519     }
520 }
521
522 static void UpdateBookmarksOption( input_thread_t *p_input )
523 {
524     vlc_mutex_lock( &p_input->p->p_item->lock );
525
526     /* Update the "bookmark" list */
527     var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
528     for( int i = 0; i < p_input->p->i_bookmark; i++ )
529     {
530         vlc_value_t val, text;
531
532         val.i_int = i;
533         text.psz_string = p_input->p->pp_bookmark[i]->psz_name;
534         var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
535                     &val, &text );
536     }
537
538     /* Create the "bookmarks" option value */
539     const char *psz_format = "{name=%s,bytes=%"PRId64",time=%"PRId64"}";
540     int i_len = strlen( "bookmarks=" );
541     for( int i = 0; i < p_input->p->i_bookmark; i++ )
542     {
543         const seekpoint_t *p_bookmark = p_input->p->pp_bookmark[i];
544
545         i_len += snprintf( NULL, 0, psz_format,
546                            p_bookmark->psz_name,
547                            p_bookmark->i_byte_offset,
548                            p_bookmark->i_time_offset/1000000 );
549     }
550
551     char *psz_value = malloc( i_len + p_input->p->i_bookmark + 1 );
552     char *psz_next = psz_value;
553
554     psz_next += sprintf( psz_next, "bookmarks=" );
555     for( int i = 0; i < p_input->p->i_bookmark && psz_value != NULL; i++ )
556     {
557         const seekpoint_t *p_bookmark = p_input->p->pp_bookmark[i];
558
559         psz_next += sprintf( psz_next, psz_format,
560                              p_bookmark->psz_name,
561                              p_bookmark->i_byte_offset,
562                              p_bookmark->i_time_offset/1000000 );
563
564         if( i < p_input->p->i_bookmark - 1)
565             *psz_next++ = ',';
566     }
567     vlc_mutex_unlock( &p_input->p->p_item->lock );
568
569     if( psz_value )
570         input_item_AddOption( p_input->p->p_item, psz_value, VLC_INPUT_OPTION_UNIQUE );
571
572     free( psz_value );
573
574     input_SendEventBookmark( p_input );
575 }