1 /*****************************************************************************
2 * input.c: input thread
3 *****************************************************************************
4 * Copyright (C) 1998-2007 the VideoLAN team
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
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 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 General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
32 #include <vlc_common.h>
38 #include "input_internal.h"
41 #include "es_out_timeshift.h"
49 #include "../stream_output/stream_output.h"
51 #include <vlc_dialog.h>
53 #include <vlc_charset.h>
55 #include <vlc_strings.h>
56 #include <vlc_modules.h>
58 #ifdef HAVE_SYS_STAT_H
59 # include <sys/stat.h>
62 /*****************************************************************************
64 *****************************************************************************/
65 static void Destructor( input_thread_t
* p_input
);
67 static void *Run ( vlc_object_t
*p_this
);
69 static input_thread_t
* Create ( vlc_object_t
*, input_item_t
*,
70 const char *, bool, input_resource_t
* );
71 static int Init ( input_thread_t
*p_input
);
72 static void End ( input_thread_t
*p_input
);
73 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
);
75 static void ObjectKillChildrens( input_thread_t
*, vlc_object_t
* );
77 static inline int ControlPop( input_thread_t
*, int *, vlc_value_t
*, mtime_t i_deadline
, bool b_postpone_seek
);
78 static void ControlRelease( int i_type
, vlc_value_t val
);
79 static bool ControlIsSeekRequest( int i_type
);
80 static bool Control( input_thread_t
*, int, vlc_value_t
);
82 static int UpdateTitleSeekpointFromAccess( input_thread_t
* );
83 static void UpdateGenericFromAccess( input_thread_t
* );
85 static int UpdateTitleSeekpointFromDemux( input_thread_t
* );
86 static void UpdateGenericFromDemux( input_thread_t
* );
88 static void MRLSections( input_thread_t
*, char *, int *, int *, int *, int *);
90 static input_source_t
*InputSourceNew( input_thread_t
*);
91 static int InputSourceInit( input_thread_t
*, input_source_t
*,
92 const char *, const char *psz_forced_demux
);
93 static void InputSourceClean( input_source_t
* );
94 static void InputSourceMeta( input_thread_t
*, input_source_t
*, vlc_meta_t
* );
97 //static void InputGetAttachments( input_thread_t *, input_source_t * );
98 static void SlaveDemux( input_thread_t
*p_input
, bool *pb_demux_polled
);
99 static void SlaveSeek( input_thread_t
*p_input
);
101 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
102 static void InputUpdateMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
103 static void InputGetExtraFiles( input_thread_t
*p_input
,
104 int *pi_list
, char ***pppsz_list
,
105 const char *psz_access
, const char *psz_path
);
107 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
108 int i_new
, input_attachment_t
**pp_new
);
110 static void SubtitleAdd( input_thread_t
*p_input
, char *psz_subtitle
, bool b_forced
);
112 static void input_ChangeState( input_thread_t
*p_input
, int i_state
); /* TODO fix name */
116 * Create a new input_thread_t.
118 * You need to call input_Start on it when you are done
119 * adding callback on the variables/events you want to monitor.
121 * \param p_parent a vlc_object
122 * \param p_item an input item
123 * \param psz_log an optional prefix for this input logs
124 * \param p_resource an optional input ressource
125 * \return a pointer to the spawned input thread
127 input_thread_t
*input_Create( vlc_object_t
*p_parent
,
128 input_item_t
*p_item
,
129 const char *psz_log
, input_resource_t
*p_resource
)
131 return Create( p_parent
, p_item
, psz_log
, false, p_resource
);
134 #undef input_CreateAndStart
136 * Create a new input_thread_t and start it.
138 * Provided for convenience.
142 input_thread_t
*input_CreateAndStart( vlc_object_t
*p_parent
,
143 input_item_t
*p_item
, const char *psz_log
)
145 input_thread_t
*p_input
= input_Create( p_parent
, p_item
, psz_log
, NULL
);
147 if( input_Start( p_input
) )
149 vlc_object_release( p_input
);
157 * Initialize an input thread and run it until it stops by itself.
159 * \param p_parent a vlc_object
160 * \param p_item an input item
161 * \return an error code, VLC_SUCCESS on success
163 int input_Read( vlc_object_t
*p_parent
, input_item_t
*p_item
)
165 input_thread_t
*p_input
= Create( p_parent
, p_item
, NULL
, false, NULL
);
169 if( !Init( p_input
) )
171 MainLoop( p_input
, false );
175 vlc_object_release( p_input
);
180 * Initialize an input and initialize it to preparse the item
181 * This function is blocking. It will only accept parsing regular files.
183 * \param p_parent a vlc_object_t
184 * \param p_item an input item
185 * \return VLC_SUCCESS or an error
187 int input_Preparse( vlc_object_t
*p_parent
, input_item_t
*p_item
)
189 input_thread_t
*p_input
;
191 /* Allocate descriptor */
192 p_input
= Create( p_parent
, p_item
, NULL
, true, NULL
);
196 if( !Init( p_input
) )
199 vlc_object_release( p_input
);
205 * Start a input_thread_t created by input_Create.
207 * You must not start an already running input_thread_t.
209 * \param the input thread to start
211 int input_Start( input_thread_t
*p_input
)
213 /* Create thread and wait for its readiness. */
214 if( vlc_thread_create( p_input
, "input", Run
,
215 VLC_THREAD_PRIORITY_INPUT
) )
217 input_ChangeState( p_input
, ERROR_S
);
218 msg_Err( p_input
, "cannot create input thread" );
225 * Request a running input thread to stop and die
227 * b_abort must be true when a user stop is requested and not because you have
228 * detected an error or an eof. It will be used to properly send the
229 * INPUT_EVENT_ABORT event.
231 * \param p_input the input thread to stop
232 * \param b_abort true if the input has been aborted by a user request
234 void input_Stop( input_thread_t
*p_input
, bool b_abort
)
236 /* Set die for input and ALL of this childrens (even (grand-)grand-childrens)
237 * It is needed here even if it is done in INPUT_CONTROL_SET_DIE handler to
238 * unlock the control loop */
239 ObjectKillChildrens( p_input
, VLC_OBJECT(p_input
) );
241 vlc_mutex_lock( &p_input
->p
->lock_control
);
242 p_input
->p
->b_abort
|= b_abort
;
243 vlc_mutex_unlock( &p_input
->p
->lock_control
);
245 input_ControlPush( p_input
, INPUT_CONTROL_SET_DIE
, NULL
);
249 * Get the item from an input thread
250 * FIXME it does not increase ref count of the item.
251 * if it is used after p_input is destroyed nothing prevent it from
254 input_item_t
*input_GetItem( input_thread_t
*p_input
)
256 assert( p_input
&& p_input
->p
);
257 return p_input
->p
->p_item
;
260 /*****************************************************************************
261 * ObjectKillChildrens
262 *****************************************************************************/
263 static void ObjectKillChildrens( input_thread_t
*p_input
, vlc_object_t
*p_obj
)
268 /* FIXME ObjectKillChildrens seems a very bad idea in fact */
269 i
= vlc_internals( p_obj
)->i_object_type
;
270 if( i
== VLC_OBJECT_VOUT
||i
== VLC_OBJECT_AOUT
||
271 p_obj
== VLC_OBJECT(p_input
->p
->p_sout
) ||
272 i
== VLC_OBJECT_DECODER
)
275 vlc_object_kill( p_obj
);
277 p_list
= vlc_list_children( p_obj
);
278 for( i
= 0; i
< p_list
->i_count
; i
++ )
279 ObjectKillChildrens( p_input
, p_list
->p_values
[i
].p_object
);
280 vlc_list_release( p_list
);
283 /*****************************************************************************
284 * This function creates a new input, and returns a pointer
285 * to its description. On error, it returns NULL.
287 * XXX Do not forget to update vlc_input.h if you add new variables.
288 *****************************************************************************/
289 static input_thread_t
*Create( vlc_object_t
*p_parent
, input_item_t
*p_item
,
290 const char *psz_header
, bool b_quick
,
291 input_resource_t
*p_resource
)
293 static const char input_name
[] = "input";
294 input_thread_t
*p_input
= NULL
; /* thread descriptor */
297 /* Allocate descriptor */
298 p_input
= vlc_custom_create( p_parent
, sizeof( *p_input
),
299 VLC_OBJECT_INPUT
, input_name
);
300 if( p_input
== NULL
)
303 vlc_object_attach( p_input
, p_parent
);
305 /* Construct a nice name for the input timer */
306 char psz_timer_name
[255];
307 char * psz_name
= input_item_GetName( p_item
);
308 snprintf( psz_timer_name
, sizeof(psz_timer_name
),
309 "input launching for '%s'", psz_name
);
311 msg_Dbg( p_input
, "Creating an input for '%s'", psz_name
);
315 /* Start a timer to mesure how long it takes
316 * to launch an input */
317 stats_TimerStart( p_input
, psz_timer_name
,
318 STATS_TIMER_INPUT_LAUNCHING
);
320 p_input
->p
= calloc( 1, sizeof( input_thread_private_t
) );
324 /* Parse input options */
325 vlc_mutex_lock( &p_item
->lock
);
326 assert( (int)p_item
->optflagc
== p_item
->i_options
);
327 for( i
= 0; i
< p_item
->i_options
; i
++ )
328 var_OptionParse( VLC_OBJECT(p_input
), p_item
->ppsz_options
[i
],
329 !!(p_item
->optflagv
[i
] & VLC_INPUT_OPTION_TRUSTED
) );
330 vlc_mutex_unlock( &p_item
->lock
);
332 p_input
->b_preparsing
= b_quick
;
333 p_input
->psz_header
= psz_header
? strdup( psz_header
) : NULL
;
335 /* Init Common fields */
336 p_input
->b_eof
= false;
337 p_input
->p
->b_can_pace_control
= true;
338 p_input
->p
->i_start
= 0;
339 p_input
->p
->i_time
= 0;
340 p_input
->p
->i_stop
= 0;
341 p_input
->p
->i_run
= 0;
342 p_input
->p
->i_title
= 0;
343 p_input
->p
->title
= NULL
;
344 p_input
->p
->i_title_offset
= p_input
->p
->i_seekpoint_offset
= 0;
345 p_input
->p
->i_state
= INIT_S
;
346 double f_rate
= var_InheritFloat( p_input
, "rate" );
349 msg_Warn( p_input
, "Negative or zero rate values are forbidden" );
352 p_input
->p
->i_rate
= INPUT_RATE_DEFAULT
/ f_rate
;
353 p_input
->p
->b_recording
= false;
354 memset( &p_input
->p
->bookmark
, 0, sizeof(p_input
->p
->bookmark
) );
355 TAB_INIT( p_input
->p
->i_bookmark
, p_input
->p
->pp_bookmark
);
356 TAB_INIT( p_input
->p
->i_attachment
, p_input
->p
->attachment
);
357 p_input
->p
->p_sout
= NULL
;
358 p_input
->p
->b_out_pace_control
= false;
360 vlc_gc_incref( p_item
); /* Released in Destructor() */
361 p_input
->p
->p_item
= p_item
;
363 /* Init Input fields */
364 p_input
->p
->input
.p_access
= NULL
;
365 p_input
->p
->input
.p_stream
= NULL
;
366 p_input
->p
->input
.p_demux
= NULL
;
367 p_input
->p
->input
.b_title_demux
= false;
368 p_input
->p
->input
.i_title
= 0;
369 p_input
->p
->input
.title
= NULL
;
370 p_input
->p
->input
.i_title_offset
= p_input
->p
->input
.i_seekpoint_offset
= 0;
371 p_input
->p
->input
.b_can_pace_control
= true;
372 p_input
->p
->input
.b_can_rate_control
= true;
373 p_input
->p
->input
.b_rescale_ts
= true;
374 p_input
->p
->input
.b_eof
= false;
376 vlc_mutex_lock( &p_item
->lock
);
378 if( !p_item
->p_stats
)
379 p_item
->p_stats
= stats_NewInputStats( p_input
);
380 vlc_mutex_unlock( &p_item
->lock
);
383 p_input
->p
->i_slave
= 0;
384 p_input
->p
->slave
= NULL
;
389 p_input
->p
->p_resource_private
= NULL
;
390 p_input
->p
->p_resource
= input_resource_Hold( p_resource
);
394 p_input
->p
->p_resource_private
= input_resource_New( VLC_OBJECT( p_input
) );
395 p_input
->p
->p_resource
= input_resource_Hold( p_input
->p
->p_resource_private
);
397 input_resource_SetInput( p_input
->p
->p_resource
, p_input
);
399 /* Init control buffer */
400 vlc_mutex_init( &p_input
->p
->lock_control
);
401 vlc_cond_init( &p_input
->p
->wait_control
);
402 p_input
->p
->i_control
= 0;
403 p_input
->p
->b_abort
= false;
405 /* Create Object Variables for private use only */
406 input_ConfigVarInit( p_input
);
408 /* Create Objects variables for public Get and Set */
409 input_ControlVarInit( p_input
);
412 if( !p_input
->b_preparsing
)
414 char *psz_bookmarks
= var_GetNonEmptyString( p_input
, "bookmarks" );
417 /* FIXME: have a common cfg parsing routine used by sout and others */
418 char *psz_parser
, *psz_start
, *psz_end
;
419 psz_parser
= psz_bookmarks
;
420 while( (psz_start
= strchr( psz_parser
, '{' ) ) )
422 seekpoint_t
*p_seekpoint
;
425 psz_end
= strchr( psz_start
, '}' );
426 if( !psz_end
) break;
427 psz_parser
= psz_end
+ 1;
428 backup
= *psz_parser
;
432 p_seekpoint
= vlc_seekpoint_New();
433 while( (psz_end
= strchr( psz_start
, ',' ) ) )
436 if( !strncmp( psz_start
, "name=", 5 ) )
438 p_seekpoint
->psz_name
= strdup(psz_start
+ 5);
440 else if( !strncmp( psz_start
, "bytes=", 6 ) )
442 p_seekpoint
->i_byte_offset
= atoll(psz_start
+ 6);
444 else if( !strncmp( psz_start
, "time=", 5 ) )
446 p_seekpoint
->i_time_offset
= atoll(psz_start
+ 5) *
449 psz_start
= psz_end
+ 1;
451 msg_Dbg( p_input
, "adding bookmark: %s, bytes=%"PRId64
", time=%"PRId64
,
452 p_seekpoint
->psz_name
, p_seekpoint
->i_byte_offset
,
453 p_seekpoint
->i_time_offset
);
454 input_Control( p_input
, INPUT_ADD_BOOKMARK
, p_seekpoint
);
455 vlc_seekpoint_Delete( p_seekpoint
);
456 *psz_parser
= backup
;
458 free( psz_bookmarks
);
462 /* Remove 'Now playing' info as it is probably outdated */
463 input_item_SetNowPlaying( p_item
, NULL
);
464 input_SendEventMeta( p_input
);
467 if( p_input
->b_preparsing
)
468 p_input
->i_flags
|= OBJECT_FLAGS_QUIET
| OBJECT_FLAGS_NOINTERACT
;
470 /* Make sure the interaction option is honored */
471 if( !var_InheritBool( p_input
, "interact" ) )
472 p_input
->i_flags
|= OBJECT_FLAGS_NOINTERACT
;
475 memset( &p_input
->p
->counters
, 0, sizeof( p_input
->p
->counters
) );
476 vlc_mutex_init( &p_input
->p
->counters
.counters_lock
);
478 p_input
->p
->p_es_out_display
= input_EsOutNew( p_input
, p_input
->p
->i_rate
);
479 p_input
->p
->p_es_out
= NULL
;
481 /* Set the destructor when we are sure we are initialized */
482 vlc_object_set_destructor( p_input
, (vlc_destructor_t
)Destructor
);
488 * Input destructor (called when the object's refcount reaches 0).
490 static void Destructor( input_thread_t
* p_input
)
493 char * psz_name
= input_item_GetName( p_input
->p
->p_item
);
494 msg_Dbg( p_input
, "Destroying the input for '%s'", psz_name
);
498 stats_TimerDump( p_input
, STATS_TIMER_INPUT_LAUNCHING
);
499 stats_TimerClean( p_input
, STATS_TIMER_INPUT_LAUNCHING
);
501 if( p_input
->p
->p_es_out_display
)
502 es_out_Delete( p_input
->p
->p_es_out_display
);
504 if( p_input
->p
->p_resource
)
505 input_resource_Release( p_input
->p
->p_resource
);
506 if( p_input
->p
->p_resource_private
)
507 input_resource_Release( p_input
->p
->p_resource_private
);
509 vlc_gc_decref( p_input
->p
->p_item
);
511 vlc_mutex_destroy( &p_input
->p
->counters
.counters_lock
);
513 for( int i
= 0; i
< p_input
->p
->i_control
; i
++ )
515 input_control_t
*p_ctrl
= &p_input
->p
->control
[i
];
516 ControlRelease( p_ctrl
->i_type
, p_ctrl
->val
);
519 vlc_cond_destroy( &p_input
->p
->wait_control
);
520 vlc_mutex_destroy( &p_input
->p
->lock_control
);
524 /*****************************************************************************
525 * Run: main thread loop
526 * This is the "normal" thread that spawns the input processing chain,
527 * reads the stream, cleans up and waits
528 *****************************************************************************/
529 static void *Run( vlc_object_t
*p_this
)
531 input_thread_t
*p_input
= (input_thread_t
*)p_this
;
532 const int canc
= vlc_savecancel();
534 if( Init( p_input
) )
537 MainLoop( p_input
, true ); /* FIXME it can be wrong (like with VLM) */
543 /* Tell we're dead */
544 vlc_mutex_lock( &p_input
->p
->lock_control
);
545 const bool b_abort
= p_input
->p
->b_abort
;
546 vlc_mutex_unlock( &p_input
->p
->lock_control
);
549 input_SendEventAbort( p_input
);
550 input_SendEventDead( p_input
);
552 vlc_restorecancel( canc
);
556 /*****************************************************************************
557 * Main loop: Fill buffers from access, and demux
558 *****************************************************************************/
562 * It asks the demuxer to demux some data
564 static void MainLoopDemux( input_thread_t
*p_input
, bool *pb_changed
, bool *pb_demux_polled
, mtime_t i_start_mdate
)
569 *pb_demux_polled
= p_input
->p
->input
.p_demux
->pf_demux
!= NULL
;
571 if( ( p_input
->p
->i_stop
> 0 && p_input
->p
->i_time
>= p_input
->p
->i_stop
) ||
572 ( p_input
->p
->i_run
> 0 && i_start_mdate
+p_input
->p
->i_run
< mdate() ) )
575 i_ret
= demux_Demux( p_input
->p
->input
.p_demux
);
579 if( p_input
->p
->input
.p_demux
->info
.i_update
)
581 if( p_input
->p
->input
.b_title_demux
)
583 i_ret
= UpdateTitleSeekpointFromDemux( p_input
);
586 UpdateGenericFromDemux( p_input
);
588 else if( p_input
->p
->input
.p_access
&&
589 p_input
->p
->input
.p_access
->info
.i_update
)
591 if( !p_input
->p
->input
.b_title_demux
)
593 i_ret
= UpdateTitleSeekpointFromAccess( p_input
);
596 UpdateGenericFromAccess( p_input
);
600 if( i_ret
== 0 ) /* EOF */
602 msg_Dbg( p_input
, "EOF reached" );
603 p_input
->p
->input
.b_eof
= true;
607 input_ChangeState( p_input
, ERROR_S
);
610 if( i_ret
> 0 && p_input
->p
->i_slave
> 0 )
613 SlaveDemux( p_input
, &b_demux_polled
);
615 *pb_demux_polled
|= b_demux_polled
;
619 static int MainLoopTryRepeat( input_thread_t
*p_input
, mtime_t
*pi_start_mdate
)
621 int i_repeat
= var_GetInteger( p_input
, "input-repeat" );
627 msg_Dbg( p_input
, "repeating the same input (%d)", i_repeat
);
631 var_SetInteger( p_input
, "input-repeat", i_repeat
);
634 /* Seek to start title/seekpoint */
635 val
.i_int
= p_input
->p
->input
.i_title_start
-
636 p_input
->p
->input
.i_title_offset
;
637 if( val
.i_int
< 0 || val
.i_int
>= p_input
->p
->input
.i_title
)
639 input_ControlPush( p_input
,
640 INPUT_CONTROL_SET_TITLE
, &val
);
642 val
.i_int
= p_input
->p
->input
.i_seekpoint_start
-
643 p_input
->p
->input
.i_seekpoint_offset
;
644 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
645 input_ControlPush( p_input
,
646 INPUT_CONTROL_SET_SEEKPOINT
, &val
);
648 /* Seek to start position */
649 if( p_input
->p
->i_start
> 0 )
651 val
.i_time
= p_input
->p
->i_start
;
652 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &val
);
657 input_ControlPush( p_input
, INPUT_CONTROL_SET_POSITION
, &val
);
661 *pi_start_mdate
= mdate();
667 * It update the variables used by the interfaces
669 static void MainLoopInterface( input_thread_t
*p_input
)
671 double f_position
= 0.0;
673 mtime_t i_length
= 0;
675 /* update input status variables */
676 if( demux_Control( p_input
->p
->input
.p_demux
,
677 DEMUX_GET_POSITION
, &f_position
) )
680 if( demux_Control( p_input
->p
->input
.p_demux
,
681 DEMUX_GET_TIME
, &i_time
) )
683 p_input
->p
->i_time
= i_time
;
685 if( demux_Control( p_input
->p
->input
.p_demux
,
686 DEMUX_GET_LENGTH
, &i_length
) )
689 es_out_SetTimes( p_input
->p
->p_es_out
, f_position
, i_time
, i_length
);
691 /* update current bookmark */
692 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
693 p_input
->p
->bookmark
.i_time_offset
= i_time
;
694 if( p_input
->p
->input
.p_stream
)
695 p_input
->p
->bookmark
.i_byte_offset
= stream_Tell( p_input
->p
->input
.p_stream
);
696 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
701 * It updates the globals statics
703 static void MainLoopStatistic( input_thread_t
*p_input
)
705 stats_ComputeInputStats( p_input
, p_input
->p
->p_item
->p_stats
);
706 input_SendEventStatistics( p_input
);
711 * The main input loop.
713 static void MainLoop( input_thread_t
*p_input
, bool b_interactive
)
715 mtime_t i_start_mdate
= mdate();
716 mtime_t i_intf_update
= 0;
717 mtime_t i_statistic_update
= 0;
718 mtime_t i_last_seek_mdate
= 0;
719 bool b_pause_after_eof
= b_interactive
&&
720 var_CreateGetBool( p_input
, "play-and-pause" );
722 /* Start the timer */
723 stats_TimerStop( p_input
, STATS_TIMER_INPUT_LAUNCHING
);
725 while( vlc_object_alive( p_input
) && !p_input
->b_error
)
735 b_force_update
= false;
737 /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
738 * is paused -> this may cause problem with some of them
739 * The same problem can be seen when seeking while paused */
740 b_paused
= p_input
->p
->i_state
== PAUSE_S
&&
741 ( !es_out_GetBuffering( p_input
->p
->p_es_out
) || p_input
->p
->input
.b_eof
);
743 b_demux_polled
= true;
746 if( !p_input
->p
->input
.b_eof
)
748 MainLoopDemux( p_input
, &b_force_update
, &b_demux_polled
, i_start_mdate
);
750 i_wakeup
= es_out_GetWakeup( p_input
->p
->p_es_out
);
752 else if( !es_out_GetEmpty( p_input
->p
->p_es_out
) )
754 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
755 i_wakeup
= mdate() + INPUT_IDLE_SLEEP
;
757 /* Pause after eof only if the input is pausable.
758 * This way we won't trigger timeshifting for nothing */
759 else if( b_pause_after_eof
&& p_input
->p
->b_can_pause
)
761 msg_Dbg( p_input
, "pausing at EOF (pause after each)");
763 Control( p_input
, INPUT_CONTROL_SET_STATE
, val
);
765 b_pause_after_eof
= false;
770 if( MainLoopTryRepeat( p_input
, &i_start_mdate
) )
772 b_pause_after_eof
= var_GetBool( p_input
, "play-and-pause" );
778 mtime_t i_deadline
= i_wakeup
;
779 if( b_paused
|| !b_demux_polled
)
780 i_deadline
= __MIN( i_intf_update
, i_statistic_update
);
785 mtime_t i_limit
= i_deadline
;
787 /* We will postpone the execution of a seek until we have
788 * finished the ES bufferisation (postpone is limited to
790 bool b_buffering
= es_out_GetBuffering( p_input
->p
->p_es_out
) &&
791 !p_input
->p
->input
.b_eof
;
794 /* When postpone is in order, check the ES level every 20ms */
795 mtime_t i_current
= mdate();
796 if( i_last_seek_mdate
+ INT64_C(125000) >= i_current
)
797 i_limit
= __MIN( i_deadline
, i_current
+ INT64_C(20000) );
801 if( ControlPop( p_input
, &i_type
, &val
, i_limit
, b_buffering
) )
803 if( b_buffering
&& i_limit
< i_deadline
)
808 msg_Dbg( p_input
, "control type=%d", i_type
);
810 if( Control( p_input
, i_type
, val
) )
812 if( ControlIsSeekRequest( i_type
) )
813 i_last_seek_mdate
= mdate();
814 b_force_update
= true;
818 /* Update interface and statistics */
820 if( i_intf_update
< i_current
|| b_force_update
)
822 MainLoopInterface( p_input
);
823 i_intf_update
= i_current
+ INT64_C(250000);
824 b_force_update
= false;
826 if( i_statistic_update
< i_current
)
828 MainLoopStatistic( p_input
);
829 i_statistic_update
= i_current
+ INT64_C(1000000);
832 /* Update the wakeup time */
834 i_wakeup
= es_out_GetWakeup( p_input
->p
->p_es_out
);
835 } while( i_current
< i_wakeup
);
838 if( !p_input
->b_error
)
839 input_ChangeState( p_input
, END_S
);
842 static void InitStatistics( input_thread_t
* p_input
)
844 if( p_input
->b_preparsing
) return;
846 /* Prepare statistics */
847 #define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
848 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
849 if( libvlc_stats( p_input
) )
851 INIT_COUNTER( read_bytes
, INTEGER
, COUNTER
);
852 INIT_COUNTER( read_packets
, INTEGER
, COUNTER
);
853 INIT_COUNTER( demux_read
, INTEGER
, COUNTER
);
854 INIT_COUNTER( input_bitrate
, FLOAT
, DERIVATIVE
);
855 INIT_COUNTER( demux_bitrate
, FLOAT
, DERIVATIVE
);
856 INIT_COUNTER( demux_corrupted
, INTEGER
, COUNTER
);
857 INIT_COUNTER( demux_discontinuity
, INTEGER
, COUNTER
);
858 INIT_COUNTER( played_abuffers
, INTEGER
, COUNTER
);
859 INIT_COUNTER( lost_abuffers
, INTEGER
, COUNTER
);
860 INIT_COUNTER( displayed_pictures
, INTEGER
, COUNTER
);
861 INIT_COUNTER( lost_pictures
, INTEGER
, COUNTER
);
862 INIT_COUNTER( decoded_audio
, INTEGER
, COUNTER
);
863 INIT_COUNTER( decoded_video
, INTEGER
, COUNTER
);
864 INIT_COUNTER( decoded_sub
, INTEGER
, COUNTER
);
865 p_input
->p
->counters
.p_sout_send_bitrate
= NULL
;
866 p_input
->p
->counters
.p_sout_sent_packets
= NULL
;
867 p_input
->p
->counters
.p_sout_sent_bytes
= NULL
;
868 if( p_input
->p
->counters
.p_demux_bitrate
)
869 p_input
->p
->counters
.p_demux_bitrate
->update_interval
= 1000000;
870 if( p_input
->p
->counters
.p_input_bitrate
)
871 p_input
->p
->counters
.p_input_bitrate
->update_interval
= 1000000;
876 static int InitSout( input_thread_t
* p_input
)
878 if( p_input
->b_preparsing
)
881 /* Find a usable sout and attach it to p_input */
882 char *psz
= var_GetNonEmptyString( p_input
, "sout" );
883 if( psz
&& strncasecmp( p_input
->p
->p_item
->psz_uri
, "vlc:", 4 ) )
885 p_input
->p
->p_sout
= input_resource_RequestSout( p_input
->p
->p_resource
, NULL
, psz
);
886 if( !p_input
->p
->p_sout
)
888 input_ChangeState( p_input
, ERROR_S
);
889 msg_Err( p_input
, "cannot start stream output instance, " \
894 if( libvlc_stats( p_input
) )
896 INIT_COUNTER( sout_sent_packets
, INTEGER
, COUNTER
);
897 INIT_COUNTER( sout_sent_bytes
, INTEGER
, COUNTER
);
898 INIT_COUNTER( sout_send_bitrate
, FLOAT
, DERIVATIVE
);
899 if( p_input
->p
->counters
.p_sout_send_bitrate
)
900 p_input
->p
->counters
.p_sout_send_bitrate
->update_interval
=
906 input_resource_RequestSout( p_input
->p
->p_resource
, NULL
, NULL
);
914 static void InitTitle( input_thread_t
* p_input
)
916 input_source_t
*p_master
= &p_input
->p
->input
;
918 if( p_input
->b_preparsing
)
921 /* Create global title (from master) */
922 p_input
->p
->i_title
= p_master
->i_title
;
923 p_input
->p
->title
= p_master
->title
;
924 p_input
->p
->i_title_offset
= p_master
->i_title_offset
;
925 p_input
->p
->i_seekpoint_offset
= p_master
->i_seekpoint_offset
;
926 if( p_input
->p
->i_title
> 0 )
928 /* Setup variables */
929 input_ControlVarNavigation( p_input
);
930 input_SendEventTitle( p_input
, 0 );
934 p_input
->p
->b_can_pace_control
= p_master
->b_can_pace_control
;
935 p_input
->p
->b_can_pause
= p_master
->b_can_pause
;
936 p_input
->p
->b_can_rate_control
= p_master
->b_can_rate_control
;
939 static void StartTitle( input_thread_t
* p_input
)
943 /* Start title/chapter */
944 val
.i_int
= p_input
->p
->input
.i_title_start
-
945 p_input
->p
->input
.i_title_offset
;
946 if( val
.i_int
> 0 && val
.i_int
< p_input
->p
->input
.i_title
)
947 input_ControlPush( p_input
, INPUT_CONTROL_SET_TITLE
, &val
);
949 val
.i_int
= p_input
->p
->input
.i_seekpoint_start
-
950 p_input
->p
->input
.i_seekpoint_offset
;
951 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
952 input_ControlPush( p_input
, INPUT_CONTROL_SET_SEEKPOINT
, &val
);
954 /* Start/stop/run time */
955 p_input
->p
->i_start
= (int64_t)(1000000.0
956 * var_GetFloat( p_input
, "start-time" ));
957 p_input
->p
->i_stop
= (int64_t)(1000000.0
958 * var_GetFloat( p_input
, "stop-time" ));
959 p_input
->p
->i_run
= (int64_t)(1000000.0
960 * var_GetFloat( p_input
, "run-time" ));
961 if( p_input
->p
->i_run
< 0 )
963 msg_Warn( p_input
, "invalid run-time ignored" );
964 p_input
->p
->i_run
= 0;
967 if( p_input
->p
->i_start
> 0 )
971 msg_Dbg( p_input
, "starting at time: %ds",
972 (int)( p_input
->p
->i_start
/ INT64_C(1000000) ) );
974 s
.i_time
= p_input
->p
->i_start
;
975 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &s
);
977 if( p_input
->p
->i_stop
> 0 && p_input
->p
->i_stop
<= p_input
->p
->i_start
)
979 msg_Warn( p_input
, "invalid stop-time ignored" );
980 p_input
->p
->i_stop
= 0;
982 p_input
->p
->b_fast_seek
= var_GetBool( p_input
, "input-fast-seek" );
985 static void LoadSubtitles( input_thread_t
*p_input
)
988 /* Get fps and set it if not already set */
989 const double f_fps
= p_input
->p
->f_fps
;
992 float f_requested_fps
;
994 var_Create( p_input
, "sub-original-fps", VLC_VAR_FLOAT
);
995 var_SetFloat( p_input
, "sub-original-fps", f_fps
);
997 f_requested_fps
= var_CreateGetFloat( p_input
, "sub-fps" );
998 if( f_requested_fps
!= f_fps
)
1000 var_Create( p_input
, "sub-fps", VLC_VAR_FLOAT
|
1001 VLC_VAR_DOINHERIT
);
1002 var_SetFloat( p_input
, "sub-fps", f_requested_fps
);
1006 const int i_delay
= var_CreateGetInteger( p_input
, "sub-delay" );
1008 var_SetTime( p_input
, "spu-delay", (mtime_t
)i_delay
* 100000 );
1010 /* Look for and add subtitle files */
1011 bool b_forced
= true;
1013 char *psz_subtitle
= var_GetNonEmptyString( p_input
, "sub-file" );
1014 if( psz_subtitle
!= NULL
)
1016 msg_Dbg( p_input
, "forced subtitle: %s", psz_subtitle
);
1017 SubtitleAdd( p_input
, psz_subtitle
, b_forced
);
1021 if( var_GetBool( p_input
, "sub-autodetect-file" ) )
1023 char *psz_autopath
= var_GetNonEmptyString( p_input
, "sub-autodetect-path" );
1024 char **ppsz_subs
= subtitles_Detect( p_input
, psz_autopath
,
1025 p_input
->p
->p_item
->psz_uri
);
1026 free( psz_autopath
);
1028 for( int i
= 0; ppsz_subs
&& ppsz_subs
[i
]; i
++ )
1030 if( !psz_subtitle
|| strcmp( psz_subtitle
, ppsz_subs
[i
] ) )
1032 SubtitleAdd( p_input
, ppsz_subs
[i
], b_forced
);
1036 free( ppsz_subs
[i
] );
1040 free( psz_subtitle
);
1042 /* Load subtitles from attachments */
1043 int i_attachment
= 0;
1044 input_attachment_t
**pp_attachment
= NULL
;
1046 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1047 for( int i
= 0; i
< p_input
->p
->i_attachment
; i
++ )
1049 const input_attachment_t
*a
= p_input
->p
->attachment
[i
];
1050 if( !strcmp( a
->psz_mime
, "application/x-srt" ) )
1051 TAB_APPEND( i_attachment
, pp_attachment
,
1052 vlc_input_attachment_New( a
->psz_name
, NULL
,
1053 a
->psz_description
, NULL
, 0 ) );
1055 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1057 if( i_attachment
> 0 )
1058 var_Create( p_input
, "sub-description", VLC_VAR_STRING
);
1059 for( int i
= 0; i
< i_attachment
; i
++ )
1061 input_attachment_t
*a
= pp_attachment
[i
];
1065 if( a
->psz_name
[i
] &&
1066 asprintf( &psz_mrl
, "attachment://%s", a
->psz_name
) >= 0 )
1068 var_SetString( p_input
, "sub-description", a
->psz_description
? a
->psz_description
: "");
1070 SubtitleAdd( p_input
, psz_mrl
, b_forced
);
1075 vlc_input_attachment_Delete( a
);
1077 free( pp_attachment
);
1078 if( i_attachment
> 0 )
1079 var_Destroy( p_input
, "sub-description" );
1082 static void LoadSlaves( input_thread_t
*p_input
)
1084 char *psz
= var_GetNonEmptyString( p_input
, "input-slave" );
1088 char *psz_org
= psz
;
1089 while( psz
&& *psz
)
1091 while( *psz
== ' ' || *psz
== '#' )
1094 char *psz_delim
= strchr( psz
, '#' );
1096 *psz_delim
++ = '\0';
1101 msg_Dbg( p_input
, "adding slave input '%s'", psz
);
1103 input_source_t
*p_slave
= InputSourceNew( p_input
);
1104 if( p_slave
&& !InputSourceInit( p_input
, p_slave
, psz
, NULL
) )
1105 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, p_slave
);
1114 static void UpdatePtsDelay( input_thread_t
*p_input
)
1116 input_thread_private_t
*p_sys
= p_input
->p
;
1118 /* Get max pts delay from input source */
1119 mtime_t i_pts_delay
= p_sys
->input
.i_pts_delay
;
1120 for( int i
= 0; i
< p_sys
->i_slave
; i
++ )
1121 i_pts_delay
= __MAX( i_pts_delay
, p_sys
->slave
[i
]->i_pts_delay
);
1123 if( i_pts_delay
< 0 )
1126 /* Take care of audio/spu delay */
1127 const mtime_t i_audio_delay
= var_GetTime( p_input
, "audio-delay" );
1128 const mtime_t i_spu_delay
= var_GetTime( p_input
, "spu-delay" );
1129 const mtime_t i_extra_delay
= __MIN( i_audio_delay
, i_spu_delay
);
1130 if( i_extra_delay
< 0 )
1131 i_pts_delay
-= i_extra_delay
;
1133 /* Update cr_average depending on the caching */
1134 const int i_cr_average
= var_GetInteger( p_input
, "cr-average" ) * i_pts_delay
/ DEFAULT_PTS_DELAY
;
1137 es_out_SetDelay( p_input
->p
->p_es_out_display
, AUDIO_ES
, i_audio_delay
);
1138 es_out_SetDelay( p_input
->p
->p_es_out_display
, SPU_ES
, i_spu_delay
);
1139 es_out_SetJitter( p_input
->p
->p_es_out
, i_pts_delay
, 0, i_cr_average
);
1142 static void InitPrograms( input_thread_t
* p_input
)
1147 /* Compute correct pts_delay */
1148 UpdatePtsDelay( p_input
);
1151 i_es_out_mode
= ES_OUT_MODE_AUTO
;
1152 if( p_input
->p
->p_sout
)
1156 if( var_GetBool( p_input
, "sout-all" ) )
1158 i_es_out_mode
= ES_OUT_MODE_ALL
;
1161 if( (prgms
= var_GetNonEmptyString( p_input
, "programs" )) != NULL
)
1165 TAB_INIT( list
.i_count
, list
.p_values
);
1166 for( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1168 prgm
= strtok_r( NULL
, ",", &buf
) )
1170 vlc_value_t val
= { .i_int
= atoi( prgm
) };
1171 INSERT_ELEM( list
.p_values
, list
.i_count
, list
.i_count
, val
);
1174 if( list
.i_count
> 0 )
1175 i_es_out_mode
= ES_OUT_MODE_PARTIAL
;
1176 /* Note : we should remove the "program" callback. */
1181 es_out_SetMode( p_input
->p
->p_es_out
, i_es_out_mode
);
1183 /* Inform the demuxer about waited group (needed only for DVB) */
1184 if( i_es_out_mode
== ES_OUT_MODE_ALL
)
1186 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, -1, NULL
);
1188 else if( i_es_out_mode
== ES_OUT_MODE_PARTIAL
)
1190 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, -1,
1192 TAB_CLEAN( list
.i_count
, list
.p_values
);
1196 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
,
1197 es_out_GetGroupForced( p_input
->p
->p_es_out
), NULL
);
1201 static int Init( input_thread_t
* p_input
)
1206 for( i
= 0; i
< p_input
->p
->p_item
->i_options
; i
++ )
1208 if( !strncmp( p_input
->p
->p_item
->ppsz_options
[i
], "meta-file", 9 ) )
1210 msg_Dbg( p_input
, "Input is a meta file: disabling unneeded options" );
1211 var_SetString( p_input
, "sout", "" );
1212 var_SetBool( p_input
, "sout-all", false );
1213 var_SetString( p_input
, "input-slave", "" );
1214 var_SetInteger( p_input
, "input-repeat", 0 );
1215 var_SetString( p_input
, "sub-file", "" );
1216 var_SetBool( p_input
, "sub-autodetect-file", false );
1220 InitStatistics( p_input
);
1222 if( InitSout( p_input
) )
1227 p_input
->p
->p_es_out
= input_EsOutTimeshiftNew( p_input
, p_input
->p
->p_es_out_display
, p_input
->p
->i_rate
);
1230 input_ChangeState( p_input
, OPENING_S
);
1231 input_SendEventCache( p_input
, 0.0 );
1234 if( InputSourceInit( p_input
, &p_input
->p
->input
,
1235 p_input
->p
->p_item
->psz_uri
, NULL
) )
1240 InitTitle( p_input
);
1242 /* Load master infos */
1245 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_LENGTH
,
1249 i_length
= input_item_GetDuration( p_input
->p
->p_item
);
1250 input_SendEventLength( p_input
, i_length
);
1252 input_SendEventPosition( p_input
, 0.0, 0 );
1254 if( !p_input
->b_preparsing
)
1256 StartTitle( p_input
);
1257 LoadSubtitles( p_input
);
1258 LoadSlaves( p_input
);
1259 InitPrograms( p_input
);
1262 if( !p_input
->b_preparsing
&& p_input
->p
->p_sout
)
1264 p_input
->p
->b_out_pace_control
= (p_input
->p
->p_sout
->i_out_pace_nocontrol
> 0);
1266 if( p_input
->p
->b_can_pace_control
&& p_input
->p
->b_out_pace_control
)
1268 /* We don't want a high input priority here or we'll
1269 * end-up sucking up all the CPU time */
1270 vlc_thread_set_priority( p_input
, VLC_THREAD_PRIORITY_LOW
);
1273 msg_Dbg( p_input
, "starting in %s mode",
1274 p_input
->p
->b_out_pace_control
? "async" : "sync" );
1277 p_meta
= vlc_meta_New();
1280 /* Get meta data from users */
1281 InputMetaUser( p_input
, p_meta
);
1283 /* Get meta data from master input */
1284 InputSourceMeta( p_input
, &p_input
->p
->input
, p_meta
);
1286 /* And from slave */
1287 for( int i
= 0; i
< p_input
->p
->i_slave
; i
++ )
1288 InputSourceMeta( p_input
, p_input
->p
->slave
[i
], p_meta
);
1291 InputUpdateMeta( p_input
, p_meta
);
1294 msg_Dbg( p_input
, "`%s' successfully opened",
1295 p_input
->p
->p_item
->psz_uri
);
1297 /* initialization is complete */
1298 input_ChangeState( p_input
, PLAYING_S
);
1303 input_ChangeState( p_input
, ERROR_S
);
1305 if( p_input
->p
->p_es_out
)
1306 es_out_Delete( p_input
->p
->p_es_out
);
1307 es_out_SetMode( p_input
->p
->p_es_out_display
, ES_OUT_MODE_END
);
1308 if( p_input
->p
->p_resource
)
1310 if( p_input
->p
->p_sout
)
1311 input_resource_RequestSout( p_input
->p
->p_resource
,
1312 p_input
->p
->p_sout
, NULL
);
1313 input_resource_SetInput( p_input
->p
->p_resource
, NULL
);
1314 if( p_input
->p
->p_resource_private
)
1315 input_resource_Terminate( p_input
->p
->p_resource_private
);
1318 if( !p_input
->b_preparsing
&& libvlc_stats( p_input
) )
1320 #define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
1321 stats_CounterClean( p_input->p->counters.p_##c );\
1322 p_input->p->counters.p_##c = NULL; } while(0)
1323 EXIT_COUNTER( read_bytes
);
1324 EXIT_COUNTER( read_packets
);
1325 EXIT_COUNTER( demux_read
);
1326 EXIT_COUNTER( input_bitrate
);
1327 EXIT_COUNTER( demux_bitrate
);
1328 EXIT_COUNTER( demux_corrupted
);
1329 EXIT_COUNTER( demux_discontinuity
);
1330 EXIT_COUNTER( played_abuffers
);
1331 EXIT_COUNTER( lost_abuffers
);
1332 EXIT_COUNTER( displayed_pictures
);
1333 EXIT_COUNTER( lost_pictures
);
1334 EXIT_COUNTER( decoded_audio
);
1335 EXIT_COUNTER( decoded_video
);
1336 EXIT_COUNTER( decoded_sub
);
1338 if( p_input
->p
->p_sout
)
1340 EXIT_COUNTER( sout_sent_packets
);
1341 EXIT_COUNTER( sout_sent_bytes
);
1342 EXIT_COUNTER( sout_send_bitrate
);
1347 /* Mark them deleted */
1348 p_input
->p
->input
.p_demux
= NULL
;
1349 p_input
->p
->input
.p_stream
= NULL
;
1350 p_input
->p
->input
.p_access
= NULL
;
1351 p_input
->p
->p_es_out
= NULL
;
1352 p_input
->p
->p_sout
= NULL
;
1354 return VLC_EGENERIC
;
1357 /*****************************************************************************
1358 * End: end the input thread
1359 *****************************************************************************/
1360 static void End( input_thread_t
* p_input
)
1364 /* We are at the end */
1365 input_ChangeState( p_input
, END_S
);
1367 /* Clean control variables */
1368 input_ControlVarStop( p_input
);
1370 /* Stop es out activity */
1371 es_out_SetMode( p_input
->p
->p_es_out
, ES_OUT_MODE_NONE
);
1373 /* Clean up master */
1374 InputSourceClean( &p_input
->p
->input
);
1377 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
1379 InputSourceClean( p_input
->p
->slave
[i
] );
1380 free( p_input
->p
->slave
[i
] );
1382 free( p_input
->p
->slave
);
1384 /* Unload all modules */
1385 if( p_input
->p
->p_es_out
)
1386 es_out_Delete( p_input
->p
->p_es_out
);
1387 es_out_SetMode( p_input
->p
->p_es_out_display
, ES_OUT_MODE_END
);
1389 if( !p_input
->b_preparsing
)
1391 #define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
1392 if( libvlc_stats( p_input
) )
1394 /* make sure we are up to date */
1395 stats_ComputeInputStats( p_input
, p_input
->p
->p_item
->p_stats
);
1396 CL_CO( read_bytes
);
1397 CL_CO( read_packets
);
1398 CL_CO( demux_read
);
1399 CL_CO( input_bitrate
);
1400 CL_CO( demux_bitrate
);
1401 CL_CO( demux_corrupted
);
1402 CL_CO( demux_discontinuity
);
1403 CL_CO( played_abuffers
);
1404 CL_CO( lost_abuffers
);
1405 CL_CO( displayed_pictures
);
1406 CL_CO( lost_pictures
);
1407 CL_CO( decoded_audio
) ;
1408 CL_CO( decoded_video
);
1409 CL_CO( decoded_sub
) ;
1412 /* Close optional stream output instance */
1413 if( p_input
->p
->p_sout
)
1415 CL_CO( sout_sent_packets
);
1416 CL_CO( sout_sent_bytes
);
1417 CL_CO( sout_send_bitrate
);
1422 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1423 if( p_input
->p
->i_attachment
> 0 )
1425 for( i
= 0; i
< p_input
->p
->i_attachment
; i
++ )
1426 vlc_input_attachment_Delete( p_input
->p
->attachment
[i
] );
1427 TAB_CLEAN( p_input
->p
->i_attachment
, p_input
->p
->attachment
);
1429 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1432 input_resource_RequestSout( p_input
->p
->p_resource
,
1433 p_input
->p
->p_sout
, NULL
);
1434 input_resource_SetInput( p_input
->p
->p_resource
, NULL
);
1435 if( p_input
->p
->p_resource_private
)
1436 input_resource_Terminate( p_input
->p
->p_resource_private
);
1439 /*****************************************************************************
1441 *****************************************************************************/
1442 void input_ControlPush( input_thread_t
*p_input
,
1443 int i_type
, vlc_value_t
*p_val
)
1445 vlc_mutex_lock( &p_input
->p
->lock_control
);
1446 if( i_type
== INPUT_CONTROL_SET_DIE
)
1448 /* Special case, empty the control */
1449 for( int i
= 0; i
< p_input
->p
->i_control
; i
++ )
1451 input_control_t
*p_ctrl
= &p_input
->p
->control
[i
];
1452 ControlRelease( p_ctrl
->i_type
, p_ctrl
->val
);
1454 p_input
->p
->i_control
= 0;
1457 if( p_input
->p
->i_control
>= INPUT_CONTROL_FIFO_SIZE
)
1459 msg_Err( p_input
, "input control fifo overflow, trashing type=%d",
1462 ControlRelease( i_type
, *p_val
);
1471 memset( &c
.val
, 0, sizeof(c
.val
) );
1473 p_input
->p
->control
[p_input
->p
->i_control
++] = c
;
1475 vlc_cond_signal( &p_input
->p
->wait_control
);
1476 vlc_mutex_unlock( &p_input
->p
->lock_control
);
1479 static int ControlGetReducedIndexLocked( input_thread_t
*p_input
)
1481 const int i_lt
= p_input
->p
->control
[0].i_type
;
1483 for( i
= 1; i
< p_input
->p
->i_control
; i
++ )
1485 const int i_ct
= p_input
->p
->control
[i
].i_type
;
1488 ( i_ct
== INPUT_CONTROL_SET_STATE
||
1489 i_ct
== INPUT_CONTROL_SET_RATE
||
1490 i_ct
== INPUT_CONTROL_SET_POSITION
||
1491 i_ct
== INPUT_CONTROL_SET_TIME
||
1492 i_ct
== INPUT_CONTROL_SET_PROGRAM
||
1493 i_ct
== INPUT_CONTROL_SET_TITLE
||
1494 i_ct
== INPUT_CONTROL_SET_SEEKPOINT
||
1495 i_ct
== INPUT_CONTROL_SET_BOOKMARK
) )
1501 /* TODO but that's not that important
1502 - merge SET_X with SET_X_CMD
1503 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1504 - ignore SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1514 static inline int ControlPop( input_thread_t
*p_input
,
1515 int *pi_type
, vlc_value_t
*p_val
,
1516 mtime_t i_deadline
, bool b_postpone_seek
)
1518 input_thread_private_t
*p_sys
= p_input
->p
;
1520 vlc_mutex_lock( &p_sys
->lock_control
);
1521 while( p_sys
->i_control
<= 0 ||
1522 ( b_postpone_seek
&& ControlIsSeekRequest( p_sys
->control
[0].i_type
) ) )
1524 if( !vlc_object_alive( p_input
) || i_deadline
< 0 )
1526 vlc_mutex_unlock( &p_sys
->lock_control
);
1527 return VLC_EGENERIC
;
1530 if( vlc_cond_timedwait( &p_sys
->wait_control
, &p_sys
->lock_control
,
1533 vlc_mutex_unlock( &p_sys
->lock_control
);
1534 return VLC_EGENERIC
;
1539 const int i_index
= ControlGetReducedIndexLocked( p_input
);
1542 *pi_type
= p_sys
->control
[i_index
].i_type
;
1543 *p_val
= p_sys
->control
[i_index
].val
;
1545 p_sys
->i_control
-= i_index
+ 1;
1546 if( p_sys
->i_control
> 0 )
1547 memmove( &p_sys
->control
[0], &p_sys
->control
[i_index
+1],
1548 sizeof(*p_sys
->control
) * p_sys
->i_control
);
1549 vlc_mutex_unlock( &p_sys
->lock_control
);
1553 static bool ControlIsSeekRequest( int i_type
)
1557 case INPUT_CONTROL_SET_POSITION
:
1558 case INPUT_CONTROL_SET_TIME
:
1559 case INPUT_CONTROL_SET_TITLE
:
1560 case INPUT_CONTROL_SET_TITLE_NEXT
:
1561 case INPUT_CONTROL_SET_TITLE_PREV
:
1562 case INPUT_CONTROL_SET_SEEKPOINT
:
1563 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1564 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1565 case INPUT_CONTROL_SET_BOOKMARK
:
1572 static void ControlRelease( int i_type
, vlc_value_t val
)
1576 case INPUT_CONTROL_ADD_SUBTITLE
:
1577 case INPUT_CONTROL_ADD_SLAVE
:
1578 free( val
.psz_string
);
1587 static void ControlPause( input_thread_t
*p_input
, mtime_t i_control_date
)
1589 int i_ret
= VLC_SUCCESS
;
1590 int i_state
= PAUSE_S
;
1592 if( p_input
->p
->b_can_pause
)
1594 if( p_input
->p
->input
.p_access
)
1595 i_ret
= access_Control( p_input
->p
->input
.p_access
,
1596 ACCESS_SET_PAUSE_STATE
, true );
1598 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1599 DEMUX_SET_PAUSE_STATE
, true );
1603 msg_Warn( p_input
, "cannot set pause state" );
1609 i_ret
= es_out_SetPauseState( p_input
->p
->p_es_out
,
1610 p_input
->p
->b_can_pause
, true,
1614 msg_Warn( p_input
, "cannot set pause state at es_out level" );
1618 /* Switch to new state */
1619 input_ChangeState( p_input
, i_state
);
1622 static void ControlUnpause( input_thread_t
*p_input
, mtime_t i_control_date
)
1624 int i_ret
= VLC_SUCCESS
;
1626 if( p_input
->p
->b_can_pause
)
1628 if( p_input
->p
->input
.p_access
)
1629 i_ret
= access_Control( p_input
->p
->input
.p_access
,
1630 ACCESS_SET_PAUSE_STATE
, false );
1632 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1633 DEMUX_SET_PAUSE_STATE
, false );
1636 /* FIXME What to do ? */
1637 msg_Warn( p_input
, "cannot unset pause -> EOF" );
1638 input_ControlPush( p_input
, INPUT_CONTROL_SET_DIE
, NULL
);
1642 /* Switch to play */
1643 input_ChangeState( p_input
, PLAYING_S
);
1647 es_out_SetPauseState( p_input
->p
->p_es_out
, false, false, i_control_date
);
1650 static bool Control( input_thread_t
*p_input
,
1651 int i_type
, vlc_value_t val
)
1653 const mtime_t i_control_date
= mdate();
1654 /* FIXME b_force_update is abused, it should be carefully checked */
1655 bool b_force_update
= false;
1658 return b_force_update
;
1662 case INPUT_CONTROL_SET_DIE
:
1663 msg_Dbg( p_input
, "control: stopping input" );
1665 /* Mark all submodules to die */
1666 ObjectKillChildrens( p_input
, VLC_OBJECT(p_input
) );
1669 case INPUT_CONTROL_SET_POSITION
:
1673 if( p_input
->p
->b_recording
)
1675 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION(_OFFSET) ignored while recording" );
1678 f_pos
= val
.f_float
;
1679 if( i_type
!= INPUT_CONTROL_SET_POSITION
)
1680 f_pos
+= var_GetFloat( p_input
, "position" );
1683 else if( f_pos
> 1.0 )
1685 /* Reset the decoders states and clock sync (before calling the demuxer */
1686 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1687 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_POSITION
,
1688 f_pos
, !p_input
->p
->b_fast_seek
) )
1690 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1691 "%2.1f%% failed", f_pos
* 100 );
1695 if( p_input
->p
->i_slave
> 0 )
1696 SlaveSeek( p_input
);
1697 p_input
->p
->input
.b_eof
= false;
1699 b_force_update
= true;
1704 case INPUT_CONTROL_SET_TIME
:
1709 if( p_input
->p
->b_recording
)
1711 msg_Err( p_input
, "INPUT_CONTROL_SET_TIME(_OFFSET) ignored while recording" );
1715 i_time
= val
.i_time
;
1716 if( i_type
!= INPUT_CONTROL_SET_TIME
)
1717 i_time
+= var_GetTime( p_input
, "time" );
1722 /* Reset the decoders states and clock sync (before calling the demuxer */
1723 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1725 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1726 DEMUX_SET_TIME
, i_time
,
1727 !p_input
->p
->b_fast_seek
);
1732 /* Emulate it with a SET_POS */
1733 if( !demux_Control( p_input
->p
->input
.p_demux
,
1734 DEMUX_GET_LENGTH
, &i_length
) && i_length
> 0 )
1736 double f_pos
= (double)i_time
/ (double)i_length
;
1737 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1738 DEMUX_SET_POSITION
, f_pos
,
1739 !p_input
->p
->b_fast_seek
);
1744 msg_Warn( p_input
, "INPUT_CONTROL_SET_TIME(_OFFSET) %"PRId64
1745 " failed or not possible", i_time
);
1749 if( p_input
->p
->i_slave
> 0 )
1750 SlaveSeek( p_input
);
1751 p_input
->p
->input
.b_eof
= false;
1753 b_force_update
= true;
1758 case INPUT_CONTROL_SET_STATE
:
1759 if( val
.i_int
!= PLAYING_S
&& val
.i_int
!= PAUSE_S
)
1760 msg_Err( p_input
, "invalid state in INPUT_CONTROL_SET_STATE" );
1761 else if( p_input
->p
->i_state
== PAUSE_S
)
1763 ControlUnpause( p_input
, i_control_date
);
1765 b_force_update
= true;
1767 else if( val
.i_int
== PAUSE_S
&& p_input
->p
->i_state
== PLAYING_S
/* &&
1768 p_input->p->b_can_pause */ )
1770 ControlPause( p_input
, i_control_date
);
1772 b_force_update
= true;
1774 else if( val
.i_int
== PAUSE_S
&& !p_input
->p
->b_can_pause
&& 0 )
1776 b_force_update
= true;
1778 /* Correct "state" value */
1779 input_ChangeState( p_input
, p_input
->p
->i_state
);
1783 case INPUT_CONTROL_SET_RATE
:
1785 /* Get rate and direction */
1786 int i_rate
= abs( val
.i_int
);
1787 int i_rate_sign
= val
.i_int
< 0 ? -1 : 1;
1789 /* Check rate bound */
1790 if( i_rate
< INPUT_RATE_MIN
)
1792 msg_Dbg( p_input
, "cannot set rate faster" );
1793 i_rate
= INPUT_RATE_MIN
;
1795 else if( i_rate
> INPUT_RATE_MAX
)
1797 msg_Dbg( p_input
, "cannot set rate slower" );
1798 i_rate
= INPUT_RATE_MAX
;
1801 /* Apply direction */
1802 if( i_rate_sign
< 0 )
1804 if( p_input
->p
->input
.b_rescale_ts
)
1806 msg_Dbg( p_input
, "cannot set negative rate" );
1807 i_rate
= p_input
->p
->i_rate
;
1808 assert( i_rate
> 0 );
1812 i_rate
*= i_rate_sign
;
1816 if( i_rate
!= INPUT_RATE_DEFAULT
&&
1817 ( ( !p_input
->p
->b_can_rate_control
&& !p_input
->p
->input
.b_rescale_ts
) ||
1818 ( p_input
->p
->p_sout
&& !p_input
->p
->b_out_pace_control
) ) )
1820 msg_Dbg( p_input
, "cannot change rate" );
1821 i_rate
= INPUT_RATE_DEFAULT
;
1823 if( i_rate
!= p_input
->p
->i_rate
&&
1824 !p_input
->p
->b_can_pace_control
&& p_input
->p
->b_can_rate_control
)
1827 if( p_input
->p
->input
.p_access
)
1829 i_ret
= VLC_EGENERIC
;
1833 if( !p_input
->p
->input
.b_rescale_ts
)
1834 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_RESET_PCR
);
1836 i_ret
= demux_Control( p_input
->p
->input
.p_demux
,
1837 DEMUX_SET_RATE
, &i_rate
);
1841 msg_Warn( p_input
, "ACCESS/DEMUX_SET_RATE failed" );
1842 i_rate
= p_input
->p
->i_rate
;
1847 if( i_rate
!= p_input
->p
->i_rate
)
1849 p_input
->p
->i_rate
= i_rate
;
1850 input_SendEventRate( p_input
, i_rate
);
1852 if( p_input
->p
->input
.b_rescale_ts
)
1854 const int i_rate_source
= (p_input
->p
->b_can_pace_control
|| p_input
->p
->b_can_rate_control
) ? i_rate
: INPUT_RATE_DEFAULT
;
1855 es_out_SetRate( p_input
->p
->p_es_out
, i_rate_source
, i_rate
);
1858 b_force_update
= true;
1863 case INPUT_CONTROL_SET_PROGRAM
:
1864 /* No need to force update, es_out does it if needed */
1865 es_out_Control( p_input
->p
->p_es_out
,
1866 ES_OUT_SET_GROUP
, val
.i_int
);
1868 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, val
.i_int
,
1872 case INPUT_CONTROL_SET_ES
:
1873 /* No need to force update, es_out does it if needed */
1874 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_SET_ES_BY_ID
, val
.i_int
);
1877 case INPUT_CONTROL_RESTART_ES
:
1878 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_RESTART_ES_BY_ID
, val
.i_int
);
1881 case INPUT_CONTROL_SET_AUDIO_DELAY
:
1882 input_SendEventAudioDelay( p_input
, val
.i_time
);
1883 UpdatePtsDelay( p_input
);
1886 case INPUT_CONTROL_SET_SPU_DELAY
:
1887 input_SendEventSubtitleDelay( p_input
, val
.i_time
);
1888 UpdatePtsDelay( p_input
);
1891 case INPUT_CONTROL_SET_TITLE
:
1892 case INPUT_CONTROL_SET_TITLE_NEXT
:
1893 case INPUT_CONTROL_SET_TITLE_PREV
:
1894 if( p_input
->p
->b_recording
)
1896 msg_Err( p_input
, "INPUT_CONTROL_SET_TITLE(*) ignored while recording" );
1899 if( p_input
->p
->input
.b_title_demux
&&
1900 p_input
->p
->input
.i_title
> 0 )
1903 /* FIXME handle demux title */
1904 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1907 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
1908 i_title
= p_demux
->info
.i_title
- 1;
1909 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
1910 i_title
= p_demux
->info
.i_title
+ 1;
1912 i_title
= val
.i_int
;
1914 if( i_title
>= 0 && i_title
< p_input
->p
->input
.i_title
)
1916 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1918 demux_Control( p_demux
, DEMUX_SET_TITLE
, i_title
);
1919 input_SendEventTitle( p_input
, i_title
);
1922 else if( p_input
->p
->input
.i_title
> 0 )
1924 access_t
*p_access
= p_input
->p
->input
.p_access
;
1927 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
1928 i_title
= p_access
->info
.i_title
- 1;
1929 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
1930 i_title
= p_access
->info
.i_title
+ 1;
1932 i_title
= val
.i_int
;
1934 if( i_title
>= 0 && i_title
< p_input
->p
->input
.i_title
)
1936 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1938 stream_Control( p_input
->p
->input
.p_stream
, STREAM_CONTROL_ACCESS
,
1939 ACCESS_SET_TITLE
, i_title
);
1940 input_SendEventTitle( p_input
, i_title
);
1944 case INPUT_CONTROL_SET_SEEKPOINT
:
1945 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1946 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1947 if( p_input
->p
->b_recording
)
1949 msg_Err( p_input
, "INPUT_CONTROL_SET_SEEKPOINT(*) ignored while recording" );
1953 if( p_input
->p
->input
.b_title_demux
&&
1954 p_input
->p
->input
.i_title
> 0 )
1956 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1958 int64_t i_input_time
;
1959 int64_t i_seekpoint_time
;
1961 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
1963 i_seekpoint
= p_demux
->info
.i_seekpoint
;
1964 i_seekpoint_time
= p_input
->p
->input
.title
[p_demux
->info
.i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
1965 i_input_time
= var_GetTime( p_input
, "time" );
1966 if( i_seekpoint_time
>= 0 && i_input_time
>= 0 )
1968 if( i_input_time
< i_seekpoint_time
+ 3000000 )
1974 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
1975 i_seekpoint
= p_demux
->info
.i_seekpoint
+ 1;
1977 i_seekpoint
= val
.i_int
;
1979 if( i_seekpoint
>= 0 && i_seekpoint
<
1980 p_input
->p
->input
.title
[p_demux
->info
.i_title
]->i_seekpoint
)
1983 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
1985 demux_Control( p_demux
, DEMUX_SET_SEEKPOINT
, i_seekpoint
);
1986 input_SendEventSeekpoint( p_input
, p_demux
->info
.i_title
, i_seekpoint
);
1989 else if( p_input
->p
->input
.i_title
> 0 )
1991 access_t
*p_access
= p_input
->p
->input
.p_access
;
1993 int64_t i_input_time
;
1994 int64_t i_seekpoint_time
;
1996 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
1998 i_seekpoint
= p_access
->info
.i_seekpoint
;
1999 i_seekpoint_time
= p_input
->p
->input
.title
[p_access
->info
.i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
2000 i_input_time
= var_GetTime( p_input
, "time" );
2001 if( i_seekpoint_time
>= 0 && i_input_time
>= 0 )
2003 if( i_input_time
< i_seekpoint_time
+ 3000000 )
2009 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
2010 i_seekpoint
= p_access
->info
.i_seekpoint
+ 1;
2012 i_seekpoint
= val
.i_int
;
2014 if( i_seekpoint
>= 0 && i_seekpoint
<
2015 p_input
->p
->input
.title
[p_access
->info
.i_title
]->i_seekpoint
)
2017 es_out_SetTime( p_input
->p
->p_es_out
, -1 );
2019 stream_Control( p_input
->p
->input
.p_stream
, STREAM_CONTROL_ACCESS
,
2020 ACCESS_SET_SEEKPOINT
, i_seekpoint
);
2021 input_SendEventSeekpoint( p_input
, p_access
->info
.i_title
, i_seekpoint
);
2026 case INPUT_CONTROL_ADD_SUBTITLE
:
2027 if( val
.psz_string
)
2028 SubtitleAdd( p_input
, val
.psz_string
, true );
2031 case INPUT_CONTROL_ADD_SLAVE
:
2032 if( val
.psz_string
)
2034 input_source_t
*slave
= InputSourceNew( p_input
);
2036 if( slave
&& !InputSourceInit( p_input
, slave
, val
.psz_string
, NULL
) )
2042 msg_Dbg( p_input
, "adding %s as slave on the fly",
2046 if( demux_Control( p_input
->p
->input
.p_demux
,
2047 DEMUX_GET_TIME
, &i_time
) )
2049 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2050 InputSourceClean( slave
);
2054 if( demux_Control( slave
->p_demux
,
2055 DEMUX_SET_TIME
, i_time
, true ) )
2057 msg_Err( p_input
, "seek failed for new slave" );
2058 InputSourceClean( slave
);
2063 /* Get meta (access and demux) */
2064 p_meta
= vlc_meta_New();
2067 access_Control( slave
->p_access
, ACCESS_GET_META
, p_meta
);
2068 demux_Control( slave
->p_demux
, DEMUX_GET_META
, p_meta
);
2069 InputUpdateMeta( p_input
, p_meta
);
2072 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, slave
);
2077 msg_Warn( p_input
, "failed to add %s as slave",
2083 case INPUT_CONTROL_SET_RECORD_STATE
:
2084 if( !!p_input
->p
->b_recording
!= !!val
.b_bool
)
2086 if( p_input
->p
->input
.b_can_stream_record
)
2088 if( demux_Control( p_input
->p
->input
.p_demux
,
2089 DEMUX_SET_RECORD_STATE
, val
.b_bool
) )
2094 if( es_out_SetRecordState( p_input
->p
->p_es_out_display
, val
.b_bool
) )
2097 p_input
->p
->b_recording
= val
.b_bool
;
2099 input_SendEventRecord( p_input
, val
.b_bool
);
2101 b_force_update
= true;
2105 case INPUT_CONTROL_SET_FRAME_NEXT
:
2106 if( p_input
->p
->i_state
== PAUSE_S
)
2108 es_out_SetFrameNext( p_input
->p
->p_es_out
);
2110 else if( p_input
->p
->i_state
== PLAYING_S
)
2112 ControlPause( p_input
, i_control_date
);
2116 msg_Err( p_input
, "invalid state for frame next" );
2118 b_force_update
= true;
2121 case INPUT_CONTROL_SET_BOOKMARK
:
2123 seekpoint_t bookmark
;
2125 bookmark
.i_time_offset
= -1;
2126 bookmark
.i_byte_offset
= -1;
2128 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2129 if( val
.i_int
>= 0 && val
.i_int
< p_input
->p
->i_bookmark
)
2131 const seekpoint_t
*p_bookmark
= p_input
->p
->pp_bookmark
[val
.i_int
];
2132 bookmark
.i_time_offset
= p_bookmark
->i_time_offset
;
2133 bookmark
.i_byte_offset
= p_bookmark
->i_byte_offset
;
2135 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2137 if( bookmark
.i_time_offset
< 0 && bookmark
.i_byte_offset
< 0 )
2139 msg_Err( p_input
, "invalid bookmark %"PRId64
, val
.i_int
);
2143 if( bookmark
.i_time_offset
>= 0 )
2145 val
.i_time
= bookmark
.i_time_offset
;
2146 b_force_update
= Control( p_input
, INPUT_CONTROL_SET_TIME
, val
);
2148 else if( bookmark
.i_byte_offset
>= 0 &&
2149 p_input
->p
->input
.p_stream
)
2151 const uint64_t i_size
= stream_Size( p_input
->p
->input
.p_stream
);
2152 if( i_size
> 0 && bookmark
.i_byte_offset
<= i_size
)
2154 val
.f_float
= (double)bookmark
.i_byte_offset
/ i_size
;
2155 b_force_update
= Control( p_input
, INPUT_CONTROL_SET_POSITION
, val
);
2162 msg_Err( p_input
, "not yet implemented" );
2166 ControlRelease( i_type
, val
);
2167 return b_force_update
;
2170 /*****************************************************************************
2171 * UpdateTitleSeekpoint
2172 *****************************************************************************/
2173 static int UpdateTitleSeekpoint( input_thread_t
*p_input
,
2174 int i_title
, int i_seekpoint
)
2176 int i_title_end
= p_input
->p
->input
.i_title_end
-
2177 p_input
->p
->input
.i_title_offset
;
2178 int i_seekpoint_end
= p_input
->p
->input
.i_seekpoint_end
-
2179 p_input
->p
->input
.i_seekpoint_offset
;
2181 if( i_title_end
>= 0 && i_seekpoint_end
>= 0 )
2183 if( i_title
> i_title_end
||
2184 ( i_title
== i_title_end
&& i_seekpoint
> i_seekpoint_end
) )
2187 else if( i_seekpoint_end
>= 0 )
2189 if( i_seekpoint
> i_seekpoint_end
)
2192 else if( i_title_end
>= 0 )
2194 if( i_title
> i_title_end
)
2199 /*****************************************************************************
2201 *****************************************************************************/
2202 static int UpdateTitleSeekpointFromDemux( input_thread_t
*p_input
)
2204 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
2206 /* TODO event-like */
2207 if( p_demux
->info
.i_update
& INPUT_UPDATE_TITLE
)
2209 input_SendEventTitle( p_input
, p_demux
->info
.i_title
);
2211 p_demux
->info
.i_update
&= ~INPUT_UPDATE_TITLE
;
2213 if( p_demux
->info
.i_update
& INPUT_UPDATE_SEEKPOINT
)
2215 input_SendEventSeekpoint( p_input
,
2216 p_demux
->info
.i_title
, p_demux
->info
.i_seekpoint
);
2218 p_demux
->info
.i_update
&= ~INPUT_UPDATE_SEEKPOINT
;
2221 /* Hmmm only works with master input */
2222 if( p_input
->p
->input
.p_demux
== p_demux
)
2223 return UpdateTitleSeekpoint( p_input
,
2224 p_demux
->info
.i_title
,
2225 p_demux
->info
.i_seekpoint
);
2229 static void UpdateGenericFromDemux( input_thread_t
*p_input
)
2231 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
2233 if( p_demux
->info
.i_update
& INPUT_UPDATE_META
)
2235 vlc_meta_t
*p_meta
= vlc_meta_New();
2238 demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_META
, p_meta
);
2239 InputUpdateMeta( p_input
, p_meta
);
2241 p_demux
->info
.i_update
&= ~INPUT_UPDATE_META
;
2244 p_demux
->info
.i_update
&= ~INPUT_UPDATE_SIZE
;
2248 /*****************************************************************************
2249 * Update*FromAccess:
2250 *****************************************************************************/
2251 static int UpdateTitleSeekpointFromAccess( input_thread_t
*p_input
)
2253 access_t
*p_access
= p_input
->p
->input
.p_access
;
2255 if( p_access
->info
.i_update
& INPUT_UPDATE_TITLE
)
2257 input_SendEventTitle( p_input
, p_access
->info
.i_title
);
2259 stream_Control( p_input
->p
->input
.p_stream
, STREAM_UPDATE_SIZE
);
2261 p_access
->info
.i_update
&= ~INPUT_UPDATE_TITLE
;
2263 if( p_access
->info
.i_update
& INPUT_UPDATE_SEEKPOINT
)
2265 input_SendEventSeekpoint( p_input
,
2266 p_access
->info
.i_title
, p_access
->info
.i_seekpoint
);
2268 p_access
->info
.i_update
&= ~INPUT_UPDATE_SEEKPOINT
;
2270 /* Hmmm only works with master input */
2271 if( p_input
->p
->input
.p_access
== p_access
)
2272 return UpdateTitleSeekpoint( p_input
,
2273 p_access
->info
.i_title
,
2274 p_access
->info
.i_seekpoint
);
2277 static void UpdateGenericFromAccess( input_thread_t
*p_input
)
2279 access_t
*p_access
= p_input
->p
->input
.p_access
;
2281 if( p_access
->info
.i_update
& INPUT_UPDATE_META
)
2283 /* TODO maybe multi - access ? */
2284 vlc_meta_t
*p_meta
= vlc_meta_New();
2287 access_Control( p_input
->p
->input
.p_access
, ACCESS_GET_META
, p_meta
);
2288 InputUpdateMeta( p_input
, p_meta
);
2290 p_access
->info
.i_update
&= ~INPUT_UPDATE_META
;
2292 if( p_access
->info
.i_update
& INPUT_UPDATE_SIGNAL
)
2297 if( access_Control( p_access
, ACCESS_GET_SIGNAL
, &f_quality
, &f_strength
) )
2298 f_quality
= f_strength
= -1;
2300 input_SendEventSignal( p_input
, f_quality
, f_strength
);
2302 p_access
->info
.i_update
&= ~INPUT_UPDATE_SIGNAL
;
2305 p_access
->info
.i_update
&= ~INPUT_UPDATE_SIZE
;
2308 /*****************************************************************************
2310 *****************************************************************************/
2311 static input_source_t
*InputSourceNew( input_thread_t
*p_input
)
2313 VLC_UNUSED(p_input
);
2315 return calloc( 1, sizeof( input_source_t
) );
2318 /*****************************************************************************
2320 *****************************************************************************/
2321 static int InputSourceInit( input_thread_t
*p_input
,
2322 input_source_t
*in
, const char *psz_mrl
,
2323 const char *psz_forced_demux
)
2325 const char *psz_access
;
2326 const char *psz_demux
;
2328 char *psz_var_demux
= NULL
;
2332 char *psz_dup
= strdup( psz_mrl
);
2334 if( psz_dup
== NULL
)
2338 input_SplitMRL( &psz_access
, &psz_demux
, &psz_path
, psz_dup
);
2340 msg_Dbg( p_input
, "`%s' gives access `%s' demux `%s' path `%s'",
2341 psz_mrl
, psz_access
, psz_demux
, psz_path
);
2342 if( !p_input
->b_preparsing
)
2344 /* Hack to allow udp://@:port syntax */
2346 (strncmp( psz_access
, "udp", 3 ) &&
2347 strncmp( psz_access
, "rtp", 3 )) )
2349 /* Find optional titles and seekpoints */
2350 MRLSections( p_input
, psz_path
, &in
->i_title_start
, &in
->i_title_end
,
2351 &in
->i_seekpoint_start
, &in
->i_seekpoint_end
);
2354 if( psz_forced_demux
&& *psz_forced_demux
)
2356 psz_demux
= psz_forced_demux
;
2358 else if( *psz_demux
== '\0' )
2360 /* special hack for forcing a demuxer with --demux=module
2361 * (and do nothing with a list) */
2362 psz_var_demux
= var_GetNonEmptyString( p_input
, "demux" );
2364 if( psz_var_demux
!= NULL
&&
2365 !strchr(psz_var_demux
, ',' ) &&
2366 !strchr(psz_var_demux
, ':' ) )
2368 psz_demux
= psz_var_demux
;
2370 msg_Dbg( p_input
, "enforced demux ` %s'", psz_demux
);
2374 /* Try access_demux first */
2375 in
->p_demux
= demux_New( p_input
, p_input
, psz_access
, psz_demux
, psz_path
,
2376 NULL
, p_input
->p
->p_es_out
, false );
2380 /* Preparsing is only for file:// */
2383 if( !*psz_access
) /* path without scheme:// */
2384 psz_access
= "file";
2385 if( strcmp( psz_access
, "file" ) )
2387 msg_Dbg( p_input
, "trying to pre-parse %s", psz_path
);
2392 /* Get infos from access_demux */
2393 int i_ret
= demux_Control( in
->p_demux
,
2394 DEMUX_GET_PTS_DELAY
, &in
->i_pts_delay
);
2396 in
->i_pts_delay
= __MAX( 0, __MIN( in
->i_pts_delay
, INPUT_PTS_DELAY_MAX
) );
2399 in
->b_title_demux
= true;
2400 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2401 &in
->title
, &in
->i_title
,
2402 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2404 TAB_INIT( in
->i_title
, in
->title
);
2406 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_PACE
,
2407 &in
->b_can_pace_control
) )
2408 in
->b_can_pace_control
= false;
2410 assert( in
->p_demux
->pf_demux
!= NULL
|| !in
->b_can_pace_control
);
2412 if( !in
->b_can_pace_control
)
2414 if( demux_Control( in
->p_demux
, DEMUX_CAN_CONTROL_RATE
,
2415 &in
->b_can_rate_control
, &in
->b_rescale_ts
) )
2417 in
->b_can_rate_control
= false;
2418 in
->b_rescale_ts
= true; /* not used */
2423 in
->b_can_rate_control
= true;
2424 in
->b_rescale_ts
= true;
2426 if( demux_Control( in
->p_demux
, DEMUX_CAN_PAUSE
,
2427 &in
->b_can_pause
) )
2428 in
->b_can_pause
= false;
2429 var_SetBool( p_input
, "can-pause", in
->b_can_pause
|| !in
->b_can_pace_control
); /* XXX temporary because of es_out_timeshift*/
2430 var_SetBool( p_input
, "can-rate", !in
->b_can_pace_control
|| in
->b_can_rate_control
); /* XXX temporary because of es_out_timeshift*/
2431 var_SetBool( p_input
, "can-rewind", !in
->b_rescale_ts
&& !in
->b_can_pace_control
&& in
->b_can_rate_control
);
2434 if( demux_Control( in
->p_demux
, DEMUX_CAN_SEEK
, &b_can_seek
) )
2436 var_SetBool( p_input
, "can-seek", b_can_seek
);
2440 /* Now try a real access */
2441 in
->p_access
= access_New( p_input
, p_input
, psz_access
, psz_demux
, psz_path
);
2442 if( in
->p_access
== NULL
)
2444 if( vlc_object_alive( p_input
) )
2446 msg_Err( p_input
, "open of `%s' failed: %s", psz_mrl
,
2448 dialog_Fatal( p_input
, _("Your input can't be opened"),
2449 _("VLC is unable to open the MRL '%s'."
2450 " Check the log for details."), psz_mrl
);
2455 /* Get infos from access */
2456 if( !p_input
->b_preparsing
)
2459 access_Control( in
->p_access
,
2460 ACCESS_GET_PTS_DELAY
, &in
->i_pts_delay
);
2461 in
->i_pts_delay
= __MAX( 0, __MIN( in
->i_pts_delay
, INPUT_PTS_DELAY_MAX
) );
2463 in
->b_title_demux
= false;
2464 if( access_Control( in
->p_access
, ACCESS_GET_TITLE_INFO
,
2465 &in
->title
, &in
->i_title
,
2466 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2469 TAB_INIT( in
->i_title
, in
->title
);
2471 access_Control( in
->p_access
, ACCESS_CAN_CONTROL_PACE
,
2472 &in
->b_can_pace_control
);
2473 in
->b_can_rate_control
= in
->b_can_pace_control
;
2474 in
->b_rescale_ts
= true;
2476 access_Control( in
->p_access
, ACCESS_CAN_PAUSE
, &in
->b_can_pause
);
2477 var_SetBool( p_input
, "can-pause", in
->b_can_pause
|| !in
->b_can_pace_control
); /* XXX temporary because of es_out_timeshift*/
2478 var_SetBool( p_input
, "can-rate", !in
->b_can_pace_control
|| in
->b_can_rate_control
); /* XXX temporary because of es_out_timeshift*/
2479 var_SetBool( p_input
, "can-rewind", !in
->b_rescale_ts
&& !in
->b_can_pace_control
);
2481 access_Control( in
->p_access
, ACCESS_CAN_SEEK
, &b_can_seek
);
2482 var_SetBool( p_input
, "can-seek", b_can_seek
);
2487 char **ppsz_input_list
;
2489 TAB_INIT( i_input_list
, ppsz_input_list
);
2491 /* On master stream only, use input-list */
2492 if( &p_input
->p
->input
== in
)
2498 psz_parser
= var_CreateGetNonEmptyString( p_input
, "input-list" );
2500 while( psz_parser
&& *psz_parser
)
2502 char *p
= strchr( psz_parser
, ',' );
2508 char *psz_name
= strdup( psz_parser
);
2510 TAB_APPEND( i_input_list
, ppsz_input_list
, psz_name
);
2517 /* Autodetect extra files if none specified */
2518 if( i_input_list
<= 0 )
2520 InputGetExtraFiles( p_input
, &i_input_list
, &ppsz_input_list
,
2521 psz_access
, psz_path
);
2523 if( i_input_list
> 0 )
2524 TAB_APPEND( i_input_list
, ppsz_input_list
, NULL
);
2526 /* Create the stream_t */
2527 in
->p_stream
= stream_AccessNew( in
->p_access
, ppsz_input_list
);
2528 if( ppsz_input_list
)
2530 for( int i
= 0; ppsz_input_list
[i
] != NULL
; i
++ )
2531 free( ppsz_input_list
[i
] );
2532 TAB_CLEAN( i_input_list
, ppsz_input_list
);
2535 if( in
->p_stream
== NULL
)
2537 msg_Warn( p_input
, "cannot create a stream_t from access" );
2541 /* Add stream filters */
2542 char *psz_stream_filter
= var_GetNonEmptyString( p_input
,
2544 in
->p_stream
= stream_FilterChainNew( in
->p_stream
,
2546 var_GetBool( p_input
, "input-record-native" ) );
2547 free( psz_stream_filter
);
2549 /* Open a demuxer */
2550 if( *psz_demux
== '\0' && *in
->p_access
->psz_demux
)
2552 psz_demux
= in
->p_access
->psz_demux
;
2555 in
->p_demux
= demux_New( p_input
, p_input
, psz_access
, psz_demux
,
2556 /* Take access/stream redirections into account: */
2557 in
->p_stream
->psz_path
? in
->p_stream
->psz_path
: psz_path
,
2558 in
->p_stream
, p_input
->p
->p_es_out
,
2559 p_input
->b_preparsing
);
2561 if( in
->p_demux
== NULL
)
2563 if( vlc_object_alive( p_input
) )
2565 msg_Err( p_input
, "no suitable demux module for `%s/%s://%s'",
2566 psz_access
, psz_demux
, psz_path
);
2567 dialog_Fatal( VLC_OBJECT( p_input
),
2568 _("VLC can't recognize the input's format"),
2569 _("The format of '%s' cannot be detected. "
2570 "Have a look at the log for details."), psz_mrl
);
2574 assert( in
->p_demux
->pf_demux
!= NULL
);
2576 /* Get title from demux */
2577 if( !p_input
->b_preparsing
&& in
->i_title
<= 0 )
2579 if( demux_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2580 &in
->title
, &in
->i_title
,
2581 &in
->i_title_offset
, &in
->i_seekpoint_offset
))
2583 TAB_INIT( in
->i_title
, in
->title
);
2587 in
->b_title_demux
= true;
2592 free( psz_var_demux
);
2595 /* Set record capabilities */
2596 if( demux_Control( in
->p_demux
, DEMUX_CAN_RECORD
, &in
->b_can_stream_record
) )
2597 in
->b_can_stream_record
= false;
2599 if( !var_GetBool( p_input
, "input-record-native" ) )
2600 in
->b_can_stream_record
= false;
2601 var_SetBool( p_input
, "can-record", true );
2603 var_SetBool( p_input
, "can-record", in
->b_can_stream_record
);
2607 * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2608 if( 1 || !p_input
->b_preparsing
)
2611 input_attachment_t
**attachment
;
2612 if( !demux_Control( in
->p_demux
, DEMUX_GET_ATTACHMENTS
,
2613 &attachment
, &i_attachment
) )
2615 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2616 AppendAttachment( &p_input
->p
->i_attachment
, &p_input
->p
->attachment
,
2617 i_attachment
, attachment
);
2618 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2621 if( !demux_Control( in
->p_demux
, DEMUX_GET_FPS
, &f_fps
) && f_fps
> 0.0 )
2623 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2624 p_input
->p
->f_fps
= f_fps
;
2625 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2628 if( var_GetInteger( p_input
, "clock-synchro" ) != -1 )
2629 in
->b_can_pace_control
= !var_GetInteger( p_input
, "clock-synchro" );
2635 demux_Delete( in
->p_demux
);
2638 stream_Delete( in
->p_stream
);
2641 access_Delete( in
->p_access
);
2643 free( psz_var_demux
);
2646 return VLC_EGENERIC
;
2649 /*****************************************************************************
2651 *****************************************************************************/
2652 static void InputSourceClean( input_source_t
*in
)
2657 demux_Delete( in
->p_demux
);
2660 stream_Delete( in
->p_stream
);
2663 access_Delete( in
->p_access
);
2665 if( in
->i_title
> 0 )
2667 for( i
= 0; i
< in
->i_title
; i
++ )
2668 vlc_input_title_Delete( in
->title
[i
] );
2669 TAB_CLEAN( in
->i_title
, in
->title
);
2673 /*****************************************************************************
2675 *****************************************************************************/
2676 static void InputSourceMeta( input_thread_t
*p_input
,
2677 input_source_t
*p_source
, vlc_meta_t
*p_meta
)
2679 access_t
*p_access
= p_source
->p_access
;
2680 demux_t
*p_demux
= p_source
->p_demux
;
2682 /* XXX Remember that checking against p_item->p_meta->i_status & ITEM_PREPARSED
2687 /* Read access meta */
2688 has_meta
= p_access
&& !access_Control( p_access
, ACCESS_GET_META
, p_meta
);
2690 /* Read demux meta */
2691 has_meta
|= !demux_Control( p_demux
, DEMUX_GET_META
, p_meta
);
2693 bool has_unsupported
;
2694 if( demux_Control( p_demux
, DEMUX_HAS_UNSUPPORTED_META
, &has_unsupported
) )
2695 has_unsupported
= true;
2697 /* If the demux report unsupported meta data, or if we don't have meta data
2698 * try an external "meta reader" */
2699 if( has_meta
&& !has_unsupported
)
2702 demux_meta_t
*p_demux_meta
=
2703 vlc_custom_create( p_demux
, sizeof( *p_demux_meta
),
2704 VLC_OBJECT_GENERIC
, "demux meta" );
2707 vlc_object_attach( p_demux_meta
, p_demux
);
2708 p_demux_meta
->p_demux
= p_demux
;
2709 p_demux_meta
->p_item
= p_input
->p
->p_item
;
2711 module_t
*p_id3
= module_need( p_demux_meta
, "meta reader", NULL
, false );
2714 if( p_demux_meta
->p_meta
)
2716 vlc_meta_Merge( p_meta
, p_demux_meta
->p_meta
);
2717 vlc_meta_Delete( p_demux_meta
->p_meta
);
2720 if( p_demux_meta
->i_attachments
> 0 )
2722 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
2723 AppendAttachment( &p_input
->p
->i_attachment
, &p_input
->p
->attachment
,
2724 p_demux_meta
->i_attachments
, p_demux_meta
->attachments
);
2725 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
2727 module_unneed( p_demux
, p_id3
);
2729 vlc_object_release( p_demux_meta
);
2733 static void SlaveDemux( input_thread_t
*p_input
, bool *pb_demux_polled
)
2738 *pb_demux_polled
= false;
2739 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_TIME
, &i_time
) )
2741 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2745 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
2747 input_source_t
*in
= p_input
->p
->slave
[i
];
2753 const bool b_demux_polled
= in
->p_demux
->pf_demux
!= NULL
;
2754 if( !b_demux_polled
)
2757 *pb_demux_polled
= true;
2759 /* Call demux_Demux until we have read enough data */
2760 if( demux_Control( in
->p_demux
, DEMUX_SET_NEXT_DEMUX_TIME
, i_time
) )
2765 if( demux_Control( in
->p_demux
, DEMUX_GET_TIME
, &i_stime
) )
2767 msg_Err( p_input
, "slave[%d] doesn't like "
2768 "DEMUX_GET_TIME -> EOF", i
);
2773 if( i_stime
>= i_time
)
2779 if( ( i_ret
= demux_Demux( in
->p_demux
) ) <= 0 )
2785 i_ret
= demux_Demux( in
->p_demux
);
2790 msg_Dbg( p_input
, "slave %d EOF", i
);
2796 static void SlaveSeek( input_thread_t
*p_input
)
2801 if( demux_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_TIME
, &i_time
) )
2803 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2807 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
2809 input_source_t
*in
= p_input
->p
->slave
[i
];
2811 if( demux_Control( in
->p_demux
, DEMUX_SET_TIME
, i_time
, true ) )
2814 msg_Err( p_input
, "seek failed for slave %d -> EOF", i
);
2824 /*****************************************************************************
2826 *****************************************************************************/
2827 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2829 static const struct { int i_meta
; const char *psz_name
; } p_list
[] = {
2830 { vlc_meta_Title
, "meta-title" },
2831 { vlc_meta_Artist
, "meta-artist" },
2832 { vlc_meta_Genre
, "meta-genre" },
2833 { vlc_meta_Copyright
, "meta-copyright" },
2834 { vlc_meta_Description
, "meta-description" },
2835 { vlc_meta_Date
, "meta-date" },
2836 { vlc_meta_URL
, "meta-url" },
2840 /* Get meta information from user */
2841 for( int i
= 0; p_list
[i
].psz_name
; i
++ )
2843 char *psz_string
= var_GetNonEmptyString( p_input
, p_list
[i
].psz_name
);
2847 EnsureUTF8( psz_string
);
2848 vlc_meta_Set( p_meta
, p_list
[i
].i_meta
, psz_string
);
2853 /*****************************************************************************
2854 * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2855 * arturl and locking issue.
2856 *****************************************************************************/
2857 static void InputUpdateMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2859 es_out_ControlSetMeta( p_input
->p
->p_es_out
, p_meta
);
2860 vlc_meta_Delete( p_meta
);
2863 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
2864 int i_new
, input_attachment_t
**pp_new
)
2866 int i_attachment
= *pi_attachment
;
2867 input_attachment_t
**attachment
= *ppp_attachment
;
2870 attachment
= xrealloc( attachment
,
2871 sizeof(input_attachment_t
**) * ( i_attachment
+ i_new
) );
2872 for( i
= 0; i
< i_new
; i
++ )
2873 attachment
[i_attachment
++] = pp_new
[i
];
2877 *pi_attachment
= i_attachment
;
2878 *ppp_attachment
= attachment
;
2880 /*****************************************************************************
2881 * InputGetExtraFiles
2882 * Autodetect extra input list
2883 *****************************************************************************/
2884 static void InputGetExtraFilesPattern( input_thread_t
*p_input
,
2885 int *pi_list
, char ***pppsz_list
,
2886 const char *psz_path
,
2887 const char *psz_match
,
2888 const char *psz_format
,
2889 int i_start
, int i_stop
)
2894 TAB_INIT( i_list
, ppsz_list
);
2896 char *psz_base
= strdup( psz_path
);
2900 /* Remove the extension */
2901 char *psz_end
= &psz_base
[strlen(psz_base
)-strlen(psz_match
)];
2902 assert( psz_end
>= psz_base
);
2905 /* Try to list files */
2906 for( int i
= i_start
; i
<= i_stop
; i
++ )
2911 if( asprintf( &psz_file
, psz_format
, psz_base
, i
) < 0 )
2914 if( vlc_stat( psz_file
, &st
) || !S_ISREG( st
.st_mode
) || !st
.st_size
)
2920 msg_Dbg( p_input
, "Detected extra file `%s'", psz_file
);
2921 TAB_APPEND( i_list
, ppsz_list
, psz_file
);
2926 *pppsz_list
= ppsz_list
;
2929 static void InputGetExtraFiles( input_thread_t
*p_input
,
2930 int *pi_list
, char ***pppsz_list
,
2931 const char *psz_access
, const char *psz_path
)
2935 const char *psz_match
;
2936 const char *psz_format
;
2940 /* XXX the order is important */
2941 { ".001", "%s.%.3d", 2, 999 },
2942 { ".part1.rar", "%s.part%.1d.rar",2, 9 },
2943 { ".part01.rar", "%s.part%.2d.rar",2, 99, },
2944 { ".part001.rar", "%s.part%.3d.rar",2, 999 },
2945 { ".rar", "%s.r%.2d", 0, 99 },
2946 { NULL
, NULL
, 0, 0 }
2949 TAB_INIT( *pi_list
, *pppsz_list
);
2951 if( ( psz_access
&& *psz_access
&& strcmp( psz_access
, "file" ) ) || !psz_path
)
2954 const size_t i_path
= strlen(psz_path
);
2956 for( int i
= 0; p_pattern
[i
].psz_match
!= NULL
; i
++ )
2958 const size_t i_ext
= strlen(p_pattern
[i
].psz_match
);
2960 if( i_path
< i_ext
)
2962 if( !strcmp( &psz_path
[i_path
-i_ext
], p_pattern
[i
].psz_match
) )
2964 InputGetExtraFilesPattern( p_input
, pi_list
, pppsz_list
,
2966 p_pattern
[i
].psz_match
, p_pattern
[i
].psz_format
,
2967 p_pattern
[i
].i_start
, p_pattern
[i
].i_stop
);
2974 static void input_ChangeState( input_thread_t
*p_input
, int i_state
)
2976 const bool b_changed
= p_input
->p
->i_state
!= i_state
;
2978 p_input
->p
->i_state
= i_state
;
2979 if( i_state
== ERROR_S
)
2980 p_input
->b_error
= true;
2981 else if( i_state
== END_S
)
2982 p_input
->b_eof
= true;
2986 input_item_SetErrorWhenReading( p_input
->p
->p_item
, p_input
->b_error
);
2987 input_SendEventState( p_input
, i_state
);
2992 /*****************************************************************************
2993 * MRLSplit: parse the access, demux and url part of the
2994 * Media Resource Locator.
2995 *****************************************************************************/
2996 void input_SplitMRL( const char **ppsz_access
, const char **ppsz_demux
,
2997 char **ppsz_path
, char *psz_dup
)
2999 const char *psz_access
;
3000 const char *psz_demux
= "";
3003 /* Either there is an access/demux specification before ://
3004 * or we have a plain local file path. */
3005 psz_path
= strstr( psz_dup
, "://" );
3006 if( psz_path
!= NULL
)
3009 psz_path
+= 3; /* skips "://" */
3011 psz_access
= psz_dup
;
3012 /* We really don't want module name substitution here! */
3013 if( psz_access
[0] == '$' )
3016 /* Separate access from demux (<access>/<demux>://<path>) */
3017 char *p
= strchr( psz_access
, '/' );
3022 if( psz_demux
[0] == '$' )
3026 /* Remove HTML anchor if present (not supported).
3027 * The hash symbol itself should be URI-encoded. */
3028 p
= strchr( psz_path
, '#' );
3035 fprintf( stderr
, "%s(\"%s\"): not a valid URI!\n", __func__
,
3042 *ppsz_access
= psz_access
;
3043 *ppsz_demux
= psz_demux
;
3044 *ppsz_path
= psz_path
;
3047 static inline bool next(char ** src
)
3051 long result
= strtol( *src
, &end
, 0 );
3052 if( errno
!= 0 || result
>= LONG_MAX
|| result
<= LONG_MIN
||
3061 /*****************************************************************************
3062 * MRLSections: parse title and seekpoint info from the Media Resource Locator.
3065 * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
3066 *****************************************************************************/
3067 static void MRLSections( input_thread_t
*p_input
, char *psz_source
,
3068 int *pi_title_start
, int *pi_title_end
,
3069 int *pi_chapter_start
, int *pi_chapter_end
)
3071 char *psz
, *psz_end
, *psz_next
, *psz_check
;
3073 *pi_title_start
= *pi_title_end
= -1;
3074 *pi_chapter_start
= *pi_chapter_end
= -1;
3076 /* Start by parsing titles and chapters */
3077 if( !psz_source
|| !( psz
= strrchr( psz_source
, '@' ) ) ) return;
3080 /* Check we are really dealing with a title/chapter section */
3081 psz_check
= psz
+ 1;
3082 if( !*psz_check
) return;
3083 if( isdigit(*psz_check
) )
3084 if(!next(&psz_check
)) return;
3085 if( *psz_check
!= ':' && *psz_check
!= '-' && *psz_check
) return;
3086 if( *psz_check
== ':' && ++psz_check
)
3088 if( isdigit(*psz_check
) )
3089 if(!next(&psz_check
)) return;
3091 if( *psz_check
!= '-' && *psz_check
) return;
3092 if( *psz_check
== '-' && ++psz_check
)
3094 if( isdigit(*psz_check
) )
3095 if(!next(&psz_check
)) return;
3097 if( *psz_check
!= ':' && *psz_check
) return;
3098 if( *psz_check
== ':' && ++psz_check
)
3100 if( isdigit(*psz_check
) )
3101 if(!next(&psz_check
)) return;
3103 if( *psz_check
) return;
3105 /* Separate start and end */
3107 if( ( psz_end
= strchr( psz
, '-' ) ) ) *psz_end
++ = 0;
3109 /* Look for the start title */
3110 *pi_title_start
= strtol( psz
, &psz_next
, 0 );
3111 if( !*pi_title_start
&& psz
== psz_next
) *pi_title_start
= -1;
3112 *pi_title_end
= *pi_title_start
;
3115 /* Look for the start chapter */
3117 *pi_chapter_start
= strtol( psz
, &psz_next
, 0 );
3118 if( !*pi_chapter_start
&& psz
== psz_next
) *pi_chapter_start
= -1;
3119 *pi_chapter_end
= *pi_chapter_start
;
3123 /* Look for the end title */
3124 *pi_title_end
= strtol( psz_end
, &psz_next
, 0 );
3125 if( !*pi_title_end
&& psz_end
== psz_next
) *pi_title_end
= -1;
3128 /* Look for the end chapter */
3129 if( *psz_end
) psz_end
++;
3130 *pi_chapter_end
= strtol( psz_end
, &psz_next
, 0 );
3131 if( !*pi_chapter_end
&& psz_end
== psz_next
) *pi_chapter_end
= -1;
3134 msg_Dbg( p_input
, "source=`%s' title=%d/%d seekpoint=%d/%d",
3135 psz_source
, *pi_title_start
, *pi_chapter_start
,
3136 *pi_title_end
, *pi_chapter_end
);
3139 /*****************************************************************************
3140 * input_AddSubtitles: add a subtitles file and enable it
3141 *****************************************************************************/
3142 static void SubtitleAdd( input_thread_t
*p_input
, char *psz_subtitle
, bool b_forced
)
3144 input_source_t
*sub
;
3147 char *psz_path
, *psz_extension
;
3149 /* if we are provided a subtitle.sub file,
3150 * see if we don't have a subtitle.idx and use it instead */
3151 psz_path
= strdup( psz_subtitle
);
3154 psz_extension
= strrchr( psz_path
, '.');
3155 if( psz_extension
&& strcmp( psz_extension
, ".sub" ) == 0 )
3159 strcpy( psz_extension
, ".idx" );
3161 if( !vlc_stat( psz_path
, &st
) && S_ISREG( st
.st_mode
) )
3163 msg_Dbg( p_input
, "using %s subtitles file instead of %s",
3164 psz_path
, psz_subtitle
);
3165 strcpy( psz_subtitle
, psz_path
);
3171 char *url
= make_URI( psz_subtitle
, "file" );
3173 var_Change( p_input
, "spu-es", VLC_VAR_CHOICESCOUNT
, &count
, NULL
);
3175 sub
= InputSourceNew( p_input
);
3177 || InputSourceInit( p_input
, sub
, url
, "subtitle" ) )
3184 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, sub
);
3187 if( b_forced
&& !var_Change( p_input
, "spu-es", VLC_VAR_GETLIST
, &list
, NULL
) )
3189 if( count
.i_int
== 0 )
3191 /* if it was first one, there is disable too */
3193 if( count
.i_int
< list
.p_list
->i_count
)
3195 const int i_id
= list
.p_list
->p_values
[count
.i_int
].i_int
;
3197 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_SET_ES_DEFAULT_BY_ID
, i_id
);
3198 es_out_Control( p_input
->p
->p_es_out_display
, ES_OUT_SET_ES_BY_ID
, i_id
);
3200 var_FreeList( &list
, NULL
);
3204 /*****************************************************************************
3206 *****************************************************************************/
3207 void input_UpdateStatistic( input_thread_t
*p_input
,
3208 input_statistic_t i_type
, int i_delta
)
3210 assert( p_input
->p
->i_state
!= INIT_S
);
3212 vlc_mutex_lock( &p_input
->p
->counters
.counters_lock
);
3215 #define I(c) stats_UpdateInteger( p_input, p_input->p->counters.c, i_delta, NULL )
3216 case INPUT_STATISTIC_DECODED_VIDEO
:
3219 case INPUT_STATISTIC_DECODED_AUDIO
:
3222 case INPUT_STATISTIC_DECODED_SUBTITLE
:
3225 case INPUT_STATISTIC_SENT_PACKET
:
3226 I(p_sout_sent_packets
);
3229 case INPUT_STATISTIC_SENT_BYTE
:
3231 int i_bytes
; /* That's pretty stupid to define it as an integer, it will overflow
3233 if( !stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_sout_sent_bytes
, i_delta
, &i_bytes
) )
3234 stats_UpdateFloat( p_input
, p_input
->p
->counters
.p_sout_send_bitrate
, i_bytes
, NULL
);
3238 msg_Err( p_input
, "Invalid statistic type %d (internal error)", i_type
);
3241 vlc_mutex_unlock( &p_input
->p
->counters
.counters_lock
);
3245 /* TODO FIXME nearly the same logic that snapshot code */
3246 char *input_CreateFilename( vlc_object_t
*p_obj
, const char *psz_path
, const char *psz_prefix
, const char *psz_extension
)
3251 path
= vlc_opendir( psz_path
);
3256 char *psz_tmp
= str_format( p_obj
, psz_prefix
);
3260 filename_sanitize( psz_tmp
);
3262 if( asprintf( &psz_file
, "%s"DIR_SEP
"%s%s%s",
3264 psz_extension
? "." : "",
3265 psz_extension
? psz_extension
: "" ) < 0 )
3272 psz_file
= str_format( p_obj
, psz_path
);
3273 path_sanitize( psz_file
);