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>
43 #include "input_internal.h"
51 #include "../stream_output/stream_output.h"
53 #include <vlc_iso_lang.h>
54 /* FIXME we should find a better way than including that */
55 #include "../text/iso-639_def.h"
57 /*****************************************************************************
59 *****************************************************************************/
65 /* Number of es for this pgrm */
71 /* Clock for this program */
72 input_clock_t
*p_clock
;
81 es_out_pgrm_t
*p_pgrm
;
86 /* Channel in the track type */
90 char *psz_language_code
;
93 decoder_t
*p_dec_record
;
95 /* Fields for Video with CC */
96 bool pb_cc_present
[4];
97 es_out_id_t
*pp_cc_es
[4];
99 /* Field for CC track from a master video */
100 es_out_id_t
*p_master
;
102 /* ID for the meta data */
108 int i_count
; /* es count */
109 es_out_id_t
*p_main_es
; /* current main es */
110 enum es_out_policy_e e_policy
;
112 /* Parameters used for es selection */
113 bool b_autoselect
; /* if we want to select an es when no user prefs */
114 int i_id
; /* es id as set by es fmt.id */
115 int i_demux_id
; /* same as previous, demuxer set default value */
116 int i_channel
; /* es number in creation order */
117 char **ppsz_language
;
122 input_thread_t
*p_input
;
129 es_out_pgrm_t
**pgrm
;
130 es_out_pgrm_t
*p_pgrm
; /* Master program */
141 es_out_es_props_t video
, audio
, sub
;
143 /* es/group to select */
147 int64_t i_audio_delay
;
150 /* Clock configuration */
152 mtime_t i_pts_jitter
;
158 mtime_t i_pause_date
;
160 /* Current preroll */
161 mtime_t i_preroll_end
;
163 /* Used for buffering */
165 mtime_t i_buffering_extra_initial
;
166 mtime_t i_buffering_extra_stream
;
167 mtime_t i_buffering_extra_system
;
170 sout_instance_t
*p_sout_record
;
172 /* Used only to limit debugging output */
173 int i_prev_stream_level
;
176 static es_out_id_t
*EsOutAdd ( es_out_t
*, const es_format_t
* );
177 static int EsOutSend ( es_out_t
*, es_out_id_t
*, block_t
* );
178 static void EsOutDel ( es_out_t
*, es_out_id_t
* );
179 static int EsOutControl( es_out_t
*, int i_query
, va_list );
180 static void EsOutDelete ( es_out_t
* );
182 static void EsOutTerminate( es_out_t
* );
183 static void EsOutSelect( es_out_t
*, es_out_id_t
*es
, bool b_force
);
184 static void EsOutUpdateInfo( es_out_t
*, es_out_id_t
*es
, const es_format_t
*, const vlc_meta_t
* );
185 static int EsOutSetRecord( es_out_t
*, bool b_record
);
187 static bool EsIsSelected( es_out_id_t
*es
);
188 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
);
189 static void EsDeleteInfo( es_out_t
*, es_out_id_t
*es
);
190 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
);
191 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
);
192 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
193 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
194 static void EsOutProgramsChangeRate( es_out_t
*out
);
195 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
);
196 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
);
197 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_progmeta
);
199 static char *LanguageGetName( const char *psz_code
);
200 static char *LanguageGetCode( const char *psz_lang
);
201 static char **LanguageSplit( const char *psz_langs
);
202 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
);
204 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
);
205 static char *EsInfoCategoryName( es_out_id_t
* es
);
207 static const vlc_fourcc_t EsOutFourccClosedCaptions
[4] = {
213 static inline int EsOutGetClosedCaptionsChannel( vlc_fourcc_t fcc
)
216 for( i
= 0; i
< 4; i
++ )
218 if( fcc
== EsOutFourccClosedCaptions
[i
] )
223 static inline bool EsFmtIsTeletext( const es_format_t
*p_fmt
)
225 return p_fmt
->i_cat
== SPU_ES
&& p_fmt
->i_codec
== VLC_CODEC_TELETEXT
;
228 /*****************************************************************************
229 * Es category specific structs
230 *****************************************************************************/
231 static es_out_es_props_t
* GetPropsByCat( es_out_sys_t
*p_sys
, int i_cat
)
236 return &p_sys
->audio
;
240 return &p_sys
->video
;
245 static void EsOutPropsCleanup( es_out_es_props_t
*p_props
)
247 if( p_props
->ppsz_language
)
249 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
250 free( p_props
->ppsz_language
[i
] );
251 free( p_props
->ppsz_language
);
255 static void EsOutPropsInit( es_out_es_props_t
*p_props
,
257 input_thread_t
*p_input
,
258 enum es_out_policy_e e_default_policy
,
259 const char *psz_trackidvar
,
260 const char *psz_trackvar
,
261 const char *psz_langvar
,
262 const char *psz_debug
)
264 p_props
->e_policy
= e_default_policy
;
265 p_props
->i_count
= 0;
266 p_props
->b_autoselect
= autoselect
;
267 p_props
->i_id
= (psz_trackidvar
) ? var_GetInteger( p_input
, psz_trackidvar
): -1;
268 p_props
->i_channel
= (psz_trackvar
) ? var_GetInteger( p_input
, psz_trackvar
): -1;
269 p_props
->i_demux_id
= -1;
270 p_props
->p_main_es
= NULL
;
272 if( !input_priv(p_input
)->b_preparsing
&& psz_langvar
)
274 char *psz_string
= var_GetString( p_input
, psz_langvar
);
275 p_props
->ppsz_language
= LanguageSplit( psz_string
);
276 if( p_props
->ppsz_language
)
278 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
279 msg_Dbg( p_input
, "selected %s language[%d] %s",
280 psz_debug
, i
, p_props
->ppsz_language
[i
] );
286 /*****************************************************************************
288 *****************************************************************************/
289 es_out_t
*input_EsOutNew( input_thread_t
*p_input
, int i_rate
)
291 es_out_t
*out
= malloc( sizeof( *out
) );
295 es_out_sys_t
*p_sys
= calloc( 1, sizeof( *p_sys
) );
302 out
->pf_add
= EsOutAdd
;
303 out
->pf_send
= EsOutSend
;
304 out
->pf_del
= EsOutDel
;
305 out
->pf_control
= EsOutControl
;
306 out
->pf_destroy
= EsOutDelete
;
309 vlc_mutex_init_recursive( &p_sys
->lock
);
310 p_sys
->p_input
= p_input
;
312 p_sys
->b_active
= false;
313 p_sys
->i_mode
= ES_OUT_MODE_NONE
;
315 TAB_INIT( p_sys
->i_pgrm
, p_sys
->pgrm
);
317 TAB_INIT( p_sys
->i_es
, p_sys
->es
);
320 EsOutPropsInit( &p_sys
->video
, true, p_input
, ES_OUT_ES_POLICY_SIMULTANEOUS
,
321 NULL
, NULL
, NULL
, NULL
);
322 EsOutPropsInit( &p_sys
->audio
, true, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
323 "audio-track-id", "audio-track", "audio-language", "audio" );
324 EsOutPropsInit( &p_sys
->sub
, false, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
325 "sub-track-id", "sub-track", "sub-language", "sub" );
327 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
329 p_sys
->i_pause_date
= -1;
331 p_sys
->i_rate
= i_rate
;
333 p_sys
->b_buffering
= true;
334 p_sys
->i_preroll_end
= -1;
335 p_sys
->i_prev_stream_level
= -1;
340 /*****************************************************************************
342 *****************************************************************************/
343 static void EsOutDelete( es_out_t
*out
)
345 es_out_sys_t
*p_sys
= out
->p_sys
;
347 assert( !p_sys
->i_es
&& !p_sys
->i_pgrm
&& !p_sys
->p_pgrm
);
348 EsOutPropsCleanup( &p_sys
->audio
);
349 EsOutPropsCleanup( &p_sys
->sub
);
351 vlc_mutex_destroy( &p_sys
->lock
);
357 static void EsOutTerminate( es_out_t
*out
)
359 es_out_sys_t
*p_sys
= out
->p_sys
;
361 if( p_sys
->p_sout_record
)
362 EsOutSetRecord( out
, false );
364 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
366 if( p_sys
->es
[i
]->p_dec
)
367 input_DecoderDelete( p_sys
->es
[i
]->p_dec
);
369 free( p_sys
->es
[i
]->psz_language
);
370 free( p_sys
->es
[i
]->psz_language_code
);
371 es_format_Clean( &p_sys
->es
[i
]->fmt
);
373 free( p_sys
->es
[i
] );
375 TAB_CLEAN( p_sys
->i_es
, p_sys
->es
);
377 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
378 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
380 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[i
];
381 input_clock_Delete( p_pgrm
->p_clock
);
383 vlc_meta_Delete( p_pgrm
->p_meta
);
387 TAB_CLEAN( p_sys
->i_pgrm
, p_sys
->pgrm
);
389 p_sys
->p_pgrm
= NULL
;
391 input_item_SetEpgOffline( input_priv(p_sys
->p_input
)->p_item
);
392 input_SendEventMetaEpg( p_sys
->p_input
);
395 static mtime_t
EsOutGetWakeup( es_out_t
*out
)
397 es_out_sys_t
*p_sys
= out
->p_sys
;
398 input_thread_t
*p_input
= p_sys
->p_input
;
403 /* We do not have a wake up date if the input cannot have its speed
404 * controlled or sout is imposing its own or while buffering
406 * FIXME for !input_priv(p_input)->b_can_pace_control a wake-up time is still needed
407 * to avoid too heavy buffering */
408 if( !input_priv(p_input
)->b_can_pace_control
||
409 input_priv(p_input
)->b_out_pace_control
||
413 return input_clock_GetWakeup( p_sys
->p_pgrm
->p_clock
);
416 static es_out_id_t
*EsOutGetFromID( es_out_t
*out
, int i_id
)
420 /* Special HACK, -i_id is the cat of the stream */
421 return (es_out_id_t
*)((uint8_t*)NULL
-i_id
);
424 for( int i
= 0; i
< out
->p_sys
->i_es
; i
++ )
426 if( out
->p_sys
->es
[i
]->i_id
== i_id
)
427 return out
->p_sys
->es
[i
];
432 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
434 es_out_sys_t
*p_sys
= out
->p_sys
;
436 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
438 EsOutDecodersStopBuffering( out
, true );
439 if( p_sys
->b_buffering
)
443 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
445 es_out_id_t
*es
= p_sys
->es
[i
];
447 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
449 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
455 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, int64_t i_delay
)
457 es_out_sys_t
*p_sys
= out
->p_sys
;
459 if( i_cat
== AUDIO_ES
)
460 p_sys
->i_audio_delay
= i_delay
;
461 else if( i_cat
== SPU_ES
)
462 p_sys
->i_spu_delay
= i_delay
;
464 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
465 EsOutDecoderChangeDelay( out
, p_sys
->es
[i
] );
468 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
470 es_out_sys_t
*p_sys
= out
->p_sys
;
471 input_thread_t
*p_input
= p_sys
->p_input
;
473 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
477 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
480 if( var_CountChoices( p_input
, "video-es" ) )
481 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
482 else if( var_CountChoices( p_input
, "audio-es" ) )
483 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
485 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
488 char *psz_sout
= NULL
; // TODO conf
490 if( !psz_sout
&& psz_path
)
492 char *psz_file
= input_CreateFilename( p_input
, psz_path
, INPUT_RECORD_PREFIX
, NULL
);
495 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file
) < 0 )
506 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
510 if( !p_sys
->p_sout_record
)
513 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
515 es_out_id_t
*p_es
= p_sys
->es
[i
];
517 if( !p_es
->p_dec
|| p_es
->p_master
)
520 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
521 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
522 input_DecoderStartWait( p_es
->p_dec_record
);
527 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
529 es_out_id_t
*p_es
= p_sys
->es
[i
];
531 if( !p_es
->p_dec_record
)
534 input_DecoderDelete( p_es
->p_dec_record
);
535 p_es
->p_dec_record
= NULL
;
538 sout_DeleteInstance( p_sys
->p_sout_record
);
540 p_sys
->p_sout_record
= NULL
;
545 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
547 es_out_sys_t
*p_sys
= out
->p_sys
;
549 /* XXX the order is important */
552 EsOutDecodersChangePause( out
, true, i_date
);
553 EsOutProgramChangePause( out
, true, i_date
);
557 if( p_sys
->i_buffering_extra_initial
> 0 )
559 mtime_t i_stream_start
;
560 mtime_t i_system_start
;
561 mtime_t i_stream_duration
;
562 mtime_t i_system_duration
;
564 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
565 &i_stream_start
, &i_system_start
,
566 &i_stream_duration
, &i_system_duration
);
569 /* FIXME pcr != exactly what wanted */
570 const mtime_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
;
573 p_sys
->i_buffering_extra_initial
= 0;
574 p_sys
->i_buffering_extra_stream
= 0;
575 p_sys
->i_buffering_extra_system
= 0;
577 EsOutProgramChangePause( out
, false, i_date
);
578 EsOutDecodersChangePause( out
, false, i_date
);
580 EsOutProgramsChangeRate( out
);
582 p_sys
->b_paused
= b_paused
;
583 p_sys
->i_pause_date
= i_date
;
586 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
588 es_out_sys_t
*p_sys
= out
->p_sys
;
590 p_sys
->i_rate
= i_rate
;
591 EsOutProgramsChangeRate( out
);
594 static void EsOutChangePosition( es_out_t
*out
)
596 es_out_sys_t
*p_sys
= out
->p_sys
;
598 input_SendEventCache( p_sys
->p_input
, 0.0 );
600 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
602 es_out_id_t
*p_es
= p_sys
->es
[i
];
604 if( p_es
->p_dec
!= NULL
)
606 input_DecoderFlush( p_es
->p_dec
);
607 if( !p_sys
->b_buffering
)
609 input_DecoderStartWait( p_es
->p_dec
);
610 if( p_es
->p_dec_record
!= NULL
)
611 input_DecoderStartWait( p_es
->p_dec_record
);
616 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
617 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
619 p_sys
->b_buffering
= true;
620 p_sys
->i_buffering_extra_initial
= 0;
621 p_sys
->i_buffering_extra_stream
= 0;
622 p_sys
->i_buffering_extra_system
= 0;
623 p_sys
->i_preroll_end
= -1;
624 p_sys
->i_prev_stream_level
= -1;
629 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
631 es_out_sys_t
*p_sys
= out
->p_sys
;
633 mtime_t i_stream_start
;
634 mtime_t i_system_start
;
635 mtime_t i_stream_duration
;
636 mtime_t i_system_duration
;
637 if (input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
638 &i_stream_start
, &i_system_start
,
639 &i_stream_duration
, &i_system_duration
))
642 mtime_t i_preroll_duration
= 0;
643 if( p_sys
->i_preroll_end
>= 0 )
644 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
646 const mtime_t i_buffering_duration
= p_sys
->i_pts_delay
+
648 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
650 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
653 if (i_buffering_duration
== 0)
656 f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
657 input_SendEventCache( p_sys
->p_input
, f_level
);
659 int i_level
= (int)(100 * f_level
);
660 if( p_sys
->i_prev_stream_level
!= i_level
)
662 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", i_level
);
663 p_sys
->i_prev_stream_level
= i_level
;
668 input_SendEventCache( p_sys
->p_input
, 1.0 );
670 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
671 (int)(i_stream_duration
/1000), (int)(i_system_duration
/1000) );
672 p_sys
->b_buffering
= false;
673 p_sys
->i_preroll_end
= -1;
674 p_sys
->i_prev_stream_level
= -1;
676 if( p_sys
->i_buffering_extra_initial
> 0 )
682 const mtime_t i_decoder_buffering_start
= mdate();
683 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
685 es_out_id_t
*p_es
= p_sys
->es
[i
];
687 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
689 input_DecoderWait( p_es
->p_dec
);
690 if( p_es
->p_dec_record
)
691 input_DecoderWait( p_es
->p_dec_record
);
694 msg_Dbg( p_sys
->p_input
, "Decoder wait done in %d ms",
695 (int)(mdate() - i_decoder_buffering_start
)/1000 );
697 /* Here is a good place to destroy unused vout with every demuxer */
698 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
701 const mtime_t i_wakeup_delay
= 10*1000; /* FIXME CLEANUP thread wake up time*/
702 const mtime_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: mdate();
704 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_clock
, true,
705 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
707 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
709 es_out_id_t
*p_es
= p_sys
->es
[i
];
714 input_DecoderStopWait( p_es
->p_dec
);
715 if( p_es
->p_dec_record
)
716 input_DecoderStopWait( p_es
->p_dec_record
);
719 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
721 es_out_sys_t
*p_sys
= out
->p_sys
;
723 /* Pause decoders first */
724 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
726 es_out_id_t
*es
= p_sys
->es
[i
];
730 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
731 if( es
->p_dec_record
)
732 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
737 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
739 es_out_sys_t
*p_sys
= out
->p_sys
;
742 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
744 es_out_id_t
*p_es
= p_sys
->es
[i
];
747 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
748 if( p_es
->p_dec_record
)
749 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
751 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
753 /* TODO maybe we want to be able to tune it ? */
754 #if defined(OPTIMIZE_MEMORY)
755 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
757 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
759 return i_size
< i_level_high
;
762 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
764 es_out_sys_t
*p_sys
= out
->p_sys
;
766 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
767 input_clock_ChangePause( p_sys
->pgrm
[i
]->p_clock
, b_paused
, i_date
);
770 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
772 es_out_sys_t
*p_sys
= out
->p_sys
;
775 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
776 i_delay
= p_sys
->i_audio_delay
;
777 else if( p_es
->fmt
.i_cat
== SPU_ES
)
778 i_delay
= p_sys
->i_spu_delay
;
783 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
784 if( p_es
->p_dec_record
)
785 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
787 static void EsOutProgramsChangeRate( es_out_t
*out
)
789 es_out_sys_t
*p_sys
= out
->p_sys
;
791 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
792 input_clock_ChangeRate( p_sys
->pgrm
[i
]->p_clock
, p_sys
->i_rate
);
795 static void EsOutFrameNext( es_out_t
*out
)
797 es_out_sys_t
*p_sys
= out
->p_sys
;
798 es_out_id_t
*p_es_video
= NULL
;
800 if( p_sys
->b_buffering
)
802 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
806 assert( p_sys
->b_paused
);
808 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
810 es_out_id_t
*p_es
= p_sys
->es
[i
];
812 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
821 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
826 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
828 msg_Dbg( out
->p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)(i_duration
/1000) );
830 if( i_duration
<= 0 )
831 i_duration
= 40*1000;
833 /* FIXME it is not a clean way ? */
834 if( p_sys
->i_buffering_extra_initial
<= 0 )
836 mtime_t i_stream_start
;
837 mtime_t i_system_start
;
838 mtime_t i_stream_duration
;
839 mtime_t i_system_duration
;
842 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
843 &i_stream_start
, &i_system_start
,
844 &i_stream_duration
, &i_system_duration
);
848 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
849 p_sys
->i_buffering_extra_system
=
850 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
853 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_clock
);
855 p_sys
->b_buffering
= true;
856 p_sys
->i_buffering_extra_system
+= i_duration
;
857 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
858 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
859 INPUT_RATE_DEFAULT
/ i_rate
;
861 p_sys
->i_preroll_end
= -1;
862 p_sys
->i_prev_stream_level
= -1;
864 static mtime_t
EsOutGetBuffering( es_out_t
*out
)
866 es_out_sys_t
*p_sys
= out
->p_sys
;
867 mtime_t i_stream_duration
, i_system_start
;
873 mtime_t i_stream_start
, i_system_duration
;
875 if( input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
876 &i_stream_start
, &i_system_start
,
877 &i_stream_duration
, &i_system_duration
) )
883 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
885 i_delay
= i_stream_duration
;
889 mtime_t i_system_duration
;
891 if( p_sys
->b_paused
)
893 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
894 if( p_sys
->i_buffering_extra_initial
> 0 )
895 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
899 i_system_duration
= mdate() - i_system_start
;
902 const mtime_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
903 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
910 static void EsOutESVarUpdateGeneric( es_out_t
*out
, int i_id
,
911 const es_format_t
*fmt
, const char *psz_language
,
914 es_out_sys_t
*p_sys
= out
->p_sys
;
915 input_thread_t
*p_input
= p_sys
->p_input
;
916 vlc_value_t val
, text
;
920 if( EsFmtIsTeletext( fmt
) )
921 input_SendEventTeletextDel( p_sys
->p_input
, i_id
);
923 input_SendEventEsDel( p_input
, fmt
->i_cat
, i_id
);
927 /* Get the number of ES already added */
929 if( fmt
->i_cat
== AUDIO_ES
)
930 psz_var
= "audio-es";
931 else if( fmt
->i_cat
== VIDEO_ES
)
932 psz_var
= "video-es";
936 var_Change( p_input
, psz_var
, VLC_VAR_CHOICESCOUNT
, &val
, NULL
);
941 /* First one, we need to add the "Disable" choice */
942 val2
.i_int
= -1; text
.psz_string
= _("Disable");
943 var_Change( p_input
, psz_var
, VLC_VAR_ADDCHOICE
, &val2
, &text
);
947 /* Take care of the ES description */
948 if( fmt
->psz_description
&& *fmt
->psz_description
)
950 if( psz_language
&& *psz_language
)
952 if( asprintf( &text
.psz_string
, "%s - [%s]", fmt
->psz_description
,
953 psz_language
) == -1 )
954 text
.psz_string
= NULL
;
956 else text
.psz_string
= strdup( fmt
->psz_description
);
960 if( psz_language
&& *psz_language
)
962 if( asprintf( &text
.psz_string
, "%s %"PRId64
" - [%s]", _( "Track" ), val
.i_int
, psz_language
) == -1 )
963 text
.psz_string
= NULL
;
967 if( asprintf( &text
.psz_string
, "%s %"PRId64
, _( "Track" ), val
.i_int
) == -1 )
968 text
.psz_string
= NULL
;
972 input_SendEventEsAdd( p_input
, fmt
->i_cat
, i_id
, text
.psz_string
);
973 if( EsFmtIsTeletext( fmt
) )
976 snprintf( psz_page
, sizeof(psz_page
), "%d%2.2x",
977 fmt
->subs
.teletext
.i_magazine
,
978 fmt
->subs
.teletext
.i_page
);
979 input_SendEventTeletextAdd( p_sys
->p_input
,
980 i_id
, fmt
->subs
.teletext
.i_magazine
>= 0 ? psz_page
: NULL
);
983 free( text
.psz_string
);
986 static void EsOutESVarUpdate( es_out_t
*out
, es_out_id_t
*es
,
989 EsOutESVarUpdateGeneric( out
, es
->i_id
, &es
->fmt
, es
->psz_language
, b_delete
);
992 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
994 return out
->p_sys
->i_group_id
== 0 || out
->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
= out
->p_sys
;
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
;
1012 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
1014 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1016 if( p_sys
->es
[i
]->p_pgrm
== old
&& EsIsSelected( p_sys
->es
[i
] ) &&
1017 p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
1018 EsUnselect( out
, p_sys
->es
[i
], true );
1021 p_sys
->audio
.p_main_es
= NULL
;
1022 p_sys
->video
.p_main_es
= NULL
;
1023 p_sys
->sub
.p_main_es
= NULL
;
1026 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
1028 /* Mark it selected */
1029 p_pgrm
->b_selected
= true;
1031 /* Switch master stream */
1032 p_sys
->p_pgrm
= p_pgrm
;
1034 /* Update "program" */
1035 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
1038 input_SendEventEsDel( p_input
, AUDIO_ES
, -1 );
1039 input_SendEventEsDel( p_input
, VIDEO_ES
, -1 );
1040 input_SendEventEsDel( p_input
, SPU_ES
, -1 );
1041 input_SendEventTeletextDel( p_input
, -1 );
1042 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1045 var_SetInteger( p_input
, "teletext-es", -1 );
1047 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1049 if( p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
)
1051 EsOutESVarUpdate( out
, p_sys
->es
[i
], false );
1052 EsOutUpdateInfo( out
, p_sys
->es
[i
], &p_sys
->es
[i
]->fmt
, NULL
);
1055 EsOutSelect( out
, p_sys
->es
[i
], false );
1058 /* Ensure the correct running EPG table is selected */
1059 input_item_ChangeEPGSource( input_priv(p_input
)->p_item
, p_pgrm
->i_id
);
1061 /* Update now playing */
1062 if( p_pgrm
->p_meta
)
1064 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
,
1065 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) );
1066 input_item_SetPublisher( input_priv(p_input
)->p_item
,
1067 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Publisher
) );
1068 input_item_SetTitle( input_priv(p_input
)->p_item
,
1069 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1070 input_SendEventMeta( p_input
);
1071 /* FIXME: we probably want to replace every input meta */
1078 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1080 es_out_sys_t
*p_sys
= out
->p_sys
;
1081 input_thread_t
*p_input
= p_sys
->p_input
;
1083 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1088 p_pgrm
->i_id
= i_group
;
1090 p_pgrm
->b_selected
= false;
1091 p_pgrm
->b_scrambled
= false;
1092 p_pgrm
->p_meta
= NULL
;
1093 p_pgrm
->p_clock
= input_clock_New( p_sys
->i_rate
);
1094 if( !p_pgrm
->p_clock
)
1099 if( p_sys
->b_paused
)
1100 input_clock_ChangePause( p_pgrm
->p_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1101 input_clock_SetJitter( p_pgrm
->p_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1104 TAB_APPEND( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1106 /* Update "program" variable */
1107 if( EsOutIsProgramVisible( out
, i_group
) )
1108 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1110 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1111 EsOutProgramSelect( out
, p_pgrm
);
1119 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1121 es_out_sys_t
*p_sys
= out
->p_sys
;
1122 input_thread_t
*p_input
= p_sys
->p_input
;
1123 es_out_pgrm_t
*p_pgrm
= NULL
;
1126 for( i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1128 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1130 p_pgrm
= p_sys
->pgrm
[i
];
1135 if( p_pgrm
== NULL
)
1136 return VLC_EGENERIC
;
1140 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1141 i_group
, p_pgrm
->i_es
);
1142 return VLC_EGENERIC
;
1145 TAB_REMOVE( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1147 /* If program is selected we need to unselect it */
1148 if( p_sys
->p_pgrm
== p_pgrm
)
1149 p_sys
->p_pgrm
= NULL
;
1151 input_clock_Delete( p_pgrm
->p_clock
);
1153 if( p_pgrm
->p_meta
)
1154 vlc_meta_Delete( p_pgrm
->p_meta
);
1157 /* Update "program" variable */
1158 input_SendEventProgramDel( p_input
, i_group
);
1165 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1167 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1169 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1171 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1172 return p_sys
->pgrm
[i
];
1174 return EsOutProgramAdd( p_out
, i_group
);
1177 /* EsOutProgramMeta:
1179 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1182 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1184 if( asprintf( &psz
, _("%s [%s %d]"), vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
),
1185 _("Program"), p_pgrm
->i_id
) == -1 )
1190 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1196 static char *EsOutProgramGetProgramName( es_out_pgrm_t
*p_pgrm
)
1199 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1201 return strdup( vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1205 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1211 static char *EsInfoCategoryName( es_out_id_t
* es
)
1215 if( asprintf( &psz_category
, _("Stream %d"), es
->i_meta_id
) == -1 )
1218 return psz_category
;
1221 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1223 es_out_sys_t
*p_sys
= out
->p_sys
;
1224 es_out_pgrm_t
*p_pgrm
;
1225 input_thread_t
*p_input
= p_sys
->p_input
;
1226 const char *psz_title
= NULL
;
1227 const char *psz_provider
= NULL
;
1230 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1232 /* Check against empty meta data (empty for what we handle) */
1233 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1234 !vlc_meta_Get( p_meta
, vlc_meta_ESNowPlaying
) &&
1235 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) )
1242 EsOutGlobalMeta( out
, p_meta
);
1247 if( !EsOutIsProgramVisible( out
, i_group
) )
1249 p_pgrm
= EsOutProgramFind( out
, i_group
);
1253 if( p_pgrm
->p_meta
)
1255 const char *psz_current_title
= vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
);
1256 const char *psz_new_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1257 if( !psz_current_title
!= !psz_new_title
||
1258 ( psz_new_title
&& psz_new_title
&& strcmp(psz_new_title
, psz_current_title
)) )
1260 /* Remove old entries */
1261 char *psz_oldinfokey
= EsOutProgramGetMetaName( p_pgrm
);
1262 input_Control( p_input
, INPUT_DEL_INFO
, psz_oldinfokey
, NULL
);
1263 /* TODO update epg name ?
1264 * TODO update scrambled info name ? */
1265 free( psz_oldinfokey
);
1267 vlc_meta_Delete( p_pgrm
->p_meta
);
1269 p_pgrm
->p_meta
= vlc_meta_New();
1270 if( p_pgrm
->p_meta
)
1271 vlc_meta_Merge( p_pgrm
->p_meta
, p_meta
);
1273 if( p_sys
->p_pgrm
== p_pgrm
)
1275 EsOutMeta( out
, NULL
, p_meta
);
1278 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1279 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1281 /* Update the description text of the program */
1282 if( psz_title
&& *psz_title
)
1285 if( psz_provider
&& *psz_provider
)
1287 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1292 psz_text
= strdup( psz_title
);
1295 /* ugly but it works */
1298 input_SendEventProgramDel( p_input
, i_group
);
1299 input_SendEventProgramAdd( p_input
, i_group
, psz_text
);
1300 if( p_sys
->p_pgrm
== p_pgrm
)
1301 input_SendEventProgramSelect( p_input
, i_group
);
1307 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1309 info_category_t
*p_cat
= NULL
;
1310 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1312 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1314 p_cat
= info_category_New( psz_cat
);
1318 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1321 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1322 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1323 free( ppsz_all_keys
[i
] );
1325 free( ppsz_all_keys
);
1329 if( p_sys
->p_pgrm
== p_pgrm
)
1331 input_item_SetPublisher( input_priv(p_input
)->p_item
, psz_provider
);
1332 input_SendEventMeta( p_input
);
1335 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1336 "%s",psz_provider
);
1339 input_Control( p_input
, INPUT_MERGE_INFOS
, p_cat
);
1342 static void EsOutProgramEpgEvent( es_out_t
*out
, int i_group
, const vlc_epg_event_t
*p_event
)
1344 es_out_sys_t
*p_sys
= out
->p_sys
;
1345 input_thread_t
*p_input
= p_sys
->p_input
;
1346 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1347 es_out_pgrm_t
*p_pgrm
;
1350 if( !EsOutIsProgramVisible( out
, i_group
) )
1352 p_pgrm
= EsOutProgramFind( out
, i_group
);
1356 input_item_SetEpgEvent( p_item
, p_event
);
1359 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1361 es_out_sys_t
*p_sys
= out
->p_sys
;
1362 input_thread_t
*p_input
= p_sys
->p_input
;
1363 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1364 es_out_pgrm_t
*p_pgrm
;
1368 if( !EsOutIsProgramVisible( out
, i_group
) )
1370 p_pgrm
= EsOutProgramFind( out
, i_group
);
1375 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1376 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1382 epg
.psz_name
= EsOutProgramGetProgramName( p_pgrm
);
1384 input_item_SetEpg( p_item
, &epg
, p_sys
->p_pgrm
&& (p_epg
->i_source_id
== p_sys
->p_pgrm
->i_id
) );
1385 input_SendEventMetaEpg( p_sys
->p_input
);
1387 free( epg
.psz_name
);
1389 /* Update now playing */
1390 if( p_epg
->b_present
&& p_pgrm
->p_meta
&&
1391 ( p_epg
->p_current
|| p_epg
->i_event
== 0 ) )
1393 vlc_meta_SetNowPlaying( p_pgrm
->p_meta
, NULL
);
1396 vlc_mutex_lock( &p_item
->lock
);
1397 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1399 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1401 if( p_tmp
->b_present
&& p_tmp
->i_source_id
== p_pgrm
->i_id
)
1403 const char *psz_name
= ( p_tmp
->p_current
) ? p_tmp
->p_current
->psz_name
: NULL
;
1404 if( !p_pgrm
->p_meta
)
1405 p_pgrm
->p_meta
= vlc_meta_New();
1406 if( p_pgrm
->p_meta
)
1407 vlc_meta_Set( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
, psz_name
);
1411 vlc_mutex_unlock( &p_item
->lock
);
1413 /* Update selected program input info */
1414 if( p_pgrm
== p_sys
->p_pgrm
)
1416 const char *psz_nowplaying
= p_pgrm
->p_meta
?
1417 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) : NULL
;
1419 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
, psz_nowplaying
);
1420 input_SendEventMeta( p_input
);
1422 if( psz_nowplaying
)
1424 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
,
1425 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
), "%s", psz_nowplaying
);
1429 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
,
1430 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
) );
1437 static void EsOutEpgTime( es_out_t
*out
, int64_t time
)
1439 es_out_sys_t
*p_sys
= out
->p_sys
;
1440 input_thread_t
*p_input
= p_sys
->p_input
;
1441 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1443 input_item_SetEpgTime( p_item
, time
);
1446 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1448 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1449 input_thread_t
*p_input
= p_sys
->p_input
;
1450 bool b_scrambled
= false;
1452 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
1454 if( p_sys
->es
[i
]->p_pgrm
== p_pgrm
&& p_sys
->es
[i
]->b_scrambled
)
1460 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1463 p_pgrm
->b_scrambled
= b_scrambled
;
1464 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1467 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
, _("Scrambled"), _("Yes") );
1469 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, _("Scrambled") );
1472 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1475 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_program_meta
)
1477 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1478 input_thread_t
*p_input
= p_sys
->p_input
;
1479 input_item_t
*p_item
= input_GetItem( p_input
);
1481 vlc_mutex_lock( &p_item
->lock
);
1483 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1484 vlc_mutex_unlock( &p_item
->lock
);
1486 /* Check program meta to not override GROUP_META values */
1487 if( (!p_program_meta
|| vlc_meta_Get( p_program_meta
, vlc_meta_Title
) == NULL
) &&
1488 vlc_meta_Get( p_meta
, vlc_meta_Title
) != NULL
)
1489 input_item_SetName( p_item
, vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1491 const char *psz_arturl
= NULL
;
1492 char *psz_alloc
= NULL
;
1494 if( p_program_meta
)
1495 psz_arturl
= vlc_meta_Get( p_program_meta
, vlc_meta_ArtworkURL
);
1496 if( psz_arturl
== NULL
&& p_meta
)
1497 psz_arturl
= vlc_meta_Get( p_meta
, vlc_meta_ArtworkURL
);
1499 if( psz_arturl
== NULL
) /* restore/favor previously set item art URL */
1500 psz_arturl
= psz_alloc
= input_item_GetArtURL( p_item
);
1502 if( psz_arturl
!= NULL
)
1503 input_item_SetArtURL( p_item
, psz_arturl
);
1505 if( psz_arturl
!= NULL
&& !strncmp( psz_arturl
, "attachment://", 13 ) )
1506 { /* Clear art cover if streaming out.
1507 * FIXME: Why? Remove this when sout gets meta data support. */
1508 if( input_priv(p_input
)->p_sout
!= NULL
)
1509 input_item_SetArtURL( p_item
, NULL
);
1511 input_ExtractAttachmentAndCacheArt( p_input
, psz_arturl
+ 13 );
1515 input_item_SetPreparsed( p_item
, true );
1517 input_SendEventMeta( p_input
);
1518 /* TODO handle sout meta ? */
1521 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1523 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1524 EsOutMeta( p_out
, p_meta
,
1525 (p_sys
->p_pgrm
&& p_sys
->p_pgrm
->p_meta
) ? p_sys
->p_pgrm
->p_meta
: NULL
);
1528 static es_out_id_t
*EsOutAddSlave( es_out_t
*out
, const es_format_t
*fmt
, es_out_id_t
*p_master
)
1530 es_out_sys_t
*p_sys
= out
->p_sys
;
1531 input_thread_t
*p_input
= p_sys
->p_input
;
1533 if( fmt
->i_group
< 0 )
1535 msg_Err( p_input
, "invalid group number" );
1539 es_out_id_t
*es
= malloc( sizeof( *es
) );
1540 es_out_pgrm_t
*p_pgrm
;
1546 vlc_mutex_lock( &p_sys
->lock
);
1548 /* Search the program */
1549 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1552 vlc_mutex_unlock( &p_sys
->lock
);
1557 /* Increase ref count for program */
1561 es
->p_pgrm
= p_pgrm
;
1562 es_format_Copy( &es
->fmt
, fmt
);
1563 if( es
->fmt
.i_id
< 0 )
1564 es
->fmt
.i_id
= p_sys
->i_id
;
1565 if( !es
->fmt
.i_original_fourcc
)
1566 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1568 es
->i_id
= es
->fmt
.i_id
;
1569 es
->i_meta_id
= p_sys
->i_id
++; /* always incremented */
1570 es
->b_scrambled
= false;
1572 switch( es
->fmt
.i_cat
)
1576 es
->fmt
.i_codec
= vlc_fourcc_GetCodecAudio( es
->fmt
.i_codec
,
1577 es
->fmt
.audio
.i_bitspersample
);
1578 es
->i_channel
= p_sys
->audio
.i_count
++;
1580 audio_replay_gain_t rg
;
1581 memset( &rg
, 0, sizeof(rg
) );
1582 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1583 vlc_audio_replay_gain_MergeFromMeta( &rg
, input_priv(p_input
)->p_item
->p_meta
);
1584 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1586 for( i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1588 if( !es
->fmt
.audio_replay_gain
.pb_peak
[i
] )
1590 es
->fmt
.audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1591 es
->fmt
.audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1593 if( !es
->fmt
.audio_replay_gain
.pb_gain
[i
] )
1595 es
->fmt
.audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1596 es
->fmt
.audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1603 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
, es
->fmt
.i_codec
);
1604 es
->i_channel
= p_sys
->video
.i_count
++;
1606 if( !es
->fmt
.video
.i_visible_width
|| !es
->fmt
.video
.i_visible_height
)
1608 es
->fmt
.video
.i_visible_width
= es
->fmt
.video
.i_width
;
1609 es
->fmt
.video
.i_visible_height
= es
->fmt
.video
.i_height
;
1612 if( es
->fmt
.video
.i_frame_rate
&& es
->fmt
.video
.i_frame_rate_base
)
1613 vlc_ureduce( &es
->fmt
.video
.i_frame_rate
,
1614 &es
->fmt
.video
.i_frame_rate_base
,
1615 es
->fmt
.video
.i_frame_rate
,
1616 es
->fmt
.video
.i_frame_rate_base
, 0 );
1620 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
, es
->fmt
.i_codec
);
1621 es
->i_channel
= p_sys
->sub
.i_count
++;
1628 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1629 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1631 es
->p_dec_record
= NULL
;
1632 for( i
= 0; i
< 4; i
++ )
1633 es
->pb_cc_present
[i
] = false;
1634 es
->p_master
= p_master
;
1636 TAB_APPEND( p_sys
->i_es
, p_sys
->es
, es
);
1638 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1639 EsOutESVarUpdate( out
, es
, false );
1641 EsOutUpdateInfo( out
, es
, &es
->fmt
, NULL
);
1642 EsOutSelect( out
, es
, false );
1644 if( es
->b_scrambled
)
1645 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1647 vlc_mutex_unlock( &p_sys
->lock
);
1655 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1657 return EsOutAddSlave( out
, fmt
, NULL
);
1660 static bool EsIsSelected( es_out_id_t
*es
)
1664 bool b_decode
= false;
1665 if( es
->p_master
->p_dec
)
1667 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_original_fourcc
);
1668 if( i_channel
!= -1 )
1669 input_DecoderGetCcState( es
->p_master
->p_dec
, &b_decode
, i_channel
);
1675 return es
->p_dec
!= NULL
;
1678 static void EsCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1680 es_out_sys_t
*p_sys
= out
->p_sys
;
1681 input_thread_t
*p_input
= p_sys
->p_input
;
1683 p_es
->p_dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, input_priv(p_input
)->p_sout
);
1686 if( p_sys
->b_buffering
)
1687 input_DecoderStartWait( p_es
->p_dec
);
1689 if( !p_es
->p_master
&& p_sys
->p_sout_record
)
1691 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
1692 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
1693 input_DecoderStartWait( p_es
->p_dec_record
);
1697 EsOutDecoderChangeDelay( out
, p_es
);
1699 static void EsDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1706 input_DecoderDelete( p_es
->p_dec
);
1709 if( p_es
->p_dec_record
)
1711 input_DecoderDelete( p_es
->p_dec_record
);
1712 p_es
->p_dec_record
= NULL
;
1716 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
)
1718 es_out_sys_t
*p_sys
= out
->p_sys
;
1719 input_thread_t
*p_input
= p_sys
->p_input
;
1721 if( EsIsSelected( es
) )
1723 msg_Warn( p_input
, "ES 0x%x is already selected", es
->i_id
);
1730 if( !es
->p_master
->p_dec
)
1733 i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_original_fourcc
);
1734 if( i_channel
== -1 || input_DecoderSetCcState( es
->p_master
->p_dec
, true, i_channel
) )
1739 const bool b_sout
= input_priv(p_input
)->p_sout
!= NULL
;
1740 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1742 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1744 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1749 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1751 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) )
1753 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1758 if( es
->fmt
.i_cat
== SPU_ES
)
1760 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) )
1762 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1768 EsCreateDecoder( out
, es
);
1770 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1774 /* Mark it as selected */
1775 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, es
->i_id
);
1776 input_SendEventTeletextSelect( p_input
, EsFmtIsTeletext( &es
->fmt
) ? es
->i_id
: -1 );
1779 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1781 es_out_sys_t
*p_sys
= out
->p_sys
;
1782 input_thread_t
*p_input
= p_sys
->p_input
;
1784 if( !EsIsSelected( es
) )
1786 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->i_id
);
1792 if( es
->p_master
->p_dec
)
1794 int i_channel
= EsOutGetClosedCaptionsChannel( es
->fmt
.i_original_fourcc
);
1795 if( i_channel
!= -1 )
1796 input_DecoderSetCcState( es
->p_master
->p_dec
, false, i_channel
);
1801 const int i_spu_id
= var_GetInteger( p_input
, "spu-es");
1803 for( i
= 0; i
< 4; i
++ )
1805 if( !es
->pb_cc_present
[i
] || !es
->pp_cc_es
[i
] )
1808 if( i_spu_id
== es
->pp_cc_es
[i
]->i_id
)
1810 /* Force unselection of the CC */
1811 input_SendEventEsSelect( p_input
, SPU_ES
, -1 );
1813 EsOutDel( out
, es
->pp_cc_es
[i
] );
1815 es
->pb_cc_present
[i
] = false;
1817 EsDestroyDecoder( out
, es
);
1823 /* Mark it as unselected */
1824 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, -1 );
1825 if( EsFmtIsTeletext( &es
->fmt
) )
1826 input_SendEventTeletextSelect( p_input
, -1 );
1830 * Select an ES given the current mode
1831 * XXX: you need to take a the lock before (stream.stream_lock)
1833 * \param out The es_out structure
1834 * \param es es_out_id structure
1835 * \param b_force ...
1838 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1840 es_out_sys_t
*p_sys
= out
->p_sys
;
1841 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
1843 if( !p_sys
->b_active
||
1844 ( !b_force
&& es
->fmt
.i_priority
< ES_PRIORITY_SELECTABLE_MIN
) )
1849 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
1851 if( !EsIsSelected( es
) )
1852 EsSelect( out
, es
);
1854 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
1856 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
1861 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1863 prgm
= strtok_r( NULL
, ",", &buf
) )
1865 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
1867 if( !EsIsSelected( es
) )
1868 EsSelect( out
, es
);
1875 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1877 const es_out_id_t
*wanted_es
= NULL
;
1879 if( es
->p_pgrm
!= p_sys
->p_pgrm
|| !p_esprops
)
1882 /* user designated by ID ES have higher prio than everything */
1883 if ( p_esprops
->i_id
>= 0 )
1885 if( es
->i_id
== p_esprops
->i_id
)
1889 else if( p_esprops
->i_channel
>= 0 )
1891 if( p_esprops
->i_channel
== es
->i_channel
)
1894 else if( p_esprops
->ppsz_language
)
1896 /* If not deactivated */
1897 const int i_stop_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
, "none" );
1899 int current_es_idx
= ( p_esprops
->p_main_es
== NULL
) ? -1 :
1900 LanguageArrayIndex( p_esprops
->ppsz_language
,
1901 p_esprops
->p_main_es
->psz_language_code
);
1902 int es_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
,
1903 es
->psz_language_code
);
1904 if( es_idx
>= 0 && (i_stop_idx
< 0 || i_stop_idx
> es_idx
) )
1906 /* Only select the language if it's in the list */
1907 if( p_esprops
->p_main_es
== NULL
||
1908 current_es_idx
< 0 || /* current es was not selected by lang prefs */
1909 es_idx
< current_es_idx
|| /* current es has lower lang prio */
1910 ( es_idx
== current_es_idx
&& /* lang is same, but es has higher prio */
1911 p_esprops
->p_main_es
->fmt
.i_priority
< es
->fmt
.i_priority
) )
1916 /* We did not find a language matching our prefs */
1917 else if( i_stop_idx
< 0 ) /* If not fallback disabled by 'none' */
1919 /* Select if asked by demuxer */
1920 if( current_es_idx
< 0 ) /* No es is currently selected by lang pref */
1922 /* If demux has specified a track */
1923 if( p_esprops
->i_demux_id
>= 0 && es
->i_id
== p_esprops
->i_demux_id
)
1927 /* Otherwise, fallback by priority */
1928 else if( p_esprops
->p_main_es
== NULL
||
1929 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
1931 if( p_esprops
->b_autoselect
)
1939 /* If there is no user preference, select the default subtitle
1940 * or adapt by ES priority */
1941 else if( p_esprops
->i_demux_id
>= 0 && es
->i_id
== p_esprops
->i_demux_id
)
1945 else if( p_esprops
->p_main_es
== NULL
||
1946 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
1948 if( p_esprops
->b_autoselect
)
1952 if( wanted_es
== es
&& !EsIsSelected( es
) )
1953 EsSelect( out
, es
);
1956 /* FIXME TODO handle priority here */
1957 if( p_esprops
&& EsIsSelected( es
) )
1959 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1961 if( p_esprops
->e_policy
== ES_OUT_ES_POLICY_EXCLUSIVE
&&
1962 p_esprops
->p_main_es
&&
1963 p_esprops
->p_main_es
!= es
)
1965 EsUnselect( out
, p_esprops
->p_main_es
, false );
1967 p_esprops
->p_main_es
= es
;
1973 * Send a block for the given es_out
1975 * \param out the es_out to send from
1976 * \param es the es_out_id
1977 * \param p_block the data block to send
1979 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
1981 es_out_sys_t
*p_sys
= out
->p_sys
;
1982 input_thread_t
*p_input
= p_sys
->p_input
;
1984 if( libvlc_stats( p_input
) )
1988 vlc_mutex_lock( &input_priv(p_input
)->counters
.counters_lock
);
1989 stats_Update( input_priv(p_input
)->counters
.p_demux_read
,
1990 p_block
->i_buffer
, &i_total
);
1991 stats_Update( input_priv(p_input
)->counters
.p_demux_bitrate
, i_total
, NULL
);
1993 /* Update number of corrupted data packats */
1994 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
1996 stats_Update( input_priv(p_input
)->counters
.p_demux_corrupted
, 1, NULL
);
1998 /* Update number of discontinuities */
1999 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
2001 stats_Update( input_priv(p_input
)->counters
.p_demux_discontinuity
, 1, NULL
);
2003 vlc_mutex_unlock( &input_priv(p_input
)->counters
.counters_lock
);
2006 vlc_mutex_lock( &p_sys
->lock
);
2008 /* Mark preroll blocks */
2009 if( p_sys
->i_preroll_end
>= 0 )
2011 int64_t i_date
= p_block
->i_pts
;
2012 if( p_block
->i_pts
<= VLC_TS_INVALID
)
2013 i_date
= p_block
->i_dts
;
2015 if( i_date
< p_sys
->i_preroll_end
)
2016 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
2021 block_Release( p_block
);
2022 vlc_mutex_unlock( &p_sys
->lock
);
2026 /* Check for sout mode */
2027 if( input_priv(p_input
)->p_sout
)
2029 /* FIXME review this, proper lock may be missing */
2030 if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
> 0 &&
2031 input_priv(p_input
)->b_out_pace_control
)
2033 msg_Dbg( p_input
, "switching to sync mode" );
2034 input_priv(p_input
)->b_out_pace_control
= false;
2036 else if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
<= 0 &&
2037 !input_priv(p_input
)->b_out_pace_control
)
2039 msg_Dbg( p_input
, "switching to async mode" );
2040 input_priv(p_input
)->b_out_pace_control
= true;
2045 if( es
->p_dec_record
)
2047 block_t
*p_dup
= block_Duplicate( p_block
);
2049 input_DecoderDecode( es
->p_dec_record
, p_dup
,
2050 input_priv(p_input
)->b_out_pace_control
);
2052 input_DecoderDecode( es
->p_dec
, p_block
,
2053 input_priv(p_input
)->b_out_pace_control
);
2055 es_format_t fmt_dsc
;
2056 vlc_meta_t
*p_meta_dsc
;
2057 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
2059 EsOutUpdateInfo( out
, es
, &fmt_dsc
, p_meta_dsc
);
2061 es_format_Clean( &fmt_dsc
);
2063 vlc_meta_Delete( p_meta_dsc
);
2066 /* Check CC status */
2069 input_DecoderIsCcPresent( es
->p_dec
, pb_cc
);
2070 for( int i
= 0; i
< 4; i
++ )
2074 if( es
->pb_cc_present
[i
] || !pb_cc
[i
] )
2076 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, es
->i_id
);
2078 es_format_Init( &fmt
, SPU_ES
, EsOutFourccClosedCaptions
[i
] );
2079 fmt
.i_group
= es
->fmt
.i_group
;
2080 if( asprintf( &fmt
.psz_description
,
2081 _("Closed captions %u"), 1 + i
) == -1 )
2082 fmt
.psz_description
= NULL
;
2083 es
->pp_cc_es
[i
] = EsOutAddSlave( out
, &fmt
, es
);
2084 es_format_Clean( &fmt
);
2087 es
->pb_cc_present
[i
] = true;
2089 /* Enable if user specified on command line */
2090 if (p_sys
->sub
.i_channel
== i
)
2091 EsOutSelect(out
, es
->pp_cc_es
[i
], true);
2094 vlc_mutex_unlock( &p_sys
->lock
);
2099 /*****************************************************************************
2101 *****************************************************************************/
2102 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2104 es_out_sys_t
*p_sys
= out
->p_sys
;
2105 bool b_reselect
= false;
2108 vlc_mutex_lock( &p_sys
->lock
);
2110 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
2112 /* We don't try to reselect */
2114 { /* FIXME: This might hold the ES output caller (i.e. the demux), and
2115 * the corresponding thread (typically the input thread), for a little
2116 * bit too long if the ES is deleted in the middle of a stream. */
2117 while( !input_Stopped(p_sys
->p_input
) && !p_sys
->b_buffering
)
2119 if( input_DecoderIsEmpty( es
->p_dec
) &&
2120 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2122 /* FIXME there should be a way to have auto deleted es, but there will be
2123 * a problem when another codec of the same type is created (mainly video) */
2126 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2129 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2130 EsOutESVarUpdate( out
, es
, true );
2132 EsDeleteInfo( out
, es
);
2134 TAB_REMOVE( p_sys
->i_es
, p_sys
->es
, es
);
2136 /* Update program */
2138 if( es
->p_pgrm
->i_es
== 0 )
2139 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2141 if( es
->b_scrambled
)
2142 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2147 if( p_esprops
->p_main_es
== es
)
2150 p_esprops
->p_main_es
= NULL
;
2152 p_esprops
->i_count
--;
2155 /* Re-select another track when needed */
2158 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2160 if( es
->fmt
.i_cat
== p_sys
->es
[i
]->fmt
.i_cat
)
2161 EsOutSelect( out
, p_sys
->es
[i
], false );
2165 free( es
->psz_language
);
2166 free( es
->psz_language_code
);
2168 es_format_Clean( &es
->fmt
);
2170 vlc_mutex_unlock( &p_sys
->lock
);
2176 * Control query handler
2178 * \param out the es_out to control
2179 * \param i_query A es_out query as defined in include/ninput.h
2180 * \param args a variable list of arguments for the query
2181 * \return VLC_SUCCESS or an error code
2183 static int EsOutControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2185 es_out_sys_t
*p_sys
= out
->p_sys
;
2189 case ES_OUT_SET_ES_STATE
:
2191 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2192 bool b
= va_arg( args
, int );
2193 if( b
&& !EsIsSelected( es
) )
2195 EsSelect( out
, es
);
2196 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2198 else if( !b
&& EsIsSelected( es
) )
2200 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2206 case ES_OUT_GET_ES_STATE
:
2208 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2209 bool *pb
= va_arg( args
, bool * );
2211 *pb
= EsIsSelected( es
);
2215 case ES_OUT_SET_ES_CAT_POLICY
:
2217 enum es_format_category_e i_cat
= va_arg( args
, enum es_format_category_e
);
2218 enum es_out_policy_e i_pol
= va_arg( args
, enum es_out_policy_e
);
2219 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, i_cat
);
2220 if( p_esprops
== NULL
)
2221 return VLC_EGENERIC
;
2222 p_esprops
->e_policy
= i_pol
;
2226 case ES_OUT_GET_GROUP_FORCED
:
2228 int *pi_group
= va_arg( args
, int * );
2229 *pi_group
= p_sys
->i_group_id
;
2233 case ES_OUT_SET_MODE
:
2235 const int i_mode
= va_arg( args
, int );
2236 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2237 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2238 i_mode
== ES_OUT_MODE_END
);
2240 if( i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& p_sys
->i_es
> 0 )
2242 /* XXX Terminate vout if there are tracks but no video one.
2243 * This one is not mandatory but is he earliest place where it
2246 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2248 es_out_id_t
*p_es
= p_sys
->es
[i
];
2249 if( p_es
->fmt
.i_cat
== VIDEO_ES
)
2252 if( i
>= p_sys
->i_es
)
2253 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2255 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2256 p_sys
->i_mode
= i_mode
;
2258 /* Reapply policy mode */
2259 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2261 if( EsIsSelected( p_sys
->es
[i
] ) )
2262 EsUnselect( out
, p_sys
->es
[i
],
2263 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2265 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2266 EsOutSelect( out
, p_sys
->es
[i
], false );
2267 if( i_mode
== ES_OUT_MODE_END
)
2268 EsOutTerminate( out
);
2273 case ES_OUT_RESTART_ES
:
2275 #define IGNORE_ES NAV_ES
2276 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2278 enum es_format_category_e i_cat
;
2281 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2283 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2285 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2290 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2292 if( i_cat
== IGNORE_ES
)
2294 if( es
== p_sys
->es
[i
] )
2296 if( i_query
== ES_OUT_RESTART_ES
&& p_sys
->es
[i
]->p_dec
)
2298 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2299 EsCreateDecoder( out
, p_sys
->es
[i
] );
2301 else if( i_query
== ES_OUT_SET_ES
)
2303 EsOutSelect( out
, es
, true );
2310 if( i_cat
== UNKNOWN_ES
|| p_sys
->es
[i
]->fmt
.i_cat
== i_cat
)
2312 if( EsIsSelected( p_sys
->es
[i
] ) )
2314 if( i_query
== ES_OUT_RESTART_ES
)
2316 if( p_sys
->es
[i
]->p_dec
)
2318 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2319 EsCreateDecoder( out
, p_sys
->es
[i
] );
2324 EsUnselect( out
, p_sys
->es
[i
],
2325 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2334 case ES_OUT_SET_ES_DEFAULT
:
2336 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2340 /*p_sys->i_default_video_id = -1;*/
2341 /*p_sys->i_default_audio_id = -1;*/
2342 p_sys
->sub
.i_demux_id
= -1;
2344 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+AUDIO_ES
) )
2346 /*p_sys->i_default_video_id = -1;*/
2348 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+VIDEO_ES
) )
2350 /*p_sys->i_default_audio_id = -1;*/
2352 else if( es
== (es_out_id_t
*)((uint8_t*)NULL
+SPU_ES
) )
2354 p_sys
->sub
.i_demux_id
= -1;
2358 /*if( es->fmt.i_cat == VIDEO_ES )
2359 p_sys->i_default_video_id = es->i_id;
2361 if( es->fmt.i_cat == AUDIO_ES )
2362 p_sys->i_default_audio_id = es->i_id;
2364 if( es
->fmt
.i_cat
== SPU_ES
)
2365 p_sys
->sub
.i_demux_id
= es
->i_id
;
2370 case ES_OUT_SET_PCR
:
2371 case ES_OUT_SET_GROUP_PCR
:
2373 es_out_pgrm_t
*p_pgrm
= NULL
;
2377 /* Search program */
2378 if( i_query
== ES_OUT_SET_PCR
)
2380 p_pgrm
= p_sys
->p_pgrm
;
2382 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2386 i_group
= va_arg( args
, int );
2387 p_pgrm
= EsOutProgramFind( out
, i_group
);
2390 return VLC_EGENERIC
;
2392 i_pcr
= va_arg( args
, int64_t );
2393 if( i_pcr
<= VLC_TS_INVALID
)
2395 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2396 return VLC_EGENERIC
;
2399 /* TODO do not use mdate() but proper stream acquisition date */
2401 input_clock_Update( p_pgrm
->p_clock
, VLC_OBJECT(p_sys
->p_input
),
2403 input_priv(p_sys
->p_input
)->b_can_pace_control
|| p_sys
->b_buffering
,
2404 EsOutIsExtraBufferingAllowed( out
),
2407 if( !p_sys
->p_pgrm
)
2410 if( p_sys
->b_buffering
)
2412 /* Check buffering state on master clock update */
2413 EsOutDecodersStopBuffering( out
, false );
2415 else if( p_pgrm
== p_sys
->p_pgrm
)
2417 if( b_late
&& ( !input_priv(p_sys
->p_input
)->p_sout
||
2418 !input_priv(p_sys
->p_input
)->b_out_pace_control
) )
2420 const mtime_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2421 mtime_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_clock
);
2423 /* Avoid dangerously high value */
2424 const mtime_t i_jitter_max
= INT64_C(1000) * var_InheritInteger( p_sys
->p_input
, "clock-jitter" );
2425 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2427 msg_Err( p_sys
->p_input
,
2428 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2429 (int)(i_pts_delay
- i_pts_delay_base
) / 1000 );
2430 i_pts_delay
= p_sys
->i_pts_delay
;
2433 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
2434 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
2438 msg_Err( p_sys
->p_input
,
2439 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2440 (int)(i_pts_delay
/1000) );
2442 /* Force a rebufferization when we are too late */
2444 /* It is not really good, as we throw away already buffered data
2445 * TODO have a mean to correctly reenter bufferization */
2446 es_out_Control( out
, ES_OUT_RESET_PCR
);
2449 es_out_SetJitter( out
, i_pts_delay_base
, i_pts_delay
- i_pts_delay_base
, p_sys
->i_cr_average
);
2455 case ES_OUT_RESET_PCR
:
2456 msg_Dbg( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2457 EsOutChangePosition( out
);
2460 case ES_OUT_SET_GROUP
:
2462 int i
= va_arg( args
, int );
2463 for( int j
= 0; j
< p_sys
->i_pgrm
; j
++ )
2465 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[j
];
2466 if( p_pgrm
->i_id
== i
)
2468 EsOutProgramSelect( out
, p_pgrm
);
2472 return VLC_EGENERIC
;
2475 case ES_OUT_SET_ES_FMT
:
2477 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2478 * to update the p_extra data */
2479 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2480 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2482 return VLC_EGENERIC
;
2484 es_format_Clean( &es
->fmt
);
2485 es_format_Copy( &es
->fmt
, p_fmt
);
2489 EsDestroyDecoder( out
, es
);
2490 EsCreateDecoder( out
, es
);
2496 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2498 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2499 bool b_scrambled
= (bool)va_arg( args
, int );
2501 if( !es
->b_scrambled
!= !b_scrambled
)
2503 es
->b_scrambled
= b_scrambled
;
2504 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2509 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2511 const int64_t i_date
= va_arg( args
, int64_t );
2514 return VLC_EGENERIC
;
2516 p_sys
->i_preroll_end
= i_date
;
2520 case ES_OUT_SET_GROUP_META
:
2522 int i_group
= va_arg( args
, int );
2523 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2525 EsOutProgramMeta( out
, i_group
, p_meta
);
2528 case ES_OUT_SET_GROUP_EPG
:
2530 int i_group
= va_arg( args
, int );
2531 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2533 EsOutProgramEpg( out
, i_group
, p_epg
);
2536 case ES_OUT_SET_GROUP_EPG_EVENT
:
2538 int i_group
= va_arg( args
, int );
2539 const vlc_epg_event_t
*p_evt
= va_arg( args
, const vlc_epg_event_t
* );
2541 EsOutProgramEpgEvent( out
, i_group
, p_evt
);
2544 case ES_OUT_SET_EPG_TIME
:
2546 int64_t i64
= va_arg( args
, int64_t );
2548 EsOutEpgTime( out
, i64
);
2552 case ES_OUT_DEL_GROUP
:
2554 int i_group
= va_arg( args
, int );
2556 return EsOutProgramDel( out
, i_group
);
2559 case ES_OUT_SET_META
:
2561 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2563 EsOutGlobalMeta( out
, p_meta
);
2567 case ES_OUT_GET_WAKE_UP
:
2569 mtime_t
*pi_wakeup
= va_arg( args
, mtime_t
* );
2570 *pi_wakeup
= EsOutGetWakeup( out
);
2574 case ES_OUT_SET_ES_BY_ID
:
2575 case ES_OUT_RESTART_ES_BY_ID
:
2576 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2578 const int i_id
= va_arg( args
, int );
2579 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2580 int i_new_query
= 0;
2584 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
; break;
2585 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2586 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2588 vlc_assert_unreachable();
2590 /* TODO if the lock is made non recursive it should be changed */
2591 int i_ret
= es_out_Control( out
, i_new_query
, p_es
);
2593 /* Clean up vout after user action (in active mode only).
2594 * FIXME it does not work well with multiple video windows */
2595 if( p_sys
->b_active
)
2596 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2600 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2602 const int i_id
= va_arg( args
, int );
2603 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2605 return VLC_EGENERIC
;
2607 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2608 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2609 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
2613 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2614 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2628 case ES_OUT_GET_BUFFERING
:
2630 bool *pb
= va_arg( args
, bool* );
2631 *pb
= p_sys
->b_buffering
;
2635 case ES_OUT_GET_EMPTY
:
2637 bool *pb
= va_arg( args
, bool* );
2638 *pb
= EsOutDecodersIsEmpty( out
);
2642 case ES_OUT_SET_DELAY
:
2644 const int i_cat
= va_arg( args
, int );
2645 const mtime_t i_delay
= va_arg( args
, mtime_t
);
2646 EsOutSetDelay( out
, i_cat
, i_delay
);
2650 case ES_OUT_SET_RECORD_STATE
:
2652 bool b
= va_arg( args
, int );
2653 return EsOutSetRecord( out
, b
);
2656 case ES_OUT_SET_PAUSE_STATE
:
2658 const bool b_source_paused
= (bool)va_arg( args
, int );
2659 const bool b_paused
= (bool)va_arg( args
, int );
2660 const mtime_t i_date
= va_arg( args
, mtime_t
);
2662 assert( !b_source_paused
== !b_paused
);
2663 EsOutChangePause( out
, b_paused
, i_date
);
2668 case ES_OUT_SET_RATE
:
2670 const int i_src_rate
= va_arg( args
, int );
2671 const int i_rate
= va_arg( args
, int );
2673 assert( i_src_rate
== i_rate
);
2674 EsOutChangeRate( out
, i_rate
);
2679 case ES_OUT_SET_TIME
:
2681 const mtime_t i_date
= va_arg( args
, mtime_t
);
2683 assert( i_date
== -1 );
2684 EsOutChangePosition( out
);
2689 case ES_OUT_SET_FRAME_NEXT
:
2690 EsOutFrameNext( out
);
2693 case ES_OUT_SET_TIMES
:
2695 double f_position
= va_arg( args
, double );
2696 mtime_t i_time
= va_arg( args
, mtime_t
);
2697 mtime_t i_length
= va_arg( args
, mtime_t
);
2699 input_SendEventLength( p_sys
->p_input
, i_length
);
2701 if( !p_sys
->b_buffering
)
2705 /* Fix for buffering delay */
2706 if( !input_priv(p_sys
->p_input
)->p_sout
||
2707 !input_priv(p_sys
->p_input
)->b_out_pace_control
)
2708 i_delay
= EsOutGetBuffering( out
);
2717 f_position
-= (double)i_delay
/ i_length
;
2718 if( f_position
< 0 )
2721 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
2725 case ES_OUT_SET_JITTER
:
2727 mtime_t i_pts_delay
= va_arg( args
, mtime_t
);
2728 mtime_t i_pts_jitter
= va_arg( args
, mtime_t
);
2729 int i_cr_average
= va_arg( args
, int );
2731 bool b_change_clock
=
2732 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
2733 i_cr_average
!= p_sys
->i_cr_average
;
2735 assert( i_pts_jitter
>= 0 );
2736 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
2737 p_sys
->i_pts_jitter
= i_pts_jitter
;
2738 p_sys
->i_cr_average
= i_cr_average
;
2740 for( int i
= 0; i
< p_sys
->i_pgrm
&& b_change_clock
; i
++ )
2741 input_clock_SetJitter( p_sys
->pgrm
[i
]->p_clock
,
2742 i_pts_delay
+ i_pts_jitter
, i_cr_average
);
2746 case ES_OUT_GET_PCR_SYSTEM
:
2748 if( p_sys
->b_buffering
)
2749 return VLC_EGENERIC
;
2751 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2753 return VLC_EGENERIC
;
2755 mtime_t
*pi_system
= va_arg( args
, mtime_t
*);
2756 mtime_t
*pi_delay
= va_arg( args
, mtime_t
*);
2757 input_clock_GetSystemOrigin( p_pgrm
->p_clock
, pi_system
, pi_delay
);
2761 case ES_OUT_MODIFY_PCR_SYSTEM
:
2763 if( p_sys
->b_buffering
)
2764 return VLC_EGENERIC
;
2766 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2768 return VLC_EGENERIC
;
2770 const bool b_absolute
= va_arg( args
, int );
2771 const mtime_t i_system
= va_arg( args
, mtime_t
);
2772 input_clock_ChangeSystemOrigin( p_pgrm
->p_clock
, b_absolute
, i_system
);
2775 case ES_OUT_SET_EOS
:
2777 for (int i
= 0; i
< p_sys
->i_es
; i
++) {
2778 es_out_id_t
*id
= p_sys
->es
[i
];
2779 if (id
->p_dec
!= NULL
)
2780 input_DecoderDrain(id
->p_dec
);
2785 case ES_OUT_POST_SUBNODE
:
2787 input_item_node_t
*node
= va_arg(args
, input_item_node_t
*);
2788 input_item_node_PostAndDelete(node
);
2793 msg_Err( p_sys
->p_input
, "unknown query 0x%x in %s", i_query
,
2795 return VLC_EGENERIC
;
2798 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
2800 es_out_sys_t
*p_sys
= out
->p_sys
;
2803 vlc_mutex_lock( &p_sys
->lock
);
2804 i_ret
= EsOutControlLocked( out
, i_query
, args
);
2805 vlc_mutex_unlock( &p_sys
->lock
);
2810 /****************************************************************************
2811 * LanguageGetName: try to expend iso639 into plain name
2812 ****************************************************************************/
2813 static char *LanguageGetName( const char *psz_code
)
2815 const iso639_lang_t
*pl
;
2817 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
2819 return strdup( "" );
2822 if( strlen( psz_code
) == 2 )
2824 pl
= GetLang_1( psz_code
);
2826 else if( strlen( psz_code
) == 3 )
2828 pl
= GetLang_2B( psz_code
);
2829 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2831 pl
= GetLang_2T( psz_code
);
2836 char *lang
= LanguageGetCode( psz_code
);
2837 pl
= GetLang_1( lang
);
2841 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2843 return strdup( psz_code
);
2847 return strdup( vlc_gettext(pl
->psz_eng_name
) );
2851 /* Get a 2 char code */
2852 static char *LanguageGetCode( const char *psz_lang
)
2854 const iso639_lang_t
*pl
;
2856 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
2857 return strdup("??");
2859 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
2861 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
2862 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
2863 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
2864 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
2865 return strdup( pl
->psz_iso639_1
);
2868 return strdup("??");
2871 static char **LanguageSplit( const char *psz_langs
)
2878 if( psz_langs
== NULL
) return NULL
;
2880 psz_parser
= psz_dup
= strdup(psz_langs
);
2882 while( psz_parser
&& *psz_parser
)
2887 psz
= strchr(psz_parser
, ',' );
2888 if( psz
) *psz
++ = '\0';
2890 if( !strcmp( psz_parser
, "any" ) )
2892 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2894 else if( !strcmp( psz_parser
, "none" ) )
2896 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
2900 psz_code
= LanguageGetCode( psz_parser
);
2901 if( strcmp( psz_code
, "??" ) )
2903 TAB_APPEND( i_psz
, ppsz
, psz_code
);
2916 TAB_APPEND( i_psz
, ppsz
, NULL
);
2923 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
)
2925 if( !ppsz_langs
|| !psz_lang
)
2928 for( int i
= 0; ppsz_langs
[i
]; i
++ )
2930 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
2931 ( !strcasecmp( ppsz_langs
[i
], "any" ) && strcasecmp( psz_lang
, "none") ) )
2933 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
2940 /****************************************************************************
2942 * - add meta info to the playlist item
2943 ****************************************************************************/
2944 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
, const vlc_meta_t
*p_meta
)
2946 es_out_sys_t
*p_sys
= out
->p_sys
;
2947 input_thread_t
*p_input
= p_sys
->p_input
;
2948 const es_format_t
*p_fmt_es
= &es
->fmt
;
2951 if( es
->fmt
.i_cat
== fmt
->i_cat
)
2953 es_format_t update
= *fmt
;
2954 update
.i_id
= es
->i_meta_id
;
2955 update
.i_codec
= es
->fmt
.i_codec
;
2956 update
.i_original_fourcc
= es
->fmt
.i_original_fourcc
;
2958 /* Update infos that could have been lost by the decoder (no need to
2959 * dup them since input_item_UpdateTracksInfo() will do it). */
2960 if (update
.psz_language
== NULL
)
2961 update
.psz_language
= es
->fmt
.psz_language
;
2962 if (update
.psz_description
== NULL
)
2963 update
.psz_description
= es
->fmt
.psz_description
;
2964 if (update
.i_cat
== SPU_ES
)
2966 if (update
.subs
.psz_encoding
== NULL
)
2967 update
.subs
.psz_encoding
= es
->fmt
.subs
.psz_encoding
;
2968 if (update
.subs
.p_style
== NULL
)
2969 update
.subs
.p_style
= es
->fmt
.subs
.p_style
;
2971 if (update
.i_extra_languages
== 0)
2973 assert(update
.p_extra_languages
== NULL
);
2974 update
.i_extra_languages
= es
->fmt
.i_extra_languages
;
2975 update
.p_extra_languages
= es
->fmt
.p_extra_languages
;
2978 /* No need to update codec specific data */
2980 update
.p_extra
= NULL
;
2982 input_item_UpdateTracksInfo(input_GetItem(p_input
), &update
);
2985 /* Create category */
2986 char* psz_cat
= EsInfoCategoryName( es
);
2988 if( unlikely( !psz_cat
) )
2991 info_category_t
* p_cat
= info_category_New( psz_cat
);
2995 if( unlikely( !p_cat
) )
2998 /* Add information */
2999 const char *psz_type
;
3000 switch( fmt
->i_cat
)
3003 psz_type
= _("Audio");
3006 psz_type
= _("Video");
3009 psz_type
= _("Subtitle");
3017 info_category_AddInfo( p_cat
, _("Type"), "%s", psz_type
);
3019 if( es
->i_meta_id
!= es
->i_id
)
3020 info_category_AddInfo( p_cat
, _("Original ID"),
3023 const char *psz_codec_description
=
3024 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, p_fmt_es
->i_codec
);
3025 const vlc_fourcc_t i_codec_fourcc
= ( p_fmt_es
->i_original_fourcc
)?
3026 p_fmt_es
->i_original_fourcc
: p_fmt_es
->i_codec
;
3027 if( psz_codec_description
&& *psz_codec_description
)
3028 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
3029 psz_codec_description
, (char*)&i_codec_fourcc
);
3030 else if ( i_codec_fourcc
!= VLC_FOURCC(0,0,0,0) )
3031 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
3032 (char*)&i_codec_fourcc
);
3034 if( es
->psz_language
&& *es
->psz_language
)
3035 info_category_AddInfo( p_cat
, _("Language"), "%s",
3037 if( fmt
->psz_description
&& *fmt
->psz_description
)
3038 info_category_AddInfo( p_cat
, _("Description"), "%s",
3039 fmt
->psz_description
);
3041 switch( fmt
->i_cat
)
3044 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
3046 if( fmt
->audio
.i_physical_channels
)
3047 info_category_AddInfo( p_cat
, _("Channels"), "%s",
3048 _( aout_FormatPrintChannels( &fmt
->audio
) ) );
3050 if( fmt
->audio
.i_rate
!= 0 )
3052 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
3053 fmt
->audio
.i_rate
);
3054 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3055 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
3058 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
3059 if( i_bitspersample
== 0 )
3060 i_bitspersample
= aout_BitsPerSample( p_fmt_es
->i_codec
);
3061 if( i_bitspersample
!= 0 )
3062 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
3065 if( fmt
->i_bitrate
!= 0 )
3067 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
3068 fmt
->i_bitrate
/ 1000 );
3069 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3070 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
3072 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
3074 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
3075 if( !p_rg
->pb_gain
[i
] )
3077 const char *psz_name
;
3078 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
3079 psz_name
= _("Track replay gain");
3081 psz_name
= _("Album replay gain");
3082 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
3088 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
3090 if( fmt
->video
.i_visible_width
> 0 &&
3091 fmt
->video
.i_visible_height
> 0 )
3092 info_category_AddInfo( p_cat
, _("Video resolution"), "%ux%u",
3093 fmt
->video
.i_visible_width
,
3094 fmt
->video
.i_visible_height
);
3096 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
3097 info_category_AddInfo( p_cat
, _("Buffer dimensions"), "%ux%u",
3098 fmt
->video
.i_width
, fmt
->video
.i_height
);
3100 if( fmt
->video
.i_frame_rate
> 0 &&
3101 fmt
->video
.i_frame_rate_base
> 0 )
3103 div
= lldiv( (float)fmt
->video
.i_frame_rate
/
3104 fmt
->video
.i_frame_rate_base
* 1000000,
3107 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
".%06u",
3108 div
.quot
, (unsigned int )div
.rem
);
3110 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
,
3113 if( fmt
->i_codec
!= p_fmt_es
->i_codec
)
3115 const char *psz_chroma_description
=
3116 vlc_fourcc_GetDescription( VIDEO_ES
, fmt
->i_codec
);
3117 if( psz_chroma_description
)
3118 info_category_AddInfo( p_cat
, _("Decoded format"), "%s",
3119 psz_chroma_description
);
3122 static const char orient_names
[][13] = {
3123 N_("Top left"), N_("Left top"),
3124 N_("Right bottom"), N_("Top right"),
3125 N_("Bottom left"), N_("Bottom right"),
3126 N_("Left bottom"), N_("Right top"),
3128 info_category_AddInfo( p_cat
, _("Orientation"), "%s",
3129 _(orient_names
[fmt
->video
.orientation
]) );
3131 if( fmt
->video
.primaries
!= COLOR_PRIMARIES_UNDEF
)
3133 static const char *primaries_names
[] = { N_("Undefined"),
3134 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3135 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3141 if( fmt
->video
.primaries
< ARRAY_SIZE(primaries_names
) )
3142 info_category_AddInfo( p_cat
, _("Color primaries"), "%s",
3143 _(primaries_names
[fmt
->video
.primaries
]) );
3145 if( fmt
->video
.transfer
!= TRANSFER_FUNC_UNDEF
)
3147 static const char *func_names
[] = { N_("Undefined"),
3152 "ITU-R BT.709, ITU-R BT.2020",
3157 if( fmt
->video
.transfer
< ARRAY_SIZE(func_names
) )
3158 info_category_AddInfo( p_cat
, _("Color transfer function"), "%s",
3159 _(func_names
[fmt
->video
.transfer
]) );
3161 if( fmt
->video
.space
!= COLOR_SPACE_UNDEF
)
3163 static const char *space_names
[] = { N_("Undefined"),
3168 static const char *range_names
[] = {
3169 N_("Limited Range"),
3172 if( fmt
->video
.space
< ARRAY_SIZE(space_names
) )
3173 info_category_AddInfo( p_cat
, _("Color space"), "%s %s",
3174 _(space_names
[fmt
->video
.space
]),
3175 _(range_names
[fmt
->video
.b_color_range_full
]) );
3177 if( fmt
->video
.chroma_location
!= CHROMA_LOCATION_UNDEF
)
3179 static const char *c_loc_names
[] = { N_("Undefined"),
3185 N_("Bottom Center"),
3187 info_category_AddInfo( p_cat
, _("Chroma location"), "%s",
3188 _(c_loc_names
[fmt
->video
.chroma_location
]) );
3190 if( fmt
->video
.projection_mode
!= PROJECTION_MODE_RECTANGULAR
)
3192 const char *psz_loc_name
= NULL
;
3193 switch (fmt
->video
.projection_mode
)
3195 case PROJECTION_MODE_RECTANGULAR
:
3196 psz_loc_name
= N_("Rectangular");
3198 case PROJECTION_MODE_EQUIRECTANGULAR
:
3199 psz_loc_name
= N_("Equirectangular");
3201 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
3202 psz_loc_name
= N_("Cubemap");
3205 vlc_assert_unreachable();
3208 info_category_AddInfo( p_cat
, _("Projection"), "%s", _(psz_loc_name
) );
3210 info_category_AddInfo( p_cat
, _("Yaw"), "%.2f",
3211 fmt
->video
.pose
.f_yaw_degrees
);
3212 info_category_AddInfo( p_cat
, _("Pitch"), "%.2f",
3213 fmt
->video
.pose
.f_pitch_degrees
);
3214 info_category_AddInfo( p_cat
, _("Roll"), "%.2f",
3215 fmt
->video
.pose
.f_roll_degrees
);
3216 info_category_AddInfo( p_cat
, _("Field of view"), "%.2f",
3217 fmt
->video
.pose
.f_fov_degrees
);
3219 if ( fmt
->video
.mastering
.max_luminance
)
3221 info_category_AddInfo( p_cat
, _("Max luminance"), "%.4f cd/m²",
3222 fmt
->video
.mastering
.max_luminance
/ 10000.f
);
3224 if ( fmt
->video
.mastering
.min_luminance
)
3226 info_category_AddInfo( p_cat
, _("Min luminance"), "%.4f cd/m²",
3227 fmt
->video
.mastering
.min_luminance
/ 10000.f
);
3229 if ( fmt
->video
.mastering
.primaries
[4] &&
3230 fmt
->video
.mastering
.primaries
[5] )
3232 float x
= (float)fmt
->video
.mastering
.primaries
[4] / 50000.f
;
3233 float y
= (float)fmt
->video
.mastering
.primaries
[5] / 50000.f
;
3234 info_category_AddInfo( p_cat
, _("Primary R"), "x=%.4f y=%.4f", x
, y
);
3236 if ( fmt
->video
.mastering
.primaries
[0] &&
3237 fmt
->video
.mastering
.primaries
[1] )
3239 float x
= (float)fmt
->video
.mastering
.primaries
[0] / 50000.f
;
3240 float y
= (float)fmt
->video
.mastering
.primaries
[1] / 50000.f
;
3241 info_category_AddInfo( p_cat
, _("Primary G"), "x=%.4f y=%.4f", x
, y
);
3243 if ( fmt
->video
.mastering
.primaries
[2] &&
3244 fmt
->video
.mastering
.primaries
[3] )
3246 float x
= (float)fmt
->video
.mastering
.primaries
[2] / 50000.f
;
3247 float y
= (float)fmt
->video
.mastering
.primaries
[3] / 50000.f
;
3248 info_category_AddInfo( p_cat
, _("Primary B"), "x=%.4f y=%.4f", x
, y
);
3250 if ( fmt
->video
.mastering
.white_point
[0] &&
3251 fmt
->video
.mastering
.white_point
[1] )
3253 float x
= (float)fmt
->video
.mastering
.white_point
[0] / 50000.f
;
3254 float y
= (float)fmt
->video
.mastering
.white_point
[1] / 50000.f
;
3255 info_category_AddInfo( p_cat
, _("White point"), "x=%.4f y=%.4f", x
, y
);
3257 if ( fmt
->video
.lighting
.MaxCLL
)
3259 info_category_AddInfo( p_cat
, _("MaxCLL"), "%d cd/m²",
3260 fmt
->video
.lighting
.MaxCLL
);
3262 if ( fmt
->video
.lighting
.MaxFALL
)
3264 info_category_AddInfo( p_cat
, _("MaxFALL"), "%d cd/m²",
3265 fmt
->video
.lighting
.MaxFALL
);
3270 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
3277 /* Append generic meta */
3280 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
3281 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
3283 char *psz_key
= ppsz_all_keys
[i
];
3284 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
3287 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
3288 vlc_gettext(psz_value
) );
3291 free( ppsz_all_keys
);
3294 input_Control( p_input
, INPUT_REPLACE_INFOS
, p_cat
);
3297 static void EsDeleteInfo( es_out_t
*out
, es_out_id_t
*es
)
3299 char* psz_info_category
;
3301 if( likely( psz_info_category
= EsInfoCategoryName( es
) ) )
3303 input_Control( out
->p_sys
->p_input
, INPUT_DEL_INFO
,
3304 psz_info_category
, NULL
);
3306 free( psz_info_category
);