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