1 /*****************************************************************************
2 * input.c: input thread
3 *****************************************************************************
4 * Copyright (C) 1998-2007 VLC authors and VideoLAN
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Laurent Aimar <fenrir@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
38 #include "input_internal.h"
41 #include "es_out_timeshift.h"
49 #include <vlc_dialog.h>
51 #include <vlc_charset.h>
53 #include <vlc_strings.h>
54 #include <vlc_modules.h>
55 #include <vlc_stream.h>
56 #include <vlc_stream_extractor.h>
57 #include <vlc_renderer_discovery.h>
59 /*****************************************************************************
61 *****************************************************************************/
62 static void *Run( void * );
63 static void *Preparse( void * );
65 static input_thread_t
* Create ( vlc_object_t
*, input_item_t
*,
66 const char *, bool, input_resource_t
*,
67 vlc_renderer_item_t
* );
68 static int Init ( input_thread_t
*p_input
);
69 static void End ( input_thread_t
*p_input
);
70 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
);
72 static inline int ControlPop( input_thread_t
*, int *, vlc_value_t
*, mtime_t i_deadline
, bool b_postpone_seek
);
73 static void ControlRelease( int i_type
, vlc_value_t val
);
74 static bool ControlIsSeekRequest( int i_type
);
75 static bool Control( input_thread_t
*, int, vlc_value_t
);
76 static void ControlPause( input_thread_t
*, mtime_t
);
78 static int UpdateTitleSeekpointFromDemux( input_thread_t
* );
79 static void UpdateGenericFromDemux( input_thread_t
* );
80 static void UpdateTitleListfromDemux( input_thread_t
* );
82 static void MRLSections( const char *, int *, int *, int *, int *);
84 static input_source_t
*InputSourceNew( input_thread_t
*, const char *,
85 const char *psz_forced_demux
,
87 static void InputSourceDestroy( input_source_t
* );
88 static void InputSourceMeta( input_thread_t
*, input_source_t
*, vlc_meta_t
* );
91 //static void InputGetAttachments( input_thread_t *, input_source_t * );
92 static void SlaveDemux( input_thread_t
*p_input
);
93 static void SlaveSeek( input_thread_t
*p_input
);
95 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
96 static void InputUpdateMeta( input_thread_t
*p_input
, demux_t
*p_demux
);
97 static void InputGetExtraFiles( input_thread_t
*p_input
,
98 int *pi_list
, char ***pppsz_list
,
99 const char **psz_access
, const char *psz_path
);
101 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
102 const demux_t
***ppp_attachment_demux
,
103 int i_new
, input_attachment_t
**pp_new
, const demux_t
*p_demux
);
105 #define SLAVE_ADD_NOFLAG 0
106 #define SLAVE_ADD_FORCED (1<<0)
107 #define SLAVE_ADD_CANFAIL (1<<1)
108 #define SLAVE_ADD_SET_TIME (1<<2)
110 static int input_SlaveSourceAdd( input_thread_t
*, enum slave_type
,
111 const char *, unsigned );
112 static char *input_SubtitleFile2Uri( input_thread_t
*, const char * );
113 static void input_ChangeState( input_thread_t
*p_input
, int i_state
); /* TODO fix name */
117 * Create a new input_thread_t.
119 * You need to call input_Start on it when you are done
120 * adding callback on the variables/events you want to monitor.
122 * \param p_parent a vlc_object
123 * \param p_item an input item
124 * \param psz_log an optional prefix for this input logs
125 * \param p_resource an optional input ressource
126 * \return a pointer to the spawned input thread
128 input_thread_t
*input_Create( vlc_object_t
*p_parent
,
129 input_item_t
*p_item
,
130 const char *psz_log
, input_resource_t
*p_resource
,
131 vlc_renderer_item_t
*p_renderer
)
133 return Create( p_parent
, p_item
, psz_log
, false, p_resource
, p_renderer
);
138 * Initialize an input thread and run it until it stops by itself.
140 * \param p_parent a vlc_object
141 * \param p_item an input item
142 * \return an error code, VLC_SUCCESS on success
144 int input_Read( vlc_object_t
*p_parent
, input_item_t
*p_item
)
146 input_thread_t
*p_input
= Create( p_parent
, p_item
, NULL
, false, NULL
, NULL
);
150 if( !Init( p_input
) )
152 MainLoop( p_input
, false );
156 vlc_object_release( p_input
);
160 input_thread_t
*input_CreatePreparser( vlc_object_t
*parent
,
163 return Create( parent
, item
, NULL
, true, NULL
, NULL
);
167 * Start a input_thread_t created by input_Create.
169 * You must not start an already running input_thread_t.
171 * \param the input thread to start
173 int input_Start( input_thread_t
*p_input
)
175 input_thread_private_t
*priv
= input_priv(p_input
);
176 void *(*func
)(void *) = Run
;
178 if( priv
->b_preparsing
)
181 assert( !priv
->is_running
);
182 /* Create thread and wait for its readiness. */
183 priv
->is_running
= !vlc_clone( &priv
->thread
, func
, priv
,
184 VLC_THREAD_PRIORITY_INPUT
);
185 if( !priv
->is_running
)
187 input_ChangeState( p_input
, ERROR_S
);
188 msg_Err( p_input
, "cannot create input thread" );
195 * Request a running input thread to stop and die
197 * \param p_input the input thread to stop
199 void input_Stop( input_thread_t
*p_input
)
201 input_thread_private_t
*sys
= input_priv(p_input
);
203 vlc_mutex_lock( &sys
->lock_control
);
204 /* Discard all pending controls */
205 for( int i
= 0; i
< sys
->i_control
; i
++ )
207 input_control_t
*ctrl
= &sys
->control
[i
];
208 ControlRelease( ctrl
->i_type
, ctrl
->val
);
211 sys
->is_stopped
= true;
212 vlc_cond_signal( &sys
->wait_control
);
213 vlc_mutex_unlock( &sys
->lock_control
);
214 vlc_interrupt_kill( &sys
->interrupt
);
220 * It does not call input_Stop itself.
222 void input_Close( input_thread_t
*p_input
)
224 if( input_priv(p_input
)->is_running
)
225 vlc_join( input_priv(p_input
)->thread
, NULL
);
226 vlc_interrupt_deinit( &input_priv(p_input
)->interrupt
);
227 vlc_object_release( p_input
);
231 * Input destructor (called when the object's refcount reaches 0).
233 static void input_Destructor( vlc_object_t
*obj
)
235 input_thread_t
*p_input
= (input_thread_t
*)obj
;
236 input_thread_private_t
*priv
= input_priv(p_input
);
238 char * psz_name
= input_item_GetName( priv
->p_item
);
239 msg_Dbg( p_input
, "Destroying the input for '%s'", psz_name
);
243 if( priv
->p_renderer
)
244 vlc_renderer_item_release( priv
->p_renderer
);
245 if( priv
->p_es_out_display
)
246 es_out_Delete( priv
->p_es_out_display
);
248 if( priv
->p_resource
)
249 input_resource_Release( priv
->p_resource
);
250 if( priv
->p_resource_private
)
251 input_resource_Release( priv
->p_resource_private
);
253 input_item_Release( priv
->p_item
);
255 vlc_mutex_destroy( &priv
->counters
.counters_lock
);
257 for( int i
= 0; i
< priv
->i_control
; i
++ )
259 input_control_t
*p_ctrl
= &priv
->control
[i
];
260 ControlRelease( p_ctrl
->i_type
, p_ctrl
->val
);
263 vlc_cond_destroy( &priv
->wait_control
);
264 vlc_mutex_destroy( &priv
->lock_control
);
268 * Get the item from an input thread
269 * FIXME it does not increase ref count of the item.
270 * if it is used after p_input is destroyed nothing prevent it from
273 input_item_t
*input_GetItem( input_thread_t
*p_input
)
275 assert( p_input
!= NULL
);
276 return input_priv(p_input
)->p_item
;
279 /*****************************************************************************
280 * This function creates a new input, and returns a pointer
281 * to its description. On error, it returns NULL.
283 * XXX Do not forget to update vlc_input.h if you add new variables.
284 *****************************************************************************/
285 static input_thread_t
*Create( vlc_object_t
*p_parent
, input_item_t
*p_item
,
286 const char *psz_header
, bool b_preparsing
,
287 input_resource_t
*p_resource
,
288 vlc_renderer_item_t
*p_renderer
)
290 /* Allocate descriptor */
291 input_thread_private_t
*priv
;
293 priv
= vlc_custom_create( p_parent
, sizeof( *priv
), "input" );
294 if( unlikely(priv
== NULL
) )
297 input_thread_t
*p_input
= &priv
->input
;
299 char * psz_name
= input_item_GetName( p_item
);
300 msg_Dbg( p_input
, "Creating an input for %s'%s'",
301 b_preparsing
? "preparsing " : "", psz_name
);
304 /* Parse input options */
305 input_item_ApplyOptions( VLC_OBJECT(p_input
), p_item
);
307 p_input
->obj
.header
= psz_header
? strdup( psz_header
) : NULL
;
309 /* Init Common fields */
310 priv
->b_preparsing
= b_preparsing
;
311 priv
->b_can_pace_control
= true;
317 priv
->i_title_offset
= input_priv(p_input
)->i_seekpoint_offset
= 0;
318 priv
->i_state
= INIT_S
;
319 priv
->is_running
= false;
320 priv
->is_stopped
= false;
321 priv
->b_recording
= false;
322 priv
->i_rate
= INPUT_RATE_DEFAULT
;
323 memset( &priv
->bookmark
, 0, sizeof(priv
->bookmark
) );
324 TAB_INIT( priv
->i_bookmark
, priv
->pp_bookmark
);
325 TAB_INIT( priv
->i_attachment
, priv
->attachment
);
326 priv
->attachment_demux
= NULL
;
328 priv
->b_out_pace_control
= false;
329 /* The renderer is passed after its refcount was incremented.
330 * The input thread is now responsible for releasing it */
331 priv
->p_renderer
= p_renderer
;
333 priv
->viewpoint_changed
= false;
334 /* Fetch the viewpoint from the mediaplayer or the playlist if any */
335 vlc_viewpoint_t
*p_viewpoint
= var_InheritAddress( p_input
, "viewpoint" );
336 if (p_viewpoint
!= NULL
)
337 priv
->viewpoint
= *p_viewpoint
;
339 vlc_viewpoint_init( &priv
->viewpoint
);
341 input_item_Hold( p_item
); /* Released in Destructor() */
342 priv
->p_item
= p_item
;
344 /* Init Input fields */
346 vlc_mutex_lock( &p_item
->lock
);
348 if( !p_item
->p_stats
)
349 p_item
->p_stats
= stats_NewInputStats( p_input
);
351 /* setup the preparse depth of the item
352 * if we are preparsing, use the i_preparse_depth of the parent item */
353 if( !priv
->b_preparsing
)
355 char *psz_rec
= var_InheritString( p_parent
, "recursive" );
357 if( psz_rec
!= NULL
)
359 if ( !strcasecmp( psz_rec
, "none" ) )
360 p_item
->i_preparse_depth
= 0;
361 else if ( !strcasecmp( psz_rec
, "collapse" ) )
362 p_item
->i_preparse_depth
= 1;
364 p_item
->i_preparse_depth
= -1; /* default is expand */
367 p_item
->i_preparse_depth
= -1;
370 p_input
->obj
.flags
|= OBJECT_FLAGS_QUIET
| OBJECT_FLAGS_NOINTERACT
;
372 /* Make sure the interaction option is honored */
373 if( !var_InheritBool( p_input
, "interact" ) )
374 p_input
->obj
.flags
|= OBJECT_FLAGS_NOINTERACT
;
375 else if( p_item
->b_preparse_interact
)
377 /* If true, this item was asked explicitly to interact with the user
378 * (via libvlc_MetadataRequest). Sub items created from this input won't
379 * have this flag and won't interact with the user */
380 p_input
->obj
.flags
&= ~OBJECT_FLAGS_NOINTERACT
;
383 vlc_mutex_unlock( &p_item
->lock
);
392 priv
->p_resource_private
= NULL
;
393 priv
->p_resource
= input_resource_Hold( p_resource
);
397 priv
->p_resource_private
= input_resource_New( VLC_OBJECT( p_input
) );
398 priv
->p_resource
= input_resource_Hold( priv
->p_resource_private
);
400 input_resource_SetInput( priv
->p_resource
, p_input
);
402 /* Init control buffer */
403 vlc_mutex_init( &priv
->lock_control
);
404 vlc_cond_init( &priv
->wait_control
);
406 vlc_interrupt_init(&priv
->interrupt
);
408 /* Create Object Variables for private use only */
409 input_ConfigVarInit( p_input
);
411 /* Create Objects variables for public Get and Set */
412 input_ControlVarInit( p_input
);
415 if( !priv
->b_preparsing
)
417 char *psz_bookmarks
= var_GetNonEmptyString( p_input
, "bookmarks" );
420 /* FIXME: have a common cfg parsing routine used by sout and others */
421 char *psz_parser
, *psz_start
, *psz_end
;
422 psz_parser
= psz_bookmarks
;
423 while( (psz_start
= strchr( psz_parser
, '{' ) ) )
425 seekpoint_t
*p_seekpoint
;
428 psz_end
= strchr( psz_start
, '}' );
429 if( !psz_end
) break;
430 psz_parser
= psz_end
+ 1;
431 backup
= *psz_parser
;
435 p_seekpoint
= vlc_seekpoint_New();
437 if( unlikely( p_seekpoint
== NULL
) )
440 while( (psz_end
= strchr( psz_start
, ',' ) ) )
443 if( !strncmp( psz_start
, "name=", 5 ) )
445 free( p_seekpoint
->psz_name
);
447 p_seekpoint
->psz_name
= strdup(psz_start
+ 5);
449 else if( !strncmp( psz_start
, "time=", 5 ) )
451 p_seekpoint
->i_time_offset
= atof(psz_start
+ 5) *
454 psz_start
= psz_end
+ 1;
456 msg_Dbg( p_input
, "adding bookmark: %s, time=%"PRId64
,
457 p_seekpoint
->psz_name
,
458 p_seekpoint
->i_time_offset
);
459 input_Control( p_input
, INPUT_ADD_BOOKMARK
, p_seekpoint
);
460 vlc_seekpoint_Delete( p_seekpoint
);
461 *psz_parser
= backup
;
463 free( psz_bookmarks
);
467 /* Remove 'Now playing' info as it is probably outdated */
468 input_item_SetNowPlaying( p_item
, NULL
);
469 input_item_SetESNowPlaying( p_item
, NULL
);
470 input_SendEventMeta( p_input
);
473 memset( &priv
->counters
, 0, sizeof( priv
->counters
) );
474 vlc_mutex_init( &priv
->counters
.counters_lock
);
476 priv
->p_es_out_display
= input_EsOutNew( p_input
, priv
->i_rate
);
477 priv
->p_es_out
= NULL
;
479 /* Set the destructor when we are sure we are initialized */
480 vlc_object_set_destructor( p_input
, input_Destructor
);
485 /*****************************************************************************
486 * Run: main thread loop
487 * This is the "normal" thread that spawns the input processing chain,
488 * reads the stream, cleans up and waits
489 *****************************************************************************/
490 static void *Run( void *data
)
492 input_thread_private_t
*priv
= data
;
493 input_thread_t
*p_input
= &priv
->input
;
495 vlc_interrupt_set(&priv
->interrupt
);
497 if( !Init( p_input
) )
499 if( priv
->b_can_pace_control
&& priv
->b_out_pace_control
)
501 /* We don't want a high input priority here or we'll
502 * end-up sucking up all the CPU time */
503 vlc_set_priority( priv
->thread
, VLC_THREAD_PRIORITY_LOW
);
506 MainLoop( p_input
, true ); /* FIXME it can be wrong (like with VLM) */
512 input_SendEventDead( p_input
);
516 static void *Preparse( void *data
)
518 input_thread_private_t
*priv
= data
;
519 input_thread_t
*p_input
= &priv
->input
;
521 vlc_interrupt_set(&priv
->interrupt
);
523 if( !Init( p_input
) )
524 { /* if the demux is a playlist, call Mainloop that will call
525 * demux_Demux in order to fetch sub items */
526 bool b_is_playlist
= false;
528 if ( input_item_ShouldPreparseSubItems( priv
->p_item
)
529 && demux_Control( priv
->master
->p_demux
, DEMUX_IS_PLAYLIST
,
531 b_is_playlist
= false;
533 MainLoop( p_input
, false );
537 input_SendEventDead( p_input
);
541 bool input_Stopped( input_thread_t
*input
)
543 input_thread_private_t
*sys
= input_priv(input
);
546 vlc_mutex_lock( &sys
->lock_control
);
547 ret
= sys
->is_stopped
;
548 vlc_mutex_unlock( &sys
->lock_control
);
552 /*****************************************************************************
553 * Main loop: Fill buffers from access, and demux
554 *****************************************************************************/
558 * It asks the demuxer to demux some data
560 static void MainLoopDemux( input_thread_t
*p_input
, bool *pb_changed
)
563 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
567 if( input_priv(p_input
)->i_stop
> 0 && input_priv(p_input
)->i_time
>= input_priv(p_input
)->i_stop
)
568 i_ret
= VLC_DEMUXER_EOF
;
570 i_ret
= demux_Demux( p_demux
);
572 i_ret
= i_ret
> 0 ? VLC_DEMUXER_SUCCESS
: ( i_ret
< 0 ? VLC_DEMUXER_EGENERIC
: VLC_DEMUXER_EOF
);
574 if( i_ret
== VLC_DEMUXER_SUCCESS
)
576 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_TITLE_LIST
) )
577 UpdateTitleListfromDemux( p_input
);
579 if( input_priv(p_input
)->master
->b_title_demux
)
581 i_ret
= UpdateTitleSeekpointFromDemux( p_input
);
585 UpdateGenericFromDemux( p_input
);
588 if( i_ret
== VLC_DEMUXER_EOF
)
590 msg_Dbg( p_input
, "EOF reached" );
591 input_priv(p_input
)->master
->b_eof
= true;
592 es_out_Eos(input_priv(p_input
)->p_es_out
);
594 else if( i_ret
== VLC_DEMUXER_EGENERIC
)
596 input_ChangeState( p_input
, ERROR_S
);
598 else if( input_priv(p_input
)->i_slave
> 0 )
599 SlaveDemux( p_input
);
602 static int MainLoopTryRepeat( input_thread_t
*p_input
)
604 int i_repeat
= var_GetInteger( p_input
, "input-repeat" );
610 msg_Dbg( p_input
, "repeating the same input (%d)", i_repeat
);
614 var_SetInteger( p_input
, "input-repeat", i_repeat
);
617 /* Seek to start title/seekpoint */
618 val
.i_int
= input_priv(p_input
)->master
->i_title_start
-
619 input_priv(p_input
)->master
->i_title_offset
;
620 if( val
.i_int
< 0 || val
.i_int
>= input_priv(p_input
)->master
->i_title
)
622 input_ControlPush( p_input
,
623 INPUT_CONTROL_SET_TITLE
, &val
);
625 val
.i_int
= input_priv(p_input
)->master
->i_seekpoint_start
-
626 input_priv(p_input
)->master
->i_seekpoint_offset
;
627 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
628 input_ControlPush( p_input
,
629 INPUT_CONTROL_SET_SEEKPOINT
, &val
);
631 /* Seek to start position */
632 if( input_priv(p_input
)->i_start
> 0 )
634 val
.i_int
= input_priv(p_input
)->i_start
;
635 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &val
);
640 input_ControlPush( p_input
, INPUT_CONTROL_SET_POSITION
, &val
);
647 * Update timing infos and statistics.
649 static void MainLoopStatistics( input_thread_t
*p_input
)
651 double f_position
= 0.0;
653 mtime_t i_length
= 0;
655 /* update input status variables */
656 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
657 DEMUX_GET_POSITION
, &f_position
) )
660 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
661 DEMUX_GET_TIME
, &i_time
) )
663 input_priv(p_input
)->i_time
= i_time
;
665 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
666 DEMUX_GET_LENGTH
, &i_length
) )
669 es_out_SetTimes( input_priv(p_input
)->p_es_out
, f_position
, i_time
, i_length
);
671 /* update current bookmark */
672 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
673 input_priv(p_input
)->bookmark
.i_time_offset
= i_time
;
674 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
676 stats_ComputeInputStats( p_input
, input_priv(p_input
)->p_item
->p_stats
);
677 input_SendEventStatistics( p_input
);
682 * The main input loop.
684 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
)
686 mtime_t i_intf_update
= 0;
687 mtime_t i_last_seek_mdate
= 0;
689 if( b_interactive
&& var_InheritBool( p_input
, "start-paused" ) )
690 ControlPause( p_input
, mdate() );
692 bool b_pause_after_eof
= b_interactive
&&
693 var_InheritBool( p_input
, "play-and-pause" );
694 bool b_paused_at_eof
= false;
696 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
697 const bool b_can_demux
= p_demux
->pf_demux
!= NULL
;
699 while( !input_Stopped( p_input
) && input_priv(p_input
)->i_state
!= ERROR_S
)
701 mtime_t i_wakeup
= -1;
702 bool b_paused
= input_priv(p_input
)->i_state
== PAUSE_S
;
703 /* FIXME if input_priv(p_input)->i_state == PAUSE_S the access/access_demux
704 * is paused -> this may cause problem with some of them
705 * The same problem can be seen when seeking while paused */
707 b_paused
= !es_out_GetBuffering( input_priv(p_input
)->p_es_out
)
708 || input_priv(p_input
)->master
->b_eof
;
712 if( !input_priv(p_input
)->master
->b_eof
)
714 bool b_force_update
= false;
716 MainLoopDemux( p_input
, &b_force_update
);
719 i_wakeup
= es_out_GetWakeup( input_priv(p_input
)->p_es_out
);
723 b_paused_at_eof
= false;
725 else if( !es_out_GetEmpty( input_priv(p_input
)->p_es_out
) )
727 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
728 i_wakeup
= mdate() + INPUT_IDLE_SLEEP
;
730 /* Pause after eof only if the input is pausable.
731 * This way we won't trigger timeshifting for nothing */
732 else if( b_pause_after_eof
&& input_priv(p_input
)->b_can_pause
)
734 if( b_paused_at_eof
)
737 vlc_value_t val
= { .i_int
= PAUSE_S
};
739 msg_Dbg( p_input
, "pausing at EOF (pause after each)");
740 Control( p_input
, INPUT_CONTROL_SET_STATE
, val
);
743 b_paused_at_eof
= true;
747 if( MainLoopTryRepeat( p_input
) )
751 /* Update interface and statistics */
752 mtime_t now
= mdate();
753 if( now
>= i_intf_update
)
755 MainLoopStatistics( p_input
);
756 i_intf_update
= now
+ INT64_C(250000);
763 mtime_t i_deadline
= i_wakeup
;
765 /* Postpone seeking until ES buffering is complete or at most
767 bool b_postpone
= es_out_GetBuffering( input_priv(p_input
)->p_es_out
)
768 && !input_priv(p_input
)->master
->b_eof
;
771 mtime_t now
= mdate();
773 /* Recheck ES buffer level every 20 ms when seeking */
774 if( now
< i_last_seek_mdate
+ INT64_C(125000)
775 && (i_deadline
< 0 || i_deadline
> now
+ INT64_C(20000)) )
776 i_deadline
= now
+ INT64_C(20000);
784 if( ControlPop( p_input
, &i_type
, &val
, i_deadline
, b_postpone
) )
788 break; /* Wake-up time reached */
792 msg_Dbg( p_input
, "control type=%d", i_type
);
794 if( Control( p_input
, i_type
, val
) )
796 if( ControlIsSeekRequest( i_type
) )
797 i_last_seek_mdate
= mdate();
801 /* Update the wakeup time */
803 i_wakeup
= es_out_GetWakeup( input_priv(p_input
)->p_es_out
);
808 static void InitStatistics( input_thread_t
*p_input
)
810 input_thread_private_t
*priv
= input_priv(p_input
);
812 if( priv
->b_preparsing
) return;
814 /* Prepare statistics */
815 #define INIT_COUNTER( c, compute ) free( priv->counters.p_##c ); \
816 priv->counters.p_##c = \
817 stats_CounterCreate( STATS_##compute);
818 if( libvlc_stats( p_input
) )
820 INIT_COUNTER( read_bytes
, COUNTER
);
821 INIT_COUNTER( read_packets
, COUNTER
);
822 INIT_COUNTER( demux_read
, COUNTER
);
823 INIT_COUNTER( input_bitrate
, DERIVATIVE
);
824 INIT_COUNTER( demux_bitrate
, DERIVATIVE
);
825 INIT_COUNTER( demux_corrupted
, COUNTER
);
826 INIT_COUNTER( demux_discontinuity
, COUNTER
);
827 INIT_COUNTER( played_abuffers
, COUNTER
);
828 INIT_COUNTER( lost_abuffers
, COUNTER
);
829 INIT_COUNTER( displayed_pictures
, COUNTER
);
830 INIT_COUNTER( lost_pictures
, COUNTER
);
831 INIT_COUNTER( decoded_audio
, COUNTER
);
832 INIT_COUNTER( decoded_video
, COUNTER
);
833 INIT_COUNTER( decoded_sub
, COUNTER
);
834 priv
->counters
.p_sout_send_bitrate
= NULL
;
835 priv
->counters
.p_sout_sent_packets
= NULL
;
836 priv
->counters
.p_sout_sent_bytes
= NULL
;
841 static int InitSout( input_thread_t
* p_input
)
843 input_thread_private_t
*priv
= input_priv(p_input
);
845 if( priv
->b_preparsing
)
848 /* Find a usable sout and attach it to p_input */
850 if( priv
->p_renderer
)
852 const char *psz_renderer_sout
= vlc_renderer_item_sout( priv
->p_renderer
);
853 if( asprintf( &psz
, "#%s", psz_renderer_sout
) < 0 )
857 psz
= var_GetNonEmptyString( p_input
, "sout" );
858 if( psz
&& strncasecmp( priv
->p_item
->psz_uri
, "vlc:", 4 ) )
860 priv
->p_sout
= input_resource_RequestSout( priv
->p_resource
, NULL
, psz
);
861 if( priv
->p_sout
== NULL
)
863 input_ChangeState( p_input
, ERROR_S
);
864 msg_Err( p_input
, "cannot start stream output instance, " \
869 if( libvlc_stats( p_input
) )
871 INIT_COUNTER( sout_sent_packets
, COUNTER
);
872 INIT_COUNTER( sout_sent_bytes
, COUNTER
);
873 INIT_COUNTER( sout_send_bitrate
, DERIVATIVE
);
878 input_resource_RequestSout( priv
->p_resource
, NULL
, NULL
);
886 static void InitTitle( input_thread_t
* p_input
)
888 input_thread_private_t
*priv
= input_priv(p_input
);
889 input_source_t
*p_master
= priv
->master
;
891 if( priv
->b_preparsing
)
894 vlc_mutex_lock( &priv
->p_item
->lock
);
895 /* Create global title (from master) */
896 priv
->i_title
= p_master
->i_title
;
897 priv
->title
= p_master
->title
;
898 priv
->i_title_offset
= p_master
->i_title_offset
;
899 priv
->i_seekpoint_offset
= p_master
->i_seekpoint_offset
;
900 if( priv
->i_title
> 0 )
902 /* Setup variables */
903 input_ControlVarNavigation( p_input
);
904 input_SendEventTitle( p_input
, 0 );
908 priv
->b_can_pace_control
= p_master
->b_can_pace_control
;
909 priv
->b_can_pause
= p_master
->b_can_pause
;
910 priv
->b_can_rate_control
= p_master
->b_can_rate_control
;
911 vlc_mutex_unlock( &priv
->p_item
->lock
);
914 static void StartTitle( input_thread_t
* p_input
)
916 input_thread_private_t
*priv
= input_priv(p_input
);
919 /* Start title/chapter */
920 val
.i_int
= priv
->master
->i_title_start
- priv
->master
->i_title_offset
;
921 if( val
.i_int
> 0 && val
.i_int
< priv
->master
->i_title
)
922 input_ControlPush( p_input
, INPUT_CONTROL_SET_TITLE
, &val
);
924 val
.i_int
= priv
->master
->i_seekpoint_start
-
925 priv
->master
->i_seekpoint_offset
;
926 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
927 input_ControlPush( p_input
, INPUT_CONTROL_SET_SEEKPOINT
, &val
);
929 /* Start/stop/run time */
930 priv
->i_start
= llroundf(1000000.f
931 * var_GetFloat( p_input
, "start-time" ));
932 priv
->i_stop
= llroundf(1000000.f
933 * var_GetFloat( p_input
, "stop-time" ));
934 if( priv
->i_stop
<= 0 )
936 priv
->i_stop
= llroundf(1000000.f
937 * var_GetFloat( p_input
, "run-time" ));
938 if( priv
->i_stop
< 0 )
940 msg_Warn( p_input
, "invalid run-time ignored" );
944 priv
->i_stop
+= priv
->i_start
;
947 if( priv
->i_start
> 0 )
951 msg_Dbg( p_input
, "starting at time: %"PRId64
"s",
952 priv
->i_start
/ CLOCK_FREQ
);
954 s
.i_int
= priv
->i_start
;
955 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &s
);
957 if( priv
->i_stop
> 0 && priv
->i_stop
<= priv
->i_start
)
959 msg_Warn( p_input
, "invalid stop-time ignored" );
962 priv
->b_fast_seek
= var_GetBool( p_input
, "input-fast-seek" );
965 static int SlaveCompare(const void *a
, const void *b
)
967 const input_item_slave_t
*p_slave0
= *((const input_item_slave_t
**) a
);
968 const input_item_slave_t
*p_slave1
= *((const input_item_slave_t
**) b
);
970 if( p_slave0
== NULL
|| p_slave1
== NULL
)
972 /* Put NULL (or rejected) subs at the end */
973 return p_slave0
== NULL
? 1 : p_slave1
== NULL
? -1 : 0;
976 if( p_slave0
->i_priority
> p_slave1
->i_priority
)
979 if( p_slave0
->i_priority
< p_slave1
->i_priority
)
985 static bool SlaveExists( input_item_slave_t
**pp_slaves
, int i_slaves
,
988 for( int i
= 0; i
< i_slaves
; i
++ )
990 if( pp_slaves
[i
] != NULL
991 && !strcmp( pp_slaves
[i
]->psz_uri
, psz_uri
) )
997 static void SetSubtitlesOptions( input_thread_t
*p_input
)
999 /* Get fps and set it if not already set */
1000 const float f_fps
= input_priv(p_input
)->master
->f_fps
;
1003 var_Create( p_input
, "sub-original-fps", VLC_VAR_FLOAT
);
1004 var_SetFloat( p_input
, "sub-original-fps", f_fps
);
1006 float f_requested_fps
= var_CreateGetFloat( p_input
, "sub-fps" );
1007 if( f_requested_fps
!= f_fps
)
1009 var_Create( p_input
, "sub-fps", VLC_VAR_FLOAT
|
1010 VLC_VAR_DOINHERIT
);
1011 var_SetFloat( p_input
, "sub-fps", f_requested_fps
);
1015 const int i_delay
= var_CreateGetInteger( p_input
, "sub-delay" );
1017 var_SetInteger( p_input
, "spu-delay", (mtime_t
)i_delay
* 100000 );
1020 static void GetVarSlaves( input_thread_t
*p_input
,
1021 input_item_slave_t
***ppp_slaves
, int *p_slaves
)
1023 char *psz
= var_GetNonEmptyString( p_input
, "input-slave" );
1027 input_item_slave_t
**pp_slaves
= *ppp_slaves
;
1028 int i_slaves
= *p_slaves
;
1030 char *psz_org
= psz
;
1031 while( psz
&& *psz
)
1033 while( *psz
== ' ' || *psz
== '#' )
1036 char *psz_delim
= strchr( psz
, '#' );
1038 *psz_delim
++ = '\0';
1043 char *uri
= strstr(psz
, "://")
1044 ? strdup( psz
) : vlc_path2uri( psz
, NULL
);
1049 input_item_slave_t
*p_slave
=
1050 input_item_slave_New( uri
, SLAVE_TYPE_AUDIO
, SLAVE_PRIORITY_USER
);
1053 if( unlikely( p_slave
== NULL
) )
1055 TAB_APPEND(i_slaves
, pp_slaves
, p_slave
);
1059 *ppp_slaves
= pp_slaves
; /* in case of realloc */
1060 *p_slaves
= i_slaves
;
1063 static void LoadSlaves( input_thread_t
*p_input
)
1065 input_item_slave_t
**pp_slaves
;
1067 TAB_INIT( i_slaves
, pp_slaves
);
1069 /* Look for and add slaves */
1071 char *psz_subtitle
= var_GetNonEmptyString( p_input
, "sub-file" );
1072 if( psz_subtitle
!= NULL
)
1074 msg_Dbg( p_input
, "forced subtitle: %s", psz_subtitle
);
1075 char *psz_uri
= input_SubtitleFile2Uri( p_input
, psz_subtitle
);
1076 free( psz_subtitle
);
1077 psz_subtitle
= NULL
;
1078 if( psz_uri
!= NULL
)
1080 input_item_slave_t
*p_slave
=
1081 input_item_slave_New( psz_uri
, SLAVE_TYPE_SPU
,
1082 SLAVE_PRIORITY_USER
);
1086 TAB_APPEND(i_slaves
, pp_slaves
, p_slave
);
1087 psz_subtitle
= p_slave
->psz_uri
;
1092 if( var_GetBool( p_input
, "sub-autodetect-file" ) )
1094 /* Add local subtitles */
1095 char *psz_autopath
= var_GetNonEmptyString( p_input
, "sub-autodetect-path" );
1097 if( subtitles_Detect( p_input
, psz_autopath
, input_priv(p_input
)->p_item
->psz_uri
,
1098 &pp_slaves
, &i_slaves
) == VLC_SUCCESS
)
1100 /* check that we did not add the subtitle through sub-file */
1101 if( psz_subtitle
!= NULL
)
1103 for( int i
= 1; i
< i_slaves
; i
++ )
1105 input_item_slave_t
*p_curr
= pp_slaves
[i
];
1107 && !strcmp( psz_subtitle
, p_curr
->psz_uri
) )
1109 /* reject current sub */
1110 input_item_slave_Delete( p_curr
);
1111 pp_slaves
[i
] = NULL
;
1116 free( psz_autopath
);
1119 /* Add slaves found by the directory demuxer or via libvlc */
1120 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1121 vlc_mutex_lock( &p_item
->lock
);
1123 /* Move item slaves to local pp_slaves */
1124 for( int i
= 0; i
< p_item
->i_slaves
; i
++ )
1126 input_item_slave_t
*p_slave
= p_item
->pp_slaves
[i
];
1127 if( !SlaveExists( pp_slaves
, i_slaves
, p_slave
->psz_uri
) )
1128 TAB_APPEND(i_slaves
, pp_slaves
, p_slave
);
1130 input_item_slave_Delete( p_slave
);
1132 /* Slaves that are successfully loaded will be added back to the item */
1133 TAB_CLEAN( p_item
->i_slaves
, p_item
->pp_slaves
);
1134 vlc_mutex_unlock( &p_item
->lock
);
1136 /* Add slaves from the "input-slave" option */
1137 GetVarSlaves( p_input
, &pp_slaves
, &i_slaves
);
1140 qsort( pp_slaves
, i_slaves
, sizeof (input_item_slave_t
*),
1143 /* add all detected slaves */
1144 bool p_forced
[2] = {};
1145 static_assert( SLAVE_TYPE_AUDIO
<= 1 && SLAVE_TYPE_SPU
<= 1,
1146 "slave type size mismatch");
1147 for( int i
= 0; i
< i_slaves
&& pp_slaves
[i
] != NULL
; i
++ )
1149 input_item_slave_t
*p_slave
= pp_slaves
[i
];
1150 /* Slaves added via options should not fail */
1151 unsigned i_flags
= p_slave
->i_priority
!= SLAVE_PRIORITY_USER
1152 ? SLAVE_ADD_CANFAIL
: SLAVE_ADD_NOFLAG
;
1154 if( !p_forced
[p_slave
->i_type
]
1155 && ( p_slave
->b_forced
|| p_slave
->i_priority
== SLAVE_PRIORITY_USER
) )
1156 i_flags
|= SLAVE_ADD_FORCED
;
1158 if( input_SlaveSourceAdd( p_input
, p_slave
->i_type
, p_slave
->psz_uri
,
1159 i_flags
) == VLC_SUCCESS
)
1161 input_item_AddSlave( input_priv(p_input
)->p_item
, p_slave
);
1162 p_forced
[p_slave
->i_type
] = true;
1165 input_item_slave_Delete( p_slave
);
1167 TAB_CLEAN( i_slaves
, pp_slaves
);
1169 /* Load subtitles from attachments */
1170 int i_attachment
= 0;
1171 input_attachment_t
**pp_attachment
= NULL
;
1173 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1174 for( int i
= 0; i
< input_priv(p_input
)->i_attachment
; i
++ )
1176 const input_attachment_t
*a
= input_priv(p_input
)->attachment
[i
];
1177 if( !strcmp( a
->psz_mime
, "application/x-srt" ) )
1178 TAB_APPEND( i_attachment
, pp_attachment
,
1179 vlc_input_attachment_New( a
->psz_name
, NULL
,
1180 a
->psz_description
, NULL
, 0 ) );
1182 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1184 if( i_attachment
> 0 )
1185 var_Create( p_input
, "sub-description", VLC_VAR_STRING
);
1186 for( int i
= 0; i
< i_attachment
; i
++ )
1188 input_attachment_t
*a
= pp_attachment
[i
];
1192 if( a
->psz_name
[0] &&
1193 asprintf( &psz_mrl
, "attachment://%s", a
->psz_name
) >= 0 )
1195 var_SetString( p_input
, "sub-description", a
->psz_description
? a
->psz_description
: "");
1197 input_SlaveSourceAdd( p_input
, SLAVE_TYPE_SPU
, psz_mrl
,
1200 /* Don't update item slaves for attachements */
1202 vlc_input_attachment_Delete( a
);
1204 free( pp_attachment
);
1205 if( i_attachment
> 0 )
1206 var_Destroy( p_input
, "sub-description" );
1209 static void UpdatePtsDelay( input_thread_t
*p_input
)
1211 input_thread_private_t
*p_sys
= input_priv(p_input
);
1213 /* Get max pts delay from input source */
1214 mtime_t i_pts_delay
= p_sys
->master
->i_pts_delay
;
1215 for( int i
= 0; i
< p_sys
->i_slave
; i
++ )
1216 i_pts_delay
= __MAX( i_pts_delay
, p_sys
->slave
[i
]->i_pts_delay
);
1218 if( i_pts_delay
< 0 )
1221 /* Take care of audio/spu delay */
1222 const mtime_t i_audio_delay
= var_GetInteger( p_input
, "audio-delay" );
1223 const mtime_t i_spu_delay
= var_GetInteger( p_input
, "spu-delay" );
1224 const mtime_t i_extra_delay
= __MIN( i_audio_delay
, i_spu_delay
);
1225 if( i_extra_delay
< 0 )
1226 i_pts_delay
-= i_extra_delay
;
1228 /* Update cr_average depending on the caching */
1229 const int i_cr_average
= var_GetInteger( p_input
, "cr-average" ) * i_pts_delay
/ DEFAULT_PTS_DELAY
;
1232 es_out_SetDelay( input_priv(p_input
)->p_es_out_display
, AUDIO_ES
, i_audio_delay
);
1233 es_out_SetDelay( input_priv(p_input
)->p_es_out_display
, SPU_ES
, i_spu_delay
);
1234 es_out_SetJitter( input_priv(p_input
)->p_es_out
, i_pts_delay
, 0, i_cr_average
);
1237 static void InitPrograms( input_thread_t
* p_input
)
1242 /* Compute correct pts_delay */
1243 UpdatePtsDelay( p_input
);
1246 i_es_out_mode
= ES_OUT_MODE_AUTO
;
1247 if( input_priv(p_input
)->p_sout
)
1251 if( (prgms
= var_GetNonEmptyString( p_input
, "programs" )) != NULL
)
1255 TAB_INIT( list
.i_count
, list
.p_values
);
1256 for( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1258 prgm
= strtok_r( NULL
, ",", &buf
) )
1260 vlc_value_t val
= { .i_int
= atoi( prgm
) };
1261 TAB_APPEND(list
.i_count
, list
.p_values
, val
);
1264 if( list
.i_count
> 0 )
1265 i_es_out_mode
= ES_OUT_MODE_PARTIAL
;
1266 /* Note : we should remove the "program" callback. */
1270 else if( var_GetBool( p_input
, "sout-all" ) )
1272 i_es_out_mode
= ES_OUT_MODE_ALL
;
1275 es_out_SetMode( input_priv(p_input
)->p_es_out
, i_es_out_mode
);
1277 /* Inform the demuxer about waited group (needed only for DVB) */
1278 if( i_es_out_mode
== ES_OUT_MODE_ALL
)
1280 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
, -1, NULL
);
1282 else if( i_es_out_mode
== ES_OUT_MODE_PARTIAL
)
1284 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
, -1,
1286 TAB_CLEAN( list
.i_count
, list
.p_values
);
1290 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
,
1291 es_out_GetGroupForced( input_priv(p_input
)->p_es_out
), NULL
);
1295 static int Init( input_thread_t
* p_input
)
1297 input_thread_private_t
*priv
= input_priv(p_input
);
1298 input_source_t
*master
;
1300 if( var_Type( p_input
->obj
.parent
, "meta-file" ) )
1302 msg_Dbg( p_input
, "Input is a meta file: disabling unneeded options" );
1303 var_SetString( p_input
, "sout", "" );
1304 var_SetBool( p_input
, "sout-all", false );
1305 var_SetString( p_input
, "input-slave", "" );
1306 var_SetInteger( p_input
, "input-repeat", 0 );
1307 var_SetString( p_input
, "sub-file", "" );
1308 var_SetBool( p_input
, "sub-autodetect-file", false );
1311 InitStatistics( p_input
);
1313 if( InitSout( p_input
) )
1318 priv
->p_es_out
= input_EsOutTimeshiftNew( p_input
, priv
->p_es_out_display
,
1320 if( priv
->p_es_out
== NULL
)
1324 input_ChangeState( p_input
, OPENING_S
);
1325 input_SendEventCache( p_input
, 0.0 );
1328 master
= InputSourceNew( p_input
, priv
->p_item
->psz_uri
, NULL
, false );
1329 if( master
== NULL
)
1331 priv
->master
= master
;
1333 InitTitle( p_input
);
1335 /* Load master infos */
1338 if( demux_Control( master
->p_demux
, DEMUX_GET_LENGTH
, &i_length
) )
1341 i_length
= input_item_GetDuration( priv
->p_item
);
1342 input_SendEventLength( p_input
, i_length
);
1344 input_SendEventPosition( p_input
, 0.0, 0 );
1346 if( !priv
->b_preparsing
)
1348 StartTitle( p_input
);
1349 SetSubtitlesOptions( p_input
);
1350 LoadSlaves( p_input
);
1351 InitPrograms( p_input
);
1353 double f_rate
= var_InheritFloat( p_input
, "rate" );
1354 if( f_rate
!= 0.0 && f_rate
!= 1.0 )
1356 vlc_value_t val
= { .i_int
= INPUT_RATE_DEFAULT
/ f_rate
};
1357 input_ControlPush( p_input
, INPUT_CONTROL_SET_RATE
, &val
);
1361 if( !priv
->b_preparsing
&& priv
->p_sout
)
1363 priv
->b_out_pace_control
= priv
->p_sout
->i_out_pace_nocontrol
> 0;
1365 msg_Dbg( p_input
, "starting in %ssync mode",
1366 priv
->b_out_pace_control
? "a" : "" );
1369 vlc_meta_t
*p_meta
= vlc_meta_New();
1370 if( p_meta
!= NULL
)
1372 /* Get meta data from users */
1373 InputMetaUser( p_input
, p_meta
);
1375 /* Get meta data from master input */
1376 InputSourceMeta( p_input
, master
, p_meta
);
1378 /* And from slave */
1379 for( int i
= 0; i
< priv
->i_slave
; i
++ )
1380 InputSourceMeta( p_input
, priv
->slave
[i
], p_meta
);
1382 es_out_ControlSetMeta( priv
->p_es_out
, p_meta
);
1383 vlc_meta_Delete( p_meta
);
1386 msg_Dbg( p_input
, "`%s' successfully opened",
1387 input_priv(p_input
)->p_item
->psz_uri
);
1389 /* initialization is complete */
1390 input_ChangeState( p_input
, PLAYING_S
);
1395 input_ChangeState( p_input
, ERROR_S
);
1397 if( input_priv(p_input
)->p_es_out
)
1398 es_out_Delete( input_priv(p_input
)->p_es_out
);
1399 es_out_SetMode( input_priv(p_input
)->p_es_out_display
, ES_OUT_MODE_END
);
1400 if( input_priv(p_input
)->p_resource
)
1402 if( input_priv(p_input
)->p_sout
)
1403 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1404 input_priv(p_input
)->p_sout
, NULL
);
1405 input_resource_SetInput( input_priv(p_input
)->p_resource
, NULL
);
1406 if( input_priv(p_input
)->p_resource_private
)
1407 input_resource_Terminate( input_priv(p_input
)->p_resource_private
);
1410 if( !priv
->b_preparsing
&& libvlc_stats( p_input
) )
1412 #define EXIT_COUNTER( c ) do { if( input_priv(p_input)->counters.p_##c ) \
1413 stats_CounterClean( input_priv(p_input)->counters.p_##c );\
1414 input_priv(p_input)->counters.p_##c = NULL; } while(0)
1415 EXIT_COUNTER( read_bytes
);
1416 EXIT_COUNTER( read_packets
);
1417 EXIT_COUNTER( demux_read
);
1418 EXIT_COUNTER( input_bitrate
);
1419 EXIT_COUNTER( demux_bitrate
);
1420 EXIT_COUNTER( demux_corrupted
);
1421 EXIT_COUNTER( demux_discontinuity
);
1422 EXIT_COUNTER( played_abuffers
);
1423 EXIT_COUNTER( lost_abuffers
);
1424 EXIT_COUNTER( displayed_pictures
);
1425 EXIT_COUNTER( lost_pictures
);
1426 EXIT_COUNTER( decoded_audio
);
1427 EXIT_COUNTER( decoded_video
);
1428 EXIT_COUNTER( decoded_sub
);
1430 if( input_priv(p_input
)->p_sout
)
1432 EXIT_COUNTER( sout_sent_packets
);
1433 EXIT_COUNTER( sout_sent_bytes
);
1434 EXIT_COUNTER( sout_send_bitrate
);
1439 /* Mark them deleted */
1440 input_priv(p_input
)->p_es_out
= NULL
;
1441 input_priv(p_input
)->p_sout
= NULL
;
1443 return VLC_EGENERIC
;
1446 /*****************************************************************************
1447 * End: end the input thread
1448 *****************************************************************************/
1449 static void End( input_thread_t
* p_input
)
1451 input_thread_private_t
*priv
= input_priv(p_input
);
1453 /* We are at the end */
1454 input_ChangeState( p_input
, END_S
);
1456 /* Clean control variables */
1457 input_ControlVarStop( p_input
);
1459 /* Stop es out activity */
1460 es_out_SetMode( priv
->p_es_out
, ES_OUT_MODE_NONE
);
1463 for( int i
= 0; i
< priv
->i_slave
; i
++ )
1464 InputSourceDestroy( priv
->slave
[i
] );
1465 free( priv
->slave
);
1467 /* Clean up master */
1468 InputSourceDestroy( priv
->master
);
1471 priv
->i_title_offset
= 0;
1472 priv
->i_seekpoint_offset
= 0;
1474 /* Unload all modules */
1475 if( priv
->p_es_out
)
1476 es_out_Delete( priv
->p_es_out
);
1477 es_out_SetMode( priv
->p_es_out_display
, ES_OUT_MODE_END
);
1479 if( !priv
->b_preparsing
)
1481 #define CL_CO( c ) \
1483 stats_CounterClean( priv->counters.p_##c ); \
1484 priv->counters.p_##c = NULL; \
1487 if( libvlc_stats( p_input
) )
1489 /* make sure we are up to date */
1490 stats_ComputeInputStats( p_input
, priv
->p_item
->p_stats
);
1491 CL_CO( read_bytes
);
1492 CL_CO( read_packets
);
1493 CL_CO( demux_read
);
1494 CL_CO( input_bitrate
);
1495 CL_CO( demux_bitrate
);
1496 CL_CO( demux_corrupted
);
1497 CL_CO( demux_discontinuity
);
1498 CL_CO( played_abuffers
);
1499 CL_CO( lost_abuffers
);
1500 CL_CO( displayed_pictures
);
1501 CL_CO( lost_pictures
);
1502 CL_CO( decoded_audio
) ;
1503 CL_CO( decoded_video
);
1504 CL_CO( decoded_sub
) ;
1507 /* Close optional stream output instance */
1510 CL_CO( sout_sent_packets
);
1511 CL_CO( sout_sent_bytes
);
1512 CL_CO( sout_send_bitrate
);
1517 vlc_mutex_lock( &priv
->p_item
->lock
);
1518 if( priv
->i_attachment
> 0 )
1520 for( int i
= 0; i
< priv
->i_attachment
; i
++ )
1521 vlc_input_attachment_Delete( priv
->attachment
[i
] );
1522 TAB_CLEAN( priv
->i_attachment
, priv
->attachment
);
1523 free( priv
->attachment_demux
);
1524 priv
->attachment_demux
= NULL
;
1527 /* clean bookmarks */
1528 for( int i
= 0; i
< priv
->i_bookmark
; ++i
)
1529 vlc_seekpoint_Delete( priv
->pp_bookmark
[i
] );
1530 TAB_CLEAN( priv
->i_bookmark
, priv
->pp_bookmark
);
1532 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1535 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1536 input_priv(p_input
)->p_sout
, NULL
);
1537 input_resource_SetInput( input_priv(p_input
)->p_resource
, NULL
);
1538 if( input_priv(p_input
)->p_resource_private
)
1539 input_resource_Terminate( input_priv(p_input
)->p_resource_private
);
1542 /*****************************************************************************
1544 *****************************************************************************/
1545 void input_ControlPush( input_thread_t
*p_input
,
1546 int i_type
, vlc_value_t
*p_val
)
1548 input_thread_private_t
*sys
= input_priv(p_input
);
1550 vlc_mutex_lock( &sys
->lock_control
);
1551 if( sys
->is_stopped
|| sys
->i_control
>= INPUT_CONTROL_FIFO_SIZE
)
1553 if( sys
->is_stopped
)
1554 msg_Dbg( p_input
, "input control stopped, trashing type=%d",
1557 msg_Err( p_input
, "input control fifo overflow, trashing type=%d",
1560 ControlRelease( i_type
, *p_val
);
1569 memset( &c
.val
, 0, sizeof(c
.val
) );
1571 sys
->control
[sys
->i_control
++] = c
;
1573 vlc_cond_signal( &sys
->wait_control
);
1575 vlc_mutex_unlock( &sys
->lock_control
);
1578 static int ControlGetReducedIndexLocked( input_thread_t
*p_input
)
1580 const int i_lt
= input_priv(p_input
)->control
[0].i_type
;
1582 for( i
= 1; i
< input_priv(p_input
)->i_control
; i
++ )
1584 const int i_ct
= input_priv(p_input
)->control
[i
].i_type
;
1587 ( i_ct
== INPUT_CONTROL_SET_STATE
||
1588 i_ct
== INPUT_CONTROL_SET_RATE
||
1589 i_ct
== INPUT_CONTROL_SET_POSITION
||
1590 i_ct
== INPUT_CONTROL_SET_TIME
||
1591 i_ct
== INPUT_CONTROL_SET_PROGRAM
||
1592 i_ct
== INPUT_CONTROL_SET_TITLE
||
1593 i_ct
== INPUT_CONTROL_SET_SEEKPOINT
||
1594 i_ct
== INPUT_CONTROL_SET_BOOKMARK
) )
1600 /* TODO but that's not that important
1601 - merge SET_X with SET_X_CMD
1602 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1603 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1613 static inline int ControlPop( input_thread_t
*p_input
,
1614 int *pi_type
, vlc_value_t
*p_val
,
1615 mtime_t i_deadline
, bool b_postpone_seek
)
1617 input_thread_private_t
*p_sys
= input_priv(p_input
);
1619 vlc_mutex_lock( &p_sys
->lock_control
);
1620 while( p_sys
->i_control
<= 0 ||
1621 ( b_postpone_seek
&& ControlIsSeekRequest( p_sys
->control
[0].i_type
) ) )
1623 if( p_sys
->is_stopped
)
1625 vlc_mutex_unlock( &p_sys
->lock_control
);
1626 return VLC_EGENERIC
;
1629 if( i_deadline
>= 0 )
1631 if( vlc_cond_timedwait( &p_sys
->wait_control
, &p_sys
->lock_control
,
1634 vlc_mutex_unlock( &p_sys
->lock_control
);
1635 return VLC_EGENERIC
;
1639 vlc_cond_wait( &p_sys
->wait_control
, &p_sys
->lock_control
);
1643 const int i_index
= ControlGetReducedIndexLocked( p_input
);
1645 for( int i
= 0; i
< i_index
; ++i
)
1647 /* Release Reduced controls */
1648 ControlRelease( p_sys
->control
[i
].i_type
, p_sys
->control
[i
].val
);
1652 *pi_type
= p_sys
->control
[i_index
].i_type
;
1653 *p_val
= p_sys
->control
[i_index
].val
;
1655 p_sys
->i_control
-= i_index
+ 1;
1656 if( p_sys
->i_control
> 0 )
1657 memmove( &p_sys
->control
[0], &p_sys
->control
[i_index
+1],
1658 sizeof(*p_sys
->control
) * p_sys
->i_control
);
1659 vlc_mutex_unlock( &p_sys
->lock_control
);
1663 static bool ControlIsSeekRequest( int i_type
)
1667 case INPUT_CONTROL_SET_POSITION
:
1668 case INPUT_CONTROL_SET_TIME
:
1669 case INPUT_CONTROL_SET_TITLE
:
1670 case INPUT_CONTROL_SET_TITLE_NEXT
:
1671 case INPUT_CONTROL_SET_TITLE_PREV
:
1672 case INPUT_CONTROL_SET_SEEKPOINT
:
1673 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1674 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1675 case INPUT_CONTROL_SET_BOOKMARK
:
1676 case INPUT_CONTROL_NAV_ACTIVATE
:
1677 case INPUT_CONTROL_NAV_UP
:
1678 case INPUT_CONTROL_NAV_DOWN
:
1679 case INPUT_CONTROL_NAV_LEFT
:
1680 case INPUT_CONTROL_NAV_RIGHT
:
1681 case INPUT_CONTROL_NAV_POPUP
:
1682 case INPUT_CONTROL_NAV_MENU
:
1689 static void ControlRelease( int i_type
, vlc_value_t val
)
1693 case INPUT_CONTROL_ADD_SLAVE
:
1695 input_item_slave_Delete( val
.p_address
);
1697 case INPUT_CONTROL_SET_VIEWPOINT
:
1698 case INPUT_CONTROL_SET_INITIAL_VIEWPOINT
:
1699 case INPUT_CONTROL_UPDATE_VIEWPOINT
:
1700 free( val
.p_address
);
1709 static void ControlPause( input_thread_t
*p_input
, mtime_t i_control_date
)
1711 int i_state
= PAUSE_S
;
1713 if( input_priv(p_input
)->b_can_pause
)
1715 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
1717 if( demux_Control( p_demux
, DEMUX_SET_PAUSE_STATE
, true ) )
1719 msg_Warn( p_input
, "cannot set pause state" );
1725 if( es_out_SetPauseState( input_priv(p_input
)->p_es_out
, input_priv(p_input
)->b_can_pause
,
1726 true, i_control_date
) )
1728 msg_Warn( p_input
, "cannot set pause state at es_out level" );
1732 /* Switch to new state */
1733 input_ChangeState( p_input
, i_state
);
1736 static void ControlUnpause( input_thread_t
*p_input
, mtime_t i_control_date
)
1738 if( input_priv(p_input
)->b_can_pause
)
1740 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
1742 if( demux_Control( p_demux
, DEMUX_SET_PAUSE_STATE
, false ) )
1744 msg_Err( p_input
, "cannot resume" );
1745 input_ChangeState( p_input
, ERROR_S
);
1750 /* Switch to play */
1751 input_ChangeState( p_input
, PLAYING_S
);
1752 es_out_SetPauseState( input_priv(p_input
)->p_es_out
, false, false, i_control_date
);
1755 static void ViewpointApply( input_thread_t
*p_input
)
1757 input_thread_private_t
*priv
= input_priv(p_input
);
1759 vlc_viewpoint_clip( &priv
->viewpoint
);
1761 vout_thread_t
**pp_vout
;
1763 input_resource_HoldVouts( priv
->p_resource
, &pp_vout
, &i_vout
);
1765 for( size_t i
= 0; i
< i_vout
; ++i
)
1767 var_SetAddress( pp_vout
[i
], "viewpoint", &priv
->viewpoint
);
1768 /* This variable can only be read from callbacks */
1769 var_Change( pp_vout
[i
], "viewpoint", VLC_VAR_SETVALUE
,
1770 &(vlc_value_t
) { .p_address
= NULL
}, NULL
);
1771 vlc_object_release( pp_vout
[i
] );
1775 audio_output_t
*p_aout
= input_resource_HoldAout( priv
->p_resource
);
1779 var_SetAddress( p_aout
, "viewpoint", &priv
->viewpoint
);
1780 /* This variable can only be read from callbacks */
1781 var_Change( p_aout
, "viewpoint", VLC_VAR_SETVALUE
,
1782 &(vlc_value_t
) { .p_address
= NULL
}, NULL
);
1783 vlc_object_release( p_aout
);
1787 static void ControlNav( input_thread_t
*p_input
, int i_type
)
1789 input_thread_private_t
*priv
= input_priv(p_input
);
1791 if( !demux_Control( priv
->master
->p_demux
, i_type
1792 - INPUT_CONTROL_NAV_ACTIVATE
+ DEMUX_NAV_ACTIVATE
) )
1793 return; /* The demux handled the navigation control */
1795 /* Handle Up/Down/Left/Right if the demux can't navigate */
1796 vlc_viewpoint_t vp
= {};
1797 int vol_direction
= 0;
1798 int seek_direction
= 0;
1801 case INPUT_CONTROL_NAV_UP
:
1805 case INPUT_CONTROL_NAV_DOWN
:
1809 case INPUT_CONTROL_NAV_LEFT
:
1810 seek_direction
= -1;
1813 case INPUT_CONTROL_NAV_RIGHT
:
1817 case INPUT_CONTROL_NAV_ACTIVATE
:
1818 case INPUT_CONTROL_NAV_POPUP
:
1819 case INPUT_CONTROL_NAV_MENU
:
1822 vlc_assert_unreachable();
1825 /* Try to change the viewpoint if possible */
1826 vout_thread_t
**pp_vout
;
1828 bool b_viewpoint_ch
= false;
1829 input_resource_HoldVouts( priv
->p_resource
, &pp_vout
, &i_vout
);
1830 for( size_t i
= 0; i
< i_vout
; ++i
)
1833 && var_GetBool( pp_vout
[i
], "viewpoint-changeable" ) )
1834 b_viewpoint_ch
= true;
1835 vlc_object_release( pp_vout
[i
] );
1839 if( b_viewpoint_ch
)
1841 priv
->viewpoint_changed
= true;
1842 priv
->viewpoint
.yaw
+= vp
.yaw
;
1843 priv
->viewpoint
.pitch
+= vp
.pitch
;
1844 priv
->viewpoint
.roll
+= vp
.roll
;
1845 priv
->viewpoint
.fov
+= vp
.fov
;
1846 ViewpointApply( p_input
);
1850 /* Seek or change volume if the input doesn't have navigation or viewpoint */
1851 if( seek_direction
!= 0 )
1853 mtime_t it
= var_InheritInteger( p_input
, "short-jump-size" );
1854 var_SetInteger( p_input
, "time-offset", it
* seek_direction
* CLOCK_FREQ
);
1858 assert( vol_direction
!= 0 );
1859 audio_output_t
*p_aout
= input_resource_HoldAout( priv
->p_resource
);
1862 aout_VolumeUpdate( p_aout
, vol_direction
, NULL
);
1863 vlc_object_release( p_aout
);
1869 static void ControlUpdateSout( input_thread_t
*p_input
, const char* psz_chain
)
1871 var_SetString( p_input
, "sout", psz_chain
);
1872 if( psz_chain
&& *psz_chain
)
1874 if( InitSout( p_input
) != VLC_SUCCESS
)
1876 msg_Err( p_input
, "Failed to start sout" );
1882 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1883 input_priv(p_input
)->p_sout
, NULL
);
1884 input_priv(p_input
)->p_sout
= NULL
;
1886 es_out_Control( input_priv(p_input
)->p_es_out
, ES_OUT_RESTART_ALL_ES
);
1890 static void ControlInsertDemuxFilter( input_thread_t
* p_input
, const char* psz_demux_chain
)
1892 input_source_t
*p_inputSource
= input_priv(p_input
)->master
;
1893 demux_t
*p_filtered_demux
= demux_FilterChainNew( p_inputSource
->p_demux
, psz_demux_chain
);
1894 if ( p_filtered_demux
!= NULL
)
1895 p_inputSource
->p_demux
= p_filtered_demux
;
1896 else if ( psz_demux_chain
!= NULL
)
1897 msg_Dbg(p_input
, "Failed to create demux filter %s", psz_demux_chain
);
1900 static bool Control( input_thread_t
*p_input
,
1901 int i_type
, vlc_value_t val
)
1903 const mtime_t i_control_date
= mdate();
1904 /* FIXME b_force_update is abused, it should be carefully checked */
1905 bool b_force_update
= false;
1908 return b_force_update
;
1912 case INPUT_CONTROL_SET_POSITION
:
1914 if( input_priv(p_input
)->b_recording
)
1916 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION ignored while recording" );
1920 float f_pos
= val
.f_float
;
1923 else if( f_pos
> 1.f
)
1925 /* Reset the decoders states and clock sync (before calling the demuxer */
1926 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
1927 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_POSITION
,
1928 (double) f_pos
, !input_priv(p_input
)->b_fast_seek
) )
1930 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION "
1931 "%2.1f%% failed", (double)(f_pos
* 100.f
) );
1935 if( input_priv(p_input
)->i_slave
> 0 )
1936 SlaveSeek( p_input
);
1937 input_priv(p_input
)->master
->b_eof
= false;
1939 b_force_update
= true;
1944 case INPUT_CONTROL_SET_TIME
:
1949 if( input_priv(p_input
)->b_recording
)
1951 msg_Err( p_input
, "INPUT_CONTROL_SET_TIME ignored while recording" );
1959 /* Reset the decoders states and clock sync (before calling the demuxer */
1960 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
1962 i_ret
= demux_Control( input_priv(p_input
)->master
->p_demux
,
1963 DEMUX_SET_TIME
, i_time
,
1964 !input_priv(p_input
)->b_fast_seek
);
1969 /* Emulate it with a SET_POS */
1970 if( !demux_Control( input_priv(p_input
)->master
->p_demux
,
1971 DEMUX_GET_LENGTH
, &i_length
) && i_length
> 0 )
1973 double f_pos
= (double)i_time
/ (double)i_length
;
1974 i_ret
= demux_Control( input_priv(p_input
)->master
->p_demux
,
1975 DEMUX_SET_POSITION
, f_pos
,
1976 !input_priv(p_input
)->b_fast_seek
);
1981 msg_Warn( p_input
, "INPUT_CONTROL_SET_TIME %"PRId64
1982 " failed or not possible", i_time
);
1986 if( input_priv(p_input
)->i_slave
> 0 )
1987 SlaveSeek( p_input
);
1988 input_priv(p_input
)->master
->b_eof
= false;
1990 b_force_update
= true;
1995 case INPUT_CONTROL_SET_STATE
:
1999 if( input_priv(p_input
)->i_state
== PAUSE_S
)
2001 ControlUnpause( p_input
, i_control_date
);
2002 b_force_update
= true;
2006 if( input_priv(p_input
)->i_state
== PLAYING_S
)
2008 ControlPause( p_input
, i_control_date
);
2009 b_force_update
= true;
2013 msg_Err( p_input
, "invalid INPUT_CONTROL_SET_STATE" );
2017 case INPUT_CONTROL_SET_RATE
:
2019 /* Get rate and direction */
2020 long long i_rate
= llabs( val
.i_int
);
2021 int i_rate_sign
= val
.i_int
< 0 ? -1 : 1;
2023 /* Check rate bound */
2024 if( i_rate
< INPUT_RATE_MIN
)
2026 msg_Dbg( p_input
, "cannot set rate faster" );
2027 i_rate
= INPUT_RATE_MIN
;
2029 else if( i_rate
> INPUT_RATE_MAX
)
2031 msg_Dbg( p_input
, "cannot set rate slower" );
2032 i_rate
= INPUT_RATE_MAX
;
2035 /* Apply direction */
2036 if( i_rate_sign
< 0 )
2038 if( input_priv(p_input
)->master
->b_rescale_ts
)
2040 msg_Dbg( p_input
, "cannot set negative rate" );
2041 i_rate
= input_priv(p_input
)->i_rate
;
2042 assert( i_rate
> 0 );
2046 i_rate
*= i_rate_sign
;
2050 if( i_rate
!= INPUT_RATE_DEFAULT
&&
2051 ( ( !input_priv(p_input
)->b_can_rate_control
&& !input_priv(p_input
)->master
->b_rescale_ts
) ||
2052 ( input_priv(p_input
)->p_sout
&& !input_priv(p_input
)->b_out_pace_control
) ) )
2054 msg_Dbg( p_input
, "cannot change rate" );
2055 i_rate
= INPUT_RATE_DEFAULT
;
2057 if( i_rate
!= input_priv(p_input
)->i_rate
&&
2058 !input_priv(p_input
)->b_can_pace_control
&& input_priv(p_input
)->b_can_rate_control
)
2060 if( !input_priv(p_input
)->master
->b_rescale_ts
)
2061 es_out_Control( input_priv(p_input
)->p_es_out
, ES_OUT_RESET_PCR
);
2063 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_RATE
,
2066 msg_Warn( p_input
, "ACCESS/DEMUX_SET_RATE failed" );
2067 i_rate
= input_priv(p_input
)->i_rate
;
2072 if( i_rate
!= input_priv(p_input
)->i_rate
)
2074 input_priv(p_input
)->i_rate
= i_rate
;
2075 input_SendEventRate( p_input
, i_rate
);
2077 if( input_priv(p_input
)->master
->b_rescale_ts
)
2079 const int i_rate_source
= (input_priv(p_input
)->b_can_pace_control
|| input_priv(p_input
)->b_can_rate_control
) ? i_rate
: INPUT_RATE_DEFAULT
;
2080 es_out_SetRate( input_priv(p_input
)->p_es_out
, i_rate_source
, i_rate
);
2083 b_force_update
= true;
2088 case INPUT_CONTROL_SET_PROGRAM
:
2089 /* No need to force update, es_out does it if needed */
2090 es_out_Control( input_priv(p_input
)->p_es_out
,
2091 ES_OUT_SET_GROUP
, val
.i_int
);
2093 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
, val
.i_int
,
2097 case INPUT_CONTROL_SET_ES
:
2098 /* No need to force update, es_out does it if needed */
2099 es_out_Control( input_priv(p_input
)->p_es_out_display
,
2100 ES_OUT_SET_ES_BY_ID
, (int)val
.i_int
);
2102 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_ES
, (int)val
.i_int
);
2105 case INPUT_CONTROL_RESTART_ES
:
2106 es_out_Control( input_priv(p_input
)->p_es_out_display
,
2107 ES_OUT_RESTART_ES_BY_ID
, (int)val
.i_int
);
2110 case INPUT_CONTROL_SET_VIEWPOINT
:
2111 case INPUT_CONTROL_SET_INITIAL_VIEWPOINT
:
2112 case INPUT_CONTROL_UPDATE_VIEWPOINT
:
2114 input_thread_private_t
*priv
= input_priv(p_input
);
2115 const vlc_viewpoint_t
*p_vp
= val
.p_address
;
2117 if ( i_type
== INPUT_CONTROL_SET_INITIAL_VIEWPOINT
)
2120 /* Set the initial viewpoint if it had not been changed by the
2122 if( !priv
->viewpoint_changed
)
2123 priv
->viewpoint
= *p_vp
;
2124 /* Update viewpoints of aout and every vouts in all cases. */
2126 else if ( i_type
== INPUT_CONTROL_SET_VIEWPOINT
)
2128 priv
->viewpoint_changed
= true;
2129 priv
->viewpoint
= *p_vp
;
2133 priv
->viewpoint_changed
= true;
2134 priv
->viewpoint
.yaw
+= p_vp
->yaw
;
2135 priv
->viewpoint
.pitch
+= p_vp
->pitch
;
2136 priv
->viewpoint
.roll
+= p_vp
->roll
;
2137 priv
->viewpoint
.fov
+= p_vp
->fov
;
2140 ViewpointApply( p_input
);
2144 case INPUT_CONTROL_SET_AUDIO_DELAY
:
2145 input_SendEventAudioDelay( p_input
, val
.i_int
);
2146 UpdatePtsDelay( p_input
);
2149 case INPUT_CONTROL_SET_SPU_DELAY
:
2150 input_SendEventSubtitleDelay( p_input
, val
.i_int
);
2151 UpdatePtsDelay( p_input
);
2154 case INPUT_CONTROL_SET_TITLE
:
2155 case INPUT_CONTROL_SET_TITLE_NEXT
:
2156 case INPUT_CONTROL_SET_TITLE_PREV
:
2158 if( input_priv(p_input
)->b_recording
)
2160 msg_Err( p_input
, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
2163 if( input_priv(p_input
)->master
->i_title
<= 0 )
2166 int i_title
= demux_GetTitle( input_priv(p_input
)->master
->p_demux
);
2167 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
2169 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
2172 i_title
= val
.i_int
;
2173 if( i_title
< 0 || i_title
>= input_priv(p_input
)->master
->i_title
)
2176 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
2177 demux_Control( input_priv(p_input
)->master
->p_demux
,
2178 DEMUX_SET_TITLE
, i_title
);
2179 input_SendEventTitle( p_input
, i_title
);
2182 case INPUT_CONTROL_SET_SEEKPOINT
:
2183 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
2184 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
2186 if( input_priv(p_input
)->b_recording
)
2188 msg_Err( p_input
, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
2191 if( input_priv(p_input
)->master
->i_title
<= 0 )
2194 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2196 int i_title
= demux_GetTitle( p_demux
);
2197 int i_seekpoint
= demux_GetSeekpoint( p_demux
);
2199 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
2201 int64_t i_seekpoint_time
= input_priv(p_input
)->master
->title
[i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
2202 int64_t i_input_time
= var_GetInteger( p_input
, "time" );
2203 if( i_seekpoint_time
>= 0 && i_input_time
>= 0 )
2205 if( i_input_time
< i_seekpoint_time
+ 3000000 )
2211 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
2214 i_seekpoint
= val
.i_int
;
2216 || i_seekpoint
>= input_priv(p_input
)->master
->title
[i_title
]->i_seekpoint
)
2219 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
2220 demux_Control( input_priv(p_input
)->master
->p_demux
,
2221 DEMUX_SET_SEEKPOINT
, i_seekpoint
);
2222 input_SendEventSeekpoint( p_input
, i_title
, i_seekpoint
);
2226 case INPUT_CONTROL_ADD_SLAVE
:
2229 input_item_slave_t
*p_item_slave
= val
.p_address
;
2230 unsigned i_flags
= SLAVE_ADD_CANFAIL
| SLAVE_ADD_SET_TIME
;
2231 if( p_item_slave
->b_forced
)
2232 i_flags
|= SLAVE_ADD_FORCED
;
2234 if( input_SlaveSourceAdd( p_input
, p_item_slave
->i_type
,
2235 p_item_slave
->psz_uri
, i_flags
)
2238 /* Update item slaves */
2239 input_item_AddSlave( input_priv(p_input
)->p_item
, p_item_slave
);
2240 /* The slave is now owned by the item */
2241 val
.p_address
= NULL
;
2246 case INPUT_CONTROL_SET_RECORD_STATE
:
2247 if( !!input_priv(p_input
)->b_recording
!= !!val
.b_bool
)
2249 if( input_priv(p_input
)->master
->b_can_stream_record
)
2251 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
2252 DEMUX_SET_RECORD_STATE
, val
.b_bool
) )
2257 if( es_out_SetRecordState( input_priv(p_input
)->p_es_out_display
, val
.b_bool
) )
2260 input_priv(p_input
)->b_recording
= val
.b_bool
;
2262 input_SendEventRecord( p_input
, val
.b_bool
);
2264 b_force_update
= true;
2268 case INPUT_CONTROL_SET_FRAME_NEXT
:
2269 if( input_priv(p_input
)->i_state
== PAUSE_S
)
2271 es_out_SetFrameNext( input_priv(p_input
)->p_es_out
);
2273 else if( input_priv(p_input
)->i_state
== PLAYING_S
)
2275 ControlPause( p_input
, i_control_date
);
2279 msg_Err( p_input
, "invalid state for frame next" );
2281 b_force_update
= true;
2284 case INPUT_CONTROL_SET_BOOKMARK
:
2286 mtime_t time_offset
= -1;
2288 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2289 if( val
.i_int
>= 0 && val
.i_int
< input_priv(p_input
)->i_bookmark
)
2291 const seekpoint_t
*p_bookmark
= input_priv(p_input
)->pp_bookmark
[val
.i_int
];
2292 time_offset
= p_bookmark
->i_time_offset
;
2294 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2296 if( time_offset
< 0 )
2298 msg_Err( p_input
, "invalid bookmark %"PRId64
, val
.i_int
);
2302 val
.i_int
= time_offset
;
2303 b_force_update
= Control( p_input
, INPUT_CONTROL_SET_TIME
, val
);
2306 case INPUT_CONTROL_SET_RENDERER
:
2309 vlc_renderer_item_t
*p_item
= val
.p_address
;
2310 input_thread_private_t
*p_priv
= input_priv( p_input
);
2311 // We do not support switching from a renderer to another for now
2312 if ( p_item
== NULL
&& p_priv
->p_renderer
== NULL
)
2315 if ( p_priv
->p_renderer
)
2317 ControlUpdateSout( p_input
, NULL
);
2318 demux_FilterDisable( p_priv
->master
->p_demux
,
2319 vlc_renderer_item_demux_filter( p_priv
->p_renderer
) );
2320 vlc_renderer_item_release( p_priv
->p_renderer
);
2321 p_priv
->p_renderer
= NULL
;
2323 if( p_item
!= NULL
)
2325 p_priv
->p_renderer
= vlc_renderer_item_hold( p_item
);
2326 ControlUpdateSout( p_input
, vlc_renderer_item_sout( p_item
) );
2327 if( !demux_FilterEnable( p_priv
->master
->p_demux
,
2328 vlc_renderer_item_demux_filter( p_priv
->p_renderer
) ) )
2330 ControlInsertDemuxFilter( p_input
,
2331 vlc_renderer_item_demux_filter( p_item
) );
2333 input_resource_TerminateVout( p_priv
->p_resource
);
2339 case INPUT_CONTROL_NAV_ACTIVATE
:
2340 case INPUT_CONTROL_NAV_UP
:
2341 case INPUT_CONTROL_NAV_DOWN
:
2342 case INPUT_CONTROL_NAV_LEFT
:
2343 case INPUT_CONTROL_NAV_RIGHT
:
2344 case INPUT_CONTROL_NAV_POPUP
:
2345 case INPUT_CONTROL_NAV_MENU
:
2346 ControlNav( p_input
, i_type
);
2350 msg_Err( p_input
, "not yet implemented" );
2354 ControlRelease( i_type
, val
);
2355 return b_force_update
;
2358 /*****************************************************************************
2359 * UpdateTitleSeekpoint
2360 *****************************************************************************/
2361 static int UpdateTitleSeekpoint( input_thread_t
*p_input
,
2362 int i_title
, int i_seekpoint
)
2364 int i_title_end
= input_priv(p_input
)->master
->i_title_end
-
2365 input_priv(p_input
)->master
->i_title_offset
;
2366 int i_seekpoint_end
= input_priv(p_input
)->master
->i_seekpoint_end
-
2367 input_priv(p_input
)->master
->i_seekpoint_offset
;
2369 if( i_title_end
>= 0 && i_seekpoint_end
>= 0 )
2371 if( i_title
> i_title_end
||
2372 ( i_title
== i_title_end
&& i_seekpoint
> i_seekpoint_end
) )
2373 return VLC_DEMUXER_EOF
;
2375 else if( i_seekpoint_end
>= 0 )
2377 if( i_seekpoint
> i_seekpoint_end
)
2378 return VLC_DEMUXER_EOF
;
2380 else if( i_title_end
>= 0 )
2382 if( i_title
> i_title_end
)
2383 return VLC_DEMUXER_EOF
;
2385 return VLC_DEMUXER_SUCCESS
;
2387 /*****************************************************************************
2389 *****************************************************************************/
2390 static int UpdateTitleSeekpointFromDemux( input_thread_t
*p_input
)
2392 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2394 /* TODO event-like */
2395 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_TITLE
) )
2396 input_SendEventTitle( p_input
, demux_GetTitle( p_demux
) );
2398 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_SEEKPOINT
) )
2399 input_SendEventSeekpoint( p_input
, demux_GetTitle( p_demux
),
2400 demux_GetSeekpoint( p_demux
) );
2402 return UpdateTitleSeekpoint( p_input
,
2403 demux_GetTitle( p_demux
),
2404 demux_GetSeekpoint( p_demux
) );
2407 static void UpdateGenericFromDemux( input_thread_t
*p_input
)
2409 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2411 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_META
) )
2412 InputUpdateMeta( p_input
, p_demux
);
2418 if( !demux_Control( p_demux
, DEMUX_GET_SIGNAL
, &quality
, &strength
) )
2419 input_SendEventSignal( p_input
, quality
, strength
);
2423 static void UpdateTitleListfromDemux( input_thread_t
*p_input
)
2425 input_thread_private_t
*priv
= input_priv(p_input
);
2426 input_source_t
*in
= priv
->master
;
2428 /* Delete the preexisting titles */
2429 if( in
->i_title
> 0 )
2431 for( int i
= 0; i
< in
->i_title
; i
++ )
2432 vlc_input_title_Delete( in
->title
[i
] );
2433 TAB_CLEAN( in
->i_title
, in
->title
);
2436 in
->b_title_demux
= false;
2439 /* Get the new title list */
2440 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2441 &in
->title
, &in
->i_title
,
2442 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2443 TAB_INIT( in
->i_title
, in
->title
);
2445 in
->b_title_demux
= true;
2447 InitTitle( p_input
);
2451 InputStreamHandleAnchor( input_source_t
*source
, stream_t
**stream
,
2452 char const *anchor
)
2455 if( stream_extractor_AttachParsed( stream
, anchor
, &extra
) )
2457 msg_Err( source
, "unable to attach stream-extractors for %s",
2458 (*stream
)->psz_url
);
2460 return VLC_EGENERIC
;
2463 if( vlc_stream_directory_Attach( stream
, NULL
) )
2464 msg_Dbg( source
, "attachment of directory-extractor failed for %s",
2465 (*stream
)->psz_url
);
2467 MRLSections( extra
? extra
: "",
2468 &source
->i_title_start
, &source
->i_title_end
,
2469 &source
->i_seekpoint_start
, &source
->i_seekpoint_end
);
2474 static demux_t
*InputDemuxNew( input_thread_t
*p_input
, input_source_t
*p_source
,
2475 const char *psz_access
, const char *psz_demux
,
2476 const char *psz_path
, const char *psz_anchor
)
2478 input_thread_private_t
*priv
= input_priv(p_input
);
2479 demux_t
*p_demux
= NULL
;
2481 /* first, try to create an access demux */
2482 p_demux
= demux_NewAdvanced( VLC_OBJECT( p_source
), p_input
,
2483 psz_access
, psz_demux
, psz_path
,
2484 NULL
, priv
->p_es_out
, priv
->b_preparsing
);
2487 MRLSections( psz_anchor
,
2488 &p_source
->i_title_start
, &p_source
->i_title_end
,
2489 &p_source
->i_seekpoint_start
, &p_source
->i_seekpoint_end
);
2494 /* not an access-demux: create the underlying access stream */
2497 if( asprintf( &psz_base_mrl
, "%s://%s", psz_access
, psz_path
) < 0 )
2500 char *psz_filters
= var_InheritString( p_source
, "stream-filter" );
2501 stream_t
* p_stream
= stream_AccessNew( VLC_OBJECT( p_source
), p_input
,
2504 FREENULL( psz_base_mrl
);
2506 if( p_stream
== NULL
)
2509 /* attach explicit stream filters to stream */
2511 p_stream
= stream_FilterChainNew( p_stream
, psz_filters
);
2513 FREENULL( psz_filters
);
2515 /* handle anchors */
2516 if( InputStreamHandleAnchor( p_source
, &p_stream
, psz_anchor
) )
2519 /* attach conditional record stream-filter */
2520 if( var_InheritBool( p_source
, "input-record-native" ) )
2521 p_stream
= stream_FilterChainNew( p_stream
, "record" );
2523 /* create a regular demux with the access stream created */
2524 p_demux
= demux_NewAdvanced( VLC_OBJECT( p_source
), p_input
,
2525 psz_access
, psz_demux
, psz_path
,
2526 p_stream
, priv
->p_es_out
,
2527 priv
->b_preparsing
);
2532 free( psz_base_mrl
);
2533 free( psz_filters
);
2536 vlc_stream_Delete( p_stream
);
2541 /*****************************************************************************
2543 *****************************************************************************/
2544 static input_source_t
*InputSourceNew( input_thread_t
*p_input
,
2545 const char *psz_mrl
,
2546 const char *psz_forced_demux
,
2547 bool b_in_can_fail
)
2549 input_thread_private_t
*priv
= input_priv(p_input
);
2550 input_source_t
*in
= vlc_custom_create( p_input
, sizeof( *in
),
2552 if( unlikely(in
== NULL
) )
2555 const char *psz_access
, *psz_demux
, *psz_path
, *psz_anchor
= NULL
;
2558 char *psz_dup
= strdup( psz_mrl
);
2559 char *psz_demux_var
= NULL
;
2561 if( psz_dup
== NULL
)
2563 vlc_object_release( in
);
2568 input_SplitMRL( &psz_access
, &psz_demux
, &psz_path
, &psz_anchor
, psz_dup
);
2570 if( psz_demux
== NULL
|| psz_demux
[0] == '\0' )
2571 psz_demux
= psz_demux_var
= var_InheritString( in
, "demux" );
2573 if( psz_forced_demux
!= NULL
)
2574 psz_demux
= psz_forced_demux
;
2576 if( psz_demux
== NULL
)
2579 msg_Dbg( p_input
, "`%s' gives access `%s' demux `%s' path `%s'",
2580 psz_mrl
, psz_access
, psz_demux
, psz_path
);
2582 if( input_priv(p_input
)->master
== NULL
/* XXX ugly */)
2583 { /* On master stream only, use input-list */
2584 char *str
= var_InheritString( p_input
, "input-list" );
2589 var_Create( p_input
, "concat-list", VLC_VAR_STRING
);
2590 if( likely(asprintf( &list
, "%s://%s,%s", psz_access
, psz_path
,
2593 var_SetString( p_input
, "concat-list", list
);
2597 psz_access
= "concat";
2601 if( strcasecmp( psz_access
, "concat" ) )
2602 { /* Autodetect extra files if none specified */
2606 TAB_INIT( count
, tab
);
2607 InputGetExtraFiles( p_input
, &count
, &tab
, &psz_access
, psz_path
);
2612 for( int i
= 0; i
< count
; i
++ )
2615 if( asprintf( &str
, "%s,%s", list
? list
: psz_mrl
,
2624 var_Create( p_input
, "concat-list", VLC_VAR_STRING
);
2625 if( likely(list
!= NULL
) )
2627 var_SetString( p_input
, "concat-list", list
);
2631 TAB_CLEAN( count
, tab
);
2634 in
->p_demux
= InputDemuxNew( p_input
, in
, psz_access
, psz_demux
,
2635 psz_path
, psz_anchor
);
2637 free( psz_demux_var
);
2640 if( in
->p_demux
== NULL
)
2642 if( !b_in_can_fail
&& !input_Stopped( p_input
) )
2643 vlc_dialog_display_error( p_input
, _("Your input can't be opened"),
2644 _("VLC is unable to open the MRL '%s'."
2645 " Check the log for details."), psz_mrl
);
2646 vlc_object_release( in
);
2650 char *psz_demux_chain
= NULL
;
2651 if( priv
->p_renderer
)
2653 const char* psz_renderer_demux
= vlc_renderer_item_demux_filter(
2655 if( psz_renderer_demux
)
2656 psz_demux_chain
= strdup( psz_renderer_demux
);
2658 if( !psz_demux_chain
)
2659 psz_demux_chain
= var_GetNonEmptyString(p_input
, "demux-filter");
2660 if( psz_demux_chain
!= NULL
) /* add the chain of demux filters */
2662 in
->p_demux
= demux_FilterChainNew( in
->p_demux
, psz_demux_chain
);
2663 free( psz_demux_chain
);
2665 if( in
->p_demux
== NULL
)
2667 msg_Err(p_input
, "Failed to create demux filter");
2668 vlc_object_release( in
);
2673 /* Get infos from (access_)demux */
2675 if( demux_Control( in
->p_demux
, DEMUX_CAN_SEEK
, &b_can_seek
) )
2677 var_SetBool( p_input
, "can-seek", b_can_seek
);
2679 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_PACE
,
2680 &in
->b_can_pace_control
) )
2681 in
->b_can_pace_control
= false;
2683 assert( in
->p_demux
->pf_demux
!= NULL
|| !in
->b_can_pace_control
);
2685 if( !in
->b_can_pace_control
)
2687 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_RATE
,
2688 &in
->b_can_rate_control
) )
2690 in
->b_can_rate_control
= false;
2691 in
->b_rescale_ts
= true;
2694 in
->b_rescale_ts
= !in
->b_can_rate_control
;
2698 in
->b_can_rate_control
= true;
2699 in
->b_rescale_ts
= true;
2702 demux_Control( in
->p_demux
, DEMUX_CAN_PAUSE
, &in
->b_can_pause
);
2704 var_SetBool( p_input
, "can-pause", in
->b_can_pause
|| !in
->b_can_pace_control
); /* XXX temporary because of es_out_timeshift*/
2705 var_SetBool( p_input
, "can-rate", !in
->b_can_pace_control
|| in
->b_can_rate_control
); /* XXX temporary because of es_out_timeshift*/
2706 var_SetBool( p_input
, "can-rewind", !in
->b_rescale_ts
&& !in
->b_can_pace_control
&& in
->b_can_rate_control
);
2708 /* Set record capabilities */
2709 if( demux_Control( in
->p_demux
, DEMUX_CAN_RECORD
, &in
->b_can_stream_record
) )
2710 in
->b_can_stream_record
= false;
2712 if( !var_GetBool( p_input
, "input-record-native" ) )
2713 in
->b_can_stream_record
= false;
2714 var_SetBool( p_input
, "can-record", true );
2716 var_SetBool( p_input
, "can-record", in
->b_can_stream_record
);
2720 * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2721 if( !input_priv(p_input
)->b_preparsing
)
2723 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2724 &in
->title
, &in
->i_title
,
2725 &in
->i_title_offset
, &in
->i_seekpoint_offset
))
2727 TAB_INIT( in
->i_title
, in
->title
);
2731 in
->b_title_demux
= true;
2735 input_attachment_t
**attachment
;
2736 if( !demux_Control( in
->p_demux
, DEMUX_GET_ATTACHMENTS
,
2737 &attachment
, &i_attachment
) )
2739 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2740 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2741 i_attachment
, attachment
, in
->p_demux
);
2742 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2745 demux_Control( in
->p_demux
, DEMUX_GET_PTS_DELAY
, &in
->i_pts_delay
);
2746 if( in
->i_pts_delay
> INPUT_PTS_DELAY_MAX
)
2747 in
->i_pts_delay
= INPUT_PTS_DELAY_MAX
;
2748 else if( in
->i_pts_delay
< 0 )
2749 in
->i_pts_delay
= 0;
2752 if( demux_Control( in
->p_demux
, DEMUX_GET_FPS
, &in
->f_fps
) )
2755 if( var_GetInteger( p_input
, "clock-synchro" ) != -1 )
2756 in
->b_can_pace_control
= !var_GetInteger( p_input
, "clock-synchro" );
2761 /*****************************************************************************
2762 * InputSourceDestroy:
2763 *****************************************************************************/
2764 static void InputSourceDestroy( input_source_t
*in
)
2769 demux_Delete( in
->p_demux
);
2771 if( in
->i_title
> 0 )
2773 for( i
= 0; i
< in
->i_title
; i
++ )
2774 vlc_input_title_Delete( in
->title
[i
] );
2775 TAB_CLEAN( in
->i_title
, in
->title
);
2778 vlc_object_release( in
);
2781 /*****************************************************************************
2783 *****************************************************************************/
2784 static void InputSourceMeta( input_thread_t
*p_input
,
2785 input_source_t
*p_source
, vlc_meta_t
*p_meta
)
2787 demux_t
*p_demux
= p_source
->p_demux
;
2789 /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
2792 bool has_meta
= false;
2794 /* Read demux meta */
2795 if( !demux_Control( p_demux
, DEMUX_GET_META
, p_meta
) )
2798 bool has_unsupported
;
2799 if( demux_Control( p_demux
, DEMUX_HAS_UNSUPPORTED_META
, &has_unsupported
) )
2800 has_unsupported
= true;
2802 /* If the demux report unsupported meta data, or if we don't have meta data
2803 * try an external "meta reader" */
2804 if( has_meta
&& !has_unsupported
)
2807 demux_meta_t
*p_demux_meta
=
2808 vlc_custom_create( p_source
, sizeof( *p_demux_meta
), "demux meta" );
2809 if( unlikely(p_demux_meta
== NULL
) )
2811 p_demux_meta
->p_item
= input_priv(p_input
)->p_item
;
2813 module_t
*p_id3
= module_need( p_demux_meta
, "meta reader", NULL
, false );
2816 if( p_demux_meta
->p_meta
)
2818 vlc_meta_Merge( p_meta
, p_demux_meta
->p_meta
);
2819 vlc_meta_Delete( p_demux_meta
->p_meta
);
2822 if( p_demux_meta
->i_attachments
> 0 )
2824 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2825 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2826 p_demux_meta
->i_attachments
, p_demux_meta
->attachments
, p_demux
);
2827 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2829 module_unneed( p_demux
, p_id3
);
2831 vlc_object_release( p_demux_meta
);
2835 static void SlaveDemux( input_thread_t
*p_input
)
2840 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
2842 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2846 for( i
= 0; i
< input_priv(p_input
)->i_slave
; i
++ )
2848 input_source_t
*in
= input_priv(p_input
)->slave
[i
];
2854 /* Call demux_Demux until we have read enough data */
2855 if( demux_Control( in
->p_demux
, DEMUX_SET_NEXT_DEMUX_TIME
, i_time
) )
2860 if( demux_Control( in
->p_demux
, DEMUX_GET_TIME
, &i_stime
) )
2862 msg_Err( p_input
, "slave[%d] doesn't like "
2863 "DEMUX_GET_TIME -> EOF", i
);
2868 if( i_stime
>= i_time
)
2874 if( ( i_ret
= demux_Demux( in
->p_demux
) ) <= 0 )
2880 i_ret
= demux_Demux( in
->p_demux
);
2885 msg_Dbg( p_input
, "slave %d EOF", i
);
2891 static void SlaveSeek( input_thread_t
*p_input
)
2896 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
2898 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2902 for( i
= 0; i
< input_priv(p_input
)->i_slave
; i
++ )
2904 input_source_t
*in
= input_priv(p_input
)->slave
[i
];
2906 if( demux_Control( in
->p_demux
, DEMUX_SET_TIME
, i_time
, true ) )
2909 msg_Err( p_input
, "seek failed for slave %d -> EOF", i
);
2919 /*****************************************************************************
2921 *****************************************************************************/
2922 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2924 static const struct { int i_meta
; const char *psz_name
; } p_list
[] = {
2925 { vlc_meta_Title
, "meta-title" },
2926 { vlc_meta_Artist
, "meta-artist" },
2927 { vlc_meta_Genre
, "meta-genre" },
2928 { vlc_meta_Copyright
, "meta-copyright" },
2929 { vlc_meta_Description
, "meta-description" },
2930 { vlc_meta_Date
, "meta-date" },
2931 { vlc_meta_URL
, "meta-url" },
2935 /* Get meta information from user */
2936 for( int i
= 0; p_list
[i
].psz_name
; i
++ )
2938 char *psz_string
= var_GetNonEmptyString( p_input
, p_list
[i
].psz_name
);
2942 EnsureUTF8( psz_string
);
2943 vlc_meta_Set( p_meta
, p_list
[i
].i_meta
, psz_string
);
2948 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
2949 const demux_t
***ppp_attachment_demux
,
2950 int i_new
, input_attachment_t
**pp_new
, const demux_t
*p_demux
)
2952 int i_attachment
= *pi_attachment
;
2955 input_attachment_t
**pp_att
= realloc( *ppp_attachment
,
2956 sizeof(*pp_att
) * ( i_attachment
+ i_new
) );
2957 if( likely(pp_att
) )
2959 *ppp_attachment
= pp_att
;
2960 const demux_t
**pp_attdmx
= realloc( *ppp_attachment_demux
,
2961 sizeof(*pp_attdmx
) * ( i_attachment
+ i_new
) );
2962 if( likely(pp_attdmx
) )
2964 *ppp_attachment_demux
= pp_attdmx
;
2966 for( i
= 0; i
< i_new
; i
++ )
2968 pp_att
[i_attachment
] = pp_new
[i
];
2969 pp_attdmx
[i_attachment
++] = p_demux
;
2972 *pi_attachment
= i_attachment
;
2978 /* on alloc errors */
2979 for( i
= 0; i
< i_new
; i
++ )
2980 vlc_input_attachment_Delete( pp_new
[i
] );
2984 /*****************************************************************************
2985 * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2986 * arturl and locking issue.
2987 *****************************************************************************/
2988 static void InputUpdateMeta( input_thread_t
*p_input
, demux_t
*p_demux
)
2990 vlc_meta_t
*p_meta
= vlc_meta_New();
2991 if( unlikely(p_meta
== NULL
) )
2994 demux_Control( p_demux
, DEMUX_GET_META
, p_meta
);
2996 /* If metadata changed, then the attachments might have changed.
2997 We need to update them in case they contain album art. */
2998 input_attachment_t
**attachment
;
3001 if( !demux_Control( p_demux
, DEMUX_GET_ATTACHMENTS
,
3002 &attachment
, &i_attachment
) )
3004 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
3005 if( input_priv(p_input
)->i_attachment
> 0 )
3008 for( int i
= 0; i
< input_priv(p_input
)->i_attachment
; i
++ )
3010 if( input_priv(p_input
)->attachment_demux
[i
] == p_demux
)
3011 vlc_input_attachment_Delete( input_priv(p_input
)->attachment
[i
] );
3014 input_priv(p_input
)->attachment
[j
] = input_priv(p_input
)->attachment
[i
];
3015 input_priv(p_input
)->attachment_demux
[j
] = input_priv(p_input
)->attachment_demux
[i
];
3019 input_priv(p_input
)->i_attachment
= j
;
3021 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
3022 i_attachment
, attachment
, p_demux
);
3023 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
3026 es_out_ControlSetMeta( input_priv(p_input
)->p_es_out
, p_meta
);
3027 vlc_meta_Delete( p_meta
);
3030 /*****************************************************************************
3031 * InputGetExtraFiles
3032 * Autodetect extra input list
3033 *****************************************************************************/
3034 static void InputGetExtraFilesPattern( input_thread_t
*p_input
,
3035 int *pi_list
, char ***pppsz_list
,
3036 const char *psz_path
,
3037 const char *psz_match
,
3038 const char *psz_format
,
3039 int i_start
, int i_stop
)
3043 TAB_INIT( i_list
, ppsz_list
);
3045 char *psz_base
= strdup( psz_path
);
3049 /* Remove the extension */
3050 char *psz_end
= &psz_base
[strlen(psz_base
)-strlen(psz_match
)];
3051 assert( psz_end
>= psz_base
);
3054 /* Try to list files */
3055 for( int i
= i_start
; i
<= i_stop
; i
++ )
3058 if( asprintf( &psz_probe
, psz_format
, psz_base
, i
) < 0 )
3061 char *filepath
= get_path( psz_probe
);
3064 if( filepath
== NULL
||
3065 vlc_stat( filepath
, &st
) || !S_ISREG( st
.st_mode
) || !st
.st_size
)
3072 msg_Dbg( p_input
, "Detected extra file `%s'", filepath
);
3074 char* psz_uri
= vlc_path2uri( filepath
, NULL
);
3076 TAB_APPEND( i_list
, ppsz_list
, psz_uri
);
3084 *pppsz_list
= ppsz_list
;
3087 static void InputGetExtraFiles( input_thread_t
*p_input
,
3088 int *pi_list
, char ***pppsz_list
,
3089 const char **ppsz_access
, const char *psz_path
)
3091 static const struct pattern
3093 const char *psz_access_force
;
3094 const char *psz_match
;
3095 const char *psz_format
;
3099 /* XXX the order is important */
3100 { "concat", ".001", "%s.%.3d", 2, 999 },
3101 { NULL
, ".part1.rar","%s.part%.1d.rar", 2, 9 },
3102 { NULL
, ".part01.rar","%s.part%.2d.rar", 2, 99, },
3103 { NULL
, ".part001.rar", "%s.part%.3d.rar", 2, 999 },
3104 { NULL
, ".rar", "%s.r%.2d", 0, 99 },
3107 TAB_INIT( *pi_list
, *pppsz_list
);
3109 if( ( **ppsz_access
&& strcmp( *ppsz_access
, "file" ) ) || !psz_path
)
3112 const size_t i_path
= strlen(psz_path
);
3114 for( size_t i
= 0; i
< ARRAY_SIZE( patterns
); ++i
)
3116 const struct pattern
* pat
= &patterns
[i
];
3117 const size_t i_ext
= strlen( pat
->psz_match
);
3119 if( i_path
< i_ext
)
3122 if( !strcmp( &psz_path
[i_path
-i_ext
], pat
->psz_match
) )
3124 InputGetExtraFilesPattern( p_input
, pi_list
, pppsz_list
, psz_path
,
3125 pat
->psz_match
, pat
->psz_format
, pat
->i_start
, pat
->i_stop
);
3127 if( *pi_list
> 0 && pat
->psz_access_force
)
3128 *ppsz_access
= pat
->psz_access_force
;
3135 static void input_ChangeState( input_thread_t
*p_input
, int i_state
)
3137 if( input_priv(p_input
)->i_state
== i_state
)
3140 input_priv(p_input
)->i_state
= i_state
;
3141 if( i_state
== ERROR_S
)
3142 input_item_SetErrorWhenReading( input_priv(p_input
)->p_item
, true );
3143 input_SendEventState( p_input
, i_state
);
3147 /*****************************************************************************
3148 * MRLSplit: parse the access, demux and url part of the
3149 * Media Resource Locator.
3150 *****************************************************************************/
3151 void input_SplitMRL( const char **access
, const char **demux
,
3152 const char **path
, const char **anchor
, char *buf
)
3156 /* Separate <path> from <access>[/<demux>]:// */
3157 p
= strstr( buf
, "://" );
3161 p
+= 3; /* skips "://" */
3164 /* Remove HTML anchor if present (not supported).
3165 * The hash symbol itself should be URI-encoded. */
3166 p
= strchr( p
, '#' );
3178 fprintf( stderr
, "%s(\"%s\") probably not a valid URI!\n", __func__
,
3181 /* Note: this is a valid non const pointer to "": */
3182 *path
= buf
+ strlen( buf
);
3185 /* Separate access from demux */
3186 p
= strchr( buf
, '/' );
3197 /* We really don't want module name substitution here! */
3204 static const char *MRLSeekPoint( const char *str
, int *title
, int *chapter
)
3209 /* Look for the title */
3210 u
= strtoul( str
, &end
, 0 );
3211 *title
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3214 /* Look for the chapter */
3218 u
= strtoul( str
, &end
, 0 );
3219 *chapter
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3229 /*****************************************************************************
3230 * MRLSections: parse title and seekpoint info from the Media Resource Locator.
3233 * [url][@[title_start][:chapter_start][-[title_end][:chapter_end]]]
3234 *****************************************************************************/
3235 static void MRLSections( const char *p
,
3236 int *pi_title_start
, int *pi_title_end
,
3237 int *pi_chapter_start
, int *pi_chapter_end
)
3239 *pi_title_start
= *pi_title_end
= *pi_chapter_start
= *pi_chapter_end
= -1;
3241 int title_start
, chapter_start
, title_end
, chapter_end
;
3247 p
= MRLSeekPoint( p
, &title_start
, &chapter_start
);
3249 title_start
= chapter_start
= -1;
3252 p
= MRLSeekPoint( p
+ 1, &title_end
, &chapter_end
);
3254 title_end
= chapter_end
= -1;
3256 if( *p
) /* syntax error */
3259 *pi_title_start
= title_start
;
3260 *pi_title_end
= title_end
;
3261 *pi_chapter_start
= chapter_start
;
3262 *pi_chapter_end
= chapter_end
;
3265 static int input_SlaveSourceAdd( input_thread_t
*p_input
,
3266 enum slave_type i_type
, const char *psz_uri
,
3271 const char *psz_forced_demux
;
3272 const bool b_can_fail
= i_flags
& SLAVE_ADD_CANFAIL
;
3273 const bool b_forced
= i_flags
& SLAVE_ADD_FORCED
;
3274 const bool b_set_time
= i_flags
& SLAVE_ADD_SET_TIME
;
3278 case SLAVE_TYPE_SPU
:
3280 psz_forced_demux
= "subtitle";
3282 case SLAVE_TYPE_AUDIO
:
3283 psz_es
= "audio-es";
3284 psz_forced_demux
= NULL
;
3287 vlc_assert_unreachable();
3291 var_Change( p_input
, psz_es
, VLC_VAR_CHOICESCOUNT
, &count
, NULL
);
3293 msg_Dbg( p_input
, "loading %s slave: %s (forced: %d)", psz_es
, psz_uri
,
3296 input_source_t
*p_source
= InputSourceNew( p_input
, psz_uri
,
3297 psz_forced_demux
, b_can_fail
);
3298 if( p_source
== NULL
)
3300 msg_Warn( p_input
, "failed to add %s as slave", psz_uri
);
3301 return VLC_EGENERIC
;
3304 if( i_type
== SLAVE_TYPE_AUDIO
)
3311 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
3312 DEMUX_GET_TIME
, &i_time
) )
3314 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
3315 InputSourceDestroy( p_source
);
3316 return VLC_EGENERIC
;
3319 if( demux_Control( p_source
->p_demux
,
3320 DEMUX_SET_TIME
, i_time
, true ) )
3322 msg_Err( p_input
, "seek failed for new slave" );
3323 InputSourceDestroy( p_source
);
3324 return VLC_EGENERIC
;
3328 /* Get meta (access and demux) */
3329 InputUpdateMeta( p_input
, p_source
->p_demux
);
3332 TAB_APPEND( input_priv(p_input
)->i_slave
, input_priv(p_input
)->slave
, p_source
);
3340 if( var_Change( p_input
, psz_es
, VLC_VAR_GETCHOICES
, &list
, NULL
) )
3343 if( count
.i_int
== 0 )
3345 /* if it was first one, there is disable too */
3347 if( count
.i_int
< list
.p_list
->i_count
)
3349 const int i_id
= list
.p_list
->p_values
[count
.i_int
].i_int
;
3351 es_out_Control( input_priv(p_input
)->p_es_out_display
, ES_OUT_SET_ES_DEFAULT_BY_ID
, i_id
);
3352 es_out_Control( input_priv(p_input
)->p_es_out_display
, ES_OUT_SET_ES_BY_ID
, i_id
);
3354 var_FreeList( &list
, NULL
);
3359 static char *input_SubtitleFile2Uri( input_thread_t
*p_input
,
3360 const char *psz_subtitle
)
3362 /* if we are provided a subtitle.sub file,
3363 * see if we don't have a subtitle.idx and use it instead */
3364 char *psz_idxpath
= NULL
;
3365 char *psz_extension
= strrchr( psz_subtitle
, '.');
3366 if( psz_extension
&& strcmp( psz_extension
, ".sub" ) == 0 )
3368 psz_idxpath
= strdup( psz_subtitle
);
3373 psz_extension
= psz_extension
- psz_subtitle
+ psz_idxpath
;
3374 strcpy( psz_extension
, ".idx" );
3376 if( !vlc_stat( psz_idxpath
, &st
) && S_ISREG( st
.st_mode
) )
3378 msg_Dbg( p_input
, "using %s as subtitle file instead of %s",
3379 psz_idxpath
, psz_subtitle
);
3380 psz_subtitle
= psz_idxpath
;
3385 char *psz_uri
= vlc_path2uri( psz_subtitle
, NULL
);
3386 free( psz_idxpath
);
3390 /*****************************************************************************
3392 *****************************************************************************/
3393 void input_UpdateStatistic( input_thread_t
*p_input
,
3394 input_statistic_t i_type
, int i_delta
)
3396 assert( input_priv(p_input
)->i_state
!= INIT_S
);
3398 vlc_mutex_lock( &input_priv(p_input
)->counters
.counters_lock
);
3401 #define I(c) stats_Update( input_priv(p_input)->counters.c, i_delta, NULL )
3402 case INPUT_STATISTIC_DECODED_VIDEO
:
3405 case INPUT_STATISTIC_DECODED_AUDIO
:
3408 case INPUT_STATISTIC_DECODED_SUBTITLE
:
3411 case INPUT_STATISTIC_SENT_PACKET
:
3412 I(p_sout_sent_packets
);
3415 case INPUT_STATISTIC_SENT_BYTE
:
3419 stats_Update( input_priv(p_input
)->counters
.p_sout_sent_bytes
, i_delta
, &bytes
);
3420 stats_Update( input_priv(p_input
)->counters
.p_sout_send_bitrate
, bytes
, NULL
);
3424 msg_Err( p_input
, "Invalid statistic type %d (internal error)", i_type
);
3427 vlc_mutex_unlock( &input_priv(p_input
)->counters
.counters_lock
);
3431 /* TODO FIXME nearly the same logic that snapshot code */
3432 char *input_CreateFilename(input_thread_t
*input
, const char *dir
,
3433 const char *filenamefmt
, const char *ext
)
3436 char *filename
= str_format(input
, filenamefmt
);
3437 if (unlikely(filename
== NULL
))
3440 filename_sanitize(filename
);
3443 ? asprintf(&path
, "%s"DIR_SEP
"%s.%s", dir
, filename
, ext
)
3444 : asprintf(&path
, "%s"DIR_SEP
"%s", dir
, filename
)) < 0)