Strings simplification for translations
[vlc.git] / src / input / es_out.c
blobe0e34676a44e11297edba645402684c510fefce4
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 if( libvlc_stats( p_input ) )
2044 uint64_t i_total;
2046 vlc_mutex_lock( &input_priv(p_input)->counters.counters_lock );
2047 stats_Update( input_priv(p_input)->counters.p_demux_read,
2048 p_block->i_buffer, &i_total );
2049 stats_Update( input_priv(p_input)->counters.p_demux_bitrate, i_total, NULL );
2051 /* Update number of corrupted data packats */
2052 if( p_block->i_flags & BLOCK_FLAG_CORRUPTED )
2054 stats_Update( input_priv(p_input)->counters.p_demux_corrupted, 1, NULL );
2056 /* Update number of discontinuities */
2057 if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY )
2059 stats_Update( input_priv(p_input)->counters.p_demux_discontinuity, 1, NULL );
2061 vlc_mutex_unlock( &input_priv(p_input)->counters.counters_lock );
2064 vlc_mutex_lock( &p_sys->lock );
2066 /* Mark preroll blocks */
2067 if( p_sys->i_preroll_end >= 0 )
2069 int64_t i_date = p_block->i_pts;
2070 if( p_block->i_pts <= VLC_TS_INVALID )
2071 i_date = p_block->i_dts;
2073 if( i_date + p_block->i_length < p_sys->i_preroll_end )
2074 p_block->i_flags |= BLOCK_FLAG_PREROLL;
2077 if( !es->p_dec )
2079 block_Release( p_block );
2080 vlc_mutex_unlock( &p_sys->lock );
2081 return VLC_SUCCESS;
2084 /* Check for sout mode */
2085 if( input_priv(p_input)->p_sout )
2087 /* FIXME review this, proper lock may be missing */
2088 if( input_priv(p_input)->p_sout->i_out_pace_nocontrol > 0 &&
2089 input_priv(p_input)->b_out_pace_control )
2091 msg_Dbg( p_input, "switching to sync mode" );
2092 input_priv(p_input)->b_out_pace_control = false;
2094 else if( input_priv(p_input)->p_sout->i_out_pace_nocontrol <= 0 &&
2095 !input_priv(p_input)->b_out_pace_control )
2097 msg_Dbg( p_input, "switching to async mode" );
2098 input_priv(p_input)->b_out_pace_control = true;
2102 /* Decode */
2103 if( es->p_dec_record )
2105 block_t *p_dup = block_Duplicate( p_block );
2106 if( p_dup )
2107 input_DecoderDecode( es->p_dec_record, p_dup,
2108 input_priv(p_input)->b_out_pace_control );
2110 input_DecoderDecode( es->p_dec, p_block,
2111 input_priv(p_input)->b_out_pace_control );
2113 es_format_t fmt_dsc;
2114 vlc_meta_t *p_meta_dsc;
2115 if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
2117 EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );
2119 es_format_Clean( &fmt_dsc );
2120 if( p_meta_dsc )
2121 vlc_meta_Delete( p_meta_dsc );
2124 /* Check CC status */
2125 decoder_cc_desc_t desc;
2127 input_DecoderGetCcDesc( es->p_dec, &desc );
2128 if( var_InheritInteger( p_input, "captions" ) == 708 )
2129 EsOutCreateCCChannels( out, VLC_CODEC_CEA708, desc.i_708_channels,
2130 _("DTVCC Closed captions %u"), es );
2131 EsOutCreateCCChannels( out, VLC_CODEC_CEA608, desc.i_608_channels,
2132 _("Closed captions %u"), es );
2134 vlc_mutex_unlock( &p_sys->lock );
2136 return VLC_SUCCESS;
2139 /*****************************************************************************
2140 * EsOutDel:
2141 *****************************************************************************/
2142 static void EsOutDel( es_out_t *out, es_out_id_t *es )
2144 es_out_sys_t *p_sys = out->p_sys;
2145 bool b_reselect = false;
2146 int i;
2148 vlc_mutex_lock( &p_sys->lock );
2150 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, es->fmt.i_cat );
2152 /* We don't try to reselect */
2153 if( es->p_dec )
2154 { /* FIXME: This might hold the ES output caller (i.e. the demux), and
2155 * the corresponding thread (typically the input thread), for a little
2156 * bit too long if the ES is deleted in the middle of a stream. */
2157 input_DecoderDrain( es->p_dec );
2158 while( !input_Stopped(p_sys->p_input) && !p_sys->b_buffering )
2160 if( input_DecoderIsEmpty( es->p_dec ) &&
2161 ( !es->p_dec_record || input_DecoderIsEmpty( es->p_dec_record ) ))
2162 break;
2163 /* FIXME there should be a way to have auto deleted es, but there will be
2164 * a problem when another codec of the same type is created (mainly video) */
2165 msleep( 20*1000 );
2167 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2170 if( es->p_pgrm == p_sys->p_pgrm )
2171 EsOutESVarUpdate( out, es, true );
2173 EsDeleteInfo( out, es );
2175 TAB_REMOVE( p_sys->i_es, p_sys->es, es );
2177 /* Update program */
2178 es->p_pgrm->i_es--;
2179 if( es->p_pgrm->i_es == 0 )
2180 msg_Dbg( p_sys->p_input, "Program doesn't contain anymore ES" );
2182 if( es->b_scrambled )
2183 EsOutProgramUpdateScrambled( out, es->p_pgrm );
2185 /* */
2186 if( p_esprops )
2188 if( p_esprops->p_main_es == es )
2190 b_reselect = true;
2191 p_esprops->p_main_es = NULL;
2193 p_esprops->i_count--;
2196 /* Re-select another track when needed */
2197 if( b_reselect )
2199 for( i = 0; i < p_sys->i_es; i++ )
2201 if( es->fmt.i_cat == p_sys->es[i]->fmt.i_cat )
2203 if( EsIsSelected(p_sys->es[i]) )
2205 input_SendEventEsSelect( p_sys->p_input, es->fmt.i_cat, p_sys->es[i]->i_id );
2206 if( p_esprops->p_main_es == NULL )
2207 p_esprops->p_main_es = p_sys->es[i];
2209 else
2210 EsOutSelect( out, p_sys->es[i], false );
2215 free( es->psz_language );
2216 free( es->psz_language_code );
2218 es_format_Clean( &es->fmt );
2220 vlc_mutex_unlock( &p_sys->lock );
2222 free( es );
2226 * Control query handler
2228 * \param out the es_out to control
2229 * \param i_query A es_out query as defined in include/ninput.h
2230 * \param args a variable list of arguments for the query
2231 * \return VLC_SUCCESS or an error code
2233 static int EsOutControlLocked( es_out_t *out, int i_query, va_list args )
2235 es_out_sys_t *p_sys = out->p_sys;
2237 switch( i_query )
2239 case ES_OUT_SET_ES_STATE:
2241 es_out_id_t *es = va_arg( args, es_out_id_t * );
2242 bool b = va_arg( args, int );
2243 if( b && !EsIsSelected( es ) )
2245 EsSelect( out, es );
2246 return EsIsSelected( es ) ? VLC_SUCCESS : VLC_EGENERIC;
2248 else if( !b && EsIsSelected( es ) )
2250 EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
2251 return VLC_SUCCESS;
2253 return VLC_SUCCESS;
2256 case ES_OUT_GET_ES_STATE:
2258 es_out_id_t *es = va_arg( args, es_out_id_t * );
2259 bool *pb = va_arg( args, bool * );
2261 *pb = EsIsSelected( es );
2262 return VLC_SUCCESS;
2265 case ES_OUT_SET_ES_CAT_POLICY:
2267 enum es_format_category_e i_cat = va_arg( args, enum es_format_category_e );
2268 enum es_out_policy_e i_pol = va_arg( args, enum es_out_policy_e );
2269 es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, i_cat );
2270 if( p_esprops == NULL )
2271 return VLC_EGENERIC;
2272 p_esprops->e_policy = i_pol;
2273 return VLC_SUCCESS;
2276 case ES_OUT_GET_GROUP_FORCED:
2278 int *pi_group = va_arg( args, int * );
2279 *pi_group = p_sys->i_group_id;
2280 return VLC_SUCCESS;
2283 case ES_OUT_SET_MODE:
2285 const int i_mode = va_arg( args, int );
2286 assert( i_mode == ES_OUT_MODE_NONE || i_mode == ES_OUT_MODE_ALL ||
2287 i_mode == ES_OUT_MODE_AUTO || i_mode == ES_OUT_MODE_PARTIAL ||
2288 i_mode == ES_OUT_MODE_END );
2290 if( i_mode != ES_OUT_MODE_NONE && !p_sys->b_active && p_sys->i_es > 0 )
2292 /* XXX Terminate vout if there are tracks but no video one.
2293 * This one is not mandatory but is he earliest place where it
2294 * can be done */
2295 int i;
2296 for( i = 0; i < p_sys->i_es; i++ )
2298 es_out_id_t *p_es = p_sys->es[i];
2299 if( p_es->fmt.i_cat == VIDEO_ES )
2300 break;
2302 if( i >= p_sys->i_es )
2303 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
2305 p_sys->b_active = i_mode != ES_OUT_MODE_NONE;
2306 p_sys->i_mode = i_mode;
2308 /* Reapply policy mode */
2309 for( int i = 0; i < p_sys->i_es; i++ )
2311 if( EsIsSelected( p_sys->es[i] ) )
2312 EsUnselect( out, p_sys->es[i],
2313 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
2315 for( int i = 0; i < p_sys->i_es; i++ )
2316 EsOutSelect( out, p_sys->es[i], false );
2317 if( i_mode == ES_OUT_MODE_END )
2318 EsOutTerminate( out );
2319 return VLC_SUCCESS;
2322 case ES_OUT_SET_ES:
2323 case ES_OUT_RESTART_ES:
2325 #define IGNORE_ES DATA_ES
2326 es_out_id_t *es = va_arg( args, es_out_id_t * );
2328 enum es_format_category_e i_cat;
2329 if( es == NULL )
2330 i_cat = UNKNOWN_ES;
2331 else if( es == es_cat + AUDIO_ES )
2332 i_cat = AUDIO_ES;
2333 else if( es == es_cat + VIDEO_ES )
2334 i_cat = VIDEO_ES;
2335 else if( es == es_cat + SPU_ES )
2336 i_cat = SPU_ES;
2337 else
2338 i_cat = IGNORE_ES;
2340 for( int i = 0; i < p_sys->i_es; i++ )
2342 if( i_cat == IGNORE_ES )
2344 if( es == p_sys->es[i] )
2346 if( i_query == ES_OUT_RESTART_ES && p_sys->es[i]->p_dec )
2348 EsDestroyDecoder( out, p_sys->es[i] );
2349 EsCreateDecoder( out, p_sys->es[i] );
2351 else if( i_query == ES_OUT_SET_ES )
2353 EsOutSelect( out, es, true );
2355 break;
2358 else
2360 if( i_cat == UNKNOWN_ES || p_sys->es[i]->fmt.i_cat == i_cat )
2362 if( EsIsSelected( p_sys->es[i] ) )
2364 if( i_query == ES_OUT_RESTART_ES )
2366 if( p_sys->es[i]->p_dec )
2368 EsDestroyDecoder( out, p_sys->es[i] );
2369 EsCreateDecoder( out, p_sys->es[i] );
2372 else
2374 EsUnselect( out, p_sys->es[i],
2375 p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
2381 return VLC_SUCCESS;
2383 case ES_OUT_RESTART_ALL_ES:
2385 for( int i = 0; i < p_sys->i_es; i++ )
2387 EsDestroyDecoder( out, p_sys->es[i] );
2388 EsCreateDecoder( out, p_sys->es[i] );
2390 return VLC_SUCCESS;
2393 case ES_OUT_SET_ES_DEFAULT:
2395 es_out_id_t *es = va_arg( args, es_out_id_t * );
2397 if( es == NULL )
2399 /*p_sys->i_default_video_id = -1;*/
2400 /*p_sys->i_default_audio_id = -1;*/
2401 p_sys->sub.i_demux_id = -1;
2403 else if( es == es_cat + AUDIO_ES )
2405 /*p_sys->i_default_video_id = -1;*/
2407 else if( es == es_cat + VIDEO_ES )
2409 /*p_sys->i_default_audio_id = -1;*/
2411 else if( es == es_cat + SPU_ES )
2413 p_sys->sub.i_demux_id = -1;
2415 else
2417 /*if( es->fmt.i_cat == VIDEO_ES )
2418 p_sys->i_default_video_id = es->i_id;
2419 else
2420 if( es->fmt.i_cat == AUDIO_ES )
2421 p_sys->i_default_audio_id = es->i_id;
2422 else*/
2423 if( es->fmt.i_cat == SPU_ES )
2424 p_sys->sub.i_demux_id = es->i_id;
2426 return VLC_SUCCESS;
2429 case ES_OUT_SET_PCR:
2430 case ES_OUT_SET_GROUP_PCR:
2432 es_out_pgrm_t *p_pgrm = NULL;
2433 int i_group = 0;
2434 int64_t i_pcr;
2436 /* Search program */
2437 if( i_query == ES_OUT_SET_PCR )
2439 p_pgrm = p_sys->p_pgrm;
2440 if( !p_pgrm )
2441 p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
2443 else
2445 i_group = va_arg( args, int );
2446 p_pgrm = EsOutProgramFind( out, i_group );
2448 if( !p_pgrm )
2449 return VLC_EGENERIC;
2451 i_pcr = va_arg( args, int64_t );
2452 if( i_pcr <= VLC_TS_INVALID )
2454 msg_Err( p_sys->p_input, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2455 return VLC_EGENERIC;
2458 /* TODO do not use mdate() but proper stream acquisition date */
2459 bool b_late;
2460 input_clock_Update( p_pgrm->p_clock, VLC_OBJECT(p_sys->p_input),
2461 &b_late,
2462 input_priv(p_sys->p_input)->b_can_pace_control || p_sys->b_buffering,
2463 EsOutIsExtraBufferingAllowed( out ),
2464 i_pcr, mdate() );
2466 if( !p_sys->p_pgrm )
2467 return VLC_SUCCESS;
2469 if( p_sys->b_buffering )
2471 /* Check buffering state on master clock update */
2472 EsOutDecodersStopBuffering( out, false );
2474 else if( p_pgrm == p_sys->p_pgrm )
2476 if( b_late && ( !input_priv(p_sys->p_input)->p_sout ||
2477 !input_priv(p_sys->p_input)->b_out_pace_control ) )
2479 const mtime_t i_pts_delay_base = p_sys->i_pts_delay - p_sys->i_pts_jitter;
2480 mtime_t i_pts_delay = input_clock_GetJitter( p_pgrm->p_clock );
2482 /* Avoid dangerously high value */
2483 const mtime_t i_jitter_max = INT64_C(1000) * var_InheritInteger( p_sys->p_input, "clock-jitter" );
2484 if( i_pts_delay > __MIN( i_pts_delay_base + i_jitter_max, INPUT_PTS_DELAY_MAX ) )
2486 msg_Err( p_sys->p_input,
2487 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2488 (int)(i_pts_delay - i_pts_delay_base) / 1000 );
2489 i_pts_delay = p_sys->i_pts_delay;
2491 /* reset clock */
2492 for( int i = 0; i < p_sys->i_pgrm; i++ )
2493 input_clock_Reset( p_sys->pgrm[i]->p_clock );
2495 else
2497 msg_Err( p_sys->p_input,
2498 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2499 (int)(i_pts_delay/1000) );
2501 /* Force a rebufferization when we are too late */
2503 /* It is not really good, as we throw away already buffered data
2504 * TODO have a mean to correctly reenter bufferization */
2505 es_out_Control( out, ES_OUT_RESET_PCR );
2508 es_out_SetJitter( out, i_pts_delay_base, i_pts_delay - i_pts_delay_base, p_sys->i_cr_average );
2511 return VLC_SUCCESS;
2514 case ES_OUT_RESET_PCR:
2515 msg_Dbg( p_sys->p_input, "ES_OUT_RESET_PCR called" );
2516 EsOutChangePosition( out );
2517 return VLC_SUCCESS;
2519 case ES_OUT_SET_GROUP:
2521 int i = va_arg( args, int );
2522 for( int j = 0; j < p_sys->i_pgrm; j++ )
2524 es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
2525 if( p_pgrm->i_id == i )
2527 EsOutProgramSelect( out, p_pgrm );
2528 return VLC_SUCCESS;
2531 return VLC_EGENERIC;
2534 case ES_OUT_SET_ES_FMT:
2536 /* This ain't pretty but is need by some demuxers (eg. Ogg )
2537 * to update the p_extra data */
2538 es_out_id_t *es = va_arg( args, es_out_id_t * );
2539 es_format_t *p_fmt = va_arg( args, es_format_t * );
2540 if( es == NULL )
2541 return VLC_EGENERIC;
2543 es_format_Clean( &es->fmt );
2544 es_format_Copy( &es->fmt, p_fmt );
2546 if( es->p_dec )
2548 EsDestroyDecoder( out, es );
2549 EsCreateDecoder( out, es );
2552 return VLC_SUCCESS;
2555 case ES_OUT_SET_ES_SCRAMBLED_STATE:
2557 es_out_id_t *es = va_arg( args, es_out_id_t * );
2558 bool b_scrambled = (bool)va_arg( args, int );
2560 if( !es->b_scrambled != !b_scrambled )
2562 es->b_scrambled = b_scrambled;
2563 EsOutProgramUpdateScrambled( out, es->p_pgrm );
2565 return VLC_SUCCESS;
2568 case ES_OUT_SET_NEXT_DISPLAY_TIME:
2570 const int64_t i_date = va_arg( args, int64_t );
2572 if( i_date < 0 )
2573 return VLC_EGENERIC;
2575 p_sys->i_preroll_end = i_date;
2577 return VLC_SUCCESS;
2579 case ES_OUT_SET_GROUP_META:
2581 int i_group = va_arg( args, int );
2582 const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
2584 EsOutProgramMeta( out, i_group, p_meta );
2585 return VLC_SUCCESS;
2587 case ES_OUT_SET_GROUP_EPG:
2589 int i_group = va_arg( args, int );
2590 const vlc_epg_t *p_epg = va_arg( args, const vlc_epg_t * );
2592 EsOutProgramEpg( out, i_group, p_epg );
2593 return VLC_SUCCESS;
2595 case ES_OUT_SET_GROUP_EPG_EVENT:
2597 int i_group = va_arg( args, int );
2598 const vlc_epg_event_t *p_evt = va_arg( args, const vlc_epg_event_t * );
2600 EsOutProgramEpgEvent( out, i_group, p_evt );
2601 return VLC_SUCCESS;
2603 case ES_OUT_SET_EPG_TIME:
2605 int64_t i64 = va_arg( args, int64_t );
2607 EsOutEpgTime( out, i64 );
2608 return VLC_SUCCESS;
2611 case ES_OUT_DEL_GROUP:
2613 int i_group = va_arg( args, int );
2615 return EsOutProgramDel( out, i_group );
2618 case ES_OUT_SET_META:
2620 const vlc_meta_t *p_meta = va_arg( args, const vlc_meta_t * );
2622 EsOutGlobalMeta( out, p_meta );
2623 return VLC_SUCCESS;
2626 case ES_OUT_GET_WAKE_UP:
2628 mtime_t *pi_wakeup = va_arg( args, mtime_t* );
2629 *pi_wakeup = EsOutGetWakeup( out );
2630 return VLC_SUCCESS;
2633 case ES_OUT_SET_ES_BY_ID:
2634 case ES_OUT_RESTART_ES_BY_ID:
2635 case ES_OUT_SET_ES_DEFAULT_BY_ID:
2637 const int i_id = va_arg( args, int );
2638 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2639 int i_new_query = 0;
2641 switch( i_query )
2643 case ES_OUT_SET_ES_BY_ID: i_new_query = ES_OUT_SET_ES; break;
2644 case ES_OUT_RESTART_ES_BY_ID: i_new_query = ES_OUT_RESTART_ES; break;
2645 case ES_OUT_SET_ES_DEFAULT_BY_ID: i_new_query = ES_OUT_SET_ES_DEFAULT; break;
2646 default:
2647 vlc_assert_unreachable();
2649 /* TODO if the lock is made non recursive it should be changed */
2650 int i_ret = es_out_Control( out, i_new_query, p_es );
2652 /* Clean up vout after user action (in active mode only).
2653 * FIXME it does not work well with multiple video windows */
2654 if( p_sys->b_active )
2655 input_resource_TerminateVout( input_priv(p_sys->p_input)->p_resource );
2656 return i_ret;
2659 case ES_OUT_GET_ES_OBJECTS_BY_ID:
2661 const int i_id = va_arg( args, int );
2662 es_out_id_t *p_es = EsOutGetFromID( out, i_id );
2663 if( !p_es )
2664 return VLC_EGENERIC;
2666 vlc_object_t **pp_decoder = va_arg( args, vlc_object_t ** );
2667 vout_thread_t **pp_vout = va_arg( args, vout_thread_t ** );
2668 audio_output_t **pp_aout = va_arg( args, audio_output_t ** );
2669 if( p_es->p_dec )
2671 if( pp_decoder )
2672 *pp_decoder = vlc_object_hold( p_es->p_dec );
2673 input_DecoderGetObjects( p_es->p_dec, pp_vout, pp_aout );
2675 else
2677 if( pp_decoder )
2678 *pp_decoder = NULL;
2679 if( pp_vout )
2680 *pp_vout = NULL;
2681 if( pp_aout )
2682 *pp_aout = NULL;
2684 return VLC_SUCCESS;
2687 case ES_OUT_GET_BUFFERING:
2689 bool *pb = va_arg( args, bool* );
2690 *pb = p_sys->b_buffering;
2691 return VLC_SUCCESS;
2694 case ES_OUT_GET_EMPTY:
2696 bool *pb = va_arg( args, bool* );
2697 *pb = EsOutDecodersIsEmpty( out );
2698 return VLC_SUCCESS;
2701 case ES_OUT_SET_DELAY:
2703 const int i_cat = va_arg( args, int );
2704 const mtime_t i_delay = va_arg( args, mtime_t );
2705 EsOutSetDelay( out, i_cat, i_delay );
2706 return VLC_SUCCESS;
2709 case ES_OUT_SET_RECORD_STATE:
2711 bool b = va_arg( args, int );
2712 return EsOutSetRecord( out, b );
2715 case ES_OUT_SET_PAUSE_STATE:
2717 const bool b_source_paused = (bool)va_arg( args, int );
2718 const bool b_paused = (bool)va_arg( args, int );
2719 const mtime_t i_date = va_arg( args, mtime_t );
2721 assert( !b_source_paused == !b_paused );
2722 EsOutChangePause( out, b_paused, i_date );
2724 return VLC_SUCCESS;
2727 case ES_OUT_SET_RATE:
2729 const int i_src_rate = va_arg( args, int );
2730 const int i_rate = va_arg( args, int );
2732 assert( i_src_rate == i_rate );
2733 EsOutChangeRate( out, i_rate );
2735 return VLC_SUCCESS;
2738 case ES_OUT_SET_TIME:
2740 const mtime_t i_date = va_arg( args, mtime_t );
2742 assert( i_date == -1 );
2743 EsOutChangePosition( out );
2745 return VLC_SUCCESS;
2748 case ES_OUT_SET_FRAME_NEXT:
2749 EsOutFrameNext( out );
2750 return VLC_SUCCESS;
2752 case ES_OUT_SET_TIMES:
2754 double f_position = va_arg( args, double );
2755 mtime_t i_time = va_arg( args, mtime_t );
2756 mtime_t i_length = va_arg( args, mtime_t );
2758 input_SendEventLength( p_sys->p_input, i_length );
2760 if( !p_sys->b_buffering )
2762 mtime_t i_delay;
2764 /* Fix for buffering delay */
2765 if( !input_priv(p_sys->p_input)->p_sout ||
2766 !input_priv(p_sys->p_input)->b_out_pace_control )
2767 i_delay = EsOutGetBuffering( out );
2768 else
2769 i_delay = 0;
2771 i_time -= i_delay;
2772 if( i_time < 0 )
2773 i_time = 0;
2775 if( i_length > 0 )
2776 f_position -= (double)i_delay / i_length;
2777 if( f_position < 0 )
2778 f_position = 0;
2780 input_SendEventPosition( p_sys->p_input, f_position, i_time );
2782 return VLC_SUCCESS;
2784 case ES_OUT_SET_JITTER:
2786 mtime_t i_pts_delay = va_arg( args, mtime_t );
2787 mtime_t i_pts_jitter = va_arg( args, mtime_t );
2788 int i_cr_average = va_arg( args, int );
2790 bool b_change_clock =
2791 i_pts_delay + i_pts_jitter != p_sys->i_pts_delay ||
2792 i_cr_average != p_sys->i_cr_average;
2794 assert( i_pts_jitter >= 0 );
2795 p_sys->i_pts_delay = i_pts_delay + i_pts_jitter;
2796 p_sys->i_pts_jitter = i_pts_jitter;
2797 p_sys->i_cr_average = i_cr_average;
2799 for( int i = 0; i < p_sys->i_pgrm && b_change_clock; i++ )
2800 input_clock_SetJitter( p_sys->pgrm[i]->p_clock,
2801 i_pts_delay + i_pts_jitter, i_cr_average );
2802 return VLC_SUCCESS;
2805 case ES_OUT_GET_PCR_SYSTEM:
2807 if( p_sys->b_buffering )
2808 return VLC_EGENERIC;
2810 es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
2811 if( !p_pgrm )
2812 return VLC_EGENERIC;
2814 mtime_t *pi_system = va_arg( args, mtime_t *);
2815 mtime_t *pi_delay = va_arg( args, mtime_t *);
2816 input_clock_GetSystemOrigin( p_pgrm->p_clock, pi_system, pi_delay );
2817 return VLC_SUCCESS;
2820 case ES_OUT_MODIFY_PCR_SYSTEM:
2822 if( p_sys->b_buffering )
2823 return VLC_EGENERIC;
2825 es_out_pgrm_t *p_pgrm = p_sys->p_pgrm;
2826 if( !p_pgrm )
2827 return VLC_EGENERIC;
2829 const bool b_absolute = va_arg( args, int );
2830 const mtime_t i_system = va_arg( args, mtime_t );
2831 input_clock_ChangeSystemOrigin( p_pgrm->p_clock, b_absolute, i_system );
2832 return VLC_SUCCESS;
2834 case ES_OUT_SET_EOS:
2836 for (int i = 0; i < p_sys->i_es; i++) {
2837 es_out_id_t *id = p_sys->es[i];
2838 if (id->p_dec != NULL)
2839 input_DecoderDrain(id->p_dec);
2841 return VLC_SUCCESS;
2844 case ES_OUT_POST_SUBNODE:
2846 input_item_node_t *node = va_arg(args, input_item_node_t *);
2847 input_item_node_PostAndDelete(node);
2848 return VLC_SUCCESS;
2851 default:
2852 msg_Err( p_sys->p_input, "unknown query 0x%x in %s", i_query,
2853 __func__ );
2854 return VLC_EGENERIC;
2857 static int EsOutControl( es_out_t *out, int i_query, va_list args )
2859 es_out_sys_t *p_sys = out->p_sys;
2860 int i_ret;
2862 vlc_mutex_lock( &p_sys->lock );
2863 i_ret = EsOutControlLocked( out, i_query, args );
2864 vlc_mutex_unlock( &p_sys->lock );
2866 return i_ret;
2869 /****************************************************************************
2870 * LanguageGetName: try to expend iso639 into plain name
2871 ****************************************************************************/
2872 static char *LanguageGetName( const char *psz_code )
2874 const iso639_lang_t *pl;
2876 if( psz_code == NULL || !strcmp( psz_code, "und" ) )
2878 return strdup( "" );
2881 if( strlen( psz_code ) == 2 )
2883 pl = GetLang_1( psz_code );
2885 else if( strlen( psz_code ) == 3 )
2887 pl = GetLang_2B( psz_code );
2888 if( !strcmp( pl->psz_iso639_1, "??" ) )
2890 pl = GetLang_2T( psz_code );
2893 else
2895 char *lang = LanguageGetCode( psz_code );
2896 pl = GetLang_1( lang );
2897 free( lang );
2900 if( !strcmp( pl->psz_iso639_1, "??" ) )
2902 return strdup( psz_code );
2904 else
2906 return strdup( vlc_gettext(pl->psz_eng_name) );
2910 /* Get a 2 char code */
2911 static char *LanguageGetCode( const char *psz_lang )
2913 const iso639_lang_t *pl;
2915 if( psz_lang == NULL || *psz_lang == '\0' )
2916 return strdup("??");
2918 for( pl = p_languages; pl->psz_eng_name != NULL; pl++ )
2920 if( !strcasecmp( pl->psz_eng_name, psz_lang ) ||
2921 !strcasecmp( pl->psz_iso639_1, psz_lang ) ||
2922 !strcasecmp( pl->psz_iso639_2T, psz_lang ) ||
2923 !strcasecmp( pl->psz_iso639_2B, psz_lang ) )
2924 return strdup( pl->psz_iso639_1 );
2927 return strdup("??");
2930 static char **LanguageSplit( const char *psz_langs )
2932 char *psz_dup;
2933 char *psz_parser;
2934 char **ppsz = NULL;
2935 int i_psz = 0;
2937 if( psz_langs == NULL ) return NULL;
2939 psz_parser = psz_dup = strdup(psz_langs);
2941 while( psz_parser && *psz_parser )
2943 char *psz;
2944 char *psz_code;
2946 psz = strchr(psz_parser, ',' );
2947 if( psz ) *psz++ = '\0';
2949 if( !strcmp( psz_parser, "any" ) )
2951 TAB_APPEND( i_psz, ppsz, strdup("any") );
2953 else if( !strcmp( psz_parser, "none" ) )
2955 TAB_APPEND( i_psz, ppsz, strdup("none") );
2957 else
2959 psz_code = LanguageGetCode( psz_parser );
2960 if( strcmp( psz_code, "??" ) )
2962 TAB_APPEND( i_psz, ppsz, psz_code );
2964 else
2966 free( psz_code );
2970 psz_parser = psz;
2973 if( i_psz )
2975 TAB_APPEND( i_psz, ppsz, NULL );
2978 free( psz_dup );
2979 return ppsz;
2982 static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang )
2984 if( !ppsz_langs || !psz_lang )
2985 return -1;
2987 for( int i = 0; ppsz_langs[i]; i++ )
2989 if( !strcasecmp( ppsz_langs[i], psz_lang ) ||
2990 ( !strcasecmp( ppsz_langs[i], "any" ) && strcasecmp( psz_lang, "none") ) )
2991 return i;
2992 if( !strcasecmp( ppsz_langs[i], "none" ) )
2993 break;
2996 return -1;
2999 /****************************************************************************
3000 * EsOutUpdateInfo:
3001 * - add meta info to the playlist item
3002 ****************************************************************************/
3003 static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt, const vlc_meta_t *p_meta )
3005 es_out_sys_t *p_sys = out->p_sys;
3006 input_thread_t *p_input = p_sys->p_input;
3007 const es_format_t *p_fmt_es = &es->fmt;
3008 lldiv_t div;
3010 if( es->fmt.i_cat == fmt->i_cat )
3012 es_format_t update = *fmt;
3013 update.i_id = es->i_meta_id;
3014 update.i_codec = es->fmt.i_codec;
3015 update.i_original_fourcc = es->fmt.i_original_fourcc;
3017 /* Update infos that could have been lost by the decoder (no need to
3018 * dup them since input_item_UpdateTracksInfo() will do it). */
3019 if (update.psz_language == NULL)
3020 update.psz_language = es->fmt.psz_language;
3021 if (update.psz_description == NULL)
3022 update.psz_description = es->fmt.psz_description;
3023 if (update.i_cat == SPU_ES)
3025 if (update.subs.psz_encoding == NULL)
3026 update.subs.psz_encoding = es->fmt.subs.psz_encoding;
3027 if (update.subs.p_style == NULL)
3028 update.subs.p_style = es->fmt.subs.p_style;
3030 if (update.i_extra_languages == 0)
3032 assert(update.p_extra_languages == NULL);
3033 update.i_extra_languages = es->fmt.i_extra_languages;
3034 update.p_extra_languages = es->fmt.p_extra_languages;
3037 /* No need to update codec specific data */
3038 update.i_extra = 0;
3039 update.p_extra = NULL;
3041 input_item_UpdateTracksInfo(input_GetItem(p_input), &update);
3044 /* Create category */
3045 char* psz_cat = EsInfoCategoryName( es );
3047 if( unlikely( !psz_cat ) )
3048 return;
3050 info_category_t* p_cat = info_category_New( psz_cat );
3052 free( psz_cat );
3054 if( unlikely( !p_cat ) )
3055 return;
3057 /* Add information */
3058 const char *psz_type;
3059 switch( fmt->i_cat )
3061 case AUDIO_ES:
3062 psz_type = _("Audio");
3063 break;
3064 case VIDEO_ES:
3065 psz_type = _("Video");
3066 break;
3067 case SPU_ES:
3068 psz_type = _("Subtitle");
3069 break;
3070 default:
3071 psz_type = NULL;
3072 break;
3075 if( psz_type )
3076 info_category_AddInfo( p_cat, _("Type"), "%s", psz_type );
3078 if( es->i_meta_id != es->i_id )
3079 info_category_AddInfo( p_cat, _("Original ID"),
3080 "%d", es->i_id );
3082 const vlc_fourcc_t i_codec_fourcc = ( p_fmt_es->i_original_fourcc )?
3083 p_fmt_es->i_original_fourcc : p_fmt_es->i_codec;
3084 const char *psz_codec_description =
3085 vlc_fourcc_GetDescription( p_fmt_es->i_cat, i_codec_fourcc );
3086 if( psz_codec_description && *psz_codec_description )
3087 info_category_AddInfo( p_cat, _("Codec"), "%s (%.4s)",
3088 psz_codec_description, (char*)&i_codec_fourcc );
3089 else if ( i_codec_fourcc != VLC_FOURCC(0,0,0,0) )
3090 info_category_AddInfo( p_cat, _("Codec"), "%.4s",
3091 (char*)&i_codec_fourcc );
3093 if( es->psz_language && *es->psz_language )
3094 info_category_AddInfo( p_cat, _("Language"), "%s",
3095 es->psz_language );
3096 if( fmt->psz_description && *fmt->psz_description )
3097 info_category_AddInfo( p_cat, _("Description"), "%s",
3098 fmt->psz_description );
3100 switch( fmt->i_cat )
3102 case AUDIO_ES:
3103 info_category_AddInfo( p_cat, _("Type"), _("Audio") );
3105 if( fmt->audio.i_physical_channels )
3106 info_category_AddInfo( p_cat, _("Channels"), "%s",
3107 _( aout_FormatPrintChannels( &fmt->audio ) ) );
3109 if( fmt->audio.i_rate != 0 )
3111 info_category_AddInfo( p_cat, _("Sample rate"), _("%u Hz"),
3112 fmt->audio.i_rate );
3113 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3114 var_SetInteger( p_input, "sample-rate", fmt->audio.i_rate );
3117 unsigned int i_bitspersample = fmt->audio.i_bitspersample;
3118 if( i_bitspersample == 0 )
3119 i_bitspersample = aout_BitsPerSample( p_fmt_es->i_codec );
3120 if( i_bitspersample != 0 )
3121 info_category_AddInfo( p_cat, _("Bits per sample"), "%u",
3122 i_bitspersample );
3124 if( fmt->i_bitrate != 0 )
3126 info_category_AddInfo( p_cat, _("Bitrate"), _("%u kb/s"),
3127 fmt->i_bitrate / 1000 );
3128 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3129 var_SetInteger( p_input, "bit-rate", fmt->i_bitrate );
3131 for( int i = 0; i < AUDIO_REPLAY_GAIN_MAX; i++ )
3133 const audio_replay_gain_t *p_rg = &fmt->audio_replay_gain;
3134 if( !p_rg->pb_gain[i] )
3135 continue;
3136 const char *psz_name;
3137 if( i == AUDIO_REPLAY_GAIN_TRACK )
3138 psz_name = _("Track replay gain");
3139 else
3140 psz_name = _("Album replay gain");
3141 info_category_AddInfo( p_cat, psz_name, _("%.2f dB"),
3142 p_rg->pf_gain[i] );
3144 break;
3146 case VIDEO_ES:
3147 info_category_AddInfo( p_cat, _("Type"), _("Video") );
3149 if( fmt->video.i_visible_width > 0 &&
3150 fmt->video.i_visible_height > 0 )
3151 info_category_AddInfo( p_cat, _("Video resolution"), "%ux%u",
3152 fmt->video.i_visible_width,
3153 fmt->video.i_visible_height);
3155 if( fmt->video.i_width > 0 && fmt->video.i_height > 0 )
3156 info_category_AddInfo( p_cat, _("Buffer dimensions"), "%ux%u",
3157 fmt->video.i_width, fmt->video.i_height );
3159 if( fmt->video.i_frame_rate > 0 &&
3160 fmt->video.i_frame_rate_base > 0 )
3162 div = lldiv( (float)fmt->video.i_frame_rate /
3163 fmt->video.i_frame_rate_base * 1000000,
3164 1000000 );
3165 if( div.rem > 0 )
3166 info_category_AddInfo( p_cat, _("Frame rate"), "%"PRId64".%06u",
3167 div.quot, (unsigned int )div.rem );
3168 else
3169 info_category_AddInfo( p_cat, _("Frame rate"), "%"PRId64,
3170 div.quot );
3172 if( fmt->i_codec != p_fmt_es->i_codec )
3174 const char *psz_chroma_description =
3175 vlc_fourcc_GetDescription( VIDEO_ES, fmt->i_codec );
3176 if( psz_chroma_description )
3177 info_category_AddInfo( p_cat, _("Decoded format"), "%s",
3178 psz_chroma_description );
3181 static const char orient_names[][13] = {
3182 N_("Top left"), N_("Left top"),
3183 N_("Right bottom"), N_("Top right"),
3184 N_("Bottom left"), N_("Bottom right"),
3185 N_("Left bottom"), N_("Right top"),
3187 info_category_AddInfo( p_cat, _("Orientation"), "%s",
3188 _(orient_names[fmt->video.orientation]) );
3190 if( fmt->video.primaries != COLOR_PRIMARIES_UNDEF )
3192 static const char primaries_names[][32] = {
3193 [COLOR_PRIMARIES_UNDEF] = N_("Undefined"),
3194 [COLOR_PRIMARIES_BT601_525] =
3195 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3196 [COLOR_PRIMARIES_BT601_625] =
3197 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3198 [COLOR_PRIMARIES_BT709] = "ITU-R BT.709",
3199 [COLOR_PRIMARIES_BT2020] = "ITU-R BT.2020",
3200 [COLOR_PRIMARIES_DCI_P3] = "DCI/P3 D65",
3201 [COLOR_PRIMARIES_BT470_M] = "ITU-R BT.470 M",
3203 static_assert(ARRAY_SIZE(primaries_names) == COLOR_PRIMARIES_MAX+1,
3204 "Color primiaries table mismatch");
3205 info_category_AddInfo( p_cat, _("Color primaries"), "%s",
3206 _(primaries_names[fmt->video.primaries]) );
3208 if( fmt->video.transfer != TRANSFER_FUNC_UNDEF )
3210 static const char func_names[][20] = {
3211 [TRANSFER_FUNC_UNDEF] = N_("Undefined"),
3212 [TRANSFER_FUNC_LINEAR] = N_("Linear"),
3213 [TRANSFER_FUNC_SRGB] = "sRGB",
3214 [TRANSFER_FUNC_BT470_BG] = "ITU-R BT.470 BG",
3215 [TRANSFER_FUNC_BT470_M] = "ITU-R BT.470 M",
3216 [TRANSFER_FUNC_BT709] = "ITU-R BT.709",
3217 [TRANSFER_FUNC_SMPTE_ST2084] = "SMPTE ST2084",
3218 [TRANSFER_FUNC_SMPTE_240] = "SMPTE 240M",
3219 [TRANSFER_FUNC_HLG] = N_("Hybrid Log-Gamma"),
3221 static_assert(ARRAY_SIZE(func_names) == TRANSFER_FUNC_MAX+1,
3222 "Transfer functions table mismatch");
3223 info_category_AddInfo( p_cat, _("Color transfer function"), "%s",
3224 _(func_names[fmt->video.transfer]) );
3226 if( fmt->video.space != COLOR_SPACE_UNDEF )
3228 static const char space_names[][16] = {
3229 [COLOR_SPACE_UNDEF] = N_("Undefined"),
3230 [COLOR_SPACE_BT601] = "ITU-R BT.601",
3231 [COLOR_SPACE_BT709] = "ITU-R BT.709",
3232 [COLOR_SPACE_BT2020] = "ITU-R BT.2020",
3234 static_assert(ARRAY_SIZE(space_names) == COLOR_SPACE_MAX+1,
3235 "Color space table mismatch");
3236 info_category_AddInfo( p_cat, _("Color space"), _("%s Range"),
3237 _(space_names[fmt->video.space]),
3238 _(fmt->video.b_color_range_full ? "Full" : "Limited") );
3240 if( fmt->video.chroma_location != CHROMA_LOCATION_UNDEF )
3242 static const char c_loc_names[][16] = {
3243 [CHROMA_LOCATION_UNDEF] = N_("Undefined"),
3244 [CHROMA_LOCATION_LEFT] = N_("Left"),
3245 [CHROMA_LOCATION_CENTER] = N_("Center"),
3246 [CHROMA_LOCATION_TOP_LEFT] = N_("Top Left"),
3247 [CHROMA_LOCATION_TOP_CENTER] = N_("Top Center"),
3248 [CHROMA_LOCATION_BOTTOM_LEFT] =N_("Bottom Left"),
3249 [CHROMA_LOCATION_BOTTOM_CENTER] = N_("Bottom Center"),
3251 static_assert(ARRAY_SIZE(c_loc_names) == CHROMA_LOCATION_MAX+1,
3252 "Chroma location table mismatch");
3253 info_category_AddInfo( p_cat, _("Chroma location"), "%s",
3254 _(c_loc_names[fmt->video.chroma_location]) );
3256 if( fmt->video.projection_mode != PROJECTION_MODE_RECTANGULAR )
3258 const char *psz_loc_name = NULL;
3259 switch (fmt->video.projection_mode)
3261 case PROJECTION_MODE_RECTANGULAR:
3262 psz_loc_name = N_("Rectangular");
3263 break;
3264 case PROJECTION_MODE_EQUIRECTANGULAR:
3265 psz_loc_name = N_("Equirectangular");
3266 break;
3267 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD:
3268 psz_loc_name = N_("Cubemap");
3269 break;
3270 default:
3271 vlc_assert_unreachable();
3272 break;
3274 info_category_AddInfo( p_cat, _("Projection"), "%s", _(psz_loc_name) );
3276 info_category_AddInfo( p_cat, _("Yaw"), "%.2f",
3277 fmt->video.pose.yaw );
3278 info_category_AddInfo( p_cat, _("Pitch"), "%.2f",
3279 fmt->video.pose.pitch );
3280 info_category_AddInfo( p_cat, _("Roll"), "%.2f",
3281 fmt->video.pose.roll );
3282 info_category_AddInfo( p_cat, _("Field of view"), "%.2f",
3283 fmt->video.pose.fov );
3285 if ( fmt->video.mastering.max_luminance )
3287 info_category_AddInfo( p_cat, _("Max. luminance"), "%.4f cd/m²",
3288 fmt->video.mastering.max_luminance / 10000.f );
3290 if ( fmt->video.mastering.min_luminance )
3292 info_category_AddInfo( p_cat, _("Min. luminance"), "%.4f cd/m²",
3293 fmt->video.mastering.min_luminance / 10000.f );
3295 if ( fmt->video.mastering.primaries[4] &&
3296 fmt->video.mastering.primaries[5] )
3298 float x = (float)fmt->video.mastering.primaries[4] / 50000.f;
3299 float y = (float)fmt->video.mastering.primaries[5] / 50000.f;
3300 info_category_AddInfo( p_cat, _("Primary R"), "x=%.4f y=%.4f", x, y );
3302 if ( fmt->video.mastering.primaries[0] &&
3303 fmt->video.mastering.primaries[1] )
3305 float x = (float)fmt->video.mastering.primaries[0] / 50000.f;
3306 float y = (float)fmt->video.mastering.primaries[1] / 50000.f;
3307 info_category_AddInfo( p_cat, _("Primary G"), "x=%.4f y=%.4f", x, y );
3309 if ( fmt->video.mastering.primaries[2] &&
3310 fmt->video.mastering.primaries[3] )
3312 float x = (float)fmt->video.mastering.primaries[2] / 50000.f;
3313 float y = (float)fmt->video.mastering.primaries[3] / 50000.f;
3314 info_category_AddInfo( p_cat, _("Primary B"), "x=%.4f y=%.4f", x, y );
3316 if ( fmt->video.mastering.white_point[0] &&
3317 fmt->video.mastering.white_point[1] )
3319 float x = (float)fmt->video.mastering.white_point[0] / 50000.f;
3320 float y = (float)fmt->video.mastering.white_point[1] / 50000.f;
3321 info_category_AddInfo( p_cat, _("White point"), "x=%.4f y=%.4f", x, y );
3323 if ( fmt->video.lighting.MaxCLL )
3325 info_category_AddInfo( p_cat, "MaxCLL", "%d cd/m²",
3326 fmt->video.lighting.MaxCLL );
3328 if ( fmt->video.lighting.MaxFALL )
3330 info_category_AddInfo( p_cat, "MaxFALL", "%d cd/m²",
3331 fmt->video.lighting.MaxFALL );
3333 break;
3335 case SPU_ES:
3336 info_category_AddInfo( p_cat, _("Type"), _("Subtitle") );
3337 break;
3339 default:
3340 break;
3343 /* Append generic meta */
3344 if( p_meta )
3346 char **ppsz_all_keys = vlc_meta_CopyExtraNames( p_meta );
3347 for( int i = 0; ppsz_all_keys && ppsz_all_keys[i]; i++ )
3349 char *psz_key = ppsz_all_keys[i];
3350 const char *psz_value = vlc_meta_GetExtra( p_meta, psz_key );
3352 if( psz_value )
3353 info_category_AddInfo( p_cat, vlc_gettext(psz_key), "%s",
3354 vlc_gettext(psz_value) );
3355 free( psz_key );
3357 free( ppsz_all_keys );
3359 /* */
3360 input_Control( p_input, INPUT_REPLACE_INFOS, p_cat );
3363 static void EsDeleteInfo( es_out_t *out, es_out_id_t *es )
3365 char* psz_info_category;
3367 if( likely( psz_info_category = EsInfoCategoryName( es ) ) )
3369 input_Control( out->p_sys->p_input, INPUT_DEL_INFO,
3370 psz_info_category, NULL );
3372 free( psz_info_category );