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>
35 #include "input_internal.h"
41 static void UpdateBookmarksOption( input_thread_t
* );
43 /****************************************************************************
45 ****************************************************************************/
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
, ... )
57 va_start( args
, i_query
);
58 i_result
= input_vaControl( p_input
, i_query
, args
);
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
;
72 bool b_bool
, *pb_bool
;
81 case INPUT_GET_POSITION
:
82 pf
= va_arg( args
, double * );
83 *pf
= var_GetFloat( p_input
, "position" );
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" );
96 pi_64
= va_arg( args
, int64_t * );
97 *pi_64
= var_GetInteger( p_input
, "time" );
101 i_64
= va_arg( args
, int64_t );
102 return var_SetInteger( p_input
, "time", i_64
);
105 pi_int
= va_arg( args
, int * );
106 *pi_int
= INPUT_RATE_DEFAULT
/ var_GetFloat( p_input
, "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" );
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" );
128 case INPUT_GET_SPU_DELAY
:
129 pi_64
= va_arg( args
, int64_t * );
130 *pi_64
= var_GetInteger( p_input
, "spu-delay" );
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
:
145 case INPUT_NAV_RIGHT
:
146 case INPUT_NAV_POPUP
:
148 input_ControlPush( p_input
, i_query
- INPUT_NAV_ACTIVATE
149 + INPUT_CONTROL_NAV_ACTIVATE
, NULL
);
154 char *psz_cat
= va_arg( args
, char * );
155 char *psz_name
= va_arg( args
, char * );
156 char *psz_format
= va_arg( args
, char * );
160 if( vasprintf( &psz_value
, psz_format
, args
) == -1 )
163 int i_ret
= input_item_AddInfo( priv
->p_item
, psz_cat
, psz_name
,
167 if( !priv
->b_preparsing
&& !i_ret
)
168 input_SendEventMetaInfo( p_input
);
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
);
179 input_item_MergeInfos( priv
->p_item
, p_cat
);
181 if( !priv
->b_preparsing
)
182 input_SendEventMetaInfo( p_input
);
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
);
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
);
212 vlc_seekpoint_Delete( p_bkmk
);
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
);
231 vlc_seekpoint_Delete( priv
->pp_bookmark
[i_bkmk
] );
232 priv
->pp_bookmark
[i_bkmk
] = p_bkmk
;
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
);
258 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
)
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
++ )
276 vlc_seekpoint_Duplicate( input_priv(p_input
)->pp_bookmark
[i
] );
279 vlc_mutex_unlock( &priv
->p_item
->lock
);
287 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
);
303 case INPUT_SET_BOOKMARK
:
304 i_bkmk
= va_arg( args
, int );
307 input_ControlPush( p_input
, INPUT_CONTROL_SET_BOOKMARK
, &val
);
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
);
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
);
338 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
);
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
;
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
);
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
);
393 *array
= calloc( p_title
->i_seekpoint
, sizeof(**array
) );
394 if( unlikely(array
== NULL
) )
396 vlc_mutex_unlock( &priv
->p_item
->lock
);
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
);
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
) )
419 if( b_check_ext
&& type
== SLAVE_TYPE_SPU
&&
420 !subtitles_Filter( psz
) )
423 input_item_slave_t
*p_slave
=
424 input_item_slave_New( psz
, type
, SLAVE_PRIORITY_USER
);
427 p_slave
->b_forced
= b_bool
;
429 val
.p_address
= p_slave
;
430 input_ControlPush( p_input
, INPUT_CONTROL_ADD_SLAVE
, &val
);
433 vout_thread_t
*p_vout
= input_GetVout( p_input
);
438 case SLAVE_TYPE_AUDIO
:
439 vout_OSDMessage(p_vout
, VOUT_SPU_CHANNEL_OSD
, "%s",
440 vlc_gettext("Audio track added"));
443 vout_OSDMessage(p_vout
, VOUT_SPU_CHANNEL_OSD
, "%s",
444 vlc_gettext("Subtitle track added"));
447 vlc_object_release( (vlc_object_t
*)p_vout
);
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
;
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
);
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
);
490 *pp_attachment
= NULL
;
491 vlc_mutex_unlock( &priv
->p_item
->lock
);
495 case INPUT_SET_RECORD_STATE
:
496 b_bool
= va_arg( args
, int );
497 var_SetBool( p_input
, "record", b_bool
);
500 case INPUT_GET_RECORD_STATE
:
501 pb_bool
= va_arg( args
, bool* );
502 *pb_bool
= var_GetBool( p_input
, "record" );
505 case INPUT_RESTART_ES
:
506 val
.i_int
= va_arg( args
, int );
507 input_ControlPush( p_input
, INPUT_CONTROL_RESTART_ES
, &val
);
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
) )
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
,
521 else if ( va_arg( args
, int ) )
522 input_ControlPush( p_input
, INPUT_CONTROL_SET_VIEWPOINT
, &val
);
524 input_ControlPush( p_input
, INPUT_CONTROL_UPDATE_VIEWPOINT
, &val
);
530 audio_output_t
*p_aout
= input_resource_HoldAout( priv
->p_resource
);
534 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
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
);
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
);
585 msg_Err( p_input
, "unknown query 0x%x in %s", i_query
, __func__
);
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;
636 input_item_AddOption( priv
->p_item
, vstr
.ptr
,
637 VLC_INPUT_OPTION_UNIQUE
);
642 input_SendEventBookmark( p_input
);