input: add a new type input_control_param_t to extend control
[vlc.git] / src / input / control.c
blobd7505116fb39d32a64afef673c478a6e12f04c99
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>
30 #include <vlc_renderer_discovery.h>
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <assert.h>
36 #include "input_internal.h"
37 #include "event.h"
38 #include "resource.h"
39 #include "es_out.h"
42 static void UpdateBookmarksOption( input_thread_t * );
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_SUCCESS if ok
53 int input_Control( input_thread_t *p_input, int i_query, ... )
55 va_list args;
56 int i_result;
58 va_start( args, i_query );
59 i_result = input_vaControl( p_input, i_query, args );
60 va_end( args );
62 return i_result;
65 int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
67 input_thread_private_t *priv = input_priv(p_input);
68 seekpoint_t *p_bkmk, ***ppp_bkmk;
69 int i_bkmk = 0;
70 int *pi_bkmk;
72 int i_int, *pi_int;
73 bool b_bool, *pb_bool;
74 double f, *pf;
75 int64_t i_64, *pi_64;
77 char *psz;
78 vlc_value_t val;
80 switch( i_query )
82 case INPUT_GET_POSITION:
83 pf = va_arg( args, double * );
84 *pf = var_GetFloat( p_input, "position" );
85 return VLC_SUCCESS;
87 case INPUT_SET_POSITION:
88 f = va_arg( args, double );
89 return var_SetFloat( p_input, "position", f );
91 case INPUT_GET_LENGTH:
92 pi_64 = va_arg( args, int64_t * );
93 *pi_64 = var_GetInteger( p_input, "length" );
94 return VLC_SUCCESS;
96 case INPUT_GET_TIME:
97 pi_64 = va_arg( args, int64_t * );
98 *pi_64 = var_GetInteger( p_input, "time" );
99 return VLC_SUCCESS;
101 case INPUT_SET_TIME:
102 i_64 = va_arg( args, int64_t );
103 return var_SetInteger( p_input, "time", i_64 );
105 case INPUT_GET_RATE:
106 pi_int = va_arg( args, int * );
107 *pi_int = INPUT_RATE_DEFAULT / var_GetFloat( p_input, "rate" );
108 return VLC_SUCCESS;
110 case INPUT_SET_RATE:
111 i_int = va_arg( args, int );
112 return var_SetFloat( p_input, "rate",
113 (float)INPUT_RATE_DEFAULT / (float)i_int );
115 case INPUT_GET_STATE:
116 pi_int = va_arg( args, int * );
117 *pi_int = var_GetInteger( p_input, "state" );
118 return VLC_SUCCESS;
120 case INPUT_SET_STATE:
121 i_int = va_arg( args, int );
122 return var_SetInteger( p_input, "state", i_int );
124 case INPUT_GET_AUDIO_DELAY:
125 pi_64 = va_arg( args, int64_t * );
126 *pi_64 = var_GetInteger( p_input, "audio-delay" );
127 return VLC_SUCCESS;
129 case INPUT_GET_SPU_DELAY:
130 pi_64 = va_arg( args, int64_t * );
131 *pi_64 = var_GetInteger( p_input, "spu-delay" );
132 return VLC_SUCCESS;
134 case INPUT_SET_AUDIO_DELAY:
135 i_64 = va_arg( args, int64_t );
136 return var_SetInteger( p_input, "audio-delay", i_64 );
138 case INPUT_SET_SPU_DELAY:
139 i_64 = va_arg( args, int64_t );
140 return var_SetInteger( p_input, "spu-delay", i_64 );
142 case INPUT_NAV_ACTIVATE:
143 case INPUT_NAV_UP:
144 case INPUT_NAV_DOWN:
145 case INPUT_NAV_LEFT:
146 case INPUT_NAV_RIGHT:
147 case INPUT_NAV_POPUP:
148 case INPUT_NAV_MENU:
149 input_ControlPushHelper( p_input, i_query - INPUT_NAV_ACTIVATE
150 + INPUT_CONTROL_NAV_ACTIVATE, NULL );
151 return VLC_SUCCESS;
153 case INPUT_ADD_INFO:
155 char *psz_cat = va_arg( args, char * );
156 char *psz_name = va_arg( args, char * );
157 char *psz_format = va_arg( args, char * );
159 char *psz_value;
161 if( vasprintf( &psz_value, psz_format, args ) == -1 )
162 return VLC_EGENERIC;
164 int i_ret = input_item_AddInfo( priv->p_item, psz_cat, psz_name,
165 "%s", psz_value );
166 free( psz_value );
168 if( !priv->b_preparsing && !i_ret )
169 input_SendEventMetaInfo( p_input );
170 return i_ret;
172 case INPUT_REPLACE_INFOS:
173 case INPUT_MERGE_INFOS:
175 info_category_t *p_cat = va_arg( args, info_category_t * );
177 if( i_query == INPUT_REPLACE_INFOS )
178 input_item_ReplaceInfos( priv->p_item, p_cat );
179 else
180 input_item_MergeInfos( priv->p_item, p_cat );
182 if( !priv->b_preparsing )
183 input_SendEventMetaInfo( p_input );
184 return VLC_SUCCESS;
186 case INPUT_DEL_INFO:
188 char *psz_cat = va_arg( args, char * );
189 char *psz_name = va_arg( args, char * );
191 int i_ret = input_item_DelInfo( priv->p_item, psz_cat, psz_name );
193 if( !priv->b_preparsing && !i_ret )
194 input_SendEventMetaInfo( p_input );
195 return i_ret;
197 case INPUT_ADD_BOOKMARK:
198 p_bkmk = va_arg( args, seekpoint_t * );
199 p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
201 vlc_mutex_lock( &priv->p_item->lock );
202 if( !p_bkmk->psz_name )
204 if( asprintf( &p_bkmk->psz_name, _("Bookmark %i"),
205 priv->i_bookmark ) == -1 )
206 p_bkmk->psz_name = NULL;
209 if( p_bkmk->psz_name )
210 TAB_APPEND( priv->i_bookmark, priv->pp_bookmark, p_bkmk );
211 else
213 vlc_seekpoint_Delete( p_bkmk );
214 p_bkmk = NULL;
216 vlc_mutex_unlock( &priv->p_item->lock );
218 UpdateBookmarksOption( p_input );
220 return p_bkmk ? VLC_SUCCESS : VLC_EGENERIC;
222 case INPUT_CHANGE_BOOKMARK:
223 p_bkmk = va_arg( args, seekpoint_t * );
224 i_bkmk = va_arg( args, int );
226 vlc_mutex_lock( &priv->p_item->lock );
227 if( i_bkmk < priv->i_bookmark )
229 p_bkmk = vlc_seekpoint_Duplicate( p_bkmk );
230 if( p_bkmk )
232 vlc_seekpoint_Delete( priv->pp_bookmark[i_bkmk] );
233 priv->pp_bookmark[i_bkmk] = p_bkmk;
236 else p_bkmk = NULL;
237 vlc_mutex_unlock( &priv->p_item->lock );
239 UpdateBookmarksOption( p_input );
241 return p_bkmk ? VLC_SUCCESS : VLC_EGENERIC;
243 case INPUT_DEL_BOOKMARK:
244 i_bkmk = va_arg( args, int );
246 vlc_mutex_lock( &priv->p_item->lock );
247 if( i_bkmk < priv->i_bookmark )
249 p_bkmk = priv->pp_bookmark[i_bkmk];
250 TAB_REMOVE( priv->i_bookmark, priv->pp_bookmark, p_bkmk );
251 vlc_seekpoint_Delete( p_bkmk );
253 vlc_mutex_unlock( &priv->p_item->lock );
255 UpdateBookmarksOption( p_input );
257 return VLC_SUCCESS;
259 vlc_mutex_unlock( &priv->p_item->lock );
261 return VLC_EGENERIC;
263 case INPUT_GET_BOOKMARKS:
264 ppp_bkmk = va_arg( args, seekpoint_t *** );
265 pi_bkmk = va_arg( args, int * );
267 vlc_mutex_lock( &priv->p_item->lock );
268 if( priv->i_bookmark )
270 int i;
272 *pi_bkmk = priv->i_bookmark;
273 *ppp_bkmk = vlc_alloc( priv->i_bookmark, sizeof(seekpoint_t *) );
274 for( i = 0; i < priv->i_bookmark; i++ )
276 (*ppp_bkmk)[i] =
277 vlc_seekpoint_Duplicate( input_priv(p_input)->pp_bookmark[i] );
280 vlc_mutex_unlock( &priv->p_item->lock );
281 return VLC_SUCCESS;
283 else
285 *ppp_bkmk = NULL;
286 *pi_bkmk = 0;
288 vlc_mutex_unlock( &priv->p_item->lock );
289 return VLC_EGENERIC;
291 break;
293 case INPUT_CLEAR_BOOKMARKS:
294 vlc_mutex_lock( &priv->p_item->lock );
295 for( int i = 0; i < priv->i_bookmark; ++i )
296 vlc_seekpoint_Delete( priv->pp_bookmark[i] );
298 TAB_CLEAN( priv->i_bookmark, priv->pp_bookmark );
299 vlc_mutex_unlock( &priv->p_item->lock );
301 UpdateBookmarksOption( p_input );
302 return VLC_SUCCESS;
304 case INPUT_SET_BOOKMARK:
305 i_bkmk = va_arg( args, int );
307 val.i_int = i_bkmk;
308 input_ControlPushHelper( p_input, INPUT_CONTROL_SET_BOOKMARK, &val );
310 return VLC_SUCCESS;
312 case INPUT_GET_BOOKMARK:
313 p_bkmk = va_arg( args, seekpoint_t * );
315 vlc_mutex_lock( &priv->p_item->lock );
316 *p_bkmk = priv->bookmark;
317 vlc_mutex_unlock( &priv->p_item->lock );
318 return VLC_SUCCESS;
320 case INPUT_GET_TITLE_INFO:
322 input_title_t **p_title = va_arg( args, input_title_t ** );
323 int *pi_req_title_offset = va_arg( args, int * );
325 vlc_mutex_lock( &priv->p_item->lock );
327 int i_current_title = var_GetInteger( p_input, "title" );
328 if ( *pi_req_title_offset < 0 ) /* return current title if -1 */
329 *pi_req_title_offset = i_current_title;
331 if( priv->i_title && priv->i_title > *pi_req_title_offset )
333 *p_title = vlc_input_title_Duplicate( priv->title[*pi_req_title_offset] );
334 vlc_mutex_unlock( &priv->p_item->lock );
335 return VLC_SUCCESS;
337 else
339 vlc_mutex_unlock( &priv->p_item->lock );
340 return VLC_EGENERIC;
344 case INPUT_GET_FULL_TITLE_INFO:
346 vlc_mutex_lock( &priv->p_item->lock );
347 unsigned count = priv->i_title;
348 input_title_t **array = vlc_alloc( count, sizeof (*array) );
350 if( count > 0 && unlikely(array == NULL) )
352 vlc_mutex_unlock( &priv->p_item->lock );
353 return VLC_ENOMEM;
356 for( unsigned i = 0; i < count; i++ )
357 array[i] = vlc_input_title_Duplicate( priv->title[i] );
359 vlc_mutex_unlock( &priv->p_item->lock );
361 *va_arg( args, input_title_t *** ) = array;
362 *va_arg( args, int * ) = count;
363 return VLC_SUCCESS;
366 case INPUT_GET_SEEKPOINTS:
368 seekpoint_t ***array = va_arg( args, seekpoint_t *** );
369 int *pi_title_to_fetch = va_arg( args, int * );
371 vlc_mutex_lock( &priv->p_item->lock );
373 if ( *pi_title_to_fetch < 0 ) /* query current title if -1 */
374 *pi_title_to_fetch = var_GetInteger( p_input, "title" );
376 if( priv->i_title == 0 || priv->i_title <= *pi_title_to_fetch )
378 vlc_mutex_unlock( &priv->p_item->lock );
379 return VLC_EGENERIC;
382 const input_title_t *p_title = priv->title[*pi_title_to_fetch];
384 /* set arg2 to the number of seekpoints we found */
385 const int i_chapters = p_title->i_seekpoint;
386 *pi_title_to_fetch = i_chapters;
388 if ( i_chapters == 0 )
390 vlc_mutex_unlock( &priv->p_item->lock );
391 return VLC_SUCCESS;
394 *array = calloc( p_title->i_seekpoint, sizeof(**array) );
395 if( unlikely(*array == NULL) )
397 vlc_mutex_unlock( &priv->p_item->lock );
398 return VLC_ENOMEM;
400 for( int i = 0; i < i_chapters; i++ )
402 (*array)[i] = vlc_seekpoint_Duplicate( p_title->seekpoint[i] );
405 vlc_mutex_unlock( &priv->p_item->lock );
407 return VLC_SUCCESS;
410 case INPUT_ADD_SLAVE:
412 enum slave_type type = (enum slave_type) va_arg( args, enum slave_type );
413 psz = va_arg( args, char * );
414 b_bool = va_arg( args, int );
415 bool b_notify = va_arg( args, int );
416 bool b_check_ext = va_arg( args, int );
418 if( !psz || ( type != SLAVE_TYPE_SPU && type != SLAVE_TYPE_AUDIO ) )
419 return VLC_EGENERIC;
420 if( b_check_ext && type == SLAVE_TYPE_SPU &&
421 !subtitles_Filter( psz ) )
422 return VLC_EGENERIC;
424 input_item_slave_t *p_slave =
425 input_item_slave_New( psz, type, SLAVE_PRIORITY_USER );
426 if( !p_slave )
427 return VLC_ENOMEM;
428 p_slave->b_forced = b_bool;
430 val.p_address = p_slave;
431 input_ControlPushHelper( p_input, INPUT_CONTROL_ADD_SLAVE, &val );
432 if( b_notify )
434 vout_thread_t *p_vout = input_GetVout( p_input );
435 if( p_vout )
437 switch( type )
439 case SLAVE_TYPE_AUDIO:
440 vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s",
441 vlc_gettext("Audio track added"));
442 break;
443 case SLAVE_TYPE_SPU:
444 vout_OSDMessage(p_vout, VOUT_SPU_CHANNEL_OSD, "%s",
445 vlc_gettext("Subtitle track added"));
446 break;
448 vlc_object_release( (vlc_object_t *)p_vout );
451 return VLC_SUCCESS;
454 case INPUT_GET_ATTACHMENTS: /* arg1=input_attachment_t***, arg2=int* res=can fail */
456 input_attachment_t ***ppp_attachment = va_arg( args, input_attachment_t *** );
457 int *pi_attachment = va_arg( args, int * );
459 vlc_mutex_lock( &priv->p_item->lock );
460 if( priv->i_attachment <= 0 )
462 vlc_mutex_unlock( &priv->p_item->lock );
463 *ppp_attachment = NULL;
464 *pi_attachment = 0;
465 return VLC_EGENERIC;
467 *pi_attachment = priv->i_attachment;
468 *ppp_attachment = vlc_alloc( priv->i_attachment, sizeof(input_attachment_t*));
469 for( int i = 0; i < priv->i_attachment; i++ )
470 (*ppp_attachment)[i] = vlc_input_attachment_Duplicate( priv->attachment[i] );
472 vlc_mutex_unlock( &priv->p_item->lock );
473 return VLC_SUCCESS;
476 case INPUT_GET_ATTACHMENT: /* arg1=input_attachment_t**, arg2=char* res=can fail */
478 input_attachment_t **pp_attachment = va_arg( args, input_attachment_t ** );
479 const char *psz_name = va_arg( args, const char * );
481 vlc_mutex_lock( &priv->p_item->lock );
482 for( int i = 0; i < priv->i_attachment; i++ )
484 if( !strcmp( priv->attachment[i]->psz_name, psz_name ) )
486 *pp_attachment = vlc_input_attachment_Duplicate(priv->attachment[i] );
487 vlc_mutex_unlock( &priv->p_item->lock );
488 return VLC_SUCCESS;
491 *pp_attachment = NULL;
492 vlc_mutex_unlock( &priv->p_item->lock );
493 return VLC_EGENERIC;
496 case INPUT_SET_RECORD_STATE:
497 b_bool = va_arg( args, int );
498 var_SetBool( p_input, "record", b_bool );
499 return VLC_SUCCESS;
501 case INPUT_GET_RECORD_STATE:
502 pb_bool = va_arg( args, bool* );
503 *pb_bool = var_GetBool( p_input, "record" );
504 return VLC_SUCCESS;
506 case INPUT_RESTART_ES:
507 val.i_int = va_arg( args, int );
508 input_ControlPushHelper( p_input, INPUT_CONTROL_RESTART_ES, &val );
509 return VLC_SUCCESS;
511 case INPUT_UPDATE_VIEWPOINT:
512 case INPUT_SET_INITIAL_VIEWPOINT:
514 input_control_param_t param;
515 param.viewpoint = *va_arg( args, const vlc_viewpoint_t* );
516 if ( i_query == INPUT_SET_INITIAL_VIEWPOINT )
517 input_ControlPush( p_input, INPUT_CONTROL_SET_INITIAL_VIEWPOINT,
518 &param );
519 else if ( va_arg( args, int ) )
520 input_ControlPush( p_input, INPUT_CONTROL_SET_VIEWPOINT, &param);
521 else
522 input_ControlPush( p_input, INPUT_CONTROL_UPDATE_VIEWPOINT, &param );
523 return VLC_SUCCESS;
526 case INPUT_GET_AOUT:
528 audio_output_t *p_aout = input_resource_HoldAout( priv->p_resource );
529 if( !p_aout )
530 return VLC_EGENERIC;
532 audio_output_t **pp_aout = va_arg( args, audio_output_t** );
533 *pp_aout = p_aout;
534 return VLC_SUCCESS;
537 case INPUT_GET_VOUTS:
539 vout_thread_t ***ppp_vout = va_arg( args, vout_thread_t*** );
540 size_t *pi_vout = va_arg( args, size_t * );
542 input_resource_HoldVouts( priv->p_resource, ppp_vout, pi_vout );
543 if( *pi_vout == 0 )
544 return VLC_EGENERIC;
545 return VLC_SUCCESS;
548 case INPUT_GET_ES_OBJECTS:
550 const int i_id = va_arg( args, int );
551 vlc_object_t **pp_decoder = va_arg( args, vlc_object_t ** );
552 vout_thread_t **pp_vout = va_arg( args, vout_thread_t ** );
553 audio_output_t **pp_aout = va_arg( args, audio_output_t ** );
555 return es_out_Control( priv->p_es_out_display,
556 ES_OUT_GET_ES_OBJECTS_BY_ID, i_id,
557 pp_decoder, pp_vout, pp_aout );
560 case INPUT_GET_PCR_SYSTEM:
562 vlc_tick_t *pi_system = va_arg( args, vlc_tick_t * );
563 vlc_tick_t *pi_delay = va_arg( args, vlc_tick_t * );
564 return es_out_ControlGetPcrSystem( priv->p_es_out_display, pi_system, pi_delay );
567 case INPUT_MODIFY_PCR_SYSTEM:
569 bool b_absolute = va_arg( args, int );
570 vlc_tick_t i_system = va_arg( args, vlc_tick_t );
571 return es_out_ControlModifyPcrSystem( priv->p_es_out_display, b_absolute, i_system );
574 case INPUT_SET_RENDERER:
576 vlc_renderer_item_t* p_item = va_arg( args, vlc_renderer_item_t* );
577 val.p_address = p_item ? vlc_renderer_item_hold( p_item ) : NULL;
578 input_ControlPushHelper( p_input, INPUT_CONTROL_SET_RENDERER, &val );
579 return VLC_SUCCESS;
582 default:
583 msg_Err( p_input, "unknown query 0x%x in %s", i_query, __func__ );
584 return VLC_EGENERIC;
588 static void UpdateBookmarksOption( input_thread_t *p_input )
590 input_thread_private_t *priv = input_priv(p_input);
591 struct vlc_memstream vstr;
593 vlc_memstream_open( &vstr );
594 vlc_memstream_puts( &vstr, "bookmarks=" );
596 vlc_mutex_lock( &priv->p_item->lock );
597 var_Change( p_input, "bookmark", VLC_VAR_CLEARCHOICES );
599 for( int i = 0; i < priv->i_bookmark; i++ )
601 seekpoint_t const* sp = priv->pp_bookmark[i];
603 /* Add bookmark to choice-list */
604 var_Change( p_input, "bookmark", VLC_VAR_ADDCHOICE,
605 (vlc_value_t){ .i_int = i }, sp->psz_name );
607 /* Append bookmark to option-buffer */
608 /* TODO: escape inappropriate values */
609 vlc_memstream_printf( &vstr, "%s{name=%s,time=%.3f}",
610 i > 0 ? "," : "", sp->psz_name, ( 1. * sp->i_time_offset ) / CLOCK_FREQ );
613 vlc_mutex_unlock( &priv->p_item->lock );
615 if( vlc_memstream_close( &vstr ) == VLC_SUCCESS )
617 bool b_overwritten = false;
619 for( int i = 0; i < priv->p_item->i_options; ++i )
621 char** ppsz_option = &priv->p_item->ppsz_options[i];
623 if( strncmp( *ppsz_option, "bookmarks=", 10 ) == 0 )
625 free( *ppsz_option );
626 *ppsz_option = vstr.ptr;
627 b_overwritten = true;
631 if( !b_overwritten )
633 input_item_AddOption( priv->p_item, vstr.ptr,
634 VLC_INPUT_OPTION_UNIQUE );
635 free( vstr.ptr );
639 input_SendEventBookmark( p_input );