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>
40 #include <vlc_fourcc.h>
42 #include "input_internal.h"
49 #include "../stream_output/stream_output.h"
51 #include <vlc_iso_lang.h>
52 /* FIXME we should find a better way than including that */
53 #include "../text/iso-639_def.h"
55 /*****************************************************************************
57 *****************************************************************************/
63 /* Number of es for this pgrm */
69 /* Clock for this program */
70 input_clock_t
*p_clock
;
73 char *psz_now_playing
;
81 es_out_pgrm_t
*p_pgrm
;
86 /* Channel in the track type */
90 char *psz_language_code
;
93 decoder_t
*p_dec_record
;
95 /* Fields for Video with CC */
96 bool pb_cc_present
[4];
97 es_out_id_t
*pp_cc_es
[4];
99 /* Field for CC track from a master video */
100 es_out_id_t
*p_master
;
102 /* ID for the meta data */
108 input_thread_t
*p_input
;
115 es_out_pgrm_t
**pgrm
;
116 es_out_pgrm_t
**pp_selected_pgrm
; /* --programs */
117 es_out_pgrm_t
*p_pgrm
; /* Master program */
133 /* es/group to select */
135 int i_audio_last
, i_audio_id
;
136 int i_sub_last
, i_sub_id
;
137 int i_default_sub_id
; /* As specified in container; if applicable */
138 char **ppsz_audio_language
;
139 char **ppsz_sub_language
;
141 /* current main es */
142 es_out_id_t
*p_es_audio
;
143 es_out_id_t
*p_es_video
;
144 es_out_id_t
*p_es_sub
;
147 int64_t i_audio_delay
;
150 /* Clock configuration */
152 mtime_t i_pts_jitter
;
158 mtime_t i_pause_date
;
160 /* Current preroll */
161 mtime_t i_preroll_end
;
163 /* Used for buffering */
165 mtime_t i_buffering_extra_initial
;
166 mtime_t i_buffering_extra_stream
;
167 mtime_t i_buffering_extra_system
;
170 sout_instance_t
*p_sout_record
;
173 static es_out_id_t
*EsOutAdd ( es_out_t
*, const es_format_t
* );
174 static int EsOutSend ( es_out_t
*, es_out_id_t
*, block_t
* );
175 static void EsOutDel ( es_out_t
*, es_out_id_t
* );
176 static int EsOutControl( es_out_t
*, int i_query
, va_list );
177 static void EsOutDelete ( es_out_t
* );
179 static void EsOutTerminate( es_out_t
* );
180 static void EsOutSelect( es_out_t
*, es_out_id_t
*es
, bool b_force
);
181 static void EsOutUpdateInfo( es_out_t
*, es_out_id_t
*es
, const es_format_t
*, const vlc_meta_t
* );
182 static int EsOutSetRecord( es_out_t
*, bool b_record
);
184 static bool EsIsSelected( es_out_id_t
*es
);
185 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
);
186 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
);
187 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
);
188 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
189 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
190 static void EsOutProgramsChangeRate( es_out_t
*out
);
191 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
);
193 static char *LanguageGetName( const char *psz_code
);
194 static char *LanguageGetCode( const char *psz_lang
);
195 static char **LanguageSplit( const char *psz_langs
, bool b_default_any
);
196 static int LanguageArrayIndex( char **ppsz_langs
, char *psz_lang
);
198 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
);
200 static const vlc_fourcc_t EsOutFourccClosedCaptions
[4] = {
201 VLC_FOURCC('c', 'c', '1', ' '),
202 VLC_FOURCC('c', 'c', '2', ' '),
203 VLC_FOURCC('c', 'c', '3', ' '),
204 VLC_FOURCC('c', 'c', '4', ' '),
206 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc
)
209 for( i
= 0; i
< 4; i
++ )
211 if( fcc
== EsOutFourccClosedCaptions
[i
] )
216 static inline bool EsFmtIsTeletext( const es_format_t
*p_fmt
)
218 return p_fmt
->i_cat
== SPU_ES
&& p_fmt
->i_codec
== VLC_CODEC_TELETEXT
;
221 /*****************************************************************************
223 *****************************************************************************/
224 es_out_t
*input_EsOutNew( input_thread_t
*p_input
, int i_rate
)
226 es_out_t
*out
= malloc( sizeof( *out
) );
230 es_out_sys_t
*p_sys
= malloc( sizeof( *p_sys
) );
237 out
->pf_add
= EsOutAdd
;
238 out
->pf_send
= EsOutSend
;
239 out
->pf_del
= EsOutDel
;
240 out
->pf_control
= EsOutControl
;
241 out
->pf_destroy
= EsOutDelete
;
244 vlc_mutex_init_recursive( &p_sys
->lock
);
245 p_sys
->p_input
= p_input
;
247 p_sys
->b_active
= false;
248 p_sys
->i_mode
= ES_OUT_MODE_NONE
;
251 TAB_INIT( p_sys
->i_pgrm
, p_sys
->pgrm
);
252 p_sys
->p_pgrm
= NULL
;
256 TAB_INIT( p_sys
->i_es
, p_sys
->es
);
263 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
265 p_sys
->i_audio_last
= var_GetInteger( p_input
, "audio-track" );
267 p_sys
->i_sub_last
= var_GetInteger( p_input
, "sub-track" );
269 p_sys
->i_default_sub_id
= -1;
271 if( !p_input
->b_preparsing
)
275 psz_string
= var_GetString( p_input
, "audio-language" );
276 p_sys
->ppsz_audio_language
= LanguageSplit( psz_string
, true );
277 if( p_sys
->ppsz_audio_language
)
279 for( int i
= 0; p_sys
->ppsz_audio_language
[i
]; i
++ )
280 msg_Dbg( p_input
, "selected audio language[%d] %s",
281 i
, p_sys
->ppsz_audio_language
[i
] );
285 psz_string
= var_GetString( p_input
, "sub-language" );
286 p_sys
->ppsz_sub_language
= LanguageSplit( psz_string
, false );
287 if( p_sys
->ppsz_sub_language
)
289 for( int i
= 0; p_sys
->ppsz_sub_language
[i
]; i
++ )
290 msg_Dbg( p_input
, "selected subtitle language[%d] %s",
291 i
, p_sys
->ppsz_sub_language
[i
] );
297 p_sys
->ppsz_sub_language
= NULL
;
298 p_sys
->ppsz_audio_language
= NULL
;
301 p_sys
->i_audio_id
= var_GetInteger( p_input
, "audio-track-id" );
303 p_sys
->i_sub_id
= var_GetInteger( p_input
, "sub-track-id" );
305 p_sys
->p_es_audio
= NULL
;
306 p_sys
->p_es_video
= NULL
;
307 p_sys
->p_es_sub
= NULL
;
309 p_sys
->i_audio_delay
= 0;
310 p_sys
->i_spu_delay
= 0;
312 p_sys
->b_paused
= false;
313 p_sys
->i_pause_date
= -1;
315 p_sys
->i_rate
= i_rate
;
316 p_sys
->i_pts_delay
= 0;
317 p_sys
->i_pts_jitter
= 0;
318 p_sys
->i_cr_average
= 0;
320 p_sys
->b_buffering
= true;
321 p_sys
->i_buffering_extra_initial
= 0;
322 p_sys
->i_buffering_extra_stream
= 0;
323 p_sys
->i_buffering_extra_system
= 0;
324 p_sys
->i_preroll_end
= -1;
326 p_sys
->p_sout_record
= NULL
;
331 /*****************************************************************************
333 *****************************************************************************/
334 static void EsOutDelete( es_out_t
*out
)
336 es_out_sys_t
*p_sys
= out
->p_sys
;
338 assert( !p_sys
->i_es
&& !p_sys
->i_pgrm
&& !p_sys
->p_pgrm
);
339 if( p_sys
->ppsz_audio_language
)
341 for( int i
= 0; p_sys
->ppsz_audio_language
[i
]; i
++ )
342 free( p_sys
->ppsz_audio_language
[i
] );
343 free( p_sys
->ppsz_audio_language
);
345 if( p_sys
->ppsz_sub_language
)
347 for( int i
= 0; p_sys
->ppsz_sub_language
[i
]; i
++ )
348 free( p_sys
->ppsz_sub_language
[i
] );
349 free( p_sys
->ppsz_sub_language
);
352 vlc_mutex_destroy( &p_sys
->lock
);
358 static void EsOutTerminate( es_out_t
*out
)
360 es_out_sys_t
*p_sys
= out
->p_sys
;
362 if( p_sys
->p_sout_record
)
363 EsOutSetRecord( out
, false );
365 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
367 if( p_sys
->es
[i
]->p_dec
)
368 input_DecoderDelete( p_sys
->es
[i
]->p_dec
);
370 free( p_sys
->es
[i
]->psz_language
);
371 free( p_sys
->es
[i
]->psz_language_code
);
372 es_format_Clean( &p_sys
->es
[i
]->fmt
);
374 free( p_sys
->es
[i
] );
376 TAB_CLEAN( p_sys
->i_es
, p_sys
->es
);
378 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
379 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
381 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[i
];
382 input_clock_Delete( p_pgrm
->p_clock
);
383 free( p_pgrm
->psz_now_playing
);
384 free( p_pgrm
->psz_publisher
);
385 free( p_pgrm
->psz_name
);
389 TAB_CLEAN( p_sys
->i_pgrm
, p_sys
->pgrm
);
391 p_sys
->p_pgrm
= NULL
;
393 input_item_SetEpgOffline( p_sys
->p_input
->p
->p_item
);
394 input_SendEventMetaEpg( p_sys
->p_input
);
397 static mtime_t
EsOutGetWakeup( es_out_t
*out
)
399 es_out_sys_t
*p_sys
= out
->p_sys
;
400 input_thread_t
*p_input
= p_sys
->p_input
;
405 /* We do not have a wake up date if the input cannot have its speed
406 * controlled or sout is imposing its own or while buffering
408 * FIXME for !p_input->p->b_can_pace_control a wkeup time is still needed to avoid too strong buffering */
409 if( !p_input
->p
->b_can_pace_control
||
410 p_input
->p
->b_out_pace_control
||
414 return input_clock_GetWakeup( p_sys
->p_pgrm
->p_clock
);
417 static es_out_id_t
*EsOutGetFromID( es_out_t
*out
, int i_id
)
422 /* Special HACK, -i_id is the cat of the stream */
423 return (es_out_id_t
*)((uint8_t*)NULL
-i_id
);
426 for( i
= 0; i
< out
->p_sys
->i_es
; i
++ )
428 if( out
->p_sys
->es
[i
]->i_id
== i_id
)
429 return out
->p_sys
->es
[i
];
434 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
436 es_out_sys_t
*p_sys
= out
->p_sys
;
439 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
441 EsOutDecodersStopBuffering( out
, true );
442 if( p_sys
->b_buffering
)
446 for( i
= 0; i
< p_sys
->i_es
; i
++ )
448 es_out_id_t
*es
= p_sys
->es
[i
];
450 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
452 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
458 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, int64_t i_delay
)
460 es_out_sys_t
*p_sys
= out
->p_sys
;
462 if( i_cat
== AUDIO_ES
)
463 p_sys
->i_audio_delay
= i_delay
;
464 else if( i_cat
== SPU_ES
)
465 p_sys
->i_spu_delay
= i_delay
;
467 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
468 EsOutDecoderChangeDelay( out
, p_sys
->es
[i
] );
471 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
473 es_out_sys_t
*p_sys
= out
->p_sys
;
474 input_thread_t
*p_input
= p_sys
->p_input
;
476 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
480 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
483 if( var_CountChoices( p_input
, "video-es" ) )
484 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
485 else if( var_CountChoices( p_input
, "audio-es" ) )
486 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
488 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
491 char *psz_sout
= NULL
; // TODO conf
493 if( !psz_sout
&& psz_path
)
495 char *psz_file
= input_CreateFilename( VLC_OBJECT(p_input
), psz_path
, INPUT_RECORD_PREFIX
, NULL
);
498 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file
) < 0 )
509 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
513 if( !p_sys
->p_sout_record
)
516 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
518 es_out_id_t
*p_es
= p_sys
->es
[i
];
520 if( !p_es
->p_dec
|| p_es
->p_master
)
523 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
524 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
525 input_DecoderStartBuffering( p_es
->p_dec_record
);
530 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
532 es_out_id_t
*p_es
= p_sys
->es
[i
];
534 if( !p_es
->p_dec_record
)
537 input_DecoderDelete( p_es
->p_dec_record
);
538 p_es
->p_dec_record
= NULL
;
541 sout_DeleteInstance( p_sys
->p_sout_record
);
543 p_sys
->p_sout_record
= NULL
;
548 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
550 es_out_sys_t
*p_sys
= out
->p_sys
;
552 /* XXX the order is important */
555 EsOutDecodersChangePause( out
, true, i_date
);
556 EsOutProgramChangePause( out
, true, i_date
);
560 if( p_sys
->i_buffering_extra_initial
> 0 )
562 mtime_t i_stream_start
;
563 mtime_t i_system_start
;
564 mtime_t i_stream_duration
;
565 mtime_t i_system_duration
;
567 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
568 &i_stream_start
, &i_system_start
,
569 &i_stream_duration
, &i_system_duration
);
572 /* FIXME pcr != exactly what wanted */
573 const mtime_t i_used
= /*(i_stream_duration - p_sys->p_input->p->i_pts_delay)*/ p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
576 p_sys
->i_buffering_extra_initial
= 0;
577 p_sys
->i_buffering_extra_stream
= 0;
578 p_sys
->i_buffering_extra_system
= 0;
580 EsOutProgramChangePause( out
, false, i_date
);
581 EsOutDecodersChangePause( out
, false, i_date
);
583 EsOutProgramsChangeRate( out
);
585 p_sys
->b_paused
= b_paused
;
586 p_sys
->i_pause_date
= i_date
;
589 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
591 es_out_sys_t
*p_sys
= out
->p_sys
;
593 p_sys
->i_rate
= i_rate
;
594 EsOutProgramsChangeRate( out
);
597 static void EsOutChangePosition( es_out_t
*out
)
599 es_out_sys_t
*p_sys
= out
->p_sys
;
601 input_SendEventCache( p_sys
->p_input
, 0.0 );
603 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
605 es_out_id_t
*p_es
= p_sys
->es
[i
];
610 input_DecoderStartBuffering( p_es
->p_dec
);
612 if( p_es
->p_dec_record
)
613 input_DecoderStartBuffering( p_es
->p_dec_record
);
616 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
617 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
619 p_sys
->b_buffering
= true;
620 p_sys
->i_buffering_extra_initial
= 0;
621 p_sys
->i_buffering_extra_stream
= 0;
622 p_sys
->i_buffering_extra_system
= 0;
623 p_sys
->i_preroll_end
= -1;
628 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
630 es_out_sys_t
*p_sys
= out
->p_sys
;
633 mtime_t i_stream_start
;
634 mtime_t i_system_start
;
635 mtime_t i_stream_duration
;
636 mtime_t i_system_duration
;
637 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
638 &i_stream_start
, &i_system_start
,
639 &i_stream_duration
, &i_system_duration
);
640 assert( !i_ret
|| b_forced
);
644 mtime_t i_preroll_duration
= 0;
645 if( p_sys
->i_preroll_end
>= 0 )
646 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
648 const mtime_t i_buffering_duration
= p_sys
->i_pts_delay
+
650 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
652 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
654 const double f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
655 input_SendEventCache( p_sys
->p_input
, f_level
);
657 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", (int)(100 * f_level
) );
660 input_SendEventCache( p_sys
->p_input
, 1.0 );
662 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
663 (int)(i_stream_duration
/1000), (int)(i_system_duration
/1000) );
664 p_sys
->b_buffering
= false;
665 p_sys
->i_preroll_end
= -1;
667 if( p_sys
->i_buffering_extra_initial
> 0 )
673 const mtime_t i_decoder_buffering_start
= mdate();
674 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
676 es_out_id_t
*p_es
= p_sys
->es
[i
];
678 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
680 input_DecoderWaitBuffering( p_es
->p_dec
);
681 if( p_es
->p_dec_record
)
682 input_DecoderWaitBuffering( p_es
->p_dec_record
);
685 msg_Dbg( p_sys
->p_input
, "Decoder buffering done in %d ms",
686 (int)(mdate() - i_decoder_buffering_start
)/1000 );
688 /* Here is a good place to destroy unused vout with every demuxer */
689 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
692 const mtime_t i_wakeup_delay
= 10*1000; /* FIXME CLEANUP thread wake up time*/
693 const mtime_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: mdate();
695 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_clock
, true,
696 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
698 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
700 es_out_id_t
*p_es
= p_sys
->es
[i
];
705 input_DecoderStopBuffering( p_es
->p_dec
);
706 if( p_es
->p_dec_record
)
707 input_DecoderStopBuffering( p_es
->p_dec_record
);
710 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
712 es_out_sys_t
*p_sys
= out
->p_sys
;
714 /* Pause decoders first */
715 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
717 es_out_id_t
*es
= p_sys
->es
[i
];
721 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
722 if( es
->p_dec_record
)
723 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
728 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
730 es_out_sys_t
*p_sys
= out
->p_sys
;
733 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
735 es_out_id_t
*p_es
= p_sys
->es
[i
];
738 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
739 if( p_es
->p_dec_record
)
740 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
742 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
744 /* TODO maybe we want to be able to tune it ? */
745 #if defined(OPTIMIZE_MEMORY)
746 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
748 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
750 return i_size
< i_level_high
;
753 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
755 es_out_sys_t
*p_sys
= out
->p_sys
;
757 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
758 input_clock_ChangePause( p_sys
->pgrm
[i
]->p_clock
, b_paused
, i_date
);
761 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
763 es_out_sys_t
*p_sys
= out
->p_sys
;
766 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
767 i_delay
= p_sys
->i_audio_delay
;
768 else if( p_es
->fmt
.i_cat
== SPU_ES
)
769 i_delay
= p_sys
->i_spu_delay
;
774 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
775 if( p_es
->p_dec_record
)
776 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
779 static void EsOutProgramsChangeRate( es_out_t
*out
)
781 es_out_sys_t
*p_sys
= out
->p_sys
;
783 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
784 input_clock_ChangeRate( p_sys
->pgrm
[i
]->p_clock
, p_sys
->i_rate
);
787 static void EsOutFrameNext( es_out_t
*out
)
789 es_out_sys_t
*p_sys
= out
->p_sys
;
790 es_out_id_t
*p_es_video
= NULL
;
792 if( p_sys
->b_buffering
)
794 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
798 assert( p_sys
->b_paused
);
800 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
802 es_out_id_t
*p_es
= p_sys
->es
[i
];
804 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
813 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
818 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
820 msg_Dbg( out
->p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)(i_duration
/1000) );
822 if( i_duration
<= 0 )
823 i_duration
= 40*1000;
825 /* FIXME it is not a clean way ? */
826 if( p_sys
->i_buffering_extra_initial
<= 0 )
828 mtime_t i_stream_start
;
829 mtime_t i_system_start
;
830 mtime_t i_stream_duration
;
831 mtime_t i_system_duration
;
834 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
835 &i_stream_start
, &i_system_start
,
836 &i_stream_duration
, &i_system_duration
);
840 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
841 p_sys
->i_buffering_extra_system
=
842 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
845 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_clock
);
847 p_sys
->b_buffering
= true;
848 p_sys
->i_buffering_extra_system
+= i_duration
;
849 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
850 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
851 INPUT_RATE_DEFAULT
/ i_rate
;
853 p_sys
->i_preroll_end
= -1;
855 static mtime_t
EsOutGetBuffering( es_out_t
*out
)
857 es_out_sys_t
*p_sys
= out
->p_sys
;
863 mtime_t i_stream_start
;
864 mtime_t i_system_start
;
865 mtime_t i_stream_duration
;
866 mtime_t i_system_duration
;
867 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
868 &i_stream_start
, &i_system_start
,
869 &i_stream_duration
, &i_system_duration
);
876 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
878 i_delay
= i_stream_duration
;
882 mtime_t i_system_duration
;
883 if( p_sys
->b_paused
)
885 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
886 if( p_sys
->i_buffering_extra_initial
> 0 )
887 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
891 i_system_duration
= mdate() - i_system_start
;
894 const mtime_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
895 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
902 static void EsOutESVarUpdateGeneric( es_out_t
*out
, int i_id
,
903 const es_format_t
*fmt
, const char *psz_language
,
906 es_out_sys_t
*p_sys
= out
->p_sys
;
907 input_thread_t
*p_input
= p_sys
->p_input
;
908 vlc_value_t val
, text
;
912 if( EsFmtIsTeletext( fmt
) )
913 input_SendEventTeletextDel( p_sys
->p_input
, i_id
);
915 input_SendEventEsDel( p_input
, fmt
->i_cat
, i_id
);
919 /* Get the number of ES already added */
921 if( fmt
->i_cat
== AUDIO_ES
)
922 psz_var
= "audio-es";
923 else if( fmt
->i_cat
== VIDEO_ES
)
924 psz_var
= "video-es";
928 var_Change( p_input
, psz_var
, VLC_VAR_CHOICESCOUNT
, &val
, NULL
);
933 /* First one, we need to add the "Disable" choice */
934 val2
.i_int
= -1; text
.psz_string
= _("Disable");
935 var_Change( p_input
, psz_var
, VLC_VAR_ADDCHOICE
, &val2
, &text
);
939 /* Take care of the ES description */
940 if( fmt
->psz_description
&& *fmt
->psz_description
)
942 if( psz_language
&& *psz_language
)
944 if( asprintf( &text
.psz_string
, "%s - [%s]", fmt
->psz_description
,
945 psz_language
) == -1 )
946 text
.psz_string
= NULL
;
948 else text
.psz_string
= strdup( fmt
->psz_description
);
952 if( psz_language
&& *psz_language
)
954 if( asprintf( &text
.psz_string
, "%s %"PRId64
" - [%s]", _( "Track" ), val
.i_int
, psz_language
) == -1 )
955 text
.psz_string
= NULL
;
959 if( asprintf( &text
.psz_string
, "%s %"PRId64
, _( "Track" ), val
.i_int
) == -1 )
960 text
.psz_string
= NULL
;
964 input_SendEventEsAdd( p_input
, fmt
->i_cat
, i_id
, text
.psz_string
);
965 if( EsFmtIsTeletext( fmt
) )
968 snprintf( psz_page
, sizeof(psz_page
), "%d%2.2x",
969 fmt
->subs
.teletext
.i_magazine
,
970 fmt
->subs
.teletext
.i_page
);
971 input_SendEventTeletextAdd( p_sys
->p_input
,
972 i_id
, fmt
->subs
.teletext
.i_magazine
>= 0 ? psz_page
: NULL
);
975 free( text
.psz_string
);
978 static void EsOutESVarUpdate( es_out_t
*out
, es_out_id_t
*es
,
981 EsOutESVarUpdateGeneric( out
, es
->i_id
, &es
->fmt
, es
->psz_language
, b_delete
);
984 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
986 return out
->p_sys
->i_group_id
== 0 || out
->p_sys
->i_group_id
== i_group
;
989 /* EsOutProgramSelect:
990 * Select a program and update the object variable
992 static void EsOutProgramSelect( es_out_t
*out
, es_out_pgrm_t
*p_pgrm
)
994 es_out_sys_t
*p_sys
= out
->p_sys
;
995 input_thread_t
*p_input
= p_sys
->p_input
;
998 if( p_sys
->p_pgrm
== p_pgrm
)
999 return; /* Nothing to do */
1003 es_out_pgrm_t
*old
= p_sys
->p_pgrm
;
1004 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
1006 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1008 if( p_sys
->es
[i
]->p_pgrm
== old
&& EsIsSelected( p_sys
->es
[i
] ) &&
1009 p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
1010 EsUnselect( out
, p_sys
->es
[i
], true );
1013 p_sys
->p_es_audio
= NULL
;
1014 p_sys
->p_es_sub
= NULL
;
1015 p_sys
->p_es_video
= NULL
;
1018 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
1020 /* Mark it selected */
1021 p_pgrm
->b_selected
= true;
1023 /* Switch master stream */
1024 p_sys
->p_pgrm
= p_pgrm
;
1026 /* Update "program" */
1027 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
1030 input_SendEventEsDel( p_input
, AUDIO_ES
, -1 );
1031 input_SendEventEsDel( p_input
, VIDEO_ES
, -1 );
1032 input_SendEventEsDel( p_input
, SPU_ES
, -1 );
1033 input_SendEventTeletextDel( p_input
, -1 );
1034 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1037 var_SetInteger( p_input
, "teletext-es", -1 );
1039 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1041 if( p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
)
1042 EsOutESVarUpdate( out
, p_sys
->es
[i
], false );
1043 EsOutSelect( out
, p_sys
->es
[i
], false );
1046 /* Update now playing */
1047 input_item_SetNowPlaying( p_input
->p
->p_item
, p_pgrm
->psz_now_playing
);
1048 input_item_SetPublisher( p_input
->p
->p_item
, p_pgrm
->psz_publisher
);
1050 input_SendEventMeta( p_input
);
1056 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1058 es_out_sys_t
*p_sys
= out
->p_sys
;
1059 input_thread_t
*p_input
= p_sys
->p_input
;
1061 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1066 p_pgrm
->i_id
= i_group
;
1068 p_pgrm
->b_selected
= false;
1069 p_pgrm
->b_scrambled
= false;
1070 p_pgrm
->psz_name
= NULL
;
1071 p_pgrm
->psz_now_playing
= NULL
;
1072 p_pgrm
->psz_publisher
= NULL
;
1073 p_pgrm
->p_clock
= input_clock_New( p_sys
->i_rate
);
1074 if( !p_pgrm
->p_clock
)
1079 if( p_sys
->b_paused
)
1080 input_clock_ChangePause( p_pgrm
->p_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1081 input_clock_SetJitter( p_pgrm
->p_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1084 TAB_APPEND( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1086 /* Update "program" variable */
1087 if( EsOutIsProgramVisible( out
, i_group
) )
1088 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1090 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1091 EsOutProgramSelect( out
, p_pgrm
);
1099 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1101 es_out_sys_t
*p_sys
= out
->p_sys
;
1102 input_thread_t
*p_input
= p_sys
->p_input
;
1103 es_out_pgrm_t
*p_pgrm
= NULL
;
1106 for( i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1108 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1110 p_pgrm
= p_sys
->pgrm
[i
];
1115 if( p_pgrm
== NULL
)
1116 return VLC_EGENERIC
;
1120 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1121 i_group
, p_pgrm
->i_es
);
1122 return VLC_EGENERIC
;
1125 TAB_REMOVE( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1127 /* If program is selected we need to unselect it */
1128 if( p_sys
->p_pgrm
== p_pgrm
)
1129 p_sys
->p_pgrm
= NULL
;
1131 input_clock_Delete( p_pgrm
->p_clock
);
1133 free( p_pgrm
->psz_name
);
1134 free( p_pgrm
->psz_now_playing
);
1135 free( p_pgrm
->psz_publisher
);
1138 /* Update "program" variable */
1139 input_SendEventProgramDel( p_input
, i_group
);
1146 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1148 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1150 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1152 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1153 return p_sys
->pgrm
[i
];
1155 return EsOutProgramAdd( p_out
, i_group
);
1158 /* EsOutProgramMeta:
1160 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1163 if( p_pgrm
->psz_name
)
1165 if( asprintf( &psz
, _("%s [%s %d]"), p_pgrm
->psz_name
, _("Program"), p_pgrm
->i_id
) == -1 )
1170 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1176 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1178 es_out_sys_t
*p_sys
= out
->p_sys
;
1179 es_out_pgrm_t
*p_pgrm
;
1180 input_thread_t
*p_input
= p_sys
->p_input
;
1181 const char *psz_title
= NULL
;
1182 const char *psz_provider
= NULL
;
1185 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1187 /* Check against empty meta data (empty for what we handle) */
1188 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1189 !vlc_meta_Get( p_meta
, vlc_meta_NowPlaying
) &&
1190 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) &&
1191 vlc_meta_GetExtraCount( p_meta
) <= 0 )
1196 if( !EsOutIsProgramVisible( out
, i_group
) )
1198 p_pgrm
= EsOutProgramFind( out
, i_group
);
1203 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1204 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1206 /* Update the description text of the program */
1207 if( psz_title
&& *psz_title
)
1209 if( !p_pgrm
->psz_name
|| strcmp( p_pgrm
->psz_name
, psz_title
) )
1211 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1213 /* Remove old entries */
1214 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, NULL
);
1215 /* TODO update epg name ?
1216 * TODO update scrambled info name ? */
1219 free( p_pgrm
->psz_name
);
1220 p_pgrm
->psz_name
= strdup( psz_title
);
1223 if( psz_provider
&& *psz_provider
)
1225 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1230 psz_text
= strdup( psz_title
);
1233 /* ugly but it works */
1236 input_SendEventProgramDel( p_input
, i_group
);
1237 input_SendEventProgramAdd( p_input
, i_group
, psz_text
);
1238 if( p_sys
->p_pgrm
== p_pgrm
)
1239 input_SendEventProgramSelect( p_input
, i_group
);
1245 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1247 info_category_t
*p_cat
= NULL
;
1248 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1250 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1252 p_cat
= info_category_New( psz_cat
);
1256 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1259 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1260 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1261 free( ppsz_all_keys
[i
] );
1263 free( ppsz_all_keys
);
1267 if( p_sys
->p_pgrm
== p_pgrm
)
1269 input_item_SetPublisher( p_input
->p
->p_item
, psz_provider
);
1270 input_SendEventMeta( p_input
);
1273 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1274 "%s",psz_provider
);
1277 input_Control( p_input
, INPUT_MERGE_INFOS
, p_cat
);
1280 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1282 es_out_sys_t
*p_sys
= out
->p_sys
;
1283 input_thread_t
*p_input
= p_sys
->p_input
;
1284 input_item_t
*p_item
= p_input
->p
->p_item
;
1285 es_out_pgrm_t
*p_pgrm
;
1289 if( !EsOutIsProgramVisible( out
, i_group
) )
1291 p_pgrm
= EsOutProgramFind( out
, i_group
);
1296 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1297 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1303 epg
.psz_name
= psz_cat
;
1305 input_item_SetEpg( p_item
, &epg
);
1306 input_SendEventMetaEpg( p_sys
->p_input
);
1308 /* Update now playing */
1309 free( p_pgrm
->psz_now_playing
);
1310 p_pgrm
->psz_now_playing
= NULL
;
1312 vlc_mutex_lock( &p_item
->lock
);
1313 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1315 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1317 if( p_tmp
->psz_name
&& !strcmp(p_tmp
->psz_name
, psz_cat
) )
1319 if( p_tmp
->p_current
&& p_tmp
->p_current
->psz_name
&& *p_tmp
->p_current
->psz_name
)
1320 p_pgrm
->psz_now_playing
= strdup( p_tmp
->p_current
->psz_name
);
1324 vlc_mutex_unlock( &p_item
->lock
);
1326 if( p_pgrm
== p_sys
->p_pgrm
)
1328 input_item_SetNowPlaying( p_input
->p
->p_item
, p_pgrm
->psz_now_playing
);
1329 input_SendEventMeta( p_input
);
1332 if( p_pgrm
->psz_now_playing
)
1334 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
,
1335 vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying
),
1336 p_pgrm
->psz_now_playing
);
1340 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
,
1341 vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying
) );
1347 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1349 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1350 input_thread_t
*p_input
= p_sys
->p_input
;
1351 bool b_scrambled
= false;
1353 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
1355 if( p_sys
->es
[i
]->p_pgrm
== p_pgrm
&& p_sys
->es
[i
]->b_scrambled
)
1361 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1364 p_pgrm
->b_scrambled
= b_scrambled
;
1365 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1368 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
, _("Scrambled"), _("Yes") );
1370 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, _("Scrambled") );
1372 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1375 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1377 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1378 input_thread_t
*p_input
= p_sys
->p_input
;
1380 input_item_t
*p_item
= input_GetItem( p_input
);
1382 char *psz_title
= NULL
;
1383 char *psz_arturl
= input_item_GetArtURL( p_item
);
1385 vlc_mutex_lock( &p_item
->lock
);
1387 if( vlc_meta_Get( p_meta
, vlc_meta_Title
) && !p_item
->b_fixed_name
)
1388 psz_title
= strdup( vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1390 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1392 if( !psz_arturl
|| *psz_arturl
== '\0' )
1394 const char *psz_tmp
= vlc_meta_Get( p_item
->p_meta
, vlc_meta_ArtworkURL
);
1396 psz_arturl
= strdup( psz_tmp
);
1398 vlc_mutex_unlock( &p_item
->lock
);
1400 if( psz_arturl
&& *psz_arturl
)
1402 input_item_SetArtURL( p_item
, psz_arturl
);
1404 if( !strncmp( psz_arturl
, "attachment://", strlen("attachment") ) )
1406 /* Don't look for art cover if sout
1407 * XXX It can change when sout has meta data support */
1408 if( p_input
->p
->p_sout
&& !p_input
->b_preparsing
)
1409 input_item_SetArtURL( p_item
, "" );
1411 input_ExtractAttachmentAndCacheArt( p_input
);
1418 input_item_SetName( p_item
, psz_title
);
1421 input_item_SetPreparsed( p_item
, true );
1423 input_SendEventMeta( p_input
);
1424 /* TODO handle sout meta ? */
1430 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1432 es_out_sys_t
*p_sys
= out
->p_sys
;
1433 input_thread_t
*p_input
= p_sys
->p_input
;
1435 if( fmt
->i_group
< 0 )
1437 msg_Err( p_input
, "invalid group number" );
1441 es_out_id_t
*es
= malloc( sizeof( *es
) );
1442 es_out_pgrm_t
*p_pgrm
;
1448 vlc_mutex_lock( &p_sys
->lock
);
1450 /* Search the program */
1451 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1454 vlc_mutex_unlock( &p_sys
->lock
);
1459 /* Increase ref count for program */
1463 es
->p_pgrm
= p_pgrm
;
1464 es_format_Copy( &es
->fmt
, fmt
);
1465 if( es
->fmt
.i_id
< 0 )
1466 es
->fmt
.i_id
= out
->p_sys
->i_id
;
1467 if( !es
->fmt
.i_original_fourcc
)
1468 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1469 if( es
->fmt
.i_cat
== AUDIO_ES
)
1470 es
->fmt
.i_codec
= vlc_fourcc_GetCodecAudio( es
->fmt
.i_codec
,
1471 es
->fmt
.audio
.i_bitspersample
);
1473 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
,
1476 es
->i_id
= es
->fmt
.i_id
;
1477 es
->i_meta_id
= out
->p_sys
->i_id
;
1478 es
->b_scrambled
= false;
1480 switch( es
->fmt
.i_cat
)
1484 audio_replay_gain_t rg
;
1486 es
->i_channel
= p_sys
->i_audio
;
1488 memset( &rg
, 0, sizeof(rg
) );
1489 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1490 vlc_audio_replay_gain_MergeFromMeta( &rg
, p_input
->p
->p_item
->p_meta
);
1491 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1493 for( i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1495 if( !es
->fmt
.audio_replay_gain
.pb_peak
[i
] )
1497 es
->fmt
.audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1498 es
->fmt
.audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1500 if( !es
->fmt
.audio_replay_gain
.pb_gain
[i
] )
1502 es
->fmt
.audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1503 es
->fmt
.audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1510 es
->i_channel
= p_sys
->i_video
;
1511 if( es
->fmt
.video
.i_frame_rate
&& es
->fmt
.video
.i_frame_rate_base
)
1512 vlc_ureduce( &es
->fmt
.video
.i_frame_rate
,
1513 &es
->fmt
.video
.i_frame_rate_base
,
1514 es
->fmt
.video
.i_frame_rate
,
1515 es
->fmt
.video
.i_frame_rate_base
, 0 );
1519 es
->i_channel
= p_sys
->i_sub
;
1526 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1527 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1529 es
->p_dec_record
= NULL
;
1530 for( i
= 0; i
< 4; i
++ )
1531 es
->pb_cc_present
[i
] = false;
1532 es
->p_master
= NULL
;
1534 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1535 EsOutESVarUpdate( out
, es
, false );
1537 /* Select it if needed */
1538 EsOutSelect( out
, es
, false );
1541 TAB_APPEND( out
->p_sys
->i_es
, out
->p_sys
->es
, es
);
1542 p_sys
->i_id
++; /* always incremented */
1543 switch( es
->fmt
.i_cat
)
1556 EsOutUpdateInfo( out
, es
, &es
->fmt
, NULL
);
1558 if( es
->b_scrambled
)
1559 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1561 vlc_mutex_unlock( &p_sys
->lock
);
1566 static bool EsIsSelected( es_out_id_t
*es
)
1570 bool b_decode
= false;
1571 if( es
->p_master
->p_dec
)
1573 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1574 if( i_channel
!= -1 )
1575 input_DecoderGetCcState( es
->p_master
->p_dec
, &b_decode
, i_channel
);
1581 return es
->p_dec
!= NULL
;
1584 static void EsCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1586 es_out_sys_t
*p_sys
= out
->p_sys
;
1587 input_thread_t
*p_input
= p_sys
->p_input
;
1589 p_es
->p_dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_input
->p
->p_sout
);
1592 if( p_sys
->b_buffering
)
1593 input_DecoderStartBuffering( p_es
->p_dec
);
1595 if( !p_es
->p_master
&& p_sys
->p_sout_record
)
1597 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
1598 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
1599 input_DecoderStartBuffering( p_es
->p_dec_record
);
1603 EsOutDecoderChangeDelay( out
, p_es
);
1605 static void EsDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1612 input_DecoderDelete( p_es
->p_dec
);
1615 if( p_es
->p_dec_record
)
1617 input_DecoderDelete( p_es
->p_dec_record
);
1618 p_es
->p_dec_record
= NULL
;
1622 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
)
1624 es_out_sys_t
*p_sys
= out
->p_sys
;
1625 input_thread_t
*p_input
= p_sys
->p_input
;
1627 if( EsIsSelected( es
) )
1629 msg_Warn( p_input
, "ES 0x%x is already selected", es
->i_id
);
1636 if( !es
->p_master
->p_dec
)
1639 i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1640 if( i_channel
== -1 || input_DecoderSetCcState( es
->p_master
->p_dec
, true, i_channel
) )
1645 const bool b_sout
= p_input
->p
->p_sout
!= NULL
;
1646 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1648 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1650 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1655 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1657 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) )
1659 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1664 if( es
->fmt
.i_cat
== SPU_ES
)
1666 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) )
1668 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1674 EsCreateDecoder( out
, es
);
1676 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1680 /* Mark it as selected */
1681 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, es
->i_id
);
1682 input_SendEventTeletextSelect( p_input
, EsFmtIsTeletext( &es
->fmt
) ? es
->i_id
: -1 );
1685 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1687 es_out_sys_t
*p_sys
= out
->p_sys
;
1688 input_thread_t
*p_input
= p_sys
->p_input
;
1690 if( !EsIsSelected( es
) )
1692 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->i_id
);
1698 if( es
->p_master
->p_dec
)
1700 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1701 if( i_channel
!= -1 )
1702 input_DecoderSetCcState( es
->p_master
->p_dec
, false, i_channel
);
1707 const int i_spu_id
= var_GetInteger( p_input
, "spu-es");
1709 for( i
= 0; i
< 4; i
++ )
1711 if( !es
->pb_cc_present
[i
] || !es
->pp_cc_es
[i
] )
1714 if( i_spu_id
== es
->pp_cc_es
[i
]->i_id
)
1716 /* Force unselection of the CC */
1717 input_SendEventEsSelect( p_input
, SPU_ES
, -1 );
1719 EsOutDel( out
, es
->pp_cc_es
[i
] );
1721 es
->pb_cc_present
[i
] = false;
1723 EsDestroyDecoder( out
, es
);
1729 /* Mark it as unselected */
1730 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, -1 );
1731 if( EsFmtIsTeletext( &es
->fmt
) )
1732 input_SendEventTeletextSelect( p_input
, -1 );
1736 * Select an ES given the current mode
1737 * XXX: you need to take a the lock before (stream.stream_lock)
1739 * \param out The es_out structure
1740 * \param es es_out_id structure
1741 * \param b_force ...
1744 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1746 es_out_sys_t
*p_sys
= out
->p_sys
;
1748 int i_cat
= es
->fmt
.i_cat
;
1750 if( !p_sys
->b_active
||
1751 ( !b_force
&& es
->fmt
.i_priority
< 0 ) )
1756 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
1758 if( !EsIsSelected( es
) )
1759 EsSelect( out
, es
);
1761 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
1763 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
1768 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1770 prgm
= strtok_r( NULL
, ",", &buf
) )
1772 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
1774 if( !EsIsSelected( es
) )
1775 EsSelect( out
, es
);
1782 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1786 if( es
->p_pgrm
!= p_sys
->p_pgrm
)
1789 if( i_cat
== AUDIO_ES
)
1791 int idx1
= LanguageArrayIndex( p_sys
->ppsz_audio_language
,
1792 es
->psz_language_code
);
1794 if( p_sys
->p_es_audio
&&
1795 p_sys
->p_es_audio
->fmt
.i_priority
>= es
->fmt
.i_priority
)
1797 int idx2
= LanguageArrayIndex( p_sys
->ppsz_audio_language
,
1798 p_sys
->p_es_audio
->psz_language_code
);
1800 if( idx1
< 0 || ( idx2
>= 0 && idx2
<= idx1
) )
1802 i_wanted
= es
->i_channel
;
1806 /* Select audio if (no audio selected yet)
1807 * - no audio-language
1808 * - no audio code for the ES
1809 * - audio code in the requested list */
1811 !strcmp( es
->psz_language_code
, "??" ) ||
1812 !p_sys
->ppsz_audio_language
)
1813 i_wanted
= es
->i_channel
;
1816 if( p_sys
->i_audio_last
>= 0 )
1817 i_wanted
= p_sys
->i_audio_last
;
1819 if( p_sys
->i_audio_id
>= 0 )
1821 if( es
->i_id
== p_sys
->i_audio_id
)
1822 i_wanted
= es
->i_channel
;
1827 else if( i_cat
== SPU_ES
)
1829 int idx1
= LanguageArrayIndex( p_sys
->ppsz_sub_language
,
1830 es
->psz_language_code
);
1832 if( p_sys
->p_es_sub
&&
1833 p_sys
->p_es_sub
->fmt
.i_priority
>= es
->fmt
.i_priority
)
1835 int idx2
= LanguageArrayIndex( p_sys
->ppsz_sub_language
,
1836 p_sys
->p_es_sub
->psz_language_code
);
1838 msg_Dbg( p_sys
->p_input
, "idx1=%d(%s) idx2=%d(%s)",
1839 idx1
, es
->psz_language_code
, idx2
,
1840 p_sys
->p_es_sub
->psz_language_code
);
1842 if( idx1
< 0 || ( idx2
>= 0 && idx2
<= idx1
) )
1844 /* We found a SPU that matches our language request */
1845 i_wanted
= es
->i_channel
;
1847 else if( idx1
>= 0 )
1849 msg_Dbg( p_sys
->p_input
, "idx1=%d(%s)",
1850 idx1
, es
->psz_language_code
);
1852 i_wanted
= es
->i_channel
;
1854 else if( p_sys
->i_default_sub_id
>= 0 )
1856 if( es
->i_id
== p_sys
->i_default_sub_id
)
1857 i_wanted
= es
->i_channel
;
1860 if( p_sys
->i_sub_last
>= 0 )
1861 i_wanted
= p_sys
->i_sub_last
;
1863 if( p_sys
->i_sub_id
>= 0 )
1865 if( es
->i_id
== p_sys
->i_sub_id
)
1866 i_wanted
= es
->i_channel
;
1871 else if( i_cat
== VIDEO_ES
)
1873 i_wanted
= es
->i_channel
;
1876 if( i_wanted
== es
->i_channel
&& !EsIsSelected( es
) )
1877 EsSelect( out
, es
);
1880 /* FIXME TODO handle priority here */
1881 if( EsIsSelected( es
) )
1883 if( i_cat
== AUDIO_ES
)
1885 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1886 p_sys
->p_es_audio
&&
1887 p_sys
->p_es_audio
!= es
&&
1888 EsIsSelected( p_sys
->p_es_audio
) )
1890 EsUnselect( out
, p_sys
->p_es_audio
, false );
1892 p_sys
->p_es_audio
= es
;
1894 else if( i_cat
== SPU_ES
)
1896 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1898 p_sys
->p_es_sub
!= es
&&
1899 EsIsSelected( p_sys
->p_es_sub
) )
1901 EsUnselect( out
, p_sys
->p_es_sub
, false );
1903 p_sys
->p_es_sub
= es
;
1905 else if( i_cat
== VIDEO_ES
)
1907 p_sys
->p_es_video
= es
;
1913 * Send a block for the given es_out
1915 * \param out the es_out to send from
1916 * \param es the es_out_id
1917 * \param p_block the data block to send
1919 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
1921 es_out_sys_t
*p_sys
= out
->p_sys
;
1922 input_thread_t
*p_input
= p_sys
->p_input
;
1925 if( libvlc_stats( p_input
) )
1927 vlc_mutex_lock( &p_input
->p
->counters
.counters_lock
);
1928 stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_demux_read
,
1929 p_block
->i_buffer
, &i_total
);
1930 stats_UpdateFloat( p_input
, p_input
->p
->counters
.p_demux_bitrate
,
1931 (float)i_total
, NULL
);
1933 /* Update number of corrupted data packats */
1934 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
1936 stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_demux_corrupted
,
1939 /* Update number of discontinuities */
1940 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
1942 stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_demux_discontinuity
,
1945 vlc_mutex_unlock( &p_input
->p
->counters
.counters_lock
);
1948 vlc_mutex_lock( &p_sys
->lock
);
1950 /* Mark preroll blocks */
1951 if( p_sys
->i_preroll_end
>= 0 )
1953 int64_t i_date
= p_block
->i_pts
;
1954 if( p_block
->i_pts
<= VLC_TS_INVALID
)
1955 i_date
= p_block
->i_dts
;
1957 if( i_date
< p_sys
->i_preroll_end
)
1958 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
1961 p_block
->i_rate
= 0;
1965 block_Release( p_block
);
1966 vlc_mutex_unlock( &p_sys
->lock
);
1970 /* Check for sout mode */
1971 if( p_input
->p
->p_sout
)
1973 /* FIXME review this, proper lock may be missing */
1974 if( p_input
->p
->p_sout
->i_out_pace_nocontrol
> 0 &&
1975 p_input
->p
->b_out_pace_control
)
1977 msg_Dbg( p_input
, "switching to sync mode" );
1978 p_input
->p
->b_out_pace_control
= false;
1980 else if( p_input
->p
->p_sout
->i_out_pace_nocontrol
<= 0 &&
1981 !p_input
->p
->b_out_pace_control
)
1983 msg_Dbg( p_input
, "switching to async mode" );
1984 p_input
->p
->b_out_pace_control
= true;
1989 if( es
->p_dec_record
)
1991 block_t
*p_dup
= block_Duplicate( p_block
);
1993 input_DecoderDecode( es
->p_dec_record
, p_dup
,
1994 p_input
->p
->b_out_pace_control
);
1996 input_DecoderDecode( es
->p_dec
, p_block
,
1997 p_input
->p
->b_out_pace_control
);
1999 es_format_t fmt_dsc
;
2000 vlc_meta_t
*p_meta_dsc
;
2001 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
2003 EsOutUpdateInfo( out
, es
, &fmt_dsc
, p_meta_dsc
);
2005 es_format_Clean( &fmt_dsc
);
2007 vlc_meta_Delete( p_meta_dsc
);
2010 /* Check CC status */
2013 input_DecoderIsCcPresent( es
->p_dec
, pb_cc
);
2014 for( int i
= 0; i
< 4; i
++ )
2018 if( es
->pb_cc_present
[i
] || !pb_cc
[i
] )
2020 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, es
->i_id
);
2022 es_format_Init( &fmt
, SPU_ES
, EsOutFourccClosedCaptions
[i
] );
2023 fmt
.i_group
= es
->fmt
.i_group
;
2024 if( asprintf( &fmt
.psz_description
,
2025 _("Closed captions %u"), 1 + i
) == -1 )
2026 fmt
.psz_description
= NULL
;
2027 es
->pp_cc_es
[i
] = EsOutAdd( out
, &fmt
);
2028 es
->pp_cc_es
[i
]->p_master
= es
;
2029 es_format_Clean( &fmt
);
2032 es
->pb_cc_present
[i
] = true;
2035 vlc_mutex_unlock( &p_sys
->lock
);
2040 /*****************************************************************************
2042 *****************************************************************************/
2043 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2045 es_out_sys_t
*p_sys
= out
->p_sys
;
2046 bool b_reselect
= false;
2049 vlc_mutex_lock( &p_sys
->lock
);
2051 /* We don't try to reselect */
2054 while( !p_sys
->p_input
->b_die
&& !p_sys
->b_buffering
&& es
->p_dec
)
2056 if( input_DecoderIsEmpty( es
->p_dec
) &&
2057 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2059 /* FIXME there should be a way to have auto deleted es, but there will be
2060 * a problem when another codec of the same type is created (mainly video) */
2063 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2066 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2067 EsOutESVarUpdate( out
, es
, true );
2069 TAB_REMOVE( p_sys
->i_es
, p_sys
->es
, es
);
2071 /* Update program */
2073 if( es
->p_pgrm
->i_es
== 0 )
2074 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2076 if( es
->b_scrambled
)
2077 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2080 if( p_sys
->p_es_audio
== es
|| p_sys
->p_es_video
== es
||
2081 p_sys
->p_es_sub
== es
) b_reselect
= true;
2083 if( p_sys
->p_es_audio
== es
) p_sys
->p_es_audio
= NULL
;
2084 if( p_sys
->p_es_video
== es
) p_sys
->p_es_video
= NULL
;
2085 if( p_sys
->p_es_sub
== es
) p_sys
->p_es_sub
= NULL
;
2087 switch( es
->fmt
.i_cat
)
2100 /* Re-select another track when needed */
2103 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2105 if( es
->fmt
.i_cat
== p_sys
->es
[i
]->fmt
.i_cat
)
2106 EsOutSelect( out
, p_sys
->es
[i
], false );
2110 free( es
->psz_language
);
2111 free( es
->psz_language_code
);
2113 es_format_Clean( &es
->fmt
);
2115 vlc_mutex_unlock( &p_sys
->lock
);
2121 * Control query handler
2123 * \param out the es_out to control
2124 * \param i_query A es_out query as defined in include/ninput.h
2125 * \param args a variable list of arguments for the query
2126 * \return VLC_SUCCESS or an error code
2128 static int EsOutControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2130 es_out_sys_t
*p_sys
= out
->p_sys
;
2134 case ES_OUT_SET_ES_STATE
:
2136 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2137 bool b
= va_arg( args
, int );
2138 if( b
&& !EsIsSelected( es
) )
2140 EsSelect( out
, es
);
2141 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2143 else if( !b
&& EsIsSelected( es
) )
2145 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2151 case ES_OUT_GET_ES_STATE
:
2153 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2154 bool *pb
= va_arg( args
, bool * );
2156 *pb
= EsIsSelected( es
);
2160 case ES_OUT_GET_GROUP_FORCED
:
2162 int *pi_group
= va_arg( args
, int * );
2163 *pi_group
= p_sys
->i_group_id
;
2167 case ES_OUT_SET_MODE
:
2169 const int i_mode
= va_arg( args
, int );
2170 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2171 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2172 i_mode
== ES_OUT_MODE_END
);
2174 if( i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& p_sys
->i_es
> 0 )
2176 /* XXX Terminate vout if there are tracks but no video one.
2177 * This one is not mandatory but is he earliest place where it
2180 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2182 es_out_id_t
*p_es
= p_sys
->es
[i
];
2183 if( p_es
->fmt
.i_cat
== VIDEO_ES
)
2186 if( i
>= p_sys
->i_es
)
2187 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
2189 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2190 p_sys
->i_mode
= i_mode
;
2192 /* Reapply policy mode */
2193 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2195 if( EsIsSelected( p_sys
->es
[i
] ) )
2196 EsUnselect( out
, p_sys
->es
[i
],
2197 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2199 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2200 EsOutSelect( out
, p_sys
->es
[i
], false );
2201 if( i_mode
== ES_OUT_MODE_END
)
2202 EsOutTerminate( out
);
2207 case ES_OUT_RESTART_ES
:
2209 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2214 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2216 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2218 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2223 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2227 if( es
== p_sys
->es
[i
] )
2229 EsOutSelect( out
, es
, true );
2235 if( i_cat
== UNKNOWN_ES
|| p_sys
->es
[i
]->fmt
.i_cat
== i_cat
)
2237 if( EsIsSelected( p_sys
->es
[i
] ) )
2239 if( i_query
== ES_OUT_RESTART_ES
)
2241 if( p_sys
->es
[i
]->p_dec
)
2243 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2244 EsCreateDecoder( out
, p_sys
->es
[i
] );
2249 EsUnselect( out
, p_sys
->es
[i
],
2250 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2259 case ES_OUT_SET_ES_DEFAULT
:
2261 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2265 /*p_sys->i_default_video_id = -1;*/
2266 /*p_sys->i_default_audio_id = -1;*/
2267 p_sys
->i_default_sub_id
= -1;
2269 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2271 /*p_sys->i_default_video_id = -1;*/
2273 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2275 /*p_sys->i_default_audio_id = -1;*/
2277 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2279 p_sys
->i_default_sub_id
= -1;
2283 /*if( es->fmt.i_cat == VIDEO_ES )
2284 p_sys->i_default_video_id = es->i_id;
2286 if( es->fmt.i_cat == AUDIO_ES )
2287 p_sys->i_default_audio_id = es->i_id;
2289 if( es
->fmt
.i_cat
== SPU_ES
)
2290 p_sys
->i_default_sub_id
= es
->i_id
;
2295 case ES_OUT_SET_PCR
:
2296 case ES_OUT_SET_GROUP_PCR
:
2298 es_out_pgrm_t
*p_pgrm
= NULL
;
2302 /* Search program */
2303 if( i_query
== ES_OUT_SET_PCR
)
2305 p_pgrm
= p_sys
->p_pgrm
;
2307 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2311 i_group
= (int)va_arg( args
, int );
2312 p_pgrm
= EsOutProgramFind( out
, i_group
);
2315 return VLC_EGENERIC
;
2317 i_pcr
= (int64_t)va_arg( args
, int64_t );
2318 if( i_pcr
<= VLC_TS_INVALID
)
2320 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2321 return VLC_EGENERIC
;
2324 /* TODO do not use mdate() but proper stream acquisition date */
2326 input_clock_Update( p_pgrm
->p_clock
, VLC_OBJECT(p_sys
->p_input
),
2328 p_sys
->p_input
->p
->b_can_pace_control
|| p_sys
->b_buffering
,
2329 EsOutIsExtraBufferingAllowed( out
),
2332 if( p_pgrm
== p_sys
->p_pgrm
)
2334 if( p_sys
->b_buffering
)
2336 /* Check buffering state on master clock update */
2337 EsOutDecodersStopBuffering( out
, false );
2339 else if( b_late
&& ( !p_sys
->p_input
->p
->p_sout
||
2340 !p_sys
->p_input
->p
->b_out_pace_control
) )
2342 const mtime_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2343 mtime_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_clock
);
2345 /* Avoid dangerously high value */
2346 const mtime_t i_jitter_max
= INT64_C(1000) * var_InheritInteger( p_sys
->p_input
, "clock-jitter" );
2347 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2349 msg_Err( p_sys
->p_input
,
2350 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2351 (int)(i_pts_delay
- i_pts_delay_base
) / 1000 );
2352 i_pts_delay
= p_sys
->i_pts_delay
;
2356 msg_Err( p_sys
->p_input
,
2357 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2358 (int)(i_pts_delay
/1000) );
2361 /* Force a rebufferization when we are too late */
2363 /* It is not really good, as we throw away already buffered data
2364 * TODO have a mean to correctly reenter bufferization */
2365 es_out_Control( out
, ES_OUT_RESET_PCR
);
2367 es_out_SetJitter( out
, i_pts_delay_base
, i_pts_delay
- i_pts_delay_base
, p_sys
->i_cr_average
);
2373 case ES_OUT_RESET_PCR
:
2374 msg_Err( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2375 EsOutChangePosition( out
);
2378 case ES_OUT_SET_GROUP
:
2380 int i
= va_arg( args
, int );
2381 for( int j
= 0; j
< p_sys
->i_pgrm
; j
++ )
2383 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[j
];
2384 if( p_pgrm
->i_id
== i
)
2386 EsOutProgramSelect( out
, p_pgrm
);
2390 return VLC_EGENERIC
;
2393 case ES_OUT_SET_ES_FMT
:
2395 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2396 * to update the p_extra data */
2397 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2398 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2400 return VLC_EGENERIC
;
2402 if( p_fmt
->i_extra
)
2404 es
->fmt
.i_extra
= p_fmt
->i_extra
;
2405 es
->fmt
.p_extra
= xrealloc( es
->fmt
.p_extra
, p_fmt
->i_extra
);
2406 memcpy( es
->fmt
.p_extra
, p_fmt
->p_extra
, p_fmt
->i_extra
);
2411 EsDestroyDecoder( out
, es
);
2413 EsCreateDecoder( out
, es
);
2415 es
->p_dec
->fmt_in
.i_extra
= p_fmt
->i_extra
;
2416 es
->p_dec
->fmt_in
.p_extra
=
2417 xrealloc( es
->p_dec
->fmt_in
.p_extra
, p_fmt
->i_extra
);
2418 memcpy( es
->p_dec
->fmt_in
.p_extra
,
2419 p_fmt
->p_extra
, p_fmt
->i_extra
);
2426 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2428 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2429 bool b_scrambled
= (bool)va_arg( args
, int );
2431 if( !es
->b_scrambled
!= !b_scrambled
)
2433 es
->b_scrambled
= b_scrambled
;
2434 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2439 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2441 const int64_t i_date
= (int64_t)va_arg( args
, int64_t );
2444 return VLC_EGENERIC
;
2446 p_sys
->i_preroll_end
= i_date
;
2450 case ES_OUT_SET_GROUP_META
:
2452 int i_group
= (int)va_arg( args
, int );
2453 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2455 EsOutProgramMeta( out
, i_group
, p_meta
);
2458 case ES_OUT_SET_GROUP_EPG
:
2460 int i_group
= (int)va_arg( args
, int );
2461 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2463 EsOutProgramEpg( out
, i_group
, p_epg
);
2467 case ES_OUT_DEL_GROUP
:
2469 int i_group
= (int)va_arg( args
, int );
2471 return EsOutProgramDel( out
, i_group
);
2474 case ES_OUT_SET_META
:
2476 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2478 EsOutMeta( out
, p_meta
);
2482 case ES_OUT_GET_WAKE_UP
:
2484 mtime_t
*pi_wakeup
= (mtime_t
*)va_arg( args
, mtime_t
* );
2485 *pi_wakeup
= EsOutGetWakeup( out
);
2489 case ES_OUT_SET_ES_BY_ID
:
2490 case ES_OUT_RESTART_ES_BY_ID
:
2491 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2493 const int i_id
= (int)va_arg( args
, int );
2494 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2499 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
; break;
2500 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2501 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2505 /* TODO if the lock is made non recursive it should be changed */
2506 int i_ret
= es_out_Control( out
, i_new_query
, p_es
);
2508 /* Clean up vout after user action (in active mode only).
2509 * FIXME it does not work well with multiple video windows */
2510 if( p_sys
->b_active
)
2511 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
2515 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2517 const int i_id
= va_arg( args
, int );
2518 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2520 return VLC_EGENERIC
;
2522 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2523 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2524 aout_instance_t
**pp_aout
= va_arg( args
, aout_instance_t
** );
2528 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2529 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2543 case ES_OUT_GET_BUFFERING
:
2545 bool *pb
= va_arg( args
, bool* );
2546 *pb
= p_sys
->b_buffering
;
2550 case ES_OUT_GET_EMPTY
:
2552 bool *pb
= va_arg( args
, bool* );
2553 *pb
= EsOutDecodersIsEmpty( out
);
2557 case ES_OUT_SET_DELAY
:
2559 const int i_cat
= (int)va_arg( args
, int );
2560 const mtime_t i_delay
= (mtime_t
)va_arg( args
, mtime_t
);
2561 EsOutSetDelay( out
, i_cat
, i_delay
);
2565 case ES_OUT_SET_RECORD_STATE
:
2567 bool b
= va_arg( args
, int );
2568 return EsOutSetRecord( out
, b
);
2571 case ES_OUT_SET_PAUSE_STATE
:
2573 const bool b_source_paused
= (bool)va_arg( args
, int );
2574 const bool b_paused
= (bool)va_arg( args
, int );
2575 const mtime_t i_date
= (mtime_t
) va_arg( args
, mtime_t
);
2577 assert( !b_source_paused
== !b_paused
);
2578 EsOutChangePause( out
, b_paused
, i_date
);
2583 case ES_OUT_SET_RATE
:
2585 const int i_src_rate
= (int)va_arg( args
, int );
2586 const int i_rate
= (int)va_arg( args
, int );
2588 assert( i_src_rate
== i_rate
);
2589 EsOutChangeRate( out
, i_rate
);
2594 case ES_OUT_SET_TIME
:
2596 const mtime_t i_date
= (mtime_t
)va_arg( args
, mtime_t
);
2598 assert( i_date
== -1 );
2599 EsOutChangePosition( out
);
2604 case ES_OUT_SET_FRAME_NEXT
:
2605 EsOutFrameNext( out
);
2608 case ES_OUT_SET_TIMES
:
2610 double f_position
= (double)va_arg( args
, double );
2611 mtime_t i_time
= (mtime_t
)va_arg( args
, mtime_t
);
2612 mtime_t i_length
= (mtime_t
)va_arg( args
, mtime_t
);
2614 input_SendEventLength( p_sys
->p_input
, i_length
);
2616 if( !p_sys
->b_buffering
)
2620 /* Fix for buffering delay */
2621 if( !p_sys
->p_input
->p
->p_sout
||
2622 !p_sys
->p_input
->p
->b_out_pace_control
)
2623 i_delay
= EsOutGetBuffering( out
);
2632 f_position
-= (double)i_delay
/ i_length
;
2633 if( f_position
< 0 )
2636 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
2640 case ES_OUT_SET_JITTER
:
2642 mtime_t i_pts_delay
= (mtime_t
)va_arg( args
, mtime_t
);
2643 mtime_t i_pts_jitter
= (mtime_t
)va_arg( args
, mtime_t
);
2644 int i_cr_average
= (int)va_arg( args
, int );
2646 bool b_change_clock
=
2647 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
2648 i_cr_average
!= p_sys
->i_cr_average
;
2650 assert( i_pts_jitter
>= 0 );
2651 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
2652 p_sys
->i_pts_jitter
= i_pts_jitter
;
2653 p_sys
->i_cr_average
= i_cr_average
;
2655 for( int i
= 0; i
< p_sys
->i_pgrm
&& b_change_clock
; i
++ )
2656 input_clock_SetJitter( p_sys
->pgrm
[i
]->p_clock
,
2657 i_pts_delay
+ i_pts_jitter
, i_cr_average
);
2661 case ES_OUT_GET_PCR_SYSTEM
:
2663 if( p_sys
->b_buffering
)
2664 return VLC_EGENERIC
;
2666 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2668 return VLC_EGENERIC
;
2670 mtime_t
*pi_system
= va_arg( args
, mtime_t
*);
2671 mtime_t
*pi_delay
= va_arg( args
, mtime_t
*);
2672 input_clock_GetSystemOrigin( p_pgrm
->p_clock
, pi_system
, pi_delay
);
2676 case ES_OUT_MODIFY_PCR_SYSTEM
:
2678 if( p_sys
->b_buffering
)
2679 return VLC_EGENERIC
;
2681 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2683 return VLC_EGENERIC
;
2685 const bool b_absolute
= va_arg( args
, int );
2686 const mtime_t i_system
= va_arg( args
, mtime_t
);
2687 input_clock_ChangeSystemOrigin( p_pgrm
->p_clock
, b_absolute
, i_system
);
2692 msg_Err( p_sys
->p_input
, "unknown query in es_out_Control" );
2693 return VLC_EGENERIC
;
2696 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
2698 es_out_sys_t
*p_sys
= out
->p_sys
;
2701 vlc_mutex_lock( &p_sys
->lock
);
2702 i_ret
= EsOutControlLocked( out
, i_query
, args
);
2703 vlc_mutex_unlock( &p_sys
->lock
);
2708 /****************************************************************************
2709 * LanguageGetName: try to expend iso639 into plain name
2710 ****************************************************************************/
2711 static char *LanguageGetName( const char *psz_code
)
2713 const iso639_lang_t
*pl
;
2715 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
2717 return strdup( "" );
2720 if( strlen( psz_code
) == 2 )
2722 pl
= GetLang_1( psz_code
);
2724 else if( strlen( psz_code
) == 3 )
2726 pl
= GetLang_2B( psz_code
);
2727 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2729 pl
= GetLang_2T( psz_code
);
2734 return strdup( psz_code
);
2737 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2739 return strdup( psz_code
);
2743 if( *pl
->psz_native_name
)
2745 return strdup( pl
->psz_native_name
);
2747 return strdup( pl
->psz_eng_name
);
2751 /* Get a 2 char code */
2752 static char *LanguageGetCode( const char *psz_lang
)
2754 const iso639_lang_t
*pl
;
2756 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
2757 return strdup("??");
2759 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
2761 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
2762 !strcasecmp( pl
->psz_native_name
, psz_lang
) ||
2763 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
2764 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
2765 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
2769 if( pl
->psz_eng_name
!= NULL
)
2770 return strdup( pl
->psz_iso639_1
);
2772 return strdup("??");
2775 static char **LanguageSplit( const char *psz_langs
, bool b_default_any
)
2782 if( psz_langs
== NULL
) return NULL
;
2784 psz_parser
= psz_dup
= strdup(psz_langs
);
2786 while( psz_parser
&& *psz_parser
)
2791 psz
= strchr(psz_parser
, ',' );
2792 if( psz
) *psz
++ = '\0';
2794 if( !strcmp( psz_parser
, "any" ) )
2796 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2798 else if( !strcmp( psz_parser
, "none" ) )
2800 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
2804 psz_code
= LanguageGetCode( psz_parser
);
2805 if( strcmp( psz_code
, "??" ) )
2807 TAB_APPEND( i_psz
, ppsz
, psz_code
);
2820 if( b_default_any
&& strcmp( ppsz
[i_psz
- 1], "none" ) )
2821 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2822 TAB_APPEND( i_psz
, ppsz
, NULL
);
2829 static int LanguageArrayIndex( char **ppsz_langs
, char *psz_lang
)
2833 if( !ppsz_langs
|| !psz_lang
) return -1;
2835 for( i
= 0; ppsz_langs
[i
]; i
++ )
2837 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
2838 !strcasecmp( ppsz_langs
[i
], "any" ) )
2840 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
2847 /****************************************************************************
2849 * - add meta info to the playlist item
2850 ****************************************************************************/
2851 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
, const vlc_meta_t
*p_meta
)
2853 es_out_sys_t
*p_sys
= out
->p_sys
;
2854 input_thread_t
*p_input
= p_sys
->p_input
;
2855 const es_format_t
*p_fmt_es
= &es
->fmt
;
2858 /* Create category */
2860 snprintf( psz_cat
, sizeof(psz_cat
),_("Stream %d"), es
->i_meta_id
);
2861 info_category_t
*p_cat
= info_category_New( psz_cat
);
2865 /* Add information */
2866 const char *psz_type
;
2867 switch( fmt
->i_cat
)
2870 psz_type
= _("Audio");
2873 psz_type
= _("Video");
2876 psz_type
= _("Subtitle");
2884 info_category_AddInfo( p_cat
, _("Type"), "%s", psz_type
);
2886 if( es
->i_meta_id
!= es
->i_id
)
2887 info_category_AddInfo( p_cat
, _("Original ID"),
2890 const char *psz_codec_description
=
2891 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, p_fmt_es
->i_codec
);
2892 const vlc_fourcc_t i_codec_fourcc
= ( p_fmt_es
->i_original_fourcc
)?
2893 p_fmt_es
->i_original_fourcc
: p_fmt_es
->i_codec
;
2894 if( psz_codec_description
)
2895 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
2896 psz_codec_description
, (char*)&i_codec_fourcc
);
2898 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
2899 (char*)&i_codec_fourcc
);
2901 if( es
->psz_language
&& *es
->psz_language
)
2902 info_category_AddInfo( p_cat
, _("Language"), "%s",
2904 if( fmt
->psz_description
&& *fmt
->psz_description
)
2905 info_category_AddInfo( p_cat
, _("Description"), "%s",
2906 fmt
->psz_description
);
2908 switch( fmt
->i_cat
)
2911 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
2913 if( fmt
->audio
.i_physical_channels
& AOUT_CHAN_PHYSMASK
)
2914 info_category_AddInfo( p_cat
, _("Channels"), "%s",
2915 _( aout_FormatPrintChannels( &fmt
->audio
) ) );
2916 else if( fmt
->audio
.i_channels
> 0 )
2917 info_category_AddInfo( p_cat
, _("Channels"), "%u",
2918 fmt
->audio
.i_channels
);
2920 if( fmt
->audio
.i_rate
> 0 )
2922 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
2923 fmt
->audio
.i_rate
);
2924 /* FIXME that should be removed or improved ! (used by text/strings.c) */
2925 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
2928 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
2929 if( i_bitspersample
<= 0 )
2930 i_bitspersample
= aout_BitsPerSample( p_fmt_es
->i_codec
);
2931 if( i_bitspersample
> 0 )
2932 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
2935 if( fmt
->i_bitrate
> 0 )
2937 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
2938 fmt
->i_bitrate
/ 1000 );
2939 /* FIXME that should be removed or improved ! (used by text/strings.c) */
2940 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
2942 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
2944 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
2945 if( !p_rg
->pb_gain
[i
] )
2947 const char *psz_name
;
2948 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
2949 psz_name
= _("Track replay gain");
2951 psz_name
= _("Album replay gain");
2952 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
2958 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
2960 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
2961 info_category_AddInfo( p_cat
, _("Resolution"), "%ux%u",
2962 fmt
->video
.i_width
, fmt
->video
.i_height
);
2964 if( fmt
->video
.i_visible_width
> 0 &&
2965 fmt
->video
.i_visible_height
> 0 )
2966 info_category_AddInfo( p_cat
, _("Display resolution"), "%ux%u",
2967 fmt
->video
.i_visible_width
,
2968 fmt
->video
.i_visible_height
);
2969 if( fmt
->video
.i_frame_rate
> 0 &&
2970 fmt
->video
.i_frame_rate_base
> 0 )
2972 div
= lldiv( (float)fmt
->video
.i_frame_rate
/
2973 fmt
->video
.i_frame_rate_base
* 1000000,
2976 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
".%06u",
2977 div
.quot
, (unsigned int )div
.rem
);
2979 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
,
2985 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
2992 /* Append generic meta */
2995 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
2996 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
2998 char *psz_key
= ppsz_all_keys
[i
];
2999 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
3002 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
3003 vlc_gettext(psz_value
) );
3006 free( ppsz_all_keys
);
3009 input_Control( p_input
, INPUT_REPLACE_INFOS
, p_cat
);