vlmshell: convert seconds to ticks using vlc_tick_from_sec()
[vlc.git] / src / input / es_out.c
blobcd61ba76e3df5a88fc0db0588ea789dcef31c372
1 /*****************************************************************************
2 * es_out.c: Es Out handler for input.
3 *****************************************************************************
4 * Copyright (C) 2003-2004 VLC authors and VideoLAN
5 * $Id$
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 /*****************************************************************************
26 * Preamble
27 *****************************************************************************/
28 #ifdef HAVE_CONFIG_H
29 # include "config.h"
30 #endif
32 #include <stdio.h>
33 #include <assert.h>
34 #include <vlc_common.h>
36 #include <vlc_input.h>
37 #include <vlc_es_out.h>
38 #include <vlc_block.h>
39 #include <vlc_aout.h>
40 #include <vlc_fourcc.h>
41 #include <vlc_meta.h>
42 #include <vlc_list.h>
44 #include "input_internal.h"
45 #include "../clock/input_clock.h"
46 #include "decoder.h"
47 #include "es_out.h"
48 #include "event.h"
49 #include "info.h"
50 #include "item.h"
52 #include "../stream_output/stream_output.h"
54 #include <vlc_iso_lang.h>
55 /* FIXME we should find a better way than including that */
56 #include "../text/iso-639_def.h"
58 /*****************************************************************************
59 * Local prototypes
60 *****************************************************************************/
61 typedef struct
63 /* Program ID */
64 int i_id;
66 /* Number of es for this pgrm */
67 int i_es;
69 bool b_selected;
70 bool b_scrambled;
72 /* Clock for this program */
73 input_clock_t *p_input_clock;
75 vlc_meta_t *p_meta;
76 struct vlc_list node;
77 } es_out_pgrm_t;
79 struct es_out_id_t
81 /* ES ID */
82 int i_id;
83 es_out_pgrm_t *p_pgrm;
85 /* */
86 bool b_scrambled;
88 /* Channel in the track type */
89 int i_channel;
90 es_format_t fmt;
91 char *psz_language;
92 char *psz_language_code;
94 decoder_t *p_dec;
95 decoder_t *p_dec_record;
97 /* Fields for Video with CC */
98 struct
100 vlc_fourcc_t type;
101 uint64_t i_bitmap; /* channels bitmap */
102 es_out_id_t *pp_es[64]; /* a max of 64 chans for CEA708 */
103 } cc;
105 /* Field for CC track from a master video */
106 es_out_id_t *p_master;
108 /* ID for the meta data */
109 int i_meta_id;
111 struct vlc_list node;
114 typedef struct
116 int i_count; /* es count */
117 es_out_id_t *p_main_es; /* current main es */
118 enum es_out_policy_e e_policy;
120 /* Parameters used for es selection */
121 bool b_autoselect; /* if we want to select an es when no user prefs */
122 int i_id; /* es id as set by es fmt.id */
123 int i_demux_id; /* same as previous, demuxer set default value */
124 int i_channel; /* es number in creation order */
125 char **ppsz_language;
126 } es_out_es_props_t;
128 typedef struct
130 input_thread_t *p_input;
132 /* */
133 vlc_mutex_t lock;
135 /* all programs */
136 struct vlc_list programs;
137 es_out_pgrm_t *p_pgrm; /* Master program */
139 /* all es */
140 int i_id;
141 struct vlc_list es;
142 struct vlc_list es_slaves; /* Dynamically created es on regular es selection */
144 /* mode gestion */
145 bool b_active;
146 int i_mode;
148 es_out_es_props_t video, audio, sub;
150 /* es/group to select */
151 int i_group_id;
153 /* delay */
154 vlc_tick_t i_audio_delay;
155 vlc_tick_t i_spu_delay;
157 /* Clock configuration */
158 vlc_tick_t i_pts_delay;
159 vlc_tick_t i_pts_jitter;
160 int i_cr_average;
161 int i_rate;
163 /* */
164 bool b_paused;
165 vlc_tick_t i_pause_date;
167 /* Current preroll */
168 vlc_tick_t i_preroll_end;
170 /* Used for buffering */
171 bool b_buffering;
172 vlc_tick_t i_buffering_extra_initial;
173 vlc_tick_t i_buffering_extra_stream;
174 vlc_tick_t i_buffering_extra_system;
176 /* Record */
177 sout_instance_t *p_sout_record;
179 /* Used only to limit debugging output */
180 int i_prev_stream_level;
182 es_out_t out;
183 } es_out_sys_t;
185 static void EsOutDel ( es_out_t *, es_out_id_t * );
187 static void EsOutTerminate( es_out_t * );
188 static void EsOutSelect( es_out_t *, es_out_id_t *es, bool b_force );
189 static void EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const es_format_t *, const vlc_meta_t * );
190 static int EsOutSetRecord( es_out_t *, bool b_record );
192 static bool EsIsSelected( es_out_id_t *es );
193 static void EsSelect( es_out_t *out, es_out_id_t *es );
194 static void EsDeleteInfo( es_out_t *, es_out_id_t *es );
195 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update );
196 static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es );
197 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date );
198 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date );
199 static void EsOutProgramsChangeRate( es_out_t *out );
200 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced );
201 static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta );
202 static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_progmeta );
204 static char *LanguageGetName( const char *psz_code );
205 static char *LanguageGetCode( const char *psz_lang );
206 static char **LanguageSplit( const char *psz_langs );
207 static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang );
209 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
210 static char *EsInfoCategoryName( es_out_id_t* es );
212 static inline int EsOutGetClosedCaptionsChannel( const es_format_t *p_fmt )
214 int i_channel;
215 if( p_fmt->i_codec == VLC_CODEC_CEA608 && p_fmt->subs.cc.i_channel < 4 )
216 i_channel = p_fmt->subs.cc.i_channel;
217 else if( p_fmt->i_codec == VLC_CODEC_CEA708 && p_fmt->subs.cc.i_channel < 64 )
218 i_channel = p_fmt->subs.cc.i_channel;
219 else
220 i_channel = -1;
221 return i_channel;
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 #define foreach_es_then_es_slaves( pos ) \
229 for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
230 vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )
233 /*****************************************************************************
234 * Es category specific structs
235 *****************************************************************************/
236 static es_out_es_props_t * GetPropsByCat( es_out_sys_t *p_sys, int i_cat )
238 switch( i_cat )
240 case AUDIO_ES:
241 return &p_sys->audio;
242 case SPU_ES:
243 return &p_sys->sub;
244 case VIDEO_ES:
245 return &p_sys->video;
247 return NULL;
250 static void EsOutPropsCleanup( es_out_es_props_t *p_props )
252 if( p_props->ppsz_language )
254 for( int i = 0; p_props->ppsz_language[i]; i++ )
255 free( p_props->ppsz_language[i] );
256 free( p_props->ppsz_language );
260 static void EsOutPropsInit( es_out_es_props_t *p_props,
261 bool autoselect,
262 input_thread_t *p_input,
263 enum es_out_policy_e e_default_policy,
264 const char *psz_trackidvar,
265 const char *psz_trackvar,
266 const char *psz_langvar,
267 const char *psz_debug )
269 p_props->e_policy = e_default_policy;
270 p_props->i_count = 0;
271 p_props->b_autoselect = autoselect;
272 p_props->i_id = (psz_trackidvar) ? var_GetInteger( p_input, psz_trackidvar ): -1;
273 p_props->i_channel = (psz_trackvar) ? var_GetInteger( p_input, psz_trackvar ): -1;
274 p_props->i_demux_id = -1;
275 p_props->p_main_es = NULL;
277 if( !input_priv(p_input)->b_preparsing && psz_langvar )
279 char *psz_string = var_GetString( p_input, psz_langvar );
280 p_props->ppsz_language = LanguageSplit( psz_string );
281 if( p_props->ppsz_language )
283 for( int i = 0; p_props->ppsz_language[i]; i++ )
284 msg_Dbg( p_input, "selected %s language[%d] %s",
285 psz_debug, i, p_props->ppsz_language[i] );
287 free( psz_string );
291 static const struct es_out_callbacks es_out_cbs;
293 /*****************************************************************************
294 * input_EsOutNew:
295 *****************************************************************************/
296 es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
298 es_out_sys_t *p_sys = calloc( 1, sizeof( *p_sys ) );
299 if( !p_sys )
300 return NULL;
302 p_sys->out.cbs = &es_out_cbs;
304 vlc_mutex_init_recursive( &p_sys->lock );
305 p_sys->p_input = p_input;
307 p_sys->b_active = false;
308 p_sys->i_mode = ES_OUT_MODE_NONE;
310 vlc_list_init(&p_sys->programs);
311 vlc_list_init(&p_sys->es);
312 vlc_list_init(&p_sys->es_slaves);
314 /* */
315 EsOutPropsInit( &p_sys->video, true, p_input, ES_OUT_ES_POLICY_SIMULTANEOUS,
316 NULL, NULL, NULL, NULL );
317 EsOutPropsInit( &p_sys->audio, true, p_input, ES_OUT_ES_POLICY_EXCLUSIVE,
318 "audio-track-id", "audio-track", "audio-language", "audio" );
319 EsOutPropsInit( &p_sys->sub, false, p_input, ES_OUT_ES_POLICY_EXCLUSIVE,
320 "sub-track-id", "sub-track", "sub-language", "sub" );
322 p_sys->i_group_id = var_GetInteger( p_input, "program" );
324 p_sys->i_pause_date = -1;
326 p_sys->i_rate = i_rate;
328 p_sys->b_buffering = true;
329 p_sys->i_preroll_end = -1;
330 p_sys->i_prev_stream_level = -1;
332 return &p_sys->out;
335 /*****************************************************************************
337 *****************************************************************************/
338 static void EsOutDelete( es_out_t *out )
340 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
342 assert(vlc_list_is_empty(&p_sys->es));
343 assert(vlc_list_is_empty(&p_sys->es_slaves));
344 assert(vlc_list_is_empty(&p_sys->programs));
345 assert(p_sys->p_pgrm == NULL);
346 EsOutPropsCleanup( &p_sys->audio );
347 EsOutPropsCleanup( &p_sys->sub );
349 vlc_mutex_destroy( &p_sys->lock );
351 free( p_sys );
354 static void EsOutTerminate( es_out_t *out )
356 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
357 es_out_id_t *es;
359 if( p_sys->p_sout_record )
360 EsOutSetRecord( out, false );
362 foreach_es_then_es_slaves(es)
364 if (es->p_dec != NULL)
365 input_DecoderDelete(es->p_dec);
367 free(es->psz_language);
368 free(es->psz_language_code);
369 es_format_Clean(&es->fmt);
370 vlc_list_remove(&es->node);
371 free(es);
374 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
375 es_out_pgrm_t *p_pgrm;
376 vlc_list_foreach(p_pgrm, &p_sys->programs, node)
378 input_clock_Delete( p_pgrm->p_input_clock );
379 if( p_pgrm->p_meta )
380 vlc_meta_Delete( p_pgrm->p_meta );
382 vlc_list_remove(&p_pgrm->node);
383 free( p_pgrm );
386 p_sys->p_pgrm = NULL;
388 input_item_SetEpgOffline( input_priv(p_sys->p_input)->p_item );
389 input_SendEventMetaEpg( p_sys->p_input );
392 static vlc_tick_t EsOutGetWakeup( es_out_t *out )
394 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
395 input_thread_t *p_input = p_sys->p_input;
397 if( !p_sys->p_pgrm )
398 return 0;
400 /* We do not have a wake up date if the input cannot have its speed
401 * controlled or sout is imposing its own or while buffering
403 * FIXME for !input_priv(p_input)->b_can_pace_control a wake-up time is still needed
404 * to avoid too heavy buffering */
405 if( !input_priv(p_input)->b_can_pace_control ||
406 input_priv(p_input)->b_out_pace_control ||
407 p_sys->b_buffering )
408 return 0;
410 return input_clock_GetWakeup( p_sys->p_pgrm->p_input_clock );
413 static es_out_id_t es_cat[DATA_ES];
415 static es_out_id_t *EsOutGetFromID( es_out_t *out, int i_id )
417 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
418 es_out_id_t *es;
420 if( i_id < 0 )
422 /* Special HACK, -i_id is the cat of the stream */
423 return es_cat - i_id;
426 foreach_es_then_es_slaves(es)
427 if (es->i_id == i_id)
428 return es;
429 return NULL;
432 static bool EsOutDecodersIsEmpty( es_out_t *out )
434 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
435 es_out_id_t *es;
437 if( p_sys->b_buffering && p_sys->p_pgrm )
439 EsOutDecodersStopBuffering( out, true );
440 if( p_sys->b_buffering )
441 return true;
444 foreach_es_then_es_slaves(es)
446 if( es->p_dec && !input_DecoderIsEmpty( es->p_dec ) )
447 return false;
448 if( es->p_dec_record && !input_DecoderIsEmpty( es->p_dec_record ) )
449 return false;
451 return true;
454 static void EsOutSetDelay( es_out_t *out, int i_cat, vlc_tick_t i_delay )
456 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
457 es_out_id_t *es;
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 foreach_es_then_es_slaves(es)
465 EsOutDecoderChangeDelay(out, es);
468 static int EsOutSetRecord( es_out_t *out, bool b_record )
470 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
471 input_thread_t *p_input = p_sys->p_input;
472 es_out_id_t *p_es;
474 assert( ( b_record && !p_sys->p_sout_record ) || ( !b_record && p_sys->p_sout_record ) );
476 if( b_record )
478 char *psz_path = var_CreateGetNonEmptyString( p_input, "input-record-path" );
479 if( !psz_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 );
485 else
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 );
494 if( psz_file )
496 char* psz_file_esc = config_StringEscape( psz_file );
497 if ( psz_file_esc )
499 if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file_esc ) < 0 )
500 psz_sout = NULL;
501 free( psz_file_esc );
503 free( psz_file );
506 free( psz_path );
508 if( !psz_sout )
509 return VLC_EGENERIC;
511 #ifdef ENABLE_SOUT
512 p_sys->p_sout_record = sout_NewInstance( p_input, psz_sout );
513 #endif
514 free( psz_sout );
516 if( !p_sys->p_sout_record )
517 return VLC_EGENERIC;
519 vlc_list_foreach( p_es, &p_sys->es, node ) /* Only master es */
521 if( !p_es->p_dec )
522 continue;
524 p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock, p_sys->p_sout_record );
525 if( p_es->p_dec_record && p_sys->b_buffering )
526 input_DecoderStartWait( p_es->p_dec_record );
529 else
531 vlc_list_foreach( p_es, &p_sys->es, node ) /* Only master es */
533 if( !p_es->p_dec_record )
534 continue;
536 input_DecoderDelete( p_es->p_dec_record );
537 p_es->p_dec_record = NULL;
539 #ifdef ENABLE_SOUT
540 sout_DeleteInstance( p_sys->p_sout_record );
541 #endif
542 p_sys->p_sout_record = NULL;
545 return VLC_SUCCESS;
547 static void EsOutChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date )
549 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
551 /* XXX the order is important */
552 if( b_paused )
554 EsOutDecodersChangePause( out, true, i_date );
555 EsOutProgramChangePause( out, true, i_date );
557 else
559 if( p_sys->i_buffering_extra_initial > 0 )
561 vlc_tick_t i_stream_start;
562 vlc_tick_t i_system_start;
563 vlc_tick_t i_stream_duration;
564 vlc_tick_t i_system_duration;
565 int i_ret;
566 i_ret = input_clock_GetState( p_sys->p_pgrm->p_input_clock,
567 &i_stream_start, &i_system_start,
568 &i_stream_duration, &i_system_duration );
569 if( !i_ret )
571 /* FIXME pcr != exactly what wanted */
572 const vlc_tick_t i_used = /*(i_stream_duration - input_priv(p_sys->p_input)->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
573 i_date -= i_used;
575 p_sys->i_buffering_extra_initial = 0;
576 p_sys->i_buffering_extra_stream = 0;
577 p_sys->i_buffering_extra_system = 0;
579 EsOutProgramChangePause( out, false, i_date );
580 EsOutDecodersChangePause( out, false, i_date );
582 EsOutProgramsChangeRate( out );
584 p_sys->b_paused = b_paused;
585 p_sys->i_pause_date = i_date;
588 static void EsOutChangeRate( es_out_t *out, int i_rate )
590 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
591 float rate = (float)i_rate / (float)INPUT_RATE_DEFAULT;
592 es_out_id_t *es;
594 p_sys->i_rate = i_rate;
595 EsOutProgramsChangeRate( out );
597 foreach_es_then_es_slaves(es)
598 if( es->p_dec != NULL )
599 input_DecoderChangeRate( es->p_dec, rate );
602 static void EsOutChangePosition( es_out_t *out )
604 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
605 es_out_id_t *p_es;
607 input_SendEventCache( p_sys->p_input, 0.0 );
609 foreach_es_then_es_slaves(p_es)
610 if( p_es->p_dec != NULL )
612 input_DecoderFlush( p_es->p_dec );
613 if( !p_sys->b_buffering )
615 input_DecoderStartWait( p_es->p_dec );
616 if( p_es->p_dec_record != NULL )
617 input_DecoderStartWait( p_es->p_dec_record );
621 es_out_pgrm_t *pgrm;
622 vlc_list_foreach(pgrm, &p_sys->programs, node)
623 input_clock_Reset(pgrm->p_input_clock);
625 p_sys->b_buffering = true;
626 p_sys->i_buffering_extra_initial = 0;
627 p_sys->i_buffering_extra_stream = 0;
628 p_sys->i_buffering_extra_system = 0;
629 p_sys->i_preroll_end = -1;
630 p_sys->i_prev_stream_level = -1;
635 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
637 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
638 es_out_id_t *p_es;
640 vlc_tick_t i_stream_start;
641 vlc_tick_t i_system_start;
642 vlc_tick_t i_stream_duration;
643 vlc_tick_t i_system_duration;
644 if (input_clock_GetState( p_sys->p_pgrm->p_input_clock,
645 &i_stream_start, &i_system_start,
646 &i_stream_duration, &i_system_duration ))
647 return;
649 vlc_tick_t i_preroll_duration = 0;
650 if( p_sys->i_preroll_end >= 0 )
651 i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
653 const vlc_tick_t i_buffering_duration = p_sys->i_pts_delay +
654 i_preroll_duration +
655 p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
657 if( i_stream_duration <= i_buffering_duration && !b_forced )
659 double f_level;
660 if (i_buffering_duration == 0)
661 f_level = 0;
662 else
663 f_level = __MAX( (double)i_stream_duration / i_buffering_duration, 0 );
664 input_SendEventCache( p_sys->p_input, f_level );
666 int i_level = (int)(100 * f_level);
667 if( p_sys->i_prev_stream_level != i_level )
669 msg_Dbg( p_sys->p_input, "Buffering %d%%", i_level );
670 p_sys->i_prev_stream_level = i_level;
673 return;
675 input_SendEventCache( p_sys->p_input, 1.0 );
677 msg_Dbg( p_sys->p_input, "Stream buffering done (%d ms in %d ms)",
678 (int)MS_FROM_VLC_TICK(i_stream_duration), (int)MS_FROM_VLC_TICK(i_system_duration) );
679 p_sys->b_buffering = false;
680 p_sys->i_preroll_end = -1;
681 p_sys->i_prev_stream_level = -1;
683 if( p_sys->i_buffering_extra_initial > 0 )
685 /* FIXME wrong ? */
686 return;
689 const vlc_tick_t i_decoder_buffering_start = vlc_tick_now();
690 foreach_es_then_es_slaves(p_es)
692 if( !p_es->p_dec || p_es->fmt.i_cat == SPU_ES )
693 continue;
694 input_DecoderWait( p_es->p_dec );
695 if( p_es->p_dec_record )
696 input_DecoderWait( p_es->p_dec_record );
699 msg_Dbg( p_sys->p_input, "Decoder wait done in %d ms",
700 (int)MS_FROM_VLC_TICK(vlc_tick_now() - i_decoder_buffering_start) );
702 /* Here is a good place to destroy unused vout with every demuxer */
703 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
705 /* */
706 const vlc_tick_t i_wakeup_delay = VLC_TICK_FROM_MS(10); /* FIXME CLEANUP thread wake up time*/
707 const vlc_tick_t i_current_date = p_sys->b_paused ? p_sys->i_pause_date : vlc_tick_now();
709 input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_input_clock, true,
710 i_current_date + i_wakeup_delay - i_buffering_duration );
712 foreach_es_then_es_slaves(p_es)
714 if( !p_es->p_dec )
715 continue;
717 input_DecoderStopWait( p_es->p_dec );
718 if( p_es->p_dec_record )
719 input_DecoderStopWait( p_es->p_dec_record );
722 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date )
724 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
725 es_out_id_t *es;
727 /* Pause decoders first */
728 foreach_es_then_es_slaves(es)
729 if( es->p_dec )
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 );
737 static bool EsOutIsExtraBufferingAllowed( es_out_t *out )
739 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
740 es_out_id_t *p_es;
742 size_t i_size = 0;
743 foreach_es_then_es_slaves(p_es)
745 if( p_es->p_dec )
746 i_size += input_DecoderGetFifoSize( p_es->p_dec );
747 if( p_es->p_dec_record )
748 i_size += input_DecoderGetFifoSize( p_es->p_dec_record );
750 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
752 /* TODO maybe we want to be able to tune it ? */
753 #if defined(OPTIMIZE_MEMORY)
754 const size_t i_level_high = 512*1024; /* 0.5 MiB */
755 #else
756 const size_t i_level_high = 10*1024*1024; /* 10 MiB */
757 #endif
758 return i_size < i_level_high;
761 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, vlc_tick_t i_date )
763 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
764 es_out_pgrm_t *pgrm;
766 vlc_list_foreach(pgrm, &p_sys->programs, node)
767 input_clock_ChangePause(pgrm->p_input_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 = container_of(out, es_out_sys_t, out);
774 vlc_tick_t i_delay;
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;
779 else
780 return;
782 if( p_es->p_dec )
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 = container_of(out, es_out_sys_t, out);
790 es_out_pgrm_t *pgrm;
792 vlc_list_foreach(pgrm, &p_sys->programs, node)
793 input_clock_ChangeRate(pgrm->p_input_clock, p_sys->i_rate);
796 static void EsOutFrameNext( es_out_t *out )
798 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
799 es_out_id_t *p_es_video = NULL, *p_es;
801 if( p_sys->b_buffering )
803 msg_Warn( p_sys->p_input, "buffering, ignoring 'frame next'" );
804 return;
807 assert( p_sys->b_paused );
809 foreach_es_then_es_slaves(p_es)
810 if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec && !p_es_video /* nested loop */ )
812 p_es_video = p_es;
813 break;
816 if( !p_es_video )
818 msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame next'" );
819 return;
822 vlc_tick_t i_duration;
823 input_DecoderFrameNext( p_es_video->p_dec, &i_duration );
825 msg_Dbg( p_sys->p_input, "EsOutFrameNext consummed %d ms", (int)MS_FROM_VLC_TICK(i_duration) );
827 if( i_duration <= 0 )
828 i_duration = VLC_TICK_FROM_MS(40);
830 /* FIXME it is not a clean way ? */
831 if( p_sys->i_buffering_extra_initial <= 0 )
833 vlc_tick_t i_stream_start;
834 vlc_tick_t i_system_start;
835 vlc_tick_t i_stream_duration;
836 vlc_tick_t i_system_duration;
837 int i_ret;
839 i_ret = input_clock_GetState( p_sys->p_pgrm->p_input_clock,
840 &i_stream_start, &i_system_start,
841 &i_stream_duration, &i_system_duration );
842 if( i_ret )
843 return;
845 p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->i_pts_delay; /* FIXME < 0 ? */
846 p_sys->i_buffering_extra_system =
847 p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
850 const int i_rate = input_clock_GetRate( p_sys->p_pgrm->p_input_clock );
852 p_sys->b_buffering = true;
853 p_sys->i_buffering_extra_system += i_duration;
854 p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial +
855 ( p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial ) *
856 INPUT_RATE_DEFAULT / i_rate;
858 p_sys->i_preroll_end = -1;
859 p_sys->i_prev_stream_level = -1;
861 static vlc_tick_t EsOutGetBuffering( es_out_t *out )
863 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
864 vlc_tick_t i_stream_duration, i_system_start;
866 if( !p_sys->p_pgrm )
867 return 0;
868 else
870 vlc_tick_t i_stream_start, i_system_duration;
872 if( input_clock_GetState( p_sys->p_pgrm->p_input_clock,
873 &i_stream_start, &i_system_start,
874 &i_stream_duration, &i_system_duration ) )
875 return 0;
878 vlc_tick_t i_delay;
880 if( p_sys->b_buffering && p_sys->i_buffering_extra_initial <= 0 )
882 i_delay = i_stream_duration;
884 else
886 vlc_tick_t i_system_duration;
888 if( p_sys->b_paused )
890 i_system_duration = p_sys->i_pause_date - i_system_start;
891 if( p_sys->i_buffering_extra_initial > 0 )
892 i_system_duration += p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
894 else
896 i_system_duration = vlc_tick_now() - i_system_start;
899 const vlc_tick_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration;
900 i_delay = p_sys->i_pts_delay - i_consumed;
902 if( i_delay < 0 )
903 return 0;
904 return i_delay;
907 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id,
908 const es_format_t *fmt, const char *psz_language,
909 bool b_delete )
911 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
912 input_thread_t *p_input = p_sys->p_input;
913 vlc_value_t text;
914 size_t count;
916 if( b_delete )
918 if( EsFmtIsTeletext( fmt ) )
919 input_SendEventTeletextDel( p_sys->p_input, i_id );
921 input_SendEventEsDel( p_input, fmt->i_cat, i_id );
922 return;
925 /* Get the number of ES already added */
926 const char *psz_var;
927 if( fmt->i_cat == AUDIO_ES )
928 psz_var = "audio-es";
929 else if( fmt->i_cat == VIDEO_ES )
930 psz_var = "video-es";
931 else
932 psz_var = "spu-es";
934 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &count );
935 if( count == 0 )
937 vlc_value_t val2;
939 /* First one, we need to add the "Disable" choice */
940 val2.i_int = -1;
941 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, val2, _("Disable") );
942 count++;
945 /* Take care of the ES description */
946 if( fmt->psz_description && *fmt->psz_description )
948 if( psz_language && *psz_language )
950 if( asprintf( &text.psz_string, "%s - [%s]", fmt->psz_description,
951 psz_language ) == -1 )
952 text.psz_string = NULL;
954 else text.psz_string = strdup( fmt->psz_description );
956 else
958 if( psz_language && *psz_language )
960 if( asprintf( &text.psz_string, "%s %zu - [%s]", _("Track"), count,
961 psz_language ) == -1 )
962 text.psz_string = NULL;
964 else
966 if( asprintf( &text.psz_string, "%s %zu", _("Track"), count ) == -1 )
967 text.psz_string = NULL;
971 input_SendEventEsAdd( p_input, fmt->i_cat, i_id, text.psz_string );
972 if( EsFmtIsTeletext( fmt ) )
974 char psz_page[3+1];
975 snprintf( psz_page, sizeof(psz_page), "%d%2.2x",
976 fmt->subs.teletext.i_magazine,
977 fmt->subs.teletext.i_page );
978 input_SendEventTeletextAdd( p_sys->p_input,
979 i_id, fmt->subs.teletext.i_magazine >= 0 ? psz_page : NULL );
982 free( text.psz_string );
985 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
986 bool b_delete )
988 EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
991 static bool EsOutIsProgramVisible( es_out_t *out, int i_group )
993 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
994 return p_sys->i_group_id == 0 || p_sys->i_group_id == i_group;
997 /* EsOutProgramSelect:
998 * Select a program and update the object variable
1000 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
1002 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1003 input_thread_t *p_input = p_sys->p_input;
1004 es_out_id_t *es;
1006 if( p_sys->p_pgrm == p_pgrm )
1007 return; /* Nothing to do */
1009 if( p_sys->p_pgrm )
1011 es_out_pgrm_t *old = p_sys->p_pgrm;
1013 msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
1015 foreach_es_then_es_slaves(es)
1016 if (es->p_pgrm == old && EsIsSelected(es)
1017 && p_sys->i_mode != ES_OUT_MODE_ALL)
1018 EsUnselect(out, es, true);
1020 p_sys->audio.p_main_es = NULL;
1021 p_sys->video.p_main_es = NULL;
1022 p_sys->sub.p_main_es = NULL;
1025 msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
1027 /* Mark it selected */
1028 p_pgrm->b_selected = true;
1030 /* Switch master stream */
1031 p_sys->p_pgrm = p_pgrm;
1033 /* Update "program" */
1034 input_SendEventProgramSelect( p_input, p_pgrm->i_id );
1036 /* Update "es-*" */
1037 input_SendEventEsDel( p_input, AUDIO_ES, -1 );
1038 input_SendEventEsDel( p_input, VIDEO_ES, -1 );
1039 input_SendEventEsDel( p_input, SPU_ES, -1 );
1040 input_SendEventTeletextDel( p_input, -1 );
1041 input_SendEventProgramScrambled( p_input, p_pgrm->i_id, p_pgrm->b_scrambled );
1043 /* TODO event */
1044 var_SetInteger( p_input, "teletext-es", -1 );
1046 foreach_es_then_es_slaves(es)
1048 if (es->p_pgrm == p_sys->p_pgrm)
1050 EsOutESVarUpdate(out, es, false);
1051 EsOutUpdateInfo(out, es, &es->fmt, NULL);
1054 EsOutSelect(out, es, false);
1057 /* Ensure the correct running EPG table is selected */
1058 input_item_ChangeEPGSource( input_priv(p_input)->p_item, p_pgrm->i_id );
1060 /* Update now playing */
1061 if( p_pgrm->p_meta )
1063 input_item_SetESNowPlaying( input_priv(p_input)->p_item,
1064 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_ESNowPlaying ) );
1065 input_item_SetPublisher( input_priv(p_input)->p_item,
1066 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Publisher ) );
1067 input_item_SetTitle( input_priv(p_input)->p_item,
1068 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) );
1069 input_SendEventMeta( p_input );
1070 /* FIXME: we probably want to replace every input meta */
1074 /* EsOutAddProgram:
1075 * Add a program
1077 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
1079 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1080 input_thread_t *p_input = p_sys->p_input;
1082 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
1083 if( !p_pgrm )
1084 return NULL;
1086 /* Init */
1087 p_pgrm->i_id = i_group;
1088 p_pgrm->i_es = 0;
1089 p_pgrm->b_selected = false;
1090 p_pgrm->b_scrambled = false;
1091 p_pgrm->p_meta = NULL;
1092 p_pgrm->p_input_clock = input_clock_New( p_sys->i_rate );
1093 if( !p_pgrm->p_input_clock )
1095 free( p_pgrm );
1096 return NULL;
1098 if( p_sys->b_paused )
1099 input_clock_ChangePause( p_pgrm->p_input_clock, p_sys->b_paused, p_sys->i_pause_date );
1100 input_clock_SetJitter( p_pgrm->p_input_clock, p_sys->i_pts_delay, p_sys->i_cr_average );
1102 /* Append it */
1103 vlc_list_append(&p_pgrm->node, &p_sys->programs);
1105 /* Update "program" variable */
1106 if( EsOutIsProgramVisible( out, i_group ) )
1107 input_SendEventProgramAdd( p_input, i_group, NULL );
1109 if( i_group == p_sys->i_group_id || ( !p_sys->p_pgrm && p_sys->i_group_id == 0 ) )
1110 EsOutProgramSelect( out, p_pgrm );
1112 return p_pgrm;
1115 /* EsOutDelProgram:
1116 * Delete a program
1118 static int EsOutProgramDel( es_out_t *out, int i_group )
1120 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1121 input_thread_t *p_input = p_sys->p_input;
1122 es_out_pgrm_t *p_pgrm = NULL, *pgrm;
1124 vlc_list_foreach(pgrm, &p_sys->programs, node)
1125 if (pgrm->i_id == i_group)
1127 p_pgrm = pgrm;
1128 break;
1131 if( p_pgrm == NULL )
1132 return VLC_EGENERIC;
1134 if( p_pgrm->i_es )
1136 msg_Dbg( p_input, "can't delete program %d which still has %i ES",
1137 i_group, p_pgrm->i_es );
1138 return VLC_EGENERIC;
1141 vlc_list_remove(&p_pgrm->node);
1143 /* If program is selected we need to unselect it */
1144 if( p_sys->p_pgrm == p_pgrm )
1145 p_sys->p_pgrm = NULL;
1147 input_clock_Delete( p_pgrm->p_input_clock );
1149 if( p_pgrm->p_meta )
1150 vlc_meta_Delete( p_pgrm->p_meta );
1151 free( p_pgrm );
1153 /* Update "program" variable */
1154 input_SendEventProgramDel( p_input, i_group );
1156 return VLC_SUCCESS;
1159 /* EsOutProgramFind
1161 static es_out_pgrm_t *EsOutProgramFind( es_out_t *p_out, int i_group )
1163 es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
1164 es_out_pgrm_t *pgrm;
1166 vlc_list_foreach(pgrm, &p_sys->programs, node)
1167 if (pgrm->i_id == i_group)
1168 return pgrm;
1170 return EsOutProgramAdd( p_out, i_group );
1173 /* EsOutProgramMeta:
1175 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
1177 char *psz = NULL;
1178 if( p_pgrm->p_meta && vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) )
1180 if( asprintf( &psz, _("%s [%s %d]"), vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ),
1181 _("Program"), p_pgrm->i_id ) == -1 )
1182 return NULL;
1184 else
1186 if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
1187 return NULL;
1189 return psz;
1192 static char *EsOutProgramGetProgramName( es_out_pgrm_t *p_pgrm )
1194 char *psz = NULL;
1195 if( p_pgrm->p_meta && vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) )
1197 return strdup( vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) );
1199 else
1201 if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
1202 return NULL;
1204 return psz;
1207 static char *EsInfoCategoryName( es_out_id_t* es )
1209 char *psz_category;
1211 if( asprintf( &psz_category, _("Stream %d"), es->i_meta_id ) == -1 )
1212 return NULL;
1214 return psz_category;
1217 static void EsOutProgramMeta( es_out_t *out, int i_group, const vlc_meta_t *p_meta )
1219 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1220 es_out_pgrm_t *p_pgrm;
1221 input_thread_t *p_input = p_sys->p_input;
1222 const char *psz_title = NULL;
1223 const char *psz_provider = NULL;
1224 int i;
1226 msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
1228 /* Check against empty meta data (empty for what we handle) */
1229 if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
1230 !vlc_meta_Get( p_meta, vlc_meta_ESNowPlaying) &&
1231 !vlc_meta_Get( p_meta, vlc_meta_Publisher) )
1233 return;
1236 if( i_group < 0 )
1238 EsOutGlobalMeta( out, p_meta );
1239 return;
1242 /* Find program */
1243 if( !EsOutIsProgramVisible( out, i_group ) )
1244 return;
1245 p_pgrm = EsOutProgramFind( out, i_group );
1246 if( !p_pgrm )
1247 return;
1249 if( p_pgrm->p_meta )
1251 const char *psz_current_title = vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title );
1252 const char *psz_new_title = vlc_meta_Get( p_meta, vlc_meta_Title );
1253 if( (psz_current_title != NULL && psz_new_title != NULL)
1254 ? strcmp(psz_new_title, psz_current_title)
1255 : (psz_current_title != psz_new_title) )
1257 /* Remove old entries */
1258 char *psz_oldinfokey = EsOutProgramGetMetaName( p_pgrm );
1259 input_Control( p_input, INPUT_DEL_INFO, psz_oldinfokey, NULL );
1260 /* TODO update epg name ?
1261 * TODO update scrambled info name ? */
1262 free( psz_oldinfokey );
1264 vlc_meta_Delete( p_pgrm->p_meta );
1266 p_pgrm->p_meta = vlc_meta_New();
1267 if( p_pgrm->p_meta )
1268 vlc_meta_Merge( p_pgrm->p_meta, p_meta );
1270 if( p_sys->p_pgrm == p_pgrm )
1272 EsOutMeta( out, NULL, p_meta );
1274 /* */
1275 psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
1276 psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
1278 /* Update the description text of the program */
1279 if( psz_title && *psz_title )
1281 char *psz_text;
1282 if( psz_provider && *psz_provider )
1284 if( asprintf( &psz_text, "%s [%s]", psz_title, psz_provider ) < 0 )
1285 psz_text = NULL;
1287 else
1289 psz_text = strdup( psz_title );
1292 /* ugly but it works */
1293 if( psz_text )
1295 input_SendEventProgramDel( p_input, i_group );
1296 input_SendEventProgramAdd( p_input, i_group, psz_text );
1297 if( p_sys->p_pgrm == p_pgrm )
1298 input_SendEventProgramSelect( p_input, i_group );
1299 free( psz_text );
1303 /* */
1304 char **ppsz_all_keys = vlc_meta_CopyExtraNames(p_meta );
1306 info_category_t *p_cat = NULL;
1307 if( psz_provider || ( ppsz_all_keys[0] && *ppsz_all_keys[0] ) )
1309 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
1310 if( psz_cat )
1311 p_cat = info_category_New( psz_cat );
1312 free( psz_cat );
1315 for( i = 0; ppsz_all_keys[i]; i++ )
1317 if( p_cat )
1318 info_category_AddInfo( p_cat, vlc_gettext(ppsz_all_keys[i]), "%s",
1319 vlc_meta_GetExtra( p_meta, ppsz_all_keys[i] ) );
1320 free( ppsz_all_keys[i] );
1322 free( ppsz_all_keys );
1324 if( psz_provider )
1326 if( p_sys->p_pgrm == p_pgrm )
1328 input_item_SetPublisher( input_priv(p_input)->p_item, psz_provider );
1329 input_SendEventMeta( p_input );
1331 if( p_cat )
1332 info_category_AddInfo( p_cat, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher),
1333 "%s",psz_provider );
1335 if( p_cat )
1336 input_Control( p_input, INPUT_MERGE_INFOS, p_cat );
1339 static void EsOutProgramEpgEvent( es_out_t *out, int i_group, const vlc_epg_event_t *p_event )
1341 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1342 input_thread_t *p_input = p_sys->p_input;
1343 input_item_t *p_item = input_priv(p_input)->p_item;
1344 es_out_pgrm_t *p_pgrm;
1346 /* Find program */
1347 if( !EsOutIsProgramVisible( out, i_group ) )
1348 return;
1349 p_pgrm = EsOutProgramFind( out, i_group );
1350 if( !p_pgrm )
1351 return;
1353 input_item_SetEpgEvent( p_item, p_event );
1356 static void EsOutProgramEpg( es_out_t *out, int i_group, const vlc_epg_t *p_epg )
1358 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1359 input_thread_t *p_input = p_sys->p_input;
1360 input_item_t *p_item = input_priv(p_input)->p_item;
1361 es_out_pgrm_t *p_pgrm;
1362 char *psz_cat;
1364 /* Find program */
1365 if( !EsOutIsProgramVisible( out, i_group ) )
1366 return;
1367 p_pgrm = EsOutProgramFind( out, i_group );
1368 if( !p_pgrm )
1369 return;
1371 /* Update info */
1372 psz_cat = EsOutProgramGetMetaName( p_pgrm );
1373 msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, psz_cat );
1375 /* Merge EPG */
1376 vlc_epg_t epg;
1378 epg = *p_epg;
1379 epg.psz_name = EsOutProgramGetProgramName( p_pgrm );
1381 input_item_SetEpg( p_item, &epg, p_sys->p_pgrm && (p_epg->i_source_id == p_sys->p_pgrm->i_id) );
1382 input_SendEventMetaEpg( p_sys->p_input );
1384 free( epg.psz_name );
1386 /* Update now playing */
1387 if( p_epg->b_present && p_pgrm->p_meta &&
1388 ( p_epg->p_current || p_epg->i_event == 0 ) )
1390 vlc_meta_SetNowPlaying( p_pgrm->p_meta, NULL );
1393 vlc_mutex_lock( &p_item->lock );
1394 for( int i = 0; i < p_item->i_epg; i++ )
1396 const vlc_epg_t *p_tmp = p_item->pp_epg[i];
1398 if( p_tmp->b_present && p_tmp->i_source_id == p_pgrm->i_id )
1400 const char *psz_name = ( p_tmp->p_current ) ? p_tmp->p_current->psz_name : NULL;
1401 if( !p_pgrm->p_meta )
1402 p_pgrm->p_meta = vlc_meta_New();
1403 if( p_pgrm->p_meta )
1404 vlc_meta_Set( p_pgrm->p_meta, vlc_meta_ESNowPlaying, psz_name );
1405 break;
1408 vlc_mutex_unlock( &p_item->lock );
1410 /* Update selected program input info */
1411 if( p_pgrm == p_sys->p_pgrm )
1413 const char *psz_nowplaying = p_pgrm->p_meta ?
1414 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_ESNowPlaying ) : NULL;
1416 input_item_SetESNowPlaying( input_priv(p_input)->p_item, psz_nowplaying );
1417 input_SendEventMeta( p_input );
1419 if( psz_nowplaying )
1421 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1422 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying), "%s", psz_nowplaying );
1424 else
1426 input_Control( p_input, INPUT_DEL_INFO, psz_cat,
1427 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying) );
1431 free( psz_cat );
1434 static void EsOutEpgTime( es_out_t *out, int64_t time )
1436 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1437 input_thread_t *p_input = p_sys->p_input;
1438 input_item_t *p_item = input_priv(p_input)->p_item;
1440 input_item_SetEpgTime( p_item, time );
1443 static void EsOutProgramUpdateScrambled( es_out_t *p_out, es_out_pgrm_t *p_pgrm )
1445 es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
1446 input_thread_t *p_input = p_sys->p_input;
1447 es_out_id_t *es;
1448 bool b_scrambled = false;
1450 vlc_list_foreach( es, &p_sys->es, node ) /* Only master es */
1451 if (es->p_pgrm == p_pgrm && es->b_scrambled)
1453 b_scrambled = true;
1454 break;
1457 if( !p_pgrm->b_scrambled == !b_scrambled )
1458 return;
1460 p_pgrm->b_scrambled = b_scrambled;
1461 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
1463 if( b_scrambled )
1464 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Scrambled"), _("Yes") );
1465 else
1466 input_Control( p_input, INPUT_DEL_INFO, psz_cat, _("Scrambled") );
1467 free( psz_cat );
1469 input_SendEventProgramScrambled( p_input, p_pgrm->i_id, b_scrambled );
1472 static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_program_meta )
1474 es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
1475 input_thread_t *p_input = p_sys->p_input;
1476 input_item_t *p_item = input_GetItem( p_input );
1478 vlc_mutex_lock( &p_item->lock );
1479 if( p_meta )
1480 vlc_meta_Merge( p_item->p_meta, p_meta );
1481 vlc_mutex_unlock( &p_item->lock );
1483 /* Check program meta to not override GROUP_META values */
1484 if( p_meta && (!p_program_meta || vlc_meta_Get( p_program_meta, vlc_meta_Title ) == NULL) &&
1485 vlc_meta_Get( p_meta, vlc_meta_Title ) != NULL )
1486 input_item_SetName( p_item, vlc_meta_Get( p_meta, vlc_meta_Title ) );
1488 const char *psz_arturl = NULL;
1489 char *psz_alloc = NULL;
1491 if( p_program_meta )
1492 psz_arturl = vlc_meta_Get( p_program_meta, vlc_meta_ArtworkURL );
1493 if( psz_arturl == NULL && p_meta )
1494 psz_arturl = vlc_meta_Get( p_meta, vlc_meta_ArtworkURL );
1496 if( psz_arturl == NULL ) /* restore/favor previously set item art URL */
1497 psz_arturl = psz_alloc = input_item_GetArtURL( p_item );
1499 if( psz_arturl != NULL )
1500 input_item_SetArtURL( p_item, psz_arturl );
1502 if( psz_arturl != NULL && !strncmp( psz_arturl, "attachment://", 13 ) )
1503 { /* Clear art cover if streaming out.
1504 * FIXME: Why? Remove this when sout gets meta data support. */
1505 if( input_priv(p_input)->p_sout != NULL )
1506 input_item_SetArtURL( p_item, NULL );
1507 else
1508 input_ExtractAttachmentAndCacheArt( p_input, psz_arturl + 13 );
1510 free( psz_alloc );
1512 input_item_SetPreparsed( p_item, true );
1514 input_SendEventMeta( p_input );
1515 /* TODO handle sout meta ? */
1518 static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta )
1520 es_out_sys_t *p_sys = container_of(p_out, es_out_sys_t, out);
1521 EsOutMeta( p_out, p_meta,
1522 (p_sys->p_pgrm && p_sys->p_pgrm->p_meta) ? p_sys->p_pgrm->p_meta : NULL );
1525 static es_out_id_t *EsOutAddSlave( es_out_t *out, const es_format_t *fmt, es_out_id_t *p_master )
1527 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1528 input_thread_t *p_input = p_sys->p_input;
1530 if( fmt->i_group < 0 )
1532 msg_Err( p_input, "invalid group number" );
1533 return NULL;
1536 es_out_id_t *es = malloc( sizeof( *es ) );
1537 es_out_pgrm_t *p_pgrm;
1538 int i;
1540 if( !es )
1541 return NULL;
1543 vlc_mutex_lock( &p_sys->lock );
1545 /* Search the program */
1546 p_pgrm = EsOutProgramFind( out, fmt->i_group );
1547 if( !p_pgrm )
1549 vlc_mutex_unlock( &p_sys->lock );
1550 free( es );
1551 return NULL;
1554 /* Increase ref count for program */
1555 p_pgrm->i_es++;
1557 /* Set up ES */
1558 es->p_pgrm = p_pgrm;
1559 es_format_Copy( &es->fmt, fmt );
1560 if( es->fmt.i_id < 0 )
1561 es->fmt.i_id = p_sys->i_id;
1562 if( !es->fmt.i_original_fourcc )
1563 es->fmt.i_original_fourcc = es->fmt.i_codec;
1565 es->i_id = es->fmt.i_id;
1566 es->i_meta_id = p_sys->i_id++; /* always incremented */
1567 es->b_scrambled = false;
1569 switch( es->fmt.i_cat )
1571 case AUDIO_ES:
1573 es->fmt.i_codec = vlc_fourcc_GetCodecAudio( es->fmt.i_codec,
1574 es->fmt.audio.i_bitspersample );
1575 es->i_channel = p_sys->audio.i_count++;
1577 audio_replay_gain_t rg;
1578 memset( &rg, 0, sizeof(rg) );
1579 vlc_mutex_lock( &input_priv(p_input)->p_item->lock );
1580 vlc_audio_replay_gain_MergeFromMeta( &rg, input_priv(p_input)->p_item->p_meta );
1581 vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
1583 for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
1585 if( !es->fmt.audio_replay_gain.pb_peak[i] )
1587 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
1588 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
1590 if( !es->fmt.audio_replay_gain.pb_gain[i] )
1592 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
1593 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
1596 break;
1599 case VIDEO_ES:
1600 es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat, es->fmt.i_codec );
1601 es->i_channel = p_sys->video.i_count++;
1603 if( !es->fmt.video.i_visible_width || !es->fmt.video.i_visible_height )
1605 es->fmt.video.i_visible_width = es->fmt.video.i_width;
1606 es->fmt.video.i_visible_height = es->fmt.video.i_height;
1609 if( es->fmt.video.i_frame_rate && es->fmt.video.i_frame_rate_base )
1610 vlc_ureduce( &es->fmt.video.i_frame_rate,
1611 &es->fmt.video.i_frame_rate_base,
1612 es->fmt.video.i_frame_rate,
1613 es->fmt.video.i_frame_rate_base, 0 );
1614 break;
1616 case SPU_ES:
1617 es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat, es->fmt.i_codec );
1618 es->i_channel = p_sys->sub.i_count++;
1619 break;
1621 default:
1622 es->i_channel = 0;
1623 break;
1625 es->psz_language = LanguageGetName( es->fmt.psz_language ); /* remember so we only need to do it once */
1626 es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
1627 es->p_dec = NULL;
1628 es->p_dec_record = NULL;
1629 es->cc.type = 0;
1630 es->cc.i_bitmap = 0;
1631 es->p_master = p_master;
1633 vlc_list_append(&es->node, es->p_master ? &p_sys->es_slaves : &p_sys->es);
1635 if( es->p_pgrm == p_sys->p_pgrm )
1636 EsOutESVarUpdate( out, es, false );
1638 EsOutUpdateInfo( out, es, &es->fmt, NULL );
1639 EsOutSelect( out, es, false );
1641 if( es->b_scrambled )
1642 EsOutProgramUpdateScrambled( out, es->p_pgrm );
1644 vlc_mutex_unlock( &p_sys->lock );
1646 return es;
1649 /* EsOutAdd:
1650 * Add an es_out
1652 static es_out_id_t *EsOutAdd( es_out_t *out, const es_format_t *fmt )
1654 return EsOutAddSlave( out, fmt, NULL );
1657 static bool EsIsSelected( es_out_id_t *es )
1659 if( es->p_master )
1661 bool b_decode = false;
1662 if( es->p_master->p_dec )
1664 int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
1665 input_DecoderGetCcState( es->p_master->p_dec, es->fmt.i_codec,
1666 i_channel, &b_decode );
1668 return b_decode;
1670 else
1672 return es->p_dec != NULL;
1675 static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
1677 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1678 input_thread_t *p_input = p_sys->p_input;
1679 decoder_t *dec;
1681 dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock,
1682 input_priv(p_input)->p_sout );
1683 if( dec != NULL )
1685 float rate = (float)p_sys->i_rate / (float)INPUT_RATE_DEFAULT;
1687 input_DecoderChangeRate( dec, rate );
1689 if( p_sys->b_buffering )
1690 input_DecoderStartWait( dec );
1692 if( !p_es->p_master && p_sys->p_sout_record )
1694 p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_input_clock, p_sys->p_sout_record );
1695 if( p_es->p_dec_record && p_sys->b_buffering )
1696 input_DecoderStartWait( p_es->p_dec_record );
1699 p_es->p_dec = dec;
1701 EsOutDecoderChangeDelay( out, p_es );
1703 static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
1705 VLC_UNUSED(out);
1707 if( !p_es->p_dec )
1708 return;
1710 input_DecoderDelete( p_es->p_dec );
1711 p_es->p_dec = NULL;
1713 if( p_es->p_dec_record )
1715 input_DecoderDelete( p_es->p_dec_record );
1716 p_es->p_dec_record = NULL;
1720 static void EsSelect( es_out_t *out, es_out_id_t *es )
1722 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1723 input_thread_t *p_input = p_sys->p_input;
1725 if( EsIsSelected( es ) )
1727 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1728 return;
1731 if( es->p_master )
1733 int i_channel;
1734 if( !es->p_master->p_dec )
1735 return;
1737 i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
1739 if( i_channel == -1 ||
1740 input_DecoderSetCcState( es->p_master->p_dec, es->fmt.i_codec,
1741 i_channel, true ) )
1742 return;
1744 else
1746 const bool b_sout = input_priv(p_input)->p_sout != NULL;
1747 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1749 if( !var_GetBool( p_input, b_sout ? "sout-video" : "video" ) )
1751 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1752 es->i_id );
1753 return;
1756 else if( es->fmt.i_cat == AUDIO_ES )
1758 if( !var_GetBool( p_input, b_sout ? "sout-audio" : "audio" ) )
1760 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1761 es->i_id );
1762 return;
1765 if( es->fmt.i_cat == SPU_ES )
1767 if( !var_GetBool( p_input, b_sout ? "sout-spu" : "spu" ) )
1769 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1770 es->i_id );
1771 return;
1775 EsCreateDecoder( out, es );
1777 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1778 return;
1781 /* Mark it as selected */
1782 input_SendEventEsSelect( p_input, es->fmt.i_cat, es->i_id );
1783 input_SendEventTeletextSelect( p_input, EsFmtIsTeletext( &es->fmt ) ? es->i_id : -1 );
1786 static void EsDeleteCCChannels( es_out_t *out, es_out_id_t *parent )
1788 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1789 input_thread_t *p_input = p_sys->p_input;
1791 if( parent->cc.type == 0 )
1792 return;
1794 const int i_spu_id = var_GetInteger( p_input, "spu-es");
1796 uint64_t i_bitmap = parent->cc.i_bitmap;
1797 for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1 )
1799 if( (i_bitmap & 1) == 0 || !parent->cc.pp_es[i] )
1800 continue;
1802 if( i_spu_id == parent->cc.pp_es[i]->i_id )
1804 /* Force unselection of the CC */
1805 input_SendEventEsSelect( p_input, SPU_ES, -1 );
1807 EsOutDel( out, parent->cc.pp_es[i] );
1810 parent->cc.i_bitmap = 0;
1811 parent->cc.type = 0;
1814 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1816 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1817 input_thread_t *p_input = p_sys->p_input;
1819 if( !EsIsSelected( es ) )
1821 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1822 return;
1825 if( es->p_master )
1827 if( es->p_master->p_dec )
1829 int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
1830 if( i_channel != -1 )
1831 input_DecoderSetCcState( es->p_master->p_dec, es->fmt.i_codec,
1832 i_channel, false );
1835 else
1837 EsDeleteCCChannels( out, es );
1838 EsDestroyDecoder( out, es );
1841 if( !b_update )
1842 return;
1844 /* Mark it as unselected */
1845 input_SendEventEsSelect( p_input, es->fmt.i_cat, -1 );
1846 if( EsFmtIsTeletext( &es->fmt ) )
1847 input_SendEventTeletextSelect( p_input, -1 );
1851 * Select an ES given the current mode
1852 * XXX: you need to take a the lock before (stream.stream_lock)
1854 * \param out The es_out structure
1855 * \param es es_out_id structure
1856 * \param b_force ...
1857 * \return nothing
1859 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1861 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
1862 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, es->fmt.i_cat );
1864 if( !p_sys->b_active ||
1865 ( !b_force && es->fmt.i_priority < ES_PRIORITY_SELECTABLE_MIN ) )
1867 return;
1870 bool b_auto_unselect = p_esprops && p_sys->i_mode == ES_OUT_MODE_AUTO &&
1871 p_esprops->e_policy == ES_OUT_ES_POLICY_EXCLUSIVE &&
1872 p_esprops->p_main_es && p_esprops->p_main_es != es;
1874 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1876 if( !EsIsSelected( es ) )
1878 if( b_auto_unselect )
1879 EsUnselect( out, p_esprops->p_main_es, false );
1881 EsSelect( out, es );
1884 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1886 char *prgms = var_GetNonEmptyString( p_sys->p_input, "programs" );
1887 if( prgms != NULL )
1889 char *buf;
1891 for ( const char *prgm = strtok_r( prgms, ",", &buf );
1892 prgm != NULL;
1893 prgm = strtok_r( NULL, ",", &buf ) )
1895 if( atoi( prgm ) == es->p_pgrm->i_id || b_force )
1897 if( !EsIsSelected( es ) )
1898 EsSelect( out, es );
1899 break;
1902 free( prgms );
1905 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1907 const es_out_id_t *wanted_es = NULL;
1909 if( es->p_pgrm != p_sys->p_pgrm || !p_esprops )
1910 return;
1912 /* user designated by ID ES have higher prio than everything */
1913 if ( p_esprops->i_id >= 0 )
1915 if( es->i_id == p_esprops->i_id )
1916 wanted_es = es;
1918 /* then per pos */
1919 else if( p_esprops->i_channel >= 0 )
1921 if( p_esprops->i_channel == es->i_channel )
1922 wanted_es = es;
1924 else if( p_esprops->ppsz_language )
1926 /* If not deactivated */
1927 const int i_stop_idx = LanguageArrayIndex( p_esprops->ppsz_language, "none" );
1929 int current_es_idx = ( p_esprops->p_main_es == NULL ) ? -1 :
1930 LanguageArrayIndex( p_esprops->ppsz_language,
1931 p_esprops->p_main_es->psz_language_code );
1932 int es_idx = LanguageArrayIndex( p_esprops->ppsz_language,
1933 es->psz_language_code );
1934 if( es_idx >= 0 && (i_stop_idx < 0 || i_stop_idx > es_idx) )
1936 /* Only select the language if it's in the list */
1937 if( p_esprops->p_main_es == NULL ||
1938 current_es_idx < 0 || /* current es was not selected by lang prefs */
1939 es_idx < current_es_idx || /* current es has lower lang prio */
1940 ( es_idx == current_es_idx && /* lang is same, but es has higher prio */
1941 p_esprops->p_main_es->fmt.i_priority < es->fmt.i_priority ) )
1943 wanted_es = es;
1946 /* We did not find a language matching our prefs */
1947 else if( i_stop_idx < 0 ) /* If not fallback disabled by 'none' */
1949 /* Select if asked by demuxer */
1950 if( current_es_idx < 0 ) /* No es is currently selected by lang pref */
1952 /* If demux has specified a track */
1953 if( p_esprops->i_demux_id >= 0 && es->i_id == p_esprops->i_demux_id )
1955 wanted_es = es;
1957 /* Otherwise, fallback by priority */
1958 else if( p_esprops->p_main_es == NULL ||
1959 es->fmt.i_priority > p_esprops->p_main_es->fmt.i_priority )
1961 if( p_esprops->b_autoselect )
1962 wanted_es = es;
1969 /* If there is no user preference, select the default subtitle
1970 * or adapt by ES priority */
1971 else if( p_esprops->i_demux_id >= 0 && es->i_id == p_esprops->i_demux_id )
1973 wanted_es = es;
1975 else if( p_esprops->p_main_es == NULL ||
1976 es->fmt.i_priority > p_esprops->p_main_es->fmt.i_priority )
1978 if( p_esprops->b_autoselect )
1979 wanted_es = es;
1982 if( wanted_es == es && !EsIsSelected( es ) )
1984 if( b_auto_unselect )
1985 EsUnselect( out, p_esprops->p_main_es, false );
1987 EsSelect( out, es );
1991 /* FIXME TODO handle priority here */
1992 if( p_esprops && p_sys->i_mode == ES_OUT_MODE_AUTO && EsIsSelected( es ) )
1993 p_esprops->p_main_es = es;
1996 static void EsOutCreateCCChannels( es_out_t *out, vlc_fourcc_t codec, uint64_t i_bitmap,
1997 const char *psz_descfmt, es_out_id_t *parent )
1999 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
2000 input_thread_t *p_input = p_sys->p_input;
2002 /* Only one type of captions is allowed ! */
2003 if( parent->cc.type && parent->cc.type != codec )
2004 return;
2006 uint64_t i_existingbitmap = parent->cc.i_bitmap;
2007 for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1, i_existingbitmap >>= 1 )
2009 es_format_t fmt;
2011 if( (i_bitmap & 1) == 0 || (i_existingbitmap & 1) )
2012 continue;
2014 msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, parent->i_id );
2016 es_format_Init( &fmt, SPU_ES, codec );
2017 fmt.subs.cc.i_channel = i;
2018 fmt.i_group = parent->fmt.i_group;
2019 if( asprintf( &fmt.psz_description, psz_descfmt, 1 + i ) == -1 )
2020 fmt.psz_description = NULL;
2022 es_out_id_t **pp_es = &parent->cc.pp_es[i];
2023 *pp_es = EsOutAddSlave( out, &fmt, parent );
2024 es_format_Clean( &fmt );
2026 /* */
2027 parent->cc.i_bitmap |= (1ULL << i);
2028 parent->cc.type = codec;
2030 /* Enable if user specified on command line */
2031 if (p_sys->sub.i_channel == i)
2032 EsOutSelect(out, *pp_es, true);
2037 * Send a block for the given es_out
2039 * \param out the es_out to send from
2040 * \param es the es_out_id
2041 * \param p_block the data block to send
2043 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
2045 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
2046 input_thread_t *p_input = p_sys->p_input;
2048 assert( p_block->p_next == NULL );
2050 struct input_stats *stats = input_priv(p_input)->stats;
2051 if( stats != NULL )
2053 input_rate_Add( &stats->demux_bitrate, p_block->i_buffer );
2055 /* Update number of corrupted data packats */
2056 if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
2057 atomic_fetch_add_explicit(&stats->demux_corrupted, 1,
2058 memory_order_relaxed);
2060 /* Update number of discontinuities */
2061 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
2062 atomic_fetch_add_explicit(&stats->demux_discontinuity, 1,
2063 memory_order_relaxed);
2066 vlc_mutex_lock( &p_sys->lock );
2068 /* Mark preroll blocks */
2069 if( p_sys->i_preroll_end >= 0 )
2071 vlc_tick_t i_date = p_block->i_pts;
2072 if( p_block->i_pts == VLC_TICK_INVALID )
2073 i_date = p_block->i_dts;
2075 if( i_date + p_block->i_length < p_sys->i_preroll_end )
2076 p_block->i_flags |= BLOCK_FLAG_PREROLL;
2079 if( !es->p_dec )
2081 block_Release( p_block );
2082 vlc_mutex_unlock( &p_sys->lock );
2083 return VLC_SUCCESS;
2086 /* Check for sout mode */
2087 if( input_priv(p_input)->p_sout )
2089 /* FIXME review this, proper lock may be missing */
2090 if( input_priv(p_input)->p_sout->i_out_pace_nocontrol > 0 &&
2091 input_priv(p_input)->b_out_pace_control )
2093 msg_Dbg( p_input, "switching to sync mode" );
2094 input_priv(p_input)->b_out_pace_control = false;
2096 else if( input_priv(p_input)->p_sout->i_out_pace_nocontrol <= 0 &&
2097 !input_priv(p_input)->b_out_pace_control )
2099 msg_Dbg( p_input, "switching to async mode" );
2100 input_priv(p_input)->b_out_pace_control = true;
2104 /* Decode */
2105 if( es->p_dec_record )
2107 block_t *p_dup = block_Duplicate( p_block );
2108 if( p_dup )
2109 input_DecoderDecode( es->p_dec_record, p_dup,
2110 input_priv(p_input)->b_out_pace_control );
2112 input_DecoderDecode( es->p_dec, p_block,
2113 input_priv(p_input)->b_out_pace_control );
2115 es_format_t fmt_dsc;
2116 vlc_meta_t *p_meta_dsc;
2117 if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
2119 EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );
2121 es_format_Clean( &fmt_dsc );
2122 if( p_meta_dsc )
2123 vlc_meta_Delete( p_meta_dsc );
2126 /* Check CC status */
2127 decoder_cc_desc_t desc;
2129 input_DecoderGetCcDesc( es->p_dec, &desc );
2130 if( var_InheritInteger( p_input, "captions" ) == 708 )
2131 EsOutCreateCCChannels( out, VLC_CODEC_CEA708, desc.i_708_channels,
2132 _("DTVCC Closed captions %u"), es );
2133 EsOutCreateCCChannels( out, VLC_CODEC_CEA608, desc.i_608_channels,
2134 _("Closed captions %u"), es );
2136 vlc_mutex_unlock( &p_sys->lock );
2138 return VLC_SUCCESS;
2141 /*****************************************************************************
2142 * EsOutDel:
2143 *****************************************************************************/
2144 static void EsOutDel( es_out_t *out, es_out_id_t *es )
2146 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
2147 bool b_reselect = false;
2149 vlc_mutex_lock( &p_sys->lock );
2151 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, es->fmt.i_cat );
2153 /* We don't try to reselect */
2154 if( es->p_dec )
2155 { /* FIXME: This might hold the ES output caller (i.e. the demux), and
2156 * the corresponding thread (typically the input thread), for a little
2157 * bit too long if the ES is deleted in the middle of a stream. */
2158 input_DecoderDrain( es->p_dec );
2159 while( !input_Stopped(p_sys->p_input) && !p_sys->b_buffering )
2161 if( input_DecoderIsEmpty( es->p_dec ) &&
2162 ( !es->p_dec_record || input_DecoderIsEmpty( es->p_dec_record ) ))
2163 break;
2164 /* FIXME there should be a way to have auto deleted es, but there will be
2165 * a problem when another codec of the same type is created (mainly video) */
2166 vlc_tick_sleep(VLC_TICK_FROM_MS(20));
2168 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2171 if( es->p_pgrm == p_sys->p_pgrm )
2172 EsOutESVarUpdate( out, es, true );
2174 EsDeleteInfo( out, es );
2176 vlc_list_remove(&es->node);
2178 /* Update program */
2179 es->p_pgrm->i_es--;
2180 if( es->p_pgrm->i_es == 0 )
2181 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
2183 if( es->b_scrambled )
2184 EsOutProgramUpdateScrambled( out, es->p_pgrm );
2186 /* */
2187 if( p_esprops )
2189 if( p_esprops->p_main_es == es )
2191 b_reselect = true;
2192 p_esprops->p_main_es = NULL;
2194 p_esprops->i_count--;
2197 /* Re-select another track when needed */
2198 if( b_reselect )
2200 es_out_id_t *other;
2202 foreach_es_then_es_slaves(other)
2203 if( es->fmt.i_cat == other->fmt.i_cat )
2205 if (EsIsSelected(other))
2207 input_SendEventEsSelect(p_sys->p_input, es->fmt.i_cat,
2208 other->i_id);
2209 if( p_esprops->p_main_es == NULL )
2210 p_esprops->p_main_es = other;
2212 else
2213 EsOutSelect(out, other, false);
2217 free( es->psz_language );
2218 free( es->psz_language_code );
2220 es_format_Clean( &es->fmt );
2222 vlc_mutex_unlock( &p_sys->lock );
2224 free( es );
2228 * Control query handler
2230 * \param out the es_out to control
2231 * \param i_query A es_out query as defined in include/ninput.h
2232 * \param args a variable list of arguments for the query
2233 * \return VLC_SUCCESS or an error code
2235 static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
2237 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
2239 switch( i_query )
2241 case ES_OUT_SET_ES_STATE:
2243 es_out_id_t *es = va_arg( args, es_out_id_t * );
2244 bool b = va_arg( args, int );
2245 if( b && !EsIsSelected( es ) )
2247 EsSelect( out, es );
2248 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
2250 else if( !b && EsIsSelected( es ) )
2252 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2253 return VLC_SUCCESS;
2255 return VLC_SUCCESS;
2258 case ES_OUT_GET_ES_STATE:
2260 es_out_id_t *es = va_arg( args, es_out_id_t * );
2261 bool *pb = va_arg( args, bool * );
2263 *pb = EsIsSelected( es );
2264 return VLC_SUCCESS;
2267 case ES_OUT_SET_ES_CAT_POLICY:
2269 enum es_format_category_e i_cat = va_arg( args, enum es_format_category_e );
2270 enum es_out_policy_e i_pol = va_arg( args, enum es_out_policy_e );
2271 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, i_cat );
2272 if( p_esprops == NULL )
2273 return VLC_EGENERIC;
2274 p_esprops->e_policy = i_pol;
2275 return VLC_SUCCESS;
2278 case ES_OUT_GET_GROUP_FORCED:
2280 int *pi_group = va_arg( args, int * );
2281 *pi_group = p_sys->i_group_id;
2282 return VLC_SUCCESS;
2285 case ES_OUT_SET_MODE:
2287 const int i_mode = va_arg( args, int );
2288 assert( i_mode == ES_OUT_MODE_NONE || i_mode == ES_OUT_MODE_ALL ||
2289 i_mode == ES_OUT_MODE_AUTO || i_mode == ES_OUT_MODE_PARTIAL ||
2290 i_mode == ES_OUT_MODE_END );
2292 if (i_mode != ES_OUT_MODE_NONE && !p_sys->b_active && !vlc_list_is_empty(&p_sys->es))
2294 /* XXX Terminate vout if there are tracks but no video one.
2295 * This one is not mandatory but is he earliest place where it
2296 * can be done */
2297 es_out_id_t *p_es;
2298 bool found = false;
2300 foreach_es_then_es_slaves(p_es)
2301 if( p_es->fmt.i_cat == VIDEO_ES && !found /* nested loop */ )
2303 found = true;
2304 break;
2307 if (!found)
2308 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
2310 p_sys->b_active = i_mode != ES_OUT_MODE_NONE;
2311 p_sys->i_mode = i_mode;
2313 /* Reapply policy mode */
2314 es_out_id_t *es;
2316 foreach_es_then_es_slaves(es)
2318 if (EsIsSelected(es))
2319 EsUnselect(out, es, es->p_pgrm == p_sys->p_pgrm);
2321 foreach_es_then_es_slaves(es)
2323 EsOutSelect(out, es, false);
2326 if( i_mode == ES_OUT_MODE_END )
2327 EsOutTerminate( out );
2328 return VLC_SUCCESS;
2331 case ES_OUT_SET_ES:
2332 case ES_OUT_RESTART_ES:
2334 #define IGNORE_ES DATA_ES
2335 es_out_id_t *es = va_arg( args, es_out_id_t * ), *other;
2337 enum es_format_category_e i_cat;
2338 if( es == NULL )
2339 i_cat = UNKNOWN_ES;
2340 else if( es == es_cat + AUDIO_ES )
2341 i_cat = AUDIO_ES;
2342 else if( es == es_cat + VIDEO_ES )
2343 i_cat = VIDEO_ES;
2344 else if( es == es_cat + SPU_ES )
2345 i_cat = SPU_ES;
2346 else
2347 i_cat = IGNORE_ES;
2349 foreach_es_then_es_slaves(other)
2351 if( i_cat == IGNORE_ES )
2353 if (es == other)
2355 if (i_query == ES_OUT_RESTART_ES && es->p_dec != NULL)
2357 EsDestroyDecoder(out, es);
2358 EsCreateDecoder(out, es);
2360 else if( i_query == ES_OUT_SET_ES )
2362 EsOutSelect(out, es, true);
2364 break;
2367 else if (i_cat == UNKNOWN_ES || other->fmt.i_cat == i_cat)
2369 if (EsIsSelected(other))
2371 if (i_query == ES_OUT_RESTART_ES)
2373 if (other->p_dec != NULL)
2375 EsDestroyDecoder(out, other);
2376 EsCreateDecoder(out, other);
2379 else
2380 EsUnselect(out, other, other->p_pgrm == p_sys->p_pgrm);
2385 return VLC_SUCCESS;
2387 case ES_OUT_STOP_ALL_ES:
2389 es_out_id_t *es;
2390 int count = 0;
2392 foreach_es_then_es_slaves(es)
2393 count++;
2395 int *selected_es = vlc_alloc(count + 1, sizeof(int));
2396 if (!selected_es)
2397 return VLC_ENOMEM;
2399 *va_arg(args, void **) = selected_es;
2400 *selected_es = count;
2402 foreach_es_then_es_slaves(es)
2404 if (EsIsSelected(es))
2406 EsDestroyDecoder(out, es);
2407 *++selected_es = es->i_id;
2409 else
2410 *++selected_es = -1;
2412 return VLC_SUCCESS;
2414 case ES_OUT_START_ALL_ES:
2416 int *selected_es = va_arg( args, void * );
2417 int count = selected_es[0];
2418 for( int i = 0; i < count; ++i )
2420 int i_id = selected_es[i + 1];
2421 if( i_id != -1 )
2423 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2424 EsCreateDecoder( out, p_es );
2427 free(selected_es);
2428 return VLC_SUCCESS;
2431 case ES_OUT_SET_ES_DEFAULT:
2433 es_out_id_t *es = va_arg( args, es_out_id_t * );
2435 if( es == NULL )
2437 /*p_sys->i_default_video_id = -1;*/
2438 /*p_sys->i_default_audio_id = -1;*/
2439 p_sys->sub.i_demux_id = -1;
2441 else if( es == es_cat + AUDIO_ES )
2443 /*p_sys->i_default_video_id = -1;*/
2445 else if( es == es_cat + VIDEO_ES )
2447 /*p_sys->i_default_audio_id = -1;*/
2449 else if( es == es_cat + SPU_ES )
2451 p_sys->sub.i_demux_id = -1;
2453 else
2455 /*if( es->fmt.i_cat == VIDEO_ES )
2456 p_sys->i_default_video_id = es->i_id;
2457 else
2458 if( es->fmt.i_cat == AUDIO_ES )
2459 p_sys->i_default_audio_id = es->i_id;
2460 else*/
2461 if( es->fmt.i_cat == SPU_ES )
2462 p_sys->sub.i_demux_id = es->i_id;
2464 return VLC_SUCCESS;
2467 case ES_OUT_SET_PCR:
2468 case ES_OUT_SET_GROUP_PCR:
2470 es_out_pgrm_t *p_pgrm = NULL;
2471 int i_group = 0;
2472 vlc_tick_t i_pcr;
2474 /* Search program */
2475 if( i_query == ES_OUT_SET_PCR )
2477 p_pgrm = p_sys->p_pgrm;
2478 if( !p_pgrm )
2479 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
2481 else
2483 i_group = va_arg( args, int );
2484 p_pgrm = EsOutProgramFind( out, i_group );
2486 if( !p_pgrm )
2487 return VLC_EGENERIC;
2489 i_pcr = va_arg( args, vlc_tick_t );
2490 if( i_pcr == VLC_TICK_INVALID )
2492 msg_Err( p_sys->p_input, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2493 return VLC_EGENERIC;
2496 /* TODO do not use vlc_tick_now() but proper stream acquisition date */
2497 bool b_late;
2498 input_clock_Update( p_pgrm->p_input_clock, VLC_OBJECT(p_sys->p_input),
2499 &b_late,
2500 input_priv(p_sys->p_input)->b_can_pace_control || p_sys->b_buffering,
2501 EsOutIsExtraBufferingAllowed( out ),
2502 i_pcr, vlc_tick_now() );
2504 if( !p_sys->p_pgrm )
2505 return VLC_SUCCESS;
2507 if( p_sys->b_buffering )
2509 /* Check buffering state on master clock update */
2510 EsOutDecodersStopBuffering( out, false );
2512 else if( p_pgrm == p_sys->p_pgrm )
2514 if( b_late && ( !input_priv(p_sys->p_input)->p_sout ||
2515 !input_priv(p_sys->p_input)->b_out_pace_control ) )
2517 const vlc_tick_t i_pts_delay_base = p_sys->i_pts_delay - p_sys->i_pts_jitter;
2518 vlc_tick_t i_pts_delay = input_clock_GetJitter( p_pgrm->p_input_clock );
2520 /* Avoid dangerously high value */
2521 const vlc_tick_t i_jitter_max =
2522 VLC_TICK_FROM_MS(var_InheritInteger( p_sys->p_input, "clock-jitter" ));
2523 if( i_pts_delay > __MIN( i_pts_delay_base + i_jitter_max, INPUT_PTS_DELAY_MAX ) )
2525 es_out_pgrm_t *pgrm;
2527 msg_Err( p_sys->p_input,
2528 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2529 (int)MS_FROM_VLC_TICK(i_pts_delay - i_pts_delay_base) );
2530 i_pts_delay = p_sys->i_pts_delay;
2532 /* reset clock */
2533 vlc_list_foreach(pgrm, &p_sys->programs, node)
2534 input_clock_Reset(pgrm->p_input_clock);
2536 else
2538 msg_Err( p_sys->p_input,
2539 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2540 (int)MS_FROM_VLC_TICK(i_pts_delay) );
2542 /* Force a rebufferization when we are too late */
2544 /* It is not really good, as we throw away already buffered data
2545 * TODO have a mean to correctly reenter bufferization */
2546 es_out_Control( out, ES_OUT_RESET_PCR );
2549 es_out_SetJitter( out, i_pts_delay_base, i_pts_delay - i_pts_delay_base, p_sys->i_cr_average );
2552 return VLC_SUCCESS;
2555 case ES_OUT_RESET_PCR:
2556 msg_Dbg( p_sys->p_input, "ES_OUT_RESET_PCR called" );
2557 EsOutChangePosition( out );
2558 return VLC_SUCCESS;
2560 case ES_OUT_SET_GROUP:
2562 int i = va_arg( args, int );
2563 es_out_pgrm_t *p_pgrm;
2565 vlc_list_foreach(p_pgrm, &p_sys->programs, node)
2566 if( p_pgrm->i_id == i )
2568 EsOutProgramSelect( out, p_pgrm );
2569 return VLC_SUCCESS;
2571 return VLC_EGENERIC;
2574 case ES_OUT_SET_ES_FMT:
2576 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2577 * to update the p_extra data */
2578 es_out_id_t *es = va_arg( args, es_out_id_t * );
2579 es_format_t *p_fmt = va_arg( args, es_format_t * );
2580 if( es == NULL )
2581 return VLC_EGENERIC;
2583 es_format_Clean( &es->fmt );
2584 es_format_Copy( &es->fmt, p_fmt );
2586 if( es->p_dec )
2588 EsDestroyDecoder( out, es );
2589 EsCreateDecoder( out, es );
2592 return VLC_SUCCESS;
2595 case ES_OUT_SET_ES_SCRAMBLED_STATE:
2597 es_out_id_t *es = va_arg( args, es_out_id_t * );
2598 bool b_scrambled = (bool)va_arg( args, int );
2600 if( !es->b_scrambled != !b_scrambled )
2602 es->b_scrambled = b_scrambled;
2603 EsOutProgramUpdateScrambled( out, es->p_pgrm );
2605 return VLC_SUCCESS;
2608 case ES_OUT_SET_NEXT_DISPLAY_TIME:
2610 const int64_t i_date = va_arg( args, int64_t );
2612 if( i_date < 0 )
2613 return VLC_EGENERIC;
2615 p_sys->i_preroll_end = i_date;
2617 return VLC_SUCCESS;
2619 case ES_OUT_SET_GROUP_META:
2621 int i_group = va_arg( args, int );
2622 const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
2624 EsOutProgramMeta( out, i_group, p_meta );
2625 return VLC_SUCCESS;
2627 case ES_OUT_SET_GROUP_EPG:
2629 int i_group = va_arg( args, int );
2630 const vlc_epg_t *p_epg = va_arg( args, const vlc_epg_t * );
2632 EsOutProgramEpg( out, i_group, p_epg );
2633 return VLC_SUCCESS;
2635 case ES_OUT_SET_GROUP_EPG_EVENT:
2637 int i_group = va_arg( args, int );
2638 const vlc_epg_event_t *p_evt = va_arg( args, const vlc_epg_event_t * );
2640 EsOutProgramEpgEvent( out, i_group, p_evt );
2641 return VLC_SUCCESS;
2643 case ES_OUT_SET_EPG_TIME:
2645 int64_t i64 = va_arg( args, int64_t );
2647 EsOutEpgTime( out, i64 );
2648 return VLC_SUCCESS;
2651 case ES_OUT_DEL_GROUP:
2653 int i_group = va_arg( args, int );
2655 return EsOutProgramDel( out, i_group );
2658 case ES_OUT_SET_META:
2660 const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
2662 EsOutGlobalMeta( out, p_meta );
2663 return VLC_SUCCESS;
2666 case ES_OUT_GET_WAKE_UP:
2668 vlc_tick_t *pi_wakeup = va_arg( args, vlc_tick_t* );
2669 *pi_wakeup = EsOutGetWakeup( out );
2670 return VLC_SUCCESS;
2673 case ES_OUT_SET_ES_BY_ID:
2674 case ES_OUT_RESTART_ES_BY_ID:
2675 case ES_OUT_SET_ES_DEFAULT_BY_ID:
2677 const int i_id = va_arg( args, int );
2678 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2679 int i_new_query = 0;
2681 switch( i_query )
2683 case ES_OUT_SET_ES_BY_ID: i_new_query = ES_OUT_SET_ES; break;
2684 case ES_OUT_RESTART_ES_BY_ID: i_new_query = ES_OUT_RESTART_ES; break;
2685 case ES_OUT_SET_ES_DEFAULT_BY_ID: i_new_query = ES_OUT_SET_ES_DEFAULT; break;
2686 default:
2687 vlc_assert_unreachable();
2689 /* TODO if the lock is made non recursive it should be changed */
2690 int i_ret = es_out_Control( out, i_new_query, p_es );
2692 /* Clean up vout after user action (in active mode only).
2693 * FIXME it does not work well with multiple video windows */
2694 if( p_sys->b_active )
2695 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
2696 return i_ret;
2699 case ES_OUT_GET_ES_OBJECTS_BY_ID:
2701 const int i_id = va_arg( args, int );
2702 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2703 if( !p_es )
2704 return VLC_EGENERIC;
2706 vlc_object_t **pp_decoder = va_arg( args, vlc_object_t ** );
2707 vout_thread_t **pp_vout = va_arg( args, vout_thread_t ** );
2708 audio_output_t **pp_aout = va_arg( args, audio_output_t ** );
2709 if( p_es->p_dec )
2711 if( pp_decoder )
2712 *pp_decoder = vlc_object_hold( p_es->p_dec );
2713 input_DecoderGetObjects( p_es->p_dec, pp_vout, pp_aout );
2715 else
2717 if( pp_decoder )
2718 *pp_decoder = NULL;
2719 if( pp_vout )
2720 *pp_vout = NULL;
2721 if( pp_aout )
2722 *pp_aout = NULL;
2724 return VLC_SUCCESS;
2727 case ES_OUT_GET_BUFFERING:
2729 bool *pb = va_arg( args, bool* );
2730 *pb = p_sys->b_buffering;
2731 return VLC_SUCCESS;
2734 case ES_OUT_GET_EMPTY:
2736 bool *pb = va_arg( args, bool* );
2737 *pb = EsOutDecodersIsEmpty( out );
2738 return VLC_SUCCESS;
2741 case ES_OUT_SET_DELAY:
2743 const int i_cat = va_arg( args, int );
2744 const vlc_tick_t i_delay = va_arg( args, vlc_tick_t );
2745 EsOutSetDelay( out, i_cat, i_delay );
2746 return VLC_SUCCESS;
2749 case ES_OUT_SET_RECORD_STATE:
2751 bool b = va_arg( args, int );
2752 return EsOutSetRecord( out, b );
2755 case ES_OUT_SET_PAUSE_STATE:
2757 const bool b_source_paused = (bool)va_arg( args, int );
2758 const bool b_paused = (bool)va_arg( args, int );
2759 const vlc_tick_t i_date = va_arg( args, vlc_tick_t );
2761 assert( !b_source_paused == !b_paused );
2762 EsOutChangePause( out, b_paused, i_date );
2764 return VLC_SUCCESS;
2767 case ES_OUT_SET_RATE:
2769 const int i_src_rate = va_arg( args, int );
2770 const int i_rate = va_arg( args, int );
2772 assert( i_src_rate == i_rate );
2773 EsOutChangeRate( out, i_rate );
2775 return VLC_SUCCESS;
2778 case ES_OUT_SET_FRAME_NEXT:
2779 EsOutFrameNext( out );
2780 return VLC_SUCCESS;
2782 case ES_OUT_SET_TIMES:
2784 double f_position = va_arg( args, double );
2785 vlc_tick_t i_time = va_arg( args, vlc_tick_t );
2786 vlc_tick_t i_length = va_arg( args, vlc_tick_t );
2788 input_SendEventLength( p_sys->p_input, i_length );
2790 if( !p_sys->b_buffering )
2792 vlc_tick_t i_delay;
2794 /* Fix for buffering delay */
2795 if( !input_priv(p_sys->p_input)->p_sout ||
2796 !input_priv(p_sys->p_input)->b_out_pace_control )
2797 i_delay = EsOutGetBuffering( out );
2798 else
2799 i_delay = 0;
2801 i_time -= i_delay;
2802 if( i_time < 0 )
2803 i_time = 0;
2805 if( i_length > 0 )
2806 f_position -= (double)i_delay / i_length;
2807 if( f_position < 0 )
2808 f_position = 0;
2810 input_SendEventPosition( p_sys->p_input, f_position, i_time );
2812 return VLC_SUCCESS;
2814 case ES_OUT_SET_JITTER:
2816 vlc_tick_t i_pts_delay = va_arg( args, vlc_tick_t );
2817 vlc_tick_t i_pts_jitter = va_arg( args, vlc_tick_t );
2818 int i_cr_average = va_arg( args, int );
2819 es_out_pgrm_t *pgrm;
2821 bool b_change_clock =
2822 i_pts_delay + i_pts_jitter != p_sys->i_pts_delay ||
2823 i_cr_average != p_sys->i_cr_average;
2825 assert( i_pts_jitter >= 0 );
2826 p_sys->i_pts_delay = i_pts_delay + i_pts_jitter;
2827 p_sys->i_pts_jitter = i_pts_jitter;
2828 p_sys->i_cr_average = i_cr_average;
2830 if (b_change_clock)
2831 vlc_list_foreach(pgrm, &p_sys->programs, node)
2832 input_clock_SetJitter(pgrm->p_input_clock, i_pts_delay
2833 + i_pts_jitter, i_cr_average);
2834 return VLC_SUCCESS;
2837 case ES_OUT_GET_PCR_SYSTEM:
2839 if( p_sys->b_buffering )
2840 return VLC_EGENERIC;
2842 es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
2843 if( !p_pgrm )
2844 return VLC_EGENERIC;
2846 vlc_tick_t *pi_system = va_arg( args, vlc_tick_t *);
2847 vlc_tick_t *pi_delay = va_arg( args, vlc_tick_t *);
2848 input_clock_GetSystemOrigin( p_pgrm->p_input_clock, pi_system, pi_delay );
2849 return VLC_SUCCESS;
2852 case ES_OUT_MODIFY_PCR_SYSTEM:
2854 if( p_sys->b_buffering )
2855 return VLC_EGENERIC;
2857 es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
2858 if( !p_pgrm )
2859 return VLC_EGENERIC;
2861 const bool b_absolute = va_arg( args, int );
2862 const vlc_tick_t i_system = va_arg( args, vlc_tick_t );
2863 input_clock_ChangeSystemOrigin( p_pgrm->p_input_clock, b_absolute, i_system );
2864 return VLC_SUCCESS;
2866 case ES_OUT_SET_EOS:
2868 es_out_id_t *id;
2869 foreach_es_then_es_slaves(id)
2870 if (id->p_dec != NULL)
2871 input_DecoderDrain(id->p_dec);
2872 return VLC_SUCCESS;
2875 case ES_OUT_POST_SUBNODE:
2877 input_item_node_t *node = va_arg(args, input_item_node_t *);
2878 input_item_node_PostAndDelete(node);
2879 return VLC_SUCCESS;
2882 default:
2883 msg_Err( p_sys->p_input, "unknown query 0x%x in %s", i_query,
2884 __func__ );
2885 return VLC_EGENERIC;
2888 static int EsOutControl( es_out_t *out, int i_query, va_list args )
2890 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
2891 int i_ret;
2893 vlc_mutex_lock( &p_sys->lock );
2894 i_ret = EsOutControlLocked( out, i_query, args );
2895 vlc_mutex_unlock( &p_sys->lock );
2897 return i_ret;
2900 static const struct es_out_callbacks es_out_cbs =
2902 .add = EsOutAdd,
2903 .send = EsOutSend,
2904 .del = EsOutDel,
2905 .control = EsOutControl,
2906 .destroy = EsOutDelete,
2909 /****************************************************************************
2910 * LanguageGetName: try to expend iso639 into plain name
2911 ****************************************************************************/
2912 static char *LanguageGetName( const char *psz_code )
2914 const iso639_lang_t *pl;
2916 if( psz_code == NULL || !strcmp( psz_code, "und" ) )
2918 return strdup( "" );
2921 if( strlen( psz_code ) == 2 )
2923 pl = GetLang_1( psz_code );
2925 else if( strlen( psz_code ) == 3 )
2927 pl = GetLang_2B( psz_code );
2928 if( !strcmp( pl->psz_iso639_1, "??" ) )
2930 pl = GetLang_2T( psz_code );
2933 else
2935 char *lang = LanguageGetCode( psz_code );
2936 pl = GetLang_1( lang );
2937 free( lang );
2940 if( !strcmp( pl->psz_iso639_1, "??" ) )
2942 return strdup( psz_code );
2944 else
2946 return strdup( vlc_gettext(pl->psz_eng_name) );
2950 /* Get a 2 char code */
2951 static char *LanguageGetCode( const char *psz_lang )
2953 const iso639_lang_t *pl;
2955 if( psz_lang == NULL || *psz_lang == '\0' )
2956 return strdup("??");
2958 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
2960 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
2961 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
2962 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
2963 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
2964 return strdup( pl->psz_iso639_1 );
2967 return strdup("??");
2970 static char **LanguageSplit( const char *psz_langs )
2972 char *psz_dup;
2973 char *psz_parser;
2974 char **ppsz = NULL;
2975 int i_psz = 0;
2977 if( psz_langs == NULL ) return NULL;
2979 psz_parser = psz_dup = strdup(psz_langs);
2981 while( psz_parser && *psz_parser )
2983 char *psz;
2984 char *psz_code;
2986 psz = strchr(psz_parser, ',' );
2987 if( psz ) *psz++ = '\0';
2989 if( !strcmp( psz_parser, "any" ) )
2991 TAB_APPEND( i_psz, ppsz, strdup("any") );
2993 else if( !strcmp( psz_parser, "none" ) )
2995 TAB_APPEND( i_psz, ppsz, strdup("none") );
2997 else
2999 psz_code = LanguageGetCode( psz_parser );
3000 if( strcmp( psz_code, "??" ) )
3002 TAB_APPEND( i_psz, ppsz, psz_code );
3004 else
3006 free( psz_code );
3010 psz_parser = psz;
3013 if( i_psz )
3015 TAB_APPEND( i_psz, ppsz, NULL );
3018 free( psz_dup );
3019 return ppsz;
3022 static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang )
3024 if( !ppsz_langs || !psz_lang )
3025 return -1;
3027 for( int i = 0; ppsz_langs[i]; i++ )
3029 if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
3030 ( !strcasecmp( ppsz_langs[i], "any" ) && strcasecmp( psz_lang, "none") ) )
3031 return i;
3032 if( !strcasecmp( ppsz_langs[i], "none" ) )
3033 break;
3036 return -1;
3039 /****************************************************************************
3040 * EsOutUpdateInfo:
3041 * - add meta info to the playlist item
3042 ****************************************************************************/
3043 static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt, const vlc_meta_t *p_meta )
3045 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
3046 input_thread_t *p_input = p_sys->p_input;
3047 const es_format_t *p_fmt_es = &es->fmt;
3049 if( es->fmt.i_cat == fmt->i_cat )
3051 es_format_t update = *fmt;
3052 update.i_id = es->i_meta_id;
3053 update.i_codec = es->fmt.i_codec;
3054 update.i_original_fourcc = es->fmt.i_original_fourcc;
3056 /* Update infos that could have been lost by the decoder (no need to
3057 * dup them since input_item_UpdateTracksInfo() will do it). */
3058 if (update.psz_language == NULL)
3059 update.psz_language = es->fmt.psz_language;
3060 if (update.psz_description == NULL)
3061 update.psz_description = es->fmt.psz_description;
3062 if (update.i_cat == SPU_ES)
3064 if (update.subs.psz_encoding == NULL)
3065 update.subs.psz_encoding = es->fmt.subs.psz_encoding;
3067 if (update.i_extra_languages == 0)
3069 assert(update.p_extra_languages == NULL);
3070 update.i_extra_languages = es->fmt.i_extra_languages;
3071 update.p_extra_languages = es->fmt.p_extra_languages;
3074 /* No need to update codec specific data */
3075 update.i_extra = 0;
3076 update.p_extra = NULL;
3078 input_item_UpdateTracksInfo(input_GetItem(p_input), &update);
3081 /* Create category */
3082 char* psz_cat = EsInfoCategoryName( es );
3084 if( unlikely( !psz_cat ) )
3085 return;
3087 info_category_t* p_cat = info_category_New( psz_cat );
3089 free( psz_cat );
3091 if( unlikely( !p_cat ) )
3092 return;
3094 /* Add information */
3095 if( es->i_meta_id != es->i_id )
3096 info_category_AddInfo( p_cat, _("Original ID"),
3097 "%d", es->i_id );
3099 const vlc_fourcc_t i_codec_fourcc = ( p_fmt_es->i_original_fourcc )?
3100 p_fmt_es->i_original_fourcc : p_fmt_es->i_codec;
3101 const char *psz_codec_description =
3102 vlc_fourcc_GetDescription( p_fmt_es->i_cat, i_codec_fourcc );
3103 if( psz_codec_description && *psz_codec_description )
3104 info_category_AddInfo( p_cat, _("Codec"), "%s (%.4s)",
3105 psz_codec_description, (char*)&i_codec_fourcc );
3106 else if ( i_codec_fourcc != VLC_FOURCC(0,0,0,0) )
3107 info_category_AddInfo( p_cat, _("Codec"), "%.4s",
3108 (char*)&i_codec_fourcc );
3110 if( es->psz_language && *es->psz_language )
3111 info_category_AddInfo( p_cat, _("Language"), "%s",
3112 es->psz_language );
3113 if( fmt->psz_description && *fmt->psz_description )
3114 info_category_AddInfo( p_cat, _("Description"), "%s",
3115 fmt->psz_description );
3117 switch( fmt->i_cat )
3119 case AUDIO_ES:
3120 info_category_AddInfo( p_cat, _("Type"), _("Audio") );
3122 if( fmt->audio.i_physical_channels )
3123 info_category_AddInfo( p_cat, _("Channels"), "%s",
3124 vlc_gettext( aout_FormatPrintChannels( &fmt->audio ) ) );
3126 if( fmt->audio.i_rate != 0 )
3128 info_category_AddInfo( p_cat, _("Sample rate"), _("%u Hz"),
3129 fmt->audio.i_rate );
3130 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3131 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
3134 unsigned int i_bitspersample = fmt->audio.i_bitspersample;
3135 if( i_bitspersample == 0 )
3136 i_bitspersample = aout_BitsPerSample( p_fmt_es->i_codec );
3137 if( i_bitspersample != 0 )
3138 info_category_AddInfo( p_cat, _("Bits per sample"), "%u",
3139 i_bitspersample );
3141 if( fmt->i_bitrate != 0 )
3143 info_category_AddInfo( p_cat, _("Bitrate"), _("%u kb/s"),
3144 fmt->i_bitrate / 1000 );
3145 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3146 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
3148 for( int i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
3150 const audio_replay_gain_t *p_rg = &fmt->audio_replay_gain;
3151 if( !p_rg->pb_gain[i] )
3152 continue;
3153 const char *psz_name;
3154 if( i == AUDIO_REPLAY_GAIN_TRACK )
3155 psz_name = _("Track replay gain");
3156 else
3157 psz_name = _("Album replay gain");
3158 info_category_AddInfo( p_cat, psz_name, _("%.2f dB"),
3159 p_rg->pf_gain[i] );
3161 break;
3163 case VIDEO_ES:
3164 info_category_AddInfo( p_cat, _("Type"), _("Video") );
3166 if( fmt->video.i_visible_width > 0 &&
3167 fmt->video.i_visible_height > 0 )
3168 info_category_AddInfo( p_cat, _("Video resolution"), "%ux%u",
3169 fmt->video.i_visible_width,
3170 fmt->video.i_visible_height);
3172 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
3173 info_category_AddInfo( p_cat, _("Buffer dimensions"), "%ux%u",
3174 fmt->video.i_width, fmt->video.i_height );
3176 if( fmt->video.i_frame_rate > 0 &&
3177 fmt->video.i_frame_rate_base > 0 )
3179 if( fmt->video.i_frame_rate_base == 1 )
3180 info_category_AddInfo( p_cat, _("Frame rate"), "%u",
3181 fmt->video.i_frame_rate );
3182 else
3183 info_category_AddInfo( p_cat, _("Frame rate"), "%.6f",
3184 (double)fmt->video.i_frame_rate
3185 / (double)fmt->video.i_frame_rate_base );
3187 if( fmt->i_codec != p_fmt_es->i_codec )
3189 const char *psz_chroma_description =
3190 vlc_fourcc_GetDescription( VIDEO_ES, fmt->i_codec );
3191 if( psz_chroma_description )
3192 info_category_AddInfo( p_cat, _("Decoded format"), "%s",
3193 psz_chroma_description );
3196 static const char orient_names[][13] = {
3197 N_("Top left"), N_("Left top"),
3198 N_("Right bottom"), N_("Top right"),
3199 N_("Bottom left"), N_("Bottom right"),
3200 N_("Left bottom"), N_("Right top"),
3202 info_category_AddInfo( p_cat, _("Orientation"), "%s",
3203 vlc_gettext(orient_names[fmt->video.orientation]) );
3205 if( fmt->video.primaries != COLOR_PRIMARIES_UNDEF )
3207 static const char primaries_names[][32] = {
3208 [COLOR_PRIMARIES_UNDEF] = N_("Undefined"),
3209 [COLOR_PRIMARIES_BT601_525] =
3210 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3211 [COLOR_PRIMARIES_BT601_625] =
3212 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3213 [COLOR_PRIMARIES_BT709] = "ITU-R BT.709",
3214 [COLOR_PRIMARIES_BT2020] = "ITU-R BT.2020",
3215 [COLOR_PRIMARIES_DCI_P3] = "DCI/P3 D65",
3216 [COLOR_PRIMARIES_BT470_M] = "ITU-R BT.470 M",
3218 static_assert(ARRAY_SIZE(primaries_names) == COLOR_PRIMARIES_MAX+1,
3219 "Color primiaries table mismatch");
3220 info_category_AddInfo( p_cat, _("Color primaries"), "%s",
3221 vlc_gettext(primaries_names[fmt->video.primaries]) );
3223 if( fmt->video.transfer != TRANSFER_FUNC_UNDEF )
3225 static const char func_names[][20] = {
3226 [TRANSFER_FUNC_UNDEF] = N_("Undefined"),
3227 [TRANSFER_FUNC_LINEAR] = N_("Linear"),
3228 [TRANSFER_FUNC_SRGB] = "sRGB",
3229 [TRANSFER_FUNC_BT470_BG] = "ITU-R BT.470 BG",
3230 [TRANSFER_FUNC_BT470_M] = "ITU-R BT.470 M",
3231 [TRANSFER_FUNC_BT709] = "ITU-R BT.709",
3232 [TRANSFER_FUNC_SMPTE_ST2084] = "SMPTE ST2084",
3233 [TRANSFER_FUNC_SMPTE_240] = "SMPTE 240M",
3234 [TRANSFER_FUNC_HLG] = N_("Hybrid Log-Gamma"),
3236 static_assert(ARRAY_SIZE(func_names) == TRANSFER_FUNC_MAX+1,
3237 "Transfer functions table mismatch");
3238 info_category_AddInfo( p_cat, _("Color transfer function"), "%s",
3239 vlc_gettext(func_names[fmt->video.transfer]) );
3241 if( fmt->video.space != COLOR_SPACE_UNDEF )
3243 static const char space_names[][16] = {
3244 [COLOR_SPACE_UNDEF] = N_("Undefined"),
3245 [COLOR_SPACE_BT601] = "ITU-R BT.601",
3246 [COLOR_SPACE_BT709] = "ITU-R BT.709",
3247 [COLOR_SPACE_BT2020] = "ITU-R BT.2020",
3249 static_assert(ARRAY_SIZE(space_names) == COLOR_SPACE_MAX+1,
3250 "Color space table mismatch");
3251 info_category_AddInfo( p_cat, _("Color space"), _("%s %s Range"),
3252 vlc_gettext(space_names[fmt->video.space]),
3253 vlc_gettext(fmt->video.b_color_range_full
3254 ? N_("Full") : N_("Limited")) );
3256 if( fmt->video.chroma_location != CHROMA_LOCATION_UNDEF )
3258 static const char c_loc_names[][16] = {
3259 [CHROMA_LOCATION_UNDEF] = N_("Undefined"),
3260 [CHROMA_LOCATION_LEFT] = N_("Left"),
3261 [CHROMA_LOCATION_CENTER] = N_("Center"),
3262 [CHROMA_LOCATION_TOP_LEFT] = N_("Top Left"),
3263 [CHROMA_LOCATION_TOP_CENTER] = N_("Top Center"),
3264 [CHROMA_LOCATION_BOTTOM_LEFT] =N_("Bottom Left"),
3265 [CHROMA_LOCATION_BOTTOM_CENTER] = N_("Bottom Center"),
3267 static_assert(ARRAY_SIZE(c_loc_names) == CHROMA_LOCATION_MAX+1,
3268 "Chroma location table mismatch");
3269 info_category_AddInfo( p_cat, _("Chroma location"), "%s",
3270 vlc_gettext(c_loc_names[fmt->video.chroma_location]) );
3272 if( fmt->video.projection_mode != PROJECTION_MODE_RECTANGULAR )
3274 const char *psz_loc_name = NULL;
3275 switch (fmt->video.projection_mode)
3277 case PROJECTION_MODE_RECTANGULAR:
3278 psz_loc_name = N_("Rectangular");
3279 break;
3280 case PROJECTION_MODE_EQUIRECTANGULAR:
3281 psz_loc_name = N_("Equirectangular");
3282 break;
3283 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:
3284 psz_loc_name = N_("Cubemap");
3285 break;
3286 default:
3287 vlc_assert_unreachable();
3288 break;
3290 info_category_AddInfo( p_cat, _("Projection"), "%s",
3291 vlc_gettext(psz_loc_name) );
3293 info_category_AddInfo( p_cat, vlc_pgettext("ViewPoint", "Yaw"),
3294 "%.2f", fmt->video.pose.yaw );
3295 info_category_AddInfo( p_cat, vlc_pgettext("ViewPoint", "Pitch"),
3296 "%.2f", fmt->video.pose.pitch );
3297 info_category_AddInfo( p_cat, vlc_pgettext("ViewPoint", "Roll"),
3298 "%.2f", fmt->video.pose.roll );
3299 info_category_AddInfo( p_cat,
3300 vlc_pgettext("ViewPoint", "Field of view"),
3301 "%.2f", fmt->video.pose.fov );
3303 if ( fmt->video.mastering.max_luminance )
3305 info_category_AddInfo( p_cat, _("Max. luminance"), "%.4f cd/m²",
3306 fmt->video.mastering.max_luminance / 10000.f );
3308 if ( fmt->video.mastering.min_luminance )
3310 info_category_AddInfo( p_cat, _("Min. luminance"), "%.4f cd/m²",
3311 fmt->video.mastering.min_luminance / 10000.f );
3313 if ( fmt->video.mastering.primaries[4] &&
3314 fmt->video.mastering.primaries[5] )
3316 float x = (float)fmt->video.mastering.primaries[4] / 50000.f;
3317 float y = (float)fmt->video.mastering.primaries[5] / 50000.f;
3318 info_category_AddInfo( p_cat, _("Primary R"), "x=%.4f y=%.4f", x, y );
3320 if ( fmt->video.mastering.primaries[0] &&
3321 fmt->video.mastering.primaries[1] )
3323 float x = (float)fmt->video.mastering.primaries[0] / 50000.f;
3324 float y = (float)fmt->video.mastering.primaries[1] / 50000.f;
3325 info_category_AddInfo( p_cat, _("Primary G"), "x=%.4f y=%.4f", x, y );
3327 if ( fmt->video.mastering.primaries[2] &&
3328 fmt->video.mastering.primaries[3] )
3330 float x = (float)fmt->video.mastering.primaries[2] / 50000.f;
3331 float y = (float)fmt->video.mastering.primaries[3] / 50000.f;
3332 info_category_AddInfo( p_cat, _("Primary B"), "x=%.4f y=%.4f", x, y );
3334 if ( fmt->video.mastering.white_point[0] &&
3335 fmt->video.mastering.white_point[1] )
3337 float x = (float)fmt->video.mastering.white_point[0] / 50000.f;
3338 float y = (float)fmt->video.mastering.white_point[1] / 50000.f;
3339 info_category_AddInfo( p_cat, _("White point"), "x=%.4f y=%.4f", x, y );
3341 if ( fmt->video.lighting.MaxCLL )
3343 info_category_AddInfo( p_cat, "MaxCLL", "%d cd/m²",
3344 fmt->video.lighting.MaxCLL );
3346 if ( fmt->video.lighting.MaxFALL )
3348 info_category_AddInfo( p_cat, "MaxFALL", "%d cd/m²",
3349 fmt->video.lighting.MaxFALL );
3351 break;
3353 case SPU_ES:
3354 info_category_AddInfo( p_cat, _("Type"), _("Subtitle") );
3355 break;
3357 default:
3358 break;
3361 /* Append generic meta */
3362 if( p_meta )
3364 char **ppsz_all_keys = vlc_meta_CopyExtraNames( p_meta );
3365 for( int i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
3367 char *psz_key = ppsz_all_keys[i];
3368 const char *psz_value = vlc_meta_GetExtra( p_meta, psz_key );
3370 if( psz_value )
3371 info_category_AddInfo( p_cat, vlc_gettext(psz_key), "%s",
3372 vlc_gettext(psz_value) );
3373 free( psz_key );
3375 free( ppsz_all_keys );
3377 /* */
3378 input_Control( p_input, INPUT_REPLACE_INFOS, p_cat );
3381 static void EsDeleteInfo( es_out_t *out, es_out_id_t *es )
3383 es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
3384 char* psz_info_category;
3386 if( likely( psz_info_category = EsInfoCategoryName( es ) ) )
3388 input_Control( p_sys->p_input, INPUT_DEL_INFO,
3389 psz_info_category, NULL );
3391 free( psz_info_category );