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 */
99 uint64_t i_bitmap
; /* channels bitmap */
100 es_out_id_t
*pp_es
[64]; /* a max of 64 chans for CEA708 */
103 /* Field for CC track from a master video */
104 es_out_id_t
*p_master
;
106 /* ID for the meta data */
112 int i_count
; /* es count */
113 es_out_id_t
*p_main_es
; /* current main es */
114 enum es_out_policy_e e_policy
;
116 /* Parameters used for es selection */
117 bool b_autoselect
; /* if we want to select an es when no user prefs */
118 int i_id
; /* es id as set by es fmt.id */
119 int i_demux_id
; /* same as previous, demuxer set default value */
120 int i_channel
; /* es number in creation order */
121 char **ppsz_language
;
126 input_thread_t
*p_input
;
133 es_out_pgrm_t
**pgrm
;
134 es_out_pgrm_t
*p_pgrm
; /* Master program */
145 es_out_es_props_t video
, audio
, sub
;
147 /* es/group to select */
151 int64_t i_audio_delay
;
154 /* Clock configuration */
156 mtime_t i_pts_jitter
;
162 mtime_t i_pause_date
;
164 /* Current preroll */
165 mtime_t i_preroll_end
;
167 /* Used for buffering */
169 mtime_t i_buffering_extra_initial
;
170 mtime_t i_buffering_extra_stream
;
171 mtime_t i_buffering_extra_system
;
174 sout_instance_t
*p_sout_record
;
176 /* Used only to limit debugging output */
177 int i_prev_stream_level
;
180 static es_out_id_t
*EsOutAdd ( es_out_t
*, const es_format_t
* );
181 static int EsOutSend ( es_out_t
*, es_out_id_t
*, block_t
* );
182 static void EsOutDel ( es_out_t
*, es_out_id_t
* );
183 static int EsOutControl( es_out_t
*, int i_query
, va_list );
184 static void EsOutDelete ( es_out_t
* );
186 static void EsOutTerminate( es_out_t
* );
187 static void EsOutSelect( es_out_t
*, es_out_id_t
*es
, bool b_force
);
188 static void EsOutUpdateInfo( es_out_t
*, es_out_id_t
*es
, const es_format_t
*, const vlc_meta_t
* );
189 static int EsOutSetRecord( es_out_t
*, bool b_record
);
191 static bool EsIsSelected( es_out_id_t
*es
);
192 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
);
193 static void EsDeleteInfo( es_out_t
*, es_out_id_t
*es
);
194 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
);
195 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
);
196 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
197 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
);
198 static void EsOutProgramsChangeRate( es_out_t
*out
);
199 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
);
200 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
);
201 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_progmeta
);
203 static char *LanguageGetName( const char *psz_code
);
204 static char *LanguageGetCode( const char *psz_lang
);
205 static char **LanguageSplit( const char *psz_langs
);
206 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
);
208 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
);
209 static char *EsInfoCategoryName( es_out_id_t
* es
);
211 static inline int EsOutGetClosedCaptionsChannel( const es_format_t
*p_fmt
)
214 if( p_fmt
->i_codec
== VLC_CODEC_CEA608
&& p_fmt
->subs
.cc
.i_channel
< 4 )
215 i_channel
= p_fmt
->subs
.cc
.i_channel
;
216 else if( p_fmt
->i_codec
== VLC_CODEC_CEA708
&& p_fmt
->subs
.cc
.i_channel
< 64 )
217 i_channel
= p_fmt
->subs
.cc
.i_channel
;
222 static inline bool EsFmtIsTeletext( const es_format_t
*p_fmt
)
224 return p_fmt
->i_cat
== SPU_ES
&& p_fmt
->i_codec
== VLC_CODEC_TELETEXT
;
227 /*****************************************************************************
228 * Es category specific structs
229 *****************************************************************************/
230 static es_out_es_props_t
* GetPropsByCat( es_out_sys_t
*p_sys
, int i_cat
)
235 return &p_sys
->audio
;
239 return &p_sys
->video
;
244 static void EsOutPropsCleanup( es_out_es_props_t
*p_props
)
246 if( p_props
->ppsz_language
)
248 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
249 free( p_props
->ppsz_language
[i
] );
250 free( p_props
->ppsz_language
);
254 static void EsOutPropsInit( es_out_es_props_t
*p_props
,
256 input_thread_t
*p_input
,
257 enum es_out_policy_e e_default_policy
,
258 const char *psz_trackidvar
,
259 const char *psz_trackvar
,
260 const char *psz_langvar
,
261 const char *psz_debug
)
263 p_props
->e_policy
= e_default_policy
;
264 p_props
->i_count
= 0;
265 p_props
->b_autoselect
= autoselect
;
266 p_props
->i_id
= (psz_trackidvar
) ? var_GetInteger( p_input
, psz_trackidvar
): -1;
267 p_props
->i_channel
= (psz_trackvar
) ? var_GetInteger( p_input
, psz_trackvar
): -1;
268 p_props
->i_demux_id
= -1;
269 p_props
->p_main_es
= NULL
;
271 if( !input_priv(p_input
)->b_preparsing
&& psz_langvar
)
273 char *psz_string
= var_GetString( p_input
, psz_langvar
);
274 p_props
->ppsz_language
= LanguageSplit( psz_string
);
275 if( p_props
->ppsz_language
)
277 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
278 msg_Dbg( p_input
, "selected %s language[%d] %s",
279 psz_debug
, i
, p_props
->ppsz_language
[i
] );
285 /*****************************************************************************
287 *****************************************************************************/
288 es_out_t
*input_EsOutNew( input_thread_t
*p_input
, int i_rate
)
290 es_out_t
*out
= malloc( sizeof( *out
) );
294 es_out_sys_t
*p_sys
= calloc( 1, sizeof( *p_sys
) );
301 out
->pf_add
= EsOutAdd
;
302 out
->pf_send
= EsOutSend
;
303 out
->pf_del
= EsOutDel
;
304 out
->pf_control
= EsOutControl
;
305 out
->pf_destroy
= EsOutDelete
;
308 vlc_mutex_init_recursive( &p_sys
->lock
);
309 p_sys
->p_input
= p_input
;
311 p_sys
->b_active
= false;
312 p_sys
->i_mode
= ES_OUT_MODE_NONE
;
314 TAB_INIT( p_sys
->i_pgrm
, p_sys
->pgrm
);
316 TAB_INIT( p_sys
->i_es
, p_sys
->es
);
319 EsOutPropsInit( &p_sys
->video
, true, p_input
, ES_OUT_ES_POLICY_SIMULTANEOUS
,
320 NULL
, NULL
, NULL
, NULL
);
321 EsOutPropsInit( &p_sys
->audio
, true, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
322 "audio-track-id", "audio-track", "audio-language", "audio" );
323 EsOutPropsInit( &p_sys
->sub
, false, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
324 "sub-track-id", "sub-track", "sub-language", "sub" );
326 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
328 p_sys
->i_pause_date
= -1;
330 p_sys
->i_rate
= i_rate
;
332 p_sys
->b_buffering
= true;
333 p_sys
->i_preroll_end
= -1;
334 p_sys
->i_prev_stream_level
= -1;
339 /*****************************************************************************
341 *****************************************************************************/
342 static void EsOutDelete( es_out_t
*out
)
344 es_out_sys_t
*p_sys
= out
->p_sys
;
346 assert( !p_sys
->i_es
&& !p_sys
->i_pgrm
&& !p_sys
->p_pgrm
);
347 EsOutPropsCleanup( &p_sys
->audio
);
348 EsOutPropsCleanup( &p_sys
->sub
);
350 vlc_mutex_destroy( &p_sys
->lock
);
356 static void EsOutTerminate( es_out_t
*out
)
358 es_out_sys_t
*p_sys
= out
->p_sys
;
360 if( p_sys
->p_sout_record
)
361 EsOutSetRecord( out
, false );
363 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
365 if( p_sys
->es
[i
]->p_dec
)
366 input_DecoderDelete( p_sys
->es
[i
]->p_dec
);
368 free( p_sys
->es
[i
]->psz_language
);
369 free( p_sys
->es
[i
]->psz_language_code
);
370 es_format_Clean( &p_sys
->es
[i
]->fmt
);
372 free( p_sys
->es
[i
] );
374 TAB_CLEAN( p_sys
->i_es
, p_sys
->es
);
376 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
377 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
379 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[i
];
380 input_clock_Delete( p_pgrm
->p_clock
);
382 vlc_meta_Delete( p_pgrm
->p_meta
);
386 TAB_CLEAN( p_sys
->i_pgrm
, p_sys
->pgrm
);
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 mtime_t
EsOutGetWakeup( es_out_t
*out
)
396 es_out_sys_t
*p_sys
= out
->p_sys
;
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_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
)
421 /* Special HACK, -i_id is the cat of the stream */
422 return es_cat
- i_id
;
425 for( int i
= 0; i
< out
->p_sys
->i_es
; i
++ )
427 if( out
->p_sys
->es
[i
]->i_id
== i_id
)
428 return out
->p_sys
->es
[i
];
433 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
435 es_out_sys_t
*p_sys
= out
->p_sys
;
437 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
439 EsOutDecodersStopBuffering( out
, true );
440 if( p_sys
->b_buffering
)
444 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
446 es_out_id_t
*es
= p_sys
->es
[i
];
448 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
450 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
456 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, int64_t i_delay
)
458 es_out_sys_t
*p_sys
= out
->p_sys
;
460 if( i_cat
== AUDIO_ES
)
461 p_sys
->i_audio_delay
= i_delay
;
462 else if( i_cat
== SPU_ES
)
463 p_sys
->i_spu_delay
= i_delay
;
465 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
466 EsOutDecoderChangeDelay( out
, p_sys
->es
[i
] );
469 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
471 es_out_sys_t
*p_sys
= out
->p_sys
;
472 input_thread_t
*p_input
= p_sys
->p_input
;
474 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
478 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
481 if( var_CountChoices( p_input
, "video-es" ) )
482 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
483 else if( var_CountChoices( p_input
, "audio-es" ) )
484 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
486 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
489 char *psz_sout
= NULL
; // TODO conf
491 if( !psz_sout
&& psz_path
)
493 char *psz_file
= input_CreateFilename( p_input
, psz_path
, INPUT_RECORD_PREFIX
, NULL
);
496 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file
) < 0 )
507 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
511 if( !p_sys
->p_sout_record
)
514 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
516 es_out_id_t
*p_es
= p_sys
->es
[i
];
518 if( !p_es
->p_dec
|| p_es
->p_master
)
521 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, p_sys
->p_sout_record
);
522 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
523 input_DecoderStartWait( p_es
->p_dec_record
);
528 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
530 es_out_id_t
*p_es
= p_sys
->es
[i
];
532 if( !p_es
->p_dec_record
)
535 input_DecoderDelete( p_es
->p_dec_record
);
536 p_es
->p_dec_record
= NULL
;
539 sout_DeleteInstance( p_sys
->p_sout_record
);
541 p_sys
->p_sout_record
= NULL
;
546 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
548 es_out_sys_t
*p_sys
= out
->p_sys
;
550 /* XXX the order is important */
553 EsOutDecodersChangePause( out
, true, i_date
);
554 EsOutProgramChangePause( out
, true, i_date
);
558 if( p_sys
->i_buffering_extra_initial
> 0 )
560 mtime_t i_stream_start
;
561 mtime_t i_system_start
;
562 mtime_t i_stream_duration
;
563 mtime_t i_system_duration
;
565 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
566 &i_stream_start
, &i_system_start
,
567 &i_stream_duration
, &i_system_duration
);
570 /* FIXME pcr != exactly what wanted */
571 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
;
574 p_sys
->i_buffering_extra_initial
= 0;
575 p_sys
->i_buffering_extra_stream
= 0;
576 p_sys
->i_buffering_extra_system
= 0;
578 EsOutProgramChangePause( out
, false, i_date
);
579 EsOutDecodersChangePause( out
, false, i_date
);
581 EsOutProgramsChangeRate( out
);
583 p_sys
->b_paused
= b_paused
;
584 p_sys
->i_pause_date
= i_date
;
587 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
589 es_out_sys_t
*p_sys
= out
->p_sys
;
591 p_sys
->i_rate
= i_rate
;
592 EsOutProgramsChangeRate( out
);
595 static void EsOutChangePosition( es_out_t
*out
)
597 es_out_sys_t
*p_sys
= out
->p_sys
;
599 input_SendEventCache( p_sys
->p_input
, 0.0 );
601 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
603 es_out_id_t
*p_es
= p_sys
->es
[i
];
605 if( p_es
->p_dec
!= NULL
)
607 input_DecoderFlush( p_es
->p_dec
);
608 if( !p_sys
->b_buffering
)
610 input_DecoderStartWait( p_es
->p_dec
);
611 if( p_es
->p_dec_record
!= NULL
)
612 input_DecoderStartWait( p_es
->p_dec_record
);
617 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
618 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
620 p_sys
->b_buffering
= true;
621 p_sys
->i_buffering_extra_initial
= 0;
622 p_sys
->i_buffering_extra_stream
= 0;
623 p_sys
->i_buffering_extra_system
= 0;
624 p_sys
->i_preroll_end
= -1;
625 p_sys
->i_prev_stream_level
= -1;
630 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
632 es_out_sys_t
*p_sys
= out
->p_sys
;
634 mtime_t i_stream_start
;
635 mtime_t i_system_start
;
636 mtime_t i_stream_duration
;
637 mtime_t i_system_duration
;
638 if (input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
639 &i_stream_start
, &i_system_start
,
640 &i_stream_duration
, &i_system_duration
))
643 mtime_t i_preroll_duration
= 0;
644 if( p_sys
->i_preroll_end
>= 0 )
645 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
647 const mtime_t i_buffering_duration
= p_sys
->i_pts_delay
+
649 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
651 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
654 if (i_buffering_duration
== 0)
657 f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
658 input_SendEventCache( p_sys
->p_input
, f_level
);
660 int i_level
= (int)(100 * f_level
);
661 if( p_sys
->i_prev_stream_level
!= i_level
)
663 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", i_level
);
664 p_sys
->i_prev_stream_level
= i_level
;
669 input_SendEventCache( p_sys
->p_input
, 1.0 );
671 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
672 (int)(i_stream_duration
/1000), (int)(i_system_duration
/1000) );
673 p_sys
->b_buffering
= false;
674 p_sys
->i_preroll_end
= -1;
675 p_sys
->i_prev_stream_level
= -1;
677 if( p_sys
->i_buffering_extra_initial
> 0 )
683 const mtime_t i_decoder_buffering_start
= mdate();
684 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
686 es_out_id_t
*p_es
= p_sys
->es
[i
];
688 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
690 input_DecoderWait( p_es
->p_dec
);
691 if( p_es
->p_dec_record
)
692 input_DecoderWait( p_es
->p_dec_record
);
695 msg_Dbg( p_sys
->p_input
, "Decoder wait done in %d ms",
696 (int)(mdate() - i_decoder_buffering_start
)/1000 );
698 /* Here is a good place to destroy unused vout with every demuxer */
699 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
702 const mtime_t i_wakeup_delay
= 10*1000; /* FIXME CLEANUP thread wake up time*/
703 const mtime_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: mdate();
705 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_clock
, true,
706 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
708 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
710 es_out_id_t
*p_es
= p_sys
->es
[i
];
715 input_DecoderStopWait( p_es
->p_dec
);
716 if( p_es
->p_dec_record
)
717 input_DecoderStopWait( p_es
->p_dec_record
);
720 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
722 es_out_sys_t
*p_sys
= out
->p_sys
;
724 /* Pause decoders first */
725 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
727 es_out_id_t
*es
= p_sys
->es
[i
];
731 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
732 if( es
->p_dec_record
)
733 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
738 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
740 es_out_sys_t
*p_sys
= out
->p_sys
;
743 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
745 es_out_id_t
*p_es
= p_sys
->es
[i
];
748 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
749 if( p_es
->p_dec_record
)
750 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
752 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
754 /* TODO maybe we want to be able to tune it ? */
755 #if defined(OPTIMIZE_MEMORY)
756 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
758 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
760 return i_size
< i_level_high
;
763 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, mtime_t i_date
)
765 es_out_sys_t
*p_sys
= out
->p_sys
;
767 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
768 input_clock_ChangePause( p_sys
->pgrm
[i
]->p_clock
, b_paused
, i_date
);
771 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
773 es_out_sys_t
*p_sys
= out
->p_sys
;
776 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
777 i_delay
= p_sys
->i_audio_delay
;
778 else if( p_es
->fmt
.i_cat
== SPU_ES
)
779 i_delay
= p_sys
->i_spu_delay
;
784 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
785 if( p_es
->p_dec_record
)
786 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
788 static void EsOutProgramsChangeRate( es_out_t
*out
)
790 es_out_sys_t
*p_sys
= out
->p_sys
;
792 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
793 input_clock_ChangeRate( p_sys
->pgrm
[i
]->p_clock
, p_sys
->i_rate
);
796 static void EsOutFrameNext( es_out_t
*out
)
798 es_out_sys_t
*p_sys
= out
->p_sys
;
799 es_out_id_t
*p_es_video
= NULL
;
801 if( p_sys
->b_buffering
)
803 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
807 assert( p_sys
->b_paused
);
809 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
811 es_out_id_t
*p_es
= p_sys
->es
[i
];
813 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
822 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
827 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
829 msg_Dbg( out
->p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)(i_duration
/1000) );
831 if( i_duration
<= 0 )
832 i_duration
= 40*1000;
834 /* FIXME it is not a clean way ? */
835 if( p_sys
->i_buffering_extra_initial
<= 0 )
837 mtime_t i_stream_start
;
838 mtime_t i_system_start
;
839 mtime_t i_stream_duration
;
840 mtime_t i_system_duration
;
843 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
844 &i_stream_start
, &i_system_start
,
845 &i_stream_duration
, &i_system_duration
);
849 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
850 p_sys
->i_buffering_extra_system
=
851 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
854 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_clock
);
856 p_sys
->b_buffering
= true;
857 p_sys
->i_buffering_extra_system
+= i_duration
;
858 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
859 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
860 INPUT_RATE_DEFAULT
/ i_rate
;
862 p_sys
->i_preroll_end
= -1;
863 p_sys
->i_prev_stream_level
= -1;
865 static mtime_t
EsOutGetBuffering( es_out_t
*out
)
867 es_out_sys_t
*p_sys
= out
->p_sys
;
868 mtime_t i_stream_duration
, i_system_start
;
874 mtime_t i_stream_start
, i_system_duration
;
876 if( input_clock_GetState( p_sys
->p_pgrm
->p_clock
,
877 &i_stream_start
, &i_system_start
,
878 &i_stream_duration
, &i_system_duration
) )
884 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
886 i_delay
= i_stream_duration
;
890 mtime_t i_system_duration
;
892 if( p_sys
->b_paused
)
894 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
895 if( p_sys
->i_buffering_extra_initial
> 0 )
896 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
900 i_system_duration
= mdate() - i_system_start
;
903 const mtime_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
904 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
911 static void EsOutESVarUpdateGeneric( es_out_t
*out
, int i_id
,
912 const es_format_t
*fmt
, const char *psz_language
,
915 es_out_sys_t
*p_sys
= out
->p_sys
;
916 input_thread_t
*p_input
= p_sys
->p_input
;
917 vlc_value_t val
, text
;
921 if( EsFmtIsTeletext( fmt
) )
922 input_SendEventTeletextDel( p_sys
->p_input
, i_id
);
924 input_SendEventEsDel( p_input
, fmt
->i_cat
, i_id
);
928 /* Get the number of ES already added */
930 if( fmt
->i_cat
== AUDIO_ES
)
931 psz_var
= "audio-es";
932 else if( fmt
->i_cat
== VIDEO_ES
)
933 psz_var
= "video-es";
937 var_Change( p_input
, psz_var
, VLC_VAR_CHOICESCOUNT
, &val
, NULL
);
942 /* First one, we need to add the "Disable" choice */
943 val2
.i_int
= -1; text
.psz_string
= _("Disable");
944 var_Change( p_input
, psz_var
, VLC_VAR_ADDCHOICE
, &val2
, &text
);
948 /* Take care of the ES description */
949 if( fmt
->psz_description
&& *fmt
->psz_description
)
951 if( psz_language
&& *psz_language
)
953 if( asprintf( &text
.psz_string
, "%s - [%s]", fmt
->psz_description
,
954 psz_language
) == -1 )
955 text
.psz_string
= NULL
;
957 else text
.psz_string
= strdup( fmt
->psz_description
);
961 if( psz_language
&& *psz_language
)
963 if( asprintf( &text
.psz_string
, "%s %"PRId64
" - [%s]", _( "Track" ), val
.i_int
, psz_language
) == -1 )
964 text
.psz_string
= NULL
;
968 if( asprintf( &text
.psz_string
, "%s %"PRId64
, _( "Track" ), val
.i_int
) == -1 )
969 text
.psz_string
= NULL
;
973 input_SendEventEsAdd( p_input
, fmt
->i_cat
, i_id
, text
.psz_string
);
974 if( EsFmtIsTeletext( fmt
) )
977 snprintf( psz_page
, sizeof(psz_page
), "%d%2.2x",
978 fmt
->subs
.teletext
.i_magazine
,
979 fmt
->subs
.teletext
.i_page
);
980 input_SendEventTeletextAdd( p_sys
->p_input
,
981 i_id
, fmt
->subs
.teletext
.i_magazine
>= 0 ? psz_page
: NULL
);
984 free( text
.psz_string
);
987 static void EsOutESVarUpdate( es_out_t
*out
, es_out_id_t
*es
,
990 EsOutESVarUpdateGeneric( out
, es
->i_id
, &es
->fmt
, es
->psz_language
, b_delete
);
993 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
995 return out
->p_sys
->i_group_id
== 0 || out
->p_sys
->i_group_id
== i_group
;
998 /* EsOutProgramSelect:
999 * Select a program and update the object variable
1001 static void EsOutProgramSelect( es_out_t
*out
, es_out_pgrm_t
*p_pgrm
)
1003 es_out_sys_t
*p_sys
= out
->p_sys
;
1004 input_thread_t
*p_input
= p_sys
->p_input
;
1007 if( p_sys
->p_pgrm
== p_pgrm
)
1008 return; /* Nothing to do */
1012 es_out_pgrm_t
*old
= p_sys
->p_pgrm
;
1013 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
1015 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1017 if( p_sys
->es
[i
]->p_pgrm
== old
&& EsIsSelected( p_sys
->es
[i
] ) &&
1018 p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
1019 EsUnselect( out
, p_sys
->es
[i
], true );
1022 p_sys
->audio
.p_main_es
= NULL
;
1023 p_sys
->video
.p_main_es
= NULL
;
1024 p_sys
->sub
.p_main_es
= NULL
;
1027 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
1029 /* Mark it selected */
1030 p_pgrm
->b_selected
= true;
1032 /* Switch master stream */
1033 p_sys
->p_pgrm
= p_pgrm
;
1035 /* Update "program" */
1036 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
1039 input_SendEventEsDel( p_input
, AUDIO_ES
, -1 );
1040 input_SendEventEsDel( p_input
, VIDEO_ES
, -1 );
1041 input_SendEventEsDel( p_input
, SPU_ES
, -1 );
1042 input_SendEventTeletextDel( p_input
, -1 );
1043 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1046 var_SetInteger( p_input
, "teletext-es", -1 );
1048 for( i
= 0; i
< p_sys
->i_es
; i
++ )
1050 if( p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
)
1052 EsOutESVarUpdate( out
, p_sys
->es
[i
], false );
1053 EsOutUpdateInfo( out
, p_sys
->es
[i
], &p_sys
->es
[i
]->fmt
, NULL
);
1056 EsOutSelect( out
, p_sys
->es
[i
], false );
1059 /* Ensure the correct running EPG table is selected */
1060 input_item_ChangeEPGSource( input_priv(p_input
)->p_item
, p_pgrm
->i_id
);
1062 /* Update now playing */
1063 if( p_pgrm
->p_meta
)
1065 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
,
1066 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) );
1067 input_item_SetPublisher( input_priv(p_input
)->p_item
,
1068 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Publisher
) );
1069 input_item_SetTitle( input_priv(p_input
)->p_item
,
1070 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1071 input_SendEventMeta( p_input
);
1072 /* FIXME: we probably want to replace every input meta */
1079 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1081 es_out_sys_t
*p_sys
= out
->p_sys
;
1082 input_thread_t
*p_input
= p_sys
->p_input
;
1084 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1089 p_pgrm
->i_id
= i_group
;
1091 p_pgrm
->b_selected
= false;
1092 p_pgrm
->b_scrambled
= false;
1093 p_pgrm
->p_meta
= NULL
;
1094 p_pgrm
->p_clock
= input_clock_New( p_sys
->i_rate
);
1095 if( !p_pgrm
->p_clock
)
1100 if( p_sys
->b_paused
)
1101 input_clock_ChangePause( p_pgrm
->p_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1102 input_clock_SetJitter( p_pgrm
->p_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1105 TAB_APPEND( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1107 /* Update "program" variable */
1108 if( EsOutIsProgramVisible( out
, i_group
) )
1109 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1111 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1112 EsOutProgramSelect( out
, p_pgrm
);
1120 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1122 es_out_sys_t
*p_sys
= out
->p_sys
;
1123 input_thread_t
*p_input
= p_sys
->p_input
;
1124 es_out_pgrm_t
*p_pgrm
= NULL
;
1127 for( i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1129 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1131 p_pgrm
= p_sys
->pgrm
[i
];
1136 if( p_pgrm
== NULL
)
1137 return VLC_EGENERIC
;
1141 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1142 i_group
, p_pgrm
->i_es
);
1143 return VLC_EGENERIC
;
1146 TAB_REMOVE( p_sys
->i_pgrm
, p_sys
->pgrm
, p_pgrm
);
1148 /* If program is selected we need to unselect it */
1149 if( p_sys
->p_pgrm
== p_pgrm
)
1150 p_sys
->p_pgrm
= NULL
;
1152 input_clock_Delete( p_pgrm
->p_clock
);
1154 if( p_pgrm
->p_meta
)
1155 vlc_meta_Delete( p_pgrm
->p_meta
);
1158 /* Update "program" variable */
1159 input_SendEventProgramDel( p_input
, i_group
);
1166 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1168 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1170 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
1172 if( p_sys
->pgrm
[i
]->i_id
== i_group
)
1173 return p_sys
->pgrm
[i
];
1175 return EsOutProgramAdd( p_out
, i_group
);
1178 /* EsOutProgramMeta:
1180 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1183 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1185 if( asprintf( &psz
, _("%s [%s %d]"), vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
),
1186 _("Program"), p_pgrm
->i_id
) == -1 )
1191 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1197 static char *EsOutProgramGetProgramName( es_out_pgrm_t
*p_pgrm
)
1200 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1202 return strdup( vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1206 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1212 static char *EsInfoCategoryName( es_out_id_t
* es
)
1216 if( asprintf( &psz_category
, _("Stream %d"), es
->i_meta_id
) == -1 )
1219 return psz_category
;
1222 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1224 es_out_sys_t
*p_sys
= out
->p_sys
;
1225 es_out_pgrm_t
*p_pgrm
;
1226 input_thread_t
*p_input
= p_sys
->p_input
;
1227 const char *psz_title
= NULL
;
1228 const char *psz_provider
= NULL
;
1231 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1233 /* Check against empty meta data (empty for what we handle) */
1234 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1235 !vlc_meta_Get( p_meta
, vlc_meta_ESNowPlaying
) &&
1236 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) )
1243 EsOutGlobalMeta( out
, p_meta
);
1248 if( !EsOutIsProgramVisible( out
, i_group
) )
1250 p_pgrm
= EsOutProgramFind( out
, i_group
);
1254 if( p_pgrm
->p_meta
)
1256 const char *psz_current_title
= vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
);
1257 const char *psz_new_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1258 if( !psz_current_title
!= !psz_new_title
||
1259 ( psz_new_title
&& psz_new_title
&& strcmp(psz_new_title
, psz_current_title
)) )
1261 /* Remove old entries */
1262 char *psz_oldinfokey
= EsOutProgramGetMetaName( p_pgrm
);
1263 input_Control( p_input
, INPUT_DEL_INFO
, psz_oldinfokey
, NULL
);
1264 /* TODO update epg name ?
1265 * TODO update scrambled info name ? */
1266 free( psz_oldinfokey
);
1268 vlc_meta_Delete( p_pgrm
->p_meta
);
1270 p_pgrm
->p_meta
= vlc_meta_New();
1271 if( p_pgrm
->p_meta
)
1272 vlc_meta_Merge( p_pgrm
->p_meta
, p_meta
);
1274 if( p_sys
->p_pgrm
== p_pgrm
)
1276 EsOutMeta( out
, NULL
, p_meta
);
1279 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1280 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1282 /* Update the description text of the program */
1283 if( psz_title
&& *psz_title
)
1286 if( psz_provider
&& *psz_provider
)
1288 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1293 psz_text
= strdup( psz_title
);
1296 /* ugly but it works */
1299 input_SendEventProgramDel( p_input
, i_group
);
1300 input_SendEventProgramAdd( p_input
, i_group
, psz_text
);
1301 if( p_sys
->p_pgrm
== p_pgrm
)
1302 input_SendEventProgramSelect( p_input
, i_group
);
1308 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1310 info_category_t
*p_cat
= NULL
;
1311 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1313 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1315 p_cat
= info_category_New( psz_cat
);
1319 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1322 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1323 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1324 free( ppsz_all_keys
[i
] );
1326 free( ppsz_all_keys
);
1330 if( p_sys
->p_pgrm
== p_pgrm
)
1332 input_item_SetPublisher( input_priv(p_input
)->p_item
, psz_provider
);
1333 input_SendEventMeta( p_input
);
1336 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1337 "%s",psz_provider
);
1340 input_Control( p_input
, INPUT_MERGE_INFOS
, p_cat
);
1343 static void EsOutProgramEpgEvent( es_out_t
*out
, int i_group
, const vlc_epg_event_t
*p_event
)
1345 es_out_sys_t
*p_sys
= out
->p_sys
;
1346 input_thread_t
*p_input
= p_sys
->p_input
;
1347 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1348 es_out_pgrm_t
*p_pgrm
;
1351 if( !EsOutIsProgramVisible( out
, i_group
) )
1353 p_pgrm
= EsOutProgramFind( out
, i_group
);
1357 input_item_SetEpgEvent( p_item
, p_event
);
1360 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1362 es_out_sys_t
*p_sys
= out
->p_sys
;
1363 input_thread_t
*p_input
= p_sys
->p_input
;
1364 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1365 es_out_pgrm_t
*p_pgrm
;
1369 if( !EsOutIsProgramVisible( out
, i_group
) )
1371 p_pgrm
= EsOutProgramFind( out
, i_group
);
1376 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1377 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1383 epg
.psz_name
= EsOutProgramGetProgramName( p_pgrm
);
1385 input_item_SetEpg( p_item
, &epg
, p_sys
->p_pgrm
&& (p_epg
->i_source_id
== p_sys
->p_pgrm
->i_id
) );
1386 input_SendEventMetaEpg( p_sys
->p_input
);
1388 free( epg
.psz_name
);
1390 /* Update now playing */
1391 if( p_epg
->b_present
&& p_pgrm
->p_meta
&&
1392 ( p_epg
->p_current
|| p_epg
->i_event
== 0 ) )
1394 vlc_meta_SetNowPlaying( p_pgrm
->p_meta
, NULL
);
1397 vlc_mutex_lock( &p_item
->lock
);
1398 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1400 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1402 if( p_tmp
->b_present
&& p_tmp
->i_source_id
== p_pgrm
->i_id
)
1404 const char *psz_name
= ( p_tmp
->p_current
) ? p_tmp
->p_current
->psz_name
: NULL
;
1405 if( !p_pgrm
->p_meta
)
1406 p_pgrm
->p_meta
= vlc_meta_New();
1407 if( p_pgrm
->p_meta
)
1408 vlc_meta_Set( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
, psz_name
);
1412 vlc_mutex_unlock( &p_item
->lock
);
1414 /* Update selected program input info */
1415 if( p_pgrm
== p_sys
->p_pgrm
)
1417 const char *psz_nowplaying
= p_pgrm
->p_meta
?
1418 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) : NULL
;
1420 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
, psz_nowplaying
);
1421 input_SendEventMeta( p_input
);
1423 if( psz_nowplaying
)
1425 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
,
1426 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
), "%s", psz_nowplaying
);
1430 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
,
1431 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
) );
1438 static void EsOutEpgTime( es_out_t
*out
, int64_t time
)
1440 es_out_sys_t
*p_sys
= out
->p_sys
;
1441 input_thread_t
*p_input
= p_sys
->p_input
;
1442 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1444 input_item_SetEpgTime( p_item
, time
);
1447 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1449 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1450 input_thread_t
*p_input
= p_sys
->p_input
;
1451 bool b_scrambled
= false;
1453 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
1455 if( p_sys
->es
[i
]->p_pgrm
== p_pgrm
&& p_sys
->es
[i
]->b_scrambled
)
1461 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1464 p_pgrm
->b_scrambled
= b_scrambled
;
1465 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1468 input_Control( p_input
, INPUT_ADD_INFO
, psz_cat
, _("Scrambled"), _("Yes") );
1470 input_Control( p_input
, INPUT_DEL_INFO
, psz_cat
, _("Scrambled") );
1473 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1476 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_program_meta
)
1478 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1479 input_thread_t
*p_input
= p_sys
->p_input
;
1480 input_item_t
*p_item
= input_GetItem( p_input
);
1482 vlc_mutex_lock( &p_item
->lock
);
1484 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1485 vlc_mutex_unlock( &p_item
->lock
);
1487 /* Check program meta to not override GROUP_META values */
1488 if( p_meta
&& (!p_program_meta
|| vlc_meta_Get( p_program_meta
, vlc_meta_Title
) == NULL
) &&
1489 vlc_meta_Get( p_meta
, vlc_meta_Title
) != NULL
)
1490 input_item_SetName( p_item
, vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1492 const char *psz_arturl
= NULL
;
1493 char *psz_alloc
= NULL
;
1495 if( p_program_meta
)
1496 psz_arturl
= vlc_meta_Get( p_program_meta
, vlc_meta_ArtworkURL
);
1497 if( psz_arturl
== NULL
&& p_meta
)
1498 psz_arturl
= vlc_meta_Get( p_meta
, vlc_meta_ArtworkURL
);
1500 if( psz_arturl
== NULL
) /* restore/favor previously set item art URL */
1501 psz_arturl
= psz_alloc
= input_item_GetArtURL( p_item
);
1503 if( psz_arturl
!= NULL
)
1504 input_item_SetArtURL( p_item
, psz_arturl
);
1506 if( psz_arturl
!= NULL
&& !strncmp( psz_arturl
, "attachment://", 13 ) )
1507 { /* Clear art cover if streaming out.
1508 * FIXME: Why? Remove this when sout gets meta data support. */
1509 if( input_priv(p_input
)->p_sout
!= NULL
)
1510 input_item_SetArtURL( p_item
, NULL
);
1512 input_ExtractAttachmentAndCacheArt( p_input
, psz_arturl
+ 13 );
1516 input_item_SetPreparsed( p_item
, true );
1518 input_SendEventMeta( p_input
);
1519 /* TODO handle sout meta ? */
1522 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1524 es_out_sys_t
*p_sys
= p_out
->p_sys
;
1525 EsOutMeta( p_out
, p_meta
,
1526 (p_sys
->p_pgrm
&& p_sys
->p_pgrm
->p_meta
) ? p_sys
->p_pgrm
->p_meta
: NULL
);
1529 static es_out_id_t
*EsOutAddSlave( es_out_t
*out
, const es_format_t
*fmt
, es_out_id_t
*p_master
)
1531 es_out_sys_t
*p_sys
= out
->p_sys
;
1532 input_thread_t
*p_input
= p_sys
->p_input
;
1534 if( fmt
->i_group
< 0 )
1536 msg_Err( p_input
, "invalid group number" );
1540 es_out_id_t
*es
= malloc( sizeof( *es
) );
1541 es_out_pgrm_t
*p_pgrm
;
1547 vlc_mutex_lock( &p_sys
->lock
);
1549 /* Search the program */
1550 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1553 vlc_mutex_unlock( &p_sys
->lock
);
1558 /* Increase ref count for program */
1562 es
->p_pgrm
= p_pgrm
;
1563 es_format_Copy( &es
->fmt
, fmt
);
1564 if( es
->fmt
.i_id
< 0 )
1565 es
->fmt
.i_id
= p_sys
->i_id
;
1566 if( !es
->fmt
.i_original_fourcc
)
1567 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1569 es
->i_id
= es
->fmt
.i_id
;
1570 es
->i_meta_id
= p_sys
->i_id
++; /* always incremented */
1571 es
->b_scrambled
= false;
1573 switch( es
->fmt
.i_cat
)
1577 es
->fmt
.i_codec
= vlc_fourcc_GetCodecAudio( es
->fmt
.i_codec
,
1578 es
->fmt
.audio
.i_bitspersample
);
1579 es
->i_channel
= p_sys
->audio
.i_count
++;
1581 audio_replay_gain_t rg
;
1582 memset( &rg
, 0, sizeof(rg
) );
1583 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1584 vlc_audio_replay_gain_MergeFromMeta( &rg
, input_priv(p_input
)->p_item
->p_meta
);
1585 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1587 for( i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1589 if( !es
->fmt
.audio_replay_gain
.pb_peak
[i
] )
1591 es
->fmt
.audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1592 es
->fmt
.audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1594 if( !es
->fmt
.audio_replay_gain
.pb_gain
[i
] )
1596 es
->fmt
.audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1597 es
->fmt
.audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1604 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
, es
->fmt
.i_codec
);
1605 es
->i_channel
= p_sys
->video
.i_count
++;
1607 if( !es
->fmt
.video
.i_visible_width
|| !es
->fmt
.video
.i_visible_height
)
1609 es
->fmt
.video
.i_visible_width
= es
->fmt
.video
.i_width
;
1610 es
->fmt
.video
.i_visible_height
= es
->fmt
.video
.i_height
;
1613 if( es
->fmt
.video
.i_frame_rate
&& es
->fmt
.video
.i_frame_rate_base
)
1614 vlc_ureduce( &es
->fmt
.video
.i_frame_rate
,
1615 &es
->fmt
.video
.i_frame_rate_base
,
1616 es
->fmt
.video
.i_frame_rate
,
1617 es
->fmt
.video
.i_frame_rate_base
, 0 );
1621 es
->fmt
.i_codec
= vlc_fourcc_GetCodec( es
->fmt
.i_cat
, es
->fmt
.i_codec
);
1622 es
->i_channel
= p_sys
->sub
.i_count
++;
1629 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1630 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1632 es
->p_dec_record
= NULL
;
1634 es
->cc
.i_bitmap
= 0;
1635 es
->p_master
= p_master
;
1637 TAB_APPEND( p_sys
->i_es
, p_sys
->es
, es
);
1639 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1640 EsOutESVarUpdate( out
, es
, false );
1642 EsOutUpdateInfo( out
, es
, &es
->fmt
, NULL
);
1643 EsOutSelect( out
, es
, false );
1645 if( es
->b_scrambled
)
1646 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1648 vlc_mutex_unlock( &p_sys
->lock
);
1656 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1658 return EsOutAddSlave( out
, fmt
, NULL
);
1661 static bool EsIsSelected( es_out_id_t
*es
)
1665 bool b_decode
= false;
1666 if( es
->p_master
->p_dec
)
1668 int i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1669 input_DecoderGetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1670 i_channel
, &b_decode
);
1676 return es
->p_dec
!= NULL
;
1679 static void EsCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1681 es_out_sys_t
*p_sys
= out
->p_sys
;
1682 input_thread_t
*p_input
= p_sys
->p_input
;
1684 p_es
->p_dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_clock
, input_priv(p_input
)->p_sout
);
1687 if( p_sys
->b_buffering
)
1688 input_DecoderStartWait( p_es
->p_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_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
);
1698 EsOutDecoderChangeDelay( out
, p_es
);
1700 static void EsDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1707 input_DecoderDelete( p_es
->p_dec
);
1710 if( p_es
->p_dec_record
)
1712 input_DecoderDelete( p_es
->p_dec_record
);
1713 p_es
->p_dec_record
= NULL
;
1717 static void EsSelect( es_out_t
*out
, es_out_id_t
*es
)
1719 es_out_sys_t
*p_sys
= out
->p_sys
;
1720 input_thread_t
*p_input
= p_sys
->p_input
;
1722 if( EsIsSelected( es
) )
1724 msg_Warn( p_input
, "ES 0x%x is already selected", es
->i_id
);
1731 if( !es
->p_master
->p_dec
)
1734 i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1736 if( i_channel
== -1 ||
1737 input_DecoderSetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1743 const bool b_sout
= input_priv(p_input
)->p_sout
!= NULL
;
1744 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1746 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1748 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1753 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1755 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) )
1757 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1762 if( es
->fmt
.i_cat
== SPU_ES
)
1764 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) )
1766 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1772 EsCreateDecoder( out
, es
);
1774 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1778 /* Mark it as selected */
1779 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, es
->i_id
);
1780 input_SendEventTeletextSelect( p_input
, EsFmtIsTeletext( &es
->fmt
) ? es
->i_id
: -1 );
1783 static void EsDeleteCCChannels( es_out_t
*out
, es_out_id_t
*parent
)
1785 es_out_sys_t
*p_sys
= out
->p_sys
;
1786 input_thread_t
*p_input
= p_sys
->p_input
;
1788 if( parent
->cc
.type
== 0 )
1791 const int i_spu_id
= var_GetInteger( p_input
, "spu-es");
1793 uint64_t i_bitmap
= parent
->cc
.i_bitmap
;
1794 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1 )
1796 if( (i_bitmap
& 1) == 0 || !parent
->cc
.pp_es
[i
] )
1799 if( i_spu_id
== parent
->cc
.pp_es
[i
]->i_id
)
1801 /* Force unselection of the CC */
1802 input_SendEventEsSelect( p_input
, SPU_ES
, -1 );
1804 EsOutDel( out
, parent
->cc
.pp_es
[i
] );
1807 parent
->cc
.i_bitmap
= 0;
1808 parent
->cc
.type
= 0;
1811 static void EsUnselect( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1813 es_out_sys_t
*p_sys
= out
->p_sys
;
1814 input_thread_t
*p_input
= p_sys
->p_input
;
1816 if( !EsIsSelected( es
) )
1818 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->i_id
);
1824 if( es
->p_master
->p_dec
)
1826 int i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1827 if( i_channel
!= -1 )
1828 input_DecoderSetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1834 EsDeleteCCChannels( out
, es
);
1835 EsDestroyDecoder( out
, es
);
1841 /* Mark it as unselected */
1842 input_SendEventEsSelect( p_input
, es
->fmt
.i_cat
, -1 );
1843 if( EsFmtIsTeletext( &es
->fmt
) )
1844 input_SendEventTeletextSelect( p_input
, -1 );
1848 * Select an ES given the current mode
1849 * XXX: you need to take a the lock before (stream.stream_lock)
1851 * \param out The es_out structure
1852 * \param es es_out_id structure
1853 * \param b_force ...
1856 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1858 es_out_sys_t
*p_sys
= out
->p_sys
;
1859 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
1861 if( !p_sys
->b_active
||
1862 ( !b_force
&& es
->fmt
.i_priority
< ES_PRIORITY_SELECTABLE_MIN
) )
1867 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
1869 if( !EsIsSelected( es
) )
1870 EsSelect( out
, es
);
1872 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
1874 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
1879 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
1881 prgm
= strtok_r( NULL
, ",", &buf
) )
1883 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
1885 if( !EsIsSelected( es
) )
1886 EsSelect( out
, es
);
1893 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1895 const es_out_id_t
*wanted_es
= NULL
;
1897 if( es
->p_pgrm
!= p_sys
->p_pgrm
|| !p_esprops
)
1900 /* user designated by ID ES have higher prio than everything */
1901 if ( p_esprops
->i_id
>= 0 )
1903 if( es
->i_id
== p_esprops
->i_id
)
1907 else if( p_esprops
->i_channel
>= 0 )
1909 if( p_esprops
->i_channel
== es
->i_channel
)
1912 else if( p_esprops
->ppsz_language
)
1914 /* If not deactivated */
1915 const int i_stop_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
, "none" );
1917 int current_es_idx
= ( p_esprops
->p_main_es
== NULL
) ? -1 :
1918 LanguageArrayIndex( p_esprops
->ppsz_language
,
1919 p_esprops
->p_main_es
->psz_language_code
);
1920 int es_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
,
1921 es
->psz_language_code
);
1922 if( es_idx
>= 0 && (i_stop_idx
< 0 || i_stop_idx
> es_idx
) )
1924 /* Only select the language if it's in the list */
1925 if( p_esprops
->p_main_es
== NULL
||
1926 current_es_idx
< 0 || /* current es was not selected by lang prefs */
1927 es_idx
< current_es_idx
|| /* current es has lower lang prio */
1928 ( es_idx
== current_es_idx
&& /* lang is same, but es has higher prio */
1929 p_esprops
->p_main_es
->fmt
.i_priority
< es
->fmt
.i_priority
) )
1934 /* We did not find a language matching our prefs */
1935 else if( i_stop_idx
< 0 ) /* If not fallback disabled by 'none' */
1937 /* Select if asked by demuxer */
1938 if( current_es_idx
< 0 ) /* No es is currently selected by lang pref */
1940 /* If demux has specified a track */
1941 if( p_esprops
->i_demux_id
>= 0 && es
->i_id
== p_esprops
->i_demux_id
)
1945 /* Otherwise, fallback by priority */
1946 else if( p_esprops
->p_main_es
== NULL
||
1947 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
1949 if( p_esprops
->b_autoselect
)
1957 /* If there is no user preference, select the default subtitle
1958 * or adapt by ES priority */
1959 else if( p_esprops
->i_demux_id
>= 0 && es
->i_id
== p_esprops
->i_demux_id
)
1963 else if( p_esprops
->p_main_es
== NULL
||
1964 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
1966 if( p_esprops
->b_autoselect
)
1970 if( wanted_es
== es
&& !EsIsSelected( es
) )
1971 EsSelect( out
, es
);
1974 /* FIXME TODO handle priority here */
1975 if( p_esprops
&& EsIsSelected( es
) )
1977 if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
1979 if( p_esprops
->e_policy
== ES_OUT_ES_POLICY_EXCLUSIVE
&&
1980 p_esprops
->p_main_es
&&
1981 p_esprops
->p_main_es
!= es
)
1983 EsUnselect( out
, p_esprops
->p_main_es
, false );
1985 p_esprops
->p_main_es
= es
;
1990 static void EsOutCreateCCChannels( es_out_t
*out
, vlc_fourcc_t codec
, uint64_t i_bitmap
,
1991 const char *psz_descfmt
, es_out_id_t
*parent
)
1993 es_out_sys_t
*p_sys
= out
->p_sys
;
1994 input_thread_t
*p_input
= p_sys
->p_input
;
1996 /* Only one type of captions is allowed ! */
1997 if( parent
->cc
.type
&& parent
->cc
.type
!= codec
)
2000 uint64_t i_existingbitmap
= parent
->cc
.i_bitmap
;
2001 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1, i_existingbitmap
>>= 1 )
2005 if( (i_bitmap
& 1) == 0 || (i_existingbitmap
& 1) )
2008 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, parent
->i_id
);
2010 es_format_Init( &fmt
, SPU_ES
, codec
);
2011 fmt
.subs
.cc
.i_channel
= i
;
2012 fmt
.i_group
= parent
->fmt
.i_group
;
2013 if( asprintf( &fmt
.psz_description
, psz_descfmt
, 1 + i
) == -1 )
2014 fmt
.psz_description
= NULL
;
2016 es_out_id_t
**pp_es
= &parent
->cc
.pp_es
[i
];
2017 *pp_es
= EsOutAddSlave( out
, &fmt
, parent
);
2018 es_format_Clean( &fmt
);
2021 parent
->cc
.i_bitmap
|= (1ULL << i
);
2022 parent
->cc
.type
= codec
;
2024 /* Enable if user specified on command line */
2025 if (p_sys
->sub
.i_channel
== i
)
2026 EsOutSelect(out
, *pp_es
, true);
2031 * Send a block for the given es_out
2033 * \param out the es_out to send from
2034 * \param es the es_out_id
2035 * \param p_block the data block to send
2037 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
2039 es_out_sys_t
*p_sys
= out
->p_sys
;
2040 input_thread_t
*p_input
= p_sys
->p_input
;
2042 if( libvlc_stats( p_input
) )
2046 vlc_mutex_lock( &input_priv(p_input
)->counters
.counters_lock
);
2047 stats_Update( input_priv(p_input
)->counters
.p_demux_read
,
2048 p_block
->i_buffer
, &i_total
);
2049 stats_Update( input_priv(p_input
)->counters
.p_demux_bitrate
, i_total
, NULL
);
2051 /* Update number of corrupted data packats */
2052 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
2054 stats_Update( input_priv(p_input
)->counters
.p_demux_corrupted
, 1, NULL
);
2056 /* Update number of discontinuities */
2057 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
2059 stats_Update( input_priv(p_input
)->counters
.p_demux_discontinuity
, 1, NULL
);
2061 vlc_mutex_unlock( &input_priv(p_input
)->counters
.counters_lock
);
2064 vlc_mutex_lock( &p_sys
->lock
);
2066 /* Mark preroll blocks */
2067 if( p_sys
->i_preroll_end
>= 0 )
2069 int64_t i_date
= p_block
->i_pts
;
2070 if( p_block
->i_pts
<= VLC_TS_INVALID
)
2071 i_date
= p_block
->i_dts
;
2073 if( i_date
+ p_block
->i_length
< p_sys
->i_preroll_end
)
2074 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
2079 block_Release( p_block
);
2080 vlc_mutex_unlock( &p_sys
->lock
);
2084 /* Check for sout mode */
2085 if( input_priv(p_input
)->p_sout
)
2087 /* FIXME review this, proper lock may be missing */
2088 if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
> 0 &&
2089 input_priv(p_input
)->b_out_pace_control
)
2091 msg_Dbg( p_input
, "switching to sync mode" );
2092 input_priv(p_input
)->b_out_pace_control
= false;
2094 else 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 async mode" );
2098 input_priv(p_input
)->b_out_pace_control
= true;
2103 if( es
->p_dec_record
)
2105 block_t
*p_dup
= block_Duplicate( p_block
);
2107 input_DecoderDecode( es
->p_dec_record
, p_dup
,
2108 input_priv(p_input
)->b_out_pace_control
);
2110 input_DecoderDecode( es
->p_dec
, p_block
,
2111 input_priv(p_input
)->b_out_pace_control
);
2113 es_format_t fmt_dsc
;
2114 vlc_meta_t
*p_meta_dsc
;
2115 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
2117 EsOutUpdateInfo( out
, es
, &fmt_dsc
, p_meta_dsc
);
2119 es_format_Clean( &fmt_dsc
);
2121 vlc_meta_Delete( p_meta_dsc
);
2124 /* Check CC status */
2125 decoder_cc_desc_t desc
;
2127 input_DecoderGetCcDesc( es
->p_dec
, &desc
);
2128 if( var_InheritInteger( p_input
, "captions" ) == 708 )
2129 EsOutCreateCCChannels( out
, VLC_CODEC_CEA708
, desc
.i_708_channels
,
2130 _("DTVCC Closed captions %u"), es
);
2131 EsOutCreateCCChannels( out
, VLC_CODEC_CEA608
, desc
.i_608_channels
,
2132 _("Closed captions %u"), es
);
2134 vlc_mutex_unlock( &p_sys
->lock
);
2139 /*****************************************************************************
2141 *****************************************************************************/
2142 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2144 es_out_sys_t
*p_sys
= out
->p_sys
;
2145 bool b_reselect
= false;
2148 vlc_mutex_lock( &p_sys
->lock
);
2150 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
2152 /* We don't try to reselect */
2154 { /* FIXME: This might hold the ES output caller (i.e. the demux), and
2155 * the corresponding thread (typically the input thread), for a little
2156 * bit too long if the ES is deleted in the middle of a stream. */
2157 input_DecoderDrain( es
->p_dec
);
2158 while( !input_Stopped(p_sys
->p_input
) && !p_sys
->b_buffering
)
2160 if( input_DecoderIsEmpty( es
->p_dec
) &&
2161 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2163 /* FIXME there should be a way to have auto deleted es, but there will be
2164 * a problem when another codec of the same type is created (mainly video) */
2167 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2170 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2171 EsOutESVarUpdate( out
, es
, true );
2173 EsDeleteInfo( out
, es
);
2175 TAB_REMOVE( p_sys
->i_es
, p_sys
->es
, es
);
2177 /* Update program */
2179 if( es
->p_pgrm
->i_es
== 0 )
2180 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2182 if( es
->b_scrambled
)
2183 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2188 if( p_esprops
->p_main_es
== es
)
2191 p_esprops
->p_main_es
= NULL
;
2193 p_esprops
->i_count
--;
2196 /* Re-select another track when needed */
2199 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2201 if( es
->fmt
.i_cat
== p_sys
->es
[i
]->fmt
.i_cat
)
2203 if( EsIsSelected(p_sys
->es
[i
]) )
2205 input_SendEventEsSelect( p_sys
->p_input
, es
->fmt
.i_cat
, p_sys
->es
[i
]->i_id
);
2206 if( p_esprops
->p_main_es
== NULL
)
2207 p_esprops
->p_main_es
= p_sys
->es
[i
];
2210 EsOutSelect( out
, p_sys
->es
[i
], false );
2215 free( es
->psz_language
);
2216 free( es
->psz_language_code
);
2218 es_format_Clean( &es
->fmt
);
2220 vlc_mutex_unlock( &p_sys
->lock
);
2226 * Control query handler
2228 * \param out the es_out to control
2229 * \param i_query A es_out query as defined in include/ninput.h
2230 * \param args a variable list of arguments for the query
2231 * \return VLC_SUCCESS or an error code
2233 static int EsOutControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2235 es_out_sys_t
*p_sys
= out
->p_sys
;
2239 case ES_OUT_SET_ES_STATE
:
2241 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2242 bool b
= va_arg( args
, int );
2243 if( b
&& !EsIsSelected( es
) )
2245 EsSelect( out
, es
);
2246 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2248 else if( !b
&& EsIsSelected( es
) )
2250 EsUnselect( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2256 case ES_OUT_GET_ES_STATE
:
2258 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2259 bool *pb
= va_arg( args
, bool * );
2261 *pb
= EsIsSelected( es
);
2265 case ES_OUT_SET_ES_CAT_POLICY
:
2267 enum es_format_category_e i_cat
= va_arg( args
, enum es_format_category_e
);
2268 enum es_out_policy_e i_pol
= va_arg( args
, enum es_out_policy_e
);
2269 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, i_cat
);
2270 if( p_esprops
== NULL
)
2271 return VLC_EGENERIC
;
2272 p_esprops
->e_policy
= i_pol
;
2276 case ES_OUT_GET_GROUP_FORCED
:
2278 int *pi_group
= va_arg( args
, int * );
2279 *pi_group
= p_sys
->i_group_id
;
2283 case ES_OUT_SET_MODE
:
2285 const int i_mode
= va_arg( args
, int );
2286 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2287 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2288 i_mode
== ES_OUT_MODE_END
);
2290 if( i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& p_sys
->i_es
> 0 )
2292 /* XXX Terminate vout if there are tracks but no video one.
2293 * This one is not mandatory but is he earliest place where it
2296 for( i
= 0; i
< p_sys
->i_es
; i
++ )
2298 es_out_id_t
*p_es
= p_sys
->es
[i
];
2299 if( p_es
->fmt
.i_cat
== VIDEO_ES
)
2302 if( i
>= p_sys
->i_es
)
2303 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2305 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2306 p_sys
->i_mode
= i_mode
;
2308 /* Reapply policy mode */
2309 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2311 if( EsIsSelected( p_sys
->es
[i
] ) )
2312 EsUnselect( out
, p_sys
->es
[i
],
2313 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2315 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2316 EsOutSelect( out
, p_sys
->es
[i
], false );
2317 if( i_mode
== ES_OUT_MODE_END
)
2318 EsOutTerminate( out
);
2323 case ES_OUT_RESTART_ES
:
2325 #define IGNORE_ES DATA_ES
2326 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2328 enum es_format_category_e i_cat
;
2331 else if( es
== es_cat
+ AUDIO_ES
)
2333 else if( es
== es_cat
+ VIDEO_ES
)
2335 else if( es
== es_cat
+ SPU_ES
)
2340 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2342 if( i_cat
== IGNORE_ES
)
2344 if( es
== p_sys
->es
[i
] )
2346 if( i_query
== ES_OUT_RESTART_ES
&& p_sys
->es
[i
]->p_dec
)
2348 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2349 EsCreateDecoder( out
, p_sys
->es
[i
] );
2351 else if( i_query
== ES_OUT_SET_ES
)
2353 EsOutSelect( out
, es
, true );
2360 if( i_cat
== UNKNOWN_ES
|| p_sys
->es
[i
]->fmt
.i_cat
== i_cat
)
2362 if( EsIsSelected( p_sys
->es
[i
] ) )
2364 if( i_query
== ES_OUT_RESTART_ES
)
2366 if( p_sys
->es
[i
]->p_dec
)
2368 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2369 EsCreateDecoder( out
, p_sys
->es
[i
] );
2374 EsUnselect( out
, p_sys
->es
[i
],
2375 p_sys
->es
[i
]->p_pgrm
== p_sys
->p_pgrm
);
2383 case ES_OUT_RESTART_ALL_ES
:
2385 for( int i
= 0; i
< p_sys
->i_es
; i
++ )
2387 EsDestroyDecoder( out
, p_sys
->es
[i
] );
2388 EsCreateDecoder( out
, p_sys
->es
[i
] );
2393 case ES_OUT_SET_ES_DEFAULT
:
2395 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2399 /*p_sys->i_default_video_id = -1;*/
2400 /*p_sys->i_default_audio_id = -1;*/
2401 p_sys
->sub
.i_demux_id
= -1;
2403 else if( es
== es_cat
+ AUDIO_ES
)
2405 /*p_sys->i_default_video_id = -1;*/
2407 else if( es
== es_cat
+ VIDEO_ES
)
2409 /*p_sys->i_default_audio_id = -1;*/
2411 else if( es
== es_cat
+ SPU_ES
)
2413 p_sys
->sub
.i_demux_id
= -1;
2417 /*if( es->fmt.i_cat == VIDEO_ES )
2418 p_sys->i_default_video_id = es->i_id;
2420 if( es->fmt.i_cat == AUDIO_ES )
2421 p_sys->i_default_audio_id = es->i_id;
2423 if( es
->fmt
.i_cat
== SPU_ES
)
2424 p_sys
->sub
.i_demux_id
= es
->i_id
;
2429 case ES_OUT_SET_PCR
:
2430 case ES_OUT_SET_GROUP_PCR
:
2432 es_out_pgrm_t
*p_pgrm
= NULL
;
2436 /* Search program */
2437 if( i_query
== ES_OUT_SET_PCR
)
2439 p_pgrm
= p_sys
->p_pgrm
;
2441 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2445 i_group
= va_arg( args
, int );
2446 p_pgrm
= EsOutProgramFind( out
, i_group
);
2449 return VLC_EGENERIC
;
2451 i_pcr
= va_arg( args
, int64_t );
2452 if( i_pcr
<= VLC_TS_INVALID
)
2454 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2455 return VLC_EGENERIC
;
2458 /* TODO do not use mdate() but proper stream acquisition date */
2460 input_clock_Update( p_pgrm
->p_clock
, VLC_OBJECT(p_sys
->p_input
),
2462 input_priv(p_sys
->p_input
)->b_can_pace_control
|| p_sys
->b_buffering
,
2463 EsOutIsExtraBufferingAllowed( out
),
2466 if( !p_sys
->p_pgrm
)
2469 if( p_sys
->b_buffering
)
2471 /* Check buffering state on master clock update */
2472 EsOutDecodersStopBuffering( out
, false );
2474 else if( p_pgrm
== p_sys
->p_pgrm
)
2476 if( b_late
&& ( !input_priv(p_sys
->p_input
)->p_sout
||
2477 !input_priv(p_sys
->p_input
)->b_out_pace_control
) )
2479 const mtime_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2480 mtime_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_clock
);
2482 /* Avoid dangerously high value */
2483 const mtime_t i_jitter_max
= INT64_C(1000) * var_InheritInteger( p_sys
->p_input
, "clock-jitter" );
2484 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2486 msg_Err( p_sys
->p_input
,
2487 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2488 (int)(i_pts_delay
- i_pts_delay_base
) / 1000 );
2489 i_pts_delay
= p_sys
->i_pts_delay
;
2492 for( int i
= 0; i
< p_sys
->i_pgrm
; i
++ )
2493 input_clock_Reset( p_sys
->pgrm
[i
]->p_clock
);
2497 msg_Err( p_sys
->p_input
,
2498 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2499 (int)(i_pts_delay
/1000) );
2501 /* Force a rebufferization when we are too late */
2503 /* It is not really good, as we throw away already buffered data
2504 * TODO have a mean to correctly reenter bufferization */
2505 es_out_Control( out
, ES_OUT_RESET_PCR
);
2508 es_out_SetJitter( out
, i_pts_delay_base
, i_pts_delay
- i_pts_delay_base
, p_sys
->i_cr_average
);
2514 case ES_OUT_RESET_PCR
:
2515 msg_Dbg( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2516 EsOutChangePosition( out
);
2519 case ES_OUT_SET_GROUP
:
2521 int i
= va_arg( args
, int );
2522 for( int j
= 0; j
< p_sys
->i_pgrm
; j
++ )
2524 es_out_pgrm_t
*p_pgrm
= p_sys
->pgrm
[j
];
2525 if( p_pgrm
->i_id
== i
)
2527 EsOutProgramSelect( out
, p_pgrm
);
2531 return VLC_EGENERIC
;
2534 case ES_OUT_SET_ES_FMT
:
2536 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2537 * to update the p_extra data */
2538 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2539 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2541 return VLC_EGENERIC
;
2543 es_format_Clean( &es
->fmt
);
2544 es_format_Copy( &es
->fmt
, p_fmt
);
2548 EsDestroyDecoder( out
, es
);
2549 EsCreateDecoder( out
, es
);
2555 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2557 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2558 bool b_scrambled
= (bool)va_arg( args
, int );
2560 if( !es
->b_scrambled
!= !b_scrambled
)
2562 es
->b_scrambled
= b_scrambled
;
2563 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2568 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2570 const int64_t i_date
= va_arg( args
, int64_t );
2573 return VLC_EGENERIC
;
2575 p_sys
->i_preroll_end
= i_date
;
2579 case ES_OUT_SET_GROUP_META
:
2581 int i_group
= va_arg( args
, int );
2582 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2584 EsOutProgramMeta( out
, i_group
, p_meta
);
2587 case ES_OUT_SET_GROUP_EPG
:
2589 int i_group
= va_arg( args
, int );
2590 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2592 EsOutProgramEpg( out
, i_group
, p_epg
);
2595 case ES_OUT_SET_GROUP_EPG_EVENT
:
2597 int i_group
= va_arg( args
, int );
2598 const vlc_epg_event_t
*p_evt
= va_arg( args
, const vlc_epg_event_t
* );
2600 EsOutProgramEpgEvent( out
, i_group
, p_evt
);
2603 case ES_OUT_SET_EPG_TIME
:
2605 int64_t i64
= va_arg( args
, int64_t );
2607 EsOutEpgTime( out
, i64
);
2611 case ES_OUT_DEL_GROUP
:
2613 int i_group
= va_arg( args
, int );
2615 return EsOutProgramDel( out
, i_group
);
2618 case ES_OUT_SET_META
:
2620 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2622 EsOutGlobalMeta( out
, p_meta
);
2626 case ES_OUT_GET_WAKE_UP
:
2628 mtime_t
*pi_wakeup
= va_arg( args
, mtime_t
* );
2629 *pi_wakeup
= EsOutGetWakeup( out
);
2633 case ES_OUT_SET_ES_BY_ID
:
2634 case ES_OUT_RESTART_ES_BY_ID
:
2635 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2637 const int i_id
= va_arg( args
, int );
2638 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2639 int i_new_query
= 0;
2643 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
; break;
2644 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2645 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2647 vlc_assert_unreachable();
2649 /* TODO if the lock is made non recursive it should be changed */
2650 int i_ret
= es_out_Control( out
, i_new_query
, p_es
);
2652 /* Clean up vout after user action (in active mode only).
2653 * FIXME it does not work well with multiple video windows */
2654 if( p_sys
->b_active
)
2655 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2659 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2661 const int i_id
= va_arg( args
, int );
2662 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2664 return VLC_EGENERIC
;
2666 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2667 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2668 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
2672 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2673 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2687 case ES_OUT_GET_BUFFERING
:
2689 bool *pb
= va_arg( args
, bool* );
2690 *pb
= p_sys
->b_buffering
;
2694 case ES_OUT_GET_EMPTY
:
2696 bool *pb
= va_arg( args
, bool* );
2697 *pb
= EsOutDecodersIsEmpty( out
);
2701 case ES_OUT_SET_DELAY
:
2703 const int i_cat
= va_arg( args
, int );
2704 const mtime_t i_delay
= va_arg( args
, mtime_t
);
2705 EsOutSetDelay( out
, i_cat
, i_delay
);
2709 case ES_OUT_SET_RECORD_STATE
:
2711 bool b
= va_arg( args
, int );
2712 return EsOutSetRecord( out
, b
);
2715 case ES_OUT_SET_PAUSE_STATE
:
2717 const bool b_source_paused
= (bool)va_arg( args
, int );
2718 const bool b_paused
= (bool)va_arg( args
, int );
2719 const mtime_t i_date
= va_arg( args
, mtime_t
);
2721 assert( !b_source_paused
== !b_paused
);
2722 EsOutChangePause( out
, b_paused
, i_date
);
2727 case ES_OUT_SET_RATE
:
2729 const int i_src_rate
= va_arg( args
, int );
2730 const int i_rate
= va_arg( args
, int );
2732 assert( i_src_rate
== i_rate
);
2733 EsOutChangeRate( out
, i_rate
);
2738 case ES_OUT_SET_TIME
:
2740 const mtime_t i_date
= va_arg( args
, mtime_t
);
2742 assert( i_date
== -1 );
2743 EsOutChangePosition( out
);
2748 case ES_OUT_SET_FRAME_NEXT
:
2749 EsOutFrameNext( out
);
2752 case ES_OUT_SET_TIMES
:
2754 double f_position
= va_arg( args
, double );
2755 mtime_t i_time
= va_arg( args
, mtime_t
);
2756 mtime_t i_length
= va_arg( args
, mtime_t
);
2758 input_SendEventLength( p_sys
->p_input
, i_length
);
2760 if( !p_sys
->b_buffering
)
2764 /* Fix for buffering delay */
2765 if( !input_priv(p_sys
->p_input
)->p_sout
||
2766 !input_priv(p_sys
->p_input
)->b_out_pace_control
)
2767 i_delay
= EsOutGetBuffering( out
);
2776 f_position
-= (double)i_delay
/ i_length
;
2777 if( f_position
< 0 )
2780 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
2784 case ES_OUT_SET_JITTER
:
2786 mtime_t i_pts_delay
= va_arg( args
, mtime_t
);
2787 mtime_t i_pts_jitter
= va_arg( args
, mtime_t
);
2788 int i_cr_average
= va_arg( args
, int );
2790 bool b_change_clock
=
2791 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
2792 i_cr_average
!= p_sys
->i_cr_average
;
2794 assert( i_pts_jitter
>= 0 );
2795 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
2796 p_sys
->i_pts_jitter
= i_pts_jitter
;
2797 p_sys
->i_cr_average
= i_cr_average
;
2799 for( int i
= 0; i
< p_sys
->i_pgrm
&& b_change_clock
; i
++ )
2800 input_clock_SetJitter( p_sys
->pgrm
[i
]->p_clock
,
2801 i_pts_delay
+ i_pts_jitter
, i_cr_average
);
2805 case ES_OUT_GET_PCR_SYSTEM
:
2807 if( p_sys
->b_buffering
)
2808 return VLC_EGENERIC
;
2810 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2812 return VLC_EGENERIC
;
2814 mtime_t
*pi_system
= va_arg( args
, mtime_t
*);
2815 mtime_t
*pi_delay
= va_arg( args
, mtime_t
*);
2816 input_clock_GetSystemOrigin( p_pgrm
->p_clock
, pi_system
, pi_delay
);
2820 case ES_OUT_MODIFY_PCR_SYSTEM
:
2822 if( p_sys
->b_buffering
)
2823 return VLC_EGENERIC
;
2825 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
2827 return VLC_EGENERIC
;
2829 const bool b_absolute
= va_arg( args
, int );
2830 const mtime_t i_system
= va_arg( args
, mtime_t
);
2831 input_clock_ChangeSystemOrigin( p_pgrm
->p_clock
, b_absolute
, i_system
);
2834 case ES_OUT_SET_EOS
:
2836 for (int i
= 0; i
< p_sys
->i_es
; i
++) {
2837 es_out_id_t
*id
= p_sys
->es
[i
];
2838 if (id
->p_dec
!= NULL
)
2839 input_DecoderDrain(id
->p_dec
);
2844 case ES_OUT_POST_SUBNODE
:
2846 input_item_node_t
*node
= va_arg(args
, input_item_node_t
*);
2847 input_item_node_PostAndDelete(node
);
2852 msg_Err( p_sys
->p_input
, "unknown query 0x%x in %s", i_query
,
2854 return VLC_EGENERIC
;
2857 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
2859 es_out_sys_t
*p_sys
= out
->p_sys
;
2862 vlc_mutex_lock( &p_sys
->lock
);
2863 i_ret
= EsOutControlLocked( out
, i_query
, args
);
2864 vlc_mutex_unlock( &p_sys
->lock
);
2869 /****************************************************************************
2870 * LanguageGetName: try to expend iso639 into plain name
2871 ****************************************************************************/
2872 static char *LanguageGetName( const char *psz_code
)
2874 const iso639_lang_t
*pl
;
2876 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
2878 return strdup( "" );
2881 if( strlen( psz_code
) == 2 )
2883 pl
= GetLang_1( psz_code
);
2885 else if( strlen( psz_code
) == 3 )
2887 pl
= GetLang_2B( psz_code
);
2888 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2890 pl
= GetLang_2T( psz_code
);
2895 char *lang
= LanguageGetCode( psz_code
);
2896 pl
= GetLang_1( lang
);
2900 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
2902 return strdup( psz_code
);
2906 return strdup( vlc_gettext(pl
->psz_eng_name
) );
2910 /* Get a 2 char code */
2911 static char *LanguageGetCode( const char *psz_lang
)
2913 const iso639_lang_t
*pl
;
2915 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
2916 return strdup("??");
2918 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
2920 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
2921 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
2922 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
2923 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
2924 return strdup( pl
->psz_iso639_1
);
2927 return strdup("??");
2930 static char **LanguageSplit( const char *psz_langs
)
2937 if( psz_langs
== NULL
) return NULL
;
2939 psz_parser
= psz_dup
= strdup(psz_langs
);
2941 while( psz_parser
&& *psz_parser
)
2946 psz
= strchr(psz_parser
, ',' );
2947 if( psz
) *psz
++ = '\0';
2949 if( !strcmp( psz_parser
, "any" ) )
2951 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
2953 else if( !strcmp( psz_parser
, "none" ) )
2955 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
2959 psz_code
= LanguageGetCode( psz_parser
);
2960 if( strcmp( psz_code
, "??" ) )
2962 TAB_APPEND( i_psz
, ppsz
, psz_code
);
2975 TAB_APPEND( i_psz
, ppsz
, NULL
);
2982 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
)
2984 if( !ppsz_langs
|| !psz_lang
)
2987 for( int i
= 0; ppsz_langs
[i
]; i
++ )
2989 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
2990 ( !strcasecmp( ppsz_langs
[i
], "any" ) && strcasecmp( psz_lang
, "none") ) )
2992 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
2999 /****************************************************************************
3001 * - add meta info to the playlist item
3002 ****************************************************************************/
3003 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
, const vlc_meta_t
*p_meta
)
3005 es_out_sys_t
*p_sys
= out
->p_sys
;
3006 input_thread_t
*p_input
= p_sys
->p_input
;
3007 const es_format_t
*p_fmt_es
= &es
->fmt
;
3010 if( es
->fmt
.i_cat
== fmt
->i_cat
)
3012 es_format_t update
= *fmt
;
3013 update
.i_id
= es
->i_meta_id
;
3014 update
.i_codec
= es
->fmt
.i_codec
;
3015 update
.i_original_fourcc
= es
->fmt
.i_original_fourcc
;
3017 /* Update infos that could have been lost by the decoder (no need to
3018 * dup them since input_item_UpdateTracksInfo() will do it). */
3019 if (update
.psz_language
== NULL
)
3020 update
.psz_language
= es
->fmt
.psz_language
;
3021 if (update
.psz_description
== NULL
)
3022 update
.psz_description
= es
->fmt
.psz_description
;
3023 if (update
.i_cat
== SPU_ES
)
3025 if (update
.subs
.psz_encoding
== NULL
)
3026 update
.subs
.psz_encoding
= es
->fmt
.subs
.psz_encoding
;
3027 if (update
.subs
.p_style
== NULL
)
3028 update
.subs
.p_style
= es
->fmt
.subs
.p_style
;
3030 if (update
.i_extra_languages
== 0)
3032 assert(update
.p_extra_languages
== NULL
);
3033 update
.i_extra_languages
= es
->fmt
.i_extra_languages
;
3034 update
.p_extra_languages
= es
->fmt
.p_extra_languages
;
3037 /* No need to update codec specific data */
3039 update
.p_extra
= NULL
;
3041 input_item_UpdateTracksInfo(input_GetItem(p_input
), &update
);
3044 /* Create category */
3045 char* psz_cat
= EsInfoCategoryName( es
);
3047 if( unlikely( !psz_cat
) )
3050 info_category_t
* p_cat
= info_category_New( psz_cat
);
3054 if( unlikely( !p_cat
) )
3057 /* Add information */
3058 const char *psz_type
;
3059 switch( fmt
->i_cat
)
3062 psz_type
= _("Audio");
3065 psz_type
= _("Video");
3068 psz_type
= _("Subtitle");
3076 info_category_AddInfo( p_cat
, _("Type"), "%s", psz_type
);
3078 if( es
->i_meta_id
!= es
->i_id
)
3079 info_category_AddInfo( p_cat
, _("Original ID"),
3082 const vlc_fourcc_t i_codec_fourcc
= ( p_fmt_es
->i_original_fourcc
)?
3083 p_fmt_es
->i_original_fourcc
: p_fmt_es
->i_codec
;
3084 const char *psz_codec_description
=
3085 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, i_codec_fourcc
);
3086 if( psz_codec_description
&& *psz_codec_description
)
3087 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
3088 psz_codec_description
, (char*)&i_codec_fourcc
);
3089 else if ( i_codec_fourcc
!= VLC_FOURCC(0,0,0,0) )
3090 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
3091 (char*)&i_codec_fourcc
);
3093 if( es
->psz_language
&& *es
->psz_language
)
3094 info_category_AddInfo( p_cat
, _("Language"), "%s",
3096 if( fmt
->psz_description
&& *fmt
->psz_description
)
3097 info_category_AddInfo( p_cat
, _("Description"), "%s",
3098 fmt
->psz_description
);
3100 switch( fmt
->i_cat
)
3103 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
3105 if( fmt
->audio
.i_physical_channels
)
3106 info_category_AddInfo( p_cat
, _("Channels"), "%s",
3107 _( aout_FormatPrintChannels( &fmt
->audio
) ) );
3109 if( fmt
->audio
.i_rate
!= 0 )
3111 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
3112 fmt
->audio
.i_rate
);
3113 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3114 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
3117 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
3118 if( i_bitspersample
== 0 )
3119 i_bitspersample
= aout_BitsPerSample( p_fmt_es
->i_codec
);
3120 if( i_bitspersample
!= 0 )
3121 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
3124 if( fmt
->i_bitrate
!= 0 )
3126 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
3127 fmt
->i_bitrate
/ 1000 );
3128 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3129 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
3131 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
3133 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
3134 if( !p_rg
->pb_gain
[i
] )
3136 const char *psz_name
;
3137 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
3138 psz_name
= _("Track replay gain");
3140 psz_name
= _("Album replay gain");
3141 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
3147 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
3149 if( fmt
->video
.i_visible_width
> 0 &&
3150 fmt
->video
.i_visible_height
> 0 )
3151 info_category_AddInfo( p_cat
, _("Video resolution"), "%ux%u",
3152 fmt
->video
.i_visible_width
,
3153 fmt
->video
.i_visible_height
);
3155 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
3156 info_category_AddInfo( p_cat
, _("Buffer dimensions"), "%ux%u",
3157 fmt
->video
.i_width
, fmt
->video
.i_height
);
3159 if( fmt
->video
.i_frame_rate
> 0 &&
3160 fmt
->video
.i_frame_rate_base
> 0 )
3162 div
= lldiv( (float)fmt
->video
.i_frame_rate
/
3163 fmt
->video
.i_frame_rate_base
* 1000000,
3166 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
".%06u",
3167 div
.quot
, (unsigned int )div
.rem
);
3169 info_category_AddInfo( p_cat
, _("Frame rate"), "%"PRId64
,
3172 if( fmt
->i_codec
!= p_fmt_es
->i_codec
)
3174 const char *psz_chroma_description
=
3175 vlc_fourcc_GetDescription( VIDEO_ES
, fmt
->i_codec
);
3176 if( psz_chroma_description
)
3177 info_category_AddInfo( p_cat
, _("Decoded format"), "%s",
3178 psz_chroma_description
);
3181 static const char orient_names
[][13] = {
3182 N_("Top left"), N_("Left top"),
3183 N_("Right bottom"), N_("Top right"),
3184 N_("Bottom left"), N_("Bottom right"),
3185 N_("Left bottom"), N_("Right top"),
3187 info_category_AddInfo( p_cat
, _("Orientation"), "%s",
3188 _(orient_names
[fmt
->video
.orientation
]) );
3190 if( fmt
->video
.primaries
!= COLOR_PRIMARIES_UNDEF
)
3192 static const char primaries_names
[][32] = {
3193 [COLOR_PRIMARIES_UNDEF
] = N_("Undefined"),
3194 [COLOR_PRIMARIES_BT601_525
] =
3195 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3196 [COLOR_PRIMARIES_BT601_625
] =
3197 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3198 [COLOR_PRIMARIES_BT709
] = "ITU-R BT.709",
3199 [COLOR_PRIMARIES_BT2020
] = "ITU-R BT.2020",
3200 [COLOR_PRIMARIES_DCI_P3
] = "DCI/P3 D65",
3201 [COLOR_PRIMARIES_BT470_M
] = "ITU-R BT.470 M",
3203 static_assert(ARRAY_SIZE(primaries_names
) == COLOR_PRIMARIES_MAX
+1,
3204 "Color primiaries table mismatch");
3205 info_category_AddInfo( p_cat
, _("Color primaries"), "%s",
3206 _(primaries_names
[fmt
->video
.primaries
]) );
3208 if( fmt
->video
.transfer
!= TRANSFER_FUNC_UNDEF
)
3210 static const char func_names
[][20] = {
3211 [TRANSFER_FUNC_UNDEF
] = N_("Undefined"),
3212 [TRANSFER_FUNC_LINEAR
] = N_("Linear"),
3213 [TRANSFER_FUNC_SRGB
] = "sRGB",
3214 [TRANSFER_FUNC_BT470_BG
] = "ITU-R BT.470 BG",
3215 [TRANSFER_FUNC_BT470_M
] = "ITU-R BT.470 M",
3216 [TRANSFER_FUNC_BT709
] = "ITU-R BT.709",
3217 [TRANSFER_FUNC_SMPTE_ST2084
] = "SMPTE ST2084",
3218 [TRANSFER_FUNC_SMPTE_240
] = "SMPTE 240M",
3219 [TRANSFER_FUNC_HLG
] = N_("Hybrid Log-Gamma"),
3221 static_assert(ARRAY_SIZE(func_names
) == TRANSFER_FUNC_MAX
+1,
3222 "Transfer functions table mismatch");
3223 info_category_AddInfo( p_cat
, _("Color transfer function"), "%s",
3224 _(func_names
[fmt
->video
.transfer
]) );
3226 if( fmt
->video
.space
!= COLOR_SPACE_UNDEF
)
3228 static const char space_names
[][16] = {
3229 [COLOR_SPACE_UNDEF
] = N_("Undefined"),
3230 [COLOR_SPACE_BT601
] = "ITU-R BT.601",
3231 [COLOR_SPACE_BT709
] = "ITU-R BT.709",
3232 [COLOR_SPACE_BT2020
] = "ITU-R BT.2020",
3234 static_assert(ARRAY_SIZE(space_names
) == COLOR_SPACE_MAX
+1,
3235 "Color space table mismatch");
3236 info_category_AddInfo( p_cat
, _("Color space"), _("%s Range"),
3237 _(space_names
[fmt
->video
.space
]),
3238 _(fmt
->video
.b_color_range_full
? "Full" : "Limited") );
3240 if( fmt
->video
.chroma_location
!= CHROMA_LOCATION_UNDEF
)
3242 static const char c_loc_names
[][16] = {
3243 [CHROMA_LOCATION_UNDEF
] = N_("Undefined"),
3244 [CHROMA_LOCATION_LEFT
] = N_("Left"),
3245 [CHROMA_LOCATION_CENTER
] = N_("Center"),
3246 [CHROMA_LOCATION_TOP_LEFT
] = N_("Top Left"),
3247 [CHROMA_LOCATION_TOP_CENTER
] = N_("Top Center"),
3248 [CHROMA_LOCATION_BOTTOM_LEFT
] =N_("Bottom Left"),
3249 [CHROMA_LOCATION_BOTTOM_CENTER
] = N_("Bottom Center"),
3251 static_assert(ARRAY_SIZE(c_loc_names
) == CHROMA_LOCATION_MAX
+1,
3252 "Chroma location table mismatch");
3253 info_category_AddInfo( p_cat
, _("Chroma location"), "%s",
3254 _(c_loc_names
[fmt
->video
.chroma_location
]) );
3256 if( fmt
->video
.projection_mode
!= PROJECTION_MODE_RECTANGULAR
)
3258 const char *psz_loc_name
= NULL
;
3259 switch (fmt
->video
.projection_mode
)
3261 case PROJECTION_MODE_RECTANGULAR
:
3262 psz_loc_name
= N_("Rectangular");
3264 case PROJECTION_MODE_EQUIRECTANGULAR
:
3265 psz_loc_name
= N_("Equirectangular");
3267 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
3268 psz_loc_name
= N_("Cubemap");
3271 vlc_assert_unreachable();
3274 info_category_AddInfo( p_cat
, _("Projection"), "%s", _(psz_loc_name
) );
3276 info_category_AddInfo( p_cat
, _("Yaw"), "%.2f",
3277 fmt
->video
.pose
.yaw
);
3278 info_category_AddInfo( p_cat
, _("Pitch"), "%.2f",
3279 fmt
->video
.pose
.pitch
);
3280 info_category_AddInfo( p_cat
, _("Roll"), "%.2f",
3281 fmt
->video
.pose
.roll
);
3282 info_category_AddInfo( p_cat
, _("Field of view"), "%.2f",
3283 fmt
->video
.pose
.fov
);
3285 if ( fmt
->video
.mastering
.max_luminance
)
3287 info_category_AddInfo( p_cat
, _("Max. luminance"), "%.4f cd/m²",
3288 fmt
->video
.mastering
.max_luminance
/ 10000.f
);
3290 if ( fmt
->video
.mastering
.min_luminance
)
3292 info_category_AddInfo( p_cat
, _("Min. luminance"), "%.4f cd/m²",
3293 fmt
->video
.mastering
.min_luminance
/ 10000.f
);
3295 if ( fmt
->video
.mastering
.primaries
[4] &&
3296 fmt
->video
.mastering
.primaries
[5] )
3298 float x
= (float)fmt
->video
.mastering
.primaries
[4] / 50000.f
;
3299 float y
= (float)fmt
->video
.mastering
.primaries
[5] / 50000.f
;
3300 info_category_AddInfo( p_cat
, _("Primary R"), "x=%.4f y=%.4f", x
, y
);
3302 if ( fmt
->video
.mastering
.primaries
[0] &&
3303 fmt
->video
.mastering
.primaries
[1] )
3305 float x
= (float)fmt
->video
.mastering
.primaries
[0] / 50000.f
;
3306 float y
= (float)fmt
->video
.mastering
.primaries
[1] / 50000.f
;
3307 info_category_AddInfo( p_cat
, _("Primary G"), "x=%.4f y=%.4f", x
, y
);
3309 if ( fmt
->video
.mastering
.primaries
[2] &&
3310 fmt
->video
.mastering
.primaries
[3] )
3312 float x
= (float)fmt
->video
.mastering
.primaries
[2] / 50000.f
;
3313 float y
= (float)fmt
->video
.mastering
.primaries
[3] / 50000.f
;
3314 info_category_AddInfo( p_cat
, _("Primary B"), "x=%.4f y=%.4f", x
, y
);
3316 if ( fmt
->video
.mastering
.white_point
[0] &&
3317 fmt
->video
.mastering
.white_point
[1] )
3319 float x
= (float)fmt
->video
.mastering
.white_point
[0] / 50000.f
;
3320 float y
= (float)fmt
->video
.mastering
.white_point
[1] / 50000.f
;
3321 info_category_AddInfo( p_cat
, _("White point"), "x=%.4f y=%.4f", x
, y
);
3323 if ( fmt
->video
.lighting
.MaxCLL
)
3325 info_category_AddInfo( p_cat
, "MaxCLL", "%d cd/m²",
3326 fmt
->video
.lighting
.MaxCLL
);
3328 if ( fmt
->video
.lighting
.MaxFALL
)
3330 info_category_AddInfo( p_cat
, "MaxFALL", "%d cd/m²",
3331 fmt
->video
.lighting
.MaxFALL
);
3336 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
3343 /* Append generic meta */
3346 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
3347 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
3349 char *psz_key
= ppsz_all_keys
[i
];
3350 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
3353 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
3354 vlc_gettext(psz_value
) );
3357 free( ppsz_all_keys
);
3360 input_Control( p_input
, INPUT_REPLACE_INFOS
, p_cat
);
3363 static void EsDeleteInfo( es_out_t
*out
, es_out_id_t
*es
)
3365 char* psz_info_category
;
3367 if( likely( psz_info_category
= EsInfoCategoryName( es
) ) )
3369 input_Control( out
->p_sys
->p_input
, INPUT_DEL_INFO
,
3370 psz_info_category
, NULL
);
3372 free( psz_info_category
);