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 *****************************************************************************/
33 #include "input_internal.h"
36 #include "../stream_output/stream_output.h"
38 #include <vlc_playlist.h>
39 #include <vlc_interface.h>
41 #include <vlc_demux.h>
42 #include <vlc_charset.h>
44 #ifdef HAVE_SYS_STAT_H
45 # include <sys/stat.h>
48 /*****************************************************************************
50 *****************************************************************************/
51 static int Run ( input_thread_t
*p_input
);
52 static int RunAndDestroy ( input_thread_t
*p_input
);
54 static input_thread_t
* Create ( vlc_object_t
*, input_item_t
*,
55 const char *, vlc_bool_t
, sout_instance_t
* );
56 static int Init ( input_thread_t
*p_input
);
57 static void Error ( input_thread_t
*p_input
);
58 static void End ( input_thread_t
*p_input
);
59 static void MainLoop( input_thread_t
*p_input
);
60 static void Destroy( input_thread_t
*p_input
, sout_instance_t
**pp_sout
);
62 static inline int ControlPopNoLock( input_thread_t
*, int *, vlc_value_t
* );
63 static void ControlReduce( input_thread_t
* );
64 static vlc_bool_t
Control( input_thread_t
*, int, vlc_value_t
);
66 static int UpdateFromAccess( input_thread_t
* );
67 static int UpdateFromDemux( input_thread_t
* );
69 static void UpdateItemLength( input_thread_t
*, int64_t i_length
);
71 static void MRLSections( input_thread_t
*, char *, int *, int *, int *, int *);
73 static input_source_t
*InputSourceNew( input_thread_t
*);
74 static int InputSourceInit( input_thread_t
*, input_source_t
*,
75 const char *, const char *psz_forced_demux
);
76 static void InputSourceClean( input_source_t
* );
78 //static void InputGetAttachments( input_thread_t *, input_source_t * );
79 static void SlaveDemux( input_thread_t
*p_input
);
80 static void SlaveSeek( input_thread_t
*p_input
);
82 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
83 static void InputUpdateMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
);
85 static sout_instance_t
*SoutFind( vlc_object_t
*p_parent
, input_item_t
*p_item
, vlc_bool_t
* );
86 static void SoutKeep( sout_instance_t
* );
88 static void DemuxMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
, demux_t
*p_demux
);
89 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
90 int i_new
, input_attachment_t
**pp_new
);
92 /*****************************************************************************
93 * This function creates a new input, and returns a pointer
94 * to its description. On error, it returns NULL.
96 * Variables for _public_ use:
99 * - rate,rate-slower, rate-faster
100 * - position, position-offset
101 * - time, time-offset
102 * - title,title-next,title-prev
103 * - chapter,chapter-next, chapter-prev
104 * - program, audio-es, video-es, spu-es
105 * - audio-delay, spu-delay
110 * - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
111 * * For intf callback upon changes
113 * TODO explain when Callback is called
114 * TODO complete this list (?)
115 *****************************************************************************/
116 static input_thread_t
*Create( vlc_object_t
*p_parent
, input_item_t
*p_item
,
117 const char *psz_header
, vlc_bool_t b_quick
, sout_instance_t
*p_sout
)
119 input_thread_t
*p_input
= NULL
; /* thread descriptor */
123 /* Allocate descriptor */
124 p_input
= vlc_object_create( p_parent
, VLC_OBJECT_INPUT
);
125 if( p_input
== NULL
)
127 msg_Err( p_parent
, "out of memory" );
130 MALLOC_NULL( p_input
->p
, input_thread_private_t
);
132 /* One "randomly" selected input thread is responsible for computing
133 * the global stats. Check if there is already someone doing this */
134 if( p_input
->p_libvlc
->p_playlist
->p_stats
&& !b_quick
)
136 vlc_mutex_lock( &p_input
->p_libvlc
->p_playlist
->p_stats
->lock
);
137 if( p_input
->p_libvlc
->p_playlist
->p_stats_computer
== NULL
)
139 p_input
->p_libvlc
->p_playlist
->p_stats_computer
= p_input
;
141 vlc_mutex_unlock( &p_input
->p_libvlc
->p_playlist
->p_stats
->lock
);
144 p_input
->b_preparsing
= b_quick
;
145 p_input
->psz_header
= psz_header
? strdup( psz_header
) : NULL
;
147 /* Init Common fields */
148 p_input
->b_eof
= VLC_FALSE
;
149 p_input
->b_can_pace_control
= VLC_TRUE
;
150 p_input
->p
->i_start
= 0;
152 p_input
->p
->i_stop
= 0;
153 p_input
->p
->i_run
= 0;
154 p_input
->p
->i_title
= 0;
155 p_input
->p
->title
= NULL
;
156 p_input
->p
->i_title_offset
= p_input
->p
->i_seekpoint_offset
= 0;
157 p_input
->i_state
= INIT_S
;
158 p_input
->p
->i_rate
= INPUT_RATE_DEFAULT
;
159 TAB_INIT( p_input
->p
->i_bookmark
, p_input
->p
->bookmark
);
160 TAB_INIT( p_input
->p
->i_attachment
, p_input
->p
->attachment
);
161 p_input
->p
->p_es_out
= NULL
;
162 p_input
->p
->p_sout
= NULL
;
163 p_input
->p
->b_sout_keep
= VLC_FALSE
;
164 p_input
->p
->b_out_pace_control
= VLC_FALSE
;
165 p_input
->i_pts_delay
= 0;
167 /* Init Input fields */
168 p_input
->p
->input
.p_item
= p_item
;
169 p_input
->p
->input
.p_access
= NULL
;
170 p_input
->p
->input
.p_stream
= NULL
;
171 p_input
->p
->input
.p_demux
= NULL
;
172 p_input
->p
->input
.b_title_demux
= VLC_FALSE
;
173 p_input
->p
->input
.i_title
= 0;
174 p_input
->p
->input
.title
= NULL
;
175 p_input
->p
->input
.i_title_offset
= p_input
->p
->input
.i_seekpoint_offset
= 0;
176 p_input
->p
->input
.b_can_pace_control
= VLC_TRUE
;
177 p_input
->p
->input
.b_can_rate_control
= VLC_TRUE
;
178 p_input
->p
->input
.b_rescale_ts
= VLC_TRUE
;
179 p_input
->p
->input
.b_eof
= VLC_FALSE
;
180 p_input
->p
->input
.i_cr_average
= 0;
182 vlc_mutex_lock( &p_item
->lock
);
184 if( !p_item
->p_stats
)
185 p_item
->p_stats
= stats_NewInputStats( p_input
);
186 vlc_mutex_unlock( &p_item
->lock
);
189 p_input
->p
->i_slave
= 0;
190 p_input
->p
->slave
= NULL
;
192 /* Init control buffer */
193 vlc_mutex_init( p_input
, &p_input
->p
->lock_control
);
194 p_input
->p
->i_control
= 0;
196 /* Parse input options */
197 vlc_mutex_lock( &p_item
->lock
);
198 for( i
= 0; i
< p_item
->i_options
; i
++ )
199 var_OptionParse( p_input
, p_item
->ppsz_options
[i
] );
200 vlc_mutex_unlock( &p_item
->lock
);
202 /* Create Object Variables for private use only */
203 input_ConfigVarInit( p_input
);
205 /* Create Objects variables for public Get and Set */
206 input_ControlVarInit( p_input
);
208 p_input
->p
->input
.i_cr_average
= var_GetInteger( p_input
, "cr-average" );
210 if( !p_input
->b_preparsing
)
212 var_Get( p_input
, "bookmarks", &val
);
215 /* FIXME: have a common cfg parsing routine used by sout and others */
216 char *psz_parser
, *psz_start
, *psz_end
;
217 psz_parser
= val
.psz_string
;
218 while( (psz_start
= strchr( psz_parser
, '{' ) ) )
220 seekpoint_t
*p_seekpoint
= vlc_seekpoint_New();
223 psz_end
= strchr( psz_start
, '}' );
224 if( !psz_end
) break;
225 psz_parser
= psz_end
+ 1;
226 backup
= *psz_parser
;
229 while( (psz_end
= strchr( psz_start
, ',' ) ) )
232 if( !strncmp( psz_start
, "name=", 5 ) )
234 p_seekpoint
->psz_name
= strdup(psz_start
+ 5);
236 else if( !strncmp( psz_start
, "bytes=", 6 ) )
238 p_seekpoint
->i_byte_offset
= atoll(psz_start
+ 6);
240 else if( !strncmp( psz_start
, "time=", 5 ) )
242 p_seekpoint
->i_time_offset
= atoll(psz_start
+ 5) *
245 psz_start
= psz_end
+ 1;
247 msg_Dbg( p_input
, "adding bookmark: %s, bytes="I64Fd
", time="I64Fd
,
248 p_seekpoint
->psz_name
, p_seekpoint
->i_byte_offset
,
249 p_seekpoint
->i_time_offset
);
250 input_Control( p_input
, INPUT_ADD_BOOKMARK
, p_seekpoint
);
251 vlc_seekpoint_Delete( p_seekpoint
);
252 *psz_parser
= backup
;
254 free( val
.psz_string
);
258 /* Remove 'Now playing' info as it is probably outdated */
259 input_Control( p_input
, INPUT_DEL_INFO
,
260 _(VLC_META_INFO_CAT
),
261 _(VLC_META_NOW_PLAYING
) );
262 input_item_SetNowPlaying( p_item
, NULL
);
265 if( p_input
->b_preparsing
)
266 p_input
->i_flags
|= OBJECT_FLAGS_QUIET
| OBJECT_FLAGS_NOINTERACT
;
270 p_input
->p
->p_sout
= p_sout
;
272 /* Attach only once we are ready */
273 vlc_object_attach( p_input
, p_parent
);
278 static void Destroy( input_thread_t
*p_input
, sout_instance_t
**pp_sout
)
280 vlc_object_detach( p_input
);
281 input_thread_private_t
*priv
= p_input
->p
;
288 *pp_sout
= priv
->p_sout
;
289 else if( priv
->b_sout_keep
)
290 SoutKeep( priv
->p_sout
);
292 sout_DeleteInstance( priv
->p_sout
);
295 vlc_object_destroy( p_input
);
296 vlc_mutex_destroy( &priv
->lock_control
);
301 * Initialize an input thread and run it. You will need to monitor the
302 * thread to clean up after it is done
304 * \param p_parent a vlc_object
305 * \param p_item an input item
306 * \return a pointer to the spawned input thread
308 input_thread_t
*__input_CreateThread( vlc_object_t
*p_parent
,
309 input_item_t
*p_item
)
311 vlc_bool_t b_sout_keep
;
312 sout_instance_t
*p_sout
= SoutFind( p_parent
, p_item
, &b_sout_keep
);
313 input_thread_t
*p_input
= __input_CreateThreadExtended( p_parent
, p_item
, NULL
, p_sout
);
315 if( !p_input
&& p_sout
)
318 p_input
->p
->b_sout_keep
= b_sout_keep
;
323 input_thread_t
*__input_CreateThreadExtended( vlc_object_t
*p_parent
,
324 input_item_t
*p_item
,
325 const char *psz_log
, sout_instance_t
*p_sout
)
327 input_thread_t
*p_input
;
329 p_input
= Create( p_parent
, p_item
, psz_log
, VLC_FALSE
, p_sout
);
333 /* Create thread and wait for its readiness. */
334 if( vlc_thread_create( p_input
, "input", Run
,
335 VLC_THREAD_PRIORITY_INPUT
, VLC_TRUE
) )
337 input_ChangeState( p_input
, ERROR_S
);
338 msg_Err( p_input
, "cannot create input thread" );
339 Destroy( p_input
, &p_sout
);
347 * Initialize an input thread and run it. This thread will clean after himself,
348 * you can forget about it. It can work either in blocking or non-blocking mode
350 * \param p_parent a vlc_object
351 * \param p_item an input item
352 * \param b_block should we block until read is finished ?
353 * \return the input object id if non blocking, an error code else
355 int __input_Read( vlc_object_t
*p_parent
, input_item_t
*p_item
,
358 vlc_bool_t b_sout_keep
;
359 sout_instance_t
*p_sout
= SoutFind( p_parent
, p_item
, &b_sout_keep
);
360 input_thread_t
*p_input
;
362 p_input
= Create( p_parent
, p_item
, NULL
, VLC_FALSE
, p_sout
);
363 if( !p_input
&& p_sout
)
368 p_input
->p
->b_sout_keep
= b_sout_keep
;
372 RunAndDestroy( p_input
);
377 if( vlc_thread_create( p_input
, "input", RunAndDestroy
,
378 VLC_THREAD_PRIORITY_INPUT
, VLC_TRUE
) )
380 input_ChangeState( p_input
, ERROR_S
);
381 msg_Err( p_input
, "cannot create input thread" );
382 Destroy( p_input
, NULL
);
386 return p_input
->i_object_id
;
390 * Initialize an input and initialize it to preparse the item
391 * This function is blocking. It will only accept to parse files
393 * \param p_parent a vlc_object_t
394 * \param p_item an input item
395 * \return VLC_SUCCESS or an error
397 int __input_Preparse( vlc_object_t
*p_parent
, input_item_t
*p_item
)
399 input_thread_t
*p_input
;
401 /* Allocate descriptor */
402 p_input
= Create( p_parent
, p_item
, NULL
, VLC_TRUE
, NULL
);
406 if( !Init( p_input
) )
409 Destroy( p_input
, NULL
);
415 * Request a running input thread to stop and die
417 * \param the input thread to stop
419 void input_StopThread( input_thread_t
*p_input
)
424 /* Set die for input */
425 vlc_object_kill( p_input
);
426 /* FIXME: seems to be duplicated in ControlPush(INPUT_CONTROL_SET_DIE) */
428 /* We cannot touch p_input fields directly (we come from another thread),
429 * so use the vlc_object_find way, it's perfectly safe */
431 /* Set die for all access */
432 p_list
= vlc_list_find( p_input
, VLC_OBJECT_ACCESS
, FIND_CHILD
);
433 for( i
= 0; i
< p_list
->i_count
; i
++ )
435 vlc_object_kill( p_list
->p_values
[i
].p_object
);
437 vlc_list_release( p_list
);
439 /* Set die for all stream */
440 p_list
= vlc_list_find( p_input
, VLC_OBJECT_STREAM
, FIND_CHILD
);
441 for( i
= 0; i
< p_list
->i_count
; i
++ )
443 vlc_object_kill( p_list
->p_values
[i
].p_object
);
445 vlc_list_release( p_list
);
447 /* Set die for all demux */
448 p_list
= vlc_list_find( p_input
, VLC_OBJECT_DEMUX
, FIND_CHILD
);
449 for( i
= 0; i
< p_list
->i_count
; i
++ )
451 vlc_object_kill( p_list
->p_values
[i
].p_object
);
453 vlc_list_release( p_list
);
455 input_ControlPush( p_input
, INPUT_CONTROL_SET_DIE
, NULL
);
459 * Clean up a dead input thread
460 * This function does not return until the thread is effectively cancelled.
462 * \param the input thread to kill
464 void input_DestroyThread( input_thread_t
*p_input
)
466 input_DestroyThreadExtended( p_input
, NULL
);
469 void input_DestroyThreadExtended( input_thread_t
*p_input
, sout_instance_t
**pp_sout
)
471 /* Join the thread */
472 vlc_thread_join( p_input
);
475 Destroy( p_input
, pp_sout
);
478 /*****************************************************************************
479 * Run: main thread loop
480 * This is the "normal" thread that spawns the input processing chain,
481 * reads the stream, cleans up and waits
482 *****************************************************************************/
483 static int Run( input_thread_t
*p_input
)
485 /* Signal that the thread is launched */
486 vlc_thread_ready( p_input
);
488 if( Init( p_input
) )
490 /* If we failed, wait before we are killed, and exit */
491 p_input
->b_error
= VLC_TRUE
;
492 playlist_Signal( pl_Get( p_input
) );
496 /* Tell we're dead */
497 p_input
->b_dead
= VLC_TRUE
;
504 if( !p_input
->b_eof
&& !p_input
->b_error
&& p_input
->p
->input
.b_eof
)
506 /* We have finish to demux data but not to play them */
507 while( !p_input
->b_die
)
509 if( input_EsOutDecodersEmpty( p_input
->p
->p_es_out
) )
512 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
514 msleep( INPUT_IDLE_SLEEP
);
517 /* We have finished */
518 p_input
->b_eof
= VLC_TRUE
;
519 playlist_Signal( pl_Get( p_input
) );
522 /* Wait until we are asked to die */
523 if( !p_input
->b_die
)
534 /*****************************************************************************
535 * RunAndDestroy: main thread loop
536 * This is the "just forget me" thread that spawns the input processing chain,
537 * reads the stream, cleans up and releases memory
538 *****************************************************************************/
539 static int RunAndDestroy( input_thread_t
*p_input
)
541 /* Signal that the thread is launched */
542 vlc_thread_ready( p_input
);
544 if( Init( p_input
) )
549 if( !p_input
->b_eof
&& !p_input
->b_error
&& p_input
->p
->input
.b_eof
)
551 /* We have finished demuxing data but not playing it */
552 while( !p_input
->b_die
)
554 if( input_EsOutDecodersEmpty( p_input
->p
->p_es_out
) )
557 msg_Dbg( p_input
, "waiting decoder fifos to empty" );
559 msleep( INPUT_IDLE_SLEEP
);
562 /* We have finished */
563 p_input
->b_eof
= VLC_TRUE
;
571 Destroy( p_input
, NULL
);
575 /*****************************************************************************
576 * Main loop: Fill buffers from access, and demux
577 *****************************************************************************/
578 static void MainLoop( input_thread_t
*p_input
)
580 int64_t i_start_mdate
= mdate();
581 int64_t i_intf_update
= 0;
584 while( !p_input
->b_die
&& !p_input
->b_error
&& !p_input
->p
->input
.b_eof
)
586 vlc_bool_t b_force_update
= VLC_FALSE
;
592 if( p_input
->i_state
!= PAUSE_S
)
594 if( ( p_input
->p
->i_stop
> 0 && p_input
->i_time
>= p_input
->p
->i_stop
) ||
595 ( p_input
->p
->i_run
> 0 && i_start_mdate
+p_input
->p
->i_run
< mdate() ) )
598 i_ret
= p_input
->p
->input
.p_demux
->pf_demux(p_input
->p
->input
.p_demux
);
603 if( p_input
->p
->input
.b_title_demux
&&
604 p_input
->p
->input
.p_demux
->info
.i_update
)
606 i_ret
= UpdateFromDemux( p_input
);
607 b_force_update
= VLC_TRUE
;
609 else if( !p_input
->p
->input
.b_title_demux
&&
610 p_input
->p
->input
.p_access
&&
611 p_input
->p
->input
.p_access
->info
.i_update
)
613 i_ret
= UpdateFromAccess( p_input
);
614 b_force_update
= VLC_TRUE
;
618 if( i_ret
== 0 ) /* EOF */
622 var_Get( p_input
, "input-repeat", &repeat
);
623 if( repeat
.i_int
== 0 )
625 /* End of file - we do not set b_die because only the
626 * playlist is allowed to do so. */
627 input_ChangeState( p_input
, END_S
);
628 msg_Dbg( p_input
, "EOF reached" );
629 p_input
->p
->input
.b_eof
= VLC_TRUE
;
633 msg_Dbg( p_input
, "repeating the same input (%d)",
635 if( repeat
.i_int
> 0 )
638 var_Set( p_input
, "input-repeat", repeat
);
641 /* Seek to start title/seekpoint */
642 val
.i_int
= p_input
->p
->input
.i_title_start
-
643 p_input
->p
->input
.i_title_offset
;
644 if( val
.i_int
< 0 || val
.i_int
>= p_input
->p
->input
.i_title
)
646 input_ControlPush( p_input
,
647 INPUT_CONTROL_SET_TITLE
, &val
);
649 val
.i_int
= p_input
->p
->input
.i_seekpoint_start
-
650 p_input
->p
->input
.i_seekpoint_offset
;
651 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
652 input_ControlPush( p_input
,
653 INPUT_CONTROL_SET_SEEKPOINT
, &val
);
655 /* Seek to start position */
656 if( p_input
->p
->i_start
> 0 )
658 val
.i_time
= p_input
->p
->i_start
;
659 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
,
665 input_ControlPush( p_input
, INPUT_CONTROL_SET_POSITION
,
670 i_start_mdate
= mdate();
675 p_input
->b_error
= VLC_TRUE
;
678 if( i_ret
> 0 && p_input
->p
->i_slave
> 0 )
680 SlaveDemux( p_input
);
690 vlc_mutex_lock( &p_input
->p
->lock_control
);
691 ControlReduce( p_input
);
692 while( !ControlPopNoLock( p_input
, &i_type
, &val
) )
694 msg_Dbg( p_input
, "control type=%d", i_type
);
695 if( Control( p_input
, i_type
, val
) )
696 b_force_update
= VLC_TRUE
;
698 vlc_mutex_unlock( &p_input
->p
->lock_control
);
700 if( b_force_update
|| i_intf_update
< mdate() )
704 int64_t i_time
, i_length
;
705 /* update input status variables */
706 if( !demux2_Control( p_input
->p
->input
.p_demux
,
707 DEMUX_GET_POSITION
, &f_pos
) )
709 val
.f_float
= (float)f_pos
;
710 var_Change( p_input
, "position", VLC_VAR_SETVALUE
, &val
, NULL
);
712 if( !demux2_Control( p_input
->p
->input
.p_demux
,
713 DEMUX_GET_TIME
, &i_time
) )
715 p_input
->i_time
= i_time
;
717 var_Change( p_input
, "time", VLC_VAR_SETVALUE
, &val
, NULL
);
719 if( !demux2_Control( p_input
->p
->input
.p_demux
,
720 DEMUX_GET_LENGTH
, &i_length
) )
723 var_Get( p_input
, "length", &old_val
);
724 val
.i_time
= i_length
;
725 var_Change( p_input
, "length", VLC_VAR_SETVALUE
, &val
, NULL
);
727 if( old_val
.i_time
!= val
.i_time
)
729 UpdateItemLength( p_input
, i_length
);
733 var_SetBool( p_input
, "intf-change", VLC_TRUE
);
734 i_intf_update
= mdate() + I64C(150000);
736 /* 150ms * 8 = ~ 1 second */
737 if( ++i_updates
% 8 == 0 )
739 stats_ComputeInputStats( p_input
, p_input
->p
->input
.p_item
->p_stats
);
740 /* Are we the thread responsible for computing global stats ? */
741 if( p_input
->p_libvlc
->p_playlist
->p_stats_computer
== p_input
)
743 stats_ComputeGlobalStats( p_input
->p_libvlc
->p_playlist
,
744 p_input
->p_libvlc
->p_playlist
->p_stats
);
750 static int Init( input_thread_t
* p_input
)
760 /* Initialize optional stream output. (before access/demuxer)
761 * XXX: we add a special case if the uri starts by vlc.
762 * else 'vlc in.file --sout "" vlc:quit' cannot work (the output will
763 * be destroyed in case of a file).
764 * (this will break playing of file starting by 'vlc:' but I don't
765 * want to add more logic, just force file by file:// or code it ;)
767 memset( &p_input
->p
->counters
, 0, sizeof( p_input
->p
->counters
) );
768 vlc_mutex_init( p_input
, &p_input
->p
->counters
.counters_lock
);
770 for( i
= 0; i
< p_input
->p
->input
.p_item
->i_options
; i
++ )
772 if( !strncmp( p_input
->p
->input
.p_item
->ppsz_options
[i
], "meta-file", 9 ) )
774 msg_Dbg( p_input
, "Input is a meta file: disabling unneeded options" );
775 var_SetString( p_input
, "sout", "" );
776 var_SetBool( p_input
, "sout-all", VLC_FALSE
);
777 var_SetString( p_input
, "input-slave", "" );
778 var_SetInteger( p_input
, "input-repeat", 0 );
779 var_SetString( p_input
, "sub-file", "" );
780 var_SetBool( p_input
, "sub-autodetect-file", VLC_FALSE
);
784 if( !p_input
->b_preparsing
)
786 /* Prepare statistics */
787 #define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
788 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
789 if( p_input
->p_libvlc
->b_stats
)
791 INIT_COUNTER( read_bytes
, INTEGER
, COUNTER
);
792 INIT_COUNTER( read_packets
, INTEGER
, COUNTER
);
793 INIT_COUNTER( demux_read
, INTEGER
, COUNTER
);
794 INIT_COUNTER( input_bitrate
, FLOAT
, DERIVATIVE
);
795 INIT_COUNTER( demux_bitrate
, FLOAT
, DERIVATIVE
);
796 INIT_COUNTER( played_abuffers
, INTEGER
, COUNTER
);
797 INIT_COUNTER( lost_abuffers
, INTEGER
, COUNTER
);
798 INIT_COUNTER( displayed_pictures
, INTEGER
, COUNTER
);
799 INIT_COUNTER( lost_pictures
, INTEGER
, COUNTER
);
800 INIT_COUNTER( decoded_audio
, INTEGER
, COUNTER
);
801 INIT_COUNTER( decoded_video
, INTEGER
, COUNTER
);
802 INIT_COUNTER( decoded_sub
, INTEGER
, COUNTER
);
803 p_input
->p
->counters
.p_sout_send_bitrate
= NULL
;
804 p_input
->p
->counters
.p_sout_sent_packets
= NULL
;
805 p_input
->p
->counters
.p_sout_sent_bytes
= NULL
;
806 if( p_input
->p
->counters
.p_demux_bitrate
)
807 p_input
->p
->counters
.p_demux_bitrate
->update_interval
= 1000000;
808 if( p_input
->p
->counters
.p_input_bitrate
)
809 p_input
->p
->counters
.p_input_bitrate
->update_interval
= 1000000;
812 /* Find a usable sout and attach it to p_input */
813 psz
= var_GetNonEmptyString( p_input
, "sout" );
814 if( psz
&& strncasecmp( p_input
->p
->input
.p_item
->psz_uri
, "vlc:", 4 ) )
816 /* Check the validity of the provided sout */
817 if( p_input
->p
->p_sout
)
819 if( strcmp( p_input
->p
->p_sout
->psz_sout
, psz
) )
821 msg_Dbg( p_input
, "destroying unusable sout" );
823 sout_DeleteInstance( p_input
->p
->p_sout
);
824 p_input
->p
->p_sout
= NULL
;
828 if( p_input
->p
->p_sout
)
831 msg_Dbg( p_input
, "sout keep: reusing sout" );
832 msg_Dbg( p_input
, "sout keep: you probably want to use "
833 "gather stream_out" );
834 vlc_object_attach( p_input
->p
->p_sout
, p_input
);
838 /* Create a new one */
839 p_input
->p
->p_sout
= sout_NewInstance( p_input
, psz
);
840 if( !p_input
->p
->p_sout
)
842 input_ChangeState( p_input
, ERROR_S
);
843 msg_Err( p_input
, "cannot start stream output instance, " \
850 if( p_input
->p_libvlc
->b_stats
)
852 INIT_COUNTER( sout_sent_packets
, INTEGER
, COUNTER
);
853 INIT_COUNTER (sout_sent_bytes
, INTEGER
, COUNTER
);
854 INIT_COUNTER( sout_send_bitrate
, FLOAT
, DERIVATIVE
);
855 if( p_input
->p
->counters
.p_sout_send_bitrate
)
856 p_input
->p
->counters
.p_sout_send_bitrate
->update_interval
=
860 else if( p_input
->p
->p_sout
)
862 msg_Dbg( p_input
, "destroying useless sout" );
864 sout_DeleteInstance( p_input
->p
->p_sout
);
865 p_input
->p
->p_sout
= NULL
;
871 p_input
->p
->p_es_out
= input_EsOutNew( p_input
, p_input
->p
->i_rate
);
872 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_SET_ACTIVE
, VLC_FALSE
);
873 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_SET_MODE
, ES_OUT_MODE_NONE
);
875 var_Create( p_input
, "bit-rate", VLC_VAR_INTEGER
);
876 var_Create( p_input
, "sample-rate", VLC_VAR_INTEGER
);
878 if( InputSourceInit( p_input
, &p_input
->p
->input
,
879 p_input
->p
->input
.p_item
->psz_uri
, NULL
) )
884 /* Create global title (from master) */
885 if( !p_input
->b_preparsing
)
887 p_input
->p
->i_title
= p_input
->p
->input
.i_title
;
888 p_input
->p
->title
= p_input
->p
->input
.title
;
889 p_input
->p
->i_title_offset
= p_input
->p
->input
.i_title_offset
;
890 p_input
->p
->i_seekpoint_offset
= p_input
->p
->input
.i_seekpoint_offset
;
891 if( p_input
->p
->i_title
> 0 )
893 /* Setup variables */
894 input_ControlVarNavigation( p_input
);
895 input_ControlVarTitle( p_input
, 0 );
899 p_input
->b_can_pace_control
= p_input
->p
->input
.b_can_pace_control
;
900 p_input
->p
->b_can_pause
= p_input
->p
->input
.b_can_pause
;
901 p_input
->p
->b_can_rate_control
= p_input
->p
->input
.b_can_rate_control
;
904 if( p_input
->i_pts_delay
< 0 )
905 p_input
->i_pts_delay
= 0;
907 /* If the desynchronisation requested by the user is < 0, we need to
908 * cache more data. */
909 var_Get( p_input
, "audio-desync", &val
);
910 if( val
.i_int
< 0 ) p_input
->i_pts_delay
-= (val
.i_int
* 1000);
912 /* Update cr_average depending on the caching */
913 p_input
->p
->input
.i_cr_average
*= (10 * p_input
->i_pts_delay
/ 200000);
914 p_input
->p
->input
.i_cr_average
/= 10;
915 if( p_input
->p
->input
.i_cr_average
< 10 ) p_input
->p
->input
.i_cr_average
= 10;
918 /* Load master infos */
920 if( !demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_LENGTH
,
921 &val
.i_time
) && val
.i_time
> 0 )
923 var_Change( p_input
, "length", VLC_VAR_SETVALUE
, &val
, NULL
);
924 UpdateItemLength( p_input
, val
.i_time
);
928 val
.i_time
= input_item_GetDuration( p_input
->p
->input
.p_item
);
930 { /* fallback: gets length from metadata */
931 var_Change( p_input
, "length", VLC_VAR_SETVALUE
, &val
, NULL
);
932 UpdateItemLength( p_input
, val
.i_time
);
936 /* Start title/chapter */
937 if( !p_input
->b_preparsing
)
939 val
.i_int
= p_input
->p
->input
.i_title_start
-
940 p_input
->p
->input
.i_title_offset
;
941 if( val
.i_int
> 0 && val
.i_int
< p_input
->p
->input
.i_title
)
942 input_ControlPush( p_input
, INPUT_CONTROL_SET_TITLE
, &val
);
943 val
.i_int
= p_input
->p
->input
.i_seekpoint_start
-
944 p_input
->p
->input
.i_seekpoint_offset
;
945 if( val
.i_int
> 0 /* TODO: check upper boundary */ )
946 input_ControlPush( p_input
, INPUT_CONTROL_SET_SEEKPOINT
, &val
);
950 p_input
->p
->i_start
= I64C(1000000) * var_GetInteger( p_input
, "start-time" );
951 p_input
->p
->i_stop
= I64C(1000000) * var_GetInteger( p_input
, "stop-time" );
952 p_input
->p
->i_run
= I64C(1000000) * var_GetInteger( p_input
, "run-time" );
953 if( p_input
->p
->i_run
< 0 )
955 msg_Warn( p_input
, "invalid run-time ignored" );
956 p_input
->p
->i_run
= 0;
959 if( p_input
->p
->i_start
> 0 )
961 if( p_input
->p
->i_start
>= val
.i_time
)
963 msg_Warn( p_input
, "invalid start-time ignored" );
969 msg_Dbg( p_input
, "starting at time: %ds",
970 (int)( p_input
->p
->i_start
/ I64C(1000000) ) );
972 s
.i_time
= p_input
->p
->i_start
;
973 input_ControlPush( p_input
, INPUT_CONTROL_SET_TIME
, &s
);
976 if( p_input
->p
->i_stop
> 0 && p_input
->p
->i_stop
<= p_input
->p
->i_start
)
978 msg_Warn( p_input
, "invalid stop-time ignored" );
979 p_input
->p
->i_stop
= 0;
983 /* Get fps and set it if not already set */
984 if( !demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_FPS
, &f_fps
) &&
987 float f_requested_fps
;
989 var_Create( p_input
, "sub-original-fps", VLC_VAR_FLOAT
);
990 var_SetFloat( p_input
, "sub-original-fps", f_fps
);
992 f_requested_fps
= var_CreateGetFloat( p_input
, "sub-fps" );
993 if( f_requested_fps
!= f_fps
)
995 var_Create( p_input
, "sub-fps", VLC_VAR_FLOAT
|
997 var_SetFloat( p_input
, "sub-fps", f_requested_fps
);
1001 i_delay
= var_CreateGetInteger( p_input
, "sub-delay" );
1004 var_SetTime( p_input
, "spu-delay", (mtime_t
)i_delay
* 100000 );
1007 /* Look for and add subtitle files */
1008 psz_subtitle
= var_GetNonEmptyString( p_input
, "sub-file" );
1009 if( psz_subtitle
!= NULL
)
1011 msg_Dbg( p_input
, "forced subtitle: %s", psz_subtitle
);
1012 input_AddSubtitles( p_input
, psz_subtitle
, VLC_FALSE
);
1015 var_Get( p_input
, "sub-autodetect-file", &val
);
1018 char *psz_autopath
= var_GetNonEmptyString( p_input
, "sub-autodetect-path" );
1019 char **subs
= subtitles_Detect( p_input
, psz_autopath
,
1020 p_input
->p
->input
.p_item
->psz_uri
);
1021 input_source_t
*sub
;
1023 if( psz_autopath
== NULL
)
1024 psz_autopath
= strdup("");
1026 /* Try to autoselect the first autodetected subtitles file
1027 * if no subtitles file was specified */
1028 if( ( psz_subtitle
== NULL
) && subs
&& subs
[0] )
1030 input_AddSubtitles( p_input
, subs
[0], VLC_FALSE
);
1035 /* Then, just add the following subtitles files */
1036 for( ; subs
&& subs
[i
]; i
++ )
1038 if( !psz_subtitle
|| strcmp( psz_subtitle
, subs
[i
] ) )
1040 sub
= InputSourceNew( p_input
);
1041 if( !InputSourceInit( p_input
, sub
, subs
[i
], "subtitle" ) )
1043 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, sub
);
1049 if( subs
) free( subs
);
1050 if( psz_autopath
) free( psz_autopath
);
1052 free( psz_subtitle
);
1054 /* Look for slave */
1055 psz
= var_GetNonEmptyString( p_input
, "input-slave" );
1059 input_source_t
*slave
;
1060 while( psz
&& *psz
)
1062 while( *psz
== ' ' || *psz
== '#' )
1066 if( ( psz_delim
= strchr( psz
, '#' ) ) )
1068 *psz_delim
++ = '\0';
1075 msg_Dbg( p_input
, "adding slave input '%s'", psz
);
1076 slave
= InputSourceNew( p_input
);
1077 if( !InputSourceInit( p_input
, slave
, psz
, NULL
) )
1079 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, slave
);
1089 p_input
->p
->i_start
= 0;
1090 p_input
->p
->i_start
= 0;
1094 if( !p_input
->b_preparsing
)
1096 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_SET_ACTIVE
, VLC_TRUE
);
1097 i_es_out_mode
= ES_OUT_MODE_AUTO
;
1099 if( p_input
->p
->p_sout
)
1101 var_Get( p_input
, "sout-all", &val
);
1104 i_es_out_mode
= ES_OUT_MODE_ALL
;
1109 var_Get( p_input
, "programs", &val
);
1110 if ( val
.p_list
&& val
.p_list
->i_count
)
1112 i_es_out_mode
= ES_OUT_MODE_PARTIAL
;
1113 /* Note : we should remove the "program" callback. */
1116 var_Change( p_input
, "programs", VLC_VAR_FREELIST
, &val
,
1120 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_SET_MODE
, i_es_out_mode
);
1122 /* Inform the demuxer about waited group (needed only for DVB) */
1123 if( i_es_out_mode
== ES_OUT_MODE_ALL
)
1125 demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, -1, NULL
);
1127 else if( i_es_out_mode
== ES_OUT_MODE_PARTIAL
)
1129 demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, -1,
1134 demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
,
1135 (int) var_GetInteger( p_input
, "program" ), NULL
);
1138 if( p_input
->p
->p_sout
)
1140 if( p_input
->p
->p_sout
->i_out_pace_nocontrol
> 0 )
1142 p_input
->p
->b_out_pace_control
= VLC_FALSE
;
1146 p_input
->p
->b_out_pace_control
= VLC_TRUE
;
1149 if( p_input
->b_can_pace_control
&& p_input
->p
->b_out_pace_control
)
1151 /* We don't want a high input priority here or we'll
1152 * end-up sucking up all the CPU time */
1153 vlc_thread_set_priority( p_input
, VLC_THREAD_PRIORITY_LOW
);
1156 msg_Dbg( p_input
, "starting in %s mode",
1157 p_input
->p
->b_out_pace_control
? "async" : "sync" );
1161 p_meta
= vlc_meta_New();
1162 /* Get meta data from users */
1163 InputMetaUser( p_input
, p_meta
);
1165 /* Get meta data from master input */
1166 DemuxMeta( p_input
, p_meta
, p_input
->p
->input
.p_demux
);
1168 /* Access_file does not give any meta, and there are no slave */
1169 if( !p_input
->b_preparsing
)
1171 if( p_input
->p
->input
.p_access
)
1172 access2_Control( p_input
->p
->input
.p_access
, ACCESS_GET_META
,
1175 /* Get meta data from slave input */
1176 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
1178 DemuxMeta( p_input
, p_meta
, p_input
->p
->slave
[i
]->p_demux
);
1179 if( p_input
->p
->slave
[i
]->p_access
)
1181 access2_Control( p_input
->p
->slave
[i
]->p_access
,
1182 ACCESS_GET_META
, p_meta
);
1187 InputUpdateMeta( p_input
, p_meta
);
1189 if( !p_input
->b_preparsing
)
1191 msg_Dbg( p_input
, "`%s' successfully opened",
1192 p_input
->p
->input
.p_item
->psz_uri
);
1196 /* initialization is complete */
1197 input_ChangeState( p_input
, PLAYING_S
);
1202 input_ChangeState( p_input
, ERROR_S
);
1204 if( p_input
->p
->p_es_out
)
1205 input_EsOutDelete( p_input
->p
->p_es_out
);
1207 if( p_input
->p
->p_sout
)
1209 vlc_object_detach( p_input
->p
->p_sout
);
1210 sout_DeleteInstance( p_input
->p
->p_sout
);
1214 if( !p_input
->b_preparsing
&& p_input
->p_libvlc
->b_stats
)
1216 #define EXIT_COUNTER( c ) do { if( p_input->p->counters.p_##c ) \
1217 stats_CounterClean( p_input->p->counters.p_##c );\
1218 p_input->p->counters.p_##c = NULL; } while(0)
1219 EXIT_COUNTER( read_bytes
);
1220 EXIT_COUNTER( read_packets
);
1221 EXIT_COUNTER( demux_read
);
1222 EXIT_COUNTER( input_bitrate
);
1223 EXIT_COUNTER( demux_bitrate
);
1224 EXIT_COUNTER( played_abuffers
);
1225 EXIT_COUNTER( lost_abuffers
);
1226 EXIT_COUNTER( displayed_pictures
);
1227 EXIT_COUNTER( lost_pictures
);
1228 EXIT_COUNTER( decoded_audio
);
1229 EXIT_COUNTER( decoded_video
);
1230 EXIT_COUNTER( decoded_sub
);
1232 if( p_input
->p
->p_sout
)
1234 EXIT_COUNTER( sout_sent_packets
);
1235 EXIT_COUNTER (sout_sent_bytes
);
1236 EXIT_COUNTER( sout_send_bitrate
);
1241 /* Mark them deleted */
1242 p_input
->p
->input
.p_demux
= NULL
;
1243 p_input
->p
->input
.p_stream
= NULL
;
1244 p_input
->p
->input
.p_access
= NULL
;
1245 p_input
->p
->p_es_out
= NULL
;
1246 p_input
->p
->p_sout
= NULL
;
1248 return VLC_EGENERIC
;
1251 /*****************************************************************************
1252 * Error: RunThread() error loop
1253 *****************************************************************************
1254 * This function is called when an error occurred during thread main's loop.
1255 *****************************************************************************/
1256 static void Error( input_thread_t
*p_input
)
1258 input_ChangeState( p_input
, ERROR_S
);
1259 while( !p_input
->b_die
)
1262 msleep( INPUT_IDLE_SLEEP
);
1266 /*****************************************************************************
1267 * End: end the input thread
1268 *****************************************************************************/
1269 static void End( input_thread_t
* p_input
)
1273 /* We are at the end */
1274 input_ChangeState( p_input
, END_S
);
1276 /* Clean control variables */
1277 input_ControlVarClean( p_input
);
1279 /* Clean up master */
1280 InputSourceClean( &p_input
->p
->input
);
1283 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
1285 InputSourceClean( p_input
->p
->slave
[i
] );
1286 free( p_input
->p
->slave
[i
] );
1288 if( p_input
->p
->slave
) free( p_input
->p
->slave
);
1290 /* Unload all modules */
1291 if( p_input
->p
->p_es_out
)
1292 input_EsOutDelete( p_input
->p
->p_es_out
);
1294 if( !p_input
->b_preparsing
)
1296 #define CL_CO( c ) stats_CounterClean( p_input->p->counters.p_##c ); p_input->p->counters.p_##c = NULL;
1297 if( p_input
->p_libvlc
->b_stats
)
1299 /* make sure we are up to date */
1300 stats_ComputeInputStats( p_input
, p_input
->p
->input
.p_item
->p_stats
);
1301 if( p_input
->p_libvlc
->p_playlist
->p_stats_computer
== p_input
)
1303 stats_ComputeGlobalStats( p_input
->p_libvlc
->p_playlist
,
1304 p_input
->p_libvlc
->p_playlist
->p_stats
);
1305 p_input
->p_libvlc
->p_playlist
->p_stats_computer
= NULL
;
1307 CL_CO( read_bytes
);
1308 CL_CO( read_packets
);
1309 CL_CO( demux_read
);
1310 CL_CO( input_bitrate
);
1311 CL_CO( demux_bitrate
);
1312 CL_CO( played_abuffers
);
1313 CL_CO( lost_abuffers
);
1314 CL_CO( displayed_pictures
);
1315 CL_CO( lost_pictures
);
1316 CL_CO( decoded_audio
) ;
1317 CL_CO( decoded_video
);
1318 CL_CO( decoded_sub
) ;
1321 /* Close optional stream output instance */
1322 if( p_input
->p
->p_sout
)
1324 CL_CO( sout_sent_packets
);
1325 CL_CO( sout_sent_bytes
);
1326 CL_CO( sout_send_bitrate
);
1328 vlc_object_detach( p_input
->p
->p_sout
);
1333 if( p_input
->p
->i_attachment
> 0 )
1335 for( i
= 0; i
< p_input
->p
->i_attachment
; i
++ )
1336 vlc_input_attachment_Delete( p_input
->p
->attachment
[i
] );
1337 TAB_CLEAN( p_input
->p
->i_attachment
, p_input
->p
->attachment
);
1340 vlc_mutex_destroy( &p_input
->p
->counters
.counters_lock
);
1342 /* Tell we're dead */
1343 p_input
->b_dead
= VLC_TRUE
;
1346 static sout_instance_t
*SoutFind( vlc_object_t
*p_parent
, input_item_t
*p_item
, vlc_bool_t
*pb_sout_keep
)
1348 vlc_bool_t b_keep_sout
= var_CreateGetBool( p_parent
, "sout-keep" );
1349 sout_instance_t
*p_sout
= NULL
;
1352 /* Search sout-keep options
1353 * XXX it has to be done here, but it is duplicated work :( */
1354 vlc_mutex_lock( &p_item
->lock
);
1355 for( i
= 0; i
< p_item
->i_options
; i
++ )
1357 const char *psz_option
= p_item
->ppsz_options
[i
];
1360 if( *psz_option
== ':' )
1363 if( !strcmp( psz_option
, "sout-keep" ) )
1364 b_keep_sout
= VLC_TRUE
;
1365 else if( !strcmp( psz_option
, "no-sout-keep" ) || !strcmp( psz_option
, "nosout-keep" ) )
1366 b_keep_sout
= VLC_FALSE
;
1368 vlc_mutex_unlock( &p_item
->lock
);
1370 /* Find a potential sout to reuse
1371 * XXX it might be unusable but this will be checked later */
1374 /* Remove the sout from the playlist garbage collector */
1375 playlist_t
*p_playlist
= pl_Yield( p_parent
);
1377 vlc_mutex_lock( &p_playlist
->gc_lock
);
1378 p_sout
= vlc_object_find( p_playlist
, VLC_OBJECT_SOUT
, FIND_CHILD
);
1381 if( p_sout
->p_parent
!= VLC_OBJECT(p_playlist
) )
1383 vlc_object_release( p_sout
);
1388 vlc_object_detach( p_sout
); /* Remove it from the GC */
1390 vlc_object_release( p_sout
);
1393 vlc_mutex_unlock( &p_playlist
->gc_lock
);
1395 pl_Release( p_parent
);
1399 *pb_sout_keep
= b_keep_sout
;
1403 static void SoutKeep( sout_instance_t
*p_sout
)
1405 /* attach sout to the playlist */
1406 playlist_t
*p_playlist
= pl_Yield( p_sout
);
1408 msg_Dbg( p_sout
, "sout has been kept" );
1409 vlc_object_attach( p_sout
, p_playlist
);
1411 pl_Release( p_sout
);
1414 /*****************************************************************************
1416 *****************************************************************************/
1417 static inline int ControlPopNoLock( input_thread_t
*p_input
,
1418 int *pi_type
, vlc_value_t
*p_val
)
1420 if( p_input
->p
->i_control
<= 0 )
1422 return VLC_EGENERIC
;
1425 *pi_type
= p_input
->p
->control
[0].i_type
;
1426 *p_val
= p_input
->p
->control
[0].val
;
1428 p_input
->p
->i_control
--;
1429 if( p_input
->p
->i_control
> 0 )
1433 for( i
= 0; i
< p_input
->p
->i_control
; i
++ )
1435 p_input
->p
->control
[i
].i_type
= p_input
->p
->control
[i
+1].i_type
;
1436 p_input
->p
->control
[i
].val
= p_input
->p
->control
[i
+1].val
;
1443 static void ControlReduce( input_thread_t
*p_input
)
1450 for( i
= 1; i
< p_input
->p
->i_control
; i
++ )
1452 const int i_lt
= p_input
->p
->control
[i
-1].i_type
;
1453 const int i_ct
= p_input
->p
->control
[i
].i_type
;
1455 /* XXX We can't merge INPUT_CONTROL_SET_ES */
1456 /* msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->p->i_control,
1460 ( i_ct
== INPUT_CONTROL_SET_STATE
||
1461 i_ct
== INPUT_CONTROL_SET_RATE
||
1462 i_ct
== INPUT_CONTROL_SET_POSITION
||
1463 i_ct
== INPUT_CONTROL_SET_TIME
||
1464 i_ct
== INPUT_CONTROL_SET_PROGRAM
||
1465 i_ct
== INPUT_CONTROL_SET_TITLE
||
1466 i_ct
== INPUT_CONTROL_SET_SEEKPOINT
||
1467 i_ct
== INPUT_CONTROL_SET_BOOKMARK
) )
1470 // msg_Dbg( p_input, "merged at %d", i );
1471 /* Remove the i-1 */
1472 for( j
= i
; j
< p_input
->p
->i_control
; j
++ )
1473 p_input
->p
->control
[j
-1] = p_input
->p
->control
[j
];
1474 p_input
->p
->i_control
--;
1478 /* TODO but that's not that important
1479 - merge SET_X with SET_X_CMD
1480 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
1481 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
1488 static vlc_bool_t
Control( input_thread_t
*p_input
, int i_type
,
1491 vlc_bool_t b_force_update
= VLC_FALSE
;
1493 if( !p_input
) return b_force_update
;
1497 case INPUT_CONTROL_SET_DIE
:
1498 msg_Dbg( p_input
, "control: stopping input" );
1499 /* Mark all submodules to die */
1500 if( p_input
->p
->input
.p_access
)
1501 vlc_object_kill( p_input
->p
->input
.p_access
);
1502 if( p_input
->p
->input
.p_stream
)
1503 vlc_object_kill( p_input
->p
->input
.p_stream
);
1504 vlc_object_kill( p_input
->p
->input
.p_demux
);
1506 vlc_object_kill( p_input
);
1509 case INPUT_CONTROL_SET_POSITION
:
1510 case INPUT_CONTROL_SET_POSITION_OFFSET
:
1513 if( i_type
== INPUT_CONTROL_SET_POSITION
)
1515 f_pos
= val
.f_float
;
1519 /* Should not fail */
1520 demux2_Control( p_input
->p
->input
.p_demux
,
1521 DEMUX_GET_POSITION
, &f_pos
);
1522 f_pos
+= val
.f_float
;
1524 if( f_pos
< 0.0 ) f_pos
= 0.0;
1525 if( f_pos
> 1.0 ) f_pos
= 1.0;
1526 /* Reset the decoders states and clock sync (before calling the demuxer */
1527 input_EsOutChangePosition( p_input
->p
->p_es_out
);
1528 if( demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_POSITION
,
1531 msg_Err( p_input
, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
1532 "%2.1f%% failed", f_pos
* 100 );
1536 if( p_input
->p
->i_slave
> 0 )
1537 SlaveSeek( p_input
);
1539 b_force_update
= VLC_TRUE
;
1544 case INPUT_CONTROL_SET_TIME
:
1545 case INPUT_CONTROL_SET_TIME_OFFSET
:
1550 if( i_type
== INPUT_CONTROL_SET_TIME
)
1552 i_time
= val
.i_time
;
1556 /* Should not fail */
1557 demux2_Control( p_input
->p
->input
.p_demux
,
1558 DEMUX_GET_TIME
, &i_time
);
1559 i_time
+= val
.i_time
;
1561 if( i_time
< 0 ) i_time
= 0;
1563 /* Reset the decoders states and clock sync (before calling the demuxer */
1564 input_EsOutChangePosition( p_input
->p
->p_es_out
);
1566 i_ret
= demux2_Control( p_input
->p
->input
.p_demux
,
1567 DEMUX_SET_TIME
, i_time
);
1572 /* Emulate it with a SET_POS */
1573 demux2_Control( p_input
->p
->input
.p_demux
,
1574 DEMUX_GET_LENGTH
, &i_length
);
1577 double f_pos
= (double)i_time
/ (double)i_length
;
1578 i_ret
= demux2_Control( p_input
->p
->input
.p_demux
,
1579 DEMUX_SET_POSITION
, f_pos
);
1584 msg_Warn( p_input
, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
1585 " failed or not possible", i_time
);
1589 if( p_input
->p
->i_slave
> 0 )
1590 SlaveSeek( p_input
);
1592 b_force_update
= VLC_TRUE
;
1597 case INPUT_CONTROL_SET_STATE
:
1598 if( ( val
.i_int
== PLAYING_S
&& p_input
->i_state
== PAUSE_S
) ||
1599 ( val
.i_int
== PAUSE_S
&& p_input
->i_state
== PAUSE_S
) )
1602 if( p_input
->p
->input
.p_access
)
1603 i_ret
= access2_Control( p_input
->p
->input
.p_access
,
1604 ACCESS_SET_PAUSE_STATE
, VLC_FALSE
);
1606 i_ret
= demux2_Control( p_input
->p
->input
.p_demux
,
1607 DEMUX_SET_PAUSE_STATE
, VLC_FALSE
);
1611 /* FIXME What to do ? */
1612 msg_Warn( p_input
, "cannot unset pause -> EOF" );
1613 vlc_mutex_unlock( &p_input
->p
->lock_control
);
1614 input_ControlPush( p_input
, INPUT_CONTROL_SET_DIE
, NULL
);
1615 vlc_mutex_lock( &p_input
->p
->lock_control
);
1618 b_force_update
= VLC_TRUE
;
1620 /* Switch to play */
1621 p_input
->i_state
= PLAYING_S
;
1622 val
.i_int
= PLAYING_S
;
1623 var_Change( p_input
, "state", VLC_VAR_SETVALUE
, &val
, NULL
);
1627 input_EsOutChangeState( p_input
->p
->p_es_out
);
1629 else if( val
.i_int
== PAUSE_S
&& p_input
->i_state
== PLAYING_S
&&
1630 p_input
->p
->b_can_pause
)
1633 if( p_input
->p
->input
.p_access
)
1634 i_ret
= access2_Control( p_input
->p
->input
.p_access
,
1635 ACCESS_SET_PAUSE_STATE
, VLC_TRUE
);
1637 i_ret
= demux2_Control( p_input
->p
->input
.p_demux
,
1638 DEMUX_SET_PAUSE_STATE
, VLC_TRUE
);
1640 b_force_update
= VLC_TRUE
;
1644 msg_Warn( p_input
, "cannot set pause state" );
1645 val
.i_int
= p_input
->i_state
;
1649 val
.i_int
= PAUSE_S
;
1652 /* Switch to new state */
1653 p_input
->i_state
= val
.i_int
;
1654 var_Change( p_input
, "state", VLC_VAR_SETVALUE
, &val
, NULL
);
1658 input_EsOutChangeState( p_input
->p
->p_es_out
);
1660 else if( val
.i_int
== PAUSE_S
&& !p_input
->p
->b_can_pause
)
1662 b_force_update
= VLC_TRUE
;
1664 /* Correct "state" value */
1665 val
.i_int
= p_input
->i_state
;
1666 var_Change( p_input
, "state", VLC_VAR_SETVALUE
, &val
, NULL
);
1668 else if( val
.i_int
!= PLAYING_S
&& val
.i_int
!= PAUSE_S
)
1670 msg_Err( p_input
, "invalid state in INPUT_CONTROL_SET_STATE" );
1674 case INPUT_CONTROL_SET_RATE
:
1675 case INPUT_CONTROL_SET_RATE_SLOWER
:
1676 case INPUT_CONTROL_SET_RATE_FASTER
:
1680 if( i_type
== INPUT_CONTROL_SET_RATE
)
1686 static const int ppi_factor
[][2] = {
1687 {1,64}, {1,32}, {1,16}, {1,8}, {1,4}, {1,3}, {1,2}, {2,3},
1689 {3,2}, {2,1}, {3,1}, {4,1}, {8,1}, {16,1}, {32,1}, {64,1},
1698 for( i
= 0; ppi_factor
[i
][0] != 0; i
++ )
1700 const int i_test_r
= INPUT_RATE_DEFAULT
* ppi_factor
[i
][0] / ppi_factor
[i
][1];
1701 const int i_test_e
= abs(p_input
->p
->i_rate
- i_test_r
);
1702 if( i_test_e
< i_error
)
1708 assert( i_idx
>= 0 && ppi_factor
[i_idx
][0] != 0 );
1710 if( i_type
== INPUT_CONTROL_SET_RATE_SLOWER
)
1712 if( ppi_factor
[i_idx
+1][0] > 0 )
1713 i_rate
= INPUT_RATE_DEFAULT
* ppi_factor
[i_idx
+1][0] / ppi_factor
[i_idx
+1][1];
1715 i_rate
= INPUT_RATE_MAX
+1;
1719 assert( i_type
== INPUT_CONTROL_SET_RATE_FASTER
);
1721 i_rate
= INPUT_RATE_DEFAULT
* ppi_factor
[i_idx
-1][0] / ppi_factor
[i_idx
-1][1];
1723 i_rate
= INPUT_RATE_MIN
-1;
1727 if( i_rate
< INPUT_RATE_MIN
)
1729 msg_Dbg( p_input
, "cannot set rate faster" );
1730 i_rate
= INPUT_RATE_MIN
;
1732 else if( i_rate
> INPUT_RATE_MAX
)
1734 msg_Dbg( p_input
, "cannot set rate slower" );
1735 i_rate
= INPUT_RATE_MAX
;
1737 if( i_rate
!= INPUT_RATE_DEFAULT
&&
1738 ( ( !p_input
->b_can_pace_control
&& !p_input
->p
->b_can_rate_control
) ||
1739 ( p_input
->p
->p_sout
&& !p_input
->p
->b_out_pace_control
) ) )
1741 msg_Dbg( p_input
, "cannot change rate" );
1742 i_rate
= INPUT_RATE_DEFAULT
;
1744 if( i_rate
!= p_input
->p
->i_rate
&&
1745 !p_input
->b_can_pace_control
&& p_input
->p
->b_can_rate_control
)
1748 if( p_input
->p
->input
.p_access
)
1749 i_ret
= VLC_EGENERIC
;
1751 i_ret
= demux2_Control( p_input
->p
->input
.p_demux
,
1752 DEMUX_SET_RATE
, &i_rate
);
1755 msg_Warn( p_input
, "ACCESS/DEMUX_SET_RATE failed" );
1756 i_rate
= p_input
->p
->i_rate
;
1761 if( i_rate
!= p_input
->p
->i_rate
)
1764 var_Change( p_input
, "rate", VLC_VAR_SETVALUE
, &val
, NULL
);
1766 p_input
->p
->i_rate
= i_rate
;
1768 /* FIXME do we need a RESET_PCR when !p_input->p->input.b_rescale_ts ? */
1769 if( p_input
->p
->input
.b_rescale_ts
)
1770 input_EsOutChangeRate( p_input
->p
->p_es_out
, i_rate
);
1772 b_force_update
= VLC_TRUE
;
1777 case INPUT_CONTROL_SET_PROGRAM
:
1778 /* No need to force update, es_out does it if needed */
1779 es_out_Control( p_input
->p
->p_es_out
,
1780 ES_OUT_SET_GROUP
, val
.i_int
);
1782 demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_SET_GROUP
, val
.i_int
,
1786 case INPUT_CONTROL_SET_ES
:
1787 /* No need to force update, es_out does it if needed */
1788 es_out_Control( p_input
->p
->p_es_out
, ES_OUT_SET_ES
,
1789 input_EsOutGetFromID( p_input
->p
->p_es_out
,
1793 case INPUT_CONTROL_SET_AUDIO_DELAY
:
1794 input_EsOutSetDelay( p_input
->p
->p_es_out
,
1795 AUDIO_ES
, val
.i_time
);
1796 var_Change( p_input
, "audio-delay", VLC_VAR_SETVALUE
, &val
, NULL
);
1799 case INPUT_CONTROL_SET_SPU_DELAY
:
1800 input_EsOutSetDelay( p_input
->p
->p_es_out
,
1801 SPU_ES
, val
.i_time
);
1802 var_Change( p_input
, "spu-delay", VLC_VAR_SETVALUE
, &val
, NULL
);
1805 case INPUT_CONTROL_SET_TITLE
:
1806 case INPUT_CONTROL_SET_TITLE_NEXT
:
1807 case INPUT_CONTROL_SET_TITLE_PREV
:
1808 if( p_input
->p
->input
.b_title_demux
&&
1809 p_input
->p
->input
.i_title
> 0 )
1812 /* FIXME handle demux title */
1813 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1816 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
1817 i_title
= p_demux
->info
.i_title
- 1;
1818 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
1819 i_title
= p_demux
->info
.i_title
+ 1;
1821 i_title
= val
.i_int
;
1823 if( i_title
>= 0 && i_title
< p_input
->p
->input
.i_title
)
1825 input_EsOutChangePosition( p_input
->p
->p_es_out
);
1827 demux2_Control( p_demux
, DEMUX_SET_TITLE
, i_title
);
1828 input_ControlVarTitle( p_input
, i_title
);
1831 else if( p_input
->p
->input
.i_title
> 0 )
1833 access_t
*p_access
= p_input
->p
->input
.p_access
;
1836 if( i_type
== INPUT_CONTROL_SET_TITLE_PREV
)
1837 i_title
= p_access
->info
.i_title
- 1;
1838 else if( i_type
== INPUT_CONTROL_SET_TITLE_NEXT
)
1839 i_title
= p_access
->info
.i_title
+ 1;
1841 i_title
= val
.i_int
;
1843 if( i_title
>= 0 && i_title
< p_input
->p
->input
.i_title
)
1845 input_EsOutChangePosition( p_input
->p
->p_es_out
);
1847 access2_Control( p_access
, ACCESS_SET_TITLE
, i_title
);
1848 stream_AccessReset( p_input
->p
->input
.p_stream
);
1852 case INPUT_CONTROL_SET_SEEKPOINT
:
1853 case INPUT_CONTROL_SET_SEEKPOINT_NEXT
:
1854 case INPUT_CONTROL_SET_SEEKPOINT_PREV
:
1855 if( p_input
->p
->input
.b_title_demux
&&
1856 p_input
->p
->input
.i_title
> 0 )
1858 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1860 int64_t i_input_time
;
1861 int64_t i_seekpoint_time
;
1863 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
1865 i_seekpoint
= p_demux
->info
.i_seekpoint
;
1866 i_seekpoint_time
= p_input
->p
->input
.title
[p_demux
->info
.i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
1867 if( i_seekpoint_time
>= 0 &&
1868 !demux2_Control( p_demux
,
1869 DEMUX_GET_TIME
, &i_input_time
) )
1871 if ( i_input_time
< i_seekpoint_time
+ 3000000 )
1877 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
1878 i_seekpoint
= p_demux
->info
.i_seekpoint
+ 1;
1880 i_seekpoint
= val
.i_int
;
1882 if( i_seekpoint
>= 0 && i_seekpoint
<
1883 p_input
->p
->input
.title
[p_demux
->info
.i_title
]->i_seekpoint
)
1886 input_EsOutChangePosition( p_input
->p
->p_es_out
);
1888 demux2_Control( p_demux
, DEMUX_SET_SEEKPOINT
, i_seekpoint
);
1891 else if( p_input
->p
->input
.i_title
> 0 )
1893 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1894 access_t
*p_access
= p_input
->p
->input
.p_access
;
1896 int64_t i_input_time
;
1897 int64_t i_seekpoint_time
;
1899 if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_PREV
)
1901 i_seekpoint
= p_access
->info
.i_seekpoint
;
1902 i_seekpoint_time
= p_input
->p
->input
.title
[p_access
->info
.i_title
]->seekpoint
[i_seekpoint
]->i_time_offset
;
1903 if( i_seekpoint_time
>= 0 &&
1904 demux2_Control( p_demux
,
1905 DEMUX_GET_TIME
, &i_input_time
) )
1907 if ( i_input_time
< i_seekpoint_time
+ 3000000 )
1913 else if( i_type
== INPUT_CONTROL_SET_SEEKPOINT_NEXT
)
1914 i_seekpoint
= p_access
->info
.i_seekpoint
+ 1;
1916 i_seekpoint
= val
.i_int
;
1918 if( i_seekpoint
>= 0 && i_seekpoint
<
1919 p_input
->p
->input
.title
[p_access
->info
.i_title
]->i_seekpoint
)
1921 input_EsOutChangePosition( p_input
->p
->p_es_out
);
1923 access2_Control( p_access
, ACCESS_SET_SEEKPOINT
,
1925 stream_AccessReset( p_input
->p
->input
.p_stream
);
1930 case INPUT_CONTROL_ADD_SLAVE
:
1931 if( val
.psz_string
)
1933 input_source_t
*slave
= InputSourceNew( p_input
);
1935 if( !InputSourceInit( p_input
, slave
, val
.psz_string
, NULL
) )
1941 msg_Dbg( p_input
, "adding %s as slave on the fly",
1945 if( demux2_Control( p_input
->p
->input
.p_demux
,
1946 DEMUX_GET_TIME
, &i_time
) )
1948 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
1949 InputSourceClean( slave
);
1953 if( demux2_Control( slave
->p_demux
,
1954 DEMUX_SET_TIME
, i_time
) )
1956 msg_Err( p_input
, "seek failed for new slave" );
1957 InputSourceClean( slave
);
1962 /* Get meta (access and demux) */
1963 p_meta
= vlc_meta_New();
1964 access2_Control( slave
->p_access
, ACCESS_GET_META
,
1966 demux2_Control( slave
->p_demux
, DEMUX_GET_META
, p_meta
);
1967 InputUpdateMeta( p_input
, p_meta
);
1969 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, slave
);
1974 msg_Warn( p_input
, "failed to add %s as slave",
1978 free( val
.psz_string
);
1982 case INPUT_CONTROL_SET_BOOKMARK
:
1984 msg_Err( p_input
, "not yet implemented" );
1988 return b_force_update
;
1991 /*****************************************************************************
1993 *****************************************************************************/
1994 static int UpdateFromDemux( input_thread_t
*p_input
)
1996 demux_t
*p_demux
= p_input
->p
->input
.p_demux
;
1999 if( p_demux
->info
.i_update
& INPUT_UPDATE_TITLE
)
2001 v
.i_int
= p_demux
->info
.i_title
;
2002 var_Change( p_input
, "title", VLC_VAR_SETVALUE
, &v
, NULL
);
2004 input_ControlVarTitle( p_input
, p_demux
->info
.i_title
);
2006 p_demux
->info
.i_update
&= ~INPUT_UPDATE_TITLE
;
2008 if( p_demux
->info
.i_update
& INPUT_UPDATE_SEEKPOINT
)
2010 v
.i_int
= p_demux
->info
.i_seekpoint
;
2011 var_Change( p_input
, "chapter", VLC_VAR_SETVALUE
, &v
, NULL
);
2013 p_demux
->info
.i_update
&= ~INPUT_UPDATE_SEEKPOINT
;
2015 p_demux
->info
.i_update
&= ~INPUT_UPDATE_SIZE
;
2017 /* Hmmm only works with master input */
2018 if( p_input
->p
->input
.p_demux
== p_demux
)
2020 int i_title_end
= p_input
->p
->input
.i_title_end
-
2021 p_input
->p
->input
.i_title_offset
;
2022 int i_seekpoint_end
= p_input
->p
->input
.i_seekpoint_end
-
2023 p_input
->p
->input
.i_seekpoint_offset
;
2025 if( i_title_end
>= 0 && i_seekpoint_end
>= 0 )
2027 if( p_demux
->info
.i_title
> i_title_end
||
2028 ( p_demux
->info
.i_title
== i_title_end
&&
2029 p_demux
->info
.i_seekpoint
> i_seekpoint_end
) ) return 0;
2031 else if( i_seekpoint_end
>=0 )
2033 if( p_demux
->info
.i_seekpoint
> i_seekpoint_end
) return 0;
2035 else if( i_title_end
>= 0 )
2037 if( p_demux
->info
.i_title
> i_title_end
) return 0;
2044 /*****************************************************************************
2046 *****************************************************************************/
2047 static int UpdateFromAccess( input_thread_t
*p_input
)
2049 access_t
*p_access
= p_input
->p
->input
.p_access
;
2052 if( p_access
->info
.i_update
& INPUT_UPDATE_TITLE
)
2054 v
.i_int
= p_access
->info
.i_title
;
2055 var_Change( p_input
, "title", VLC_VAR_SETVALUE
, &v
, NULL
);
2057 input_ControlVarTitle( p_input
, p_access
->info
.i_title
);
2059 stream_AccessUpdate( p_input
->p
->input
.p_stream
);
2061 p_access
->info
.i_update
&= ~INPUT_UPDATE_TITLE
;
2063 if( p_access
->info
.i_update
& INPUT_UPDATE_SEEKPOINT
)
2065 v
.i_int
= p_access
->info
.i_seekpoint
;
2066 var_Change( p_input
, "chapter", VLC_VAR_SETVALUE
, &v
, NULL
);
2067 p_access
->info
.i_update
&= ~INPUT_UPDATE_SEEKPOINT
;
2069 if( p_access
->info
.i_update
& INPUT_UPDATE_META
)
2071 /* TODO maybe multi - access ? */
2072 vlc_meta_t
*p_meta
= vlc_meta_New();
2073 access2_Control( p_input
->p
->input
.p_access
,ACCESS_GET_META
, p_meta
);
2074 InputUpdateMeta( p_input
, p_meta
);
2075 var_SetInteger( pl_Get( p_input
), "item-change", p_input
->p
->input
.p_item
->i_id
);
2076 p_access
->info
.i_update
&= ~INPUT_UPDATE_META
;
2079 p_access
->info
.i_update
&= ~INPUT_UPDATE_SIZE
;
2081 /* Hmmm only works with master input */
2082 if( p_input
->p
->input
.p_access
== p_access
)
2084 int i_title_end
= p_input
->p
->input
.i_title_end
-
2085 p_input
->p
->input
.i_title_offset
;
2086 int i_seekpoint_end
= p_input
->p
->input
.i_seekpoint_end
-
2087 p_input
->p
->input
.i_seekpoint_offset
;
2089 if( i_title_end
>= 0 && i_seekpoint_end
>=0 )
2091 if( p_access
->info
.i_title
> i_title_end
||
2092 ( p_access
->info
.i_title
== i_title_end
&&
2093 p_access
->info
.i_seekpoint
> i_seekpoint_end
) ) return 0;
2095 else if( i_seekpoint_end
>=0 )
2097 if( p_access
->info
.i_seekpoint
> i_seekpoint_end
) return 0;
2099 else if( i_title_end
>= 0 )
2101 if( p_access
->info
.i_title
> i_title_end
) return 0;
2108 /*****************************************************************************
2110 *****************************************************************************/
2111 static void UpdateItemLength( input_thread_t
*p_input
, int64_t i_length
)
2113 input_item_SetDuration( p_input
->p
->input
.p_item
, (mtime_t
) i_length
);
2115 if( !p_input
->b_preparsing
)
2117 pl_Yield( p_input
);
2118 var_SetInteger( pl_Get( p_input
), "item-change",
2119 p_input
->p
->input
.p_item
->i_id
);
2120 pl_Release( p_input
);
2124 /*****************************************************************************
2126 *****************************************************************************/
2127 static input_source_t
*InputSourceNew( input_thread_t
*p_input
)
2129 input_source_t
*in
= (input_source_t
*) malloc( sizeof( input_source_t
) );
2133 msg_Err( p_input
, "out of memory for new input source" );
2138 in
->p_access
= NULL
;
2139 in
->p_stream
= NULL
;
2141 in
->b_title_demux
= VLC_FALSE
;
2142 TAB_INIT( in
->i_title
, in
->title
);
2143 in
->b_can_pause
= VLC_TRUE
;
2144 in
->b_can_pace_control
= VLC_TRUE
;
2145 in
->b_can_rate_control
= VLC_TRUE
;
2146 in
->b_rescale_ts
= VLC_TRUE
;
2147 in
->b_eof
= VLC_FALSE
;
2149 in
->i_cr_average
= 0;
2154 /*****************************************************************************
2156 *****************************************************************************/
2157 static int InputSourceInit( input_thread_t
*p_input
,
2158 input_source_t
*in
, const char *psz_mrl
,
2159 const char *psz_forced_demux
)
2161 char psz_dup
[strlen (psz_mrl
) + 1];
2162 const char *psz_access
;
2163 const char *psz_demux
;
2170 strcpy( psz_dup
, psz_mrl
);
2172 if( !in
) return VLC_EGENERIC
;
2173 if( !p_input
) return VLC_EGENERIC
;
2176 if( !p_input
->b_preparsing
)
2178 MRLSplit( VLC_OBJECT(p_input
), psz_dup
,
2179 &psz_access
, &psz_demux
, &psz_path
);
2181 msg_Dbg( p_input
, "`%s' gives access `%s' demux `%s' path `%s'",
2182 psz_mrl
, psz_access
, psz_demux
, psz_path
);
2184 /* Hack to allow udp://@:port syntax */
2186 (strncmp( psz_access
, "udp", 3 ) &&
2187 strncmp( psz_access
, "rtp", 3 )) )
2189 /* Find optional titles and seekpoints */
2190 MRLSections( p_input
, psz_path
, &in
->i_title_start
, &in
->i_title_end
,
2191 &in
->i_seekpoint_start
, &in
->i_seekpoint_end
);
2193 if( psz_forced_demux
&& *psz_forced_demux
)
2195 psz_demux
= psz_forced_demux
;
2197 else if( !psz_demux
|| *psz_demux
== '\0' )
2199 /* special hack for forcing a demuxer with --demux=module
2200 * (and do nothing with a list) */
2201 char *psz_var_demux
= var_GetNonEmptyString( p_input
, "demux" );
2203 if( psz_var_demux
!= NULL
&&
2204 !strchr(psz_var_demux
, ',' ) &&
2205 !strchr(psz_var_demux
, ':' ) )
2207 psz_demux
= psz_var_demux
;
2209 msg_Dbg( p_input
, "enforced demux ` %s'", psz_demux
);
2213 /* Try access_demux if no demux given */
2214 if( *psz_demux
== '\0' )
2216 in
->p_demux
= demux2_New( p_input
, psz_access
, psz_demux
, psz_path
,
2217 NULL
, p_input
->p
->p_es_out
, VLC_FALSE
);
2223 if( !strncmp( psz_path
, "file://", 7 ) )
2225 msg_Dbg( p_input
, "trying to pre-parse %s", psz_path
);
2227 psz_access
= "file";
2232 int64_t i_pts_delay
;
2234 /* Get infos from access_demux */
2235 demux2_Control( in
->p_demux
,
2236 DEMUX_GET_PTS_DELAY
, &i_pts_delay
);
2237 p_input
->i_pts_delay
= __MAX( p_input
->i_pts_delay
, i_pts_delay
);
2239 in
->b_title_demux
= VLC_TRUE
;
2240 if( demux2_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2241 &in
->title
, &in
->i_title
,
2242 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2247 if( demux2_Control( in
->p_demux
, DEMUX_CAN_CONTROL_PACE
,
2248 &in
->b_can_pace_control
) )
2249 in
->b_can_pace_control
= VLC_FALSE
;
2251 if( !in
->b_can_pace_control
)
2253 if( demux2_Control( in
->p_demux
, DEMUX_CAN_CONTROL_RATE
,
2254 &in
->b_can_rate_control
, &in
->b_rescale_ts
) )
2256 in
->b_can_rate_control
= VLC_FALSE
;
2257 in
->b_rescale_ts
= VLC_TRUE
; /* not used */
2262 in
->b_can_rate_control
= VLC_TRUE
;
2263 in
->b_rescale_ts
= VLC_TRUE
;
2265 if( demux2_Control( in
->p_demux
, DEMUX_CAN_PAUSE
,
2266 &in
->b_can_pause
) )
2267 in
->b_can_pause
= VLC_FALSE
;
2270 demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
2276 int64_t i_pts_delay
;
2278 input_ChangeState( p_input
, OPENING_S
);
2280 /* Now try a real access */
2281 in
->p_access
= access2_New( p_input
, psz_access
, psz_demux
, psz_path
,
2282 p_input
->b_preparsing
);
2284 /* Access failed, URL encoded ? */
2285 if( in
->p_access
== NULL
&& strchr( psz_path
, '%' ) )
2287 decode_URI( psz_path
);
2289 msg_Dbg( p_input
, "retrying with access `%s' demux `%s' path `%s'",
2290 psz_access
, psz_demux
, psz_path
);
2292 in
->p_access
= access2_New( p_input
,
2293 psz_access
, psz_demux
, psz_path
,
2294 p_input
->b_preparsing
);
2296 /* access failed, maybe our access detection was wrong.
2297 * Retry with the full name */
2298 if( in
->p_access
== NULL
&& strchr( psz_mrl
, ':' ) )
2300 msg_Dbg( p_input
, "retrying with access `' demux `' path `%s'",
2303 in
->p_access
= access2_New( p_input
,
2305 p_input
->b_preparsing
);
2307 if( in
->p_access
== NULL
)
2309 msg_Err( p_input
, "open of `%s' failed: %s", psz_mrl
,
2311 intf_UserFatal( VLC_OBJECT( p_input
), VLC_FALSE
,
2312 _("Your input can't be opened"),
2313 _("VLC is unable to open the MRL '%s'."
2314 " Check the log for details."), psz_mrl
);
2319 psz_tmp
= psz
= var_GetNonEmptyString( p_input
, "access-filter" );
2320 while( psz
&& *psz
)
2322 access_t
*p_access
= in
->p_access
;
2323 char *end
= strchr( psz
, ':' );
2328 in
->p_access
= access2_FilterNew( in
->p_access
, psz
);
2329 if( in
->p_access
== NULL
)
2331 in
->p_access
= p_access
;
2332 msg_Warn( p_input
, "failed to insert access filter %s",
2340 /* Get infos from access */
2341 if( !p_input
->b_preparsing
)
2343 access2_Control( in
->p_access
,
2344 ACCESS_GET_PTS_DELAY
, &i_pts_delay
);
2345 p_input
->i_pts_delay
= __MAX( p_input
->i_pts_delay
, i_pts_delay
);
2347 in
->b_title_demux
= VLC_FALSE
;
2348 if( access2_Control( in
->p_access
, ACCESS_GET_TITLE_INFO
,
2349 &in
->title
, &in
->i_title
,
2350 &in
->i_title_offset
, &in
->i_seekpoint_offset
) )
2356 access2_Control( in
->p_access
, ACCESS_CAN_CONTROL_PACE
,
2357 &in
->b_can_pace_control
);
2358 in
->b_can_rate_control
= in
->b_can_pace_control
;
2359 in
->b_rescale_ts
= VLC_TRUE
;
2361 access2_Control( in
->p_access
, ACCESS_CAN_PAUSE
,
2363 access2_Control( in
->p_access
, ACCESS_CAN_SEEK
,
2365 var_Set( p_input
, "seekable", val
);
2368 input_ChangeState( p_input
, BUFFERING_S
);
2370 /* Create the stream_t */
2371 in
->p_stream
= stream_AccessNew( in
->p_access
, p_input
->b_preparsing
);
2372 if( in
->p_stream
== NULL
)
2374 msg_Warn( p_input
, "cannot create a stream_t from access" );
2378 /* Open a demuxer */
2379 if( *psz_demux
== '\0' && *in
->p_access
->psz_demux
)
2381 psz_demux
= in
->p_access
->psz_demux
;
2385 /* Take access redirections into account */
2386 char *psz_real_path
;
2387 char *psz_buf
= NULL
;
2388 if( in
->p_access
->psz_path
)
2390 const char *psz_a
, *psz_d
;
2391 psz_buf
= strdup( in
->p_access
->psz_path
);
2392 MRLSplit( VLC_OBJECT(p_input
), psz_buf
,
2393 &psz_a
, &psz_d
, &psz_real_path
);
2397 psz_real_path
= psz_path
;
2399 in
->p_demux
= demux2_New( p_input
, psz_access
, psz_demux
,
2401 in
->p_stream
, p_input
->p
->p_es_out
,
2402 p_input
->b_preparsing
);
2406 if( in
->p_demux
== NULL
)
2408 msg_Err( p_input
, "no suitable demux module for `%s/%s://%s'",
2409 psz_access
, psz_demux
, psz_path
);
2410 intf_UserFatal( VLC_OBJECT( p_input
), VLC_FALSE
,
2411 _("VLC can't recognize the input's format"),
2412 _("The format of '%s' cannot be detected. "
2413 "Have a look the log for details."), psz_mrl
);
2417 /* Get title from demux */
2418 if( !p_input
->b_preparsing
&& in
->i_title
<= 0 )
2420 if( demux2_Control( in
->p_demux
, DEMUX_GET_TITLE_INFO
,
2421 &in
->title
, &in
->i_title
,
2422 &in
->i_title_offset
, &in
->i_seekpoint_offset
))
2424 TAB_INIT( in
->i_title
, in
->title
);
2428 in
->b_title_demux
= VLC_TRUE
;
2434 * FIXME improve for b_preparsing: move it after GET_META and check psz_arturl */
2435 if( 1 || !p_input
->b_preparsing
)
2438 input_attachment_t
**attachment
;
2439 if( !demux2_Control( in
->p_demux
, DEMUX_GET_ATTACHMENTS
,
2440 &attachment
, &i_attachment
) )
2442 vlc_mutex_lock( &p_input
->p
->input
.p_item
->lock
);
2443 AppendAttachment( &p_input
->p
->i_attachment
, &p_input
->p
->attachment
,
2444 i_attachment
, attachment
);
2445 vlc_mutex_unlock( &p_input
->p
->input
.p_item
->lock
);
2448 if( !demux2_Control( in
->p_demux
, DEMUX_GET_FPS
, &f_fps
) )
2450 vlc_mutex_lock( &p_input
->p
->input
.p_item
->lock
);
2452 vlc_mutex_unlock( &p_input
->p
->input
.p_item
->lock
);
2455 if( var_GetInteger( p_input
, "clock-synchro" ) != -1 )
2456 in
->b_can_pace_control
= !var_GetInteger( p_input
, "clock-synchro" );
2461 input_ChangeState( p_input
, ERROR_S
);
2464 demux2_Delete( in
->p_demux
);
2467 stream_Delete( in
->p_stream
);
2470 access2_Delete( in
->p_access
);
2472 return VLC_EGENERIC
;
2475 /*****************************************************************************
2477 *****************************************************************************/
2478 static void InputSourceClean( input_source_t
*in
)
2483 demux2_Delete( in
->p_demux
);
2486 stream_Delete( in
->p_stream
);
2489 access2_Delete( in
->p_access
);
2491 if( in
->i_title
> 0 )
2493 for( i
= 0; i
< in
->i_title
; i
++ )
2494 vlc_input_title_Delete( in
->title
[i
] );
2495 TAB_CLEAN( in
->i_title
, in
->title
);
2499 static void SlaveDemux( input_thread_t
*p_input
)
2504 if( demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_TIME
, &i_time
) )
2506 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2510 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
2512 input_source_t
*in
= p_input
->p
->slave
[i
];
2518 if( demux2_Control( in
->p_demux
, DEMUX_SET_NEXT_DEMUX_TIME
, i_time
) )
2523 if( demux2_Control( in
->p_demux
, DEMUX_GET_TIME
, &i_stime
) )
2525 msg_Err( p_input
, "slave[%d] doesn't like "
2526 "DEMUX_GET_TIME -> EOF", i
);
2531 if( i_stime
>= i_time
)
2534 if( ( i_ret
= in
->p_demux
->pf_demux( in
->p_demux
) ) <= 0 )
2540 i_ret
= in
->p_demux
->pf_demux( in
->p_demux
);
2545 msg_Dbg( p_input
, "slave %d EOF", i
);
2546 in
->b_eof
= VLC_TRUE
;
2551 static void SlaveSeek( input_thread_t
*p_input
)
2556 if( !p_input
) return;
2558 if( demux2_Control( p_input
->p
->input
.p_demux
, DEMUX_GET_TIME
, &i_time
) )
2560 msg_Err( p_input
, "demux doesn't like DEMUX_GET_TIME" );
2564 for( i
= 0; i
< p_input
->p
->i_slave
; i
++ )
2566 input_source_t
*in
= p_input
->p
->slave
[i
];
2568 if( demux2_Control( in
->p_demux
, DEMUX_SET_TIME
, i_time
) )
2570 msg_Err( p_input
, "seek failed for slave %d -> EOF", i
);
2571 in
->b_eof
= VLC_TRUE
;
2576 /*****************************************************************************
2578 *****************************************************************************/
2579 static void InputMetaUser( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2583 if( !p_meta
) return;
2585 /* Get meta information from user */
2586 #define GET_META( field, s ) \
2587 var_Get( p_input, (s), &val ); \
2588 if( *val.psz_string ) \
2589 vlc_meta_Set( p_meta, vlc_meta_ ## field, val.psz_string ); \
2590 free( val.psz_string )
2592 GET_META( Title
, "meta-title" );
2593 GET_META( Artist
, "meta-artist" );
2594 GET_META( Genre
, "meta-genre" );
2595 GET_META( Copyright
, "meta-copyright" );
2596 GET_META( Description
, "meta-description" );
2597 GET_META( Date
, "meta-date" );
2598 GET_META( URL
, "meta-url" );
2602 /*****************************************************************************
2603 * InputUpdateMeta: merge p_item meta data with p_meta taking care of
2604 * arturl and locking issue.
2605 *****************************************************************************/
2606 static void InputUpdateMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
)
2608 input_item_t
*p_item
= p_input
->p
->input
.p_item
;
2609 char * psz_arturl
= NULL
;
2610 char *psz_title
= NULL
;
2612 int i_arturl_event
= VLC_FALSE
;
2617 psz_arturl
= input_item_GetArtURL( p_item
);
2619 vlc_mutex_lock( &p_item
->lock
);
2620 if( vlc_meta_Get( p_meta
, vlc_meta_Title
) && !p_item
->b_fixed_name
)
2621 psz_title
= strdup( vlc_meta_Get( p_meta
, vlc_meta_Title
) );
2623 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
2625 if( psz_arturl
&& *psz_arturl
)
2627 vlc_meta_Set( p_item
->p_meta
, vlc_meta_ArtworkURL
, psz_arturl
);
2628 i_arturl_event
= VLC_TRUE
;
2631 vlc_meta_Delete( p_meta
);
2633 if( psz_arturl
&& !strncmp( psz_arturl
, "attachment://", strlen("attachment") ) )
2635 /* Don't look for art cover if sout
2636 * XXX It can change when sout has meta data support */
2637 if( p_input
->p
->p_sout
&& !p_input
->b_preparsing
)
2639 vlc_meta_Set( p_item
->p_meta
, vlc_meta_ArtworkURL
, "" );
2640 i_arturl_event
= VLC_TRUE
;
2644 input_ExtractAttachmentAndCacheArt( p_input
);
2650 if( vlc_dictionary_keys_count( &p_item
->p_meta
->extra_tags
) > 0 )
2652 p_meta
= vlc_meta_New();
2653 vlc_meta_Merge( p_meta
, input_item_GetMetaObject( p_item
) );
2655 vlc_mutex_unlock( &p_item
->lock
);
2657 input_item_SetPreparsed( p_item
, VLC_TRUE
);
2659 if( i_arturl_event
== VLC_TRUE
)
2663 /* Notify interested third parties */
2664 event
.type
= vlc_InputItemMetaChanged
;
2665 event
.u
.input_item_meta_changed
.meta_type
= vlc_meta_ArtworkURL
;
2666 vlc_event_send( &p_item
->event_manager
, &event
);
2671 input_Control( p_input
, INPUT_SET_NAME
, psz_title
);
2677 char ** ppsz_all_keys
= vlc_dictionary_all_keys( &p_meta
->extra_tags
);
2678 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
2680 input_Control( p_input
, INPUT_ADD_INFO
, _(VLC_META_INFO_CAT
), _(ppsz_all_keys
[i
]),
2681 vlc_dictionary_value_for_key( &p_meta
->extra_tags
, ppsz_all_keys
[i
] ) );
2682 free( ppsz_all_keys
[i
] );
2684 free( ppsz_all_keys
);
2685 vlc_meta_Delete( p_meta
);
2688 /** \todo handle sout meta */
2692 static inline vlc_bool_t
IsValidAccess( const char *psz
)
2696 while( ( c
= *psz
) != '\0' )
2701 if( ( !isascii( c
) || !isalnum( c
) ) && c
!= '-' && ( c
!= '/' ) )
2705 /* should not happen though */
2709 static void AppendAttachment( int *pi_attachment
, input_attachment_t
***ppp_attachment
,
2710 int i_new
, input_attachment_t
**pp_new
)
2712 int i_attachment
= *pi_attachment
;
2713 input_attachment_t
**attachment
= *ppp_attachment
;
2716 attachment
= realloc( attachment
,
2717 sizeof(input_attachment_t
**) * ( i_attachment
+ i_new
) );
2718 for( i
= 0; i
< i_new
; i
++ )
2719 attachment
[i_attachment
++] = pp_new
[i
];
2724 *pi_attachment
= i_attachment
;
2725 *ppp_attachment
= attachment
;
2728 static void DemuxMeta( input_thread_t
*p_input
, vlc_meta_t
*p_meta
, demux_t
*p_demux
)
2735 /* XXX I am not sure it is a great idea, besides, there is more than that
2736 * if we want to do it right */
2737 vlc_mutex_lock( &p_item
->lock
);
2738 if( p_item
->p_meta
&& (p_item
->p_meta
->i_status
& ITEM_PREPARSED
) )
2740 vlc_mutex_unlock( &p_item
->lock
);
2743 vlc_mutex_unlock( &p_item
->lock
);
2746 demux2_Control( p_demux
, DEMUX_GET_META
, p_meta
);
2747 if( demux2_Control( p_demux
, DEMUX_HAS_UNSUPPORTED_META
, &b_bool
) )
2752 p_demux
->p_private
= malloc( sizeof( demux_meta_t
) );
2753 if(! p_demux
->p_private
)
2756 p_id3
= module_Need( p_demux
, "meta reader", NULL
, 0 );
2759 demux_meta_t
*p_demux_meta
= (demux_meta_t
*)p_demux
->p_private
;
2761 if( p_demux_meta
->p_meta
)
2763 vlc_meta_Merge( p_meta
, p_demux_meta
->p_meta
);
2764 vlc_meta_Delete( p_demux_meta
->p_meta
);
2767 if( p_demux_meta
->i_attachments
> 0 )
2769 vlc_mutex_lock( &p_input
->p
->input
.p_item
->lock
);
2770 AppendAttachment( &p_input
->p
->i_attachment
, &p_input
->p
->attachment
,
2771 p_demux_meta
->i_attachments
, p_demux_meta
->attachments
);
2772 vlc_mutex_unlock( &p_input
->p
->input
.p_item
->lock
);
2774 module_Unneed( p_demux
, p_id3
);
2776 free( p_demux
->p_private
);
2780 /*****************************************************************************
2781 * MRLSplit: parse the access, demux and url part of the
2782 * Media Resource Locator.
2783 *****************************************************************************/
2784 void MRLSplit( vlc_object_t
*p_input
, char *psz_dup
,
2785 const char **ppsz_access
, const char **ppsz_demux
,
2788 const char *psz_access
= "";
2789 const char *psz_demux
= "";
2793 psz
= strchr( psz_dup
, ':' );
2797 /* Guess whether ':' is part of a local filename, or separates
2798 * access/demux from path */
2799 if( !IsValidAccess( psz_dup
) )
2801 #if defined( WIN32 ) || defined( UNDER_CE )
2802 else if( ( psz
- psz_dup
== 1 ) && isalpha( psz_dup
[0] ) )
2804 msg_Dbg( p_input
, "drive letter %c: found in source", *psz_dup
);
2813 if( psz
[0] == '/' && psz
[1] == '/' ) psz
+= 2;
2817 psz
= strchr( psz_dup
, '/' );
2824 psz_access
= psz_dup
;
2831 *ppsz_access
= psz_access
;
2832 *ppsz_demux
= psz_demux
;
2833 *ppsz_path
= psz_path
;
2836 /*****************************************************************************
2837 * MRLSections: parse title and seekpoint info from the Media Resource Locator.
2840 * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
2841 *****************************************************************************/
2842 static void MRLSections( input_thread_t
*p_input
, char *psz_source
,
2843 int *pi_title_start
, int *pi_title_end
,
2844 int *pi_chapter_start
, int *pi_chapter_end
)
2846 char *psz
, *psz_end
, *psz_next
, *psz_check
;
2848 *pi_title_start
= *pi_title_end
= -1;
2849 *pi_chapter_start
= *pi_chapter_end
= -1;
2851 /* Start by parsing titles and chapters */
2852 if( !psz_source
|| !( psz
= strrchr( psz_source
, '@' ) ) ) return;
2854 /* Check we are really dealing with a title/chapter section */
2855 psz_check
= psz
+ 1;
2856 if( !*psz_check
) return;
2857 if( isdigit(*psz_check
) ) strtol( psz_check
, &psz_check
, 0 );
2858 if( *psz_check
!= ':' && *psz_check
!= '-' && *psz_check
) return;
2859 if( *psz_check
== ':' && ++psz_check
)
2860 if( isdigit(*psz_check
) ) strtol( psz_check
, &psz_check
, 0 );
2861 if( *psz_check
!= '-' && *psz_check
) return;
2862 if( *psz_check
== '-' && ++psz_check
)
2863 if( isdigit(*psz_check
) ) strtol( psz_check
, &psz_check
, 0 );
2864 if( *psz_check
!= ':' && *psz_check
) return;
2865 if( *psz_check
== ':' && ++psz_check
)
2866 if( isdigit(*psz_check
) ) strtol( psz_check
, &psz_check
, 0 );
2867 if( *psz_check
) return;
2869 /* Separate start and end */
2871 if( ( psz_end
= strchr( psz
, '-' ) ) ) *psz_end
++ = 0;
2873 /* Look for the start title */
2874 *pi_title_start
= strtol( psz
, &psz_next
, 0 );
2875 if( !*pi_title_start
&& psz
== psz_next
) *pi_title_start
= -1;
2876 *pi_title_end
= *pi_title_start
;
2879 /* Look for the start chapter */
2881 *pi_chapter_start
= strtol( psz
, &psz_next
, 0 );
2882 if( !*pi_chapter_start
&& psz
== psz_next
) *pi_chapter_start
= -1;
2883 *pi_chapter_end
= *pi_chapter_start
;
2887 /* Look for the end title */
2888 *pi_title_end
= strtol( psz_end
, &psz_next
, 0 );
2889 if( !*pi_title_end
&& psz_end
== psz_next
) *pi_title_end
= -1;
2892 /* Look for the end chapter */
2893 if( *psz_end
) psz_end
++;
2894 *pi_chapter_end
= strtol( psz_end
, &psz_next
, 0 );
2895 if( !*pi_chapter_end
&& psz_end
== psz_next
) *pi_chapter_end
= -1;
2898 msg_Dbg( p_input
, "source=`%s' title=%d/%d seekpoint=%d/%d",
2899 psz_source
, *pi_title_start
, *pi_chapter_start
,
2900 *pi_title_end
, *pi_chapter_end
);
2903 /*****************************************************************************
2904 * input_AddSubtitles: add a subtitles file and enable it
2905 *****************************************************************************/
2906 vlc_bool_t
input_AddSubtitles( input_thread_t
*p_input
, char *psz_subtitle
,
2907 vlc_bool_t b_check_extension
)
2909 input_source_t
*sub
;
2912 char *psz_path
, *psz_extension
;
2914 if( b_check_extension
&& !subtitles_Filter( psz_subtitle
) )
2919 /* if we are provided a subtitle.sub file,
2920 * see if we don't have a subtitle.idx and use it instead */
2921 psz_path
= strdup( psz_subtitle
);
2924 psz_extension
= strrchr( psz_path
, '.');
2925 if( psz_extension
&& strcmp( psz_extension
, ".sub" ) == 0 )
2929 strcpy( psz_extension
, ".idx" );
2930 /* FIXME: a portable wrapper for stat() or access() would be more suited */
2931 if( ( f
= utf8_fopen( psz_path
, "rt" ) ) )
2934 msg_Dbg( p_input
, "using %s subtitles file instead of %s",
2935 psz_path
, psz_subtitle
);
2936 strcpy( psz_subtitle
, psz_path
);
2942 var_Change( p_input
, "spu-es", VLC_VAR_CHOICESCOUNT
, &count
, NULL
);
2944 sub
= InputSourceNew( p_input
);
2945 if( !InputSourceInit( p_input
, sub
, psz_subtitle
, "subtitle" ) )
2947 TAB_APPEND( p_input
->p
->i_slave
, p_input
->p
->slave
, sub
);
2950 if( !var_Change( p_input
, "spu-es", VLC_VAR_GETLIST
, &list
, NULL
) )
2952 if( count
.i_int
== 0 )
2954 /* if it was first one, there is disable too */
2956 if( count
.i_int
< list
.p_list
->i_count
)
2958 input_ControlPush( p_input
, INPUT_CONTROL_SET_ES
,
2959 &list
.p_list
->p_values
[count
.i_int
] );
2961 var_Change( p_input
, "spu-es", VLC_VAR_FREELIST
, &list
, NULL
);