1 /*****************************************************************************
2 * es_out.c: Es Out handler for input.
3 *****************************************************************************
4 * Copyright (C) 2003-2004 VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
30 #include <vlc/input.h>
31 #include <vlc/decoder.h>
33 #include "input_internal.h"
35 #include "vlc_playlist.h"
37 /* FIXME we should find a better way than including that */
38 #include "../misc/iso-639_def.h"
40 /*****************************************************************************
42 *****************************************************************************/
48 /* Number of es for this pgrm */
51 vlc_bool_t b_selected;
53 /* Clock for this program */
62 es_out_pgrm_t *p_pgrm;
64 /* Channel in the track type */
68 char *psz_language_code;
74 input_thread_t *p_input;
79 es_out_pgrm_t **pp_selected_pgrm; /* --programs */
80 es_out_pgrm_t *p_pgrm; /* Master program */
99 char **ppsz_audio_language;
100 char **ppsz_sub_language;
102 /* current main es */
103 es_out_id_t *p_es_audio;
104 es_out_id_t *p_es_video;
105 es_out_id_t *p_es_sub;
108 int64_t i_audio_delay;
112 static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );
113 static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
114 static void EsOutDel ( es_out_t *, es_out_id_t * );
115 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
116 static int EsOutControl( es_out_t *, int i_query, va_list );
118 static void EsOutAddInfo( es_out_t *, es_out_id_t *es );
120 static void EsSelect( es_out_t *out, es_out_id_t *es );
121 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
122 static char *LanguageGetName( const char *psz_code );
123 static char *LanguageGetCode( const char *psz_lang );
124 static char **LanguageSplit( const char *psz_langs );
125 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
127 /*****************************************************************************
129 *****************************************************************************/
130 es_out_t *input_EsOutNew( input_thread_t *p_input )
132 es_out_t *out = malloc( sizeof( es_out_t ) );
133 es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
137 out->pf_add = EsOutAdd;
138 out->pf_send = EsOutSend;
139 out->pf_del = EsOutDel;
140 out->pf_control = EsOutControl;
143 p_sys->p_input = p_input;
145 p_sys->b_active = VLC_FALSE;
146 p_sys->i_mode = ES_OUT_MODE_AUTO;
151 p_sys->p_pgrm = NULL;
162 var_Get( p_input, "audio-track", &val );
163 p_sys->i_audio_last = val.i_int;
165 var_Get( p_input, "spu-track", &val );
166 p_sys->i_sub_last = val.i_int;
168 var_Get( p_input, "audio-language", &val );
169 p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
170 if( p_sys->ppsz_audio_language )
172 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
173 msg_Dbg( p_input, "Select audio in language[%d] %s",
174 i, p_sys->ppsz_audio_language[i] );
177 var_Get( p_input, "spu-language", &val );
178 p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
179 if( p_sys->ppsz_sub_language )
181 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
182 msg_Dbg( p_input, "Select subtitle in language[%d] %s",
183 i, p_sys->ppsz_sub_language[i] );
187 p_sys->p_es_audio = NULL;
188 p_sys->p_es_video = NULL;
189 p_sys->p_es_sub = NULL;
191 p_sys->i_audio_delay= 0;
192 p_sys->i_spu_delay = 0;
197 /*****************************************************************************
199 *****************************************************************************/
200 void input_EsOutDelete( es_out_t *out )
202 es_out_sys_t *p_sys = out->p_sys;
205 for( i = 0; i < p_sys->i_es; i++ )
207 if( p_sys->es[i]->p_dec )
209 input_DecoderDelete( p_sys->es[i]->p_dec );
211 if( p_sys->es[i]->psz_language )
212 free( p_sys->es[i]->psz_language );
213 if( p_sys->es[i]->psz_language_code )
214 free( p_sys->es[i]->psz_language_code );
215 es_format_Clean( &p_sys->es[i]->fmt );
217 free( p_sys->es[i] );
219 if( p_sys->ppsz_audio_language )
221 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
222 free( p_sys->ppsz_audio_language[i] );
223 free( p_sys->ppsz_audio_language );
225 if( p_sys->ppsz_sub_language )
227 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
228 free( p_sys->ppsz_sub_language[i] );
229 free( p_sys->ppsz_sub_language );
235 for( i = 0; i < p_sys->i_pgrm; i++ )
237 free( p_sys->pgrm[i] );
246 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
251 /* Special HACK, -i_id is tha cat of the stream */
252 return (es_out_id_t*)((uint8_t*)NULL-i_id);
255 for( i = 0; i < out->p_sys->i_es; i++ )
257 if( out->p_sys->es[i]->i_id == i_id )
258 return out->p_sys->es[i];
263 void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
265 es_out_sys_t *p_sys = out->p_sys;
268 for( i = 0; i < p_sys->i_es; i++ )
270 es_out_id_t *es = p_sys->es[i];
272 /* Send a dummy block to let decoder know that
273 * there is a discontinuity */
274 if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
276 input_DecoderDiscontinuity( es->p_dec );
281 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
283 es_out_sys_t *p_sys = out->p_sys;
285 if( i_cat == AUDIO_ES )
286 p_sys->i_audio_delay = i_delay;
287 else if( i_cat == SPU_ES )
288 p_sys->i_spu_delay = i_delay;
291 vlc_bool_t input_EsOutDecodersEmpty( es_out_t *out )
293 es_out_sys_t *p_sys = out->p_sys;
296 for( i = 0; i < p_sys->i_es; i++ )
298 es_out_id_t *es = p_sys->es[i];
300 if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
306 /*****************************************************************************
308 *****************************************************************************/
309 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
310 vlc_bool_t b_delete )
312 es_out_sys_t *p_sys = out->p_sys;
313 input_thread_t *p_input = p_sys->p_input;
314 vlc_value_t val, text;
318 if( es->fmt.i_cat == AUDIO_ES )
319 psz_var = "audio-es";
320 else if( es->fmt.i_cat == VIDEO_ES )
321 psz_var = "video-es";
322 else if( es->fmt.i_cat == SPU_ES )
329 val.i_int = es->i_id;
330 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
331 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
335 /* Get the number of ES already added */
336 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
341 /* First one, we need to add the "Disable" choice */
342 val2.i_int = -1; text.psz_string = _("Disable");
343 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
347 /* Take care of the ES description */
348 if( es->fmt.psz_description && *es->fmt.psz_description )
350 if( es->psz_language && *es->psz_language )
352 text.psz_string = malloc( strlen( es->fmt.psz_description) + strlen( es->psz_language ) + 10 );
353 sprintf( text.psz_string, "%s - [%s]", es->fmt.psz_description, es->psz_language );
355 else text.psz_string = strdup( es->fmt.psz_description );
359 if( es->psz_language && *es->psz_language )
362 text.psz_string = malloc( strlen( _("Track %i") )+ strlen( es->psz_language ) + 30 );
363 asprintf( &temp, _("Track %i"), val.i_int );
364 sprintf( text.psz_string, "%s - [%s]", temp, es->psz_language );
369 text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
370 sprintf( text.psz_string, _("Track %i"), val.i_int );
374 val.i_int = es->i_id;
375 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
377 free( text.psz_string );
379 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
382 /* EsOutProgramSelect:
383 * Select a program and update the object variable
385 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
387 es_out_sys_t *p_sys = out->p_sys;
388 input_thread_t *p_input = p_sys->p_input;
392 if( p_sys->p_pgrm == p_pgrm )
393 return; /* Nothing to do */
397 es_out_pgrm_t *old = p_sys->p_pgrm;
398 msg_Dbg( p_input, "Unselecting program id=%d", old->i_id );
400 for( i = 0; i < p_sys->i_es; i++ )
402 if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
403 p_sys->i_mode != ES_OUT_MODE_ALL )
404 EsUnselect( out, p_sys->es[i], VLC_TRUE );
407 p_sys->p_es_audio = NULL;
408 p_sys->p_es_sub = NULL;
409 p_sys->p_es_video = NULL;
412 msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id );
414 /* Mark it selected */
415 p_pgrm->b_selected = VLC_TRUE;
417 /* Switch master stream */
418 if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
420 p_sys->p_pgrm->clock.b_master = VLC_FALSE;
422 p_pgrm->clock.b_master = VLC_TRUE;
423 p_sys->p_pgrm = p_pgrm;
425 /* Update "program" */
426 val.i_int = p_pgrm->i_id;
427 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
430 var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
431 var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
432 var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
433 for( i = 0; i < p_sys->i_es; i++ )
435 if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
436 EsOutESVarUpdate( out, p_sys->es[i], VLC_FALSE );
437 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
440 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
446 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
448 es_out_sys_t *p_sys = out->p_sys;
449 input_thread_t *p_input = p_sys->p_input;
452 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
455 p_pgrm->i_id = i_group;
457 p_pgrm->b_selected = VLC_FALSE;
458 input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
461 TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
463 /* Update "program" variable */
465 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
467 if( i_group == var_GetInteger( p_input, "program" ) )
469 EsOutProgramSelect( out, p_pgrm );
473 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
481 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
483 es_out_sys_t *p_sys = out->p_sys;
484 input_thread_t *p_input = p_sys->p_input;
486 es_out_id_t *es = malloc( sizeof( es_out_id_t ) );
487 es_out_pgrm_t *p_pgrm = NULL;
490 if( fmt->i_group < 0 )
492 msg_Err( p_input, "invalid group number" );
496 /* Search the program */
497 for( i = 0; i < p_sys->i_pgrm; i++ )
499 if( fmt->i_group == p_sys->pgrm[i]->i_id )
501 p_pgrm = p_sys->pgrm[i];
507 /* Create a new one */
508 p_pgrm = EsOutProgramAdd( out, fmt->i_group );
511 /* Increase ref count for program */
516 fmt->i_id = out->p_sys->i_id;
517 es->i_id = fmt->i_id;
519 es_format_Copy( &es->fmt, fmt );
523 es->i_channel = p_sys->i_audio;
527 es->i_channel = p_sys->i_video;
531 es->i_channel = p_sys->i_sub;
538 es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
539 es->psz_language_code = LanguageGetCode( fmt->psz_language );
542 if( es->p_pgrm == p_sys->p_pgrm )
543 EsOutESVarUpdate( out, es, VLC_FALSE );
545 /* Select it if needed */
546 EsOutSelect( out, es, VLC_FALSE );
549 TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
550 p_sys->i_id++; /* always incremented */
564 EsOutAddInfo( out, es );
569 static void EsSelect( es_out_t *out, es_out_id_t *es )
571 es_out_sys_t *p_sys = out->p_sys;
572 input_thread_t *p_input = p_sys->p_input;
578 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
582 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
584 if( !var_GetBool( p_input, "video" ) ||
585 ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
587 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
592 else if( es->fmt.i_cat == AUDIO_ES )
594 var_Get( p_input, "audio", &val );
595 if( !var_GetBool( p_input, "audio" ) ||
596 ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
598 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
604 es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
605 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
608 if( es->fmt.i_cat == VIDEO_ES )
609 psz_var = "video-es";
610 else if( es->fmt.i_cat == AUDIO_ES )
611 psz_var = "audio-es";
612 else if( es->fmt.i_cat == SPU_ES )
617 /* Mark it as selected */
618 val.i_int = es->i_id;
619 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
622 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
625 static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
627 es_out_sys_t *p_sys = out->p_sys;
628 input_thread_t *p_input = p_sys->p_input;
632 if( es->p_dec == NULL )
634 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
638 input_DecoderDelete( es->p_dec );
645 if( es->p_dec == NULL )
647 if( es->fmt.i_cat == VIDEO_ES )
648 psz_var = "video-es";
649 else if( es->fmt.i_cat == AUDIO_ES )
650 psz_var = "audio-es";
651 else if( es->fmt.i_cat == SPU_ES )
656 /* Mark it as selected */
658 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
660 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
664 * Select an ES given the current mode
665 * XXX: you need to take a the lock before (stream.stream_lock)
667 * \param out The es_out structure
668 * \param es es_out_id structure
672 static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
674 es_out_sys_t *p_sys = out->p_sys;
676 int i_cat = es->fmt.i_cat;
678 if( !p_sys->b_active ||
679 ( !b_force && es->fmt.i_priority < 0 ) )
684 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
689 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
693 var_Get( p_sys->p_input, "programs", &val );
694 for ( i = 0; i < val.p_list->i_count; i++ )
696 if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
703 var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
705 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
709 if( es->p_pgrm != p_sys->p_pgrm )
712 if( i_cat == AUDIO_ES )
714 int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
715 es->psz_language_code );
717 if( p_sys->p_es_audio &&
718 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
720 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
721 p_sys->p_es_audio->psz_language_code );
723 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
725 i_wanted = es->i_channel;
729 /* Select audio if (no audio selected yet)
730 * - no audio-language
731 * - no audio code for the ES
732 * - audio code in the requested list */
734 !strcmp( es->psz_language_code, "??" ) ||
735 !p_sys->ppsz_audio_language )
736 i_wanted = es->i_channel;
739 if( p_sys->i_audio_last >= 0 )
740 i_wanted = p_sys->i_audio_last;
742 else if( i_cat == SPU_ES )
744 int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
745 es->psz_language_code );
747 if( p_sys->p_es_sub &&
748 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
750 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
751 p_sys->p_es_sub->psz_language_code );
753 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
754 idx1, es->psz_language_code, idx2,
755 p_sys->p_es_sub->psz_language_code );
757 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
759 /* We found a SPU that matches our language request */
760 i_wanted = es->i_channel;
764 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
765 idx1, es->psz_language_code );
767 i_wanted = es->i_channel;
769 if( p_sys->i_sub_last >= 0 )
770 i_wanted = p_sys->i_sub_last;
772 else if( i_cat == VIDEO_ES )
774 i_wanted = es->i_channel;
777 if( i_wanted == es->i_channel && es->p_dec == NULL )
781 /* FIXME TODO handle priority here */
784 if( i_cat == AUDIO_ES )
786 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
788 p_sys->p_es_audio != es &&
789 p_sys->p_es_audio->p_dec )
791 EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
793 p_sys->p_es_audio = es;
795 else if( i_cat == SPU_ES )
797 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
799 p_sys->p_es_sub != es &&
800 p_sys->p_es_sub->p_dec )
802 EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
804 p_sys->p_es_sub = es;
806 else if( i_cat == VIDEO_ES )
808 p_sys->p_es_video = es;
814 * Send a block for the given es_out
816 * \param out the es_out to send from
817 * \param es the es_out_id
818 * \param p_block the data block to send
820 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
822 es_out_sys_t *p_sys = out->p_sys;
823 input_thread_t *p_input = p_sys->p_input;
824 es_out_pgrm_t *p_pgrm = es->p_pgrm;
827 if( es->fmt.i_cat == AUDIO_ES )
828 i_delay = p_sys->i_audio_delay;
829 else if( es->fmt.i_cat == SPU_ES )
830 i_delay = p_sys->i_spu_delay;
834 /* +11 -> avoid null value with non null dts/pts */
835 if( p_block->i_dts > 0 )
838 input_ClockGetTS( p_input, &p_pgrm->clock,
839 ( p_block->i_dts + 11 ) * 9 / 100 ) + i_delay;
841 if( p_block->i_pts > 0 )
844 input_ClockGetTS( p_input, &p_pgrm->clock,
845 ( p_block->i_pts + 11 ) * 9 / 100 ) + i_delay;
847 if ( es->fmt.i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' ) )
849 mtime_t current_date = mdate();
851 || p_block->i_pts > current_date + 10000000
852 || current_date > p_block->i_pts )
854 /* ETSI EN 300 472 Annex A : do not take into account the PTS
855 * for teletext streams. */
856 p_block->i_pts = current_date + 400000
857 + p_input->i_pts_delay + i_delay;
861 p_block->i_rate = p_input->i_rate;
863 /* TODO handle mute */
864 if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES ||
865 p_input->i_rate == INPUT_RATE_DEFAULT ) )
867 input_DecoderDecode( es->p_dec, p_block );
871 block_Release( p_block );
877 /*****************************************************************************
879 *****************************************************************************/
880 static void EsOutDel( es_out_t *out, es_out_id_t *es )
882 es_out_sys_t *p_sys = out->p_sys;
884 /* We don't try to reselect */
886 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
888 if( es->p_pgrm == p_sys->p_pgrm )
889 EsOutESVarUpdate( out, es, VLC_TRUE );
891 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
894 if( es->p_pgrm->i_es == 0 )
896 msg_Warn( p_sys->p_input, "Program doesn't contain anymore ES, "
900 if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
901 if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
902 if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
904 switch( es->fmt.i_cat )
917 if( es->psz_language )
918 free( es->psz_language );
919 if( es->psz_language_code )
920 free( es->psz_language_code );
922 es_format_Clean( &es->fmt );
928 * Control query handler
930 * \param out the es_out to control
931 * \param i_query A es_out query as defined in include/ninput.h
932 * \param args a variable list of arguments for the query
933 * \return VLC_SUCCESS or an error code
935 static int EsOutControl( es_out_t *out, int i_query, va_list args )
937 es_out_sys_t *p_sys = out->p_sys;
945 case ES_OUT_SET_ES_STATE:
946 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
947 b = (vlc_bool_t) va_arg( args, vlc_bool_t );
948 if( b && es->p_dec == NULL )
951 return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
953 else if( !b && es->p_dec )
955 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
960 case ES_OUT_GET_ES_STATE:
961 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
962 pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
964 *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
967 case ES_OUT_SET_ACTIVE:
969 b = (vlc_bool_t) va_arg( args, vlc_bool_t );
973 var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
977 case ES_OUT_GET_ACTIVE:
978 pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
979 *pb = p_sys->b_active;
982 case ES_OUT_SET_MODE:
983 i = (int) va_arg( args, int );
984 if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
985 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
989 /* Reapply policy mode */
990 for( i = 0; i < p_sys->i_es; i++ )
992 if( p_sys->es[i]->p_dec )
994 EsUnselect( out, p_sys->es[i],
995 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
998 for( i = 0; i < p_sys->i_es; i++ )
1000 EsOutSelect( out, p_sys->es[i], VLC_FALSE );
1004 return VLC_EGENERIC;
1006 case ES_OUT_GET_MODE:
1007 pi = (int*) va_arg( args, int* );
1008 *pi = p_sys->i_mode;
1012 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1013 /* Special case NULL, NULL+i_cat */
1016 for( i = 0; i < p_sys->i_es; i++ )
1018 if( p_sys->es[i]->p_dec )
1019 EsUnselect( out, p_sys->es[i],
1020 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1023 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1025 for( i = 0; i < p_sys->i_es; i++ )
1027 if( p_sys->es[i]->p_dec &&
1028 p_sys->es[i]->fmt.i_cat == AUDIO_ES )
1029 EsUnselect( out, p_sys->es[i],
1030 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1033 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1035 for( i = 0; i < p_sys->i_es; i++ )
1037 if( p_sys->es[i]->p_dec &&
1038 p_sys->es[i]->fmt.i_cat == VIDEO_ES )
1039 EsUnselect( out, p_sys->es[i],
1040 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1043 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1045 for( i = 0; i < p_sys->i_es; i++ )
1047 if( p_sys->es[i]->p_dec &&
1048 p_sys->es[i]->fmt.i_cat == SPU_ES )
1049 EsUnselect( out, p_sys->es[i],
1050 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1055 for( i = 0; i < p_sys->i_es; i++ )
1057 if( es == p_sys->es[i] )
1059 EsOutSelect( out, es, VLC_TRUE );
1066 case ES_OUT_SET_PCR:
1067 case ES_OUT_SET_GROUP_PCR:
1069 es_out_pgrm_t *p_pgrm = NULL;
1073 if( i_query == ES_OUT_SET_PCR )
1075 p_pgrm = p_sys->p_pgrm;
1080 i_group = (int)va_arg( args, int );
1081 for( i = 0; i < p_sys->i_pgrm; i++ )
1083 if( p_sys->pgrm[i]->i_id == i_group )
1085 p_pgrm = p_sys->pgrm[i];
1090 if( p_pgrm == NULL )
1091 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
1093 i_pcr = (int64_t)va_arg( args, int64_t );
1094 /* search program */
1095 /* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
1096 input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock,
1097 (i_pcr + 11 ) * 9 / 100);
1101 case ES_OUT_RESET_PCR:
1102 for( i = 0; i < p_sys->i_pgrm; i++ )
1104 p_sys->pgrm[i]->clock.i_synchro_state = SYNCHRO_REINIT;
1105 p_sys->pgrm[i]->clock.last_pts = 0;
1112 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1113 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1114 *pi_ts = input_ClockGetTS( p_sys->p_input,
1115 &p_sys->p_pgrm->clock,
1116 ( i_ts + 11 ) * 9 / 100 );
1119 return VLC_EGENERIC;
1121 case ES_OUT_GET_GROUP:
1122 pi = (int*) va_arg( args, int* );
1124 *pi = p_sys->p_pgrm->i_id;
1126 *pi = -1; /* FIXME */
1129 case ES_OUT_SET_GROUP:
1132 i = (int) va_arg( args, int );
1133 for( j = 0; j < p_sys->i_pgrm; j++ )
1135 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1136 if( p_pgrm->i_id == i )
1138 EsOutProgramSelect( out, p_pgrm );
1142 return VLC_EGENERIC;
1145 case ES_OUT_SET_FMT:
1147 /* This ain't pretty but is need by some demuxers (eg. Ogg )
1148 * to update the p_extra data */
1150 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1151 p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1152 if( es == NULL ) return VLC_EGENERIC;
1154 if( p_fmt->i_extra )
1156 es->fmt.i_extra = p_fmt->i_extra;
1157 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1158 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1160 if( !es->p_dec ) return VLC_SUCCESS;
1162 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1163 es->p_dec->fmt_in.p_extra =
1164 realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1165 memcpy( es->p_dec->fmt_in.p_extra,
1166 p_fmt->p_extra, p_fmt->i_extra );
1173 msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
1174 return VLC_EGENERIC;
1178 /****************************************************************************
1179 * LanguageGetName: try to expend iso639 into plain name
1180 ****************************************************************************/
1181 static char *LanguageGetName( const char *psz_code )
1183 const iso639_lang_t *pl;
1185 if( psz_code == NULL )
1187 return strdup( "" );
1190 if( strlen( psz_code ) == 2 )
1192 pl = GetLang_1( psz_code );
1194 else if( strlen( psz_code ) == 3 )
1196 pl = GetLang_2B( psz_code );
1197 if( !strcmp( pl->psz_iso639_1, "??" ) )
1199 pl = GetLang_2T( psz_code );
1204 return strdup( psz_code );
1207 if( !strcmp( pl->psz_iso639_1, "??" ) )
1209 return strdup( psz_code );
1213 if( *pl->psz_native_name )
1215 return strdup( pl->psz_native_name );
1217 return strdup( pl->psz_eng_name );
1221 /* Get a 2 char code */
1222 static char *LanguageGetCode( const char *psz_lang )
1224 const iso639_lang_t *pl;
1226 if( psz_lang == NULL || *psz_lang == '\0' )
1227 return strdup("??");
1229 for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
1231 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
1232 !strcasecmp( pl->psz_native_name, psz_lang ) ||
1233 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
1234 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
1235 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
1239 if( pl->psz_iso639_1 != NULL )
1240 return strdup( pl->psz_iso639_1 );
1242 return strdup("??");
1245 static char **LanguageSplit( const char *psz_langs )
1252 if( psz_langs == NULL )
1255 psz_parser = psz_dup = strdup(psz_langs);
1257 while( psz_parser && *psz_parser )
1262 psz = strchr(psz_parser, ',' );
1268 psz_code = LanguageGetCode( psz_parser );
1269 if( strcmp( psz_code, "??" ) )
1271 TAB_APPEND( i_psz, ppsz, psz_code );
1279 TAB_APPEND( i_psz, ppsz, NULL );
1285 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
1289 if( !ppsz_langs || !psz_lang )
1292 for( i = 0; ppsz_langs[i]; i++ )
1293 if( !strcasecmp( ppsz_langs[i], psz_lang ) )
1299 /****************************************************************************
1301 * - add meta info to the playlist item
1302 ****************************************************************************/
1303 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
1305 es_out_sys_t *p_sys = out->p_sys;
1306 input_thread_t *p_input = p_sys->p_input;
1307 es_format_t *fmt = &es->fmt;
1310 /* Add stream info */
1311 asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
1313 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
1314 "%.4s", (char*)&fmt->i_codec );
1316 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
1317 "%s", es->psz_language );
1319 /* Add information */
1320 switch( fmt->i_cat )
1323 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1324 _("Type"), _("Audio") );
1326 if( fmt->audio.i_channels > 0 )
1327 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
1328 "%d", fmt->audio.i_channels );
1330 if( fmt->audio.i_rate > 0 )
1331 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
1332 _("%d Hz"), fmt->audio.i_rate );
1334 if( fmt->audio.i_bitspersample > 0 )
1335 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1336 _("Bits per sample"), "%d",
1337 fmt->audio.i_bitspersample );
1339 if( fmt->i_bitrate > 0 )
1340 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
1341 _("%d kb/s"), fmt->i_bitrate / 1000 );
1345 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1346 _("Type"), _("Video") );
1348 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
1349 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1350 _("Resolution"), "%dx%d",
1351 fmt->video.i_width, fmt->video.i_height );
1353 if( fmt->video.i_visible_width > 0 &&
1354 fmt->video.i_visible_height > 0 )
1355 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1356 _("Display resolution"), "%dx%d",
1357 fmt->video.i_visible_width,
1358 fmt->video.i_visible_height);
1362 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1363 _("Type"), _("Subtitle") );