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"
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
**pp_selected_pgrm
; /* --programs */
118 es_out_pgrm_t
*p_pgrm
; /* Master program */
134 /* es/group to select */
136 int i_audio_last
, i_audio_id
;
137 int i_sub_last
, i_sub_id
;
138 int i_default_sub_id
; /* As specified in container; if applicable */
139 char **ppsz_audio_language
;
140 char **ppsz_sub_language
;
142 /* current main es */
143 es_out_id_t
*p_es_audio
;
144 es_out_id_t
*p_es_video
;
145 es_out_id_t
*p_es_sub
;
148 int64_t i_audio_delay
;
151 /* Clock configuration */
153 mtime_t i_pts_jitter
;
159 mtime_t i_pause_date
;
161 /* Current preroll */
162 mtime_t i_preroll_end
;
164 /* Used for buffering */
166 mtime_t i_buffering_extra_initial
;
167 mtime_t i_buffering_extra_stream
;
168 mtime_t i_buffering_extra_system
;
171 sout_instance_t
*p_sout_record
;
174 static es_out_id_t
*EsOutAdd ( es_out_t
*, const es_format_t
* );
175 static int EsOutSend ( es_out_t
*, es_out_id_t
*, block_t
* );
176 static void EsOutDel ( es_out_t
*, es_out_id_t
* );
177 static int EsOutControl( es_out_t
*, int i_query
, va_list );
178 static void EsOutDelete ( es_out_t
* );
180 static void EsOutTerminate( es_out_t
* );
181 static void EsOutSelect( es_out_t
*, es_out_id_t
*es
, bool b_force
);
182 static void EsOutUpdateInfo( es_out_t
*, es_out_id_t
*es
, const es_format_t
*, const vlc_meta_t
* );
183 static int EsOutSetRecord( es_out_t
*, bool b_record
);
185 static bool EsIsSelected( es_out_id_t
*es
);
186 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
);
187 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
);
188 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
);
189 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
190 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
191 static void EsOutProgramsChangeRate( es_out_t
*out
);
192 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
);
194 static char *LanguageGetName( const char *psz_code
);
195 static char *LanguageGetCode( const char *psz_lang
);
196 static char **LanguageSplit( const char *psz_langs
, bool b_default_any
);
197 static int LanguageArrayIndex( char **ppsz_langs
, char *psz_lang
);
199 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
);
201 static const vlc_fourcc_t EsOutFourccClosedCaptions
[4] = {
202 VLC_FOURCC('c', 'c', '1', ' '),
203 VLC_FOURCC('c', 'c', '2', ' '),
204 VLC_FOURCC('c', 'c', '3', ' '),
205 VLC_FOURCC('c', 'c', '4', ' '),
207 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc
)
210 for( i
= 0; i
< 4; i
++ )
212 if( fcc
== EsOutFourccClosedCaptions
[i
] )
217 static inline bool EsFmtIsTeletext( const es_format_t
*p_fmt
)
219 return p_fmt
->i_cat
== SPU_ES
&& p_fmt
->i_codec
== VLC_CODEC_TELETEXT
;
222 /*****************************************************************************
224 *****************************************************************************/
225 es_out_t
*input_EsOutNew( input_thread_t
*p_input
, int i_rate
)
227 es_out_t
*out
= malloc( sizeof( *out
) );
231 es_out_sys_t
*p_sys
= malloc( sizeof( *p_sys
) );
238 out
->pf_add
= EsOutAdd
;
239 out
->pf_send
= EsOutSend
;
240 out
->pf_del
= EsOutDel
;
241 out
->pf_control
= EsOutControl
;
242 out
->pf_destroy
= EsOutDelete
;
245 vlc_mutex_init_recursive( &p_sys
->lock
);
246 p_sys
->p_input
= p_input
;
248 p_sys
->b_active
= false;
249 p_sys
->i_mode
= ES_OUT_MODE_NONE
;
252 TAB_INIT( p_sys
->i_pgrm
, p_sys
->pgrm
);
253 p_sys
->p_pgrm
= NULL
;
257 TAB_INIT( p_sys
->i_es
, p_sys
->es
);
264 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
266 p_sys
->i_audio_last
= var_GetInteger( p_input
, "audio-track" );
268 p_sys
->i_sub_last
= var_GetInteger( p_input
, "sub-track" );
270 p_sys
->i_default_sub_id
= -1;
272 if( !p_input
->b_preparsing
)
276 psz_string
= var_GetString( p_input
, "audio-language" );
277 p_sys
->ppsz_audio_language
= LanguageSplit( psz_string
, true );
278 if( p_sys
->ppsz_audio_language
)
280 for( int i
= 0; p_sys
->ppsz_audio_language
[i
]; i
++ )
281 msg_Dbg( p_input
, "selected audio language[%d] %s",
282 i
, p_sys
->ppsz_audio_language
[i
] );
286 psz_string
= var_GetString( p_input
, "sub-language" );
287 p_sys
->ppsz_sub_language
= LanguageSplit( psz_string
, false );
288 if( p_sys
->ppsz_sub_language
)
290 for( int i
= 0; p_sys
->ppsz_sub_language
[i
]; i
++ )
291 msg_Dbg( p_input
, "selected subtitle language[%d] %s",
292 i
, p_sys
->ppsz_sub_language
[i
] );
298 p_sys
->ppsz_sub_language
= NULL
;
299 p_sys
->ppsz_audio_language
= NULL
;
302 p_sys
->i_audio_id
= var_GetInteger( p_input
, "audio-track-id" );
304 p_sys
->i_sub_id
= var_GetInteger( p_input
, "sub-track-id" );
306 p_sys
->p_es_audio
= NULL
;
307 p_sys
->p_es_video
= NULL
;
308 p_sys
->p_es_sub
= NULL
;
310 p_sys
->i_audio_delay
= 0;
311 p_sys
->i_spu_delay
= 0;
313 p_sys
->b_paused
= false;
314 p_sys
->i_pause_date
= -1;
316 p_sys
->i_rate
= i_rate
;
317 p_sys
->i_pts_delay
= 0;
318 p_sys
->i_pts_jitter
= 0;
319 p_sys
->i_cr_average
= 0;
321 p_sys
->b_buffering
= true;
322 p_sys
->i_buffering_extra_initial
= 0;
323 p_sys
->i_buffering_extra_stream
= 0;
324 p_sys
->i_buffering_extra_system
= 0;
325 p_sys
->i_preroll_end
= -1;
327 p_sys
->p_sout_record
= NULL
;
332 /*****************************************************************************
334 *****************************************************************************/
335 static void EsOutDelete( es_out_t
*out
)
337 es_out_sys_t
*p_sys
= out
->p_sys
;
339 assert( !p_sys
->i_es
&& !p_sys
->i_pgrm
&& !p_sys
->p_pgrm
);
340 if( p_sys
->ppsz_audio_language
)
342 for( int i
= 0; p_sys
->ppsz_audio_language
[i
]; i
++ )
343 free( p_sys
->ppsz_audio_language
[i
] );
344 free( p_sys
->ppsz_audio_language
);
346 if( p_sys
->ppsz_sub_language
)
348 for( int i
= 0; p_sys
->ppsz_sub_language
[i
]; i
++ )
349 free( p_sys
->ppsz_sub_language
[i
] );
350 free( p_sys
->ppsz_sub_language
);
353 vlc_mutex_destroy( &p_sys
->lock
);
359 static void EsOutTerminate( es_out_t
*out
)
361 es_out_sys_t
*p_sys
= out
->p_sys
;
363 if( p_sys
->p_sout_record
)
364 EsOutSetRecord( out
, false );
366 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
368 if( p_sys
->es
[i
]->p_dec
)
369 input_DecoderDelete( p_sys
->es
[i
]->p_dec
);
371 free( p_sys
->es
[i
]->psz_language
);
372 free( p_sys
->es
[i
]->psz_language_code
);
373 es_format_Clean( &p_sys
->es
[i
]->fmt
);
375 free( p_sys
->es
[i
] );
377 TAB_CLEAN( p_sys
->i_es
, p_sys
->es
);
379 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
380 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
382 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[i
];
383 input_clock_Delete( p_pgrm
->p_clock
);
384 free( p_pgrm
->psz_now_playing
);
385 free( p_pgrm
->psz_publisher
);
386 free( p_pgrm
->psz_name
);
390 TAB_CLEAN( p_sys
->i_pgrm
, p_sys
->pgrm
);
392 p_sys
->p_pgrm
= NULL
;
394 input_item_SetEpgOffline( p_sys
->p_input
->p
->p_item
);
395 input_SendEventMetaEpg( p_sys
->p_input
);
398 static mtime_t
EsOutGetWakeup( es_out_t
*out
)
400 es_out_sys_t
*p_sys
= out
->p_sys
;
401 input_thread_t
*p_input
= p_sys
->p_input
;
406 /* We do not have a wake up date if the input cannot have its speed
407 * controlled or sout is imposing its own or while buffering
409 * FIXME for !p_input->p->b_can_pace_control a wkeup time is still needed to avoid too strong buffering */
410 if( !p_input
->p
->b_can_pace_control
||
411 p_input
->p
->b_out_pace_control
||
415 return input_clock_GetWakeup( p_sys
->p_pgrm
->p_clock
);
418 static es_out_id_t
*EsOutGetFromID( es_out_t
*out
, int i_id
)
423 /* Special HACK, -i_id is the cat of the stream */
424 return (es_out_id_t
*)((uint8_t*)NULL
-i_id
);
427 for( i
= 0; i
< out
->p_sys
->i_es
; i
++ )
429 if( out
->p_sys
->es
[i
]->i_id
== i_id
)
430 return out
->p_sys
->es
[i
];
435 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
437 es_out_sys_t
*p_sys
= out
->p_sys
;
440 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
442 EsOutDecodersStopBuffering( out
, true );
443 if( p_sys
->b_buffering
)
447 for( i
= 0; i
< p_sys
->i_es
; i
++ )
449 es_out_id_t
*es
= p_sys
->es
[i
];
451 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
453 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
459 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, int64_t i_delay
)
461 es_out_sys_t
*p_sys
= out
->p_sys
;
463 if( i_cat
== AUDIO_ES
)
464 p_sys
->i_audio_delay
= i_delay
;
465 else if( i_cat
== SPU_ES
)
466 p_sys
->i_spu_delay
= i_delay
;
468 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
469 EsOutDecoderChangeDelay( out
, p_sys
->es
[i
] );
472 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
474 es_out_sys_t
*p_sys
= out
->p_sys
;
475 input_thread_t
*p_input
= p_sys
->p_input
;
477 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
481 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
484 if( var_CountChoices( p_input
, "video-es" ) )
485 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
486 else if( var_CountChoices( p_input
, "audio-es" ) )
487 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
489 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
492 char *psz_sout
= NULL
; // TODO conf
494 if( !psz_sout
&& psz_path
)
496 char *psz_file
= input_CreateFilename( VLC_OBJECT(p_input
), psz_path
, INPUT_RECORD_PREFIX
, NULL
);
499 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file
) < 0 )
510 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
514 if( !p_sys
->p_sout_record
)
517 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
519 es_out_id_t
*p_es
= p_sys
->es
[i
];
521 if( !p_es
->p_dec
|| p_es
->p_master
)
524 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
525 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
526 input_DecoderStartBuffering( p_es
->p_dec_record
);
531 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
533 es_out_id_t
*p_es
= p_sys
->es
[i
];
535 if( !p_es
->p_dec_record
)
538 input_DecoderDelete( p_es
->p_dec_record
);
539 p_es
->p_dec_record
= NULL
;
542 sout_DeleteInstance( p_sys
->p_sout_record
);
544 p_sys
->p_sout_record
= NULL
;
549 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
551 es_out_sys_t
*p_sys
= out
->p_sys
;
553 /* XXX the order is important */
556 EsOutDecodersChangePause( out
, true, i_date
);
557 EsOutProgramChangePause( out
, true, i_date
);
561 if( p_sys
->i_buffering_extra_initial
> 0 )
563 mtime_t i_stream_start
;
564 mtime_t i_system_start
;
565 mtime_t i_stream_duration
;
566 mtime_t i_system_duration
;
568 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
569 &i_stream_start
, &i_system_start
,
570 &i_stream_duration
, &i_system_duration
);
573 /* FIXME pcr != exactly what wanted */
574 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
;
577 p_sys
->i_buffering_extra_initial
= 0;
578 p_sys
->i_buffering_extra_stream
= 0;
579 p_sys
->i_buffering_extra_system
= 0;
581 EsOutProgramChangePause( out
, false, i_date
);
582 EsOutDecodersChangePause( out
, false, i_date
);
584 EsOutProgramsChangeRate( out
);
586 p_sys
->b_paused
= b_paused
;
587 p_sys
->i_pause_date
= i_date
;
590 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
592 es_out_sys_t
*p_sys
= out
->p_sys
;
594 p_sys
->i_rate
= i_rate
;
595 EsOutProgramsChangeRate( out
);
598 static void EsOutChangePosition( es_out_t
*out
)
600 es_out_sys_t
*p_sys
= out
->p_sys
;
602 input_SendEventCache( p_sys
->p_input
, 0.0 );
604 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
606 es_out_id_t
*p_es
= p_sys
->es
[i
];
611 input_DecoderStartBuffering( p_es
->p_dec
);
613 if( p_es
->p_dec_record
)
614 input_DecoderStartBuffering( p_es
->p_dec_record
);
617 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
618 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
620 p_sys
->b_buffering
= true;
621 p_sys
->i_buffering_extra_initial
= 0;
622 p_sys
->i_buffering_extra_stream
= 0;
623 p_sys
->i_buffering_extra_system
= 0;
624 p_sys
->i_preroll_end
= -1;
629 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
631 es_out_sys_t
*p_sys
= out
->p_sys
;
634 mtime_t i_stream_start
;
635 mtime_t i_system_start
;
636 mtime_t i_stream_duration
;
637 mtime_t i_system_duration
;
638 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
639 &i_stream_start
, &i_system_start
,
640 &i_stream_duration
, &i_system_duration
);
641 assert( !i_ret
|| b_forced
);
645 mtime_t i_preroll_duration
= 0;
646 if( p_sys
->i_preroll_end
>= 0 )
647 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
649 const mtime_t i_buffering_duration
= p_sys
->i_pts_delay
+
651 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
653 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
655 const double f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
656 input_SendEventCache( p_sys
->p_input
, f_level
);
658 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", (int)(100 * f_level
) );
661 input_SendEventCache( p_sys
->p_input
, 1.0 );
663 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
664 (int)(i_stream_duration
/1000), (int)(i_system_duration
/1000) );
665 p_sys
->b_buffering
= false;
666 p_sys
->i_preroll_end
= -1;
668 if( p_sys
->i_buffering_extra_initial
> 0 )
674 const mtime_t i_decoder_buffering_start
= mdate();
675 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
677 es_out_id_t
*p_es
= p_sys
->es
[i
];
679 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
681 input_DecoderWaitBuffering( p_es
->p_dec
);
682 if( p_es
->p_dec_record
)
683 input_DecoderWaitBuffering( p_es
->p_dec_record
);
686 msg_Dbg( p_sys
->p_input
, "Decoder buffering done in %d ms",
687 (int)(mdate() - i_decoder_buffering_start
)/1000 );
689 /* Here is a good place to destroy unused vout with every demuxer */
690 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
693 const mtime_t i_wakeup_delay
= 10*1000; /* FIXME CLEANUP thread wake up time*/
694 const mtime_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: mdate();
696 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_clock
, true,
697 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
699 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
701 es_out_id_t
*p_es
= p_sys
->es
[i
];
706 input_DecoderStopBuffering( p_es
->p_dec
);
707 if( p_es
->p_dec_record
)
708 input_DecoderStopBuffering( p_es
->p_dec_record
);
711 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
713 es_out_sys_t
*p_sys
= out
->p_sys
;
715 /* Pause decoders first */
716 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
718 es_out_id_t
*es
= p_sys
->es
[i
];
722 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
723 if( es
->p_dec_record
)
724 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
729 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
731 es_out_sys_t
*p_sys
= out
->p_sys
;
734 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
736 es_out_id_t
*p_es
= p_sys
->es
[i
];
739 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
740 if( p_es
->p_dec_record
)
741 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
743 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
745 /* TODO maybe we want to be able to tune it ? */
746 #if defined(OPTIMIZE_MEMORY)
747 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
749 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
751 return i_size
< i_level_high
;
754 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
756 es_out_sys_t
*p_sys
= out
->p_sys
;
758 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
759 input_clock_ChangePause( p_sys
->pgrm
[i
]->p_clock
, b_paused
, i_date
);
762 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
764 es_out_sys_t
*p_sys
= out
->p_sys
;
767 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
768 i_delay
= p_sys
->i_audio_delay
;
769 else if( p_es
->fmt
.i_cat
== SPU_ES
)
770 i_delay
= p_sys
->i_spu_delay
;
775 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
776 if( p_es
->p_dec_record
)
777 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
780 static void EsOutProgramsChangeRate( es_out_t
*out
)
782 es_out_sys_t
*p_sys
= out
->p_sys
;
784 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
785 input_clock_ChangeRate( p_sys
->pgrm
[i
]->p_clock
, p_sys
->i_rate
);
788 static void EsOutFrameNext( es_out_t
*out
)
790 es_out_sys_t
*p_sys
= out
->p_sys
;
791 es_out_id_t
*p_es_video
= NULL
;
793 if( p_sys
->b_buffering
)
795 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
799 assert( p_sys
->b_paused
);
801 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
803 es_out_id_t
*p_es
= p_sys
->es
[i
];
805 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
814 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
819 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
821 msg_Dbg( out
->p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)(i_duration
/1000) );
823 if( i_duration
<= 0 )
824 i_duration
= 40*1000;
826 /* FIXME it is not a clean way ? */
827 if( p_sys
->i_buffering_extra_initial
<= 0 )
829 mtime_t i_stream_start
;
830 mtime_t i_system_start
;
831 mtime_t i_stream_duration
;
832 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
);
841 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
842 p_sys
->i_buffering_extra_system
=
843 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
846 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_clock
);
848 p_sys
->b_buffering
= true;
849 p_sys
->i_buffering_extra_system
+= i_duration
;
850 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
851 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
852 INPUT_RATE_DEFAULT
/ i_rate
;
854 p_sys
->i_preroll_end
= -1;
856 static mtime_t
EsOutGetBuffering( es_out_t
*out
)
858 es_out_sys_t
*p_sys
= out
->p_sys
;
864 mtime_t i_stream_start
;
865 mtime_t i_system_start
;
866 mtime_t i_stream_duration
;
867 mtime_t i_system_duration
;
868 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
869 &i_stream_start
, &i_system_start
,
870 &i_stream_duration
, &i_system_duration
);
877 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
879 i_delay
= i_stream_duration
;
883 mtime_t i_system_duration
;
884 if( p_sys
->b_paused
)
886 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
887 if( p_sys
->i_buffering_extra_initial
> 0 )
888 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
892 i_system_duration
= mdate() - i_system_start
;
895 const mtime_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
896 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
903 static void EsOutESVarUpdateGeneric( es_out_t
*out
, int i_id
,
904 const es_format_t
*fmt
, const char *psz_language
,
907 es_out_sys_t
*p_sys
= out
->p_sys
;
908 input_thread_t
*p_input
= p_sys
->p_input
;
909 vlc_value_t val
, text
;
913 if( EsFmtIsTeletext( fmt
) )
914 input_SendEventTeletextDel( p_sys
->p_input
, i_id
);
916 input_SendEventEsDel( p_input
, fmt
->i_cat
, i_id
);
920 /* Get the number of ES already added */
922 if( fmt
->i_cat
== AUDIO_ES
)
923 psz_var
= "audio-es";
924 else if( fmt
->i_cat
== VIDEO_ES
)
925 psz_var
= "video-es";
929 var_Change( p_input
, psz_var
, VLC_VAR_CHOICESCOUNT
, &val
, NULL
);
934 /* First one, we need to add the "Disable" choice */
935 val2
.i_int
= -1; text
.psz_string
= _("Disable");
936 var_Change( p_input
, psz_var
, VLC_VAR_ADDCHOICE
, &val2
, &text
);
940 /* Take care of the ES description */
941 if( fmt
->psz_description
&& *fmt
->psz_description
)
943 if( psz_language
&& *psz_language
)
945 if( asprintf( &text
.psz_string
, "%s - [%s]", fmt
->psz_description
,
946 psz_language
) == -1 )
947 text
.psz_string
= NULL
;
949 else text
.psz_string
= strdup( fmt
->psz_description
);
953 if( psz_language
&& *psz_language
)
955 if( asprintf( &text
.psz_string
, "%s %"PRId64
" - [%s]", _( "Track" ), val
.i_int
, psz_language
) == -1 )
956 text
.psz_string
= NULL
;
960 if( asprintf( &text
.psz_string
, "%s %"PRId64
, _( "Track" ), val
.i_int
) == -1 )
961 text
.psz_string
= NULL
;
965 input_SendEventEsAdd( p_input
, fmt
->i_cat
, i_id
, text
.psz_string
);
966 if( EsFmtIsTeletext( fmt
) )
969 snprintf( psz_page
, sizeof(psz_page
), "%d%2.2x",
970 fmt
->subs
.teletext
.i_magazine
,
971 fmt
->subs
.teletext
.i_page
);
972 input_SendEventTeletextAdd( p_sys
->p_input
,
973 i_id
, fmt
->subs
.teletext
.i_magazine
>= 0 ? psz_page
: NULL
);
976 free( text
.psz_string
);
979 static void EsOutESVarUpdate( es_out_t
*out
, es_out_id_t
*es
,
982 EsOutESVarUpdateGeneric( out
, es
->i_id
, &es
->fmt
, es
->psz_language
, b_delete
);
985 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
987 return out
->p_sys
->i_group_id
== 0 || out
->p_sys
->i_group_id
== i_group
;
990 /* EsOutProgramSelect:
991 * Select a program and update the object variable
993 static void EsOutProgramSelect( es_out_t
*out
, es_out_pgrm_t
*p_pgrm
)
995 es_out_sys_t
*p_sys
= out
->p_sys
;
996 input_thread_t
*p_input
= p_sys
->p_input
;
999 if( p_sys
->p_pgrm
== p_pgrm
)
1000 return; /* Nothing to do */
1004 es_out_pgrm_t
*old
= p_sys
->p_pgrm
;
1005 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
1007 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1009 if( p_sys
->es
[i
]->p_pgrm
== old
&& EsIsSelected( p_sys
->es
[i
] ) &&
1010 p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
1011 EsUnselect( out
, p_sys
->es
[i
], true );
1014 p_sys
->p_es_audio
= NULL
;
1015 p_sys
->p_es_sub
= NULL
;
1016 p_sys
->p_es_video
= NULL
;
1019 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
1021 /* Mark it selected */
1022 p_pgrm
->b_selected
= true;
1024 /* Switch master stream */
1025 p_sys
->p_pgrm
= p_pgrm
;
1027 /* Update "program" */
1028 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
1031 input_SendEventEsDel( p_input
, AUDIO_ES
, -1 );
1032 input_SendEventEsDel( p_input
, VIDEO_ES
, -1 );
1033 input_SendEventEsDel( p_input
, SPU_ES
, -1 );
1034 input_SendEventTeletextDel( p_input
, -1 );
1035 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1038 var_SetInteger( p_input
, "teletext-es", -1 );
1040 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1042 if( p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
)
1043 EsOutESVarUpdate( out
, p_sys
->es
[i
], false );
1044 EsOutSelect( out
, p_sys
->es
[i
], false );
1047 /* Update now playing */
1048 input_item_SetNowPlaying( p_input
->p
->p_item
, p_pgrm
->psz_now_playing
);
1049 input_item_SetPublisher( p_input
->p
->p_item
, p_pgrm
->psz_publisher
);
1051 input_SendEventMeta( p_input
);
1057 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1059 es_out_sys_t
*p_sys
= out
->p_sys
;
1060 input_thread_t
*p_input
= p_sys
->p_input
;
1062 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1067 p_pgrm
->i_id
= i_group
;
1069 p_pgrm
->b_selected
= false;
1070 p_pgrm
->b_scrambled
= false;
1071 p_pgrm
->psz_name
= NULL
;
1072 p_pgrm
->psz_now_playing
= NULL
;
1073 p_pgrm
->psz_publisher
= NULL
;
1074 p_pgrm
->p_clock
= input_clock_New( p_sys
->i_rate
);
1075 if( !p_pgrm
->p_clock
)
1080 if( p_sys
->b_paused
)
1081 input_clock_ChangePause( p_pgrm
->p_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1082 input_clock_SetJitter( p_pgrm
->p_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1085 TAB_APPEND( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1087 /* Update "program" variable */
1088 if( EsOutIsProgramVisible( out
, i_group
) )
1089 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1091 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1092 EsOutProgramSelect( out
, p_pgrm
);
1100 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1102 es_out_sys_t
*p_sys
= out
->p_sys
;
1103 input_thread_t
*p_input
= p_sys
->p_input
;
1104 es_out_pgrm_t
*p_pgrm
= NULL
;
1107 for( i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1109 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1111 p_pgrm
= p_sys
->pgrm
[i
];
1116 if( p_pgrm
== NULL
)
1117 return VLC_EGENERIC
;
1121 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1122 i_group
, p_pgrm
->i_es
);
1123 return VLC_EGENERIC
;
1126 TAB_REMOVE( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1128 /* If program is selected we need to unselect it */
1129 if( p_sys
->p_pgrm
== p_pgrm
)
1130 p_sys
->p_pgrm
= NULL
;
1132 input_clock_Delete( p_pgrm
->p_clock
);
1134 free( p_pgrm
->psz_name
);
1135 free( p_pgrm
->psz_now_playing
);
1136 free( p_pgrm
->psz_publisher
);
1139 /* Update "program" variable */
1140 input_SendEventProgramDel( p_input
, i_group
);
1147 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1149 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1151 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1153 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1154 return p_sys
->pgrm
[i
];
1156 return EsOutProgramAdd( p_out
, i_group
);
1159 /* EsOutProgramMeta:
1161 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1164 if( p_pgrm
->psz_name
)
1166 if( asprintf( &psz
, _("%s [%s %d]"), p_pgrm
->psz_name
, _("Program"), p_pgrm
->i_id
) == -1 )
1171 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1177 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1179 es_out_sys_t
*p_sys
= out
->p_sys
;
1180 es_out_pgrm_t
*p_pgrm
;
1181 input_thread_t
*p_input
= p_sys
->p_input
;
1182 const char *psz_title
= NULL
;
1183 const char *psz_provider
= NULL
;
1186 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1188 /* Check against empty meta data (empty for what we handle) */
1189 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1190 !vlc_meta_Get( p_meta
, vlc_meta_NowPlaying
) &&
1191 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) &&
1192 vlc_meta_GetExtraCount( p_meta
) <= 0 )
1197 p_pgrm
= EsOutProgramFind( out
, i_group
);
1202 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1203 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1205 /* Update the description text of the program */
1206 if( psz_title
&& *psz_title
)
1208 if( !p_pgrm
->psz_name
|| strcmp( p_pgrm
->psz_name
, psz_title
) )
1210 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1212 /* Remove old entries */
1213 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, NULL
);
1214 /* TODO update epg name ?
1215 * TODO update scrambled info name ? */
1218 free( p_pgrm
->psz_name
);
1219 p_pgrm
->psz_name
= strdup( psz_title
);
1222 if( psz_provider
&& *psz_provider
)
1224 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1229 psz_text
= strdup( psz_title
);
1232 /* ugly but it works */
1233 if( EsOutIsProgramVisible( out
, i_group
) && psz_text
)
1235 input_SendEventProgramDel( p_input
, i_group
);
1236 input_SendEventProgramAdd( p_input
, i_group
, psz_text
);
1237 if( p_sys
->p_pgrm
== p_pgrm
)
1238 input_SendEventProgramSelect( p_input
, i_group
);
1244 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1246 info_category_t
*p_cat
= NULL
;
1247 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1249 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1251 p_cat
= info_category_New( psz_cat
);
1255 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1258 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1259 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1260 free( ppsz_all_keys
[i
] );
1262 free( ppsz_all_keys
);
1266 if( p_sys
->p_pgrm
== p_pgrm
)
1268 input_item_SetPublisher( p_input
->p
->p_item
, psz_provider
);
1269 input_SendEventMeta( p_input
);
1272 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1273 "%s",psz_provider
);
1276 input_Control( p_input
, INPUT_MERGE_INFOS
, p_cat
);
1279 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1281 es_out_sys_t
*p_sys
= out
->p_sys
;
1282 input_thread_t
*p_input
= p_sys
->p_input
;
1283 input_item_t
*p_item
= p_input
->p
->p_item
;
1284 es_out_pgrm_t
*p_pgrm
;
1288 p_pgrm
= EsOutProgramFind( out
, i_group
);
1293 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1294 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1300 epg
.psz_name
= psz_cat
;
1302 input_item_SetEpg( p_item
, &epg
);
1303 input_SendEventMetaEpg( p_sys
->p_input
);
1305 /* Update now playing */
1306 free( p_pgrm
->psz_now_playing
);
1307 p_pgrm
->psz_now_playing
= NULL
;
1309 vlc_mutex_lock( &p_item
->lock
);
1310 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1312 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1314 if( p_tmp
->psz_name
&& !strcmp(p_tmp
->psz_name
, psz_cat
) )
1316 if( p_tmp
->p_current
&& p_tmp
->p_current
->psz_name
&& *p_tmp
->p_current
->psz_name
)
1317 p_pgrm
->psz_now_playing
= strdup( p_tmp
->p_current
->psz_name
);
1321 vlc_mutex_unlock( &p_item
->lock
);
1323 if( p_pgrm
== p_sys
->p_pgrm
)
1325 input_item_SetNowPlaying( p_input
->p
->p_item
, p_pgrm
->psz_now_playing
);
1326 input_SendEventMeta( p_input
);
1329 if( p_pgrm
->psz_now_playing
)
1331 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
,
1332 vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying
),
1333 p_pgrm
->psz_now_playing
);
1337 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
,
1338 vlc_meta_TypeToLocalizedString(vlc_meta_NowPlaying
) );
1344 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1346 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1347 input_thread_t
*p_input
= p_sys
->p_input
;
1348 bool b_scrambled
= false;
1350 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
1352 if( p_sys
->es
[i
]->p_pgrm
== p_pgrm
&& p_sys
->es
[i
]->b_scrambled
)
1358 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1361 p_pgrm
->b_scrambled
= b_scrambled
;
1362 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1365 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
, _("Scrambled"), _("Yes") );
1367 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, _("Scrambled") );
1369 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1372 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1374 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1375 input_thread_t
*p_input
= p_sys
->p_input
;
1377 input_item_t
*p_item
= input_GetItem( p_input
);
1379 char *psz_title
= NULL
;
1380 char *psz_arturl
= input_item_GetArtURL( p_item
);
1382 vlc_mutex_lock( &p_item
->lock
);
1384 if( vlc_meta_Get( p_meta
, vlc_meta_Title
) && !p_item
->b_fixed_name
)
1385 psz_title
= strdup( vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1387 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1389 if( !psz_arturl
|| *psz_arturl
== '\0' )
1391 const char *psz_tmp
= vlc_meta_Get( p_item
->p_meta
, vlc_meta_ArtworkURL
);
1393 psz_arturl
= strdup( psz_tmp
);
1395 vlc_mutex_unlock( &p_item
->lock
);
1397 if( psz_arturl
&& *psz_arturl
)
1399 input_item_SetArtURL( p_item
, psz_arturl
);
1401 if( !strncmp( psz_arturl
, "attachment://", strlen("attachment") ) )
1403 /* Don't look for art cover if sout
1404 * XXX It can change when sout has meta data support */
1405 if( p_input
->p
->p_sout
&& !p_input
->b_preparsing
)
1406 input_item_SetArtURL( p_item
, "" );
1408 input_ExtractAttachmentAndCacheArt( p_input
);
1415 input_item_SetName( p_item
, psz_title
);
1418 input_item_SetPreparsed( p_item
, true );
1420 input_SendEventMeta( p_input
);
1421 /* TODO handle sout meta ? */
1427 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1429 es_out_sys_t
*p_sys
= out
->p_sys
;
1430 input_thread_t
*p_input
= p_sys
->p_input
;
1432 if( fmt
->i_group
< 0 )
1434 msg_Err( p_input
, "invalid group number" );
1438 es_out_id_t
*es
= malloc( sizeof( *es
) );
1439 es_out_pgrm_t
*p_pgrm
;
1445 vlc_mutex_lock( &p_sys
->lock
);
1447 /* Search the program */
1448 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1451 vlc_mutex_unlock( &p_sys
->lock
);
1456 /* Increase ref count for program */
1460 es
->p_pgrm
= p_pgrm
;
1461 es_format_Copy( &es
->fmt
, fmt
);
1462 if( es
->fmt
.i_id
< 0 )
1463 es
->fmt
.i_id
= out
->p_sys
->i_id
;
1464 if( !es
->fmt
.i_original_fourcc
)
1465 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1466 if( es
->fmt
.i_cat
== AUDIO_ES
)
1467 es
->fmt
.i_codec
= vlc_fourcc_GetCodecAudio( es
->fmt
.i_codec
,
1468 es
->fmt
.audio
.i_bitspersample
);
1470 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
,
1473 es
->i_id
= es
->fmt
.i_id
;
1474 es
->i_meta_id
= out
->p_sys
->i_id
;
1475 es
->b_scrambled
= false;
1477 switch( es
->fmt
.i_cat
)
1481 audio_replay_gain_t rg
;
1483 es
->i_channel
= p_sys
->i_audio
;
1485 memset( &rg
, 0, sizeof(rg
) );
1486 vlc_mutex_lock( &p_input
->p
->p_item
->lock
);
1487 vlc_audio_replay_gain_MergeFromMeta( &rg
, p_input
->p
->p_item
->p_meta
);
1488 vlc_mutex_unlock( &p_input
->p
->p_item
->lock
);
1490 for( i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1492 if( !es
->fmt
.audio_replay_gain
.pb_peak
[i
] )
1494 es
->fmt
.audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1495 es
->fmt
.audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1497 if( !es
->fmt
.audio_replay_gain
.pb_gain
[i
] )
1499 es
->fmt
.audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1500 es
->fmt
.audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1507 es
->i_channel
= p_sys
->i_video
;
1508 if( es
->fmt
.video
.i_frame_rate
&& es
->fmt
.video
.i_frame_rate_base
)
1509 vlc_ureduce( &es
->fmt
.video
.i_frame_rate
,
1510 &es
->fmt
.video
.i_frame_rate_base
,
1511 es
->fmt
.video
.i_frame_rate
,
1512 es
->fmt
.video
.i_frame_rate_base
, 0 );
1516 es
->i_channel
= p_sys
->i_sub
;
1523 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1524 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1526 es
->p_dec_record
= NULL
;
1527 for( i
= 0; i
< 4; i
++ )
1528 es
->pb_cc_present
[i
] = false;
1529 es
->p_master
= NULL
;
1531 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1532 EsOutESVarUpdate( out
, es
, false );
1534 /* Select it if needed */
1535 EsOutSelect( out
, es
, false );
1538 TAB_APPEND( out
->p_sys
->i_es
, out
->p_sys
->es
, es
);
1539 p_sys
->i_id
++; /* always incremented */
1540 switch( es
->fmt
.i_cat
)
1553 EsOutUpdateInfo( out
, es
, &es
->fmt
, NULL
);
1555 if( es
->b_scrambled
)
1556 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1558 vlc_mutex_unlock( &p_sys
->lock
);
1563 static bool EsIsSelected( es_out_id_t
*es
)
1567 bool b_decode
= false;
1568 if( es
->p_master
->p_dec
)
1570 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1571 if( i_channel
!= -1 )
1572 input_DecoderGetCcState( es
->p_master
->p_dec
, &b_decode
, i_channel
);
1578 return es
->p_dec
!= NULL
;
1581 static void EsCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1583 es_out_sys_t
*p_sys
= out
->p_sys
;
1584 input_thread_t
*p_input
= p_sys
->p_input
;
1586 p_es
->p_dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_input
->p
->p_sout
);
1589 if( p_sys
->b_buffering
)
1590 input_DecoderStartBuffering( p_es
->p_dec
);
1592 if( !p_es
->p_master
&& p_sys
->p_sout_record
)
1594 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
1595 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
1596 input_DecoderStartBuffering( p_es
->p_dec_record
);
1600 EsOutDecoderChangeDelay( out
, p_es
);
1602 static void EsDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1609 input_DecoderDelete( p_es
->p_dec
);
1612 if( p_es
->p_dec_record
)
1614 input_DecoderDelete( p_es
->p_dec_record
);
1615 p_es
->p_dec_record
= NULL
;
1619 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
)
1621 es_out_sys_t
*p_sys
= out
->p_sys
;
1622 input_thread_t
*p_input
= p_sys
->p_input
;
1624 if( EsIsSelected( es
) )
1626 msg_Warn( p_input
, "ES 0x%x is already selected", es
->i_id
);
1633 if( !es
->p_master
->p_dec
)
1636 i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1637 if( i_channel
== -1 || input_DecoderSetCcState( es
->p_master
->p_dec
, true, i_channel
) )
1642 const bool b_sout
= p_input
->p
->p_sout
!= NULL
;
1643 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1645 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1647 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1652 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1654 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) )
1656 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1661 if( es
->fmt
.i_cat
== SPU_ES
)
1663 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) )
1665 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1671 EsCreateDecoder( out
, es
);
1673 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1677 /* Mark it as selected */
1678 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, es
->i_id
);
1679 input_SendEventTeletextSelect( p_input
, EsFmtIsTeletext( &es
->fmt
) ? es
->i_id
: -1 );
1682 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1684 es_out_sys_t
*p_sys
= out
->p_sys
;
1685 input_thread_t
*p_input
= p_sys
->p_input
;
1687 if( !EsIsSelected( es
) )
1689 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->i_id
);
1695 if( es
->p_master
->p_dec
)
1697 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_codec
);
1698 if( i_channel
!= -1 )
1699 input_DecoderSetCcState( es
->p_master
->p_dec
, false, i_channel
);
1704 const int i_spu_id
= var_GetInteger( p_input
, "spu-es");
1706 for( i
= 0; i
< 4; i
++ )
1708 if( !es
->pb_cc_present
[i
] || !es
->pp_cc_es
[i
] )
1711 if( i_spu_id
== es
->pp_cc_es
[i
]->i_id
)
1713 /* Force unselection of the CC */
1714 input_SendEventEsSelect( p_input
, SPU_ES
, -1 );
1716 EsOutDel( out
, es
->pp_cc_es
[i
] );
1718 es
->pb_cc_present
[i
] = false;
1720 EsDestroyDecoder( out
, es
);
1726 /* Mark it as unselected */
1727 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, -1 );
1728 if( EsFmtIsTeletext( &es
->fmt
) )
1729 input_SendEventTeletextSelect( p_input
, -1 );
1733 * Select an ES given the current mode
1734 * XXX: you need to take a the lock before (stream.stream_lock)
1736 * \param out The es_out structure
1737 * \param es es_out_id structure
1738 * \param b_force ...
1741 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1743 es_out_sys_t
*p_sys
= out
->p_sys
;
1745 int i_cat
= es
->fmt
.i_cat
;
1747 if( !p_sys
->b_active
||
1748 ( !b_force
&& es
->fmt
.i_priority
< 0 ) )
1753 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
1755 if( !EsIsSelected( es
) )
1756 EsSelect( out
, es
);
1758 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
1760 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
1765 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1767 prgm
= strtok_r( NULL
, ",", &buf
) )
1769 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
1771 if( !EsIsSelected( es
) )
1772 EsSelect( out
, es
);
1779 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1783 if( es
->p_pgrm
!= p_sys
->p_pgrm
)
1786 if( i_cat
== AUDIO_ES
)
1788 int idx1
= LanguageArrayIndex( p_sys
->ppsz_audio_language
,
1789 es
->psz_language_code
);
1791 if( p_sys
->p_es_audio
&&
1792 p_sys
->p_es_audio
->fmt
.i_priority
>= es
->fmt
.i_priority
)
1794 int idx2
= LanguageArrayIndex( p_sys
->ppsz_audio_language
,
1795 p_sys
->p_es_audio
->psz_language_code
);
1797 if( idx1
< 0 || ( idx2
>= 0 && idx2
<= idx1
) )
1799 i_wanted
= es
->i_channel
;
1803 /* Select audio if (no audio selected yet)
1804 * - no audio-language
1805 * - no audio code for the ES
1806 * - audio code in the requested list */
1808 !strcmp( es
->psz_language_code
, "??" ) ||
1809 !p_sys
->ppsz_audio_language
)
1810 i_wanted
= es
->i_channel
;
1813 if( p_sys
->i_audio_last
>= 0 )
1814 i_wanted
= p_sys
->i_audio_last
;
1816 if( p_sys
->i_audio_id
>= 0 )
1818 if( es
->i_id
== p_sys
->i_audio_id
)
1819 i_wanted
= es
->i_channel
;
1824 else if( i_cat
== SPU_ES
)
1826 int idx1
= LanguageArrayIndex( p_sys
->ppsz_sub_language
,
1827 es
->psz_language_code
);
1829 if( p_sys
->p_es_sub
&&
1830 p_sys
->p_es_sub
->fmt
.i_priority
>= es
->fmt
.i_priority
)
1832 int idx2
= LanguageArrayIndex( p_sys
->ppsz_sub_language
,
1833 p_sys
->p_es_sub
->psz_language_code
);
1835 msg_Dbg( p_sys
->p_input
, "idx1=%d(%s) idx2=%d(%s)",
1836 idx1
, es
->psz_language_code
, idx2
,
1837 p_sys
->p_es_sub
->psz_language_code
);
1839 if( idx1
< 0 || ( idx2
>= 0 && idx2
<= idx1
) )
1841 /* We found a SPU that matches our language request */
1842 i_wanted
= es
->i_channel
;
1844 else if( idx1
>= 0 )
1846 msg_Dbg( p_sys
->p_input
, "idx1=%d(%s)",
1847 idx1
, es
->psz_language_code
);
1849 i_wanted
= es
->i_channel
;
1851 else if( p_sys
->i_default_sub_id
>= 0 )
1853 if( es
->i_id
== p_sys
->i_default_sub_id
)
1854 i_wanted
= es
->i_channel
;
1857 if( p_sys
->i_sub_last
>= 0 )
1858 i_wanted
= p_sys
->i_sub_last
;
1860 if( p_sys
->i_sub_id
>= 0 )
1862 if( es
->i_id
== p_sys
->i_sub_id
)
1863 i_wanted
= es
->i_channel
;
1868 else if( i_cat
== VIDEO_ES
)
1870 i_wanted
= es
->i_channel
;
1873 if( i_wanted
== es
->i_channel
&& !EsIsSelected( es
) )
1874 EsSelect( out
, es
);
1877 /* FIXME TODO handle priority here */
1878 if( EsIsSelected( es
) )
1880 if( i_cat
== AUDIO_ES
)
1882 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1883 p_sys
->p_es_audio
&&
1884 p_sys
->p_es_audio
!= es
&&
1885 EsIsSelected( p_sys
->p_es_audio
) )
1887 EsUnselect( out
, p_sys
->p_es_audio
, false );
1889 p_sys
->p_es_audio
= es
;
1891 else if( i_cat
== SPU_ES
)
1893 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1895 p_sys
->p_es_sub
!= es
&&
1896 EsIsSelected( p_sys
->p_es_sub
) )
1898 EsUnselect( out
, p_sys
->p_es_sub
, false );
1900 p_sys
->p_es_sub
= es
;
1902 else if( i_cat
== VIDEO_ES
)
1904 p_sys
->p_es_video
= es
;
1910 * Send a block for the given es_out
1912 * \param out the es_out to send from
1913 * \param es the es_out_id
1914 * \param p_block the data block to send
1916 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
1918 es_out_sys_t
*p_sys
= out
->p_sys
;
1919 input_thread_t
*p_input
= p_sys
->p_input
;
1922 if( libvlc_stats( p_input
) )
1924 vlc_mutex_lock( &p_input
->p
->counters
.counters_lock
);
1925 stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_demux_read
,
1926 p_block
->i_buffer
, &i_total
);
1927 stats_UpdateFloat( p_input
, p_input
->p
->counters
.p_demux_bitrate
,
1928 (float)i_total
, NULL
);
1930 /* Update number of corrupted data packats */
1931 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
1933 stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_demux_corrupted
,
1936 /* Update number of discontinuities */
1937 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
1939 stats_UpdateInteger( p_input
, p_input
->p
->counters
.p_demux_discontinuity
,
1942 vlc_mutex_unlock( &p_input
->p
->counters
.counters_lock
);
1945 vlc_mutex_lock( &p_sys
->lock
);
1947 /* Mark preroll blocks */
1948 if( p_sys
->i_preroll_end
>= 0 )
1950 int64_t i_date
= p_block
->i_pts
;
1951 if( p_block
->i_pts
<= VLC_TS_INVALID
)
1952 i_date
= p_block
->i_dts
;
1954 if( i_date
< p_sys
->i_preroll_end
)
1955 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
1958 p_block
->i_rate
= 0;
1962 block_Release( p_block
);
1963 vlc_mutex_unlock( &p_sys
->lock
);
1967 /* Check for sout mode */
1968 if( p_input
->p
->p_sout
)
1970 /* FIXME review this, proper lock may be missing */
1971 if( p_input
->p
->p_sout
->i_out_pace_nocontrol
> 0 &&
1972 p_input
->p
->b_out_pace_control
)
1974 msg_Dbg( p_input
, "switching to sync mode" );
1975 p_input
->p
->b_out_pace_control
= false;
1977 else if( p_input
->p
->p_sout
->i_out_pace_nocontrol
<= 0 &&
1978 !p_input
->p
->b_out_pace_control
)
1980 msg_Dbg( p_input
, "switching to async mode" );
1981 p_input
->p
->b_out_pace_control
= true;
1986 if( es
->p_dec_record
)
1988 block_t
*p_dup
= block_Duplicate( p_block
);
1990 input_DecoderDecode( es
->p_dec_record
, p_dup
,
1991 p_input
->p
->b_out_pace_control
);
1993 input_DecoderDecode( es
->p_dec
, p_block
,
1994 p_input
->p
->b_out_pace_control
);
1996 es_format_t fmt_dsc
;
1997 vlc_meta_t
*p_meta_dsc
;
1998 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
2000 EsOutUpdateInfo( out
, es
, &fmt_dsc
, p_meta_dsc
);
2002 es_format_Clean( &fmt_dsc
);
2004 vlc_meta_Delete( p_meta_dsc
);
2007 /* Check CC status */
2010 input_DecoderIsCcPresent( es
->p_dec
, pb_cc
);
2011 for( int i
= 0; i
< 4; i
++ )
2015 if( es
->pb_cc_present
[i
] || !pb_cc
[i
] )
2017 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, es
->i_id
);
2019 es_format_Init( &fmt
, SPU_ES
, EsOutFourccClosedCaptions
[i
] );
2020 fmt
.i_group
= es
->fmt
.i_group
;
2021 if( asprintf( &fmt
.psz_description
,
2022 _("Closed captions %u"), 1 + i
) == -1 )
2023 fmt
.psz_description
= NULL
;
2024 es
->pp_cc_es
[i
] = EsOutAdd( out
, &fmt
);
2025 es
->pp_cc_es
[i
]->p_master
= es
;
2026 es_format_Clean( &fmt
);
2029 es
->pb_cc_present
[i
] = true;
2032 vlc_mutex_unlock( &p_sys
->lock
);
2037 /*****************************************************************************
2039 *****************************************************************************/
2040 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2042 es_out_sys_t
*p_sys
= out
->p_sys
;
2043 bool b_reselect
= false;
2046 vlc_mutex_lock( &p_sys
->lock
);
2048 /* We don't try to reselect */
2051 while( !p_sys
->p_input
->b_die
&& !p_sys
->b_buffering
&& es
->p_dec
)
2053 if( input_DecoderIsEmpty( es
->p_dec
) &&
2054 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2056 /* FIXME there should be a way to have auto deleted es, but there will be
2057 * a problem when another codec of the same type is created (mainly video) */
2060 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2063 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2064 EsOutESVarUpdate( out
, es
, true );
2066 TAB_REMOVE( p_sys
->i_es
, p_sys
->es
, es
);
2068 /* Update program */
2070 if( es
->p_pgrm
->i_es
== 0 )
2071 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2073 if( es
->b_scrambled
)
2074 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2077 if( p_sys
->p_es_audio
== es
|| p_sys
->p_es_video
== es
||
2078 p_sys
->p_es_sub
== es
) b_reselect
= true;
2080 if( p_sys
->p_es_audio
== es
) p_sys
->p_es_audio
= NULL
;
2081 if( p_sys
->p_es_video
== es
) p_sys
->p_es_video
= NULL
;
2082 if( p_sys
->p_es_sub
== es
) p_sys
->p_es_sub
= NULL
;
2084 switch( es
->fmt
.i_cat
)
2097 /* Re-select another track when needed */
2100 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2102 if( es
->fmt
.i_cat
== p_sys
->es
[i
]->fmt
.i_cat
)
2103 EsOutSelect( out
, p_sys
->es
[i
], false );
2107 free( es
->psz_language
);
2108 free( es
->psz_language_code
);
2110 es_format_Clean( &es
->fmt
);
2112 vlc_mutex_unlock( &p_sys
->lock
);
2118 * Control query handler
2120 * \param out the es_out to control
2121 * \param i_query A es_out query as defined in include/ninput.h
2122 * \param args a variable list of arguments for the query
2123 * \return VLC_SUCCESS or an error code
2125 static int EsOutControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2127 es_out_sys_t
*p_sys
= out
->p_sys
;
2131 case ES_OUT_SET_ES_STATE
:
2133 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2134 bool b
= va_arg( args
, int );
2135 if( b
&& !EsIsSelected( es
) )
2137 EsSelect( out
, es
);
2138 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2140 else if( !b
&& EsIsSelected( es
) )
2142 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2148 case ES_OUT_GET_ES_STATE
:
2150 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2151 bool *pb
= va_arg( args
, bool * );
2153 *pb
= EsIsSelected( es
);
2157 case ES_OUT_GET_GROUP_FORCED
:
2159 int *pi_group
= va_arg( args
, int * );
2160 *pi_group
= p_sys
->i_group_id
;
2164 case ES_OUT_SET_MODE
:
2166 const int i_mode
= va_arg( args
, int );
2167 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2168 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2169 i_mode
== ES_OUT_MODE_END
);
2171 if( i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& p_sys
->i_es
> 0 )
2173 /* XXX Terminate vout if there are tracks but no video one.
2174 * This one is not mandatory but is he earliest place where it
2177 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2179 es_out_id_t
*p_es
= p_sys
->es
[i
];
2180 if( p_es
->fmt
.i_cat
== VIDEO_ES
)
2183 if( i
>= p_sys
->i_es
)
2184 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
2186 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2187 p_sys
->i_mode
= i_mode
;
2189 /* Reapply policy mode */
2190 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2192 if( EsIsSelected( p_sys
->es
[i
] ) )
2193 EsUnselect( out
, p_sys
->es
[i
],
2194 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2196 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2197 EsOutSelect( out
, p_sys
->es
[i
], false );
2198 if( i_mode
== ES_OUT_MODE_END
)
2199 EsOutTerminate( out
);
2204 case ES_OUT_RESTART_ES
:
2206 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2211 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2213 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2215 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2220 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2224 if( es
== p_sys
->es
[i
] )
2226 EsOutSelect( out
, es
, true );
2232 if( i_cat
== UNKNOWN_ES
|| p_sys
->es
[i
]->fmt
.i_cat
== i_cat
)
2234 if( EsIsSelected( p_sys
->es
[i
] ) )
2236 if( i_query
== ES_OUT_RESTART_ES
)
2238 if( p_sys
->es
[i
]->p_dec
)
2240 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2241 EsCreateDecoder( out
, p_sys
->es
[i
] );
2246 EsUnselect( out
, p_sys
->es
[i
],
2247 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2256 case ES_OUT_SET_ES_DEFAULT
:
2258 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2262 /*p_sys->i_default_video_id = -1;*/
2263 /*p_sys->i_default_audio_id = -1;*/
2264 p_sys
->i_default_sub_id
= -1;
2266 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2268 /*p_sys->i_default_video_id = -1;*/
2270 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2272 /*p_sys->i_default_audio_id = -1;*/
2274 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2276 p_sys
->i_default_sub_id
= -1;
2280 /*if( es->fmt.i_cat == VIDEO_ES )
2281 p_sys->i_default_video_id = es->i_id;
2283 if( es->fmt.i_cat == AUDIO_ES )
2284 p_sys->i_default_audio_id = es->i_id;
2286 if( es
->fmt
.i_cat
== SPU_ES
)
2287 p_sys
->i_default_sub_id
= es
->i_id
;
2292 case ES_OUT_SET_PCR
:
2293 case ES_OUT_SET_GROUP_PCR
:
2295 es_out_pgrm_t
*p_pgrm
= NULL
;
2299 /* Search program */
2300 if( i_query
== ES_OUT_SET_PCR
)
2302 p_pgrm
= p_sys
->p_pgrm
;
2304 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2308 i_group
= (int)va_arg( args
, int );
2309 p_pgrm
= EsOutProgramFind( out
, i_group
);
2312 return VLC_EGENERIC
;
2314 i_pcr
= (int64_t)va_arg( args
, int64_t );
2315 if( i_pcr
<= VLC_TS_INVALID
)
2317 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2318 return VLC_EGENERIC
;
2321 /* TODO do not use mdate() but proper stream acquisition date */
2323 input_clock_Update( p_pgrm
->p_clock
, VLC_OBJECT(p_sys
->p_input
),
2325 p_sys
->p_input
->p
->b_can_pace_control
|| p_sys
->b_buffering
,
2326 EsOutIsExtraBufferingAllowed( out
),
2329 if( p_pgrm
== p_sys
->p_pgrm
)
2331 if( p_sys
->b_buffering
)
2333 /* Check buffering state on master clock update */
2334 EsOutDecodersStopBuffering( out
, false );
2336 else if( b_late
&& ( !p_sys
->p_input
->p
->p_sout
||
2337 !p_sys
->p_input
->p
->b_out_pace_control
) )
2339 const mtime_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2340 mtime_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_clock
);
2342 /* Avoid dangerously high value */
2343 const mtime_t i_jitter_max
= INT64_C(1000) * var_InheritInteger( p_sys
->p_input
, "clock-jitter" );
2344 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2346 msg_Err( p_sys
->p_input
,
2347 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2348 (int)(i_pts_delay
- i_pts_delay_base
) / 1000 );
2349 i_pts_delay
= p_sys
->i_pts_delay
;
2353 msg_Err( p_sys
->p_input
,
2354 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2355 (int)(i_pts_delay
/1000) );
2358 /* Force a rebufferization when we are too late */
2360 /* It is not really good, as we throw away already buffered data
2361 * TODO have a mean to correctly reenter bufferization */
2362 es_out_Control( out
, ES_OUT_RESET_PCR
);
2364 es_out_SetJitter( out
, i_pts_delay_base
, i_pts_delay
- i_pts_delay_base
, p_sys
->i_cr_average
);
2370 case ES_OUT_RESET_PCR
:
2371 msg_Err( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2372 EsOutChangePosition( out
);
2375 case ES_OUT_SET_GROUP
:
2377 int i
= va_arg( args
, int );
2378 for( int j
= 0; j
< p_sys
->i_pgrm
; j
++ )
2380 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[j
];
2381 if( p_pgrm
->i_id
== i
)
2383 EsOutProgramSelect( out
, p_pgrm
);
2387 return VLC_EGENERIC
;
2390 case ES_OUT_SET_ES_FMT
:
2392 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2393 * to update the p_extra data */
2394 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2395 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2397 return VLC_EGENERIC
;
2399 if( p_fmt
->i_extra
)
2401 es
->fmt
.i_extra
= p_fmt
->i_extra
;
2402 es
->fmt
.p_extra
= xrealloc( es
->fmt
.p_extra
, p_fmt
->i_extra
);
2403 memcpy( es
->fmt
.p_extra
, p_fmt
->p_extra
, p_fmt
->i_extra
);
2408 EsDestroyDecoder( out
, es
);
2410 EsCreateDecoder( out
, es
);
2412 es
->p_dec
->fmt_in
.i_extra
= p_fmt
->i_extra
;
2413 es
->p_dec
->fmt_in
.p_extra
=
2414 xrealloc( es
->p_dec
->fmt_in
.p_extra
, p_fmt
->i_extra
);
2415 memcpy( es
->p_dec
->fmt_in
.p_extra
,
2416 p_fmt
->p_extra
, p_fmt
->i_extra
);
2423 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2425 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2426 bool b_scrambled
= (bool)va_arg( args
, int );
2428 if( !es
->b_scrambled
!= !b_scrambled
)
2430 es
->b_scrambled
= b_scrambled
;
2431 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2436 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2438 const int64_t i_date
= (int64_t)va_arg( args
, int64_t );
2441 return VLC_EGENERIC
;
2443 p_sys
->i_preroll_end
= i_date
;
2447 case ES_OUT_SET_GROUP_META
:
2449 int i_group
= (int)va_arg( args
, int );
2450 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2452 EsOutProgramMeta( out
, i_group
, p_meta
);
2455 case ES_OUT_SET_GROUP_EPG
:
2457 int i_group
= (int)va_arg( args
, int );
2458 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2460 EsOutProgramEpg( out
, i_group
, p_epg
);
2464 case ES_OUT_DEL_GROUP
:
2466 int i_group
= (int)va_arg( args
, int );
2468 return EsOutProgramDel( out
, i_group
);
2471 case ES_OUT_SET_META
:
2473 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2475 EsOutMeta( out
, p_meta
);
2479 case ES_OUT_GET_WAKE_UP
:
2481 mtime_t
*pi_wakeup
= (mtime_t
*)va_arg( args
, mtime_t
* );
2482 *pi_wakeup
= EsOutGetWakeup( out
);
2486 case ES_OUT_SET_ES_BY_ID
:
2487 case ES_OUT_RESTART_ES_BY_ID
:
2488 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2490 const int i_id
= (int)va_arg( args
, int );
2491 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2496 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
; break;
2497 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2498 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2502 /* TODO if the lock is made non recursive it should be changed */
2503 int i_ret
= es_out_Control( out
, i_new_query
, p_es
);
2505 /* Clean up vout after user action (in active mode only).
2506 * FIXME it does not work well with multiple video windows */
2507 if( p_sys
->b_active
)
2508 input_resource_TerminateVout( p_sys
->p_input
->p
->p_resource
);
2512 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2514 const int i_id
= va_arg( args
, int );
2515 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2517 return VLC_EGENERIC
;
2519 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2520 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2521 aout_instance_t
**pp_aout
= va_arg( args
, aout_instance_t
** );
2525 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2526 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2540 case ES_OUT_GET_BUFFERING
:
2542 bool *pb
= va_arg( args
, bool* );
2543 *pb
= p_sys
->b_buffering
;
2547 case ES_OUT_GET_EMPTY
:
2549 bool *pb
= va_arg( args
, bool* );
2550 *pb
= EsOutDecodersIsEmpty( out
);
2554 case ES_OUT_SET_DELAY
:
2556 const int i_cat
= (int)va_arg( args
, int );
2557 const mtime_t i_delay
= (mtime_t
)va_arg( args
, mtime_t
);
2558 EsOutSetDelay( out
, i_cat
, i_delay
);
2562 case ES_OUT_SET_RECORD_STATE
:
2564 bool b
= va_arg( args
, int );
2565 return EsOutSetRecord( out
, b
);
2568 case ES_OUT_SET_PAUSE_STATE
:
2570 const bool b_source_paused
= (bool)va_arg( args
, int );
2571 const bool b_paused
= (bool)va_arg( args
, int );
2572 const mtime_t i_date
= (mtime_t
) va_arg( args
, mtime_t
);
2574 assert( !b_source_paused
== !b_paused
);
2575 EsOutChangePause( out
, b_paused
, i_date
);
2580 case ES_OUT_SET_RATE
:
2582 const int i_src_rate
= (int)va_arg( args
, int );
2583 const int i_rate
= (int)va_arg( args
, int );
2585 assert( i_src_rate
== i_rate
);
2586 EsOutChangeRate( out
, i_rate
);
2591 case ES_OUT_SET_TIME
:
2593 const mtime_t i_date
= (mtime_t
)va_arg( args
, mtime_t
);
2595 assert( i_date
== -1 );
2596 EsOutChangePosition( out
);
2601 case ES_OUT_SET_FRAME_NEXT
:
2602 EsOutFrameNext( out
);
2605 case ES_OUT_SET_TIMES
:
2607 double f_position
= (double)va_arg( args
, double );
2608 mtime_t i_time
= (mtime_t
)va_arg( args
, mtime_t
);
2609 mtime_t i_length
= (mtime_t
)va_arg( args
, mtime_t
);
2611 input_SendEventLength( p_sys
->p_input
, i_length
);
2613 if( !p_sys
->b_buffering
)
2617 /* Fix for buffering delay */
2618 if( !p_sys
->p_input
->p
->p_sout
||
2619 !p_sys
->p_input
->p
->b_out_pace_control
)
2620 i_delay
= EsOutGetBuffering( out
);
2629 f_position
-= (double)i_delay
/ i_length
;
2630 if( f_position
< 0 )
2633 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
2637 case ES_OUT_SET_JITTER
:
2639 mtime_t i_pts_delay
= (mtime_t
)va_arg( args
, mtime_t
);
2640 mtime_t i_pts_jitter
= (mtime_t
)va_arg( args
, mtime_t
);
2641 int i_cr_average
= (int)va_arg( args
, int );
2643 bool b_change_clock
=
2644 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
2645 i_cr_average
!= p_sys
->i_cr_average
;
2647 assert( i_pts_jitter
>= 0 );
2648 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
2649 p_sys
->i_pts_jitter
= i_pts_jitter
;
2650 p_sys
->i_cr_average
= i_cr_average
;
2652 for( int i
= 0; i
< p_sys
->i_pgrm
&& b_change_clock
; i
++ )
2653 input_clock_SetJitter( p_sys
->pgrm
[i
]->p_clock
,
2654 i_pts_delay
+ i_pts_jitter
, i_cr_average
);
2658 case ES_OUT_GET_PCR_SYSTEM
:
2660 if( p_sys
->b_buffering
)
2661 return VLC_EGENERIC
;
2663 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2665 return VLC_EGENERIC
;
2667 mtime_t
*pi_system
= va_arg( args
, mtime_t
*);
2668 mtime_t
*pi_delay
= va_arg( args
, mtime_t
*);
2669 input_clock_GetSystemOrigin( p_pgrm
->p_clock
, pi_system
, pi_delay
);
2673 case ES_OUT_MODIFY_PCR_SYSTEM
:
2675 if( p_sys
->b_buffering
)
2676 return VLC_EGENERIC
;
2678 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2680 return VLC_EGENERIC
;
2682 const bool b_absolute
= va_arg( args
, int );
2683 const mtime_t i_system
= va_arg( args
, mtime_t
);
2684 input_clock_ChangeSystemOrigin( p_pgrm
->p_clock
, b_absolute
, i_system
);
2689 msg_Err( p_sys
->p_input
, "unknown query in es_out_Control" );
2690 return VLC_EGENERIC
;
2693 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
2695 es_out_sys_t
*p_sys
= out
->p_sys
;
2698 vlc_mutex_lock( &p_sys
->lock
);
2699 i_ret
= EsOutControlLocked( out
, i_query
, args
);
2700 vlc_mutex_unlock( &p_sys
->lock
);
2705 /****************************************************************************
2706 * LanguageGetName: try to expend iso639 into plain name
2707 ****************************************************************************/
2708 static char *LanguageGetName( const char *psz_code
)
2710 const iso639_lang_t
*pl
;
2712 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
2714 return strdup( "" );
2717 if( strlen( psz_code
) == 2 )
2719 pl
= GetLang_1( psz_code
);
2721 else if( strlen( psz_code
) == 3 )
2723 pl
= GetLang_2B( psz_code
);
2724 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2726 pl
= GetLang_2T( psz_code
);
2731 return strdup( psz_code
);
2734 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2736 return strdup( psz_code
);
2740 if( *pl
->psz_native_name
)
2742 return strdup( pl
->psz_native_name
);
2744 return strdup( pl
->psz_eng_name
);
2748 /* Get a 2 char code */
2749 static char *LanguageGetCode( const char *psz_lang
)
2751 const iso639_lang_t
*pl
;
2753 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
2754 return strdup("??");
2756 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
2758 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
2759 !strcasecmp( pl
->psz_native_name
, psz_lang
) ||
2760 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
2761 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
2762 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
2766 if( pl
->psz_eng_name
!= NULL
)
2767 return strdup( pl
->psz_iso639_1
);
2769 return strdup("??");
2772 static char **LanguageSplit( const char *psz_langs
, bool b_default_any
)
2779 if( psz_langs
== NULL
) return NULL
;
2781 psz_parser
= psz_dup
= strdup(psz_langs
);
2783 while( psz_parser
&& *psz_parser
)
2788 psz
= strchr(psz_parser
, ',' );
2789 if( psz
) *psz
++ = '\0';
2791 if( !strcmp( psz_parser
, "any" ) )
2793 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2795 else if( !strcmp( psz_parser
, "none" ) )
2797 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
2801 psz_code
= LanguageGetCode( psz_parser
);
2802 if( strcmp( psz_code
, "??" ) )
2804 TAB_APPEND( i_psz
, ppsz
, psz_code
);
2817 if( b_default_any
&& strcmp( ppsz
[i_psz
- 1], "none" ) )
2818 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2819 TAB_APPEND( i_psz
, ppsz
, NULL
);
2826 static int LanguageArrayIndex( char **ppsz_langs
, char *psz_lang
)
2830 if( !ppsz_langs
|| !psz_lang
) return -1;
2832 for( i
= 0; ppsz_langs
[i
]; i
++ )
2834 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
2835 !strcasecmp( ppsz_langs
[i
], "any" ) )
2837 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
2844 /****************************************************************************
2846 * - add meta info to the playlist item
2847 ****************************************************************************/
2848 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
, const vlc_meta_t
*p_meta
)
2850 es_out_sys_t
*p_sys
= out
->p_sys
;
2851 input_thread_t
*p_input
= p_sys
->p_input
;
2852 const es_format_t
*p_fmt_es
= &es
->fmt
;
2855 if( es
->fmt
.i_cat
== fmt
->i_cat
)
2857 es_format_t update
= *fmt
;
2858 update
.i_id
= es
->i_meta_id
;
2859 update
.i_codec
= es
->fmt
.i_codec
;
2860 update
.i_original_fourcc
= es
->fmt
.i_original_fourcc
;
2861 input_item_UpdateTracksInfo(input_GetItem(p_input
), &update
);
2864 /* Create category */
2866 snprintf( psz_cat
, sizeof(psz_cat
),_("Stream %d"), es
->i_meta_id
);
2867 info_category_t
*p_cat
= info_category_New( psz_cat
);
2871 /* Add information */
2872 const char *psz_type
;
2873 switch( fmt
->i_cat
)
2876 psz_type
= _("Audio");
2879 psz_type
= _("Video");
2882 psz_type
= _("Subtitle");
2890 info_category_AddInfo( p_cat
, _("Type"), "%s", psz_type
);
2892 if( es
->i_meta_id
!= es
->i_id
)
2893 info_category_AddInfo( p_cat
, _("Original ID"),
2896 const char *psz_codec_description
=
2897 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, p_fmt_es
->i_codec
);
2898 const vlc_fourcc_t i_codec_fourcc
= ( p_fmt_es
->i_original_fourcc
)?
2899 p_fmt_es
->i_original_fourcc
: p_fmt_es
->i_codec
;
2900 if( psz_codec_description
)
2901 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
2902 psz_codec_description
, (char*)&i_codec_fourcc
);
2904 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
2905 (char*)&i_codec_fourcc
);
2907 if( es
->psz_language
&& *es
->psz_language
)
2908 info_category_AddInfo( p_cat
, _("Language"), "%s",
2910 if( fmt
->psz_description
&& *fmt
->psz_description
)
2911 info_category_AddInfo( p_cat
, _("Description"), "%s",
2912 fmt
->psz_description
);
2914 switch( fmt
->i_cat
)
2917 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
2919 if( fmt
->audio
.i_physical_channels
& AOUT_CHAN_PHYSMASK
)
2920 info_category_AddInfo( p_cat
, _("Channels"), "%s",
2921 _( aout_FormatPrintChannels( &fmt
->audio
) ) );
2922 else if( fmt
->audio
.i_channels
> 0 )
2923 info_category_AddInfo( p_cat
, _("Channels"), "%u",
2924 fmt
->audio
.i_channels
);
2926 if( fmt
->audio
.i_rate
> 0 )
2928 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
2929 fmt
->audio
.i_rate
);
2930 /* FIXME that should be removed or improved ! (used by text/strings.c) */
2931 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
2934 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
2935 if( i_bitspersample
<= 0 )
2936 i_bitspersample
= aout_BitsPerSample( p_fmt_es
->i_codec
);
2937 if( i_bitspersample
> 0 )
2938 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
2941 if( fmt
->i_bitrate
> 0 )
2943 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
2944 fmt
->i_bitrate
/ 1000 );
2945 /* FIXME that should be removed or improved ! (used by text/strings.c) */
2946 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
2948 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
2950 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
2951 if( !p_rg
->pb_gain
[i
] )
2953 const char *psz_name
;
2954 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
2955 psz_name
= _("Track replay gain");
2957 psz_name
= _("Album replay gain");
2958 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
2964 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
2966 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
2967 info_category_AddInfo( p_cat
, _("Resolution"), "%ux%u",
2968 fmt
->video
.i_width
, fmt
->video
.i_height
);
2970 if( fmt
->video
.i_visible_width
> 0 &&
2971 fmt
->video
.i_visible_height
> 0 )
2972 info_category_AddInfo( p_cat
, _("Display resolution"), "%ux%u",
2973 fmt
->video
.i_visible_width
,
2974 fmt
->video
.i_visible_height
);
2975 if( fmt
->video
.i_frame_rate
> 0 &&
2976 fmt
->video
.i_frame_rate_base
> 0 )
2978 div
= lldiv( (float)fmt
->video
.i_frame_rate
/
2979 fmt
->video
.i_frame_rate_base
* 1000000,
2982 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
".%06u",
2983 div
.quot
, (unsigned int )div
.rem
);
2985 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
,
2991 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
2998 /* Append generic meta */
3001 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
3002 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
3004 char *psz_key
= ppsz_all_keys
[i
];
3005 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
3008 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
3009 vlc_gettext(psz_value
) );
3012 free( ppsz_all_keys
);
3015 input_Control( p_input
, INPUT_REPLACE_INFOS
, p_cat
);