Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

input.c

00001 /*****************************************************************************
00002  * input.c: input thread
00003  *****************************************************************************
00004  * Copyright (C) 1998-2004 the VideoLAN team
00005  * $Id: input.c 12888 2005-10-19 09:12:12Z gbazin $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *          Laurent Aimar <[email protected]>
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00023  *****************************************************************************/
00024 
00025 /*****************************************************************************
00026  * Preamble
00027  *****************************************************************************/
00028 #include <stdlib.h>
00029 #include <ctype.h>
00030 
00031 #include <vlc/vlc.h>
00032 #include <vlc/input.h>
00033 #include <vlc/decoder.h>
00034 #include <vlc/vout.h>
00035 
00036 #include "input_internal.h"
00037 
00038 #include "stream_output.h"
00039 #include "vlc_playlist.h"
00040 #include "vlc_interface.h"
00041 
00042 /*****************************************************************************
00043  * Local prototypes
00044  *****************************************************************************/
00045 static  int Run  ( input_thread_t *p_input );
00046 
00047 static  int Init ( input_thread_t *p_input, vlc_bool_t b_quick );
00048 static void Error( input_thread_t *p_input );
00049 static void End  ( input_thread_t *p_input );
00050 
00051 static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
00052 static void       ControlReduce( input_thread_t * );
00053 static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
00054 
00055 
00056 static int  UpdateFromAccess( input_thread_t * );
00057 static int  UpdateFromDemux( input_thread_t * );
00058 static int  UpdateMeta( input_thread_t *, vlc_bool_t );
00059 
00060 static void UpdateItemLength( input_thread_t *, int64_t i_length, vlc_bool_t );
00061 
00062 static void ParseOption( input_thread_t *p_input, const char *psz_option );
00063 
00064 static void DecodeUrl( char * );
00065 static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
00066 
00067 static input_source_t *InputSourceNew( input_thread_t *);
00068 static int  InputSourceInit( input_thread_t *, input_source_t *,
00069                              char *, char *psz_forced_demux,
00070                              vlc_bool_t b_quick );
00071 static void InputSourceClean( input_thread_t *, input_source_t * );
00072 
00073 static void SlaveDemux( input_thread_t *p_input );
00074 static void SlaveSeek( input_thread_t *p_input );
00075 
00076 static vlc_meta_t *InputMetaUser( input_thread_t *p_input );
00077 
00078 /*****************************************************************************
00079  * input_CreateThread: creates a new input thread
00080  *****************************************************************************
00081  * This function creates a new input, and returns a pointer
00082  * to its description. On error, it returns NULL.
00083  *
00084  * Variables for _public_ use:
00085  * * Get and Set:
00086  *  - state
00087  *  - rate,rate-slower, rate-faster
00088  *  - position, position-offset
00089  *  - time, time-offset
00090  *  - title,title-next,title-prev
00091  *  - chapter,chapter-next, chapter-prev
00092  *  - program, audio-es, video-es, spu-es
00093  *  - audio-delay, spu-delay
00094  *  - bookmark
00095  * * Get only:
00096  *  - length
00097  *  - bookmarks
00098  *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
00099  * * For intf callback upon changes
00100  *  - intf-change
00101  * TODO explain when Callback is called
00102  * TODO complete this list (?)
00103  *****************************************************************************/
00104 input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
00105                                       input_item_t *p_item )
00106 
00107 {
00108     input_thread_t *p_input;                        /* thread descriptor */
00109     vlc_value_t val;
00110     int i;
00111 
00112     /* Allocate descriptor */
00113     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
00114     if( p_input == NULL )
00115     {
00116         msg_Err( p_parent, "out of memory" );
00117         return NULL;
00118     }
00119 
00120     /* Init Common fields */
00121     p_input->b_eof = VLC_FALSE;
00122     p_input->b_can_pace_control = VLC_TRUE;
00123     p_input->i_start = 0;
00124     p_input->i_time  = 0;
00125     p_input->i_stop  = 0;
00126     p_input->i_title = 0;
00127     p_input->title   = NULL;
00128     p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
00129     p_input->i_state = INIT_S;
00130     p_input->i_rate  = INPUT_RATE_DEFAULT;
00131     p_input->i_bookmark = 0;
00132     p_input->bookmark = NULL;
00133     p_input->p_meta  = NULL;
00134     p_input->p_es_out = NULL;
00135     p_input->p_sout  = NULL;
00136     p_input->b_out_pace_control = VLC_FALSE;
00137     p_input->i_pts_delay = 0;
00138 
00139     /* Init Input fields */
00140     p_input->input.p_item = p_item;
00141     p_input->input.p_access = NULL;
00142     p_input->input.p_stream = NULL;
00143     p_input->input.p_demux  = NULL;
00144     p_input->input.b_title_demux = VLC_FALSE;
00145     p_input->input.i_title  = 0;
00146     p_input->input.title    = NULL;
00147     p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
00148     p_input->input.b_can_pace_control = VLC_TRUE;
00149     p_input->input.b_eof = VLC_FALSE;
00150     p_input->input.i_cr_average = 0;
00151 
00152     /* No slave */
00153     p_input->i_slave = 0;
00154     p_input->slave   = NULL;
00155 
00156     /* Init control buffer */
00157     vlc_mutex_init( p_input, &p_input->lock_control );
00158     p_input->i_control = 0;
00159 
00160     /* Parse input options */
00161     vlc_mutex_lock( &p_item->lock );
00162     for( i = 0; i < p_item->i_options; i++ )
00163     {
00164         ParseOption( p_input, p_item->ppsz_options[i] );
00165     }
00166     vlc_mutex_unlock( &p_item->lock );
00167 
00168     /* Create Object Variables for private use only */
00169     input_ConfigVarInit( p_input );
00170 
00171     /* Create Objects variables for public Get and Set */
00172     input_ControlVarInit( p_input );
00173     p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
00174 
00175     /* TODO */
00176     var_Get( p_input, "bookmarks", &val );
00177     if( val.psz_string )
00178     {
00179         /* FIXME: have a common cfg parsing routine used by sout and others */
00180         char *psz_parser, *psz_start, *psz_end;
00181         psz_parser = val.psz_string;
00182         while( (psz_start = strchr( psz_parser, '{' ) ) )
00183         {
00184             seekpoint_t *p_seekpoint = vlc_seekpoint_New();
00185             char backup;
00186             psz_start++;
00187             psz_end = strchr( psz_start, '}' );
00188             if( !psz_end ) break;
00189             psz_parser = psz_end + 1;
00190             backup = *psz_parser;
00191             *psz_parser = 0;
00192             *psz_end = ',';
00193 
00194             while( (psz_end = strchr( psz_start, ',' ) ) )
00195             {
00196                 *psz_end = 0;
00197                 if( !strncmp( psz_start, "name=", 5 ) )
00198                 {
00199                     p_seekpoint->psz_name = psz_start + 5;
00200                 }
00201                 else if( !strncmp( psz_start, "bytes=", 6 ) )
00202                 {
00203                     p_seekpoint->i_byte_offset = atoll(psz_start + 6);
00204                 }
00205                 else if( !strncmp( psz_start, "time=", 5 ) )
00206                 {
00207                     p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000;
00208                 }
00209                 psz_start = psz_end + 1;
00210             }
00211             msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
00212                      p_seekpoint->psz_name, p_seekpoint->i_byte_offset,
00213                      p_seekpoint->i_time_offset );
00214             input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
00215             vlc_seekpoint_Delete( p_seekpoint );
00216             *psz_parser = backup;
00217         }
00218         free( val.psz_string );
00219     }
00220 
00221     /* Remove 'Now playing' info as it is probably outdated */
00222     input_Control( p_input, INPUT_DEL_INFO, _("Meta-information"),
00223                    VLC_META_NOW_PLAYING );
00224 
00225     /* Now we can attach our new input */
00226     vlc_object_attach( p_input, p_parent );
00227 
00228     /* Create thread and wait for its readiness. */
00229     if( vlc_thread_create( p_input, "input", Run,
00230                            VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
00231     {
00232         msg_Err( p_input, "cannot create input thread" );
00233         vlc_object_detach( p_input );
00234         vlc_object_destroy( p_input );
00235         return NULL;
00236     }
00237 
00238     return p_input;
00239 }
00240 
00241 /*****************************************************************************
00242  * input_PreParse: Lightweight input for playlist item preparsing
00243  *****************************************************************************/
00244 int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
00245 {
00246     input_thread_t *p_input;                        /* thread descriptor */
00247     int i;
00248 
00249     /* Allocate descriptor */
00250     p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
00251     if( p_input == NULL )
00252     {
00253         msg_Err( p_parent, "out of memory" );
00254         return VLC_EGENERIC;
00255     }
00256 
00257     /* Init Common fields */
00258     p_input->b_eof = VLC_FALSE;
00259     p_input->b_can_pace_control = VLC_TRUE;
00260     p_input->i_start = 0;
00261     p_input->i_time  = 0;
00262     p_input->i_stop  = 0;
00263     p_input->i_title = 0;
00264     p_input->title   = NULL;
00265     p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
00266     p_input->i_state = INIT_S;
00267     p_input->i_rate  = INPUT_RATE_DEFAULT;
00268     p_input->i_bookmark = 0;
00269     p_input->bookmark = NULL;
00270     p_input->p_meta  = NULL;
00271     p_input->p_es_out = NULL;
00272     p_input->p_sout  = NULL;
00273     p_input->b_out_pace_control = VLC_FALSE;
00274     p_input->i_pts_delay = 0;
00275 
00276     /* Init Input fields */
00277     p_input->input.p_item = p_item;
00278     p_input->input.p_access = NULL;
00279     p_input->input.p_stream = NULL;
00280     p_input->input.p_demux  = NULL;
00281     p_input->input.b_title_demux = VLC_FALSE;
00282     p_input->input.i_title  = 0;
00283     p_input->input.title    = NULL;
00284     p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
00285     p_input->input.b_can_pace_control = VLC_TRUE;
00286     p_input->input.b_eof = VLC_FALSE;
00287     p_input->input.i_cr_average = 0;
00288 
00289     /* No slave */
00290     p_input->i_slave = 0;
00291     p_input->slave   = NULL;
00292 
00293     /* Init control buffer */
00294     vlc_mutex_init( p_input, &p_input->lock_control );
00295     p_input->i_control = 0;
00296 
00297     /* Parse input options */
00298     vlc_mutex_lock( &p_item->lock );
00299     for( i = 0; i < p_item->i_options; i++ )
00300     {
00301         ParseOption( p_input, p_item->ppsz_options[i] );
00302     }
00303     vlc_mutex_unlock( &p_item->lock );
00304 
00305     /* Create Object Variables for private use only */
00306     input_ConfigVarInit( p_input );
00307     input_ControlVarInit( p_input );
00308 
00309     p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
00310 
00311     /* Now we can attach our new input */
00312     vlc_object_attach( p_input, p_parent );
00313 
00314     Init( p_input, VLC_TRUE );
00315 
00316     /* Clean up master */
00317     InputSourceClean( p_input, &p_input->input );
00318 
00319     /* Kill access and demux */
00320     if( p_input->input.p_access ) p_input->input.p_access->b_die = VLC_TRUE;
00321     if( p_input->input.p_demux ) p_input->input.p_access->b_die = VLC_TRUE;
00322 
00323     /* Unload all modules */
00324     if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
00325 
00326     /* Delete meta */
00327     if( p_input->p_meta ) vlc_meta_Delete( p_input->p_meta );
00328 
00329     vlc_object_detach( p_input );
00330     vlc_object_destroy( p_input );
00331 
00332     return VLC_SUCCESS;
00333 }
00334 
00335 /*****************************************************************************
00336  * input_StopThread: mark an input thread as zombie
00337  *****************************************************************************
00338  * This function should not return until the thread is effectively cancelled.
00339  *****************************************************************************/
00340 void input_StopThread( input_thread_t *p_input )
00341 {
00342     vlc_list_t *p_list;
00343     int i;
00344 
00345     /* Set die for input */
00346     p_input->b_die = VLC_TRUE;
00347 
00348     /* We cannot touch p_input fields directly (we can from another thread),
00349      * so use the vlc_object_find way, it's perfectly safe */
00350 
00351     /* Set die for all access */
00352     p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
00353     for( i = 0; i < p_list->i_count; i++ )
00354     {
00355         p_list->p_values[i].p_object->b_die = VLC_TRUE;
00356     }
00357     vlc_list_release( p_list );
00358 
00359     /* Set die for all stream */
00360     p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
00361     for( i = 0; i < p_list->i_count; i++ )
00362     {
00363         p_list->p_values[i].p_object->b_die = VLC_TRUE;
00364     }
00365     vlc_list_release( p_list );
00366 
00367     /* Set die for all demux */
00368     p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
00369     for( i = 0; i < p_list->i_count; i++ )
00370     {
00371         p_list->p_values[i].p_object->b_die = VLC_TRUE;
00372     }
00373     vlc_list_release( p_list );
00374 
00375     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
00376 }
00377 
00378 /*****************************************************************************
00379  * input_DestroyThread: mark an input thread as zombie
00380  *****************************************************************************
00381  * This function should not return until the thread is effectively cancelled.
00382  *****************************************************************************/
00383 void input_DestroyThread( input_thread_t *p_input )
00384 {
00385     /* Join the thread */
00386     vlc_thread_join( p_input );
00387 
00388     /* Delete input lock (only after thread joined) */
00389     vlc_mutex_destroy( &p_input->lock_control );
00390 
00391     /* TODO: maybe input_DestroyThread should also delete p_input instead
00392      * of the playlist but I'm not sure if it's possible */
00393 }
00394 
00395 /*****************************************************************************
00396  * Run: main thread loop
00397  *****************************************************************************
00398  * Thread in charge of processing the network packets and demultiplexing.
00399  *
00400  * TODO:
00401  *  read subtitle support (XXX take care of spu-delay in the right way).
00402  *  multi-input support (XXX may be done with subs)
00403  *****************************************************************************/
00404 static int Run( input_thread_t *p_input )
00405 {
00406     int64_t i_intf_update = 0;
00407 
00408     /* Signal that the thread is launched */
00409     vlc_thread_ready( p_input );
00410 
00411     if( Init( p_input, VLC_FALSE ) )
00412     {
00413         /* If we failed, wait before we are killed, and exit */
00414         p_input->b_error = VLC_TRUE;
00415 
00416         Error( p_input );
00417 
00418         /* Tell we're dead */
00419         p_input->b_dead = VLC_TRUE;
00420 
00421         return 0;
00422     }
00423 
00424     /* Main loop */
00425     while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
00426     {
00427         vlc_bool_t b_force_update = VLC_FALSE;
00428         int i_ret;
00429         int i_type;
00430         vlc_value_t val;
00431 
00432         /* Do the read */
00433         if( p_input->i_state != PAUSE_S  )
00434         {
00435             if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
00436                 i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
00437             else
00438                 i_ret = 0;  /* EOF */
00439 
00440             if( i_ret > 0 )
00441             {
00442                 /* TODO */
00443                 if( p_input->input.b_title_demux &&
00444                     p_input->input.p_demux->info.i_update )
00445                 {
00446                     i_ret = UpdateFromDemux( p_input );
00447                     b_force_update = VLC_TRUE;
00448                 }
00449                 else if( !p_input->input.b_title_demux &&
00450                           p_input->input.p_access &&
00451                           p_input->input.p_access->info.i_update )
00452                 {
00453                     i_ret = UpdateFromAccess( p_input );
00454                     b_force_update = VLC_TRUE;
00455                 }
00456             }
00457 
00458             if( i_ret == 0 )    /* EOF */
00459             {
00460                 vlc_value_t repeat;
00461 
00462                 var_Get( p_input, "input-repeat", &repeat );
00463                 if( repeat.i_int == 0 )
00464                 {
00465                     /* End of file - we do not set b_die because only the
00466                      * playlist is allowed to do so. */
00467                     msg_Dbg( p_input, "EOF reached" );
00468                     p_input->input.b_eof = VLC_TRUE;
00469                 }
00470                 else
00471                 {
00472                     msg_Dbg( p_input, "repeating the same input (%d)",
00473                              repeat.i_int );
00474                     if( repeat.i_int > 0 )
00475                     {
00476                         repeat.i_int--;
00477                         var_Set( p_input, "input-repeat", repeat );
00478                     }
00479 
00480                     /* Seek to start title/seekpoint */
00481                     val.i_int = p_input->input.i_title_start -
00482                         p_input->input.i_title_offset;
00483                     if( val.i_int < 0 || val.i_int >= p_input->input.i_title )
00484                         val.i_int = 0;
00485                     input_ControlPush( p_input,
00486                                        INPUT_CONTROL_SET_TITLE, &val );
00487 
00488                     val.i_int = p_input->input.i_seekpoint_start -
00489                         p_input->input.i_seekpoint_offset;
00490                     if( val.i_int > 0 /* TODO: check upper boundary */ )
00491                         input_ControlPush( p_input,
00492                                            INPUT_CONTROL_SET_SEEKPOINT, &val );
00493 
00494                     /* Seek to start position */
00495                     if( p_input->i_start > 0 )
00496                     {
00497                         val.i_time = p_input->i_start;
00498                         input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
00499                                            &val );
00500                     }
00501                     else
00502                     {
00503                         val.f_float = 0.0;
00504                         input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
00505                                            &val );
00506                     }
00507                 }
00508             }
00509             else if( i_ret < 0 )
00510             {
00511                 p_input->b_error = VLC_TRUE;
00512             }
00513 
00514             if( i_ret > 0 && p_input->i_slave > 0 )
00515             {
00516                 SlaveDemux( p_input );
00517             }
00518         }
00519         else
00520         {
00521             /* Small wait */
00522             msleep( 10*1000 );
00523         }
00524 
00525         /* Handle control */
00526         vlc_mutex_lock( &p_input->lock_control );
00527         ControlReduce( p_input );
00528         while( !ControlPopNoLock( p_input, &i_type, &val ) )
00529         {
00530             msg_Dbg( p_input, "control type=%d", i_type );
00531             if( Control( p_input, i_type, val ) )
00532                 b_force_update = VLC_TRUE;
00533         }
00534         vlc_mutex_unlock( &p_input->lock_control );
00535 
00536         if( b_force_update || i_intf_update < mdate() )
00537         {
00538             vlc_value_t val;
00539             double f_pos;
00540             int64_t i_time, i_length;
00541             /* update input status variables */
00542             if( !demux2_Control( p_input->input.p_demux,
00543                                  DEMUX_GET_POSITION, &f_pos ) )
00544             {
00545                 val.f_float = (float)f_pos;
00546                 var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
00547             }
00548             if( !demux2_Control( p_input->input.p_demux,
00549                                  DEMUX_GET_TIME, &i_time ) )
00550             {
00551                 p_input->i_time = i_time;
00552                 val.i_time = i_time;
00553                 var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
00554             }
00555             if( !demux2_Control( p_input->input.p_demux,
00556                                  DEMUX_GET_LENGTH, &i_length ) )
00557             {
00558                 vlc_value_t old_val;
00559                 var_Get( p_input, "length", &old_val );
00560                 val.i_time = i_length;
00561                 var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
00562 
00563                 if( old_val.i_time != val.i_time )
00564                 {
00565                     UpdateItemLength( p_input, i_length, VLC_TRUE );
00566                 }
00567             }
00568 
00569             var_SetBool( p_input, "intf-change", VLC_TRUE );
00570             i_intf_update = mdate() + I64C(150000);
00571         }
00572     }
00573 
00574     if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
00575     {
00576         /* We have finish to demux data but not to play them */
00577         while( !p_input->b_die )
00578         {
00579             if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
00580                 break;
00581 
00582             msg_Dbg( p_input, "waiting decoder fifos to empty" );
00583 
00584             msleep( INPUT_IDLE_SLEEP );
00585         }
00586 
00587         /* We have finished */
00588         p_input->b_eof = VLC_TRUE;
00589     }
00590 
00591     /* Wait we are asked to die */
00592     if( !p_input->b_die )
00593     {
00594         Error( p_input );
00595     }
00596 
00597     /* Clean up */
00598     End( p_input );
00599 
00600     return 0;
00601 }
00602 
00603 
00604 static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
00605 {
00606     char *psz;
00607     char *psz_subtitle;
00608     vlc_value_t val;
00609     double f_fps;
00610     vlc_meta_t *p_meta, *p_meta_tmp;
00611     int i_es_out_mode;
00612     int i, i_delay;
00613 
00614     /* Initialize optional stream output. (before access/demuxer)
00615      * XXX: we add a special case if the uri starts by vlc.
00616      * else 'vlc in.file --sout "" vlc:quit'  cannot work (the output will
00617      * be destroyed in case of a file).
00618      * (this will break playing of file starting by 'vlc:' but I don't
00619      * want to add more logic, just force file by file:// or code it ;)
00620      */
00621     if( !b_quick )
00622     {
00623         psz = var_GetString( p_input, "sout" );
00624         if( *psz && strncasecmp( p_input->input.p_item->psz_uri, "vlc:", 4 ) )
00625         {
00626             p_input->p_sout = sout_NewInstance( p_input, psz );
00627             if( p_input->p_sout == NULL )
00628             {
00629                 msg_Err( p_input, "cannot start stream output instance, " \
00630                                   "aborting" );
00631                 free( psz );
00632                 return VLC_EGENERIC;
00633             }
00634         }
00635         free( psz );
00636     }
00637 
00638     /* Create es out */
00639     p_input->p_es_out = input_EsOutNew( p_input );
00640     es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
00641     es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
00642 
00643     if( InputSourceInit( p_input, &p_input->input,
00644                          p_input->input.p_item->psz_uri, NULL, b_quick ) )
00645     {
00646         goto error;
00647     }
00648 
00649     /* Create global title (from master) */
00650     if( !b_quick )
00651     {
00652         p_input->i_title = p_input->input.i_title;
00653         p_input->title   = p_input->input.title;
00654         p_input->i_title_offset = p_input->input.i_title_offset;
00655         p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset;
00656         if( p_input->i_title > 0 )
00657         {
00658             /* Setup variables */
00659             input_ControlVarNavigation( p_input );
00660             input_ControlVarTitle( p_input, 0 );
00661         }
00662 
00663         /* Global flag */
00664         p_input->b_can_pace_control = p_input->input.b_can_pace_control;
00665         p_input->b_can_pause        = p_input->input.b_can_pause;
00666 
00667         /* Fix pts delay */
00668         if( p_input->i_pts_delay < 0 )
00669             p_input->i_pts_delay = 0;
00670 
00671         /* If the desynchronisation requested by the user is < 0, we need to
00672          * cache more data. */
00673         var_Get( p_input, "audio-desync", &val );
00674         if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);
00675 
00676         /* Update cr_average depending on the caching */
00677         p_input->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
00678         p_input->input.i_cr_average /= 10;
00679         if( p_input->input.i_cr_average < 10 ) p_input->input.i_cr_average = 10;
00680     }
00681 
00682     /* Load master infos */
00683     /* Init length */
00684     if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH,
00685                          &val.i_time ) && val.i_time > 0 )
00686     {
00687         var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
00688         UpdateItemLength( p_input, val.i_time, b_quick );
00689         p_input->input.p_item->i_duration = val.i_time;
00690     }
00691 
00692     /* Start title/chapter */
00693     if( !b_quick )
00694     {
00695         val.i_int = p_input->input.i_title_start -
00696                     p_input->input.i_title_offset;
00697         if( val.i_int > 0 && val.i_int < p_input->input.i_title )
00698             input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
00699         val.i_int = p_input->input.i_seekpoint_start -
00700                     p_input->input.i_seekpoint_offset;
00701         if( val.i_int > 0 /* TODO: check upper boundary */ )
00702             input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );
00703 
00704         /* Start time*/
00705         /* Set start time */
00706         p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
00707                            I64C(1000000);
00708         p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
00709                            I64C(1000000);
00710 
00711         if( p_input->i_start > 0 )
00712         {
00713             if( p_input->i_start >= val.i_time )
00714             {
00715                 msg_Warn( p_input, "invalid start-time ignored" );
00716             }
00717             else
00718             {
00719                 vlc_value_t s;
00720 
00721                 msg_Dbg( p_input, "starting at time: %ds",
00722                                   (int)( p_input->i_start / I64C(1000000) ) );
00723 
00724                 s.i_time = p_input->i_start;
00725                 input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
00726             }
00727         }
00728         if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
00729         {
00730             msg_Warn( p_input, "invalid stop-time ignored" );
00731             p_input->i_stop = 0;
00732         }
00733 
00734 
00735         /* Load subtitles */
00736         /* Get fps and set it if not already set */
00737         if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
00738             f_fps > 1.0 )
00739         {
00740             float f_requested_fps;
00741 
00742             var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
00743             var_SetFloat( p_input, "sub-original-fps", f_fps );
00744 
00745             f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
00746             if( f_requested_fps != f_fps )
00747             {
00748                 var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
00749                                                 VLC_VAR_DOINHERIT );
00750                 var_SetFloat( p_input, "sub-fps", f_requested_fps );
00751             }
00752         }
00753 
00754         i_delay = var_CreateGetInteger( p_input, "sub-delay" );
00755         if( i_delay != 0 )
00756         {
00757             var_SetTime( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
00758         }
00759 
00760 
00761         /* Look for and add subtitle files */
00762         psz_subtitle = var_GetString( p_input, "sub-file" );
00763         if( *psz_subtitle )
00764         {
00765             input_source_t *sub;
00766             vlc_value_t count;
00767             vlc_value_t list;
00768 
00769             msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
00770 
00771             var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );
00772 
00773             /* */
00774             sub = InputSourceNew( p_input );
00775             if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle",
00776                                   VLC_FALSE ) )
00777             {
00778                 TAB_APPEND( p_input->i_slave, p_input->slave, sub );
00779 
00780                 /* Select the ES */
00781                 if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list,
00782                                  NULL ) )
00783                 {
00784                     if( count.i_int == 0 )
00785                         count.i_int++;
00786                         /* if it was first one, there is disable too */
00787 
00788                     if( count.i_int < list.p_list->i_count )
00789                     {
00790                         input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
00791                                           &list.p_list->p_values[count.i_int] );
00792                     }
00793                     var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list,
00794                                 NULL );
00795                 }
00796             }
00797         }
00798 
00799         var_Get( p_input, "sub-autodetect-file", &val );
00800         if( val.b_bool )
00801         {
00802             char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
00803             char **subs = subtitles_Detect( p_input, psz_autopath,
00804                                             p_input->input.p_item->psz_uri );
00805             input_source_t *sub;
00806 
00807             for( i = 0; subs && subs[i]; i++ )
00808             {
00809                 if( strcmp( psz_subtitle, subs[i] ) )
00810                 {
00811                     sub = InputSourceNew( p_input );
00812                     if( !InputSourceInit( p_input, sub, subs[i], "subtitle",
00813                                           VLC_FALSE ) )
00814                     {
00815                          TAB_APPEND( p_input->i_slave, p_input->slave, sub );
00816                     }
00817                 }
00818                 free( subs[i] );
00819             }
00820             if( subs ) free( subs );
00821             if( psz_autopath ) free( psz_autopath );
00822         }
00823         free( psz_subtitle );
00824 
00825         /* Look for slave */
00826         psz = var_GetString( p_input, "input-slave" );
00827         if( *psz )
00828         {
00829             char *psz_delim;
00830             input_source_t *slave;
00831             while( psz && *psz )
00832             {
00833                 while( *psz == ' ' || *psz == '#' )
00834                 {
00835                     psz++;
00836                 }
00837                 if( ( psz_delim = strchr( psz, '#' ) ) )
00838                 {
00839                     *psz_delim++ = '\0';
00840                 }
00841                 if( *psz == 0 )
00842                 {
00843                     break;
00844                 }
00845 
00846                 msg_Dbg( p_input, "adding slave input '%s'", psz );
00847                 slave = InputSourceNew( p_input );
00848                 if( !InputSourceInit( p_input, slave, psz, NULL, VLC_FALSE ) )
00849                 {
00850                     TAB_APPEND( p_input->i_slave, p_input->slave, slave );
00851                 }
00852                 psz = psz_delim;
00853             }
00854         }
00855         if( psz ) free( psz );
00856     }
00857     else
00858     {
00859         p_input->i_start = 0;
00860         p_input->i_start = 0;
00861     }
00862 
00863     /* Set up es_out */
00864     if( !b_quick )
00865     {
00866         es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
00867         i_es_out_mode = ES_OUT_MODE_AUTO;
00868         val.p_list = NULL;
00869         if( p_input->p_sout )
00870         {
00871             var_Get( p_input, "sout-all", &val );
00872             if ( val.b_bool )
00873             {
00874                 i_es_out_mode = ES_OUT_MODE_ALL;
00875                 val.p_list = NULL;
00876             }
00877             else
00878             {
00879                 var_Get( p_input, "programs", &val );
00880                 if ( val.p_list && val.p_list->i_count )
00881                 {
00882                     i_es_out_mode = ES_OUT_MODE_PARTIAL;
00883                     /* Note : we should remove the "program" callback. */
00884                 }
00885                 else
00886                     var_Change( p_input, "programs", VLC_VAR_FREELIST, &val,
00887                                 NULL );
00888             }
00889         }
00890         es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
00891 
00892         /* Inform the demuxer about waited group (needed only for DVB) */
00893         if( i_es_out_mode == ES_OUT_MODE_ALL )
00894         {
00895             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1, NULL );
00896         }
00897         else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
00898         {
00899             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1,
00900                             val.p_list );
00901         }
00902         else
00903         {
00904             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP,
00905                            (int) var_GetInteger( p_input, "program" ), NULL );
00906         }
00907 
00908         if( p_input->p_sout )
00909         {
00910             if( p_input->p_sout->i_out_pace_nocontrol > 0 )
00911             {
00912                 p_input->b_out_pace_control = VLC_FALSE;
00913             }
00914             else
00915             {
00916                 p_input->b_out_pace_control = VLC_TRUE;
00917             }
00918 
00919             if( p_input->b_can_pace_control && p_input->b_out_pace_control )
00920             {
00921                 /* We don't want a high input priority here or we'll
00922                  * end-up sucking up all the CPU time */
00923                 vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
00924             }
00925 
00926             msg_Dbg( p_input, "starting in %s mode",
00927                      p_input->b_out_pace_control ? "asynch" : "synch" );
00928         }
00929     }
00930 
00931     /* Get meta data from users */
00932     p_meta_tmp = InputMetaUser( p_input );
00933 
00934     /* Get meta data from master input */
00935     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
00936         p_meta = NULL;
00937 
00938     /* Merge them */
00939     if( p_meta == NULL )
00940     {
00941         p_meta = p_meta_tmp;
00942     }
00943     else if( p_meta_tmp )
00944     {
00945         vlc_meta_Merge( p_meta, p_meta_tmp );
00946         vlc_meta_Delete( p_meta_tmp );
00947     }
00948 
00949     /* Access_file does not give any meta, and there are no slave */
00950     if( !b_quick )
00951     {
00952         if( !p_input->input.p_access ||
00953             access2_Control( p_input->input.p_access, ACCESS_GET_META,
00954                              &p_meta_tmp))
00955             p_meta_tmp = NULL;
00956 
00957         if( p_meta == NULL )
00958         {
00959             p_meta = p_meta_tmp;
00960         }
00961         else if( p_meta_tmp )
00962         {
00963             vlc_meta_Merge( p_meta, p_meta_tmp );
00964             vlc_meta_Delete( p_meta_tmp );
00965         }
00966 
00967         /* Get meta data from slave input */
00968         for( i = 0; i < p_input->i_slave; i++ )
00969         {
00970             vlc_meta_t *p_meta_slave;
00971 
00972             if( !demux2_Control( p_input->slave[i]->p_demux,
00973                                  DEMUX_GET_META, &p_meta_slave ) )
00974             {
00975                 if( p_meta == NULL )
00976                 {
00977                     p_meta = p_meta_slave;
00978                 }
00979                 else if( p_meta_slave )
00980                 {
00981                     vlc_meta_Merge( p_meta, p_meta_slave );
00982                     vlc_meta_Delete( p_meta_slave );
00983                 }
00984             }
00985 
00986             if( p_input->slave[i]->p_access &&
00987                 !access2_Control( p_input->slave[i]->p_access,
00988                                   ACCESS_GET_META, &p_meta_slave ) )
00989             {
00990                 if( p_meta == NULL )
00991                 {
00992                     p_meta = p_meta_slave;
00993                 }
00994                 else if( p_meta_slave )
00995                 {
00996                     vlc_meta_Merge( p_meta, p_meta_slave );
00997                     vlc_meta_Delete( p_meta_slave );
00998                 }
00999             }
01000         }
01001     }
01002 
01003     p_input->p_meta = p_meta;
01004     UpdateMeta( p_input, b_quick );
01005 
01006     if( !b_quick )
01007     {
01008         msg_Dbg( p_input, "`%s' successfully opened",
01009                  p_input->input.p_item->psz_uri );
01010 
01011     }
01012 
01013     /* Trigger intf update for this item */
01014     /* Playlist has a callback on this variable and will forward
01015      * it to intf */
01016     var_SetInteger( p_input, "item-change", p_input->input.p_item->i_id );
01017 
01018     /* initialization is complete */
01019     p_input->i_state = PLAYING_S;
01020 
01021     val.i_int = PLAYING_S;
01022     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01023 
01024     return VLC_SUCCESS;
01025 
01026 error:
01027     if( p_input->p_es_out )
01028         input_EsOutDelete( p_input->p_es_out );
01029 
01030     if( p_input->p_sout )
01031         sout_DeleteInstance( p_input->p_sout );
01032 
01033     /* Mark them deleted */
01034     p_input->input.p_demux = NULL;
01035     p_input->input.p_stream = NULL;
01036     p_input->input.p_access = NULL;
01037     p_input->p_es_out = NULL;
01038     p_input->p_sout = NULL;
01039 
01040     return VLC_EGENERIC;
01041 }
01042 
01043 /*****************************************************************************
01044  * Error: RunThread() error loop
01045  *****************************************************************************
01046  * This function is called when an error occurred during thread main's loop.
01047  *****************************************************************************/
01048 static void Error( input_thread_t *p_input )
01049 {
01050     while( !p_input->b_die )
01051     {
01052         /* Sleep a while */
01053         msleep( INPUT_IDLE_SLEEP );
01054     }
01055 }
01056 
01057 /*****************************************************************************
01058  * End: end the input thread
01059  *****************************************************************************/
01060 static void End( input_thread_t * p_input )
01061 {
01062     vlc_value_t val;
01063     int i;
01064 
01065     msg_Dbg( p_input, "closing input" );
01066 
01067     /* We are at the end */
01068     p_input->i_state = END_S;
01069 
01070     val.i_int = END_S;
01071     var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01072 
01073     /* Clean control variables */
01074     input_ControlVarClean( p_input );
01075 
01076     /* Clean up master */
01077     InputSourceClean( p_input, &p_input->input );
01078 
01079     /* Delete slave */
01080     for( i = 0; i < p_input->i_slave; i++ )
01081     {
01082         InputSourceClean( p_input, p_input->slave[i] );
01083         free( p_input->slave[i] );
01084     }
01085     if( p_input->slave ) free( p_input->slave );
01086 
01087     /* Unload all modules */
01088     if( p_input->p_es_out )
01089         input_EsOutDelete( p_input->p_es_out );
01090 
01091     /* Close optional stream output instance */
01092     if( p_input->p_sout )
01093     {
01094         vlc_object_t *p_pl =
01095             vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
01096         vlc_value_t keep;
01097 
01098         if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
01099         {
01100             /* attach sout to the playlist */
01101             msg_Dbg( p_input, "keeping sout" );
01102             vlc_object_detach( p_input->p_sout );
01103             vlc_object_attach( p_input->p_sout, p_pl );
01104         }
01105         else
01106         {
01107             msg_Dbg( p_input, "destroying sout" );
01108             sout_DeleteInstance( p_input->p_sout );
01109         }
01110         if( p_pl )
01111             vlc_object_release( p_pl );
01112     }
01113 
01114     /* Delete meta */
01115     if( p_input->p_meta )
01116         vlc_meta_Delete( p_input->p_meta );
01117 
01118     /* Tell we're dead */
01119     p_input->b_dead = VLC_TRUE;
01120 }
01121 
01122 /*****************************************************************************
01123  * Control
01124  *****************************************************************************/
01125 static inline int ControlPopNoLock( input_thread_t *p_input,
01126                                     int *pi_type, vlc_value_t *p_val )
01127 {
01128     if( p_input->i_control <= 0 )
01129     {
01130         return VLC_EGENERIC;
01131     }
01132 
01133     *pi_type = p_input->control[0].i_type;
01134     *p_val   = p_input->control[0].val;
01135 
01136     p_input->i_control--;
01137     if( p_input->i_control > 0 )
01138     {
01139         int i;
01140 
01141         for( i = 0; i < p_input->i_control; i++ )
01142         {
01143             p_input->control[i].i_type = p_input->control[i+1].i_type;
01144             p_input->control[i].val    = p_input->control[i+1].val;
01145         }
01146     }
01147 
01148     return VLC_SUCCESS;
01149 }
01150 
01151 static void ControlReduce( input_thread_t *p_input )
01152 {
01153     int i;
01154     for( i = 1; i < p_input->i_control; i++ )
01155     {
01156         const int i_lt = p_input->control[i-1].i_type;
01157         const int i_ct = p_input->control[i].i_type;
01158 
01159         /* XXX We can't merge INPUT_CONTROL_SET_ES */
01160 /*        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
01161                  i_lt, i_ct );
01162 */
01163         if( i_lt == i_ct &&
01164             ( i_ct == INPUT_CONTROL_SET_STATE ||
01165               i_ct == INPUT_CONTROL_SET_RATE ||
01166               i_ct == INPUT_CONTROL_SET_POSITION ||
01167               i_ct == INPUT_CONTROL_SET_TIME ||
01168               i_ct == INPUT_CONTROL_SET_PROGRAM ||
01169               i_ct == INPUT_CONTROL_SET_TITLE ||
01170               i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
01171               i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
01172         {
01173             int j;
01174 //            msg_Dbg( p_input, "merged at %d", i );
01175             /* Remove the i-1 */
01176             for( j = i; j <  p_input->i_control; j++ )
01177                 p_input->control[j-1] = p_input->control[j];
01178             p_input->i_control--;
01179         }
01180         else
01181         {
01182             /* TODO but that's not that important
01183                 - merge SET_X with SET_X_CMD
01184                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
01185                 - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
01186                 - ?
01187                 */
01188         }
01189     }
01190 }
01191 
01192 static vlc_bool_t Control( input_thread_t *p_input, int i_type,
01193                            vlc_value_t val )
01194 {
01195     vlc_bool_t b_force_update = VLC_FALSE;
01196 
01197     if( !p_input ) return b_force_update;
01198 
01199     switch( i_type )
01200     {
01201         case INPUT_CONTROL_SET_DIE:
01202             msg_Dbg( p_input, "control: stopping input" );
01203             /* Mark all submodules to die */
01204             if( p_input->input.p_access )
01205                 p_input->input.p_access->b_die = VLC_TRUE;
01206             if( p_input->input.p_stream )
01207                 p_input->input.p_stream->b_die = VLC_TRUE;
01208             p_input->input.p_demux->b_die = VLC_TRUE;
01209 
01210             p_input->b_die = VLC_TRUE;
01211             break;
01212 
01213         case INPUT_CONTROL_SET_POSITION:
01214         case INPUT_CONTROL_SET_POSITION_OFFSET:
01215         {
01216             double f_pos;
01217             if( i_type == INPUT_CONTROL_SET_POSITION )
01218             {
01219                 f_pos = val.f_float;
01220             }
01221             else
01222             {
01223                 /* Should not fail */
01224                 demux2_Control( p_input->input.p_demux,
01225                                 DEMUX_GET_POSITION, &f_pos );
01226                 f_pos += val.f_float;
01227             }
01228             if( f_pos < 0.0 ) f_pos = 0.0;
01229             if( f_pos > 1.0 ) f_pos = 1.0;
01230             /* Reset the decoders states and clock synch (before calling the demuxer */
01231             es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01232             input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01233             if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
01234                                 f_pos ) )
01235             {
01236                 msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
01237                          "%2.1f%% failed", f_pos * 100 );
01238             }
01239             else
01240             {
01241                 if( p_input->i_slave > 0 )
01242                     SlaveSeek( p_input );
01243 
01244                 b_force_update = VLC_TRUE;
01245             }
01246             break;
01247         }
01248 
01249         case INPUT_CONTROL_SET_TIME:
01250         case INPUT_CONTROL_SET_TIME_OFFSET:
01251         {
01252             int64_t i_time;
01253             int i_ret;
01254 
01255             if( i_type == INPUT_CONTROL_SET_TIME )
01256             {
01257                 i_time = val.i_time;
01258             }
01259             else
01260             {
01261                 /* Should not fail */
01262                 demux2_Control( p_input->input.p_demux,
01263                                 DEMUX_GET_TIME, &i_time );
01264                 i_time += val.i_time;
01265             }
01266             if( i_time < 0 ) i_time = 0;
01267 
01268             /* Reset the decoders states and clock synch (before calling the demuxer */
01269             es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01270             input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01271 
01272             i_ret = demux2_Control( p_input->input.p_demux,
01273                                     DEMUX_SET_TIME, i_time );
01274             if( i_ret )
01275             {
01276                 int64_t i_length;
01277 
01278                 /* Emulate it with a SET_POS */
01279                 demux2_Control( p_input->input.p_demux,
01280                                 DEMUX_GET_LENGTH, &i_length );
01281                 if( i_length > 0 )
01282                 {
01283                     double f_pos = (double)i_time / (double)i_length;
01284                     i_ret = demux2_Control( p_input->input.p_demux,
01285                                             DEMUX_SET_POSITION, f_pos );
01286                 }
01287             }
01288             if( i_ret )
01289             {
01290                 msg_Warn( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) "I64Fd
01291                          " failed or not possible", i_time );
01292             }
01293             else
01294             {
01295                 if( p_input->i_slave > 0 )
01296                     SlaveSeek( p_input );
01297 
01298                 b_force_update = VLC_TRUE;
01299             }
01300             break;
01301         }
01302 
01303         case INPUT_CONTROL_SET_STATE:
01304             if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
01305                 ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
01306             {
01307                 int i_ret;
01308                 if( p_input->input.p_access )
01309                     i_ret = access2_Control( p_input->input.p_access,
01310                                              ACCESS_SET_PAUSE_STATE, VLC_FALSE );
01311                 else
01312                     i_ret = demux2_Control( p_input->input.p_demux,
01313                                             DEMUX_SET_PAUSE_STATE, VLC_FALSE );
01314 
01315                 if( i_ret )
01316                 {
01317                     /* FIXME What to do ? */
01318                     msg_Warn( p_input, "cannot unset pause -> EOF" );
01319                     vlc_mutex_unlock( &p_input->lock_control );
01320                     input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
01321                     vlc_mutex_lock( &p_input->lock_control );
01322                 }
01323 
01324                 b_force_update = VLC_TRUE;
01325 
01326                 /* Switch to play */
01327                 p_input->i_state = PLAYING_S;
01328                 val.i_int = PLAYING_S;
01329                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01330 
01331                 /* Reset clock */
01332                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01333                 input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01334             }
01335             else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S &&
01336                      p_input->b_can_pause )
01337             {
01338                 int i_ret;
01339                 if( p_input->input.p_access )
01340                     i_ret = access2_Control( p_input->input.p_access,
01341                                              ACCESS_SET_PAUSE_STATE, VLC_TRUE );
01342                 else
01343                     i_ret = demux2_Control( p_input->input.p_demux,
01344                                             DEMUX_SET_PAUSE_STATE, VLC_TRUE );
01345 
01346                 b_force_update = VLC_TRUE;
01347 
01348                 if( i_ret )
01349                 {
01350                     msg_Warn( p_input, "cannot set pause state" );
01351                     val.i_int = p_input->i_state;
01352                 }
01353                 else
01354                 {
01355                     val.i_int = PAUSE_S;
01356                 }
01357 
01358                 /* Switch to new state */
01359                 p_input->i_state = val.i_int;
01360                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01361             }
01362             else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
01363             {
01364                 b_force_update = VLC_TRUE;
01365 
01366                 /* Correct "state" value */
01367                 val.i_int = p_input->i_state;
01368                 var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
01369             }
01370             else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
01371             {
01372                 msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
01373             }
01374             break;
01375 
01376         case INPUT_CONTROL_SET_RATE:
01377         case INPUT_CONTROL_SET_RATE_SLOWER:
01378         case INPUT_CONTROL_SET_RATE_FASTER:
01379         {
01380             int i_rate;
01381 
01382             if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
01383                 i_rate = p_input->i_rate * 2;
01384             else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
01385                 i_rate = p_input->i_rate / 2;
01386             else
01387                 i_rate = val.i_int;
01388 
01389             if( i_rate < INPUT_RATE_MIN )
01390             {
01391                 msg_Dbg( p_input, "cannot set rate faster" );
01392                 i_rate = INPUT_RATE_MIN;
01393             }
01394             else if( i_rate > INPUT_RATE_MAX )
01395             {
01396                 msg_Dbg( p_input, "cannot set rate slower" );
01397                 i_rate = INPUT_RATE_MAX;
01398             }
01399             if( i_rate != INPUT_RATE_DEFAULT &&
01400                 ( !p_input->b_can_pace_control ||
01401                   ( p_input->p_sout && !p_input->b_out_pace_control ) ) )
01402             {
01403                 msg_Dbg( p_input, "cannot change rate" );
01404                 i_rate = INPUT_RATE_DEFAULT;
01405             }
01406             if( i_rate != p_input->i_rate )
01407             {
01408                 p_input->i_rate  = i_rate;
01409                 val.i_int = i_rate;
01410                 var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
01411 
01412                 /* We haven't send data to decoder when rate != default */
01413                 if( i_rate == INPUT_RATE_DEFAULT )
01414                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
01415 
01416                 /* Reset clock */
01417                 es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01418 
01419                 b_force_update = VLC_TRUE;
01420             }
01421             break;
01422         }
01423 
01424         case INPUT_CONTROL_SET_PROGRAM:
01425             /* No need to force update, es_out does it if needed */
01426             es_out_Control( p_input->p_es_out,
01427                             ES_OUT_SET_GROUP, val.i_int );
01428 
01429             demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, val.i_int,
01430                             NULL );
01431             break;
01432 
01433         case INPUT_CONTROL_SET_ES:
01434             /* No need to force update, es_out does it if needed */
01435             es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
01436                             input_EsOutGetFromID( p_input->p_es_out,
01437                                                   val.i_int ) );
01438             break;
01439 
01440         case INPUT_CONTROL_SET_AUDIO_DELAY:
01441             input_EsOutSetDelay( p_input->p_es_out,
01442                                  AUDIO_ES, val.i_time );
01443             var_Change( p_input, "audio-delay", VLC_VAR_SETVALUE, &val, NULL );
01444             break;
01445 
01446         case INPUT_CONTROL_SET_SPU_DELAY:
01447             input_EsOutSetDelay( p_input->p_es_out,
01448                                  SPU_ES, val.i_time );
01449             var_Change( p_input, "spu-delay", VLC_VAR_SETVALUE, &val, NULL );
01450             break;
01451 
01452         case INPUT_CONTROL_SET_TITLE:
01453         case INPUT_CONTROL_SET_TITLE_NEXT:
01454         case INPUT_CONTROL_SET_TITLE_PREV:
01455             if( p_input->input.b_title_demux &&
01456                 p_input->input.i_title > 0 )
01457             {
01458                 /* TODO */
01459                 /* FIXME handle demux title */
01460                 demux_t *p_demux = p_input->input.p_demux;
01461                 int i_title;
01462 
01463                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
01464                     i_title = p_demux->info.i_title - 1;
01465                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
01466                     i_title = p_demux->info.i_title + 1;
01467                 else
01468                     i_title = val.i_int;
01469 
01470                 if( i_title >= 0 && i_title < p_input->input.i_title )
01471                 {
01472                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01473                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01474 
01475                     demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
01476                     input_ControlVarTitle( p_input, i_title );
01477                 }
01478             }
01479             else if( p_input->input.i_title > 0 )
01480             {
01481                 access_t *p_access = p_input->input.p_access;
01482                 int i_title;
01483 
01484                 if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
01485                     i_title = p_access->info.i_title - 1;
01486                 else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
01487                     i_title = p_access->info.i_title + 1;
01488                 else
01489                     i_title = val.i_int;
01490 
01491                 if( i_title >= 0 && i_title < p_input->input.i_title )
01492                 {
01493                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01494                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01495                     
01496                     access2_Control( p_access, ACCESS_SET_TITLE, i_title );
01497                     stream_AccessReset( p_input->input.p_stream );
01498                 }
01499             }
01500             break;
01501         case INPUT_CONTROL_SET_SEEKPOINT:
01502         case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
01503         case INPUT_CONTROL_SET_SEEKPOINT_PREV:
01504             if( p_input->input.b_title_demux &&
01505                 p_input->input.i_title > 0 )
01506             {
01507                 demux_t *p_demux = p_input->input.p_demux;
01508                 int i_seekpoint;
01509                 int64_t i_input_time;
01510                 int64_t i_seekpoint_time;
01511 
01512                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
01513                 {
01514                     i_seekpoint = p_demux->info.i_seekpoint;
01515                     i_seekpoint_time = p_input->input.title[p_demux->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
01516                     if( i_seekpoint_time >= 0 &&
01517                          !demux2_Control( p_demux,
01518                                           DEMUX_GET_TIME, &i_input_time ) )
01519                     {
01520                         if ( i_input_time < i_seekpoint_time + 3000000 )
01521                             i_seekpoint--;
01522                     }
01523                     else
01524                         i_seekpoint--;
01525                 }
01526                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT )
01527                     i_seekpoint = p_demux->info.i_seekpoint + 1;
01528                 else
01529                     i_seekpoint = val.i_int;
01530 
01531                 if( i_seekpoint >= 0 && i_seekpoint <
01532                     p_input->input.title[p_demux->info.i_title]->i_seekpoint )
01533                 {
01534                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01535                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01536                     
01537                     demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
01538                 }
01539             }
01540             else if( p_input->input.i_title > 0 )
01541             {
01542                 demux_t *p_demux = p_input->input.p_demux;
01543                 access_t *p_access = p_input->input.p_access;
01544                 int i_seekpoint;
01545                 int64_t i_input_time;
01546                 int64_t i_seekpoint_time;
01547 
01548                 if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
01549                 {
01550                     i_seekpoint = p_access->info.i_seekpoint;
01551                     i_seekpoint_time = p_input->input.title[p_access->info.i_title]->seekpoint[i_seekpoint]->i_time_offset;
01552                     if( i_seekpoint_time >= 0 &&
01553                         demux2_Control( p_demux,
01554                                         DEMUX_GET_TIME, &i_input_time ) )
01555                     {
01556                         if ( i_input_time < i_seekpoint_time + 3000000 )
01557                             i_seekpoint--;
01558                     }
01559                     else
01560                         i_seekpoint--;
01561                 }
01562                 else if( i_type == INPUT_CONTROL_SET_SEEKPOINT_NEXT ) 
01563                     i_seekpoint = p_access->info.i_seekpoint + 1;
01564                 else
01565                     i_seekpoint = val.i_int;
01566 
01567                 if( i_seekpoint >= 0 && i_seekpoint <
01568                     p_input->input.title[p_access->info.i_title]->i_seekpoint )
01569                 {
01570                     input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
01571                     es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
01572                     
01573                     access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
01574                     stream_AccessReset( p_input->input.p_stream );
01575                 }
01576             }
01577             break;
01578 
01579         case INPUT_CONTROL_ADD_SLAVE:
01580             if( val.psz_string )
01581             {
01582                 input_source_t *slave = InputSourceNew( p_input );
01583 
01584                 if( !InputSourceInit( p_input, slave, val.psz_string, NULL,
01585                                       VLC_FALSE ) )
01586                 {
01587                     vlc_meta_t *p_meta_new = NULL;
01588                     vlc_meta_t *p_meta;
01589                     int64_t i_time;
01590 
01591                     /* Add the slave */
01592                     msg_Dbg( p_input, "adding %s as slave on the fly",
01593                              val.psz_string );
01594 
01595                     /* Set position */
01596                     if( demux2_Control( p_input->input.p_demux,
01597                                         DEMUX_GET_TIME, &i_time ) )
01598                     {
01599                         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
01600                         InputSourceClean( p_input, slave );
01601                         free( slave );
01602                         break;
01603                     }
01604                     if( demux2_Control( slave->p_demux,
01605                                         DEMUX_SET_TIME, i_time ) )
01606                     {
01607                         msg_Err( p_input, "seek failed for new slave" );
01608                         InputSourceClean( p_input, slave );
01609                         free( slave );
01610                         break;
01611                     }
01612 
01613 
01614                     /* Get meta (access and demux) */
01615                     if( access2_Control( slave->p_access,
01616                                           ACCESS_GET_META, &p_meta_new ) )
01617                         p_meta_new = NULL;
01618                     if( !demux2_Control( slave->p_demux,
01619                                          DEMUX_GET_META, &p_meta ) )
01620                     {
01621                         if( p_meta_new )
01622                         {
01623                             vlc_meta_Merge( p_meta_new, p_meta );
01624                             vlc_meta_Delete( p_meta );
01625                         }
01626                         else
01627                         {
01628                             p_meta_new = p_meta;
01629                         }
01630                     }
01631                     /* Update meta */
01632                     if( p_meta_new )
01633                     {
01634                         if( p_input->p_meta )
01635                         {
01636                             vlc_meta_Merge( p_input->p_meta, p_meta_new );
01637                             vlc_meta_Delete( p_meta_new );
01638                         }
01639                         else
01640                         {
01641                             p_input->p_meta = p_meta_new;
01642                         }
01643                         UpdateMeta( p_input, VLC_FALSE );
01644                     }
01645 
01646                     TAB_APPEND( p_input->i_slave, p_input->slave, slave );
01647                 }
01648                 else
01649                 {
01650                     msg_Warn( p_input, "failed to add %s as slave",
01651                               val.psz_string );
01652                 }
01653 
01654                 free( val.psz_string );
01655             }
01656             break;
01657 
01658         case INPUT_CONTROL_SET_BOOKMARK:
01659         default:
01660             msg_Err( p_input, "not yet implemented" );
01661             break;
01662     }
01663 
01664     return b_force_update;
01665 }
01666 
01667 /*****************************************************************************
01668  * UpdateFromDemux:
01669  *****************************************************************************/
01670 static int UpdateFromDemux( input_thread_t *p_input )
01671 {
01672     demux_t *p_demux = p_input->input.p_demux;
01673     vlc_value_t v;
01674 
01675     if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
01676     {
01677         v.i_int = p_demux->info.i_title;
01678         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
01679 
01680         input_ControlVarTitle( p_input, p_demux->info.i_title );
01681 
01682         p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
01683     }
01684     if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
01685     {
01686         v.i_int = p_demux->info.i_seekpoint;
01687         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
01688 
01689         p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
01690     }
01691     p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
01692 
01693     /* Hmmm only works with master input */
01694     if( p_input->input.p_demux == p_demux )
01695     {
01696         int i_title_end = p_input->input.i_title_end -
01697             p_input->input.i_title_offset;
01698         int i_seekpoint_end = p_input->input.i_seekpoint_end -
01699             p_input->input.i_seekpoint_offset;
01700 
01701         if( i_title_end >= 0 && i_seekpoint_end >= 0 )
01702         {
01703             if( p_demux->info.i_title > i_title_end ||
01704                 ( p_demux->info.i_title == i_title_end &&
01705                   p_demux->info.i_seekpoint > i_seekpoint_end ) ) return 0;
01706         }
01707         else if( i_seekpoint_end >=0 )
01708         {
01709             if( p_demux->info.i_seekpoint > i_seekpoint_end ) return 0;
01710         }
01711         else if( i_title_end >= 0 )
01712         {
01713             if( p_demux->info.i_title > i_title_end ) return 0;
01714         }
01715     }
01716 
01717     return 1;
01718 }
01719 
01720 /*****************************************************************************
01721  * UpdateFromAccess:
01722  *****************************************************************************/
01723 static int UpdateFromAccess( input_thread_t *p_input )
01724 {
01725     access_t *p_access = p_input->input.p_access;
01726     vlc_value_t v;
01727 
01728     if( p_access->info.i_update & INPUT_UPDATE_TITLE )
01729     {
01730         v.i_int = p_access->info.i_title;
01731         var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
01732 
01733         input_ControlVarTitle( p_input, p_access->info.i_title );
01734 
01735         stream_AccessUpdate( p_input->input.p_stream );
01736 
01737         p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
01738     }
01739     if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
01740     {
01741         v.i_int = p_access->info.i_seekpoint;
01742         var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
01743 
01744         p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
01745     }
01746     if( p_access->info.i_update & INPUT_UPDATE_META )
01747     {
01748         /* TODO maybe multi - access ? */
01749         vlc_meta_t *p_meta;
01750         if( !access2_Control( p_input->input.p_access,ACCESS_GET_META,&p_meta))
01751         {
01752             if( p_input->p_meta )
01753             {
01754                 vlc_meta_Merge( p_input->p_meta, p_meta );
01755                 vlc_meta_Delete( p_meta );
01756             }
01757             else
01758             {
01759                 p_input->p_meta = p_meta;
01760             }
01761 
01762             UpdateMeta( p_input, VLC_FALSE );
01763             var_SetBool( p_input, "item-change", p_input->input.p_item->i_id );
01764         }
01765         p_access->info.i_update &= ~INPUT_UPDATE_META;
01766     }
01767 
01768     p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
01769 
01770     /* Hmmm only works with master input */
01771     if( p_input->input.p_access == p_access )
01772     {
01773         int i_title_end = p_input->input.i_title_end -
01774             p_input->input.i_title_offset;
01775         int i_seekpoint_end = p_input->input.i_seekpoint_end -
01776             p_input->input.i_seekpoint_offset;
01777 
01778         if( i_title_end >= 0 && i_seekpoint_end >=0 )
01779         {
01780             if( p_access->info.i_title > i_title_end ||
01781                 ( p_access->info.i_title == i_title_end &&
01782                   p_access->info.i_seekpoint > i_seekpoint_end ) ) return 0;
01783         }
01784         else if( i_seekpoint_end >=0 )
01785         {
01786             if( p_access->info.i_seekpoint > i_seekpoint_end ) return 0;
01787         }
01788         else if( i_title_end >= 0 )
01789         {
01790             if( p_access->info.i_title > i_title_end ) return 0;
01791         }
01792     }
01793 
01794     return 1;
01795 }
01796 
01797 /*****************************************************************************
01798  * UpdateMeta:
01799  *****************************************************************************/
01800 static int  UpdateMeta( input_thread_t *p_input, vlc_bool_t b_quick )
01801 {
01802     vlc_meta_t *p_meta = p_input->p_meta;
01803     int i;
01804 
01805     if( !p_meta || p_meta->i_meta == 0 )
01806         return VLC_SUCCESS;
01807 
01808     if( !b_quick ) msg_Dbg( p_input, "meta information:" );
01809     for( i = 0; i < p_meta->i_meta; i++ )
01810     {
01811         if( !b_quick )
01812             msg_Dbg( p_input, "  - '%s' = '%s'",
01813                      _(p_meta->name[i]), p_meta->value[i] );
01814 
01815         if( !strcmp(p_meta->name[i], VLC_META_TITLE) && p_meta->value[i] &&
01816             !p_input->input.p_item->b_fixed_name )
01817             input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );
01818 
01819         if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
01820             input_Control( p_input, INPUT_ADD_INFO, _("General"),
01821                            _("Author"), p_meta->value[i] );
01822 
01823         input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
01824                       _(p_meta->name[i]), "%s", p_meta->value[i] );
01825     }
01826 
01827     for( i = 0; i < p_meta->i_track; i++ )
01828     {
01829         vlc_meta_t *tk = p_meta->track[i];
01830         int j;
01831 
01832         if( tk->i_meta > 0 )
01833         {
01834             char *psz_cat = malloc( strlen(_("Stream")) + 10 );
01835 
01836             msg_Dbg( p_input, "  - track[%d]:", i );
01837 
01838             sprintf( psz_cat, "%s %d", _("Stream"), i );
01839             for( j = 0; j < tk->i_meta; j++ )
01840             {
01841                 msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
01842                          tk->value[j] );
01843 
01844                 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01845                                _(tk->name[j]), "%s", tk->value[j] );
01846             }
01847         }
01848     }
01849 
01850     if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
01851     {
01852         p_input->p_sout->p_meta = vlc_meta_Duplicate( p_meta );
01853     }
01854 
01855     return VLC_SUCCESS;
01856 }
01857 
01858 /*****************************************************************************
01859  * UpdateItemLength:
01860  *****************************************************************************/
01861 static void UpdateItemLength( input_thread_t *p_input, int64_t i_length,
01862                               vlc_bool_t b_quick )
01863 {
01864     playlist_t *p_playlist;
01865     char psz_buffer[MSTRTIME_MAX_SIZE];
01866 
01867     vlc_mutex_lock( &p_input->input.p_item->lock );
01868     p_input->input.p_item->i_duration = i_length;
01869     vlc_mutex_unlock( &p_input->input.p_item->lock );
01870 
01871         p_playlist = vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
01872                                                FIND_PARENT);
01873     if( p_playlist )
01874     {
01875         var_SetInteger( p_playlist, "item-change",
01876                         p_input->input.p_item->i_id );
01877         vlc_object_release( p_playlist );
01878     }
01879 
01880     input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
01881                    msecstotimestr( psz_buffer, i_length / 1000 ) );
01882 }
01883 
01884 /*****************************************************************************
01885  * InputSourceNew:
01886  *****************************************************************************/
01887 static input_source_t *InputSourceNew( input_thread_t *p_input )
01888 {
01889     input_source_t *in = (input_source_t*) malloc( sizeof( input_source_t ) );
01890    
01891     if( !in )
01892     {
01893         msg_Err( p_input, "out of memory for new input source" );
01894         return NULL;
01895     }
01896 
01897     in->p_item   = NULL;
01898     in->p_access = NULL;
01899     in->p_stream = NULL;
01900     in->p_demux  = NULL;
01901     in->b_title_demux = VLC_FALSE;
01902     in->i_title  = 0;
01903     in->title    = NULL;
01904     in->b_can_pace_control = VLC_TRUE;
01905     in->b_eof = VLC_FALSE;
01906     in->i_cr_average = 0;
01907 
01908     return in;
01909 }
01910 
01911 /*****************************************************************************
01912  * InputSourceInit:
01913  *****************************************************************************/
01914 static int InputSourceInit( input_thread_t *p_input,
01915                             input_source_t *in, char *psz_mrl,
01916                             char *psz_forced_demux, vlc_bool_t b_quick )
01917 {
01918     char *psz_dup = strdup( psz_mrl );
01919     char *psz_access;
01920     char *psz_demux;
01921     char *psz_path;
01922     char *psz_tmp;
01923     char *psz;
01924     vlc_value_t val;
01925 
01926     if( !in ) return VLC_EGENERIC;
01927 
01928     /* Split uri */
01929     if( !b_quick )
01930     {
01931         MRLSplit( VLC_OBJECT(p_input), psz_dup,
01932                   &psz_access, &psz_demux, &psz_path );
01933 
01934         msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
01935                  psz_mrl, psz_access, psz_demux, psz_path );
01936 
01937         /* Hack to allow udp://@:port syntax */
01938         if( !psz_access ||
01939             (strncmp( psz_access, "udp", 3 ) &&
01940              strncmp( psz_access, "rtp", 3 )) )
01941 
01942         /* Find optional titles and seekpoints */
01943         MRLSections( p_input, psz_path, &in->i_title_start, &in->i_title_end,
01944                      &in->i_seekpoint_start, &in->i_seekpoint_end );
01945 
01946         if( psz_forced_demux && *psz_forced_demux )
01947         {
01948             psz_demux = psz_forced_demux;
01949         }
01950         else if( !psz_demux || *psz_demux == '\0' )
01951         {
01952             /* special hack for forcing a demuxer with --demux=module
01953              * (and do nothing with a list) */
01954             char *psz_var_demux = var_GetString( p_input, "demux" );
01955 
01956             if( *psz_var_demux != '\0' &&
01957                 !strchr(psz_var_demux, ',' ) &&
01958                 !strchr(psz_var_demux, ':' ) )
01959             {
01960                 psz_demux = psz_var_demux;
01961 
01962                 msg_Dbg( p_input, "Enforce demux ` %s'", psz_demux );
01963             }
01964             else if( psz_var_demux )
01965             {
01966                 free( psz_var_demux );
01967             }
01968         }
01969 
01970         /* Try access_demux if no demux given */
01971         if( *psz_demux == '\0' )
01972         {
01973             in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
01974                                       NULL, p_input->p_es_out, VLC_FALSE );
01975         }
01976     }
01977     else
01978     {
01979         psz_path = psz_mrl;
01980         msg_Dbg( p_input, "trying to preparse %s",  psz_path );
01981         psz_demux = strdup( "" );
01982         psz_access = strdup( "file" );
01983     }
01984 
01985     if( in->p_demux )
01986     {
01987         int64_t i_pts_delay;
01988 
01989         /* Get infos from access_demux */
01990         demux2_Control( in->p_demux,
01991                         DEMUX_GET_PTS_DELAY, &i_pts_delay );
01992         p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
01993 
01994         in->b_title_demux = VLC_TRUE;
01995         if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
01996                             &in->title, &in->i_title,
01997                             &in->i_title_offset, &in->i_seekpoint_offset ) )
01998         {
01999             in->i_title = 0;
02000             in->title   = NULL;
02001         }
02002         demux2_Control( in->p_demux, DEMUX_CAN_CONTROL_PACE,
02003                         &in->b_can_pace_control );
02004         demux2_Control( in->p_demux, DEMUX_CAN_PAUSE,
02005                         &in->b_can_pause );
02006 
02007         /* FIXME todo
02008         demux2_Control( in->p_demux, DEMUX_CAN_SEEK,
02009                         &val.b_bool );
02010         */
02011     }
02012     else
02013     {
02014         int64_t i_pts_delay;
02015 
02016         /* Now try a real access */
02017         in->p_access = access2_New( p_input, psz_access, psz_demux, psz_path,
02018                                     b_quick );
02019 
02020         /* Access failed, URL encoded ? */
02021         if( in->p_access == NULL && strchr( psz_path, '%' ) )
02022         {
02023             DecodeUrl( psz_path );
02024 
02025             msg_Dbg( p_input, "retrying with access `%s' demux `%s' path `%s'",
02026                      psz_access, psz_demux, psz_path );
02027 
02028             in->p_access = access2_New( p_input,
02029                                         psz_access, psz_demux, psz_path,
02030                                         b_quick );
02031         }
02032 #ifndef WIN32      /* Remove this gross hack from the win32 build as colons
02033                         * are forbidden in filenames on Win32. */
02034 
02035         /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
02036         if( in->p_access == NULL &&
02037             *psz_access == '\0' && ( *psz_demux || *psz_path ) )
02038         {
02039             if( psz_dup ) free( psz_dup );
02040             psz_dup = strdup( psz_mrl );
02041             psz_access = "";
02042             psz_demux = "";
02043             psz_path = psz_dup;
02044 
02045             in->p_access = access2_New( p_input,
02046                                         psz_access, psz_demux, psz_path,
02047                                         b_quick );
02048         }
02049 #endif
02050 
02051         if( in->p_access == NULL )
02052         {
02053             msg_Err( p_input, "no suitable access module for `%s'", psz_mrl );
02054             goto error;
02055         }
02056 
02057         /* */
02058         psz_tmp = psz = var_GetString( p_input, "access-filter" );
02059         while( psz && *psz )
02060         {
02061             access_t *p_access = in->p_access;
02062             char *end = strchr( psz, ':' );
02063 
02064             if( end )
02065                 *end++ = '\0';
02066 
02067             in->p_access = access2_FilterNew( in->p_access, psz );
02068             if( in->p_access == NULL )
02069             {
02070                 in->p_access = p_access;
02071                 msg_Warn( p_input, "failed to insert access filter %s",
02072                           psz );
02073             }
02074 
02075             psz = end;
02076         }
02077         if( psz_tmp ) free( psz_tmp );
02078 
02079         /* Get infos from access */
02080         if( !b_quick )
02081         {
02082             access2_Control( in->p_access,
02083                              ACCESS_GET_PTS_DELAY, &i_pts_delay );
02084             p_input->i_pts_delay = __MAX( p_input->i_pts_delay, i_pts_delay );
02085 
02086             in->b_title_demux = VLC_FALSE;
02087             if( access2_Control( in->p_access, ACCESS_GET_TITLE_INFO,
02088                                  &in->title, &in->i_title,
02089                                 &in->i_title_offset, &in->i_seekpoint_offset ) )
02090 
02091             {
02092                 in->i_title = 0;
02093                 in->title   = NULL;
02094             }
02095             access2_Control( in->p_access, ACCESS_CAN_CONTROL_PACE,
02096                              &in->b_can_pace_control );
02097             access2_Control( in->p_access, ACCESS_CAN_PAUSE,
02098                              &in->b_can_pause );
02099             access2_Control( in->p_access, ACCESS_CAN_SEEK,
02100                              &val.b_bool );
02101             var_Set( p_input, "seekable", val );
02102         }
02103 
02104         /* Create the stream_t */
02105         in->p_stream = stream_AccessNew( in->p_access, b_quick );
02106         if( in->p_stream == NULL )
02107         {
02108             msg_Warn( p_input, "cannot create a stream_t from access" );
02109             goto error;
02110         }
02111 
02112         /* Open a demuxer */
02113         if( *psz_demux == '\0' && *in->p_access->psz_demux )
02114         {
02115             psz_demux = in->p_access->psz_demux;
02116         }
02117         in->p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
02118                                   in->p_stream, p_input->p_es_out, b_quick );
02119         if( in->p_demux == NULL )
02120         {
02121             msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
02122                      psz_access, psz_demux, psz_path );
02123             goto error;
02124         }
02125 
02126         /* TODO get title from demux */
02127         if( !b_quick && in->i_title <= 0 )
02128         {
02129             if( demux2_Control( in->p_demux, DEMUX_GET_TITLE_INFO,
02130                                 &in->title, &in->i_title,
02131                                 &in->i_title_offset, &in->i_seekpoint_offset ))
02132             {
02133                 in->i_title = 0;
02134                 in->title   = NULL;
02135             }
02136             else
02137             {
02138                 in->b_title_demux = VLC_TRUE;
02139             }
02140         }
02141     }
02142 
02143     if( var_GetInteger( p_input, "clock-synchro" ) != -1 )
02144         in->b_can_pace_control = !var_GetInteger( p_input, "clock-synchro" );
02145 
02146     if( psz_dup ) free( psz_dup );
02147     return VLC_SUCCESS;
02148 
02149 error:
02150     if( in->p_demux )
02151         demux2_Delete( in->p_demux );
02152 
02153     if( in->p_stream )
02154         stream_Delete( in->p_stream );
02155 
02156     if( in->p_access )
02157         access2_Delete( in->p_access );
02158     if( psz_dup ) free( psz_dup );
02159 
02160     return VLC_EGENERIC;
02161 }
02162 
02163 /*****************************************************************************
02164  * InputSourceClean:
02165  *****************************************************************************/
02166 static void InputSourceClean( input_thread_t *p_input, input_source_t *in )
02167 {
02168     if( in->p_demux )
02169         demux2_Delete( in->p_demux );
02170 
02171     if( in->p_stream )
02172         stream_Delete( in->p_stream );
02173 
02174     if( in->p_access )
02175         access2_Delete( in->p_access );
02176 
02177     if( in->i_title > 0 )
02178     {
02179         int i;
02180         for( i = 0; i < in->i_title; i++ )
02181         {
02182             vlc_input_title_Delete( in->title[i] );
02183         }
02184         free( in->title );
02185     }
02186 }
02187 
02188 static void SlaveDemux( input_thread_t *p_input )
02189 {
02190     int64_t i_time;
02191     int i;
02192     
02193     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
02194     {
02195         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
02196         return;
02197     }
02198 
02199     for( i = 0; i < p_input->i_slave; i++ )
02200     {
02201         input_source_t *in = p_input->slave[i];
02202         int i_ret = 1;
02203 
02204         if( in->b_eof )
02205             continue;
02206 
02207         if( demux2_Control( in->p_demux, DEMUX_SET_NEXT_DEMUX_TIME, i_time ) )
02208         {
02209             for( ;; )
02210             {
02211                 int64_t i_stime;
02212                 if( demux2_Control( in->p_demux, DEMUX_GET_TIME, &i_stime ) )
02213                 {
02214                     msg_Err( p_input, "slave[%d] doesn't like "
02215                              "DEMUX_GET_TIME -> EOF", i );
02216                     i_ret = 0;
02217                     break;
02218                 }
02219 
02220                 if( i_stime >= i_time )
02221                     break;
02222 
02223                 if( ( i_ret = in->p_demux->pf_demux( in->p_demux ) ) <= 0 )
02224                     break;
02225             }
02226         }
02227         else
02228         {
02229             i_ret = in->p_demux->pf_demux( in->p_demux );
02230         }
02231 
02232         if( i_ret <= 0 )
02233         {
02234             msg_Dbg( p_input, "slave %d EOF", i );
02235             in->b_eof = VLC_TRUE;
02236         }
02237     }
02238 }
02239 
02240 static void SlaveSeek( input_thread_t *p_input )
02241 {
02242     int64_t i_time;
02243     int i;
02244 
02245     if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
02246     {
02247         msg_Err( p_input, "demux doesn't like DEMUX_GET_TIME" );
02248         return;
02249     }
02250 
02251     for( i = 0; i < p_input->i_slave; i++ )
02252     {
02253         input_source_t *in = p_input->slave[i];
02254 
02255         if( demux2_Control( in->p_demux, DEMUX_SET_TIME, i_time ) )
02256         {
02257             msg_Err( p_input, "seek failed for slave %d -> EOF", i );
02258             in->b_eof = VLC_TRUE;
02259         }
02260     }
02261 }
02262 /*****************************************************************************
02263  * InputMetaUser:
02264  *****************************************************************************/
02265 static vlc_meta_t *InputMetaUser( input_thread_t *p_input )
02266 {
02267     vlc_meta_t *p_meta;
02268     vlc_value_t val;
02269 
02270     if( ( p_meta = vlc_meta_New() ) == NULL )
02271         return NULL;
02272 
02273     /* Get meta information from user */
02274 #define GET_META( c, s ) \
02275     var_Get( p_input, (s), &val );  \
02276     if( *val.psz_string )       \
02277         vlc_meta_Add( p_meta, c, val.psz_string ); \
02278     free( val.psz_string )
02279 
02280     GET_META( VLC_META_TITLE, "meta-title" );
02281     GET_META( VLC_META_AUTHOR, "meta-author" );
02282     GET_META( VLC_META_ARTIST, "meta-artist" );
02283     GET_META( VLC_META_GENRE, "meta-genre" );
02284     GET_META( VLC_META_COPYRIGHT, "meta-copyright" );
02285     GET_META( VLC_META_DESCRIPTION, "meta-description" );
02286     GET_META( VLC_META_DATE, "meta-date" );
02287     GET_META( VLC_META_URL, "meta-url" );
02288 #undef GET_META
02289 
02290     return p_meta;
02291 }
02292 
02293 /*****************************************************************************
02294  * DecodeUrl: decode a given encoded url
02295  *****************************************************************************/
02296 static void DecodeUrl( char *psz )
02297 {
02298     char *dup = strdup( psz );
02299     char *p = dup;
02300 
02301     while( *p )
02302     {
02303         if( *p == '%' )
02304         {
02305             char val[3];
02306             p++;
02307             if( !*p )
02308             {
02309                 break;
02310             }
02311 
02312             val[0] = *p++;
02313             val[1] = *p++;
02314             val[2] = '\0';
02315 
02316             *psz++ = strtol( val, NULL, 16 );
02317         }
02318         else if( *p == '+' )
02319         {
02320             *psz++ = ' ';
02321             p++;
02322         }
02323         else
02324         {
02325             *psz++ = *p++;
02326         }
02327     }
02328     if( psz ) *psz++  ='\0';
02329     if( dup ) free( dup );
02330 }
02331 
02332 /*****************************************************************************
02333  * ParseOption: parses the options for the input
02334  *****************************************************************************
02335  * This function parses the input (config) options and creates their associated
02336  * object variables.
02337  * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
02338  * bar is the value of the option.
02339  *****************************************************************************/
02340 static void ParseOption( input_thread_t *p_input, const char *psz_option )
02341 {
02342     char *psz_name = (char *)psz_option;
02343     char *psz_value = strchr( psz_option, '=' );
02344     int  i_name_len, i_type;
02345     vlc_bool_t b_isno = VLC_FALSE;
02346     vlc_value_t val;
02347 
02348     if( psz_value ) i_name_len = psz_value - psz_option;
02349     else i_name_len = strlen( psz_option );
02350 
02351     /* It's too much of an hassle to remove the ':' when we parse
02352      * the cmd line :) */
02353     if( i_name_len && *psz_name == ':' )
02354     {
02355         psz_name++;
02356         i_name_len--;
02357     }
02358 
02359     if( i_name_len == 0 ) return;
02360 
02361     psz_name = strndup( psz_name, i_name_len );
02362     if( psz_value ) psz_value++;
02363 
02364     /* FIXME: :programs should be handled generically */
02365     if( !strcmp( psz_name, "programs" ) )
02366         i_type = VLC_VAR_LIST;
02367     else
02368         i_type = config_GetType( p_input, psz_name );
02369 
02370     if( !i_type && !psz_value )
02371     {
02372         /* check for "no-foo" or "nofoo" */
02373         if( !strncmp( psz_name, "no-", 3 ) )
02374         {
02375             memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
02376         }
02377         else if( !strncmp( psz_name, "no", 2 ) )
02378         {
02379             memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
02380         }
02381         else goto cleanup;           /* Option doesn't exist */
02382 
02383         b_isno = VLC_TRUE;
02384         i_type = config_GetType( p_input, psz_name );
02385 
02386         if( !i_type ) goto cleanup;  /* Option doesn't exist */
02387     }
02388     else if( !i_type ) goto cleanup; /* Option doesn't exist */
02389 
02390     if( ( i_type != VLC_VAR_BOOL ) &&
02391         ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */
02392 
02393     /* Create the variable in the input object.
02394      * Children of the input object will be able to retreive this value
02395      * thanks to the inheritance property of the object variables. */
02396     var_Create( p_input, psz_name, i_type );
02397 
02398     switch( i_type )
02399     {
02400     case VLC_VAR_BOOL:
02401         val.b_bool = !b_isno;
02402         break;
02403 
02404     case VLC_VAR_INTEGER:
02405         val.i_int = atoi( psz_value );
02406         break;
02407 
02408     case VLC_VAR_FLOAT:
02409         val.f_float = atof( psz_value );
02410         break;
02411 
02412     case VLC_VAR_STRING:
02413     case VLC_VAR_MODULE:
02414     case VLC_VAR_FILE:
02415     case VLC_VAR_DIRECTORY:
02416         val.psz_string = psz_value;
02417         break;
02418 
02419     case VLC_VAR_LIST:
02420     {
02421         char *psz_orig, *psz_var;
02422         vlc_list_t *p_list = malloc(sizeof(vlc_list_t));
02423         val.p_list = p_list;
02424         p_list->i_count = 0;
02425 
02426         psz_var = psz_orig = strdup(psz_value);
02427         while( psz_var && *psz_var )
02428         {
02429             char *psz_item = psz_var;
02430             vlc_value_t val2;
02431             while( *psz_var && *psz_var != ',' ) psz_var++;
02432             if( *psz_var == ',' )
02433             {
02434                 *psz_var = '\0';
02435                 psz_var++;
02436             }
02437             val2.i_int = strtol( psz_item, NULL, 0 );
02438             INSERT_ELEM( p_list->p_values, p_list->i_count,
02439                          p_list->i_count, val2 );
02440             /* p_list->i_count is incremented twice by INSERT_ELEM */
02441             p_list->i_count--;
02442             INSERT_ELEM( p_list->pi_types, p_list->i_count,
02443                          p_list->i_count, VLC_VAR_INTEGER );
02444         }
02445         if( psz_orig ) free( psz_orig );
02446         break;
02447     }
02448 
02449     default:
02450         goto cleanup;
02451         break;
02452     }
02453 
02454     var_Set( p_input, psz_name, val );
02455 
02456     msg_Dbg( p_input, "set input option: %s to %s", psz_name,
02457              psz_value ? psz_value : ( val.b_bool ? "true" : "false") );
02458 
02459   cleanup:
02460     if( psz_name ) free( psz_name );
02461     return;
02462 }
02463 
02464 /*****************************************************************************
02465  * MRLSplit: parse the access, demux and url part of the
02466  *           Media Resource Locator.
02467  *****************************************************************************/
02468 void MRLSplit( vlc_object_t *p_input, char *psz_dup,
02469                char **ppsz_access, char **ppsz_demux, char **ppsz_path )
02470 {
02471     char *psz_access = NULL;
02472     char *psz_demux  = NULL;
02473     char *psz_path   = NULL;
02474     char *psz, *psz_check;
02475 
02476     psz = strchr( psz_dup, ':' );
02477 
02478     /* '@' not allowed in access/demux part */
02479     psz_check = strchr( psz_dup, '@' );
02480     if( psz_check && psz_check < psz ) psz = 0;
02481 
02482 #if defined( WIN32 ) || defined( UNDER_CE )
02483     if( psz - psz_dup == 1 )
02484     {
02485         msg_Warn( p_input, "drive letter %c: found in source", *psz_dup );
02486         psz_path = psz_dup;
02487     }
02488     else
02489 #endif
02490 
02491     if( psz )
02492     {
02493         *psz++ = '\0';
02494         if( psz[0] == '/' && psz[1] == '/' ) psz += 2;
02495 
02496         psz_path = psz;
02497 
02498         psz = strchr( psz_dup, '/' );
02499         if( psz )
02500         {
02501             *psz++ = '\0';
02502             psz_demux = psz;
02503         }
02504 
02505         psz_access = psz_dup;
02506     }
02507     else
02508     {
02509         psz_path = psz_dup;
02510     }
02511 
02512     if( !psz_access ) *ppsz_access = "";
02513     else *ppsz_access = psz_access;
02514 
02515     if( !psz_demux ) *ppsz_demux = "";
02516     else *ppsz_demux = psz_demux;
02517 
02518     if( !psz_path ) *ppsz_path = "";
02519     else *ppsz_path = psz_path;
02520 }
02521 
02522 /*****************************************************************************
02523  * MRLSections: parse title and seekpoint info from the Media Resource Locator.
02524  *
02525  * Syntax:
02526  * [url][@[title-start][:chapter-start][-[title-end][:chapter-end]]]
02527  *****************************************************************************/
02528 static void MRLSections( input_thread_t *p_input, char *psz_source,
02529                          int *pi_title_start, int *pi_title_end,
02530                          int *pi_chapter_start, int *pi_chapter_end )
02531 {
02532     char *psz, *psz_end, *psz_next, *psz_check;
02533 
02534     *pi_title_start = *pi_title_end = -1;
02535     *pi_chapter_start = *pi_chapter_end = -1;
02536 
02537     /* Start by parsing titles and chapters */
02538     if( !psz_source || !( psz = strrchr( psz_source, '@' ) ) ) return;
02539 
02540     /* Check we are really dealing with a title/chapter section */
02541     psz_check = psz + 1;
02542     if( !*psz_check ) return;
02543     if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02544     if( *psz_check != ':' && *psz_check != '-' && *psz_check ) return;
02545     if( *psz_check == ':' && ++psz_check )
02546         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02547     if( *psz_check != '-' && *psz_check ) return;
02548     if( *psz_check == '-' && ++psz_check )
02549         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02550     if( *psz_check != ':' && *psz_check ) return;
02551     if( *psz_check == ':' && ++psz_check )
02552         if( isdigit(*psz_check) ) strtol( psz_check, &psz_check, 0 );
02553     if( *psz_check ) return;
02554 
02555     /* Separate start and end */
02556     *psz++ = 0;
02557     if( ( psz_end = strchr( psz, '-' ) ) ) *psz_end++ = 0;
02558 
02559     /* Look for the start title */
02560     *pi_title_start = strtol( psz, &psz_next, 0 );
02561     if( !*pi_title_start && psz == psz_next ) *pi_title_start = -1;
02562     *pi_title_end = *pi_title_start;
02563     psz = psz_next;
02564 
02565     /* Look for the start chapter */
02566     if( *psz ) psz++;
02567     *pi_chapter_start = strtol( psz, &psz_next, 0 );
02568     if( !*pi_chapter_start && psz == psz_next ) *pi_chapter_start = -1;
02569     *pi_chapter_end = *pi_chapter_start;
02570 
02571     if( psz_end )
02572     {
02573         /* Look for the end title */
02574         *pi_title_end = strtol( psz_end, &psz_next, 0 );
02575         if( !*pi_title_end && psz_end == psz_next ) *pi_title_end = -1;
02576         psz_end = psz_next;
02577 
02578         /* Look for the end chapter */
02579         if( *psz_end ) psz_end++;
02580         *pi_chapter_end = strtol( psz_end, &psz_next, 0 );
02581         if( !*pi_chapter_end && psz_end == psz_next ) *pi_chapter_end = -1;
02582     }
02583 
02584     msg_Dbg( p_input, "source=`%s' title=%d/%d seekpoint=%d/%d",
02585              psz_source, *pi_title_start, *pi_chapter_start,
02586              *pi_title_end, *pi_chapter_end );
02587 }
02588 
02589 
02590 /***********************************************************************
02591  * Info management functions
02592  ***********************************************************************/
02603 char *vlc_input_item_GetInfo( input_item_t *p_i,
02604                               const char *psz_cat,
02605                               const char *psz_name )
02606 {
02607     int i,j;
02608 
02609     vlc_mutex_lock( &p_i->lock );
02610 
02611     for( i = 0 ; i< p_i->i_categories  ; i++ )
02612     {
02613         info_category_t *p_cat = p_i->pp_categories[i];
02614 
02615         if( !psz_cat || strcmp( p_cat->psz_name, psz_cat ) )
02616             continue;
02617 
02618         for( j = 0; j < p_cat->i_infos ; j++ )
02619         {
02620             if( !strcmp( p_cat->pp_infos[j]->psz_name, psz_name ) )
02621             {
02622                 char *psz_ret = strdup( p_cat->pp_infos[j]->psz_value );
02623                 vlc_mutex_unlock( &p_i->lock );
02624                 return psz_ret;
02625             }
02626         }
02627     }
02628     vlc_mutex_unlock( &p_i->lock );
02629     return strdup( "" );
02630 }
02631 
02632 int vlc_input_item_AddInfo( input_item_t *p_i,
02633                             const char *psz_cat,
02634                             const char *psz_name,
02635                             const char *psz_format, ... )
02636 {
02637     va_list args;
02638     int i;
02639     info_t *p_info = NULL;
02640     info_category_t *p_cat = NULL ;
02641 
02642     vlc_mutex_lock( &p_i->lock );
02643 
02644     for( i = 0 ; i < p_i->i_categories ; i ++ )
02645     {
02646         if( !strcmp( p_i->pp_categories[i]->psz_name, psz_cat ) )
02647         {
02648             p_cat = p_i->pp_categories[i];
02649             break;
02650         }
02651     }
02652     if( !p_cat )
02653     {
02654         if( !(p_cat = (info_category_t *)malloc( sizeof(info_category_t) )) )
02655         {
02656             vlc_mutex_unlock( &p_i->lock );
02657             return VLC_EGENERIC;
02658         }
02659         p_cat->psz_name = strdup( psz_cat );
02660         p_cat->i_infos = 0;
02661         p_cat->pp_infos = 0;
02662         INSERT_ELEM( p_i->pp_categories, p_i->i_categories, p_i->i_categories,
02663                      p_cat );
02664     }
02665 
02666     for( i = 0; i< p_cat->i_infos; i++ )
02667     {
02668         if( !strcmp( p_cat->pp_infos[i]->psz_name, psz_name ) )
02669         {
02670             p_info = p_cat->pp_infos[i];
02671             break;
02672         }
02673     }
02674 
02675     if( !p_info )
02676     {
02677         if( ( p_info = (info_t *)malloc( sizeof( info_t ) ) ) == NULL )
02678         {
02679             vlc_mutex_unlock( &p_i->lock );
02680             return VLC_EGENERIC;
02681         }
02682         INSERT_ELEM( p_cat->pp_infos, p_cat->i_infos, p_cat->i_infos, p_info );
02683         p_info->psz_name = strdup( psz_name );
02684     }
02685     else
02686     {
02687         if( p_info->psz_value ) free( p_info->psz_value );
02688     }
02689 
02690     va_start( args, psz_format );
02691     vasprintf( &p_info->psz_value, psz_format, args);
02692     va_end( args );
02693 
02694     vlc_mutex_unlock( &p_i->lock );
02695 
02696     return VLC_SUCCESS;
02697 }
02698 

Generated on Tue Dec 20 10:14:48 2005 for vlc-0.8.4a by  doxygen 1.4.2