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>
44 #include "input_internal.h"
45 #include "../clock/input_clock.h"
52 #include "../stream_output/stream_output.h"
54 #include <vlc_iso_lang.h>
55 /* FIXME we should find a better way than including that */
56 #include "../text/iso-639_def.h"
58 /*****************************************************************************
60 *****************************************************************************/
66 /* Number of es for this pgrm */
72 /* Clock for this program */
73 input_clock_t
*p_input_clock
;
83 es_out_pgrm_t
*p_pgrm
;
87 bool b_forced
; /* if true, bypass variables when selecting this track */
89 /* Channel in the track type */
93 char *psz_language_code
;
96 decoder_t
*p_dec_record
;
98 /* Fields for Video with CC */
102 uint64_t i_bitmap
; /* channels bitmap */
103 es_out_id_t
*pp_es
[64]; /* a max of 64 chans for CEA708 */
106 /* Field for CC track from a master video */
107 es_out_id_t
*p_master
;
109 /* ID for the meta data */
112 struct vlc_list node
;
117 int i_count
; /* es count */
118 es_out_id_t
*p_main_es
; /* current main es */
119 enum es_out_policy_e e_policy
;
121 /* Parameters used for es selection */
122 bool b_autoselect
; /* if we want to select an es when no user prefs */
123 int i_id
; /* es id as set by es fmt.id */
124 int i_demux_id
; /* same as previous, demuxer set default value */
125 int i_channel
; /* es number in creation order */
126 char **ppsz_language
;
131 input_thread_t
*p_input
;
137 struct vlc_list programs
;
138 es_out_pgrm_t
*p_pgrm
; /* Master program */
143 struct vlc_list es_slaves
; /* Dynamically created es on regular es selection */
149 es_out_es_props_t video
, audio
, sub
;
151 /* es/group to select */
155 vlc_tick_t i_audio_delay
;
156 vlc_tick_t i_spu_delay
;
158 /* Clock configuration */
159 vlc_tick_t i_pts_delay
;
160 vlc_tick_t i_pts_jitter
;
166 vlc_tick_t i_pause_date
;
168 /* Current preroll */
169 vlc_tick_t i_preroll_end
;
171 /* Used for buffering */
173 vlc_tick_t i_buffering_extra_initial
;
174 vlc_tick_t i_buffering_extra_stream
;
175 vlc_tick_t i_buffering_extra_system
;
178 sout_instance_t
*p_sout_record
;
180 /* Used only to limit debugging output */
181 int i_prev_stream_level
;
186 static void EsOutDelLocked( es_out_t
*, es_out_id_t
* );
187 static void EsOutDel ( es_out_t
*, es_out_id_t
* );
189 static void EsOutTerminate( es_out_t
* );
190 static void EsOutSelect( es_out_t
*, es_out_id_t
*es
, bool b_force
);
191 static void EsOutUpdateInfo( es_out_t
*, es_out_id_t
*es
, const es_format_t
*, const vlc_meta_t
* );
192 static int EsOutSetRecord( es_out_t
*, bool b_record
);
194 static bool EsIsSelected( es_out_id_t
*es
);
195 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
);
196 static void EsDeleteInfo( es_out_t
*, es_out_id_t
*es
);
197 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
);
198 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
);
199 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
);
200 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
);
201 static void EsOutProgramsChangeRate( es_out_t
*out
);
202 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
);
203 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
);
204 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_progmeta
);
206 static char *LanguageGetName( const char *psz_code
);
207 static char *LanguageGetCode( const char *psz_lang
);
208 static char **LanguageSplit( const char *psz_langs
);
209 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
);
211 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
);
212 static char *EsInfoCategoryName( es_out_id_t
* es
);
214 static inline int EsOutGetClosedCaptionsChannel( const es_format_t
*p_fmt
)
217 if( p_fmt
->i_codec
== VLC_CODEC_CEA608
&& p_fmt
->subs
.cc
.i_channel
< 4 )
218 i_channel
= p_fmt
->subs
.cc
.i_channel
;
219 else if( p_fmt
->i_codec
== VLC_CODEC_CEA708
&& p_fmt
->subs
.cc
.i_channel
< 64 )
220 i_channel
= p_fmt
->subs
.cc
.i_channel
;
225 static inline bool EsFmtIsTeletext( const es_format_t
*p_fmt
)
227 return p_fmt
->i_cat
== SPU_ES
&& p_fmt
->i_codec
== VLC_CODEC_TELETEXT
;
230 #define foreach_es_then_es_slaves( pos ) \
231 for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
232 vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )
235 /*****************************************************************************
236 * Es category specific structs
237 *****************************************************************************/
238 static es_out_es_props_t
* GetPropsByCat( es_out_sys_t
*p_sys
, int i_cat
)
243 return &p_sys
->audio
;
247 return &p_sys
->video
;
252 static void EsOutPropsCleanup( es_out_es_props_t
*p_props
)
254 if( p_props
->ppsz_language
)
256 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
257 free( p_props
->ppsz_language
[i
] );
258 free( p_props
->ppsz_language
);
262 static void EsOutPropsInit( es_out_es_props_t
*p_props
,
264 input_thread_t
*p_input
,
265 enum es_out_policy_e e_default_policy
,
266 const char *psz_trackidvar
,
267 const char *psz_trackvar
,
268 const char *psz_langvar
,
269 const char *psz_debug
)
271 p_props
->e_policy
= e_default_policy
;
272 p_props
->i_count
= 0;
273 p_props
->b_autoselect
= autoselect
;
274 p_props
->i_id
= (psz_trackidvar
) ? var_GetInteger( p_input
, psz_trackidvar
): -1;
275 p_props
->i_channel
= (psz_trackvar
) ? var_GetInteger( p_input
, psz_trackvar
): -1;
276 p_props
->i_demux_id
= -1;
277 p_props
->p_main_es
= NULL
;
279 if( !input_priv(p_input
)->b_preparsing
&& psz_langvar
)
281 char *psz_string
= var_GetString( p_input
, psz_langvar
);
282 p_props
->ppsz_language
= LanguageSplit( psz_string
);
283 if( p_props
->ppsz_language
)
285 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
286 msg_Dbg( p_input
, "selected %s language[%d] %s",
287 psz_debug
, i
, p_props
->ppsz_language
[i
] );
293 static const struct es_out_callbacks es_out_cbs
;
295 /*****************************************************************************
297 *****************************************************************************/
298 es_out_t
*input_EsOutNew( input_thread_t
*p_input
, int i_rate
)
300 es_out_sys_t
*p_sys
= calloc( 1, sizeof( *p_sys
) );
304 p_sys
->out
.cbs
= &es_out_cbs
;
306 vlc_mutex_init( &p_sys
->lock
);
307 p_sys
->p_input
= p_input
;
309 p_sys
->b_active
= false;
310 p_sys
->i_mode
= ES_OUT_MODE_NONE
;
312 vlc_list_init(&p_sys
->programs
);
313 vlc_list_init(&p_sys
->es
);
314 vlc_list_init(&p_sys
->es_slaves
);
317 EsOutPropsInit( &p_sys
->video
, true, p_input
, ES_OUT_ES_POLICY_SIMULTANEOUS
,
318 NULL
, NULL
, NULL
, NULL
);
319 EsOutPropsInit( &p_sys
->audio
, true, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
320 "audio-track-id", "audio-track", "audio-language", "audio" );
321 EsOutPropsInit( &p_sys
->sub
, false, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
322 "sub-track-id", "sub-track", "sub-language", "sub" );
324 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
326 p_sys
->i_pause_date
= -1;
328 p_sys
->i_rate
= i_rate
;
330 p_sys
->b_buffering
= true;
331 p_sys
->i_preroll_end
= -1;
332 p_sys
->i_prev_stream_level
= -1;
337 /*****************************************************************************
339 *****************************************************************************/
340 static void EsOutDelete( es_out_t
*out
)
342 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
344 assert(vlc_list_is_empty(&p_sys
->es
));
345 assert(vlc_list_is_empty(&p_sys
->es_slaves
));
346 assert(vlc_list_is_empty(&p_sys
->programs
));
347 assert(p_sys
->p_pgrm
== NULL
);
348 EsOutPropsCleanup( &p_sys
->audio
);
349 EsOutPropsCleanup( &p_sys
->sub
);
351 vlc_mutex_destroy( &p_sys
->lock
);
356 static void EsOutTerminate( es_out_t
*out
)
358 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
361 if( p_sys
->p_sout_record
)
362 EsOutSetRecord( out
, false );
364 foreach_es_then_es_slaves(es
)
366 if (es
->p_dec
!= NULL
)
367 input_DecoderDelete(es
->p_dec
);
369 free(es
->psz_language
);
370 free(es
->psz_language_code
);
371 es_format_Clean(&es
->fmt
);
372 vlc_list_remove(&es
->node
);
376 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
377 es_out_pgrm_t
*p_pgrm
;
378 vlc_list_foreach(p_pgrm
, &p_sys
->programs
, node
)
380 input_clock_Delete( p_pgrm
->p_input_clock
);
382 vlc_meta_Delete( p_pgrm
->p_meta
);
384 vlc_list_remove(&p_pgrm
->node
);
388 p_sys
->p_pgrm
= NULL
;
390 input_item_SetEpgOffline( input_priv(p_sys
->p_input
)->p_item
);
391 input_SendEventMetaEpg( p_sys
->p_input
);
394 static vlc_tick_t
EsOutGetWakeup( es_out_t
*out
)
396 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
397 input_thread_t
*p_input
= p_sys
->p_input
;
402 /* We do not have a wake up date if the input cannot have its speed
403 * controlled or sout is imposing its own or while buffering
405 * FIXME for !input_priv(p_input)->b_can_pace_control a wake-up time is still needed
406 * to avoid too heavy buffering */
407 if( !input_priv(p_input
)->b_can_pace_control
||
408 input_priv(p_input
)->b_out_pace_control
||
412 return input_clock_GetWakeup( p_sys
->p_pgrm
->p_input_clock
);
415 static es_out_id_t es_cat
[DATA_ES
];
417 static es_out_id_t
*EsOutGetFromID( es_out_t
*out
, int i_id
)
419 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
424 /* Special HACK, -i_id is the cat of the stream */
425 return es_cat
- i_id
;
428 foreach_es_then_es_slaves(es
)
429 if (es
->i_id
== i_id
)
434 static es_out_id_t
*EsOutGetSelectedCat( es_out_t
*out
,
435 enum es_format_category_e cat
)
437 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
440 foreach_es_then_es_slaves( es
)
441 if( es
->fmt
.i_cat
== cat
&& EsIsSelected( es
) )
446 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
448 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
451 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
453 EsOutDecodersStopBuffering( out
, true );
454 if( p_sys
->b_buffering
)
458 foreach_es_then_es_slaves(es
)
460 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
462 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
468 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, vlc_tick_t i_delay
)
470 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
473 if( i_cat
== AUDIO_ES
)
474 p_sys
->i_audio_delay
= i_delay
;
475 else if( i_cat
== SPU_ES
)
476 p_sys
->i_spu_delay
= i_delay
;
478 foreach_es_then_es_slaves(es
)
479 EsOutDecoderChangeDelay(out
, es
);
482 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
484 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
485 input_thread_t
*p_input
= p_sys
->p_input
;
488 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
492 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
495 if( var_CountChoices( p_input
, "video-es" ) )
496 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
497 else if( var_CountChoices( p_input
, "audio-es" ) )
498 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
500 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
503 char *psz_sout
= NULL
; // TODO conf
505 if( !psz_sout
&& psz_path
)
507 char *psz_file
= input_CreateFilename( p_input
, psz_path
, INPUT_RECORD_PREFIX
, NULL
);
510 char* psz_file_esc
= config_StringEscape( psz_file
);
513 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file_esc
) < 0 )
515 free( psz_file_esc
);
526 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
530 if( !p_sys
->p_sout_record
)
533 vlc_list_foreach( p_es
, &p_sys
->es
, node
) /* Only master es */
538 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_input_clock
, p_sys
->p_sout_record
);
539 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
540 input_DecoderStartWait( p_es
->p_dec_record
);
545 vlc_list_foreach( p_es
, &p_sys
->es
, node
) /* Only master es */
547 if( !p_es
->p_dec_record
)
550 input_DecoderDelete( p_es
->p_dec_record
);
551 p_es
->p_dec_record
= NULL
;
554 sout_DeleteInstance( p_sys
->p_sout_record
);
556 p_sys
->p_sout_record
= NULL
;
561 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
)
563 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
565 /* XXX the order is important */
568 EsOutDecodersChangePause( out
, true, i_date
);
569 EsOutProgramChangePause( out
, true, i_date
);
573 if( p_sys
->i_buffering_extra_initial
> 0 )
575 vlc_tick_t i_stream_start
;
576 vlc_tick_t i_system_start
;
577 vlc_tick_t i_stream_duration
;
578 vlc_tick_t i_system_duration
;
580 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
581 &i_stream_start
, &i_system_start
,
582 &i_stream_duration
, &i_system_duration
);
585 /* FIXME pcr != exactly what wanted */
586 const vlc_tick_t i_used
= /*(i_stream_duration - input_priv(p_sys->p_input)->i_pts_delay)*/ p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
589 p_sys
->i_buffering_extra_initial
= 0;
590 p_sys
->i_buffering_extra_stream
= 0;
591 p_sys
->i_buffering_extra_system
= 0;
593 EsOutProgramChangePause( out
, false, i_date
);
594 EsOutDecodersChangePause( out
, false, i_date
);
596 EsOutProgramsChangeRate( out
);
598 p_sys
->b_paused
= b_paused
;
599 p_sys
->i_pause_date
= i_date
;
602 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
604 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
605 float rate
= (float)i_rate
/ (float)INPUT_RATE_DEFAULT
;
608 p_sys
->i_rate
= i_rate
;
609 EsOutProgramsChangeRate( out
);
611 foreach_es_then_es_slaves(es
)
612 if( es
->p_dec
!= NULL
)
613 input_DecoderChangeRate( es
->p_dec
, rate
);
616 static void EsOutChangePosition( es_out_t
*out
)
618 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
621 input_SendEventCache( p_sys
->p_input
, 0.0 );
623 foreach_es_then_es_slaves(p_es
)
624 if( p_es
->p_dec
!= NULL
)
626 input_DecoderFlush( p_es
->p_dec
);
627 if( !p_sys
->b_buffering
)
629 input_DecoderStartWait( p_es
->p_dec
);
630 if( p_es
->p_dec_record
!= NULL
)
631 input_DecoderStartWait( p_es
->p_dec_record
);
636 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
637 input_clock_Reset(pgrm
->p_input_clock
);
639 p_sys
->b_buffering
= true;
640 p_sys
->i_buffering_extra_initial
= 0;
641 p_sys
->i_buffering_extra_stream
= 0;
642 p_sys
->i_buffering_extra_system
= 0;
643 p_sys
->i_preroll_end
= -1;
644 p_sys
->i_prev_stream_level
= -1;
649 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
651 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
654 vlc_tick_t i_stream_start
;
655 vlc_tick_t i_system_start
;
656 vlc_tick_t i_stream_duration
;
657 vlc_tick_t i_system_duration
;
658 if (input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
659 &i_stream_start
, &i_system_start
,
660 &i_stream_duration
, &i_system_duration
))
663 vlc_tick_t i_preroll_duration
= 0;
664 if( p_sys
->i_preroll_end
>= 0 )
665 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
667 const vlc_tick_t i_buffering_duration
= p_sys
->i_pts_delay
+
669 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
671 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
674 if (i_buffering_duration
== 0)
677 f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
678 input_SendEventCache( p_sys
->p_input
, f_level
);
680 int i_level
= (int)(100 * f_level
);
681 if( p_sys
->i_prev_stream_level
!= i_level
)
683 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", i_level
);
684 p_sys
->i_prev_stream_level
= i_level
;
689 input_SendEventCache( p_sys
->p_input
, 1.0 );
691 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
692 (int)MS_FROM_VLC_TICK(i_stream_duration
), (int)MS_FROM_VLC_TICK(i_system_duration
) );
693 p_sys
->b_buffering
= false;
694 p_sys
->i_preroll_end
= -1;
695 p_sys
->i_prev_stream_level
= -1;
697 if( p_sys
->i_buffering_extra_initial
> 0 )
703 const vlc_tick_t i_decoder_buffering_start
= vlc_tick_now();
704 foreach_es_then_es_slaves(p_es
)
706 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
708 input_DecoderWait( p_es
->p_dec
);
709 if( p_es
->p_dec_record
)
710 input_DecoderWait( p_es
->p_dec_record
);
713 msg_Dbg( p_sys
->p_input
, "Decoder wait done in %d ms",
714 (int)MS_FROM_VLC_TICK(vlc_tick_now() - i_decoder_buffering_start
) );
716 /* Here is a good place to destroy unused vout with every demuxer */
717 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
720 const vlc_tick_t i_wakeup_delay
= VLC_TICK_FROM_MS(10); /* FIXME CLEANUP thread wake up time*/
721 const vlc_tick_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: vlc_tick_now();
723 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_input_clock
, true,
724 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
726 foreach_es_then_es_slaves(p_es
)
731 input_DecoderStopWait( p_es
->p_dec
);
732 if( p_es
->p_dec_record
)
733 input_DecoderStopWait( p_es
->p_dec_record
);
736 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
)
738 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
741 /* Pause decoders first */
742 foreach_es_then_es_slaves(es
)
745 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
746 if( es
->p_dec_record
)
747 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
751 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
753 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
757 foreach_es_then_es_slaves(p_es
)
760 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
761 if( p_es
->p_dec_record
)
762 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
764 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
766 /* TODO maybe we want to be able to tune it ? */
767 #if defined(OPTIMIZE_MEMORY)
768 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
770 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
772 return i_size
< i_level_high
;
775 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
)
777 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
780 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
781 input_clock_ChangePause(pgrm
->p_input_clock
, b_paused
, i_date
);
784 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
786 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
789 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
790 i_delay
= p_sys
->i_audio_delay
;
791 else if( p_es
->fmt
.i_cat
== SPU_ES
)
792 i_delay
= p_sys
->i_spu_delay
;
797 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
798 if( p_es
->p_dec_record
)
799 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
801 static void EsOutProgramsChangeRate( es_out_t
*out
)
803 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
806 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
807 input_clock_ChangeRate(pgrm
->p_input_clock
, p_sys
->i_rate
);
810 static void EsOutFrameNext( es_out_t
*out
)
812 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
813 es_out_id_t
*p_es_video
= NULL
, *p_es
;
815 if( p_sys
->b_buffering
)
817 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
821 assert( p_sys
->b_paused
);
823 foreach_es_then_es_slaves(p_es
)
824 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
&& !p_es_video
/* nested loop */ )
832 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
836 vlc_tick_t i_duration
;
837 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
839 msg_Dbg( p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)MS_FROM_VLC_TICK(i_duration
) );
841 if( i_duration
<= 0 )
842 i_duration
= VLC_TICK_FROM_MS(40);
844 /* FIXME it is not a clean way ? */
845 if( p_sys
->i_buffering_extra_initial
<= 0 )
847 vlc_tick_t i_stream_start
;
848 vlc_tick_t i_system_start
;
849 vlc_tick_t i_stream_duration
;
850 vlc_tick_t i_system_duration
;
853 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
854 &i_stream_start
, &i_system_start
,
855 &i_stream_duration
, &i_system_duration
);
859 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
860 p_sys
->i_buffering_extra_system
=
861 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
864 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_input_clock
);
866 p_sys
->b_buffering
= true;
867 p_sys
->i_buffering_extra_system
+= i_duration
;
868 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
869 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
870 INPUT_RATE_DEFAULT
/ i_rate
;
872 p_sys
->i_preroll_end
= -1;
873 p_sys
->i_prev_stream_level
= -1;
875 static vlc_tick_t
EsOutGetBuffering( es_out_t
*out
)
877 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
878 vlc_tick_t i_stream_duration
, i_system_start
;
884 vlc_tick_t i_stream_start
, i_system_duration
;
886 if( input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
887 &i_stream_start
, &i_system_start
,
888 &i_stream_duration
, &i_system_duration
) )
894 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
896 i_delay
= i_stream_duration
;
900 vlc_tick_t i_system_duration
;
902 if( p_sys
->b_paused
)
904 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
905 if( p_sys
->i_buffering_extra_initial
> 0 )
906 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
910 i_system_duration
= vlc_tick_now() - i_system_start
;
913 const vlc_tick_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
914 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
921 static void EsOutESVarUpdateGeneric( es_out_t
*out
, int i_id
,
922 const es_format_t
*fmt
, const char *psz_language
,
925 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
926 input_thread_t
*p_input
= p_sys
->p_input
;
933 if( EsFmtIsTeletext( fmt
) )
934 input_SendEventTeletextDel( p_sys
->p_input
, i_id
);
936 input_SendEventEsDel( p_input
, fmt
->i_cat
, i_id
);
940 /* Get the number of ES already added */
941 foreach_es_then_es_slaves(es
)
942 if( es
->fmt
.i_cat
== fmt
->i_cat
)
945 /* Take care of the ES description */
946 if( fmt
->psz_description
&& *fmt
->psz_description
)
948 if( psz_language
&& *psz_language
)
950 if( asprintf( &text
.psz_string
, "%s - [%s]", fmt
->psz_description
,
951 psz_language
) == -1 )
952 text
.psz_string
= NULL
;
954 else text
.psz_string
= strdup( fmt
->psz_description
);
958 if( psz_language
&& *psz_language
)
960 if( asprintf( &text
.psz_string
, "%s %zu - [%s]", _("Track"), count
,
961 psz_language
) == -1 )
962 text
.psz_string
= NULL
;
966 if( asprintf( &text
.psz_string
, "%s %zu", _("Track"), count
) == -1 )
967 text
.psz_string
= NULL
;
971 input_SendEventEsAdd( p_input
, fmt
->i_cat
, i_id
, text
.psz_string
);
972 if( EsFmtIsTeletext( fmt
) )
975 snprintf( psz_page
, sizeof(psz_page
), "%d%2.2x",
976 fmt
->subs
.teletext
.i_magazine
,
977 fmt
->subs
.teletext
.i_page
);
978 input_SendEventTeletextAdd( p_sys
->p_input
,
979 i_id
, fmt
->subs
.teletext
.i_magazine
>= 0 ? psz_page
: NULL
);
982 free( text
.psz_string
);
985 static void EsOutESVarUpdate( es_out_t
*out
, es_out_id_t
*es
,
988 EsOutESVarUpdateGeneric( out
, es
->i_id
, &es
->fmt
, es
->psz_language
, b_delete
);
991 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
993 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
994 return p_sys
->i_group_id
== 0 || p_sys
->i_group_id
== i_group
;
997 /* EsOutProgramSelect:
998 * Select a program and update the object variable
1000 static void EsOutProgramSelect( es_out_t
*out
, es_out_pgrm_t
*p_pgrm
)
1002 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1003 input_thread_t
*p_input
= p_sys
->p_input
;
1006 if( p_sys
->p_pgrm
== p_pgrm
)
1007 return; /* Nothing to do */
1011 es_out_pgrm_t
*old
= p_sys
->p_pgrm
;
1013 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
1015 foreach_es_then_es_slaves(es
)
1016 if (es
->p_pgrm
== old
&& EsIsSelected(es
)
1017 && p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
1018 EsUnselect(out
, es
, true);
1020 p_sys
->audio
.p_main_es
= NULL
;
1021 p_sys
->video
.p_main_es
= NULL
;
1022 p_sys
->sub
.p_main_es
= NULL
;
1025 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
1027 /* Mark it selected */
1028 p_pgrm
->b_selected
= true;
1030 /* Switch master stream */
1031 p_sys
->p_pgrm
= p_pgrm
;
1033 /* Update "program" */
1034 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
1037 input_SendEventEsDel( p_input
, AUDIO_ES
, -1 );
1038 input_SendEventEsDel( p_input
, VIDEO_ES
, -1 );
1039 input_SendEventEsDel( p_input
, SPU_ES
, -1 );
1040 input_SendEventTeletextDel( p_input
, -1 );
1041 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1043 foreach_es_then_es_slaves(es
)
1045 if (es
->p_pgrm
== p_sys
->p_pgrm
)
1047 EsOutESVarUpdate(out
, es
, false);
1048 EsOutUpdateInfo(out
, es
, &es
->fmt
, NULL
);
1051 EsOutSelect(out
, es
, false);
1054 /* Ensure the correct running EPG table is selected */
1055 input_item_ChangeEPGSource( input_priv(p_input
)->p_item
, p_pgrm
->i_id
);
1057 /* Update now playing */
1058 if( p_pgrm
->p_meta
)
1060 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
,
1061 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) );
1062 input_item_SetPublisher( input_priv(p_input
)->p_item
,
1063 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Publisher
) );
1064 input_item_SetTitle( input_priv(p_input
)->p_item
,
1065 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1066 input_SendEventMeta( p_input
);
1067 /* FIXME: we probably want to replace every input meta */
1074 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1076 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1077 input_thread_t
*p_input
= p_sys
->p_input
;
1079 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1084 p_pgrm
->i_id
= i_group
;
1086 p_pgrm
->b_selected
= false;
1087 p_pgrm
->b_scrambled
= false;
1088 p_pgrm
->p_meta
= NULL
;
1089 p_pgrm
->p_input_clock
= input_clock_New( p_sys
->i_rate
);
1090 if( !p_pgrm
->p_input_clock
)
1095 if( p_sys
->b_paused
)
1096 input_clock_ChangePause( p_pgrm
->p_input_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1097 input_clock_SetJitter( p_pgrm
->p_input_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1100 vlc_list_append(&p_pgrm
->node
, &p_sys
->programs
);
1102 /* Update "program" variable */
1103 if( EsOutIsProgramVisible( out
, i_group
) )
1104 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1106 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1107 EsOutProgramSelect( out
, p_pgrm
);
1115 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1117 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1118 input_thread_t
*p_input
= p_sys
->p_input
;
1119 es_out_pgrm_t
*p_pgrm
= NULL
, *pgrm
;
1121 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
1122 if (pgrm
->i_id
== i_group
)
1128 if( p_pgrm
== NULL
)
1129 return VLC_EGENERIC
;
1133 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1134 i_group
, p_pgrm
->i_es
);
1135 return VLC_EGENERIC
;
1138 vlc_list_remove(&p_pgrm
->node
);
1140 /* If program is selected we need to unselect it */
1141 if( p_sys
->p_pgrm
== p_pgrm
)
1142 p_sys
->p_pgrm
= NULL
;
1144 input_clock_Delete( p_pgrm
->p_input_clock
);
1146 if( p_pgrm
->p_meta
)
1147 vlc_meta_Delete( p_pgrm
->p_meta
);
1150 /* Update "program" variable */
1151 input_SendEventProgramDel( p_input
, i_group
);
1158 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1160 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1161 es_out_pgrm_t
*pgrm
;
1163 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
1164 if (pgrm
->i_id
== i_group
)
1167 return EsOutProgramAdd( p_out
, i_group
);
1170 /* EsOutProgramMeta:
1172 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1175 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1177 if( asprintf( &psz
, _("%s [%s %d]"), vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
),
1178 _("Program"), p_pgrm
->i_id
) == -1 )
1183 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1189 static char *EsOutProgramGetProgramName( es_out_pgrm_t
*p_pgrm
)
1192 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1194 return strdup( vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1198 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1204 static char *EsInfoCategoryName( es_out_id_t
* es
)
1208 if( asprintf( &psz_category
, _("Stream %d"), es
->i_meta_id
) == -1 )
1211 return psz_category
;
1214 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1216 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1217 es_out_pgrm_t
*p_pgrm
;
1218 input_thread_t
*p_input
= p_sys
->p_input
;
1219 const char *psz_title
= NULL
;
1220 const char *psz_provider
= NULL
;
1223 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1225 /* Check against empty meta data (empty for what we handle) */
1226 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1227 !vlc_meta_Get( p_meta
, vlc_meta_ESNowPlaying
) &&
1228 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) )
1235 EsOutGlobalMeta( out
, p_meta
);
1240 if( !EsOutIsProgramVisible( out
, i_group
) )
1242 p_pgrm
= EsOutProgramFind( out
, i_group
);
1246 if( p_pgrm
->p_meta
)
1248 const char *psz_current_title
= vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
);
1249 const char *psz_new_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1250 if( (psz_current_title
!= NULL
&& psz_new_title
!= NULL
)
1251 ? strcmp(psz_new_title
, psz_current_title
)
1252 : (psz_current_title
!= psz_new_title
) )
1254 /* Remove old entries */
1255 char *psz_oldinfokey
= EsOutProgramGetMetaName( p_pgrm
);
1256 input_Control( p_input
, INPUT_DEL_INFO
, psz_oldinfokey
, NULL
);
1257 /* TODO update epg name ?
1258 * TODO update scrambled info name ? */
1259 free( psz_oldinfokey
);
1261 vlc_meta_Delete( p_pgrm
->p_meta
);
1263 p_pgrm
->p_meta
= vlc_meta_New();
1264 if( p_pgrm
->p_meta
)
1265 vlc_meta_Merge( p_pgrm
->p_meta
, p_meta
);
1267 if( p_sys
->p_pgrm
== p_pgrm
)
1269 EsOutMeta( out
, NULL
, p_meta
);
1272 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1273 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1275 /* Update the description text of the program */
1276 if( psz_title
&& *psz_title
)
1279 if( psz_provider
&& *psz_provider
)
1281 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1286 psz_text
= strdup( psz_title
);
1289 /* ugly but it works */
1292 input_SendEventProgramDel( p_input
, i_group
);
1293 input_SendEventProgramAdd( p_input
, i_group
, psz_text
);
1294 if( p_sys
->p_pgrm
== p_pgrm
)
1295 input_SendEventProgramSelect( p_input
, i_group
);
1301 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1303 info_category_t
*p_cat
= NULL
;
1304 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1306 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1308 p_cat
= info_category_New( psz_cat
);
1312 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1315 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1316 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1317 free( ppsz_all_keys
[i
] );
1319 free( ppsz_all_keys
);
1323 if( p_sys
->p_pgrm
== p_pgrm
)
1325 input_item_SetPublisher( input_priv(p_input
)->p_item
, psz_provider
);
1326 input_SendEventMeta( p_input
);
1329 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1330 "%s",psz_provider
);
1333 input_Control( p_input
, INPUT_MERGE_INFOS
, p_cat
);
1336 static void EsOutProgramEpgEvent( es_out_t
*out
, int i_group
, const vlc_epg_event_t
*p_event
)
1338 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1339 input_thread_t
*p_input
= p_sys
->p_input
;
1340 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1341 es_out_pgrm_t
*p_pgrm
;
1344 if( !EsOutIsProgramVisible( out
, i_group
) )
1346 p_pgrm
= EsOutProgramFind( out
, i_group
);
1350 input_item_SetEpgEvent( p_item
, p_event
);
1353 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1355 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1356 input_thread_t
*p_input
= p_sys
->p_input
;
1357 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1358 es_out_pgrm_t
*p_pgrm
;
1362 if( !EsOutIsProgramVisible( out
, i_group
) )
1364 p_pgrm
= EsOutProgramFind( out
, i_group
);
1369 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1370 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1376 epg
.psz_name
= EsOutProgramGetProgramName( p_pgrm
);
1378 input_item_SetEpg( p_item
, &epg
, p_sys
->p_pgrm
&& (p_epg
->i_source_id
== p_sys
->p_pgrm
->i_id
) );
1379 input_SendEventMetaEpg( p_sys
->p_input
);
1381 free( epg
.psz_name
);
1383 /* Update now playing */
1384 if( p_epg
->b_present
&& p_pgrm
->p_meta
&&
1385 ( p_epg
->p_current
|| p_epg
->i_event
== 0 ) )
1387 vlc_meta_SetNowPlaying( p_pgrm
->p_meta
, NULL
);
1390 vlc_mutex_lock( &p_item
->lock
);
1391 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1393 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1395 if( p_tmp
->b_present
&& p_tmp
->i_source_id
== p_pgrm
->i_id
)
1397 const char *psz_name
= ( p_tmp
->p_current
) ? p_tmp
->p_current
->psz_name
: NULL
;
1398 if( !p_pgrm
->p_meta
)
1399 p_pgrm
->p_meta
= vlc_meta_New();
1400 if( p_pgrm
->p_meta
)
1401 vlc_meta_Set( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
, psz_name
);
1405 vlc_mutex_unlock( &p_item
->lock
);
1407 /* Update selected program input info */
1408 if( p_pgrm
== p_sys
->p_pgrm
)
1410 const char *psz_nowplaying
= p_pgrm
->p_meta
?
1411 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) : NULL
;
1413 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
, psz_nowplaying
);
1414 input_SendEventMeta( p_input
);
1416 if( psz_nowplaying
)
1418 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
,
1419 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
), "%s", psz_nowplaying
);
1423 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
,
1424 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
) );
1431 static void EsOutEpgTime( es_out_t
*out
, int64_t time
)
1433 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1434 input_thread_t
*p_input
= p_sys
->p_input
;
1435 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1437 input_item_SetEpgTime( p_item
, time
);
1440 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1442 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1443 input_thread_t
*p_input
= p_sys
->p_input
;
1445 bool b_scrambled
= false;
1447 vlc_list_foreach( es
, &p_sys
->es
, node
) /* Only master es */
1448 if (es
->p_pgrm
== p_pgrm
&& es
->b_scrambled
)
1454 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1457 p_pgrm
->b_scrambled
= b_scrambled
;
1458 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1461 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
, _("Scrambled"), _("Yes") );
1463 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, _("Scrambled") );
1466 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1469 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_program_meta
)
1471 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1472 input_thread_t
*p_input
= p_sys
->p_input
;
1473 input_item_t
*p_item
= input_GetItem( p_input
);
1475 vlc_mutex_lock( &p_item
->lock
);
1477 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1478 vlc_mutex_unlock( &p_item
->lock
);
1480 /* Check program meta to not override GROUP_META values */
1481 if( p_meta
&& (!p_program_meta
|| vlc_meta_Get( p_program_meta
, vlc_meta_Title
) == NULL
) &&
1482 vlc_meta_Get( p_meta
, vlc_meta_Title
) != NULL
)
1483 input_item_SetName( p_item
, vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1485 const char *psz_arturl
= NULL
;
1486 char *psz_alloc
= NULL
;
1488 if( p_program_meta
)
1489 psz_arturl
= vlc_meta_Get( p_program_meta
, vlc_meta_ArtworkURL
);
1490 if( psz_arturl
== NULL
&& p_meta
)
1491 psz_arturl
= vlc_meta_Get( p_meta
, vlc_meta_ArtworkURL
);
1493 if( psz_arturl
== NULL
) /* restore/favor previously set item art URL */
1494 psz_arturl
= psz_alloc
= input_item_GetArtURL( p_item
);
1496 if( psz_arturl
!= NULL
)
1497 input_item_SetArtURL( p_item
, psz_arturl
);
1499 if( psz_arturl
!= NULL
&& !strncmp( psz_arturl
, "attachment://", 13 ) )
1500 { /* Clear art cover if streaming out.
1501 * FIXME: Why? Remove this when sout gets meta data support. */
1502 if( input_priv(p_input
)->p_sout
!= NULL
)
1503 input_item_SetArtURL( p_item
, NULL
);
1505 input_ExtractAttachmentAndCacheArt( p_input
, psz_arturl
+ 13 );
1509 input_item_SetPreparsed( p_item
, true );
1511 input_SendEventMeta( p_input
);
1512 /* TODO handle sout meta ? */
1515 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1517 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1518 EsOutMeta( p_out
, p_meta
,
1519 (p_sys
->p_pgrm
&& p_sys
->p_pgrm
->p_meta
) ? p_sys
->p_pgrm
->p_meta
: NULL
);
1522 static es_out_id_t
*EsOutAddSlaveLocked( es_out_t
*out
, const es_format_t
*fmt
,
1523 es_out_id_t
*p_master
)
1525 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1526 input_thread_t
*p_input
= p_sys
->p_input
;
1528 if( fmt
->i_group
< 0 )
1530 msg_Err( p_input
, "invalid group number" );
1534 es_out_id_t
*es
= malloc( sizeof( *es
) );
1535 es_out_pgrm_t
*p_pgrm
;
1541 /* Search the program */
1542 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1549 /* Increase ref count for program */
1553 es
->p_pgrm
= p_pgrm
;
1554 es_format_Copy( &es
->fmt
, fmt
);
1555 if( es
->fmt
.i_id
< 0 )
1556 es
->fmt
.i_id
= p_sys
->i_id
;
1557 if( !es
->fmt
.i_original_fourcc
)
1558 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1560 es
->i_id
= es
->fmt
.i_id
;
1561 es
->i_meta_id
= p_sys
->i_id
++; /* always incremented */
1562 es
->b_scrambled
= false;
1563 es
->b_forced
= false;
1565 switch( es
->fmt
.i_cat
)
1569 es
->fmt
.i_codec
= vlc_fourcc_GetCodecAudio( es
->fmt
.i_codec
,
1570 es
->fmt
.audio
.i_bitspersample
);
1571 es
->i_channel
= p_sys
->audio
.i_count
++;
1573 audio_replay_gain_t rg
;
1574 memset( &rg
, 0, sizeof(rg
) );
1575 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1576 vlc_audio_replay_gain_MergeFromMeta( &rg
, input_priv(p_input
)->p_item
->p_meta
);
1577 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1579 for( i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1581 if( !es
->fmt
.audio_replay_gain
.pb_peak
[i
] )
1583 es
->fmt
.audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1584 es
->fmt
.audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1586 if( !es
->fmt
.audio_replay_gain
.pb_gain
[i
] )
1588 es
->fmt
.audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1589 es
->fmt
.audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1596 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
, es
->fmt
.i_codec
);
1597 es
->i_channel
= p_sys
->video
.i_count
++;
1599 if( !es
->fmt
.video
.i_visible_width
|| !es
->fmt
.video
.i_visible_height
)
1601 es
->fmt
.video
.i_visible_width
= es
->fmt
.video
.i_width
;
1602 es
->fmt
.video
.i_visible_height
= es
->fmt
.video
.i_height
;
1605 if( es
->fmt
.video
.i_frame_rate
&& es
->fmt
.video
.i_frame_rate_base
)
1606 vlc_ureduce( &es
->fmt
.video
.i_frame_rate
,
1607 &es
->fmt
.video
.i_frame_rate_base
,
1608 es
->fmt
.video
.i_frame_rate
,
1609 es
->fmt
.video
.i_frame_rate_base
, 0 );
1613 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
, es
->fmt
.i_codec
);
1614 es
->i_channel
= p_sys
->sub
.i_count
++;
1621 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1622 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1624 es
->p_dec_record
= NULL
;
1626 es
->cc
.i_bitmap
= 0;
1627 es
->p_master
= p_master
;
1629 vlc_list_append(&es
->node
, es
->p_master
? &p_sys
->es_slaves
: &p_sys
->es
);
1631 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1632 EsOutESVarUpdate( out
, es
, false );
1634 EsOutUpdateInfo( out
, es
, &es
->fmt
, NULL
);
1635 EsOutSelect( out
, es
, false );
1637 if( es
->b_scrambled
)
1638 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1646 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1648 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1649 vlc_mutex_lock( &p_sys
->lock
);
1650 es_out_id_t
*es
= EsOutAddSlaveLocked( out
, fmt
, NULL
);
1651 vlc_mutex_unlock( &p_sys
->lock
);
1655 static bool EsIsSelected( es_out_id_t
*es
)
1659 bool b_decode
= false;
1660 if( es
->p_master
->p_dec
)
1662 int i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1663 input_DecoderGetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1664 i_channel
, &b_decode
);
1670 return es
->p_dec
!= NULL
;
1673 static void EsCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1675 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1676 input_thread_t
*p_input
= p_sys
->p_input
;
1679 dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_input_clock
,
1680 input_priv(p_input
)->p_sout
);
1683 float rate
= (float)p_sys
->i_rate
/ (float)INPUT_RATE_DEFAULT
;
1685 input_DecoderChangeRate( dec
, rate
);
1687 if( p_sys
->b_buffering
)
1688 input_DecoderStartWait( dec
);
1690 if( !p_es
->p_master
&& p_sys
->p_sout_record
)
1692 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_input_clock
, p_sys
->p_sout_record
);
1693 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
1694 input_DecoderStartWait( p_es
->p_dec_record
);
1699 EsOutDecoderChangeDelay( out
, p_es
);
1701 static void EsDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1708 input_DecoderDelete( p_es
->p_dec
);
1711 if( p_es
->p_dec_record
)
1713 input_DecoderDelete( p_es
->p_dec_record
);
1714 p_es
->p_dec_record
= NULL
;
1718 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
)
1720 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1721 input_thread_t
*p_input
= p_sys
->p_input
;
1723 if( EsIsSelected( es
) )
1725 msg_Warn( p_input
, "ES 0x%x is already selected", es
->i_id
);
1732 if( !es
->p_master
->p_dec
)
1735 i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1737 if( i_channel
== -1 ||
1738 input_DecoderSetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1744 const bool b_sout
= input_priv(p_input
)->p_sout
!= NULL
;
1745 /* If b_forced, the ES is specifically requested by the user, so bypass
1746 * the following vars check. */
1749 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1751 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1753 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1758 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1760 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) )
1762 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1767 if( es
->fmt
.i_cat
== SPU_ES
)
1769 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) )
1771 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1778 EsCreateDecoder( out
, es
);
1780 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1784 /* Mark it as selected */
1785 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, es
->i_id
);
1786 input_SendEventTeletextSelect( p_input
, EsFmtIsTeletext( &es
->fmt
) ? es
->i_id
: -1 );
1789 static void EsDeleteCCChannels( es_out_t
*out
, es_out_id_t
*parent
)
1791 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1792 input_thread_t
*p_input
= p_sys
->p_input
;
1794 if( parent
->cc
.type
== 0 )
1797 es_out_id_t
*spu_es
= EsOutGetSelectedCat( out
, SPU_ES
);
1798 const int i_spu_id
= spu_es
? spu_es
->i_id
: -1;
1800 uint64_t i_bitmap
= parent
->cc
.i_bitmap
;
1801 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1 )
1803 if( (i_bitmap
& 1) == 0 || !parent
->cc
.pp_es
[i
] )
1806 if( i_spu_id
== parent
->cc
.pp_es
[i
]->i_id
)
1808 /* Force unselection of the CC */
1809 input_SendEventEsSelect( p_input
, SPU_ES
, -1 );
1811 EsOutDelLocked( out
, parent
->cc
.pp_es
[i
] );
1814 parent
->cc
.i_bitmap
= 0;
1815 parent
->cc
.type
= 0;
1818 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1820 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1821 input_thread_t
*p_input
= p_sys
->p_input
;
1823 if( !EsIsSelected( es
) )
1825 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->i_id
);
1831 if( es
->p_master
->p_dec
)
1833 int i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1834 if( i_channel
!= -1 )
1835 input_DecoderSetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1841 EsDeleteCCChannels( out
, es
);
1842 EsDestroyDecoder( out
, es
);
1848 /* Mark it as unselected */
1849 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, -1 );
1850 if( EsFmtIsTeletext( &es
->fmt
) )
1851 input_SendEventTeletextSelect( p_input
, -1 );
1855 * Select an ES given the current mode
1856 * XXX: you need to take a the lock before (stream.stream_lock)
1858 * \param out The es_out structure
1859 * \param es es_out_id structure
1860 * \param b_force ...
1863 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1865 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1866 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
1868 if( !p_sys
->b_active
||
1869 ( !b_force
&& es
->fmt
.i_priority
< ES_PRIORITY_SELECTABLE_MIN
) )
1874 bool b_auto_unselect
= p_esprops
&& p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1875 p_esprops
->e_policy
== ES_OUT_ES_POLICY_EXCLUSIVE
&&
1876 p_esprops
->p_main_es
&& p_esprops
->p_main_es
!= es
;
1878 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
1880 if( !EsIsSelected( es
) )
1882 if( b_auto_unselect
)
1883 EsUnselect( out
, p_esprops
->p_main_es
, false );
1885 EsSelect( out
, es
);
1888 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
1890 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
1895 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1897 prgm
= strtok_r( NULL
, ",", &buf
) )
1899 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
1901 if( !EsIsSelected( es
) )
1902 EsSelect( out
, es
);
1909 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1911 const es_out_id_t
*wanted_es
= NULL
;
1913 if( es
->p_pgrm
!= p_sys
->p_pgrm
|| !p_esprops
)
1916 /* user designated by ID ES have higher prio than everything */
1917 if ( p_esprops
->i_id
>= 0 )
1919 if( es
->i_id
== p_esprops
->i_id
)
1923 else if( p_esprops
->i_channel
>= 0 )
1925 if( p_esprops
->i_channel
== es
->i_channel
)
1928 else if( p_esprops
->ppsz_language
)
1930 /* If not deactivated */
1931 const int i_stop_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
, "none" );
1933 int current_es_idx
= ( p_esprops
->p_main_es
== NULL
) ? -1 :
1934 LanguageArrayIndex( p_esprops
->ppsz_language
,
1935 p_esprops
->p_main_es
->psz_language_code
);
1936 int es_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
,
1937 es
->psz_language_code
);
1938 if( es_idx
>= 0 && (i_stop_idx
< 0 || i_stop_idx
> es_idx
) )
1940 /* Only select the language if it's in the list */
1941 if( p_esprops
->p_main_es
== NULL
||
1942 current_es_idx
< 0 || /* current es was not selected by lang prefs */
1943 es_idx
< current_es_idx
|| /* current es has lower lang prio */
1944 ( es_idx
== current_es_idx
&& /* lang is same, but es has higher prio */
1945 p_esprops
->p_main_es
->fmt
.i_priority
< es
->fmt
.i_priority
) )
1950 /* We did not find a language matching our prefs */
1951 else if( i_stop_idx
< 0 ) /* If not fallback disabled by 'none' */
1953 /* Select if asked by demuxer */
1954 if( current_es_idx
< 0 ) /* No es is currently selected by lang pref */
1956 /* If demux has specified a track */
1957 if( p_esprops
->i_demux_id
>= 0 && es
->i_id
== p_esprops
->i_demux_id
)
1961 /* Otherwise, fallback by priority */
1962 else if( p_esprops
->p_main_es
== NULL
||
1963 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
1965 if( p_esprops
->b_autoselect
)
1973 /* If there is no user preference, select the default subtitle
1974 * or adapt by ES priority */
1975 else if( p_esprops
->i_demux_id
>= 0 && es
->i_id
== p_esprops
->i_demux_id
)
1979 else if( p_esprops
->p_main_es
== NULL
||
1980 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
1982 if( p_esprops
->b_autoselect
)
1986 if( wanted_es
== es
&& !EsIsSelected( es
) )
1988 if( b_auto_unselect
)
1989 EsUnselect( out
, p_esprops
->p_main_es
, false );
1991 EsSelect( out
, es
);
1995 /* FIXME TODO handle priority here */
1996 if( p_esprops
&& p_sys
->i_mode
== ES_OUT_MODE_AUTO
&& EsIsSelected( es
) )
1997 p_esprops
->p_main_es
= es
;
2000 static void EsOutCreateCCChannels( es_out_t
*out
, vlc_fourcc_t codec
, uint64_t i_bitmap
,
2001 const char *psz_descfmt
, es_out_id_t
*parent
)
2003 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2004 input_thread_t
*p_input
= p_sys
->p_input
;
2006 /* Only one type of captions is allowed ! */
2007 if( parent
->cc
.type
&& parent
->cc
.type
!= codec
)
2010 uint64_t i_existingbitmap
= parent
->cc
.i_bitmap
;
2011 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1, i_existingbitmap
>>= 1 )
2015 if( (i_bitmap
& 1) == 0 || (i_existingbitmap
& 1) )
2018 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, parent
->i_id
);
2020 es_format_Init( &fmt
, SPU_ES
, codec
);
2021 fmt
.subs
.cc
.i_channel
= i
;
2022 fmt
.i_group
= parent
->fmt
.i_group
;
2023 if( asprintf( &fmt
.psz_description
, psz_descfmt
, 1 + i
) == -1 )
2024 fmt
.psz_description
= NULL
;
2026 es_out_id_t
**pp_es
= &parent
->cc
.pp_es
[i
];
2027 *pp_es
= EsOutAddSlaveLocked( out
, &fmt
, parent
);
2028 es_format_Clean( &fmt
);
2031 parent
->cc
.i_bitmap
|= (1ULL << i
);
2032 parent
->cc
.type
= codec
;
2034 /* Enable if user specified on command line */
2035 if (p_sys
->sub
.i_channel
== i
)
2036 EsOutSelect(out
, *pp_es
, true);
2041 * Send a block for the given es_out
2043 * \param out the es_out to send from
2044 * \param es the es_out_id
2045 * \param p_block the data block to send
2047 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
2049 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2050 input_thread_t
*p_input
= p_sys
->p_input
;
2052 assert( p_block
->p_next
== NULL
);
2054 struct input_stats
*stats
= input_priv(p_input
)->stats
;
2057 input_rate_Add( &stats
->demux_bitrate
, p_block
->i_buffer
);
2059 /* Update number of corrupted data packats */
2060 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
2061 atomic_fetch_add_explicit(&stats
->demux_corrupted
, 1,
2062 memory_order_relaxed
);
2064 /* Update number of discontinuities */
2065 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
2066 atomic_fetch_add_explicit(&stats
->demux_discontinuity
, 1,
2067 memory_order_relaxed
);
2070 vlc_mutex_lock( &p_sys
->lock
);
2072 /* Mark preroll blocks */
2073 if( p_sys
->i_preroll_end
>= 0 )
2075 vlc_tick_t i_date
= p_block
->i_pts
;
2076 if( p_block
->i_pts
== VLC_TICK_INVALID
)
2077 i_date
= p_block
->i_dts
;
2079 if( i_date
+ p_block
->i_length
< p_sys
->i_preroll_end
)
2080 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
2085 block_Release( p_block
);
2086 vlc_mutex_unlock( &p_sys
->lock
);
2090 /* Check for sout mode */
2091 if( input_priv(p_input
)->p_sout
)
2093 /* FIXME review this, proper lock may be missing */
2094 if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
> 0 &&
2095 input_priv(p_input
)->b_out_pace_control
)
2097 msg_Dbg( p_input
, "switching to sync mode" );
2098 input_priv(p_input
)->b_out_pace_control
= false;
2100 else if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
<= 0 &&
2101 !input_priv(p_input
)->b_out_pace_control
)
2103 msg_Dbg( p_input
, "switching to async mode" );
2104 input_priv(p_input
)->b_out_pace_control
= true;
2109 if( es
->p_dec_record
)
2111 block_t
*p_dup
= block_Duplicate( p_block
);
2113 input_DecoderDecode( es
->p_dec_record
, p_dup
,
2114 input_priv(p_input
)->b_out_pace_control
);
2116 input_DecoderDecode( es
->p_dec
, p_block
,
2117 input_priv(p_input
)->b_out_pace_control
);
2119 es_format_t fmt_dsc
;
2120 vlc_meta_t
*p_meta_dsc
;
2121 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
2123 EsOutUpdateInfo( out
, es
, &fmt_dsc
, p_meta_dsc
);
2125 es_format_Clean( &fmt_dsc
);
2127 vlc_meta_Delete( p_meta_dsc
);
2130 /* Check CC status */
2131 decoder_cc_desc_t desc
;
2133 input_DecoderGetCcDesc( es
->p_dec
, &desc
);
2134 if( var_InheritInteger( p_input
, "captions" ) == 708 )
2135 EsOutCreateCCChannels( out
, VLC_CODEC_CEA708
, desc
.i_708_channels
,
2136 _("DTVCC Closed captions %u"), es
);
2137 EsOutCreateCCChannels( out
, VLC_CODEC_CEA608
, desc
.i_608_channels
,
2138 _("Closed captions %u"), es
);
2140 vlc_mutex_unlock( &p_sys
->lock
);
2145 /*****************************************************************************
2147 *****************************************************************************/
2148 static void EsOutDelLocked( es_out_t
*out
, es_out_id_t
*es
)
2150 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2151 bool b_reselect
= false;
2153 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
2155 /* We don't try to reselect */
2157 { /* FIXME: This might hold the ES output caller (i.e. the demux), and
2158 * the corresponding thread (typically the input thread), for a little
2159 * bit too long if the ES is deleted in the middle of a stream. */
2160 input_DecoderDrain( es
->p_dec
);
2161 while( !input_Stopped(p_sys
->p_input
) && !p_sys
->b_buffering
)
2163 if( input_DecoderIsEmpty( es
->p_dec
) &&
2164 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2166 /* FIXME there should be a way to have auto deleted es, but there will be
2167 * a problem when another codec of the same type is created (mainly video) */
2168 vlc_tick_sleep(VLC_TICK_FROM_MS(20));
2170 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2173 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2174 EsOutESVarUpdate( out
, es
, true );
2176 EsDeleteInfo( out
, es
);
2178 vlc_list_remove(&es
->node
);
2180 /* Update program */
2182 if( es
->p_pgrm
->i_es
== 0 )
2183 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2185 if( es
->b_scrambled
)
2186 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2191 if( p_esprops
->p_main_es
== es
)
2194 p_esprops
->p_main_es
= NULL
;
2196 p_esprops
->i_count
--;
2199 /* Re-select another track when needed */
2204 foreach_es_then_es_slaves(other
)
2205 if( es
->fmt
.i_cat
== other
->fmt
.i_cat
)
2207 if (EsIsSelected(other
))
2209 input_SendEventEsSelect(p_sys
->p_input
, es
->fmt
.i_cat
,
2211 if( p_esprops
->p_main_es
== NULL
)
2212 p_esprops
->p_main_es
= other
;
2215 EsOutSelect(out
, other
, false);
2219 free( es
->psz_language
);
2220 free( es
->psz_language_code
);
2222 es_format_Clean( &es
->fmt
);
2227 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2229 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2230 vlc_mutex_lock( &p_sys
->lock
);
2231 EsOutDelLocked( out
, es
);
2232 vlc_mutex_unlock( &p_sys
->lock
);
2235 static int EsOutVaControlLocked( es_out_t
*, int, va_list );
2236 static int EsOutControlLocked( es_out_t
*out
, int i_query
, ... )
2240 va_start( args
, i_query
);
2241 int ret
= EsOutVaControlLocked( out
, i_query
, args
);
2247 * Control query handler
2249 * \param out the es_out to control
2250 * \param i_query A es_out query as defined in include/ninput.h
2251 * \param args a variable list of arguments for the query
2252 * \return VLC_SUCCESS or an error code
2254 static int EsOutVaControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2256 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2260 case ES_OUT_SET_ES_STATE
:
2262 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2263 bool b
= va_arg( args
, int );
2264 if( b
&& !EsIsSelected( es
) )
2266 EsSelect( out
, es
);
2267 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2269 else if( !b
&& EsIsSelected( es
) )
2271 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2277 case ES_OUT_GET_ES_STATE
:
2279 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2280 bool *pb
= va_arg( args
, bool * );
2282 *pb
= EsIsSelected( es
);
2286 case ES_OUT_SET_ES_CAT_POLICY
:
2288 enum es_format_category_e i_cat
= va_arg( args
, enum es_format_category_e
);
2289 enum es_out_policy_e i_pol
= va_arg( args
, enum es_out_policy_e
);
2290 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, i_cat
);
2291 if( p_esprops
== NULL
)
2292 return VLC_EGENERIC
;
2293 p_esprops
->e_policy
= i_pol
;
2297 case ES_OUT_GET_GROUP_FORCED
:
2299 int *pi_group
= va_arg( args
, int * );
2300 *pi_group
= p_sys
->i_group_id
;
2304 case ES_OUT_SET_MODE
:
2306 const int i_mode
= va_arg( args
, int );
2307 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2308 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2309 i_mode
== ES_OUT_MODE_END
);
2311 if (i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& !vlc_list_is_empty(&p_sys
->es
))
2313 /* XXX Terminate vout if there are tracks but no video one.
2314 * This one is not mandatory but is he earliest place where it
2319 foreach_es_then_es_slaves(p_es
)
2320 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& !found
/* nested loop */ )
2327 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2329 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2330 p_sys
->i_mode
= i_mode
;
2332 /* Reapply policy mode */
2335 foreach_es_then_es_slaves(es
)
2337 if (EsIsSelected(es
))
2338 EsUnselect(out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2340 foreach_es_then_es_slaves(es
)
2342 EsOutSelect(out
, es
, false);
2345 if( i_mode
== ES_OUT_MODE_END
)
2346 EsOutTerminate( out
);
2351 case ES_OUT_RESTART_ES
:
2353 #define IGNORE_ES DATA_ES
2354 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* ), *other
;
2356 enum es_format_category_e i_cat
;
2359 else if( es
== es_cat
+ AUDIO_ES
)
2361 else if( es
== es_cat
+ VIDEO_ES
)
2363 else if( es
== es_cat
+ SPU_ES
)
2368 foreach_es_then_es_slaves(other
)
2370 if( i_cat
== IGNORE_ES
)
2374 if (i_query
== ES_OUT_RESTART_ES
&& es
->p_dec
!= NULL
)
2376 EsDestroyDecoder(out
, es
);
2377 EsCreateDecoder(out
, es
);
2379 else if( i_query
== ES_OUT_SET_ES
)
2381 EsOutSelect(out
, es
, true);
2386 else if (i_cat
== UNKNOWN_ES
|| other
->fmt
.i_cat
== i_cat
)
2388 if (EsIsSelected(other
))
2390 if (i_query
== ES_OUT_RESTART_ES
)
2392 if (other
->p_dec
!= NULL
)
2394 EsDestroyDecoder(out
, other
);
2395 EsCreateDecoder(out
, other
);
2399 EsUnselect(out
, other
, other
->p_pgrm
== p_sys
->p_pgrm
);
2406 case ES_OUT_UNSET_ES
:
2408 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* ), *other
;
2409 foreach_es_then_es_slaves(other
)
2413 if (EsIsSelected(other
))
2415 EsUnselect(out
, other
, other
->p_pgrm
== p_sys
->p_pgrm
);
2421 return VLC_EGENERIC
;
2423 case ES_OUT_STOP_ALL_ES
:
2428 foreach_es_then_es_slaves(es
)
2431 int *selected_es
= vlc_alloc(count
+ 1, sizeof(int));
2435 *va_arg(args
, void **) = selected_es
;
2436 *selected_es
= count
;
2438 foreach_es_then_es_slaves(es
)
2440 if (EsIsSelected(es
))
2442 EsDestroyDecoder(out
, es
);
2443 *++selected_es
= es
->i_id
;
2446 *++selected_es
= -1;
2450 case ES_OUT_START_ALL_ES
:
2452 int *selected_es
= va_arg( args
, void * );
2453 int count
= selected_es
[0];
2454 for( int i
= 0; i
< count
; ++i
)
2456 int i_id
= selected_es
[i
+ 1];
2459 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2460 EsCreateDecoder( out
, p_es
);
2467 case ES_OUT_SET_ES_DEFAULT
:
2469 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2473 /*p_sys->i_default_video_id = -1;*/
2474 /*p_sys->i_default_audio_id = -1;*/
2475 p_sys
->sub
.i_demux_id
= -1;
2477 else if( es
== es_cat
+ AUDIO_ES
)
2479 /*p_sys->i_default_video_id = -1;*/
2481 else if( es
== es_cat
+ VIDEO_ES
)
2483 /*p_sys->i_default_audio_id = -1;*/
2485 else if( es
== es_cat
+ SPU_ES
)
2487 p_sys
->sub
.i_demux_id
= -1;
2491 /*if( es->fmt.i_cat == VIDEO_ES )
2492 p_sys->i_default_video_id = es->i_id;
2494 if( es->fmt.i_cat == AUDIO_ES )
2495 p_sys->i_default_audio_id = es->i_id;
2497 if( es
->fmt
.i_cat
== SPU_ES
)
2498 p_sys
->sub
.i_demux_id
= es
->i_id
;
2503 case ES_OUT_SET_PCR
:
2504 case ES_OUT_SET_GROUP_PCR
:
2506 es_out_pgrm_t
*p_pgrm
= NULL
;
2510 /* Search program */
2511 if( i_query
== ES_OUT_SET_PCR
)
2513 p_pgrm
= p_sys
->p_pgrm
;
2515 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2519 i_group
= va_arg( args
, int );
2520 p_pgrm
= EsOutProgramFind( out
, i_group
);
2523 return VLC_EGENERIC
;
2525 i_pcr
= va_arg( args
, vlc_tick_t
);
2526 if( i_pcr
== VLC_TICK_INVALID
)
2528 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2529 return VLC_EGENERIC
;
2532 /* TODO do not use vlc_tick_now() but proper stream acquisition date */
2534 input_clock_Update( p_pgrm
->p_input_clock
, VLC_OBJECT(p_sys
->p_input
),
2536 input_priv(p_sys
->p_input
)->b_can_pace_control
|| p_sys
->b_buffering
,
2537 EsOutIsExtraBufferingAllowed( out
),
2538 i_pcr
, vlc_tick_now() );
2540 if( !p_sys
->p_pgrm
)
2543 if( p_sys
->b_buffering
)
2545 /* Check buffering state on master clock update */
2546 EsOutDecodersStopBuffering( out
, false );
2548 else if( p_pgrm
== p_sys
->p_pgrm
)
2550 if( b_late
&& ( !input_priv(p_sys
->p_input
)->p_sout
||
2551 !input_priv(p_sys
->p_input
)->b_out_pace_control
) )
2553 const vlc_tick_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2554 vlc_tick_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_input_clock
);
2556 /* Avoid dangerously high value */
2557 const vlc_tick_t i_jitter_max
=
2558 VLC_TICK_FROM_MS(var_InheritInteger( p_sys
->p_input
, "clock-jitter" ));
2559 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2561 es_out_pgrm_t
*pgrm
;
2563 msg_Err( p_sys
->p_input
,
2564 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2565 (int)MS_FROM_VLC_TICK(i_pts_delay
- i_pts_delay_base
) );
2566 i_pts_delay
= p_sys
->i_pts_delay
;
2569 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
2570 input_clock_Reset(pgrm
->p_input_clock
);
2574 msg_Err( p_sys
->p_input
,
2575 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2576 (int)MS_FROM_VLC_TICK(i_pts_delay
) );
2578 /* Force a rebufferization when we are too late */
2580 /* It is not really good, as we throw away already buffered data
2581 * TODO have a mean to correctly reenter bufferization */
2582 EsOutControlLocked( out
, ES_OUT_RESET_PCR
);
2585 es_out_SetJitter( out
, i_pts_delay_base
, i_pts_delay
- i_pts_delay_base
, p_sys
->i_cr_average
);
2591 case ES_OUT_RESET_PCR
:
2592 msg_Dbg( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2593 EsOutChangePosition( out
);
2596 case ES_OUT_SET_GROUP
:
2598 int i
= va_arg( args
, int );
2599 es_out_pgrm_t
*p_pgrm
;
2601 vlc_list_foreach(p_pgrm
, &p_sys
->programs
, node
)
2602 if( p_pgrm
->i_id
== i
)
2604 EsOutProgramSelect( out
, p_pgrm
);
2607 return VLC_EGENERIC
;
2610 case ES_OUT_SET_ES_FMT
:
2612 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2613 * to update the p_extra data */
2614 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2615 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2617 return VLC_EGENERIC
;
2619 es_format_Clean( &es
->fmt
);
2620 es_format_Copy( &es
->fmt
, p_fmt
);
2624 EsDestroyDecoder( out
, es
);
2625 EsCreateDecoder( out
, es
);
2631 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2633 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2634 bool b_scrambled
= (bool)va_arg( args
, int );
2636 if( !es
->b_scrambled
!= !b_scrambled
)
2638 es
->b_scrambled
= b_scrambled
;
2639 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2644 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2646 const int64_t i_date
= va_arg( args
, int64_t );
2649 return VLC_EGENERIC
;
2651 p_sys
->i_preroll_end
= i_date
;
2655 case ES_OUT_SET_GROUP_META
:
2657 int i_group
= va_arg( args
, int );
2658 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2660 EsOutProgramMeta( out
, i_group
, p_meta
);
2663 case ES_OUT_SET_GROUP_EPG
:
2665 int i_group
= va_arg( args
, int );
2666 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2668 EsOutProgramEpg( out
, i_group
, p_epg
);
2671 case ES_OUT_SET_GROUP_EPG_EVENT
:
2673 int i_group
= va_arg( args
, int );
2674 const vlc_epg_event_t
*p_evt
= va_arg( args
, const vlc_epg_event_t
* );
2676 EsOutProgramEpgEvent( out
, i_group
, p_evt
);
2679 case ES_OUT_SET_EPG_TIME
:
2681 int64_t i64
= va_arg( args
, int64_t );
2683 EsOutEpgTime( out
, i64
);
2687 case ES_OUT_DEL_GROUP
:
2689 int i_group
= va_arg( args
, int );
2691 return EsOutProgramDel( out
, i_group
);
2694 case ES_OUT_SET_META
:
2696 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2698 EsOutGlobalMeta( out
, p_meta
);
2702 case ES_OUT_GET_WAKE_UP
:
2704 vlc_tick_t
*pi_wakeup
= va_arg( args
, vlc_tick_t
* );
2705 *pi_wakeup
= EsOutGetWakeup( out
);
2709 case ES_OUT_SET_ES_BY_ID
:
2710 case ES_OUT_RESTART_ES_BY_ID
:
2711 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2713 const int i_id
= va_arg( args
, int );
2714 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2715 int i_new_query
= 0;
2719 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
;
2720 p_es
->b_forced
= va_arg( args
, int );
2722 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2723 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2725 vlc_assert_unreachable();
2727 int i_ret
= EsOutControlLocked( out
, i_new_query
, p_es
);
2729 /* Clean up vout after user action (in active mode only).
2730 * FIXME it does not work well with multiple video windows */
2731 if( p_sys
->b_active
)
2732 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2736 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2738 const int i_id
= va_arg( args
, int );
2739 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2741 return VLC_EGENERIC
;
2743 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2744 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2745 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
2749 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2750 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2764 case ES_OUT_GET_BUFFERING
:
2766 bool *pb
= va_arg( args
, bool* );
2767 *pb
= p_sys
->b_buffering
;
2771 case ES_OUT_GET_EMPTY
:
2773 bool *pb
= va_arg( args
, bool* );
2774 *pb
= EsOutDecodersIsEmpty( out
);
2778 case ES_OUT_SET_DELAY
:
2780 const int i_cat
= va_arg( args
, int );
2781 const vlc_tick_t i_delay
= va_arg( args
, vlc_tick_t
);
2782 EsOutSetDelay( out
, i_cat
, i_delay
);
2786 case ES_OUT_SET_RECORD_STATE
:
2788 bool b
= va_arg( args
, int );
2789 return EsOutSetRecord( out
, b
);
2792 case ES_OUT_SET_PAUSE_STATE
:
2794 const bool b_source_paused
= (bool)va_arg( args
, int );
2795 const bool b_paused
= (bool)va_arg( args
, int );
2796 const vlc_tick_t i_date
= va_arg( args
, vlc_tick_t
);
2798 assert( !b_source_paused
== !b_paused
);
2799 EsOutChangePause( out
, b_paused
, i_date
);
2804 case ES_OUT_SET_RATE
:
2806 const int i_src_rate
= va_arg( args
, int );
2807 const int i_rate
= va_arg( args
, int );
2809 assert( i_src_rate
== i_rate
);
2810 EsOutChangeRate( out
, i_rate
);
2815 case ES_OUT_SET_FRAME_NEXT
:
2816 EsOutFrameNext( out
);
2819 case ES_OUT_SET_TIMES
:
2821 double f_position
= va_arg( args
, double );
2822 vlc_tick_t i_time
= va_arg( args
, vlc_tick_t
);
2823 vlc_tick_t i_length
= va_arg( args
, vlc_tick_t
);
2825 input_SendEventLength( p_sys
->p_input
, i_length
);
2827 if( !p_sys
->b_buffering
)
2831 /* Fix for buffering delay */
2832 if( !input_priv(p_sys
->p_input
)->p_sout
||
2833 !input_priv(p_sys
->p_input
)->b_out_pace_control
)
2834 i_delay
= EsOutGetBuffering( out
);
2843 f_position
-= (double)i_delay
/ i_length
;
2844 if( f_position
< 0 )
2847 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
2851 case ES_OUT_SET_JITTER
:
2853 vlc_tick_t i_pts_delay
= va_arg( args
, vlc_tick_t
);
2854 vlc_tick_t i_pts_jitter
= va_arg( args
, vlc_tick_t
);
2855 int i_cr_average
= va_arg( args
, int );
2856 es_out_pgrm_t
*pgrm
;
2858 bool b_change_clock
=
2859 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
2860 i_cr_average
!= p_sys
->i_cr_average
;
2862 assert( i_pts_jitter
>= 0 );
2863 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
2864 p_sys
->i_pts_jitter
= i_pts_jitter
;
2865 p_sys
->i_cr_average
= i_cr_average
;
2868 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
2869 input_clock_SetJitter(pgrm
->p_input_clock
, i_pts_delay
2870 + i_pts_jitter
, i_cr_average
);
2874 case ES_OUT_GET_PCR_SYSTEM
:
2876 if( p_sys
->b_buffering
)
2877 return VLC_EGENERIC
;
2879 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2881 return VLC_EGENERIC
;
2883 vlc_tick_t
*pi_system
= va_arg( args
, vlc_tick_t
*);
2884 vlc_tick_t
*pi_delay
= va_arg( args
, vlc_tick_t
*);
2885 input_clock_GetSystemOrigin( p_pgrm
->p_input_clock
, pi_system
, pi_delay
);
2889 case ES_OUT_MODIFY_PCR_SYSTEM
:
2891 if( p_sys
->b_buffering
)
2892 return VLC_EGENERIC
;
2894 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2896 return VLC_EGENERIC
;
2898 const bool b_absolute
= va_arg( args
, int );
2899 const vlc_tick_t i_system
= va_arg( args
, vlc_tick_t
);
2900 input_clock_ChangeSystemOrigin( p_pgrm
->p_input_clock
, b_absolute
, i_system
);
2903 case ES_OUT_SET_EOS
:
2906 foreach_es_then_es_slaves(id
)
2907 if (id
->p_dec
!= NULL
)
2908 input_DecoderDrain(id
->p_dec
);
2912 case ES_OUT_POST_SUBNODE
:
2914 input_item_node_t
*node
= va_arg(args
, input_item_node_t
*);
2915 input_item_node_PostAndDelete(node
);
2920 msg_Err( p_sys
->p_input
, "unknown query 0x%x in %s", i_query
,
2922 return VLC_EGENERIC
;
2925 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
2927 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2930 vlc_mutex_lock( &p_sys
->lock
);
2931 i_ret
= EsOutVaControlLocked( out
, i_query
, args
);
2932 vlc_mutex_unlock( &p_sys
->lock
);
2937 static const struct es_out_callbacks es_out_cbs
=
2942 .control
= EsOutControl
,
2943 .destroy
= EsOutDelete
,
2946 /****************************************************************************
2947 * LanguageGetName: try to expend iso639 into plain name
2948 ****************************************************************************/
2949 static char *LanguageGetName( const char *psz_code
)
2951 const iso639_lang_t
*pl
;
2953 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
2955 return strdup( "" );
2958 if( strlen( psz_code
) == 2 )
2960 pl
= GetLang_1( psz_code
);
2962 else if( strlen( psz_code
) == 3 )
2964 pl
= GetLang_2B( psz_code
);
2965 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2967 pl
= GetLang_2T( psz_code
);
2972 char *lang
= LanguageGetCode( psz_code
);
2973 pl
= GetLang_1( lang
);
2977 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2979 return strdup( psz_code
);
2983 return strdup( vlc_gettext(pl
->psz_eng_name
) );
2987 /* Get a 2 char code */
2988 static char *LanguageGetCode( const char *psz_lang
)
2990 const iso639_lang_t
*pl
;
2992 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
2993 return strdup("??");
2995 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
2997 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
2998 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
2999 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
3000 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
3001 return strdup( pl
->psz_iso639_1
);
3004 return strdup("??");
3007 static char **LanguageSplit( const char *psz_langs
)
3014 if( psz_langs
== NULL
) return NULL
;
3016 psz_parser
= psz_dup
= strdup(psz_langs
);
3018 while( psz_parser
&& *psz_parser
)
3023 psz
= strchr(psz_parser
, ',' );
3024 if( psz
) *psz
++ = '\0';
3026 if( !strcmp( psz_parser
, "any" ) )
3028 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
3030 else if( !strcmp( psz_parser
, "none" ) )
3032 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
3036 psz_code
= LanguageGetCode( psz_parser
);
3037 if( strcmp( psz_code
, "??" ) )
3039 TAB_APPEND( i_psz
, ppsz
, psz_code
);
3052 TAB_APPEND( i_psz
, ppsz
, NULL
);
3059 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
)
3061 if( !ppsz_langs
|| !psz_lang
)
3064 for( int i
= 0; ppsz_langs
[i
]; i
++ )
3066 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
3067 ( !strcasecmp( ppsz_langs
[i
], "any" ) && strcasecmp( psz_lang
, "none") ) )
3069 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
3076 /****************************************************************************
3078 * - add meta info to the playlist item
3079 ****************************************************************************/
3080 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
, const vlc_meta_t
*p_meta
)
3082 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
3083 input_thread_t
*p_input
= p_sys
->p_input
;
3084 const es_format_t
*p_fmt_es
= &es
->fmt
;
3086 if( es
->fmt
.i_cat
== fmt
->i_cat
)
3088 es_format_t update
= *fmt
;
3089 update
.i_id
= es
->i_meta_id
;
3090 update
.i_codec
= es
->fmt
.i_codec
;
3091 update
.i_original_fourcc
= es
->fmt
.i_original_fourcc
;
3093 /* Update infos that could have been lost by the decoder (no need to
3094 * dup them since input_item_UpdateTracksInfo() will do it). */
3095 if (update
.psz_language
== NULL
)
3096 update
.psz_language
= es
->fmt
.psz_language
;
3097 if (update
.psz_description
== NULL
)
3098 update
.psz_description
= es
->fmt
.psz_description
;
3099 if (update
.i_cat
== SPU_ES
)
3101 if (update
.subs
.psz_encoding
== NULL
)
3102 update
.subs
.psz_encoding
= es
->fmt
.subs
.psz_encoding
;
3104 if (update
.i_extra_languages
== 0)
3106 assert(update
.p_extra_languages
== NULL
);
3107 update
.i_extra_languages
= es
->fmt
.i_extra_languages
;
3108 update
.p_extra_languages
= es
->fmt
.p_extra_languages
;
3111 /* No need to update codec specific data */
3113 update
.p_extra
= NULL
;
3115 input_item_UpdateTracksInfo(input_GetItem(p_input
), &update
);
3118 /* Create category */
3119 char* psz_cat
= EsInfoCategoryName( es
);
3121 if( unlikely( !psz_cat
) )
3124 info_category_t
* p_cat
= info_category_New( psz_cat
);
3128 if( unlikely( !p_cat
) )
3131 /* Add information */
3132 if( es
->i_meta_id
!= es
->i_id
)
3133 info_category_AddInfo( p_cat
, _("Original ID"),
3136 const vlc_fourcc_t i_codec_fourcc
= ( p_fmt_es
->i_original_fourcc
)?
3137 p_fmt_es
->i_original_fourcc
: p_fmt_es
->i_codec
;
3138 const char *psz_codec_description
=
3139 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, i_codec_fourcc
);
3140 if( psz_codec_description
&& *psz_codec_description
)
3141 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
3142 psz_codec_description
, (char*)&i_codec_fourcc
);
3143 else if ( i_codec_fourcc
!= VLC_FOURCC(0,0,0,0) )
3144 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
3145 (char*)&i_codec_fourcc
);
3147 if( es
->psz_language
&& *es
->psz_language
)
3148 info_category_AddInfo( p_cat
, _("Language"), "%s",
3150 if( fmt
->psz_description
&& *fmt
->psz_description
)
3151 info_category_AddInfo( p_cat
, _("Description"), "%s",
3152 fmt
->psz_description
);
3154 switch( fmt
->i_cat
)
3157 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
3159 if( fmt
->audio
.i_physical_channels
)
3160 info_category_AddInfo( p_cat
, _("Channels"), "%s",
3161 vlc_gettext( aout_FormatPrintChannels( &fmt
->audio
) ) );
3163 if( fmt
->audio
.i_rate
!= 0 )
3165 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
3166 fmt
->audio
.i_rate
);
3167 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3168 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
3171 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
3172 if( i_bitspersample
== 0 )
3173 i_bitspersample
= aout_BitsPerSample( p_fmt_es
->i_codec
);
3174 if( i_bitspersample
!= 0 )
3175 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
3178 if( fmt
->i_bitrate
!= 0 )
3180 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
3181 fmt
->i_bitrate
/ 1000 );
3182 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3183 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
3185 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
3187 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
3188 if( !p_rg
->pb_gain
[i
] )
3190 const char *psz_name
;
3191 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
3192 psz_name
= _("Track replay gain");
3194 psz_name
= _("Album replay gain");
3195 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
3201 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
3203 if( fmt
->video
.i_visible_width
> 0 &&
3204 fmt
->video
.i_visible_height
> 0 )
3205 info_category_AddInfo( p_cat
, _("Video resolution"), "%ux%u",
3206 fmt
->video
.i_visible_width
,
3207 fmt
->video
.i_visible_height
);
3209 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
3210 info_category_AddInfo( p_cat
, _("Buffer dimensions"), "%ux%u",
3211 fmt
->video
.i_width
, fmt
->video
.i_height
);
3213 if( fmt
->video
.i_frame_rate
> 0 &&
3214 fmt
->video
.i_frame_rate_base
> 0 )
3216 if( fmt
->video
.i_frame_rate_base
== 1 )
3217 info_category_AddInfo( p_cat
, _("Frame rate"), "%u",
3218 fmt
->video
.i_frame_rate
);
3220 info_category_AddInfo( p_cat
, _("Frame rate"), "%.6f",
3221 (double)fmt
->video
.i_frame_rate
3222 / (double)fmt
->video
.i_frame_rate_base
);
3224 if( fmt
->i_codec
!= p_fmt_es
->i_codec
)
3226 const char *psz_chroma_description
=
3227 vlc_fourcc_GetDescription( VIDEO_ES
, fmt
->i_codec
);
3228 if( psz_chroma_description
)
3229 info_category_AddInfo( p_cat
, _("Decoded format"), "%s",
3230 psz_chroma_description
);
3233 static const char orient_names
[][13] = {
3234 N_("Top left"), N_("Left top"),
3235 N_("Right bottom"), N_("Top right"),
3236 N_("Bottom left"), N_("Bottom right"),
3237 N_("Left bottom"), N_("Right top"),
3239 info_category_AddInfo( p_cat
, _("Orientation"), "%s",
3240 vlc_gettext(orient_names
[fmt
->video
.orientation
]) );
3242 if( fmt
->video
.primaries
!= COLOR_PRIMARIES_UNDEF
)
3244 static const char primaries_names
[][32] = {
3245 [COLOR_PRIMARIES_UNDEF
] = N_("Undefined"),
3246 [COLOR_PRIMARIES_BT601_525
] =
3247 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3248 [COLOR_PRIMARIES_BT601_625
] =
3249 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3250 [COLOR_PRIMARIES_BT709
] = "ITU-R BT.709",
3251 [COLOR_PRIMARIES_BT2020
] = "ITU-R BT.2020",
3252 [COLOR_PRIMARIES_DCI_P3
] = "DCI/P3 D65",
3253 [COLOR_PRIMARIES_BT470_M
] = "ITU-R BT.470 M",
3255 static_assert(ARRAY_SIZE(primaries_names
) == COLOR_PRIMARIES_MAX
+1,
3256 "Color primiaries table mismatch");
3257 info_category_AddInfo( p_cat
, _("Color primaries"), "%s",
3258 vlc_gettext(primaries_names
[fmt
->video
.primaries
]) );
3260 if( fmt
->video
.transfer
!= TRANSFER_FUNC_UNDEF
)
3262 static const char func_names
[][20] = {
3263 [TRANSFER_FUNC_UNDEF
] = N_("Undefined"),
3264 [TRANSFER_FUNC_LINEAR
] = N_("Linear"),
3265 [TRANSFER_FUNC_SRGB
] = "sRGB",
3266 [TRANSFER_FUNC_BT470_BG
] = "ITU-R BT.470 BG",
3267 [TRANSFER_FUNC_BT470_M
] = "ITU-R BT.470 M",
3268 [TRANSFER_FUNC_BT709
] = "ITU-R BT.709",
3269 [TRANSFER_FUNC_SMPTE_ST2084
] = "SMPTE ST2084",
3270 [TRANSFER_FUNC_SMPTE_240
] = "SMPTE 240M",
3271 [TRANSFER_FUNC_HLG
] = N_("Hybrid Log-Gamma"),
3273 static_assert(ARRAY_SIZE(func_names
) == TRANSFER_FUNC_MAX
+1,
3274 "Transfer functions table mismatch");
3275 info_category_AddInfo( p_cat
, _("Color transfer function"), "%s",
3276 vlc_gettext(func_names
[fmt
->video
.transfer
]) );
3278 if( fmt
->video
.space
!= COLOR_SPACE_UNDEF
)
3280 static const char space_names
[][16] = {
3281 [COLOR_SPACE_UNDEF
] = N_("Undefined"),
3282 [COLOR_SPACE_BT601
] = "ITU-R BT.601",
3283 [COLOR_SPACE_BT709
] = "ITU-R BT.709",
3284 [COLOR_SPACE_BT2020
] = "ITU-R BT.2020",
3286 static_assert(ARRAY_SIZE(space_names
) == COLOR_SPACE_MAX
+1,
3287 "Color space table mismatch");
3288 info_category_AddInfo( p_cat
, _("Color space"), _("%s %s Range"),
3289 vlc_gettext(space_names
[fmt
->video
.space
]),
3290 vlc_gettext(fmt
->video
.b_color_range_full
3291 ? N_("Full") : N_("Limited")) );
3293 if( fmt
->video
.chroma_location
!= CHROMA_LOCATION_UNDEF
)
3295 static const char c_loc_names
[][16] = {
3296 [CHROMA_LOCATION_UNDEF
] = N_("Undefined"),
3297 [CHROMA_LOCATION_LEFT
] = N_("Left"),
3298 [CHROMA_LOCATION_CENTER
] = N_("Center"),
3299 [CHROMA_LOCATION_TOP_LEFT
] = N_("Top Left"),
3300 [CHROMA_LOCATION_TOP_CENTER
] = N_("Top Center"),
3301 [CHROMA_LOCATION_BOTTOM_LEFT
] =N_("Bottom Left"),
3302 [CHROMA_LOCATION_BOTTOM_CENTER
] = N_("Bottom Center"),
3304 static_assert(ARRAY_SIZE(c_loc_names
) == CHROMA_LOCATION_MAX
+1,
3305 "Chroma location table mismatch");
3306 info_category_AddInfo( p_cat
, _("Chroma location"), "%s",
3307 vlc_gettext(c_loc_names
[fmt
->video
.chroma_location
]) );
3309 if( fmt
->video
.projection_mode
!= PROJECTION_MODE_RECTANGULAR
)
3311 const char *psz_loc_name
= NULL
;
3312 switch (fmt
->video
.projection_mode
)
3314 case PROJECTION_MODE_RECTANGULAR
:
3315 psz_loc_name
= N_("Rectangular");
3317 case PROJECTION_MODE_EQUIRECTANGULAR
:
3318 psz_loc_name
= N_("Equirectangular");
3320 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
3321 psz_loc_name
= N_("Cubemap");
3324 vlc_assert_unreachable();
3327 info_category_AddInfo( p_cat
, _("Projection"), "%s",
3328 vlc_gettext(psz_loc_name
) );
3330 info_category_AddInfo( p_cat
, vlc_pgettext("ViewPoint", "Yaw"),
3331 "%.2f", fmt
->video
.pose
.yaw
);
3332 info_category_AddInfo( p_cat
, vlc_pgettext("ViewPoint", "Pitch"),
3333 "%.2f", fmt
->video
.pose
.pitch
);
3334 info_category_AddInfo( p_cat
, vlc_pgettext("ViewPoint", "Roll"),
3335 "%.2f", fmt
->video
.pose
.roll
);
3336 info_category_AddInfo( p_cat
,
3337 vlc_pgettext("ViewPoint", "Field of view"),
3338 "%.2f", fmt
->video
.pose
.fov
);
3340 if ( fmt
->video
.mastering
.max_luminance
)
3342 info_category_AddInfo( p_cat
, _("Max. luminance"), "%.4f cd/m²",
3343 fmt
->video
.mastering
.max_luminance
/ 10000.f
);
3345 if ( fmt
->video
.mastering
.min_luminance
)
3347 info_category_AddInfo( p_cat
, _("Min. luminance"), "%.4f cd/m²",
3348 fmt
->video
.mastering
.min_luminance
/ 10000.f
);
3350 if ( fmt
->video
.mastering
.primaries
[4] &&
3351 fmt
->video
.mastering
.primaries
[5] )
3353 float x
= (float)fmt
->video
.mastering
.primaries
[4] / 50000.f
;
3354 float y
= (float)fmt
->video
.mastering
.primaries
[5] / 50000.f
;
3355 info_category_AddInfo( p_cat
, _("Primary R"), "x=%.4f y=%.4f", x
, y
);
3357 if ( fmt
->video
.mastering
.primaries
[0] &&
3358 fmt
->video
.mastering
.primaries
[1] )
3360 float x
= (float)fmt
->video
.mastering
.primaries
[0] / 50000.f
;
3361 float y
= (float)fmt
->video
.mastering
.primaries
[1] / 50000.f
;
3362 info_category_AddInfo( p_cat
, _("Primary G"), "x=%.4f y=%.4f", x
, y
);
3364 if ( fmt
->video
.mastering
.primaries
[2] &&
3365 fmt
->video
.mastering
.primaries
[3] )
3367 float x
= (float)fmt
->video
.mastering
.primaries
[2] / 50000.f
;
3368 float y
= (float)fmt
->video
.mastering
.primaries
[3] / 50000.f
;
3369 info_category_AddInfo( p_cat
, _("Primary B"), "x=%.4f y=%.4f", x
, y
);
3371 if ( fmt
->video
.mastering
.white_point
[0] &&
3372 fmt
->video
.mastering
.white_point
[1] )
3374 float x
= (float)fmt
->video
.mastering
.white_point
[0] / 50000.f
;
3375 float y
= (float)fmt
->video
.mastering
.white_point
[1] / 50000.f
;
3376 info_category_AddInfo( p_cat
, _("White point"), "x=%.4f y=%.4f", x
, y
);
3378 if ( fmt
->video
.lighting
.MaxCLL
)
3380 info_category_AddInfo( p_cat
, "MaxCLL", "%" PRIu16
" cd/m²",
3381 fmt
->video
.lighting
.MaxCLL
);
3383 if ( fmt
->video
.lighting
.MaxFALL
)
3385 info_category_AddInfo( p_cat
, "MaxFALL", "%" PRIu16
" cd/m²",
3386 fmt
->video
.lighting
.MaxFALL
);
3391 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
3398 /* Append generic meta */
3401 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
3402 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
3404 char *psz_key
= ppsz_all_keys
[i
];
3405 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
3408 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
3409 vlc_gettext(psz_value
) );
3412 free( ppsz_all_keys
);
3415 input_Control( p_input
, INPUT_REPLACE_INFOS
, p_cat
);
3418 static void EsDeleteInfo( es_out_t
*out
, es_out_id_t
*es
)
3420 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
3421 char* psz_info_category
;
3423 if( likely( psz_info_category
= EsInfoCategoryName( es
) ) )
3425 input_Control( p_sys
->p_input
, INPUT_DEL_INFO
,
3426 psz_info_category
, NULL
);
3428 free( psz_info_category
);