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

es_out.c

00001 /*****************************************************************************
00002  * es_out.c: Es Out handler for input.
00003  *****************************************************************************
00004  * Copyright (C) 2003-2004 the VideoLAN team
00005  * $Id: es_out.c 12354 2005-08-22 20:24:20Z gbazin $
00006  *
00007  * Authors: Laurent Aimar <[email protected]>
00008  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
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 
00030 #include <vlc/vlc.h>
00031 #include <vlc/input.h>
00032 #include <vlc/decoder.h>
00033 
00034 #include "input_internal.h"
00035 
00036 #include "vlc_playlist.h"
00037 #include "iso_lang.h"
00038 /* FIXME we should find a better way than including that */
00039 #include "../misc/iso-639_def.h"
00040 
00041 /*****************************************************************************
00042  * Local prototypes
00043  *****************************************************************************/
00044 typedef struct
00045 {
00046     /* Program ID */
00047     int i_id;
00048 
00049     /* Number of es for this pgrm */
00050     int i_es;
00051 
00052     vlc_bool_t b_selected;
00053 
00054     /* Clock for this program */
00055     input_clock_t clock;
00056 
00057     char    *psz_now_playing;
00058 
00059 } es_out_pgrm_t;
00060 
00061 struct es_out_id_t
00062 {
00063     /* ES ID */
00064     int       i_id;
00065     es_out_pgrm_t *p_pgrm;
00066 
00067     /* Signal a discontinuity in the timeline for every PID */
00068     vlc_bool_t b_discontinuity;
00069 
00070     /* Misc. */
00071     int64_t i_preroll_end;
00072 
00073     /* Channel in the track type */
00074     int         i_channel;
00075     es_format_t fmt;
00076     char        *psz_language;
00077     char        *psz_language_code;
00078     decoder_t   *p_dec;
00079 };
00080 
00081 struct es_out_sys_t
00082 {
00083     input_thread_t *p_input;
00084 
00085     /* all programs */
00086     int           i_pgrm;
00087     es_out_pgrm_t **pgrm;
00088     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
00089     es_out_pgrm_t *p_pgrm;  /* Master program */
00090 
00091     /* all es */
00092     int         i_id;
00093     int         i_es;
00094     es_out_id_t **es;
00095 
00096     /* mode gestion */
00097     vlc_bool_t  b_active;
00098     int         i_mode;
00099 
00100     /* es count */
00101     int         i_audio;
00102     int         i_video;
00103     int         i_sub;
00104 
00105     /* es to select */
00106     int         i_audio_last;
00107     int         i_sub_last;
00108     char        **ppsz_audio_language;
00109     char        **ppsz_sub_language;
00110 
00111     /* current main es */
00112     es_out_id_t *p_es_audio;
00113     es_out_id_t *p_es_video;
00114     es_out_id_t *p_es_sub;
00115 
00116     /* delay */
00117     int64_t i_audio_delay;
00118     int64_t i_spu_delay;
00119 };
00120 
00121 static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
00122 static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
00123 static void         EsOutDel    ( es_out_t *, es_out_id_t * );
00124 static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
00125 static int          EsOutControl( es_out_t *, int i_query, va_list );
00126 
00127 static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
00128 
00129 static void EsSelect( es_out_t *out, es_out_id_t *es );
00130 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
00131 static char *LanguageGetName( const char *psz_code );
00132 static char *LanguageGetCode( const char *psz_lang );
00133 static char **LanguageSplit( const char *psz_langs );
00134 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
00135 
00136 /*****************************************************************************
00137  * input_EsOutNew:
00138  *****************************************************************************/
00139 es_out_t *input_EsOutNew( input_thread_t *p_input )
00140 {
00141     es_out_t     *out = malloc( sizeof( es_out_t ) );
00142     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
00143     vlc_value_t  val;
00144     int i;
00145 
00146     out->pf_add     = EsOutAdd;
00147     out->pf_send    = EsOutSend;
00148     out->pf_del     = EsOutDel;
00149     out->pf_control = EsOutControl;
00150     out->p_sys      = p_sys;
00151 
00152     p_sys->p_input = p_input;
00153 
00154     p_sys->b_active = VLC_FALSE;
00155     p_sys->i_mode   = ES_OUT_MODE_AUTO;
00156 
00157 
00158     p_sys->i_pgrm   = 0;
00159     p_sys->pgrm     = NULL;
00160     p_sys->p_pgrm   = NULL;
00161 
00162     p_sys->i_id    = 0;
00163     p_sys->i_es    = 0;
00164     p_sys->es      = NULL;
00165 
00166     p_sys->i_audio = 0;
00167     p_sys->i_video = 0;
00168     p_sys->i_sub   = 0;
00169 
00170     /* */
00171     var_Get( p_input, "audio-track", &val );
00172     p_sys->i_audio_last = val.i_int;
00173 
00174     var_Get( p_input, "sub-track", &val );
00175     p_sys->i_sub_last = val.i_int;
00176 
00177     var_Get( p_input, "audio-language", &val );
00178     p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
00179     if( p_sys->ppsz_audio_language )
00180     {
00181         for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
00182             msg_Dbg( p_input, "select audio in language[%d] %s",
00183                      i, p_sys->ppsz_audio_language[i] );
00184     }
00185     if( val.psz_string ) free( val.psz_string );
00186 
00187     var_Get( p_input, "sub-language", &val );
00188     p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
00189     if( p_sys->ppsz_sub_language )
00190     {
00191         for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
00192             msg_Dbg( p_input, "select subtitle in language[%d] %s",
00193                      i, p_sys->ppsz_sub_language[i] );
00194     }
00195     if( val.psz_string ) free( val.psz_string );
00196 
00197     p_sys->p_es_audio = NULL;
00198     p_sys->p_es_video = NULL;
00199     p_sys->p_es_sub   = NULL;
00200 
00201     p_sys->i_audio_delay= 0;
00202     p_sys->i_spu_delay  = 0;
00203 
00204     return out;
00205 }
00206 
00207 /*****************************************************************************
00208  * input_EsOutDelete:
00209  *****************************************************************************/
00210 void input_EsOutDelete( es_out_t *out )
00211 {
00212     es_out_sys_t *p_sys = out->p_sys;
00213     int i;
00214 
00215     for( i = 0; i < p_sys->i_es; i++ )
00216     {
00217         if( p_sys->es[i]->p_dec )
00218         {
00219             input_DecoderDelete( p_sys->es[i]->p_dec );
00220         }
00221         if( p_sys->es[i]->psz_language )
00222             free( p_sys->es[i]->psz_language );
00223         if( p_sys->es[i]->psz_language_code )
00224             free( p_sys->es[i]->psz_language_code );
00225         es_format_Clean( &p_sys->es[i]->fmt );
00226 
00227         free( p_sys->es[i] );
00228     }
00229     if( p_sys->ppsz_audio_language )
00230     {
00231         for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
00232             free( p_sys->ppsz_audio_language[i] );
00233         free( p_sys->ppsz_audio_language );
00234     }
00235     if( p_sys->ppsz_sub_language )
00236     {
00237         for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
00238             free( p_sys->ppsz_sub_language[i] );
00239         free( p_sys->ppsz_sub_language );
00240     }
00241 
00242     if( p_sys->es )
00243         free( p_sys->es );
00244 
00245     for( i = 0; i < p_sys->i_pgrm; i++ )
00246     {
00247         if( p_sys->pgrm[i]->psz_now_playing )
00248             free( p_sys->pgrm[i]->psz_now_playing );
00249         free( p_sys->pgrm[i] );
00250     }
00251     if( p_sys->pgrm )
00252         free( p_sys->pgrm );
00253 
00254     free( p_sys );
00255     free( out );
00256 }
00257 
00258 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
00259 {
00260     int i;
00261     if( i_id < 0 )
00262     {
00263         /* Special HACK, -i_id is tha cat of the stream */
00264         return (es_out_id_t*)((uint8_t*)NULL-i_id);
00265     }
00266 
00267     for( i = 0; i < out->p_sys->i_es; i++ )
00268     {
00269         if( out->p_sys->es[i]->i_id == i_id )
00270             return out->p_sys->es[i];
00271     }
00272     return NULL;
00273 }
00274 
00275 void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
00276 {
00277     es_out_sys_t      *p_sys = out->p_sys;
00278     int i;
00279 
00280     for( i = 0; i < p_sys->i_es; i++ )
00281     {
00282         es_out_id_t *es = p_sys->es[i];
00283         es->b_discontinuity = VLC_TRUE; /* signal discontinuity */
00284         
00285         /* Send a dummy block to let decoder know that
00286          * there is a discontinuity */
00287         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
00288         {
00289             input_DecoderDiscontinuity( es->p_dec );
00290         }
00291     }
00292 }
00293 
00294 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
00295 {
00296     es_out_sys_t *p_sys = out->p_sys;
00297 
00298     if( i_cat == AUDIO_ES )
00299         p_sys->i_audio_delay = i_delay;
00300     else if( i_cat == SPU_ES )
00301         p_sys->i_spu_delay = i_delay;
00302 }
00303 
00304 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
00305 {
00306     es_out_sys_t      *p_sys = out->p_sys;
00307     int i;
00308 
00309     for( i = 0; i < p_sys->i_es; i++ )
00310     {
00311         es_out_id_t *es = p_sys->es[i];
00312 
00313         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
00314             return VLC_FALSE;
00315     }
00316     return VLC_TRUE;
00317 }
00318 
00319 /*****************************************************************************
00320  *
00321  *****************************************************************************/
00322 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
00323                               vlc_bool_t b_delete )
00324 {
00325     es_out_sys_t      *p_sys = out->p_sys;
00326     input_thread_t    *p_input = p_sys->p_input;
00327     vlc_value_t       val, text;
00328 
00329     char *psz_var;
00330 
00331     if( es->fmt.i_cat == AUDIO_ES )
00332         psz_var = "audio-es";
00333     else if( es->fmt.i_cat == VIDEO_ES )
00334         psz_var = "video-es";
00335     else if( es->fmt.i_cat == SPU_ES )
00336         psz_var = "spu-es";
00337     else
00338         return;
00339 
00340     if( b_delete )
00341     {
00342         val.i_int = es->i_id;
00343         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
00344         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00345         return;
00346     }
00347 
00348     /* Get the number of ES already added */
00349     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
00350     if( val.i_int == 0 )
00351     {
00352         vlc_value_t val2;
00353 
00354         /* First one, we need to add the "Disable" choice */
00355         val2.i_int = -1; text.psz_string = _("Disable");
00356         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
00357         val.i_int++;
00358     }
00359 
00360     /* Take care of the ES description */
00361     if( es->fmt.psz_description && *es->fmt.psz_description )
00362     {
00363         if( es->psz_language && *es->psz_language )
00364         {
00365             text.psz_string = malloc( strlen( es->fmt.psz_description) + strlen( es->psz_language ) + 10 );
00366             sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, es->psz_language );
00367         }
00368         else text.psz_string = strdup( es->fmt.psz_description );
00369     }
00370     else
00371     {
00372         if( es->psz_language && *es->psz_language )
00373         {
00374             char *temp;
00375             text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 );
00376             asprintf( &temp,  _("Track %i"), val.i_int );
00377             sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
00378             free( temp );
00379         }
00380         else
00381         {
00382             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
00383             sprintf( text.psz_string, _("Track %i"), val.i_int );
00384         }
00385     }
00386 
00387     val.i_int = es->i_id;
00388     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
00389 
00390     free( text.psz_string );
00391 
00392     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00393 }
00394 
00395 /* EsOutProgramSelect:
00396  *  Select a program and update the object variable
00397  */
00398 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
00399 {
00400     es_out_sys_t      *p_sys = out->p_sys;
00401     input_thread_t    *p_input = p_sys->p_input;
00402     vlc_value_t       val;
00403     int               i;
00404 
00405     if( p_sys->p_pgrm == p_pgrm )
00406         return; /* Nothing to do */
00407 
00408     if( p_sys->p_pgrm )
00409     {
00410         es_out_pgrm_t *old = p_sys->p_pgrm;
00411         msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
00412 
00413         for( i = 0; i < p_sys->i_es; i++ )
00414         {
00415             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
00416                 p_sys->i_mode != ES_OUT_MODE_ALL )
00417                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
00418         }
00419 
00420         p_sys->p_es_audio = NULL;
00421         p_sys->p_es_sub = NULL;
00422         p_sys->p_es_video = NULL;
00423     }
00424 
00425     msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
00426 
00427     /* Mark it selected */
00428     p_pgrm->b_selected = VLC_TRUE;
00429 
00430     /* Switch master stream */
00431     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
00432     {
00433         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
00434     }
00435     p_pgrm->clock.b_master = VLC_TRUE;
00436     p_sys->p_pgrm = p_pgrm;
00437 
00438     /* Update "program" */
00439     val.i_int = p_pgrm->i_id;
00440     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
00441 
00442     /* Update "es-*" */
00443     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
00444     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
00445     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
00446     for( i = 0; i < p_sys->i_es; i++ )
00447     {
00448         if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
00449             EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
00450         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
00451     }
00452 
00453     /* Update now playing if defined per program */
00454     if( p_pgrm->psz_now_playing )
00455     {
00456         char *psz_cat = malloc( strlen(_("Program")) + 10 );
00457 
00458         sprintf( psz_cat, "%s %d", _("Program"), p_pgrm->i_id );
00459         input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
00460                        VLC_META_NOW_PLAYING, "%s", p_pgrm->psz_now_playing );
00461         free( psz_cat );
00462     }
00463 
00464 
00465     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00466 }
00467 
00468 /* EsOutAddProgram:
00469  *  Add a program
00470  */
00471 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
00472 {
00473     es_out_sys_t      *p_sys = out->p_sys;
00474     input_thread_t    *p_input = p_sys->p_input;
00475     vlc_value_t       val;
00476 
00477     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
00478 
00479     /* Init */
00480     p_pgrm->i_id = i_group;
00481     p_pgrm->i_es = 0;
00482     p_pgrm->b_selected = VLC_FALSE;
00483     p_pgrm->psz_now_playing = NULL;
00484     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
00485 
00486     /* Append it */
00487     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
00488 
00489     /* Update "program" variable */
00490     val.i_int = i_group;
00491     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
00492 
00493     if( i_group == var_GetInteger( p_input, "program" ) )
00494     {
00495         EsOutProgramSelect( out, p_pgrm );
00496     }
00497     else
00498     {
00499         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00500     }
00501     return p_pgrm;
00502 }
00503 
00504 /* EsOutDelProgram:
00505  *  Delete a program
00506  */
00507 static int EsOutProgramDel( es_out_t *out, int i_group )
00508 {
00509     es_out_sys_t      *p_sys = out->p_sys;
00510     input_thread_t    *p_input = p_sys->p_input;
00511     es_out_pgrm_t     *p_pgrm = NULL;
00512     vlc_value_t       val;
00513     int               i;
00514 
00515     for( i = 0; i < p_sys->i_pgrm; i++ )
00516     {
00517         if( p_sys->pgrm[i]->i_id == i_group )
00518         {
00519             p_pgrm = p_sys->pgrm[i];
00520             break;
00521         }
00522     }
00523 
00524     if( p_pgrm == NULL )
00525         return VLC_EGENERIC;
00526 
00527     if( p_pgrm->i_es )
00528     {
00529         msg_Dbg( p_input, "can't delete program %d which still has %i ES",
00530                  i_group, p_pgrm->i_es );
00531         return VLC_EGENERIC;
00532     }
00533 
00534     TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
00535 
00536     /* If program is selected we need to unselect it */
00537     if( p_sys->p_pgrm == p_pgrm ) p_sys->p_pgrm = 0;
00538 
00539     if( p_pgrm->psz_now_playing ) free( p_pgrm->psz_now_playing );
00540     free( p_pgrm );
00541 
00542     /* Update "program" variable */
00543     val.i_int = i_group;
00544     var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
00545 
00546     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00547 
00548     return VLC_SUCCESS;
00549 }
00550 
00551 /* EsOutProgramMeta:
00552  */
00553 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
00554 {
00555     es_out_sys_t      *p_sys = out->p_sys;
00556     es_out_pgrm_t     *p_pgrm = NULL;
00557     input_thread_t    *p_input = p_sys->p_input;
00558     char              *psz_cat = malloc( strlen(_("Program")) + 10 );
00559     char              *psz_name = NULL;
00560     char              *psz_now_playing = NULL;
00561     char              *psz_provider = NULL;
00562     int i;
00563 
00564     msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
00565     sprintf( psz_cat, "%s %d", _("Program"), i_group );
00566 
00567     for( i = 0; i < p_meta->i_meta; i++ )
00568     {
00569         msg_Dbg( p_input, "  - %s = %s", p_meta->name[i], p_meta->value[i] );
00570 
00571         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
00572                       _(p_meta->name[i]), "%s", p_meta->value[i] );
00573         if( !strcasecmp( p_meta->name[i], "Name" ) )
00574             psz_name = p_meta->value[i];
00575         else if( !strcasecmp( p_meta->name[i], "Provider" ) )
00576             psz_provider = p_meta->value[i];
00577         else if( !strcasecmp( p_meta->name[i], VLC_META_NOW_PLAYING ) )
00578             psz_now_playing = p_meta->value[i];
00579     }
00580 
00581     if( !psz_name && !psz_now_playing )
00582     {
00583         free( psz_cat );
00584         return;
00585     }
00586 
00587     for( i = 0; i < p_sys->i_pgrm; i++ )
00588     {
00589         if( p_sys->pgrm[i]->i_id == i_group )
00590         {
00591             p_pgrm = p_sys->pgrm[i];
00592             break;
00593         }
00594     }
00595 
00596     if( p_pgrm == NULL )
00597         p_pgrm = EsOutProgramAdd( out, i_group );
00598 
00599     /* Update the description text of the program */
00600     if( psz_name && *psz_name )
00601     {
00602         vlc_value_t val;
00603         vlc_value_t text;
00604 
00605         /* ugly but it works */
00606         val.i_int = i_group;
00607         var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
00608 
00609         if( psz_provider && *psz_provider )
00610         {
00611             asprintf( &text.psz_string, "%s [%s]", psz_name, psz_provider );
00612             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
00613             free( text.psz_string );
00614         }
00615         else
00616         {
00617             text.psz_string = psz_name;
00618             var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
00619         }
00620     }
00621     if( psz_now_playing )
00622     {
00623         p_pgrm->psz_now_playing = strdup(psz_now_playing);
00624 
00625         if( p_sys->p_pgrm == p_pgrm )
00626         {
00627             input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
00628                            VLC_META_NOW_PLAYING, "%s", psz_now_playing );
00629         }
00630     }
00631     free( psz_cat );
00632 }
00633 
00634 /* EsOutAdd:
00635  *  Add an es_out
00636  */
00637 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
00638 {
00639     es_out_sys_t      *p_sys = out->p_sys;
00640     input_thread_t    *p_input = p_sys->p_input;
00641 
00642     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
00643     es_out_pgrm_t     *p_pgrm = NULL;
00644     int i;
00645 
00646     if( fmt->i_group < 0 )
00647     {
00648         msg_Err( p_input, "invalid group number" );
00649         return NULL;
00650     }
00651 
00652     /* Search the program */
00653     for( i = 0; i < p_sys->i_pgrm; i++ )
00654     {
00655         if( fmt->i_group == p_sys->pgrm[i]->i_id )
00656         {
00657             p_pgrm = p_sys->pgrm[i];
00658             break;
00659         }
00660     }
00661     if( p_pgrm == NULL )
00662     {
00663         /* Create a new one */
00664         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
00665     }
00666 
00667     /* Increase ref count for program */
00668     p_pgrm->i_es++;
00669 
00670     /* Set up ES */
00671     if( fmt->i_id < 0 )
00672         fmt->i_id = out->p_sys->i_id;
00673     es->i_id = fmt->i_id;
00674     es->p_pgrm = p_pgrm;
00675     es_format_Copy( &es->fmt, fmt );
00676     es->i_preroll_end = -1;
00677     es->b_discontinuity = VLC_FALSE;
00678 
00679     switch( fmt->i_cat )
00680     {
00681     case AUDIO_ES:
00682         es->i_channel = p_sys->i_audio;
00683         break;
00684 
00685     case VIDEO_ES:
00686         es->i_channel = p_sys->i_video;
00687         if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
00688             vlc_ureduce( &es->fmt.video.i_frame_rate,
00689                          &es->fmt.video.i_frame_rate_base,
00690                          fmt->video.i_frame_rate,
00691                          fmt->video.i_frame_rate_base, 0 );
00692         break;
00693 
00694     case SPU_ES:
00695         es->i_channel = p_sys->i_sub;
00696         break;
00697 
00698     default:
00699         es->i_channel = 0;
00700         break;
00701     }
00702     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
00703     es->psz_language_code = LanguageGetCode( fmt->psz_language );
00704     es->p_dec = NULL;
00705 
00706     if( es->p_pgrm == p_sys->p_pgrm )
00707         EsOutESVarUpdate( out, es, VLC_FALSE );
00708 
00709     /* Select it if needed */
00710     EsOutSelect( out, es, VLC_FALSE );
00711 
00712 
00713     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
00714     p_sys->i_id++;  /* always incremented */
00715     switch( fmt->i_cat )
00716     {
00717         case AUDIO_ES:
00718             p_sys->i_audio++;
00719             break;
00720         case SPU_ES:
00721             p_sys->i_sub++;
00722             break;
00723         case VIDEO_ES:
00724             p_sys->i_video++;
00725             break;
00726     }
00727 
00728     EsOutAddInfo( out, es );
00729 
00730     return es;
00731 }
00732 
00733 static void EsSelect( es_out_t *out, es_out_id_t *es )
00734 {
00735     es_out_sys_t   *p_sys = out->p_sys;
00736     input_thread_t *p_input = p_sys->p_input;
00737     vlc_value_t    val;
00738     char           *psz_var;
00739 
00740     if( es->p_dec )
00741     {
00742         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
00743         return;
00744     }
00745 
00746     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
00747     {
00748         if( !var_GetBool( p_input, "video" ) ||
00749             ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
00750         {
00751             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
00752                      es->i_id );
00753             return;
00754         }
00755     }
00756     else if( es->fmt.i_cat == AUDIO_ES )
00757     {
00758         var_Get( p_input, "audio", &val );
00759         if( !var_GetBool( p_input, "audio" ) ||
00760             ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
00761         {
00762             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
00763                      es->i_id );
00764             return;
00765         }
00766     }
00767 
00768     es->i_preroll_end = -1;
00769     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
00770     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
00771         return;
00772 
00773     if( es->fmt.i_cat == VIDEO_ES )
00774         psz_var = "video-es";
00775     else if( es->fmt.i_cat == AUDIO_ES )
00776         psz_var = "audio-es";
00777     else if( es->fmt.i_cat == SPU_ES )
00778         psz_var = "spu-es";
00779     else
00780         return;
00781 
00782     /* Mark it as selected */
00783     val.i_int = es->i_id;
00784     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
00785 
00786 
00787     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00788 }
00789 
00790 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
00791 {
00792     es_out_sys_t   *p_sys = out->p_sys;
00793     input_thread_t *p_input = p_sys->p_input;
00794     vlc_value_t    val;
00795     char           *psz_var;
00796 
00797     if( es->p_dec == NULL )
00798     {
00799         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
00800         return;
00801     }
00802 
00803     input_DecoderDelete( es->p_dec );
00804     es->p_dec = NULL;
00805 
00806     if( !b_update )
00807         return;
00808 
00809     /* Update var */
00810     if( es->p_dec == NULL )
00811         return;
00812     if( es->fmt.i_cat == VIDEO_ES )
00813         psz_var = "video-es";
00814     else if( es->fmt.i_cat == AUDIO_ES )
00815         psz_var = "audio-es";
00816     else if( es->fmt.i_cat == SPU_ES )
00817         psz_var = "spu-es";
00818     else
00819         return;
00820 
00821     /* Mark it as selected */
00822     val.i_int = -1;
00823     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
00824 
00825     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
00826 }
00827 
00837 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
00838 {
00839     es_out_sys_t      *p_sys = out->p_sys;
00840 
00841     int i_cat = es->fmt.i_cat;
00842 
00843     if( !p_sys->b_active ||
00844         ( !b_force && es->fmt.i_priority < 0 ) )
00845     {
00846         return;
00847     }
00848 
00849     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
00850     {
00851         if( !es->p_dec )
00852             EsSelect( out, es );
00853     }
00854     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
00855     {
00856         vlc_value_t val;
00857         int i;
00858         var_Get( p_sys->p_input, "programs", &val );
00859         for ( i = 0; i < val.p_list->i_count; i++ )
00860         {
00861             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
00862             {
00863                 if( !es->p_dec )
00864                     EsSelect( out, es );
00865                 break;
00866             }
00867         }
00868         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
00869     }
00870     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
00871     {
00872         int i_wanted  = -1;
00873 
00874         if( es->p_pgrm != p_sys->p_pgrm )
00875             return;
00876 
00877         if( i_cat == AUDIO_ES )
00878         {
00879             int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
00880                                      es->psz_language_code );
00881 
00882             if( p_sys->p_es_audio &&
00883                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
00884             {
00885                 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
00886                                          p_sys->p_es_audio->psz_language_code );
00887 
00888                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
00889                     return;
00890                 i_wanted = es->i_channel;
00891             }
00892             else
00893             {
00894                 /* Select audio if (no audio selected yet)
00895                  * - no audio-language
00896                  * - no audio code for the ES
00897                  * - audio code in the requested list */
00898                 if( idx1 >= 0 ||
00899                     !strcmp( es->psz_language_code, "??" ) ||
00900                     !p_sys->ppsz_audio_language )
00901                     i_wanted = es->i_channel;
00902             }
00903 
00904             if( p_sys->i_audio_last >= 0 )
00905                 i_wanted = p_sys->i_audio_last;
00906         }
00907         else if( i_cat == SPU_ES )
00908         {
00909             int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
00910                                      es->psz_language_code );
00911 
00912             if( p_sys->p_es_sub &&
00913                 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
00914             {
00915                 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
00916                                          p_sys->p_es_sub->psz_language_code );
00917 
00918                 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
00919                         idx1, es->psz_language_code, idx2,
00920                         p_sys->p_es_sub->psz_language_code );
00921 
00922                 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
00923                     return;
00924                 /* We found a SPU that matches our language request */
00925                 i_wanted  = es->i_channel;
00926             }
00927             else if( idx1 >= 0 )
00928             {
00929                 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
00930                         idx1, es->psz_language_code );
00931 
00932                 i_wanted  = es->i_channel;
00933             }
00934             if( p_sys->i_sub_last >= 0 )
00935                 i_wanted  = p_sys->i_sub_last;
00936         }
00937         else if( i_cat == VIDEO_ES )
00938         {
00939             i_wanted  = es->i_channel;
00940         }
00941 
00942         if( i_wanted == es->i_channel && es->p_dec == NULL )
00943             EsSelect( out, es );
00944     }
00945 
00946     /* FIXME TODO handle priority here */
00947     if( es->p_dec )
00948     {
00949         if( i_cat == AUDIO_ES )
00950         {
00951             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
00952                 p_sys->p_es_audio &&
00953                 p_sys->p_es_audio != es &&
00954                 p_sys->p_es_audio->p_dec )
00955             {
00956                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
00957             }
00958             p_sys->p_es_audio = es;
00959         }
00960         else if( i_cat == SPU_ES )
00961         {
00962             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
00963                 p_sys->p_es_sub &&
00964                 p_sys->p_es_sub != es &&
00965                 p_sys->p_es_sub->p_dec )
00966             {
00967                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
00968             }
00969             p_sys->p_es_sub = es;
00970         }
00971         else if( i_cat == VIDEO_ES )
00972         {
00973             p_sys->p_es_video = es;
00974         }
00975     }
00976 }
00977 
00985 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
00986 {
00987     es_out_sys_t *p_sys = out->p_sys;
00988     input_thread_t    *p_input = p_sys->p_input;
00989     es_out_pgrm_t *p_pgrm = es->p_pgrm;
00990     int64_t i_delay;
00991 
00992     if( es->fmt.i_cat == AUDIO_ES )
00993         i_delay = p_sys->i_audio_delay;
00994     else if( es->fmt.i_cat == SPU_ES )
00995         i_delay = p_sys->i_spu_delay;
00996     else
00997         i_delay = 0;
00998 
00999     /* Mark preroll blocks */
01000     if( es->i_preroll_end >= 0 )
01001     {
01002         int64_t i_date = p_block->i_pts;
01003         if( i_date <= 0 )
01004             i_date = p_block->i_dts;
01005 
01006         if( i_date < es->i_preroll_end )
01007             p_block->i_flags |= BLOCK_FLAG_PREROLL;
01008         else
01009             es->i_preroll_end = -1;
01010     }
01011 
01012     /* +11 -> avoid null value with non null dts/pts */
01013     if( p_block->i_dts > 0 )
01014     {
01015         p_block->i_dts =
01016             input_ClockGetTS( p_input, &p_pgrm->clock,
01017                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
01018     }
01019     if( p_block->i_pts > 0 )
01020     {
01021         p_block->i_pts =
01022             input_ClockGetTS( p_input, &p_pgrm->clock,
01023                               ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
01024     }
01025     if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
01026     {
01027         mtime_t current_date = mdate();
01028         if( !p_block->i_pts
01029                || p_block->i_pts > current_date + 10000000
01030                || current_date > p_block->i_pts )
01031         {
01032             /* ETSI EN 300 472 Annex A : do not take into account the PTS
01033              * for teletext streams. */
01034             p_block->i_pts = current_date + 400000
01035                                + p_input->i_pts_delay + i_delay;
01036         }
01037     }
01038 
01039     p_block->i_rate = p_input->i_rate;
01040 
01041     /* TODO handle mute */
01042     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
01043         p_input->i_rate == INPUT_RATE_DEFAULT ) )
01044     {
01045         input_DecoderDecode( es->p_dec, p_block );
01046     }
01047     else
01048     {
01049         block_Release( p_block );
01050     }
01051 
01052     return VLC_SUCCESS;
01053 }
01054 
01055 /*****************************************************************************
01056  * EsOutDel:
01057  *****************************************************************************/
01058 static void EsOutDel( es_out_t *out, es_out_id_t *es )
01059 {
01060     es_out_sys_t *p_sys = out->p_sys;
01061     vlc_bool_t b_reselect = VLC_FALSE;
01062     int i;
01063 
01064     /* We don't try to reselect */
01065     if( es->p_dec )
01066         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
01067 
01068     if( es->p_pgrm == p_sys->p_pgrm )
01069         EsOutESVarUpdate( out, es, VLC_TRUE );
01070 
01071     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
01072 
01073     es->p_pgrm->i_es--;
01074     if( es->p_pgrm->i_es == 0 )
01075     {
01076         msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
01077     }
01078 
01079     if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
01080         p_sys->p_es_sub == es ) b_reselect = VLC_TRUE;
01081 
01082     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
01083     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
01084     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
01085 
01086     switch( es->fmt.i_cat )
01087     {
01088         case AUDIO_ES:
01089             p_sys->i_audio--;
01090             break;
01091         case SPU_ES:
01092             p_sys->i_sub--;
01093             break;
01094         case VIDEO_ES:
01095             p_sys->i_video--;
01096             break;
01097     }
01098 
01099     /* Re-select another track when needed */
01100     if( b_reselect )
01101         for( i = 0; i < p_sys->i_es; i++ )
01102         {
01103             if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
01104                 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
01105         }
01106 
01107     if( es->psz_language )
01108         free( es->psz_language );
01109     if( es->psz_language_code )
01110         free( es->psz_language_code );
01111 
01112     es_format_Clean( &es->fmt );
01113 
01114     free( es );
01115 }
01116 
01125 static int EsOutControl( es_out_t *out, int i_query, va_list args )
01126 {
01127     es_out_sys_t *p_sys = out->p_sys;
01128     vlc_bool_t  b, *pb;
01129     int         i, *pi;
01130 
01131     es_out_id_t *es;
01132 
01133     switch( i_query )
01134     {
01135         case ES_OUT_SET_ES_STATE:
01136             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
01137             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
01138             if( b && es->p_dec == NULL )
01139             {
01140                 EsSelect( out, es );
01141                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
01142             }
01143             else if( !b && es->p_dec )
01144             {
01145                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
01146                 return VLC_SUCCESS;
01147             }
01148             return VLC_SUCCESS;
01149 
01150         case ES_OUT_GET_ES_STATE:
01151             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
01152             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
01153 
01154             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
01155             return VLC_SUCCESS;
01156 
01157         case ES_OUT_SET_ACTIVE:
01158         {
01159             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
01160             p_sys->b_active = b;
01161             /* Needed ? */
01162             if( b )
01163                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
01164             return VLC_SUCCESS;
01165         }
01166 
01167         case ES_OUT_GET_ACTIVE:
01168             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
01169             *pb = p_sys->b_active;
01170             return VLC_SUCCESS;
01171 
01172         case ES_OUT_SET_MODE:
01173             i = (int) va_arg( args, int );
01174             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
01175                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
01176             {
01177                 p_sys->i_mode = i;
01178 
01179                 /* Reapply policy mode */
01180                 for( i = 0; i < p_sys->i_es; i++ )
01181                 {
01182                     if( p_sys->es[i]->p_dec )
01183                     {
01184                         EsUnselect( out, p_sys->es[i],
01185                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
01186                     }
01187                 }
01188                 for( i = 0; i < p_sys->i_es; i++ )
01189                 {
01190                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
01191                 }
01192                 return VLC_SUCCESS;
01193             }
01194             return VLC_EGENERIC;
01195 
01196         case ES_OUT_GET_MODE:
01197             pi = (int*) va_arg( args, int* );
01198             *pi = p_sys->i_mode;
01199             return VLC_SUCCESS;
01200 
01201         case ES_OUT_SET_ES:
01202             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
01203             /* Special case NULL, NULL+i_cat */
01204             if( es == NULL )
01205             {
01206                 for( i = 0; i < p_sys->i_es; i++ )
01207                 {
01208                     if( p_sys->es[i]->p_dec )
01209                         EsUnselect( out, p_sys->es[i],
01210                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
01211                 }
01212             }
01213             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
01214             {
01215                 for( i = 0; i < p_sys->i_es; i++ )
01216                 {
01217                     if( p_sys->es[i]->p_dec &&
01218                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
01219                         EsUnselect( out, p_sys->es[i],
01220                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
01221                 }
01222             }
01223             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
01224             {
01225                 for( i = 0; i < p_sys->i_es; i++ )
01226                 {
01227                     if( p_sys->es[i]->p_dec &&
01228                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
01229                         EsUnselect( out, p_sys->es[i],
01230                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
01231                 }
01232             }
01233             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
01234             {
01235                 for( i = 0; i < p_sys->i_es; i++ )
01236                 {
01237                     if( p_sys->es[i]->p_dec &&
01238                         p_sys->es[i]->fmt.i_cat == SPU_ES )
01239                         EsUnselect( out, p_sys->es[i],
01240                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
01241                 }
01242             }
01243             else
01244             {
01245                 for( i = 0; i < p_sys->i_es; i++ )
01246                 {
01247                     if( es == p_sys->es[i] )
01248                     {
01249                         EsOutSelect( out, es, VLC_TRUE );
01250                         break;
01251                     }
01252                 }
01253             }
01254             return VLC_SUCCESS;
01255 
01256         case ES_OUT_SET_PCR:
01257         case ES_OUT_SET_GROUP_PCR:
01258         {
01259             es_out_pgrm_t *p_pgrm = NULL;
01260             int            i_group = 0;
01261             int64_t        i_pcr;
01262 
01263             if( i_query == ES_OUT_SET_PCR )
01264             {
01265                 p_pgrm = p_sys->p_pgrm;
01266             }
01267             else
01268             {
01269                 int i;
01270                 i_group = (int)va_arg( args, int );
01271                 for( i = 0; i < p_sys->i_pgrm; i++ )
01272                 {
01273                     if( p_sys->pgrm[i]->i_id == i_group )
01274                     {
01275                         p_pgrm = p_sys->pgrm[i];
01276                         break;
01277                     }
01278                 }
01279             }
01280             if( p_pgrm == NULL )
01281                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
01282 
01283             i_pcr = (int64_t)va_arg( args, int64_t );
01284             /* search program */
01285             /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
01286             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
01287                                (i_pcr + 11 ) * 9 / 100);
01288             return VLC_SUCCESS;
01289         }
01290 
01291         case ES_OUT_RESET_PCR:
01292             for( i = 0; i < p_sys->i_pgrm; i++ )
01293             {
01294                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
01295                 p_sys->pgrm[i]->clock.last_pts = 0;
01296             }
01297             return VLC_SUCCESS;
01298 
01299         case ES_OUT_GET_TS:
01300             if( p_sys->p_pgrm )
01301             {
01302                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
01303                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
01304                 *pi_ts = input_ClockGetTS( p_sys->p_input,
01305                                            &p_sys->p_pgrm->clock,
01306                                            ( i_ts + 11 ) * 9 / 100 );
01307                 return VLC_SUCCESS;
01308             }
01309             return VLC_EGENERIC;
01310 
01311         case ES_OUT_GET_GROUP:
01312             pi = (int*) va_arg( args, int* );
01313             if( p_sys->p_pgrm )
01314                 *pi = p_sys->p_pgrm->i_id;
01315             else
01316                 *pi = -1;    /* FIXME */
01317             return VLC_SUCCESS;
01318 
01319         case ES_OUT_SET_GROUP:
01320         {
01321             int j;
01322             i = (int) va_arg( args, int );
01323             for( j = 0; j < p_sys->i_pgrm; j++ )
01324             {
01325                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
01326                 if( p_pgrm->i_id == i )
01327                 {
01328                     EsOutProgramSelect( out, p_pgrm );
01329                     return VLC_SUCCESS;
01330                 }
01331             }
01332             return VLC_EGENERIC;
01333         }
01334 
01335         case ES_OUT_SET_FMT:
01336         {
01337             /* This ain't pretty but is need by some demuxers (eg. Ogg )
01338              * to update the p_extra data */
01339             es_format_t *p_fmt;
01340             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
01341             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
01342             if( es == NULL ) return VLC_EGENERIC;
01343 
01344             if( p_fmt->i_extra )
01345             {
01346                 es->fmt.i_extra = p_fmt->i_extra;
01347                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
01348                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
01349 
01350                 if( !es->p_dec ) return VLC_SUCCESS;
01351 
01352 #if 1
01353                 input_DecoderDelete( es->p_dec );
01354                 es->p_dec = input_DecoderNew( p_sys->p_input,
01355                                               &es->fmt, VLC_FALSE );
01356 
01357 #else
01358                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
01359                 es->p_dec->fmt_in.p_extra =
01360                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
01361                 memcpy( es->p_dec->fmt_in.p_extra,
01362                         p_fmt->p_extra, p_fmt->i_extra );
01363 #endif
01364             }
01365 
01366             return VLC_SUCCESS;
01367         }
01368 
01369         case ES_OUT_SET_NEXT_DISPLAY_TIME:
01370         {
01371             int64_t i_date;
01372 
01373             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
01374             i_date = (int64_t)va_arg( args, int64_t );
01375 
01376             if( !es || !es->p_dec )
01377                 return VLC_EGENERIC;
01378 
01379             es->i_preroll_end = i_date;
01380             input_DecoderPreroll( es->p_dec, i_date );
01381 
01382             return VLC_SUCCESS;
01383         }
01384         case ES_OUT_SET_GROUP_META:
01385         {
01386             int i_group = (int)va_arg( args, int );
01387             vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
01388 
01389             EsOutProgramMeta( out, i_group, p_meta );
01390             return VLC_SUCCESS;
01391         }
01392         case ES_OUT_DEL_GROUP:
01393         {
01394             int i_group = (int)va_arg( args, int );
01395 
01396             return EsOutProgramDel( out, i_group );
01397         }
01398 
01399         default:
01400             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
01401             return VLC_EGENERIC;
01402     }
01403 }
01404 
01405 /****************************************************************************
01406  * LanguageGetName: try to expend iso639 into plain name
01407  ****************************************************************************/
01408 static char *LanguageGetName( const char *psz_code )
01409 {
01410     const iso639_lang_t *pl;
01411 
01412     if( psz_code == NULL )
01413     {
01414         return strdup( "" );
01415     }
01416 
01417     if( strlen( psz_code ) == 2 )
01418     {
01419         pl = GetLang_1( psz_code );
01420     }
01421     else if( strlen( psz_code ) == 3 )
01422     {
01423         pl = GetLang_2B( psz_code );
01424         if( !strcmp( pl->psz_iso639_1, "??" ) )
01425         {
01426             pl = GetLang_2T( psz_code );
01427         }
01428     }
01429     else
01430     {
01431         return strdup( psz_code );
01432     }
01433 
01434     if( !strcmp( pl->psz_iso639_1, "??" ) )
01435     {
01436        return strdup( psz_code );
01437     }
01438     else
01439     {
01440         if( *pl->psz_native_name )
01441         {
01442             return strdup( pl->psz_native_name );
01443         }
01444         return strdup( pl->psz_eng_name );
01445     }
01446 }
01447 
01448 /* Get a 2 char code */
01449 static char *LanguageGetCode( const char *psz_lang )
01450 {
01451     const iso639_lang_t *pl;
01452 
01453     if( psz_lang == NULL || *psz_lang == '\0' )
01454         return strdup("??");
01455 
01456     for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
01457     {
01458         if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
01459             !strcasecmp( pl->psz_native_name, psz_lang ) ||
01460             !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
01461             !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
01462             !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
01463             break;
01464     }
01465 
01466     if( pl->psz_iso639_1 != NULL )
01467         return strdup( pl->psz_iso639_1 );
01468 
01469     return strdup("??");
01470 }
01471 
01472 static char **LanguageSplit( const char *psz_langs )
01473 {
01474     char *psz_dup;
01475     char *psz_parser;
01476     char **ppsz = NULL;
01477     int i_psz = 0;
01478 
01479     if( psz_langs == NULL ) return NULL;
01480 
01481     psz_parser = psz_dup = strdup(psz_langs);
01482 
01483     while( psz_parser && *psz_parser )
01484     {
01485         char *psz;
01486         char *psz_code;
01487 
01488         psz = strchr(psz_parser, ',' );
01489         if( psz ) *psz++ = '\0';
01490 
01491         psz_code = LanguageGetCode( psz_parser );
01492         if( strcmp( psz_code, "??" ) )
01493         {
01494             TAB_APPEND( i_psz, ppsz, psz_code );
01495         }
01496 
01497         psz_parser = psz;
01498     }
01499 
01500     if( i_psz )
01501     {
01502         TAB_APPEND( i_psz, ppsz, NULL );
01503     }
01504 
01505     free( psz_dup );
01506     return ppsz;
01507 }
01508 
01509 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
01510 {
01511     int i;
01512 
01513     if( !ppsz_langs || !psz_lang ) return -1;
01514 
01515     for( i = 0; ppsz_langs[i]; i++ )
01516         if( !strcasecmp( ppsz_langs[i], psz_lang ) ) return i;
01517 
01518     return -1;
01519 }
01520 
01521 /****************************************************************************
01522  * EsOutAddInfo:
01523  * - add meta info to the playlist item
01524  ****************************************************************************/
01525 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
01526 {
01527     es_out_sys_t   *p_sys = out->p_sys;
01528     input_thread_t *p_input = p_sys->p_input;
01529     es_format_t    *fmt = &es->fmt;
01530     char           *psz_cat;
01531 
01532     /* Add stream info */
01533     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
01534 
01535     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
01536                    "%.4s", (char*)&fmt->i_codec );
01537 
01538     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
01539                    "%s", es->psz_language );
01540 
01541     /* Add information */
01542     switch( fmt->i_cat )
01543     {
01544     case AUDIO_ES:
01545         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01546                        _("Type"), _("Audio") );
01547 
01548         if( fmt->audio.i_channels > 0 )
01549             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
01550                            "%d", fmt->audio.i_channels );
01551 
01552         if( fmt->audio.i_rate > 0 )
01553             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
01554                            _("%d Hz"), fmt->audio.i_rate );
01555 
01556         if( fmt->audio.i_bitspersample > 0 )
01557             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01558                            _("Bits per sample"), "%d",
01559                            fmt->audio.i_bitspersample );
01560 
01561         if( fmt->i_bitrate > 0 )
01562             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
01563                            _("%d kb/s"), fmt->i_bitrate / 1000 );
01564         break;
01565 
01566     case VIDEO_ES:
01567         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01568                        _("Type"), _("Video") );
01569 
01570         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
01571             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01572                            _("Resolution"), "%dx%d",
01573                            fmt->video.i_width, fmt->video.i_height );
01574 
01575         if( fmt->video.i_visible_width > 0 &&
01576             fmt->video.i_visible_height > 0 )
01577             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01578                            _("Display resolution"), "%dx%d",
01579                            fmt->video.i_visible_width,
01580                            fmt->video.i_visible_height);
01581        if( fmt->video.i_frame_rate > 0 &&
01582            fmt->video.i_frame_rate_base > 0 )
01583            input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01584                           _("Frame rate"), "%f",
01585                           (float)fmt->video.i_frame_rate / 
01586                           fmt->video.i_frame_rate_base );
01587         break;
01588 
01589     case SPU_ES:
01590         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
01591                        _("Type"), _("Subtitle") );
01592         break;
01593 
01594     default:
01595         break;
01596     }
01597 
01598     free( psz_cat );
01599 }

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