1 /*****************************************************************************
2 * input.c: input thread
3 *****************************************************************************
4 * Copyright (C) 1998-2007 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Laurent Aimar <fenrir@via.ecp.fr>
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 /*****************************************************************************
26 *****************************************************************************/
31 #include <vlc_common.h>
32 #include <vlc_decoder.h>
38 #include "input_internal.h"
48 #include <vlc_dialog.h>
50 #include <vlc_charset.h>
52 #include <vlc_strings.h>
53 #include <vlc_modules.h>
54 #include <vlc_stream.h>
55 #include <vlc_stream_extractor.h>
56 #include <vlc_renderer_discovery.h>
59 /*****************************************************************************
61 *****************************************************************************/
62 enum input_create_option
{
63 INPUT_CREATE_OPTION_NONE
,
64 INPUT_CREATE_OPTION_PREPARSING
,
65 INPUT_CREATE_OPTION_THUMBNAILING
,
68 static void *Run( void * );
69 static void *Preparse( void * );
71 static input_thread_t
* Create ( vlc_object_t
*, input_thread_events_cb
, void *,
72 input_item_t
*, enum input_create_option option
,
73 input_resource_t
*, vlc_renderer_item_t
* );
74 static void Destroy ( input_thread_t
*p_input
);
75 static int Init ( input_thread_t
*p_input
);
76 static void End ( input_thread_t
*p_input
);
77 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
);
79 static inline int ControlPop( input_thread_t
*, int *, input_control_param_t
*, vlc_tick_t i_deadline
, bool b_postpone_seek
);
80 static void ControlRelease( int i_type
, const input_control_param_t
*p_param
);
81 static bool ControlIsSeekRequest( int i_type
);
82 static bool Control( input_thread_t
*, int, input_control_param_t
);
83 static void ControlPause( input_thread_t
*, vlc_tick_t
);
85 static int UpdateTitleSeekpointFromDemux( input_thread_t
* );
86 static void UpdateGenericFromDemux( input_thread_t
* );
87 static void UpdateTitleListfromDemux( input_thread_t
* );
89 static void MRLSections( const char *, int *, int *, int *, int *);
91 static input_source_t
*InputSourceNew( const char *psz_mrl
);
92 static int InputSourceInit( input_source_t
*in
, input_thread_t
*p_input
,
94 const char *psz_forced_demux
, bool b_in_can_fail
);
95 static void InputSourceDestroy( input_source_t
* );
96 static void InputSourceMeta( input_thread_t
*, input_source_t
*, vlc_meta_t
* );
99 //static void InputGetAttachments( input_thread_t *, input_source_t * );
100 static void SlaveDemux( input_thread_t
*p_input
);
101 static void SlaveSeek( input_thread_t
*p_input
);
103 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
104 static void InputUpdateMeta( input_thread_t
*p_input
, demux_t
*p_demux
);
105 static void InputGetExtraFiles( input_thread_t
*p_input
,
106 int *pi_list
, char ***pppsz_list
,
107 const char **psz_access
, const char *psz_path
);
109 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
110 const demux_t
***ppp_attachment_demux
,
111 int i_new
, input_attachment_t
**pp_new
, const demux_t
*p_demux
);
113 #define SLAVE_ADD_NOFLAG 0
114 #define SLAVE_ADD_FORCED (1<<0)
115 #define SLAVE_ADD_CANFAIL (1<<1)
116 #define SLAVE_ADD_SET_TIME (1<<2)
118 static int input_SlaveSourceAdd( input_thread_t
*, enum slave_type
,
119 const char *, unsigned );
120 static char *input_SubtitleFile2Uri( input_thread_t
*, const char * );
121 static void input_ChangeState( input_thread_t
*p_input
, int i_state
, vlc_tick_t
); /* TODO fix name */
125 * Create a new input_thread_t.
127 * You need to call input_Start on it when you are done
128 * adding callback on the variables/events you want to monitor.
130 * \param p_parent a vlc_object
131 * \param p_item an input item
132 * \param p_resource an optional input ressource
133 * \return a pointer to the spawned input thread
135 input_thread_t
*input_Create( vlc_object_t
*p_parent
,
136 input_thread_events_cb events_cb
, void *events_data
,
137 input_item_t
*p_item
,
138 input_resource_t
*p_resource
,
139 vlc_renderer_item_t
*p_renderer
)
141 return Create( p_parent
, events_cb
, events_data
, p_item
,
142 INPUT_CREATE_OPTION_NONE
, p_resource
, p_renderer
);
145 input_thread_t
*input_CreatePreparser( vlc_object_t
*parent
,
146 input_thread_events_cb events_cb
,
147 void *events_data
, input_item_t
*item
)
149 return Create( parent
, events_cb
, events_data
, item
,
150 INPUT_CREATE_OPTION_PREPARSING
, NULL
, NULL
);
153 input_thread_t
*input_CreateThumbnailer(vlc_object_t
*obj
,
154 input_thread_events_cb events_cb
,
155 void *events_data
, input_item_t
*item
)
157 return Create( obj
, events_cb
, events_data
, item
,
158 INPUT_CREATE_OPTION_THUMBNAILING
, NULL
, NULL
);
162 * Start a input_thread_t created by input_Create.
164 * You must not start an already running input_thread_t.
166 * \param the input thread to start
168 int input_Start( input_thread_t
*p_input
)
170 input_thread_private_t
*priv
= input_priv(p_input
);
171 void *(*func
)(void *) = Run
;
173 if( priv
->b_preparsing
)
176 assert( !priv
->is_running
);
177 /* Create thread and wait for its readiness. */
178 priv
->is_running
= !vlc_clone( &priv
->thread
, func
, priv
,
179 VLC_THREAD_PRIORITY_INPUT
);
180 if( !priv
->is_running
)
182 msg_Err( p_input
, "cannot create input thread" );
189 * Request a running input thread to stop and die
191 * \param p_input the input thread to stop
193 void input_Stop( input_thread_t
*p_input
)
195 input_thread_private_t
*sys
= input_priv(p_input
);
197 vlc_mutex_lock( &sys
->lock_control
);
198 /* Discard all pending controls */
199 for( size_t i
= 0; i
< sys
->i_control
; i
++ )
201 input_control_t
*ctrl
= &sys
->control
[i
];
202 ControlRelease( ctrl
->i_type
, &ctrl
->param
);
205 sys
->is_stopped
= true;
206 vlc_cond_signal( &sys
->wait_control
);
207 vlc_mutex_unlock( &sys
->lock_control
);
208 vlc_interrupt_kill( &sys
->interrupt
);
214 * It does not call input_Stop itself.
216 void input_Close( input_thread_t
*p_input
)
218 if( input_priv(p_input
)->is_running
)
219 vlc_join( input_priv(p_input
)->thread
, NULL
);
220 vlc_interrupt_deinit( &input_priv(p_input
)->interrupt
);
224 void input_SetTime( input_thread_t
*p_input
, vlc_tick_t i_time
, bool b_fast
)
226 input_control_param_t param
;
228 param
.time
.i_val
= i_time
;
229 param
.time
.b_fast_seek
= b_fast
;
230 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, ¶m
);
233 void input_SetPosition( input_thread_t
*p_input
, float f_position
, bool b_fast
)
235 input_control_param_t param
;
237 param
.pos
.f_val
= f_position
;
238 param
.pos
.b_fast_seek
= b_fast
;
239 input_ControlPush( p_input
, INPUT_CONTROL_SET_POSITION
, ¶m
);
243 * Get the item from an input thread
244 * FIXME it does not increase ref count of the item.
245 * if it is used after p_input is destroyed nothing prevent it from
248 input_item_t
*input_GetItem( input_thread_t
*p_input
)
250 assert( p_input
!= NULL
);
251 return input_priv(p_input
)->p_item
;
254 /*****************************************************************************
255 * This function creates a new input, and returns a pointer
256 * to its description. On error, it returns NULL.
258 * XXX Do not forget to update vlc_input.h if you add new variables.
259 *****************************************************************************/
260 static input_thread_t
*Create( vlc_object_t
*p_parent
,
261 input_thread_events_cb events_cb
, void *events_data
,
262 input_item_t
*p_item
,
263 enum input_create_option option
,
264 input_resource_t
*p_resource
,
265 vlc_renderer_item_t
*p_renderer
)
267 /* Allocate descriptor */
268 input_thread_private_t
*priv
;
270 priv
= vlc_custom_create( p_parent
, sizeof( *priv
), "input" );
271 if( unlikely(priv
== NULL
) )
274 priv
->master
= InputSourceNew( NULL
);
281 input_thread_t
*p_input
= &priv
->input
;
283 char * psz_name
= input_item_GetName( p_item
);
284 const char *option_str
;
287 case INPUT_CREATE_OPTION_PREPARSING
:
288 option_str
= "preparsing ";
290 case INPUT_CREATE_OPTION_THUMBNAILING
:
291 option_str
= "thumbnailing ";
297 msg_Dbg( p_input
, "Creating an input for %s'%s'", option_str
, psz_name
);
300 /* Parse input options */
301 input_item_ApplyOptions( VLC_OBJECT(p_input
), p_item
);
303 /* Init Common fields */
304 priv
->events_cb
= events_cb
;
305 priv
->events_data
= events_data
;
306 priv
->b_preparsing
= option
== INPUT_CREATE_OPTION_PREPARSING
;
307 priv
->b_thumbnailing
= option
== INPUT_CREATE_OPTION_THUMBNAILING
;
308 priv
->b_can_pace_control
= true;
311 priv
->i_title_offset
= input_priv(p_input
)->i_seekpoint_offset
= 0;
312 priv
->i_state
= INIT_S
;
313 priv
->is_running
= false;
314 priv
->is_stopped
= false;
315 priv
->b_recording
= false;
317 priv
->normal_time
= VLC_TICK_0
;
318 TAB_INIT( priv
->i_attachment
, priv
->attachment
);
319 priv
->attachment_demux
= NULL
;
321 priv
->b_out_pace_control
= priv
->b_thumbnailing
;
322 priv
->p_renderer
= p_renderer
&& priv
->b_preparsing
== false ?
323 vlc_renderer_item_hold( p_renderer
) : NULL
;
325 priv
->viewpoint_changed
= false;
326 /* Fetch the viewpoint from the mediaplayer or the playlist if any */
327 vlc_viewpoint_t
*p_viewpoint
= var_InheritAddress( p_input
, "viewpoint" );
328 if (p_viewpoint
!= NULL
)
329 priv
->viewpoint
= *p_viewpoint
;
331 vlc_viewpoint_init( &priv
->viewpoint
);
333 priv
->i_last_es_cat
= UNKNOWN_ES
;
335 input_item_Hold( p_item
); /* Released in Destructor() */
336 priv
->p_item
= p_item
;
338 /* Init Input fields */
339 vlc_mutex_lock( &p_item
->lock
);
341 if( !p_item
->p_stats
)
342 p_item
->p_stats
= calloc( 1, sizeof(*p_item
->p_stats
) );
344 /* setup the preparse depth of the item
345 * if we are preparsing, use the i_preparse_depth of the parent item */
346 if( priv
->b_preparsing
|| priv
->b_thumbnailing
)
348 p_input
->obj
.logger
= NULL
;
349 p_input
->obj
.no_interact
= true;
353 char *psz_rec
= var_InheritString( p_parent
, "recursive" );
355 if( psz_rec
!= NULL
)
357 if ( !strcasecmp( psz_rec
, "none" ) )
358 p_item
->i_preparse_depth
= 0;
359 else if ( !strcasecmp( psz_rec
, "collapse" ) )
360 p_item
->i_preparse_depth
= 1;
362 p_item
->i_preparse_depth
= -1; /* default is expand */
365 p_item
->i_preparse_depth
= -1;
368 /* Make sure the interaction option is honored */
369 if( !var_InheritBool( p_input
, "interact" ) )
370 p_input
->obj
.no_interact
= true;
371 else if( p_item
->b_preparse_interact
)
373 /* If true, this item was asked explicitly to interact with the user
374 * (via libvlc_MetadataRequest). Sub items created from this input won't
375 * have this flag and won't interact with the user */
376 p_input
->obj
.no_interact
= false;
379 vlc_mutex_unlock( &p_item
->lock
);
387 priv
->p_resource
= input_resource_Hold( p_resource
);
389 priv
->p_resource
= input_resource_New( VLC_OBJECT( p_input
) );
390 input_resource_SetInput( priv
->p_resource
, p_input
);
392 /* Init control buffer */
393 vlc_mutex_init( &priv
->lock_control
);
394 vlc_cond_init( &priv
->wait_control
);
396 vlc_interrupt_init(&priv
->interrupt
);
398 /* Create Object Variables for private use only */
399 input_ConfigVarInit( p_input
);
401 priv
->b_low_delay
= var_InheritBool( p_input
, "low-delay" );
403 /* Remove 'Now playing' info as it is probably outdated */
404 input_item_SetNowPlaying( p_item
, NULL
);
405 input_item_SetESNowPlaying( p_item
, NULL
);
408 if( !priv
->b_preparsing
&& var_InheritBool( p_input
, "stats" ) )
409 priv
->stats
= input_stats_Create();
413 priv
->p_es_out_display
= input_EsOutNew( p_input
, priv
->master
, priv
->rate
);
414 if( !priv
->p_es_out_display
)
419 priv
->p_es_out
= NULL
;
424 static void Destroy(input_thread_t
*input
)
426 input_thread_private_t
*priv
= input_priv(input
);
429 char *name
= input_item_GetName(priv
->p_item
);
430 msg_Dbg(input
, "destroying input for '%s'", name
);
434 if (priv
->p_renderer
!= NULL
)
435 vlc_renderer_item_release(priv
->p_renderer
);
436 if (priv
->p_es_out_display
!= NULL
)
437 es_out_Delete(priv
->p_es_out_display
);
439 if (priv
->p_resource
!= NULL
)
440 input_resource_Release(priv
->p_resource
);
442 input_source_Release(priv
->master
);
443 input_item_Release(priv
->p_item
);
445 if (priv
->stats
!= NULL
)
446 input_stats_Destroy(priv
->stats
);
448 for (size_t i
= 0; i
< priv
->i_control
; i
++)
450 input_control_t
*ctrl
= &priv
->control
[i
];
452 ControlRelease(ctrl
->i_type
, &ctrl
->param
);
455 vlc_object_delete(VLC_OBJECT(input
));
458 /*****************************************************************************
459 * Run: main thread loop
460 * This is the "normal" thread that spawns the input processing chain,
461 * reads the stream, cleans up and waits
462 *****************************************************************************/
463 static void *Run( void *data
)
465 input_thread_private_t
*priv
= data
;
466 input_thread_t
*p_input
= &priv
->input
;
468 vlc_interrupt_set(&priv
->interrupt
);
470 if( !Init( p_input
) )
472 if( priv
->b_can_pace_control
&& priv
->b_out_pace_control
)
474 /* We don't want a high input priority here or we'll
475 * end-up sucking up all the CPU time */
476 vlc_set_priority( priv
->thread
, VLC_THREAD_PRIORITY_LOW
);
479 MainLoop( p_input
, true ); /* FIXME it can be wrong (like with VLM) */
485 input_SendEventDead( p_input
);
489 static void *Preparse( void *data
)
491 input_thread_private_t
*priv
= data
;
492 input_thread_t
*p_input
= &priv
->input
;
494 vlc_interrupt_set(&priv
->interrupt
);
496 if( !Init( p_input
) )
497 { /* if the demux is a playlist, call Mainloop that will call
498 * demux_Demux in order to fetch sub items */
499 bool b_is_playlist
= false;
501 if ( input_item_ShouldPreparseSubItems( priv
->p_item
)
502 && demux_Control( priv
->master
->p_demux
, DEMUX_IS_PLAYLIST
,
504 b_is_playlist
= false;
506 MainLoop( p_input
, false );
510 input_SendEventDead( p_input
);
514 bool input_Stopped( input_thread_t
*input
)
516 input_thread_private_t
*sys
= input_priv(input
);
519 vlc_mutex_lock( &sys
->lock_control
);
520 ret
= sys
->is_stopped
;
521 vlc_mutex_unlock( &sys
->lock_control
);
525 /*****************************************************************************
526 * Main loop: Fill buffers from access, and demux
527 *****************************************************************************/
531 * It asks the demuxer to demux some data
533 static void MainLoopDemux( input_thread_t
*p_input
, bool *pb_changed
)
535 input_thread_private_t
* p_priv
= input_priv(p_input
);
536 demux_t
*p_demux
= p_priv
->master
->p_demux
;
537 int i_ret
= VLC_DEMUXER_SUCCESS
;
541 if( p_priv
->i_stop
> 0 )
544 if( demux_Control( p_demux
, DEMUX_GET_TIME
, &i_time
) )
545 i_time
= VLC_TICK_INVALID
;
547 if( p_priv
->i_stop
<= i_time
)
548 i_ret
= VLC_DEMUXER_EOF
;
551 if( i_ret
== VLC_DEMUXER_SUCCESS
)
552 i_ret
= demux_Demux( p_demux
);
554 i_ret
= i_ret
> 0 ? VLC_DEMUXER_SUCCESS
: ( i_ret
< 0 ? VLC_DEMUXER_EGENERIC
: VLC_DEMUXER_EOF
);
556 if( i_ret
== VLC_DEMUXER_SUCCESS
)
558 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_TITLE_LIST
) )
559 UpdateTitleListfromDemux( p_input
);
561 if( p_priv
->master
->b_title_demux
)
563 i_ret
= UpdateTitleSeekpointFromDemux( p_input
);
567 UpdateGenericFromDemux( p_input
);
570 if( i_ret
== VLC_DEMUXER_EOF
)
572 msg_Dbg( p_input
, "EOF reached" );
573 p_priv
->master
->b_eof
= true;
574 es_out_Eos(p_priv
->p_es_out
);
576 else if( i_ret
== VLC_DEMUXER_EGENERIC
)
578 input_ChangeState( p_input
, ERROR_S
, VLC_TICK_INVALID
);
580 else if( p_priv
->i_slave
> 0 )
581 SlaveDemux( p_input
);
584 static int MainLoopTryRepeat( input_thread_t
*p_input
)
586 int i_repeat
= var_GetInteger( p_input
, "input-repeat" );
592 msg_Dbg( p_input
, "repeating the same input (%d)", i_repeat
);
596 var_SetInteger( p_input
, "input-repeat", i_repeat
);
599 input_thread_private_t
*priv
= input_priv(p_input
);
600 /* Seek to start title/seekpoint */
601 val
.i_int
= priv
->master
->i_title_start
- priv
->master
->i_title_offset
;
602 if( val
.i_int
< 0 || val
.i_int
>= priv
->master
->i_title
)
604 input_ControlPushHelper( p_input
,
605 INPUT_CONTROL_SET_TITLE
, &val
);
607 val
.i_int
= priv
->master
->i_seekpoint_start
-
608 priv
->master
->i_seekpoint_offset
;
609 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
610 input_ControlPushHelper( p_input
,
611 INPUT_CONTROL_SET_SEEKPOINT
, &val
);
613 /* Seek to start position */
614 if( priv
->i_start
> 0 )
615 input_SetTime( p_input
, priv
->i_start
, false );
617 input_SetPosition( p_input
, 0.0f
, false );
623 * Update timing infos and statistics.
625 static void MainLoopStatistics( input_thread_t
*p_input
)
627 input_thread_private_t
*priv
= input_priv(p_input
);
628 double f_position
= 0.0;
632 /* update input status variables */
633 if( demux_Control( priv
->master
->p_demux
,
634 DEMUX_GET_POSITION
, &f_position
) )
637 if( demux_Control( priv
->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
638 i_time
= VLC_TICK_INVALID
;
640 if( demux_Control( priv
->master
->p_demux
, DEMUX_GET_LENGTH
, &i_length
) )
641 i_length
= VLC_TICK_INVALID
;
643 /* In case of failure (not implemented or in case of seek), use the last
644 * normal_time value (that is VLC_TICK_0 by default). */
645 demux_Control( priv
->master
->p_demux
, DEMUX_GET_NORMAL_TIME
, &priv
->normal_time
);
647 es_out_SetTimes( priv
->p_es_out
, f_position
, i_time
, priv
->normal_time
,
650 struct input_stats_t new_stats
;
651 if( priv
->stats
!= NULL
)
652 input_stats_Compute( priv
->stats
, &new_stats
);
654 vlc_mutex_lock( &priv
->p_item
->lock
);
655 if( priv
->stats
!= NULL
)
656 *priv
->p_item
->p_stats
= new_stats
;
657 vlc_mutex_unlock( &priv
->p_item
->lock
);
659 input_SendEventStatistics( p_input
, &new_stats
);
664 * The main input loop.
666 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
)
668 vlc_tick_t i_intf_update
= 0;
669 vlc_tick_t i_last_seek_mdate
= 0;
671 if( b_interactive
&& var_InheritBool( p_input
, "start-paused" ) )
672 ControlPause( p_input
, vlc_tick_now() );
674 bool b_pause_after_eof
= b_interactive
&&
675 var_InheritBool( p_input
, "play-and-pause" );
676 bool b_paused_at_eof
= false;
678 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
679 const bool b_can_demux
= p_demux
->pf_demux
!= NULL
;
681 while( !input_Stopped( p_input
) && input_priv(p_input
)->i_state
!= ERROR_S
)
683 vlc_tick_t i_wakeup
= -1;
684 bool b_paused
= input_priv(p_input
)->i_state
== PAUSE_S
;
685 /* FIXME if input_priv(p_input)->i_state == PAUSE_S the access/access_demux
686 * is paused -> this may cause problem with some of them
687 * The same problem can be seen when seeking while paused */
689 b_paused
= !es_out_GetBuffering( input_priv(p_input
)->p_es_out
)
690 || input_priv(p_input
)->master
->b_eof
;
694 if( !input_priv(p_input
)->master
->b_eof
)
696 bool b_force_update
= false;
698 MainLoopDemux( p_input
, &b_force_update
);
701 i_wakeup
= es_out_GetWakeup( input_priv(p_input
)->p_es_out
);
705 b_paused_at_eof
= false;
707 else if( !es_out_GetEmpty( input_priv(p_input
)->p_es_out
) )
709 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
710 i_wakeup
= vlc_tick_now() + INPUT_IDLE_SLEEP
;
712 /* Pause after eof only if the input is pausable.
713 * This way we won't trigger timeshifting for nothing */
714 else if( b_pause_after_eof
&& input_priv(p_input
)->b_can_pause
)
716 if( b_paused_at_eof
)
719 input_control_param_t param
;
720 param
.val
.i_int
= PAUSE_S
;
722 msg_Dbg( p_input
, "pausing at EOF (pause after each)");
723 Control( p_input
, INPUT_CONTROL_SET_STATE
, param
);
726 b_paused_at_eof
= true;
730 if( MainLoopTryRepeat( p_input
) )
734 /* Update interface and statistics */
735 vlc_tick_t now
= vlc_tick_now();
736 if( now
>= i_intf_update
)
738 MainLoopStatistics( p_input
);
739 i_intf_update
= now
+ VLC_TICK_FROM_MS(250);
746 vlc_tick_t i_deadline
= i_wakeup
;
748 /* Postpone seeking until ES buffering is complete or at most
750 bool b_postpone
= es_out_GetBuffering( input_priv(p_input
)->p_es_out
)
751 && !input_priv(p_input
)->master
->b_eof
;
754 vlc_tick_t now
= vlc_tick_now();
756 /* Recheck ES buffer level every 20 ms when seeking */
757 if( now
< i_last_seek_mdate
+ VLC_TICK_FROM_MS(125)
758 && (i_deadline
< 0 || i_deadline
> now
+ VLC_TICK_FROM_MS(20)) )
759 i_deadline
= now
+ VLC_TICK_FROM_MS(20);
765 input_control_param_t param
;
767 if( ControlPop( p_input
, &i_type
, ¶m
, i_deadline
, b_postpone
) )
771 break; /* Wake-up time reached */
775 msg_Dbg( p_input
, "control type=%d", i_type
);
777 if( Control( p_input
, i_type
, param
) )
779 if( ControlIsSeekRequest( i_type
) )
780 i_last_seek_mdate
= vlc_tick_now();
784 /* Update the wakeup time */
786 i_wakeup
= es_out_GetWakeup( input_priv(p_input
)->p_es_out
);
792 static int InitSout( input_thread_t
* p_input
)
794 input_thread_private_t
*priv
= input_priv(p_input
);
796 if( priv
->b_preparsing
)
799 /* Find a usable sout and attach it to p_input */
800 char *psz
= var_GetNonEmptyString( p_input
, "sout" );
801 if( priv
->p_renderer
)
803 /* Keep sout if it comes from a renderer and if the user didn't touch
805 bool keep_sout
= psz
== NULL
;
808 const char *psz_renderer_sout
= vlc_renderer_item_sout( priv
->p_renderer
);
809 if( asprintf( &psz
, "#%s", psz_renderer_sout
) < 0 )
812 var_SetBool( p_input
, "sout-keep", true );
814 if( psz
&& strncasecmp( priv
->p_item
->psz_uri
, "vlc:", 4 ) )
816 priv
->p_sout
= input_resource_RequestSout( priv
->p_resource
, NULL
, psz
);
817 if( priv
->p_sout
== NULL
)
819 input_ChangeState( p_input
, ERROR_S
, VLC_TICK_INVALID
);
820 msg_Err( p_input
, "cannot start stream output instance, " \
828 input_resource_RequestSout( priv
->p_resource
, NULL
, NULL
);
836 static void InitTitle( input_thread_t
* p_input
, bool had_titles
)
838 input_thread_private_t
*priv
= input_priv(p_input
);
839 input_source_t
*p_master
= priv
->master
;
841 if( priv
->b_preparsing
)
844 vlc_mutex_lock( &priv
->p_item
->lock
);
845 priv
->i_title_offset
= p_master
->i_title_offset
;
846 priv
->i_seekpoint_offset
= p_master
->i_seekpoint_offset
;
849 priv
->b_can_pace_control
= p_master
->b_can_pace_control
;
850 priv
->b_can_pause
= p_master
->b_can_pause
;
851 priv
->b_can_rate_control
= p_master
->b_can_rate_control
;
852 vlc_mutex_unlock( &priv
->p_item
->lock
);
854 /* Send event only if the count is valid or if titles are gone */
855 if (had_titles
|| p_master
->i_title
> 0)
856 input_SendEventTitle( p_input
, &(struct vlc_input_event_title
) {
857 .action
= VLC_INPUT_TITLE_NEW_LIST
,
859 .array
= p_master
->title
,
860 .count
= p_master
->i_title
,
865 static void StartTitle( input_thread_t
* p_input
)
867 input_thread_private_t
*priv
= input_priv(p_input
);
870 /* Start title/chapter */
871 val
.i_int
= priv
->master
->i_title_start
- priv
->master
->i_title_offset
;
872 if( val
.i_int
> 0 && val
.i_int
< priv
->master
->i_title
)
873 input_ControlPushHelper( p_input
, INPUT_CONTROL_SET_TITLE
, &val
);
875 val
.i_int
= priv
->master
->i_seekpoint_start
-
876 priv
->master
->i_seekpoint_offset
;
877 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
878 input_ControlPushHelper( p_input
, INPUT_CONTROL_SET_SEEKPOINT
, &val
);
880 /* Start/stop/run time */
881 priv
->i_start
= llroundf((float)CLOCK_FREQ
882 * var_GetFloat( p_input
, "start-time" ));
883 priv
->i_stop
= llroundf((float)CLOCK_FREQ
884 * var_GetFloat( p_input
, "stop-time" ));
885 if( priv
->i_stop
<= 0 )
887 priv
->i_stop
= llroundf((float)CLOCK_FREQ
888 * var_GetFloat( p_input
, "run-time" ));
889 if( priv
->i_stop
< 0 )
891 msg_Warn( p_input
, "invalid run-time ignored" );
895 priv
->i_stop
+= priv
->i_start
;
898 if( priv
->i_start
> 0 )
900 msg_Dbg( p_input
, "starting at time: %"PRId64
"s",
901 SEC_FROM_VLC_TICK(priv
->i_start
) );
903 input_SetTime( p_input
, priv
->i_start
, false );
905 if( priv
->i_stop
> 0 && priv
->i_stop
<= priv
->i_start
)
907 msg_Warn( p_input
, "invalid stop-time ignored" );
912 static int SlaveCompare(const void *a
, const void *b
)
914 const input_item_slave_t
*p_slave0
= *((const input_item_slave_t
**) a
);
915 const input_item_slave_t
*p_slave1
= *((const input_item_slave_t
**) b
);
917 if( p_slave0
== NULL
|| p_slave1
== NULL
)
919 /* Put NULL (or rejected) subs at the end */
920 return p_slave0
== NULL
? 1 : p_slave1
== NULL
? -1 : 0;
923 if( p_slave0
->i_priority
> p_slave1
->i_priority
)
926 if( p_slave0
->i_priority
< p_slave1
->i_priority
)
932 static bool SlaveExists( input_item_slave_t
**pp_slaves
, int i_slaves
,
935 for( int i
= 0; i
< i_slaves
; i
++ )
937 if( pp_slaves
[i
] != NULL
938 && !strcmp( pp_slaves
[i
]->psz_uri
, psz_uri
) )
944 static void RequestSubRate( input_thread_t
*p_input
, float f_slave_fps
)
946 input_thread_private_t
*priv
= input_priv(p_input
);
947 const float f_fps
= input_priv(p_input
)->master
->f_fps
;
948 if( f_fps
> 1.f
&& f_slave_fps
> 1.f
)
949 priv
->slave_subs_rate
= f_fps
/ f_slave_fps
;
950 else if ( priv
->slave_subs_rate
!= 0 )
951 priv
->slave_subs_rate
= 1.f
;
954 static void SetSubtitlesOptions( input_thread_t
*p_input
)
956 /* Get fps and set it if not already set */
957 const float f_fps
= input_priv(p_input
)->master
->f_fps
;
960 var_SetFloat( p_input
, "sub-original-fps", f_fps
);
961 RequestSubRate( p_input
, var_InheritFloat( p_input
, "sub-fps" ) );
965 static void GetVarSlaves( input_thread_t
*p_input
,
966 input_item_slave_t
***ppp_slaves
, int *p_slaves
)
968 char *psz
= var_GetNonEmptyString( p_input
, "input-slave" );
972 input_item_slave_t
**pp_slaves
= *ppp_slaves
;
973 int i_slaves
= *p_slaves
;
978 while( *psz
== ' ' || *psz
== '#' )
981 char *psz_delim
= strchr( psz
, '#' );
988 char *uri
= strstr(psz
, "://")
989 ? strdup( psz
) : vlc_path2uri( psz
, NULL
);
994 input_item_slave_t
*p_slave
=
995 input_item_slave_New( uri
, SLAVE_TYPE_AUDIO
, SLAVE_PRIORITY_USER
);
998 if( unlikely( p_slave
== NULL
) )
1000 TAB_APPEND(i_slaves
, pp_slaves
, p_slave
);
1004 *ppp_slaves
= pp_slaves
; /* in case of realloc */
1005 *p_slaves
= i_slaves
;
1008 static void LoadSlaves( input_thread_t
*p_input
)
1010 input_item_slave_t
**pp_slaves
;
1012 TAB_INIT( i_slaves
, pp_slaves
);
1014 /* Look for and add slaves */
1016 char *psz_subtitle
= var_GetNonEmptyString( p_input
, "sub-file" );
1017 if( psz_subtitle
!= NULL
)
1019 msg_Dbg( p_input
, "forced subtitle: %s", psz_subtitle
);
1020 char *psz_uri
= input_SubtitleFile2Uri( p_input
, psz_subtitle
);
1021 free( psz_subtitle
);
1022 psz_subtitle
= NULL
;
1023 if( psz_uri
!= NULL
)
1025 input_item_slave_t
*p_slave
=
1026 input_item_slave_New( psz_uri
, SLAVE_TYPE_SPU
,
1027 SLAVE_PRIORITY_USER
);
1031 TAB_APPEND(i_slaves
, pp_slaves
, p_slave
);
1032 psz_subtitle
= p_slave
->psz_uri
;
1037 if( var_GetBool( p_input
, "sub-autodetect-file" ) )
1039 /* Add local subtitles */
1040 char *psz_autopath
= var_GetNonEmptyString( p_input
, "sub-autodetect-path" );
1042 if( subtitles_Detect( p_input
, psz_autopath
, input_priv(p_input
)->p_item
->psz_uri
,
1043 &pp_slaves
, &i_slaves
) == VLC_SUCCESS
)
1045 /* check that we did not add the subtitle through sub-file */
1046 if( psz_subtitle
!= NULL
)
1048 for( int i
= 1; i
< i_slaves
; i
++ )
1050 input_item_slave_t
*p_curr
= pp_slaves
[i
];
1052 && !strcmp( psz_subtitle
, p_curr
->psz_uri
) )
1054 /* reject current sub */
1055 input_item_slave_Delete( p_curr
);
1056 pp_slaves
[i
] = NULL
;
1061 free( psz_autopath
);
1064 /* Add slaves found by the directory demuxer or via libvlc */
1065 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1066 vlc_mutex_lock( &p_item
->lock
);
1068 /* Move item slaves to local pp_slaves */
1069 for( int i
= 0; i
< p_item
->i_slaves
; i
++ )
1071 input_item_slave_t
*p_slave
= p_item
->pp_slaves
[i
];
1072 if( !SlaveExists( pp_slaves
, i_slaves
, p_slave
->psz_uri
) )
1073 TAB_APPEND(i_slaves
, pp_slaves
, p_slave
);
1075 input_item_slave_Delete( p_slave
);
1077 /* Slaves that are successfully loaded will be added back to the item */
1078 TAB_CLEAN( p_item
->i_slaves
, p_item
->pp_slaves
);
1079 vlc_mutex_unlock( &p_item
->lock
);
1081 /* Add slaves from the "input-slave" option */
1082 GetVarSlaves( p_input
, &pp_slaves
, &i_slaves
);
1085 qsort( pp_slaves
, i_slaves
, sizeof (input_item_slave_t
*),
1088 /* add all detected slaves */
1089 bool p_forced
[2] = { false, false };
1090 static_assert( SLAVE_TYPE_AUDIO
<= 1 && SLAVE_TYPE_SPU
<= 1,
1091 "slave type size mismatch");
1092 for( int i
= 0; i
< i_slaves
&& pp_slaves
[i
] != NULL
; i
++ )
1094 input_item_slave_t
*p_slave
= pp_slaves
[i
];
1095 /* Slaves added via options should not fail */
1096 unsigned i_flags
= p_slave
->i_priority
!= SLAVE_PRIORITY_USER
1097 ? SLAVE_ADD_CANFAIL
: SLAVE_ADD_NOFLAG
;
1098 bool b_forced
= false;
1100 /* Force the first subtitle with the highest priority or with the
1102 if( !p_forced
[p_slave
->i_type
]
1103 && ( p_slave
->b_forced
|| p_slave
->i_priority
== SLAVE_PRIORITY_USER
) )
1105 i_flags
|= SLAVE_ADD_FORCED
;
1109 if( input_SlaveSourceAdd( p_input
, p_slave
->i_type
, p_slave
->psz_uri
,
1110 i_flags
) == VLC_SUCCESS
)
1112 input_item_AddSlave( input_priv(p_input
)->p_item
, p_slave
);
1114 p_forced
[p_slave
->i_type
] = true;
1117 input_item_slave_Delete( p_slave
);
1119 TAB_CLEAN( i_slaves
, pp_slaves
);
1121 /* Load subtitles from attachments */
1122 int i_attachment
= 0;
1123 input_attachment_t
**pp_attachment
= NULL
;
1125 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1126 for( int i
= 0; i
< input_priv(p_input
)->i_attachment
; i
++ )
1128 const input_attachment_t
*a
= input_priv(p_input
)->attachment
[i
];
1129 if( !strcmp( a
->psz_mime
, "application/x-srt" ) )
1130 TAB_APPEND( i_attachment
, pp_attachment
,
1131 vlc_input_attachment_New( a
->psz_name
, NULL
,
1132 a
->psz_description
, NULL
, 0 ) );
1134 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1136 if( i_attachment
> 0 )
1137 var_Create( p_input
, "sub-description", VLC_VAR_STRING
);
1138 for( int i
= 0; i
< i_attachment
; i
++ )
1140 input_attachment_t
*a
= pp_attachment
[i
];
1144 if( a
->psz_name
[0] &&
1145 asprintf( &psz_mrl
, "attachment://%s", a
->psz_name
) >= 0 )
1147 var_SetString( p_input
, "sub-description", a
->psz_description
? a
->psz_description
: "");
1149 /* Force the first subtitle from attachment if there is no
1150 * subtitles already forced */
1151 if( input_SlaveSourceAdd( p_input
, SLAVE_TYPE_SPU
, psz_mrl
,
1152 p_forced
[ SLAVE_TYPE_SPU
] ?
1153 SLAVE_ADD_NOFLAG
: SLAVE_ADD_FORCED
) == VLC_SUCCESS
)
1154 p_forced
[ SLAVE_TYPE_SPU
] = true;
1157 /* Don't update item slaves for attachements */
1159 vlc_input_attachment_Delete( a
);
1161 free( pp_attachment
);
1162 if( i_attachment
> 0 )
1163 var_Destroy( p_input
, "sub-description" );
1166 static void UpdatePtsDelay( input_thread_t
*p_input
)
1168 input_thread_private_t
*p_sys
= input_priv(p_input
);
1170 /* Get max pts delay from input source */
1171 vlc_tick_t i_pts_delay
= p_sys
->master
->i_pts_delay
;
1172 for( int i
= 0; i
< p_sys
->i_slave
; i
++ )
1173 i_pts_delay
= __MAX( i_pts_delay
, p_sys
->slave
[i
]->i_pts_delay
);
1175 if( i_pts_delay
< 0 )
1178 /* Update cr_average depending on the caching */
1179 const int i_cr_average
= var_GetInteger( p_input
, "cr-average" ) * i_pts_delay
/ DEFAULT_PTS_DELAY
;
1181 es_out_SetJitter( input_priv(p_input
)->p_es_out
, i_pts_delay
, 0, i_cr_average
);
1184 static void InitPrograms( input_thread_t
* p_input
)
1190 /* Compute correct pts_delay */
1191 UpdatePtsDelay( p_input
);
1194 i_es_out_mode
= ES_OUT_MODE_AUTO
;
1195 if( input_priv(p_input
)->p_sout
&& !input_priv(p_input
)->p_renderer
)
1199 if( (prgms
= var_GetNonEmptyString( p_input
, "programs" )) != NULL
)
1203 TAB_INIT(count
, tab
);
1204 for( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1206 prgm
= strtok_r( NULL
, ",", &buf
) )
1208 TAB_APPEND(count
, tab
, atoi(prgm
));
1212 i_es_out_mode
= ES_OUT_MODE_PARTIAL
;
1213 /* Note : we should remove the "program" callback. */
1217 else if( var_GetBool( p_input
, "sout-all" ) )
1219 i_es_out_mode
= ES_OUT_MODE_ALL
;
1222 es_out_SetMode( input_priv(p_input
)->p_es_out
, i_es_out_mode
);
1224 /* Inform the demuxer about waited group (needed only for DVB) */
1225 if( i_es_out_mode
== ES_OUT_MODE_ALL
)
1227 demux_Control( input_priv(p_input
)->master
->p_demux
,
1228 DEMUX_SET_GROUP_ALL
);
1230 else if( i_es_out_mode
== ES_OUT_MODE_PARTIAL
)
1232 demux_Control( input_priv(p_input
)->master
->p_demux
,
1233 DEMUX_SET_GROUP_LIST
, count
, tab
);
1238 int program
= es_out_GetGroupForced( input_priv(p_input
)->p_es_out
);
1240 demux_Control( input_priv(p_input
)->master
->p_demux
,
1241 DEMUX_SET_GROUP_DEFAULT
);
1243 demux_Control( input_priv(p_input
)->master
->p_demux
,
1244 DEMUX_SET_GROUP_LIST
, (size_t)1,
1245 (const int *)&program
);
1249 static int Init( input_thread_t
* p_input
)
1251 input_thread_private_t
*priv
= input_priv(p_input
);
1252 input_source_t
*master
;
1255 input_ChangeState( p_input
, OPENING_S
, VLC_TICK_INVALID
);
1256 input_SendEventCache( p_input
, 0.0 );
1258 if( var_Type( vlc_object_parent(p_input
), "meta-file" ) )
1260 msg_Dbg( p_input
, "Input is a meta file: disabling unneeded options" );
1261 var_SetString( p_input
, "sout", "" );
1262 var_SetBool( p_input
, "sout-all", false );
1263 var_SetString( p_input
, "input-slave", "" );
1264 var_SetInteger( p_input
, "input-repeat", 0 );
1265 var_SetString( p_input
, "sub-file", "" );
1266 var_SetBool( p_input
, "sub-autodetect-file", false );
1270 if( InitSout( p_input
) )
1275 priv
->p_es_out
= input_EsOutTimeshiftNew( p_input
, priv
->p_es_out_display
, priv
->rate
);
1276 if( priv
->p_es_out
== NULL
)
1280 master
= priv
->master
;
1281 if( master
== NULL
)
1283 int ret
= InputSourceInit( master
, p_input
, priv
->p_item
->psz_uri
,
1285 if( ret
!= VLC_SUCCESS
)
1287 InputSourceDestroy( master
);
1291 InitTitle( p_input
, false );
1293 /* Load master infos */
1295 vlc_tick_t i_length
;
1296 if( demux_Control( master
->p_demux
, DEMUX_GET_LENGTH
, &i_length
) )
1297 i_length
= VLC_TICK_INVALID
;
1298 if( i_length
== VLC_TICK_INVALID
)
1299 i_length
= input_item_GetDuration( priv
->p_item
);
1301 input_SendEventTimes( p_input
, 0.0, VLC_TICK_INVALID
, priv
->normal_time
,
1304 if( !priv
->b_preparsing
)
1306 StartTitle( p_input
);
1307 SetSubtitlesOptions( p_input
);
1308 LoadSlaves( p_input
);
1309 InitPrograms( p_input
);
1311 double f_rate
= var_GetFloat( p_input
, "rate" );
1312 if( f_rate
!= 0.0 && f_rate
!= 1.0 )
1314 vlc_value_t val
= { .f_float
= f_rate
};
1315 input_ControlPushHelper( p_input
, INPUT_CONTROL_SET_RATE
, &val
);
1319 if( !priv
->b_preparsing
&& priv
->p_sout
)
1321 priv
->b_out_pace_control
= priv
->p_sout
->i_out_pace_nocontrol
> 0;
1323 msg_Dbg( p_input
, "starting in %ssync mode",
1324 priv
->b_out_pace_control
? "a" : "" );
1327 if (!input_item_IsPreparsed(input_priv(p_input
)->p_item
))
1329 vlc_meta_t
*p_meta
= vlc_meta_New();
1330 if( p_meta
!= NULL
)
1332 /* Get meta data from users */
1333 InputMetaUser( p_input
, p_meta
);
1335 /* Get meta data from master input */
1336 InputSourceMeta( p_input
, master
, p_meta
);
1338 /* And from slave */
1339 for( int i
= 0; i
< priv
->i_slave
; i
++ )
1340 InputSourceMeta( p_input
, priv
->slave
[i
], p_meta
);
1342 es_out_ControlSetMeta( priv
->p_es_out
, p_meta
);
1343 vlc_meta_Delete( p_meta
);
1347 msg_Dbg( p_input
, "`%s' successfully opened",
1348 input_priv(p_input
)->p_item
->psz_uri
);
1350 /* initialization is complete */
1351 input_ChangeState( p_input
, PLAYING_S
, vlc_tick_now() );
1356 input_ChangeState( p_input
, ERROR_S
, VLC_TICK_INVALID
);
1358 if( input_priv(p_input
)->p_es_out
)
1359 es_out_Delete( input_priv(p_input
)->p_es_out
);
1360 es_out_SetMode( input_priv(p_input
)->p_es_out_display
, ES_OUT_MODE_END
);
1361 if( input_priv(p_input
)->p_resource
)
1363 if( input_priv(p_input
)->p_sout
)
1364 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1365 input_priv(p_input
)->p_sout
, NULL
);
1366 input_resource_SetInput( input_priv(p_input
)->p_resource
, NULL
);
1367 if( input_priv(p_input
)->p_resource
)
1369 input_resource_Release( input_priv(p_input
)->p_resource
);
1370 input_priv(p_input
)->p_resource
= NULL
;
1374 /* Mark them deleted */
1375 input_priv(p_input
)->p_es_out
= NULL
;
1376 input_priv(p_input
)->p_sout
= NULL
;
1378 return VLC_EGENERIC
;
1381 /*****************************************************************************
1382 * End: end the input thread
1383 *****************************************************************************/
1384 static void End( input_thread_t
* p_input
)
1386 input_thread_private_t
*priv
= input_priv(p_input
);
1388 /* We are at the end */
1389 input_ChangeState( p_input
, END_S
, VLC_TICK_INVALID
);
1391 /* Stop es out activity */
1392 es_out_SetMode( priv
->p_es_out
, ES_OUT_MODE_NONE
);
1395 for( int i
= 0; i
< priv
->i_slave
; i
++ )
1397 InputSourceDestroy( priv
->slave
[i
] );
1398 input_source_Release( priv
->slave
[i
] );
1400 free( priv
->slave
);
1402 /* Clean up master */
1403 InputSourceDestroy( priv
->master
);
1404 priv
->i_title_offset
= 0;
1405 priv
->i_seekpoint_offset
= 0;
1407 /* Unload all modules */
1408 if( priv
->p_es_out
)
1409 es_out_Delete( priv
->p_es_out
);
1410 es_out_SetMode( priv
->p_es_out_display
, ES_OUT_MODE_END
);
1412 if( priv
->stats
!= NULL
)
1414 input_item_t
*item
= priv
->p_item
;
1415 /* make sure we are up to date */
1416 vlc_mutex_lock( &item
->lock
);
1417 input_stats_Compute( priv
->stats
, item
->p_stats
);
1418 vlc_mutex_unlock( &item
->lock
);
1421 vlc_mutex_lock( &priv
->p_item
->lock
);
1422 if( priv
->i_attachment
> 0 )
1424 for( int i
= 0; i
< priv
->i_attachment
; i
++ )
1425 vlc_input_attachment_Delete( priv
->attachment
[i
] );
1426 TAB_CLEAN( priv
->i_attachment
, priv
->attachment
);
1427 free( priv
->attachment_demux
);
1428 priv
->attachment_demux
= NULL
;
1431 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1434 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1435 input_priv(p_input
)->p_sout
, NULL
);
1436 input_resource_SetInput( input_priv(p_input
)->p_resource
, NULL
);
1437 if( input_priv(p_input
)->p_resource
)
1439 input_resource_Release( input_priv(p_input
)->p_resource
);
1440 input_priv(p_input
)->p_resource
= NULL
;
1444 static size_t ControlGetReducedIndexLocked( input_thread_t
*p_input
,
1445 input_control_t
*c
)
1447 input_thread_private_t
*sys
= input_priv(p_input
);
1449 if( sys
->i_control
== 0 )
1452 input_control_t
*prev_control
= &sys
->control
[sys
->i_control
- 1];
1453 const int i_lt
= prev_control
->i_type
;
1454 const int i_ct
= c
->i_type
;
1458 if ( i_ct
== INPUT_CONTROL_SET_STATE
||
1459 i_ct
== INPUT_CONTROL_SET_RATE
||
1460 i_ct
== INPUT_CONTROL_SET_POSITION
||
1461 i_ct
== INPUT_CONTROL_SET_TIME
||
1462 i_ct
== INPUT_CONTROL_SET_PROGRAM
||
1463 i_ct
== INPUT_CONTROL_SET_TITLE
||
1464 i_ct
== INPUT_CONTROL_SET_SEEKPOINT
)
1466 return sys
->i_control
- 1;
1468 else if ( i_ct
== INPUT_CONTROL_JUMP_TIME
)
1470 c
->param
.time
.i_val
+= prev_control
->param
.time
.i_val
;
1471 return sys
->i_control
- 1;
1473 else if ( i_ct
== INPUT_CONTROL_JUMP_POSITION
)
1475 c
->param
.pos
.f_val
+= prev_control
->param
.pos
.f_val
;
1476 return sys
->i_control
- 1;
1480 return sys
->i_control
;
1483 /*****************************************************************************
1485 *****************************************************************************/
1486 int input_ControlPush( input_thread_t
*p_input
,
1487 int i_type
, const input_control_param_t
*p_param
)
1489 input_thread_private_t
*sys
= input_priv(p_input
);
1491 vlc_mutex_lock( &sys
->lock_control
);
1492 input_control_t c
= {
1498 size_t i_next_control_idx
= ControlGetReducedIndexLocked( p_input
, &c
);
1500 if( sys
->is_stopped
|| i_next_control_idx
>= INPUT_CONTROL_FIFO_SIZE
)
1502 if( sys
->is_stopped
)
1503 msg_Dbg( p_input
, "input control stopped, trashing type=%d",
1506 msg_Err( p_input
, "input control fifo overflow, trashing type=%d",
1509 ControlRelease( i_type
, p_param
);
1510 vlc_mutex_unlock( &sys
->lock_control
);
1511 return VLC_EGENERIC
;
1514 sys
->control
[i_next_control_idx
] = c
;
1515 sys
->i_control
= i_next_control_idx
+ 1;
1517 vlc_cond_signal( &sys
->wait_control
);
1518 vlc_mutex_unlock( &sys
->lock_control
);
1522 static inline int ControlPop( input_thread_t
*p_input
,
1523 int *pi_type
, input_control_param_t
*p_param
,
1524 vlc_tick_t i_deadline
, bool b_postpone_seek
)
1526 input_thread_private_t
*p_sys
= input_priv(p_input
);
1528 vlc_mutex_lock( &p_sys
->lock_control
);
1529 while( p_sys
->i_control
<= 0 ||
1530 ( b_postpone_seek
&& ControlIsSeekRequest( p_sys
->control
[0].i_type
) ) )
1532 if( p_sys
->is_stopped
)
1534 vlc_mutex_unlock( &p_sys
->lock_control
);
1535 return VLC_EGENERIC
;
1538 if( i_deadline
>= 0 )
1540 if( vlc_cond_timedwait( &p_sys
->wait_control
, &p_sys
->lock_control
,
1543 vlc_mutex_unlock( &p_sys
->lock_control
);
1544 return VLC_EGENERIC
;
1548 vlc_cond_wait( &p_sys
->wait_control
, &p_sys
->lock_control
);
1552 *pi_type
= p_sys
->control
[0].i_type
;
1553 *p_param
= p_sys
->control
[0].param
;
1555 p_sys
->i_control
--;
1556 if( p_sys
->i_control
> 0 )
1557 memmove( &p_sys
->control
[0], &p_sys
->control
[1],
1558 sizeof(*p_sys
->control
) * p_sys
->i_control
);
1559 vlc_mutex_unlock( &p_sys
->lock_control
);
1563 static bool ControlIsSeekRequest( int i_type
)
1567 case INPUT_CONTROL_SET_POSITION
:
1568 case INPUT_CONTROL_JUMP_POSITION
:
1569 case INPUT_CONTROL_SET_TIME
:
1570 case INPUT_CONTROL_JUMP_TIME
:
1571 case INPUT_CONTROL_SET_TITLE
:
1572 case INPUT_CONTROL_SET_TITLE_NEXT
:
1573 case INPUT_CONTROL_SET_TITLE_PREV
:
1574 case INPUT_CONTROL_SET_SEEKPOINT
:
1575 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1576 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1577 case INPUT_CONTROL_NAV_ACTIVATE
:
1578 case INPUT_CONTROL_NAV_UP
:
1579 case INPUT_CONTROL_NAV_DOWN
:
1580 case INPUT_CONTROL_NAV_LEFT
:
1581 case INPUT_CONTROL_NAV_RIGHT
:
1582 case INPUT_CONTROL_NAV_POPUP
:
1583 case INPUT_CONTROL_NAV_MENU
:
1590 static void ControlRelease( int i_type
, const input_control_param_t
*p_param
)
1592 if( p_param
== NULL
)
1597 case INPUT_CONTROL_ADD_SLAVE
:
1598 if( p_param
->val
.p_address
)
1599 input_item_slave_Delete( p_param
->val
.p_address
);
1601 case INPUT_CONTROL_SET_RENDERER
:
1602 if( p_param
->val
.p_address
)
1603 vlc_renderer_item_release( p_param
->val
.p_address
);
1605 case INPUT_CONTROL_SET_ES
:
1606 case INPUT_CONTROL_UNSET_ES
:
1607 case INPUT_CONTROL_RESTART_ES
:
1608 vlc_es_id_Release( p_param
->id
);
1610 case INPUT_CONTROL_SET_ES_LIST
:
1612 for (size_t i
= 0; ; i
++)
1614 vlc_es_id_t
*es_id
= p_param
->list
.ids
[i
];
1617 vlc_es_id_Release(es_id
);
1619 free(p_param
->list
.ids
);
1622 case INPUT_CONTROL_SET_ES_CAT_IDS
:
1623 free( p_param
->cat_ids
.str_ids
);
1632 static void ControlPause( input_thread_t
*p_input
, vlc_tick_t i_control_date
)
1634 int i_state
= PAUSE_S
;
1636 if( input_priv(p_input
)->b_can_pause
)
1638 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
1640 if( demux_Control( p_demux
, DEMUX_SET_PAUSE_STATE
, true ) )
1642 msg_Warn( p_input
, "cannot set pause state" );
1648 if( es_out_SetPauseState( input_priv(p_input
)->p_es_out
, input_priv(p_input
)->b_can_pause
,
1649 true, i_control_date
) )
1651 msg_Warn( p_input
, "cannot set pause state at es_out level" );
1655 /* Switch to new state */
1656 input_ChangeState( p_input
, i_state
, i_control_date
);
1659 static void ControlUnpause( input_thread_t
*p_input
, vlc_tick_t i_control_date
)
1661 if( input_priv(p_input
)->b_can_pause
)
1663 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
1665 if( demux_Control( p_demux
, DEMUX_SET_PAUSE_STATE
, false ) )
1667 msg_Err( p_input
, "cannot resume" );
1668 input_ChangeState( p_input
, ERROR_S
, i_control_date
);
1673 /* Switch to play */
1674 input_ChangeState( p_input
, PLAYING_S
, i_control_date
);
1675 es_out_SetPauseState( input_priv(p_input
)->p_es_out
, false, false, i_control_date
);
1678 static void ViewpointApply( input_thread_t
*p_input
)
1680 input_thread_private_t
*priv
= input_priv(p_input
);
1682 vlc_viewpoint_clip( &priv
->viewpoint
);
1684 vout_thread_t
**pp_vout
;
1686 input_resource_HoldVouts( priv
->p_resource
, &pp_vout
, &i_vout
);
1688 for( size_t i
= 0; i
< i_vout
; ++i
)
1690 var_SetAddress( pp_vout
[i
], "viewpoint", &priv
->viewpoint
);
1691 /* This variable can only be read from callbacks */
1692 var_Change( pp_vout
[i
], "viewpoint", VLC_VAR_SETVALUE
,
1693 (vlc_value_t
) { .p_address
= NULL
} );
1694 vout_Release(pp_vout
[i
]);
1698 audio_output_t
*p_aout
= input_resource_HoldAout( priv
->p_resource
);
1702 var_SetAddress( p_aout
, "viewpoint", &priv
->viewpoint
);
1703 /* This variable can only be read from callbacks */
1704 var_Change( p_aout
, "viewpoint", VLC_VAR_SETVALUE
,
1705 (vlc_value_t
) { .p_address
= NULL
} );
1706 aout_Release(p_aout
);
1710 static void ControlNav( input_thread_t
*p_input
, int i_type
)
1712 input_thread_private_t
*priv
= input_priv(p_input
);
1714 if( !demux_Control( priv
->master
->p_demux
, i_type
1715 - INPUT_CONTROL_NAV_ACTIVATE
+ DEMUX_NAV_ACTIVATE
) )
1716 return; /* The demux handled the navigation control */
1718 /* Handle Up/Down/Left/Right if the demux can't navigate */
1719 vlc_viewpoint_t vp
= {0};
1720 int vol_direction
= 0;
1721 int seek_direction
= 0;
1724 case INPUT_CONTROL_NAV_UP
:
1728 case INPUT_CONTROL_NAV_DOWN
:
1732 case INPUT_CONTROL_NAV_LEFT
:
1733 seek_direction
= -1;
1736 case INPUT_CONTROL_NAV_RIGHT
:
1740 case INPUT_CONTROL_NAV_ACTIVATE
:
1741 case INPUT_CONTROL_NAV_POPUP
:
1742 case INPUT_CONTROL_NAV_MENU
:
1745 vlc_assert_unreachable();
1748 /* Try to change the viewpoint if possible */
1749 vout_thread_t
**pp_vout
;
1751 bool b_viewpoint_ch
= false;
1752 input_resource_HoldVouts( priv
->p_resource
, &pp_vout
, &i_vout
);
1753 for( size_t i
= 0; i
< i_vout
; ++i
)
1756 && var_GetBool( pp_vout
[i
], "viewpoint-changeable" ) )
1757 b_viewpoint_ch
= true;
1758 vout_Release(pp_vout
[i
]);
1762 if( b_viewpoint_ch
)
1764 priv
->viewpoint_changed
= true;
1765 priv
->viewpoint
.yaw
+= vp
.yaw
;
1766 priv
->viewpoint
.pitch
+= vp
.pitch
;
1767 priv
->viewpoint
.roll
+= vp
.roll
;
1768 priv
->viewpoint
.fov
+= vp
.fov
;
1769 ViewpointApply( p_input
);
1773 /* Seek or change volume if the input doesn't have navigation or viewpoint */
1774 if( seek_direction
!= 0 )
1776 vlc_tick_t it
= vlc_tick_from_sec( seek_direction
* var_InheritInteger( p_input
, "short-jump-size" ) );
1777 Control( p_input
, INPUT_CONTROL_JUMP_TIME
, (input_control_param_t
) {
1778 .time
.b_fast_seek
= false,
1784 assert( vol_direction
!= 0 );
1785 audio_output_t
*p_aout
= input_resource_HoldAout( priv
->p_resource
);
1788 aout_VolumeUpdate( p_aout
, vol_direction
, NULL
);
1789 aout_Release(p_aout
);
1795 static void ControlUpdateRenderer( input_thread_t
*p_input
, bool b_enable
)
1799 if( InitSout( p_input
) != VLC_SUCCESS
)
1801 msg_Err( p_input
, "Failed to start sout" );
1807 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1808 input_priv(p_input
)->p_sout
, NULL
);
1809 input_priv(p_input
)->p_sout
= NULL
;
1814 static void ControlInsertDemuxFilter( input_thread_t
* p_input
, const char* psz_demux_chain
)
1816 input_source_t
*p_inputSource
= input_priv(p_input
)->master
;
1817 demux_t
*p_filtered_demux
= demux_FilterChainNew( p_inputSource
->p_demux
, psz_demux_chain
);
1818 if ( p_filtered_demux
!= NULL
)
1819 p_inputSource
->p_demux
= p_filtered_demux
;
1820 else if ( psz_demux_chain
!= NULL
)
1821 msg_Dbg(p_input
, "Failed to create demux filter %s", psz_demux_chain
);
1825 void input_SetEsCatIds(input_thread_t
*input
, enum es_format_category_e cat
,
1826 const char *str_ids
)
1828 input_thread_private_t
*sys
= input_priv(input
);
1830 if (!sys
->is_running
&& !sys
->is_stopped
)
1832 /* Not running, send the control synchronously since we are sure that
1834 es_out_SetEsCatIds(sys
->p_es_out_display
, cat
, str_ids
);
1838 const input_control_param_t param
= {
1839 .cat_ids
= { cat
, str_ids
? strdup(str_ids
) : NULL
}
1841 input_ControlPush(input
, INPUT_CONTROL_SET_ES_CAT_IDS
, ¶m
);
1845 static void ControlSetEsList(input_thread_t
*input
,
1846 enum es_format_category_e cat
,
1849 input_thread_private_t
*priv
= input_priv(input
);
1851 if (es_out_SetEsList(priv
->p_es_out_display
, cat
, ids
) != VLC_SUCCESS
)
1854 if (ids
[0] != NULL
&& ids
[1] == NULL
)
1856 /* Update the only demux touched by this change */
1857 const input_source_t
*source
= vlc_es_id_GetSource(ids
[0]);
1859 demux_Control(source
->p_demux
, DEMUX_SET_ES
,
1860 vlc_es_id_GetInputId(ids
[0]));
1864 /* Send the updated list for each different sources */
1866 for (count
= 0; ids
[count
] != NULL
; count
++);
1867 int *array
= count
? vlc_alloc(count
, sizeof(int)) : NULL
;
1871 for (int i
= 0; i
< priv
->i_slave
+ 1; ++ i
)
1873 /* For master and all slaves */
1874 input_source_t
*source
= i
== 0 ? priv
->master
: priv
->slave
[i
- 1];
1876 /* Split the ids array into smaller arrays of ids having the same
1878 size_t set_es_idx
= 0;
1879 for (size_t ids_idx
= 0; ids_idx
< count
; ++ids_idx
)
1881 vlc_es_id_t
*id
= ids
[ids_idx
];
1882 if (vlc_es_id_GetSource(id
) == source
)
1883 array
[set_es_idx
++] = vlc_es_id_GetInputId(id
);
1886 /* Update all demuxers */
1889 if (set_es_idx
== 1)
1890 demux_Control(source
->p_demux
, DEMUX_SET_ES
, array
[0]);
1892 demux_Control(source
->p_demux
, DEMUX_SET_ES_LIST
, set_es_idx
,
1899 static bool Control( input_thread_t
*p_input
,
1900 int i_type
, input_control_param_t param
)
1902 input_thread_private_t
*priv
= input_priv(p_input
);
1903 const vlc_tick_t i_control_date
= vlc_tick_now();
1904 /* FIXME b_force_update is abused, it should be carefully checked */
1905 bool b_force_update
= false;
1910 case INPUT_CONTROL_SET_POSITION
:
1911 case INPUT_CONTROL_JUMP_POSITION
:
1913 const bool absolute
= i_type
== INPUT_CONTROL_SET_POSITION
;
1914 if( priv
->b_recording
)
1916 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION ignored while recording" );
1920 /* Reset the decoders states and clock sync (before calling the demuxer */
1921 es_out_Control( priv
->p_es_out
, ES_OUT_RESET_PCR
);
1922 if( demux_SetPosition( priv
->master
->p_demux
, (double)param
.pos
.f_val
,
1923 !param
.pos
.b_fast_seek
, absolute
) )
1925 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION "
1927 absolute
? "@" : param
.pos
.f_val
>= 0 ? "+" : "",
1928 param
.pos
.f_val
* 100.f
);
1932 if( priv
->i_slave
> 0 )
1933 SlaveSeek( p_input
);
1934 priv
->master
->b_eof
= false;
1936 b_force_update
= true;
1941 case INPUT_CONTROL_SET_TIME
:
1942 case INPUT_CONTROL_JUMP_TIME
:
1944 const bool absolute
= i_type
== INPUT_CONTROL_SET_TIME
;
1947 if( priv
->b_recording
)
1949 msg_Err( p_input
, "INPUT_CONTROL_SET_TIME ignored while recording" );
1953 /* Reset the decoders states and clock sync (before calling the demuxer */
1954 es_out_Control( priv
->p_es_out
, ES_OUT_RESET_PCR
);
1956 i_ret
= demux_SetTime( priv
->master
->p_demux
, param
.time
.i_val
,
1957 !param
.time
.b_fast_seek
, absolute
);
1960 vlc_tick_t i_length
;
1962 /* Emulate it with a SET_POS */
1963 if( !demux_Control( priv
->master
->p_demux
,
1964 DEMUX_GET_LENGTH
, &i_length
) && i_length
> 0 )
1966 double f_pos
= (double)param
.time
.i_val
/ (double)i_length
;
1967 i_ret
= demux_SetPosition( priv
->master
->p_demux
, f_pos
,
1968 !param
.time
.b_fast_seek
,
1974 msg_Warn( p_input
, "INPUT_CONTROL_SET_TIME %s%"PRId64
1975 " failed or not possible",
1976 absolute
? "@" : param
.time
.i_val
>= 0 ? "+" : "",
1981 if( priv
->i_slave
> 0 )
1982 SlaveSeek( p_input
);
1983 priv
->master
->b_eof
= false;
1985 b_force_update
= true;
1990 case INPUT_CONTROL_SET_STATE
:
1991 switch( param
.val
.i_int
)
1994 if( priv
->i_state
== PAUSE_S
)
1996 ControlUnpause( p_input
, i_control_date
);
1997 b_force_update
= true;
2001 if( priv
->i_state
== PLAYING_S
)
2003 ControlPause( p_input
, i_control_date
);
2004 b_force_update
= true;
2008 msg_Err( p_input
, "invalid INPUT_CONTROL_SET_STATE" );
2012 case INPUT_CONTROL_SET_RATE
:
2014 /* Get rate and direction */
2015 float rate
= fabsf( param
.val
.f_float
);
2016 int i_rate_sign
= param
.val
.f_float
< 0 ? -1 : 1;
2018 /* Check rate bound */
2019 if( rate
> INPUT_RATE_MAX
)
2021 msg_Info( p_input
, "cannot set rate faster" );
2022 rate
= INPUT_RATE_MAX
;
2024 else if( rate
< INPUT_RATE_MIN
)
2026 msg_Info( p_input
, "cannot set rate slower" );
2027 rate
= INPUT_RATE_MIN
;
2030 /* Apply direction */
2031 if( i_rate_sign
< 0 )
2033 if( priv
->master
->b_rescale_ts
)
2035 msg_Dbg( p_input
, "cannot set negative rate" );
2041 rate
*= i_rate_sign
;
2046 ( ( !priv
->b_can_rate_control
&& !priv
->master
->b_rescale_ts
) ||
2047 ( priv
->p_sout
&& !priv
->b_out_pace_control
) ) )
2049 msg_Dbg( p_input
, "cannot change rate" );
2052 if( rate
!= priv
->rate
&&
2053 !priv
->b_can_pace_control
&& priv
->b_can_rate_control
)
2055 if( !priv
->master
->b_rescale_ts
)
2056 es_out_Control( priv
->p_es_out
, ES_OUT_RESET_PCR
);
2058 if( demux_Control( priv
->master
->p_demux
, DEMUX_SET_RATE
,
2061 msg_Warn( p_input
, "ACCESS/DEMUX_SET_RATE failed" );
2067 if( rate
!= priv
->rate
)
2070 input_SendEventRate( p_input
, rate
);
2072 if( priv
->master
->b_rescale_ts
)
2074 const float rate_source
= (priv
->b_can_pace_control
|| priv
->b_can_rate_control
) ? rate
: 1.f
;
2075 es_out_SetRate( priv
->p_es_out
, rate_source
, rate
);
2078 b_force_update
= true;
2083 case INPUT_CONTROL_SET_PROGRAM
:
2084 /* No need to force update, es_out does it if needed */
2085 es_out_Control( priv
->p_es_out
,
2086 ES_OUT_SET_GROUP
, (int)param
.val
.i_int
);
2088 if( param
.val
.i_int
== 0 )
2089 demux_Control( priv
->master
->p_demux
,
2090 DEMUX_SET_GROUP_DEFAULT
);
2092 demux_Control( priv
->master
->p_demux
,
2093 DEMUX_SET_GROUP_LIST
,
2094 (size_t)1, &(const int){ param
.val
.i_int
});
2097 case INPUT_CONTROL_SET_ES
:
2098 if( es_out_SetEs( priv
->p_es_out_display
, param
.id
) == VLC_SUCCESS
)
2100 const input_source_t
*source
= vlc_es_id_GetSource( param
.id
);
2102 demux_Control( source
->p_demux
, DEMUX_SET_ES
,
2103 vlc_es_id_GetInputId( param
.id
) );
2106 case INPUT_CONTROL_SET_ES_LIST
:
2107 ControlSetEsList( p_input
, param
.list
.cat
, param
.list
.ids
);
2109 case INPUT_CONTROL_UNSET_ES
:
2110 es_out_UnsetEs( priv
->p_es_out_display
, param
.id
);
2112 case INPUT_CONTROL_RESTART_ES
:
2113 es_out_RestartEs( priv
->p_es_out_display
, param
.id
);
2115 case INPUT_CONTROL_SET_ES_CAT_IDS
:
2116 es_out_SetEsCatIds( priv
->p_es_out_display
, param
.cat_ids
.cat
,
2117 param
.cat_ids
.str_ids
);
2120 case INPUT_CONTROL_SET_VIEWPOINT
:
2121 case INPUT_CONTROL_SET_INITIAL_VIEWPOINT
:
2122 case INPUT_CONTROL_UPDATE_VIEWPOINT
:
2123 if ( i_type
== INPUT_CONTROL_SET_INITIAL_VIEWPOINT
)
2126 /* Set the initial viewpoint if it had not been changed by the
2128 if( !priv
->viewpoint_changed
)
2129 priv
->viewpoint
= param
.viewpoint
;
2130 /* Update viewpoints of aout and every vouts in all cases. */
2132 else if ( i_type
== INPUT_CONTROL_SET_VIEWPOINT
)
2134 priv
->viewpoint_changed
= true;
2135 priv
->viewpoint
= param
.viewpoint
;
2139 priv
->viewpoint_changed
= true;
2140 priv
->viewpoint
.yaw
+= param
.viewpoint
.yaw
;
2141 priv
->viewpoint
.pitch
+= param
.viewpoint
.pitch
;
2142 priv
->viewpoint
.roll
+= param
.viewpoint
.roll
;
2143 priv
->viewpoint
.fov
+= param
.viewpoint
.fov
;
2146 ViewpointApply( p_input
);
2149 case INPUT_CONTROL_SET_CATEGORY_DELAY
:
2150 assert(param
.cat_delay
.cat
== AUDIO_ES
2151 || param
.cat_delay
.cat
== SPU_ES
);
2152 es_out_SetDelay(priv
->p_es_out_display
,
2153 param
.cat_delay
.cat
, param
.cat_delay
.delay
);
2155 case INPUT_CONTROL_SET_ES_DELAY
:
2156 assert(param
.es_delay
.id
);
2157 es_out_SetEsDelay(priv
->p_es_out_display
, param
.es_delay
.id
,
2158 param
.es_delay
.delay
);
2161 case INPUT_CONTROL_SET_TITLE
:
2162 case INPUT_CONTROL_SET_TITLE_NEXT
:
2163 case INPUT_CONTROL_SET_TITLE_PREV
:
2165 if( priv
->b_recording
)
2167 msg_Err( p_input
, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
2170 if( priv
->master
->i_title
<= 0 )
2173 int i_title
= demux_GetTitle( priv
->master
->p_demux
);
2174 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
2176 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
2179 i_title
= param
.val
.i_int
;
2180 if( i_title
< 0 || i_title
>= priv
->master
->i_title
)
2183 es_out_Control( priv
->p_es_out
, ES_OUT_RESET_PCR
);
2184 demux_Control( priv
->master
->p_demux
,
2185 DEMUX_SET_TITLE
, i_title
);
2188 case INPUT_CONTROL_SET_SEEKPOINT
:
2189 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
2190 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
2192 if( priv
->b_recording
)
2194 msg_Err( p_input
, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
2197 if( priv
->master
->i_title
<= 0 )
2200 demux_t
*p_demux
= priv
->master
->p_demux
;
2202 int i_title
= demux_GetTitle( p_demux
);
2203 int i_seekpoint
= demux_GetSeekpoint( p_demux
);
2205 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
2207 vlc_tick_t i_seekpoint_time
= priv
->master
->title
[i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
2208 vlc_tick_t i_input_time
= var_GetInteger( p_input
, "time" );
2209 if( i_seekpoint_time
>= 0 && i_input_time
>= 0 )
2211 if( i_input_time
< i_seekpoint_time
+ VLC_TICK_FROM_SEC(3) )
2217 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
2220 i_seekpoint
= param
.val
.i_int
;
2222 || i_seekpoint
>= priv
->master
->title
[i_title
]->i_seekpoint
)
2225 es_out_Control( priv
->p_es_out
, ES_OUT_RESET_PCR
);
2226 demux_Control( priv
->master
->p_demux
,
2227 DEMUX_SET_SEEKPOINT
, i_seekpoint
);
2228 input_SendEventSeekpoint( p_input
, i_title
, i_seekpoint
);
2229 if( priv
->i_slave
> 0 )
2230 SlaveSeek( p_input
);
2234 case INPUT_CONTROL_ADD_SLAVE
:
2235 if( param
.val
.p_address
)
2237 input_item_slave_t
*p_item_slave
= param
.val
.p_address
;
2238 unsigned i_flags
= SLAVE_ADD_CANFAIL
| SLAVE_ADD_SET_TIME
;
2239 if( p_item_slave
->b_forced
)
2240 i_flags
|= SLAVE_ADD_FORCED
;
2242 if( input_SlaveSourceAdd( p_input
, p_item_slave
->i_type
,
2243 p_item_slave
->psz_uri
, i_flags
)
2246 /* Update item slaves */
2247 input_item_AddSlave( priv
->p_item
, p_item_slave
);
2248 /* The slave is now owned by the item */
2249 param
.val
.p_address
= NULL
;
2253 case INPUT_CONTROL_SET_SUBS_FPS
:
2254 RequestSubRate( p_input
, param
.val
.f_float
);
2255 input_SendEventSubsFPS( p_input
, param
.val
.f_float
);
2258 case INPUT_CONTROL_SET_RECORD_STATE
:
2260 if( !!priv
->b_recording
!= !!val
.b_bool
)
2262 if( priv
->master
->b_can_stream_record
)
2264 if( demux_Control( priv
->master
->p_demux
,
2265 DEMUX_SET_RECORD_STATE
, val
.b_bool
) )
2270 if( es_out_SetRecordState( priv
->p_es_out_display
, val
.b_bool
) )
2273 priv
->b_recording
= val
.b_bool
;
2275 input_SendEventRecord( p_input
, val
.b_bool
);
2277 b_force_update
= true;
2281 case INPUT_CONTROL_SET_FRAME_NEXT
:
2282 if( priv
->i_state
== PAUSE_S
)
2284 es_out_SetFrameNext( priv
->p_es_out
);
2286 else if( priv
->i_state
== PLAYING_S
)
2288 ControlPause( p_input
, i_control_date
);
2292 msg_Err( p_input
, "invalid state for frame next" );
2294 b_force_update
= true;
2297 case INPUT_CONTROL_SET_RENDERER
:
2300 vlc_renderer_item_t
*p_item
= param
.val
.p_address
;
2301 input_thread_private_t
*p_priv
= input_priv( p_input
);
2302 // We do not support switching from a renderer to another for now
2303 if ( p_item
== NULL
&& p_priv
->p_renderer
== NULL
)
2307 if( es_out_StopAllEs( priv
->p_es_out_display
, &context
) != VLC_SUCCESS
)
2310 if ( p_priv
->p_renderer
)
2312 ControlUpdateRenderer( p_input
, false );
2313 demux_FilterDisable( p_priv
->master
->p_demux
,
2314 vlc_renderer_item_demux_filter( p_priv
->p_renderer
) );
2315 vlc_renderer_item_release( p_priv
->p_renderer
);
2316 p_priv
->p_renderer
= NULL
;
2318 if( p_item
!= NULL
)
2320 p_priv
->p_renderer
= vlc_renderer_item_hold( p_item
);
2321 ControlUpdateRenderer( p_input
, true );
2322 if( !demux_FilterEnable( p_priv
->master
->p_demux
,
2323 vlc_renderer_item_demux_filter( p_priv
->p_renderer
) ) )
2325 ControlInsertDemuxFilter( p_input
,
2326 vlc_renderer_item_demux_filter( p_item
) );
2329 es_out_StartAllEs( priv
->p_es_out_display
, context
);
2333 case INPUT_CONTROL_SET_VBI_PAGE
:
2334 es_out_SetVbiPage( priv
->p_es_out_display
, param
.vbi_page
.id
,
2335 param
.vbi_page
.page
);
2337 case INPUT_CONTROL_SET_VBI_TRANSPARENCY
:
2338 es_out_SetVbiTransparency( priv
->p_es_out_display
,
2339 param
.vbi_transparency
.id
,
2340 param
.vbi_transparency
.enabled
);
2343 case INPUT_CONTROL_NAV_ACTIVATE
:
2344 case INPUT_CONTROL_NAV_UP
:
2345 case INPUT_CONTROL_NAV_DOWN
:
2346 case INPUT_CONTROL_NAV_LEFT
:
2347 case INPUT_CONTROL_NAV_RIGHT
:
2348 case INPUT_CONTROL_NAV_POPUP
:
2349 case INPUT_CONTROL_NAV_MENU
:
2350 ControlNav( p_input
, i_type
);
2354 msg_Err( p_input
, "not yet implemented" );
2358 ControlRelease( i_type
, ¶m
);
2359 return b_force_update
;
2362 /*****************************************************************************
2363 * UpdateTitleSeekpoint
2364 *****************************************************************************/
2365 static int UpdateTitleSeekpoint( input_thread_t
*p_input
,
2366 int i_title
, int i_seekpoint
)
2368 int i_title_end
= input_priv(p_input
)->master
->i_title_end
-
2369 input_priv(p_input
)->master
->i_title_offset
;
2370 int i_seekpoint_end
= input_priv(p_input
)->master
->i_seekpoint_end
-
2371 input_priv(p_input
)->master
->i_seekpoint_offset
;
2373 if( i_title_end
>= 0 && i_seekpoint_end
>= 0 )
2375 if( i_title
> i_title_end
||
2376 ( i_title
== i_title_end
&& i_seekpoint
> i_seekpoint_end
) )
2377 return VLC_DEMUXER_EOF
;
2379 else if( i_seekpoint_end
>= 0 )
2381 if( i_seekpoint
> i_seekpoint_end
)
2382 return VLC_DEMUXER_EOF
;
2384 else if( i_title_end
>= 0 )
2386 if( i_title
> i_title_end
)
2387 return VLC_DEMUXER_EOF
;
2389 return VLC_DEMUXER_SUCCESS
;
2391 /*****************************************************************************
2393 *****************************************************************************/
2394 static int UpdateTitleSeekpointFromDemux( input_thread_t
*p_input
)
2396 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2398 /* TODO event-like */
2399 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_TITLE
) )
2400 input_SendEventTitle( p_input
, &(struct vlc_input_event_title
) {
2401 .action
= VLC_INPUT_TITLE_SELECTED
,
2402 .selected_idx
= demux_GetTitle( p_demux
),
2405 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_SEEKPOINT
) )
2406 input_SendEventSeekpoint( p_input
, demux_GetTitle( p_demux
),
2407 demux_GetSeekpoint( p_demux
) );
2409 return UpdateTitleSeekpoint( p_input
,
2410 demux_GetTitle( p_demux
),
2411 demux_GetSeekpoint( p_demux
) );
2414 static void UpdateGenericFromDemux( input_thread_t
*p_input
)
2416 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2418 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_META
) )
2419 InputUpdateMeta( p_input
, p_demux
);
2425 if( !demux_Control( p_demux
, DEMUX_GET_SIGNAL
, &quality
, &strength
) )
2426 input_SendEventSignal( p_input
, quality
, strength
);
2430 static void UpdateTitleListfromDemux( input_thread_t
*p_input
)
2432 input_thread_private_t
*priv
= input_priv(p_input
);
2433 input_source_t
*in
= priv
->master
;
2435 /* Delete the preexisting titles */
2436 bool had_titles
= in
->i_title
> 0;
2439 for( int i
= 0; i
< in
->i_title
; i
++ )
2440 vlc_input_title_Delete( in
->title
[i
] );
2442 TAB_CLEAN( in
->i_title
, in
->title
);
2444 /* Get the new title list */
2445 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2446 &in
->title
, &in
->i_title
,
2447 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2448 TAB_INIT( in
->i_title
, in
->title
);
2450 in
->b_title_demux
= true;
2452 InitTitle( p_input
, had_titles
);
2456 InputStreamHandleAnchor( input_thread_t
*p_input
, input_source_t
*source
,
2457 stream_t
**stream
, char const *anchor
)
2460 if( stream_extractor_AttachParsed( stream
, anchor
, &extra
) )
2462 msg_Err( p_input
, "unable to attach stream-extractors for %s",
2463 (*stream
)->psz_url
);
2465 return VLC_EGENERIC
;
2468 if( vlc_stream_directory_Attach( stream
, NULL
) )
2469 msg_Dbg( p_input
, "attachment of directory-extractor failed for %s",
2470 (*stream
)->psz_url
);
2472 MRLSections( extra
? extra
: "",
2473 &source
->i_title_start
, &source
->i_title_end
,
2474 &source
->i_seekpoint_start
, &source
->i_seekpoint_end
);
2479 static demux_t
*InputDemuxNew( input_thread_t
*p_input
, es_out_t
*p_es_out
,
2480 input_source_t
*p_source
, const char *url
,
2481 const char *psz_demux
, const char *psz_anchor
)
2483 input_thread_private_t
*priv
= input_priv(p_input
);
2484 vlc_object_t
*obj
= VLC_OBJECT(p_input
);
2486 /* create the underlying access stream */
2487 stream_t
*p_stream
= stream_AccessNew( obj
, p_input
, p_es_out
,
2488 priv
->b_preparsing
, url
);
2489 if( p_stream
== NULL
)
2492 p_stream
= stream_FilterAutoNew( p_stream
);
2494 if( p_stream
->pf_read
== NULL
&& p_stream
->pf_block
== NULL
2495 && p_stream
->pf_readdir
== NULL
)
2496 { /* Combined access/demux, no stream filtering */
2497 MRLSections( psz_anchor
,
2498 &p_source
->i_title_start
, &p_source
->i_title_end
,
2499 &p_source
->i_seekpoint_start
, &p_source
->i_seekpoint_end
);
2503 /* attach explicit stream filters to stream */
2504 char *psz_filters
= var_InheritString( p_input
, "stream-filter" );
2507 p_stream
= stream_FilterChainNew( p_stream
, psz_filters
);
2508 free( psz_filters
);
2511 /* handle anchors */
2512 if( InputStreamHandleAnchor( p_input
, p_source
, &p_stream
, psz_anchor
) )
2515 /* attach conditional record stream-filter */
2516 if( var_InheritBool( p_input
, "input-record-native" ) )
2517 p_stream
= stream_FilterChainNew( p_stream
, "record" );
2519 /* create a regular demux with the access stream created */
2520 demux_t
*demux
= demux_NewAdvanced( obj
, p_input
, psz_demux
, url
, p_stream
,
2521 p_es_out
, priv
->b_preparsing
);
2526 vlc_stream_Delete( p_stream
);
2530 static void input_SplitMRL( const char **, const char **, const char **,
2531 const char **, char * );
2533 static input_source_t
*InputSourceNew( const char *psz_mrl
)
2535 input_source_t
*in
= calloc(1, sizeof(*in
) );
2536 if( unlikely(in
== NULL
) )
2539 vlc_atomic_rc_init( &in
->rc
);
2543 /* Use the MD5 sum of the complete source URL as an identifier. */
2546 AddMD5( &md5
, psz_mrl
, strlen( psz_mrl
) );
2548 in
->str_id
= psz_md5_hash( &md5
);
2559 static int InputSourceInit( input_source_t
*in
, input_thread_t
*p_input
,
2560 const char *psz_mrl
,
2561 const char *psz_forced_demux
, bool b_in_can_fail
)
2563 input_thread_private_t
*priv
= input_priv(p_input
);
2564 const char *psz_access
, *psz_demux
, *psz_path
, *psz_anchor
= NULL
;
2565 const bool master
= priv
->master
== in
;
2568 char *psz_dup
= strdup( psz_mrl
);
2569 char *psz_demux_var
= NULL
;
2571 if( psz_dup
== NULL
)
2575 input_SplitMRL( &psz_access
, &psz_demux
, &psz_path
, &psz_anchor
, psz_dup
);
2577 if( psz_demux
== NULL
|| psz_demux
[0] == '\0' )
2578 psz_demux
= psz_demux_var
= var_InheritString( p_input
, "demux" );
2580 if( psz_forced_demux
!= NULL
)
2581 psz_demux
= psz_forced_demux
;
2583 if( psz_demux
== NULL
)
2586 msg_Dbg( p_input
, "`%s' gives access `%s' demux `%s' path `%s'",
2587 psz_mrl
, psz_access
, psz_demux
, psz_path
);
2589 if( input_priv(p_input
)->master
== NULL
/* XXX ugly */)
2590 { /* On master stream only, use input-list */
2591 char *str
= var_InheritString( p_input
, "input-list" );
2596 var_Create( p_input
, "concat-list", VLC_VAR_STRING
);
2597 if( likely(asprintf( &list
, "%s://%s,%s", psz_access
, psz_path
,
2600 var_SetString( p_input
, "concat-list", list
);
2604 psz_access
= "concat";
2608 if( strcasecmp( psz_access
, "concat" ) )
2609 { /* Autodetect extra files if none specified */
2613 TAB_INIT( count
, tab
);
2614 InputGetExtraFiles( p_input
, &count
, &tab
, &psz_access
, psz_path
);
2619 for( int i
= 0; i
< count
; i
++ )
2622 if( asprintf( &str
, "%s,%s", list
? list
: psz_mrl
,
2631 var_Create( p_input
, "concat-list", VLC_VAR_STRING
);
2632 if( likely(list
!= NULL
) )
2634 var_SetString( p_input
, "concat-list", list
);
2638 TAB_CLEAN( count
, tab
);
2642 if( likely(asprintf( &url
, "%s://%s", psz_access
, psz_path
) >= 0) )
2646 es_out
= in
->p_slave_es_out
=
2647 input_EsOutSourceNew( priv
->p_es_out
, in
);
2649 es_out
= priv
->p_es_out
;
2652 in
->p_demux
= InputDemuxNew( p_input
, es_out
, in
, url
,
2653 psz_demux
, psz_anchor
);
2659 free( psz_demux_var
);
2662 if( in
->p_demux
== NULL
)
2664 if( !b_in_can_fail
&& !input_Stopped( p_input
) )
2665 vlc_dialog_display_error( p_input
, _("Your input can't be opened"),
2666 _("VLC is unable to open the MRL '%s'."
2667 " Check the log for details."), psz_mrl
);
2668 if( in
->p_slave_es_out
)
2670 es_out_Delete( in
->p_slave_es_out
);
2671 in
->p_slave_es_out
= NULL
;
2673 return VLC_EGENERIC
;
2676 char *psz_demux_chain
= NULL
;
2677 if( priv
->p_renderer
)
2679 const char* psz_renderer_demux
= vlc_renderer_item_demux_filter(
2681 if( psz_renderer_demux
)
2682 psz_demux_chain
= strdup( psz_renderer_demux
);
2684 if( !psz_demux_chain
)
2685 psz_demux_chain
= var_GetNonEmptyString(p_input
, "demux-filter");
2686 if( psz_demux_chain
!= NULL
) /* add the chain of demux filters */
2688 in
->p_demux
= demux_FilterChainNew( in
->p_demux
, psz_demux_chain
);
2689 free( psz_demux_chain
);
2691 if( in
->p_demux
== NULL
)
2693 msg_Err(p_input
, "Failed to create demux filter");
2694 if( in
->p_slave_es_out
)
2696 es_out_Delete( in
->p_slave_es_out
);
2697 in
->p_slave_es_out
= NULL
;
2699 return VLC_EGENERIC
;
2703 /* Get infos from (access_)demux */
2704 int capabilites
= 0;
2706 if( demux_Control( in
->p_demux
, DEMUX_CAN_SEEK
, &b_can_seek
) )
2709 capabilites
|= VLC_INPUT_CAPABILITIES_SEEKABLE
;
2711 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_PACE
,
2712 &in
->b_can_pace_control
) )
2713 in
->b_can_pace_control
= false;
2715 assert( in
->p_demux
->pf_demux
!= NULL
|| !in
->b_can_pace_control
);
2717 if( !in
->b_can_pace_control
)
2719 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_RATE
,
2720 &in
->b_can_rate_control
) )
2722 in
->b_can_rate_control
= false;
2723 in
->b_rescale_ts
= true;
2726 in
->b_rescale_ts
= !in
->b_can_rate_control
;
2730 in
->b_can_rate_control
= true;
2731 in
->b_rescale_ts
= true;
2734 demux_Control( in
->p_demux
, DEMUX_CAN_PAUSE
, &in
->b_can_pause
);
2736 if( in
->b_can_pause
|| !in
->b_can_pace_control
)
2737 capabilites
|= VLC_INPUT_CAPABILITIES_PAUSEABLE
;
2738 if( !in
->b_can_pace_control
|| in
->b_can_rate_control
)
2739 capabilites
|= VLC_INPUT_CAPABILITIES_CHANGE_RATE
;
2740 if( !in
->b_rescale_ts
&& !in
->b_can_pace_control
&& in
->b_can_rate_control
)
2741 capabilites
|= VLC_INPUT_CAPABILITIES_REWINDABLE
;
2743 /* Set record capabilities */
2744 if( demux_Control( in
->p_demux
, DEMUX_CAN_RECORD
, &in
->b_can_stream_record
) )
2745 in
->b_can_stream_record
= false;
2747 if( !var_GetBool( p_input
, "input-record-native" ) )
2748 in
->b_can_stream_record
= false;
2749 capabilites
|= VLC_INPUT_CAPABILITIES_RECORDABLE
;
2751 if( in
->b_can_stream_record
)
2752 capabilites
|= VLC_INPUT_CAPABILITIES_RECORDABLE
;
2755 input_SendEventCapabilities( p_input
, capabilites
);
2758 * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2759 if( !input_priv(p_input
)->b_preparsing
)
2761 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2762 &in
->title
, &in
->i_title
,
2763 &in
->i_title_offset
, &in
->i_seekpoint_offset
))
2765 TAB_INIT( in
->i_title
, in
->title
);
2769 in
->b_title_demux
= true;
2772 demux_Control( in
->p_demux
, DEMUX_GET_PTS_DELAY
, &in
->i_pts_delay
);
2773 if( in
->i_pts_delay
> INPUT_PTS_DELAY_MAX
)
2774 in
->i_pts_delay
= INPUT_PTS_DELAY_MAX
;
2775 else if( in
->i_pts_delay
< 0 )
2776 in
->i_pts_delay
= 0;
2780 input_attachment_t
**attachment
;
2781 if( !demux_Control( in
->p_demux
, DEMUX_GET_ATTACHMENTS
,
2782 &attachment
, &i_attachment
) )
2784 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2785 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2786 i_attachment
, attachment
, in
->p_demux
);
2787 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2790 if( demux_Control( in
->p_demux
, DEMUX_GET_FPS
, &in
->f_fps
) )
2793 if( var_GetInteger( p_input
, "clock-synchro" ) != -1 )
2794 in
->b_can_pace_control
= !var_GetInteger( p_input
, "clock-synchro" );
2799 input_source_t
*input_source_Hold( input_source_t
*in
)
2801 vlc_atomic_rc_inc( &in
->rc
);
2805 void input_source_Release( input_source_t
*in
)
2807 if( vlc_atomic_rc_dec( &in
->rc
) )
2814 const char *input_source_GetStrId( input_source_t
*in
)
2819 int input_source_GetNewAutoId( input_source_t
*in
)
2821 return in
->auto_id
++;
2824 bool input_source_IsCatAutoselected( input_source_t
*in
,
2825 enum es_format_category_e cat
)
2827 return in
->autoselect_cats
[cat
];
2830 /*****************************************************************************
2831 * InputSourceDestroy:
2832 *****************************************************************************/
2833 static void InputSourceDestroy( input_source_t
*in
)
2838 demux_Delete( in
->p_demux
);
2839 if( in
->p_slave_es_out
)
2840 es_out_Delete( in
->p_slave_es_out
);
2842 if( in
->i_title
> 0 )
2844 for( i
= 0; i
< in
->i_title
; i
++ )
2845 vlc_input_title_Delete( in
->title
[i
] );
2847 TAB_CLEAN( in
->i_title
, in
->title
);
2850 /*****************************************************************************
2852 *****************************************************************************/
2853 static void InputSourceMeta( input_thread_t
*p_input
,
2854 input_source_t
*p_source
, vlc_meta_t
*p_meta
)
2856 demux_t
*p_demux
= p_source
->p_demux
;
2858 /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
2861 bool has_meta
= false;
2863 /* Read demux meta */
2864 if( !demux_Control( p_demux
, DEMUX_GET_META
, p_meta
) )
2867 bool has_unsupported
;
2868 if( demux_Control( p_demux
, DEMUX_HAS_UNSUPPORTED_META
, &has_unsupported
) )
2869 has_unsupported
= true;
2871 /* If the demux report unsupported meta data, or if we don't have meta data
2872 * try an external "meta reader" */
2873 if( has_meta
&& !has_unsupported
)
2876 demux_meta_t
*p_demux_meta
=
2877 vlc_custom_create( p_input
, sizeof( *p_demux_meta
), "demux meta" );
2878 if( unlikely(p_demux_meta
== NULL
) )
2880 p_demux_meta
->p_item
= input_priv(p_input
)->p_item
;
2882 module_t
*p_id3
= module_need( p_demux_meta
, "meta reader", NULL
, false );
2885 if( p_demux_meta
->p_meta
)
2887 vlc_meta_Merge( p_meta
, p_demux_meta
->p_meta
);
2888 vlc_meta_Delete( p_demux_meta
->p_meta
);
2891 if( p_demux_meta
->i_attachments
> 0 )
2893 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2894 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2895 p_demux_meta
->i_attachments
, p_demux_meta
->attachments
, p_demux
);
2896 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2898 module_unneed( p_demux
, p_id3
);
2900 vlc_object_delete(p_demux_meta
);
2904 static void SlaveDemux( input_thread_t
*p_input
)
2906 input_thread_private_t
*priv
= input_priv(p_input
);
2910 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
2912 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2916 for( i
= 0; i
< input_priv(p_input
)->i_slave
; i
++ )
2918 input_source_t
*in
= input_priv(p_input
)->slave
[i
];
2924 if( priv
->slave_subs_rate
!= in
->sub_rate
)
2926 if( in
->b_slave_sub
&& in
->b_can_rate_control
)
2928 if( in
->sub_rate
!= 0 ) /* Don't reset when it's the first time */
2929 es_out_Control( priv
->p_es_out
, ES_OUT_RESET_PCR
);
2930 float new_rate
= priv
->slave_subs_rate
;
2931 demux_Control( in
->p_demux
, DEMUX_SET_RATE
, &new_rate
);
2933 in
->sub_rate
= priv
->slave_subs_rate
;
2937 /* Call demux_Demux until we have read enough data */
2938 if( demux_Control( in
->p_demux
, DEMUX_SET_NEXT_DEMUX_TIME
, i_time
) )
2943 if( demux_Control( in
->p_demux
, DEMUX_GET_TIME
, &i_stime
) )
2945 msg_Err( p_input
, "slave[%d] doesn't like "
2946 "DEMUX_GET_TIME -> EOF", i
);
2951 if( i_stime
>= i_time
)
2957 if( ( i_ret
= demux_Demux( in
->p_demux
) ) <= 0 )
2963 i_ret
= demux_Demux( in
->p_demux
);
2968 msg_Dbg( p_input
, "slave %d EOF", i
);
2974 static void SlaveSeek( input_thread_t
*p_input
)
2979 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
2981 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2985 for( i
= 0; i
< input_priv(p_input
)->i_slave
; i
++ )
2987 input_source_t
*in
= input_priv(p_input
)->slave
[i
];
2989 if( demux_Control( in
->p_demux
, DEMUX_SET_TIME
, i_time
, true ) )
2992 msg_Err( p_input
, "seek failed for slave %d -> EOF", i
);
3002 /*****************************************************************************
3004 *****************************************************************************/
3005 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
3007 static const struct { int i_meta
; const char *psz_name
; } p_list
[] = {
3008 { vlc_meta_Title
, "meta-title" },
3009 { vlc_meta_Artist
, "meta-artist" },
3010 { vlc_meta_Genre
, "meta-genre" },
3011 { vlc_meta_Copyright
, "meta-copyright" },
3012 { vlc_meta_Description
, "meta-description" },
3013 { vlc_meta_Date
, "meta-date" },
3014 { vlc_meta_URL
, "meta-url" },
3018 /* Get meta information from user */
3019 for( int i
= 0; p_list
[i
].psz_name
; i
++ )
3021 char *psz_string
= var_GetNonEmptyString( p_input
, p_list
[i
].psz_name
);
3025 EnsureUTF8( psz_string
);
3026 vlc_meta_Set( p_meta
, p_list
[i
].i_meta
, psz_string
);
3031 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
3032 const demux_t
***ppp_attachment_demux
,
3033 int i_new
, input_attachment_t
**pp_new
, const demux_t
*p_demux
)
3035 int i_attachment
= *pi_attachment
;
3038 if ( i_attachment
+ i_new
== 0 )
3042 input_attachment_t
**pp_att
= realloc( *ppp_attachment
,
3043 sizeof(*pp_att
) * ( i_attachment
+ i_new
) );
3044 if( likely(pp_att
) )
3046 *ppp_attachment
= pp_att
;
3047 const demux_t
**pp_attdmx
= realloc( *ppp_attachment_demux
,
3048 sizeof(*pp_attdmx
) * ( i_attachment
+ i_new
) );
3049 if( likely(pp_attdmx
) )
3051 *ppp_attachment_demux
= pp_attdmx
;
3053 for( i
= 0; i
< i_new
; i
++ )
3055 pp_att
[i_attachment
] = pp_new
[i
];
3056 pp_attdmx
[i_attachment
++] = p_demux
;
3059 *pi_attachment
= i_attachment
;
3065 /* on alloc errors */
3066 for( i
= 0; i
< i_new
; i
++ )
3067 vlc_input_attachment_Delete( pp_new
[i
] );
3071 /*****************************************************************************
3072 * InputUpdateMeta: merge p_item meta data with p_meta taking care of
3073 * arturl and locking issue.
3074 *****************************************************************************/
3075 static void InputUpdateMeta( input_thread_t
*p_input
, demux_t
*p_demux
)
3077 vlc_meta_t
*p_meta
= vlc_meta_New();
3078 if( unlikely(p_meta
== NULL
) )
3081 demux_Control( p_demux
, DEMUX_GET_META
, p_meta
);
3083 /* If metadata changed, then the attachments might have changed.
3084 We need to update them in case they contain album art. */
3085 input_attachment_t
**attachment
;
3088 if( !demux_Control( p_demux
, DEMUX_GET_ATTACHMENTS
,
3089 &attachment
, &i_attachment
) )
3091 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
3092 if( input_priv(p_input
)->i_attachment
> 0 )
3095 for( int i
= 0; i
< input_priv(p_input
)->i_attachment
; i
++ )
3097 if( input_priv(p_input
)->attachment_demux
[i
] == p_demux
)
3098 vlc_input_attachment_Delete( input_priv(p_input
)->attachment
[i
] );
3101 input_priv(p_input
)->attachment
[j
] = input_priv(p_input
)->attachment
[i
];
3102 input_priv(p_input
)->attachment_demux
[j
] = input_priv(p_input
)->attachment_demux
[i
];
3106 input_priv(p_input
)->i_attachment
= j
;
3108 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
3109 i_attachment
, attachment
, p_demux
);
3110 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
3113 es_out_ControlSetMeta( input_priv(p_input
)->p_es_out
, p_meta
);
3114 vlc_meta_Delete( p_meta
);
3117 /*****************************************************************************
3118 * InputGetExtraFiles
3119 * Autodetect extra input list
3120 *****************************************************************************/
3121 static void InputGetExtraFilesPattern( input_thread_t
*p_input
,
3122 int *pi_list
, char ***pppsz_list
,
3123 const char *psz_path
,
3124 const char *psz_match
,
3125 const char *psz_format
,
3126 int i_start
, int i_stop
)
3130 TAB_INIT( i_list
, ppsz_list
);
3132 char *psz_base
= strdup( psz_path
);
3136 /* Remove the extension */
3137 char *psz_end
= &psz_base
[strlen(psz_base
)-strlen(psz_match
)];
3138 assert( psz_end
>= psz_base
);
3141 /* Try to list files */
3142 for( int i
= i_start
; i
<= i_stop
; i
++ )
3145 if( asprintf( &psz_probe
, psz_format
, psz_base
, i
) < 0 )
3148 char *filepath
= get_path( psz_probe
);
3151 if( filepath
== NULL
||
3152 vlc_stat( filepath
, &st
) || !S_ISREG( st
.st_mode
) || !st
.st_size
)
3159 msg_Dbg( p_input
, "Detected extra file `%s'", filepath
);
3161 char* psz_uri
= vlc_path2uri( filepath
, NULL
);
3163 TAB_APPEND( i_list
, ppsz_list
, psz_uri
);
3171 *pppsz_list
= ppsz_list
;
3174 static void InputGetExtraFiles( input_thread_t
*p_input
,
3175 int *pi_list
, char ***pppsz_list
,
3176 const char **ppsz_access
, const char *psz_path
)
3178 static const struct pattern
3180 const char *psz_access_force
;
3181 const char *psz_match
;
3182 const char *psz_format
;
3186 /* XXX the order is important */
3187 { "concat", ".001", "%s.%.3d", 2, 999 },
3188 { NULL
, ".part1.rar","%s.part%.1d.rar", 2, 9 },
3189 { NULL
, ".part01.rar","%s.part%.2d.rar", 2, 99, },
3190 { NULL
, ".part001.rar", "%s.part%.3d.rar", 2, 999 },
3191 { NULL
, ".rar", "%s.r%.2d", 0, 99 },
3192 { "concat", ".mts", "%s.mts%d", 1, 999 },
3195 TAB_INIT( *pi_list
, *pppsz_list
);
3197 if( ( **ppsz_access
&& strcmp( *ppsz_access
, "file" ) ) || !psz_path
)
3200 const size_t i_path
= strlen(psz_path
);
3202 for( size_t i
= 0; i
< ARRAY_SIZE( patterns
); ++i
)
3204 const struct pattern
* pat
= &patterns
[i
];
3205 const size_t i_ext
= strlen( pat
->psz_match
);
3207 if( i_path
< i_ext
)
3210 if( !strcmp( &psz_path
[i_path
-i_ext
], pat
->psz_match
) )
3212 InputGetExtraFilesPattern( p_input
, pi_list
, pppsz_list
, psz_path
,
3213 pat
->psz_match
, pat
->psz_format
, pat
->i_start
, pat
->i_stop
);
3215 if( *pi_list
> 0 && pat
->psz_access_force
)
3216 *ppsz_access
= pat
->psz_access_force
;
3223 static void input_ChangeState( input_thread_t
*p_input
, int i_state
,
3224 vlc_tick_t state_date
)
3226 if( input_priv(p_input
)->i_state
== i_state
)
3229 input_priv(p_input
)->i_state
= i_state
;
3230 if( i_state
== ERROR_S
)
3231 input_item_SetErrorWhenReading( input_priv(p_input
)->p_item
, true );
3232 input_SendEventState( p_input
, i_state
, state_date
);
3236 /*****************************************************************************
3237 * MRLSplit: parse the access, demux and url part of the
3238 * Media Resource Locator.
3239 *****************************************************************************/
3240 static void input_SplitMRL( const char **access
, const char **demux
,
3241 const char **path
, const char **anchor
, char *buf
)
3245 /* Separate <path> from <access>[/<demux>]:// */
3246 p
= strstr( buf
, "://" );
3250 p
+= 3; /* skips "://" */
3253 /* Remove HTML anchor if present (not supported).
3254 * The hash symbol itself should be URI-encoded. */
3255 p
= strchr( p
, '#' );
3267 fprintf( stderr
, "%s(\"%s\") probably not a valid URI!\n", __func__
,
3270 /* Note: this is a valid non const pointer to "": */
3271 *path
= buf
+ strlen( buf
);
3274 /* Separate access from demux */
3275 p
= strchr( buf
, '/' );
3286 /* We really don't want module name substitution here! */
3293 static const char *MRLSeekPoint( const char *str
, int *title
, int *chapter
)
3298 /* Look for the title */
3299 u
= strtoul( str
, &end
, 0 );
3300 *title
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3303 /* Look for the chapter */
3307 u
= strtoul( str
, &end
, 0 );
3308 *chapter
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3318 /*****************************************************************************
3319 * MRLSections: parse title and seekpoint info from the Media Resource Locator.
3322 * [url][@[title_start][:chapter_start][-[title_end][:chapter_end]]]
3323 *****************************************************************************/
3324 static void MRLSections( const char *p
,
3325 int *pi_title_start
, int *pi_title_end
,
3326 int *pi_chapter_start
, int *pi_chapter_end
)
3328 *pi_title_start
= *pi_title_end
= *pi_chapter_start
= *pi_chapter_end
= -1;
3330 int title_start
, chapter_start
, title_end
, chapter_end
;
3336 p
= MRLSeekPoint( p
, &title_start
, &chapter_start
);
3338 title_start
= chapter_start
= -1;
3341 p
= MRLSeekPoint( p
+ 1, &title_end
, &chapter_end
);
3343 title_end
= chapter_end
= -1;
3345 if( *p
) /* syntax error */
3348 *pi_title_start
= title_start
;
3349 *pi_title_end
= title_end
;
3350 *pi_chapter_start
= chapter_start
;
3351 *pi_chapter_end
= chapter_end
;
3354 static int input_SlaveSourceAdd( input_thread_t
*p_input
,
3355 enum slave_type i_type
, const char *psz_uri
,
3358 input_thread_private_t
*priv
= input_priv(p_input
);
3359 const char *psz_forced_demux
;
3360 const bool b_can_fail
= i_flags
& SLAVE_ADD_CANFAIL
;
3361 const bool b_forced
= i_flags
& SLAVE_ADD_FORCED
;
3362 const bool b_set_time
= i_flags
& SLAVE_ADD_SET_TIME
;
3363 enum es_format_category_e i_cat
;
3367 case SLAVE_TYPE_SPU
:
3368 psz_forced_demux
= "subtitle";
3371 case SLAVE_TYPE_AUDIO
:
3372 psz_forced_demux
= NULL
;
3376 vlc_assert_unreachable();
3379 msg_Dbg( p_input
, "loading %s slave: %s (forced: %d)",
3380 i_cat
== SPU_ES
? "spu" : "audio", psz_uri
, b_forced
);
3382 priv
->i_last_es_cat
= UNKNOWN_ES
;
3384 input_source_t
*p_source
= InputSourceNew( psz_uri
);
3386 return VLC_EGENERIC
;
3389 p_source
->autoselect_cats
[i_cat
] = true;
3391 int ret
= InputSourceInit( p_source
, p_input
, psz_uri
,
3393 b_can_fail
|| psz_forced_demux
);
3395 if( psz_forced_demux
&& ret
!= VLC_SUCCESS
)
3396 ret
= InputSourceInit( p_source
, p_input
, psz_uri
, NULL
, b_can_fail
);
3398 if( ret
!= VLC_SUCCESS
)
3400 msg_Warn( p_input
, "failed to add %s as slave", psz_uri
);
3401 return VLC_EGENERIC
;
3404 if( i_type
== SLAVE_TYPE_AUDIO
)
3411 if( demux_Control( priv
->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
3413 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
3414 InputSourceDestroy( p_source
);
3415 input_source_Release( p_source
);
3416 return VLC_EGENERIC
;
3419 if( demux_Control( p_source
->p_demux
,
3420 DEMUX_SET_TIME
, i_time
, true ) )
3422 msg_Err( p_input
, "seek failed for new slave" );
3423 InputSourceDestroy( p_source
);
3424 input_source_Release( p_source
);
3425 return VLC_EGENERIC
;
3429 /* Get meta (access and demux) */
3430 InputUpdateMeta( p_input
, p_source
->p_demux
);
3433 p_source
->b_slave_sub
= true;
3435 TAB_APPEND( priv
->i_slave
, priv
->slave
, p_source
);
3437 if( !b_forced
|| priv
->i_last_es_cat
!= i_cat
)
3440 assert( priv
->i_last_es_id
!= -1 );
3442 es_out_SetEsDefaultById( priv
->p_es_out_display
, priv
->i_last_es_id
);
3443 es_out_SetEsById( priv
->p_es_out_display
, priv
->i_last_es_id
, false );
3448 static char *input_SubtitleFile2Uri( input_thread_t
*p_input
,
3449 const char *psz_subtitle
)
3451 /* if we are provided a subtitle.sub file,
3452 * see if we don't have a subtitle.idx and use it instead */
3453 char *psz_idxpath
= NULL
;
3454 char *psz_extension
= strrchr( psz_subtitle
, '.');
3455 if( psz_extension
&& strcmp( psz_extension
, ".sub" ) == 0 )
3457 psz_idxpath
= strdup( psz_subtitle
);
3462 psz_extension
= psz_extension
- psz_subtitle
+ psz_idxpath
;
3463 strcpy( psz_extension
, ".idx" );
3465 if( !vlc_stat( psz_idxpath
, &st
) && S_ISREG( st
.st_mode
) )
3467 msg_Dbg( p_input
, "using %s as subtitle file instead of %s",
3468 psz_idxpath
, psz_subtitle
);
3469 psz_subtitle
= psz_idxpath
;
3474 char *psz_uri
= vlc_path2uri( psz_subtitle
, NULL
);
3475 free( psz_idxpath
);
3479 int input_GetAttachments(input_thread_t
*input
,
3480 input_attachment_t
***attachments
)
3482 input_thread_private_t
*priv
= input_priv(input
);
3484 vlc_mutex_lock(&priv
->p_item
->lock
);
3485 int attachments_count
= priv
->i_attachment
;
3486 if (attachments_count
<= 0)
3488 vlc_mutex_unlock(&priv
->p_item
->lock
);
3489 *attachments
= NULL
;
3493 *attachments
= vlc_alloc(attachments_count
, sizeof(input_attachment_t
*));
3497 for (int i
= 0; i
< attachments_count
; i
++)
3498 (*attachments
)[i
] = vlc_input_attachment_Duplicate(priv
->attachment
[i
]);
3500 vlc_mutex_unlock(&priv
->p_item
->lock
);
3501 return attachments_count
;
3504 input_attachment_t
*input_GetAttachment(input_thread_t
*input
, const char *name
)
3506 input_thread_private_t
*priv
= input_priv(input
);
3508 vlc_mutex_lock(&priv
->p_item
->lock
);
3509 for (int i
= 0; i
< priv
->i_attachment
; i
++)
3511 if (!strcmp( priv
->attachment
[i
]->psz_name
, name
))
3513 input_attachment_t
*attachment
=
3514 vlc_input_attachment_Duplicate(priv
->attachment
[i
] );
3515 vlc_mutex_unlock( &priv
->p_item
->lock
);
3519 vlc_mutex_unlock( &priv
->p_item
->lock
);