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>
39 #include "input_internal.h"
42 #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>
58 /*****************************************************************************
60 *****************************************************************************/
61 static void *Run( void * );
62 static void *Preparse( void * );
64 static input_thread_t
* Create ( vlc_object_t
*, input_item_t
*,
65 const char *, bool, input_resource_t
* );
66 static int Init ( input_thread_t
*p_input
);
67 static void End ( input_thread_t
*p_input
);
68 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
);
70 static inline int ControlPop( input_thread_t
*, int *, vlc_value_t
*, mtime_t i_deadline
, bool b_postpone_seek
);
71 static void ControlRelease( int i_type
, vlc_value_t val
);
72 static bool ControlIsSeekRequest( int i_type
);
73 static bool Control( input_thread_t
*, int, vlc_value_t
);
74 static void ControlPause( input_thread_t
*, mtime_t
);
76 static int UpdateTitleSeekpointFromDemux( input_thread_t
* );
77 static void UpdateGenericFromDemux( input_thread_t
* );
78 static void UpdateTitleListfromDemux( input_thread_t
* );
80 static void MRLSections( const char *, int *, int *, int *, int *);
82 static input_source_t
*InputSourceNew( input_thread_t
*, const char *,
83 const char *psz_forced_demux
,
85 static void InputSourceDestroy( input_source_t
* );
86 static void InputSourceMeta( input_thread_t
*, input_source_t
*, vlc_meta_t
* );
89 //static void InputGetAttachments( input_thread_t *, input_source_t * );
90 static void SlaveDemux( input_thread_t
*p_input
);
91 static void SlaveSeek( input_thread_t
*p_input
);
93 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
94 static void InputUpdateMeta( input_thread_t
*p_input
, demux_t
*p_demux
);
95 static void InputGetExtraFiles( input_thread_t
*p_input
,
96 int *pi_list
, char ***pppsz_list
,
97 const char *psz_access
, const char *psz_path
);
99 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
100 const demux_t
***ppp_attachment_demux
,
101 int i_new
, input_attachment_t
**pp_new
, const demux_t
*p_demux
);
103 #define SLAVE_ADD_NOFLAG 0
104 #define SLAVE_ADD_FORCED (1<<0)
105 #define SLAVE_ADD_CANFAIL (1<<1)
106 #define SLAVE_ADD_SET_TIME (1<<2)
108 static int input_SlaveSourceAdd( input_thread_t
*, enum slave_type
,
109 const char *, unsigned );
110 static char *input_SubtitleFile2Uri( input_thread_t
*, const char * );
111 static void input_ChangeState( input_thread_t
*p_input
, int i_state
); /* TODO fix name */
115 * Create a new input_thread_t.
117 * You need to call input_Start on it when you are done
118 * adding callback on the variables/events you want to monitor.
120 * \param p_parent a vlc_object
121 * \param p_item an input item
122 * \param psz_log an optional prefix for this input logs
123 * \param p_resource an optional input ressource
124 * \return a pointer to the spawned input thread
126 input_thread_t
*input_Create( vlc_object_t
*p_parent
,
127 input_item_t
*p_item
,
128 const char *psz_log
, input_resource_t
*p_resource
)
130 return Create( p_parent
, p_item
, psz_log
, false, p_resource
);
135 * Initialize an input thread and run it until it stops by itself.
137 * \param p_parent a vlc_object
138 * \param p_item an input item
139 * \return an error code, VLC_SUCCESS on success
141 int input_Read( vlc_object_t
*p_parent
, input_item_t
*p_item
)
143 input_thread_t
*p_input
= Create( p_parent
, p_item
, NULL
, false, NULL
);
147 if( !Init( p_input
) )
149 MainLoop( p_input
, false );
153 vlc_object_release( p_input
);
157 input_thread_t
*input_CreatePreparser( vlc_object_t
*parent
,
160 return Create( parent
, item
, NULL
, true, NULL
);
164 * Start a input_thread_t created by input_Create.
166 * You must not start an already running input_thread_t.
168 * \param the input thread to start
170 int input_Start( input_thread_t
*p_input
)
172 input_thread_private_t
*priv
= input_priv(p_input
);
173 void *(*func
)(void *) = Run
;
175 if( priv
->b_preparsing
)
178 assert( !priv
->is_running
);
179 /* Create thread and wait for its readiness. */
180 priv
->is_running
= !vlc_clone( &priv
->thread
, func
, priv
,
181 VLC_THREAD_PRIORITY_INPUT
);
182 if( !priv
->is_running
)
184 input_ChangeState( p_input
, ERROR_S
);
185 msg_Err( p_input
, "cannot create input thread" );
192 * Request a running input thread to stop and die
194 * \param p_input the input thread to stop
196 void input_Stop( input_thread_t
*p_input
)
198 input_thread_private_t
*sys
= input_priv(p_input
);
200 vlc_mutex_lock( &sys
->lock_control
);
201 /* Discard all pending controls */
202 for( int i
= 0; i
< sys
->i_control
; i
++ )
204 input_control_t
*ctrl
= &sys
->control
[i
];
205 ControlRelease( ctrl
->i_type
, ctrl
->val
);
208 sys
->is_stopped
= true;
209 vlc_cond_signal( &sys
->wait_control
);
210 vlc_mutex_unlock( &sys
->lock_control
);
211 vlc_interrupt_kill( &sys
->interrupt
);
217 * It does not call input_Stop itself.
219 void input_Close( input_thread_t
*p_input
)
221 if( input_priv(p_input
)->is_running
)
222 vlc_join( input_priv(p_input
)->thread
, NULL
);
223 vlc_interrupt_deinit( &input_priv(p_input
)->interrupt
);
224 vlc_object_release( p_input
);
228 * Input destructor (called when the object's refcount reaches 0).
230 static void input_Destructor( vlc_object_t
*obj
)
232 input_thread_t
*p_input
= (input_thread_t
*)obj
;
233 input_thread_private_t
*priv
= input_priv(p_input
);
235 char * psz_name
= input_item_GetName( priv
->p_item
);
236 msg_Dbg( p_input
, "Destroying the input for '%s'", psz_name
);
240 if( priv
->p_es_out_display
)
241 es_out_Delete( priv
->p_es_out_display
);
243 if( priv
->p_resource
)
244 input_resource_Release( priv
->p_resource
);
245 if( priv
->p_resource_private
)
246 input_resource_Release( priv
->p_resource_private
);
248 input_item_Release( priv
->p_item
);
250 vlc_mutex_destroy( &priv
->counters
.counters_lock
);
252 for( int i
= 0; i
< priv
->i_control
; i
++ )
254 input_control_t
*p_ctrl
= &priv
->control
[i
];
255 ControlRelease( p_ctrl
->i_type
, p_ctrl
->val
);
258 vlc_cond_destroy( &priv
->wait_control
);
259 vlc_mutex_destroy( &priv
->lock_control
);
263 * Get the item from an input thread
264 * FIXME it does not increase ref count of the item.
265 * if it is used after p_input is destroyed nothing prevent it from
268 input_item_t
*input_GetItem( input_thread_t
*p_input
)
270 assert( p_input
!= NULL
);
271 return input_priv(p_input
)->p_item
;
274 /*****************************************************************************
275 * This function creates a new input, and returns a pointer
276 * to its description. On error, it returns NULL.
278 * XXX Do not forget to update vlc_input.h if you add new variables.
279 *****************************************************************************/
280 static input_thread_t
*Create( vlc_object_t
*p_parent
, input_item_t
*p_item
,
281 const char *psz_header
, bool b_preparsing
,
282 input_resource_t
*p_resource
)
284 /* Allocate descriptor */
285 input_thread_private_t
*priv
;
287 priv
= vlc_custom_create( p_parent
, sizeof( *priv
), "input" );
288 if( unlikely(priv
== NULL
) )
291 input_thread_t
*p_input
= &priv
->input
;
293 char * psz_name
= input_item_GetName( p_item
);
294 msg_Dbg( p_input
, "Creating an input for %s'%s'",
295 b_preparsing
? "preparsing " : "", psz_name
);
298 /* Parse input options */
299 input_item_ApplyOptions( VLC_OBJECT(p_input
), p_item
);
301 p_input
->obj
.header
= psz_header
? strdup( psz_header
) : NULL
;
303 /* Init Common fields */
304 priv
->b_preparsing
= b_preparsing
;
305 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;
316 priv
->i_rate
= INPUT_RATE_DEFAULT
;
317 memset( &priv
->bookmark
, 0, sizeof(priv
->bookmark
) );
318 TAB_INIT( priv
->i_bookmark
, priv
->pp_bookmark
);
319 TAB_INIT( priv
->i_attachment
, priv
->attachment
);
320 priv
->attachment_demux
= NULL
;
322 priv
->b_out_pace_control
= false;
324 vlc_viewpoint_t
*p_viewpoint
= var_InheritAddress( p_input
, "viewpoint" );
325 if (likely(p_viewpoint
!= NULL
))
326 priv
->viewpoint
= *p_viewpoint
;
328 vlc_viewpoint_init( &priv
->viewpoint
);
330 input_item_Hold( p_item
); /* Released in Destructor() */
331 priv
->p_item
= p_item
;
333 /* Init Input fields */
335 vlc_mutex_lock( &p_item
->lock
);
337 if( !p_item
->p_stats
)
338 p_item
->p_stats
= stats_NewInputStats( p_input
);
340 /* setup the preparse depth of the item
341 * if we are preparsing, use the i_preparse_depth of the parent item */
342 if( !priv
->b_preparsing
)
344 char *psz_rec
= var_InheritString( p_parent
, "recursive" );
346 if( psz_rec
!= NULL
)
348 if ( !strcasecmp( psz_rec
, "none" ) )
349 p_item
->i_preparse_depth
= 0;
350 else if ( !strcasecmp( psz_rec
, "collapse" ) )
351 p_item
->i_preparse_depth
= 1;
353 p_item
->i_preparse_depth
= -1; /* default is expand */
356 p_item
->i_preparse_depth
= -1;
359 p_input
->obj
.flags
|= OBJECT_FLAGS_QUIET
| OBJECT_FLAGS_NOINTERACT
;
361 /* Make sure the interaction option is honored */
362 if( !var_InheritBool( p_input
, "interact" ) )
363 p_input
->obj
.flags
|= OBJECT_FLAGS_NOINTERACT
;
364 else if( p_item
->b_preparse_interact
)
366 /* If true, this item was asked explicitly to interact with the user
367 * (via libvlc_MetadataRequest). Sub items created from this input won't
368 * have this flag and won't interact with the user */
369 p_input
->obj
.flags
&= ~OBJECT_FLAGS_NOINTERACT
;
372 vlc_mutex_unlock( &p_item
->lock
);
381 priv
->p_resource_private
= NULL
;
382 priv
->p_resource
= input_resource_Hold( p_resource
);
386 priv
->p_resource_private
= input_resource_New( VLC_OBJECT( p_input
) );
387 priv
->p_resource
= input_resource_Hold( priv
->p_resource_private
);
389 input_resource_SetInput( priv
->p_resource
, p_input
);
391 /* Init control buffer */
392 vlc_mutex_init( &priv
->lock_control
);
393 vlc_cond_init( &priv
->wait_control
);
395 vlc_interrupt_init(&priv
->interrupt
);
397 /* Create Object Variables for private use only */
398 input_ConfigVarInit( p_input
);
400 /* Create Objects variables for public Get and Set */
401 input_ControlVarInit( p_input
);
404 if( !priv
->b_preparsing
)
406 char *psz_bookmarks
= var_GetNonEmptyString( p_input
, "bookmarks" );
409 /* FIXME: have a common cfg parsing routine used by sout and others */
410 char *psz_parser
, *psz_start
, *psz_end
;
411 psz_parser
= psz_bookmarks
;
412 while( (psz_start
= strchr( psz_parser
, '{' ) ) )
414 seekpoint_t
*p_seekpoint
;
417 psz_end
= strchr( psz_start
, '}' );
418 if( !psz_end
) break;
419 psz_parser
= psz_end
+ 1;
420 backup
= *psz_parser
;
424 p_seekpoint
= vlc_seekpoint_New();
426 if( unlikely( p_seekpoint
== NULL
) )
429 while( (psz_end
= strchr( psz_start
, ',' ) ) )
432 if( !strncmp( psz_start
, "name=", 5 ) )
434 free( p_seekpoint
->psz_name
);
436 p_seekpoint
->psz_name
= strdup(psz_start
+ 5);
438 else if( !strncmp( psz_start
, "time=", 5 ) )
440 p_seekpoint
->i_time_offset
= atoll(psz_start
+ 5) *
443 psz_start
= psz_end
+ 1;
445 msg_Dbg( p_input
, "adding bookmark: %s, time=%"PRId64
,
446 p_seekpoint
->psz_name
,
447 p_seekpoint
->i_time_offset
);
448 input_Control( p_input
, INPUT_ADD_BOOKMARK
, p_seekpoint
);
449 vlc_seekpoint_Delete( p_seekpoint
);
450 *psz_parser
= backup
;
452 free( psz_bookmarks
);
456 /* Remove 'Now playing' info as it is probably outdated */
457 input_item_SetNowPlaying( p_item
, NULL
);
458 input_item_SetESNowPlaying( p_item
, NULL
);
459 input_SendEventMeta( p_input
);
462 memset( &priv
->counters
, 0, sizeof( priv
->counters
) );
463 vlc_mutex_init( &priv
->counters
.counters_lock
);
465 priv
->p_es_out_display
= input_EsOutNew( p_input
, priv
->i_rate
);
466 priv
->p_es_out
= NULL
;
468 /* Set the destructor when we are sure we are initialized */
469 vlc_object_set_destructor( p_input
, input_Destructor
);
474 /*****************************************************************************
475 * Run: main thread loop
476 * This is the "normal" thread that spawns the input processing chain,
477 * reads the stream, cleans up and waits
478 *****************************************************************************/
479 static void *Run( void *data
)
481 input_thread_private_t
*priv
= data
;
482 input_thread_t
*p_input
= &priv
->input
;
484 vlc_interrupt_set(&priv
->interrupt
);
486 if( !Init( p_input
) )
488 if( priv
->b_can_pace_control
&& priv
->b_out_pace_control
)
490 /* We don't want a high input priority here or we'll
491 * end-up sucking up all the CPU time */
492 vlc_set_priority( priv
->thread
, VLC_THREAD_PRIORITY_LOW
);
495 MainLoop( p_input
, true ); /* FIXME it can be wrong (like with VLM) */
501 input_SendEventDead( p_input
);
505 static void *Preparse( void *data
)
507 input_thread_private_t
*priv
= data
;
508 input_thread_t
*p_input
= &priv
->input
;
510 vlc_interrupt_set(&priv
->interrupt
);
512 if( !Init( p_input
) )
513 { /* if the demux is a playlist, call Mainloop that will call
514 * demux_Demux in order to fetch sub items */
515 bool b_is_playlist
= false;
517 if ( input_item_ShouldPreparseSubItems( priv
->p_item
)
518 && demux_Control( priv
->master
->p_demux
, DEMUX_IS_PLAYLIST
,
520 b_is_playlist
= false;
522 MainLoop( p_input
, false );
526 input_SendEventDead( p_input
);
530 bool input_Stopped( input_thread_t
*input
)
532 input_thread_private_t
*sys
= input_priv(input
);
535 vlc_mutex_lock( &sys
->lock_control
);
536 ret
= sys
->is_stopped
;
537 vlc_mutex_unlock( &sys
->lock_control
);
541 /*****************************************************************************
542 * Main loop: Fill buffers from access, and demux
543 *****************************************************************************/
547 * It asks the demuxer to demux some data
549 static void MainLoopDemux( input_thread_t
*p_input
, bool *pb_changed
)
552 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
556 if( input_priv(p_input
)->i_stop
> 0 && input_priv(p_input
)->i_time
>= input_priv(p_input
)->i_stop
)
557 i_ret
= VLC_DEMUXER_EOF
;
559 i_ret
= demux_Demux( p_demux
);
561 i_ret
= i_ret
> 0 ? VLC_DEMUXER_SUCCESS
: ( i_ret
< 0 ? VLC_DEMUXER_EGENERIC
: VLC_DEMUXER_EOF
);
563 if( i_ret
== VLC_DEMUXER_SUCCESS
)
565 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_TITLE_LIST
) )
566 UpdateTitleListfromDemux( p_input
);
568 if( input_priv(p_input
)->master
->b_title_demux
)
570 i_ret
= UpdateTitleSeekpointFromDemux( p_input
);
574 UpdateGenericFromDemux( p_input
);
577 if( i_ret
== VLC_DEMUXER_EOF
)
579 msg_Dbg( p_input
, "EOF reached" );
580 input_priv(p_input
)->master
->b_eof
= true;
581 es_out_Eos(input_priv(p_input
)->p_es_out
);
583 else if( i_ret
== VLC_DEMUXER_EGENERIC
)
585 input_ChangeState( p_input
, ERROR_S
);
587 else if( input_priv(p_input
)->i_slave
> 0 )
588 SlaveDemux( p_input
);
591 static int MainLoopTryRepeat( input_thread_t
*p_input
)
593 int i_repeat
= var_GetInteger( p_input
, "input-repeat" );
599 msg_Dbg( p_input
, "repeating the same input (%d)", i_repeat
);
603 var_SetInteger( p_input
, "input-repeat", i_repeat
);
606 /* Seek to start title/seekpoint */
607 val
.i_int
= input_priv(p_input
)->master
->i_title_start
-
608 input_priv(p_input
)->master
->i_title_offset
;
609 if( val
.i_int
< 0 || val
.i_int
>= input_priv(p_input
)->master
->i_title
)
611 input_ControlPush( p_input
,
612 INPUT_CONTROL_SET_TITLE
, &val
);
614 val
.i_int
= input_priv(p_input
)->master
->i_seekpoint_start
-
615 input_priv(p_input
)->master
->i_seekpoint_offset
;
616 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
617 input_ControlPush( p_input
,
618 INPUT_CONTROL_SET_SEEKPOINT
, &val
);
620 /* Seek to start position */
621 if( input_priv(p_input
)->i_start
> 0 )
623 val
.i_int
= input_priv(p_input
)->i_start
;
624 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &val
);
629 input_ControlPush( p_input
, INPUT_CONTROL_SET_POSITION
, &val
);
636 * Update timing infos and statistics.
638 static void MainLoopStatistics( input_thread_t
*p_input
)
640 double f_position
= 0.0;
642 mtime_t i_length
= 0;
644 /* update input status variables */
645 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
646 DEMUX_GET_POSITION
, &f_position
) )
649 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
650 DEMUX_GET_TIME
, &i_time
) )
652 input_priv(p_input
)->i_time
= i_time
;
654 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
655 DEMUX_GET_LENGTH
, &i_length
) )
658 es_out_SetTimes( input_priv(p_input
)->p_es_out
, f_position
, i_time
, i_length
);
660 /* update current bookmark */
661 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
662 input_priv(p_input
)->bookmark
.i_time_offset
= i_time
;
663 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
665 stats_ComputeInputStats( p_input
, input_priv(p_input
)->p_item
->p_stats
);
666 input_SendEventStatistics( p_input
);
671 * The main input loop.
673 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
)
675 mtime_t i_intf_update
= 0;
676 mtime_t i_last_seek_mdate
= 0;
678 if( b_interactive
&& var_InheritBool( p_input
, "start-paused" ) )
679 ControlPause( p_input
, mdate() );
681 bool b_pause_after_eof
= b_interactive
&&
682 var_InheritBool( p_input
, "play-and-pause" );
683 bool b_paused_at_eof
= false;
685 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
686 const bool b_can_demux
= p_demux
->pf_demux
!= NULL
;
688 while( !input_Stopped( p_input
) && input_priv(p_input
)->i_state
!= ERROR_S
)
690 mtime_t i_wakeup
= -1;
691 bool b_paused
= input_priv(p_input
)->i_state
== PAUSE_S
;
692 /* FIXME if input_priv(p_input)->i_state == PAUSE_S the access/access_demux
693 * is paused -> this may cause problem with some of them
694 * The same problem can be seen when seeking while paused */
696 b_paused
= !es_out_GetBuffering( input_priv(p_input
)->p_es_out
)
697 || input_priv(p_input
)->master
->b_eof
;
701 if( !input_priv(p_input
)->master
->b_eof
)
703 bool b_force_update
= false;
705 MainLoopDemux( p_input
, &b_force_update
);
708 i_wakeup
= es_out_GetWakeup( input_priv(p_input
)->p_es_out
);
712 b_paused_at_eof
= false;
714 else if( !es_out_GetEmpty( input_priv(p_input
)->p_es_out
) )
716 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
717 i_wakeup
= mdate() + INPUT_IDLE_SLEEP
;
719 /* Pause after eof only if the input is pausable.
720 * This way we won't trigger timeshifting for nothing */
721 else if( b_pause_after_eof
&& input_priv(p_input
)->b_can_pause
)
723 if( b_paused_at_eof
)
726 vlc_value_t val
= { .i_int
= PAUSE_S
};
728 msg_Dbg( p_input
, "pausing at EOF (pause after each)");
729 Control( p_input
, INPUT_CONTROL_SET_STATE
, val
);
732 b_paused_at_eof
= true;
736 if( MainLoopTryRepeat( p_input
) )
740 /* Update interface and statistics */
741 mtime_t now
= mdate();
742 if( now
>= i_intf_update
)
744 MainLoopStatistics( p_input
);
745 i_intf_update
= now
+ INT64_C(250000);
752 mtime_t i_deadline
= i_wakeup
;
754 /* Postpone seeking until ES buffering is complete or at most
756 bool b_postpone
= es_out_GetBuffering( input_priv(p_input
)->p_es_out
)
757 && !input_priv(p_input
)->master
->b_eof
;
760 mtime_t now
= mdate();
762 /* Recheck ES buffer level every 20 ms when seeking */
763 if( now
< i_last_seek_mdate
+ INT64_C(125000)
764 && (i_deadline
< 0 || i_deadline
> now
+ INT64_C(20000)) )
765 i_deadline
= now
+ INT64_C(20000);
773 if( ControlPop( p_input
, &i_type
, &val
, i_deadline
, b_postpone
) )
777 break; /* Wake-up time reached */
781 msg_Dbg( p_input
, "control type=%d", i_type
);
783 if( Control( p_input
, i_type
, val
) )
785 if( ControlIsSeekRequest( i_type
) )
786 i_last_seek_mdate
= mdate();
790 /* Update the wakeup time */
792 i_wakeup
= es_out_GetWakeup( input_priv(p_input
)->p_es_out
);
797 static void InitStatistics( input_thread_t
*p_input
)
799 input_thread_private_t
*priv
= input_priv(p_input
);
801 if( priv
->b_preparsing
) return;
803 /* Prepare statistics */
804 #define INIT_COUNTER( c, compute ) priv->counters.p_##c = \
805 stats_CounterCreate( STATS_##compute);
806 if( libvlc_stats( p_input
) )
808 INIT_COUNTER( read_bytes
, COUNTER
);
809 INIT_COUNTER( read_packets
, COUNTER
);
810 INIT_COUNTER( demux_read
, COUNTER
);
811 INIT_COUNTER( input_bitrate
, DERIVATIVE
);
812 INIT_COUNTER( demux_bitrate
, DERIVATIVE
);
813 INIT_COUNTER( demux_corrupted
, COUNTER
);
814 INIT_COUNTER( demux_discontinuity
, COUNTER
);
815 INIT_COUNTER( played_abuffers
, COUNTER
);
816 INIT_COUNTER( lost_abuffers
, COUNTER
);
817 INIT_COUNTER( displayed_pictures
, COUNTER
);
818 INIT_COUNTER( lost_pictures
, COUNTER
);
819 INIT_COUNTER( decoded_audio
, COUNTER
);
820 INIT_COUNTER( decoded_video
, COUNTER
);
821 INIT_COUNTER( decoded_sub
, COUNTER
);
822 priv
->counters
.p_sout_send_bitrate
= NULL
;
823 priv
->counters
.p_sout_sent_packets
= NULL
;
824 priv
->counters
.p_sout_sent_bytes
= NULL
;
829 static int InitSout( input_thread_t
* p_input
)
831 input_thread_private_t
*priv
= input_priv(p_input
);
833 if( priv
->b_preparsing
)
836 /* Find a usable sout and attach it to p_input */
837 char *psz
= var_GetNonEmptyString( p_input
, "sout" );
838 if( psz
&& strncasecmp( priv
->p_item
->psz_uri
, "vlc:", 4 ) )
840 priv
->p_sout
= input_resource_RequestSout( priv
->p_resource
, NULL
, psz
);
841 if( priv
->p_sout
== NULL
)
843 input_ChangeState( p_input
, ERROR_S
);
844 msg_Err( p_input
, "cannot start stream output instance, " \
849 if( libvlc_stats( p_input
) )
851 INIT_COUNTER( sout_sent_packets
, COUNTER
);
852 INIT_COUNTER( sout_sent_bytes
, COUNTER
);
853 INIT_COUNTER( sout_send_bitrate
, DERIVATIVE
);
858 input_resource_RequestSout( priv
->p_resource
, NULL
, NULL
);
866 static void InitTitle( input_thread_t
* p_input
)
868 input_thread_private_t
*priv
= input_priv(p_input
);
869 input_source_t
*p_master
= priv
->master
;
871 if( priv
->b_preparsing
)
874 vlc_mutex_lock( &priv
->p_item
->lock
);
875 /* Create global title (from master) */
876 priv
->i_title
= p_master
->i_title
;
877 priv
->title
= p_master
->title
;
878 priv
->i_title_offset
= p_master
->i_title_offset
;
879 priv
->i_seekpoint_offset
= p_master
->i_seekpoint_offset
;
880 if( priv
->i_title
> 0 )
882 /* Setup variables */
883 input_ControlVarNavigation( p_input
);
884 input_SendEventTitle( p_input
, 0 );
888 priv
->b_can_pace_control
= p_master
->b_can_pace_control
;
889 priv
->b_can_pause
= p_master
->b_can_pause
;
890 priv
->b_can_rate_control
= p_master
->b_can_rate_control
;
891 vlc_mutex_unlock( &priv
->p_item
->lock
);
894 static void StartTitle( input_thread_t
* p_input
)
896 input_thread_private_t
*priv
= input_priv(p_input
);
899 /* Start title/chapter */
900 val
.i_int
= priv
->master
->i_title_start
- priv
->master
->i_title_offset
;
901 if( val
.i_int
> 0 && val
.i_int
< priv
->master
->i_title
)
902 input_ControlPush( p_input
, INPUT_CONTROL_SET_TITLE
, &val
);
904 val
.i_int
= priv
->master
->i_seekpoint_start
-
905 priv
->master
->i_seekpoint_offset
;
906 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
907 input_ControlPush( p_input
, INPUT_CONTROL_SET_SEEKPOINT
, &val
);
909 /* Start/stop/run time */
910 priv
->i_start
= llroundf(1000000.f
911 * var_GetFloat( p_input
, "start-time" ));
912 priv
->i_stop
= llroundf(1000000.f
913 * var_GetFloat( p_input
, "stop-time" ));
914 if( priv
->i_stop
<= 0 )
916 priv
->i_stop
= llroundf(1000000.f
917 * var_GetFloat( p_input
, "run-time" ));
918 if( priv
->i_stop
< 0 )
920 msg_Warn( p_input
, "invalid run-time ignored" );
924 priv
->i_stop
+= priv
->i_start
;
927 if( priv
->i_start
> 0 )
931 msg_Dbg( p_input
, "starting at time: %"PRId64
"s",
932 priv
->i_start
/ CLOCK_FREQ
);
934 s
.i_int
= priv
->i_start
;
935 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &s
);
937 if( priv
->i_stop
> 0 && priv
->i_stop
<= priv
->i_start
)
939 msg_Warn( p_input
, "invalid stop-time ignored" );
942 priv
->b_fast_seek
= var_GetBool( p_input
, "input-fast-seek" );
945 static int SlaveCompare(const void *a
, const void *b
)
947 const input_item_slave_t
*p_slave0
= *((const input_item_slave_t
**) a
);
948 const input_item_slave_t
*p_slave1
= *((const input_item_slave_t
**) b
);
950 if( p_slave0
== NULL
|| p_slave1
== NULL
)
952 /* Put NULL (or rejected) subs at the end */
953 return p_slave0
== NULL
? 1 : p_slave1
== NULL
? -1 : 0;
956 if( p_slave0
->i_priority
> p_slave1
->i_priority
)
959 if( p_slave0
->i_priority
< p_slave1
->i_priority
)
965 static bool SlaveExists( input_item_slave_t
**pp_slaves
, int i_slaves
,
968 for( int i
= 0; i
< i_slaves
; i
++ )
970 if( pp_slaves
[i
] != NULL
971 && !strcmp( pp_slaves
[i
]->psz_uri
, psz_uri
) )
977 static void SetSubtitlesOptions( input_thread_t
*p_input
)
979 /* Get fps and set it if not already set */
980 const float f_fps
= input_priv(p_input
)->master
->f_fps
;
983 var_Create( p_input
, "sub-original-fps", VLC_VAR_FLOAT
);
984 var_SetFloat( p_input
, "sub-original-fps", f_fps
);
986 float f_requested_fps
= var_CreateGetFloat( p_input
, "sub-fps" );
987 if( f_requested_fps
!= f_fps
)
989 var_Create( p_input
, "sub-fps", VLC_VAR_FLOAT
|
991 var_SetFloat( p_input
, "sub-fps", f_requested_fps
);
995 const int i_delay
= var_CreateGetInteger( p_input
, "sub-delay" );
997 var_SetInteger( p_input
, "spu-delay", (mtime_t
)i_delay
* 100000 );
1000 static void GetVarSlaves( input_thread_t
*p_input
,
1001 input_item_slave_t
***ppp_slaves
, int *p_slaves
)
1003 char *psz
= var_GetNonEmptyString( p_input
, "input-slave" );
1007 input_item_slave_t
**pp_slaves
= *ppp_slaves
;
1008 int i_slaves
= *p_slaves
;
1010 char *psz_org
= psz
;
1011 while( psz
&& *psz
)
1013 while( *psz
== ' ' || *psz
== '#' )
1016 char *psz_delim
= strchr( psz
, '#' );
1018 *psz_delim
++ = '\0';
1023 char *uri
= strstr(psz
, "://")
1024 ? strdup( psz
) : vlc_path2uri( psz
, NULL
);
1029 input_item_slave_t
*p_slave
=
1030 input_item_slave_New( uri
, SLAVE_TYPE_AUDIO
, SLAVE_PRIORITY_USER
);
1033 if( unlikely( p_slave
== NULL
) )
1035 INSERT_ELEM( pp_slaves
, i_slaves
, i_slaves
, p_slave
);
1039 *ppp_slaves
= pp_slaves
; /* in case of realloc */
1040 *p_slaves
= i_slaves
;
1043 static void LoadSlaves( input_thread_t
*p_input
)
1045 input_item_slave_t
**pp_slaves
;
1047 TAB_INIT( i_slaves
, pp_slaves
);
1049 /* Look for and add slaves */
1051 char *psz_subtitle
= var_GetNonEmptyString( p_input
, "sub-file" );
1052 if( psz_subtitle
!= NULL
)
1054 msg_Dbg( p_input
, "forced subtitle: %s", psz_subtitle
);
1055 char *psz_uri
= input_SubtitleFile2Uri( p_input
, psz_subtitle
);
1056 free( psz_subtitle
);
1057 psz_subtitle
= NULL
;
1058 if( psz_uri
!= NULL
)
1060 input_item_slave_t
*p_slave
=
1061 input_item_slave_New( psz_uri
, SLAVE_TYPE_SPU
,
1062 SLAVE_PRIORITY_USER
);
1066 INSERT_ELEM( pp_slaves
, i_slaves
, i_slaves
, p_slave
);
1067 psz_subtitle
= p_slave
->psz_uri
;
1072 if( var_GetBool( p_input
, "sub-autodetect-file" ) )
1074 /* Add local subtitles */
1075 char *psz_autopath
= var_GetNonEmptyString( p_input
, "sub-autodetect-path" );
1077 if( subtitles_Detect( p_input
, psz_autopath
, input_priv(p_input
)->p_item
->psz_uri
,
1078 &pp_slaves
, &i_slaves
) == VLC_SUCCESS
)
1080 /* check that we did not add the subtitle through sub-file */
1081 if( psz_subtitle
!= NULL
)
1083 for( int i
= 1; i
< i_slaves
; i
++ )
1085 input_item_slave_t
*p_curr
= pp_slaves
[i
];
1087 && !strcmp( psz_subtitle
, p_curr
->psz_uri
) )
1089 /* reject current sub */
1090 input_item_slave_Delete( p_curr
);
1091 pp_slaves
[i
] = NULL
;
1096 free( psz_autopath
);
1099 /* Add slaves found by the directory demuxer or via libvlc */
1100 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1101 vlc_mutex_lock( &p_item
->lock
);
1103 /* Move item slaves to local pp_slaves */
1104 for( int i
= 0; i
< p_item
->i_slaves
; i
++ )
1106 input_item_slave_t
*p_slave
= p_item
->pp_slaves
[i
];
1107 if( !SlaveExists( pp_slaves
, i_slaves
, p_slave
->psz_uri
) )
1108 INSERT_ELEM( pp_slaves
, i_slaves
, i_slaves
, p_slave
);
1110 input_item_slave_Delete( p_slave
);
1112 /* Slaves that are successfully loaded will be added back to the item */
1113 TAB_CLEAN( p_item
->i_slaves
, p_item
->pp_slaves
);
1114 vlc_mutex_unlock( &p_item
->lock
);
1116 /* Add slaves from the "input-slave" option */
1117 GetVarSlaves( p_input
, &pp_slaves
, &i_slaves
);
1120 qsort( pp_slaves
, i_slaves
, sizeof (input_item_slave_t
*),
1123 /* add all detected slaves */
1124 bool p_forced
[2] = {};
1125 static_assert( SLAVE_TYPE_AUDIO
<= 1 && SLAVE_TYPE_SPU
<= 1,
1126 "slave type size mismatch");
1127 for( int i
= 0; i
< i_slaves
&& pp_slaves
[i
] != NULL
; i
++ )
1129 input_item_slave_t
*p_slave
= pp_slaves
[i
];
1130 /* Slaves added via options should not fail */
1131 unsigned i_flags
= p_slave
->i_priority
!= SLAVE_PRIORITY_USER
1132 ? SLAVE_ADD_CANFAIL
: SLAVE_ADD_NOFLAG
;
1134 if( !p_forced
[p_slave
->i_type
]
1135 && ( p_slave
->b_forced
|| p_slave
->i_priority
== SLAVE_PRIORITY_USER
) )
1136 i_flags
|= SLAVE_ADD_FORCED
;
1138 if( input_SlaveSourceAdd( p_input
, p_slave
->i_type
, p_slave
->psz_uri
,
1139 i_flags
) == VLC_SUCCESS
)
1141 input_item_AddSlave( input_priv(p_input
)->p_item
, p_slave
);
1142 p_forced
[p_slave
->i_type
] = true;
1145 input_item_slave_Delete( p_slave
);
1147 TAB_CLEAN( i_slaves
, pp_slaves
);
1149 /* Load subtitles from attachments */
1150 int i_attachment
= 0;
1151 input_attachment_t
**pp_attachment
= NULL
;
1153 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1154 for( int i
= 0; i
< input_priv(p_input
)->i_attachment
; i
++ )
1156 const input_attachment_t
*a
= input_priv(p_input
)->attachment
[i
];
1157 if( !strcmp( a
->psz_mime
, "application/x-srt" ) )
1158 TAB_APPEND( i_attachment
, pp_attachment
,
1159 vlc_input_attachment_New( a
->psz_name
, NULL
,
1160 a
->psz_description
, NULL
, 0 ) );
1162 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1164 if( i_attachment
> 0 )
1165 var_Create( p_input
, "sub-description", VLC_VAR_STRING
);
1166 for( int i
= 0; i
< i_attachment
; i
++ )
1168 input_attachment_t
*a
= pp_attachment
[i
];
1172 if( a
->psz_name
[0] &&
1173 asprintf( &psz_mrl
, "attachment://%s", a
->psz_name
) >= 0 )
1175 var_SetString( p_input
, "sub-description", a
->psz_description
? a
->psz_description
: "");
1177 input_SlaveSourceAdd( p_input
, SLAVE_TYPE_SPU
, psz_mrl
,
1180 /* Don't update item slaves for attachements */
1182 vlc_input_attachment_Delete( a
);
1184 free( pp_attachment
);
1185 if( i_attachment
> 0 )
1186 var_Destroy( p_input
, "sub-description" );
1189 static void UpdatePtsDelay( input_thread_t
*p_input
)
1191 input_thread_private_t
*p_sys
= input_priv(p_input
);
1193 /* Get max pts delay from input source */
1194 mtime_t i_pts_delay
= p_sys
->master
->i_pts_delay
;
1195 for( int i
= 0; i
< p_sys
->i_slave
; i
++ )
1196 i_pts_delay
= __MAX( i_pts_delay
, p_sys
->slave
[i
]->i_pts_delay
);
1198 if( i_pts_delay
< 0 )
1201 /* Take care of audio/spu delay */
1202 const mtime_t i_audio_delay
= var_GetInteger( p_input
, "audio-delay" );
1203 const mtime_t i_spu_delay
= var_GetInteger( p_input
, "spu-delay" );
1204 const mtime_t i_extra_delay
= __MIN( i_audio_delay
, i_spu_delay
);
1205 if( i_extra_delay
< 0 )
1206 i_pts_delay
-= i_extra_delay
;
1208 /* Update cr_average depending on the caching */
1209 const int i_cr_average
= var_GetInteger( p_input
, "cr-average" ) * i_pts_delay
/ DEFAULT_PTS_DELAY
;
1212 es_out_SetDelay( input_priv(p_input
)->p_es_out_display
, AUDIO_ES
, i_audio_delay
);
1213 es_out_SetDelay( input_priv(p_input
)->p_es_out_display
, SPU_ES
, i_spu_delay
);
1214 es_out_SetJitter( input_priv(p_input
)->p_es_out
, i_pts_delay
, 0, i_cr_average
);
1217 static void InitPrograms( input_thread_t
* p_input
)
1222 /* Compute correct pts_delay */
1223 UpdatePtsDelay( p_input
);
1226 i_es_out_mode
= ES_OUT_MODE_AUTO
;
1227 if( input_priv(p_input
)->p_sout
)
1231 if( (prgms
= var_GetNonEmptyString( p_input
, "programs" )) != NULL
)
1235 TAB_INIT( list
.i_count
, list
.p_values
);
1236 for( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1238 prgm
= strtok_r( NULL
, ",", &buf
) )
1240 vlc_value_t val
= { .i_int
= atoi( prgm
) };
1241 INSERT_ELEM( list
.p_values
, list
.i_count
, list
.i_count
, val
);
1244 if( list
.i_count
> 0 )
1245 i_es_out_mode
= ES_OUT_MODE_PARTIAL
;
1246 /* Note : we should remove the "program" callback. */
1250 else if( var_GetBool( p_input
, "sout-all" ) )
1252 i_es_out_mode
= ES_OUT_MODE_ALL
;
1255 es_out_SetMode( input_priv(p_input
)->p_es_out
, i_es_out_mode
);
1257 /* Inform the demuxer about waited group (needed only for DVB) */
1258 if( i_es_out_mode
== ES_OUT_MODE_ALL
)
1260 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
, -1, NULL
);
1262 else if( i_es_out_mode
== ES_OUT_MODE_PARTIAL
)
1264 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
, -1,
1266 TAB_CLEAN( list
.i_count
, list
.p_values
);
1270 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
,
1271 es_out_GetGroupForced( input_priv(p_input
)->p_es_out
), NULL
);
1275 static int Init( input_thread_t
* p_input
)
1277 input_thread_private_t
*priv
= input_priv(p_input
);
1278 input_source_t
*master
;
1280 if( var_Type( p_input
->obj
.parent
, "meta-file" ) )
1282 msg_Dbg( p_input
, "Input is a meta file: disabling unneeded options" );
1283 var_SetString( p_input
, "sout", "" );
1284 var_SetBool( p_input
, "sout-all", false );
1285 var_SetString( p_input
, "input-slave", "" );
1286 var_SetInteger( p_input
, "input-repeat", 0 );
1287 var_SetString( p_input
, "sub-file", "" );
1288 var_SetBool( p_input
, "sub-autodetect-file", false );
1291 InitStatistics( p_input
);
1293 if( InitSout( p_input
) )
1298 priv
->p_es_out
= input_EsOutTimeshiftNew( p_input
, priv
->p_es_out_display
,
1300 if( priv
->p_es_out
== NULL
)
1304 input_ChangeState( p_input
, OPENING_S
);
1305 input_SendEventCache( p_input
, 0.0 );
1308 master
= InputSourceNew( p_input
, priv
->p_item
->psz_uri
, NULL
, false );
1309 if( master
== NULL
)
1311 priv
->master
= master
;
1313 InitTitle( p_input
);
1315 /* Load master infos */
1318 if( demux_Control( master
->p_demux
, DEMUX_GET_LENGTH
, &i_length
) )
1321 i_length
= input_item_GetDuration( priv
->p_item
);
1322 input_SendEventLength( p_input
, i_length
);
1324 input_SendEventPosition( p_input
, 0.0, 0 );
1326 if( !priv
->b_preparsing
)
1328 StartTitle( p_input
);
1329 SetSubtitlesOptions( p_input
);
1330 LoadSlaves( p_input
);
1331 InitPrograms( p_input
);
1333 double f_rate
= var_InheritFloat( p_input
, "rate" );
1334 if( f_rate
!= 0.0 && f_rate
!= 1.0 )
1336 vlc_value_t val
= { .i_int
= INPUT_RATE_DEFAULT
/ f_rate
};
1337 input_ControlPush( p_input
, INPUT_CONTROL_SET_RATE
, &val
);
1341 if( !priv
->b_preparsing
&& priv
->p_sout
)
1343 priv
->b_out_pace_control
= priv
->p_sout
->i_out_pace_nocontrol
> 0;
1345 msg_Dbg( p_input
, "starting in %ssync mode",
1346 priv
->b_out_pace_control
? "a" : "" );
1349 vlc_meta_t
*p_meta
= vlc_meta_New();
1350 if( p_meta
!= NULL
)
1352 /* Get meta data from users */
1353 InputMetaUser( p_input
, p_meta
);
1355 /* Get meta data from master input */
1356 InputSourceMeta( p_input
, master
, p_meta
);
1358 /* And from slave */
1359 for( int i
= 0; i
< priv
->i_slave
; i
++ )
1360 InputSourceMeta( p_input
, priv
->slave
[i
], p_meta
);
1362 es_out_ControlSetMeta( priv
->p_es_out
, p_meta
);
1363 vlc_meta_Delete( p_meta
);
1366 msg_Dbg( p_input
, "`%s' successfully opened",
1367 input_priv(p_input
)->p_item
->psz_uri
);
1369 /* initialization is complete */
1370 input_ChangeState( p_input
, PLAYING_S
);
1375 input_ChangeState( p_input
, ERROR_S
);
1377 if( input_priv(p_input
)->p_es_out
)
1378 es_out_Delete( input_priv(p_input
)->p_es_out
);
1379 es_out_SetMode( input_priv(p_input
)->p_es_out_display
, ES_OUT_MODE_END
);
1380 if( input_priv(p_input
)->p_resource
)
1382 if( input_priv(p_input
)->p_sout
)
1383 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1384 input_priv(p_input
)->p_sout
, NULL
);
1385 input_resource_SetInput( input_priv(p_input
)->p_resource
, NULL
);
1386 if( input_priv(p_input
)->p_resource_private
)
1387 input_resource_Terminate( input_priv(p_input
)->p_resource_private
);
1390 if( !priv
->b_preparsing
&& libvlc_stats( p_input
) )
1392 #define EXIT_COUNTER( c ) do { if( input_priv(p_input)->counters.p_##c ) \
1393 stats_CounterClean( input_priv(p_input)->counters.p_##c );\
1394 input_priv(p_input)->counters.p_##c = NULL; } while(0)
1395 EXIT_COUNTER( read_bytes
);
1396 EXIT_COUNTER( read_packets
);
1397 EXIT_COUNTER( demux_read
);
1398 EXIT_COUNTER( input_bitrate
);
1399 EXIT_COUNTER( demux_bitrate
);
1400 EXIT_COUNTER( demux_corrupted
);
1401 EXIT_COUNTER( demux_discontinuity
);
1402 EXIT_COUNTER( played_abuffers
);
1403 EXIT_COUNTER( lost_abuffers
);
1404 EXIT_COUNTER( displayed_pictures
);
1405 EXIT_COUNTER( lost_pictures
);
1406 EXIT_COUNTER( decoded_audio
);
1407 EXIT_COUNTER( decoded_video
);
1408 EXIT_COUNTER( decoded_sub
);
1410 if( input_priv(p_input
)->p_sout
)
1412 EXIT_COUNTER( sout_sent_packets
);
1413 EXIT_COUNTER( sout_sent_bytes
);
1414 EXIT_COUNTER( sout_send_bitrate
);
1419 /* Mark them deleted */
1420 input_priv(p_input
)->p_es_out
= NULL
;
1421 input_priv(p_input
)->p_sout
= NULL
;
1423 return VLC_EGENERIC
;
1426 /*****************************************************************************
1427 * End: end the input thread
1428 *****************************************************************************/
1429 static void End( input_thread_t
* p_input
)
1431 input_thread_private_t
*priv
= input_priv(p_input
);
1433 /* We are at the end */
1434 input_ChangeState( p_input
, END_S
);
1436 /* Clean control variables */
1437 input_ControlVarStop( p_input
);
1439 /* Stop es out activity */
1440 es_out_SetMode( priv
->p_es_out
, ES_OUT_MODE_NONE
);
1443 for( int i
= 0; i
< priv
->i_slave
; i
++ )
1444 InputSourceDestroy( priv
->slave
[i
] );
1445 free( priv
->slave
);
1447 /* Clean up master */
1448 InputSourceDestroy( priv
->master
);
1451 priv
->i_title_offset
= 0;
1452 priv
->i_seekpoint_offset
= 0;
1454 /* Unload all modules */
1455 if( priv
->p_es_out
)
1456 es_out_Delete( priv
->p_es_out
);
1457 es_out_SetMode( priv
->p_es_out_display
, ES_OUT_MODE_END
);
1459 if( !priv
->b_preparsing
)
1461 #define CL_CO( c ) \
1463 stats_CounterClean( priv->counters.p_##c ); \
1464 priv->counters.p_##c = NULL; \
1467 if( libvlc_stats( p_input
) )
1469 /* make sure we are up to date */
1470 stats_ComputeInputStats( p_input
, priv
->p_item
->p_stats
);
1471 CL_CO( read_bytes
);
1472 CL_CO( read_packets
);
1473 CL_CO( demux_read
);
1474 CL_CO( input_bitrate
);
1475 CL_CO( demux_bitrate
);
1476 CL_CO( demux_corrupted
);
1477 CL_CO( demux_discontinuity
);
1478 CL_CO( played_abuffers
);
1479 CL_CO( lost_abuffers
);
1480 CL_CO( displayed_pictures
);
1481 CL_CO( lost_pictures
);
1482 CL_CO( decoded_audio
) ;
1483 CL_CO( decoded_video
);
1484 CL_CO( decoded_sub
) ;
1487 /* Close optional stream output instance */
1490 CL_CO( sout_sent_packets
);
1491 CL_CO( sout_sent_bytes
);
1492 CL_CO( sout_send_bitrate
);
1497 vlc_mutex_lock( &priv
->p_item
->lock
);
1498 if( priv
->i_attachment
> 0 )
1500 for( int i
= 0; i
< priv
->i_attachment
; i
++ )
1501 vlc_input_attachment_Delete( priv
->attachment
[i
] );
1502 TAB_CLEAN( priv
->i_attachment
, priv
->attachment
);
1503 free( priv
->attachment_demux
);
1504 priv
->attachment_demux
= NULL
;
1506 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1509 input_resource_RequestSout( input_priv(p_input
)->p_resource
,
1510 input_priv(p_input
)->p_sout
, NULL
);
1511 input_resource_SetInput( input_priv(p_input
)->p_resource
, NULL
);
1512 if( input_priv(p_input
)->p_resource_private
)
1513 input_resource_Terminate( input_priv(p_input
)->p_resource_private
);
1516 /*****************************************************************************
1518 *****************************************************************************/
1519 void input_ControlPush( input_thread_t
*p_input
,
1520 int i_type
, vlc_value_t
*p_val
)
1522 input_thread_private_t
*sys
= input_priv(p_input
);
1524 vlc_mutex_lock( &sys
->lock_control
);
1525 if( sys
->is_stopped
|| sys
->i_control
>= INPUT_CONTROL_FIFO_SIZE
)
1527 if( sys
->is_stopped
)
1528 msg_Dbg( p_input
, "input control stopped, trashing type=%d",
1531 msg_Err( p_input
, "input control fifo overflow, trashing type=%d",
1534 ControlRelease( i_type
, *p_val
);
1543 memset( &c
.val
, 0, sizeof(c
.val
) );
1545 sys
->control
[sys
->i_control
++] = c
;
1547 vlc_cond_signal( &sys
->wait_control
);
1549 vlc_mutex_unlock( &sys
->lock_control
);
1552 static int ControlGetReducedIndexLocked( input_thread_t
*p_input
)
1554 const int i_lt
= input_priv(p_input
)->control
[0].i_type
;
1556 for( i
= 1; i
< input_priv(p_input
)->i_control
; i
++ )
1558 const int i_ct
= input_priv(p_input
)->control
[i
].i_type
;
1561 ( i_ct
== INPUT_CONTROL_SET_STATE
||
1562 i_ct
== INPUT_CONTROL_SET_RATE
||
1563 i_ct
== INPUT_CONTROL_SET_POSITION
||
1564 i_ct
== INPUT_CONTROL_SET_TIME
||
1565 i_ct
== INPUT_CONTROL_SET_PROGRAM
||
1566 i_ct
== INPUT_CONTROL_SET_TITLE
||
1567 i_ct
== INPUT_CONTROL_SET_SEEKPOINT
||
1568 i_ct
== INPUT_CONTROL_SET_BOOKMARK
) )
1574 /* TODO but that's not that important
1575 - merge SET_X with SET_X_CMD
1576 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1577 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1587 static inline int ControlPop( input_thread_t
*p_input
,
1588 int *pi_type
, vlc_value_t
*p_val
,
1589 mtime_t i_deadline
, bool b_postpone_seek
)
1591 input_thread_private_t
*p_sys
= input_priv(p_input
);
1593 vlc_mutex_lock( &p_sys
->lock_control
);
1594 while( p_sys
->i_control
<= 0 ||
1595 ( b_postpone_seek
&& ControlIsSeekRequest( p_sys
->control
[0].i_type
) ) )
1597 if( p_sys
->is_stopped
)
1599 vlc_mutex_unlock( &p_sys
->lock_control
);
1600 return VLC_EGENERIC
;
1603 if( i_deadline
>= 0 )
1605 if( vlc_cond_timedwait( &p_sys
->wait_control
, &p_sys
->lock_control
,
1608 vlc_mutex_unlock( &p_sys
->lock_control
);
1609 return VLC_EGENERIC
;
1613 vlc_cond_wait( &p_sys
->wait_control
, &p_sys
->lock_control
);
1617 const int i_index
= ControlGetReducedIndexLocked( p_input
);
1619 for( int i
= 0; i
< i_index
; ++i
)
1621 /* Release Reduced controls */
1622 ControlRelease( p_sys
->control
[i
].i_type
, p_sys
->control
[i
].val
);
1626 *pi_type
= p_sys
->control
[i_index
].i_type
;
1627 *p_val
= p_sys
->control
[i_index
].val
;
1629 p_sys
->i_control
-= i_index
+ 1;
1630 if( p_sys
->i_control
> 0 )
1631 memmove( &p_sys
->control
[0], &p_sys
->control
[i_index
+1],
1632 sizeof(*p_sys
->control
) * p_sys
->i_control
);
1633 vlc_mutex_unlock( &p_sys
->lock_control
);
1637 static bool ControlIsSeekRequest( int i_type
)
1641 case INPUT_CONTROL_SET_POSITION
:
1642 case INPUT_CONTROL_SET_TIME
:
1643 case INPUT_CONTROL_SET_TITLE
:
1644 case INPUT_CONTROL_SET_TITLE_NEXT
:
1645 case INPUT_CONTROL_SET_TITLE_PREV
:
1646 case INPUT_CONTROL_SET_SEEKPOINT
:
1647 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1648 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1649 case INPUT_CONTROL_SET_BOOKMARK
:
1650 case INPUT_CONTROL_NAV_ACTIVATE
:
1651 case INPUT_CONTROL_NAV_UP
:
1652 case INPUT_CONTROL_NAV_DOWN
:
1653 case INPUT_CONTROL_NAV_LEFT
:
1654 case INPUT_CONTROL_NAV_RIGHT
:
1655 case INPUT_CONTROL_NAV_POPUP
:
1656 case INPUT_CONTROL_NAV_MENU
:
1663 static void ControlRelease( int i_type
, vlc_value_t val
)
1667 case INPUT_CONTROL_ADD_SUBTITLE
:
1668 free( val
.psz_string
);
1670 case INPUT_CONTROL_ADD_SLAVE
:
1672 input_item_slave_Delete( val
.p_address
);
1674 case INPUT_CONTROL_SET_VIEWPOINT
:
1675 case INPUT_CONTROL_UPDATE_VIEWPOINT
:
1676 free( val
.p_address
);
1685 static void ControlPause( input_thread_t
*p_input
, mtime_t i_control_date
)
1687 int i_state
= PAUSE_S
;
1689 if( input_priv(p_input
)->b_can_pause
)
1691 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
1693 if( demux_Control( p_demux
, DEMUX_SET_PAUSE_STATE
, true ) )
1695 msg_Warn( p_input
, "cannot set pause state" );
1701 if( es_out_SetPauseState( input_priv(p_input
)->p_es_out
, input_priv(p_input
)->b_can_pause
,
1702 true, i_control_date
) )
1704 msg_Warn( p_input
, "cannot set pause state at es_out level" );
1708 /* Switch to new state */
1709 input_ChangeState( p_input
, i_state
);
1712 static void ControlUnpause( input_thread_t
*p_input
, mtime_t i_control_date
)
1714 if( input_priv(p_input
)->b_can_pause
)
1716 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
1718 if( demux_Control( p_demux
, DEMUX_SET_PAUSE_STATE
, false ) )
1720 msg_Err( p_input
, "cannot resume" );
1721 input_ChangeState( p_input
, ERROR_S
);
1726 /* Switch to play */
1727 input_ChangeState( p_input
, PLAYING_S
);
1728 es_out_SetPauseState( input_priv(p_input
)->p_es_out
, false, false, i_control_date
);
1731 static bool Control( input_thread_t
*p_input
,
1732 int i_type
, vlc_value_t val
)
1734 const mtime_t i_control_date
= mdate();
1735 /* FIXME b_force_update is abused, it should be carefully checked */
1736 bool b_force_update
= false;
1739 return b_force_update
;
1743 case INPUT_CONTROL_SET_POSITION
:
1745 if( input_priv(p_input
)->b_recording
)
1747 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION ignored while recording" );
1751 float f_pos
= val
.f_float
;
1754 else if( f_pos
> 1.f
)
1756 /* Reset the decoders states and clock sync (before calling the demuxer */
1757 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
1758 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_POSITION
,
1759 (double) f_pos
, !input_priv(p_input
)->b_fast_seek
) )
1761 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION "
1762 "%2.1f%% failed", (double)(f_pos
* 100.f
) );
1766 if( input_priv(p_input
)->i_slave
> 0 )
1767 SlaveSeek( p_input
);
1768 input_priv(p_input
)->master
->b_eof
= false;
1770 b_force_update
= true;
1775 case INPUT_CONTROL_SET_TIME
:
1780 if( input_priv(p_input
)->b_recording
)
1782 msg_Err( p_input
, "INPUT_CONTROL_SET_TIME ignored while recording" );
1790 /* Reset the decoders states and clock sync (before calling the demuxer */
1791 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
1793 i_ret
= demux_Control( input_priv(p_input
)->master
->p_demux
,
1794 DEMUX_SET_TIME
, i_time
,
1795 !input_priv(p_input
)->b_fast_seek
);
1800 /* Emulate it with a SET_POS */
1801 if( !demux_Control( input_priv(p_input
)->master
->p_demux
,
1802 DEMUX_GET_LENGTH
, &i_length
) && i_length
> 0 )
1804 double f_pos
= (double)i_time
/ (double)i_length
;
1805 i_ret
= demux_Control( input_priv(p_input
)->master
->p_demux
,
1806 DEMUX_SET_POSITION
, f_pos
,
1807 !input_priv(p_input
)->b_fast_seek
);
1812 msg_Warn( p_input
, "INPUT_CONTROL_SET_TIME %"PRId64
1813 " failed or not possible", i_time
);
1817 if( input_priv(p_input
)->i_slave
> 0 )
1818 SlaveSeek( p_input
);
1819 input_priv(p_input
)->master
->b_eof
= false;
1821 b_force_update
= true;
1826 case INPUT_CONTROL_SET_STATE
:
1830 if( input_priv(p_input
)->i_state
== PAUSE_S
)
1832 ControlUnpause( p_input
, i_control_date
);
1833 b_force_update
= true;
1837 if( input_priv(p_input
)->i_state
== PLAYING_S
)
1839 ControlPause( p_input
, i_control_date
);
1840 b_force_update
= true;
1844 msg_Err( p_input
, "invalid INPUT_CONTROL_SET_STATE" );
1848 case INPUT_CONTROL_SET_RATE
:
1850 /* Get rate and direction */
1851 int i_rate
= abs( val
.i_int
);
1852 int i_rate_sign
= val
.i_int
< 0 ? -1 : 1;
1854 /* Check rate bound */
1855 if( i_rate
< INPUT_RATE_MIN
)
1857 msg_Dbg( p_input
, "cannot set rate faster" );
1858 i_rate
= INPUT_RATE_MIN
;
1860 else if( i_rate
> INPUT_RATE_MAX
)
1862 msg_Dbg( p_input
, "cannot set rate slower" );
1863 i_rate
= INPUT_RATE_MAX
;
1866 /* Apply direction */
1867 if( i_rate_sign
< 0 )
1869 if( input_priv(p_input
)->master
->b_rescale_ts
)
1871 msg_Dbg( p_input
, "cannot set negative rate" );
1872 i_rate
= input_priv(p_input
)->i_rate
;
1873 assert( i_rate
> 0 );
1877 i_rate
*= i_rate_sign
;
1881 if( i_rate
!= INPUT_RATE_DEFAULT
&&
1882 ( ( !input_priv(p_input
)->b_can_rate_control
&& !input_priv(p_input
)->master
->b_rescale_ts
) ||
1883 ( input_priv(p_input
)->p_sout
&& !input_priv(p_input
)->b_out_pace_control
) ) )
1885 msg_Dbg( p_input
, "cannot change rate" );
1886 i_rate
= INPUT_RATE_DEFAULT
;
1888 if( i_rate
!= input_priv(p_input
)->i_rate
&&
1889 !input_priv(p_input
)->b_can_pace_control
&& input_priv(p_input
)->b_can_rate_control
)
1891 if( !input_priv(p_input
)->master
->b_rescale_ts
)
1892 es_out_Control( input_priv(p_input
)->p_es_out
, ES_OUT_RESET_PCR
);
1894 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_RATE
,
1897 msg_Warn( p_input
, "ACCESS/DEMUX_SET_RATE failed" );
1898 i_rate
= input_priv(p_input
)->i_rate
;
1903 if( i_rate
!= input_priv(p_input
)->i_rate
)
1905 input_priv(p_input
)->i_rate
= i_rate
;
1906 input_SendEventRate( p_input
, i_rate
);
1908 if( input_priv(p_input
)->master
->b_rescale_ts
)
1910 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
;
1911 es_out_SetRate( input_priv(p_input
)->p_es_out
, i_rate_source
, i_rate
);
1914 b_force_update
= true;
1919 case INPUT_CONTROL_SET_PROGRAM
:
1920 /* No need to force update, es_out does it if needed */
1921 es_out_Control( input_priv(p_input
)->p_es_out
,
1922 ES_OUT_SET_GROUP
, val
.i_int
);
1924 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_GROUP
, val
.i_int
,
1928 case INPUT_CONTROL_SET_ES
:
1929 /* No need to force update, es_out does it if needed */
1930 es_out_Control( input_priv(p_input
)->p_es_out_display
,
1931 ES_OUT_SET_ES_BY_ID
, (int)val
.i_int
);
1933 demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_SET_ES
, (int)val
.i_int
);
1936 case INPUT_CONTROL_RESTART_ES
:
1937 es_out_Control( input_priv(p_input
)->p_es_out_display
,
1938 ES_OUT_RESTART_ES_BY_ID
, (int)val
.i_int
);
1941 case INPUT_CONTROL_SET_VIEWPOINT
:
1942 case INPUT_CONTROL_UPDATE_VIEWPOINT
:
1944 input_thread_private_t
*priv
= input_priv(p_input
);
1945 const vlc_viewpoint_t
*p_vp
= val
.p_address
;
1946 if ( i_type
== INPUT_CONTROL_SET_VIEWPOINT
)
1947 priv
->viewpoint
= *p_vp
;
1950 priv
->viewpoint
.yaw
+= p_vp
->yaw
;
1951 priv
->viewpoint
.pitch
+= p_vp
->pitch
;
1952 priv
->viewpoint
.roll
+= p_vp
->roll
;
1953 priv
->viewpoint
.fov
+= p_vp
->fov
;
1956 priv
->viewpoint
.yaw
= fmodf( priv
->viewpoint
.yaw
, 360.f
);
1957 priv
->viewpoint
.pitch
= fmodf( priv
->viewpoint
.pitch
, 360.f
);
1958 priv
->viewpoint
.roll
= fmodf( priv
->viewpoint
.roll
, 360.f
);
1959 priv
->viewpoint
.fov
= VLC_CLIP( priv
->viewpoint
.fov
,
1960 FIELD_OF_VIEW_DEGREES_MIN
,
1961 FIELD_OF_VIEW_DEGREES_MAX
);
1963 vout_thread_t
**pp_vout
;
1965 input_resource_HoldVouts( priv
->p_resource
, &pp_vout
, &i_vout
);
1967 for( size_t i
= 0; i
< i_vout
; ++i
)
1969 var_SetAddress( pp_vout
[i
], "viewpoint", &priv
->viewpoint
);
1970 vlc_object_release( pp_vout
[i
] );
1976 case INPUT_CONTROL_SET_AUDIO_DELAY
:
1977 input_SendEventAudioDelay( p_input
, val
.i_int
);
1978 UpdatePtsDelay( p_input
);
1981 case INPUT_CONTROL_SET_SPU_DELAY
:
1982 input_SendEventSubtitleDelay( p_input
, val
.i_int
);
1983 UpdatePtsDelay( p_input
);
1986 case INPUT_CONTROL_SET_TITLE
:
1987 case INPUT_CONTROL_SET_TITLE_NEXT
:
1988 case INPUT_CONTROL_SET_TITLE_PREV
:
1990 if( input_priv(p_input
)->b_recording
)
1992 msg_Err( p_input
, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
1995 if( input_priv(p_input
)->master
->i_title
<= 0 )
1998 int i_title
= demux_GetTitle( input_priv(p_input
)->master
->p_demux
);
1999 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
2001 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
2004 i_title
= val
.i_int
;
2005 if( i_title
< 0 || i_title
>= input_priv(p_input
)->master
->i_title
)
2008 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
2009 demux_Control( input_priv(p_input
)->master
->p_demux
,
2010 DEMUX_SET_TITLE
, i_title
);
2011 input_SendEventTitle( p_input
, i_title
);
2014 case INPUT_CONTROL_SET_SEEKPOINT
:
2015 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
2016 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
2018 if( input_priv(p_input
)->b_recording
)
2020 msg_Err( p_input
, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
2023 if( input_priv(p_input
)->master
->i_title
<= 0 )
2026 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2028 int i_title
= demux_GetTitle( p_demux
);
2029 int i_seekpoint
= demux_GetSeekpoint( p_demux
);
2031 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
2033 int64_t i_seekpoint_time
= input_priv(p_input
)->master
->title
[i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
2034 int64_t i_input_time
= var_GetInteger( p_input
, "time" );
2035 if( i_seekpoint_time
>= 0 && i_input_time
>= 0 )
2037 if( i_input_time
< i_seekpoint_time
+ 3000000 )
2043 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
2046 i_seekpoint
= val
.i_int
;
2048 || i_seekpoint
>= input_priv(p_input
)->master
->title
[i_title
]->i_seekpoint
)
2051 es_out_SetTime( input_priv(p_input
)->p_es_out
, -1 );
2052 demux_Control( input_priv(p_input
)->master
->p_demux
,
2053 DEMUX_SET_SEEKPOINT
, i_seekpoint
);
2054 input_SendEventSeekpoint( p_input
, i_title
, i_seekpoint
);
2058 case INPUT_CONTROL_ADD_SUBTITLE
:
2059 if( val
.psz_string
)
2061 char *psz_uri
= input_SubtitleFile2Uri( p_input
, val
.psz_string
);
2062 if( psz_uri
!= NULL
)
2064 input_SlaveSourceAdd( p_input
, SLAVE_TYPE_SPU
, psz_uri
,
2071 case INPUT_CONTROL_ADD_SLAVE
:
2074 input_item_slave_t
*p_item_slave
= val
.p_address
;
2075 unsigned i_flags
= SLAVE_ADD_CANFAIL
| SLAVE_ADD_SET_TIME
;
2076 if( p_item_slave
->b_forced
)
2077 i_flags
|= SLAVE_ADD_FORCED
;
2079 if( input_SlaveSourceAdd( p_input
, p_item_slave
->i_type
,
2080 p_item_slave
->psz_uri
, i_flags
)
2083 /* Update item slaves */
2084 input_item_AddSlave( input_priv(p_input
)->p_item
, p_item_slave
);
2085 /* The slave is now owned by the item */
2086 val
.p_address
= NULL
;
2091 case INPUT_CONTROL_SET_RECORD_STATE
:
2092 if( !!input_priv(p_input
)->b_recording
!= !!val
.b_bool
)
2094 if( input_priv(p_input
)->master
->b_can_stream_record
)
2096 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
2097 DEMUX_SET_RECORD_STATE
, val
.b_bool
) )
2102 if( es_out_SetRecordState( input_priv(p_input
)->p_es_out_display
, val
.b_bool
) )
2105 input_priv(p_input
)->b_recording
= val
.b_bool
;
2107 input_SendEventRecord( p_input
, val
.b_bool
);
2109 b_force_update
= true;
2113 case INPUT_CONTROL_SET_FRAME_NEXT
:
2114 if( input_priv(p_input
)->i_state
== PAUSE_S
)
2116 es_out_SetFrameNext( input_priv(p_input
)->p_es_out
);
2118 else if( input_priv(p_input
)->i_state
== PLAYING_S
)
2120 ControlPause( p_input
, i_control_date
);
2124 msg_Err( p_input
, "invalid state for frame next" );
2126 b_force_update
= true;
2129 case INPUT_CONTROL_SET_BOOKMARK
:
2131 mtime_t time_offset
= -1;
2133 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2134 if( val
.i_int
>= 0 && val
.i_int
< input_priv(p_input
)->i_bookmark
)
2136 const seekpoint_t
*p_bookmark
= input_priv(p_input
)->pp_bookmark
[val
.i_int
];
2137 time_offset
= p_bookmark
->i_time_offset
;
2139 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2141 if( time_offset
< 0 )
2143 msg_Err( p_input
, "invalid bookmark %"PRId64
, val
.i_int
);
2147 val
.i_int
= time_offset
;
2148 b_force_update
= Control( p_input
, INPUT_CONTROL_SET_TIME
, val
);
2152 case INPUT_CONTROL_NAV_ACTIVATE
:
2153 case INPUT_CONTROL_NAV_UP
:
2154 case INPUT_CONTROL_NAV_DOWN
:
2155 case INPUT_CONTROL_NAV_LEFT
:
2156 case INPUT_CONTROL_NAV_RIGHT
:
2157 case INPUT_CONTROL_NAV_POPUP
:
2158 case INPUT_CONTROL_NAV_MENU
:
2159 demux_Control( input_priv(p_input
)->master
->p_demux
, i_type
2160 - INPUT_CONTROL_NAV_ACTIVATE
+ DEMUX_NAV_ACTIVATE
);
2164 msg_Err( p_input
, "not yet implemented" );
2168 ControlRelease( i_type
, val
);
2169 return b_force_update
;
2172 /*****************************************************************************
2173 * UpdateTitleSeekpoint
2174 *****************************************************************************/
2175 static int UpdateTitleSeekpoint( input_thread_t
*p_input
,
2176 int i_title
, int i_seekpoint
)
2178 int i_title_end
= input_priv(p_input
)->master
->i_title_end
-
2179 input_priv(p_input
)->master
->i_title_offset
;
2180 int i_seekpoint_end
= input_priv(p_input
)->master
->i_seekpoint_end
-
2181 input_priv(p_input
)->master
->i_seekpoint_offset
;
2183 if( i_title_end
>= 0 && i_seekpoint_end
>= 0 )
2185 if( i_title
> i_title_end
||
2186 ( i_title
== i_title_end
&& i_seekpoint
> i_seekpoint_end
) )
2187 return VLC_DEMUXER_EOF
;
2189 else if( i_seekpoint_end
>= 0 )
2191 if( i_seekpoint
> i_seekpoint_end
)
2192 return VLC_DEMUXER_EOF
;
2194 else if( i_title_end
>= 0 )
2196 if( i_title
> i_title_end
)
2197 return VLC_DEMUXER_EOF
;
2199 return VLC_DEMUXER_SUCCESS
;
2201 /*****************************************************************************
2203 *****************************************************************************/
2204 static int UpdateTitleSeekpointFromDemux( input_thread_t
*p_input
)
2206 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2208 /* TODO event-like */
2209 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_TITLE
) )
2210 input_SendEventTitle( p_input
, demux_GetTitle( p_demux
) );
2212 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_SEEKPOINT
) )
2213 input_SendEventSeekpoint( p_input
, demux_GetTitle( p_demux
),
2214 demux_GetSeekpoint( p_demux
) );
2216 return UpdateTitleSeekpoint( p_input
,
2217 demux_GetTitle( p_demux
),
2218 demux_GetSeekpoint( p_demux
) );
2221 static void UpdateGenericFromDemux( input_thread_t
*p_input
)
2223 demux_t
*p_demux
= input_priv(p_input
)->master
->p_demux
;
2225 if( demux_TestAndClearFlags( p_demux
, INPUT_UPDATE_META
) )
2226 InputUpdateMeta( p_input
, p_demux
);
2232 if( !demux_Control( p_demux
, DEMUX_GET_SIGNAL
, &quality
, &strength
) )
2233 input_SendEventSignal( p_input
, quality
, strength
);
2237 static void UpdateTitleListfromDemux( input_thread_t
*p_input
)
2239 input_source_t
*in
= input_priv(p_input
)->master
;
2241 /* Delete the preexisting titles */
2242 if( in
->i_title
> 0 )
2244 for( int i
= 0; i
< in
->i_title
; i
++ )
2245 vlc_input_title_Delete( in
->title
[i
] );
2246 TAB_CLEAN( in
->i_title
, in
->title
);
2247 in
->b_title_demux
= false;
2250 /* Get the new title list */
2251 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2252 &in
->title
, &in
->i_title
,
2253 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2254 TAB_INIT( in
->i_title
, in
->title
);
2256 in
->b_title_demux
= true;
2258 InitTitle( p_input
);
2262 InputStreamHandleAnchor( input_source_t
*source
, stream_t
**stream
,
2263 char const *anchor
)
2266 if( stream_extractor_AttachParsed( stream
, anchor
, &extra
) )
2268 msg_Err( source
, "unable to attach stream-extractors for %s",
2269 (*stream
)->psz_url
);
2271 return VLC_EGENERIC
;
2274 if( vlc_stream_directory_Attach( stream
, NULL
) )
2275 msg_Dbg( source
, "attachment of directory-extractor failed for %s",
2276 (*stream
)->psz_url
);
2278 MRLSections( extra
? extra
: "",
2279 &source
->i_title_start
, &source
->i_title_end
,
2280 &source
->i_seekpoint_start
, &source
->i_seekpoint_end
);
2285 static demux_t
*InputDemuxNew( input_thread_t
*p_input
, input_source_t
*p_source
,
2286 const char *psz_access
, const char *psz_demux
,
2287 const char *psz_path
, const char *psz_anchor
)
2289 input_thread_private_t
*priv
= input_priv(p_input
);
2290 demux_t
*p_demux
= NULL
;
2292 /* first, try to create an access demux */
2293 p_demux
= demux_NewAdvanced( VLC_OBJECT( p_source
), p_input
,
2294 psz_access
, psz_demux
, psz_path
,
2295 NULL
, priv
->p_es_out
, priv
->b_preparsing
);
2298 MRLSections( psz_anchor
,
2299 &p_source
->i_title_start
, &p_source
->i_title_end
,
2300 &p_source
->i_seekpoint_start
, &p_source
->i_seekpoint_end
);
2305 /* not an access-demux: create the underlying access stream */
2308 if( asprintf( &psz_base_mrl
, "%s://%s", psz_access
, psz_path
) < 0 )
2311 char *psz_filters
= var_InheritString( p_source
, "stream-filter" );
2312 stream_t
* p_stream
= stream_AccessNew( VLC_OBJECT( p_source
), p_input
,
2315 FREENULL( psz_base_mrl
);
2317 if( p_stream
== NULL
)
2320 p_stream
= stream_FilterAutoNew( p_stream
);
2322 /* attach explicit stream filters to stream */
2324 p_stream
= stream_FilterChainNew( p_stream
, psz_filters
);
2326 FREENULL( psz_filters
);
2328 /* handle anchors */
2329 if( InputStreamHandleAnchor( p_source
, &p_stream
, psz_anchor
) )
2332 /* attach conditional record stream-filter */
2333 if( var_InheritBool( p_source
, "input-record-native" ) )
2334 p_stream
= stream_FilterChainNew( p_stream
, "record" );
2336 /* create a regular demux with the access stream created */
2337 p_demux
= demux_NewAdvanced( VLC_OBJECT( p_source
), p_input
,
2338 psz_access
, psz_demux
, psz_path
,
2339 p_stream
, priv
->p_es_out
,
2340 priv
->b_preparsing
);
2345 free( psz_base_mrl
);
2346 free( psz_filters
);
2349 vlc_stream_Delete( p_stream
);
2354 /*****************************************************************************
2356 *****************************************************************************/
2357 static input_source_t
*InputSourceNew( input_thread_t
*p_input
,
2358 const char *psz_mrl
,
2359 const char *psz_forced_demux
,
2360 bool b_in_can_fail
)
2362 input_source_t
*in
= vlc_custom_create( p_input
, sizeof( *in
),
2364 if( unlikely(in
== NULL
) )
2367 const char *psz_access
, *psz_demux
, *psz_path
, *psz_anchor
= NULL
;
2370 char *psz_dup
= strdup( psz_mrl
);
2371 char *psz_demux_var
= NULL
;
2373 if( psz_dup
== NULL
)
2375 vlc_object_release( in
);
2380 input_SplitMRL( &psz_access
, &psz_demux
, &psz_path
, &psz_anchor
, psz_dup
);
2382 if( psz_demux
== NULL
|| psz_demux
[0] == '\0' )
2383 psz_demux
= psz_demux_var
= var_InheritString( in
, "demux" );
2385 if( psz_forced_demux
!= NULL
)
2386 psz_demux
= psz_forced_demux
;
2388 if( psz_demux
== NULL
)
2391 msg_Dbg( p_input
, "`%s' gives access `%s' demux `%s' path `%s'",
2392 psz_mrl
, psz_access
, psz_demux
, psz_path
);
2394 if( input_priv(p_input
)->master
== NULL
/* XXX ugly */)
2395 { /* On master stream only, use input-list */
2396 char *str
= var_InheritString( p_input
, "input-list" );
2401 var_Create( p_input
, "concat-list", VLC_VAR_STRING
);
2402 if( likely(asprintf( &list
, "%s://%s,%s", psz_access
, psz_path
,
2405 var_SetString( p_input
, "concat-list", list
);
2409 psz_access
= "concat";
2413 if( strcasecmp( psz_access
, "concat" ) )
2414 { /* Autodetect extra files if none specified */
2418 TAB_INIT( count
, tab
);
2419 InputGetExtraFiles( p_input
, &count
, &tab
, psz_access
, psz_path
);
2424 for( int i
= 0; i
< count
; i
++ )
2427 if( asprintf( &str
, "%s,%s", list
? list
: psz_mrl
,
2436 var_Create( p_input
, "concat-list", VLC_VAR_STRING
);
2437 if( likely(list
!= NULL
) )
2439 var_SetString( p_input
, "concat-list", list
);
2442 psz_access
= "concat";
2444 TAB_CLEAN( count
, tab
);
2447 in
->p_demux
= InputDemuxNew( p_input
, in
, psz_access
, psz_demux
,
2448 psz_path
, psz_anchor
);
2450 free( psz_demux_var
);
2453 if( in
->p_demux
== NULL
)
2455 if( !b_in_can_fail
&& !input_Stopped( p_input
) )
2456 vlc_dialog_display_error( p_input
, _("Your input can't be opened"),
2457 _("VLC is unable to open the MRL '%s'."
2458 " Check the log for details."), psz_mrl
);
2459 vlc_object_release( in
);
2463 char *psz_demux_chain
= var_GetNonEmptyString(p_input
, "demux-filter");
2464 /* add the chain of demux filters */
2465 demux_t
*p_filtered_demux
= demux_FilterChainNew( in
->p_demux
, psz_demux_chain
);
2466 if ( p_filtered_demux
!= NULL
)
2467 in
->p_demux
= p_filtered_demux
;
2468 else if ( psz_demux_chain
!= NULL
)
2469 msg_Dbg(p_input
, "Failed to create demux filter %s", psz_demux_chain
);
2470 free( psz_demux_chain
);
2472 /* Get infos from (access_)demux */
2474 if( demux_Control( in
->p_demux
, DEMUX_CAN_SEEK
, &b_can_seek
) )
2476 var_SetBool( p_input
, "can-seek", b_can_seek
);
2478 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_PACE
,
2479 &in
->b_can_pace_control
) )
2480 in
->b_can_pace_control
= false;
2482 assert( in
->p_demux
->pf_demux
!= NULL
|| !in
->b_can_pace_control
);
2484 if( !in
->b_can_pace_control
)
2486 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_RATE
,
2487 &in
->b_can_rate_control
) )
2489 in
->b_can_rate_control
= false;
2490 in
->b_rescale_ts
= true;
2493 in
->b_rescale_ts
= !in
->b_can_rate_control
;
2497 in
->b_can_rate_control
= true;
2498 in
->b_rescale_ts
= true;
2501 demux_Control( in
->p_demux
, DEMUX_CAN_PAUSE
, &in
->b_can_pause
);
2503 var_SetBool( p_input
, "can-pause", in
->b_can_pause
|| !in
->b_can_pace_control
); /* XXX temporary because of es_out_timeshift*/
2504 var_SetBool( p_input
, "can-rate", !in
->b_can_pace_control
|| in
->b_can_rate_control
); /* XXX temporary because of es_out_timeshift*/
2505 var_SetBool( p_input
, "can-rewind", !in
->b_rescale_ts
&& !in
->b_can_pace_control
&& in
->b_can_rate_control
);
2507 /* Set record capabilities */
2508 if( demux_Control( in
->p_demux
, DEMUX_CAN_RECORD
, &in
->b_can_stream_record
) )
2509 in
->b_can_stream_record
= false;
2511 if( !var_GetBool( p_input
, "input-record-native" ) )
2512 in
->b_can_stream_record
= false;
2513 var_SetBool( p_input
, "can-record", true );
2515 var_SetBool( p_input
, "can-record", in
->b_can_stream_record
);
2519 * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2520 if( !input_priv(p_input
)->b_preparsing
)
2522 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2523 &in
->title
, &in
->i_title
,
2524 &in
->i_title_offset
, &in
->i_seekpoint_offset
))
2526 TAB_INIT( in
->i_title
, in
->title
);
2530 in
->b_title_demux
= true;
2534 input_attachment_t
**attachment
;
2535 if( !demux_Control( in
->p_demux
, DEMUX_GET_ATTACHMENTS
,
2536 &attachment
, &i_attachment
) )
2538 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2539 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2540 i_attachment
, attachment
, in
->p_demux
);
2541 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2544 demux_Control( in
->p_demux
, DEMUX_GET_PTS_DELAY
, &in
->i_pts_delay
);
2545 if( in
->i_pts_delay
> INPUT_PTS_DELAY_MAX
)
2546 in
->i_pts_delay
= INPUT_PTS_DELAY_MAX
;
2547 else if( in
->i_pts_delay
< 0 )
2548 in
->i_pts_delay
= 0;
2551 if( demux_Control( in
->p_demux
, DEMUX_GET_FPS
, &in
->f_fps
) )
2554 if( var_GetInteger( p_input
, "clock-synchro" ) != -1 )
2555 in
->b_can_pace_control
= !var_GetInteger( p_input
, "clock-synchro" );
2560 /*****************************************************************************
2561 * InputSourceDestroy:
2562 *****************************************************************************/
2563 static void InputSourceDestroy( input_source_t
*in
)
2568 demux_Delete( in
->p_demux
);
2570 if( in
->i_title
> 0 )
2572 for( i
= 0; i
< in
->i_title
; i
++ )
2573 vlc_input_title_Delete( in
->title
[i
] );
2574 TAB_CLEAN( in
->i_title
, in
->title
);
2577 vlc_object_release( in
);
2580 /*****************************************************************************
2582 *****************************************************************************/
2583 static void InputSourceMeta( input_thread_t
*p_input
,
2584 input_source_t
*p_source
, vlc_meta_t
*p_meta
)
2586 demux_t
*p_demux
= p_source
->p_demux
;
2588 /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
2591 bool has_meta
= false;
2593 /* Read demux meta */
2594 if( !demux_Control( p_demux
, DEMUX_GET_META
, p_meta
) )
2597 bool has_unsupported
;
2598 if( demux_Control( p_demux
, DEMUX_HAS_UNSUPPORTED_META
, &has_unsupported
) )
2599 has_unsupported
= true;
2601 /* If the demux report unsupported meta data, or if we don't have meta data
2602 * try an external "meta reader" */
2603 if( has_meta
&& !has_unsupported
)
2606 demux_meta_t
*p_demux_meta
=
2607 vlc_custom_create( p_source
, sizeof( *p_demux_meta
), "demux meta" );
2608 if( unlikely(p_demux_meta
== NULL
) )
2610 p_demux_meta
->p_item
= input_priv(p_input
)->p_item
;
2612 module_t
*p_id3
= module_need( p_demux_meta
, "meta reader", NULL
, false );
2615 if( p_demux_meta
->p_meta
)
2617 vlc_meta_Merge( p_meta
, p_demux_meta
->p_meta
);
2618 vlc_meta_Delete( p_demux_meta
->p_meta
);
2621 if( p_demux_meta
->i_attachments
> 0 )
2623 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2624 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2625 p_demux_meta
->i_attachments
, p_demux_meta
->attachments
, p_demux
);
2626 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2628 module_unneed( p_demux
, p_id3
);
2630 vlc_object_release( p_demux_meta
);
2634 static void SlaveDemux( input_thread_t
*p_input
)
2639 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
2641 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2645 for( i
= 0; i
< input_priv(p_input
)->i_slave
; i
++ )
2647 input_source_t
*in
= input_priv(p_input
)->slave
[i
];
2653 /* Call demux_Demux until we have read enough data */
2654 if( demux_Control( in
->p_demux
, DEMUX_SET_NEXT_DEMUX_TIME
, i_time
) )
2659 if( demux_Control( in
->p_demux
, DEMUX_GET_TIME
, &i_stime
) )
2661 msg_Err( p_input
, "slave[%d] doesn't like "
2662 "DEMUX_GET_TIME -> EOF", i
);
2667 if( i_stime
>= i_time
)
2673 if( ( i_ret
= demux_Demux( in
->p_demux
) ) <= 0 )
2679 i_ret
= demux_Demux( in
->p_demux
);
2684 msg_Dbg( p_input
, "slave %d EOF", i
);
2690 static void SlaveSeek( input_thread_t
*p_input
)
2695 if( demux_Control( input_priv(p_input
)->master
->p_demux
, DEMUX_GET_TIME
, &i_time
) )
2697 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2701 for( i
= 0; i
< input_priv(p_input
)->i_slave
; i
++ )
2703 input_source_t
*in
= input_priv(p_input
)->slave
[i
];
2705 if( demux_Control( in
->p_demux
, DEMUX_SET_TIME
, i_time
, true ) )
2708 msg_Err( p_input
, "seek failed for slave %d -> EOF", i
);
2718 /*****************************************************************************
2720 *****************************************************************************/
2721 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2723 static const struct { int i_meta
; const char *psz_name
; } p_list
[] = {
2724 { vlc_meta_Title
, "meta-title" },
2725 { vlc_meta_Artist
, "meta-artist" },
2726 { vlc_meta_Genre
, "meta-genre" },
2727 { vlc_meta_Copyright
, "meta-copyright" },
2728 { vlc_meta_Description
, "meta-description" },
2729 { vlc_meta_Date
, "meta-date" },
2730 { vlc_meta_URL
, "meta-url" },
2734 /* Get meta information from user */
2735 for( int i
= 0; p_list
[i
].psz_name
; i
++ )
2737 char *psz_string
= var_GetNonEmptyString( p_input
, p_list
[i
].psz_name
);
2741 EnsureUTF8( psz_string
);
2742 vlc_meta_Set( p_meta
, p_list
[i
].i_meta
, psz_string
);
2747 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
2748 const demux_t
***ppp_attachment_demux
,
2749 int i_new
, input_attachment_t
**pp_new
, const demux_t
*p_demux
)
2751 int i_attachment
= *pi_attachment
;
2754 input_attachment_t
**pp_att
= realloc( *ppp_attachment
,
2755 sizeof(*pp_att
) * ( i_attachment
+ i_new
) );
2756 if( likely(pp_att
) )
2758 *ppp_attachment
= pp_att
;
2759 const demux_t
**pp_attdmx
= realloc( *ppp_attachment_demux
,
2760 sizeof(*pp_attdmx
) * ( i_attachment
+ i_new
) );
2761 if( likely(pp_attdmx
) )
2763 *ppp_attachment_demux
= pp_attdmx
;
2765 for( i
= 0; i
< i_new
; i
++ )
2767 pp_att
[i_attachment
] = pp_new
[i
];
2768 pp_attdmx
[i_attachment
++] = p_demux
;
2771 *pi_attachment
= i_attachment
;
2777 /* on alloc errors */
2778 for( i
= 0; i
< i_new
; i
++ )
2779 vlc_input_attachment_Delete( pp_new
[i
] );
2783 /*****************************************************************************
2784 * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2785 * arturl and locking issue.
2786 *****************************************************************************/
2787 static void InputUpdateMeta( input_thread_t
*p_input
, demux_t
*p_demux
)
2789 vlc_meta_t
*p_meta
= vlc_meta_New();
2790 if( unlikely(p_meta
== NULL
) )
2793 demux_Control( p_demux
, DEMUX_GET_META
, p_meta
);
2795 /* If metadata changed, then the attachments might have changed.
2796 We need to update them in case they contain album art. */
2797 input_attachment_t
**attachment
;
2800 if( !demux_Control( p_demux
, DEMUX_GET_ATTACHMENTS
,
2801 &attachment
, &i_attachment
) )
2803 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
2804 if( input_priv(p_input
)->i_attachment
> 0 )
2807 for( int i
= 0; i
< input_priv(p_input
)->i_attachment
; i
++ )
2809 if( input_priv(p_input
)->attachment_demux
[i
] == p_demux
)
2810 vlc_input_attachment_Delete( input_priv(p_input
)->attachment
[i
] );
2813 input_priv(p_input
)->attachment
[j
] = input_priv(p_input
)->attachment
[i
];
2814 input_priv(p_input
)->attachment_demux
[j
] = input_priv(p_input
)->attachment_demux
[i
];
2818 input_priv(p_input
)->i_attachment
= j
;
2820 AppendAttachment( &input_priv(p_input
)->i_attachment
, &input_priv(p_input
)->attachment
, &input_priv(p_input
)->attachment_demux
,
2821 i_attachment
, attachment
, p_demux
);
2822 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
2825 es_out_ControlSetMeta( input_priv(p_input
)->p_es_out
, p_meta
);
2826 vlc_meta_Delete( p_meta
);
2829 /*****************************************************************************
2830 * InputGetExtraFiles
2831 * Autodetect extra input list
2832 *****************************************************************************/
2833 static void InputGetExtraFilesPattern( input_thread_t
*p_input
,
2834 int *pi_list
, char ***pppsz_list
,
2835 const char *psz_path
,
2836 const char *psz_match
,
2837 const char *psz_format
,
2838 int i_start
, int i_stop
)
2843 TAB_INIT( i_list
, ppsz_list
);
2845 char *psz_base
= strdup( psz_path
);
2849 /* Remove the extension */
2850 char *psz_end
= &psz_base
[strlen(psz_base
)-strlen(psz_match
)];
2851 assert( psz_end
>= psz_base
);
2854 /* Try to list files */
2855 for( int i
= i_start
; i
<= i_stop
; i
++ )
2860 if( asprintf( &psz_file
, psz_format
, psz_base
, i
) < 0 )
2863 char *psz_tmp_path
= get_path( psz_file
);
2865 if( vlc_stat( psz_tmp_path
, &st
) || !S_ISREG( st
.st_mode
) || !st
.st_size
)
2868 free( psz_tmp_path
);
2872 msg_Dbg( p_input
, "Detected extra file `%s'", psz_file
);
2873 TAB_APPEND( i_list
, ppsz_list
, psz_file
);
2874 free( psz_tmp_path
);
2879 *pppsz_list
= ppsz_list
;
2882 static void InputGetExtraFiles( input_thread_t
*p_input
,
2883 int *pi_list
, char ***pppsz_list
,
2884 const char *psz_access
, const char *psz_path
)
2888 const char *psz_match
;
2889 const char *psz_format
;
2893 /* XXX the order is important */
2894 { ".001", "%s.%.3d", 2, 999 },
2895 { NULL
, NULL
, 0, 0 }
2898 TAB_INIT( *pi_list
, *pppsz_list
);
2900 if( ( psz_access
&& *psz_access
&& strcmp( psz_access
, "file" ) ) || !psz_path
)
2903 const size_t i_path
= strlen(psz_path
);
2905 for( int i
= 0; p_pattern
[i
].psz_match
!= NULL
; i
++ )
2907 const size_t i_ext
= strlen(p_pattern
[i
].psz_match
);
2909 if( i_path
< i_ext
)
2911 if( !strcmp( &psz_path
[i_path
-i_ext
], p_pattern
[i
].psz_match
) )
2913 InputGetExtraFilesPattern( p_input
, pi_list
, pppsz_list
,
2915 p_pattern
[i
].psz_match
, p_pattern
[i
].psz_format
,
2916 p_pattern
[i
].i_start
, p_pattern
[i
].i_stop
);
2923 static void input_ChangeState( input_thread_t
*p_input
, int i_state
)
2925 if( input_priv(p_input
)->i_state
== i_state
)
2928 input_priv(p_input
)->i_state
= i_state
;
2929 if( i_state
== ERROR_S
)
2930 input_item_SetErrorWhenReading( input_priv(p_input
)->p_item
, true );
2931 input_SendEventState( p_input
, i_state
);
2935 /*****************************************************************************
2936 * MRLSplit: parse the access, demux and url part of the
2937 * Media Resource Locator.
2938 *****************************************************************************/
2939 void input_SplitMRL( const char **access
, const char **demux
,
2940 const char **path
, const char **anchor
, char *buf
)
2944 /* Separate <path> from <access>[/<demux>]:// */
2945 p
= strstr( buf
, "://" );
2949 p
+= 3; /* skips "://" */
2952 /* Remove HTML anchor if present (not supported).
2953 * The hash symbol itself should be URI-encoded. */
2954 p
= strchr( p
, '#' );
2966 fprintf( stderr
, "%s(\"%s\") probably not a valid URI!\n", __func__
,
2969 /* Note: this is a valid non const pointer to "": */
2970 *path
= buf
+ strlen( buf
);
2973 /* Separate access from demux */
2974 p
= strchr( buf
, '/' );
2985 /* We really don't want module name substitution here! */
2992 static const char *MRLSeekPoint( const char *str
, int *title
, int *chapter
)
2997 /* Look for the title */
2998 u
= strtoul( str
, &end
, 0 );
2999 *title
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3002 /* Look for the chapter */
3006 u
= strtoul( str
, &end
, 0 );
3007 *chapter
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3017 /*****************************************************************************
3018 * MRLSections: parse title and seekpoint info from the Media Resource Locator.
3021 * [url][@[title_start][:chapter_start][-[title_end][:chapter_end]]]
3022 *****************************************************************************/
3023 static void MRLSections( const char *p
,
3024 int *pi_title_start
, int *pi_title_end
,
3025 int *pi_chapter_start
, int *pi_chapter_end
)
3027 *pi_title_start
= *pi_title_end
= *pi_chapter_start
= *pi_chapter_end
= -1;
3029 int title_start
, chapter_start
, title_end
, chapter_end
;
3035 p
= MRLSeekPoint( p
, &title_start
, &chapter_start
);
3037 title_start
= chapter_start
= -1;
3040 p
= MRLSeekPoint( p
+ 1, &title_end
, &chapter_end
);
3042 title_end
= chapter_end
= -1;
3044 if( *p
) /* syntax error */
3047 *pi_title_start
= title_start
;
3048 *pi_title_end
= title_end
;
3049 *pi_chapter_start
= chapter_start
;
3050 *pi_chapter_end
= chapter_end
;
3053 static int input_SlaveSourceAdd( input_thread_t
*p_input
,
3054 enum slave_type i_type
, const char *psz_uri
,
3059 const char *psz_forced_demux
;
3060 const bool b_can_fail
= i_flags
& SLAVE_ADD_CANFAIL
;
3061 const bool b_forced
= i_flags
& SLAVE_ADD_FORCED
;
3062 const bool b_set_time
= i_flags
& SLAVE_ADD_SET_TIME
;
3066 case SLAVE_TYPE_SPU
:
3068 psz_forced_demux
= "subtitle";
3070 case SLAVE_TYPE_AUDIO
:
3071 psz_es
= "audio-es";
3072 psz_forced_demux
= NULL
;
3075 vlc_assert_unreachable();
3079 var_Change( p_input
, psz_es
, VLC_VAR_CHOICESCOUNT
, &count
, NULL
);
3081 msg_Dbg( p_input
, "loading %s slave: %s (forced: %d)", psz_es
, psz_uri
,
3084 input_source_t
*p_source
= InputSourceNew( p_input
, psz_uri
,
3085 psz_forced_demux
, b_can_fail
);
3086 if( p_source
== NULL
)
3088 msg_Warn( p_input
, "failed to add %s as slave", psz_uri
);
3089 return VLC_EGENERIC
;
3092 if( i_type
== SLAVE_TYPE_AUDIO
)
3099 if( demux_Control( input_priv(p_input
)->master
->p_demux
,
3100 DEMUX_GET_TIME
, &i_time
) )
3102 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
3103 InputSourceDestroy( p_source
);
3104 return VLC_EGENERIC
;
3107 if( demux_Control( p_source
->p_demux
,
3108 DEMUX_SET_TIME
, i_time
, true ) )
3110 msg_Err( p_input
, "seek failed for new slave" );
3111 InputSourceDestroy( p_source
);
3112 return VLC_EGENERIC
;
3116 /* Get meta (access and demux) */
3117 InputUpdateMeta( p_input
, p_source
->p_demux
);
3120 TAB_APPEND( input_priv(p_input
)->i_slave
, input_priv(p_input
)->slave
, p_source
);
3128 if( var_Change( p_input
, psz_es
, VLC_VAR_GETCHOICES
, &list
, NULL
) )
3131 if( count
.i_int
== 0 )
3133 /* if it was first one, there is disable too */
3135 if( count
.i_int
< list
.p_list
->i_count
)
3137 const int i_id
= list
.p_list
->p_values
[count
.i_int
].i_int
;
3139 es_out_Control( input_priv(p_input
)->p_es_out_display
, ES_OUT_SET_ES_DEFAULT_BY_ID
, i_id
);
3140 es_out_Control( input_priv(p_input
)->p_es_out_display
, ES_OUT_SET_ES_BY_ID
, i_id
);
3142 var_FreeList( &list
, NULL
);
3147 static char *input_SubtitleFile2Uri( input_thread_t
*p_input
,
3148 const char *psz_subtitle
)
3150 /* if we are provided a subtitle.sub file,
3151 * see if we don't have a subtitle.idx and use it instead */
3152 char *psz_idxpath
= NULL
;
3153 char *psz_extension
= strrchr( psz_subtitle
, '.');
3154 if( psz_extension
&& strcmp( psz_extension
, ".sub" ) == 0 )
3156 psz_idxpath
= strdup( psz_subtitle
);
3161 psz_extension
= psz_extension
- psz_subtitle
+ psz_idxpath
;
3162 strcpy( psz_extension
, ".idx" );
3164 if( !vlc_stat( psz_idxpath
, &st
) && S_ISREG( st
.st_mode
) )
3166 msg_Dbg( p_input
, "using %s as subtitle file instead of %s",
3167 psz_idxpath
, psz_subtitle
);
3168 psz_subtitle
= psz_idxpath
;
3173 char *psz_uri
= vlc_path2uri( psz_subtitle
, NULL
);
3174 free( psz_idxpath
);
3178 /*****************************************************************************
3180 *****************************************************************************/
3181 void input_UpdateStatistic( input_thread_t
*p_input
,
3182 input_statistic_t i_type
, int i_delta
)
3184 assert( input_priv(p_input
)->i_state
!= INIT_S
);
3186 vlc_mutex_lock( &input_priv(p_input
)->counters
.counters_lock
);
3189 #define I(c) stats_Update( input_priv(p_input)->counters.c, i_delta, NULL )
3190 case INPUT_STATISTIC_DECODED_VIDEO
:
3193 case INPUT_STATISTIC_DECODED_AUDIO
:
3196 case INPUT_STATISTIC_DECODED_SUBTITLE
:
3199 case INPUT_STATISTIC_SENT_PACKET
:
3200 I(p_sout_sent_packets
);
3203 case INPUT_STATISTIC_SENT_BYTE
:
3207 stats_Update( input_priv(p_input
)->counters
.p_sout_sent_bytes
, i_delta
, &bytes
);
3208 stats_Update( input_priv(p_input
)->counters
.p_sout_send_bitrate
, bytes
, NULL
);
3212 msg_Err( p_input
, "Invalid statistic type %d (internal error)", i_type
);
3215 vlc_mutex_unlock( &input_priv(p_input
)->counters
.counters_lock
);
3219 /* TODO FIXME nearly the same logic that snapshot code */
3220 char *input_CreateFilename(input_thread_t
*input
, const char *dir
,
3221 const char *filenamefmt
, const char *ext
)
3224 char *filename
= str_format(input
, filenamefmt
);
3225 if (unlikely(filename
== NULL
))
3228 filename_sanitize(filename
);
3231 ? asprintf(&path
, "%s"DIR_SEP
"%s.%s", dir
, filename
, ext
)
3232 : asprintf(&path
, "%s"DIR_SEP
"%s", dir
, filename
)) < 0)