+/*****************************************************************************
+ * Elementary streams handling
+ *****************************************************************************/
+
+struct es_out_sys_t {
+ demux_t *p_demux;
+};
+
+typedef struct fmt_es_pair {
+ int i_id;
+ es_out_id_t *p_es;
+} fmt_es_pair_t;
+
+static int findEsPairIndex( demux_sys_t *p_sys, int i_id )
+{
+ for ( int i = 0; i < vlc_array_count(&p_sys->es); ++i ) {
+ if ( ((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->i_id == i_id )
+ return i;
+ }
+ return -1;
+}
+
+static int findEsPairIndexByEs( demux_sys_t *p_sys, es_out_id_t *p_es )
+{
+ for ( int i = 0; i < vlc_array_count(&p_sys->es); ++i ) {
+ if ( ((fmt_es_pair_t*)vlc_array_item_at_index(&p_sys->es, i))->p_es == p_es )
+ return i;
+ }
+ return -1;
+}
+
+static es_out_id_t *esOutAdd( es_out_t *p_out, const es_format_t *p_fmt )
+{
+ demux_sys_t *p_sys = p_out->p_sys->p_demux->p_sys;
+ es_format_t fmt;
+
+ es_format_Copy(&fmt, p_fmt);
+ switch (fmt.i_cat)
+ {
+ case VIDEO_ES:
+ if ( p_sys->i_video_stream != -1 && p_sys->i_video_stream != p_fmt->i_id )
+ fmt.i_priority = -2;
+ break ;
+ case AUDIO_ES:
+ if ( p_sys->i_audio_stream != -1 && p_sys->i_audio_stream != p_fmt->i_id )
+ fmt.i_priority = -2;
+ break ;
+ case SPU_ES:
+ break ;
+ }
+
+ es_out_id_t *p_es = es_out_Add( p_out->p_sys->p_demux->out, &fmt );
+ if ( p_fmt->i_id >= 0 ) {
+ /* Ensure we are not overriding anything */
+ int idx = findEsPairIndex(p_sys, p_fmt->i_id);
+ if ( idx == -1 ) {
+ fmt_es_pair_t *p_pair = malloc( sizeof(*p_pair) );
+ if ( likely(p_pair != NULL) ) {
+ p_pair->i_id = p_fmt->i_id;
+ p_pair->p_es = p_es;
+ msg_Info( p_out->p_sys->p_demux, "Adding ES %d", p_fmt->i_id );
+ vlc_array_append(&p_sys->es, p_pair);
+ }
+ }
+ }
+ es_format_Clean(&fmt);
+ return p_es;
+}
+
+static int esOutSend( es_out_t *p_out, es_out_id_t *p_es, block_t *p_block )
+{
+ return es_out_Send( p_out->p_sys->p_demux->out, p_es, p_block );
+}
+
+static void esOutDel( es_out_t *p_out, es_out_id_t *p_es )
+{
+ int idx = findEsPairIndexByEs( p_out->p_sys->p_demux->p_sys, p_es );
+ if (idx >= 0)
+ {
+ free( vlc_array_item_at_index( &p_out->p_sys->p_demux->p_sys->es, idx) );
+ vlc_array_remove(&p_out->p_sys->p_demux->p_sys->es, idx);
+ }
+ es_out_Del( p_out->p_sys->p_demux->out, p_es );
+}
+
+static int esOutControl( es_out_t *p_out, int i_query, va_list args )
+{
+ return es_out_vaControl( p_out->p_sys->p_demux->out, i_query, args );
+}
+
+static void esOutDestroy( es_out_t *p_out )
+{
+ for ( int i = 0; i < vlc_array_count(&p_out->p_sys->p_demux->p_sys->es); ++i )
+ free( vlc_array_item_at_index(&p_out->p_sys->p_demux->p_sys->es, i) );
+ vlc_array_clear(&p_out->p_sys->p_demux->p_sys->es);
+ free( p_out->p_sys );
+ free( p_out );
+}
+
+static es_out_t *esOutNew( demux_t *p_demux )
+{
+ assert( vlc_array_count(&p_demux->p_sys->es) == 0 );
+ es_out_t *p_out = malloc( sizeof(*p_out) );
+ if ( unlikely(p_out == NULL) )
+ return NULL;
+
+ p_out->pf_add = &esOutAdd;
+ p_out->pf_control = &esOutControl;
+ p_out->pf_del = &esOutDel;
+ p_out->pf_destroy = &esOutDestroy;
+ p_out->pf_send = &esOutSend;
+
+ p_out->p_sys = malloc( sizeof(*p_out->p_sys) );
+ if ( unlikely( p_out->p_sys == NULL ) ) {
+ free( p_out );
+ return NULL;
+ }
+ p_out->p_sys->p_demux = p_demux;
+ return p_out;
+}
+