es_out.c
上传用户:riyaled888
上传日期:2009-03-27
资源大小:7338k
文件大小:33k
源码类别:

多媒体

开发平台:

MultiPlatform

  1. /*****************************************************************************
  2.  * es_out.c: Es Out handler for input.
  3.  *****************************************************************************
  4.  * Copyright (C) 2003-2004 VideoLAN
  5.  * $Id: es_out.c 9139 2004-11-04 21:05:57Z hartman $
  6.  *
  7.  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  8.  *
  9.  * This program is free software; you can redistribute it and/or modify
  10.  * it under the terms of the GNU General Public License as published by
  11.  * the Free Software Foundation; either version 2 of the License, or
  12.  * (at your option) any later version.
  13.  *
  14.  * This program is distributed in the hope that it will be useful,
  15.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  17.  * GNU General Public License for more details.
  18.  *
  19.  * You should have received a copy of the GNU General Public License
  20.  * along with this program; if not, write to the Free Software
  21.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  22.  *****************************************************************************/
  23. /*****************************************************************************
  24.  * Preamble
  25.  *****************************************************************************/
  26. #include <stdlib.h>
  27. #include <vlc/vlc.h>
  28. #include <vlc/input.h>
  29. #include <vlc/decoder.h>
  30. #include "input_internal.h"
  31. #include "vlc_playlist.h"
  32. #include "iso_lang.h"
  33. /*****************************************************************************
  34.  * Local prototypes
  35.  *****************************************************************************/
  36. typedef struct
  37. {
  38.     /* Program ID */
  39.     int i_id;
  40.     /* Number of es for this pgrm */
  41.     int i_es;
  42.     vlc_bool_t b_selected;
  43.     /* Clock for this program */
  44.     input_clock_t clock;
  45. } es_out_pgrm_t;
  46. struct es_out_id_t
  47. {
  48.     /* ES ID */
  49.     int       i_id;
  50.     es_out_pgrm_t *p_pgrm;
  51.     /* Channel in the track type */
  52.     int         i_channel;
  53.     es_format_t fmt;
  54.     char        *psz_language;
  55.     decoder_t   *p_dec;
  56. };
  57. struct es_out_sys_t
  58. {
  59.     input_thread_t *p_input;
  60.     /* all programs */
  61.     int           i_pgrm;
  62.     es_out_pgrm_t **pgrm;
  63.     es_out_pgrm_t **pp_selected_pgrm; /* --programs */
  64.     es_out_pgrm_t *p_pgrm;  /* Master program */
  65.     /* all es */
  66.     int         i_id;
  67.     int         i_es;
  68.     es_out_id_t **es;
  69.     /* mode gestion */
  70.     vlc_bool_t  b_active;
  71.     int         i_mode;
  72.     /* es count */
  73.     int         i_audio;
  74.     int         i_video;
  75.     int         i_sub;
  76.     /* es to select */
  77.     int         i_audio_last;
  78.     int         i_sub_last;
  79.     /* current main es */
  80.     es_out_id_t *p_es_audio;
  81.     es_out_id_t *p_es_video;
  82.     es_out_id_t *p_es_sub;
  83.     /* delay */
  84.     int64_t i_audio_delay;
  85.     int64_t i_spu_delay;
  86. };
  87. static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
  88. static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
  89. static void         EsOutDel    ( es_out_t *, es_out_id_t * );
  90. static void         EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
  91. static int          EsOutControl( es_out_t *, int i_query, va_list );
  92. static void         EsOutAddInfo( es_out_t *, es_out_id_t *es );
  93. static void EsSelect( es_out_t *out, es_out_id_t *es );
  94. static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
  95. static char *LanguageGetName( const char *psz_code );
  96. /*****************************************************************************
  97.  * input_EsOutNew:
  98.  *****************************************************************************/
  99. es_out_t *input_EsOutNew( input_thread_t *p_input )
  100. {
  101.     es_out_t     *out = malloc( sizeof( es_out_t ) );
  102.     es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
  103.     vlc_value_t  val;
  104.     out->pf_add     = EsOutAdd;
  105.     out->pf_send    = EsOutSend;
  106.     out->pf_del     = EsOutDel;
  107.     out->pf_control = EsOutControl;
  108.     out->p_sys      = p_sys;
  109.     p_sys->p_input = p_input;
  110.     p_sys->b_active = VLC_FALSE;
  111.     p_sys->i_mode   = ES_OUT_MODE_AUTO;
  112.     p_sys->i_pgrm   = 0;
  113.     p_sys->pgrm     = NULL;
  114.     p_sys->p_pgrm   = NULL;
  115.     p_sys->i_id    = 0;
  116.     p_sys->i_es    = 0;
  117.     p_sys->es      = NULL;
  118.     p_sys->i_audio = 0;
  119.     p_sys->i_video = 0;
  120.     p_sys->i_sub   = 0;
  121.     var_Get( p_input, "audio-channel", &val );
  122.     p_sys->i_audio_last = val.i_int;
  123.     var_Get( p_input, "spu-channel", &val );
  124.     p_sys->i_sub_last = val.i_int;
  125.     p_sys->p_es_audio = NULL;
  126.     p_sys->p_es_video = NULL;
  127.     p_sys->p_es_sub   = NULL;
  128.     p_sys->i_audio_delay= 0;
  129.     p_sys->i_spu_delay  = 0;
  130.     return out;
  131. }
  132. /*****************************************************************************
  133.  * input_EsOutDelete:
  134.  *****************************************************************************/
  135. void input_EsOutDelete( es_out_t *out )
  136. {
  137.     es_out_sys_t *p_sys = out->p_sys;
  138.     int i;
  139.     for( i = 0; i < p_sys->i_es; i++ )
  140.     {
  141.         if( p_sys->es[i]->p_dec )
  142.         {
  143.             input_DecoderDelete( p_sys->es[i]->p_dec );
  144.         }
  145.         if( p_sys->es[i]->psz_language )
  146.             free( p_sys->es[i]->psz_language );
  147.         es_format_Clean( &p_sys->es[i]->fmt );
  148.         free( p_sys->es[i] );
  149.     }
  150.     if( p_sys->es )
  151.         free( p_sys->es );
  152.     for( i = 0; i < p_sys->i_pgrm; i++ )
  153.     {
  154.         free( p_sys->pgrm[i] );
  155.     }
  156.     if( p_sys->pgrm )
  157.         free( p_sys->pgrm );
  158.     free( p_sys );
  159.     free( out );
  160. }
  161. es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
  162. {
  163.     int i;
  164.     if( i_id < 0 )
  165.     {
  166.         /* Special HACK, -i_id is tha cat of the stream */
  167.         return (es_out_id_t*)((uint8_t*)NULL-i_id);
  168.     }
  169.     for( i = 0; i < out->p_sys->i_es; i++ )
  170.     {
  171.         if( out->p_sys->es[i]->i_id == i_id )
  172.             return out->p_sys->es[i];
  173.     }
  174.     return NULL;
  175. }
  176. void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
  177. {
  178.     es_out_sys_t      *p_sys = out->p_sys;
  179.     int i;
  180.     for( i = 0; i < p_sys->i_es; i++ )
  181.     {
  182.         es_out_id_t *es = p_sys->es[i];
  183.         /* Send a dummy block to let decoder know that
  184.          * there is a discontinuity */
  185.         if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
  186.         {
  187.             input_DecoderDiscontinuity( es->p_dec );
  188.         }
  189.     }
  190. }
  191. void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
  192. {
  193.     es_out_sys_t *p_sys = out->p_sys;
  194.     if( i_cat == AUDIO_ES )
  195.         p_sys->i_audio_delay = i_delay;
  196.     else if( i_cat == SPU_ES )
  197.         p_sys->i_spu_delay = i_delay;
  198. }
  199. vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
  200. {
  201.     es_out_sys_t      *p_sys = out->p_sys;
  202.     int i;
  203.     for( i = 0; i < p_sys->i_es; i++ )
  204.     {
  205.         es_out_id_t *es = p_sys->es[i];
  206.         if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
  207.             return VLC_FALSE;
  208.     }
  209.     return VLC_TRUE;
  210. }
  211. /*****************************************************************************
  212.  *
  213.  *****************************************************************************/
  214. static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
  215.                               vlc_bool_t b_delete )
  216. {
  217.     es_out_sys_t      *p_sys = out->p_sys;
  218.     input_thread_t    *p_input = p_sys->p_input;
  219.     vlc_value_t       val, text;
  220.     char *psz_var;
  221.     if( es->fmt.i_cat == AUDIO_ES )
  222.         psz_var = "audio-es";
  223.     else if( es->fmt.i_cat == VIDEO_ES )
  224.         psz_var = "video-es";
  225.     else if( es->fmt.i_cat == SPU_ES )
  226.         psz_var = "spu-es";
  227.     else
  228.         return;
  229.     if( b_delete )
  230.     {
  231.         val.i_int = es->i_id;
  232.         var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
  233.         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  234.         return;
  235.     }
  236.     /* Get the number of ES already added */
  237.     var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
  238.     if( val.i_int == 0 )
  239.     {
  240.         vlc_value_t val2;
  241.         /* First one, we need to add the "Disable" choice */
  242.         val2.i_int = -1; text.psz_string = _("Disable");
  243.         var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
  244.         val.i_int++;
  245.     }
  246.     /* Take care of the ES description */
  247.     if( es->fmt.psz_description && *es->fmt.psz_description )
  248.     {
  249.         if( es->psz_language && *es->psz_language )
  250. {
  251.     text.psz_string = malloc( strlen( es->fmt.psz_description) + strlen( es->psz_language ) + 10 );
  252.     sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, es->psz_language );
  253. }
  254. else text.psz_string = strdup( es->fmt.psz_description );
  255.     }
  256.     else
  257.     {
  258.         if( es->psz_language && *es->psz_language )
  259.         {
  260.             char *temp;
  261.             text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 );
  262.             asprintf( &temp,  _("Track %i"), val.i_int );
  263.             sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
  264.             free( temp );
  265.         }
  266.         else
  267.         {
  268.             text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
  269.             sprintf( text.psz_string, _("Track %i"), val.i_int );
  270.         }
  271.     }
  272.     val.i_int = es->i_id;
  273.     var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
  274.     free( text.psz_string );
  275.     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  276. }
  277. /* EsOutProgramSelect:
  278.  *  Select a program and update the object variable
  279.  */
  280. static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
  281. {
  282.     es_out_sys_t      *p_sys = out->p_sys;
  283.     input_thread_t    *p_input = p_sys->p_input;
  284.     vlc_value_t       val;
  285.     int               i;
  286.     if( p_sys->p_pgrm == p_pgrm )
  287.         return; /* Nothing to do */
  288.     if( p_sys->p_pgrm )
  289.     {
  290.         es_out_pgrm_t *old = p_sys->p_pgrm;
  291.         msg_Dbg( p_input, "Unselecting program id=%d", old->i_id );
  292.         for( i = 0; i < p_sys->i_es; i++ )
  293.         {
  294.             if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
  295.                 p_sys->i_mode != ES_OUT_MODE_ALL )
  296.                 EsUnselect( out, p_sys->es[i], VLC_TRUE );
  297.         }
  298.     }
  299.     msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id );
  300.     /* Mark it selected */
  301.     p_pgrm->b_selected = VLC_TRUE;
  302.     /* Switch master stream */
  303.     if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
  304.     {
  305.         p_sys->p_pgrm->clock.b_master = VLC_FALSE;
  306.     }
  307.     p_pgrm->clock.b_master = VLC_TRUE;
  308.     p_sys->p_pgrm = p_pgrm;
  309.     /* Update "program" */
  310.     val.i_int = p_pgrm->i_id;
  311.     var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
  312.     /* Update "es-*" */
  313.     var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
  314.     var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
  315.     var_Change( p_input, "spu-es",   VLC_VAR_CLEARCHOICES, NULL, NULL );
  316.     for( i = 0; i < p_sys->i_es; i++ )
  317.     {
  318.         EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
  319.         EsOutSelect( out, p_sys->es[i], VLC_FALSE );
  320.     }
  321.     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  322. }
  323. /* EsOutAddProgram:
  324.  *  Add a program
  325.  */
  326. static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
  327. {
  328.     es_out_sys_t      *p_sys = out->p_sys;
  329.     input_thread_t    *p_input = p_sys->p_input;
  330.     vlc_value_t       val;
  331.     es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
  332.     /* Init */
  333.     p_pgrm->i_id = i_group;
  334.     p_pgrm->i_es = 0;
  335.     p_pgrm->b_selected = VLC_FALSE;
  336.     input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
  337.     /* Append it */
  338.     TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
  339.     /* Update "program" variable */
  340.     val.i_int = i_group;
  341.     var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
  342.     if( i_group == var_GetInteger( p_input, "program" ) )
  343.     {
  344.         EsOutProgramSelect( out, p_pgrm );
  345.     }
  346.     else
  347.     {
  348.         var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  349.     }
  350.     return p_pgrm;
  351. }
  352. /* EsOutAdd:
  353.  *  Add an es_out
  354.  */
  355. static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
  356. {
  357.     es_out_sys_t      *p_sys = out->p_sys;
  358.     input_thread_t    *p_input = p_sys->p_input;
  359.     es_out_id_t       *es = malloc( sizeof( es_out_id_t ) );
  360.     es_out_pgrm_t     *p_pgrm = NULL;
  361.     int i;
  362.     if( fmt->i_group < 0 )
  363.     {
  364.         msg_Err( p_input, "invalid group number" );
  365.         return NULL;
  366.     }
  367.     /* Search the program */
  368.     for( i = 0; i < p_sys->i_pgrm; i++ )
  369.     {
  370.         if( fmt->i_group == p_sys->pgrm[i]->i_id )
  371.         {
  372.             p_pgrm = p_sys->pgrm[i];
  373.             break;
  374.         }
  375.     }
  376.     if( p_pgrm == NULL )
  377.     {
  378.         /* Create a new one */
  379.         p_pgrm = EsOutProgramAdd( out, fmt->i_group );
  380.     }
  381.     /* Increase ref count for program */
  382.     p_pgrm->i_es++;
  383.     /* Set up ES */
  384.     if( fmt->i_id < 0 )
  385.         fmt->i_id = out->p_sys->i_id;
  386.     es->i_id = fmt->i_id;
  387.     es->p_pgrm = p_pgrm;
  388.     es_format_Copy( &es->fmt, fmt );
  389.     switch( fmt->i_cat )
  390.     {
  391.     case AUDIO_ES:
  392.         es->i_channel = p_sys->i_audio;
  393.         break;
  394.     case VIDEO_ES:
  395.         es->i_channel = p_sys->i_video;
  396.         break;
  397.     case SPU_ES:
  398.         es->i_channel = p_sys->i_sub;
  399.         break;
  400.     default:
  401.         es->i_channel = 0;
  402.         break;
  403.     }
  404.     es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
  405.     es->p_dec = NULL;
  406.     if( es->p_pgrm == p_sys->p_pgrm )
  407.         EsOutESVarUpdate( out, es, VLC_FALSE );
  408.     /* Select it if needed */
  409.     EsOutSelect( out, es, VLC_FALSE );
  410.     TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
  411.     p_sys->i_id++;  /* always incremented */
  412.     switch( fmt->i_cat )
  413.     {
  414.         case AUDIO_ES:
  415.             p_sys->i_audio++;
  416.             break;
  417.         case SPU_ES:
  418.             p_sys->i_sub++;
  419.             break;
  420.         case VIDEO_ES:
  421.             p_sys->i_video++;
  422.             break;
  423.     }
  424.     EsOutAddInfo( out, es );
  425.     return es;
  426. }
  427. static void EsSelect( es_out_t *out, es_out_id_t *es )
  428. {
  429.     es_out_sys_t   *p_sys = out->p_sys;
  430.     input_thread_t *p_input = p_sys->p_input;
  431.     vlc_value_t    val;
  432.     char           *psz_var;
  433.     if( es->p_dec )
  434.     {
  435.         msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
  436.         return;
  437.     }
  438.     if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
  439.     {
  440.         if( !var_GetBool( p_input, "video" ) ||
  441.             ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
  442.         {
  443.             msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
  444.                      es->i_id );
  445.             return;
  446.         }
  447.     }
  448.     else if( es->fmt.i_cat == AUDIO_ES )
  449.     {
  450.         var_Get( p_input, "audio", &val );
  451.         if( !var_GetBool( p_input, "audio" ) ||
  452.             ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
  453.         {
  454.             msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
  455.                      es->i_id );
  456.             return;
  457.         }
  458.     }
  459.     es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
  460.     if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
  461.         return;
  462.     if( es->fmt.i_cat == VIDEO_ES )
  463.         psz_var = "video-es";
  464.     else if( es->fmt.i_cat == AUDIO_ES )
  465.         psz_var = "audio-es";
  466.     else if( es->fmt.i_cat == SPU_ES )
  467.         psz_var = "spu-es";
  468.     else
  469.         return;
  470.     /* Mark it as selected */
  471.     val.i_int = es->i_id;
  472.     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
  473.     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  474. }
  475. static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
  476. {
  477.     es_out_sys_t   *p_sys = out->p_sys;
  478.     input_thread_t *p_input = p_sys->p_input;
  479.     vlc_value_t    val;
  480.     char           *psz_var;
  481.     if( es->p_dec == NULL )
  482.     {
  483.         msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
  484.         return;
  485.     }
  486.     input_DecoderDelete( es->p_dec );
  487.     es->p_dec = NULL;
  488.     if( !b_update )
  489.         return;
  490.     /* Update var */
  491.     if( es->p_dec == NULL )
  492.         return;
  493.     if( es->fmt.i_cat == VIDEO_ES )
  494.         psz_var = "video-es";
  495.     else if( es->fmt.i_cat == AUDIO_ES )
  496.         psz_var = "audio-es";
  497.     else if( es->fmt.i_cat == SPU_ES )
  498.         psz_var = "spu-es";
  499.     else
  500.         return;
  501.     /* Mark it as selected */
  502.     val.i_int = -1;
  503.     var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
  504.     var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  505. }
  506. /**
  507.  * Select an ES given the current mode
  508.  * XXX: you need to take a the lock before (stream.stream_lock)
  509.  *
  510.  * param out The es_out structure
  511.  * param es es_out_id structure
  512.  * param b_force ...
  513.  * return nothing
  514.  */
  515. static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
  516. {
  517.     es_out_sys_t      *p_sys = out->p_sys;
  518.     int i_cat = es->fmt.i_cat;
  519.     if( !p_sys->b_active ||
  520.         ( !b_force && es->fmt.i_priority < 0 ) )
  521.     {
  522.         return;
  523.     }
  524.     if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
  525.     {
  526.         if( !es->p_dec )
  527.             EsSelect( out, es );
  528.     }
  529.     else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
  530.     {
  531.         vlc_value_t val;
  532.         int i;
  533.         var_Get( p_sys->p_input, "programs", &val );
  534.         for ( i = 0; i < val.p_list->i_count; i++ )
  535.         {
  536.             if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
  537.             {
  538.                 if( !es->p_dec )
  539.                     EsSelect( out, es );
  540.                 break;
  541.             }
  542.         }
  543.         var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
  544.     }
  545.     else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
  546.     {
  547.         int i_wanted  = -1;
  548.         if( es->p_pgrm != p_sys->p_pgrm )
  549.             return;
  550.         if( i_cat == AUDIO_ES )
  551.         {
  552.             if( p_sys->p_es_audio &&
  553.                 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
  554.             {
  555.                 return;
  556.             }
  557.             i_wanted  = p_sys->i_audio_last >= 0 ?
  558.                             p_sys->i_audio_last : es->i_channel;
  559.         }
  560.         else if( i_cat == SPU_ES )
  561.         {
  562.             if( p_sys->p_es_sub &&
  563.                 p_sys->p_es_sub->fmt.i_priority >=
  564.                     es->fmt.i_priority )
  565.             {
  566.                 return;
  567.             }
  568.             i_wanted  = p_sys->i_sub_last;
  569.         }
  570.         else if( i_cat == VIDEO_ES )
  571.         {
  572.             i_wanted  = es->i_channel;
  573.         }
  574.         if( i_wanted == es->i_channel && es->p_dec == NULL )
  575.             EsSelect( out, es );
  576.     }
  577.     /* FIXME TODO handle priority here */
  578.     if( es->p_dec )
  579.     {
  580.         if( i_cat == AUDIO_ES )
  581.         {
  582.             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
  583.                 p_sys->p_es_audio &&
  584.                 p_sys->p_es_audio != es &&
  585.                 p_sys->p_es_audio->p_dec )
  586.             {
  587.                 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
  588.             }
  589.             p_sys->p_es_audio = es;
  590.         }
  591.         else if( i_cat == SPU_ES )
  592.         {
  593.             if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
  594.                 p_sys->p_es_sub &&
  595.                 p_sys->p_es_sub != es &&
  596.                 p_sys->p_es_sub->p_dec )
  597.             {
  598.                 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
  599.             }
  600.             p_sys->p_es_sub = es;
  601.         }
  602.         else if( i_cat == VIDEO_ES )
  603.         {
  604.             p_sys->p_es_video = es;
  605.         }
  606.     }
  607. }
  608. /**
  609.  * Send a block for the given es_out
  610.  *
  611.  * param out the es_out to send from
  612.  * param es the es_out_id
  613.  * param p_block the data block to send
  614.  */
  615. static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
  616. {
  617.     es_out_sys_t *p_sys = out->p_sys;
  618.     input_thread_t    *p_input = p_sys->p_input;
  619.     es_out_pgrm_t *p_pgrm = es->p_pgrm;
  620.     int64_t i_delay;
  621.     if( es->fmt.i_cat == AUDIO_ES )
  622.         i_delay = p_sys->i_audio_delay;
  623.     else if( es->fmt.i_cat == SPU_ES )
  624.         i_delay = p_sys->i_spu_delay;
  625.     else
  626.         i_delay = 0;
  627.     /* +11 -> avoid null value with non null dts/pts */
  628.     if( p_block->i_dts > 0 )
  629.     {
  630.         p_block->i_dts =
  631.             input_ClockGetTS( p_input, &p_pgrm->clock,
  632.                               ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
  633.     }
  634.     if( p_block->i_pts > 0 )
  635.     {
  636.         p_block->i_pts =
  637.             input_ClockGetTS( p_input, &p_pgrm->clock,
  638.                               ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
  639.     }
  640.     p_block->i_rate = p_input->i_rate;
  641.     /* TODO handle mute */
  642.     if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
  643.         p_input->i_rate == INPUT_RATE_DEFAULT ) )
  644.     {
  645.         input_DecoderDecode( es->p_dec, p_block );
  646.     }
  647.     else
  648.     {
  649.         block_Release( p_block );
  650.     }
  651.     return VLC_SUCCESS;
  652. }
  653. /*****************************************************************************
  654.  * EsOutDel:
  655.  *****************************************************************************/
  656. static void EsOutDel( es_out_t *out, es_out_id_t *es )
  657. {
  658.     es_out_sys_t *p_sys = out->p_sys;
  659.     /* We don't try to reselect */
  660.     if( es->p_dec )
  661.         EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
  662.     if( es->p_pgrm == p_sys->p_pgrm )
  663.         EsOutESVarUpdate( out, es, VLC_TRUE );
  664.     TAB_REMOVE( p_sys->i_es, p_sys->es, es );
  665.     es->p_pgrm->i_es--;
  666.     if( es->p_pgrm->i_es == 0 )
  667.     {
  668.         msg_Warn( p_sys->p_input, "Program doesn't contain anymore ES, "
  669.                   "TODO cleaning ?" );
  670.     }
  671.     if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
  672.     if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
  673.     if( p_sys->p_es_sub   == es ) p_sys->p_es_sub   = NULL;
  674.     switch( es->fmt.i_cat )
  675.     {
  676.         case AUDIO_ES:
  677.             p_sys->i_audio--;
  678.             break;
  679.         case SPU_ES:
  680.             p_sys->i_sub--;
  681.             break;
  682.         case VIDEO_ES:
  683.             p_sys->i_video--;
  684.             break;
  685.     }
  686.     if( es->psz_language )
  687.         free( es->psz_language );
  688.     es_format_Clean( &es->fmt );
  689.     free( es );
  690. }
  691. /**
  692.  * Control query handler
  693.  *
  694.  * param out the es_out to control
  695.  * param i_query A es_out query as defined in include/ninput.h
  696.  * param args a variable list of arguments for the query
  697.  * return VLC_SUCCESS or an error code
  698.  */
  699. static int EsOutControl( es_out_t *out, int i_query, va_list args )
  700. {
  701.     es_out_sys_t *p_sys = out->p_sys;
  702.     vlc_bool_t  b, *pb;
  703.     int         i, *pi;
  704.     es_out_id_t *es;
  705.     switch( i_query )
  706.     {
  707.         case ES_OUT_SET_ES_STATE:
  708.             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
  709.             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
  710.             if( b && es->p_dec == NULL )
  711.             {
  712.                 EsSelect( out, es );
  713.                 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
  714.             }
  715.             else if( !b && es->p_dec )
  716.             {
  717.                 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
  718.                 return VLC_SUCCESS;
  719.             }
  720.             return VLC_SUCCESS;
  721.         case ES_OUT_GET_ES_STATE:
  722.             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
  723.             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
  724.             *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
  725.             return VLC_SUCCESS;
  726.         case ES_OUT_SET_ACTIVE:
  727.         {
  728.             b = (vlc_bool_t) va_arg( args, vlc_bool_t );
  729.             p_sys->b_active = b;
  730.             /* Needed ? */
  731.             if( b )
  732.                 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
  733.             return VLC_SUCCESS;
  734.         }
  735.         case ES_OUT_GET_ACTIVE:
  736.             pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
  737.             *pb = p_sys->b_active;
  738.             return VLC_SUCCESS;
  739.         case ES_OUT_SET_MODE:
  740.             i = (int) va_arg( args, int );
  741.             if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
  742.                 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
  743.             {
  744.                 p_sys->i_mode = i;
  745.                 /* Reapply policy mode */
  746.                 for( i = 0; i < p_sys->i_es; i++ )
  747.                 {
  748.                     if( p_sys->es[i]->p_dec )
  749.                     {
  750.                         EsUnselect( out, p_sys->es[i],
  751.                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
  752.                     }
  753.                 }
  754.                 for( i = 0; i < p_sys->i_es; i++ )
  755.                 {
  756.                     EsOutSelect( out, p_sys->es[i], VLC_FALSE );
  757.                 }
  758.                 return VLC_SUCCESS;
  759.             }
  760.             return VLC_EGENERIC;
  761.         case ES_OUT_GET_MODE:
  762.             pi = (int*) va_arg( args, int* );
  763.             *pi = p_sys->i_mode;
  764.             return VLC_SUCCESS;
  765.         case ES_OUT_SET_ES:
  766.             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
  767.             /* Special case NULL, NULL+i_cat */
  768.             if( es == NULL )
  769.             {
  770.                 for( i = 0; i < p_sys->i_es; i++ )
  771.                 {
  772.                     if( p_sys->es[i]->p_dec )
  773.                         EsUnselect( out, p_sys->es[i],
  774.                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
  775.                 }
  776.             }
  777.             else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
  778.             {
  779.                 for( i = 0; i < p_sys->i_es; i++ )
  780.                 {
  781.                     if( p_sys->es[i]->p_dec &&
  782.                         p_sys->es[i]->fmt.i_cat == AUDIO_ES )
  783.                         EsUnselect( out, p_sys->es[i],
  784.                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
  785.                 }
  786.             }
  787.             else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
  788.             {
  789.                 for( i = 0; i < p_sys->i_es; i++ )
  790.                 {
  791.                     if( p_sys->es[i]->p_dec &&
  792.                         p_sys->es[i]->fmt.i_cat == VIDEO_ES )
  793.                         EsUnselect( out, p_sys->es[i],
  794.                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
  795.                 }
  796.             }
  797.             else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
  798.             {
  799.                 for( i = 0; i < p_sys->i_es; i++ )
  800.                 {
  801.                     if( p_sys->es[i]->p_dec &&
  802.                         p_sys->es[i]->fmt.i_cat == SPU_ES )
  803.                         EsUnselect( out, p_sys->es[i],
  804.                                     p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
  805.                 }
  806.             }
  807.             else
  808.             {
  809.                 for( i = 0; i < p_sys->i_es; i++ )
  810.                 {
  811.                     if( es == p_sys->es[i] )
  812.                     {
  813.                         EsOutSelect( out, es, VLC_TRUE );
  814.                         break;
  815.                     }
  816.                 }
  817.             }
  818.             return VLC_SUCCESS;
  819.         case ES_OUT_SET_PCR:
  820.         case ES_OUT_SET_GROUP_PCR:
  821.         {
  822.             es_out_pgrm_t *p_pgrm = NULL;
  823.             int            i_group = 0;
  824.             int64_t        i_pcr;
  825.             if( i_query == ES_OUT_SET_PCR )
  826.             {
  827.                 p_pgrm = p_sys->p_pgrm;
  828.             }
  829.             else
  830.             {
  831.                 int i;
  832.                 i_group = (int)va_arg( args, int );
  833.                 for( i = 0; i < p_sys->i_pgrm; i++ )
  834.                 {
  835.                     if( p_sys->pgrm[i]->i_id == i_group )
  836.                     {
  837.                         p_pgrm = p_sys->pgrm[i];
  838.                         break;
  839.                     }
  840.                 }
  841.             }
  842.             if( p_pgrm == NULL )
  843.                 p_pgrm = EsOutProgramAdd( out, i_group );   /* Create it */
  844.             i_pcr = (int64_t)va_arg( args, int64_t );
  845.             /* search program */
  846.             /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
  847.             input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
  848.                                (i_pcr + 11 ) * 9 / 100);
  849.             return VLC_SUCCESS;
  850.         }
  851.         case ES_OUT_RESET_PCR:
  852.             for( i = 0; i < p_sys->i_pgrm; i++ )
  853.             {
  854.                 p_sys->pgrm[i]->clock.i_synchro_state =  SYNCHRO_REINIT;
  855.                 p_sys->pgrm[i]->clock.last_pts = 0;
  856.             }
  857.             return VLC_SUCCESS;
  858.         case ES_OUT_GET_TS:
  859.             if( p_sys->p_pgrm )
  860.             {
  861.                 int64_t i_ts = (int64_t)va_arg( args, int64_t );
  862.                 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
  863.                 *pi_ts = input_ClockGetTS( p_sys->p_input,
  864.                                            &p_sys->p_pgrm->clock,
  865.                                            ( i_ts + 11 ) * 9 / 100 );
  866.                 return VLC_SUCCESS;
  867.             }
  868.             return VLC_EGENERIC;
  869.         case ES_OUT_GET_GROUP:
  870.             pi = (int*) va_arg( args, int* );
  871.             if( p_sys->p_pgrm )
  872.                 *pi = p_sys->p_pgrm->i_id;
  873.             else
  874.                 *pi = -1;    /* FIXME */
  875.             return VLC_SUCCESS;
  876.         case ES_OUT_SET_GROUP:
  877.         {
  878.             int j;
  879.             i = (int) va_arg( args, int );
  880.             for( j = 0; j < p_sys->i_pgrm; j++ )
  881.             {
  882.                 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
  883.                 if( p_pgrm->i_id == i )
  884.                 {
  885.                     EsOutProgramSelect( out, p_pgrm );
  886.                     return VLC_SUCCESS;
  887.                 }
  888.             }
  889.             return VLC_EGENERIC;
  890.         }
  891.         case ES_OUT_SET_FMT:
  892.         {
  893.             /* This ain't pretty but is need by some demuxers (eg. Ogg )
  894.              * to update the p_extra data */
  895.             es_format_t *p_fmt;
  896.             es = (es_out_id_t*) va_arg( args, es_out_id_t * );
  897.             p_fmt = (es_format_t*) va_arg( args, es_format_t * );
  898.             if( es == NULL ) return VLC_EGENERIC;
  899.             if( p_fmt->i_extra )
  900.             {
  901.                 es->fmt.i_extra = p_fmt->i_extra;
  902.                 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
  903.                 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
  904.                 if( !es->p_dec ) return VLC_SUCCESS;
  905.                 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
  906.                 es->p_dec->fmt_in.p_extra =
  907.                     realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
  908.                 memcpy( es->p_dec->fmt_in.p_extra,
  909.                         p_fmt->p_extra, p_fmt->i_extra );
  910.             }
  911.             return VLC_SUCCESS;
  912.         }
  913.         default:
  914.             msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
  915.             return VLC_EGENERIC;
  916.     }
  917. }
  918. /****************************************************************************
  919.  * LanguageGetName: try to expend iso639 into plain name
  920.  ****************************************************************************/
  921. static char *LanguageGetName( const char *psz_code )
  922. {
  923.     const iso639_lang_t *pl;
  924.     if( psz_code == NULL )
  925.     {
  926.         return strdup( "" );
  927.     }
  928.     if( strlen( psz_code ) == 2 )
  929.     {
  930.         pl = GetLang_1( psz_code );
  931.     }
  932.     else if( strlen( psz_code ) == 3 )
  933.     {
  934.         pl = GetLang_2B( psz_code );
  935.         if( !strcmp( pl->psz_iso639_1, "??" ) )
  936.         {
  937.             pl = GetLang_2T( psz_code );
  938.         }
  939.     }
  940.     else
  941.     {
  942.         return strdup( psz_code );
  943.     }
  944.     if( !strcmp( pl->psz_iso639_1, "??" ) )
  945.     {
  946.        return strdup( psz_code );
  947.     }
  948.     else
  949.     {
  950.         if( *pl->psz_native_name )
  951.         {
  952.             return strdup( pl->psz_native_name );
  953.         }
  954.         return strdup( pl->psz_eng_name );
  955.     }
  956. }
  957. /****************************************************************************
  958.  * EsOutAddInfo:
  959.  * - add meta info to the playlist item
  960.  ****************************************************************************/
  961. static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
  962. {
  963.     es_out_sys_t   *p_sys = out->p_sys;
  964.     input_thread_t *p_input = p_sys->p_input;
  965.     es_format_t    *fmt = &es->fmt;
  966.     char           *psz_cat;
  967.     /* Add stream info */
  968.     asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
  969.     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
  970.                    "%.4s", (char*)&fmt->i_codec );
  971.     input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
  972.                    "%s", es->psz_language );
  973.     /* Add information */
  974.     switch( fmt->i_cat )
  975.     {
  976.     case AUDIO_ES:
  977.         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
  978.                        _("Type"), _("Audio") );
  979.         if( fmt->audio.i_channels > 0 )
  980.             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
  981.                            "%d", fmt->audio.i_channels );
  982.         if( fmt->audio.i_rate > 0 )
  983.             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
  984.                            _("%d Hz"), fmt->audio.i_rate );
  985.         if( fmt->audio.i_bitspersample > 0 )
  986.             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
  987.                            _("Bits per sample"), "%d",
  988.                            fmt->audio.i_bitspersample );
  989.         if( fmt->i_bitrate > 0 )
  990.             input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
  991.                            _("%d kb/s"), fmt->i_bitrate / 1000 );
  992.         break;
  993.     case VIDEO_ES:
  994.         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
  995.                        _("Type"), _("Video") );
  996.         if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
  997.             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
  998.                            _("Resolution"), "%dx%d",
  999.                            fmt->video.i_width, fmt->video.i_height );
  1000.         if( fmt->video.i_visible_width > 0 &&
  1001.             fmt->video.i_visible_height > 0 )
  1002.             input_Control( p_input, INPUT_ADD_INFO, psz_cat,
  1003.                            _("Display resolution"), "%dx%d",
  1004.                            fmt->video.i_visible_width,
  1005.                            fmt->video.i_visible_height);
  1006.         break;
  1007.     case SPU_ES:
  1008.         input_Control( p_input, INPUT_ADD_INFO, psz_cat,
  1009.                        _("Type"), _("Subtitle") );
  1010.         break;
  1011.     default:
  1012.         break;
  1013.     }
  1014.     free( psz_cat );
  1015. }