1 /*****************************************************************************
3 *****************************************************************************
4 * Copyright (C) 1999-2015 VLC authors and VideoLAN
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 *****************************************************************************/
28 #include <vlc_common.h>
29 #include <vlc_memstream.h>
30 #include <vlc_renderer_discovery.h>
36 #include "input_internal.h"
42 static void UpdateBookmarksOption( input_thread_t
* );
44 /****************************************************************************
46 ****************************************************************************/
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
, ... )
58 va_start( args
, i_query
);
59 i_result
= input_vaControl( p_input
, i_query
, args
);
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
;
73 bool b_bool
, *pb_bool
;
82 case INPUT_GET_POSITION
:
83 pf
= va_arg( args
, double * );
84 *pf
= var_GetFloat( p_input
, "position" );
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" );
97 pi_64
= va_arg( args
, int64_t * );
98 *pi_64
= var_GetInteger( p_input
, "time" );
102 i_64
= va_arg( args
, int64_t );
103 return var_SetInteger( p_input
, "time", i_64
);
106 pi_int
= va_arg( args
, int * );
107 *pi_int
= INPUT_RATE_DEFAULT
/ var_GetFloat( p_input
, "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" );
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" );
129 case INPUT_GET_SPU_DELAY
:
130 pi_64
= va_arg( args
, int64_t * );
131 *pi_64
= var_GetInteger( p_input
, "spu-delay" );
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
:
146 case INPUT_NAV_RIGHT
:
147 case INPUT_NAV_POPUP
:
149 input_ControlPushHelper( p_input
, i_query
- INPUT_NAV_ACTIVATE
150 + INPUT_CONTROL_NAV_ACTIVATE
, NULL
);
155 char *psz_cat
= va_arg( args
, char * );
156 char *psz_name
= va_arg( args
, char * );
157 char *psz_format
= va_arg( args
, char * );
161 if( vasprintf( &psz_value
, psz_format
, args
) == -1 )
164 int i_ret
= input_item_AddInfo( priv
->p_item
, psz_cat
, psz_name
,
168 if( !priv
->b_preparsing
&& !i_ret
)
169 input_SendEventMetaInfo( p_input
);
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
);
180 input_item_MergeInfos( priv
->p_item
, p_cat
);
182 if( !priv
->b_preparsing
)
183 input_SendEventMetaInfo( p_input
);
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
);
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
);
213 vlc_seekpoint_Delete( p_bkmk
);
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
);
232 vlc_seekpoint_Delete( priv
->pp_bookmark
[i_bkmk
] );
233 priv
->pp_bookmark
[i_bkmk
] = p_bkmk
;
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
);
259 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
)
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
++ )
277 vlc_seekpoint_Duplicate( input_priv(p_input
)->pp_bookmark
[i
] );
280 vlc_mutex_unlock( &priv
->p_item
->lock
);
288 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
);
304 case INPUT_SET_BOOKMARK
:
305 i_bkmk
= va_arg( args
, int );
308 input_ControlPushHelper( p_input
, INPUT_CONTROL_SET_BOOKMARK
, &val
);
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
);
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
);
339 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
);
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
;
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
);
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
);
394 *array
= calloc( p_title
->i_seekpoint
, sizeof(**array
) );
395 if( unlikely(*array
== NULL
) )
397 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
);
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
) )
420 if( b_check_ext
&& type
== SLAVE_TYPE_SPU
&&
421 !subtitles_Filter( psz
) )
424 input_item_slave_t
*p_slave
=
425 input_item_slave_New( psz
, type
, SLAVE_PRIORITY_USER
);
428 p_slave
->b_forced
= b_bool
;
430 val
.p_address
= p_slave
;
431 input_ControlPushHelper( p_input
, INPUT_CONTROL_ADD_SLAVE
, &val
);
434 vout_thread_t
*p_vout
= input_GetVout( p_input
);
439 case SLAVE_TYPE_AUDIO
:
440 vout_OSDMessage(p_vout
, VOUT_SPU_CHANNEL_OSD
, "%s",
441 vlc_gettext("Audio track added"));
444 vout_OSDMessage(p_vout
, VOUT_SPU_CHANNEL_OSD
, "%s",
445 vlc_gettext("Subtitle track added"));
448 vlc_object_release( (vlc_object_t
*)p_vout
);
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
;
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
);
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
);
491 *pp_attachment
= NULL
;
492 vlc_mutex_unlock( &priv
->p_item
->lock
);
496 case INPUT_SET_RECORD_STATE
:
497 b_bool
= va_arg( args
, int );
498 var_SetBool( p_input
, "record", b_bool
);
501 case INPUT_GET_RECORD_STATE
:
502 pb_bool
= va_arg( args
, bool* );
503 *pb_bool
= var_GetBool( p_input
, "record" );
506 case INPUT_RESTART_ES
:
507 val
.i_int
= va_arg( args
, int );
508 input_ControlPushHelper( p_input
, INPUT_CONTROL_RESTART_ES
, &val
);
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
,
519 else if ( va_arg( args
, int ) )
520 input_ControlPush( p_input
, INPUT_CONTROL_SET_VIEWPOINT
, ¶m
);
522 input_ControlPush( p_input
, INPUT_CONTROL_UPDATE_VIEWPOINT
, ¶m
);
528 audio_output_t
*p_aout
= input_resource_HoldAout( priv
->p_resource
);
532 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
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
);
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
);
583 msg_Err( p_input
, "unknown query 0x%x in %s", i_query
, __func__
);
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;
633 input_item_AddOption( priv
->p_item
, vstr
.ptr
,
634 VLC_INPUT_OPTION_UNIQUE
);
639 input_SendEventBookmark( p_input
);