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"
50 #include "../stream_output/stream_output.h"
52 #include <vlc_dialog.h>
54 #include <vlc_charset.h>
56 #include <vlc_strings.h>
57 #include <vlc_modules.h>
58 #include <vlc_playlist.h> // FIXME
60 /*****************************************************************************
62 *****************************************************************************/
63 static void Destructor( input_thread_t
* p_input
);
65 static void *Run ( void * );
67 static input_thread_t
* Create ( vlc_object_t
*, input_item_t
*,
68 const char *, bool, input_resource_t
* );
69 static int Init ( input_thread_t
*p_input
);
70 static void End ( input_thread_t
*p_input
);
71 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
);
73 static inline int ControlPop( input_thread_t
*, int *, vlc_value_t
*, mtime_t i_deadline
, bool b_postpone_seek
);
74 static void ControlRelease( int i_type
, vlc_value_t val
);
75 static bool ControlIsSeekRequest( int i_type
);
76 static bool Control( input_thread_t
*, int, vlc_value_t
);
78 static int UpdateTitleSeekpointFromAccess( input_thread_t
* );
79 static void UpdateGenericFromAccess( input_thread_t
* );
81 static int UpdateTitleSeekpointFromDemux( input_thread_t
* );
82 static void UpdateGenericFromDemux( input_thread_t
* );
83 static void UpdateTitleListfromDemux( input_thread_t
* );
85 static void MRLSections( const char *, int *, int *, int *, int *);
87 static input_source_t
*InputSourceNew( input_thread_t
*);
88 static int InputSourceInit( input_thread_t
*, input_source_t
*,
89 const char *, const char *psz_forced_demux
,
91 static void InputSourceClean( input_source_t
* );
92 static void InputSourceMeta( input_thread_t
*, input_source_t
*, vlc_meta_t
* );
95 //static void InputGetAttachments( input_thread_t *, input_source_t * );
96 static void SlaveDemux( input_thread_t
*p_input
, bool *pb_demux_polled
);
97 static void SlaveSeek( input_thread_t
*p_input
);
99 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
100 static void InputUpdateMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
101 static void InputGetExtraFiles( input_thread_t
*p_input
,
102 int *pi_list
, char ***pppsz_list
,
103 const char *psz_access
, const char *psz_path
);
105 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
106 int i_new
, input_attachment_t
**pp_new
);
113 static void SubtitleAdd( input_thread_t
*p_input
, char *psz_subtitle
, unsigned i_flags
);
115 static void input_ChangeState( input_thread_t
*p_input
, int i_state
); /* TODO fix name */
119 * Create a new input_thread_t.
121 * You need to call input_Start on it when you are done
122 * adding callback on the variables/events you want to monitor.
124 * \param p_parent a vlc_object
125 * \param p_item an input item
126 * \param psz_log an optional prefix for this input logs
127 * \param p_resource an optional input ressource
128 * \return a pointer to the spawned input thread
130 input_thread_t
*input_Create( vlc_object_t
*p_parent
,
131 input_item_t
*p_item
,
132 const char *psz_log
, input_resource_t
*p_resource
)
134 return Create( p_parent
, p_item
, psz_log
, false, p_resource
);
137 #undef input_CreateAndStart
139 * Create a new input_thread_t and start it.
141 * Provided for convenience.
145 input_thread_t
*input_CreateAndStart( vlc_object_t
*p_parent
,
146 input_item_t
*p_item
, const char *psz_log
)
148 input_thread_t
*p_input
= input_Create( p_parent
, p_item
, psz_log
, NULL
);
150 if( input_Start( p_input
) )
152 vlc_object_release( p_input
);
160 * Initialize an input thread and run it until it stops by itself.
162 * \param p_parent a vlc_object
163 * \param p_item an input item
164 * \return an error code, VLC_SUCCESS on success
166 int input_Read( vlc_object_t
*p_parent
, input_item_t
*p_item
)
168 input_thread_t
*p_input
= Create( p_parent
, p_item
, NULL
, false, NULL
);
172 if( !Init( p_input
) )
174 MainLoop( p_input
, false );
178 vlc_object_release( p_input
);
183 * Initialize an input and initialize it to preparse the item
184 * This function is blocking. It will only accept parsing regular files.
186 * \param p_parent a vlc_object_t
187 * \param p_item an input item
188 * \return VLC_SUCCESS or an error
190 int input_Preparse( vlc_object_t
*p_parent
, input_item_t
*p_item
)
192 input_thread_t
*p_input
;
194 /* Allocate descriptor */
195 p_input
= Create( p_parent
, p_item
, NULL
, true, NULL
);
199 if( !Init( p_input
) )
202 vlc_object_release( p_input
);
208 * Start a input_thread_t created by input_Create.
210 * You must not start an already running input_thread_t.
212 * \param the input thread to start
214 int input_Start( input_thread_t
*p_input
)
216 /* Create thread and wait for its readiness. */
217 p_input
->p
->is_running
= !vlc_clone( &p_input
->p
->thread
,
218 Run
, p_input
, VLC_THREAD_PRIORITY_INPUT
);
219 if( !p_input
->p
->is_running
)
221 input_ChangeState( p_input
, ERROR_S
);
222 msg_Err( p_input
, "cannot create input thread" );
229 * Request a running input thread to stop and die
231 * b_abort must be true when a user stop is requested and not because you have
232 * detected an error or an eof. It will be used to properly send the
233 * INPUT_EVENT_ABORT event.
235 * \param p_input the input thread to stop
236 * \param b_abort true if the input has been aborted by a user request
238 void input_Stop( input_thread_t
*p_input
, bool b_abort
)
240 /* Set die for input and ALL of this childrens (even (grand-)grand-childrens)
241 * It is needed here even if it is done in INPUT_CONTROL_SET_DIE handler to
242 * unlock the control loop */
243 ObjectKillChildrens( VLC_OBJECT(p_input
) );
245 vlc_mutex_lock( &p_input
->p
->lock_control
);
246 p_input
->p
->b_abort
|= b_abort
;
247 vlc_mutex_unlock( &p_input
->p
->lock_control
);
249 input_ControlPush( p_input
, INPUT_CONTROL_SET_DIE
, NULL
);
252 void input_Join( input_thread_t
*p_input
)
254 if( p_input
->p
->is_running
)
255 vlc_join( p_input
->p
->thread
, NULL
);
258 void input_Release( input_thread_t
*p_input
)
260 vlc_object_release( p_input
);
266 * It does not call input_Stop itself.
268 void input_Close( input_thread_t
*p_input
)
270 input_Join( p_input
);
271 input_Release( p_input
);
275 * Get the item from an input thread
276 * FIXME it does not increase ref count of the item.
277 * if it is used after p_input is destroyed nothing prevent it from
280 input_item_t
*input_GetItem( input_thread_t
*p_input
)
282 assert( p_input
&& p_input
->p
);
283 return p_input
->p
->p_item
;
286 /*****************************************************************************
287 * This function creates a new input, and returns a pointer
288 * to its description. On error, it returns NULL.
290 * XXX Do not forget to update vlc_input.h if you add new variables.
291 *****************************************************************************/
292 static input_thread_t
*Create( vlc_object_t
*p_parent
, input_item_t
*p_item
,
293 const char *psz_header
, bool b_quick
,
294 input_resource_t
*p_resource
)
296 input_thread_t
*p_input
= NULL
; /* thread descriptor */
299 /* Allocate descriptor */
300 p_input
= vlc_custom_create( p_parent
, sizeof( *p_input
), "input" );
301 if( p_input
== NULL
)
304 /* Construct a nice name for the input timer */
305 char psz_timer_name
[255];
306 char * psz_name
= input_item_GetName( p_item
);
307 snprintf( psz_timer_name
, sizeof(psz_timer_name
),
308 "input launching for '%s'", psz_name
);
310 msg_Dbg( p_input
, "Creating an input for '%s'", psz_name
);
314 p_input
->p
= calloc( 1, sizeof( input_thread_private_t
) );
318 /* Parse input options */
319 vlc_mutex_lock( &p_item
->lock
);
320 assert( (int)p_item
->optflagc
== p_item
->i_options
);
321 for( i
= 0; i
< p_item
->i_options
; i
++ )
322 var_OptionParse( VLC_OBJECT(p_input
), p_item
->ppsz_options
[i
],
323 !!(p_item
->optflagv
[i
] & VLC_INPUT_OPTION_TRUSTED
) );
324 vlc_mutex_unlock( &p_item
->lock
);
326 p_input
->b_preparsing
= b_quick
;
327 p_input
->psz_header
= psz_header
? strdup( psz_header
) : NULL
;
329 /* Init Common fields */
330 p_input
->b_eof
= false;
331 p_input
->p
->b_can_pace_control
= true;
332 p_input
->p
->i_start
= 0;
333 p_input
->p
->i_time
= 0;
334 p_input
->p
->i_stop
= 0;
335 p_input
->p
->i_run
= 0;
336 p_input
->p
->i_title
= 0;
337 p_input
->p
->title
= NULL
;
338 p_input
->p
->i_title_offset
= p_input
->p
->i_seekpoint_offset
= 0;
339 p_input
->p
->i_state
= INIT_S
;
340 p_input
->p
->i_rate
= INPUT_RATE_DEFAULT
;
341 p_input
->p
->b_recording
= false;
342 memset( &p_input
->p
->bookmark
, 0, sizeof(p_input
->p
->bookmark
) );
343 TAB_INIT( p_input
->p
->i_bookmark
, p_input
->p
->pp_bookmark
);
344 TAB_INIT( p_input
->p
->i_attachment
, p_input
->p
->attachment
);
345 p_input
->p
->p_sout
= NULL
;
346 p_input
->p
->b_out_pace_control
= false;
348 vlc_gc_incref( p_item
); /* Released in Destructor() */
349 p_input
->p
->p_item
= p_item
;
351 /* Init Input fields */
352 p_input
->p
->input
.p_access
= NULL
;
353 p_input
->p
->input
.p_stream
= NULL
;
354 p_input
->p
->input
.p_demux
= NULL
;
355 p_input
->p
->input
.b_title_demux
= false;
356 p_input
->p
->input
.i_title
= 0;
357 p_input
->p
->input
.title
= NULL
;
358 p_input
->p
->input
.i_title_offset
= p_input
->p
->input
.i_seekpoint_offset
= 0;
359 p_input
->p
->input
.b_can_pace_control
= true;
360 p_input
->p
->input
.b_can_rate_control
= true;
361 p_input
->p
->input
.b_rescale_ts
= true;
362 p_input
->p
->input
.b_eof
= false;
364 vlc_mutex_lock( &p_item
->lock
);
366 if( !p_item
->p_stats
)
367 p_item
->p_stats
= stats_NewInputStats( p_input
);
368 vlc_mutex_unlock( &p_item
->lock
);
371 p_input
->p
->i_slave
= 0;
372 p_input
->p
->slave
= NULL
;
377 p_input
->p
->p_resource_private
= NULL
;
378 p_input
->p
->p_resource
= input_resource_Hold( p_resource
);
382 p_input
->p
->p_resource_private
= input_resource_New( VLC_OBJECT( p_input
) );
383 p_input
->p
->p_resource
= input_resource_Hold( p_input
->p
->p_resource_private
);
385 input_resource_SetInput( p_input
->p
->p_resource
, p_input
);
387 /* Init control buffer */
388 vlc_mutex_init( &p_input
->p
->lock_control
);
389 vlc_cond_init( &p_input
->p
->wait_control
);
390 p_input
->p
->i_control
= 0;
391 p_input
->p
->b_abort
= false;
392 p_input
->p
->is_running
= false;
394 /* Create Object Variables for private use only */
395 input_ConfigVarInit( p_input
);
397 /* Create Objects variables for public Get and Set */
398 input_ControlVarInit( p_input
);
401 if( !p_input
->b_preparsing
)
403 char *psz_bookmarks
= var_GetNonEmptyString( p_input
, "bookmarks" );
406 /* FIXME: have a common cfg parsing routine used by sout and others */
407 char *psz_parser
, *psz_start
, *psz_end
;
408 psz_parser
= psz_bookmarks
;
409 while( (psz_start
= strchr( psz_parser
, '{' ) ) )
411 seekpoint_t
*p_seekpoint
;
414 psz_end
= strchr( psz_start
, '}' );
415 if( !psz_end
) break;
416 psz_parser
= psz_end
+ 1;
417 backup
= *psz_parser
;
421 p_seekpoint
= vlc_seekpoint_New();
422 while( (psz_end
= strchr( psz_start
, ',' ) ) )
425 if( !strncmp( psz_start
, "name=", 5 ) )
427 p_seekpoint
->psz_name
= strdup(psz_start
+ 5);
429 else if( !strncmp( psz_start
, "bytes=", 6 ) )
431 p_seekpoint
->i_byte_offset
= atoll(psz_start
+ 6);
433 else if( !strncmp( psz_start
, "time=", 5 ) )
435 p_seekpoint
->i_time_offset
= atoll(psz_start
+ 5) *
438 psz_start
= psz_end
+ 1;
440 msg_Dbg( p_input
, "adding bookmark: %s, bytes=%"PRId64
", time=%"PRId64
,
441 p_seekpoint
->psz_name
, p_seekpoint
->i_byte_offset
,
442 p_seekpoint
->i_time_offset
);
443 input_Control( p_input
, INPUT_ADD_BOOKMARK
, p_seekpoint
);
444 vlc_seekpoint_Delete( p_seekpoint
);
445 *psz_parser
= backup
;
447 free( psz_bookmarks
);
451 /* Remove 'Now playing' info as it is probably outdated */
452 input_item_SetNowPlaying( p_item
, NULL
);
453 input_SendEventMeta( p_input
);
456 if( p_input
->b_preparsing
)
457 p_input
->i_flags
|= OBJECT_FLAGS_QUIET
| OBJECT_FLAGS_NOINTERACT
;
459 /* Make sure the interaction option is honored */
460 if( !var_InheritBool( p_input
, "interact" ) )
461 p_input
->i_flags
|= OBJECT_FLAGS_NOINTERACT
;
464 memset( &p_input
->p
->counters
, 0, sizeof( p_input
->p
->counters
) );
465 vlc_mutex_init( &p_input
->p
->counters
.counters_lock
);
467 p_input
->p
->p_es_out_display
= input_EsOutNew( p_input
, p_input
->p
->i_rate
);
468 p_input
->p
->p_es_out
= NULL
;
470 /* Set the destructor when we are sure we are initialized */
471 vlc_object_set_destructor( p_input
, (vlc_destructor_t
)Destructor
);
477 * Input destructor (called when the object's refcount reaches 0).
479 static void Destructor( input_thread_t
* p_input
)
482 char * psz_name
= input_item_GetName( p_input
->p
->p_item
);
483 msg_Dbg( p_input
, "Destroying the input for '%s'", psz_name
);
487 if( p_input
->p
->p_es_out_display
)
488 es_out_Delete( p_input
->p
->p_es_out_display
);
490 if( p_input
->p
->p_resource
)
491 input_resource_Release( p_input
->p
->p_resource
);
492 if( p_input
->p
->p_resource_private
)
493 input_resource_Release( p_input
->p
->p_resource_private
);
495 vlc_gc_decref( p_input
->p
->p_item
);
497 vlc_mutex_destroy( &p_input
->p
->counters
.counters_lock
);
499 for( int i
= 0; i
< p_input
->p
->i_control
; i
++ )
501 input_control_t
*p_ctrl
= &p_input
->p
->control
[i
];
502 ControlRelease( p_ctrl
->i_type
, p_ctrl
->val
);
505 vlc_cond_destroy( &p_input
->p
->wait_control
);
506 vlc_mutex_destroy( &p_input
->p
->lock_control
);
510 /*****************************************************************************
511 * Run: main thread loop
512 * This is the "normal" thread that spawns the input processing chain,
513 * reads the stream, cleans up and waits
514 *****************************************************************************/
515 static void *Run( void *obj
)
517 input_thread_t
*p_input
= (input_thread_t
*)obj
;
518 const int canc
= vlc_savecancel();
520 if( Init( p_input
) )
523 MainLoop( p_input
, true ); /* FIXME it can be wrong (like with VLM) */
529 /* Tell we're dead */
530 vlc_mutex_lock( &p_input
->p
->lock_control
);
531 const bool b_abort
= p_input
->p
->b_abort
;
532 vlc_mutex_unlock( &p_input
->p
->lock_control
);
535 input_SendEventAbort( p_input
);
536 input_SendEventDead( p_input
);
538 vlc_restorecancel( canc
);
542 /*****************************************************************************
543 * Main loop: Fill buffers from access, and demux
544 *****************************************************************************/
548 * It asks the demuxer to demux some data
550 static void MainLoopDemux( input_thread_t
*p_input
, bool *pb_changed
, bool *pb_demux_polled
, mtime_t i_start_mdate
)
555 *pb_demux_polled
= p_input
->p
->input
.p_demux
->pf_demux
!= NULL
;
557 if( ( p_input
->p
->i_stop
> 0 && p_input
->p
->i_time
>= p_input
->p
->i_stop
) ||
558 ( p_input
->p
->i_run
> 0 && i_start_mdate
+p_input
->p
->i_run
< mdate() ) )
561 i_ret
= demux_Demux( p_input
->p
->input
.p_demux
);
565 if( p_input
->p
->input
.p_demux
->info
.i_update
)
567 if( p_input
->p
->input
.p_demux
->info
.i_update
& INPUT_UPDATE_TITLE_LIST
)
569 UpdateTitleListfromDemux( p_input
);
570 p_input
->p
->input
.p_demux
->info
.i_update
&= ~INPUT_UPDATE_TITLE_LIST
;
572 if( p_input
->p
->input
.b_title_demux
)
574 i_ret
= UpdateTitleSeekpointFromDemux( p_input
);
577 UpdateGenericFromDemux( p_input
);
579 else if( p_input
->p
->input
.p_access
&&
580 p_input
->p
->input
.p_access
->info
.i_update
)
582 if( !p_input
->p
->input
.b_title_demux
)
584 i_ret
= UpdateTitleSeekpointFromAccess( p_input
);
587 UpdateGenericFromAccess( p_input
);
591 if( i_ret
== 0 ) /* EOF */
593 msg_Dbg( p_input
, "EOF reached" );
594 p_input
->p
->input
.b_eof
= true;
595 es_out_Eos(p_input
->p
->p_es_out
);
599 input_ChangeState( p_input
, ERROR_S
);
602 if( i_ret
> 0 && p_input
->p
->i_slave
> 0 )
605 SlaveDemux( p_input
, &b_demux_polled
);
607 *pb_demux_polled
|= b_demux_polled
;
611 static int MainLoopTryRepeat( input_thread_t
*p_input
, mtime_t
*pi_start_mdate
)
613 int i_repeat
= var_GetInteger( p_input
, "input-repeat" );
619 msg_Dbg( p_input
, "repeating the same input (%d)", i_repeat
);
623 var_SetInteger( p_input
, "input-repeat", i_repeat
);
626 /* Seek to start title/seekpoint */
627 val
.i_int
= p_input
->p
->input
.i_title_start
-
628 p_input
->p
->input
.i_title_offset
;
629 if( val
.i_int
< 0 || val
.i_int
>= p_input
->p
->input
.i_title
)
631 input_ControlPush( p_input
,
632 INPUT_CONTROL_SET_TITLE
, &val
);
634 val
.i_int
= p_input
->p
->input
.i_seekpoint_start
-
635 p_input
->p
->input
.i_seekpoint_offset
;
636 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
637 input_ControlPush( p_input
,
638 INPUT_CONTROL_SET_SEEKPOINT
, &val
);
640 /* Seek to start position */
641 if( p_input
->p
->i_start
> 0 )
643 val
.i_time
= p_input
->p
->i_start
;
644 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &val
);
649 input_ControlPush( p_input
, INPUT_CONTROL_SET_POSITION
, &val
);
653 *pi_start_mdate
= mdate();
659 * It update the variables used by the interfaces
661 static void MainLoopInterface( input_thread_t
*p_input
)
663 double f_position
= 0.0;
665 mtime_t i_length
= 0;
667 /* update input status variables */
668 if( demux_Control( p_input
->p
->input
.p_demux
,
669 DEMUX_GET_POSITION
, &f_position
) )
672 if( demux_Control( p_input
->p
->input
.p_demux
,
673 DEMUX_GET_TIME
, &i_time
) )
675 p_input
->p
->i_time
= i_time
;
677 if( demux_Control( p_input
->p
->input
.p_demux
,
678 DEMUX_GET_LENGTH
, &i_length
) )
681 es_out_SetTimes( p_input
->p
->p_es_out
, f_position
, i_time
, i_length
);
683 /* update current bookmark */
684 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
685 p_input
->p
->bookmark
.i_time_offset
= i_time
;
686 if( p_input
->p
->input
.p_stream
)
687 p_input
->p
->bookmark
.i_byte_offset
= stream_Tell( p_input
->p
->input
.p_stream
);
688 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
693 * It updates the globals statics
695 static void MainLoopStatistic( input_thread_t
*p_input
)
697 stats_ComputeInputStats( p_input
, p_input
->p
->p_item
->p_stats
);
698 input_SendEventStatistics( p_input
);
703 * The main input loop.
705 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
)
707 mtime_t i_start_mdate
= mdate();
708 mtime_t i_intf_update
= 0;
709 mtime_t i_statistic_update
= 0;
710 mtime_t i_last_seek_mdate
= 0;
711 bool b_pause_after_eof
= b_interactive
&&
712 var_CreateGetBool( p_input
, "play-and-pause" );
714 while( vlc_object_alive( p_input
) && !p_input
->b_error
)
724 b_force_update
= false;
726 /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
727 * is paused -> this may cause problem with some of them
728 * The same problem can be seen when seeking while paused */
729 b_paused
= p_input
->p
->i_state
== PAUSE_S
&&
730 ( !es_out_GetBuffering( p_input
->p
->p_es_out
) || p_input
->p
->input
.b_eof
);
732 b_demux_polled
= true;
735 if( !p_input
->p
->input
.b_eof
)
737 MainLoopDemux( p_input
, &b_force_update
, &b_demux_polled
, i_start_mdate
);
739 i_wakeup
= es_out_GetWakeup( p_input
->p
->p_es_out
);
741 else if( !es_out_GetEmpty( p_input
->p
->p_es_out
) )
743 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
744 i_wakeup
= mdate() + INPUT_IDLE_SLEEP
;
746 /* Pause after eof only if the input is pausable.
747 * This way we won't trigger timeshifting for nothing */
748 else if( b_pause_after_eof
&& p_input
->p
->b_can_pause
)
750 msg_Dbg( p_input
, "pausing at EOF (pause after each)");
752 Control( p_input
, INPUT_CONTROL_SET_STATE
, val
);
758 if( MainLoopTryRepeat( p_input
, &i_start_mdate
) )
760 b_pause_after_eof
= var_GetBool( p_input
, "play-and-pause" );
766 mtime_t i_deadline
= i_wakeup
;
767 if( b_paused
|| !b_demux_polled
)
768 i_deadline
= __MIN( i_intf_update
, i_statistic_update
);
773 mtime_t i_limit
= i_deadline
;
775 /* We will postpone the execution of a seek until we have
776 * finished the ES bufferisation (postpone is limited to
778 bool b_buffering
= es_out_GetBuffering( p_input
->p
->p_es_out
) &&
779 !p_input
->p
->input
.b_eof
;
782 /* When postpone is in order, check the ES level every 20ms */
783 mtime_t i_current
= mdate();
784 if( i_last_seek_mdate
+ INT64_C(125000) >= i_current
)
785 i_limit
= __MIN( i_deadline
, i_current
+ INT64_C(20000) );
789 if( ControlPop( p_input
, &i_type
, &val
, i_limit
, b_buffering
) )
791 if( b_buffering
&& i_limit
< i_deadline
)
797 msg_Dbg( p_input
, "control type=%d", i_type
);
800 if( Control( p_input
, i_type
, val
) )
802 if( ControlIsSeekRequest( i_type
) )
803 i_last_seek_mdate
= mdate();
804 b_force_update
= true;
808 /* Update interface and statistics */
810 if( i_intf_update
< i_current
|| b_force_update
)
812 MainLoopInterface( p_input
);
813 i_intf_update
= i_current
+ INT64_C(250000);
814 b_force_update
= false;
816 if( i_statistic_update
< i_current
)
818 MainLoopStatistic( p_input
);
819 i_statistic_update
= i_current
+ INT64_C(1000000);
822 /* Update the wakeup time */
824 i_wakeup
= es_out_GetWakeup( p_input
->p
->p_es_out
);
825 } while( i_current
< i_wakeup
);
828 if( !p_input
->b_error
)
829 input_ChangeState( p_input
, END_S
);
832 static void InitStatistics( input_thread_t
* p_input
)
834 if( p_input
->b_preparsing
) return;
836 /* Prepare statistics */
837 #define INIT_COUNTER( c, compute ) p_input->p->counters.p_##c = \
838 stats_CounterCreate( STATS_##compute);
839 if( libvlc_stats( p_input
) )
841 INIT_COUNTER( read_bytes
, COUNTER
);
842 INIT_COUNTER( read_packets
, COUNTER
);
843 INIT_COUNTER( demux_read
, COUNTER
);
844 INIT_COUNTER( input_bitrate
, DERIVATIVE
);
845 INIT_COUNTER( demux_bitrate
, DERIVATIVE
);
846 INIT_COUNTER( demux_corrupted
, COUNTER
);
847 INIT_COUNTER( demux_discontinuity
, COUNTER
);
848 INIT_COUNTER( played_abuffers
, COUNTER
);
849 INIT_COUNTER( lost_abuffers
, COUNTER
);
850 INIT_COUNTER( displayed_pictures
, COUNTER
);
851 INIT_COUNTER( lost_pictures
, COUNTER
);
852 INIT_COUNTER( decoded_audio
, COUNTER
);
853 INIT_COUNTER( decoded_video
, COUNTER
);
854 INIT_COUNTER( decoded_sub
, COUNTER
);
855 p_input
->p
->counters
.p_sout_send_bitrate
= NULL
;
856 p_input
->p
->counters
.p_sout_sent_packets
= NULL
;
857 p_input
->p
->counters
.p_sout_sent_bytes
= NULL
;
862 static int InitSout( input_thread_t
* p_input
)
864 if( p_input
->b_preparsing
)
867 /* Find a usable sout and attach it to p_input */
868 char *psz
= var_GetNonEmptyString( p_input
, "sout" );
869 if( psz
&& strncasecmp( p_input
->p
->p_item
->psz_uri
, "vlc:", 4 ) )
871 p_input
->p
->p_sout
= input_resource_RequestSout( p_input
->p
->p_resource
, NULL
, psz
);
872 if( !p_input
->p
->p_sout
)
874 input_ChangeState( p_input
, ERROR_S
);
875 msg_Err( p_input
, "cannot start stream output instance, " \
880 if( libvlc_stats( p_input
) )
882 INIT_COUNTER( sout_sent_packets
, COUNTER
);
883 INIT_COUNTER( sout_sent_bytes
, COUNTER
);
884 INIT_COUNTER( sout_send_bitrate
, DERIVATIVE
);
889 input_resource_RequestSout( p_input
->p
->p_resource
, NULL
, NULL
);
897 static void InitTitle( input_thread_t
* p_input
)
899 input_source_t
*p_master
= &p_input
->p
->input
;
901 if( p_input
->b_preparsing
)
904 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
905 /* Create global title (from master) */
906 p_input
->p
->i_title
= p_master
->i_title
;
907 p_input
->p
->title
= p_master
->title
;
908 p_input
->p
->i_title_offset
= p_master
->i_title_offset
;
909 p_input
->p
->i_seekpoint_offset
= p_master
->i_seekpoint_offset
;
910 if( p_input
->p
->i_title
> 0 )
912 /* Setup variables */
913 input_ControlVarNavigation( p_input
);
914 input_SendEventTitle( p_input
, 0 );
918 p_input
->p
->b_can_pace_control
= p_master
->b_can_pace_control
;
919 p_input
->p
->b_can_pause
= p_master
->b_can_pause
;
920 p_input
->p
->b_can_rate_control
= p_master
->b_can_rate_control
;
921 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
924 static void StartTitle( input_thread_t
* p_input
)
928 /* Start title/chapter */
929 val
.i_int
= p_input
->p
->input
.i_title_start
-
930 p_input
->p
->input
.i_title_offset
;
931 if( val
.i_int
> 0 && val
.i_int
< p_input
->p
->input
.i_title
)
932 input_ControlPush( p_input
, INPUT_CONTROL_SET_TITLE
, &val
);
934 val
.i_int
= p_input
->p
->input
.i_seekpoint_start
-
935 p_input
->p
->input
.i_seekpoint_offset
;
936 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
937 input_ControlPush( p_input
, INPUT_CONTROL_SET_SEEKPOINT
, &val
);
939 /* Start/stop/run time */
940 p_input
->p
->i_start
= (int64_t)(1000000.0
941 * var_GetFloat( p_input
, "start-time" ));
942 p_input
->p
->i_stop
= (int64_t)(1000000.0
943 * var_GetFloat( p_input
, "stop-time" ));
944 p_input
->p
->i_run
= (int64_t)(1000000.0
945 * var_GetFloat( p_input
, "run-time" ));
946 if( p_input
->p
->i_run
< 0 )
948 msg_Warn( p_input
, "invalid run-time ignored" );
949 p_input
->p
->i_run
= 0;
952 if( p_input
->p
->i_start
> 0 )
956 msg_Dbg( p_input
, "starting at time: %ds",
957 (int)( p_input
->p
->i_start
/ INT64_C(1000000) ) );
959 s
.i_time
= p_input
->p
->i_start
;
960 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &s
);
962 if( p_input
->p
->i_stop
> 0 && p_input
->p
->i_stop
<= p_input
->p
->i_start
)
964 msg_Warn( p_input
, "invalid stop-time ignored" );
965 p_input
->p
->i_stop
= 0;
967 p_input
->p
->b_fast_seek
= var_GetBool( p_input
, "input-fast-seek" );
970 static void LoadSubtitles( input_thread_t
*p_input
)
973 /* Get fps and set it if not already set */
974 const double f_fps
= p_input
->p
->f_fps
;
977 float f_requested_fps
;
979 var_Create( p_input
, "sub-original-fps", VLC_VAR_FLOAT
);
980 var_SetFloat( p_input
, "sub-original-fps", f_fps
);
982 f_requested_fps
= var_CreateGetFloat( p_input
, "sub-fps" );
983 if( f_requested_fps
!= f_fps
)
985 var_Create( p_input
, "sub-fps", VLC_VAR_FLOAT
|
987 var_SetFloat( p_input
, "sub-fps", f_requested_fps
);
991 const int i_delay
= var_CreateGetInteger( p_input
, "sub-delay" );
993 var_SetTime( p_input
, "spu-delay", (mtime_t
)i_delay
* 100000 );
995 /* Look for and add subtitle files */
996 unsigned i_flags
= SUB_FORCED
;
998 char *psz_subtitle
= var_GetNonEmptyString( p_input
, "sub-file" );
999 if( psz_subtitle
!= NULL
)
1001 msg_Dbg( p_input
, "forced subtitle: %s", psz_subtitle
);
1002 SubtitleAdd( p_input
, psz_subtitle
, i_flags
);
1003 i_flags
= SUB_NOFLAG
;
1006 if( var_GetBool( p_input
, "sub-autodetect-file" ) )
1008 char *psz_autopath
= var_GetNonEmptyString( p_input
, "sub-autodetect-path" );
1009 char **ppsz_subs
= subtitles_Detect( p_input
, psz_autopath
,
1010 p_input
->p
->p_item
->psz_uri
);
1011 free( psz_autopath
);
1013 for( int i
= 0; ppsz_subs
&& ppsz_subs
[i
]; i
++ )
1015 if( !psz_subtitle
|| strcmp( psz_subtitle
, ppsz_subs
[i
] ) )
1017 i_flags
|= SUB_CANFAIL
;
1018 SubtitleAdd( p_input
, ppsz_subs
[i
], i_flags
);
1019 i_flags
= SUB_NOFLAG
;
1022 free( ppsz_subs
[i
] );
1026 free( psz_subtitle
);
1028 /* Load subtitles from attachments */
1029 int i_attachment
= 0;
1030 input_attachment_t
**pp_attachment
= NULL
;
1032 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1033 for( int i
= 0; i
< p_input
->p
->i_attachment
; i
++ )
1035 const input_attachment_t
*a
= p_input
->p
->attachment
[i
];
1036 if( !strcmp( a
->psz_mime
, "application/x-srt" ) )
1037 TAB_APPEND( i_attachment
, pp_attachment
,
1038 vlc_input_attachment_New( a
->psz_name
, NULL
,
1039 a
->psz_description
, NULL
, 0 ) );
1041 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1043 if( i_attachment
> 0 )
1044 var_Create( p_input
, "sub-description", VLC_VAR_STRING
);
1045 for( int i
= 0; i
< i_attachment
; i
++ )
1047 input_attachment_t
*a
= pp_attachment
[i
];
1051 if( a
->psz_name
[i
] &&
1052 asprintf( &psz_mrl
, "attachment://%s", a
->psz_name
) >= 0 )
1054 var_SetString( p_input
, "sub-description", a
->psz_description
? a
->psz_description
: "");
1056 SubtitleAdd( p_input
, psz_mrl
, i_flags
);
1058 i_flags
= SUB_NOFLAG
;
1061 vlc_input_attachment_Delete( a
);
1063 free( pp_attachment
);
1064 if( i_attachment
> 0 )
1065 var_Destroy( p_input
, "sub-description" );
1068 static void LoadSlaves( input_thread_t
*p_input
)
1070 char *psz
= var_GetNonEmptyString( p_input
, "input-slave" );
1074 char *psz_org
= psz
;
1075 while( psz
&& *psz
)
1077 while( *psz
== ' ' || *psz
== '#' )
1080 char *psz_delim
= strchr( psz
, '#' );
1082 *psz_delim
++ = '\0';
1087 char *uri
= strstr(psz
, "://")
1088 ? strdup( psz
) : vlc_path2uri( psz
, NULL
);
1092 msg_Dbg( p_input
, "adding slave input '%s'", uri
);
1094 input_source_t
*p_slave
= InputSourceNew( p_input
);
1095 if( p_slave
&& !InputSourceInit( p_input
, p_slave
, uri
, NULL
, false ) )
1096 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, p_slave
);
1104 static void UpdatePtsDelay( input_thread_t
*p_input
)
1106 input_thread_private_t
*p_sys
= p_input
->p
;
1108 /* Get max pts delay from input source */
1109 mtime_t i_pts_delay
= p_sys
->input
.i_pts_delay
;
1110 for( int i
= 0; i
< p_sys
->i_slave
; i
++ )
1111 i_pts_delay
= __MAX( i_pts_delay
, p_sys
->slave
[i
]->i_pts_delay
);
1113 if( i_pts_delay
< 0 )
1116 /* Take care of audio/spu delay */
1117 const mtime_t i_audio_delay
= var_GetTime( p_input
, "audio-delay" );
1118 const mtime_t i_spu_delay
= var_GetTime( p_input
, "spu-delay" );
1119 const mtime_t i_extra_delay
= __MIN( i_audio_delay
, i_spu_delay
);
1120 if( i_extra_delay
< 0 )
1121 i_pts_delay
-= i_extra_delay
;
1123 /* Update cr_average depending on the caching */
1124 const int i_cr_average
= var_GetInteger( p_input
, "cr-average" ) * i_pts_delay
/ DEFAULT_PTS_DELAY
;
1127 es_out_SetDelay( p_input
->p
->p_es_out_display
, AUDIO_ES
, i_audio_delay
);
1128 es_out_SetDelay( p_input
->p
->p_es_out_display
, SPU_ES
, i_spu_delay
);
1129 es_out_SetJitter( p_input
->p
->p_es_out
, i_pts_delay
, 0, i_cr_average
);
1132 static void InitPrograms( input_thread_t
* p_input
)
1137 /* Compute correct pts_delay */
1138 UpdatePtsDelay( p_input
);
1141 i_es_out_mode
= ES_OUT_MODE_AUTO
;
1142 if( p_input
->p
->p_sout
)
1146 if( var_GetBool( p_input
, "sout-all" ) )
1148 i_es_out_mode
= ES_OUT_MODE_ALL
;
1151 if( (prgms
= var_GetNonEmptyString( p_input
, "programs" )) != NULL
)
1155 TAB_INIT( list
.i_count
, list
.p_values
);
1156 for( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1158 prgm
= strtok_r( NULL
, ",", &buf
) )
1160 vlc_value_t val
= { .i_int
= atoi( prgm
) };
1161 INSERT_ELEM( list
.p_values
, list
.i_count
, list
.i_count
, val
);
1164 if( list
.i_count
> 0 )
1165 i_es_out_mode
= ES_OUT_MODE_PARTIAL
;
1166 /* Note : we should remove the "program" callback. */
1171 es_out_SetMode( p_input
->p
->p_es_out
, i_es_out_mode
);
1173 /* Inform the demuxer about waited group (needed only for DVB) */
1174 if( i_es_out_mode
== ES_OUT_MODE_ALL
)
1176 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, -1, NULL
);
1178 else if( i_es_out_mode
== ES_OUT_MODE_PARTIAL
)
1180 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, -1,
1182 TAB_CLEAN( list
.i_count
, list
.p_values
);
1186 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
,
1187 es_out_GetGroupForced( p_input
->p
->p_es_out
), NULL
);
1191 static int Init( input_thread_t
* p_input
)
1196 for( i
= 0; i
< p_input
->p
->p_item
->i_options
; i
++ )
1198 if( !strncmp( p_input
->p
->p_item
->ppsz_options
[i
], "meta-file", 9 ) )
1200 msg_Dbg( p_input
, "Input is a meta file: disabling unneeded options" );
1201 var_SetString( p_input
, "sout", "" );
1202 var_SetBool( p_input
, "sout-all", false );
1203 var_SetString( p_input
, "input-slave", "" );
1204 var_SetInteger( p_input
, "input-repeat", 0 );
1205 var_SetString( p_input
, "sub-file", "" );
1206 var_SetBool( p_input
, "sub-autodetect-file", false );
1210 InitStatistics( p_input
);
1212 if( InitSout( p_input
) )
1217 p_input
->p
->p_es_out
= input_EsOutTimeshiftNew( p_input
, p_input
->p
->p_es_out_display
, p_input
->p
->i_rate
);
1220 input_ChangeState( p_input
, OPENING_S
);
1221 input_SendEventCache( p_input
, 0.0 );
1224 if( InputSourceInit( p_input
, &p_input
->p
->input
,
1225 p_input
->p
->p_item
->psz_uri
, NULL
, false ) )
1230 InitTitle( p_input
);
1232 /* Load master infos */
1235 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_LENGTH
,
1239 i_length
= input_item_GetDuration( p_input
->p
->p_item
);
1240 input_SendEventLength( p_input
, i_length
);
1242 input_SendEventPosition( p_input
, 0.0, 0 );
1244 if( !p_input
->b_preparsing
)
1246 StartTitle( p_input
);
1247 LoadSubtitles( p_input
);
1248 LoadSlaves( p_input
);
1249 InitPrograms( p_input
);
1251 double f_rate
= var_InheritFloat( p_input
, "rate" );
1252 if( f_rate
!= 0.0 && f_rate
!= 1.0 )
1254 vlc_value_t val
= { .i_int
= INPUT_RATE_DEFAULT
/ f_rate
};
1255 input_ControlPush( p_input
, INPUT_CONTROL_SET_RATE
, &val
);
1259 if( !p_input
->b_preparsing
&& p_input
->p
->p_sout
)
1261 p_input
->p
->b_out_pace_control
= (p_input
->p
->p_sout
->i_out_pace_nocontrol
> 0);
1263 if( p_input
->p
->b_can_pace_control
&& p_input
->p
->b_out_pace_control
)
1265 /* We don't want a high input priority here or we'll
1266 * end-up sucking up all the CPU time */
1267 vlc_set_priority( p_input
->p
->thread
, VLC_THREAD_PRIORITY_LOW
);
1270 msg_Dbg( p_input
, "starting in %s mode",
1271 p_input
->p
->b_out_pace_control
? "async" : "sync" );
1274 p_meta
= vlc_meta_New();
1277 /* Get meta data from users */
1278 InputMetaUser( p_input
, p_meta
);
1280 /* Get meta data from master input */
1281 InputSourceMeta( p_input
, &p_input
->p
->input
, p_meta
);
1283 /* And from slave */
1284 for( int i
= 0; i
< p_input
->p
->i_slave
; i
++ )
1285 InputSourceMeta( p_input
, p_input
->p
->slave
[i
], p_meta
);
1288 InputUpdateMeta( p_input
, p_meta
);
1291 msg_Dbg( p_input
, "`%s' successfully opened",
1292 p_input
->p
->p_item
->psz_uri
);
1294 /* initialization is complete */
1295 input_ChangeState( p_input
, PLAYING_S
);
1300 input_ChangeState( p_input
, ERROR_S
);
1302 if( p_input
->p
->p_es_out
)
1303 es_out_Delete( p_input
->p
->p_es_out
);
1304 es_out_SetMode( p_input
->p
->p_es_out_display
, ES_OUT_MODE_END
);
1305 if( p_input
->p
->p_resource
)
1307 if( p_input
->p
->p_sout
)
1308 input_resource_RequestSout( p_input
->p
->p_resource
,
1309 p_input
->p
->p_sout
, NULL
);
1310 input_resource_SetInput( p_input
->p
->p_resource
, NULL
);
1311 if( p_input
->p
->p_resource_private
)
1312 input_resource_Terminate( p_input
->p
->p_resource_private
);
1315 if( !p_input
->b_preparsing
&& libvlc_stats( p_input
) )
1317 #define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
1318 stats_CounterClean( p_input->p->counters.p_##c );\
1319 p_input->p->counters.p_##c = NULL; } while(0)
1320 EXIT_COUNTER( read_bytes
);
1321 EXIT_COUNTER( read_packets
);
1322 EXIT_COUNTER( demux_read
);
1323 EXIT_COUNTER( input_bitrate
);
1324 EXIT_COUNTER( demux_bitrate
);
1325 EXIT_COUNTER( demux_corrupted
);
1326 EXIT_COUNTER( demux_discontinuity
);
1327 EXIT_COUNTER( played_abuffers
);
1328 EXIT_COUNTER( lost_abuffers
);
1329 EXIT_COUNTER( displayed_pictures
);
1330 EXIT_COUNTER( lost_pictures
);
1331 EXIT_COUNTER( decoded_audio
);
1332 EXIT_COUNTER( decoded_video
);
1333 EXIT_COUNTER( decoded_sub
);
1335 if( p_input
->p
->p_sout
)
1337 EXIT_COUNTER( sout_sent_packets
);
1338 EXIT_COUNTER( sout_sent_bytes
);
1339 EXIT_COUNTER( sout_send_bitrate
);
1344 /* Mark them deleted */
1345 p_input
->p
->input
.p_demux
= NULL
;
1346 p_input
->p
->input
.p_stream
= NULL
;
1347 p_input
->p
->input
.p_access
= NULL
;
1348 p_input
->p
->p_es_out
= NULL
;
1349 p_input
->p
->p_sout
= NULL
;
1351 return VLC_EGENERIC
;
1354 /*****************************************************************************
1355 * End: end the input thread
1356 *****************************************************************************/
1357 static void End( input_thread_t
* p_input
)
1361 /* We are at the end */
1362 input_ChangeState( p_input
, END_S
);
1364 /* Clean control variables */
1365 input_ControlVarStop( p_input
);
1367 /* Stop es out activity */
1368 es_out_SetMode( p_input
->p
->p_es_out
, ES_OUT_MODE_NONE
);
1370 /* Clean up master */
1371 InputSourceClean( &p_input
->p
->input
);
1374 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
1376 InputSourceClean( p_input
->p
->slave
[i
] );
1377 free( p_input
->p
->slave
[i
] );
1379 free( p_input
->p
->slave
);
1381 /* Unload all modules */
1382 if( p_input
->p
->p_es_out
)
1383 es_out_Delete( p_input
->p
->p_es_out
);
1384 es_out_SetMode( p_input
->p
->p_es_out_display
, ES_OUT_MODE_END
);
1386 if( !p_input
->b_preparsing
)
1388 #define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
1389 if( libvlc_stats( p_input
) )
1391 /* make sure we are up to date */
1392 stats_ComputeInputStats( p_input
, p_input
->p
->p_item
->p_stats
);
1393 CL_CO( read_bytes
);
1394 CL_CO( read_packets
);
1395 CL_CO( demux_read
);
1396 CL_CO( input_bitrate
);
1397 CL_CO( demux_bitrate
);
1398 CL_CO( demux_corrupted
);
1399 CL_CO( demux_discontinuity
);
1400 CL_CO( played_abuffers
);
1401 CL_CO( lost_abuffers
);
1402 CL_CO( displayed_pictures
);
1403 CL_CO( lost_pictures
);
1404 CL_CO( decoded_audio
) ;
1405 CL_CO( decoded_video
);
1406 CL_CO( decoded_sub
) ;
1409 /* Close optional stream output instance */
1410 if( p_input
->p
->p_sout
)
1412 CL_CO( sout_sent_packets
);
1413 CL_CO( sout_sent_bytes
);
1414 CL_CO( sout_send_bitrate
);
1419 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1420 if( p_input
->p
->i_attachment
> 0 )
1422 for( i
= 0; i
< p_input
->p
->i_attachment
; i
++ )
1423 vlc_input_attachment_Delete( p_input
->p
->attachment
[i
] );
1424 TAB_CLEAN( p_input
->p
->i_attachment
, p_input
->p
->attachment
);
1426 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1429 input_resource_RequestSout( p_input
->p
->p_resource
,
1430 p_input
->p
->p_sout
, NULL
);
1431 input_resource_SetInput( p_input
->p
->p_resource
, NULL
);
1432 if( p_input
->p
->p_resource_private
)
1433 input_resource_Terminate( p_input
->p
->p_resource_private
);
1436 /*****************************************************************************
1438 *****************************************************************************/
1439 void input_ControlPush( input_thread_t
*p_input
,
1440 int i_type
, vlc_value_t
*p_val
)
1442 vlc_mutex_lock( &p_input
->p
->lock_control
);
1443 if( i_type
== INPUT_CONTROL_SET_DIE
)
1445 /* Special case, empty the control */
1446 for( int i
= 0; i
< p_input
->p
->i_control
; i
++ )
1448 input_control_t
*p_ctrl
= &p_input
->p
->control
[i
];
1449 ControlRelease( p_ctrl
->i_type
, p_ctrl
->val
);
1451 p_input
->p
->i_control
= 0;
1454 if( p_input
->p
->i_control
>= INPUT_CONTROL_FIFO_SIZE
)
1456 msg_Err( p_input
, "input control fifo overflow, trashing type=%d",
1459 ControlRelease( i_type
, *p_val
);
1468 memset( &c
.val
, 0, sizeof(c
.val
) );
1470 p_input
->p
->control
[p_input
->p
->i_control
++] = c
;
1472 vlc_cond_signal( &p_input
->p
->wait_control
);
1473 vlc_mutex_unlock( &p_input
->p
->lock_control
);
1476 static int ControlGetReducedIndexLocked( input_thread_t
*p_input
)
1478 const int i_lt
= p_input
->p
->control
[0].i_type
;
1480 for( i
= 1; i
< p_input
->p
->i_control
; i
++ )
1482 const int i_ct
= p_input
->p
->control
[i
].i_type
;
1485 ( i_ct
== INPUT_CONTROL_SET_STATE
||
1486 i_ct
== INPUT_CONTROL_SET_RATE
||
1487 i_ct
== INPUT_CONTROL_SET_POSITION
||
1488 i_ct
== INPUT_CONTROL_SET_TIME
||
1489 i_ct
== INPUT_CONTROL_SET_PROGRAM
||
1490 i_ct
== INPUT_CONTROL_SET_TITLE
||
1491 i_ct
== INPUT_CONTROL_SET_SEEKPOINT
||
1492 i_ct
== INPUT_CONTROL_SET_BOOKMARK
) )
1498 /* TODO but that's not that important
1499 - merge SET_X with SET_X_CMD
1500 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1501 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1511 static inline int ControlPop( input_thread_t
*p_input
,
1512 int *pi_type
, vlc_value_t
*p_val
,
1513 mtime_t i_deadline
, bool b_postpone_seek
)
1515 input_thread_private_t
*p_sys
= p_input
->p
;
1517 vlc_mutex_lock( &p_sys
->lock_control
);
1518 while( p_sys
->i_control
<= 0 ||
1519 ( b_postpone_seek
&& ControlIsSeekRequest( p_sys
->control
[0].i_type
) ) )
1521 if( !vlc_object_alive( p_input
) || i_deadline
< 0 )
1523 vlc_mutex_unlock( &p_sys
->lock_control
);
1524 return VLC_EGENERIC
;
1527 if( vlc_cond_timedwait( &p_sys
->wait_control
, &p_sys
->lock_control
,
1530 vlc_mutex_unlock( &p_sys
->lock_control
);
1531 return VLC_EGENERIC
;
1536 const int i_index
= ControlGetReducedIndexLocked( p_input
);
1539 *pi_type
= p_sys
->control
[i_index
].i_type
;
1540 *p_val
= p_sys
->control
[i_index
].val
;
1542 p_sys
->i_control
-= i_index
+ 1;
1543 if( p_sys
->i_control
> 0 )
1544 memmove( &p_sys
->control
[0], &p_sys
->control
[i_index
+1],
1545 sizeof(*p_sys
->control
) * p_sys
->i_control
);
1546 vlc_mutex_unlock( &p_sys
->lock_control
);
1550 static bool ControlIsSeekRequest( int i_type
)
1554 case INPUT_CONTROL_SET_POSITION
:
1555 case INPUT_CONTROL_SET_TIME
:
1556 case INPUT_CONTROL_SET_TITLE
:
1557 case INPUT_CONTROL_SET_TITLE_NEXT
:
1558 case INPUT_CONTROL_SET_TITLE_PREV
:
1559 case INPUT_CONTROL_SET_SEEKPOINT
:
1560 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1561 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1562 case INPUT_CONTROL_SET_BOOKMARK
:
1563 case INPUT_CONTROL_NAV_ACTIVATE
:
1564 case INPUT_CONTROL_NAV_UP
:
1565 case INPUT_CONTROL_NAV_DOWN
:
1566 case INPUT_CONTROL_NAV_LEFT
:
1567 case INPUT_CONTROL_NAV_RIGHT
:
1574 static void ControlRelease( int i_type
, vlc_value_t val
)
1578 case INPUT_CONTROL_ADD_SUBTITLE
:
1579 case INPUT_CONTROL_ADD_SLAVE
:
1580 free( val
.psz_string
);
1589 static void ControlPause( input_thread_t
*p_input
, mtime_t i_control_date
)
1591 int i_ret
= VLC_SUCCESS
;
1592 int i_state
= PAUSE_S
;
1594 if( p_input
->p
->b_can_pause
)
1596 if( p_input
->p
->input
.p_stream
!= NULL
)
1597 i_ret
= stream_Control( p_input
->p
->input
.p_stream
,
1598 STREAM_SET_PAUSE_STATE
, true );
1600 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1601 DEMUX_SET_PAUSE_STATE
, true );
1605 msg_Warn( p_input
, "cannot set pause state" );
1611 i_ret
= es_out_SetPauseState( p_input
->p
->p_es_out
,
1612 p_input
->p
->b_can_pause
, true,
1616 msg_Warn( p_input
, "cannot set pause state at es_out level" );
1620 /* Switch to new state */
1621 input_ChangeState( p_input
, i_state
);
1624 static void ControlUnpause( input_thread_t
*p_input
, mtime_t i_control_date
)
1626 int i_ret
= VLC_SUCCESS
;
1628 if( p_input
->p
->b_can_pause
)
1630 if( p_input
->p
->input
.p_stream
)
1631 i_ret
= stream_Control( p_input
->p
->input
.p_stream
,
1632 STREAM_SET_PAUSE_STATE
, false );
1634 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1635 DEMUX_SET_PAUSE_STATE
, false );
1638 /* FIXME What to do ? */
1639 msg_Warn( p_input
, "cannot unset pause -> EOF" );
1640 input_ControlPush( p_input
, INPUT_CONTROL_SET_DIE
, NULL
);
1644 /* Switch to play */
1645 input_ChangeState( p_input
, PLAYING_S
);
1649 es_out_SetPauseState( p_input
->p
->p_es_out
, false, false, i_control_date
);
1652 static bool Control( input_thread_t
*p_input
,
1653 int i_type
, vlc_value_t val
)
1655 const mtime_t i_control_date
= mdate();
1656 /* FIXME b_force_update is abused, it should be carefully checked */
1657 bool b_force_update
= false;
1660 return b_force_update
;
1664 case INPUT_CONTROL_SET_DIE
:
1665 msg_Dbg( p_input
, "control: stopping input" );
1667 /* Mark all submodules to die */
1668 ObjectKillChildrens( VLC_OBJECT(p_input
) );
1671 case INPUT_CONTROL_SET_POSITION
:
1675 if( p_input
->p
->b_recording
)
1677 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION(_OFFSET) ignored while recording" );
1680 f_pos
= val
.f_float
;
1681 if( i_type
!= INPUT_CONTROL_SET_POSITION
)
1682 f_pos
+= var_GetFloat( p_input
, "position" );
1685 else if( f_pos
> 1.0 )
1687 /* Reset the decoders states and clock sync (before calling the demuxer */
1688 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1689 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_POSITION
,
1690 f_pos
, !p_input
->p
->b_fast_seek
) )
1692 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1693 "%2.1f%% failed", f_pos
* 100 );
1697 if( p_input
->p
->i_slave
> 0 )
1698 SlaveSeek( p_input
);
1699 p_input
->p
->input
.b_eof
= false;
1701 b_force_update
= true;
1706 case INPUT_CONTROL_SET_TIME
:
1711 if( p_input
->p
->b_recording
)
1713 msg_Err( p_input
, "INPUT_CONTROL_SET_TIME(_OFFSET) ignored while recording" );
1717 i_time
= val
.i_time
;
1718 if( i_type
!= INPUT_CONTROL_SET_TIME
)
1719 i_time
+= var_GetTime( p_input
, "time" );
1724 /* Reset the decoders states and clock sync (before calling the demuxer */
1725 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1727 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1728 DEMUX_SET_TIME
, i_time
,
1729 !p_input
->p
->b_fast_seek
);
1734 /* Emulate it with a SET_POS */
1735 if( !demux_Control( p_input
->p
->input
.p_demux
,
1736 DEMUX_GET_LENGTH
, &i_length
) && i_length
> 0 )
1738 double f_pos
= (double)i_time
/ (double)i_length
;
1739 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1740 DEMUX_SET_POSITION
, f_pos
,
1741 !p_input
->p
->b_fast_seek
);
1746 msg_Warn( p_input
, "INPUT_CONTROL_SET_TIME(_OFFSET) %"PRId64
1747 " failed or not possible", i_time
);
1751 if( p_input
->p
->i_slave
> 0 )
1752 SlaveSeek( p_input
);
1753 p_input
->p
->input
.b_eof
= false;
1755 b_force_update
= true;
1760 case INPUT_CONTROL_SET_STATE
:
1761 if( val
.i_int
!= PLAYING_S
&& val
.i_int
!= PAUSE_S
)
1762 msg_Err( p_input
, "invalid state in INPUT_CONTROL_SET_STATE" );
1763 else if( p_input
->p
->i_state
== PAUSE_S
)
1765 ControlUnpause( p_input
, i_control_date
);
1767 b_force_update
= true;
1769 else if( val
.i_int
== PAUSE_S
&& p_input
->p
->i_state
== PLAYING_S
/* &&
1770 p_input->p->b_can_pause */ )
1772 ControlPause( p_input
, i_control_date
);
1774 b_force_update
= true;
1776 else if( val
.i_int
== PAUSE_S
&& !p_input
->p
->b_can_pause
&& 0 )
1778 b_force_update
= true;
1780 /* Correct "state" value */
1781 input_ChangeState( p_input
, p_input
->p
->i_state
);
1785 case INPUT_CONTROL_SET_RATE
:
1787 /* Get rate and direction */
1788 int i_rate
= abs( val
.i_int
);
1789 int i_rate_sign
= val
.i_int
< 0 ? -1 : 1;
1791 /* Check rate bound */
1792 if( i_rate
< INPUT_RATE_MIN
)
1794 msg_Dbg( p_input
, "cannot set rate faster" );
1795 i_rate
= INPUT_RATE_MIN
;
1797 else if( i_rate
> INPUT_RATE_MAX
)
1799 msg_Dbg( p_input
, "cannot set rate slower" );
1800 i_rate
= INPUT_RATE_MAX
;
1803 /* Apply direction */
1804 if( i_rate_sign
< 0 )
1806 if( p_input
->p
->input
.b_rescale_ts
)
1808 msg_Dbg( p_input
, "cannot set negative rate" );
1809 i_rate
= p_input
->p
->i_rate
;
1810 assert( i_rate
> 0 );
1814 i_rate
*= i_rate_sign
;
1818 if( i_rate
!= INPUT_RATE_DEFAULT
&&
1819 ( ( !p_input
->p
->b_can_rate_control
&& !p_input
->p
->input
.b_rescale_ts
) ||
1820 ( p_input
->p
->p_sout
&& !p_input
->p
->b_out_pace_control
) ) )
1822 msg_Dbg( p_input
, "cannot change rate" );
1823 i_rate
= INPUT_RATE_DEFAULT
;
1825 if( i_rate
!= p_input
->p
->i_rate
&&
1826 !p_input
->p
->b_can_pace_control
&& p_input
->p
->b_can_rate_control
)
1829 if( p_input
->p
->input
.p_access
)
1831 i_ret
= VLC_EGENERIC
;
1835 if( !p_input
->p
->input
.b_rescale_ts
)
1836 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_RESET_PCR
);
1838 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1839 DEMUX_SET_RATE
, &i_rate
);
1843 msg_Warn( p_input
, "ACCESS/DEMUX_SET_RATE failed" );
1844 i_rate
= p_input
->p
->i_rate
;
1849 if( i_rate
!= p_input
->p
->i_rate
)
1851 p_input
->p
->i_rate
= i_rate
;
1852 input_SendEventRate( p_input
, i_rate
);
1854 if( p_input
->p
->input
.b_rescale_ts
)
1856 const int i_rate_source
= (p_input
->p
->b_can_pace_control
|| p_input
->p
->b_can_rate_control
) ? i_rate
: INPUT_RATE_DEFAULT
;
1857 es_out_SetRate( p_input
->p
->p_es_out
, i_rate_source
, i_rate
);
1860 b_force_update
= true;
1865 case INPUT_CONTROL_SET_PROGRAM
:
1866 /* No need to force update, es_out does it if needed */
1867 es_out_Control( p_input
->p
->p_es_out
,
1868 ES_OUT_SET_GROUP
, val
.i_int
);
1870 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, val
.i_int
,
1874 case INPUT_CONTROL_SET_ES
:
1875 /* No need to force update, es_out does it if needed */
1876 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_SET_ES_BY_ID
, val
.i_int
);
1879 case INPUT_CONTROL_RESTART_ES
:
1880 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_RESTART_ES_BY_ID
, val
.i_int
);
1883 case INPUT_CONTROL_SET_AUDIO_DELAY
:
1884 input_SendEventAudioDelay( p_input
, val
.i_time
);
1885 UpdatePtsDelay( p_input
);
1888 case INPUT_CONTROL_SET_SPU_DELAY
:
1889 input_SendEventSubtitleDelay( p_input
, val
.i_time
);
1890 UpdatePtsDelay( p_input
);
1893 case INPUT_CONTROL_SET_TITLE
:
1894 case INPUT_CONTROL_SET_TITLE_NEXT
:
1895 case INPUT_CONTROL_SET_TITLE_PREV
:
1897 if( p_input
->p
->b_recording
)
1899 msg_Err( p_input
, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
1902 if( p_input
->p
->input
.i_title
<= 0 )
1905 int i_title
= p_input
->p
->input
.b_title_demux
1906 ? p_input
->p
->input
.p_demux
->info
.i_title
1907 : p_input
->p
->input
.p_access
->info
.i_title
;
1908 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
1910 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
1913 i_title
= val
.i_int
;
1914 if( i_title
< 0 || i_title
>= p_input
->p
->input
.i_title
)
1917 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1918 if( p_input
->p
->input
.b_title_demux
)
1919 demux_Control( p_input
->p
->input
.p_demux
,
1920 DEMUX_SET_TITLE
, i_title
);
1922 stream_Control( p_input
->p
->input
.p_stream
,
1923 STREAM_SET_TITLE
, i_title
);
1924 input_SendEventTitle( p_input
, i_title
);
1927 case INPUT_CONTROL_SET_SEEKPOINT
:
1928 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1929 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1931 if( p_input
->p
->b_recording
)
1933 msg_Err( p_input
, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
1936 if( p_input
->p
->input
.i_title
<= 0 )
1939 int i_title
, i_seekpoint
;
1940 if( p_input
->p
->input
.b_title_demux
)
1942 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1944 i_title
= p_demux
->info
.i_title
;
1945 i_seekpoint
= p_demux
->info
.i_seekpoint
;
1949 access_t
*p_access
= p_input
->p
->input
.p_access
;
1951 i_title
= p_access
->info
.i_title
;
1952 i_seekpoint
= p_access
->info
.i_seekpoint
;
1955 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
1957 int64_t i_seekpoint_time
= p_input
->p
->input
.title
[i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
1958 int64_t i_input_time
= var_GetTime( p_input
, "time" );
1959 if( i_seekpoint_time
>= 0 && i_input_time
>= 0 )
1961 if( i_input_time
< i_seekpoint_time
+ 3000000 )
1967 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
1970 i_seekpoint
= val
.i_int
;
1972 || i_seekpoint
>= p_input
->p
->input
.title
[i_title
]->i_seekpoint
)
1975 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1976 if( p_input
->p
->input
.b_title_demux
)
1977 demux_Control( p_input
->p
->input
.p_demux
,
1978 DEMUX_SET_SEEKPOINT
, i_seekpoint
);
1980 stream_Control( p_input
->p
->input
.p_stream
,
1981 STREAM_SET_SEEKPOINT
, i_seekpoint
);
1982 input_SendEventSeekpoint( p_input
, i_title
, i_seekpoint
);
1986 case INPUT_CONTROL_ADD_SUBTITLE
:
1987 if( val
.psz_string
)
1988 SubtitleAdd( p_input
, val
.psz_string
, true );
1991 case INPUT_CONTROL_ADD_SLAVE
:
1992 if( val
.psz_string
)
1994 const char *uri
= val
.psz_string
;
1995 input_source_t
*slave
= InputSourceNew( p_input
);
1997 if( slave
&& !InputSourceInit( p_input
, slave
, uri
, NULL
, false ) )
2003 msg_Dbg( p_input
, "adding %s as slave on the fly", uri
);
2006 if( demux_Control( p_input
->p
->input
.p_demux
,
2007 DEMUX_GET_TIME
, &i_time
) )
2009 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2010 InputSourceClean( slave
);
2014 if( demux_Control( slave
->p_demux
,
2015 DEMUX_SET_TIME
, i_time
, true ) )
2017 msg_Err( p_input
, "seek failed for new slave" );
2018 InputSourceClean( slave
);
2023 /* Get meta (access and demux) */
2024 p_meta
= vlc_meta_New();
2027 if( slave
->p_stream
!= NULL
)
2028 stream_Control( slave
->p_stream
,
2029 STREAM_GET_META
, p_meta
);
2030 demux_Control( slave
->p_demux
, DEMUX_GET_META
, p_meta
);
2031 InputUpdateMeta( p_input
, p_meta
);
2034 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, slave
);
2039 msg_Warn( p_input
, "failed to add %s as slave", uri
);
2044 case INPUT_CONTROL_SET_RECORD_STATE
:
2045 if( !!p_input
->p
->b_recording
!= !!val
.b_bool
)
2047 if( p_input
->p
->input
.b_can_stream_record
)
2049 if( demux_Control( p_input
->p
->input
.p_demux
,
2050 DEMUX_SET_RECORD_STATE
, val
.b_bool
) )
2055 if( es_out_SetRecordState( p_input
->p
->p_es_out_display
, val
.b_bool
) )
2058 p_input
->p
->b_recording
= val
.b_bool
;
2060 input_SendEventRecord( p_input
, val
.b_bool
);
2062 b_force_update
= true;
2066 case INPUT_CONTROL_SET_FRAME_NEXT
:
2067 if( p_input
->p
->i_state
== PAUSE_S
)
2069 es_out_SetFrameNext( p_input
->p
->p_es_out
);
2071 else if( p_input
->p
->i_state
== PLAYING_S
)
2073 ControlPause( p_input
, i_control_date
);
2077 msg_Err( p_input
, "invalid state for frame next" );
2079 b_force_update
= true;
2082 case INPUT_CONTROL_SET_BOOKMARK
:
2084 seekpoint_t bookmark
;
2086 bookmark
.i_time_offset
= -1;
2087 bookmark
.i_byte_offset
= -1;
2089 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2090 if( val
.i_int
>= 0 && val
.i_int
< p_input
->p
->i_bookmark
)
2092 const seekpoint_t
*p_bookmark
= p_input
->p
->pp_bookmark
[val
.i_int
];
2093 bookmark
.i_time_offset
= p_bookmark
->i_time_offset
;
2094 bookmark
.i_byte_offset
= p_bookmark
->i_byte_offset
;
2096 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2098 if( bookmark
.i_time_offset
< 0 && bookmark
.i_byte_offset
< 0 )
2100 msg_Err( p_input
, "invalid bookmark %"PRId64
, val
.i_int
);
2104 if( bookmark
.i_time_offset
>= 0 )
2106 val
.i_time
= bookmark
.i_time_offset
;
2107 b_force_update
= Control( p_input
, INPUT_CONTROL_SET_TIME
, val
);
2109 else if( bookmark
.i_byte_offset
>= 0 &&
2110 p_input
->p
->input
.p_stream
)
2112 const uint64_t i_size
= stream_Size( p_input
->p
->input
.p_stream
);
2113 if( i_size
> 0 && (uint64_t)bookmark
.i_byte_offset
<= i_size
)
2115 val
.f_float
= (double)bookmark
.i_byte_offset
/ i_size
;
2116 b_force_update
= Control( p_input
, INPUT_CONTROL_SET_POSITION
, val
);
2122 case INPUT_CONTROL_NAV_ACTIVATE
:
2123 case INPUT_CONTROL_NAV_UP
:
2124 case INPUT_CONTROL_NAV_DOWN
:
2125 case INPUT_CONTROL_NAV_LEFT
:
2126 case INPUT_CONTROL_NAV_RIGHT
:
2127 demux_Control( p_input
->p
->input
.p_demux
, i_type
2128 - INPUT_CONTROL_NAV_ACTIVATE
+ DEMUX_NAV_ACTIVATE
);
2132 msg_Err( p_input
, "not yet implemented" );
2136 ControlRelease( i_type
, val
);
2137 return b_force_update
;
2140 /*****************************************************************************
2141 * UpdateTitleSeekpoint
2142 *****************************************************************************/
2143 static int UpdateTitleSeekpoint( input_thread_t
*p_input
,
2144 int i_title
, int i_seekpoint
)
2146 int i_title_end
= p_input
->p
->input
.i_title_end
-
2147 p_input
->p
->input
.i_title_offset
;
2148 int i_seekpoint_end
= p_input
->p
->input
.i_seekpoint_end
-
2149 p_input
->p
->input
.i_seekpoint_offset
;
2151 if( i_title_end
>= 0 && i_seekpoint_end
>= 0 )
2153 if( i_title
> i_title_end
||
2154 ( i_title
== i_title_end
&& i_seekpoint
> i_seekpoint_end
) )
2157 else if( i_seekpoint_end
>= 0 )
2159 if( i_seekpoint
> i_seekpoint_end
)
2162 else if( i_title_end
>= 0 )
2164 if( i_title
> i_title_end
)
2169 /*****************************************************************************
2171 *****************************************************************************/
2172 static int UpdateTitleSeekpointFromDemux( input_thread_t
*p_input
)
2174 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
2176 /* TODO event-like */
2177 if( p_demux
->info
.i_update
& INPUT_UPDATE_TITLE
)
2179 input_SendEventTitle( p_input
, p_demux
->info
.i_title
);
2181 p_demux
->info
.i_update
&= ~INPUT_UPDATE_TITLE
;
2183 if( p_demux
->info
.i_update
& INPUT_UPDATE_SEEKPOINT
)
2185 input_SendEventSeekpoint( p_input
,
2186 p_demux
->info
.i_title
, p_demux
->info
.i_seekpoint
);
2188 p_demux
->info
.i_update
&= ~INPUT_UPDATE_SEEKPOINT
;
2191 /* Hmmm only works with master input */
2192 if( p_input
->p
->input
.p_demux
== p_demux
)
2193 return UpdateTitleSeekpoint( p_input
,
2194 p_demux
->info
.i_title
,
2195 p_demux
->info
.i_seekpoint
);
2199 static void UpdateGenericFromDemux( input_thread_t
*p_input
)
2201 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
2203 if( p_demux
->info
.i_update
& INPUT_UPDATE_META
)
2205 vlc_meta_t
*p_meta
= vlc_meta_New();
2208 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_META
, p_meta
);
2209 InputUpdateMeta( p_input
, p_meta
);
2211 p_demux
->info
.i_update
&= ~INPUT_UPDATE_META
;
2215 static void UpdateTitleListfromDemux( input_thread_t
*p_input
)
2217 input_source_t
*in
= &p_input
->p
->input
;
2219 /* Delete the preexisting titles */
2220 if( in
->i_title
> 0 )
2222 for( int i
= 0; i
< in
->i_title
; i
++ )
2223 vlc_input_title_Delete( in
->title
[i
] );
2224 TAB_CLEAN( in
->i_title
, in
->title
);
2225 in
->b_title_demux
= false;
2228 /* Get the new title list */
2229 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2230 &in
->title
, &in
->i_title
,
2231 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2232 TAB_INIT( in
->i_title
, in
->title
);
2234 in
->b_title_demux
= true;
2236 InitTitle( p_input
);
2240 /*****************************************************************************
2241 * Update*FromAccess:
2242 *****************************************************************************/
2243 static int UpdateTitleSeekpointFromAccess( input_thread_t
*p_input
)
2245 access_t
*p_access
= p_input
->p
->input
.p_access
;
2247 if( p_access
->info
.i_update
& INPUT_UPDATE_TITLE
)
2249 input_SendEventTitle( p_input
, p_access
->info
.i_title
);
2251 stream_Control( p_input
->p
->input
.p_stream
, STREAM_UPDATE_SIZE
);
2253 p_access
->info
.i_update
&= ~INPUT_UPDATE_TITLE
;
2255 if( p_access
->info
.i_update
& INPUT_UPDATE_SEEKPOINT
)
2257 input_SendEventSeekpoint( p_input
,
2258 p_access
->info
.i_title
, p_access
->info
.i_seekpoint
);
2260 p_access
->info
.i_update
&= ~INPUT_UPDATE_SEEKPOINT
;
2262 /* Hmmm only works with master input */
2263 if( p_input
->p
->input
.p_access
== p_access
)
2264 return UpdateTitleSeekpoint( p_input
,
2265 p_access
->info
.i_title
,
2266 p_access
->info
.i_seekpoint
);
2269 static void UpdateGenericFromAccess( input_thread_t
*p_input
)
2271 stream_t
*p_stream
= p_input
->p
->input
.p_stream
;
2272 access_t
*p_access
= p_input
->p
->input
.p_access
;
2274 if( p_access
->info
.i_update
& INPUT_UPDATE_META
)
2276 /* TODO maybe multi - access ? */
2277 vlc_meta_t
*p_meta
= vlc_meta_New();
2280 stream_Control( p_stream
, STREAM_GET_META
, p_meta
);
2281 InputUpdateMeta( p_input
, p_meta
);
2283 p_access
->info
.i_update
&= ~INPUT_UPDATE_META
;
2285 if( p_access
->info
.i_update
& INPUT_UPDATE_SIGNAL
)
2290 if( stream_Control( p_stream
, STREAM_GET_SIGNAL
, &f_quality
, &f_strength
) )
2291 f_quality
= f_strength
= -1;
2293 input_SendEventSignal( p_input
, f_quality
, f_strength
);
2295 p_access
->info
.i_update
&= ~INPUT_UPDATE_SIGNAL
;
2299 /*****************************************************************************
2301 *****************************************************************************/
2302 static input_source_t
*InputSourceNew( input_thread_t
*p_input
)
2304 VLC_UNUSED(p_input
);
2306 return calloc( 1, sizeof( input_source_t
) );
2309 /*****************************************************************************
2311 *****************************************************************************/
2312 static int InputSourceInit( input_thread_t
*p_input
,
2313 input_source_t
*in
, const char *psz_mrl
,
2314 const char *psz_forced_demux
, bool b_in_can_fail
)
2316 const char *psz_access
, *psz_demux
, *psz_path
, *psz_anchor
= NULL
;
2317 char *psz_var_demux
= NULL
;
2321 char *psz_dup
= strdup( psz_mrl
);
2323 if( psz_dup
== NULL
)
2327 input_SplitMRL( &psz_access
, &psz_demux
, &psz_path
, &psz_anchor
, psz_dup
);
2329 msg_Dbg( p_input
, "`%s' gives access `%s' demux `%s' path `%s'",
2330 psz_mrl
, psz_access
, psz_demux
, psz_path
);
2331 if( !p_input
->b_preparsing
)
2333 /* Find optional titles and seekpoints */
2334 MRLSections( psz_anchor
, &in
->i_title_start
, &in
->i_title_end
,
2335 &in
->i_seekpoint_start
, &in
->i_seekpoint_end
);
2336 if( psz_forced_demux
&& *psz_forced_demux
)
2338 psz_demux
= psz_forced_demux
;
2340 else if( *psz_demux
== '\0' )
2342 /* special hack for forcing a demuxer with --demux=module
2343 * (and do nothing with a list) */
2344 psz_var_demux
= var_GetNonEmptyString( p_input
, "demux" );
2346 if( psz_var_demux
!= NULL
&&
2347 !strchr(psz_var_demux
, ',' ) &&
2348 !strchr(psz_var_demux
, ':' ) )
2350 psz_demux
= psz_var_demux
;
2352 msg_Dbg( p_input
, "enforced demux ` %s'", psz_demux
);
2356 /* Try access_demux first */
2357 in
->p_demux
= demux_New( p_input
, p_input
, psz_access
, psz_demux
, psz_path
,
2358 NULL
, p_input
->p
->p_es_out
, false );
2362 /* Preparsing is only for file:// */
2365 if( strcmp( psz_access
, "file" ) )
2367 msg_Dbg( p_input
, "trying to pre-parse %s", psz_path
);
2370 mtime_t i_pts_delay
;
2374 /* Get infos from access_demux */
2375 in
->b_title_demux
= true;
2376 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2377 &in
->title
, &in
->i_title
,
2378 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2380 TAB_INIT( in
->i_title
, in
->title
);
2382 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_PACE
,
2383 &in
->b_can_pace_control
) )
2384 in
->b_can_pace_control
= false;
2386 assert( in
->p_demux
->pf_demux
!= NULL
|| !in
->b_can_pace_control
);
2388 if( !in
->b_can_pace_control
)
2390 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_RATE
,
2391 &in
->b_can_rate_control
, &in
->b_rescale_ts
) )
2393 in
->b_can_rate_control
= false;
2394 in
->b_rescale_ts
= true; /* not used */
2399 in
->b_can_rate_control
= true;
2400 in
->b_rescale_ts
= true;
2402 if( demux_Control( in
->p_demux
, DEMUX_CAN_PAUSE
,
2403 &in
->b_can_pause
) )
2404 in
->b_can_pause
= false;
2405 var_SetBool( p_input
, "can-pause", in
->b_can_pause
|| !in
->b_can_pace_control
); /* XXX temporary because of es_out_timeshift*/
2406 var_SetBool( p_input
, "can-rate", !in
->b_can_pace_control
|| in
->b_can_rate_control
); /* XXX temporary because of es_out_timeshift*/
2407 var_SetBool( p_input
, "can-rewind", !in
->b_rescale_ts
&& !in
->b_can_pace_control
&& in
->b_can_rate_control
);
2410 if( demux_Control( in
->p_demux
, DEMUX_CAN_SEEK
, &b_can_seek
) )
2412 var_SetBool( p_input
, "can-seek", b_can_seek
);
2415 { /* Now try a real access */
2416 access_t
*p_access
= access_New( p_input
, p_input
,
2417 psz_access
, psz_demux
, psz_path
);
2418 if( p_access
== NULL
)
2420 if( vlc_object_alive( p_input
) )
2422 msg_Err( p_input
, "open of `%s' failed", psz_mrl
);
2423 if( !b_in_can_fail
)
2424 dialog_Fatal( p_input
, _("Your input can't be opened"),
2425 _("VLC is unable to open the MRL '%s'."
2426 " Check the log for details."), psz_mrl
);
2431 /* Get infos from access */
2432 if( !p_input
->b_preparsing
)
2434 access_Control( p_access
, ACCESS_GET_PTS_DELAY
, &i_pts_delay
);
2437 /* Access-forced demuxer (PARENTAL ADVISORY: EXPLICIT HACK) */
2438 if( !*psz_demux
&& *p_access
->psz_demux
)
2439 psz_demux
= p_access
->psz_demux
;
2443 char **ppsz_input_list
;
2445 TAB_INIT( i_input_list
, ppsz_input_list
);
2447 /* On master stream only, use input-list */
2448 if( &p_input
->p
->input
== in
)
2454 psz_parser
= var_CreateGetNonEmptyString( p_input
, "input-list" );
2456 while( psz_parser
&& *psz_parser
)
2458 char *p
= strchr( psz_parser
, ',' );
2464 char *psz_name
= strdup( psz_parser
);
2466 TAB_APPEND( i_input_list
, ppsz_input_list
, psz_name
);
2473 /* Autodetect extra files if none specified */
2474 if( i_input_list
<= 0 )
2476 InputGetExtraFiles( p_input
, &i_input_list
, &ppsz_input_list
,
2477 psz_access
, psz_path
);
2479 if( i_input_list
> 0 )
2480 TAB_APPEND( i_input_list
, ppsz_input_list
, NULL
);
2482 /* Create the stream_t */
2483 in
->p_stream
= stream_AccessNew( p_access
, ppsz_input_list
);
2484 if( ppsz_input_list
)
2486 for( int i
= 0; ppsz_input_list
[i
] != NULL
; i
++ )
2487 free( ppsz_input_list
[i
] );
2488 TAB_CLEAN( i_input_list
, ppsz_input_list
);
2491 if( in
->p_stream
== NULL
)
2493 msg_Warn( p_input
, "cannot create a stream_t from access" );
2497 /* Add stream filters */
2498 char *psz_stream_filter
= var_GetNonEmptyString( p_input
,
2500 in
->p_stream
= stream_FilterChainNew( in
->p_stream
,
2502 var_GetBool( p_input
, "input-record-native" ) );
2503 free( psz_stream_filter
);
2505 if( !p_input
->b_preparsing
)
2509 stream_Control( in
->p_stream
, STREAM_CAN_CONTROL_PACE
,
2510 &in
->b_can_pace_control
);
2511 in
->b_can_rate_control
= in
->b_can_pace_control
;
2512 in
->b_rescale_ts
= true;
2514 stream_Control( in
->p_stream
, STREAM_CAN_PAUSE
, &in
->b_can_pause
);
2515 var_SetBool( p_input
, "can-pause",
2516 in
->b_can_pause
|| !in
->b_can_pace_control
); /* XXX temporary because of es_out_timeshift*/
2517 var_SetBool( p_input
, "can-rate",
2518 !in
->b_can_pace_control
|| in
->b_can_rate_control
); /* XXX temporary because of es_out_timeshift*/
2519 var_SetBool( p_input
, "can-rewind",
2520 !in
->b_rescale_ts
&& !in
->b_can_pace_control
);
2522 stream_Control( in
->p_stream
, STREAM_CAN_SEEK
, &b
);
2523 var_SetBool( p_input
, "can-seek", b
);
2525 in
->b_title_demux
= false;
2526 if( stream_Control( in
->p_stream
, STREAM_GET_TITLE_INFO
,
2527 &in
->title
, &in
->i_title
, &in
->i_title_offset
,
2528 &in
->i_seekpoint_offset
) )
2529 TAB_INIT( in
->i_title
, in
->title
);
2532 in
->p_demux
= demux_New( p_input
, p_input
, psz_access
, psz_demux
,
2533 /* Take access/stream redirections into account: */
2534 in
->p_stream
->psz_path
? in
->p_stream
->psz_path
: psz_path
,
2535 in
->p_stream
, p_input
->p
->p_es_out
,
2536 p_input
->b_preparsing
);
2538 if( in
->p_demux
== NULL
)
2540 if( vlc_object_alive( p_input
) )
2542 msg_Err( p_input
, "no suitable demux module for `%s/%s://%s'",
2543 psz_access
, psz_demux
, psz_path
);
2544 if( !b_in_can_fail
)
2545 dialog_Fatal( VLC_OBJECT( p_input
),
2546 _("VLC can't recognize the input's format"),
2547 _("The format of '%s' cannot be detected. "
2548 "Have a look at the log for details."), psz_mrl
);
2552 assert( in
->p_demux
->pf_demux
!= NULL
);
2554 /* Get title from demux */
2555 if( !p_input
->b_preparsing
&& in
->i_title
<= 0 )
2557 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2558 &in
->title
, &in
->i_title
,
2559 &in
->i_title_offset
, &in
->i_seekpoint_offset
))
2561 TAB_INIT( in
->i_title
, in
->title
);
2565 in
->b_title_demux
= true;
2568 in
->p_access
= p_access
; /* <- TODO: remove this nasty pointer */
2571 free( psz_var_demux
);
2574 /* Set record capabilities */
2575 if( demux_Control( in
->p_demux
, DEMUX_CAN_RECORD
, &in
->b_can_stream_record
) )
2576 in
->b_can_stream_record
= false;
2578 if( !var_GetBool( p_input
, "input-record-native" ) )
2579 in
->b_can_stream_record
= false;
2580 var_SetBool( p_input
, "can-record", true );
2582 var_SetBool( p_input
, "can-record", in
->b_can_stream_record
);
2586 * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2587 if( !p_input
->b_preparsing
)
2590 input_attachment_t
**attachment
;
2591 if( !demux_Control( in
->p_demux
, DEMUX_GET_ATTACHMENTS
,
2592 &attachment
, &i_attachment
) )
2594 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2595 AppendAttachment( &p_input
->p
->i_attachment
, &p_input
->p
->attachment
,
2596 i_attachment
, attachment
);
2597 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2600 /* PTS delay: request from demux first. This is required for
2601 * access_demux and some special cases like SDP demux. Otherwise,
2602 * fallback to access */
2603 if( demux_Control( in
->p_demux
, DEMUX_GET_PTS_DELAY
,
2604 &in
->i_pts_delay
) )
2605 in
->i_pts_delay
= i_pts_delay
;
2606 if( in
->i_pts_delay
> INPUT_PTS_DELAY_MAX
)
2607 in
->i_pts_delay
= INPUT_PTS_DELAY_MAX
;
2608 else if( in
->i_pts_delay
< 0 )
2609 in
->i_pts_delay
= 0;
2612 if( !demux_Control( in
->p_demux
, DEMUX_GET_FPS
, &f_fps
) && f_fps
> 0.0 )
2614 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2615 p_input
->p
->f_fps
= f_fps
;
2616 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2619 if( var_GetInteger( p_input
, "clock-synchro" ) != -1 )
2620 in
->b_can_pace_control
= !var_GetInteger( p_input
, "clock-synchro" );
2626 demux_Delete( in
->p_demux
);
2629 stream_Delete( in
->p_stream
);
2631 free( psz_var_demux
);
2634 return VLC_EGENERIC
;
2637 /*****************************************************************************
2639 *****************************************************************************/
2640 static void InputSourceClean( input_source_t
*in
)
2645 demux_Delete( in
->p_demux
);
2648 stream_Delete( in
->p_stream
);
2650 if( in
->i_title
> 0 )
2652 for( i
= 0; i
< in
->i_title
; i
++ )
2653 vlc_input_title_Delete( in
->title
[i
] );
2654 TAB_CLEAN( in
->i_title
, in
->title
);
2658 /*****************************************************************************
2660 *****************************************************************************/
2661 static void InputSourceMeta( input_thread_t
*p_input
,
2662 input_source_t
*p_source
, vlc_meta_t
*p_meta
)
2664 stream_t
*p_stream
= p_source
->p_stream
;
2665 demux_t
*p_demux
= p_source
->p_demux
;
2667 /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
2670 bool has_meta
= false;
2672 /* Read access meta */
2673 if( p_stream
!= NULL
2674 && !stream_Control( p_stream
, STREAM_GET_META
, p_meta
) )
2677 /* Read demux meta */
2678 if( !demux_Control( p_demux
, DEMUX_GET_META
, p_meta
) )
2681 bool has_unsupported
;
2682 if( demux_Control( p_demux
, DEMUX_HAS_UNSUPPORTED_META
, &has_unsupported
) )
2683 has_unsupported
= true;
2685 /* If the demux report unsupported meta data, or if we don't have meta data
2686 * try an external "meta reader" */
2687 if( has_meta
&& !has_unsupported
)
2690 demux_meta_t
*p_demux_meta
=
2691 vlc_custom_create( p_demux
, sizeof( *p_demux_meta
), "demux meta" );
2694 p_demux_meta
->p_demux
= p_demux
;
2695 p_demux_meta
->p_item
= p_input
->p
->p_item
;
2697 module_t
*p_id3
= module_need( p_demux_meta
, "meta reader", NULL
, false );
2700 if( p_demux_meta
->p_meta
)
2702 vlc_meta_Merge( p_meta
, p_demux_meta
->p_meta
);
2703 vlc_meta_Delete( p_demux_meta
->p_meta
);
2706 if( p_demux_meta
->i_attachments
> 0 )
2708 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2709 AppendAttachment( &p_input
->p
->i_attachment
, &p_input
->p
->attachment
,
2710 p_demux_meta
->i_attachments
, p_demux_meta
->attachments
);
2711 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2713 module_unneed( p_demux
, p_id3
);
2715 vlc_object_release( p_demux_meta
);
2719 static void SlaveDemux( input_thread_t
*p_input
, bool *pb_demux_polled
)
2724 *pb_demux_polled
= false;
2725 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_TIME
, &i_time
) )
2727 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2731 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
2733 input_source_t
*in
= p_input
->p
->slave
[i
];
2739 const bool b_demux_polled
= in
->p_demux
->pf_demux
!= NULL
;
2740 if( !b_demux_polled
)
2743 *pb_demux_polled
= true;
2745 /* Call demux_Demux until we have read enough data */
2746 if( demux_Control( in
->p_demux
, DEMUX_SET_NEXT_DEMUX_TIME
, i_time
) )
2751 if( demux_Control( in
->p_demux
, DEMUX_GET_TIME
, &i_stime
) )
2753 msg_Err( p_input
, "slave[%d] doesn't like "
2754 "DEMUX_GET_TIME -> EOF", i
);
2759 if( i_stime
>= i_time
)
2765 if( ( i_ret
= demux_Demux( in
->p_demux
) ) <= 0 )
2771 i_ret
= demux_Demux( in
->p_demux
);
2776 msg_Dbg( p_input
, "slave %d EOF", i
);
2782 static void SlaveSeek( input_thread_t
*p_input
)
2787 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_TIME
, &i_time
) )
2789 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2793 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
2795 input_source_t
*in
= p_input
->p
->slave
[i
];
2797 if( demux_Control( in
->p_demux
, DEMUX_SET_TIME
, i_time
, true ) )
2800 msg_Err( p_input
, "seek failed for slave %d -> EOF", i
);
2810 /*****************************************************************************
2812 *****************************************************************************/
2813 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2815 static const struct { int i_meta
; const char *psz_name
; } p_list
[] = {
2816 { vlc_meta_Title
, "meta-title" },
2817 { vlc_meta_Artist
, "meta-artist" },
2818 { vlc_meta_Genre
, "meta-genre" },
2819 { vlc_meta_Copyright
, "meta-copyright" },
2820 { vlc_meta_Description
, "meta-description" },
2821 { vlc_meta_Date
, "meta-date" },
2822 { vlc_meta_URL
, "meta-url" },
2826 /* Get meta information from user */
2827 for( int i
= 0; p_list
[i
].psz_name
; i
++ )
2829 char *psz_string
= var_GetNonEmptyString( p_input
, p_list
[i
].psz_name
);
2833 EnsureUTF8( psz_string
);
2834 vlc_meta_Set( p_meta
, p_list
[i
].i_meta
, psz_string
);
2839 /*****************************************************************************
2840 * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2841 * arturl and locking issue.
2842 *****************************************************************************/
2843 static void InputUpdateMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2845 es_out_ControlSetMeta( p_input
->p
->p_es_out
, p_meta
);
2846 vlc_meta_Delete( p_meta
);
2849 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
2850 int i_new
, input_attachment_t
**pp_new
)
2852 int i_attachment
= *pi_attachment
;
2853 input_attachment_t
**attachment
= *ppp_attachment
;
2856 attachment
= xrealloc( attachment
,
2857 sizeof(input_attachment_t
**) * ( i_attachment
+ i_new
) );
2858 for( i
= 0; i
< i_new
; i
++ )
2859 attachment
[i_attachment
++] = pp_new
[i
];
2863 *pi_attachment
= i_attachment
;
2864 *ppp_attachment
= attachment
;
2866 /*****************************************************************************
2867 * InputGetExtraFiles
2868 * Autodetect extra input list
2869 *****************************************************************************/
2870 static void InputGetExtraFilesPattern( input_thread_t
*p_input
,
2871 int *pi_list
, char ***pppsz_list
,
2872 const char *psz_path
,
2873 const char *psz_match
,
2874 const char *psz_format
,
2875 int i_start
, int i_stop
)
2880 TAB_INIT( i_list
, ppsz_list
);
2882 char *psz_base
= strdup( psz_path
);
2886 /* Remove the extension */
2887 char *psz_end
= &psz_base
[strlen(psz_base
)-strlen(psz_match
)];
2888 assert( psz_end
>= psz_base
);
2891 /* Try to list files */
2892 for( int i
= i_start
; i
<= i_stop
; i
++ )
2897 if( asprintf( &psz_file
, psz_format
, psz_base
, i
) < 0 )
2900 char *psz_tmp_path
= get_path( psz_file
);
2902 if( vlc_stat( psz_tmp_path
, &st
) || !S_ISREG( st
.st_mode
) || !st
.st_size
)
2905 free( psz_tmp_path
);
2909 msg_Dbg( p_input
, "Detected extra file `%s'", psz_file
);
2910 TAB_APPEND( i_list
, ppsz_list
, psz_file
);
2911 free( psz_tmp_path
);
2916 *pppsz_list
= ppsz_list
;
2919 static void InputGetExtraFiles( input_thread_t
*p_input
,
2920 int *pi_list
, char ***pppsz_list
,
2921 const char *psz_access
, const char *psz_path
)
2925 const char *psz_match
;
2926 const char *psz_format
;
2930 /* XXX the order is important */
2931 { ".001", "%s.%.3d", 2, 999 },
2932 { NULL
, NULL
, 0, 0 }
2935 TAB_INIT( *pi_list
, *pppsz_list
);
2937 if( ( psz_access
&& *psz_access
&& strcmp( psz_access
, "file" ) ) || !psz_path
)
2940 const size_t i_path
= strlen(psz_path
);
2942 for( int i
= 0; p_pattern
[i
].psz_match
!= NULL
; i
++ )
2944 const size_t i_ext
= strlen(p_pattern
[i
].psz_match
);
2946 if( i_path
< i_ext
)
2948 if( !strcmp( &psz_path
[i_path
-i_ext
], p_pattern
[i
].psz_match
) )
2950 InputGetExtraFilesPattern( p_input
, pi_list
, pppsz_list
,
2952 p_pattern
[i
].psz_match
, p_pattern
[i
].psz_format
,
2953 p_pattern
[i
].i_start
, p_pattern
[i
].i_stop
);
2960 static void input_ChangeState( input_thread_t
*p_input
, int i_state
)
2962 const bool b_changed
= p_input
->p
->i_state
!= i_state
;
2964 p_input
->p
->i_state
= i_state
;
2965 if( i_state
== ERROR_S
)
2966 p_input
->b_error
= true;
2967 else if( i_state
== END_S
)
2968 p_input
->b_eof
= true;
2972 input_item_SetErrorWhenReading( p_input
->p
->p_item
, p_input
->b_error
);
2973 input_SendEventState( p_input
, i_state
);
2978 /*****************************************************************************
2979 * MRLSplit: parse the access, demux and url part of the
2980 * Media Resource Locator.
2981 *****************************************************************************/
2982 void input_SplitMRL( const char **access
, const char **demux
,
2983 const char **path
, const char **anchor
, char *buf
)
2987 /* Separate <path> from <access>[/<demux>]:// */
2988 p
= strstr( buf
, "://" );
2992 p
+= 3; /* skips "://" */
2995 /* Remove HTML anchor if present (not supported).
2996 * The hash symbol itself should be URI-encoded. */
2997 p
= strchr( p
, '#' );
3009 fprintf( stderr
, "%s(\"%s\") probably not a valid URI!\n", __func__
,
3012 /* Note: this is a valid non const pointer to "": */
3013 *path
= buf
+ strlen( buf
);
3016 /* Separate access from demux */
3017 p
= strchr( buf
, '/' );
3028 /* We really don't want module name substitution here! */
3035 static const char *MRLSeekPoint( const char *str
, int *title
, int *chapter
)
3040 /* Look for the title */
3041 u
= strtoul( str
, &end
, 0 );
3042 *title
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3045 /* Look for the chapter */
3049 u
= strtoul( str
, &end
, 0 );
3050 *chapter
= (str
== end
|| u
> (unsigned long)INT_MAX
) ? -1 : (int)u
;
3060 /*****************************************************************************
3061 * MRLSections: parse title and seekpoint info from the Media Resource Locator.
3064 * [url][@[title_start][:chapter_start][-[title_end][:chapter_end]]]
3065 *****************************************************************************/
3066 static void MRLSections( const char *p
,
3067 int *pi_title_start
, int *pi_title_end
,
3068 int *pi_chapter_start
, int *pi_chapter_end
)
3070 *pi_title_start
= *pi_title_end
= *pi_chapter_start
= *pi_chapter_end
= -1;
3072 int title_start
, chapter_start
, title_end
, chapter_end
;
3078 p
= MRLSeekPoint( p
, &title_start
, &chapter_start
);
3080 title_start
= chapter_start
= -1;
3083 p
= MRLSeekPoint( p
+ 1, &title_end
, &chapter_end
);
3085 title_end
= chapter_end
= -1;
3087 if( *p
) /* syntax error */
3090 *pi_title_start
= title_start
;
3091 *pi_title_end
= title_end
;
3092 *pi_chapter_start
= chapter_start
;
3093 *pi_chapter_end
= chapter_end
;
3096 /*****************************************************************************
3097 * input_AddSubtitles: add a subtitle file and enable it
3098 *****************************************************************************/
3099 static void SubtitleAdd( input_thread_t
*p_input
, char *psz_subtitle
, unsigned i_flags
)
3101 input_source_t
*sub
;
3104 char *psz_path
, *psz_extension
;
3106 /* if we are provided a subtitle.sub file,
3107 * see if we don't have a subtitle.idx and use it instead */
3108 psz_path
= strdup( psz_subtitle
);
3111 psz_extension
= strrchr( psz_path
, '.');
3112 if( psz_extension
&& strcmp( psz_extension
, ".sub" ) == 0 )
3116 strcpy( psz_extension
, ".idx" );
3118 if( !vlc_stat( psz_path
, &st
) && S_ISREG( st
.st_mode
) )
3120 msg_Dbg( p_input
, "using %s as subtitle file instead of %s",
3121 psz_path
, psz_subtitle
);
3122 strcpy( psz_subtitle
, psz_path
);
3128 char *url
= vlc_path2uri( psz_subtitle
, NULL
);
3130 var_Change( p_input
, "spu-es", VLC_VAR_CHOICESCOUNT
, &count
, NULL
);
3132 sub
= InputSourceNew( p_input
);
3134 || InputSourceInit( p_input
, sub
, url
, "subtitle", (i_flags
& SUB_CANFAIL
) ) )
3141 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, sub
);
3144 if( (i_flags
& SUB_FORCED
) && !var_Change( p_input
, "spu-es", VLC_VAR_GETLIST
, &list
, NULL
) )
3146 if( count
.i_int
== 0 )
3148 /* if it was first one, there is disable too */
3150 if( count
.i_int
< list
.p_list
->i_count
)
3152 const int i_id
= list
.p_list
->p_values
[count
.i_int
].i_int
;
3154 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_SET_ES_DEFAULT_BY_ID
, i_id
);
3155 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_SET_ES_BY_ID
, i_id
);
3157 var_FreeList( &list
, NULL
);
3161 /*****************************************************************************
3163 *****************************************************************************/
3164 void input_UpdateStatistic( input_thread_t
*p_input
,
3165 input_statistic_t i_type
, int i_delta
)
3167 assert( p_input
->p
->i_state
!= INIT_S
);
3169 vlc_mutex_lock( &p_input
->p
->counters
.counters_lock
);
3172 #define I(c) stats_Update( p_input->p->counters.c, i_delta, NULL )
3173 case INPUT_STATISTIC_DECODED_VIDEO
:
3176 case INPUT_STATISTIC_DECODED_AUDIO
:
3179 case INPUT_STATISTIC_DECODED_SUBTITLE
:
3182 case INPUT_STATISTIC_SENT_PACKET
:
3183 I(p_sout_sent_packets
);
3186 case INPUT_STATISTIC_SENT_BYTE
:
3190 stats_Update( p_input
->p
->counters
.p_sout_sent_bytes
, i_delta
, &bytes
);
3191 stats_Update( p_input
->p
->counters
.p_sout_send_bitrate
, bytes
, NULL
);
3195 msg_Err( p_input
, "Invalid statistic type %d (internal error)", i_type
);
3198 vlc_mutex_unlock( &p_input
->p
->counters
.counters_lock
);
3202 /* TODO FIXME nearly the same logic that snapshot code */
3203 char *input_CreateFilename( vlc_object_t
*p_obj
, const char *psz_path
, const char *psz_prefix
, const char *psz_extension
)
3208 path
= vlc_opendir( psz_path
);
3213 char *psz_tmp
= str_format( pl_Get(p_obj
), psz_prefix
);
3217 filename_sanitize( psz_tmp
);
3219 if( asprintf( &psz_file
, "%s"DIR_SEP
"%s%s%s",
3221 psz_extension
? "." : "",
3222 psz_extension
? psz_extension
: "" ) < 0 )
3229 psz_file
= str_format( pl_Get(p_obj
), psz_path
);
3230 path_sanitize( psz_file
);