1 /*****************************************************************************
2 * es_out.c: Es Out handler for input.
3 *****************************************************************************
4 * Copyright (C) 2003-2004 VLC authors and VideoLAN
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 it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * 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"
50 #include "../stream_output/stream_output.h"
52 #include <vlc_iso_lang.h>
53 /* FIXME we should find a better way than including that */
54 #include "../text/iso-639_def.h"
56 /*****************************************************************************
58 *****************************************************************************/
64 /* Number of es for this pgrm */
70 /* Clock for this program */
71 input_clock_t
*p_clock
;
74 char *psz_now_playing
;
82 es_out_pgrm_t
*p_pgrm
;
87 /* Channel in the track type */
91 char *psz_language_code
;
94 decoder_t
*p_dec_record
;
96 /* Fields for Video with CC */
97 bool pb_cc_present
[4];
98 es_out_id_t
*pp_cc_es
[4];
100 /* Field for CC track from a master video */
101 es_out_id_t
*p_master
;
103 /* ID for the meta data */
109 input_thread_t
*p_input
;
116 es_out_pgrm_t
**pgrm
;
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
= calloc( 1, 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
);
253 TAB_INIT( p_sys
->i_es
, p_sys
->es
);
256 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
257 p_sys
->i_audio_last
= var_GetInteger( p_input
, "audio-track" );
258 p_sys
->i_sub_last
= var_GetInteger( p_input
, "sub-track" );
260 p_sys
->i_default_sub_id
= -1;
262 if( !p_input
->b_preparsing
)
266 psz_string
= var_GetString( p_input
, "audio-language" );
267 p_sys
->ppsz_audio_language
= LanguageSplit( psz_string
, true );
268 if( p_sys
->ppsz_audio_language
)
270 for( int i
= 0; p_sys
->ppsz_audio_language
[i
]; i
++ )
271 msg_Dbg( p_input
, "selected audio language[%d] %s",
272 i
, p_sys
->ppsz_audio_language
[i
] );
276 psz_string
= var_GetString( p_input
, "sub-language" );
277 p_sys
->ppsz_sub_language
= LanguageSplit( psz_string
, false );
278 if( p_sys
->ppsz_sub_language
)
280 for( int i
= 0; p_sys
->ppsz_sub_language
[i
]; i
++ )
281 msg_Dbg( p_input
, "selected subtitle language[%d] %s",
282 i
, p_sys
->ppsz_sub_language
[i
] );
287 p_sys
->i_audio_id
= var_GetInteger( p_input
, "audio-track-id" );
289 p_sys
->i_sub_id
= var_GetInteger( p_input
, "sub-track-id" );
291 p_sys
->i_pause_date
= -1;
293 p_sys
->i_rate
= i_rate
;
295 p_sys
->b_buffering
= true;
296 p_sys
->i_preroll_end
= -1;
301 /*****************************************************************************
303 *****************************************************************************/
304 static void EsOutDelete( es_out_t
*out
)
306 es_out_sys_t
*p_sys
= out
->p_sys
;
308 assert( !p_sys
->i_es
&& !p_sys
->i_pgrm
&& !p_sys
->p_pgrm
);
309 if( p_sys
->ppsz_audio_language
)
311 for( int i
= 0; p_sys
->ppsz_audio_language
[i
]; i
++ )
312 free( p_sys
->ppsz_audio_language
[i
] );
313 free( p_sys
->ppsz_audio_language
);
315 if( p_sys
->ppsz_sub_language
)
317 for( int i
= 0; p_sys
->ppsz_sub_language
[i
]; i
++ )
318 free( p_sys
->ppsz_sub_language
[i
] );
319 free( p_sys
->ppsz_sub_language
);
322 vlc_mutex_destroy( &p_sys
->lock
);
328 static void EsOutTerminate( es_out_t
*out
)
330 es_out_sys_t
*p_sys
= out
->p_sys
;
332 if( p_sys
->p_sout_record
)
333 EsOutSetRecord( out
, false );
335 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
337 if( p_sys
->es
[i
]->p_dec
)
338 input_DecoderDelete( p_sys
->es
[i
]->p_dec
);
340 free( p_sys
->es
[i
]->psz_language
);
341 free( p_sys
->es
[i
]->psz_language_code
);
342 es_format_Clean( &p_sys
->es
[i
]->fmt
);
344 free( p_sys
->es
[i
] );
346 TAB_CLEAN( p_sys
->i_es
, p_sys
->es
);
348 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
349 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
351 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[i
];
352 input_clock_Delete( p_pgrm
->p_clock
);
353 free( p_pgrm
->psz_now_playing
);
354 free( p_pgrm
->psz_publisher
);
355 free( p_pgrm
->psz_name
);
359 TAB_CLEAN( p_sys
->i_pgrm
, p_sys
->pgrm
);
361 p_sys
->p_pgrm
= NULL
;
363 input_item_SetEpgOffline( p_sys
->p_input
->p
->p_item
);
364 input_SendEventMetaEpg( p_sys
->p_input
);
367 static mtime_t
EsOutGetWakeup( es_out_t
*out
)
369 es_out_sys_t
*p_sys
= out
->p_sys
;
370 input_thread_t
*p_input
= p_sys
->p_input
;
375 /* We do not have a wake up date if the input cannot have its speed
376 * controlled or sout is imposing its own or while buffering
378 * FIXME for !p_input->p->b_can_pace_control a wake-up time is still needed
379 * to avoid too heavy buffering */
380 if( !p_input
->p
->b_can_pace_control
||
381 p_input
->p
->b_out_pace_control
||
385 return input_clock_GetWakeup( p_sys
->p_pgrm
->p_clock
);
388 static es_out_id_t
*EsOutGetFromID( es_out_t
*out
, int i_id
)
392 /* Special HACK, -i_id is the cat of the stream */
393 return (es_out_id_t
*)((uint8_t*)NULL
-i_id
);
396 for( int i
= 0; i
< out
->p_sys
->i_es
; i
++ )
398 if( out
->p_sys
->es
[i
]->i_id
== i_id
)
399 return out
->p_sys
->es
[i
];
404 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
406 es_out_sys_t
*p_sys
= out
->p_sys
;
408 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
410 EsOutDecodersStopBuffering( out
, true );
411 if( p_sys
->b_buffering
)
415 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
417 es_out_id_t
*es
= p_sys
->es
[i
];
419 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
421 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
427 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, int64_t i_delay
)
429 es_out_sys_t
*p_sys
= out
->p_sys
;
431 if( i_cat
== AUDIO_ES
)
432 p_sys
->i_audio_delay
= i_delay
;
433 else if( i_cat
== SPU_ES
)
434 p_sys
->i_spu_delay
= i_delay
;
436 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
437 EsOutDecoderChangeDelay( out
, p_sys
->es
[i
] );
440 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
442 es_out_sys_t
*p_sys
= out
->p_sys
;
443 input_thread_t
*p_input
= p_sys
->p_input
;
445 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
449 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
452 if( var_CountChoices( p_input
, "video-es" ) )
453 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
454 else if( var_CountChoices( p_input
, "audio-es" ) )
455 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
457 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
460 char *psz_sout
= NULL
; // TODO conf
462 if( !psz_sout
&& psz_path
)
464 char *psz_file
= input_CreateFilename( VLC_OBJECT(p_input
), psz_path
, INPUT_RECORD_PREFIX
, NULL
);
467 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file
) < 0 )
478 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
482 if( !p_sys
->p_sout_record
)
485 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
487 es_out_id_t
*p_es
= p_sys
->es
[i
];
489 if( !p_es
->p_dec
|| p_es
->p_master
)
492 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
493 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
494 input_DecoderStartBuffering( p_es
->p_dec_record
);
499 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
501 es_out_id_t
*p_es
= p_sys
->es
[i
];
503 if( !p_es
->p_dec_record
)
506 input_DecoderDelete( p_es
->p_dec_record
);
507 p_es
->p_dec_record
= NULL
;
510 sout_DeleteInstance( p_sys
->p_sout_record
);
512 p_sys
->p_sout_record
= NULL
;
517 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
519 es_out_sys_t
*p_sys
= out
->p_sys
;
521 /* XXX the order is important */
524 EsOutDecodersChangePause( out
, true, i_date
);
525 EsOutProgramChangePause( out
, true, i_date
);
529 if( p_sys
->i_buffering_extra_initial
> 0 )
531 mtime_t i_stream_start
;
532 mtime_t i_system_start
;
533 mtime_t i_stream_duration
;
534 mtime_t i_system_duration
;
536 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
537 &i_stream_start
, &i_system_start
,
538 &i_stream_duration
, &i_system_duration
);
541 /* FIXME pcr != exactly what wanted */
542 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
;
545 p_sys
->i_buffering_extra_initial
= 0;
546 p_sys
->i_buffering_extra_stream
= 0;
547 p_sys
->i_buffering_extra_system
= 0;
549 EsOutProgramChangePause( out
, false, i_date
);
550 EsOutDecodersChangePause( out
, false, i_date
);
552 EsOutProgramsChangeRate( out
);
554 p_sys
->b_paused
= b_paused
;
555 p_sys
->i_pause_date
= i_date
;
558 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
560 es_out_sys_t
*p_sys
= out
->p_sys
;
562 p_sys
->i_rate
= i_rate
;
563 EsOutProgramsChangeRate( out
);
566 static void EsOutChangePosition( es_out_t
*out
)
568 es_out_sys_t
*p_sys
= out
->p_sys
;
570 input_SendEventCache( p_sys
->p_input
, 0.0 );
572 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
574 es_out_id_t
*p_es
= p_sys
->es
[i
];
579 input_DecoderStartBuffering( p_es
->p_dec
);
581 if( p_es
->p_dec_record
)
582 input_DecoderStartBuffering( p_es
->p_dec_record
);
585 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
586 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
588 p_sys
->b_buffering
= true;
589 p_sys
->i_buffering_extra_initial
= 0;
590 p_sys
->i_buffering_extra_stream
= 0;
591 p_sys
->i_buffering_extra_system
= 0;
592 p_sys
->i_preroll_end
= -1;
597 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
599 es_out_sys_t
*p_sys
= out
->p_sys
;
602 mtime_t i_stream_start
;
603 mtime_t i_system_start
;
604 mtime_t i_stream_duration
;
605 mtime_t i_system_duration
;
606 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
607 &i_stream_start
, &i_system_start
,
608 &i_stream_duration
, &i_system_duration
);
609 assert( !i_ret
|| b_forced
);
613 mtime_t i_preroll_duration
= 0;
614 if( p_sys
->i_preroll_end
>= 0 )
615 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
617 const mtime_t i_buffering_duration
= p_sys
->i_pts_delay
+
619 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
621 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
623 const double f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
624 input_SendEventCache( p_sys
->p_input
, f_level
);
626 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", (int)(100 * f_level
) );
629 input_SendEventCache( p_sys
->p_input
, 1.0 );
631 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
632 (int)(i_stream_duration
/1000), (int)(i_system_duration
/1000) );
633 p_sys
->b_buffering
= false;
634 p_sys
->i_preroll_end
= -1;
636 if( p_sys
->i_buffering_extra_initial
> 0 )
642 const mtime_t i_decoder_buffering_start
= mdate();
643 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
645 es_out_id_t
*p_es
= p_sys
->es
[i
];
647 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
649 input_DecoderWaitBuffering( p_es
->p_dec
);
650 if( p_es
->p_dec_record
)
651 input_DecoderWaitBuffering( p_es
->p_dec_record
);
654 msg_Dbg( p_sys
->p_input
, "Decoder buffering done in %d ms",
655 (int)(mdate() - i_decoder_buffering_start
)/1000 );
657 /* Here is a good place to destroy unused vout with every demuxer */
658 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
661 const mtime_t i_wakeup_delay
= 10*1000; /* FIXME CLEANUP thread wake up time*/
662 const mtime_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: mdate();
664 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_clock
, true,
665 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
667 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
669 es_out_id_t
*p_es
= p_sys
->es
[i
];
674 input_DecoderStopBuffering( p_es
->p_dec
);
675 if( p_es
->p_dec_record
)
676 input_DecoderStopBuffering( p_es
->p_dec_record
);
679 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
681 es_out_sys_t
*p_sys
= out
->p_sys
;
683 /* Pause decoders first */
684 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
686 es_out_id_t
*es
= p_sys
->es
[i
];
690 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
691 if( es
->p_dec_record
)
692 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
697 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
699 es_out_sys_t
*p_sys
= out
->p_sys
;
702 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
704 es_out_id_t
*p_es
= p_sys
->es
[i
];
707 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
708 if( p_es
->p_dec_record
)
709 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
711 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
713 /* TODO maybe we want to be able to tune it ? */
714 #if defined(OPTIMIZE_MEMORY)
715 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
717 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
719 return i_size
< i_level_high
;
722 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
724 es_out_sys_t
*p_sys
= out
->p_sys
;
726 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
727 input_clock_ChangePause( p_sys
->pgrm
[i
]->p_clock
, b_paused
, i_date
);
730 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
732 es_out_sys_t
*p_sys
= out
->p_sys
;
735 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
736 i_delay
= p_sys
->i_audio_delay
;
737 else if( p_es
->fmt
.i_cat
== SPU_ES
)
738 i_delay
= p_sys
->i_spu_delay
;
743 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
744 if( p_es
->p_dec_record
)
745 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
747 static void EsOutProgramsChangeRate( es_out_t
*out
)
749 es_out_sys_t
*p_sys
= out
->p_sys
;
751 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
752 input_clock_ChangeRate( p_sys
->pgrm
[i
]->p_clock
, p_sys
->i_rate
);
755 static void EsOutFrameNext( es_out_t
*out
)
757 es_out_sys_t
*p_sys
= out
->p_sys
;
758 es_out_id_t
*p_es_video
= NULL
;
760 if( p_sys
->b_buffering
)
762 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
766 assert( p_sys
->b_paused
);
768 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
770 es_out_id_t
*p_es
= p_sys
->es
[i
];
772 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
781 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
786 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
788 msg_Dbg( out
->p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)(i_duration
/1000) );
790 if( i_duration
<= 0 )
791 i_duration
= 40*1000;
793 /* FIXME it is not a clean way ? */
794 if( p_sys
->i_buffering_extra_initial
<= 0 )
796 mtime_t i_stream_start
;
797 mtime_t i_system_start
;
798 mtime_t i_stream_duration
;
799 mtime_t i_system_duration
;
802 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
803 &i_stream_start
, &i_system_start
,
804 &i_stream_duration
, &i_system_duration
);
808 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
809 p_sys
->i_buffering_extra_system
=
810 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
813 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_clock
);
815 p_sys
->b_buffering
= true;
816 p_sys
->i_buffering_extra_system
+= i_duration
;
817 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
818 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
819 INPUT_RATE_DEFAULT
/ i_rate
;
821 p_sys
->i_preroll_end
= -1;
823 static mtime_t
EsOutGetBuffering( es_out_t
*out
)
825 es_out_sys_t
*p_sys
= out
->p_sys
;
831 mtime_t i_stream_start
;
832 mtime_t i_system_start
;
833 mtime_t i_stream_duration
;
834 mtime_t i_system_duration
;
835 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
836 &i_stream_start
, &i_system_start
,
837 &i_stream_duration
, &i_system_duration
);
844 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
846 i_delay
= i_stream_duration
;
850 mtime_t i_system_duration
;
851 if( p_sys
->b_paused
)
853 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
854 if( p_sys
->i_buffering_extra_initial
> 0 )
855 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
859 i_system_duration
= mdate() - i_system_start
;
862 const mtime_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
863 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
870 static void EsOutESVarUpdateGeneric( es_out_t
*out
, int i_id
,
871 const es_format_t
*fmt
, const char *psz_language
,
874 es_out_sys_t
*p_sys
= out
->p_sys
;
875 input_thread_t
*p_input
= p_sys
->p_input
;
876 vlc_value_t val
, text
;
880 if( EsFmtIsTeletext( fmt
) )
881 input_SendEventTeletextDel( p_sys
->p_input
, i_id
);
883 input_SendEventEsDel( p_input
, fmt
->i_cat
, i_id
);
887 /* Get the number of ES already added */
889 if( fmt
->i_cat
== AUDIO_ES
)
890 psz_var
= "audio-es";
891 else if( fmt
->i_cat
== VIDEO_ES
)
892 psz_var
= "video-es";
896 var_Change( p_input
, psz_var
, VLC_VAR_CHOICESCOUNT
, &val
, NULL
);
901 /* First one, we need to add the "Disable" choice */
902 val2
.i_int
= -1; text
.psz_string
= _("Disable");
903 var_Change( p_input
, psz_var
, VLC_VAR_ADDCHOICE
, &val2
, &text
);
907 /* Take care of the ES description */
908 if( fmt
->psz_description
&& *fmt
->psz_description
)
910 if( psz_language
&& *psz_language
)
912 if( asprintf( &text
.psz_string
, "%s - [%s]", fmt
->psz_description
,
913 psz_language
) == -1 )
914 text
.psz_string
= NULL
;
916 else text
.psz_string
= strdup( fmt
->psz_description
);
920 if( psz_language
&& *psz_language
)
922 if( asprintf( &text
.psz_string
, "%s %"PRId64
" - [%s]", _( "Track" ), val
.i_int
, psz_language
) == -1 )
923 text
.psz_string
= NULL
;
927 if( asprintf( &text
.psz_string
, "%s %"PRId64
, _( "Track" ), val
.i_int
) == -1 )
928 text
.psz_string
= NULL
;
932 input_SendEventEsAdd( p_input
, fmt
->i_cat
, i_id
, text
.psz_string
);
933 if( EsFmtIsTeletext( fmt
) )
936 snprintf( psz_page
, sizeof(psz_page
), "%d%2.2x",
937 fmt
->subs
.teletext
.i_magazine
,
938 fmt
->subs
.teletext
.i_page
);
939 input_SendEventTeletextAdd( p_sys
->p_input
,
940 i_id
, fmt
->subs
.teletext
.i_magazine
>= 0 ? psz_page
: NULL
);
943 free( text
.psz_string
);
946 static void EsOutESVarUpdate( es_out_t
*out
, es_out_id_t
*es
,
949 EsOutESVarUpdateGeneric( out
, es
->i_id
, &es
->fmt
, es
->psz_language
, b_delete
);
952 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
954 return out
->p_sys
->i_group_id
== 0 || out
->p_sys
->i_group_id
== i_group
;
957 /* EsOutProgramSelect:
958 * Select a program and update the object variable
960 static void EsOutProgramSelect( es_out_t
*out
, es_out_pgrm_t
*p_pgrm
)
962 es_out_sys_t
*p_sys
= out
->p_sys
;
963 input_thread_t
*p_input
= p_sys
->p_input
;
966 if( p_sys
->p_pgrm
== p_pgrm
)
967 return; /* Nothing to do */
971 es_out_pgrm_t
*old
= p_sys
->p_pgrm
;
972 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
974 for( i
= 0; i
< p_sys
->i_es
; i
++ )
976 if( p_sys
->es
[i
]->p_pgrm
== old
&& EsIsSelected( p_sys
->es
[i
] ) &&
977 p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
978 EsUnselect( out
, p_sys
->es
[i
], true );
981 p_sys
->p_es_audio
= NULL
;
982 p_sys
->p_es_sub
= NULL
;
983 p_sys
->p_es_video
= NULL
;
986 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
988 /* Mark it selected */
989 p_pgrm
->b_selected
= true;
991 /* Switch master stream */
992 p_sys
->p_pgrm
= p_pgrm
;
994 /* Update "program" */
995 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
998 input_SendEventEsDel( p_input
, AUDIO_ES
, -1 );
999 input_SendEventEsDel( p_input
, VIDEO_ES
, -1 );
1000 input_SendEventEsDel( p_input
, SPU_ES
, -1 );
1001 input_SendEventTeletextDel( p_input
, -1 );
1002 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1005 var_SetInteger( p_input
, "teletext-es", -1 );
1007 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1009 if( p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
)
1010 EsOutESVarUpdate( out
, p_sys
->es
[i
], false );
1011 EsOutSelect( out
, p_sys
->es
[i
], false );
1014 /* Update now playing */
1015 input_item_SetNowPlaying( p_input
->p
->p_item
, p_pgrm
->psz_now_playing
);
1016 input_item_SetPublisher( p_input
->p
->p_item
, p_pgrm
->psz_publisher
);
1018 input_SendEventMeta( p_input
);
1024 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1026 es_out_sys_t
*p_sys
= out
->p_sys
;
1027 input_thread_t
*p_input
= p_sys
->p_input
;
1029 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1034 p_pgrm
->i_id
= i_group
;
1036 p_pgrm
->b_selected
= false;
1037 p_pgrm
->b_scrambled
= false;
1038 p_pgrm
->psz_name
= NULL
;
1039 p_pgrm
->psz_now_playing
= NULL
;
1040 p_pgrm
->psz_publisher
= NULL
;
1041 p_pgrm
->p_clock
= input_clock_New( p_sys
->i_rate
);
1042 if( !p_pgrm
->p_clock
)
1047 if( p_sys
->b_paused
)
1048 input_clock_ChangePause( p_pgrm
->p_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1049 input_clock_SetJitter( p_pgrm
->p_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1052 TAB_APPEND( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1054 /* Update "program" variable */
1055 if( EsOutIsProgramVisible( out
, i_group
) )
1056 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1058 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1059 EsOutProgramSelect( out
, p_pgrm
);
1067 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1069 es_out_sys_t
*p_sys
= out
->p_sys
;
1070 input_thread_t
*p_input
= p_sys
->p_input
;
1071 es_out_pgrm_t
*p_pgrm
= NULL
;
1074 for( i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1076 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1078 p_pgrm
= p_sys
->pgrm
[i
];
1083 if( p_pgrm
== NULL
)
1084 return VLC_EGENERIC
;
1088 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1089 i_group
, p_pgrm
->i_es
);
1090 return VLC_EGENERIC
;
1093 TAB_REMOVE( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1095 /* If program is selected we need to unselect it */
1096 if( p_sys
->p_pgrm
== p_pgrm
)
1097 p_sys
->p_pgrm
= NULL
;
1099 input_clock_Delete( p_pgrm
->p_clock
);
1101 free( p_pgrm
->psz_name
);
1102 free( p_pgrm
->psz_now_playing
);
1103 free( p_pgrm
->psz_publisher
);
1106 /* Update "program" variable */
1107 input_SendEventProgramDel( p_input
, i_group
);
1114 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1116 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1118 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1120 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1121 return p_sys
->pgrm
[i
];
1123 return EsOutProgramAdd( p_out
, i_group
);
1126 /* EsOutProgramMeta:
1128 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1131 if( p_pgrm
->psz_name
)
1133 if( asprintf( &psz
, _("%s [%s %d]"), p_pgrm
->psz_name
, _("Program"), p_pgrm
->i_id
) == -1 )
1138 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1144 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1146 es_out_sys_t
*p_sys
= out
->p_sys
;
1147 es_out_pgrm_t
*p_pgrm
;
1148 input_thread_t
*p_input
= p_sys
->p_input
;
1149 const char *psz_title
= NULL
;
1150 const char *psz_provider
= NULL
;
1153 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1155 /* Check against empty meta data (empty for what we handle) */
1156 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1157 !vlc_meta_Get( p_meta
, vlc_meta_NowPlaying
) &&
1158 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) &&
1159 vlc_meta_GetExtraCount( p_meta
) <= 0 )
1164 if( !EsOutIsProgramVisible( out
, i_group
) )
1166 p_pgrm
= EsOutProgramFind( out
, i_group
);
1171 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1172 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1174 /* Update the description text of the program */
1175 if( psz_title
&& *psz_title
)
1177 if( !p_pgrm
->psz_name
|| strcmp( p_pgrm
->psz_name
, psz_title
) )
1179 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1181 /* Remove old entries */
1182 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, NULL
);
1183 /* TODO update epg name ?
1184 * TODO update scrambled info name ? */
1187 free( p_pgrm
->psz_name
);
1188 p_pgrm
->psz_name
= strdup( psz_title
);
1191 if( psz_provider
&& *psz_provider
)
1193 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1198 psz_text
= strdup( psz_title
);
1201 /* ugly but it works */
1204 input_SendEventProgramDel( p_input
, i_group
);
1205 input_SendEventProgramAdd( p_input
, i_group
, psz_text
);
1206 if( p_sys
->p_pgrm
== p_pgrm
)
1207 input_SendEventProgramSelect( p_input
, i_group
);
1213 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1215 info_category_t
*p_cat
= NULL
;
1216 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1218 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1220 p_cat
= info_category_New( psz_cat
);
1224 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1227 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1228 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1229 free( ppsz_all_keys
[i
] );
1231 free( ppsz_all_keys
);
1235 if( p_sys
->p_pgrm
== p_pgrm
)
1237 input_item_SetPublisher( p_input
->p
->p_item
, psz_provider
);
1238 input_SendEventMeta( p_input
);
1241 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1242 "%s",psz_provider
);
1245 input_Control( p_input
, INPUT_MERGE_INFOS
, p_cat
);
1248 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1250 es_out_sys_t
*p_sys
= out
->p_sys
;
1251 input_thread_t
*p_input
= p_sys
->p_input
;
1252 input_item_t
*p_item
= p_input
->p
->p_item
;
1253 es_out_pgrm_t
*p_pgrm
;
1257 if( !EsOutIsProgramVisible( out
, i_group
) )
1259 p_pgrm
= EsOutProgramFind( out
, i_group
);
1264 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1265 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1271 epg
.psz_name
= psz_cat
;
1273 input_item_SetEpg( p_item
, &epg
);
1274 input_SendEventMetaEpg( p_sys
->p_input
);
1276 /* Update now playing */
1277 free( p_pgrm
->psz_now_playing
);
1278 p_pgrm
->psz_now_playing
= NULL
;
1280 vlc_mutex_lock( &p_item
->lock
);
1281 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1283 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1285 if( p_tmp
->psz_name
&& !strcmp(p_tmp
->psz_name
, psz_cat
) )
1287 if( p_tmp
->p_current
&& p_tmp
->p_current
->psz_name
&& *p_tmp
->p_current
->psz_name
)
1288 p_pgrm
->psz_now_playing
= strdup( p_tmp
->p_current
->psz_name
);
1292 vlc_mutex_unlock( &p_item
->lock
);
1294 if( p_pgrm
== p_sys
->p_pgrm
)
1296 input_item_SetNowPlaying( p_input
->p
->p_item
, p_pgrm
->psz_now_playing
);
1297 input_SendEventMeta( p_input
);
1300 if( p_pgrm
->psz_now_playing
)
1302 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
,
1303 vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying
),
1304 p_pgrm
->psz_now_playing
);
1308 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
,
1309 vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying
) );
1315 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1317 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1318 input_thread_t
*p_input
= p_sys
->p_input
;
1319 bool b_scrambled
= false;
1321 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
1323 if( p_sys
->es
[i
]->p_pgrm
== p_pgrm
&& p_sys
->es
[i
]->b_scrambled
)
1329 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1332 p_pgrm
->b_scrambled
= b_scrambled
;
1333 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1336 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
, _("Scrambled"), _("Yes") );
1338 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, _("Scrambled") );
1340 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1343 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1345 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1346 input_thread_t
*p_input
= p_sys
->p_input
;
1348 input_item_t
*p_item
= input_GetItem( p_input
);
1350 char *psz_title
= NULL
;
1351 char *psz_arturl
= input_item_GetArtURL( p_item
);
1353 vlc_mutex_lock( &p_item
->lock
);
1355 if( vlc_meta_Get( p_meta
, vlc_meta_Title
) && !p_item
->b_fixed_name
)
1356 psz_title
= strdup( vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1358 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1360 if( !psz_arturl
|| *psz_arturl
== '\0' )
1362 const char *psz_tmp
= vlc_meta_Get( p_item
->p_meta
, vlc_meta_ArtworkURL
);
1364 psz_arturl
= strdup( psz_tmp
);
1366 vlc_mutex_unlock( &p_item
->lock
);
1368 if( psz_arturl
&& *psz_arturl
)
1370 input_item_SetArtURL( p_item
, psz_arturl
);
1372 if( !strncmp( psz_arturl
, "attachment://", strlen("attachment") ) )
1374 /* Don't look for art cover if sout
1375 * XXX It can change when sout has meta data support */
1376 if( p_input
->p
->p_sout
&& !p_input
->b_preparsing
)
1377 input_item_SetArtURL( p_item
, "" );
1379 input_ExtractAttachmentAndCacheArt( p_input
);
1386 input_item_SetName( p_item
, psz_title
);
1389 input_item_SetPreparsed( p_item
, true );
1391 input_SendEventMeta( p_input
);
1392 /* TODO handle sout meta ? */
1398 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1400 es_out_sys_t
*p_sys
= out
->p_sys
;
1401 input_thread_t
*p_input
= p_sys
->p_input
;
1403 if( fmt
->i_group
< 0 )
1405 msg_Err( p_input
, "invalid group number" );
1409 es_out_id_t
*es
= malloc( sizeof( *es
) );
1410 es_out_pgrm_t
*p_pgrm
;
1416 vlc_mutex_lock( &p_sys
->lock
);
1418 /* Search the program */
1419 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1422 vlc_mutex_unlock( &p_sys
->lock
);
1427 /* Increase ref count for program */
1431 es
->p_pgrm
= p_pgrm
;
1432 es_format_Copy( &es
->fmt
, fmt
);
1433 if( es
->fmt
.i_id
< 0 )
1434 es
->fmt
.i_id
= out
->p_sys
->i_id
;
1435 if( !es
->fmt
.i_original_fourcc
)
1436 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1437 if( es
->fmt
.i_cat
== AUDIO_ES
)
1438 es
->fmt
.i_codec
= vlc_fourcc_GetCodecAudio( es
->fmt
.i_codec
,
1439 es
->fmt
.audio
.i_bitspersample
);
1441 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
,
1444 es
->i_id
= es
->fmt
.i_id
;
1445 es
->i_meta_id
= out
->p_sys
->i_id
;
1446 es
->b_scrambled
= false;
1448 switch( es
->fmt
.i_cat
)
1452 audio_replay_gain_t rg
;
1454 es
->i_channel
= p_sys
->i_audio
;
1456 memset( &rg
, 0, sizeof(rg
) );
1457 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1458 vlc_audio_replay_gain_MergeFromMeta( &rg
, p_input
->p
->p_item
->p_meta
);
1459 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1461 for( i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1463 if( !es
->fmt
.audio_replay_gain
.pb_peak
[i
] )
1465 es
->fmt
.audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1466 es
->fmt
.audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1468 if( !es
->fmt
.audio_replay_gain
.pb_gain
[i
] )
1470 es
->fmt
.audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1471 es
->fmt
.audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1478 es
->i_channel
= p_sys
->i_video
;
1479 if( es
->fmt
.video
.i_frame_rate
&& es
->fmt
.video
.i_frame_rate_base
)
1480 vlc_ureduce( &es
->fmt
.video
.i_frame_rate
,
1481 &es
->fmt
.video
.i_frame_rate_base
,
1482 es
->fmt
.video
.i_frame_rate
,
1483 es
->fmt
.video
.i_frame_rate_base
, 0 );
1487 es
->i_channel
= p_sys
->i_sub
;
1494 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1495 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1497 es
->p_dec_record
= NULL
;
1498 for( i
= 0; i
< 4; i
++ )
1499 es
->pb_cc_present
[i
] = false;
1500 es
->p_master
= NULL
;
1502 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1503 EsOutESVarUpdate( out
, es
, false );
1505 /* Select it if needed */
1506 EsOutSelect( out
, es
, false );
1509 TAB_APPEND( out
->p_sys
->i_es
, out
->p_sys
->es
, es
);
1510 p_sys
->i_id
++; /* always incremented */
1511 switch( es
->fmt
.i_cat
)
1524 EsOutUpdateInfo( out
, es
, &es
->fmt
, NULL
);
1526 if( es
->b_scrambled
)
1527 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1529 vlc_mutex_unlock( &p_sys
->lock
);
1534 static bool EsIsSelected( es_out_id_t
*es
)
1538 bool b_decode
= false;
1539 if( es
->p_master
->p_dec
)
1541 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1542 if( i_channel
!= -1 )
1543 input_DecoderGetCcState( es
->p_master
->p_dec
, &b_decode
, i_channel
);
1549 return es
->p_dec
!= NULL
;
1552 static void EsCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1554 es_out_sys_t
*p_sys
= out
->p_sys
;
1555 input_thread_t
*p_input
= p_sys
->p_input
;
1557 p_es
->p_dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_input
->p
->p_sout
);
1560 if( p_sys
->b_buffering
)
1561 input_DecoderStartBuffering( p_es
->p_dec
);
1563 if( !p_es
->p_master
&& p_sys
->p_sout_record
)
1565 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
1566 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
1567 input_DecoderStartBuffering( p_es
->p_dec_record
);
1571 EsOutDecoderChangeDelay( out
, p_es
);
1573 static void EsDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1580 input_DecoderDelete( p_es
->p_dec
);
1583 if( p_es
->p_dec_record
)
1585 input_DecoderDelete( p_es
->p_dec_record
);
1586 p_es
->p_dec_record
= NULL
;
1590 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
)
1592 es_out_sys_t
*p_sys
= out
->p_sys
;
1593 input_thread_t
*p_input
= p_sys
->p_input
;
1595 if( EsIsSelected( es
) )
1597 msg_Warn( p_input
, "ES 0x%x is already selected", es
->i_id
);
1604 if( !es
->p_master
->p_dec
)
1607 i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1608 if( i_channel
== -1 || input_DecoderSetCcState( es
->p_master
->p_dec
, true, i_channel
) )
1613 const bool b_sout
= p_input
->p
->p_sout
!= NULL
;
1614 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1616 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1618 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1623 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1625 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) )
1627 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1632 if( es
->fmt
.i_cat
== SPU_ES
)
1634 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) )
1636 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1642 EsCreateDecoder( out
, es
);
1644 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1648 /* Mark it as selected */
1649 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, es
->i_id
);
1650 input_SendEventTeletextSelect( p_input
, EsFmtIsTeletext( &es
->fmt
) ? es
->i_id
: -1 );
1653 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1655 es_out_sys_t
*p_sys
= out
->p_sys
;
1656 input_thread_t
*p_input
= p_sys
->p_input
;
1658 if( !EsIsSelected( es
) )
1660 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->i_id
);
1666 if( es
->p_master
->p_dec
)
1668 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1669 if( i_channel
!= -1 )
1670 input_DecoderSetCcState( es
->p_master
->p_dec
, false, i_channel
);
1675 const int i_spu_id
= var_GetInteger( p_input
, "spu-es");
1677 for( i
= 0; i
< 4; i
++ )
1679 if( !es
->pb_cc_present
[i
] || !es
->pp_cc_es
[i
] )
1682 if( i_spu_id
== es
->pp_cc_es
[i
]->i_id
)
1684 /* Force unselection of the CC */
1685 input_SendEventEsSelect( p_input
, SPU_ES
, -1 );
1687 EsOutDel( out
, es
->pp_cc_es
[i
] );
1689 es
->pb_cc_present
[i
] = false;
1691 EsDestroyDecoder( out
, es
);
1697 /* Mark it as unselected */
1698 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, -1 );
1699 if( EsFmtIsTeletext( &es
->fmt
) )
1700 input_SendEventTeletextSelect( p_input
, -1 );
1704 * Select an ES given the current mode
1705 * XXX: you need to take a the lock before (stream.stream_lock)
1707 * \param out The es_out structure
1708 * \param es es_out_id structure
1709 * \param b_force ...
1712 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1714 es_out_sys_t
*p_sys
= out
->p_sys
;
1716 int i_cat
= es
->fmt
.i_cat
;
1718 if( !p_sys
->b_active
||
1719 ( !b_force
&& es
->fmt
.i_priority
< 0 ) )
1724 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
1726 if( !EsIsSelected( es
) )
1727 EsSelect( out
, es
);
1729 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
1731 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
1736 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1738 prgm
= strtok_r( NULL
, ",", &buf
) )
1740 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
1742 if( !EsIsSelected( es
) )
1743 EsSelect( out
, es
);
1750 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1754 if( es
->p_pgrm
!= p_sys
->p_pgrm
)
1757 if( i_cat
== AUDIO_ES
)
1759 int idx1
= LanguageArrayIndex( p_sys
->ppsz_audio_language
,
1760 es
->psz_language_code
);
1762 if( p_sys
->p_es_audio
&&
1763 p_sys
->p_es_audio
->fmt
.i_priority
>= es
->fmt
.i_priority
)
1765 int idx2
= LanguageArrayIndex( p_sys
->ppsz_audio_language
,
1766 p_sys
->p_es_audio
->psz_language_code
);
1768 if( idx1
< 0 || ( idx2
>= 0 && idx2
<= idx1
) )
1770 i_wanted
= es
->i_channel
;
1774 /* Select audio if (no audio selected yet)
1775 * - no audio-language
1776 * - no audio code for the ES
1777 * - audio code in the requested list */
1779 !strcmp( es
->psz_language_code
, "??" ) ||
1780 !p_sys
->ppsz_audio_language
)
1781 i_wanted
= es
->i_channel
;
1784 if( p_sys
->i_audio_last
>= 0 )
1785 i_wanted
= p_sys
->i_audio_last
;
1787 if( p_sys
->i_audio_id
>= 0 )
1789 if( es
->i_id
== p_sys
->i_audio_id
)
1790 i_wanted
= es
->i_channel
;
1795 else if( i_cat
== SPU_ES
)
1797 int idx1
= LanguageArrayIndex( p_sys
->ppsz_sub_language
,
1798 es
->psz_language_code
);
1800 if( p_sys
->p_es_sub
&&
1801 p_sys
->p_es_sub
->fmt
.i_priority
>= es
->fmt
.i_priority
)
1803 int idx2
= LanguageArrayIndex( p_sys
->ppsz_sub_language
,
1804 p_sys
->p_es_sub
->psz_language_code
);
1806 msg_Dbg( p_sys
->p_input
, "idx1=%d(%s) idx2=%d(%s)",
1807 idx1
, es
->psz_language_code
, idx2
,
1808 p_sys
->p_es_sub
->psz_language_code
);
1810 if( idx1
< 0 || ( idx2
>= 0 && idx2
<= idx1
) )
1812 /* We found a SPU that matches our language request */
1813 i_wanted
= es
->i_channel
;
1815 else if( idx1
>= 0 )
1817 msg_Dbg( p_sys
->p_input
, "idx1=%d(%s)",
1818 idx1
, es
->psz_language_code
);
1820 i_wanted
= es
->i_channel
;
1822 else if( p_sys
->i_default_sub_id
>= 0 )
1824 if( es
->i_id
== p_sys
->i_default_sub_id
)
1825 i_wanted
= es
->i_channel
;
1828 if( p_sys
->i_sub_last
>= 0 )
1829 i_wanted
= p_sys
->i_sub_last
;
1831 if( p_sys
->i_sub_id
>= 0 )
1833 if( es
->i_id
== p_sys
->i_sub_id
)
1834 i_wanted
= es
->i_channel
;
1839 else if( i_cat
== VIDEO_ES
)
1841 i_wanted
= es
->i_channel
;
1844 if( i_wanted
== es
->i_channel
&& !EsIsSelected( es
) )
1845 EsSelect( out
, es
);
1848 /* FIXME TODO handle priority here */
1849 if( EsIsSelected( es
) )
1851 if( i_cat
== AUDIO_ES
)
1853 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1854 p_sys
->p_es_audio
&&
1855 p_sys
->p_es_audio
!= es
&&
1856 EsIsSelected( p_sys
->p_es_audio
) )
1858 EsUnselect( out
, p_sys
->p_es_audio
, false );
1860 p_sys
->p_es_audio
= es
;
1862 else if( i_cat
== SPU_ES
)
1864 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1866 p_sys
->p_es_sub
!= es
&&
1867 EsIsSelected( p_sys
->p_es_sub
) )
1869 EsUnselect( out
, p_sys
->p_es_sub
, false );
1871 p_sys
->p_es_sub
= es
;
1873 else if( i_cat
== VIDEO_ES
)
1875 p_sys
->p_es_video
= es
;
1881 * Send a block for the given es_out
1883 * \param out the es_out to send from
1884 * \param es the es_out_id
1885 * \param p_block the data block to send
1887 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
1889 es_out_sys_t
*p_sys
= out
->p_sys
;
1890 input_thread_t
*p_input
= p_sys
->p_input
;
1892 if( libvlc_stats( p_input
) )
1896 vlc_mutex_lock( &p_input
->p
->counters
.counters_lock
);
1897 stats_Update( p_input
->p
->counters
.p_demux_read
,
1898 p_block
->i_buffer
, &i_total
);
1899 stats_Update( p_input
->p
->counters
.p_demux_bitrate
, i_total
, NULL
);
1901 /* Update number of corrupted data packats */
1902 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
1904 stats_Update( p_input
->p
->counters
.p_demux_corrupted
, 1, NULL
);
1906 /* Update number of discontinuities */
1907 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
1909 stats_Update( p_input
->p
->counters
.p_demux_discontinuity
, 1, NULL
);
1911 vlc_mutex_unlock( &p_input
->p
->counters
.counters_lock
);
1914 vlc_mutex_lock( &p_sys
->lock
);
1916 /* Mark preroll blocks */
1917 if( p_sys
->i_preroll_end
>= 0 )
1919 int64_t i_date
= p_block
->i_pts
;
1920 if( p_block
->i_pts
<= VLC_TS_INVALID
)
1921 i_date
= p_block
->i_dts
;
1923 if( i_date
< p_sys
->i_preroll_end
)
1924 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
1929 block_Release( p_block
);
1930 vlc_mutex_unlock( &p_sys
->lock
);
1934 /* Check for sout mode */
1935 if( p_input
->p
->p_sout
)
1937 /* FIXME review this, proper lock may be missing */
1938 if( p_input
->p
->p_sout
->i_out_pace_nocontrol
> 0 &&
1939 p_input
->p
->b_out_pace_control
)
1941 msg_Dbg( p_input
, "switching to sync mode" );
1942 p_input
->p
->b_out_pace_control
= false;
1944 else if( p_input
->p
->p_sout
->i_out_pace_nocontrol
<= 0 &&
1945 !p_input
->p
->b_out_pace_control
)
1947 msg_Dbg( p_input
, "switching to async mode" );
1948 p_input
->p
->b_out_pace_control
= true;
1953 if( es
->p_dec_record
)
1955 block_t
*p_dup
= block_Duplicate( p_block
);
1957 input_DecoderDecode( es
->p_dec_record
, p_dup
,
1958 p_input
->p
->b_out_pace_control
);
1960 input_DecoderDecode( es
->p_dec
, p_block
,
1961 p_input
->p
->b_out_pace_control
);
1963 es_format_t fmt_dsc
;
1964 vlc_meta_t
*p_meta_dsc
;
1965 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
1967 EsOutUpdateInfo( out
, es
, &fmt_dsc
, p_meta_dsc
);
1969 es_format_Clean( &fmt_dsc
);
1971 vlc_meta_Delete( p_meta_dsc
);
1974 /* Check CC status */
1977 input_DecoderIsCcPresent( es
->p_dec
, pb_cc
);
1978 for( int i
= 0; i
< 4; i
++ )
1982 if( es
->pb_cc_present
[i
] || !pb_cc
[i
] )
1984 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, es
->i_id
);
1986 es_format_Init( &fmt
, SPU_ES
, EsOutFourccClosedCaptions
[i
] );
1987 fmt
.i_group
= es
->fmt
.i_group
;
1988 if( asprintf( &fmt
.psz_description
,
1989 _("Closed captions %u"), 1 + i
) == -1 )
1990 fmt
.psz_description
= NULL
;
1991 es
->pp_cc_es
[i
] = EsOutAdd( out
, &fmt
);
1992 es
->pp_cc_es
[i
]->p_master
= es
;
1993 es_format_Clean( &fmt
);
1996 es
->pb_cc_present
[i
] = true;
1999 vlc_mutex_unlock( &p_sys
->lock
);
2004 /*****************************************************************************
2006 *****************************************************************************/
2007 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2009 es_out_sys_t
*p_sys
= out
->p_sys
;
2010 bool b_reselect
= false;
2013 vlc_mutex_lock( &p_sys
->lock
);
2015 /* We don't try to reselect */
2018 while( vlc_object_alive(p_sys
->p_input
) && !p_sys
->b_buffering
&& es
->p_dec
)
2020 if( input_DecoderIsEmpty( es
->p_dec
) &&
2021 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2023 /* FIXME there should be a way to have auto deleted es, but there will be
2024 * a problem when another codec of the same type is created (mainly video) */
2027 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2030 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2031 EsOutESVarUpdate( out
, es
, true );
2033 TAB_REMOVE( p_sys
->i_es
, p_sys
->es
, es
);
2035 /* Update program */
2037 if( es
->p_pgrm
->i_es
== 0 )
2038 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2040 if( es
->b_scrambled
)
2041 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2044 if( p_sys
->p_es_audio
== es
|| p_sys
->p_es_video
== es
||
2045 p_sys
->p_es_sub
== es
) b_reselect
= true;
2047 if( p_sys
->p_es_audio
== es
) p_sys
->p_es_audio
= NULL
;
2048 if( p_sys
->p_es_video
== es
) p_sys
->p_es_video
= NULL
;
2049 if( p_sys
->p_es_sub
== es
) p_sys
->p_es_sub
= NULL
;
2051 switch( es
->fmt
.i_cat
)
2064 /* Re-select another track when needed */
2067 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2069 if( es
->fmt
.i_cat
== p_sys
->es
[i
]->fmt
.i_cat
)
2070 EsOutSelect( out
, p_sys
->es
[i
], false );
2074 free( es
->psz_language
);
2075 free( es
->psz_language_code
);
2077 es_format_Clean( &es
->fmt
);
2079 vlc_mutex_unlock( &p_sys
->lock
);
2085 * Control query handler
2087 * \param out the es_out to control
2088 * \param i_query A es_out query as defined in include/ninput.h
2089 * \param args a variable list of arguments for the query
2090 * \return VLC_SUCCESS or an error code
2092 static int EsOutControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2094 es_out_sys_t
*p_sys
= out
->p_sys
;
2098 case ES_OUT_SET_ES_STATE
:
2100 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2101 bool b
= va_arg( args
, int );
2102 if( b
&& !EsIsSelected( es
) )
2104 EsSelect( out
, es
);
2105 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2107 else if( !b
&& EsIsSelected( es
) )
2109 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2115 case ES_OUT_GET_ES_STATE
:
2117 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2118 bool *pb
= va_arg( args
, bool * );
2120 *pb
= EsIsSelected( es
);
2124 case ES_OUT_GET_GROUP_FORCED
:
2126 int *pi_group
= va_arg( args
, int * );
2127 *pi_group
= p_sys
->i_group_id
;
2131 case ES_OUT_SET_MODE
:
2133 const int i_mode
= va_arg( args
, int );
2134 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2135 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2136 i_mode
== ES_OUT_MODE_END
);
2138 if( i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& p_sys
->i_es
> 0 )
2140 /* XXX Terminate vout if there are tracks but no video one.
2141 * This one is not mandatory but is he earliest place where it
2144 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2146 es_out_id_t
*p_es
= p_sys
->es
[i
];
2147 if( p_es
->fmt
.i_cat
== VIDEO_ES
)
2150 if( i
>= p_sys
->i_es
)
2151 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
2153 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2154 p_sys
->i_mode
= i_mode
;
2156 /* Reapply policy mode */
2157 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2159 if( EsIsSelected( p_sys
->es
[i
] ) )
2160 EsUnselect( out
, p_sys
->es
[i
],
2161 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2163 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2164 EsOutSelect( out
, p_sys
->es
[i
], false );
2165 if( i_mode
== ES_OUT_MODE_END
)
2166 EsOutTerminate( out
);
2171 case ES_OUT_RESTART_ES
:
2173 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2178 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2180 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2182 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2187 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2191 if( es
== p_sys
->es
[i
] )
2193 EsOutSelect( out
, es
, true );
2199 if( i_cat
== UNKNOWN_ES
|| p_sys
->es
[i
]->fmt
.i_cat
== i_cat
)
2201 if( EsIsSelected( p_sys
->es
[i
] ) )
2203 if( i_query
== ES_OUT_RESTART_ES
)
2205 if( p_sys
->es
[i
]->p_dec
)
2207 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2208 EsCreateDecoder( out
, p_sys
->es
[i
] );
2213 EsUnselect( out
, p_sys
->es
[i
],
2214 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2223 case ES_OUT_SET_ES_DEFAULT
:
2225 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2229 /*p_sys->i_default_video_id = -1;*/
2230 /*p_sys->i_default_audio_id = -1;*/
2231 p_sys
->i_default_sub_id
= -1;
2233 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2235 /*p_sys->i_default_video_id = -1;*/
2237 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2239 /*p_sys->i_default_audio_id = -1;*/
2241 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2243 p_sys
->i_default_sub_id
= -1;
2247 /*if( es->fmt.i_cat == VIDEO_ES )
2248 p_sys->i_default_video_id = es->i_id;
2250 if( es->fmt.i_cat == AUDIO_ES )
2251 p_sys->i_default_audio_id = es->i_id;
2253 if( es
->fmt
.i_cat
== SPU_ES
)
2254 p_sys
->i_default_sub_id
= es
->i_id
;
2259 case ES_OUT_SET_PCR
:
2260 case ES_OUT_SET_GROUP_PCR
:
2262 es_out_pgrm_t
*p_pgrm
= NULL
;
2266 /* Search program */
2267 if( i_query
== ES_OUT_SET_PCR
)
2269 p_pgrm
= p_sys
->p_pgrm
;
2271 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2275 i_group
= (int)va_arg( args
, int );
2276 p_pgrm
= EsOutProgramFind( out
, i_group
);
2279 return VLC_EGENERIC
;
2281 i_pcr
= (int64_t)va_arg( args
, int64_t );
2282 if( i_pcr
<= VLC_TS_INVALID
)
2284 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2285 return VLC_EGENERIC
;
2288 /* TODO do not use mdate() but proper stream acquisition date */
2290 input_clock_Update( p_pgrm
->p_clock
, VLC_OBJECT(p_sys
->p_input
),
2292 p_sys
->p_input
->p
->b_can_pace_control
|| p_sys
->b_buffering
,
2293 EsOutIsExtraBufferingAllowed( out
),
2296 if( p_pgrm
== p_sys
->p_pgrm
)
2298 if( p_sys
->b_buffering
)
2300 /* Check buffering state on master clock update */
2301 EsOutDecodersStopBuffering( out
, false );
2303 else if( b_late
&& ( !p_sys
->p_input
->p
->p_sout
||
2304 !p_sys
->p_input
->p
->b_out_pace_control
) )
2306 const mtime_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2307 mtime_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_clock
);
2309 /* Avoid dangerously high value */
2310 const mtime_t i_jitter_max
= INT64_C(1000) * var_InheritInteger( p_sys
->p_input
, "clock-jitter" );
2311 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2313 msg_Err( p_sys
->p_input
,
2314 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2315 (int)(i_pts_delay
- i_pts_delay_base
) / 1000 );
2316 i_pts_delay
= p_sys
->i_pts_delay
;
2320 msg_Err( p_sys
->p_input
,
2321 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2322 (int)(i_pts_delay
/1000) );
2325 /* Force a rebufferization when we are too late */
2327 /* It is not really good, as we throw away already buffered data
2328 * TODO have a mean to correctly reenter bufferization */
2329 es_out_Control( out
, ES_OUT_RESET_PCR
);
2331 es_out_SetJitter( out
, i_pts_delay_base
, i_pts_delay
- i_pts_delay_base
, p_sys
->i_cr_average
);
2337 case ES_OUT_RESET_PCR
:
2338 msg_Err( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2339 EsOutChangePosition( out
);
2342 case ES_OUT_SET_GROUP
:
2344 int i
= va_arg( args
, int );
2345 for( int j
= 0; j
< p_sys
->i_pgrm
; j
++ )
2347 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[j
];
2348 if( p_pgrm
->i_id
== i
)
2350 EsOutProgramSelect( out
, p_pgrm
);
2354 return VLC_EGENERIC
;
2357 case ES_OUT_SET_ES_FMT
:
2359 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2360 * to update the p_extra data */
2361 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2362 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2364 return VLC_EGENERIC
;
2366 if( p_fmt
->i_extra
)
2368 es
->fmt
.i_extra
= p_fmt
->i_extra
;
2369 es
->fmt
.p_extra
= xrealloc( es
->fmt
.p_extra
, p_fmt
->i_extra
);
2370 memcpy( es
->fmt
.p_extra
, p_fmt
->p_extra
, p_fmt
->i_extra
);
2375 EsDestroyDecoder( out
, es
);
2377 EsCreateDecoder( out
, es
);
2379 es
->p_dec
->fmt_in
.i_extra
= p_fmt
->i_extra
;
2380 es
->p_dec
->fmt_in
.p_extra
=
2381 xrealloc( es
->p_dec
->fmt_in
.p_extra
, p_fmt
->i_extra
);
2382 memcpy( es
->p_dec
->fmt_in
.p_extra
,
2383 p_fmt
->p_extra
, p_fmt
->i_extra
);
2390 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2392 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2393 bool b_scrambled
= (bool)va_arg( args
, int );
2395 if( !es
->b_scrambled
!= !b_scrambled
)
2397 es
->b_scrambled
= b_scrambled
;
2398 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2403 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2405 const int64_t i_date
= (int64_t)va_arg( args
, int64_t );
2408 return VLC_EGENERIC
;
2410 p_sys
->i_preroll_end
= i_date
;
2414 case ES_OUT_SET_GROUP_META
:
2416 int i_group
= (int)va_arg( args
, int );
2417 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2419 EsOutProgramMeta( out
, i_group
, p_meta
);
2422 case ES_OUT_SET_GROUP_EPG
:
2424 int i_group
= (int)va_arg( args
, int );
2425 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2427 EsOutProgramEpg( out
, i_group
, p_epg
);
2431 case ES_OUT_DEL_GROUP
:
2433 int i_group
= (int)va_arg( args
, int );
2435 return EsOutProgramDel( out
, i_group
);
2438 case ES_OUT_SET_META
:
2440 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2442 EsOutMeta( out
, p_meta
);
2446 case ES_OUT_GET_WAKE_UP
:
2448 mtime_t
*pi_wakeup
= (mtime_t
*)va_arg( args
, mtime_t
* );
2449 *pi_wakeup
= EsOutGetWakeup( out
);
2453 case ES_OUT_SET_ES_BY_ID
:
2454 case ES_OUT_RESTART_ES_BY_ID
:
2455 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2457 const int i_id
= (int)va_arg( args
, int );
2458 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2463 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
; break;
2464 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2465 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2469 /* TODO if the lock is made non recursive it should be changed */
2470 int i_ret
= es_out_Control( out
, i_new_query
, p_es
);
2472 /* Clean up vout after user action (in active mode only).
2473 * FIXME it does not work well with multiple video windows */
2474 if( p_sys
->b_active
)
2475 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
2479 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2481 const int i_id
= va_arg( args
, int );
2482 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2484 return VLC_EGENERIC
;
2486 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2487 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2488 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
2492 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2493 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2507 case ES_OUT_GET_BUFFERING
:
2509 bool *pb
= va_arg( args
, bool* );
2510 *pb
= p_sys
->b_buffering
;
2514 case ES_OUT_GET_EMPTY
:
2516 bool *pb
= va_arg( args
, bool* );
2517 *pb
= EsOutDecodersIsEmpty( out
);
2521 case ES_OUT_SET_DELAY
:
2523 const int i_cat
= (int)va_arg( args
, int );
2524 const mtime_t i_delay
= (mtime_t
)va_arg( args
, mtime_t
);
2525 EsOutSetDelay( out
, i_cat
, i_delay
);
2529 case ES_OUT_SET_RECORD_STATE
:
2531 bool b
= va_arg( args
, int );
2532 return EsOutSetRecord( out
, b
);
2535 case ES_OUT_SET_PAUSE_STATE
:
2537 const bool b_source_paused
= (bool)va_arg( args
, int );
2538 const bool b_paused
= (bool)va_arg( args
, int );
2539 const mtime_t i_date
= (mtime_t
) va_arg( args
, mtime_t
);
2541 assert( !b_source_paused
== !b_paused
);
2542 EsOutChangePause( out
, b_paused
, i_date
);
2547 case ES_OUT_SET_RATE
:
2549 const int i_src_rate
= (int)va_arg( args
, int );
2550 const int i_rate
= (int)va_arg( args
, int );
2552 assert( i_src_rate
== i_rate
);
2553 EsOutChangeRate( out
, i_rate
);
2558 case ES_OUT_SET_TIME
:
2560 const mtime_t i_date
= (mtime_t
)va_arg( args
, mtime_t
);
2562 assert( i_date
== -1 );
2563 EsOutChangePosition( out
);
2568 case ES_OUT_SET_FRAME_NEXT
:
2569 EsOutFrameNext( out
);
2572 case ES_OUT_SET_TIMES
:
2574 double f_position
= (double)va_arg( args
, double );
2575 mtime_t i_time
= (mtime_t
)va_arg( args
, mtime_t
);
2576 mtime_t i_length
= (mtime_t
)va_arg( args
, mtime_t
);
2578 input_SendEventLength( p_sys
->p_input
, i_length
);
2580 if( !p_sys
->b_buffering
)
2584 /* Fix for buffering delay */
2585 if( !p_sys
->p_input
->p
->p_sout
||
2586 !p_sys
->p_input
->p
->b_out_pace_control
)
2587 i_delay
= EsOutGetBuffering( out
);
2596 f_position
-= (double)i_delay
/ i_length
;
2597 if( f_position
< 0 )
2600 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
2604 case ES_OUT_SET_JITTER
:
2606 mtime_t i_pts_delay
= (mtime_t
)va_arg( args
, mtime_t
);
2607 mtime_t i_pts_jitter
= (mtime_t
)va_arg( args
, mtime_t
);
2608 int i_cr_average
= (int)va_arg( args
, int );
2610 bool b_change_clock
=
2611 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
2612 i_cr_average
!= p_sys
->i_cr_average
;
2614 assert( i_pts_jitter
>= 0 );
2615 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
2616 p_sys
->i_pts_jitter
= i_pts_jitter
;
2617 p_sys
->i_cr_average
= i_cr_average
;
2619 for( int i
= 0; i
< p_sys
->i_pgrm
&& b_change_clock
; i
++ )
2620 input_clock_SetJitter( p_sys
->pgrm
[i
]->p_clock
,
2621 i_pts_delay
+ i_pts_jitter
, i_cr_average
);
2625 case ES_OUT_GET_PCR_SYSTEM
:
2627 if( p_sys
->b_buffering
)
2628 return VLC_EGENERIC
;
2630 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2632 return VLC_EGENERIC
;
2634 mtime_t
*pi_system
= va_arg( args
, mtime_t
*);
2635 mtime_t
*pi_delay
= va_arg( args
, mtime_t
*);
2636 input_clock_GetSystemOrigin( p_pgrm
->p_clock
, pi_system
, pi_delay
);
2640 case ES_OUT_MODIFY_PCR_SYSTEM
:
2642 if( p_sys
->b_buffering
)
2643 return VLC_EGENERIC
;
2645 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2647 return VLC_EGENERIC
;
2649 const bool b_absolute
= va_arg( args
, int );
2650 const mtime_t i_system
= va_arg( args
, mtime_t
);
2651 input_clock_ChangeSystemOrigin( p_pgrm
->p_clock
, b_absolute
, i_system
);
2654 case ES_OUT_SET_EOS
:
2656 for (int i
= 0; i
< p_sys
->i_es
; i
++) {
2657 es_out_id_t
*id
= p_sys
->es
[i
];
2658 decoder_t
*p_dec
= id
->p_dec
;
2661 block_t
*p_block
= block_Alloc(0);
2665 p_block
->i_flags
|= BLOCK_FLAG_CORE_EOS
;
2666 input_DecoderDecode(p_dec
, p_block
, false);
2672 msg_Err( p_sys
->p_input
, "unknown query in es_out_Control" );
2673 return VLC_EGENERIC
;
2676 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
2678 es_out_sys_t
*p_sys
= out
->p_sys
;
2681 vlc_mutex_lock( &p_sys
->lock
);
2682 i_ret
= EsOutControlLocked( out
, i_query
, args
);
2683 vlc_mutex_unlock( &p_sys
->lock
);
2688 /****************************************************************************
2689 * LanguageGetName: try to expend iso639 into plain name
2690 ****************************************************************************/
2691 static char *LanguageGetName( const char *psz_code
)
2693 const iso639_lang_t
*pl
;
2695 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
2697 return strdup( "" );
2700 if( strlen( psz_code
) == 2 )
2702 pl
= GetLang_1( psz_code
);
2704 else if( strlen( psz_code
) == 3 )
2706 pl
= GetLang_2B( psz_code
);
2707 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2709 pl
= GetLang_2T( psz_code
);
2714 return strdup( psz_code
);
2717 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2719 return strdup( psz_code
);
2723 return strdup( vlc_gettext(pl
->psz_eng_name
) );
2727 /* Get a 2 char code */
2728 static char *LanguageGetCode( const char *psz_lang
)
2730 const iso639_lang_t
*pl
;
2732 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
2733 return strdup("??");
2735 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
2737 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
2738 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
2739 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
2740 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
2741 return strdup( pl
->psz_iso639_1
);
2744 return strdup("??");
2747 static char **LanguageSplit( const char *psz_langs
, bool b_default_any
)
2754 if( psz_langs
== NULL
) return NULL
;
2756 psz_parser
= psz_dup
= strdup(psz_langs
);
2758 while( psz_parser
&& *psz_parser
)
2763 psz
= strchr(psz_parser
, ',' );
2764 if( psz
) *psz
++ = '\0';
2766 if( !strcmp( psz_parser
, "any" ) )
2768 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2770 else if( !strcmp( psz_parser
, "none" ) )
2772 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
2776 psz_code
= LanguageGetCode( psz_parser
);
2777 if( strcmp( psz_code
, "??" ) )
2779 TAB_APPEND( i_psz
, ppsz
, psz_code
);
2792 if( b_default_any
&& strcmp( ppsz
[i_psz
- 1], "none" ) )
2793 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2794 TAB_APPEND( i_psz
, ppsz
, NULL
);
2801 static int LanguageArrayIndex( char **ppsz_langs
, char *psz_lang
)
2803 if( !ppsz_langs
|| !psz_lang
)
2806 for( int i
= 0; ppsz_langs
[i
]; i
++ )
2808 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
2809 !strcasecmp( ppsz_langs
[i
], "any" ) )
2811 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
2818 /****************************************************************************
2820 * - add meta info to the playlist item
2821 ****************************************************************************/
2822 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
, const vlc_meta_t
*p_meta
)
2824 es_out_sys_t
*p_sys
= out
->p_sys
;
2825 input_thread_t
*p_input
= p_sys
->p_input
;
2826 const es_format_t
*p_fmt_es
= &es
->fmt
;
2829 if( es
->fmt
.i_cat
== fmt
->i_cat
)
2831 es_format_t update
= *fmt
;
2832 update
.i_id
= es
->i_meta_id
;
2833 update
.i_codec
= es
->fmt
.i_codec
;
2834 update
.i_original_fourcc
= es
->fmt
.i_original_fourcc
;
2835 input_item_UpdateTracksInfo(input_GetItem(p_input
), &update
);
2838 /* Create category */
2840 snprintf( psz_cat
, sizeof(psz_cat
),_("Stream %d"), es
->i_meta_id
);
2841 info_category_t
*p_cat
= info_category_New( psz_cat
);
2845 /* Add information */
2846 const char *psz_type
;
2847 switch( fmt
->i_cat
)
2850 psz_type
= _("Audio");
2853 psz_type
= _("Video");
2856 psz_type
= _("Subtitle");
2864 info_category_AddInfo( p_cat
, _("Type"), "%s", psz_type
);
2866 if( es
->i_meta_id
!= es
->i_id
)
2867 info_category_AddInfo( p_cat
, _("Original ID"),
2870 const char *psz_codec_description
=
2871 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, p_fmt_es
->i_codec
);
2872 const vlc_fourcc_t i_codec_fourcc
= ( p_fmt_es
->i_original_fourcc
)?
2873 p_fmt_es
->i_original_fourcc
: p_fmt_es
->i_codec
;
2874 if( psz_codec_description
)
2875 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
2876 psz_codec_description
, (char*)&i_codec_fourcc
);
2878 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
2879 (char*)&i_codec_fourcc
);
2881 if( es
->psz_language
&& *es
->psz_language
)
2882 info_category_AddInfo( p_cat
, _("Language"), "%s",
2884 if( fmt
->psz_description
&& *fmt
->psz_description
)
2885 info_category_AddInfo( p_cat
, _("Description"), "%s",
2886 fmt
->psz_description
);
2888 switch( fmt
->i_cat
)
2891 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
2893 if( fmt
->audio
.i_physical_channels
)
2894 info_category_AddInfo( p_cat
, _("Channels"), "%s",
2895 _( aout_FormatPrintChannels( &fmt
->audio
) ) );
2897 if( fmt
->audio
.i_rate
> 0 )
2899 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
2900 fmt
->audio
.i_rate
);
2901 /* FIXME that should be removed or improved ! (used by text/strings.c) */
2902 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
2905 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
2906 if( i_bitspersample
<= 0 )
2907 i_bitspersample
= aout_BitsPerSample( p_fmt_es
->i_codec
);
2908 if( i_bitspersample
> 0 )
2909 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
2912 if( fmt
->i_bitrate
> 0 )
2914 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
2915 fmt
->i_bitrate
/ 1000 );
2916 /* FIXME that should be removed or improved ! (used by text/strings.c) */
2917 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
2919 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
2921 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
2922 if( !p_rg
->pb_gain
[i
] )
2924 const char *psz_name
;
2925 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
2926 psz_name
= _("Track replay gain");
2928 psz_name
= _("Album replay gain");
2929 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
2935 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
2937 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
2938 info_category_AddInfo( p_cat
, _("Resolution"), "%ux%u",
2939 fmt
->video
.i_width
, fmt
->video
.i_height
);
2941 if( fmt
->video
.i_visible_width
> 0 &&
2942 fmt
->video
.i_visible_height
> 0 )
2943 info_category_AddInfo( p_cat
, _("Display resolution"), "%ux%u",
2944 fmt
->video
.i_visible_width
,
2945 fmt
->video
.i_visible_height
);
2946 if( fmt
->video
.i_frame_rate
> 0 &&
2947 fmt
->video
.i_frame_rate_base
> 0 )
2949 div
= lldiv( (float)fmt
->video
.i_frame_rate
/
2950 fmt
->video
.i_frame_rate_base
* 1000000,
2953 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
".%06u",
2954 div
.quot
, (unsigned int )div
.rem
);
2956 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
,
2959 if( fmt
->i_codec
!= p_fmt_es
->i_codec
)
2961 const char *psz_chroma_description
=
2962 vlc_fourcc_GetDescription( VIDEO_ES
, fmt
->i_codec
);
2963 if( psz_chroma_description
)
2964 info_category_AddInfo( p_cat
, _("Decoded format"), "%s",
2965 psz_chroma_description
);
2971 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
2978 /* Append generic meta */
2981 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
2982 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
2984 char *psz_key
= ppsz_all_keys
[i
];
2985 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
2988 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
2989 vlc_gettext(psz_value
) );
2992 free( ppsz_all_keys
);
2995 input_Control( p_input
, INPUT_REPLACE_INFOS
, p_cat
);