1 /*****************************************************************************
2 * es_out.c: Es Out handler for input.
3 *****************************************************************************
4 * Copyright (C) 2003-2004 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8 * Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
25 /*****************************************************************************
27 *****************************************************************************/
34 #include <vlc_common.h>
36 #include <vlc_input.h>
37 #include <vlc_es_out.h>
38 #include <vlc_block.h>
40 #include <vlc_fourcc.h>
44 #include "input_internal.h"
45 #include "../clock/input_clock.h"
52 #include "../stream_output/stream_output.h"
54 #include <vlc_iso_lang.h>
55 /* FIXME we should find a better way than including that */
56 #include "../text/iso-639_def.h"
58 /*****************************************************************************
60 *****************************************************************************/
66 /* Number of es for this pgrm */
72 /* Clock for this program */
73 input_clock_t
*p_input_clock
;
81 * Opaque structure representing an ES (Elementary Stream) track.
83 * This structure is propagated via the vlc_input_event_es event
88 enum es_format_category_e i_cat
;
96 es_out_pgrm_t
*p_pgrm
;
100 bool b_forced
; /* if true, bypass variables when selecting this track */
102 /* Channel in the track type */
107 size_t i_pos
; /* position, used to get the title of the track */
108 es_format_t fmt
; /* input fmt from the demuxer */
109 es_format_t fmt_out
; /* updated fmt (by the decoder) */
111 char *psz_language_code
;
116 decoder_t
*p_dec_record
;
118 /* Fields for Video with CC */
122 uint64_t i_bitmap
; /* channels bitmap */
123 es_out_id_t
*pp_es
[64]; /* a max of 64 chans for CEA708 */
126 /* Field for CC track from a master video */
127 es_out_id_t
*p_master
;
129 /* ID for the meta data */
132 struct vlc_list node
;
134 vlc_mouse_event mouse_event_cb
;
135 void* mouse_event_userdata
;
140 int i_count
; /* es count */
141 es_out_id_t
*p_main_es
; /* current main es */
142 enum es_out_policy_e e_policy
;
144 /* Parameters used for es selection */
145 bool b_autoselect
; /* if we want to select an es when no user prefs */
146 int i_id
; /* es id as set by es fmt.id */
147 int i_demux_id
; /* same as previous, demuxer set default value */
148 int i_channel
; /* es number in creation order */
149 char **ppsz_language
;
154 input_thread_t
*p_input
;
160 struct vlc_list programs
;
161 es_out_pgrm_t
*p_pgrm
; /* Master program */
166 struct vlc_list es_slaves
; /* Dynamically created es on regular es selection */
172 es_out_es_props_t video
, audio
, sub
;
174 /* es/group to select */
178 vlc_tick_t i_audio_delay
;
179 vlc_tick_t i_spu_delay
;
181 /* Clock configuration */
182 vlc_tick_t i_pts_delay
;
183 vlc_tick_t i_pts_jitter
;
189 vlc_tick_t i_pause_date
;
191 /* Current preroll */
192 vlc_tick_t i_preroll_end
;
194 /* Used for buffering */
196 vlc_tick_t i_buffering_extra_initial
;
197 vlc_tick_t i_buffering_extra_stream
;
198 vlc_tick_t i_buffering_extra_system
;
201 sout_instance_t
*p_sout_record
;
203 /* Used only to limit debugging output */
204 int i_prev_stream_level
;
209 static void EsOutDelLocked( es_out_t
*, es_out_id_t
* );
210 static void EsOutDel ( es_out_t
*, es_out_id_t
* );
212 static void EsOutTerminate( es_out_t
* );
213 static void EsOutSelect( es_out_t
*, es_out_id_t
*es
, bool b_force
);
214 static void EsOutUpdateInfo( es_out_t
*, es_out_id_t
*es
, const vlc_meta_t
* );
215 static int EsOutSetRecord( es_out_t
*, bool b_record
);
217 static bool EsIsSelected( es_out_id_t
*es
);
218 static void EsOutSelectEs( es_out_t
*out
, es_out_id_t
*es
);
219 static void EsOutDeleteInfoEs( es_out_t
*, es_out_id_t
*es
);
220 static void EsOutUnselectEs( es_out_t
*out
, es_out_id_t
*es
, bool b_update
);
221 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
);
222 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
);
223 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
);
224 static void EsOutProgramsChangeRate( es_out_t
*out
);
225 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
);
226 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
);
227 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_progmeta
);
228 static int EsOutEsUpdateFmt(es_out_t
*out
, es_out_id_t
*es
, const es_format_t
*fmt
);
230 static char *LanguageGetName( const char *psz_code
);
231 static char *LanguageGetCode( const char *psz_lang
);
232 static char **LanguageSplit( const char *psz_langs
);
233 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
);
235 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
);
236 static char *EsInfoCategoryName( es_out_id_t
* es
);
238 static inline int EsOutGetClosedCaptionsChannel( const es_format_t
*p_fmt
)
241 if( p_fmt
->i_codec
== VLC_CODEC_CEA608
&& p_fmt
->subs
.cc
.i_channel
< 4 )
242 i_channel
= p_fmt
->subs
.cc
.i_channel
;
243 else if( p_fmt
->i_codec
== VLC_CODEC_CEA708
&& p_fmt
->subs
.cc
.i_channel
< 64 )
244 i_channel
= p_fmt
->subs
.cc
.i_channel
;
250 #define foreach_es_then_es_slaves( pos ) \
251 for( int fetes_i=0; fetes_i<2; fetes_i++ ) \
252 vlc_list_foreach( pos, (!fetes_i ? &p_sys->es : &p_sys->es_slaves), node )
255 /*****************************************************************************
256 * Es category specific structs
257 *****************************************************************************/
258 static es_out_es_props_t
* GetPropsByCat( es_out_sys_t
*p_sys
, int i_cat
)
263 return &p_sys
->audio
;
267 return &p_sys
->video
;
272 static void EsOutPropsCleanup( es_out_es_props_t
*p_props
)
274 if( p_props
->ppsz_language
)
276 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
277 free( p_props
->ppsz_language
[i
] );
278 free( p_props
->ppsz_language
);
282 static void EsOutPropsInit( es_out_es_props_t
*p_props
,
284 input_thread_t
*p_input
,
285 enum es_out_policy_e e_default_policy
,
286 const char *psz_trackidvar
,
287 const char *psz_trackvar
,
288 const char *psz_langvar
,
289 const char *psz_debug
)
291 p_props
->e_policy
= e_default_policy
;
292 p_props
->i_count
= 0;
293 p_props
->b_autoselect
= autoselect
;
294 p_props
->i_id
= (psz_trackidvar
) ? var_GetInteger( p_input
, psz_trackidvar
): -1;
295 p_props
->i_channel
= (psz_trackvar
) ? var_GetInteger( p_input
, psz_trackvar
): -1;
296 p_props
->i_demux_id
= -1;
297 p_props
->p_main_es
= NULL
;
299 if( !input_priv(p_input
)->b_preparsing
&& psz_langvar
)
301 char *psz_string
= var_GetString( p_input
, psz_langvar
);
302 p_props
->ppsz_language
= LanguageSplit( psz_string
);
303 if( p_props
->ppsz_language
)
305 for( int i
= 0; p_props
->ppsz_language
[i
]; i
++ )
306 msg_Dbg( p_input
, "selected %s language[%d] %s",
307 psz_debug
, i
, p_props
->ppsz_language
[i
] );
313 static const struct es_out_callbacks es_out_cbs
;
315 /*****************************************************************************
317 *****************************************************************************/
318 es_out_t
*input_EsOutNew( input_thread_t
*p_input
, int i_rate
)
320 es_out_sys_t
*p_sys
= calloc( 1, sizeof( *p_sys
) );
324 p_sys
->out
.cbs
= &es_out_cbs
;
326 vlc_mutex_init( &p_sys
->lock
);
327 p_sys
->p_input
= p_input
;
329 p_sys
->b_active
= false;
330 p_sys
->i_mode
= ES_OUT_MODE_NONE
;
332 vlc_list_init(&p_sys
->programs
);
333 vlc_list_init(&p_sys
->es
);
334 vlc_list_init(&p_sys
->es_slaves
);
337 EsOutPropsInit( &p_sys
->video
, true, p_input
, ES_OUT_ES_POLICY_SIMULTANEOUS
,
338 "video-track-id", "video-track", NULL
, NULL
);
339 EsOutPropsInit( &p_sys
->audio
, true, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
340 "audio-track-id", "audio-track", "audio-language", "audio" );
341 EsOutPropsInit( &p_sys
->sub
, false, p_input
, ES_OUT_ES_POLICY_EXCLUSIVE
,
342 "sub-track-id", "sub-track", "sub-language", "sub" );
344 p_sys
->i_group_id
= var_GetInteger( p_input
, "program" );
346 p_sys
->i_pause_date
= -1;
348 p_sys
->i_rate
= i_rate
;
350 p_sys
->b_buffering
= true;
351 p_sys
->i_preroll_end
= -1;
352 p_sys
->i_prev_stream_level
= -1;
357 /*****************************************************************************
359 *****************************************************************************/
360 static void EsTerminate(es_out_id_t
*es
)
362 vlc_list_remove(&es
->node
);
364 es
->b_terminated
= true;
367 static char *EsGetTitle( es_out_id_t
*es
)
369 const es_format_t
*fmt
= &es
->fmt
;
372 /* Take care of the ES description */
373 if( fmt
->psz_description
&& *fmt
->psz_description
)
375 if( es
->psz_language
&& *es
->psz_language
)
377 if( asprintf( &title
, "%s - [%s]", fmt
->psz_description
,
378 es
->psz_language
) == -1 )
382 title
= strdup( fmt
->psz_description
);
386 if( es
->psz_language
&& *es
->psz_language
)
388 if( asprintf( &title
, "%s %zu - [%s]", _("Track"),
389 es
->i_pos
, es
->psz_language
) == -1 )
394 if( asprintf( &title
, "%s %zu", _("Track"), es
->i_pos
) == -1 )
402 static void EsRelease(es_out_id_t
*es
)
404 if (vlc_atomic_rc_dec(&es
->rc
))
407 free(es
->psz_language
);
408 free(es
->psz_language_code
);
409 es_format_Clean(&es
->fmt
);
414 static void EsHold(es_out_id_t
*es
)
416 vlc_atomic_rc_inc(&es
->rc
);
419 static void EsOutDelete( es_out_t
*out
)
421 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
423 assert(vlc_list_is_empty(&p_sys
->es
));
424 assert(vlc_list_is_empty(&p_sys
->es_slaves
));
425 assert(vlc_list_is_empty(&p_sys
->programs
));
426 assert(p_sys
->p_pgrm
== NULL
);
427 EsOutPropsCleanup( &p_sys
->audio
);
428 EsOutPropsCleanup( &p_sys
->sub
);
430 vlc_mutex_destroy( &p_sys
->lock
);
435 static void EsOutTerminate( es_out_t
*out
)
437 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
440 if( p_sys
->p_sout_record
)
441 EsOutSetRecord( out
, false );
443 foreach_es_then_es_slaves(es
)
445 if (es
->p_dec
!= NULL
)
446 input_DecoderDelete(es
->p_dec
);
452 /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
453 es_out_pgrm_t
*p_pgrm
;
454 vlc_list_foreach(p_pgrm
, &p_sys
->programs
, node
)
456 input_clock_Delete( p_pgrm
->p_input_clock
);
458 vlc_meta_Delete( p_pgrm
->p_meta
);
460 vlc_list_remove(&p_pgrm
->node
);
461 input_SendEventProgramDel( p_sys
->p_input
, p_pgrm
->i_id
);
465 p_sys
->p_pgrm
= NULL
;
467 input_item_SetEpgOffline( input_priv(p_sys
->p_input
)->p_item
);
468 input_SendEventMetaEpg( p_sys
->p_input
);
471 static vlc_tick_t
EsOutGetWakeup( es_out_t
*out
)
473 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
474 input_thread_t
*p_input
= p_sys
->p_input
;
479 /* We do not have a wake up date if the input cannot have its speed
480 * controlled or sout is imposing its own or while buffering
482 * FIXME for !input_priv(p_input)->b_can_pace_control a wake-up time is still needed
483 * to avoid too heavy buffering */
484 if( !input_priv(p_input
)->b_can_pace_control
||
485 input_priv(p_input
)->b_out_pace_control
||
489 return input_clock_GetWakeup( p_sys
->p_pgrm
->p_input_clock
);
492 static es_out_id_t es_cat
[DATA_ES
];
494 static es_out_id_t
*EsOutGetFromID( es_out_t
*out
, int i_id
)
496 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
501 /* Special HACK, -i_id is the cat of the stream */
502 return es_cat
- i_id
;
505 foreach_es_then_es_slaves(es
)
506 if (es
->fmt
.i_id
== i_id
)
511 static es_out_id_t
*EsOutGetSelectedCat( es_out_t
*out
,
512 enum es_format_category_e cat
)
514 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
517 foreach_es_then_es_slaves( es
)
518 if( es
->fmt
.i_cat
== cat
&& EsIsSelected( es
) )
523 static bool EsOutDecodersIsEmpty( es_out_t
*out
)
525 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
528 if( p_sys
->b_buffering
&& p_sys
->p_pgrm
)
530 EsOutDecodersStopBuffering( out
, true );
531 if( p_sys
->b_buffering
)
535 foreach_es_then_es_slaves(es
)
537 if( es
->p_dec
&& !input_DecoderIsEmpty( es
->p_dec
) )
539 if( es
->p_dec_record
&& !input_DecoderIsEmpty( es
->p_dec_record
) )
545 static void EsOutSetDelay( es_out_t
*out
, int i_cat
, vlc_tick_t i_delay
)
547 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
550 if( i_cat
== AUDIO_ES
)
551 p_sys
->i_audio_delay
= i_delay
;
552 else if( i_cat
== SPU_ES
)
553 p_sys
->i_spu_delay
= i_delay
;
555 foreach_es_then_es_slaves(es
)
556 EsOutDecoderChangeDelay(out
, es
);
559 static int EsOutSetRecord( es_out_t
*out
, bool b_record
)
561 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
562 input_thread_t
*p_input
= p_sys
->p_input
;
565 assert( ( b_record
&& !p_sys
->p_sout_record
) || ( !b_record
&& p_sys
->p_sout_record
) );
569 char *psz_path
= var_CreateGetNonEmptyString( p_input
, "input-record-path" );
572 if( var_CountChoices( p_input
, "video-es" ) )
573 psz_path
= config_GetUserDir( VLC_VIDEOS_DIR
);
574 else if( var_CountChoices( p_input
, "audio-es" ) )
575 psz_path
= config_GetUserDir( VLC_MUSIC_DIR
);
577 psz_path
= config_GetUserDir( VLC_DOWNLOAD_DIR
);
580 char *psz_sout
= NULL
; // TODO conf
582 if( !psz_sout
&& psz_path
)
584 char *psz_file
= input_CreateFilename( p_input
, NULL
, psz_path
,
585 INPUT_RECORD_PREFIX
, NULL
);
588 char* psz_file_esc
= config_StringEscape( psz_file
);
591 if( asprintf( &psz_sout
, "#record{dst-prefix='%s'}", psz_file_esc
) < 0 )
593 free( psz_file_esc
);
604 p_sys
->p_sout_record
= sout_NewInstance( p_input
, psz_sout
);
608 if( !p_sys
->p_sout_record
)
611 vlc_list_foreach( p_es
, &p_sys
->es
, node
) /* Only master es */
616 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_input_clock
, p_sys
->p_sout_record
);
617 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
618 input_DecoderStartWait( p_es
->p_dec_record
);
623 vlc_list_foreach( p_es
, &p_sys
->es
, node
) /* Only master es */
625 if( !p_es
->p_dec_record
)
628 input_DecoderDelete( p_es
->p_dec_record
);
629 p_es
->p_dec_record
= NULL
;
632 sout_DeleteInstance( p_sys
->p_sout_record
);
634 p_sys
->p_sout_record
= NULL
;
639 static void EsOutChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
)
641 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
643 /* XXX the order is important */
646 EsOutDecodersChangePause( out
, true, i_date
);
647 EsOutProgramChangePause( out
, true, i_date
);
651 if( p_sys
->i_buffering_extra_initial
> 0 )
653 vlc_tick_t i_stream_start
;
654 vlc_tick_t i_system_start
;
655 vlc_tick_t i_stream_duration
;
656 vlc_tick_t i_system_duration
;
658 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
659 &i_stream_start
, &i_system_start
,
660 &i_stream_duration
, &i_system_duration
);
663 /* FIXME pcr != exactly what wanted */
664 const vlc_tick_t i_used
= /*(i_stream_duration - input_priv(p_sys->p_input)->i_pts_delay)*/ p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
667 p_sys
->i_buffering_extra_initial
= 0;
668 p_sys
->i_buffering_extra_stream
= 0;
669 p_sys
->i_buffering_extra_system
= 0;
671 EsOutProgramChangePause( out
, false, i_date
);
672 EsOutDecodersChangePause( out
, false, i_date
);
674 EsOutProgramsChangeRate( out
);
676 p_sys
->b_paused
= b_paused
;
677 p_sys
->i_pause_date
= i_date
;
680 static void EsOutChangeRate( es_out_t
*out
, int i_rate
)
682 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
683 float rate
= (float)i_rate
/ (float)INPUT_RATE_DEFAULT
;
686 p_sys
->i_rate
= i_rate
;
687 EsOutProgramsChangeRate( out
);
689 foreach_es_then_es_slaves(es
)
690 if( es
->p_dec
!= NULL
)
691 input_DecoderChangeRate( es
->p_dec
, rate
);
694 static void EsOutChangePosition( es_out_t
*out
)
696 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
699 input_SendEventCache( p_sys
->p_input
, 0.0 );
701 foreach_es_then_es_slaves(p_es
)
702 if( p_es
->p_dec
!= NULL
)
704 input_DecoderFlush( p_es
->p_dec
);
705 if( !p_sys
->b_buffering
)
707 input_DecoderStartWait( p_es
->p_dec
);
708 if( p_es
->p_dec_record
!= NULL
)
709 input_DecoderStartWait( p_es
->p_dec_record
);
714 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
715 input_clock_Reset(pgrm
->p_input_clock
);
717 p_sys
->b_buffering
= true;
718 p_sys
->i_buffering_extra_initial
= 0;
719 p_sys
->i_buffering_extra_stream
= 0;
720 p_sys
->i_buffering_extra_system
= 0;
721 p_sys
->i_preroll_end
= -1;
722 p_sys
->i_prev_stream_level
= -1;
727 static void EsOutDecodersStopBuffering( es_out_t
*out
, bool b_forced
)
729 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
732 vlc_tick_t i_stream_start
;
733 vlc_tick_t i_system_start
;
734 vlc_tick_t i_stream_duration
;
735 vlc_tick_t i_system_duration
;
736 if (input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
737 &i_stream_start
, &i_system_start
,
738 &i_stream_duration
, &i_system_duration
))
741 vlc_tick_t i_preroll_duration
= 0;
742 if( p_sys
->i_preroll_end
>= 0 )
743 i_preroll_duration
= __MAX( p_sys
->i_preroll_end
- i_stream_start
, 0 );
745 const vlc_tick_t i_buffering_duration
= p_sys
->i_pts_delay
+
747 p_sys
->i_buffering_extra_stream
- p_sys
->i_buffering_extra_initial
;
749 if( i_stream_duration
<= i_buffering_duration
&& !b_forced
)
752 if (i_buffering_duration
== 0)
755 f_level
= __MAX( (double)i_stream_duration
/ i_buffering_duration
, 0 );
756 input_SendEventCache( p_sys
->p_input
, f_level
);
758 int i_level
= (int)(100 * f_level
);
759 if( p_sys
->i_prev_stream_level
!= i_level
)
761 msg_Dbg( p_sys
->p_input
, "Buffering %d%%", i_level
);
762 p_sys
->i_prev_stream_level
= i_level
;
767 input_SendEventCache( p_sys
->p_input
, 1.0 );
769 msg_Dbg( p_sys
->p_input
, "Stream buffering done (%d ms in %d ms)",
770 (int)MS_FROM_VLC_TICK(i_stream_duration
), (int)MS_FROM_VLC_TICK(i_system_duration
) );
771 p_sys
->b_buffering
= false;
772 p_sys
->i_preroll_end
= -1;
773 p_sys
->i_prev_stream_level
= -1;
775 if( p_sys
->i_buffering_extra_initial
> 0 )
781 const vlc_tick_t i_decoder_buffering_start
= vlc_tick_now();
782 foreach_es_then_es_slaves(p_es
)
784 if( !p_es
->p_dec
|| p_es
->fmt
.i_cat
== SPU_ES
)
786 input_DecoderWait( p_es
->p_dec
);
787 if( p_es
->p_dec_record
)
788 input_DecoderWait( p_es
->p_dec_record
);
791 msg_Dbg( p_sys
->p_input
, "Decoder wait done in %d ms",
792 (int)MS_FROM_VLC_TICK(vlc_tick_now() - i_decoder_buffering_start
) );
794 /* Here is a good place to destroy unused vout with every demuxer */
795 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
798 const vlc_tick_t i_wakeup_delay
= VLC_TICK_FROM_MS(10); /* FIXME CLEANUP thread wake up time*/
799 const vlc_tick_t i_current_date
= p_sys
->b_paused
? p_sys
->i_pause_date
: vlc_tick_now();
801 input_clock_ChangeSystemOrigin( p_sys
->p_pgrm
->p_input_clock
, true,
802 i_current_date
+ i_wakeup_delay
- i_buffering_duration
);
804 foreach_es_then_es_slaves(p_es
)
809 input_DecoderStopWait( p_es
->p_dec
);
810 if( p_es
->p_dec_record
)
811 input_DecoderStopWait( p_es
->p_dec_record
);
814 static void EsOutDecodersChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
)
816 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
819 /* Pause decoders first */
820 foreach_es_then_es_slaves(es
)
823 input_DecoderChangePause( es
->p_dec
, b_paused
, i_date
);
824 if( es
->p_dec_record
)
825 input_DecoderChangePause( es
->p_dec_record
, b_paused
, i_date
);
829 static bool EsOutIsExtraBufferingAllowed( es_out_t
*out
)
831 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
835 foreach_es_then_es_slaves(p_es
)
838 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec
);
839 if( p_es
->p_dec_record
)
840 i_size
+= input_DecoderGetFifoSize( p_es
->p_dec_record
);
842 //msg_Info( out, "----- EsOutIsExtraBufferingAllowed =% 5d KiB -- ", i_size / 1024 );
844 /* TODO maybe we want to be able to tune it ? */
845 #if defined(OPTIMIZE_MEMORY)
846 const size_t i_level_high
= 512*1024; /* 0.5 MiB */
848 const size_t i_level_high
= 10*1024*1024; /* 10 MiB */
850 return i_size
< i_level_high
;
853 static void EsOutProgramChangePause( es_out_t
*out
, bool b_paused
, vlc_tick_t i_date
)
855 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
858 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
859 input_clock_ChangePause(pgrm
->p_input_clock
, b_paused
, i_date
);
862 static void EsOutDecoderChangeDelay( es_out_t
*out
, es_out_id_t
*p_es
)
864 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
867 if( p_es
->fmt
.i_cat
== AUDIO_ES
)
868 i_delay
= p_sys
->i_audio_delay
;
869 else if( p_es
->fmt
.i_cat
== SPU_ES
)
870 i_delay
= p_sys
->i_spu_delay
;
875 input_DecoderChangeDelay( p_es
->p_dec
, i_delay
);
876 if( p_es
->p_dec_record
)
877 input_DecoderChangeDelay( p_es
->p_dec_record
, i_delay
);
879 static void EsOutProgramsChangeRate( es_out_t
*out
)
881 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
884 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
885 input_clock_ChangeRate(pgrm
->p_input_clock
, p_sys
->i_rate
);
888 static void EsOutFrameNext( es_out_t
*out
)
890 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
891 es_out_id_t
*p_es_video
= NULL
, *p_es
;
893 if( p_sys
->b_buffering
)
895 msg_Warn( p_sys
->p_input
, "buffering, ignoring 'frame next'" );
899 assert( p_sys
->b_paused
);
901 foreach_es_then_es_slaves(p_es
)
902 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
&& !p_es_video
/* nested loop */ )
910 msg_Warn( p_sys
->p_input
, "No video track selected, ignoring 'frame next'" );
914 vlc_tick_t i_duration
;
915 input_DecoderFrameNext( p_es_video
->p_dec
, &i_duration
);
917 msg_Dbg( p_sys
->p_input
, "EsOutFrameNext consummed %d ms", (int)MS_FROM_VLC_TICK(i_duration
) );
919 if( i_duration
<= 0 )
920 i_duration
= VLC_TICK_FROM_MS(40);
922 /* FIXME it is not a clean way ? */
923 if( p_sys
->i_buffering_extra_initial
<= 0 )
925 vlc_tick_t i_stream_start
;
926 vlc_tick_t i_system_start
;
927 vlc_tick_t i_stream_duration
;
928 vlc_tick_t i_system_duration
;
931 i_ret
= input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
932 &i_stream_start
, &i_system_start
,
933 &i_stream_duration
, &i_system_duration
);
937 p_sys
->i_buffering_extra_initial
= 1 + i_stream_duration
- p_sys
->i_pts_delay
; /* FIXME < 0 ? */
938 p_sys
->i_buffering_extra_system
=
939 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
;
942 const int i_rate
= input_clock_GetRate( p_sys
->p_pgrm
->p_input_clock
);
944 p_sys
->b_buffering
= true;
945 p_sys
->i_buffering_extra_system
+= i_duration
;
946 p_sys
->i_buffering_extra_stream
= p_sys
->i_buffering_extra_initial
+
947 ( p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
) *
948 INPUT_RATE_DEFAULT
/ i_rate
;
950 p_sys
->i_preroll_end
= -1;
951 p_sys
->i_prev_stream_level
= -1;
953 static vlc_tick_t
EsOutGetBuffering( es_out_t
*out
)
955 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
956 vlc_tick_t i_stream_duration
, i_system_start
;
962 vlc_tick_t i_stream_start
, i_system_duration
;
964 if( input_clock_GetState( p_sys
->p_pgrm
->p_input_clock
,
965 &i_stream_start
, &i_system_start
,
966 &i_stream_duration
, &i_system_duration
) )
972 if( p_sys
->b_buffering
&& p_sys
->i_buffering_extra_initial
<= 0 )
974 i_delay
= i_stream_duration
;
978 vlc_tick_t i_system_duration
;
980 if( p_sys
->b_paused
)
982 i_system_duration
= p_sys
->i_pause_date
- i_system_start
;
983 if( p_sys
->i_buffering_extra_initial
> 0 )
984 i_system_duration
+= p_sys
->i_buffering_extra_system
- p_sys
->i_buffering_extra_initial
;
988 i_system_duration
= vlc_tick_now() - i_system_start
;
991 const vlc_tick_t i_consumed
= i_system_duration
* INPUT_RATE_DEFAULT
/ p_sys
->i_rate
- i_stream_duration
;
992 i_delay
= p_sys
->i_pts_delay
- i_consumed
;
999 static void EsOutSendEsEvent(es_out_t
*out
, es_out_id_t
*es
, int action
)
1001 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1002 input_thread_t
*p_input
= p_sys
->p_input
;
1004 if (action
== VLC_INPUT_ES_ADDED
)
1006 input_thread_private_t
*priv
= input_priv(p_input
);
1007 /*FIXME: see input_SlaveSourceAdd */
1008 priv
->i_last_es_id
= es
->fmt
.i_id
;
1009 priv
->i_last_es_cat
= es
->fmt
.i_cat
;
1011 input_SendEventEs(p_input
, &(struct vlc_input_event_es
) {
1014 .title
= es
->psz_title
? es
->psz_title
: "",
1015 .fmt
= es
->fmt_out
.i_cat
!= UNKNOWN_ES
? &es
->fmt_out
: &es
->fmt
,
1019 static bool EsOutIsProgramVisible( es_out_t
*out
, int i_group
)
1021 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1022 return p_sys
->i_group_id
== 0 || p_sys
->i_group_id
== i_group
;
1025 /* EsOutProgramSelect:
1026 * Select a program and update the object variable
1028 static void EsOutProgramSelect( es_out_t
*out
, es_out_pgrm_t
*p_pgrm
)
1030 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1031 input_thread_t
*p_input
= p_sys
->p_input
;
1034 if( p_sys
->p_pgrm
== p_pgrm
)
1035 return; /* Nothing to do */
1039 es_out_pgrm_t
*old
= p_sys
->p_pgrm
;
1041 msg_Dbg( p_input
, "unselecting program id=%d", old
->i_id
);
1043 foreach_es_then_es_slaves(es
)
1045 if (es
->p_pgrm
== old
&& EsIsSelected(es
)
1046 && p_sys
->i_mode
!= ES_OUT_MODE_ALL
)
1047 EsOutUnselectEs(out
, es
, true);
1048 if (es
->p_pgrm
== old
)
1049 EsOutSendEsEvent( out
, es
, VLC_INPUT_ES_DELETED
);
1052 p_sys
->audio
.p_main_es
= NULL
;
1053 p_sys
->video
.p_main_es
= NULL
;
1054 p_sys
->sub
.p_main_es
= NULL
;
1057 msg_Dbg( p_input
, "selecting program id=%d", p_pgrm
->i_id
);
1059 /* Mark it selected */
1060 p_pgrm
->b_selected
= true;
1062 /* Switch master stream */
1063 p_sys
->p_pgrm
= p_pgrm
;
1065 /* Update "program" */
1066 input_SendEventProgramSelect( p_input
, p_pgrm
->i_id
);
1069 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, p_pgrm
->b_scrambled
);
1071 foreach_es_then_es_slaves(es
)
1073 if (es
->p_pgrm
== p_sys
->p_pgrm
)
1075 EsOutSendEsEvent(out
, es
, VLC_INPUT_ES_ADDED
);
1076 EsOutUpdateInfo(out
, es
, NULL
);
1079 EsOutSelect(out
, es
, false);
1082 /* Ensure the correct running EPG table is selected */
1083 input_item_ChangeEPGSource( input_priv(p_input
)->p_item
, p_pgrm
->i_id
);
1085 /* Update now playing */
1086 if( p_pgrm
->p_meta
)
1088 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
,
1089 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) );
1090 input_item_SetPublisher( input_priv(p_input
)->p_item
,
1091 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Publisher
) );
1092 input_item_SetTitle( input_priv(p_input
)->p_item
,
1093 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1094 input_SendEventMeta( p_input
);
1095 /* FIXME: we probably want to replace every input meta */
1102 static es_out_pgrm_t
*EsOutProgramAdd( es_out_t
*out
, int i_group
)
1104 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1105 input_thread_t
*p_input
= p_sys
->p_input
;
1107 es_out_pgrm_t
*p_pgrm
= malloc( sizeof( es_out_pgrm_t
) );
1112 p_pgrm
->i_id
= i_group
;
1114 p_pgrm
->b_selected
= false;
1115 p_pgrm
->b_scrambled
= false;
1116 p_pgrm
->p_meta
= NULL
;
1117 p_pgrm
->p_input_clock
= input_clock_New( p_sys
->i_rate
);
1118 if( !p_pgrm
->p_input_clock
)
1123 if( p_sys
->b_paused
)
1124 input_clock_ChangePause( p_pgrm
->p_input_clock
, p_sys
->b_paused
, p_sys
->i_pause_date
);
1125 input_clock_SetJitter( p_pgrm
->p_input_clock
, p_sys
->i_pts_delay
, p_sys
->i_cr_average
);
1128 vlc_list_append(&p_pgrm
->node
, &p_sys
->programs
);
1130 /* Update "program" variable */
1131 if( EsOutIsProgramVisible( out
, i_group
) )
1132 input_SendEventProgramAdd( p_input
, i_group
, NULL
);
1134 if( i_group
== p_sys
->i_group_id
|| ( !p_sys
->p_pgrm
&& p_sys
->i_group_id
== 0 ) )
1135 EsOutProgramSelect( out
, p_pgrm
);
1143 static int EsOutProgramDel( es_out_t
*out
, int i_group
)
1145 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1146 input_thread_t
*p_input
= p_sys
->p_input
;
1147 es_out_pgrm_t
*p_pgrm
= NULL
, *pgrm
;
1149 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
1150 if (pgrm
->i_id
== i_group
)
1156 if( p_pgrm
== NULL
)
1157 return VLC_EGENERIC
;
1161 msg_Dbg( p_input
, "can't delete program %d which still has %i ES",
1162 i_group
, p_pgrm
->i_es
);
1163 return VLC_EGENERIC
;
1166 vlc_list_remove(&p_pgrm
->node
);
1168 /* If program is selected we need to unselect it */
1169 if( p_sys
->p_pgrm
== p_pgrm
)
1170 p_sys
->p_pgrm
= NULL
;
1172 input_clock_Delete( p_pgrm
->p_input_clock
);
1174 if( p_pgrm
->p_meta
)
1175 vlc_meta_Delete( p_pgrm
->p_meta
);
1178 /* Update "program" variable */
1179 input_SendEventProgramDel( p_input
, i_group
);
1186 static es_out_pgrm_t
*EsOutProgramFind( es_out_t
*p_out
, int i_group
)
1188 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1189 es_out_pgrm_t
*pgrm
;
1191 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
1192 if (pgrm
->i_id
== i_group
)
1195 return EsOutProgramAdd( p_out
, i_group
);
1198 /* EsOutProgramMeta:
1200 static char *EsOutProgramGetMetaName( es_out_pgrm_t
*p_pgrm
)
1203 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1205 if( asprintf( &psz
, _("%s [%s %d]"), vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
),
1206 _("Program"), p_pgrm
->i_id
) == -1 )
1211 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1217 static char *EsOutProgramGetProgramName( es_out_pgrm_t
*p_pgrm
)
1220 if( p_pgrm
->p_meta
&& vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) )
1222 return strdup( vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
) );
1226 if( asprintf( &psz
, "%s %d", _("Program"), p_pgrm
->i_id
) == -1 )
1232 static char *EsInfoCategoryName( es_out_id_t
* es
)
1236 if( asprintf( &psz_category
, _("Stream %d"), es
->i_meta_id
) == -1 )
1239 return psz_category
;
1242 static void EsOutProgramMeta( es_out_t
*out
, int i_group
, const vlc_meta_t
*p_meta
)
1244 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1245 es_out_pgrm_t
*p_pgrm
;
1246 input_thread_t
*p_input
= p_sys
->p_input
;
1247 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1248 const char *psz_title
= NULL
;
1249 const char *psz_provider
= NULL
;
1251 bool b_has_new_infos
= false;
1253 msg_Dbg( p_input
, "EsOutProgramMeta: number=%d", i_group
);
1255 /* Check against empty meta data (empty for what we handle) */
1256 if( !vlc_meta_Get( p_meta
, vlc_meta_Title
) &&
1257 !vlc_meta_Get( p_meta
, vlc_meta_ESNowPlaying
) &&
1258 !vlc_meta_Get( p_meta
, vlc_meta_Publisher
) )
1265 EsOutGlobalMeta( out
, p_meta
);
1270 if( !EsOutIsProgramVisible( out
, i_group
) )
1272 p_pgrm
= EsOutProgramFind( out
, i_group
);
1276 if( p_pgrm
->p_meta
)
1278 const char *psz_current_title
= vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_Title
);
1279 const char *psz_new_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1280 if( (psz_current_title
!= NULL
&& psz_new_title
!= NULL
)
1281 ? strcmp(psz_new_title
, psz_current_title
)
1282 : (psz_current_title
!= psz_new_title
) )
1284 /* Remove old entries */
1285 char *psz_oldinfokey
= EsOutProgramGetMetaName( p_pgrm
);
1287 if( !input_item_DelInfo( p_item
, psz_oldinfokey
, NULL
) )
1288 b_has_new_infos
= true;
1289 /* TODO update epg name ?
1290 * TODO update scrambled info name ? */
1291 free( psz_oldinfokey
);
1293 vlc_meta_Delete( p_pgrm
->p_meta
);
1295 p_pgrm
->p_meta
= vlc_meta_New();
1296 if( p_pgrm
->p_meta
)
1297 vlc_meta_Merge( p_pgrm
->p_meta
, p_meta
);
1299 if( p_sys
->p_pgrm
== p_pgrm
)
1301 EsOutMeta( out
, NULL
, p_meta
);
1304 psz_title
= vlc_meta_Get( p_meta
, vlc_meta_Title
);
1305 psz_provider
= vlc_meta_Get( p_meta
, vlc_meta_Publisher
);
1307 /* Update the description text of the program */
1308 if( psz_title
&& *psz_title
)
1311 if( psz_provider
&& *psz_provider
)
1313 if( asprintf( &psz_text
, "%s [%s]", psz_title
, psz_provider
) < 0 )
1318 psz_text
= strdup( psz_title
);
1323 input_SendEventProgramUpdated( p_input
, i_group
, psz_text
);
1324 if( p_sys
->p_pgrm
== p_pgrm
)
1325 input_SendEventProgramSelect( p_input
, i_group
);
1331 char **ppsz_all_keys
= vlc_meta_CopyExtraNames(p_meta
);
1333 info_category_t
*p_cat
= NULL
;
1334 if( psz_provider
|| ( ppsz_all_keys
[0] && *ppsz_all_keys
[0] ) )
1336 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1338 p_cat
= info_category_New( psz_cat
);
1342 for( i
= 0; ppsz_all_keys
[i
]; i
++ )
1345 info_category_AddInfo( p_cat
, vlc_gettext(ppsz_all_keys
[i
]), "%s",
1346 vlc_meta_GetExtra( p_meta
, ppsz_all_keys
[i
] ) );
1347 free( ppsz_all_keys
[i
] );
1349 free( ppsz_all_keys
);
1353 if( p_sys
->p_pgrm
== p_pgrm
)
1355 input_item_SetPublisher( input_priv(p_input
)->p_item
, psz_provider
);
1356 input_SendEventMeta( p_input
);
1359 info_category_AddInfo( p_cat
, vlc_meta_TypeToLocalizedString(vlc_meta_Publisher
),
1360 "%s",psz_provider
);
1364 input_item_MergeInfos( p_item
, p_cat
);
1365 b_has_new_infos
= true;
1367 if( !input_priv(p_input
)->b_preparsing
&& b_has_new_infos
)
1368 input_SendEventMetaInfo( p_input
);
1371 static void EsOutProgramEpgEvent( es_out_t
*out
, int i_group
, const vlc_epg_event_t
*p_event
)
1373 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1374 input_thread_t
*p_input
= p_sys
->p_input
;
1375 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1376 es_out_pgrm_t
*p_pgrm
;
1379 if( !EsOutIsProgramVisible( out
, i_group
) )
1381 p_pgrm
= EsOutProgramFind( out
, i_group
);
1385 input_item_SetEpgEvent( p_item
, p_event
);
1388 static void EsOutProgramEpg( es_out_t
*out
, int i_group
, const vlc_epg_t
*p_epg
)
1390 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1391 input_thread_t
*p_input
= p_sys
->p_input
;
1392 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1393 es_out_pgrm_t
*p_pgrm
;
1397 if( !EsOutIsProgramVisible( out
, i_group
) )
1399 p_pgrm
= EsOutProgramFind( out
, i_group
);
1404 psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1405 msg_Dbg( p_input
, "EsOutProgramEpg: number=%d name=%s", i_group
, psz_cat
);
1411 epg
.psz_name
= EsOutProgramGetProgramName( p_pgrm
);
1413 input_item_SetEpg( p_item
, &epg
, p_sys
->p_pgrm
&& (p_epg
->i_source_id
== p_sys
->p_pgrm
->i_id
) );
1414 input_SendEventMetaEpg( p_sys
->p_input
);
1416 free( epg
.psz_name
);
1418 /* Update now playing */
1419 if( p_epg
->b_present
&& p_pgrm
->p_meta
&&
1420 ( p_epg
->p_current
|| p_epg
->i_event
== 0 ) )
1422 vlc_meta_SetNowPlaying( p_pgrm
->p_meta
, NULL
);
1425 vlc_mutex_lock( &p_item
->lock
);
1426 for( int i
= 0; i
< p_item
->i_epg
; i
++ )
1428 const vlc_epg_t
*p_tmp
= p_item
->pp_epg
[i
];
1430 if( p_tmp
->b_present
&& p_tmp
->i_source_id
== p_pgrm
->i_id
)
1432 const char *psz_name
= ( p_tmp
->p_current
) ? p_tmp
->p_current
->psz_name
: NULL
;
1433 if( !p_pgrm
->p_meta
)
1434 p_pgrm
->p_meta
= vlc_meta_New();
1435 if( p_pgrm
->p_meta
)
1436 vlc_meta_Set( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
, psz_name
);
1440 vlc_mutex_unlock( &p_item
->lock
);
1442 /* Update selected program input info */
1443 if( p_pgrm
== p_sys
->p_pgrm
)
1445 const char *psz_nowplaying
= p_pgrm
->p_meta
?
1446 vlc_meta_Get( p_pgrm
->p_meta
, vlc_meta_ESNowPlaying
) : NULL
;
1448 input_item_SetESNowPlaying( input_priv(p_input
)->p_item
, psz_nowplaying
);
1449 input_SendEventMeta( p_input
);
1451 const char *now_playing_tr
=
1452 vlc_meta_TypeToLocalizedString(vlc_meta_ESNowPlaying
);
1454 if( psz_nowplaying
)
1455 ret
= input_item_AddInfo( p_item
, psz_cat
, now_playing_tr
,
1456 "%s", psz_nowplaying
);
1458 ret
= input_item_DelInfo( p_item
, psz_cat
, now_playing_tr
);
1460 if( ret
== VLC_SUCCESS
&& !input_priv(p_input
)->b_preparsing
)
1461 input_SendEventMetaInfo( p_input
);
1467 static void EsOutEpgTime( es_out_t
*out
, int64_t time
)
1469 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1470 input_thread_t
*p_input
= p_sys
->p_input
;
1471 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1473 input_item_SetEpgTime( p_item
, time
);
1476 static void EsOutProgramUpdateScrambled( es_out_t
*p_out
, es_out_pgrm_t
*p_pgrm
)
1478 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1479 input_thread_t
*p_input
= p_sys
->p_input
;
1480 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
1482 bool b_scrambled
= false;
1484 vlc_list_foreach( es
, &p_sys
->es
, node
) /* Only master es */
1485 if (es
->p_pgrm
== p_pgrm
&& es
->b_scrambled
)
1491 if( !p_pgrm
->b_scrambled
== !b_scrambled
)
1494 p_pgrm
->b_scrambled
= b_scrambled
;
1495 char *psz_cat
= EsOutProgramGetMetaName( p_pgrm
);
1499 ret
= input_item_AddInfo( p_item
, psz_cat
, _("Scrambled"), _("Yes") );
1501 ret
= input_item_DelInfo( p_item
, psz_cat
, _("Scrambled") );
1504 if( ret
== VLC_SUCCESS
&& !input_priv(p_input
)->b_preparsing
)
1505 input_SendEventMetaInfo( p_input
);
1506 input_SendEventProgramScrambled( p_input
, p_pgrm
->i_id
, b_scrambled
);
1509 static void EsOutMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
, const vlc_meta_t
*p_program_meta
)
1511 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1512 input_thread_t
*p_input
= p_sys
->p_input
;
1513 input_item_t
*p_item
= input_GetItem( p_input
);
1515 vlc_mutex_lock( &p_item
->lock
);
1517 vlc_meta_Merge( p_item
->p_meta
, p_meta
);
1518 vlc_mutex_unlock( &p_item
->lock
);
1520 /* Check program meta to not override GROUP_META values */
1521 if( p_meta
&& (!p_program_meta
|| vlc_meta_Get( p_program_meta
, vlc_meta_Title
) == NULL
) &&
1522 vlc_meta_Get( p_meta
, vlc_meta_Title
) != NULL
)
1523 input_item_SetName( p_item
, vlc_meta_Get( p_meta
, vlc_meta_Title
) );
1525 const char *psz_arturl
= NULL
;
1526 char *psz_alloc
= NULL
;
1528 if( p_program_meta
)
1529 psz_arturl
= vlc_meta_Get( p_program_meta
, vlc_meta_ArtworkURL
);
1530 if( psz_arturl
== NULL
&& p_meta
)
1531 psz_arturl
= vlc_meta_Get( p_meta
, vlc_meta_ArtworkURL
);
1533 if( psz_arturl
== NULL
) /* restore/favor previously set item art URL */
1534 psz_arturl
= psz_alloc
= input_item_GetArtURL( p_item
);
1536 if( psz_arturl
!= NULL
)
1537 input_item_SetArtURL( p_item
, psz_arturl
);
1539 if( psz_arturl
!= NULL
&& !strncmp( psz_arturl
, "attachment://", 13 ) )
1540 { /* Clear art cover if streaming out.
1541 * FIXME: Why? Remove this when sout gets meta data support. */
1542 if( input_priv(p_input
)->p_sout
!= NULL
)
1543 input_item_SetArtURL( p_item
, NULL
);
1545 input_ExtractAttachmentAndCacheArt( p_input
, psz_arturl
+ 13 );
1549 input_item_SetPreparsed( p_item
, true );
1551 input_SendEventMeta( p_input
);
1552 /* TODO handle sout meta ? */
1555 static void EsOutGlobalMeta( es_out_t
*p_out
, const vlc_meta_t
*p_meta
)
1557 es_out_sys_t
*p_sys
= container_of(p_out
, es_out_sys_t
, out
);
1558 EsOutMeta( p_out
, p_meta
,
1559 (p_sys
->p_pgrm
&& p_sys
->p_pgrm
->p_meta
) ? p_sys
->p_pgrm
->p_meta
: NULL
);
1562 static void EsOutUpdateEsLanguageTitle(es_out_id_t
*es
,
1563 const es_format_t
*fmt
)
1565 free( es
->psz_title
);
1566 free( es
->psz_language
);
1567 free( es
->psz_language_code
);
1569 es
->psz_language
= LanguageGetName( fmt
->psz_language
);
1570 es
->psz_language_code
= LanguageGetCode( fmt
->psz_language
);
1572 es
->psz_title
= EsGetTitle(es
);
1575 static void EsOutFillEsFmt(es_out_t
*out
, es_format_t
*fmt
)
1577 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1578 input_thread_t
*p_input
= p_sys
->p_input
;
1580 switch( fmt
->i_cat
)
1584 fmt
->i_codec
= vlc_fourcc_GetCodecAudio( fmt
->i_codec
,
1585 fmt
->audio
.i_bitspersample
);
1586 audio_replay_gain_t rg
;
1587 memset( &rg
, 0, sizeof(rg
) );
1588 vlc_mutex_lock( &input_priv(p_input
)->p_item
->lock
);
1589 vlc_audio_replay_gain_MergeFromMeta( &rg
, input_priv(p_input
)->p_item
->p_meta
);
1590 vlc_mutex_unlock( &input_priv(p_input
)->p_item
->lock
);
1592 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
1594 if( !fmt
->audio_replay_gain
.pb_peak
[i
] )
1596 fmt
->audio_replay_gain
.pb_peak
[i
] = rg
.pb_peak
[i
];
1597 fmt
->audio_replay_gain
.pf_peak
[i
] = rg
.pf_peak
[i
];
1599 if( !fmt
->audio_replay_gain
.pb_gain
[i
] )
1601 fmt
->audio_replay_gain
.pb_gain
[i
] = rg
.pb_gain
[i
];
1602 fmt
->audio_replay_gain
.pf_gain
[i
] = rg
.pf_gain
[i
];
1609 fmt
->i_codec
= vlc_fourcc_GetCodec( fmt
->i_cat
, fmt
->i_codec
);
1611 if( !fmt
->video
.i_visible_width
|| !fmt
->video
.i_visible_height
)
1613 fmt
->video
.i_visible_width
= fmt
->video
.i_width
;
1614 fmt
->video
.i_visible_height
= fmt
->video
.i_height
;
1617 if( fmt
->video
.i_frame_rate
&& fmt
->video
.i_frame_rate_base
)
1618 vlc_ureduce( &fmt
->video
.i_frame_rate
,
1619 &fmt
->video
.i_frame_rate_base
,
1620 fmt
->video
.i_frame_rate
,
1621 fmt
->video
.i_frame_rate_base
, 0 );
1625 fmt
->i_codec
= vlc_fourcc_GetCodec( fmt
->i_cat
, fmt
->i_codec
);
1633 static es_out_id_t
*EsOutAddSlaveLocked( es_out_t
*out
, const es_format_t
*fmt
,
1634 es_out_id_t
*p_master
)
1636 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1637 input_thread_t
*p_input
= p_sys
->p_input
;
1639 if( fmt
->i_group
< 0 )
1641 msg_Err( p_input
, "invalid group number" );
1645 es_out_id_t
*es
= malloc( sizeof( *es
) );
1646 es_out_pgrm_t
*p_pgrm
;
1651 if( es_format_Copy( &es
->fmt
, fmt
) != VLC_SUCCESS
)
1656 if( es
->fmt
.i_id
< 0 )
1657 es
->fmt
.i_id
= p_sys
->i_id
;
1658 if( !es
->fmt
.i_original_fourcc
)
1659 es
->fmt
.i_original_fourcc
= es
->fmt
.i_codec
;
1661 /* Search the program */
1662 p_pgrm
= EsOutProgramFind( out
, fmt
->i_group
);
1665 es_format_Clean( &es
->fmt
);
1670 /* Get the number of ES already added in order to get the position of the es */
1673 foreach_es_then_es_slaves(it
)
1674 if( it
->fmt
.i_cat
== fmt
->i_cat
&& it
->fmt
.i_group
== fmt
->i_group
)
1677 /* Increase ref count for program */
1681 es
->p_pgrm
= p_pgrm
;
1683 es
->id
.i_id
= es
->fmt
.i_id
;
1684 es
->id
.i_cat
= es
->fmt
.i_cat
;
1686 es_format_Init( &es
->fmt_out
, UNKNOWN_ES
, 0 );
1688 es
->i_meta_id
= p_sys
->i_id
++; /* always incremented */
1689 es
->b_scrambled
= false;
1690 es
->b_forced
= false;
1691 es
->b_terminated
= false;
1693 switch( es
->fmt
.i_cat
)
1696 es
->i_channel
= p_sys
->audio
.i_count
++;
1700 es
->i_channel
= p_sys
->video
.i_count
++;
1704 es
->i_channel
= p_sys
->sub
.i_count
++;
1711 EsOutFillEsFmt( out
, &es
->fmt
);
1712 es
->psz_language
= LanguageGetName( es
->fmt
.psz_language
); /* remember so we only need to do it once */
1713 es
->psz_language_code
= LanguageGetCode( es
->fmt
.psz_language
);
1714 es
->psz_title
= EsGetTitle(es
);
1716 es
->p_dec_record
= NULL
;
1718 es
->cc
.i_bitmap
= 0;
1719 es
->p_master
= p_master
;
1720 es
->mouse_event_cb
= NULL
;
1721 es
->mouse_event_userdata
= NULL
;
1723 vlc_list_append(&es
->node
, es
->p_master
? &p_sys
->es_slaves
: &p_sys
->es
);
1725 vlc_atomic_rc_init(&es
->rc
);
1727 if( es
->p_pgrm
== p_sys
->p_pgrm
)
1728 EsOutSendEsEvent( out
, es
, VLC_INPUT_ES_ADDED
);
1730 EsOutUpdateInfo( out
, es
, NULL
);
1731 EsOutSelect( out
, es
, false );
1733 if( es
->b_scrambled
)
1734 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
1742 static es_out_id_t
*EsOutAdd( es_out_t
*out
, const es_format_t
*fmt
)
1744 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1745 vlc_mutex_lock( &p_sys
->lock
);
1746 es_out_id_t
*es
= EsOutAddSlaveLocked( out
, fmt
, NULL
);
1747 vlc_mutex_unlock( &p_sys
->lock
);
1751 static bool EsIsSelected( es_out_id_t
*es
)
1755 bool b_decode
= false;
1756 if( es
->p_master
->p_dec
)
1758 int i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1759 input_DecoderGetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1760 i_channel
, &b_decode
);
1766 return es
->p_dec
!= NULL
;
1769 static void EsOutCreateDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1771 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1772 input_thread_t
*p_input
= p_sys
->p_input
;
1775 dec
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_input_clock
,
1776 input_priv(p_input
)->p_sout
);
1779 float rate
= (float)p_sys
->i_rate
/ (float)INPUT_RATE_DEFAULT
;
1781 input_DecoderChangeRate( dec
, rate
);
1783 if( p_sys
->b_buffering
)
1784 input_DecoderStartWait( dec
);
1786 if( !p_es
->p_master
&& p_sys
->p_sout_record
)
1788 p_es
->p_dec_record
= input_DecoderNew( p_input
, &p_es
->fmt
, p_es
->p_pgrm
->p_input_clock
, p_sys
->p_sout_record
);
1789 if( p_es
->p_dec_record
&& p_sys
->b_buffering
)
1790 input_DecoderStartWait( p_es
->p_dec_record
);
1793 if( p_es
->mouse_event_cb
&& p_es
->fmt
.i_cat
== VIDEO_ES
)
1794 input_DecoderSetVoutMouseEvent( dec
, p_es
->mouse_event_cb
,
1795 p_es
->mouse_event_userdata
);
1799 EsOutDecoderChangeDelay( out
, p_es
);
1801 static void EsOutDestroyDecoder( es_out_t
*out
, es_out_id_t
*p_es
)
1808 input_DecoderDelete( p_es
->p_dec
);
1811 if( p_es
->p_dec_record
)
1813 input_DecoderDelete( p_es
->p_dec_record
);
1814 p_es
->p_dec_record
= NULL
;
1817 es_format_Clean( &p_es
->fmt_out
);
1820 static void EsOutSelectEs( es_out_t
*out
, es_out_id_t
*es
)
1822 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1823 input_thread_t
*p_input
= p_sys
->p_input
;
1824 bool b_thumbnailing
= input_priv(p_input
)->b_thumbnailing
;
1826 if( EsIsSelected( es
) )
1828 msg_Warn( p_input
, "ES 0x%x is already selected", es
->fmt
.i_id
);
1835 if( !es
->p_master
->p_dec
)
1838 i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1840 if( i_channel
== -1 ||
1841 input_DecoderSetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1847 const bool b_sout
= input_priv(p_input
)->p_sout
!= NULL
;
1848 /* If b_forced, the ES is specifically requested by the user, so bypass
1849 * the following vars check. */
1852 if( es
->fmt
.i_cat
== VIDEO_ES
|| es
->fmt
.i_cat
== SPU_ES
)
1854 if( !var_GetBool( p_input
, b_sout
? "sout-video" : "video" ) )
1856 msg_Dbg( p_input
, "video is disabled, not selecting ES 0x%x",
1861 else if( es
->fmt
.i_cat
== AUDIO_ES
)
1863 if( !var_GetBool( p_input
, b_sout
? "sout-audio" : "audio" ) || b_thumbnailing
)
1865 msg_Dbg( p_input
, "audio is disabled, not selecting ES 0x%x",
1870 if( es
->fmt
.i_cat
== SPU_ES
)
1872 if( !var_GetBool( p_input
, b_sout
? "sout-spu" : "spu" ) || b_thumbnailing
)
1874 msg_Dbg( p_input
, "spu is disabled, not selecting ES 0x%x",
1881 EsOutCreateDecoder( out
, es
);
1883 if( es
->p_dec
== NULL
|| es
->p_pgrm
!= p_sys
->p_pgrm
)
1887 /* Mark it as selected */
1888 EsOutSendEsEvent(out
, es
, VLC_INPUT_ES_SELECTED
);
1890 /* Special case of the zvbi decoder for teletext: send the initial selected
1891 * page and transparency */
1892 if( !es
->p_master
&& es
->fmt
.i_cat
== SPU_ES
1893 && es
->fmt
.i_codec
== VLC_CODEC_TELETEXT
1894 && var_Type( es
->p_dec
, "vbi-page" ) == VLC_VAR_INTEGER
)
1896 input_SendEventVbiPage( p_input
,
1897 var_GetInteger( es
->p_dec
, "vbi-page" ) );
1898 input_SendEventVbiTransparency( p_input
,
1899 var_GetBool( es
->p_dec
, "vbi-opaque" ) );
1903 static void EsOutDrainCCChannels( es_out_id_t
*parent
)
1905 /* Drain captions sub ES as well */
1906 uint64_t i_bitmap
= parent
->cc
.i_bitmap
;
1907 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1 )
1909 if( (i_bitmap
& 1) == 0 || !parent
->cc
.pp_es
[i
] ||
1910 !parent
->cc
.pp_es
[i
]->p_dec
)
1912 input_DecoderDrain( parent
->cc
.pp_es
[i
]->p_dec
);
1916 static void EsDeleteCCChannels( es_out_t
*out
, es_out_id_t
*parent
)
1918 if( parent
->cc
.type
== 0 )
1921 es_out_id_t
*spu_es
= EsOutGetSelectedCat( out
, SPU_ES
);
1922 const int i_spu_id
= spu_es
? spu_es
->fmt
.i_id
: -1;
1924 uint64_t i_bitmap
= parent
->cc
.i_bitmap
;
1925 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1 )
1927 if( (i_bitmap
& 1) == 0 || !parent
->cc
.pp_es
[i
] )
1930 if( i_spu_id
== parent
->cc
.pp_es
[i
]->fmt
.i_id
)
1932 /* Force unselection of the CC */
1933 EsOutSendEsEvent(out
, parent
->cc
.pp_es
[i
], VLC_INPUT_ES_UNSELECTED
);
1935 EsOutDelLocked( out
, parent
->cc
.pp_es
[i
] );
1938 parent
->cc
.i_bitmap
= 0;
1939 parent
->cc
.type
= 0;
1942 static void EsOutUnselectEs( es_out_t
*out
, es_out_id_t
*es
, bool b_update
)
1944 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1945 input_thread_t
*p_input
= p_sys
->p_input
;
1947 if( !EsIsSelected( es
) )
1949 msg_Warn( p_input
, "ES 0x%x is already unselected", es
->fmt
.i_id
);
1955 if( es
->p_master
->p_dec
)
1957 int i_channel
= EsOutGetClosedCaptionsChannel( &es
->fmt
);
1958 if( i_channel
!= -1 )
1959 input_DecoderSetCcState( es
->p_master
->p_dec
, es
->fmt
.i_codec
,
1965 EsDeleteCCChannels( out
, es
);
1966 EsOutDestroyDecoder( out
, es
);
1972 /* Mark it as unselected */
1973 EsOutSendEsEvent(out
, es
, VLC_INPUT_ES_UNSELECTED
);
1977 * Select an ES given the current mode
1978 * XXX: you need to take a the lock before (stream.stream_lock)
1980 * \param out The es_out structure
1981 * \param es es_out_id structure
1982 * \param b_force ...
1985 static void EsOutSelect( es_out_t
*out
, es_out_id_t
*es
, bool b_force
)
1987 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
1988 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
1990 if( !p_sys
->b_active
||
1991 ( !b_force
&& es
->fmt
.i_priority
< ES_PRIORITY_SELECTABLE_MIN
) )
1996 bool b_auto_unselect
= p_esprops
&& p_sys
->i_mode
== ES_OUT_MODE_AUTO
&&
1997 p_esprops
->e_policy
== ES_OUT_ES_POLICY_EXCLUSIVE
&&
1998 p_esprops
->p_main_es
&& p_esprops
->p_main_es
!= es
;
2000 if( p_sys
->i_mode
== ES_OUT_MODE_ALL
|| b_force
)
2002 if( !EsIsSelected( es
) )
2004 if( b_auto_unselect
)
2005 EsOutUnselectEs( out
, p_esprops
->p_main_es
, true );
2007 EsOutSelectEs( out
, es
);
2010 else if( p_sys
->i_mode
== ES_OUT_MODE_PARTIAL
)
2012 char *prgms
= var_GetNonEmptyString( p_sys
->p_input
, "programs" );
2017 for ( const char *prgm
= strtok_r( prgms
, ",", &buf
);
2019 prgm
= strtok_r( NULL
, ",", &buf
) )
2021 if( atoi( prgm
) == es
->p_pgrm
->i_id
|| b_force
)
2023 if( !EsIsSelected( es
) )
2024 EsOutSelectEs( out
, es
);
2031 else if( p_sys
->i_mode
== ES_OUT_MODE_AUTO
)
2033 const es_out_id_t
*wanted_es
= NULL
;
2035 if( es
->p_pgrm
!= p_sys
->p_pgrm
|| !p_esprops
)
2038 /* user designated by ID ES have higher prio than everything */
2039 if ( p_esprops
->i_id
>= 0 )
2041 if( es
->fmt
.i_id
== p_esprops
->i_id
)
2045 else if( p_esprops
->i_channel
>= 0 )
2047 if( p_esprops
->i_channel
== es
->i_channel
)
2050 else if( p_esprops
->ppsz_language
)
2052 /* If not deactivated */
2053 const int i_stop_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
, "none" );
2055 int current_es_idx
= ( p_esprops
->p_main_es
== NULL
) ? -1 :
2056 LanguageArrayIndex( p_esprops
->ppsz_language
,
2057 p_esprops
->p_main_es
->psz_language_code
);
2058 int es_idx
= LanguageArrayIndex( p_esprops
->ppsz_language
,
2059 es
->psz_language_code
);
2060 if( es_idx
>= 0 && (i_stop_idx
< 0 || i_stop_idx
> es_idx
) )
2062 /* Only select the language if it's in the list */
2063 if( p_esprops
->p_main_es
== NULL
||
2064 current_es_idx
< 0 || /* current es was not selected by lang prefs */
2065 es_idx
< current_es_idx
|| /* current es has lower lang prio */
2066 ( es_idx
== current_es_idx
&& /* lang is same, but es has higher prio */
2067 p_esprops
->p_main_es
->fmt
.i_priority
< es
->fmt
.i_priority
) )
2072 /* We did not find a language matching our prefs */
2073 else if( i_stop_idx
< 0 ) /* If not fallback disabled by 'none' */
2075 /* Select if asked by demuxer */
2076 if( current_es_idx
< 0 ) /* No es is currently selected by lang pref */
2078 /* If demux has specified a track */
2079 if( p_esprops
->i_demux_id
>= 0 && es
->fmt
.i_id
== p_esprops
->i_demux_id
)
2083 /* Otherwise, fallback by priority */
2084 else if( p_esprops
->p_main_es
== NULL
||
2085 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
2087 if( p_esprops
->b_autoselect
)
2095 /* If there is no user preference, select the default subtitle
2096 * or adapt by ES priority */
2097 else if( p_esprops
->i_demux_id
>= 0 && es
->fmt
.i_id
== p_esprops
->i_demux_id
)
2101 else if( p_esprops
->p_main_es
== NULL
||
2102 es
->fmt
.i_priority
> p_esprops
->p_main_es
->fmt
.i_priority
)
2104 if( p_esprops
->b_autoselect
)
2108 if( wanted_es
== es
&& !EsIsSelected( es
) )
2110 if( b_auto_unselect
)
2111 EsOutUnselectEs( out
, p_esprops
->p_main_es
, true );
2113 EsOutSelectEs( out
, es
);
2117 /* FIXME TODO handle priority here */
2118 if( p_esprops
&& p_sys
->i_mode
== ES_OUT_MODE_AUTO
&& EsIsSelected( es
) )
2119 p_esprops
->p_main_es
= es
;
2122 static void EsOutCreateCCChannels( es_out_t
*out
, vlc_fourcc_t codec
, uint64_t i_bitmap
,
2123 const char *psz_descfmt
, es_out_id_t
*parent
)
2125 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2126 input_thread_t
*p_input
= p_sys
->p_input
;
2128 /* Only one type of captions is allowed ! */
2129 if( parent
->cc
.type
&& parent
->cc
.type
!= codec
)
2132 uint64_t i_existingbitmap
= parent
->cc
.i_bitmap
;
2133 for( int i
= 0; i_bitmap
> 0; i
++, i_bitmap
>>= 1, i_existingbitmap
>>= 1 )
2137 if( (i_bitmap
& 1) == 0 || (i_existingbitmap
& 1) )
2140 msg_Dbg( p_input
, "Adding CC track %d for es[%d]", 1+i
, parent
->fmt
.i_id
);
2142 es_format_Init( &fmt
, SPU_ES
, codec
);
2143 fmt
.subs
.cc
.i_channel
= i
;
2144 fmt
.i_group
= parent
->fmt
.i_group
;
2145 if( asprintf( &fmt
.psz_description
, psz_descfmt
, 1 + i
) == -1 )
2146 fmt
.psz_description
= NULL
;
2148 es_out_id_t
**pp_es
= &parent
->cc
.pp_es
[i
];
2149 *pp_es
= EsOutAddSlaveLocked( out
, &fmt
, parent
);
2150 es_format_Clean( &fmt
);
2153 parent
->cc
.i_bitmap
|= (1ULL << i
);
2154 parent
->cc
.type
= codec
;
2156 /* Enable if user specified on command line */
2157 if (p_sys
->sub
.i_channel
== i
)
2158 EsOutSelect(out
, *pp_es
, true);
2163 * Send a block for the given es_out
2165 * \param out the es_out to send from
2166 * \param es the es_out_id
2167 * \param p_block the data block to send
2169 static int EsOutSend( es_out_t
*out
, es_out_id_t
*es
, block_t
*p_block
)
2171 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2172 input_thread_t
*p_input
= p_sys
->p_input
;
2174 assert( p_block
->p_next
== NULL
);
2176 struct input_stats
*stats
= input_priv(p_input
)->stats
;
2179 input_rate_Add( &stats
->demux_bitrate
, p_block
->i_buffer
);
2181 /* Update number of corrupted data packats */
2182 if( p_block
->i_flags
& BLOCK_FLAG_CORRUPTED
)
2183 atomic_fetch_add_explicit(&stats
->demux_corrupted
, 1,
2184 memory_order_relaxed
);
2186 /* Update number of discontinuities */
2187 if( p_block
->i_flags
& BLOCK_FLAG_DISCONTINUITY
)
2188 atomic_fetch_add_explicit(&stats
->demux_discontinuity
, 1,
2189 memory_order_relaxed
);
2192 vlc_mutex_lock( &p_sys
->lock
);
2194 /* Mark preroll blocks */
2195 if( p_sys
->i_preroll_end
>= 0 )
2197 vlc_tick_t i_date
= p_block
->i_pts
;
2198 if( p_block
->i_pts
== VLC_TICK_INVALID
)
2199 i_date
= p_block
->i_dts
;
2201 if( i_date
+ p_block
->i_length
< p_sys
->i_preroll_end
)
2202 p_block
->i_flags
|= BLOCK_FLAG_PREROLL
;
2207 block_Release( p_block
);
2208 vlc_mutex_unlock( &p_sys
->lock
);
2212 /* Check for sout mode */
2213 if( input_priv(p_input
)->p_sout
)
2215 /* FIXME review this, proper lock may be missing */
2216 if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
> 0 &&
2217 input_priv(p_input
)->b_out_pace_control
)
2219 msg_Dbg( p_input
, "switching to sync mode" );
2220 input_priv(p_input
)->b_out_pace_control
= false;
2222 else if( input_priv(p_input
)->p_sout
->i_out_pace_nocontrol
<= 0 &&
2223 !input_priv(p_input
)->b_out_pace_control
)
2225 msg_Dbg( p_input
, "switching to async mode" );
2226 input_priv(p_input
)->b_out_pace_control
= true;
2231 if( es
->p_dec_record
)
2233 block_t
*p_dup
= block_Duplicate( p_block
);
2235 input_DecoderDecode( es
->p_dec_record
, p_dup
,
2236 input_priv(p_input
)->b_out_pace_control
);
2238 input_DecoderDecode( es
->p_dec
, p_block
,
2239 input_priv(p_input
)->b_out_pace_control
);
2241 es_format_t fmt_dsc
;
2242 vlc_meta_t
*p_meta_dsc
;
2243 if( input_DecoderHasFormatChanged( es
->p_dec
, &fmt_dsc
, &p_meta_dsc
) )
2245 if (EsOutEsUpdateFmt( out
, es
, &fmt_dsc
) == VLC_SUCCESS
)
2246 EsOutSendEsEvent(out
, es
, VLC_INPUT_ES_UPDATED
);
2248 EsOutUpdateInfo(out
, es
, p_meta_dsc
);
2250 es_format_Clean( &fmt_dsc
);
2252 vlc_meta_Delete( p_meta_dsc
);
2255 /* Check CC status */
2256 decoder_cc_desc_t desc
;
2258 input_DecoderGetCcDesc( es
->p_dec
, &desc
);
2259 if( var_InheritInteger( p_input
, "captions" ) == 708 )
2260 EsOutCreateCCChannels( out
, VLC_CODEC_CEA708
, desc
.i_708_channels
,
2261 _("DTVCC Closed captions %u"), es
);
2262 EsOutCreateCCChannels( out
, VLC_CODEC_CEA608
, desc
.i_608_channels
,
2263 _("Closed captions %u"), es
);
2265 vlc_mutex_unlock( &p_sys
->lock
);
2271 EsOutDrainDecoder( es_out_t
*out
, es_out_id_t
*es
)
2273 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2274 assert( es
->p_dec
);
2276 /* FIXME: This might hold the ES output caller (i.e. the demux), and
2277 * the corresponding thread (typically the input thread), for a little
2278 * bit too long if the ES is deleted in the middle of a stream. */
2279 input_DecoderDrain( es
->p_dec
);
2280 EsOutDrainCCChannels( es
);
2281 while( !input_Stopped(p_sys
->p_input
) && !p_sys
->b_buffering
)
2283 if( input_DecoderIsEmpty( es
->p_dec
) &&
2284 ( !es
->p_dec_record
|| input_DecoderIsEmpty( es
->p_dec_record
) ))
2286 /* FIXME there should be a way to have auto deleted es, but there will be
2287 * a problem when another codec of the same type is created (mainly video) */
2288 vlc_tick_sleep(VLC_TICK_FROM_MS(20));
2292 /*****************************************************************************
2294 *****************************************************************************/
2295 static void EsOutDelLocked( es_out_t
*out
, es_out_id_t
*es
)
2297 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2298 bool b_reselect
= false;
2300 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, es
->fmt
.i_cat
);
2302 /* We don't try to reselect */
2305 EsOutDrainDecoder( out
, es
);
2306 EsOutUnselectEs( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2311 if( es
->p_pgrm
== p_sys
->p_pgrm
)
2312 EsOutSendEsEvent( out
, es
, VLC_INPUT_ES_DELETED
);
2314 EsOutDeleteInfoEs( out
, es
);
2316 /* Update program */
2318 if( es
->p_pgrm
->i_es
== 0 )
2319 msg_Dbg( p_sys
->p_input
, "Program doesn't contain anymore ES" );
2321 if( es
->b_scrambled
)
2322 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2327 if( p_esprops
->p_main_es
== es
)
2330 p_esprops
->p_main_es
= NULL
;
2332 p_esprops
->i_count
--;
2335 /* Re-select another track when needed */
2340 foreach_es_then_es_slaves(other
)
2341 if( es
->fmt
.i_cat
== other
->fmt
.i_cat
)
2343 if (EsIsSelected(other
))
2345 EsOutSendEsEvent(out
, es
, VLC_INPUT_ES_SELECTED
);
2346 if( p_esprops
->p_main_es
== NULL
)
2347 p_esprops
->p_main_es
= other
;
2350 EsOutSelect(out
, other
, false);
2357 static void EsOutDel( es_out_t
*out
, es_out_id_t
*es
)
2359 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2360 vlc_mutex_lock( &p_sys
->lock
);
2361 EsOutDelLocked( out
, es
);
2362 vlc_mutex_unlock( &p_sys
->lock
);
2365 static int EsOutVaControlLocked( es_out_t
*, int, va_list );
2366 static int EsOutControlLocked( es_out_t
*out
, int i_query
, ... )
2370 va_start( args
, i_query
);
2371 int ret
= EsOutVaControlLocked( out
, i_query
, args
);
2377 * Control query handler
2379 * \param out the es_out to control
2380 * \param i_query A es_out query as defined in include/ninput.h
2381 * \param args a variable list of arguments for the query
2382 * \return VLC_SUCCESS or an error code
2384 static int EsOutVaControlLocked( es_out_t
*out
, int i_query
, va_list args
)
2386 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
2390 case ES_OUT_SET_ES_STATE
:
2392 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2393 bool b
= va_arg( args
, int );
2394 if( b
&& !EsIsSelected( es
) )
2396 EsOutSelectEs( out
, es
);
2397 return EsIsSelected( es
) ? VLC_SUCCESS
: VLC_EGENERIC
;
2399 else if( !b
&& EsIsSelected( es
) )
2401 EsOutUnselectEs( out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2407 case ES_OUT_GET_ES_STATE
:
2409 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2410 bool *pb
= va_arg( args
, bool * );
2412 *pb
= EsIsSelected( es
);
2416 case ES_OUT_SET_ES_CAT_POLICY
:
2418 enum es_format_category_e i_cat
= va_arg( args
, enum es_format_category_e
);
2419 enum es_out_policy_e i_pol
= va_arg( args
, enum es_out_policy_e
);
2420 es_out_es_props_t
*p_esprops
= GetPropsByCat( p_sys
, i_cat
);
2421 if( p_esprops
== NULL
)
2422 return VLC_EGENERIC
;
2423 p_esprops
->e_policy
= i_pol
;
2427 case ES_OUT_GET_GROUP_FORCED
:
2429 int *pi_group
= va_arg( args
, int * );
2430 *pi_group
= p_sys
->i_group_id
;
2434 case ES_OUT_SET_MODE
:
2436 const int i_mode
= va_arg( args
, int );
2437 assert( i_mode
== ES_OUT_MODE_NONE
|| i_mode
== ES_OUT_MODE_ALL
||
2438 i_mode
== ES_OUT_MODE_AUTO
|| i_mode
== ES_OUT_MODE_PARTIAL
||
2439 i_mode
== ES_OUT_MODE_END
);
2441 if (i_mode
!= ES_OUT_MODE_NONE
&& !p_sys
->b_active
&& !vlc_list_is_empty(&p_sys
->es
))
2443 /* XXX Terminate vout if there are tracks but no video one.
2444 * This one is not mandatory but is he earliest place where it
2449 foreach_es_then_es_slaves(p_es
)
2450 if( p_es
->fmt
.i_cat
== VIDEO_ES
&& !found
/* nested loop */ )
2457 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2459 p_sys
->b_active
= i_mode
!= ES_OUT_MODE_NONE
;
2460 p_sys
->i_mode
= i_mode
;
2462 /* Reapply policy mode */
2465 foreach_es_then_es_slaves(es
)
2467 if (EsIsSelected(es
))
2468 EsOutUnselectEs(out
, es
, es
->p_pgrm
== p_sys
->p_pgrm
);
2470 foreach_es_then_es_slaves(es
)
2472 EsOutSelect(out
, es
, false);
2475 if( i_mode
== ES_OUT_MODE_END
)
2476 EsOutTerminate( out
);
2481 case ES_OUT_RESTART_ES
:
2483 #define IGNORE_ES DATA_ES
2484 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* ), *other
;
2486 enum es_format_category_e i_cat
;
2489 else if( es
== es_cat
+ AUDIO_ES
)
2491 else if( es
== es_cat
+ VIDEO_ES
)
2493 else if( es
== es_cat
+ SPU_ES
)
2497 if (es
->b_terminated
)
2498 return VLC_EGENERIC
;
2502 foreach_es_then_es_slaves(other
)
2504 if( i_cat
== IGNORE_ES
)
2508 if (i_query
== ES_OUT_RESTART_ES
&& es
->p_dec
!= NULL
)
2510 EsOutDestroyDecoder(out
, es
);
2511 EsOutCreateDecoder(out
, es
);
2513 else if( i_query
== ES_OUT_SET_ES
)
2515 EsOutSelect(out
, es
, true);
2520 else if (i_cat
== UNKNOWN_ES
|| other
->fmt
.i_cat
== i_cat
)
2522 if (EsIsSelected(other
))
2524 if (i_query
== ES_OUT_RESTART_ES
)
2526 if (other
->p_dec
!= NULL
)
2528 EsOutDestroyDecoder(out
, other
);
2529 EsOutCreateDecoder(out
, other
);
2533 EsOutUnselectEs(out
, other
, other
->p_pgrm
== p_sys
->p_pgrm
);
2540 case ES_OUT_UNSET_ES
:
2542 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* ), *other
;
2543 if (es
->b_terminated
)
2544 return VLC_EGENERIC
;
2545 foreach_es_then_es_slaves(other
)
2549 if (EsIsSelected(other
))
2551 EsOutUnselectEs(out
, other
, other
->p_pgrm
== p_sys
->p_pgrm
);
2557 return VLC_EGENERIC
;
2559 case ES_OUT_STOP_ALL_ES
:
2564 foreach_es_then_es_slaves(es
)
2567 int *selected_es
= vlc_alloc(count
+ 1, sizeof(int));
2571 *va_arg(args
, void **) = selected_es
;
2572 *selected_es
= count
;
2574 foreach_es_then_es_slaves(es
)
2576 if (EsIsSelected(es
))
2578 EsOutDestroyDecoder(out
, es
);
2579 *++selected_es
= es
->fmt
.i_id
;
2582 *++selected_es
= -1;
2586 case ES_OUT_START_ALL_ES
:
2588 int *selected_es
= va_arg( args
, void * );
2589 int count
= selected_es
[0];
2590 for( int i
= 0; i
< count
; ++i
)
2592 int i_id
= selected_es
[i
+ 1];
2595 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2596 EsOutCreateDecoder( out
, p_es
);
2603 case ES_OUT_SET_ES_DEFAULT
:
2605 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2609 /*p_sys->i_default_video_id = -1;*/
2610 /*p_sys->i_default_audio_id = -1;*/
2611 p_sys
->sub
.i_demux_id
= -1;
2613 else if( es
== es_cat
+ AUDIO_ES
)
2615 /*p_sys->i_default_video_id = -1;*/
2617 else if( es
== es_cat
+ VIDEO_ES
)
2619 /*p_sys->i_default_audio_id = -1;*/
2621 else if( es
== es_cat
+ SPU_ES
)
2623 p_sys
->sub
.i_demux_id
= -1;
2627 /*if( es->fmt.i_cat == VIDEO_ES )
2628 p_sys->i_default_video_id = es->fmt.i_id;
2630 if( es->fmt.i_cat == AUDIO_ES )
2631 p_sys->i_default_audio_id = es->fmt.i_id;
2633 if( es
->fmt
.i_cat
== SPU_ES
)
2634 p_sys
->sub
.i_demux_id
= es
->fmt
.i_id
;
2639 case ES_OUT_SET_PCR
:
2640 case ES_OUT_SET_GROUP_PCR
:
2642 es_out_pgrm_t
*p_pgrm
= NULL
;
2646 /* Search program */
2647 if( i_query
== ES_OUT_SET_PCR
)
2649 p_pgrm
= p_sys
->p_pgrm
;
2651 p_pgrm
= EsOutProgramAdd( out
, i_group
); /* Create it */
2655 i_group
= va_arg( args
, int );
2656 p_pgrm
= EsOutProgramFind( out
, i_group
);
2659 return VLC_EGENERIC
;
2661 i_pcr
= va_arg( args
, vlc_tick_t
);
2662 if( i_pcr
== VLC_TICK_INVALID
)
2664 msg_Err( p_sys
->p_input
, "Invalid PCR value in ES_OUT_SET_(GROUP_)PCR !" );
2665 return VLC_EGENERIC
;
2668 /* TODO do not use vlc_tick_now() but proper stream acquisition date */
2670 input_clock_Update( p_pgrm
->p_input_clock
, VLC_OBJECT(p_sys
->p_input
),
2672 input_priv(p_sys
->p_input
)->b_can_pace_control
|| p_sys
->b_buffering
,
2673 EsOutIsExtraBufferingAllowed( out
),
2674 i_pcr
, vlc_tick_now() );
2676 if( !p_sys
->p_pgrm
)
2679 if( p_sys
->b_buffering
)
2681 /* Check buffering state on master clock update */
2682 EsOutDecodersStopBuffering( out
, false );
2684 else if( p_pgrm
== p_sys
->p_pgrm
)
2686 if( b_late
&& ( !input_priv(p_sys
->p_input
)->p_sout
||
2687 !input_priv(p_sys
->p_input
)->b_out_pace_control
) )
2689 const vlc_tick_t i_pts_delay_base
= p_sys
->i_pts_delay
- p_sys
->i_pts_jitter
;
2690 vlc_tick_t i_pts_delay
= input_clock_GetJitter( p_pgrm
->p_input_clock
);
2692 /* Avoid dangerously high value */
2693 const vlc_tick_t i_jitter_max
=
2694 VLC_TICK_FROM_MS(var_InheritInteger( p_sys
->p_input
, "clock-jitter" ));
2695 if( i_pts_delay
> __MIN( i_pts_delay_base
+ i_jitter_max
, INPUT_PTS_DELAY_MAX
) )
2697 es_out_pgrm_t
*pgrm
;
2699 msg_Err( p_sys
->p_input
,
2700 "ES_OUT_SET_(GROUP_)PCR is called too late (jitter of %d ms ignored)",
2701 (int)MS_FROM_VLC_TICK(i_pts_delay
- i_pts_delay_base
) );
2702 i_pts_delay
= p_sys
->i_pts_delay
;
2705 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
2706 input_clock_Reset(pgrm
->p_input_clock
);
2710 msg_Err( p_sys
->p_input
,
2711 "ES_OUT_SET_(GROUP_)PCR is called too late (pts_delay increased to %d ms)",
2712 (int)MS_FROM_VLC_TICK(i_pts_delay
) );
2714 /* Force a rebufferization when we are too late */
2716 /* It is not really good, as we throw away already buffered data
2717 * TODO have a mean to correctly reenter bufferization */
2718 EsOutControlLocked( out
, ES_OUT_RESET_PCR
);
2721 EsOutControlLocked( out
, ES_OUT_SET_JITTER
, i_pts_delay_base
,
2722 i_pts_delay
- i_pts_delay_base
,
2723 p_sys
->i_cr_average
);
2729 case ES_OUT_RESET_PCR
:
2730 msg_Dbg( p_sys
->p_input
, "ES_OUT_RESET_PCR called" );
2731 EsOutChangePosition( out
);
2734 case ES_OUT_SET_GROUP
:
2736 int i
= va_arg( args
, int );
2737 es_out_pgrm_t
*p_pgrm
;
2739 vlc_list_foreach(p_pgrm
, &p_sys
->programs
, node
)
2740 if( p_pgrm
->i_id
== i
)
2742 EsOutProgramSelect( out
, p_pgrm
);
2745 return VLC_EGENERIC
;
2748 case ES_OUT_SET_ES_FMT
:
2750 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2751 es_format_t
*p_fmt
= va_arg( args
, es_format_t
* );
2752 if( es
== NULL
|| es
->fmt
.i_cat
!= p_fmt
->i_cat
2753 || es
->fmt
.i_id
!= p_fmt
->i_id
2754 || es
->fmt
.i_group
!= p_fmt
->i_group
)
2755 return VLC_EGENERIC
;
2757 es_format_Clean( &es
->fmt
);
2758 int ret
= es_format_Copy( &es
->fmt
, p_fmt
);
2759 if( ret
!= VLC_SUCCESS
)
2761 EsOutFillEsFmt( out
, &es
->fmt
);
2762 EsOutUpdateEsLanguageTitle(es
, &es
->fmt
);
2764 const bool b_was_selected
= EsIsSelected( es
);
2767 EsOutDrainDecoder( out
, es
);
2768 EsDeleteCCChannels( out
, es
);
2769 EsOutDestroyDecoder( out
, es
);
2773 EsOutCreateDecoder( out
, es
);
2775 EsOutSendEsEvent( out
, es
, VLC_INPUT_ES_UPDATED
);
2780 case ES_OUT_SET_ES_SCRAMBLED_STATE
:
2782 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
2783 bool b_scrambled
= (bool)va_arg( args
, int );
2785 if( !es
->b_scrambled
!= !b_scrambled
)
2787 es
->b_scrambled
= b_scrambled
;
2788 EsOutProgramUpdateScrambled( out
, es
->p_pgrm
);
2793 case ES_OUT_SET_NEXT_DISPLAY_TIME
:
2795 const int64_t i_date
= va_arg( args
, int64_t );
2798 return VLC_EGENERIC
;
2800 p_sys
->i_preroll_end
= i_date
;
2804 case ES_OUT_SET_GROUP_META
:
2806 int i_group
= va_arg( args
, int );
2807 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2809 EsOutProgramMeta( out
, i_group
, p_meta
);
2812 case ES_OUT_SET_GROUP_EPG
:
2814 int i_group
= va_arg( args
, int );
2815 const vlc_epg_t
*p_epg
= va_arg( args
, const vlc_epg_t
* );
2817 EsOutProgramEpg( out
, i_group
, p_epg
);
2820 case ES_OUT_SET_GROUP_EPG_EVENT
:
2822 int i_group
= va_arg( args
, int );
2823 const vlc_epg_event_t
*p_evt
= va_arg( args
, const vlc_epg_event_t
* );
2825 EsOutProgramEpgEvent( out
, i_group
, p_evt
);
2828 case ES_OUT_SET_EPG_TIME
:
2830 int64_t i64
= va_arg( args
, int64_t );
2832 EsOutEpgTime( out
, i64
);
2836 case ES_OUT_DEL_GROUP
:
2838 int i_group
= va_arg( args
, int );
2840 return EsOutProgramDel( out
, i_group
);
2843 case ES_OUT_SET_META
:
2845 const vlc_meta_t
*p_meta
= va_arg( args
, const vlc_meta_t
* );
2847 EsOutGlobalMeta( out
, p_meta
);
2851 case ES_OUT_GET_WAKE_UP
:
2853 vlc_tick_t
*pi_wakeup
= va_arg( args
, vlc_tick_t
* );
2854 *pi_wakeup
= EsOutGetWakeup( out
);
2858 case ES_OUT_SET_ES_BY_ID
:
2859 case ES_OUT_RESTART_ES_BY_ID
:
2860 case ES_OUT_SET_ES_DEFAULT_BY_ID
:
2862 const int i_id
= va_arg( args
, int );
2863 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2864 int i_new_query
= 0;
2868 case ES_OUT_SET_ES_BY_ID
: i_new_query
= ES_OUT_SET_ES
;
2869 p_es
->b_forced
= va_arg( args
, int );
2871 case ES_OUT_RESTART_ES_BY_ID
: i_new_query
= ES_OUT_RESTART_ES
; break;
2872 case ES_OUT_SET_ES_DEFAULT_BY_ID
: i_new_query
= ES_OUT_SET_ES_DEFAULT
; break;
2874 vlc_assert_unreachable();
2876 int i_ret
= EsOutControlLocked( out
, i_new_query
, p_es
);
2878 /* Clean up vout after user action (in active mode only).
2879 * FIXME it does not work well with multiple video windows */
2880 if( p_sys
->b_active
)
2881 input_resource_TerminateVout( input_priv(p_sys
->p_input
)->p_resource
);
2885 case ES_OUT_GET_ES_OBJECTS_BY_ID
:
2887 const int i_id
= va_arg( args
, int );
2888 es_out_id_t
*p_es
= EsOutGetFromID( out
, i_id
);
2890 return VLC_EGENERIC
;
2892 vlc_object_t
**pp_decoder
= va_arg( args
, vlc_object_t
** );
2893 vout_thread_t
**pp_vout
= va_arg( args
, vout_thread_t
** );
2894 audio_output_t
**pp_aout
= va_arg( args
, audio_output_t
** );
2898 *pp_decoder
= vlc_object_hold( p_es
->p_dec
);
2899 input_DecoderGetObjects( p_es
->p_dec
, pp_vout
, pp_aout
);
2913 case ES_OUT_GET_BUFFERING
:
2915 bool *pb
= va_arg( args
, bool* );
2916 *pb
= p_sys
->b_buffering
;
2920 case ES_OUT_GET_EMPTY
:
2922 bool *pb
= va_arg( args
, bool* );
2923 *pb
= EsOutDecodersIsEmpty( out
);
2927 case ES_OUT_SET_DELAY
:
2929 const int i_cat
= va_arg( args
, int );
2930 const vlc_tick_t i_delay
= va_arg( args
, vlc_tick_t
);
2931 EsOutSetDelay( out
, i_cat
, i_delay
);
2935 case ES_OUT_SET_RECORD_STATE
:
2937 bool b
= va_arg( args
, int );
2938 return EsOutSetRecord( out
, b
);
2941 case ES_OUT_SET_PAUSE_STATE
:
2943 const bool b_source_paused
= (bool)va_arg( args
, int );
2944 const bool b_paused
= (bool)va_arg( args
, int );
2945 const vlc_tick_t i_date
= va_arg( args
, vlc_tick_t
);
2947 assert( !b_source_paused
== !b_paused
);
2948 EsOutChangePause( out
, b_paused
, i_date
);
2953 case ES_OUT_SET_RATE
:
2955 const int i_src_rate
= va_arg( args
, int );
2956 const int i_rate
= va_arg( args
, int );
2958 assert( i_src_rate
== i_rate
);
2959 EsOutChangeRate( out
, i_rate
);
2964 case ES_OUT_SET_FRAME_NEXT
:
2965 EsOutFrameNext( out
);
2968 case ES_OUT_SET_TIMES
:
2970 double f_position
= va_arg( args
, double );
2971 vlc_tick_t i_time
= va_arg( args
, vlc_tick_t
);
2972 vlc_tick_t i_length
= va_arg( args
, vlc_tick_t
);
2974 input_SendEventLength( p_sys
->p_input
, i_length
);
2976 if( !p_sys
->b_buffering
)
2980 /* Fix for buffering delay */
2981 if( !input_priv(p_sys
->p_input
)->p_sout
||
2982 !input_priv(p_sys
->p_input
)->b_out_pace_control
)
2983 i_delay
= EsOutGetBuffering( out
);
2992 f_position
-= (double)i_delay
/ i_length
;
2993 if( f_position
< 0 )
2996 input_SendEventPosition( p_sys
->p_input
, f_position
, i_time
);
3000 case ES_OUT_SET_JITTER
:
3002 vlc_tick_t i_pts_delay
= va_arg( args
, vlc_tick_t
);
3003 vlc_tick_t i_pts_jitter
= va_arg( args
, vlc_tick_t
);
3004 int i_cr_average
= va_arg( args
, int );
3005 es_out_pgrm_t
*pgrm
;
3007 bool b_change_clock
=
3008 i_pts_delay
+ i_pts_jitter
!= p_sys
->i_pts_delay
||
3009 i_cr_average
!= p_sys
->i_cr_average
;
3011 assert( i_pts_jitter
>= 0 );
3012 p_sys
->i_pts_delay
= i_pts_delay
+ i_pts_jitter
;
3013 p_sys
->i_pts_jitter
= i_pts_jitter
;
3014 p_sys
->i_cr_average
= i_cr_average
;
3017 vlc_list_foreach(pgrm
, &p_sys
->programs
, node
)
3018 input_clock_SetJitter(pgrm
->p_input_clock
, i_pts_delay
3019 + i_pts_jitter
, i_cr_average
);
3023 case ES_OUT_GET_PCR_SYSTEM
:
3025 if( p_sys
->b_buffering
)
3026 return VLC_EGENERIC
;
3028 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
3030 return VLC_EGENERIC
;
3032 vlc_tick_t
*pi_system
= va_arg( args
, vlc_tick_t
*);
3033 vlc_tick_t
*pi_delay
= va_arg( args
, vlc_tick_t
*);
3034 input_clock_GetSystemOrigin( p_pgrm
->p_input_clock
, pi_system
, pi_delay
);
3038 case ES_OUT_MODIFY_PCR_SYSTEM
:
3040 if( p_sys
->b_buffering
)
3041 return VLC_EGENERIC
;
3043 es_out_pgrm_t
*p_pgrm
= p_sys
->p_pgrm
;
3045 return VLC_EGENERIC
;
3047 const bool b_absolute
= va_arg( args
, int );
3048 const vlc_tick_t i_system
= va_arg( args
, vlc_tick_t
);
3049 input_clock_ChangeSystemOrigin( p_pgrm
->p_input_clock
, b_absolute
, i_system
);
3052 case ES_OUT_SET_EOS
:
3055 foreach_es_then_es_slaves(id
)
3056 if (id
->p_dec
!= NULL
)
3057 input_DecoderDrain(id
->p_dec
);
3061 case ES_OUT_POST_SUBNODE
:
3063 input_thread_t
*input
= p_sys
->p_input
;
3064 input_item_node_t
*node
= va_arg(args
, input_item_node_t
*);
3065 input_SendEventParsing(input
, node
);
3066 input_item_node_Delete(node
);
3071 case ES_OUT_VOUT_SET_MOUSE_EVENT
:
3073 es_out_id_t
*p_es
= va_arg( args
, es_out_id_t
* );
3075 if( !p_es
|| p_es
->fmt
.i_cat
!= VIDEO_ES
)
3076 return VLC_EGENERIC
;
3078 p_es
->mouse_event_cb
= va_arg( args
, vlc_mouse_event
);
3079 p_es
->mouse_event_userdata
= va_arg( args
, void * );
3082 input_DecoderSetVoutMouseEvent( p_es
->p_dec
,
3083 p_es
->mouse_event_cb
, p_es
->mouse_event_userdata
);
3087 case ES_OUT_VOUT_ADD_OVERLAY
:
3089 es_out_id_t
*p_es
= va_arg( args
, es_out_id_t
* );
3090 subpicture_t
*sub
= va_arg( args
, subpicture_t
* );
3091 int *channel
= va_arg( args
, int * );
3092 if( p_es
&& p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
3093 return input_DecoderAddVoutOverlay( p_es
->p_dec
, sub
, channel
);
3094 return VLC_EGENERIC
;
3096 case ES_OUT_VOUT_FLUSH_OVERLAY
:
3098 es_out_id_t
*p_es
= va_arg( args
, es_out_id_t
* );
3099 int channel
= va_arg( args
, int );
3100 if( p_es
&& p_es
->fmt
.i_cat
== VIDEO_ES
&& p_es
->p_dec
)
3101 return input_DecoderFlushVoutOverlay( p_es
->p_dec
, channel
);
3102 return VLC_EGENERIC
;
3104 case ES_OUT_SPU_SET_HIGHLIGHT
:
3106 es_out_id_t
*p_es
= va_arg( args
, es_out_id_t
* );
3107 const vlc_spu_highlight_t
*spu_hl
=
3108 va_arg( args
, const vlc_spu_highlight_t
* );
3109 if( p_es
&& p_es
->fmt
.i_cat
== SPU_ES
&& p_es
->p_dec
)
3110 return input_DecoderSetSpuHighlight( p_es
->p_dec
, spu_hl
);
3111 return VLC_EGENERIC
;
3113 case ES_OUT_SET_VBI_PAGE
:
3114 case ES_OUT_SET_VBI_TRANSPARENCY
:
3116 es_out_id_t
*es
= va_arg( args
, es_out_id_t
* );
3118 if( !es
->p_dec
|| es
->fmt
.i_cat
!= SPU_ES
3119 || es
->fmt
.i_codec
!= VLC_CODEC_TELETEXT
)
3120 return VLC_EGENERIC
;
3123 if( i_query
== ES_OUT_SET_VBI_PAGE
)
3125 unsigned page
= va_arg( args
, unsigned );
3126 ret
= var_SetInteger( es
->p_dec
, "vbi-page", page
);
3127 if( ret
== VLC_SUCCESS
)
3128 input_SendEventVbiPage( p_sys
->p_input
, page
);
3132 bool opaque
= va_arg( args
, int );
3133 ret
= var_SetBool( es
->p_dec
, "vbi-opaque", opaque
);
3134 if( ret
== VLC_SUCCESS
)
3135 input_SendEventVbiTransparency( p_sys
->p_input
, opaque
);
3140 msg_Err( p_sys
->p_input
, "unknown query 0x%x in %s", i_query
,
3142 return VLC_EGENERIC
;
3145 static int EsOutControl( es_out_t
*out
, int i_query
, va_list args
)
3147 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
3150 vlc_mutex_lock( &p_sys
->lock
);
3151 i_ret
= EsOutVaControlLocked( out
, i_query
, args
);
3152 vlc_mutex_unlock( &p_sys
->lock
);
3157 static const struct es_out_callbacks es_out_cbs
=
3162 .control
= EsOutControl
,
3163 .destroy
= EsOutDelete
,
3166 /****************************************************************************
3167 * LanguageGetName: try to expend iso639 into plain name
3168 ****************************************************************************/
3169 static char *LanguageGetName( const char *psz_code
)
3171 const iso639_lang_t
*pl
;
3173 if( psz_code
== NULL
|| !strcmp( psz_code
, "und" ) )
3175 return strdup( "" );
3178 if( strlen( psz_code
) == 2 )
3180 pl
= GetLang_1( psz_code
);
3182 else if( strlen( psz_code
) == 3 )
3184 pl
= GetLang_2B( psz_code
);
3185 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
3187 pl
= GetLang_2T( psz_code
);
3192 char *lang
= LanguageGetCode( psz_code
);
3193 pl
= GetLang_1( lang
);
3197 if( !strcmp( pl
->psz_iso639_1
, "??" ) )
3199 return strdup( psz_code
);
3203 return strdup( vlc_gettext(pl
->psz_eng_name
) );
3207 /* Get a 2 char code */
3208 static char *LanguageGetCode( const char *psz_lang
)
3210 const iso639_lang_t
*pl
;
3212 if( psz_lang
== NULL
|| *psz_lang
== '\0' )
3213 return strdup("??");
3215 for( pl
= p_languages
; pl
->psz_eng_name
!= NULL
; pl
++ )
3217 if( !strcasecmp( pl
->psz_eng_name
, psz_lang
) ||
3218 !strcasecmp( pl
->psz_iso639_1
, psz_lang
) ||
3219 !strcasecmp( pl
->psz_iso639_2T
, psz_lang
) ||
3220 !strcasecmp( pl
->psz_iso639_2B
, psz_lang
) )
3221 return strdup( pl
->psz_iso639_1
);
3224 return strdup("??");
3227 static char **LanguageSplit( const char *psz_langs
)
3234 if( psz_langs
== NULL
) return NULL
;
3236 psz_parser
= psz_dup
= strdup(psz_langs
);
3238 while( psz_parser
&& *psz_parser
)
3243 psz
= strchr(psz_parser
, ',' );
3244 if( psz
) *psz
++ = '\0';
3246 if( !strcmp( psz_parser
, "any" ) )
3248 TAB_APPEND( i_psz
, ppsz
, strdup("any") );
3250 else if( !strcmp( psz_parser
, "none" ) )
3252 TAB_APPEND( i_psz
, ppsz
, strdup("none") );
3256 psz_code
= LanguageGetCode( psz_parser
);
3257 if( strcmp( psz_code
, "??" ) )
3259 TAB_APPEND( i_psz
, ppsz
, psz_code
);
3272 TAB_APPEND( i_psz
, ppsz
, NULL
);
3279 static int LanguageArrayIndex( char **ppsz_langs
, const char *psz_lang
)
3281 if( !ppsz_langs
|| !psz_lang
)
3284 for( int i
= 0; ppsz_langs
[i
]; i
++ )
3286 if( !strcasecmp( ppsz_langs
[i
], psz_lang
) ||
3287 ( !strcasecmp( ppsz_langs
[i
], "any" ) && strcasecmp( psz_lang
, "none") ) )
3289 if( !strcasecmp( ppsz_langs
[i
], "none" ) )
3296 static int EsOutEsUpdateFmt(es_out_t
*out
, es_out_id_t
*es
,
3297 const es_format_t
*fmt
)
3299 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
3300 input_thread_t
*p_input
= p_sys
->p_input
;
3302 assert(es
->fmt
.i_cat
== fmt
->i_cat
);
3304 es_format_t update
= *fmt
;
3306 /* decoder may overwrite these values */
3307 update
.i_id
= es
->fmt
.i_id
;
3308 update
.i_group
= es
->fmt
.i_group
;
3309 update
.i_priority
= es
->fmt
.i_priority
;
3310 update
.i_codec
= es
->fmt
.i_codec
;
3311 update
.i_original_fourcc
= es
->fmt
.i_original_fourcc
;
3313 if (update
.psz_language
== NULL
)
3314 update
.psz_language
= es
->fmt
.psz_language
;
3315 if (update
.psz_description
== NULL
)
3316 update
.psz_description
= es
->fmt
.psz_description
;
3317 if (update
.i_cat
== SPU_ES
&& update
.subs
.psz_encoding
== NULL
)
3318 update
.subs
.psz_encoding
= es
->fmt
.subs
.psz_encoding
;
3319 if (update
.i_extra_languages
== 0)
3321 assert(update
.p_extra_languages
== NULL
);
3322 update
.i_extra_languages
= es
->fmt
.i_extra_languages
;
3323 update
.p_extra_languages
= es
->fmt
.p_extra_languages
;
3326 es_format_Clean(&es
->fmt_out
);
3327 int ret
= es_format_Copy(&es
->fmt_out
, &update
);
3328 if (ret
== VLC_SUCCESS
)
3330 EsOutUpdateEsLanguageTitle(es
, &es
->fmt_out
);
3331 input_item_UpdateTracksInfo(input_GetItem(p_input
), &es
->fmt_out
);
3337 /****************************************************************************
3339 * - add meta info to the playlist item
3340 ****************************************************************************/
3341 static void EsOutUpdateInfo( es_out_t
*out
, es_out_id_t
*es
, const vlc_meta_t
*p_meta
)
3343 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
3344 input_thread_t
*p_input
= p_sys
->p_input
;
3345 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
3346 const es_format_t
*p_fmt_es
= &es
->fmt
;
3347 const es_format_t
*fmt
= es
->fmt_out
.i_cat
!= UNKNOWN_ES
? &es
->fmt_out
: &es
->fmt
;
3349 input_item_UpdateTracksInfo( p_item
, fmt
);
3351 /* Create category */
3352 char* psz_cat
= EsInfoCategoryName( es
);
3354 if( unlikely( !psz_cat
) )
3357 info_category_t
* p_cat
= info_category_New( psz_cat
);
3361 if( unlikely( !p_cat
) )
3364 /* Add information */
3365 if( es
->i_meta_id
!= es
->fmt
.i_id
)
3366 info_category_AddInfo( p_cat
, _("Original ID"),
3367 "%d", es
->fmt
.i_id
);
3369 const vlc_fourcc_t i_codec_fourcc
= p_fmt_es
->i_original_fourcc
;
3370 const char *psz_codec_description
=
3371 vlc_fourcc_GetDescription( p_fmt_es
->i_cat
, i_codec_fourcc
);
3372 if( psz_codec_description
&& *psz_codec_description
)
3373 info_category_AddInfo( p_cat
, _("Codec"), "%s (%.4s)",
3374 psz_codec_description
, (char*)&i_codec_fourcc
);
3375 else if ( i_codec_fourcc
!= VLC_FOURCC(0,0,0,0) )
3376 info_category_AddInfo( p_cat
, _("Codec"), "%.4s",
3377 (char*)&i_codec_fourcc
);
3379 if( es
->psz_language
&& *es
->psz_language
)
3380 info_category_AddInfo( p_cat
, _("Language"), "%s",
3382 if( fmt
->psz_description
&& *fmt
->psz_description
)
3383 info_category_AddInfo( p_cat
, _("Description"), "%s",
3384 fmt
->psz_description
);
3386 switch( fmt
->i_cat
)
3389 info_category_AddInfo( p_cat
, _("Type"), _("Audio") );
3391 if( fmt
->audio
.i_physical_channels
)
3392 info_category_AddInfo( p_cat
, _("Channels"), "%s",
3393 vlc_gettext( aout_FormatPrintChannels( &fmt
->audio
) ) );
3395 if( fmt
->audio
.i_rate
!= 0 )
3397 info_category_AddInfo( p_cat
, _("Sample rate"), _("%u Hz"),
3398 fmt
->audio
.i_rate
);
3399 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3400 var_SetInteger( p_input
, "sample-rate", fmt
->audio
.i_rate
);
3403 unsigned int i_bitspersample
= fmt
->audio
.i_bitspersample
;
3404 if( i_bitspersample
== 0 )
3405 i_bitspersample
= aout_BitsPerSample( fmt
->i_codec
);
3406 if( i_bitspersample
!= 0 )
3407 info_category_AddInfo( p_cat
, _("Bits per sample"), "%u",
3410 if( fmt
->i_bitrate
!= 0 )
3412 info_category_AddInfo( p_cat
, _("Bitrate"), _("%u kb/s"),
3413 fmt
->i_bitrate
/ 1000 );
3414 /* FIXME that should be removed or improved ! (used by text/strings.c) */
3415 var_SetInteger( p_input
, "bit-rate", fmt
->i_bitrate
);
3417 for( int i
= 0; i
< AUDIO_REPLAY_GAIN_MAX
; i
++ )
3419 const audio_replay_gain_t
*p_rg
= &fmt
->audio_replay_gain
;
3420 if( !p_rg
->pb_gain
[i
] )
3422 const char *psz_name
;
3423 if( i
== AUDIO_REPLAY_GAIN_TRACK
)
3424 psz_name
= _("Track replay gain");
3426 psz_name
= _("Album replay gain");
3427 info_category_AddInfo( p_cat
, psz_name
, _("%.2f dB"),
3433 info_category_AddInfo( p_cat
, _("Type"), _("Video") );
3435 if( fmt
->video
.i_visible_width
> 0 &&
3436 fmt
->video
.i_visible_height
> 0 )
3437 info_category_AddInfo( p_cat
, _("Video resolution"), "%ux%u",
3438 fmt
->video
.i_visible_width
,
3439 fmt
->video
.i_visible_height
);
3441 if( fmt
->video
.i_width
> 0 && fmt
->video
.i_height
> 0 )
3442 info_category_AddInfo( p_cat
, _("Buffer dimensions"), "%ux%u",
3443 fmt
->video
.i_width
, fmt
->video
.i_height
);
3445 if( fmt
->video
.i_frame_rate
> 0 &&
3446 fmt
->video
.i_frame_rate_base
> 0 )
3448 if( fmt
->video
.i_frame_rate_base
== 1 )
3449 info_category_AddInfo( p_cat
, _("Frame rate"), "%u",
3450 fmt
->video
.i_frame_rate
);
3452 info_category_AddInfo( p_cat
, _("Frame rate"), "%.6f",
3453 (double)fmt
->video
.i_frame_rate
3454 / (double)fmt
->video
.i_frame_rate_base
);
3456 if( fmt
->i_codec
!= p_fmt_es
->i_codec
)
3458 const char *psz_chroma_description
=
3459 vlc_fourcc_GetDescription( VIDEO_ES
, fmt
->i_codec
);
3460 if( psz_chroma_description
)
3461 info_category_AddInfo( p_cat
, _("Decoded format"), "%s",
3462 psz_chroma_description
);
3465 static const char orient_names
[][13] = {
3466 N_("Top left"), N_("Left top"),
3467 N_("Right bottom"), N_("Top right"),
3468 N_("Bottom left"), N_("Bottom right"),
3469 N_("Left bottom"), N_("Right top"),
3471 info_category_AddInfo( p_cat
, _("Orientation"), "%s",
3472 vlc_gettext(orient_names
[fmt
->video
.orientation
]) );
3474 if( fmt
->video
.primaries
!= COLOR_PRIMARIES_UNDEF
)
3476 static const char primaries_names
[][32] = {
3477 [COLOR_PRIMARIES_UNDEF
] = N_("Undefined"),
3478 [COLOR_PRIMARIES_BT601_525
] =
3479 N_("ITU-R BT.601 (525 lines, 60 Hz)"),
3480 [COLOR_PRIMARIES_BT601_625
] =
3481 N_("ITU-R BT.601 (625 lines, 50 Hz)"),
3482 [COLOR_PRIMARIES_BT709
] = "ITU-R BT.709",
3483 [COLOR_PRIMARIES_BT2020
] = "ITU-R BT.2020",
3484 [COLOR_PRIMARIES_DCI_P3
] = "DCI/P3 D65",
3485 [COLOR_PRIMARIES_BT470_M
] = "ITU-R BT.470 M",
3487 static_assert(ARRAY_SIZE(primaries_names
) == COLOR_PRIMARIES_MAX
+1,
3488 "Color primiaries table mismatch");
3489 info_category_AddInfo( p_cat
, _("Color primaries"), "%s",
3490 vlc_gettext(primaries_names
[fmt
->video
.primaries
]) );
3492 if( fmt
->video
.transfer
!= TRANSFER_FUNC_UNDEF
)
3494 static const char func_names
[][20] = {
3495 [TRANSFER_FUNC_UNDEF
] = N_("Undefined"),
3496 [TRANSFER_FUNC_LINEAR
] = N_("Linear"),
3497 [TRANSFER_FUNC_SRGB
] = "sRGB",
3498 [TRANSFER_FUNC_BT470_BG
] = "ITU-R BT.470 BG",
3499 [TRANSFER_FUNC_BT470_M
] = "ITU-R BT.470 M",
3500 [TRANSFER_FUNC_BT709
] = "ITU-R BT.709",
3501 [TRANSFER_FUNC_SMPTE_ST2084
] = "SMPTE ST2084",
3502 [TRANSFER_FUNC_SMPTE_240
] = "SMPTE 240M",
3503 [TRANSFER_FUNC_HLG
] = N_("Hybrid Log-Gamma"),
3505 static_assert(ARRAY_SIZE(func_names
) == TRANSFER_FUNC_MAX
+1,
3506 "Transfer functions table mismatch");
3507 info_category_AddInfo( p_cat
, _("Color transfer function"), "%s",
3508 vlc_gettext(func_names
[fmt
->video
.transfer
]) );
3510 if( fmt
->video
.space
!= COLOR_SPACE_UNDEF
)
3512 static const char space_names
[][16] = {
3513 [COLOR_SPACE_UNDEF
] = N_("Undefined"),
3514 [COLOR_SPACE_BT601
] = "ITU-R BT.601",
3515 [COLOR_SPACE_BT709
] = "ITU-R BT.709",
3516 [COLOR_SPACE_BT2020
] = "ITU-R BT.2020",
3518 static_assert(ARRAY_SIZE(space_names
) == COLOR_SPACE_MAX
+1,
3519 "Color space table mismatch");
3520 info_category_AddInfo( p_cat
, _("Color space"), "%s",
3521 vlc_gettext(space_names
[fmt
->video
.space
]) );
3523 if( fmt
->video
.color_range
!= COLOR_RANGE_UNDEF
)
3525 static const char range_names
[][16] = {
3526 [COLOR_RANGE_UNDEF
] = N_("Undefined"),
3527 [COLOR_RANGE_FULL
] = N_("Full"),
3528 [COLOR_RANGE_LIMITED
] = N_("Limited"),
3530 static_assert(ARRAY_SIZE(range_names
) == COLOR_RANGE_MAX
+1,
3531 "Color range table mismatch");
3532 info_category_AddInfo( p_cat
, _("Color Range"), "%s",
3533 vlc_gettext(range_names
[fmt
->video
.color_range
]) );
3535 if( fmt
->video
.chroma_location
!= CHROMA_LOCATION_UNDEF
)
3537 static const char c_loc_names
[][16] = {
3538 [CHROMA_LOCATION_UNDEF
] = N_("Undefined"),
3539 [CHROMA_LOCATION_LEFT
] = N_("Left"),
3540 [CHROMA_LOCATION_CENTER
] = N_("Center"),
3541 [CHROMA_LOCATION_TOP_LEFT
] = N_("Top Left"),
3542 [CHROMA_LOCATION_TOP_CENTER
] = N_("Top Center"),
3543 [CHROMA_LOCATION_BOTTOM_LEFT
] =N_("Bottom Left"),
3544 [CHROMA_LOCATION_BOTTOM_CENTER
] = N_("Bottom Center"),
3546 static_assert(ARRAY_SIZE(c_loc_names
) == CHROMA_LOCATION_MAX
+1,
3547 "Chroma location table mismatch");
3548 info_category_AddInfo( p_cat
, _("Chroma location"), "%s",
3549 vlc_gettext(c_loc_names
[fmt
->video
.chroma_location
]) );
3551 if( fmt
->video
.multiview_mode
!= MULTIVIEW_2D
)
3553 static const char c_multiview_names
[][18] = {
3554 [MULTIVIEW_2D
] = N_("2D"),
3555 [MULTIVIEW_STEREO_SBS
] = N_("Side-By-Side"),
3556 [MULTIVIEW_STEREO_TB
] = N_("Top-Bottom"),
3557 [MULTIVIEW_STEREO_ROW
] = N_("Row Sequential"),
3558 [MULTIVIEW_STEREO_COL
] = N_("Column Sequential"),
3559 [MULTIVIEW_STEREO_FRAME
] =N_("Frame Sequential"),
3560 [MULTIVIEW_STEREO_CHECKERBOARD
] = N_("Checkboard"),
3562 static_assert(ARRAY_SIZE(c_multiview_names
) == MULTIVIEW_STEREO_MAX
+1,
3563 "Multiview format table mismatch");
3564 info_category_AddInfo( p_cat
, _("Stereo Mode"), "%s",
3565 vlc_gettext(c_multiview_names
[fmt
->video
.multiview_mode
]) );
3566 info_category_AddInfo( p_cat
, _("First Stereo Eye"),
3567 vlc_gettext(fmt
->video
.b_multiview_right_eye_first
?
3568 N_("Right") : N_("Left")) );
3570 if( fmt
->video
.projection_mode
!= PROJECTION_MODE_RECTANGULAR
)
3572 const char *psz_loc_name
= NULL
;
3573 switch (fmt
->video
.projection_mode
)
3575 case PROJECTION_MODE_RECTANGULAR
:
3576 psz_loc_name
= N_("Rectangular");
3578 case PROJECTION_MODE_EQUIRECTANGULAR
:
3579 psz_loc_name
= N_("Equirectangular");
3581 case PROJECTION_MODE_CUBEMAP_LAYOUT_STANDARD
:
3582 psz_loc_name
= N_("Cubemap");
3585 vlc_assert_unreachable();
3588 info_category_AddInfo( p_cat
, _("Projection"), "%s",
3589 vlc_gettext(psz_loc_name
) );
3591 info_category_AddInfo( p_cat
, vlc_pgettext("ViewPoint", "Yaw"),
3592 "%.2f", fmt
->video
.pose
.yaw
);
3593 info_category_AddInfo( p_cat
, vlc_pgettext("ViewPoint", "Pitch"),
3594 "%.2f", fmt
->video
.pose
.pitch
);
3595 info_category_AddInfo( p_cat
, vlc_pgettext("ViewPoint", "Roll"),
3596 "%.2f", fmt
->video
.pose
.roll
);
3597 info_category_AddInfo( p_cat
,
3598 vlc_pgettext("ViewPoint", "Field of view"),
3599 "%.2f", fmt
->video
.pose
.fov
);
3601 if ( fmt
->video
.mastering
.max_luminance
)
3603 info_category_AddInfo( p_cat
, _("Max. mastering luminance"), "%.4f cd/m²",
3604 fmt
->video
.mastering
.max_luminance
/ 10000.f
);
3606 if ( fmt
->video
.mastering
.min_luminance
)
3608 info_category_AddInfo( p_cat
, _("Min. mastering luminance"), "%.4f cd/m²",
3609 fmt
->video
.mastering
.min_luminance
/ 10000.f
);
3611 if ( fmt
->video
.mastering
.primaries
[4] &&
3612 fmt
->video
.mastering
.primaries
[5] )
3614 float x
= (float)fmt
->video
.mastering
.primaries
[4] / 50000.f
;
3615 float y
= (float)fmt
->video
.mastering
.primaries
[5] / 50000.f
;
3616 info_category_AddInfo( p_cat
, _("Mastering Primary R"), "x=%.4f y=%.4f", x
, y
);
3618 if ( fmt
->video
.mastering
.primaries
[0] &&
3619 fmt
->video
.mastering
.primaries
[1] )
3621 float x
= (float)fmt
->video
.mastering
.primaries
[0] / 50000.f
;
3622 float y
= (float)fmt
->video
.mastering
.primaries
[1] / 50000.f
;
3623 info_category_AddInfo( p_cat
, _("Mastering Primary G"), "x=%.4f y=%.4f", x
, y
);
3625 if ( fmt
->video
.mastering
.primaries
[2] &&
3626 fmt
->video
.mastering
.primaries
[3] )
3628 float x
= (float)fmt
->video
.mastering
.primaries
[2] / 50000.f
;
3629 float y
= (float)fmt
->video
.mastering
.primaries
[3] / 50000.f
;
3630 info_category_AddInfo( p_cat
, _("Mastering Primary B"), "x=%.4f y=%.4f", x
, y
);
3632 if ( fmt
->video
.mastering
.white_point
[0] &&
3633 fmt
->video
.mastering
.white_point
[1] )
3635 float x
= (float)fmt
->video
.mastering
.white_point
[0] / 50000.f
;
3636 float y
= (float)fmt
->video
.mastering
.white_point
[1] / 50000.f
;
3637 info_category_AddInfo( p_cat
, _("Mastering White point"), "x=%.4f y=%.4f", x
, y
);
3639 if ( fmt
->video
.lighting
.MaxCLL
)
3641 info_category_AddInfo( p_cat
, "MaxCLL", "%" PRIu16
" cd/m²",
3642 fmt
->video
.lighting
.MaxCLL
);
3644 if ( fmt
->video
.lighting
.MaxFALL
)
3646 info_category_AddInfo( p_cat
, "MaxFALL", "%" PRIu16
" cd/m²",
3647 fmt
->video
.lighting
.MaxFALL
);
3652 info_category_AddInfo( p_cat
, _("Type"), _("Subtitle") );
3659 /* Append generic meta */
3662 char **ppsz_all_keys
= vlc_meta_CopyExtraNames( p_meta
);
3663 for( int i
= 0; ppsz_all_keys
&& ppsz_all_keys
[i
]; i
++ )
3665 char *psz_key
= ppsz_all_keys
[i
];
3666 const char *psz_value
= vlc_meta_GetExtra( p_meta
, psz_key
);
3669 info_category_AddInfo( p_cat
, vlc_gettext(psz_key
), "%s",
3670 vlc_gettext(psz_value
) );
3673 free( ppsz_all_keys
);
3676 input_item_ReplaceInfos( p_item
, p_cat
);
3677 if( !input_priv(p_input
)->b_preparsing
)
3678 input_SendEventMetaInfo( p_input
);
3681 static void EsOutDeleteInfoEs( es_out_t
*out
, es_out_id_t
*es
)
3683 es_out_sys_t
*p_sys
= container_of(out
, es_out_sys_t
, out
);
3684 input_thread_t
*p_input
= p_sys
->p_input
;
3685 input_item_t
*p_item
= input_priv(p_input
)->p_item
;
3686 char* psz_info_category
;
3688 if( likely( psz_info_category
= EsInfoCategoryName( es
) ) )
3690 int ret
= input_item_DelInfo( p_item
, psz_info_category
, NULL
);
3691 free( psz_info_category
);
3693 if( ret
== VLC_SUCCESS
&& !input_priv(p_input
)->b_preparsing
)
3694 input_SendEventMetaInfo( p_input
);
3698 static inline es_out_id_t
*vlc_es_id_get_out(vlc_es_id_t
*id
)
3700 return container_of(id
, es_out_id_t
, id
);
3704 vlc_es_id_Hold(vlc_es_id_t
*id
)
3706 EsHold(vlc_es_id_get_out(id
));
3711 vlc_es_id_Release(vlc_es_id_t
*id
)
3713 EsRelease(vlc_es_id_get_out(id
));
3717 vlc_es_id_GetInputId(vlc_es_id_t
*id
)
3722 enum es_format_category_e
3723 vlc_es_id_GetCat(vlc_es_id_t
*id
)