1 /*****************************************************************************
2 * es_out.c: Es Out handler for input.
3 *****************************************************************************
4 * Copyright (C) 2003-2004 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
34 #include <vlc_common.h>
36 #include <vlc_input.h>
37 #include <vlc_es_out.h>
38 #include <vlc_block.h>
41 #include "input_internal.h"
42 #include "input_decoder.h"
44 #include "../stream_output/stream_output.h"
46 #include <vlc_iso_lang.h>
47 /* FIXME we should find a better way than including that */
48 #include "../text/iso-639_def.h"
50 /*****************************************************************************
52 *****************************************************************************/
58 /* Number of es for this pgrm */
63 /* Clock for this program */
64 input_clock_t *p_clock;
67 char *psz_now_playing;
77 es_out_pgrm_t *p_pgrm;
80 int64_t i_preroll_end;
82 /* Channel in the track type */
86 char *psz_language_code;
89 decoder_t *p_dec_record;
91 /* Fields for Video with CC */
92 bool pb_cc_present[4];
93 es_out_id_t *pp_cc_es[4];
95 /* Field for CC track from a master video */
96 es_out_id_t *p_master;
101 input_thread_t *p_input;
105 es_out_pgrm_t **pgrm;
106 es_out_pgrm_t **pp_selected_pgrm; /* --programs */
107 es_out_pgrm_t *p_pgrm; /* Master program */
124 int i_audio_last, i_audio_id;
125 int i_sub_last, i_sub_id;
126 int i_default_sub_id; /* As specified in container; if applicable */
127 char **ppsz_audio_language;
128 char **ppsz_sub_language;
130 /* current main es */
131 es_out_id_t *p_es_audio;
132 es_out_id_t *p_es_video;
133 es_out_id_t *p_es_sub;
136 int64_t i_audio_delay;
139 /* Rate used for clock */
143 sout_instance_t *p_sout_record;
146 static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );
147 static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
148 static void EsOutDel ( es_out_t *, es_out_id_t * );
149 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force );
150 static int EsOutControl( es_out_t *, int i_query, va_list );
152 static void EsOutAddInfo( es_out_t *, es_out_id_t *es );
154 static bool EsIsSelected( es_out_id_t *es );
155 static void EsSelect( es_out_t *out, es_out_id_t *es );
156 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update );
157 static char *LanguageGetName( const char *psz_code );
158 static char *LanguageGetCode( const char *psz_lang );
159 static char **LanguageSplit( const char *psz_langs );
160 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang );
162 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
164 static const vlc_fourcc_t EsOutFourccClosedCaptions[4] = {
165 VLC_FOURCC('c', 'c', '1', ' '),
166 VLC_FOURCC('c', 'c', '2', ' '),
167 VLC_FOURCC('c', 'c', '3', ' '),
168 VLC_FOURCC('c', 'c', '4', ' '),
170 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc )
173 for( i = 0; i < 4; i++ )
175 if( fcc == EsOutFourccClosedCaptions[i] )
182 /*****************************************************************************
184 *****************************************************************************/
185 es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
190 es_out_t *out = malloc( sizeof( es_out_t ) );
191 if( !out ) return NULL;
193 es_out_sys_t *p_sys = malloc( sizeof( es_out_sys_t ) );
200 out->pf_add = EsOutAdd;
201 out->pf_send = EsOutSend;
202 out->pf_del = EsOutDel;
203 out->pf_control = EsOutControl;
205 out->b_sout = p_input->p->p_sout != NULL;
207 p_sys->p_input = p_input;
209 p_sys->b_active = false;
210 p_sys->i_mode = ES_OUT_MODE_AUTO;
213 TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
214 p_sys->p_pgrm = NULL;
218 TAB_INIT( p_sys->i_es, p_sys->es );
225 var_Get( p_input, "audio-track", &val );
226 p_sys->i_audio_last = val.i_int;
228 var_Get( p_input, "sub-track", &val );
229 p_sys->i_sub_last = val.i_int;
231 p_sys->i_default_sub_id = -1;
233 if( !p_input->b_preparsing )
235 var_Get( p_input, "audio-language", &val );
236 p_sys->ppsz_audio_language = LanguageSplit(val.psz_string);
237 if( p_sys->ppsz_audio_language )
239 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
240 msg_Dbg( p_input, "selected audio language[%d] %s",
241 i, p_sys->ppsz_audio_language[i] );
243 free( val.psz_string );
245 var_Get( p_input, "sub-language", &val );
246 p_sys->ppsz_sub_language = LanguageSplit(val.psz_string);
247 if( p_sys->ppsz_sub_language )
249 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
250 msg_Dbg( p_input, "selected subtitle language[%d] %s",
251 i, p_sys->ppsz_sub_language[i] );
253 free( val.psz_string );
257 p_sys->ppsz_sub_language = NULL;
258 p_sys->ppsz_audio_language = NULL;
261 var_Get( p_input, "audio-track-id", &val );
262 p_sys->i_audio_id = val.i_int;
264 var_Get( p_input, "sub-track-id", &val );
265 p_sys->i_sub_id = val.i_int;
267 p_sys->p_es_audio = NULL;
268 p_sys->p_es_video = NULL;
269 p_sys->p_es_sub = NULL;
271 p_sys->i_audio_delay= 0;
272 p_sys->i_spu_delay = 0;
274 p_sys->i_rate = i_rate;
276 p_sys->p_sout_record = NULL;
281 /*****************************************************************************
283 *****************************************************************************/
284 void input_EsOutDelete( es_out_t *out )
286 es_out_sys_t *p_sys = out->p_sys;
289 if( p_sys->p_sout_record )
290 input_EsOutSetRecord( out, false );
292 for( i = 0; i < p_sys->i_es; i++ )
294 if( p_sys->es[i]->p_dec )
295 input_DecoderDelete( p_sys->es[i]->p_dec );
297 free( p_sys->es[i]->psz_language );
298 free( p_sys->es[i]->psz_language_code );
299 es_format_Clean( &p_sys->es[i]->fmt );
301 free( p_sys->es[i] );
303 if( p_sys->ppsz_audio_language )
305 for( i = 0; p_sys->ppsz_audio_language[i]; i++ )
306 free( p_sys->ppsz_audio_language[i] );
307 free( p_sys->ppsz_audio_language );
309 if( p_sys->ppsz_sub_language )
311 for( i = 0; p_sys->ppsz_sub_language[i]; i++ )
312 free( p_sys->ppsz_sub_language[i] );
313 free( p_sys->ppsz_sub_language );
317 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
318 for( i = 0; i < p_sys->i_pgrm; i++ )
320 es_out_pgrm_t *p_pgrm = p_sys->pgrm[i];
321 input_clock_Delete( p_pgrm->p_clock );
322 free( p_pgrm->psz_now_playing );
323 free( p_pgrm->psz_publisher );
324 free( p_pgrm->psz_name );
326 vlc_epg_Delete( p_pgrm->p_epg );
330 TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
336 es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
341 /* Special HACK, -i_id is tha cat of the stream */
342 return (es_out_id_t*)((uint8_t*)NULL-i_id);
345 for( i = 0; i < out->p_sys->i_es; i++ )
347 if( out->p_sys->es[i]->i_id == i_id )
348 return out->p_sys->es[i];
353 mtime_t input_EsOutGetWakeup( es_out_t *out )
355 es_out_sys_t *p_sys = out->p_sys;
356 input_thread_t *p_input = p_sys->p_input;
361 /* We do not have a wake up date if the input cannot have its speed
362 * controlled or sout is imposing its own */
363 if( !p_input->b_can_pace_control || p_input->p->b_out_pace_control )
366 return input_clock_GetWakeup( p_sys->p_pgrm->p_clock );
369 static void EsOutDiscontinuity( es_out_t *out, bool b_flush, bool b_audio )
371 es_out_sys_t *p_sys = out->p_sys;
374 for( i = 0; i < p_sys->i_es; i++ )
376 es_out_id_t *es = p_sys->es[i];
378 /* Send a dummy block to let decoder know that
379 * there is a discontinuity */
380 if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
382 input_DecoderDiscontinuity( es->p_dec, b_flush );
383 if( es->p_dec_record )
384 input_DecoderDiscontinuity( es->p_dec_record, b_flush );
388 void input_EsOutChangeRate( es_out_t *out, int i_rate )
390 es_out_sys_t *p_sys = out->p_sys;
393 p_sys->i_rate = i_rate;
395 for( i = 0; i < p_sys->i_pgrm; i++ )
396 input_clock_ChangeRate( p_sys->pgrm[i]->p_clock, i_rate );
399 int input_EsOutSetRecord( es_out_t *out, bool b_record )
401 es_out_sys_t *p_sys = out->p_sys;
402 input_thread_t *p_input = p_sys->p_input;
404 assert( ( b_record && !p_sys->p_sout_record ) || ( !b_record && p_sys->p_sout_record ) );
408 char *psz_path = var_CreateGetString( p_input, "input-record-path" );
409 if( !psz_path || *psz_path == '\0' )
412 psz_path = strdup( config_GetHomeDir() );
415 char *psz_sout = NULL; // TODO conf
417 if( !psz_sout && psz_path )
419 char *psz_file = input_CreateFilename( VLC_OBJECT(p_input), psz_path, INPUT_RECORD_PREFIX, NULL );
422 if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file ) < 0 )
433 p_sys->p_sout_record = sout_NewInstance( p_input, psz_sout );
437 if( !p_sys->p_sout_record )
440 for( int i = 0; i < p_sys->i_es; i++ )
442 es_out_id_t *p_es = p_sys->es[i];
444 if( !p_es->p_dec || p_es->p_master )
447 p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
452 for( int i = 0; i < p_sys->i_es; i++ )
454 es_out_id_t *p_es = p_sys->es[i];
456 if( !p_es->p_dec_record )
459 input_DecoderDelete( p_es->p_dec_record );
460 p_es->p_dec_record = NULL;
463 sout_DeleteInstance( p_sys->p_sout_record );
465 p_sys->p_sout_record = NULL;
470 void input_EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
472 es_out_sys_t *p_sys = out->p_sys;
474 if( i_cat == AUDIO_ES )
475 p_sys->i_audio_delay = i_delay;
476 else if( i_cat == SPU_ES )
477 p_sys->i_spu_delay = i_delay;
479 void input_EsOutChangeState( es_out_t *out )
481 es_out_sys_t *p_sys = out->p_sys;
482 input_thread_t *p_input = p_sys->p_input;
484 if( p_input->i_state == PAUSE_S )
486 /* Send discontinuity to decoders (it will allow them to flush
487 * * if implemented */
488 EsOutDiscontinuity( out, false, false );
492 /* Out of pause, reset pcr */
493 es_out_Control( out, ES_OUT_RESET_PCR );
496 void input_EsOutChangePosition( es_out_t *out )
498 //es_out_sys_t *p_sys = out->p_sys;
500 es_out_Control( out, ES_OUT_RESET_PCR );
501 EsOutDiscontinuity( out, true, false );
504 bool input_EsOutDecodersEmpty( es_out_t *out )
506 es_out_sys_t *p_sys = out->p_sys;
509 for( i = 0; i < p_sys->i_es; i++ )
511 es_out_id_t *es = p_sys->es[i];
513 if( es->p_dec && !input_DecoderEmpty( es->p_dec ) )
515 if( es->p_dec_record && !input_DecoderEmpty( es->p_dec_record ) )
521 /*****************************************************************************
523 *****************************************************************************/
524 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id, es_format_t *fmt, const char *psz_language,
527 es_out_sys_t *p_sys = out->p_sys;
528 input_thread_t *p_input = p_sys->p_input;
529 const bool b_teletext = fmt->i_cat == SPU_ES && fmt->i_codec == VLC_FOURCC( 't', 'e', 'l', 'x' );
530 vlc_value_t val, text;
534 if( fmt->i_cat == AUDIO_ES )
535 psz_var = "audio-es";
536 else if( fmt->i_cat == VIDEO_ES )
537 psz_var = "video-es";
538 else if( fmt->i_cat == SPU_ES )
546 var_SetInteger( p_sys->p_input, "teletext-es", -1 );
549 var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
551 var_SetBool( p_sys->p_input, "intf-change", true );
555 /* Get the number of ES already added */
556 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
561 /* First one, we need to add the "Disable" choice */
562 val2.i_int = -1; text.psz_string = _("Disable");
563 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
567 /* Take care of the ES description */
568 if( fmt->psz_description && *fmt->psz_description )
570 if( psz_language && *psz_language )
572 text.psz_string = malloc( strlen( fmt->psz_description) +
573 strlen( psz_language ) + 10 );
574 sprintf( text.psz_string, "%s - [%s]", fmt->psz_description,
577 else text.psz_string = strdup( fmt->psz_description );
581 if( psz_language && *psz_language )
583 if( asprintf( &text.psz_string, "%s %i - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
584 text.psz_string = NULL;
588 if( asprintf( &text.psz_string, "%s %i", _( "Track" ), val.i_int ) == -1 )
589 text.psz_string = NULL;
594 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
596 free( text.psz_string );
600 if( var_GetInteger( p_sys->p_input, "teletext-es" ) < 0 )
601 var_SetInteger( p_sys->p_input, "teletext-es", i_id );
604 var_SetBool( p_sys->p_input, "intf-change", true );
607 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
610 EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
613 /* EsOutProgramSelect:
614 * Select a program and update the object variable
616 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
618 es_out_sys_t *p_sys = out->p_sys;
619 input_thread_t *p_input = p_sys->p_input;
623 if( p_sys->p_pgrm == p_pgrm )
624 return; /* Nothing to do */
628 es_out_pgrm_t *old = p_sys->p_pgrm;
629 msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
631 for( i = 0; i < p_sys->i_es; i++ )
633 if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
634 p_sys->i_mode != ES_OUT_MODE_ALL )
635 EsUnselect( out, p_sys->es[i], true );
638 p_sys->p_es_audio = NULL;
639 p_sys->p_es_sub = NULL;
640 p_sys->p_es_video = NULL;
643 msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
645 /* Mark it selected */
646 p_pgrm->b_selected = true;
648 /* Switch master stream */
649 p_sys->p_pgrm = p_pgrm;
651 /* Update "program" */
652 val.i_int = p_pgrm->i_id;
653 var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
656 var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
657 var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
658 var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
659 var_SetInteger( p_input, "teletext-es", -1 );
660 for( i = 0; i < p_sys->i_es; i++ )
662 if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
663 EsOutESVarUpdate( out, p_sys->es[i], false );
664 EsOutSelect( out, p_sys->es[i], false );
667 /* Update now playing */
668 input_item_SetNowPlaying( p_input->p->input.p_item,
669 p_pgrm->psz_now_playing );
670 input_item_SetPublisher( p_input->p->input.p_item,
671 p_pgrm->psz_publisher );
673 var_SetBool( p_sys->p_input, "intf-change", true );
679 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
681 es_out_sys_t *p_sys = out->p_sys;
682 input_thread_t *p_input = p_sys->p_input;
685 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
690 p_pgrm->i_id = i_group;
692 p_pgrm->b_selected = false;
693 p_pgrm->psz_name = NULL;
694 p_pgrm->psz_now_playing = NULL;
695 p_pgrm->psz_publisher = NULL;
696 p_pgrm->p_epg = NULL;
697 p_pgrm->p_clock = input_clock_New( p_input->p->input.i_cr_average, p_sys->i_rate );
698 if( !p_pgrm->p_clock )
705 TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
707 /* Update "program" variable */
709 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
711 if( i_group == var_GetInteger( p_input, "program" ) )
713 EsOutProgramSelect( out, p_pgrm );
717 var_SetBool( p_sys->p_input, "intf-change", true );
725 static int EsOutProgramDel( es_out_t *out, int i_group )
727 es_out_sys_t *p_sys = out->p_sys;
728 input_thread_t *p_input = p_sys->p_input;
729 es_out_pgrm_t *p_pgrm = NULL;
733 for( i = 0; i < p_sys->i_pgrm; i++ )
735 if( p_sys->pgrm[i]->i_id == i_group )
737 p_pgrm = p_sys->pgrm[i];
747 msg_Dbg( p_input, "can't delete program %d which still has %i ES",
748 i_group, p_pgrm->i_es );
752 TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
754 /* If program is selected we need to unselect it */
755 if( p_sys->p_pgrm == p_pgrm )
756 p_sys->p_pgrm = NULL;
758 input_clock_Delete( p_pgrm->p_clock );
760 free( p_pgrm->psz_name );
761 free( p_pgrm->psz_now_playing );
762 free( p_pgrm->psz_publisher );
764 vlc_epg_Delete( p_pgrm->p_epg );
767 /* Update "program" variable */
769 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
771 var_SetBool( p_sys->p_input, "intf-change", true );
778 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
781 if( p_pgrm->psz_name )
783 if( asprintf( &psz, _("%s [%s %d]"), p_pgrm->psz_name, _("Program"), p_pgrm->i_id ) == -1 )
788 if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
794 static void EsOutProgramMeta( es_out_t *out, int i_group, vlc_meta_t *p_meta )
796 es_out_sys_t *p_sys = out->p_sys;
797 es_out_pgrm_t *p_pgrm = NULL;
798 input_thread_t *p_input = p_sys->p_input;
800 const char *psz_title = NULL;
801 const char *psz_provider = NULL;
804 msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
806 /* Check against empty meta data (empty for what we handle) */
807 if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
808 !vlc_meta_Get( p_meta, vlc_meta_NowPlaying) &&
809 !vlc_meta_Get( p_meta, vlc_meta_Publisher) &&
810 vlc_dictionary_keys_count( &p_meta->extra_tags ) <= 0 )
815 for( i = 0; i < p_sys->i_pgrm; i++ )
817 if( p_sys->pgrm[i]->i_id == i_group )
819 p_pgrm = p_sys->pgrm[i];
824 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
827 psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
828 psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
830 /* Update the description text of the program */
831 if( psz_title && *psz_title )
836 if( !p_pgrm->psz_name || strcmp( p_pgrm->psz_name, psz_title ) )
838 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
840 /* Remove old entries */
841 input_Control( p_input, INPUT_DEL_INFO, psz_cat, NULL );
842 /* TODO update epg name */
845 free( p_pgrm->psz_name );
846 p_pgrm->psz_name = strdup( psz_title );
848 /* ugly but it works */
850 var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
852 if( psz_provider && *psz_provider )
854 if( asprintf( &text.psz_string, "%s [%s]", psz_title, psz_provider ) != -1 )
856 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
857 free( text.psz_string );
862 text.psz_string = (char *)psz_title;
863 var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, &text );
867 psz_cat = EsOutProgramGetMetaName( p_pgrm );
870 if( p_sys->p_pgrm == p_pgrm )
871 input_item_SetPublisher( p_input->p->input.p_item, psz_provider );
872 input_Control( p_input, INPUT_ADD_INFO, psz_cat, input_MetaTypeToLocalizedString(vlc_meta_Publisher), psz_provider );
874 char ** ppsz_all_keys = vlc_dictionary_all_keys( &p_meta->extra_tags );
875 for( i = 0; ppsz_all_keys[i]; i++ )
877 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _(ppsz_all_keys[i]),
878 vlc_dictionary_value_for_key( &p_meta->extra_tags, ppsz_all_keys[i] ) );
879 free( ppsz_all_keys[i] );
881 free( ppsz_all_keys );
886 static void vlc_epg_Merge( vlc_epg_t *p_dst, const vlc_epg_t *p_src )
891 for( i = 0; i < p_src->i_event; i++ )
893 vlc_epg_event_t *p_evt = p_src->pp_event[i];
897 for( j = 0; j < p_dst->i_event; j++ )
899 if( p_dst->pp_event[j]->i_start == p_evt->i_start && p_dst->pp_event[j]->i_duration == p_evt->i_duration )
904 if( p_dst->pp_event[j]->i_start > p_evt->i_start )
909 vlc_epg_event_t *p_copy = malloc( sizeof(vlc_epg_event_t) );
912 memset( p_copy, 0, sizeof(vlc_epg_event_t) );
913 p_copy->i_start = p_evt->i_start;
914 p_copy->i_duration = p_evt->i_duration;
915 p_copy->psz_name = p_evt->psz_name ? strdup( p_evt->psz_name ) : NULL;
916 p_copy->psz_short_description = p_evt->psz_short_description ? strdup( p_evt->psz_short_description ) : NULL;
917 p_copy->psz_description = p_evt->psz_description ? strdup( p_evt->psz_description ) : NULL;
918 TAB_INSERT( p_dst->i_event, p_dst->pp_event, p_copy, j );
922 vlc_epg_SetCurrent( p_dst, p_src->p_current ? p_src->p_current->i_start : -1 );
924 /* Keep only 1 old event */
925 if( p_dst->p_current )
927 while( p_dst->i_event > 1 && p_dst->pp_event[0] != p_dst->p_current && p_dst->pp_event[1] != p_dst->p_current )
928 TAB_REMOVE( p_dst->i_event, p_dst->pp_event, p_dst->pp_event[0] );
932 static void EsOutProgramEpg( es_out_t *out, int i_group, vlc_epg_t *p_epg )
934 es_out_sys_t *p_sys = out->p_sys;
935 input_thread_t *p_input = p_sys->p_input;
936 es_out_pgrm_t *p_pgrm = NULL;
941 for( i = 0; i < p_sys->i_pgrm; i++ )
943 if( p_sys->pgrm[i]->i_id == i_group )
945 p_pgrm = p_sys->pgrm[i];
950 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
954 p_pgrm->p_epg = vlc_epg_New( p_pgrm->psz_name );
955 vlc_epg_Merge( p_pgrm->p_epg, p_epg );
958 psz_cat = EsOutProgramGetMetaName( p_pgrm );
959 #ifdef HAVE_LOCALTIME_R
961 if( asprintf( &psz_epg, "EPG %s", psz_cat ) == -1 )
963 input_Control( p_input, INPUT_DEL_INFO, psz_epg, NULL );
964 msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, p_pgrm->p_epg->psz_name );
965 for( i = 0; i < p_pgrm->p_epg->i_event; i++ )
967 const vlc_epg_event_t *p_evt = p_pgrm->p_epg->pp_event[i];
968 time_t t_start = (time_t)p_evt->i_start;
972 localtime_r( &t_start, &tm_start );
974 snprintf( psz_start, sizeof(psz_start), "%2.2d:%2.2d:%2.2d", tm_start.tm_hour, tm_start.tm_min, tm_start.tm_sec );
975 if( p_evt->psz_short_description || p_evt->psz_description )
976 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d) - %s",
978 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60,
979 p_evt->psz_short_description ? p_evt->psz_short_description : p_evt->psz_description );
981 input_Control( p_input, INPUT_ADD_INFO, psz_epg, psz_start, "%s (%2.2d:%2.2d)",
983 p_evt->i_duration/60/60, (p_evt->i_duration/60)%60 );
987 /* Update now playing */
988 free( p_pgrm->psz_now_playing );
989 p_pgrm->psz_now_playing = NULL;
990 if( p_epg->p_current && p_epg->p_current->psz_name && *p_epg->p_current->psz_name )
991 p_pgrm->psz_now_playing = strdup( p_epg->p_current->psz_name );
993 if( p_pgrm == p_sys->p_pgrm )
994 input_item_SetNowPlaying( p_input->p->input.p_item, p_pgrm->psz_now_playing );
996 if( p_pgrm->psz_now_playing )
998 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
999 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying),
1000 p_pgrm->psz_now_playing );
1004 input_Control( p_input, INPUT_DEL_INFO, psz_cat,
1005 input_MetaTypeToLocalizedString(vlc_meta_NowPlaying) );
1014 static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
1016 es_out_sys_t *p_sys = out->p_sys;
1017 input_thread_t *p_input = p_sys->p_input;
1019 es_out_id_t *es = malloc( sizeof( es_out_id_t ) );
1020 es_out_pgrm_t *p_pgrm = NULL;
1023 if( !es ) return NULL;
1025 if( fmt->i_group < 0 )
1027 msg_Err( p_input, "invalid group number" );
1032 /* Search the program */
1033 for( i = 0; i < p_sys->i_pgrm; i++ )
1035 if( fmt->i_group == p_sys->pgrm[i]->i_id )
1037 p_pgrm = p_sys->pgrm[i];
1041 if( p_pgrm == NULL )
1043 /* Create a new one */
1044 p_pgrm = EsOutProgramAdd( out, fmt->i_group );
1047 /* Increase ref count for program */
1052 fmt->i_id = out->p_sys->i_id;
1053 es->i_id = fmt->i_id;
1054 es->p_pgrm = p_pgrm;
1055 es_format_Copy( &es->fmt, fmt );
1056 es->i_preroll_end = -1;
1058 switch( fmt->i_cat )
1062 audio_replay_gain_t rg;
1064 es->i_channel = p_sys->i_audio;
1066 memset( &rg, 0, sizeof(rg) );
1067 vlc_mutex_lock( &p_input->p->input.p_item->lock );
1068 vlc_audio_replay_gain_MergeFromMeta( &rg, p_input->p->input.p_item->p_meta );
1069 vlc_mutex_unlock( &p_input->p->input.p_item->lock );
1071 for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
1073 if( !es->fmt.audio_replay_gain.pb_peak[i] )
1075 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
1076 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
1078 if( !es->fmt.audio_replay_gain.pb_gain[i] )
1080 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
1081 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
1088 es->i_channel = p_sys->i_video;
1089 if( fmt->video.i_frame_rate && fmt->video.i_frame_rate_base )
1090 vlc_ureduce( &es->fmt.video.i_frame_rate,
1091 &es->fmt.video.i_frame_rate_base,
1092 fmt->video.i_frame_rate,
1093 fmt->video.i_frame_rate_base, 0 );
1097 es->i_channel = p_sys->i_sub;
1104 es->psz_language = LanguageGetName( fmt->psz_language ); /* remember so we only need to do it once */
1105 es->psz_language_code = LanguageGetCode( fmt->psz_language );
1107 es->p_dec_record = NULL;
1108 for( i = 0; i < 4; i++ )
1109 es->pb_cc_present[i] = false;
1110 es->p_master = NULL;
1112 if( es->p_pgrm == p_sys->p_pgrm )
1113 EsOutESVarUpdate( out, es, false );
1115 /* Select it if needed */
1116 EsOutSelect( out, es, false );
1119 TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
1120 p_sys->i_id++; /* always incremented */
1121 switch( fmt->i_cat )
1134 EsOutAddInfo( out, es );
1139 static bool EsIsSelected( es_out_id_t *es )
1143 bool b_decode = false;
1144 if( es->p_master->p_dec )
1146 int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1147 if( i_channel != -1 )
1148 input_DecoderGetCcState( es->p_master->p_dec, &b_decode, i_channel );
1154 return es->p_dec != NULL;
1157 static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
1159 es_out_sys_t *p_sys = out->p_sys;
1160 input_thread_t *p_input = p_sys->p_input;
1162 p_es->p_dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_input->p->p_sout );
1163 if( p_es->p_dec && !p_es->p_master && p_sys->p_sout_record )
1164 p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
1166 static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
1173 input_DecoderDelete( p_es->p_dec );
1176 if( p_es->p_dec_record )
1178 input_DecoderDelete( p_es->p_dec_record );
1179 p_es->p_dec_record = NULL;
1183 static void EsSelect( es_out_t *out, es_out_id_t *es )
1185 es_out_sys_t *p_sys = out->p_sys;
1186 input_thread_t *p_input = p_sys->p_input;
1188 const char *psz_var;
1190 if( EsIsSelected( es ) )
1192 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1199 if( !es->p_master->p_dec )
1202 i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1203 if( i_channel == -1 || input_DecoderSetCcState( es->p_master->p_dec, true, i_channel ) )
1208 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1210 if( !var_GetBool( p_input, out->b_sout ? "sout-video" : "video" ) )
1212 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1217 else if( es->fmt.i_cat == AUDIO_ES )
1219 var_Get( p_input, "audio", &val );
1220 if( !var_GetBool( p_input, out->b_sout ? "sout-audio" : "audio" ) )
1222 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1227 if( es->fmt.i_cat == SPU_ES )
1229 var_Get( p_input, "spu", &val );
1230 if( !var_GetBool( p_input, out->b_sout ? "sout-spu" : "spu" ) )
1232 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1238 es->i_preroll_end = -1;
1239 EsCreateDecoder( out, es );
1241 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1245 if( es->fmt.i_cat == VIDEO_ES )
1246 psz_var = "video-es";
1247 else if( es->fmt.i_cat == AUDIO_ES )
1248 psz_var = "audio-es";
1249 else if( es->fmt.i_cat == SPU_ES )
1254 /* Mark it as selected */
1255 val.i_int = es->i_id;
1256 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1258 var_SetBool( p_sys->p_input, "intf-change", true );
1261 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1263 es_out_sys_t *p_sys = out->p_sys;
1264 input_thread_t *p_input = p_sys->p_input;
1266 const char *psz_var;
1268 if( !EsIsSelected( es ) )
1270 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1276 if( es->p_master->p_dec )
1278 int i_channel = EsOutGetClosedCaptionsChannel( es->fmt.i_codec );
1279 if( i_channel != -1 )
1280 input_DecoderSetCcState( es->p_master->p_dec, false, i_channel );
1285 const int i_spu_id = var_GetInteger( p_input, "spu-es");
1287 for( i = 0; i < 4; i++ )
1289 if( !es->pb_cc_present[i] || !es->pp_cc_es[i] )
1292 if( i_spu_id == es->pp_cc_es[i]->i_id )
1294 /* Force unselection of the CC */
1296 var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
1298 var_SetBool( p_sys->p_input, "intf-change", true );
1300 EsOutDel( out, es->pp_cc_es[i] );
1302 es->pb_cc_present[i] = false;
1304 EsDestroyDecoder( out, es );
1311 if( es->p_dec == NULL )
1313 if( es->fmt.i_cat == VIDEO_ES )
1314 psz_var = "video-es";
1315 else if( es->fmt.i_cat == AUDIO_ES )
1316 psz_var = "audio-es";
1317 else if( es->fmt.i_cat == SPU_ES )
1322 /* Mark it as unselected */
1324 var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
1326 var_SetBool( p_sys->p_input, "intf-change", true );
1330 * Select an ES given the current mode
1331 * XXX: you need to take a the lock before (stream.stream_lock)
1333 * \param out The es_out structure
1334 * \param es es_out_id structure
1335 * \param b_force ...
1338 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1340 es_out_sys_t *p_sys = out->p_sys;
1342 int i_cat = es->fmt.i_cat;
1344 if( !p_sys->b_active ||
1345 ( !b_force && es->fmt.i_priority < 0 ) )
1350 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1352 if( !EsIsSelected( es ) )
1353 EsSelect( out, es );
1355 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1359 var_Get( p_sys->p_input, "programs", &val );
1360 for ( i = 0; i < val.p_list->i_count; i++ )
1362 if ( val.p_list->p_values[i].i_int == es->p_pgrm->i_id || b_force )
1364 if( !EsIsSelected( es ) )
1365 EsSelect( out, es );
1369 var_Change( p_sys->p_input, "programs", VLC_VAR_FREELIST, &val, NULL );
1371 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1375 if( es->p_pgrm != p_sys->p_pgrm )
1378 if( i_cat == AUDIO_ES )
1380 int idx1 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1381 es->psz_language_code );
1383 if( p_sys->p_es_audio &&
1384 p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
1386 int idx2 = LanguageArrayIndex( p_sys->ppsz_audio_language,
1387 p_sys->p_es_audio->psz_language_code );
1389 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1391 i_wanted = es->i_channel;
1395 /* Select audio if (no audio selected yet)
1396 * - no audio-language
1397 * - no audio code for the ES
1398 * - audio code in the requested list */
1400 !strcmp( es->psz_language_code, "??" ) ||
1401 !p_sys->ppsz_audio_language )
1402 i_wanted = es->i_channel;
1405 if( p_sys->i_audio_last >= 0 )
1406 i_wanted = p_sys->i_audio_last;
1408 if( p_sys->i_audio_id >= 0 )
1410 if( es->i_id == p_sys->i_audio_id )
1411 i_wanted = es->i_channel;
1416 else if( i_cat == SPU_ES )
1418 int idx1 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1419 es->psz_language_code );
1421 if( p_sys->p_es_sub &&
1422 p_sys->p_es_sub->fmt.i_priority >= es->fmt.i_priority )
1424 int idx2 = LanguageArrayIndex( p_sys->ppsz_sub_language,
1425 p_sys->p_es_sub->psz_language_code );
1427 msg_Dbg( p_sys->p_input, "idx1=%d(%s) idx2=%d(%s)",
1428 idx1, es->psz_language_code, idx2,
1429 p_sys->p_es_sub->psz_language_code );
1431 if( idx1 < 0 || ( idx2 >= 0 && idx2 <= idx1 ) )
1433 /* We found a SPU that matches our language request */
1434 i_wanted = es->i_channel;
1436 else if( idx1 >= 0 )
1438 msg_Dbg( p_sys->p_input, "idx1=%d(%s)",
1439 idx1, es->psz_language_code );
1441 i_wanted = es->i_channel;
1443 else if( p_sys->i_default_sub_id >= 0 )
1445 if( es->i_id == p_sys->i_default_sub_id )
1446 i_wanted = es->i_channel;
1449 if( p_sys->i_sub_last >= 0 )
1450 i_wanted = p_sys->i_sub_last;
1452 if( p_sys->i_sub_id >= 0 )
1454 if( es->i_id == p_sys->i_sub_id )
1455 i_wanted = es->i_channel;
1460 else if( i_cat == VIDEO_ES )
1462 i_wanted = es->i_channel;
1465 if( i_wanted == es->i_channel && !EsIsSelected( es ) )
1466 EsSelect( out, es );
1469 /* FIXME TODO handle priority here */
1470 if( EsIsSelected( es ) )
1472 if( i_cat == AUDIO_ES )
1474 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1475 p_sys->p_es_audio &&
1476 p_sys->p_es_audio != es &&
1477 EsIsSelected( p_sys->p_es_audio ) )
1479 EsUnselect( out, p_sys->p_es_audio, false );
1481 p_sys->p_es_audio = es;
1483 else if( i_cat == SPU_ES )
1485 if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
1487 p_sys->p_es_sub != es &&
1488 EsIsSelected( p_sys->p_es_sub ) )
1490 EsUnselect( out, p_sys->p_es_sub, false );
1492 p_sys->p_es_sub = es;
1494 else if( i_cat == VIDEO_ES )
1496 p_sys->p_es_video = es;
1502 * Send a block for the given es_out
1504 * \param out the es_out to send from
1505 * \param es the es_out_id
1506 * \param p_block the data block to send
1508 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
1510 es_out_sys_t *p_sys = out->p_sys;
1511 input_thread_t *p_input = p_sys->p_input;
1512 es_out_pgrm_t *p_pgrm = es->p_pgrm;
1516 if( es->fmt.i_cat == AUDIO_ES )
1517 i_delay = p_sys->i_audio_delay;
1518 else if( es->fmt.i_cat == SPU_ES )
1519 i_delay = p_sys->i_spu_delay;
1523 if( libvlc_stats( p_input ) )
1525 vlc_mutex_lock( &p_input->p->counters.counters_lock );
1526 stats_UpdateInteger( p_input, p_input->p->counters.p_demux_read,
1527 p_block->i_buffer, &i_total );
1528 stats_UpdateFloat( p_input , p_input->p->counters.p_demux_bitrate,
1529 (float)i_total, NULL );
1530 vlc_mutex_unlock( &p_input->p->counters.counters_lock );
1533 /* Mark preroll blocks */
1534 if( es->i_preroll_end >= 0 )
1536 int64_t i_date = p_block->i_pts;
1538 i_date = p_block->i_dts;
1540 if( i_date < es->i_preroll_end )
1541 p_block->i_flags |= BLOCK_FLAG_PREROLL;
1543 es->i_preroll_end = -1;
1546 if( p_block->i_dts > 0 )
1547 p_block->i_dts += i_delay;
1549 if( p_block->i_pts > 0 )
1550 p_block->i_pts += i_delay;
1552 p_block->i_rate = 0;
1556 block_Release( p_block );
1561 if( es->p_dec_record )
1563 block_t *p_dup = block_Duplicate( p_block );
1565 input_DecoderDecode( es->p_dec_record, p_dup );
1567 input_DecoderDecode( es->p_dec, p_block );
1569 /* Check CC status */
1571 bool b_cc_new = false;
1573 input_DecoderIsCcPresent( es->p_dec, pb_cc );
1574 for( int i = 0; i < 4; i++ )
1576 static const vlc_fourcc_t fcc[4] = {
1577 VLC_FOURCC('c', 'c', '1', ' '),
1578 VLC_FOURCC('c', 'c', '2', ' '),
1579 VLC_FOURCC('c', 'c', '3', ' '),
1580 VLC_FOURCC('c', 'c', '4', ' '),
1584 if( es->pb_cc_present[i] || !pb_cc[i] )
1586 msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, es->i_id );
1588 es_format_Init( &fmt, SPU_ES, fcc[i] );
1589 fmt.i_group = es->fmt.i_group;
1590 if( asprintf( &fmt.psz_description,
1591 _("Closed captions %u"), 1 + i ) == -1 )
1592 fmt.psz_description = NULL;
1593 es->pp_cc_es[i] = EsOutAdd( out, &fmt );
1594 es->pp_cc_es[i]->p_master = es;
1595 es_format_Clean( &fmt );
1598 es->pb_cc_present[i] = true;
1602 var_SetBool( p_sys->p_input, "intf-change", true );
1607 /*****************************************************************************
1609 *****************************************************************************/
1610 static void EsOutDel( es_out_t *out, es_out_id_t *es )
1612 es_out_sys_t *p_sys = out->p_sys;
1613 bool b_reselect = false;
1616 /* We don't try to reselect */
1619 while( !out->p_sys->p_input->b_die && es->p_dec )
1621 if( input_DecoderEmpty( es->p_dec ) &&
1622 ( !es->p_dec_record || input_DecoderEmpty( es->p_dec_record ) ))
1626 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1629 if( es->p_pgrm == p_sys->p_pgrm )
1630 EsOutESVarUpdate( out, es, true );
1632 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
1635 if( es->p_pgrm->i_es == 0 )
1637 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
1640 if( p_sys->p_es_audio == es || p_sys->p_es_video == es ||
1641 p_sys->p_es_sub == es ) b_reselect = true;
1643 if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
1644 if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
1645 if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
1647 switch( es->fmt.i_cat )
1660 /* Re-select another track when needed */
1662 for( i = 0; i < p_sys->i_es; i++ )
1664 if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
1665 EsOutSelect( out, p_sys->es[i], false );
1668 free( es->psz_language );
1669 free( es->psz_language_code );
1671 es_format_Clean( &es->fmt );
1677 * Control query handler
1679 * \param out the es_out to control
1680 * \param i_query A es_out query as defined in include/ninput.h
1681 * \param args a variable list of arguments for the query
1682 * \return VLC_SUCCESS or an error code
1684 static int EsOutControl( es_out_t *out, int i_query, va_list args )
1686 es_out_sys_t *p_sys = out->p_sys;
1694 case ES_OUT_SET_ES_STATE:
1695 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1696 b = (bool) va_arg( args, int );
1697 if( b && !EsIsSelected( es ) )
1699 EsSelect( out, es );
1700 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
1702 else if( !b && EsIsSelected( es ) )
1704 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
1709 case ES_OUT_GET_ES_STATE:
1710 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1711 pb = (bool*) va_arg( args, bool * );
1713 *pb = EsIsSelected( es );
1716 case ES_OUT_SET_ACTIVE:
1718 b = (bool) va_arg( args, int );
1719 p_sys->b_active = b;
1722 var_SetBool( p_sys->p_input, "intf-change", true );
1726 case ES_OUT_GET_ACTIVE:
1727 pb = (bool*) va_arg( args, bool * );
1728 *pb = p_sys->b_active;
1731 case ES_OUT_SET_MODE:
1732 i = (int) va_arg( args, int );
1733 if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
1734 i == ES_OUT_MODE_AUTO || i == ES_OUT_MODE_PARTIAL )
1738 /* Reapply policy mode */
1739 for( i = 0; i < p_sys->i_es; i++ )
1741 if( EsIsSelected( p_sys->es[i] ) )
1743 EsUnselect( out, p_sys->es[i],
1744 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1747 for( i = 0; i < p_sys->i_es; i++ )
1749 EsOutSelect( out, p_sys->es[i], false );
1753 return VLC_EGENERIC;
1755 case ES_OUT_GET_MODE:
1756 pi = (int*) va_arg( args, int* );
1757 *pi = p_sys->i_mode;
1761 case ES_OUT_RESTART_ES:
1765 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1769 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1771 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1773 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1778 for( i = 0; i < p_sys->i_es; i++ )
1782 if( es == p_sys->es[i] )
1784 EsOutSelect( out, es, true );
1790 if( i_cat == UNKNOWN_ES || p_sys->es[i]->fmt.i_cat == i_cat )
1792 if( EsIsSelected( p_sys->es[i] ) )
1794 if( i_query == ES_OUT_RESTART_ES )
1796 if( p_sys->es[i]->p_dec )
1798 EsDestroyDecoder( out, p_sys->es[i] );
1799 EsCreateDecoder( out, p_sys->es[i] );
1804 EsUnselect( out, p_sys->es[i],
1805 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
1811 if( i_query == ES_OUT_SET_ES )
1814 event.type = vlc_InputSelectedStreamChanged;
1815 vlc_event_send( &p_sys->p_input->p->event_manager, &event );
1820 case ES_OUT_SET_DEFAULT:
1822 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1826 /*p_sys->i_default_video_id = -1;*/
1827 /*p_sys->i_default_audio_id = -1;*/
1828 p_sys->i_default_sub_id = -1;
1830 else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
1832 /*p_sys->i_default_video_id = -1;*/
1834 else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
1836 /*p_sys->i_default_audio_id = -1;*/
1838 else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
1840 p_sys->i_default_sub_id = -1;
1844 /*if( es->fmt.i_cat == VIDEO_ES )
1845 p_sys->i_default_video_id = es->i_id;
1847 if( es->fmt.i_cat == AUDIO_ES )
1848 p_sys->i_default_audio_id = es->i_id;
1850 if( es->fmt.i_cat == SPU_ES )
1851 p_sys->i_default_sub_id = es->i_id;
1856 case ES_OUT_SET_PCR:
1857 case ES_OUT_SET_GROUP_PCR:
1859 es_out_pgrm_t *p_pgrm = NULL;
1863 if( i_query == ES_OUT_SET_PCR )
1865 p_pgrm = p_sys->p_pgrm;
1870 i_group = (int)va_arg( args, int );
1871 for( i = 0; i < p_sys->i_pgrm; i++ )
1873 if( p_sys->pgrm[i]->i_id == i_group )
1875 p_pgrm = p_sys->pgrm[i];
1880 if( p_pgrm == NULL )
1881 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
1883 i_pcr = (int64_t)va_arg( args, int64_t );
1885 * TODO do not use mdate() but proper stream acquisition date */
1886 input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
1887 p_sys->p_input->b_can_pace_control, i_pcr, mdate() );
1891 case ES_OUT_RESET_PCR:
1892 for( i = 0; i < p_sys->i_pgrm; i++ )
1893 input_clock_Reset( p_sys->pgrm[i]->p_clock );
1899 int64_t i_ts = (int64_t)va_arg( args, int64_t );
1900 int64_t *pi_ts = (int64_t *)va_arg( args, int64_t * );
1901 *pi_ts = input_clock_GetTS( p_sys->p_pgrm->p_clock,
1902 p_sys->p_input->i_pts_delay, i_ts );
1905 return VLC_EGENERIC;
1907 case ES_OUT_GET_GROUP:
1908 pi = (int*) va_arg( args, int* );
1910 *pi = p_sys->p_pgrm->i_id;
1912 *pi = -1; /* FIXME */
1915 case ES_OUT_SET_GROUP:
1918 i = (int) va_arg( args, int );
1919 for( j = 0; j < p_sys->i_pgrm; j++ )
1921 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
1922 if( p_pgrm->i_id == i )
1924 EsOutProgramSelect( out, p_pgrm );
1928 return VLC_EGENERIC;
1931 case ES_OUT_SET_FMT:
1933 /* This ain't pretty but is need by some demuxers (eg. Ogg )
1934 * to update the p_extra data */
1936 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1937 p_fmt = (es_format_t*) va_arg( args, es_format_t * );
1939 return VLC_EGENERIC;
1941 if( p_fmt->i_extra )
1943 es->fmt.i_extra = p_fmt->i_extra;
1944 es->fmt.p_extra = realloc( es->fmt.p_extra, p_fmt->i_extra );
1945 memcpy( es->fmt.p_extra, p_fmt->p_extra, p_fmt->i_extra );
1950 EsDestroyDecoder( out, es );
1952 EsCreateDecoder( out, es );
1954 es->p_dec->fmt_in.i_extra = p_fmt->i_extra;
1955 es->p_dec->fmt_in.p_extra =
1956 realloc( es->p_dec->fmt_in.p_extra, p_fmt->i_extra );
1957 memcpy( es->p_dec->fmt_in.p_extra,
1958 p_fmt->p_extra, p_fmt->i_extra );
1965 case ES_OUT_SET_NEXT_DISPLAY_TIME:
1969 es = (es_out_id_t*) va_arg( args, es_out_id_t * );
1970 i_date = (int64_t)va_arg( args, int64_t );
1972 if( !es || !es->p_dec )
1973 return VLC_EGENERIC;
1975 es->i_preroll_end = i_date;
1979 case ES_OUT_SET_GROUP_META:
1981 int i_group = (int)va_arg( args, int );
1982 vlc_meta_t *p_meta = (vlc_meta_t*)va_arg( args, vlc_meta_t * );
1984 EsOutProgramMeta( out, i_group, p_meta );
1987 case ES_OUT_SET_GROUP_EPG:
1989 int i_group = (int)va_arg( args, int );
1990 vlc_epg_t *p_epg = (vlc_epg_t*)va_arg( args, vlc_epg_t * );
1992 EsOutProgramEpg( out, i_group, p_epg );
1995 case ES_OUT_DEL_GROUP:
1997 int i_group = (int)va_arg( args, int );
1999 return EsOutProgramDel( out, i_group );
2003 msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
2004 return VLC_EGENERIC;
2008 /****************************************************************************
2009 * LanguageGetName: try to expend iso639 into plain name
2010 ****************************************************************************/
2011 static char *LanguageGetName( const char *psz_code )
2013 const iso639_lang_t *pl;
2015 if( psz_code == NULL )
2017 return strdup( "" );
2020 if( strlen( psz_code ) == 2 )
2022 pl = GetLang_1( psz_code );
2024 else if( strlen( psz_code ) == 3 )
2026 pl = GetLang_2B( psz_code );
2027 if( !strcmp( pl->psz_iso639_1, "??" ) )
2029 pl = GetLang_2T( psz_code );
2034 return strdup( psz_code );
2037 if( !strcmp( pl->psz_iso639_1, "??" ) )
2039 return strdup( psz_code );
2043 if( *pl->psz_native_name )
2045 return strdup( pl->psz_native_name );
2047 return strdup( pl->psz_eng_name );
2051 /* Get a 2 char code */
2052 static char *LanguageGetCode( const char *psz_lang )
2054 const iso639_lang_t *pl;
2056 if( psz_lang == NULL || *psz_lang == '\0' )
2057 return strdup("??");
2059 for( pl = p_languages; pl->psz_iso639_1 != NULL; pl++ )
2061 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
2062 !strcasecmp( pl->psz_native_name, psz_lang ) ||
2063 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
2064 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
2065 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
2069 if( pl->psz_iso639_1 != NULL )
2070 return strdup( pl->psz_iso639_1 );
2072 return strdup("??");
2075 static char **LanguageSplit( const char *psz_langs )
2082 if( psz_langs == NULL ) return NULL;
2084 psz_parser = psz_dup = strdup(psz_langs);
2086 while( psz_parser && *psz_parser )
2091 psz = strchr(psz_parser, ',' );
2092 if( psz ) *psz++ = '\0';
2094 if( !strcmp( psz_parser, "any" ) )
2096 TAB_APPEND( i_psz, ppsz, strdup("any") );
2100 psz_code = LanguageGetCode( psz_parser );
2101 if( strcmp( psz_code, "??" ) )
2103 TAB_APPEND( i_psz, ppsz, psz_code );
2116 TAB_APPEND( i_psz, ppsz, NULL );
2123 static int LanguageArrayIndex( char **ppsz_langs, char *psz_lang )
2127 if( !ppsz_langs || !psz_lang ) return -1;
2129 for( i = 0; ppsz_langs[i]; i++ )
2131 if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2132 !strcasecmp( ppsz_langs[i], "any" ) )
2141 /****************************************************************************
2143 * - add meta info to the playlist item
2144 ****************************************************************************/
2145 static void EsOutAddInfo( es_out_t *out, es_out_id_t *es )
2147 es_out_sys_t *p_sys = out->p_sys;
2148 input_thread_t *p_input = p_sys->p_input;
2149 es_format_t *fmt = &es->fmt;
2153 /* Add stream info */
2154 if( asprintf( &psz_cat, _("Stream %d"), out->p_sys->i_id - 1 ) == -1 )
2157 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
2158 "%.4s", (char*)&fmt->i_codec );
2160 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Language"),
2161 "%s", es->psz_language );
2163 /* Add information */
2164 switch( fmt->i_cat )
2167 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2168 _("Type"), _("Audio") );
2170 if( fmt->audio.i_channels > 0 )
2171 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Channels"),
2172 "%u", fmt->audio.i_channels );
2174 if( fmt->audio.i_rate > 0 )
2176 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Sample rate"),
2177 _("%u Hz"), fmt->audio.i_rate );
2178 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
2181 if( fmt->audio.i_bitspersample > 0 )
2182 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2183 _("Bits per sample"), "%u",
2184 fmt->audio.i_bitspersample );
2186 if( fmt->i_bitrate > 0 )
2188 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Bitrate"),
2189 _("%u kb/s"), fmt->i_bitrate / 1000 );
2190 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
2195 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2196 _("Type"), _("Video") );
2198 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
2199 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2200 _("Resolution"), "%ux%u",
2201 fmt->video.i_width, fmt->video.i_height );
2203 if( fmt->video.i_visible_width > 0 &&
2204 fmt->video.i_visible_height > 0 )
2205 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2206 _("Display resolution"), "%ux%u",
2207 fmt->video.i_visible_width,
2208 fmt->video.i_visible_height);
2209 if( fmt->video.i_frame_rate > 0 &&
2210 fmt->video.i_frame_rate_base > 0 )
2212 div = lldiv( (float)fmt->video.i_frame_rate /
2213 fmt->video.i_frame_rate_base * 1000000,
2215 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2216 _("Frame rate"), "%"PRId64".%06u",
2217 div.quot, (unsigned int )div.rem );
2222 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
2223 _("Type"), _("Subtitle") );