demux: avi: PTSToByte remove useless casts and change type
[vlc.git] / src / input / es_out.c
blobc4a848d5e904a15703b6bb2cd4ac3506e0dfdf34
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>
43 #include "input_internal.h"
44 #include "clock.h"
45 #include "decoder.h"
46 #include "es_out.h"
47 #include "event.h"
48 #include "info.h"
49 #include "item.h"
51 #include "../stream_output/stream_output.h"
53 #include <vlc_iso_lang.h>
54 /* FIXME we should find a better way than including that */
55 #include "../text/iso-639_def.h"
57 /*****************************************************************************
58 * Local prototypes
59 *****************************************************************************/
60 typedef struct
62 /* Program ID */
63 int i_id;
65 /* Number of es for this pgrm */
66 int i_es;
68 bool b_selected;
69 bool b_scrambled;
71 /* Clock for this program */
72 input_clock_t *p_clock;
74 vlc_meta_t *p_meta;
75 } es_out_pgrm_t;
77 struct es_out_id_t
79 /* ES ID */
80 int i_id;
81 es_out_pgrm_t *p_pgrm;
83 /* */
84 bool b_scrambled;
86 /* Channel in the track type */
87 int i_channel;
88 es_format_t fmt;
89 char *psz_language;
90 char *psz_language_code;
92 decoder_t *p_dec;
93 decoder_t *p_dec_record;
95 /* Fields for Video with CC */
96 struct
98 vlc_fourcc_t type;
99 uint64_t i_bitmap; /* channels bitmap */
100 es_out_id_t *pp_es[64]; /* a max of 64 chans for CEA708 */
101 } cc;
103 /* Field for CC track from a master video */
104 es_out_id_t *p_master;
106 /* ID for the meta data */
107 int i_meta_id;
110 typedef struct
112 int i_count; /* es count */
113 es_out_id_t *p_main_es; /* current main es */
114 enum es_out_policy_e e_policy;
116 /* Parameters used for es selection */
117 bool b_autoselect; /* if we want to select an es when no user prefs */
118 int i_id; /* es id as set by es fmt.id */
119 int i_demux_id; /* same as previous, demuxer set default value */
120 int i_channel; /* es number in creation order */
121 char **ppsz_language;
122 } es_out_es_props_t;
124 struct es_out_sys_t
126 input_thread_t *p_input;
128 /* */
129 vlc_mutex_t lock;
131 /* all programs */
132 int i_pgrm;
133 es_out_pgrm_t **pgrm;
134 es_out_pgrm_t *p_pgrm; /* Master program */
136 /* all es */
137 int i_id;
138 int i_es;
139 es_out_id_t **es;
141 /* mode gestion */
142 bool b_active;
143 int i_mode;
145 es_out_es_props_t video, audio, sub;
147 /* es/group to select */
148 int i_group_id;
150 /* delay */
151 int64_t i_audio_delay;
152 int64_t i_spu_delay;
154 /* Clock configuration */
155 mtime_t i_pts_delay;
156 mtime_t i_pts_jitter;
157 int i_cr_average;
158 int i_rate;
160 /* */
161 bool b_paused;
162 mtime_t i_pause_date;
164 /* Current preroll */
165 mtime_t i_preroll_end;
167 /* Used for buffering */
168 bool b_buffering;
169 mtime_t i_buffering_extra_initial;
170 mtime_t i_buffering_extra_stream;
171 mtime_t i_buffering_extra_system;
173 /* Record */
174 sout_instance_t *p_sout_record;
176 /* Used only to limit debugging output */
177 int i_prev_stream_level;
180 static es_out_id_t *EsOutAdd ( es_out_t *, const es_format_t * );
181 static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
182 static void EsOutDel ( es_out_t *, es_out_id_t * );
183 static int EsOutControl( es_out_t *, int i_query, va_list );
184 static void EsOutDelete ( es_out_t * );
186 static void EsOutTerminate( es_out_t * );
187 static void EsOutSelect( es_out_t *, es_out_id_t *es, bool b_force );
188 static void EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const es_format_t *, const vlc_meta_t * );
189 static int EsOutSetRecord( es_out_t *, bool b_record );
191 static bool EsIsSelected( es_out_id_t *es );
192 static void EsSelect( es_out_t *out, es_out_id_t *es );
193 static void EsDeleteInfo( es_out_t *, es_out_id_t *es );
194 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update );
195 static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es );
196 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date );
197 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date );
198 static void EsOutProgramsChangeRate( es_out_t *out );
199 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced );
200 static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta );
201 static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_progmeta );
203 static char *LanguageGetName( const char *psz_code );
204 static char *LanguageGetCode( const char *psz_lang );
205 static char **LanguageSplit( const char *psz_langs );
206 static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang );
208 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm );
209 static char *EsInfoCategoryName( es_out_id_t* es );
211 static inline int EsOutGetClosedCaptionsChannel( const es_format_t *p_fmt )
213 int i_channel;
214 if( p_fmt->i_codec == VLC_CODEC_CEA608 && p_fmt->subs.cc.i_channel < 4 )
215 i_channel = p_fmt->subs.cc.i_channel;
216 else if( p_fmt->i_codec == VLC_CODEC_CEA708 && p_fmt->subs.cc.i_channel < 64 )
217 i_channel = p_fmt->subs.cc.i_channel;
218 else
219 i_channel = -1;
220 return i_channel;
222 static inline bool EsFmtIsTeletext( const es_format_t *p_fmt )
224 return p_fmt->i_cat == SPU_ES && p_fmt->i_codec == VLC_CODEC_TELETEXT;
227 /*****************************************************************************
228 * Es category specific structs
229 *****************************************************************************/
230 static es_out_es_props_t * GetPropsByCat( es_out_sys_t *p_sys, int i_cat )
232 switch( i_cat )
234 case AUDIO_ES:
235 return &p_sys->audio;
236 case SPU_ES:
237 return &p_sys->sub;
238 case VIDEO_ES:
239 return &p_sys->video;
241 return NULL;
244 static void EsOutPropsCleanup( es_out_es_props_t *p_props )
246 if( p_props->ppsz_language )
248 for( int i = 0; p_props->ppsz_language[i]; i++ )
249 free( p_props->ppsz_language[i] );
250 free( p_props->ppsz_language );
254 static void EsOutPropsInit( es_out_es_props_t *p_props,
255 bool autoselect,
256 input_thread_t *p_input,
257 enum es_out_policy_e e_default_policy,
258 const char *psz_trackidvar,
259 const char *psz_trackvar,
260 const char *psz_langvar,
261 const char *psz_debug )
263 p_props->e_policy = e_default_policy;
264 p_props->i_count = 0;
265 p_props->b_autoselect = autoselect;
266 p_props->i_id = (psz_trackidvar) ? var_GetInteger( p_input, psz_trackidvar ): -1;
267 p_props->i_channel = (psz_trackvar) ? var_GetInteger( p_input, psz_trackvar ): -1;
268 p_props->i_demux_id = -1;
269 p_props->p_main_es = NULL;
271 if( !input_priv(p_input)->b_preparsing && psz_langvar )
273 char *psz_string = var_GetString( p_input, psz_langvar );
274 p_props->ppsz_language = LanguageSplit( psz_string );
275 if( p_props->ppsz_language )
277 for( int i = 0; p_props->ppsz_language[i]; i++ )
278 msg_Dbg( p_input, "selected %s language[%d] %s",
279 psz_debug, i, p_props->ppsz_language[i] );
281 free( psz_string );
285 /*****************************************************************************
286 * input_EsOutNew:
287 *****************************************************************************/
288 es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
290 es_out_t *out = malloc( sizeof( *out ) );
291 if( !out )
292 return NULL;
294 es_out_sys_t *p_sys = calloc( 1, sizeof( *p_sys ) );
295 if( !p_sys )
297 free( out );
298 return NULL;
301 out->pf_add = EsOutAdd;
302 out->pf_send = EsOutSend;
303 out->pf_del = EsOutDel;
304 out->pf_control = EsOutControl;
305 out->pf_destroy = EsOutDelete;
306 out->p_sys = p_sys;
308 vlc_mutex_init_recursive( &p_sys->lock );
309 p_sys->p_input = p_input;
311 p_sys->b_active = false;
312 p_sys->i_mode = ES_OUT_MODE_NONE;
314 TAB_INIT( p_sys->i_pgrm, p_sys->pgrm );
316 TAB_INIT( p_sys->i_es, p_sys->es );
318 /* */
319 EsOutPropsInit( &p_sys->video, true, p_input, ES_OUT_ES_POLICY_SIMULTANEOUS,
320 NULL, NULL, NULL, NULL );
321 EsOutPropsInit( &p_sys->audio, true, p_input, ES_OUT_ES_POLICY_EXCLUSIVE,
322 "audio-track-id", "audio-track", "audio-language", "audio" );
323 EsOutPropsInit( &p_sys->sub, false, p_input, ES_OUT_ES_POLICY_EXCLUSIVE,
324 "sub-track-id", "sub-track", "sub-language", "sub" );
326 p_sys->i_group_id = var_GetInteger( p_input, "program" );
328 p_sys->i_pause_date = -1;
330 p_sys->i_rate = i_rate;
332 p_sys->b_buffering = true;
333 p_sys->i_preroll_end = -1;
334 p_sys->i_prev_stream_level = -1;
336 return out;
339 /*****************************************************************************
341 *****************************************************************************/
342 static void EsOutDelete( es_out_t *out )
344 es_out_sys_t *p_sys = out->p_sys;
346 assert( !p_sys->i_es && !p_sys->i_pgrm && !p_sys->p_pgrm );
347 EsOutPropsCleanup( &p_sys->audio );
348 EsOutPropsCleanup( &p_sys->sub );
350 vlc_mutex_destroy( &p_sys->lock );
352 free( p_sys );
353 free( out );
356 static void EsOutTerminate( es_out_t *out )
358 es_out_sys_t *p_sys = out->p_sys;
360 if( p_sys->p_sout_record )
361 EsOutSetRecord( out, false );
363 for( int i = 0; i < p_sys->i_es; i++ )
365 if( p_sys->es[i]->p_dec )
366 input_DecoderDelete( p_sys->es[i]->p_dec );
368 free( p_sys->es[i]->psz_language );
369 free( p_sys->es[i]->psz_language_code );
370 es_format_Clean( &p_sys->es[i]->fmt );
372 free( p_sys->es[i] );
374 TAB_CLEAN( p_sys->i_es, p_sys->es );
376 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
377 for( int i = 0; i < p_sys->i_pgrm; i++ )
379 es_out_pgrm_t *p_pgrm = p_sys->pgrm[i];
380 input_clock_Delete( p_pgrm->p_clock );
381 if( p_pgrm->p_meta )
382 vlc_meta_Delete( p_pgrm->p_meta );
384 free( p_pgrm );
386 TAB_CLEAN( p_sys->i_pgrm, p_sys->pgrm );
388 p_sys->p_pgrm = NULL;
390 input_item_SetEpgOffline( input_priv(p_sys->p_input)->p_item );
391 input_SendEventMetaEpg( p_sys->p_input );
394 static mtime_t EsOutGetWakeup( es_out_t *out )
396 es_out_sys_t *p_sys = out->p_sys;
397 input_thread_t *p_input = p_sys->p_input;
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_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 if( i_id < 0 )
421 /* Special HACK, -i_id is the cat of the stream */
422 return es_cat - i_id;
425 for( int i = 0; i < out->p_sys->i_es; i++ )
427 if( out->p_sys->es[i]->i_id == i_id )
428 return out->p_sys->es[i];
430 return NULL;
433 static bool EsOutDecodersIsEmpty( es_out_t *out )
435 es_out_sys_t *p_sys = out->p_sys;
437 if( p_sys->b_buffering && p_sys->p_pgrm )
439 EsOutDecodersStopBuffering( out, true );
440 if( p_sys->b_buffering )
441 return true;
444 for( int i = 0; i < p_sys->i_es; i++ )
446 es_out_id_t *es = p_sys->es[i];
448 if( es->p_dec && !input_DecoderIsEmpty( es->p_dec ) )
449 return false;
450 if( es->p_dec_record && !input_DecoderIsEmpty( es->p_dec_record ) )
451 return false;
453 return true;
456 static void EsOutSetDelay( es_out_t *out, int i_cat, int64_t i_delay )
458 es_out_sys_t *p_sys = out->p_sys;
460 if( i_cat == AUDIO_ES )
461 p_sys->i_audio_delay = i_delay;
462 else if( i_cat == SPU_ES )
463 p_sys->i_spu_delay = i_delay;
465 for( int i = 0; i < p_sys->i_es; i++ )
466 EsOutDecoderChangeDelay( out, p_sys->es[i] );
469 static int EsOutSetRecord( es_out_t *out, bool b_record )
471 es_out_sys_t *p_sys = out->p_sys;
472 input_thread_t *p_input = p_sys->p_input;
474 assert( ( b_record && !p_sys->p_sout_record ) || ( !b_record && p_sys->p_sout_record ) );
476 if( b_record )
478 char *psz_path = var_CreateGetNonEmptyString( p_input, "input-record-path" );
479 if( !psz_path )
481 if( var_CountChoices( p_input, "video-es" ) )
482 psz_path = config_GetUserDir( VLC_VIDEOS_DIR );
483 else if( var_CountChoices( p_input, "audio-es" ) )
484 psz_path = config_GetUserDir( VLC_MUSIC_DIR );
485 else
486 psz_path = config_GetUserDir( VLC_DOWNLOAD_DIR );
489 char *psz_sout = NULL; // TODO conf
491 if( !psz_sout && psz_path )
493 char *psz_file = input_CreateFilename( p_input, psz_path, INPUT_RECORD_PREFIX, NULL );
494 if( psz_file )
496 if( asprintf( &psz_sout, "#record{dst-prefix='%s'}", psz_file ) < 0 )
497 psz_sout = NULL;
498 free( psz_file );
501 free( psz_path );
503 if( !psz_sout )
504 return VLC_EGENERIC;
506 #ifdef ENABLE_SOUT
507 p_sys->p_sout_record = sout_NewInstance( p_input, psz_sout );
508 #endif
509 free( psz_sout );
511 if( !p_sys->p_sout_record )
512 return VLC_EGENERIC;
514 for( int i = 0; i < p_sys->i_es; i++ )
516 es_out_id_t *p_es = p_sys->es[i];
518 if( !p_es->p_dec || p_es->p_master )
519 continue;
521 p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
522 if( p_es->p_dec_record && p_sys->b_buffering )
523 input_DecoderStartWait( p_es->p_dec_record );
526 else
528 for( int i = 0; i < p_sys->i_es; i++ )
530 es_out_id_t *p_es = p_sys->es[i];
532 if( !p_es->p_dec_record )
533 continue;
535 input_DecoderDelete( p_es->p_dec_record );
536 p_es->p_dec_record = NULL;
538 #ifdef ENABLE_SOUT
539 sout_DeleteInstance( p_sys->p_sout_record );
540 #endif
541 p_sys->p_sout_record = NULL;
544 return VLC_SUCCESS;
546 static void EsOutChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
548 es_out_sys_t *p_sys = out->p_sys;
550 /* XXX the order is important */
551 if( b_paused )
553 EsOutDecodersChangePause( out, true, i_date );
554 EsOutProgramChangePause( out, true, i_date );
556 else
558 if( p_sys->i_buffering_extra_initial > 0 )
560 mtime_t i_stream_start;
561 mtime_t i_system_start;
562 mtime_t i_stream_duration;
563 mtime_t i_system_duration;
564 int i_ret;
565 i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
566 &i_stream_start, &i_system_start,
567 &i_stream_duration, &i_system_duration );
568 if( !i_ret )
570 /* FIXME pcr != exactly what wanted */
571 const mtime_t i_used = /*(i_stream_duration - input_priv(p_sys->p_input)->i_pts_delay)*/ p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
572 i_date -= i_used;
574 p_sys->i_buffering_extra_initial = 0;
575 p_sys->i_buffering_extra_stream = 0;
576 p_sys->i_buffering_extra_system = 0;
578 EsOutProgramChangePause( out, false, i_date );
579 EsOutDecodersChangePause( out, false, i_date );
581 EsOutProgramsChangeRate( out );
583 p_sys->b_paused = b_paused;
584 p_sys->i_pause_date = i_date;
587 static void EsOutChangeRate( es_out_t *out, int i_rate )
589 es_out_sys_t *p_sys = out->p_sys;
591 p_sys->i_rate = i_rate;
592 EsOutProgramsChangeRate( out );
595 static void EsOutChangePosition( es_out_t *out )
597 es_out_sys_t *p_sys = out->p_sys;
599 input_SendEventCache( p_sys->p_input, 0.0 );
601 for( int i = 0; i < p_sys->i_es; i++ )
603 es_out_id_t *p_es = p_sys->es[i];
605 if( p_es->p_dec != NULL )
607 input_DecoderFlush( p_es->p_dec );
608 if( !p_sys->b_buffering )
610 input_DecoderStartWait( p_es->p_dec );
611 if( p_es->p_dec_record != NULL )
612 input_DecoderStartWait( p_es->p_dec_record );
617 for( int i = 0; i < p_sys->i_pgrm; i++ )
618 input_clock_Reset( p_sys->pgrm[i]->p_clock );
620 p_sys->b_buffering = true;
621 p_sys->i_buffering_extra_initial = 0;
622 p_sys->i_buffering_extra_stream = 0;
623 p_sys->i_buffering_extra_system = 0;
624 p_sys->i_preroll_end = -1;
625 p_sys->i_prev_stream_level = -1;
630 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced )
632 es_out_sys_t *p_sys = out->p_sys;
634 mtime_t i_stream_start;
635 mtime_t i_system_start;
636 mtime_t i_stream_duration;
637 mtime_t i_system_duration;
638 if (input_clock_GetState( p_sys->p_pgrm->p_clock,
639 &i_stream_start, &i_system_start,
640 &i_stream_duration, &i_system_duration ))
641 return;
643 mtime_t i_preroll_duration = 0;
644 if( p_sys->i_preroll_end >= 0 )
645 i_preroll_duration = __MAX( p_sys->i_preroll_end - i_stream_start, 0 );
647 const mtime_t i_buffering_duration = p_sys->i_pts_delay +
648 i_preroll_duration +
649 p_sys->i_buffering_extra_stream - p_sys->i_buffering_extra_initial;
651 if( i_stream_duration <= i_buffering_duration && !b_forced )
653 double f_level;
654 if (i_buffering_duration == 0)
655 f_level = 0;
656 else
657 f_level = __MAX( (double)i_stream_duration / i_buffering_duration, 0 );
658 input_SendEventCache( p_sys->p_input, f_level );
660 int i_level = (int)(100 * f_level);
661 if( p_sys->i_prev_stream_level != i_level )
663 msg_Dbg( p_sys->p_input, "Buffering %d%%", i_level );
664 p_sys->i_prev_stream_level = i_level;
667 return;
669 input_SendEventCache( p_sys->p_input, 1.0 );
671 msg_Dbg( p_sys->p_input, "Stream buffering done (%d ms in %d ms)",
672 (int)(i_stream_duration/1000), (int)(i_system_duration/1000) );
673 p_sys->b_buffering = false;
674 p_sys->i_preroll_end = -1;
675 p_sys->i_prev_stream_level = -1;
677 if( p_sys->i_buffering_extra_initial > 0 )
679 /* FIXME wrong ? */
680 return;
683 const mtime_t i_decoder_buffering_start = mdate();
684 for( int i = 0; i < p_sys->i_es; i++ )
686 es_out_id_t *p_es = p_sys->es[i];
688 if( !p_es->p_dec || p_es->fmt.i_cat == SPU_ES )
689 continue;
690 input_DecoderWait( p_es->p_dec );
691 if( p_es->p_dec_record )
692 input_DecoderWait( p_es->p_dec_record );
695 msg_Dbg( p_sys->p_input, "Decoder wait done in %d ms",
696 (int)(mdate() - i_decoder_buffering_start)/1000 );
698 /* Here is a good place to destroy unused vout with every demuxer */
699 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
701 /* */
702 const mtime_t i_wakeup_delay = 10*1000; /* FIXME CLEANUP thread wake up time*/
703 const mtime_t i_current_date = p_sys->b_paused ? p_sys->i_pause_date : mdate();
705 input_clock_ChangeSystemOrigin( p_sys->p_pgrm->p_clock, true,
706 i_current_date + i_wakeup_delay - i_buffering_duration );
708 for( int i = 0; i < p_sys->i_es; i++ )
710 es_out_id_t *p_es = p_sys->es[i];
712 if( !p_es->p_dec )
713 continue;
715 input_DecoderStopWait( p_es->p_dec );
716 if( p_es->p_dec_record )
717 input_DecoderStopWait( p_es->p_dec_record );
720 static void EsOutDecodersChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
722 es_out_sys_t *p_sys = out->p_sys;
724 /* Pause decoders first */
725 for( int i = 0; i < p_sys->i_es; i++ )
727 es_out_id_t *es = p_sys->es[i];
729 if( es->p_dec )
731 input_DecoderChangePause( es->p_dec, b_paused, i_date );
732 if( es->p_dec_record )
733 input_DecoderChangePause( es->p_dec_record, b_paused, i_date );
738 static bool EsOutIsExtraBufferingAllowed( es_out_t *out )
740 es_out_sys_t *p_sys = out->p_sys;
742 size_t i_size = 0;
743 for( int i = 0; i < p_sys->i_es; i++ )
745 es_out_id_t *p_es = p_sys->es[i];
747 if( p_es->p_dec )
748 i_size += input_DecoderGetFifoSize( p_es->p_dec );
749 if( p_es->p_dec_record )
750 i_size += input_DecoderGetFifoSize( p_es->p_dec_record );
752 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
754 /* TODO maybe we want to be able to tune it ? */
755 #if defined(OPTIMIZE_MEMORY)
756 const size_t i_level_high = 512*1024; /* 0.5 MiB */
757 #else
758 const size_t i_level_high = 10*1024*1024; /* 10 MiB */
759 #endif
760 return i_size < i_level_high;
763 static void EsOutProgramChangePause( es_out_t *out, bool b_paused, mtime_t i_date )
765 es_out_sys_t *p_sys = out->p_sys;
767 for( int i = 0; i < p_sys->i_pgrm; i++ )
768 input_clock_ChangePause( p_sys->pgrm[i]->p_clock, b_paused, i_date );
771 static void EsOutDecoderChangeDelay( es_out_t *out, es_out_id_t *p_es )
773 es_out_sys_t *p_sys = out->p_sys;
775 mtime_t i_delay = 0;
776 if( p_es->fmt.i_cat == AUDIO_ES )
777 i_delay = p_sys->i_audio_delay;
778 else if( p_es->fmt.i_cat == SPU_ES )
779 i_delay = p_sys->i_spu_delay;
780 else
781 return;
783 if( p_es->p_dec )
784 input_DecoderChangeDelay( p_es->p_dec, i_delay );
785 if( p_es->p_dec_record )
786 input_DecoderChangeDelay( p_es->p_dec_record, i_delay );
788 static void EsOutProgramsChangeRate( es_out_t *out )
790 es_out_sys_t *p_sys = out->p_sys;
792 for( int i = 0; i < p_sys->i_pgrm; i++ )
793 input_clock_ChangeRate( p_sys->pgrm[i]->p_clock, p_sys->i_rate );
796 static void EsOutFrameNext( es_out_t *out )
798 es_out_sys_t *p_sys = out->p_sys;
799 es_out_id_t *p_es_video = NULL;
801 if( p_sys->b_buffering )
803 msg_Warn( p_sys->p_input, "buffering, ignoring 'frame next'" );
804 return;
807 assert( p_sys->b_paused );
809 for( int i = 0; i < p_sys->i_es; i++ )
811 es_out_id_t *p_es = p_sys->es[i];
813 if( p_es->fmt.i_cat == VIDEO_ES && p_es->p_dec )
815 p_es_video = p_es;
816 break;
820 if( !p_es_video )
822 msg_Warn( p_sys->p_input, "No video track selected, ignoring 'frame next'" );
823 return;
826 mtime_t i_duration;
827 input_DecoderFrameNext( p_es_video->p_dec, &i_duration );
829 msg_Dbg( out->p_sys->p_input, "EsOutFrameNext consummed %d ms", (int)(i_duration/1000) );
831 if( i_duration <= 0 )
832 i_duration = 40*1000;
834 /* FIXME it is not a clean way ? */
835 if( p_sys->i_buffering_extra_initial <= 0 )
837 mtime_t i_stream_start;
838 mtime_t i_system_start;
839 mtime_t i_stream_duration;
840 mtime_t i_system_duration;
841 int i_ret;
843 i_ret = input_clock_GetState( p_sys->p_pgrm->p_clock,
844 &i_stream_start, &i_system_start,
845 &i_stream_duration, &i_system_duration );
846 if( i_ret )
847 return;
849 p_sys->i_buffering_extra_initial = 1 + i_stream_duration - p_sys->i_pts_delay; /* FIXME < 0 ? */
850 p_sys->i_buffering_extra_system =
851 p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial;
854 const int i_rate = input_clock_GetRate( p_sys->p_pgrm->p_clock );
856 p_sys->b_buffering = true;
857 p_sys->i_buffering_extra_system += i_duration;
858 p_sys->i_buffering_extra_stream = p_sys->i_buffering_extra_initial +
859 ( p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial ) *
860 INPUT_RATE_DEFAULT / i_rate;
862 p_sys->i_preroll_end = -1;
863 p_sys->i_prev_stream_level = -1;
865 static mtime_t EsOutGetBuffering( es_out_t *out )
867 es_out_sys_t *p_sys = out->p_sys;
868 mtime_t i_stream_duration, i_system_start;
870 if( !p_sys->p_pgrm )
871 return 0;
872 else
874 mtime_t i_stream_start, i_system_duration;
876 if( input_clock_GetState( p_sys->p_pgrm->p_clock,
877 &i_stream_start, &i_system_start,
878 &i_stream_duration, &i_system_duration ) )
879 return 0;
882 mtime_t i_delay;
884 if( p_sys->b_buffering && p_sys->i_buffering_extra_initial <= 0 )
886 i_delay = i_stream_duration;
888 else
890 mtime_t i_system_duration;
892 if( p_sys->b_paused )
894 i_system_duration = p_sys->i_pause_date - i_system_start;
895 if( p_sys->i_buffering_extra_initial > 0 )
896 i_system_duration += p_sys->i_buffering_extra_system - p_sys->i_buffering_extra_initial;
898 else
900 i_system_duration = mdate() - i_system_start;
903 const mtime_t i_consumed = i_system_duration * INPUT_RATE_DEFAULT / p_sys->i_rate - i_stream_duration;
904 i_delay = p_sys->i_pts_delay - i_consumed;
906 if( i_delay < 0 )
907 return 0;
908 return i_delay;
911 static void EsOutESVarUpdateGeneric( es_out_t *out, int i_id,
912 const es_format_t *fmt, const char *psz_language,
913 bool b_delete )
915 es_out_sys_t *p_sys = out->p_sys;
916 input_thread_t *p_input = p_sys->p_input;
917 vlc_value_t val, text;
919 if( b_delete )
921 if( EsFmtIsTeletext( fmt ) )
922 input_SendEventTeletextDel( p_sys->p_input, i_id );
924 input_SendEventEsDel( p_input, fmt->i_cat, i_id );
925 return;
928 /* Get the number of ES already added */
929 const char *psz_var;
930 if( fmt->i_cat == AUDIO_ES )
931 psz_var = "audio-es";
932 else if( fmt->i_cat == VIDEO_ES )
933 psz_var = "video-es";
934 else
935 psz_var = "spu-es";
937 var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
938 if( val.i_int == 0 )
940 vlc_value_t val2;
942 /* First one, we need to add the "Disable" choice */
943 val2.i_int = -1; text.psz_string = _("Disable");
944 var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
945 val.i_int++;
948 /* Take care of the ES description */
949 if( fmt->psz_description && *fmt->psz_description )
951 if( psz_language && *psz_language )
953 if( asprintf( &text.psz_string, "%s - [%s]", fmt->psz_description,
954 psz_language ) == -1 )
955 text.psz_string = NULL;
957 else text.psz_string = strdup( fmt->psz_description );
959 else
961 if( psz_language && *psz_language )
963 if( asprintf( &text.psz_string, "%s %"PRId64" - [%s]", _( "Track" ), val.i_int, psz_language ) == -1 )
964 text.psz_string = NULL;
966 else
968 if( asprintf( &text.psz_string, "%s %"PRId64, _( "Track" ), val.i_int ) == -1 )
969 text.psz_string = NULL;
973 input_SendEventEsAdd( p_input, fmt->i_cat, i_id, text.psz_string );
974 if( EsFmtIsTeletext( fmt ) )
976 char psz_page[3+1];
977 snprintf( psz_page, sizeof(psz_page), "%d%2.2x",
978 fmt->subs.teletext.i_magazine,
979 fmt->subs.teletext.i_page );
980 input_SendEventTeletextAdd( p_sys->p_input,
981 i_id, fmt->subs.teletext.i_magazine >= 0 ? psz_page : NULL );
984 free( text.psz_string );
987 static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es,
988 bool b_delete )
990 EsOutESVarUpdateGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
993 static bool EsOutIsProgramVisible( es_out_t *out, int i_group )
995 return out->p_sys->i_group_id == 0 || out->p_sys->i_group_id == i_group;
998 /* EsOutProgramSelect:
999 * Select a program and update the object variable
1001 static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
1003 es_out_sys_t *p_sys = out->p_sys;
1004 input_thread_t *p_input = p_sys->p_input;
1005 int i;
1007 if( p_sys->p_pgrm == p_pgrm )
1008 return; /* Nothing to do */
1010 if( p_sys->p_pgrm )
1012 es_out_pgrm_t *old = p_sys->p_pgrm;
1013 msg_Dbg( p_input, "unselecting program id=%d", old->i_id );
1015 for( i = 0; i < p_sys->i_es; i++ )
1017 if( p_sys->es[i]->p_pgrm == old && EsIsSelected( p_sys->es[i] ) &&
1018 p_sys->i_mode != ES_OUT_MODE_ALL )
1019 EsUnselect( out, p_sys->es[i], true );
1022 p_sys->audio.p_main_es = NULL;
1023 p_sys->video.p_main_es = NULL;
1024 p_sys->sub.p_main_es = NULL;
1027 msg_Dbg( p_input, "selecting program id=%d", p_pgrm->i_id );
1029 /* Mark it selected */
1030 p_pgrm->b_selected = true;
1032 /* Switch master stream */
1033 p_sys->p_pgrm = p_pgrm;
1035 /* Update "program" */
1036 input_SendEventProgramSelect( p_input, p_pgrm->i_id );
1038 /* Update "es-*" */
1039 input_SendEventEsDel( p_input, AUDIO_ES, -1 );
1040 input_SendEventEsDel( p_input, VIDEO_ES, -1 );
1041 input_SendEventEsDel( p_input, SPU_ES, -1 );
1042 input_SendEventTeletextDel( p_input, -1 );
1043 input_SendEventProgramScrambled( p_input, p_pgrm->i_id, p_pgrm->b_scrambled );
1045 /* TODO event */
1046 var_SetInteger( p_input, "teletext-es", -1 );
1048 for( i = 0; i < p_sys->i_es; i++ )
1050 if( p_sys->es[i]->p_pgrm == p_sys->p_pgrm )
1052 EsOutESVarUpdate( out, p_sys->es[i], false );
1053 EsOutUpdateInfo( out, p_sys->es[i], &p_sys->es[i]->fmt, NULL );
1056 EsOutSelect( out, p_sys->es[i], false );
1059 /* Ensure the correct running EPG table is selected */
1060 input_item_ChangeEPGSource( input_priv(p_input)->p_item, p_pgrm->i_id );
1062 /* Update now playing */
1063 if( p_pgrm->p_meta )
1065 input_item_SetESNowPlaying( input_priv(p_input)->p_item,
1066 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_ESNowPlaying ) );
1067 input_item_SetPublisher( input_priv(p_input)->p_item,
1068 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Publisher ) );
1069 input_item_SetTitle( input_priv(p_input)->p_item,
1070 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) );
1071 input_SendEventMeta( p_input );
1072 /* FIXME: we probably want to replace every input meta */
1076 /* EsOutAddProgram:
1077 * Add a program
1079 static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
1081 es_out_sys_t *p_sys = out->p_sys;
1082 input_thread_t *p_input = p_sys->p_input;
1084 es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
1085 if( !p_pgrm )
1086 return NULL;
1088 /* Init */
1089 p_pgrm->i_id = i_group;
1090 p_pgrm->i_es = 0;
1091 p_pgrm->b_selected = false;
1092 p_pgrm->b_scrambled = false;
1093 p_pgrm->p_meta = NULL;
1094 p_pgrm->p_clock = input_clock_New( p_sys->i_rate );
1095 if( !p_pgrm->p_clock )
1097 free( p_pgrm );
1098 return NULL;
1100 if( p_sys->b_paused )
1101 input_clock_ChangePause( p_pgrm->p_clock, p_sys->b_paused, p_sys->i_pause_date );
1102 input_clock_SetJitter( p_pgrm->p_clock, p_sys->i_pts_delay, p_sys->i_cr_average );
1104 /* Append it */
1105 TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
1107 /* Update "program" variable */
1108 if( EsOutIsProgramVisible( out, i_group ) )
1109 input_SendEventProgramAdd( p_input, i_group, NULL );
1111 if( i_group == p_sys->i_group_id || ( !p_sys->p_pgrm && p_sys->i_group_id == 0 ) )
1112 EsOutProgramSelect( out, p_pgrm );
1114 return p_pgrm;
1117 /* EsOutDelProgram:
1118 * Delete a program
1120 static int EsOutProgramDel( es_out_t *out, int i_group )
1122 es_out_sys_t *p_sys = out->p_sys;
1123 input_thread_t *p_input = p_sys->p_input;
1124 es_out_pgrm_t *p_pgrm = NULL;
1125 int i;
1127 for( i = 0; i < p_sys->i_pgrm; i++ )
1129 if( p_sys->pgrm[i]->i_id == i_group )
1131 p_pgrm = p_sys->pgrm[i];
1132 break;
1136 if( p_pgrm == NULL )
1137 return VLC_EGENERIC;
1139 if( p_pgrm->i_es )
1141 msg_Dbg( p_input, "can't delete program %d which still has %i ES",
1142 i_group, p_pgrm->i_es );
1143 return VLC_EGENERIC;
1146 TAB_REMOVE( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
1148 /* If program is selected we need to unselect it */
1149 if( p_sys->p_pgrm == p_pgrm )
1150 p_sys->p_pgrm = NULL;
1152 input_clock_Delete( p_pgrm->p_clock );
1154 if( p_pgrm->p_meta )
1155 vlc_meta_Delete( p_pgrm->p_meta );
1156 free( p_pgrm );
1158 /* Update "program" variable */
1159 input_SendEventProgramDel( p_input, i_group );
1161 return VLC_SUCCESS;
1164 /* EsOutProgramFind
1166 static es_out_pgrm_t *EsOutProgramFind( es_out_t *p_out, int i_group )
1168 es_out_sys_t *p_sys = p_out->p_sys;
1170 for( int i = 0; i < p_sys->i_pgrm; i++ )
1172 if( p_sys->pgrm[i]->i_id == i_group )
1173 return p_sys->pgrm[i];
1175 return EsOutProgramAdd( p_out, i_group );
1178 /* EsOutProgramMeta:
1180 static char *EsOutProgramGetMetaName( es_out_pgrm_t *p_pgrm )
1182 char *psz = NULL;
1183 if( p_pgrm->p_meta && vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) )
1185 if( asprintf( &psz, _("%s [%s %d]"), vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ),
1186 _("Program"), p_pgrm->i_id ) == -1 )
1187 return NULL;
1189 else
1191 if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
1192 return NULL;
1194 return psz;
1197 static char *EsOutProgramGetProgramName( es_out_pgrm_t *p_pgrm )
1199 char *psz = NULL;
1200 if( p_pgrm->p_meta && vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) )
1202 return strdup( vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title ) );
1204 else
1206 if( asprintf( &psz, "%s %d", _("Program"), p_pgrm->i_id ) == -1 )
1207 return NULL;
1209 return psz;
1212 static char *EsInfoCategoryName( es_out_id_t* es )
1214 char *psz_category;
1216 if( asprintf( &psz_category, _("Stream %d"), es->i_meta_id ) == -1 )
1217 return NULL;
1219 return psz_category;
1222 static void EsOutProgramMeta( es_out_t *out, int i_group, const vlc_meta_t *p_meta )
1224 es_out_sys_t *p_sys = out->p_sys;
1225 es_out_pgrm_t *p_pgrm;
1226 input_thread_t *p_input = p_sys->p_input;
1227 const char *psz_title = NULL;
1228 const char *psz_provider = NULL;
1229 int i;
1231 msg_Dbg( p_input, "EsOutProgramMeta: number=%d", i_group );
1233 /* Check against empty meta data (empty for what we handle) */
1234 if( !vlc_meta_Get( p_meta, vlc_meta_Title) &&
1235 !vlc_meta_Get( p_meta, vlc_meta_ESNowPlaying) &&
1236 !vlc_meta_Get( p_meta, vlc_meta_Publisher) )
1238 return;
1241 if( i_group < 0 )
1243 EsOutGlobalMeta( out, p_meta );
1244 return;
1247 /* Find program */
1248 if( !EsOutIsProgramVisible( out, i_group ) )
1249 return;
1250 p_pgrm = EsOutProgramFind( out, i_group );
1251 if( !p_pgrm )
1252 return;
1254 if( p_pgrm->p_meta )
1256 const char *psz_current_title = vlc_meta_Get( p_pgrm->p_meta, vlc_meta_Title );
1257 const char *psz_new_title = vlc_meta_Get( p_meta, vlc_meta_Title );
1258 if( !psz_current_title != !psz_new_title ||
1259 ( psz_new_title && psz_new_title && strcmp(psz_new_title, psz_current_title)) )
1261 /* Remove old entries */
1262 char *psz_oldinfokey = EsOutProgramGetMetaName( p_pgrm );
1263 input_Control( p_input, INPUT_DEL_INFO, psz_oldinfokey, NULL );
1264 /* TODO update epg name ?
1265 * TODO update scrambled info name ? */
1266 free( psz_oldinfokey );
1268 vlc_meta_Delete( p_pgrm->p_meta );
1270 p_pgrm->p_meta = vlc_meta_New();
1271 if( p_pgrm->p_meta )
1272 vlc_meta_Merge( p_pgrm->p_meta, p_meta );
1274 if( p_sys->p_pgrm == p_pgrm )
1276 EsOutMeta( out, NULL, p_meta );
1278 /* */
1279 psz_title = vlc_meta_Get( p_meta, vlc_meta_Title);
1280 psz_provider = vlc_meta_Get( p_meta, vlc_meta_Publisher);
1282 /* Update the description text of the program */
1283 if( psz_title && *psz_title )
1285 char *psz_text;
1286 if( psz_provider && *psz_provider )
1288 if( asprintf( &psz_text, "%s [%s]", psz_title, psz_provider ) < 0 )
1289 psz_text = NULL;
1291 else
1293 psz_text = strdup( psz_title );
1296 /* ugly but it works */
1297 if( psz_text )
1299 input_SendEventProgramDel( p_input, i_group );
1300 input_SendEventProgramAdd( p_input, i_group, psz_text );
1301 if( p_sys->p_pgrm == p_pgrm )
1302 input_SendEventProgramSelect( p_input, i_group );
1303 free( psz_text );
1307 /* */
1308 char **ppsz_all_keys = vlc_meta_CopyExtraNames(p_meta );
1310 info_category_t *p_cat = NULL;
1311 if( psz_provider || ( ppsz_all_keys[0] && *ppsz_all_keys[0] ) )
1313 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
1314 if( psz_cat )
1315 p_cat = info_category_New( psz_cat );
1316 free( psz_cat );
1319 for( i = 0; ppsz_all_keys[i]; i++ )
1321 if( p_cat )
1322 info_category_AddInfo( p_cat, vlc_gettext(ppsz_all_keys[i]), "%s",
1323 vlc_meta_GetExtra( p_meta, ppsz_all_keys[i] ) );
1324 free( ppsz_all_keys[i] );
1326 free( ppsz_all_keys );
1328 if( psz_provider )
1330 if( p_sys->p_pgrm == p_pgrm )
1332 input_item_SetPublisher( input_priv(p_input)->p_item, psz_provider );
1333 input_SendEventMeta( p_input );
1335 if( p_cat )
1336 info_category_AddInfo( p_cat, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher),
1337 "%s",psz_provider );
1339 if( p_cat )
1340 input_Control( p_input, INPUT_MERGE_INFOS, p_cat );
1343 static void EsOutProgramEpgEvent( es_out_t *out, int i_group, const vlc_epg_event_t *p_event )
1345 es_out_sys_t *p_sys = out->p_sys;
1346 input_thread_t *p_input = p_sys->p_input;
1347 input_item_t *p_item = input_priv(p_input)->p_item;
1348 es_out_pgrm_t *p_pgrm;
1350 /* Find program */
1351 if( !EsOutIsProgramVisible( out, i_group ) )
1352 return;
1353 p_pgrm = EsOutProgramFind( out, i_group );
1354 if( !p_pgrm )
1355 return;
1357 input_item_SetEpgEvent( p_item, p_event );
1360 static void EsOutProgramEpg( es_out_t *out, int i_group, const vlc_epg_t *p_epg )
1362 es_out_sys_t *p_sys = out->p_sys;
1363 input_thread_t *p_input = p_sys->p_input;
1364 input_item_t *p_item = input_priv(p_input)->p_item;
1365 es_out_pgrm_t *p_pgrm;
1366 char *psz_cat;
1368 /* Find program */
1369 if( !EsOutIsProgramVisible( out, i_group ) )
1370 return;
1371 p_pgrm = EsOutProgramFind( out, i_group );
1372 if( !p_pgrm )
1373 return;
1375 /* Update info */
1376 psz_cat = EsOutProgramGetMetaName( p_pgrm );
1377 msg_Dbg( p_input, "EsOutProgramEpg: number=%d name=%s", i_group, psz_cat );
1379 /* Merge EPG */
1380 vlc_epg_t epg;
1382 epg = *p_epg;
1383 epg.psz_name = EsOutProgramGetProgramName( p_pgrm );
1385 input_item_SetEpg( p_item, &epg, p_sys->p_pgrm && (p_epg->i_source_id == p_sys->p_pgrm->i_id) );
1386 input_SendEventMetaEpg( p_sys->p_input );
1388 free( epg.psz_name );
1390 /* Update now playing */
1391 if( p_epg->b_present && p_pgrm->p_meta &&
1392 ( p_epg->p_current || p_epg->i_event == 0 ) )
1394 vlc_meta_SetNowPlaying( p_pgrm->p_meta, NULL );
1397 vlc_mutex_lock( &p_item->lock );
1398 for( int i = 0; i < p_item->i_epg; i++ )
1400 const vlc_epg_t *p_tmp = p_item->pp_epg[i];
1402 if( p_tmp->b_present && p_tmp->i_source_id == p_pgrm->i_id )
1404 const char *psz_name = ( p_tmp->p_current ) ? p_tmp->p_current->psz_name : NULL;
1405 if( !p_pgrm->p_meta )
1406 p_pgrm->p_meta = vlc_meta_New();
1407 if( p_pgrm->p_meta )
1408 vlc_meta_Set( p_pgrm->p_meta, vlc_meta_ESNowPlaying, psz_name );
1409 break;
1412 vlc_mutex_unlock( &p_item->lock );
1414 /* Update selected program input info */
1415 if( p_pgrm == p_sys->p_pgrm )
1417 const char *psz_nowplaying = p_pgrm->p_meta ?
1418 vlc_meta_Get( p_pgrm->p_meta, vlc_meta_ESNowPlaying ) : NULL;
1420 input_item_SetESNowPlaying( input_priv(p_input)->p_item, psz_nowplaying );
1421 input_SendEventMeta( p_input );
1423 if( psz_nowplaying )
1425 input_Control( p_input, INPUT_ADD_INFO, psz_cat,
1426 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying), "%s", psz_nowplaying );
1428 else
1430 input_Control( p_input, INPUT_DEL_INFO, psz_cat,
1431 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying) );
1435 free( psz_cat );
1438 static void EsOutEpgTime( es_out_t *out, int64_t time )
1440 es_out_sys_t *p_sys = out->p_sys;
1441 input_thread_t *p_input = p_sys->p_input;
1442 input_item_t *p_item = input_priv(p_input)->p_item;
1444 input_item_SetEpgTime( p_item, time );
1447 static void EsOutProgramUpdateScrambled( es_out_t *p_out, es_out_pgrm_t *p_pgrm )
1449 es_out_sys_t *p_sys = p_out->p_sys;
1450 input_thread_t *p_input = p_sys->p_input;
1451 bool b_scrambled = false;
1453 for( int i = 0; i < p_sys->i_es; i++ )
1455 if( p_sys->es[i]->p_pgrm == p_pgrm && p_sys->es[i]->b_scrambled )
1457 b_scrambled = true;
1458 break;
1461 if( !p_pgrm->b_scrambled == !b_scrambled )
1462 return;
1464 p_pgrm->b_scrambled = b_scrambled;
1465 char *psz_cat = EsOutProgramGetMetaName( p_pgrm );
1467 if( b_scrambled )
1468 input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Scrambled"), _("Yes") );
1469 else
1470 input_Control( p_input, INPUT_DEL_INFO, psz_cat, _("Scrambled") );
1471 free( psz_cat );
1473 input_SendEventProgramScrambled( p_input, p_pgrm->i_id, b_scrambled );
1476 static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_program_meta )
1478 es_out_sys_t *p_sys = p_out->p_sys;
1479 input_thread_t *p_input = p_sys->p_input;
1480 input_item_t *p_item = input_GetItem( p_input );
1482 vlc_mutex_lock( &p_item->lock );
1483 if( p_meta )
1484 vlc_meta_Merge( p_item->p_meta, p_meta );
1485 vlc_mutex_unlock( &p_item->lock );
1487 /* Check program meta to not override GROUP_META values */
1488 if( p_meta && (!p_program_meta || vlc_meta_Get( p_program_meta, vlc_meta_Title ) == NULL) &&
1489 vlc_meta_Get( p_meta, vlc_meta_Title ) != NULL )
1490 input_item_SetName( p_item, vlc_meta_Get( p_meta, vlc_meta_Title ) );
1492 const char *psz_arturl = NULL;
1493 char *psz_alloc = NULL;
1495 if( p_program_meta )
1496 psz_arturl = vlc_meta_Get( p_program_meta, vlc_meta_ArtworkURL );
1497 if( psz_arturl == NULL && p_meta )
1498 psz_arturl = vlc_meta_Get( p_meta, vlc_meta_ArtworkURL );
1500 if( psz_arturl == NULL ) /* restore/favor previously set item art URL */
1501 psz_arturl = psz_alloc = input_item_GetArtURL( p_item );
1503 if( psz_arturl != NULL )
1504 input_item_SetArtURL( p_item, psz_arturl );
1506 if( psz_arturl != NULL && !strncmp( psz_arturl, "attachment://", 13 ) )
1507 { /* Clear art cover if streaming out.
1508 * FIXME: Why? Remove this when sout gets meta data support. */
1509 if( input_priv(p_input)->p_sout != NULL )
1510 input_item_SetArtURL( p_item, NULL );
1511 else
1512 input_ExtractAttachmentAndCacheArt( p_input, psz_arturl + 13 );
1514 free( psz_alloc );
1516 input_item_SetPreparsed( p_item, true );
1518 input_SendEventMeta( p_input );
1519 /* TODO handle sout meta ? */
1522 static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta )
1524 es_out_sys_t *p_sys = p_out->p_sys;
1525 EsOutMeta( p_out, p_meta,
1526 (p_sys->p_pgrm && p_sys->p_pgrm->p_meta) ? p_sys->p_pgrm->p_meta : NULL );
1529 static es_out_id_t *EsOutAddSlave( es_out_t *out, const es_format_t *fmt, es_out_id_t *p_master )
1531 es_out_sys_t *p_sys = out->p_sys;
1532 input_thread_t *p_input = p_sys->p_input;
1534 if( fmt->i_group < 0 )
1536 msg_Err( p_input, "invalid group number" );
1537 return NULL;
1540 es_out_id_t *es = malloc( sizeof( *es ) );
1541 es_out_pgrm_t *p_pgrm;
1542 int i;
1544 if( !es )
1545 return NULL;
1547 vlc_mutex_lock( &p_sys->lock );
1549 /* Search the program */
1550 p_pgrm = EsOutProgramFind( out, fmt->i_group );
1551 if( !p_pgrm )
1553 vlc_mutex_unlock( &p_sys->lock );
1554 free( es );
1555 return NULL;
1558 /* Increase ref count for program */
1559 p_pgrm->i_es++;
1561 /* Set up ES */
1562 es->p_pgrm = p_pgrm;
1563 es_format_Copy( &es->fmt, fmt );
1564 if( es->fmt.i_id < 0 )
1565 es->fmt.i_id = p_sys->i_id;
1566 if( !es->fmt.i_original_fourcc )
1567 es->fmt.i_original_fourcc = es->fmt.i_codec;
1569 es->i_id = es->fmt.i_id;
1570 es->i_meta_id = p_sys->i_id++; /* always incremented */
1571 es->b_scrambled = false;
1573 switch( es->fmt.i_cat )
1575 case AUDIO_ES:
1577 es->fmt.i_codec = vlc_fourcc_GetCodecAudio( es->fmt.i_codec,
1578 es->fmt.audio.i_bitspersample );
1579 es->i_channel = p_sys->audio.i_count++;
1581 audio_replay_gain_t rg;
1582 memset( &rg, 0, sizeof(rg) );
1583 vlc_mutex_lock( &input_priv(p_input)->p_item->lock );
1584 vlc_audio_replay_gain_MergeFromMeta( &rg, input_priv(p_input)->p_item->p_meta );
1585 vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
1587 for( i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
1589 if( !es->fmt.audio_replay_gain.pb_peak[i] )
1591 es->fmt.audio_replay_gain.pb_peak[i] = rg.pb_peak[i];
1592 es->fmt.audio_replay_gain.pf_peak[i] = rg.pf_peak[i];
1594 if( !es->fmt.audio_replay_gain.pb_gain[i] )
1596 es->fmt.audio_replay_gain.pb_gain[i] = rg.pb_gain[i];
1597 es->fmt.audio_replay_gain.pf_gain[i] = rg.pf_gain[i];
1600 break;
1603 case VIDEO_ES:
1604 es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat, es->fmt.i_codec );
1605 es->i_channel = p_sys->video.i_count++;
1607 if( !es->fmt.video.i_visible_width || !es->fmt.video.i_visible_height )
1609 es->fmt.video.i_visible_width = es->fmt.video.i_width;
1610 es->fmt.video.i_visible_height = es->fmt.video.i_height;
1613 if( es->fmt.video.i_frame_rate && es->fmt.video.i_frame_rate_base )
1614 vlc_ureduce( &es->fmt.video.i_frame_rate,
1615 &es->fmt.video.i_frame_rate_base,
1616 es->fmt.video.i_frame_rate,
1617 es->fmt.video.i_frame_rate_base, 0 );
1618 break;
1620 case SPU_ES:
1621 es->fmt.i_codec = vlc_fourcc_GetCodec( es->fmt.i_cat, es->fmt.i_codec );
1622 es->i_channel = p_sys->sub.i_count++;
1623 break;
1625 default:
1626 es->i_channel = 0;
1627 break;
1629 es->psz_language = LanguageGetName( es->fmt.psz_language ); /* remember so we only need to do it once */
1630 es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
1631 es->p_dec = NULL;
1632 es->p_dec_record = NULL;
1633 es->cc.type = 0;
1634 es->cc.i_bitmap = 0;
1635 es->p_master = p_master;
1637 TAB_APPEND( p_sys->i_es, p_sys->es, es );
1639 if( es->p_pgrm == p_sys->p_pgrm )
1640 EsOutESVarUpdate( out, es, false );
1642 EsOutUpdateInfo( out, es, &es->fmt, NULL );
1643 EsOutSelect( out, es, false );
1645 if( es->b_scrambled )
1646 EsOutProgramUpdateScrambled( out, es->p_pgrm );
1648 vlc_mutex_unlock( &p_sys->lock );
1650 return es;
1653 /* EsOutAdd:
1654 * Add an es_out
1656 static es_out_id_t *EsOutAdd( es_out_t *out, const es_format_t *fmt )
1658 return EsOutAddSlave( out, fmt, NULL );
1661 static bool EsIsSelected( es_out_id_t *es )
1663 if( es->p_master )
1665 bool b_decode = false;
1666 if( es->p_master->p_dec )
1668 int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
1669 input_DecoderGetCcState( es->p_master->p_dec, es->fmt.i_codec,
1670 i_channel, &b_decode );
1672 return b_decode;
1674 else
1676 return es->p_dec != NULL;
1679 static void EsCreateDecoder( es_out_t *out, es_out_id_t *p_es )
1681 es_out_sys_t *p_sys = out->p_sys;
1682 input_thread_t *p_input = p_sys->p_input;
1684 p_es->p_dec = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, input_priv(p_input)->p_sout );
1685 if( p_es->p_dec )
1687 if( p_sys->b_buffering )
1688 input_DecoderStartWait( p_es->p_dec );
1690 if( !p_es->p_master && p_sys->p_sout_record )
1692 p_es->p_dec_record = input_DecoderNew( p_input, &p_es->fmt, p_es->p_pgrm->p_clock, p_sys->p_sout_record );
1693 if( p_es->p_dec_record && p_sys->b_buffering )
1694 input_DecoderStartWait( p_es->p_dec_record );
1698 EsOutDecoderChangeDelay( out, p_es );
1700 static void EsDestroyDecoder( es_out_t *out, es_out_id_t *p_es )
1702 VLC_UNUSED(out);
1704 if( !p_es->p_dec )
1705 return;
1707 input_DecoderDelete( p_es->p_dec );
1708 p_es->p_dec = NULL;
1710 if( p_es->p_dec_record )
1712 input_DecoderDelete( p_es->p_dec_record );
1713 p_es->p_dec_record = NULL;
1717 static void EsSelect( es_out_t *out, es_out_id_t *es )
1719 es_out_sys_t *p_sys = out->p_sys;
1720 input_thread_t *p_input = p_sys->p_input;
1722 if( EsIsSelected( es ) )
1724 msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
1725 return;
1728 if( es->p_master )
1730 int i_channel;
1731 if( !es->p_master->p_dec )
1732 return;
1734 i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
1736 if( i_channel == -1 ||
1737 input_DecoderSetCcState( es->p_master->p_dec, es->fmt.i_codec,
1738 i_channel, true ) )
1739 return;
1741 else
1743 const bool b_sout = input_priv(p_input)->p_sout != NULL;
1744 if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
1746 if( !var_GetBool( p_input, b_sout ? "sout-video" : "video" ) )
1748 msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
1749 es->i_id );
1750 return;
1753 else if( es->fmt.i_cat == AUDIO_ES )
1755 if( !var_GetBool( p_input, b_sout ? "sout-audio" : "audio" ) )
1757 msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
1758 es->i_id );
1759 return;
1762 if( es->fmt.i_cat == SPU_ES )
1764 if( !var_GetBool( p_input, b_sout ? "sout-spu" : "spu" ) )
1766 msg_Dbg( p_input, "spu is disabled, not selecting ES 0x%x",
1767 es->i_id );
1768 return;
1772 EsCreateDecoder( out, es );
1774 if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
1775 return;
1778 /* Mark it as selected */
1779 input_SendEventEsSelect( p_input, es->fmt.i_cat, es->i_id );
1780 input_SendEventTeletextSelect( p_input, EsFmtIsTeletext( &es->fmt ) ? es->i_id : -1 );
1783 static void EsDeleteCCChannels( es_out_t *out, es_out_id_t *parent )
1785 es_out_sys_t *p_sys = out->p_sys;
1786 input_thread_t *p_input = p_sys->p_input;
1788 if( parent->cc.type == 0 )
1789 return;
1791 const int i_spu_id = var_GetInteger( p_input, "spu-es");
1793 uint64_t i_bitmap = parent->cc.i_bitmap;
1794 for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1 )
1796 if( (i_bitmap & 1) == 0 || !parent->cc.pp_es[i] )
1797 continue;
1799 if( i_spu_id == parent->cc.pp_es[i]->i_id )
1801 /* Force unselection of the CC */
1802 input_SendEventEsSelect( p_input, SPU_ES, -1 );
1804 EsOutDel( out, parent->cc.pp_es[i] );
1807 parent->cc.i_bitmap = 0;
1808 parent->cc.type = 0;
1811 static void EsUnselect( es_out_t *out, es_out_id_t *es, bool b_update )
1813 es_out_sys_t *p_sys = out->p_sys;
1814 input_thread_t *p_input = p_sys->p_input;
1816 if( !EsIsSelected( es ) )
1818 msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
1819 return;
1822 if( es->p_master )
1824 if( es->p_master->p_dec )
1826 int i_channel = EsOutGetClosedCaptionsChannel( &es->fmt );
1827 if( i_channel != -1 )
1828 input_DecoderSetCcState( es->p_master->p_dec, es->fmt.i_codec,
1829 i_channel, false );
1832 else
1834 EsDeleteCCChannels( out, es );
1835 EsDestroyDecoder( out, es );
1838 if( !b_update )
1839 return;
1841 /* Mark it as unselected */
1842 input_SendEventEsSelect( p_input, es->fmt.i_cat, -1 );
1843 if( EsFmtIsTeletext( &es->fmt ) )
1844 input_SendEventTeletextSelect( p_input, -1 );
1848 * Select an ES given the current mode
1849 * XXX: you need to take a the lock before (stream.stream_lock)
1851 * \param out The es_out structure
1852 * \param es es_out_id structure
1853 * \param b_force ...
1854 * \return nothing
1856 static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
1858 es_out_sys_t *p_sys = out->p_sys;
1859 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, es->fmt.i_cat );
1861 if( !p_sys->b_active ||
1862 ( !b_force && es->fmt.i_priority < ES_PRIORITY_SELECTABLE_MIN ) )
1864 return;
1867 if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
1869 if( !EsIsSelected( es ) )
1870 EsSelect( out, es );
1872 else if( p_sys->i_mode == ES_OUT_MODE_PARTIAL )
1874 char *prgms = var_GetNonEmptyString( p_sys->p_input, "programs" );
1875 if( prgms != NULL )
1877 char *buf;
1879 for ( const char *prgm = strtok_r( prgms, ",", &buf );
1880 prgm != NULL;
1881 prgm = strtok_r( NULL, ",", &buf ) )
1883 if( atoi( prgm ) == es->p_pgrm->i_id || b_force )
1885 if( !EsIsSelected( es ) )
1886 EsSelect( out, es );
1887 break;
1890 free( prgms );
1893 else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1895 const es_out_id_t *wanted_es = NULL;
1897 if( es->p_pgrm != p_sys->p_pgrm || !p_esprops )
1898 return;
1900 /* user designated by ID ES have higher prio than everything */
1901 if ( p_esprops->i_id >= 0 )
1903 if( es->i_id == p_esprops->i_id )
1904 wanted_es = es;
1906 /* then per pos */
1907 else if( p_esprops->i_channel >= 0 )
1909 if( p_esprops->i_channel == es->i_channel )
1910 wanted_es = es;
1912 else if( p_esprops->ppsz_language )
1914 /* If not deactivated */
1915 const int i_stop_idx = LanguageArrayIndex( p_esprops->ppsz_language, "none" );
1917 int current_es_idx = ( p_esprops->p_main_es == NULL ) ? -1 :
1918 LanguageArrayIndex( p_esprops->ppsz_language,
1919 p_esprops->p_main_es->psz_language_code );
1920 int es_idx = LanguageArrayIndex( p_esprops->ppsz_language,
1921 es->psz_language_code );
1922 if( es_idx >= 0 && (i_stop_idx < 0 || i_stop_idx > es_idx) )
1924 /* Only select the language if it's in the list */
1925 if( p_esprops->p_main_es == NULL ||
1926 current_es_idx < 0 || /* current es was not selected by lang prefs */
1927 es_idx < current_es_idx || /* current es has lower lang prio */
1928 ( es_idx == current_es_idx && /* lang is same, but es has higher prio */
1929 p_esprops->p_main_es->fmt.i_priority < es->fmt.i_priority ) )
1931 wanted_es = es;
1934 /* We did not find a language matching our prefs */
1935 else if( i_stop_idx < 0 ) /* If not fallback disabled by 'none' */
1937 /* Select if asked by demuxer */
1938 if( current_es_idx < 0 ) /* No es is currently selected by lang pref */
1940 /* If demux has specified a track */
1941 if( p_esprops->i_demux_id >= 0 && es->i_id == p_esprops->i_demux_id )
1943 wanted_es = es;
1945 /* Otherwise, fallback by priority */
1946 else if( p_esprops->p_main_es == NULL ||
1947 es->fmt.i_priority > p_esprops->p_main_es->fmt.i_priority )
1949 if( p_esprops->b_autoselect )
1950 wanted_es = es;
1957 /* If there is no user preference, select the default subtitle
1958 * or adapt by ES priority */
1959 else if( p_esprops->i_demux_id >= 0 && es->i_id == p_esprops->i_demux_id )
1961 wanted_es = es;
1963 else if( p_esprops->p_main_es == NULL ||
1964 es->fmt.i_priority > p_esprops->p_main_es->fmt.i_priority )
1966 if( p_esprops->b_autoselect )
1967 wanted_es = es;
1970 if( wanted_es == es && !EsIsSelected( es ) )
1971 EsSelect( out, es );
1974 /* FIXME TODO handle priority here */
1975 if( p_esprops && EsIsSelected( es ) )
1977 if( p_sys->i_mode == ES_OUT_MODE_AUTO )
1979 if( p_esprops->e_policy == ES_OUT_ES_POLICY_EXCLUSIVE &&
1980 p_esprops->p_main_es &&
1981 p_esprops->p_main_es != es )
1983 EsUnselect( out, p_esprops->p_main_es, false );
1985 p_esprops->p_main_es = es;
1990 static void EsOutCreateCCChannels( es_out_t *out, vlc_fourcc_t codec, uint64_t i_bitmap,
1991 const char *psz_descfmt, es_out_id_t *parent )
1993 es_out_sys_t *p_sys = out->p_sys;
1994 input_thread_t *p_input = p_sys->p_input;
1996 /* Only one type of captions is allowed ! */
1997 if( parent->cc.type && parent->cc.type != codec )
1998 return;
2000 uint64_t i_existingbitmap = parent->cc.i_bitmap;
2001 for( int i = 0; i_bitmap > 0; i++, i_bitmap >>= 1, i_existingbitmap >>= 1 )
2003 es_format_t fmt;
2005 if( (i_bitmap & 1) == 0 || (i_existingbitmap & 1) )
2006 continue;
2008 msg_Dbg( p_input, "Adding CC track %d for es[%d]", 1+i, parent->i_id );
2010 es_format_Init( &fmt, SPU_ES, codec );
2011 fmt.subs.cc.i_channel = i;
2012 fmt.i_group = parent->fmt.i_group;
2013 if( asprintf( &fmt.psz_description, psz_descfmt, 1 + i ) == -1 )
2014 fmt.psz_description = NULL;
2016 es_out_id_t **pp_es = &parent->cc.pp_es[i];
2017 *pp_es = EsOutAddSlave( out, &fmt, parent );
2018 es_format_Clean( &fmt );
2020 /* */
2021 parent->cc.i_bitmap |= (1ULL << i);
2022 parent->cc.type = codec;
2024 /* Enable if user specified on command line */
2025 if (p_sys->sub.i_channel == i)
2026 EsOutSelect(out, *pp_es, true);
2031 * Send a block for the given es_out
2033 * \param out the es_out to send from
2034 * \param es the es_out_id
2035 * \param p_block the data block to send
2037 static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
2039 es_out_sys_t *p_sys = out->p_sys;
2040 input_thread_t *p_input = p_sys->p_input;
2042 assert( p_block->p_next == NULL );
2044 if( libvlc_stats( p_input ) )
2046 uint64_t i_total;
2048 vlc_mutex_lock( &input_priv(p_input)->counters.counters_lock );
2049 stats_Update( input_priv(p_input)->counters.p_demux_read,
2050 p_block->i_buffer, &i_total );
2051 stats_Update( input_priv(p_input)->counters.p_demux_bitrate, i_total, NULL );
2053 /* Update number of corrupted data packats */
2054 if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
2056 stats_Update( input_priv(p_input)->counters.p_demux_corrupted, 1, NULL );
2058 /* Update number of discontinuities */
2059 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
2061 stats_Update( input_priv(p_input)->counters.p_demux_discontinuity, 1, NULL );
2063 vlc_mutex_unlock( &input_priv(p_input)->counters.counters_lock );
2066 vlc_mutex_lock( &p_sys->lock );
2068 /* Mark preroll blocks */
2069 if( p_sys->i_preroll_end >= 0 )
2071 int64_t i_date = p_block->i_pts;
2072 if( p_block->i_pts <= VLC_TS_INVALID )
2073 i_date = p_block->i_dts;
2075 if( i_date + p_block->i_length < p_sys->i_preroll_end )
2076 p_block->i_flags |= BLOCK_FLAG_PREROLL;
2079 if( !es->p_dec )
2081 block_Release( p_block );
2082 vlc_mutex_unlock( &p_sys->lock );
2083 return VLC_SUCCESS;
2086 /* Check for sout mode */
2087 if( input_priv(p_input)->p_sout )
2089 /* FIXME review this, proper lock may be missing */
2090 if( input_priv(p_input)->p_sout->i_out_pace_nocontrol > 0 &&
2091 input_priv(p_input)->b_out_pace_control )
2093 msg_Dbg( p_input, "switching to sync mode" );
2094 input_priv(p_input)->b_out_pace_control = false;
2096 else if( input_priv(p_input)->p_sout->i_out_pace_nocontrol <= 0 &&
2097 !input_priv(p_input)->b_out_pace_control )
2099 msg_Dbg( p_input, "switching to async mode" );
2100 input_priv(p_input)->b_out_pace_control = true;
2104 /* Decode */
2105 if( es->p_dec_record )
2107 block_t *p_dup = block_Duplicate( p_block );
2108 if( p_dup )
2109 input_DecoderDecode( es->p_dec_record, p_dup,
2110 input_priv(p_input)->b_out_pace_control );
2112 input_DecoderDecode( es->p_dec, p_block,
2113 input_priv(p_input)->b_out_pace_control );
2115 es_format_t fmt_dsc;
2116 vlc_meta_t *p_meta_dsc;
2117 if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
2119 EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );
2121 es_format_Clean( &fmt_dsc );
2122 if( p_meta_dsc )
2123 vlc_meta_Delete( p_meta_dsc );
2126 /* Check CC status */
2127 decoder_cc_desc_t desc;
2129 input_DecoderGetCcDesc( es->p_dec, &desc );
2130 if( var_InheritInteger( p_input, "captions" ) == 708 )
2131 EsOutCreateCCChannels( out, VLC_CODEC_CEA708, desc.i_708_channels,
2132 _("DTVCC Closed captions %u"), es );
2133 EsOutCreateCCChannels( out, VLC_CODEC_CEA608, desc.i_608_channels,
2134 _("Closed captions %u"), es );
2136 vlc_mutex_unlock( &p_sys->lock );
2138 return VLC_SUCCESS;
2141 /*****************************************************************************
2142 * EsOutDel:
2143 *****************************************************************************/
2144 static void EsOutDel( es_out_t *out, es_out_id_t *es )
2146 es_out_sys_t *p_sys = out->p_sys;
2147 bool b_reselect = false;
2148 int i;
2150 vlc_mutex_lock( &p_sys->lock );
2152 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, es->fmt.i_cat );
2154 /* We don't try to reselect */
2155 if( es->p_dec )
2156 { /* FIXME: This might hold the ES output caller (i.e. the demux), and
2157 * the corresponding thread (typically the input thread), for a little
2158 * bit too long if the ES is deleted in the middle of a stream. */
2159 input_DecoderDrain( es->p_dec );
2160 while( !input_Stopped(p_sys->p_input) && !p_sys->b_buffering )
2162 if( input_DecoderIsEmpty( es->p_dec ) &&
2163 ( !es->p_dec_record || input_DecoderIsEmpty( es->p_dec_record ) ))
2164 break;
2165 /* FIXME there should be a way to have auto deleted es, but there will be
2166 * a problem when another codec of the same type is created (mainly video) */
2167 msleep( 20*1000 );
2169 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2172 if( es->p_pgrm == p_sys->p_pgrm )
2173 EsOutESVarUpdate( out, es, true );
2175 EsDeleteInfo( out, es );
2177 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
2179 /* Update program */
2180 es->p_pgrm->i_es--;
2181 if( es->p_pgrm->i_es == 0 )
2182 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
2184 if( es->b_scrambled )
2185 EsOutProgramUpdateScrambled( out, es->p_pgrm );
2187 /* */
2188 if( p_esprops )
2190 if( p_esprops->p_main_es == es )
2192 b_reselect = true;
2193 p_esprops->p_main_es = NULL;
2195 p_esprops->i_count--;
2198 /* Re-select another track when needed */
2199 if( b_reselect )
2201 for( i = 0; i < p_sys->i_es; i++ )
2203 if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
2205 if( EsIsSelected(p_sys->es[i]) )
2207 input_SendEventEsSelect( p_sys->p_input, es->fmt.i_cat, p_sys->es[i]->i_id );
2208 if( p_esprops->p_main_es == NULL )
2209 p_esprops->p_main_es = p_sys->es[i];
2211 else
2212 EsOutSelect( out, p_sys->es[i], false );
2217 free( es->psz_language );
2218 free( es->psz_language_code );
2220 es_format_Clean( &es->fmt );
2222 vlc_mutex_unlock( &p_sys->lock );
2224 free( es );
2228 * Control query handler
2230 * \param out the es_out to control
2231 * \param i_query A es_out query as defined in include/ninput.h
2232 * \param args a variable list of arguments for the query
2233 * \return VLC_SUCCESS or an error code
2235 static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
2237 es_out_sys_t *p_sys = out->p_sys;
2239 switch( i_query )
2241 case ES_OUT_SET_ES_STATE:
2243 es_out_id_t *es = va_arg( args, es_out_id_t * );
2244 bool b = va_arg( args, int );
2245 if( b && !EsIsSelected( es ) )
2247 EsSelect( out, es );
2248 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
2250 else if( !b && EsIsSelected( es ) )
2252 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2253 return VLC_SUCCESS;
2255 return VLC_SUCCESS;
2258 case ES_OUT_GET_ES_STATE:
2260 es_out_id_t *es = va_arg( args, es_out_id_t * );
2261 bool *pb = va_arg( args, bool * );
2263 *pb = EsIsSelected( es );
2264 return VLC_SUCCESS;
2267 case ES_OUT_SET_ES_CAT_POLICY:
2269 enum es_format_category_e i_cat = va_arg( args, enum es_format_category_e );
2270 enum es_out_policy_e i_pol = va_arg( args, enum es_out_policy_e );
2271 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, i_cat );
2272 if( p_esprops == NULL )
2273 return VLC_EGENERIC;
2274 p_esprops->e_policy = i_pol;
2275 return VLC_SUCCESS;
2278 case ES_OUT_GET_GROUP_FORCED:
2280 int *pi_group = va_arg( args, int * );
2281 *pi_group = p_sys->i_group_id;
2282 return VLC_SUCCESS;
2285 case ES_OUT_SET_MODE:
2287 const int i_mode = va_arg( args, int );
2288 assert( i_mode == ES_OUT_MODE_NONE || i_mode == ES_OUT_MODE_ALL ||
2289 i_mode == ES_OUT_MODE_AUTO || i_mode == ES_OUT_MODE_PARTIAL ||
2290 i_mode == ES_OUT_MODE_END );
2292 if( i_mode != ES_OUT_MODE_NONE && !p_sys->b_active && p_sys->i_es > 0 )
2294 /* XXX Terminate vout if there are tracks but no video one.
2295 * This one is not mandatory but is he earliest place where it
2296 * can be done */
2297 int i;
2298 for( i = 0; i < p_sys->i_es; i++ )
2300 es_out_id_t *p_es = p_sys->es[i];
2301 if( p_es->fmt.i_cat == VIDEO_ES )
2302 break;
2304 if( i >= p_sys->i_es )
2305 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
2307 p_sys->b_active = i_mode != ES_OUT_MODE_NONE;
2308 p_sys->i_mode = i_mode;
2310 /* Reapply policy mode */
2311 for( int i = 0; i < p_sys->i_es; i++ )
2313 if( EsIsSelected( p_sys->es[i] ) )
2314 EsUnselect( out, p_sys->es[i],
2315 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
2317 for( int i = 0; i < p_sys->i_es; i++ )
2318 EsOutSelect( out, p_sys->es[i], false );
2319 if( i_mode == ES_OUT_MODE_END )
2320 EsOutTerminate( out );
2321 return VLC_SUCCESS;
2324 case ES_OUT_SET_ES:
2325 case ES_OUT_RESTART_ES:
2327 #define IGNORE_ES DATA_ES
2328 es_out_id_t *es = va_arg( args, es_out_id_t * );
2330 enum es_format_category_e i_cat;
2331 if( es == NULL )
2332 i_cat = UNKNOWN_ES;
2333 else if( es == es_cat + AUDIO_ES )
2334 i_cat = AUDIO_ES;
2335 else if( es == es_cat + VIDEO_ES )
2336 i_cat = VIDEO_ES;
2337 else if( es == es_cat + SPU_ES )
2338 i_cat = SPU_ES;
2339 else
2340 i_cat = IGNORE_ES;
2342 for( int i = 0; i < p_sys->i_es; i++ )
2344 if( i_cat == IGNORE_ES )
2346 if( es == p_sys->es[i] )
2348 if( i_query == ES_OUT_RESTART_ES && p_sys->es[i]->p_dec )
2350 EsDestroyDecoder( out, p_sys->es[i] );
2351 EsCreateDecoder( out, p_sys->es[i] );
2353 else if( i_query == ES_OUT_SET_ES )
2355 EsOutSelect( out, es, true );
2357 break;
2360 else
2362 if( i_cat == UNKNOWN_ES || p_sys->es[i]->fmt.i_cat == i_cat )
2364 if( EsIsSelected( p_sys->es[i] ) )
2366 if( i_query == ES_OUT_RESTART_ES )
2368 if( p_sys->es[i]->p_dec )
2370 EsDestroyDecoder( out, p_sys->es[i] );
2371 EsCreateDecoder( out, p_sys->es[i] );
2374 else
2376 EsUnselect( out, p_sys->es[i],
2377 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
2383 return VLC_SUCCESS;
2385 case ES_OUT_RESTART_ALL_ES:
2387 for( int i = 0; i < p_sys->i_es; i++ )
2389 EsDestroyDecoder( out, p_sys->es[i] );
2390 EsCreateDecoder( out, p_sys->es[i] );
2392 return VLC_SUCCESS;
2395 case ES_OUT_SET_ES_DEFAULT:
2397 es_out_id_t *es = va_arg( args, es_out_id_t * );
2399 if( es == NULL )
2401 /*p_sys->i_default_video_id = -1;*/
2402 /*p_sys->i_default_audio_id = -1;*/
2403 p_sys->sub.i_demux_id = -1;
2405 else if( es == es_cat + AUDIO_ES )
2407 /*p_sys->i_default_video_id = -1;*/
2409 else if( es == es_cat + VIDEO_ES )
2411 /*p_sys->i_default_audio_id = -1;*/
2413 else if( es == es_cat + SPU_ES )
2415 p_sys->sub.i_demux_id = -1;
2417 else
2419 /*if( es->fmt.i_cat == VIDEO_ES )
2420 p_sys->i_default_video_id = es->i_id;
2421 else
2422 if( es->fmt.i_cat == AUDIO_ES )
2423 p_sys->i_default_audio_id = es->i_id;
2424 else*/
2425 if( es->fmt.i_cat == SPU_ES )
2426 p_sys->sub.i_demux_id = es->i_id;
2428 return VLC_SUCCESS;
2431 case ES_OUT_SET_PCR:
2432 case ES_OUT_SET_GROUP_PCR:
2434 es_out_pgrm_t *p_pgrm = NULL;
2435 int i_group = 0;
2436 int64_t i_pcr;
2438 /* Search program */
2439 if( i_query == ES_OUT_SET_PCR )
2441 p_pgrm = p_sys->p_pgrm;
2442 if( !p_pgrm )
2443 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
2445 else
2447 i_group = va_arg( args, int );
2448 p_pgrm = EsOutProgramFind( out, i_group );
2450 if( !p_pgrm )
2451 return VLC_EGENERIC;
2453 i_pcr = va_arg( args, int64_t );
2454 if( i_pcr <= VLC_TS_INVALID )
2456 msg_Err( p_sys->p_input, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2457 return VLC_EGENERIC;
2460 /* TODO do not use mdate() but proper stream acquisition date */
2461 bool b_late;
2462 input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
2463 &b_late,
2464 input_priv(p_sys->p_input)->b_can_pace_control || p_sys->b_buffering,
2465 EsOutIsExtraBufferingAllowed( out ),
2466 i_pcr, mdate() );
2468 if( !p_sys->p_pgrm )
2469 return VLC_SUCCESS;
2471 if( p_sys->b_buffering )
2473 /* Check buffering state on master clock update */
2474 EsOutDecodersStopBuffering( out, false );
2476 else if( p_pgrm == p_sys->p_pgrm )
2478 if( b_late && ( !input_priv(p_sys->p_input)->p_sout ||
2479 !input_priv(p_sys->p_input)->b_out_pace_control ) )
2481 const mtime_t i_pts_delay_base = p_sys->i_pts_delay - p_sys->i_pts_jitter;
2482 mtime_t i_pts_delay = input_clock_GetJitter( p_pgrm->p_clock );
2484 /* Avoid dangerously high value */
2485 const mtime_t i_jitter_max = INT64_C(1000) * var_InheritInteger( p_sys->p_input, "clock-jitter" );
2486 if( i_pts_delay > __MIN( i_pts_delay_base + i_jitter_max, INPUT_PTS_DELAY_MAX ) )
2488 msg_Err( p_sys->p_input,
2489 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2490 (int)(i_pts_delay - i_pts_delay_base) / 1000 );
2491 i_pts_delay = p_sys->i_pts_delay;
2493 /* reset clock */
2494 for( int i = 0; i < p_sys->i_pgrm; i++ )
2495 input_clock_Reset( p_sys->pgrm[i]->p_clock );
2497 else
2499 msg_Err( p_sys->p_input,
2500 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2501 (int)(i_pts_delay/1000) );
2503 /* Force a rebufferization when we are too late */
2505 /* It is not really good, as we throw away already buffered data
2506 * TODO have a mean to correctly reenter bufferization */
2507 es_out_Control( out, ES_OUT_RESET_PCR );
2510 es_out_SetJitter( out, i_pts_delay_base, i_pts_delay - i_pts_delay_base, p_sys->i_cr_average );
2513 return VLC_SUCCESS;
2516 case ES_OUT_RESET_PCR:
2517 msg_Dbg( p_sys->p_input, "ES_OUT_RESET_PCR called" );
2518 EsOutChangePosition( out );
2519 return VLC_SUCCESS;
2521 case ES_OUT_SET_GROUP:
2523 int i = va_arg( args, int );
2524 for( int j = 0; j < p_sys->i_pgrm; j++ )
2526 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
2527 if( p_pgrm->i_id == i )
2529 EsOutProgramSelect( out, p_pgrm );
2530 return VLC_SUCCESS;
2533 return VLC_EGENERIC;
2536 case ES_OUT_SET_ES_FMT:
2538 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2539 * to update the p_extra data */
2540 es_out_id_t *es = va_arg( args, es_out_id_t * );
2541 es_format_t *p_fmt = va_arg( args, es_format_t * );
2542 if( es == NULL )
2543 return VLC_EGENERIC;
2545 es_format_Clean( &es->fmt );
2546 es_format_Copy( &es->fmt, p_fmt );
2548 if( es->p_dec )
2550 EsDestroyDecoder( out, es );
2551 EsCreateDecoder( out, es );
2554 return VLC_SUCCESS;
2557 case ES_OUT_SET_ES_SCRAMBLED_STATE:
2559 es_out_id_t *es = va_arg( args, es_out_id_t * );
2560 bool b_scrambled = (bool)va_arg( args, int );
2562 if( !es->b_scrambled != !b_scrambled )
2564 es->b_scrambled = b_scrambled;
2565 EsOutProgramUpdateScrambled( out, es->p_pgrm );
2567 return VLC_SUCCESS;
2570 case ES_OUT_SET_NEXT_DISPLAY_TIME:
2572 const int64_t i_date = va_arg( args, int64_t );
2574 if( i_date < 0 )
2575 return VLC_EGENERIC;
2577 p_sys->i_preroll_end = i_date;
2579 return VLC_SUCCESS;
2581 case ES_OUT_SET_GROUP_META:
2583 int i_group = va_arg( args, int );
2584 const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
2586 EsOutProgramMeta( out, i_group, p_meta );
2587 return VLC_SUCCESS;
2589 case ES_OUT_SET_GROUP_EPG:
2591 int i_group = va_arg( args, int );
2592 const vlc_epg_t *p_epg = va_arg( args, const vlc_epg_t * );
2594 EsOutProgramEpg( out, i_group, p_epg );
2595 return VLC_SUCCESS;
2597 case ES_OUT_SET_GROUP_EPG_EVENT:
2599 int i_group = va_arg( args, int );
2600 const vlc_epg_event_t *p_evt = va_arg( args, const vlc_epg_event_t * );
2602 EsOutProgramEpgEvent( out, i_group, p_evt );
2603 return VLC_SUCCESS;
2605 case ES_OUT_SET_EPG_TIME:
2607 int64_t i64 = va_arg( args, int64_t );
2609 EsOutEpgTime( out, i64 );
2610 return VLC_SUCCESS;
2613 case ES_OUT_DEL_GROUP:
2615 int i_group = va_arg( args, int );
2617 return EsOutProgramDel( out, i_group );
2620 case ES_OUT_SET_META:
2622 const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
2624 EsOutGlobalMeta( out, p_meta );
2625 return VLC_SUCCESS;
2628 case ES_OUT_GET_WAKE_UP:
2630 mtime_t *pi_wakeup = va_arg( args, mtime_t* );
2631 *pi_wakeup = EsOutGetWakeup( out );
2632 return VLC_SUCCESS;
2635 case ES_OUT_SET_ES_BY_ID:
2636 case ES_OUT_RESTART_ES_BY_ID:
2637 case ES_OUT_SET_ES_DEFAULT_BY_ID:
2639 const int i_id = va_arg( args, int );
2640 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2641 int i_new_query = 0;
2643 switch( i_query )
2645 case ES_OUT_SET_ES_BY_ID: i_new_query = ES_OUT_SET_ES; break;
2646 case ES_OUT_RESTART_ES_BY_ID: i_new_query = ES_OUT_RESTART_ES; break;
2647 case ES_OUT_SET_ES_DEFAULT_BY_ID: i_new_query = ES_OUT_SET_ES_DEFAULT; break;
2648 default:
2649 vlc_assert_unreachable();
2651 /* TODO if the lock is made non recursive it should be changed */
2652 int i_ret = es_out_Control( out, i_new_query, p_es );
2654 /* Clean up vout after user action (in active mode only).
2655 * FIXME it does not work well with multiple video windows */
2656 if( p_sys->b_active )
2657 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
2658 return i_ret;
2661 case ES_OUT_GET_ES_OBJECTS_BY_ID:
2663 const int i_id = va_arg( args, int );
2664 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2665 if( !p_es )
2666 return VLC_EGENERIC;
2668 vlc_object_t **pp_decoder = va_arg( args, vlc_object_t ** );
2669 vout_thread_t **pp_vout = va_arg( args, vout_thread_t ** );
2670 audio_output_t **pp_aout = va_arg( args, audio_output_t ** );
2671 if( p_es->p_dec )
2673 if( pp_decoder )
2674 *pp_decoder = vlc_object_hold( p_es->p_dec );
2675 input_DecoderGetObjects( p_es->p_dec, pp_vout, pp_aout );
2677 else
2679 if( pp_decoder )
2680 *pp_decoder = NULL;
2681 if( pp_vout )
2682 *pp_vout = NULL;
2683 if( pp_aout )
2684 *pp_aout = NULL;
2686 return VLC_SUCCESS;
2689 case ES_OUT_GET_BUFFERING:
2691 bool *pb = va_arg( args, bool* );
2692 *pb = p_sys->b_buffering;
2693 return VLC_SUCCESS;
2696 case ES_OUT_GET_EMPTY:
2698 bool *pb = va_arg( args, bool* );
2699 *pb = EsOutDecodersIsEmpty( out );
2700 return VLC_SUCCESS;
2703 case ES_OUT_SET_DELAY:
2705 const int i_cat = va_arg( args, int );
2706 const mtime_t i_delay = va_arg( args, mtime_t );
2707 EsOutSetDelay( out, i_cat, i_delay );
2708 return VLC_SUCCESS;
2711 case ES_OUT_SET_RECORD_STATE:
2713 bool b = va_arg( args, int );
2714 return EsOutSetRecord( out, b );
2717 case ES_OUT_SET_PAUSE_STATE:
2719 const bool b_source_paused = (bool)va_arg( args, int );
2720 const bool b_paused = (bool)va_arg( args, int );
2721 const mtime_t i_date = va_arg( args, mtime_t );
2723 assert( !b_source_paused == !b_paused );
2724 EsOutChangePause( out, b_paused, i_date );
2726 return VLC_SUCCESS;
2729 case ES_OUT_SET_RATE:
2731 const int i_src_rate = va_arg( args, int );
2732 const int i_rate = va_arg( args, int );
2734 assert( i_src_rate == i_rate );
2735 EsOutChangeRate( out, i_rate );
2737 return VLC_SUCCESS;
2740 case ES_OUT_SET_TIME:
2742 const mtime_t i_date = va_arg( args, mtime_t );
2744 assert( i_date == -1 );
2745 EsOutChangePosition( out );
2747 return VLC_SUCCESS;
2750 case ES_OUT_SET_FRAME_NEXT:
2751 EsOutFrameNext( out );
2752 return VLC_SUCCESS;
2754 case ES_OUT_SET_TIMES:
2756 double f_position = va_arg( args, double );
2757 mtime_t i_time = va_arg( args, mtime_t );
2758 mtime_t i_length = va_arg( args, mtime_t );
2760 input_SendEventLength( p_sys->p_input, i_length );
2762 if( !p_sys->b_buffering )
2764 mtime_t i_delay;
2766 /* Fix for buffering delay */
2767 if( !input_priv(p_sys->p_input)->p_sout ||
2768 !input_priv(p_sys->p_input)->b_out_pace_control )
2769 i_delay = EsOutGetBuffering( out );
2770 else
2771 i_delay = 0;
2773 i_time -= i_delay;
2774 if( i_time < 0 )
2775 i_time = 0;
2777 if( i_length > 0 )
2778 f_position -= (double)i_delay / i_length;
2779 if( f_position < 0 )
2780 f_position = 0;
2782 input_SendEventPosition( p_sys->p_input, f_position, i_time );
2784 return VLC_SUCCESS;
2786 case ES_OUT_SET_JITTER:
2788 mtime_t i_pts_delay = va_arg( args, mtime_t );
2789 mtime_t i_pts_jitter = va_arg( args, mtime_t );
2790 int i_cr_average = va_arg( args, int );
2792 bool b_change_clock =
2793 i_pts_delay + i_pts_jitter != p_sys->i_pts_delay ||
2794 i_cr_average != p_sys->i_cr_average;
2796 assert( i_pts_jitter >= 0 );
2797 p_sys->i_pts_delay = i_pts_delay + i_pts_jitter;
2798 p_sys->i_pts_jitter = i_pts_jitter;
2799 p_sys->i_cr_average = i_cr_average;
2801 for( int i = 0; i < p_sys->i_pgrm && b_change_clock; i++ )
2802 input_clock_SetJitter( p_sys->pgrm[i]->p_clock,
2803 i_pts_delay + i_pts_jitter, i_cr_average );
2804 return VLC_SUCCESS;
2807 case ES_OUT_GET_PCR_SYSTEM:
2809 if( p_sys->b_buffering )
2810 return VLC_EGENERIC;
2812 es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
2813 if( !p_pgrm )
2814 return VLC_EGENERIC;
2816 mtime_t *pi_system = va_arg( args, mtime_t *);
2817 mtime_t *pi_delay = va_arg( args, mtime_t *);
2818 input_clock_GetSystemOrigin( p_pgrm->p_clock, pi_system, pi_delay );
2819 return VLC_SUCCESS;
2822 case ES_OUT_MODIFY_PCR_SYSTEM:
2824 if( p_sys->b_buffering )
2825 return VLC_EGENERIC;
2827 es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
2828 if( !p_pgrm )
2829 return VLC_EGENERIC;
2831 const bool b_absolute = va_arg( args, int );
2832 const mtime_t i_system = va_arg( args, mtime_t );
2833 input_clock_ChangeSystemOrigin( p_pgrm->p_clock, b_absolute, i_system );
2834 return VLC_SUCCESS;
2836 case ES_OUT_SET_EOS:
2838 for (int i = 0; i < p_sys->i_es; i++) {
2839 es_out_id_t *id = p_sys->es[i];
2840 if (id->p_dec != NULL)
2841 input_DecoderDrain(id->p_dec);
2843 return VLC_SUCCESS;
2846 case ES_OUT_POST_SUBNODE:
2848 input_item_node_t *node = va_arg(args, input_item_node_t *);
2849 input_item_node_PostAndDelete(node);
2850 return VLC_SUCCESS;
2853 default:
2854 msg_Err( p_sys->p_input, "unknown query 0x%x in %s", i_query,
2855 __func__ );
2856 return VLC_EGENERIC;
2859 static int EsOutControl( es_out_t *out, int i_query, va_list args )
2861 es_out_sys_t *p_sys = out->p_sys;
2862 int i_ret;
2864 vlc_mutex_lock( &p_sys->lock );
2865 i_ret = EsOutControlLocked( out, i_query, args );
2866 vlc_mutex_unlock( &p_sys->lock );
2868 return i_ret;
2871 /****************************************************************************
2872 * LanguageGetName: try to expend iso639 into plain name
2873 ****************************************************************************/
2874 static char *LanguageGetName( const char *psz_code )
2876 const iso639_lang_t *pl;
2878 if( psz_code == NULL || !strcmp( psz_code, "und" ) )
2880 return strdup( "" );
2883 if( strlen( psz_code ) == 2 )
2885 pl = GetLang_1( psz_code );
2887 else if( strlen( psz_code ) == 3 )
2889 pl = GetLang_2B( psz_code );
2890 if( !strcmp( pl->psz_iso639_1, "??" ) )
2892 pl = GetLang_2T( psz_code );
2895 else
2897 char *lang = LanguageGetCode( psz_code );
2898 pl = GetLang_1( lang );
2899 free( lang );
2902 if( !strcmp( pl->psz_iso639_1, "??" ) )
2904 return strdup( psz_code );
2906 else
2908 return strdup( vlc_gettext(pl->psz_eng_name) );
2912 /* Get a 2 char code */
2913 static char *LanguageGetCode( const char *psz_lang )
2915 const iso639_lang_t *pl;
2917 if( psz_lang == NULL || *psz_lang == '\0' )
2918 return strdup("??");
2920 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
2922 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
2923 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
2924 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
2925 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
2926 return strdup( pl->psz_iso639_1 );
2929 return strdup("??");
2932 static char **LanguageSplit( const char *psz_langs )
2934 char *psz_dup;
2935 char *psz_parser;
2936 char **ppsz = NULL;
2937 int i_psz = 0;
2939 if( psz_langs == NULL ) return NULL;
2941 psz_parser = psz_dup = strdup(psz_langs);
2943 while( psz_parser && *psz_parser )
2945 char *psz;
2946 char *psz_code;
2948 psz = strchr(psz_parser, ',' );
2949 if( psz ) *psz++ = '\0';
2951 if( !strcmp( psz_parser, "any" ) )
2953 TAB_APPEND( i_psz, ppsz, strdup("any") );
2955 else if( !strcmp( psz_parser, "none" ) )
2957 TAB_APPEND( i_psz, ppsz, strdup("none") );
2959 else
2961 psz_code = LanguageGetCode( psz_parser );
2962 if( strcmp( psz_code, "??" ) )
2964 TAB_APPEND( i_psz, ppsz, psz_code );
2966 else
2968 free( psz_code );
2972 psz_parser = psz;
2975 if( i_psz )
2977 TAB_APPEND( i_psz, ppsz, NULL );
2980 free( psz_dup );
2981 return ppsz;
2984 static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang )
2986 if( !ppsz_langs || !psz_lang )
2987 return -1;
2989 for( int i = 0; ppsz_langs[i]; i++ )
2991 if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2992 ( !strcasecmp( ppsz_langs[i], "any" ) && strcasecmp( psz_lang, "none") ) )
2993 return i;
2994 if( !strcasecmp( ppsz_langs[i], "none" ) )
2995 break;
2998 return -1;
3001 /****************************************************************************
3002 * EsOutUpdateInfo:
3003 * - add meta info to the playlist item
3004 ****************************************************************************/
3005 static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt, const vlc_meta_t *p_meta )
3007 es_out_sys_t *p_sys = out->p_sys;
3008 input_thread_t *p_input = p_sys->p_input;
3009 const es_format_t *p_fmt_es = &es->fmt;
3010 lldiv_t div;
3012 if( es->fmt.i_cat == fmt->i_cat )
3014 es_format_t update = *fmt;
3015 update.i_id = es->i_meta_id;
3016 update.i_codec = es->fmt.i_codec;
3017 update.i_original_fourcc = es->fmt.i_original_fourcc;
3019 /* Update infos that could have been lost by the decoder (no need to
3020 * dup them since input_item_UpdateTracksInfo() will do it). */
3021 if (update.psz_language == NULL)
3022 update.psz_language = es->fmt.psz_language;
3023 if (update.psz_description == NULL)
3024 update.psz_description = es->fmt.psz_description;
3025 if (update.i_cat == SPU_ES)
3027 if (update.subs.psz_encoding == NULL)
3028 update.subs.psz_encoding = es->fmt.subs.psz_encoding;
3029 if (update.subs.p_style == NULL)
3030 update.subs.p_style = es->fmt.subs.p_style;
3032 if (update.i_extra_languages == 0)
3034 assert(update.p_extra_languages == NULL);
3035 update.i_extra_languages = es->fmt.i_extra_languages;
3036 update.p_extra_languages = es->fmt.p_extra_languages;
3039 /* No need to update codec specific data */
3040 update.i_extra = 0;
3041 update.p_extra = NULL;
3043 input_item_UpdateTracksInfo(input_GetItem(p_input), &update);
3046 /* Create category */
3047 char* psz_cat = EsInfoCategoryName( es );
3049 if( unlikely( !psz_cat ) )
3050 return;
3052 info_category_t* p_cat = info_category_New( psz_cat );
3054 free( psz_cat );
3056 if( unlikely( !p_cat ) )
3057 return;
3059 /* Add information */
3060 if( es->i_meta_id != es->i_id )
3061 info_category_AddInfo( p_cat, _("Original ID"),
3062 "%d", es->i_id );
3064 const vlc_fourcc_t i_codec_fourcc = ( p_fmt_es->i_original_fourcc )?
3065 p_fmt_es->i_original_fourcc : p_fmt_es->i_codec;
3066 const char *psz_codec_description =
3067 vlc_fourcc_GetDescription( p_fmt_es->i_cat, i_codec_fourcc );
3068 if( psz_codec_description && *psz_codec_description )
3069 info_category_AddInfo( p_cat, _("Codec"), "%s (%.4s)",
3070 psz_codec_description, (char*)&i_codec_fourcc );
3071 else if ( i_codec_fourcc != VLC_FOURCC(0,0,0,0) )
3072 info_category_AddInfo( p_cat, _("Codec"), "%.4s",
3073 (char*)&i_codec_fourcc );
3075 if( es->psz_language && *es->psz_language )
3076 info_category_AddInfo( p_cat, _("Language"), "%s",
3077 es->psz_language );
3078 if( fmt->psz_description && *fmt->psz_description )
3079 info_category_AddInfo( p_cat, _("Description"), "%s",
3080 fmt->psz_description );
3082 switch( fmt->i_cat )
3084 case AUDIO_ES:
3085 info_category_AddInfo( p_cat, _("Type"), _("Audio") );
3087 if( fmt->audio.i_physical_channels )
3088 info_category_AddInfo( p_cat, _("Channels"), "%s",
3089 _( aout_FormatPrintChannels( &fmt->audio ) ) );
3091 if( fmt->audio.i_rate != 0 )
3093 info_category_AddInfo( p_cat, _("Sample rate"), _("%u Hz"),
3094 fmt->audio.i_rate );
3095 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3096 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
3099 unsigned int i_bitspersample = fmt->audio.i_bitspersample;
3100 if( i_bitspersample == 0 )
3101 i_bitspersample = aout_BitsPerSample( p_fmt_es->i_codec );
3102 if( i_bitspersample != 0 )
3103 info_category_AddInfo( p_cat, _("Bits per sample"), "%u",
3104 i_bitspersample );
3106 if( fmt->i_bitrate != 0 )
3108 info_category_AddInfo( p_cat, _("Bitrate"), _("%u kb/s"),
3109 fmt->i_bitrate / 1000 );
3110 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3111 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
3113 for( int i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
3115 const audio_replay_gain_t *p_rg = &fmt->audio_replay_gain;
3116 if( !p_rg->pb_gain[i] )
3117 continue;
3118 const char *psz_name;
3119 if( i == AUDIO_REPLAY_GAIN_TRACK )
3120 psz_name = _("Track replay gain");
3121 else
3122 psz_name = _("Album replay gain");
3123 info_category_AddInfo( p_cat, psz_name, _("%.2f dB"),
3124 p_rg->pf_gain[i] );
3126 break;
3128 case VIDEO_ES:
3129 info_category_AddInfo( p_cat, _("Type"), _("Video") );
3131 if( fmt->video.i_visible_width > 0 &&
3132 fmt->video.i_visible_height > 0 )
3133 info_category_AddInfo( p_cat, _("Video resolution"), "%ux%u",
3134 fmt->video.i_visible_width,
3135 fmt->video.i_visible_height);
3137 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
3138 info_category_AddInfo( p_cat, _("Buffer dimensions"), "%ux%u",
3139 fmt->video.i_width, fmt->video.i_height );
3141 if( fmt->video.i_frame_rate > 0 &&
3142 fmt->video.i_frame_rate_base > 0 )
3144 div = lldiv( (float)fmt->video.i_frame_rate /
3145 fmt->video.i_frame_rate_base * 1000000,
3146 1000000 );
3147 if( div.rem > 0 )
3148 info_category_AddInfo( p_cat, _("Frame rate"), "%"PRId64".%06u",
3149 div.quot, (unsigned int )div.rem );
3150 else
3151 info_category_AddInfo( p_cat, _("Frame rate"), "%"PRId64,
3152 div.quot );
3154 if( fmt->i_codec != p_fmt_es->i_codec )
3156 const char *psz_chroma_description =
3157 vlc_fourcc_GetDescription( VIDEO_ES, fmt->i_codec );
3158 if( psz_chroma_description )
3159 info_category_AddInfo( p_cat, _("Decoded format"), "%s",
3160 psz_chroma_description );
3163 static const char orient_names[][13] = {
3164 N_("Top left"), N_("Left top"),
3165 N_("Right bottom"), N_("Top right"),
3166 N_("Bottom left"), N_("Bottom right"),
3167 N_("Left bottom"), N_("Right top"),
3169 info_category_AddInfo( p_cat, _("Orientation"), "%s",
3170 _(orient_names[fmt->video.orientation]) );
3172 if( fmt->video.primaries != COLOR_PRIMARIES_UNDEF )
3174 static const char primaries_names[][32] = {
3175 [COLOR_PRIMARIES_UNDEF] = N_("Undefined"),
3176 [COLOR_PRIMARIES_BT601_525] =
3177 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3178 [COLOR_PRIMARIES_BT601_625] =
3179 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3180 [COLOR_PRIMARIES_BT709] = "ITU-R BT.709",
3181 [COLOR_PRIMARIES_BT2020] = "ITU-R BT.2020",
3182 [COLOR_PRIMARIES_DCI_P3] = "DCI/P3 D65",
3183 [COLOR_PRIMARIES_BT470_M] = "ITU-R BT.470 M",
3185 static_assert(ARRAY_SIZE(primaries_names) == COLOR_PRIMARIES_MAX+1,
3186 "Color primiaries table mismatch");
3187 info_category_AddInfo( p_cat, _("Color primaries"), "%s",
3188 _(primaries_names[fmt->video.primaries]) );
3190 if( fmt->video.transfer != TRANSFER_FUNC_UNDEF )
3192 static const char func_names[][20] = {
3193 [TRANSFER_FUNC_UNDEF] = N_("Undefined"),
3194 [TRANSFER_FUNC_LINEAR] = N_("Linear"),
3195 [TRANSFER_FUNC_SRGB] = "sRGB",
3196 [TRANSFER_FUNC_BT470_BG] = "ITU-R BT.470 BG",
3197 [TRANSFER_FUNC_BT470_M] = "ITU-R BT.470 M",
3198 [TRANSFER_FUNC_BT709] = "ITU-R BT.709",
3199 [TRANSFER_FUNC_SMPTE_ST2084] = "SMPTE ST2084",
3200 [TRANSFER_FUNC_SMPTE_240] = "SMPTE 240M",
3201 [TRANSFER_FUNC_HLG] = N_("Hybrid Log-Gamma"),
3203 static_assert(ARRAY_SIZE(func_names) == TRANSFER_FUNC_MAX+1,
3204 "Transfer functions table mismatch");
3205 info_category_AddInfo( p_cat, _("Color transfer function"), "%s",
3206 _(func_names[fmt->video.transfer]) );
3208 if( fmt->video.space != COLOR_SPACE_UNDEF )
3210 static const char space_names[][16] = {
3211 [COLOR_SPACE_UNDEF] = N_("Undefined"),
3212 [COLOR_SPACE_BT601] = "ITU-R BT.601",
3213 [COLOR_SPACE_BT709] = "ITU-R BT.709",
3214 [COLOR_SPACE_BT2020] = "ITU-R BT.2020",
3216 static_assert(ARRAY_SIZE(space_names) == COLOR_SPACE_MAX+1,
3217 "Color space table mismatch");
3218 info_category_AddInfo( p_cat, _("Color space"), _("%s Range"),
3219 _(space_names[fmt->video.space]),
3220 _(fmt->video.b_color_range_full ? "Full" : "Limited") );
3222 if( fmt->video.chroma_location != CHROMA_LOCATION_UNDEF )
3224 static const char c_loc_names[][16] = {
3225 [CHROMA_LOCATION_UNDEF] = N_("Undefined"),
3226 [CHROMA_LOCATION_LEFT] = N_("Left"),
3227 [CHROMA_LOCATION_CENTER] = N_("Center"),
3228 [CHROMA_LOCATION_TOP_LEFT] = N_("Top Left"),
3229 [CHROMA_LOCATION_TOP_CENTER] = N_("Top Center"),
3230 [CHROMA_LOCATION_BOTTOM_LEFT] =N_("Bottom Left"),
3231 [CHROMA_LOCATION_BOTTOM_CENTER] = N_("Bottom Center"),
3233 static_assert(ARRAY_SIZE(c_loc_names) == CHROMA_LOCATION_MAX+1,
3234 "Chroma location table mismatch");
3235 info_category_AddInfo( p_cat, _("Chroma location"), "%s",
3236 _(c_loc_names[fmt->video.chroma_location]) );
3238 if( fmt->video.projection_mode != PROJECTION_MODE_RECTANGULAR )
3240 const char *psz_loc_name = NULL;
3241 switch (fmt->video.projection_mode)
3243 case PROJECTION_MODE_RECTANGULAR:
3244 psz_loc_name = N_("Rectangular");
3245 break;
3246 case PROJECTION_MODE_EQUIRECTANGULAR:
3247 psz_loc_name = N_("Equirectangular");
3248 break;
3249 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:
3250 psz_loc_name = N_("Cubemap");
3251 break;
3252 default:
3253 vlc_assert_unreachable();
3254 break;
3256 info_category_AddInfo( p_cat, _("Projection"), "%s", _(psz_loc_name) );
3258 info_category_AddInfo( p_cat, _("Yaw"), "%.2f",
3259 fmt->video.pose.yaw );
3260 info_category_AddInfo( p_cat, _("Pitch"), "%.2f",
3261 fmt->video.pose.pitch );
3262 info_category_AddInfo( p_cat, _("Roll"), "%.2f",
3263 fmt->video.pose.roll );
3264 info_category_AddInfo( p_cat, _("Field of view"), "%.2f",
3265 fmt->video.pose.fov );
3267 if ( fmt->video.mastering.max_luminance )
3269 info_category_AddInfo( p_cat, _("Max. luminance"), "%.4f cd/m²",
3270 fmt->video.mastering.max_luminance / 10000.f );
3272 if ( fmt->video.mastering.min_luminance )
3274 info_category_AddInfo( p_cat, _("Min. luminance"), "%.4f cd/m²",
3275 fmt->video.mastering.min_luminance / 10000.f );
3277 if ( fmt->video.mastering.primaries[4] &&
3278 fmt->video.mastering.primaries[5] )
3280 float x = (float)fmt->video.mastering.primaries[4] / 50000.f;
3281 float y = (float)fmt->video.mastering.primaries[5] / 50000.f;
3282 info_category_AddInfo( p_cat, _("Primary R"), "x=%.4f y=%.4f", x, y );
3284 if ( fmt->video.mastering.primaries[0] &&
3285 fmt->video.mastering.primaries[1] )
3287 float x = (float)fmt->video.mastering.primaries[0] / 50000.f;
3288 float y = (float)fmt->video.mastering.primaries[1] / 50000.f;
3289 info_category_AddInfo( p_cat, _("Primary G"), "x=%.4f y=%.4f", x, y );
3291 if ( fmt->video.mastering.primaries[2] &&
3292 fmt->video.mastering.primaries[3] )
3294 float x = (float)fmt->video.mastering.primaries[2] / 50000.f;
3295 float y = (float)fmt->video.mastering.primaries[3] / 50000.f;
3296 info_category_AddInfo( p_cat, _("Primary B"), "x=%.4f y=%.4f", x, y );
3298 if ( fmt->video.mastering.white_point[0] &&
3299 fmt->video.mastering.white_point[1] )
3301 float x = (float)fmt->video.mastering.white_point[0] / 50000.f;
3302 float y = (float)fmt->video.mastering.white_point[1] / 50000.f;
3303 info_category_AddInfo( p_cat, _("White point"), "x=%.4f y=%.4f", x, y );
3305 if ( fmt->video.lighting.MaxCLL )
3307 info_category_AddInfo( p_cat, "MaxCLL", "%d cd/m²",
3308 fmt->video.lighting.MaxCLL );
3310 if ( fmt->video.lighting.MaxFALL )
3312 info_category_AddInfo( p_cat, "MaxFALL", "%d cd/m²",
3313 fmt->video.lighting.MaxFALL );
3315 break;
3317 case SPU_ES:
3318 info_category_AddInfo( p_cat, _("Type"), _("Subtitle") );
3319 break;
3321 default:
3322 break;
3325 /* Append generic meta */
3326 if( p_meta )
3328 char **ppsz_all_keys = vlc_meta_CopyExtraNames( p_meta );
3329 for( int i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
3331 char *psz_key = ppsz_all_keys[i];
3332 const char *psz_value = vlc_meta_GetExtra( p_meta, psz_key );
3334 if( psz_value )
3335 info_category_AddInfo( p_cat, vlc_gettext(psz_key), "%s",
3336 vlc_gettext(psz_value) );
3337 free( psz_key );
3339 free( ppsz_all_keys );
3341 /* */
3342 input_Control( p_input, INPUT_REPLACE_INFOS, p_cat );
3345 static void EsDeleteInfo( es_out_t *out, es_out_id_t *es )
3347 char* psz_info_category;
3349 if( likely( psz_info_category = EsInfoCategoryName( es ) ) )
3351 input_Control( out->p_sys->p_input, INPUT_DEL_INFO,
3352 psz_info_category, NULL );
3354 free( psz_info_category );