codec/esout: add support for CEA708
[vlc.git] / src / input / control.c
blob8d9ffc0b8a961495c3094dcdec34f29beca41087
1 /*****************************************************************************
2 * control.c
3 *****************************************************************************
4 * Copyright (C) 1999-2015 VLC authors and VideoLAN
5 * $Id$
7 * Authors: Gildas Bazin <gbazin@videolan.org>
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.
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.
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 *****************************************************************************/
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #include <vlc_common.h>
29 #include <vlc_memstream.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <assert.h>
35 #include "input_internal.h"
36 #include "event.h"
37 #include "resource.h"
38 #include "es_out.h"
41 static void UpdateBookmarksOption( input_thread_t * );
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
52 int input_Control( input_thread_t *p_input, int i_query, ... )
54 va_list args;
55 int i_result;
57 va_start( args, i_query );
58 i_result = input_vaControl( p_input, i_query, args );
59 va_end( args );
61 return i_result;
64 int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
66 input_thread_private_t *priv = input_priv(p_input);
67 seekpoint_t *p_bkmk, ***ppp_bkmk;
68 int i_bkmk = 0;
69 int *pi_bkmk;
71 int i_int, *pi_int;
72 bool b_bool, *pb_bool;
73 double f, *pf;
74 int64_t i_64, *pi_64;
76 char *psz;
77 vlc_value_t val;
79 switch( i_query )
81 case INPUT_GET_POSITION:
82 pf = va_arg( args, double * );
83 *pf = var_GetFloat( p_input, "position" );
84 return VLC_SUCCESS;
86 case INPUT_SET_POSITION:
87 f = va_arg( args, double );
88 return var_SetFloat( p_input, "position", f );
90 case INPUT_GET_LENGTH:
91 pi_64 = va_arg( args, int64_t * );
92 *pi_64 = var_GetInteger( p_input, "length" );
93 return VLC_SUCCESS;
95 case INPUT_GET_TIME:
96 pi_64 = va_arg( args, int64_t * );
97 *pi_64 = var_GetInteger( p_input, "time" );
98 return VLC_SUCCESS;
100 case INPUT_SET_TIME:
101 i_64 = va_arg( args, int64_t );
102 return var_SetInteger( p_input, "time", i_64 );
104 case INPUT_GET_RATE:
105 pi_int = va_arg( args, int * );
106 *pi_int = INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" );
107 return VLC_SUCCESS;
109 case INPUT_SET_RATE:
110 i_int = va_arg( args, int );
111 return var_SetFloat( p_input, "rate",
112 (float)INPUT_RATE_DEFAULT / (float)i_int );
114 case INPUT_GET_STATE:
115 pi_int = va_arg( args, int * );
116 *pi_int = var_GetInteger( p_input, "state" );
117 return VLC_SUCCESS;
119 case INPUT_SET_STATE:
120 i_int = va_arg( args, int );
121 return var_SetInteger( p_input, "state", i_int );
123 case INPUT_GET_AUDIO_DELAY:
124 pi_64 = va_arg( args, int64_t * );
125 *pi_64 = var_GetInteger( p_input, "audio-delay" );
126 return VLC_SUCCESS;
128 case INPUT_GET_SPU_DELAY:
129 pi_64 = va_arg( args, int64_t * );
130 *pi_64 = var_GetInteger( p_input, "spu-delay" );
131 return VLC_SUCCESS;
133 case INPUT_SET_AUDIO_DELAY:
134 i_64 = va_arg( args, int64_t );
135 return var_SetInteger( p_input, "audio-delay", i_64 );
137 case INPUT_SET_SPU_DELAY:
138 i_64 = va_arg( args, int64_t );
139 return var_SetInteger( p_input, "spu-delay", i_64 );
141 case INPUT_NAV_ACTIVATE:
142 case INPUT_NAV_UP:
143 case INPUT_NAV_DOWN:
144 case INPUT_NAV_LEFT:
145 case INPUT_NAV_RIGHT:
146 case INPUT_NAV_POPUP:
147 case INPUT_NAV_MENU:
148 input_ControlPush( p_input, i_query - INPUT_NAV_ACTIVATE
149 + INPUT_CONTROL_NAV_ACTIVATE, NULL );
150 return VLC_SUCCESS;
152 case INPUT_ADD_INFO:
154 char *psz_cat = va_arg( args, char * );
155 char *psz_name = va_arg( args, char * );
156 char *psz_format = va_arg( args, char * );
158 char *psz_value;
160 if( vasprintf( &psz_value, psz_format, args ) == -1 )
161 return VLC_EGENERIC;
163 int i_ret = input_item_AddInfo( priv->p_item, psz_cat, psz_name,
164 "%s", psz_value );
165 free( psz_value );
167 if( !priv->b_preparsing && !i_ret )
168 input_SendEventMetaInfo( p_input );
169 return i_ret;
171 case INPUT_REPLACE_INFOS:
172 case INPUT_MERGE_INFOS:
174 info_category_t *p_cat = va_arg( args, info_category_t * );
176 if( i_query == INPUT_REPLACE_INFOS )
177 input_item_ReplaceInfos( priv->p_item, p_cat );
178 else
179 input_item_MergeInfos( priv->p_item, p_cat );
181 if( !priv->b_preparsing )
182 input_SendEventMetaInfo( p_input );
183 return VLC_SUCCESS;
185 case INPUT_DEL_INFO:
187 char *psz_cat = va_arg( args, char * );
188 char *psz_name = va_arg( args, char * );
190 int i_ret = input_item_DelInfo( priv->p_item, psz_cat, psz_name );
192 if( !priv->b_preparsing && !i_ret )
193 input_SendEventMetaInfo( p_input );
194 return i_ret;
196 case INPUT_ADD_BOOKMARK:
197 p_bkmk = va_arg( args, seekpoint_t * );
198 p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
200 vlc_mutex_lock( &priv->p_item->lock );
201 if( !p_bkmk->psz_name )
203 if( asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
204 priv->i_bookmark ) == -1 )
205 p_bkmk->psz_name = NULL;
208 if( p_bkmk->psz_name )
209 TAB_APPEND( priv->i_bookmark, priv->pp_bookmark, p_bkmk );
210 else
212 vlc_seekpoint_Delete( p_bkmk );
213 p_bkmk = NULL;
215 vlc_mutex_unlock( &priv->p_item->lock );
217 UpdateBookmarksOption( p_input );
219 return p_bkmk ? VLC_SUCCESS : VLC_EGENERIC;
221 case INPUT_CHANGE_BOOKMARK:
222 p_bkmk = va_arg( args, seekpoint_t * );
223 i_bkmk = va_arg( args, int );
225 vlc_mutex_lock( &priv->p_item->lock );
226 if( i_bkmk < priv->i_bookmark )
228 p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
229 if( p_bkmk )
231 vlc_seekpoint_Delete( priv->pp_bookmark[i_bkmk] );
232 priv->pp_bookmark[i_bkmk] = p_bkmk;
235 else p_bkmk = NULL;
236 vlc_mutex_unlock( &priv->p_item->lock );
238 UpdateBookmarksOption( p_input );
240 return p_bkmk ? VLC_SUCCESS : VLC_EGENERIC;
242 case INPUT_DEL_BOOKMARK:
243 i_bkmk = va_arg( args, int );
245 vlc_mutex_lock( &priv->p_item->lock );
246 if( i_bkmk < priv->i_bookmark )
248 p_bkmk = priv->pp_bookmark[i_bkmk];
249 TAB_REMOVE( priv->i_bookmark, priv->pp_bookmark, p_bkmk );
250 vlc_seekpoint_Delete( p_bkmk );
252 vlc_mutex_unlock( &priv->p_item->lock );
254 UpdateBookmarksOption( p_input );
256 return VLC_SUCCESS;
258 vlc_mutex_unlock( &priv->p_item->lock );
260 return VLC_EGENERIC;
262 case INPUT_GET_BOOKMARKS:
263 ppp_bkmk = va_arg( args, seekpoint_t *** );
264 pi_bkmk = va_arg( args, int * );
266 vlc_mutex_lock( &priv->p_item->lock );
267 if( priv->i_bookmark )
269 int i;
271 *pi_bkmk = priv->i_bookmark;
272 *ppp_bkmk = malloc( sizeof(seekpoint_t *) * priv->i_bookmark );
273 for( i = 0; i < priv->i_bookmark; i++ )
275 (*ppp_bkmk)[i] =
276 vlc_seekpoint_Duplicate( input_priv(p_input)->pp_bookmark[i] );
279 vlc_mutex_unlock( &priv->p_item->lock );
280 return VLC_SUCCESS;
282 else
284 *ppp_bkmk = NULL;
285 *pi_bkmk = 0;
287 vlc_mutex_unlock( &priv->p_item->lock );
288 return VLC_EGENERIC;
290 break;
292 case INPUT_CLEAR_BOOKMARKS:
293 vlc_mutex_lock( &priv->p_item->lock );
294 for( int i = 0; i < priv->i_bookmark; ++i )
295 vlc_seekpoint_Delete( priv->pp_bookmark[i] );
297 TAB_CLEAN( priv->i_bookmark, priv->pp_bookmark );
298 vlc_mutex_unlock( &priv->p_item->lock );
300 UpdateBookmarksOption( p_input );
301 return VLC_SUCCESS;
303 case INPUT_SET_BOOKMARK:
304 i_bkmk = va_arg( args, int );
306 val.i_int = i_bkmk;
307 input_ControlPush( p_input, INPUT_CONTROL_SET_BOOKMARK, &val );
309 return VLC_SUCCESS;
311 case INPUT_GET_BOOKMARK:
312 p_bkmk = va_arg( args, seekpoint_t * );
314 vlc_mutex_lock( &priv->p_item->lock );
315 *p_bkmk = priv->bookmark;
316 vlc_mutex_unlock( &priv->p_item->lock );
317 return VLC_SUCCESS;
319 case INPUT_GET_TITLE_INFO:
321 input_title_t **p_title = va_arg( args, input_title_t ** );
322 int *pi_req_title_offset = va_arg( args, int * );
324 vlc_mutex_lock( &priv->p_item->lock );
326 int i_current_title = var_GetInteger( p_input, "title" );
327 if ( *pi_req_title_offset < 0 ) /* return current title if -1 */
328 *pi_req_title_offset = i_current_title;
330 if( priv->i_title && priv->i_title > *pi_req_title_offset )
332 *p_title = vlc_input_title_Duplicate( priv->title[*pi_req_title_offset] );
333 vlc_mutex_unlock( &priv->p_item->lock );
334 return VLC_SUCCESS;
336 else
338 vlc_mutex_unlock( &priv->p_item->lock );
339 return VLC_EGENERIC;
343 case INPUT_GET_FULL_TITLE_INFO:
345 vlc_mutex_lock( &priv->p_item->lock );
346 unsigned count = priv->i_title;
347 input_title_t **array = malloc( count * sizeof (*array) );
349 if( count > 0 && unlikely(array == NULL) )
351 vlc_mutex_unlock( &priv->p_item->lock );
352 return VLC_ENOMEM;
355 for( unsigned i = 0; i < count; i++ )
356 array[i] = vlc_input_title_Duplicate( priv->title[i] );
358 vlc_mutex_unlock( &priv->p_item->lock );
360 *va_arg( args, input_title_t *** ) = array;
361 *va_arg( args, int * ) = count;
362 return VLC_SUCCESS;
365 case INPUT_GET_SEEKPOINTS:
367 seekpoint_t ***array = va_arg( args, seekpoint_t *** );
368 int *pi_title_to_fetch = va_arg( args, int * );
370 vlc_mutex_lock( &priv->p_item->lock );
372 if ( *pi_title_to_fetch < 0 ) /* query current title if -1 */
373 *pi_title_to_fetch = var_GetInteger( p_input, "title" );
375 if( priv->i_title == 0 || priv->i_title <= *pi_title_to_fetch )
377 vlc_mutex_unlock( &priv->p_item->lock );
378 return VLC_EGENERIC;
381 const input_title_t *p_title = priv->title[*pi_title_to_fetch];
383 /* set arg2 to the number of seekpoints we found */
384 const int i_chapters = p_title->i_seekpoint;
385 *pi_title_to_fetch = i_chapters;
387 if ( i_chapters == 0 )
389 vlc_mutex_unlock( &priv->p_item->lock );
390 return VLC_SUCCESS;
393 *array = calloc( p_title->i_seekpoint, sizeof(**array) );
394 if( unlikely(array == NULL) )
396 vlc_mutex_unlock( &priv->p_item->lock );
397 return VLC_ENOMEM;
399 for( int i = 0; i < i_chapters; i++ )
401 (*array)[i] = vlc_seekpoint_Duplicate( p_title->seekpoint[i] );
404 vlc_mutex_unlock( &priv->p_item->lock );
406 return VLC_SUCCESS;
409 case INPUT_ADD_SLAVE:
411 enum slave_type type = (enum slave_type) va_arg( args, enum slave_type );
412 psz = va_arg( args, char * );
413 b_bool = va_arg( args, int );
414 bool b_notify = va_arg( args, int );
415 bool b_check_ext = va_arg( args, int );
417 if( !psz || ( type != SLAVE_TYPE_SPU && type != SLAVE_TYPE_AUDIO ) )
418 return VLC_EGENERIC;
419 if( b_check_ext && type == SLAVE_TYPE_SPU &&
420 !subtitles_Filter( psz ) )
421 return VLC_EGENERIC;
423 input_item_slave_t *p_slave =
424 input_item_slave_New( psz, type, SLAVE_PRIORITY_USER );
425 if( !p_slave )
426 return VLC_ENOMEM;
427 p_slave->b_forced = b_bool;
429 val.p_address = p_slave;
430 input_ControlPush( p_input, INPUT_CONTROL_ADD_SLAVE, &val );
431 if( b_notify )
433 vout_thread_t *p_vout = input_GetVout( p_input );
434 if( p_vout )
436 switch( type )
438 case SLAVE_TYPE_AUDIO:
439 vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s",
440 vlc_gettext("Audio track added"));
441 break;
442 case SLAVE_TYPE_SPU:
443 vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s",
444 vlc_gettext("Subtitle track added"));
445 break;
447 vlc_object_release( (vlc_object_t *)p_vout );
450 return VLC_SUCCESS;
453 case INPUT_GET_ATTACHMENTS: /* arg1=input_attachment_t***, arg2=int* res=can fail */
455 input_attachment_t ***ppp_attachment = va_arg( args, input_attachment_t *** );
456 int *pi_attachment = va_arg( args, int * );
458 vlc_mutex_lock( &priv->p_item->lock );
459 if( priv->i_attachment <= 0 )
461 vlc_mutex_unlock( &priv->p_item->lock );
462 *ppp_attachment = NULL;
463 *pi_attachment = 0;
464 return VLC_EGENERIC;
466 *pi_attachment = priv->i_attachment;
467 *ppp_attachment = malloc( sizeof(input_attachment_t*) * priv->i_attachment );
468 for( int i = 0; i < priv->i_attachment; i++ )
469 (*ppp_attachment)[i] = vlc_input_attachment_Duplicate( priv->attachment[i] );
471 vlc_mutex_unlock( &priv->p_item->lock );
472 return VLC_SUCCESS;
475 case INPUT_GET_ATTACHMENT: /* arg1=input_attachment_t**, arg2=char* res=can fail */
477 input_attachment_t **pp_attachment = va_arg( args, input_attachment_t ** );
478 const char *psz_name = va_arg( args, const char * );
480 vlc_mutex_lock( &priv->p_item->lock );
481 for( int i = 0; i < priv->i_attachment; i++ )
483 if( !strcmp( priv->attachment[i]->psz_name, psz_name ) )
485 *pp_attachment = vlc_input_attachment_Duplicate(priv->attachment[i] );
486 vlc_mutex_unlock( &priv->p_item->lock );
487 return VLC_SUCCESS;
490 *pp_attachment = NULL;
491 vlc_mutex_unlock( &priv->p_item->lock );
492 return VLC_EGENERIC;
495 case INPUT_SET_RECORD_STATE:
496 b_bool = va_arg( args, int );
497 var_SetBool( p_input, "record", b_bool );
498 return VLC_SUCCESS;
500 case INPUT_GET_RECORD_STATE:
501 pb_bool = va_arg( args, bool* );
502 *pb_bool = var_GetBool( p_input, "record" );
503 return VLC_SUCCESS;
505 case INPUT_RESTART_ES:
506 val.i_int = va_arg( args, int );
507 input_ControlPush( p_input, INPUT_CONTROL_RESTART_ES, &val );
508 return VLC_SUCCESS;
510 case INPUT_UPDATE_VIEWPOINT:
511 case INPUT_SET_INITIAL_VIEWPOINT:
513 vlc_viewpoint_t *p_viewpoint = malloc( sizeof(*p_viewpoint) );
514 if( unlikely(p_viewpoint == NULL) )
515 return VLC_ENOMEM;
516 val.p_address = p_viewpoint;
517 *p_viewpoint = *va_arg( args, const vlc_viewpoint_t* );
518 if ( i_query == INPUT_SET_INITIAL_VIEWPOINT )
519 input_ControlPush( p_input, INPUT_CONTROL_SET_INITIAL_VIEWPOINT,
520 &val );
521 else if ( va_arg( args, int ) )
522 input_ControlPush( p_input, INPUT_CONTROL_SET_VIEWPOINT, &val );
523 else
524 input_ControlPush( p_input, INPUT_CONTROL_UPDATE_VIEWPOINT, &val );
525 return VLC_SUCCESS;
528 case INPUT_GET_AOUT:
530 audio_output_t *p_aout = input_resource_HoldAout( priv->p_resource );
531 if( !p_aout )
532 return VLC_EGENERIC;
534 audio_output_t **pp_aout = va_arg( args, audio_output_t** );
535 *pp_aout = p_aout;
536 return VLC_SUCCESS;
539 case INPUT_GET_VOUTS:
541 vout_thread_t ***ppp_vout = va_arg( args, vout_thread_t*** );
542 size_t *pi_vout = va_arg( args, size_t * );
544 input_resource_HoldVouts( priv->p_resource, ppp_vout, pi_vout );
545 if( *pi_vout <= 0 )
546 return VLC_EGENERIC;
547 return VLC_SUCCESS;
550 case INPUT_GET_ES_OBJECTS:
552 const int i_id = va_arg( args, int );
553 vlc_object_t **pp_decoder = va_arg( args, vlc_object_t ** );
554 vout_thread_t **pp_vout = va_arg( args, vout_thread_t ** );
555 audio_output_t **pp_aout = va_arg( args, audio_output_t ** );
557 return es_out_Control( priv->p_es_out_display,
558 ES_OUT_GET_ES_OBJECTS_BY_ID, i_id,
559 pp_decoder, pp_vout, pp_aout );
562 case INPUT_GET_PCR_SYSTEM:
564 mtime_t *pi_system = va_arg( args, mtime_t * );
565 mtime_t *pi_delay = va_arg( args, mtime_t * );
566 return es_out_ControlGetPcrSystem( priv->p_es_out_display, pi_system, pi_delay );
569 case INPUT_MODIFY_PCR_SYSTEM:
571 bool b_absolute = va_arg( args, int );
572 mtime_t i_system = va_arg( args, mtime_t );
573 return es_out_ControlModifyPcrSystem( priv->p_es_out_display, b_absolute, i_system );
576 case INPUT_SET_RENDERER:
578 vlc_renderer_item_t* p_item = va_arg( args, vlc_renderer_item_t* );
579 val.p_address = p_item;
580 input_ControlPush( p_input, INPUT_CONTROL_SET_RENDERER, &val );
581 return VLC_SUCCESS;
584 default:
585 msg_Err( p_input, "unknown query 0x%x in %s", i_query, __func__ );
586 return VLC_EGENERIC;
590 static void UpdateBookmarksOption( input_thread_t *p_input )
592 input_thread_private_t *priv = input_priv(p_input);
593 struct vlc_memstream vstr;
595 vlc_memstream_open( &vstr );
596 vlc_memstream_puts( &vstr, "bookmarks=" );
598 vlc_mutex_lock( &priv->p_item->lock );
599 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES, 0, 0 );
601 for( int i = 0; i < priv->i_bookmark; i++ )
603 seekpoint_t const* sp = priv->pp_bookmark[i];
605 /* Add bookmark to choice-list */
606 var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
607 &(vlc_value_t){ .i_int = i },
608 &(vlc_value_t){ .psz_string = sp->psz_name } );
610 /* Append bookmark to option-buffer */
611 /* TODO: escape inappropriate values */
612 vlc_memstream_printf( &vstr, "%s{name=%s,time=%.3f}",
613 i > 0 ? "," : "", sp->psz_name, ( 1. * sp->i_time_offset ) / CLOCK_FREQ );
616 vlc_mutex_unlock( &priv->p_item->lock );
618 if( vlc_memstream_close( &vstr ) == VLC_SUCCESS )
620 bool b_overwritten = false;
622 for( int i = 0; i < priv->p_item->i_options; ++i )
624 char** ppsz_option = &priv->p_item->ppsz_options[i];
626 if( strncmp( *ppsz_option, "bookmarks=", 10 ) == 0 )
628 free( *ppsz_option );
629 *ppsz_option = vstr.ptr;
630 b_overwritten = true;
634 if( !b_overwritten )
636 input_item_AddOption( priv->p_item, vstr.ptr,
637 VLC_INPUT_OPTION_UNIQUE );
638 free( vstr.ptr );
642 input_SendEventBookmark( p_input );