[vlc-devel] [PATCH 5/6] es_out: add a new ES track identifier

Thomas Guillem thomas at gllm.fr
Wed Aug 29 14:24:30 CEST 2018


Add the vlc_es_t structure representing an ES track.

This new struct will be used to fetch tracks information (via vlc_es_GetInfo())
and to select/unselect/restart tracks.

Users will receive this new struct from input thread event callbacks. They will
be able to hold/release it (and fetch tracks informations even after the track
is terminated by the es_out).

ES Tracks will still be selectable via their i_id (for TS cases) and legacy
track selection via "video-es"/"audio-es"/"spu-es" is still functional.
---
 include/vlc_common.h |   1 +
 include/vlc_es.h     |  75 +++++++++
 include/vlc_input.h  |  18 ++-
 src/input/es_out.c   | 353 ++++++++++++++++++++++++++++++-------------
 src/input/event.c    |  58 +------
 src/input/event.h    |   7 +-
 src/input/var.c      |  35 +++--
 7 files changed, 362 insertions(+), 185 deletions(-)

diff --git a/include/vlc_common.h b/include/vlc_common.h
index 3be979dab5..6c32e0f232 100644
--- a/include/vlc_common.h
+++ b/include/vlc_common.h
@@ -372,6 +372,7 @@ typedef struct video_format_t video_format_t;
 typedef struct subs_format_t subs_format_t;
 typedef struct es_format_t es_format_t;
 typedef struct video_palette_t video_palette_t;
+typedef struct vlc_es_t vlc_es_t;
 
 /* Audio */
 typedef struct audio_output audio_output_t;
diff --git a/include/vlc_es.h b/include/vlc_es.h
index 7a14b9271f..187e9f4ec1 100644
--- a/include/vlc_es.h
+++ b/include/vlc_es.h
@@ -680,4 +680,79 @@ static inline void es_format_Change( es_format_t *fmt, int i_cat, vlc_fourcc_t i
     es_format_Init( fmt, i_cat, i_codec );
 }
 
+/**
+ * Structure filled by vlc_es_GetInfo()
+ *
+ * Clean it with vlc_es_info_Clean()
+ */
+struct vlc_es_info
+{
+    /** Title of the ES track. Updated after a
+     * vlc_input_event_es::VLC_INPUT_ES_UPDATED event */
+    char *title;
+    /** Format of the ES track. Updated after a
+     * vlc_input_event_es::VLC_INPUT_ES_UPDATED event */
+    es_format_t fmt;
+    /** Selected state of the ES track. Updated after
+     * vlc_input_event_es::VLC_INPUT_ES_SELECTED and
+     * vlc_input_event_es::VLC_INPUT_ES_UNSELECTED events */
+    bool selected;
+    /** Terminated state, the ES track can't be selected if set to true.
+     * Updated after a vlc_input_event_es::VLC_INPUT_ES_DELETED event. */
+    bool terminated;
+};
+
+/**
+ * Clean the ES track information filled by vlc_es_GetInfo()
+ *
+ * @param info pointer to the ES track information
+ */
+static inline void vlc_es_info_Clean(struct vlc_es_info *info)
+{
+    free(info->title);
+    es_format_Clean(&info->fmt);
+}
+
+/**
+ * Increase the ES track reference count.
+ *
+ * Any held ES tracks must be released with vlc_es_Release().
+ *
+ * @param es pointer to the ES track
+ *
+ * @return the same ES pointer, for convenience
+ */
+VLC_API vlc_es_t *
+vlc_es_Hold(vlc_es_t *es);
+
+/**
+ * Decrease the ES track reference count.
+ *
+ * @param es pointer to the ES track
+ */
+VLC_API void
+vlc_es_Release(vlc_es_t *es);
+
+/**
+ * Get the ES track information.
+ *
+ * @param es pointer to the ES track
+ * @param info pre-allocated struct filled by this function, invalid in case of
+ * error, clean it with vlc_es_info_Clean() in case of success
+ *
+ * @return VLC_SUCCESS or VLC_ENOMEM in case of allocation error
+ */
+VLC_API int vlc_es_GetInfo(vlc_es_t *es, struct vlc_es_info *info);
+
+/**
+ * Get the ES track id
+ *
+ * The returned id is the same than the vlc_es_info.fmt one returned by
+ * vlc_es_GetInfo()
+ *
+ * @param es pointer to the es track
+ * @return the es track id (always valid)
+ */
+VLC_API int vlc_es_GetId(vlc_es_t *es);
+
 #endif
diff --git a/include/vlc_input.h b/include/vlc_input.h
index 890bcc8a6b..b03cb1092f 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -426,14 +426,18 @@ struct vlc_input_event_program {
 
 struct vlc_input_event_es {
     enum {
-        VLC_INPUT_ES_ADDED,
-        VLC_INPUT_ES_DELETED,
-        VLC_INPUT_ES_UPDATED,
-        VLC_INPUT_ES_SELECTED,
-        VLC_INPUT_ES_UNSELECTED,
+
+        VLC_INPUT_ES_ADDED,     /**< A new ES was added, get the ES track
+                                     information with vlc_es_GetInfo() */
+        VLC_INPUT_ES_DELETED,   /**< vlc_es_info.terminated changed to true */
+        VLC_INPUT_ES_UPDATED,   /**< vlc_es_info.fmt or vlc_es_info.title changed */
+        VLC_INPUT_ES_SELECTED,  /**< vlc_es_info.selected changed to true */
+        VLC_INPUT_ES_UNSELECTED,/**< vlc_es_info.selected changed to false */
     } action;
-    const char *title;
-    const es_format_t *fmt;
+    /**
+     * ES track id: only valid from the event callback, unless the id is held
+     * by the user with vlc_es_Hold(). */
+    vlc_es_t *id;
 };
 
 struct vlc_input_event_signal {
diff --git a/src/input/es_out.c b/src/input/es_out.c
index aab4493976..02069eb57f 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -76,10 +76,23 @@ typedef struct
     struct vlc_list node;
 } es_out_pgrm_t;
 
+
+/**
+ * Opaque structure representing an ES (Elementary Stream) track.
+ *
+ * This structure is propagated via the vlc_input_event_es event
+ */
+struct vlc_es_t
+{
+};
+
 struct es_out_id_t
 {
+    vlc_es_t id;
+
     /* ES ID */
     int       i_id;
+    size_t    i_pos; /* position, used to get the title of the track */
     es_out_pgrm_t *p_pgrm;
 
     /* */
@@ -88,10 +101,22 @@ struct es_out_id_t
 
     /* Channel in the track type */
     int         i_channel;
+
+    vlc_atomic_rc_t rc;
+
+    /* Lock to protect the following variables. These variables can be read by
+     * any threads via vlc_es_GetInfo(). */
+    vlc_mutex_t lock;
     es_format_t fmt;
     char        *psz_language;
     char        *psz_language_code;
     bool         b_selected;
+    bool         b_terminated;
+
+    /* Codec and original fourcc coming from the demuxer. Used by
+     * EsOutUpdateInfo() */
+    vlc_fourcc_t i_input_codec;
+    vlc_fourcc_t i_input_original_fourcc;
 
     decoder_t   *p_dec;
     decoder_t   *p_dec_record;
@@ -192,7 +217,7 @@ static void         EsOutDel    ( es_out_t *, es_out_id_t * );
 
 static void         EsOutTerminate( es_out_t * );
 static void         EsOutSelect( es_out_t *, es_out_id_t *es, bool b_force );
-static void         EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const es_format_t *, const vlc_meta_t * );
+static void         EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const vlc_meta_t * );
 static int          EsOutSetRecord(  es_out_t *, bool b_record );
 
 static void EsOutSelectEs( es_out_t *out, es_out_id_t *es );
@@ -205,6 +230,8 @@ static void EsOutProgramsChangeRate( es_out_t *out );
 static void EsOutDecodersStopBuffering( es_out_t *out, bool b_forced );
 static void EsOutGlobalMeta( es_out_t *p_out, const vlc_meta_t *p_meta );
 static void EsOutMeta( es_out_t *p_out, const vlc_meta_t *p_meta, const vlc_meta_t *p_progmeta );
+static int EsOutEsUpdateFmt( es_out_t *out, es_out_id_t *es,
+                             const es_format_t *fmt, bool from_decoder );
 
 static char *LanguageGetName( const char *psz_code );
 static char *LanguageGetCode( const char *psz_lang );
@@ -338,7 +365,70 @@ es_out_t *input_EsOutNew( input_thread_t *p_input, int i_rate )
  *****************************************************************************/
 static void EsMarkSelected(es_out_id_t *es, bool b_selected)
 {
+    vlc_mutex_lock(&es->lock);
     es->b_selected = b_selected;
+    vlc_mutex_unlock(&es->lock);
+}
+
+static void EsTerminate(es_out_id_t *es)
+{
+    vlc_list_remove(&es->node);
+
+    vlc_mutex_lock(&es->lock);
+    es->b_terminated = true;
+    vlc_mutex_unlock(&es->lock);
+}
+
+static char *EsGetTitle( es_out_id_t *es )
+{
+    const es_format_t *fmt = &es->fmt;
+    char *title;
+
+    /* Take care of the ES description */
+    if( fmt->psz_description && *fmt->psz_description )
+    {
+        if( es->psz_language && *es->psz_language )
+        {
+            if( asprintf( &title, "%s - [%s]", fmt->psz_description,
+                          es->psz_language ) == -1 )
+                title = NULL;
+        }
+        else
+            title = strdup( fmt->psz_description );
+    }
+    else
+    {
+        if( es->psz_language && *es->psz_language )
+        {
+            if( asprintf( &title, "%s %zu - [%s]", _("Track"),
+                          es->i_pos, es->psz_language ) == -1 )
+                title = NULL;
+        }
+        else
+        {
+            if( asprintf( &title, "%s %zu", _("Track"), es->i_pos ) == -1 )
+                title = NULL;
+        }
+    }
+
+    return title;
+}
+
+static void EsRelease(es_out_id_t *es)
+{
+    if (vlc_atomic_rc_dec(&es->rc))
+    {
+        free(es->psz_language);
+        free(es->psz_language_code);
+        es_format_Clean(&es->fmt);
+        vlc_mutex_destroy(&es->lock);
+        free(es);
+    }
+}
+
+static void EsHold(es_out_id_t *es)
+{
+    vlc_atomic_rc_inc(&es->rc);
 }
 
 static void EsOutDelete( es_out_t *out )
@@ -370,11 +460,8 @@ static void EsOutTerminate( es_out_t *out )
         if (es->p_dec != NULL)
             input_DecoderDelete(es->p_dec);
 
-        free(es->psz_language);
-        free(es->psz_language_code);
-        es_format_Clean(&es->fmt);
-        vlc_list_remove(&es->node);
-        free(es);
+        EsTerminate(es);
+        EsRelease(es);
     }
 
     /* FIXME duplicate work EsOutProgramDel (but we cannot use it) add a EsOutProgramClean ? */
@@ -923,62 +1010,22 @@ static vlc_tick_t EsOutGetBuffering( es_out_t *out )
     return i_delay;
 }
 
-static void EsOutSendEsEventGeneric( es_out_t *out, int i_id,
-                                     const es_format_t *fmt, const char *psz_language,
-                                     bool b_delete )
+static void EsOutSendEsEvent( es_out_t *out, es_out_id_t *es, int action )
 {
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
-    input_thread_t    *p_input = p_sys->p_input;
-    vlc_value_t       text;
-    es_out_id_t       *es;
-    size_t count = 0;
-
-    if( b_delete )
-    {
-        input_SendEventEsDel( p_input, fmt );
-        return;
-    }
-
-    /* Get the number of ES already added */
-    foreach_es_then_es_slaves(es)
-        if( es->fmt.i_cat == fmt->i_cat )
-            count++;
-
-    /* Take care of the ES description */
-    if( fmt->psz_description && *fmt->psz_description )
-    {
-        if( psz_language && *psz_language )
-        {
-            if( asprintf( &text.psz_string, "%s - [%s]", fmt->psz_description,
-                          psz_language ) == -1 )
-                text.psz_string = NULL;
-        }
-        else text.psz_string = strdup( fmt->psz_description );
-    }
-    else
+    input_thread_t *p_input = p_sys->p_input;
+    if( action == VLC_INPUT_ES_ADDED )
     {
-        if( psz_language && *psz_language )
-        {
-            if( asprintf( &text.psz_string, "%s %zu - [%s]", _("Track"), count,
-                          psz_language ) == -1 )
-                text.psz_string = NULL;
-        }
-        else
-        {
-            if( asprintf( &text.psz_string, "%s %zu", _("Track"), count ) == -1 )
-                text.psz_string = NULL;
-        }
+        input_thread_private_t *priv = input_priv(p_input);
+        /*FIXME: see input_SlaveSourceAdd */
+        priv->i_last_es_cat = es->fmt.i_cat;
+        priv->i_last_es_id = es->fmt.i_id;
     }
 
-    input_SendEventEsAdd( p_input, fmt, text.psz_string );
-
-    free( text.psz_string );
-}
-
-static void EsOutSendEsEvent( es_out_t *out, es_out_id_t *es,
-                           bool b_delete )
-{
-    EsOutSendEsEventGeneric( out, es->i_id, &es->fmt, es->psz_language, b_delete );
+    input_SendEventEs(p_input, &(struct vlc_input_event_es) {
+        .action = action,
+        .id = &es->id,
+    });
 }
 
 static bool EsOutIsProgramVisible( es_out_t *out, int i_group )
@@ -1011,7 +1058,7 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
              && p_sys->i_mode != ES_OUT_MODE_ALL)
                 EsOutUnselectEs(out, es, true);
             if (es->p_pgrm == old)
-                input_SendEventEsDel( p_input, &es->fmt );
+                EsOutSendEsEvent( out, es, VLC_INPUT_ES_DELETED );
         }
 
         p_sys->audio.p_main_es = NULL;
@@ -1037,8 +1084,8 @@ static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
     {
         if (es->p_pgrm == p_sys->p_pgrm)
         {
-            EsOutSendEsEvent(out, es, false);
-            EsOutUpdateInfo(out, es, &es->fmt, NULL);
+            EsOutSendEsEvent(out, es, VLC_INPUT_ES_ADDED);
+            EsOutUpdateInfo(out, es, NULL);
         }
 
         EsOutSelect(out, es, false);
@@ -1539,6 +1586,13 @@ static es_out_id_t *EsOutAddSlaveLocked( es_out_t *out, const es_format_t *fmt,
         return NULL;
     }
 
+    /* Get the number of ES already added in order to get the position of the es */
+    es->i_pos = 0;
+    es_out_id_t *it;
+    foreach_es_then_es_slaves(it)
+        if( it->fmt.i_cat == fmt->i_cat )
+            es->i_pos++;
+
     /* Increase ref count for program */
     p_pgrm->i_es++;
 
@@ -1550,11 +1604,15 @@ static es_out_id_t *EsOutAddSlaveLocked( es_out_t *out, const es_format_t *fmt,
     if( !es->fmt.i_original_fourcc )
         es->fmt.i_original_fourcc = es->fmt.i_codec;
 
+    es->i_input_original_fourcc = es->fmt.i_original_fourcc;
+    es->i_input_codec = es->fmt.i_codec;
+
     es->i_id = es->fmt.i_id;
     es->i_meta_id = p_sys->i_id++; /* always incremented */
     es->b_scrambled = false;
     es->b_forced = false;
     es->b_selected = false;
+    es->b_terminated = false;
 
     switch( es->fmt.i_cat )
     {
@@ -1624,10 +1682,13 @@ static es_out_id_t *EsOutAddSlaveLocked( es_out_t *out, const es_format_t *fmt,
 
     vlc_list_append(&es->node, es->p_master ? &p_sys->es_slaves : &p_sys->es);
 
+    vlc_mutex_init(&es->lock);
+    vlc_atomic_rc_init(&es->rc);
+
     if( es->p_pgrm == p_sys->p_pgrm )
-        EsOutSendEsEvent( out, es, false );
+        EsOutSendEsEvent( out, es, VLC_INPUT_ES_ADDED );
 
-    EsOutUpdateInfo( out, es, &es->fmt, NULL );
+    EsOutUpdateInfo( out, es, NULL );
     EsOutSelect( out, es, false );
 
     if( es->b_scrambled )
@@ -1765,14 +1826,11 @@ static void EsOutSelectEs( es_out_t *out, es_out_id_t *es )
 
     /* Mark it as selected */
     EsMarkSelected(es, true);
-    input_SendEventEsSelect( p_input, &es->fmt );
+    EsOutSendEsEvent(out, es, VLC_INPUT_ES_SELECTED);
 }
 
 static void EsDeleteCCChannels( es_out_t *out, es_out_id_t *parent )
 {
-    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
-    input_thread_t *p_input = p_sys->p_input;
-
     if( parent->cc.type == 0 )
         return;
 
@@ -1789,7 +1847,7 @@ static void EsDeleteCCChannels( es_out_t *out, es_out_id_t *parent )
         {
             /* Force unselection of the CC */
             EsMarkSelected(parent->cc.pp_es[i], false);
-            input_SendEventEsUnselect( p_input, &parent->cc.pp_es[i]->fmt );
+            EsOutSendEsEvent(out, parent->cc.pp_es[i], VLC_INPUT_ES_UNSELECTED);
         }
         EsOutDelLocked( out, parent->cc.pp_es[i] );
     }
@@ -1831,7 +1889,7 @@ static void EsOutUnselectEs( es_out_t *out, es_out_id_t *es, bool b_update )
         return;
 
     /* Mark it as unselected */
-    input_SendEventEsUnselect( p_input, &es->fmt );
+    EsOutSendEsEvent(out, es, VLC_INPUT_ES_UNSELECTED);
 }
 
 /**
@@ -2103,7 +2161,11 @@ static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
     vlc_meta_t  *p_meta_dsc;
     if( input_DecoderHasFormatChanged( es->p_dec, &fmt_dsc, &p_meta_dsc ) )
     {
-        EsOutUpdateInfo( out, es, &fmt_dsc, p_meta_dsc );
+        fmt_dsc.i_id = es->i_id; /* decoder may overwrite it */
+        if (EsOutEsUpdateFmt( out, es, &fmt_dsc, true) == VLC_SUCCESS)
+            EsOutSendEsEvent(out, es, VLC_INPUT_ES_UPDATED);
+
+        EsOutUpdateInfo(out, es, p_meta_dsc);
 
         es_format_Clean( &fmt_dsc );
         if( p_meta_dsc )
@@ -2163,13 +2225,13 @@ static void EsOutDelLocked( es_out_t *out, es_out_id_t *es )
         EsOutUnselectEs( out, es, es->p_pgrm == p_sys->p_pgrm );
     }
 
+    EsTerminate(es);
+
     if( es->p_pgrm == p_sys->p_pgrm )
-        EsOutSendEsEvent( out, es, true );
+        EsOutSendEsEvent( out, es, VLC_INPUT_ES_DELETED );
 
     EsOutDeleteInfoEs( out, es );
 
-    vlc_list_remove(&es->node);
-
     /* Update program */
     es->p_pgrm->i_es--;
     if( es->p_pgrm->i_es == 0 )
@@ -2199,7 +2261,7 @@ static void EsOutDelLocked( es_out_t *out, es_out_id_t *es )
             {
                 if (other->b_selected)
                 {
-                    input_SendEventEsSelect(p_sys->p_input, &es->fmt);
+                    EsOutSendEsEvent(out, es, VLC_INPUT_ES_SELECTED);
                     if( p_esprops->p_main_es == NULL )
                         p_esprops->p_main_es = other;
                 }
@@ -2208,12 +2270,7 @@ static void EsOutDelLocked( es_out_t *out, es_out_id_t *es )
             }
     }
 
-    free( es->psz_language );
-    free( es->psz_language_code );
-
-    es_format_Clean( &es->fmt );
-
-    free( es );
+    EsRelease(es);
 }
 
 static void EsOutDel( es_out_t *out, es_out_id_t *es )
@@ -2355,7 +2412,11 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         else if( es == es_cat + SPU_ES )
             i_cat = SPU_ES;
         else
+        {
+            if (es->b_terminated)
+                return VLC_EGENERIC;
             i_cat = IGNORE_ES;
+        }
 
         foreach_es_then_es_slaves(other)
         {
@@ -2398,6 +2459,8 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
     case ES_OUT_UNSET_ES:
     {
         es_out_id_t *es = va_arg( args, es_out_id_t * ), *other;
+        if (es->b_terminated)
+            return VLC_EGENERIC;
         foreach_es_then_es_slaves(other)
         {
             if (es == other)
@@ -2609,8 +2672,11 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
          || es->fmt.i_id != p_fmt->i_id )
             return VLC_EGENERIC;
 
-        es_format_Clean( &es->fmt );
-        es_format_Copy( &es->fmt, p_fmt );
+        int ret = EsOutEsUpdateFmt( out, es, p_fmt, false );
+        if( ret != VLC_SUCCESS )
+            return ret;
+
+        EsOutSendEsEvent(out, es, VLC_INPUT_ES_UPDATED);
 
         if( es->p_dec )
         {
@@ -3113,50 +3179,84 @@ static int LanguageArrayIndex( char **ppsz_langs, const char *psz_lang )
     return -1;
 }
 
-/****************************************************************************
- * EsOutUpdateInfo:
- * - add meta info to the playlist item
- ****************************************************************************/
-static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *fmt, const vlc_meta_t *p_meta )
+static int EsOutEsUpdateFmt( es_out_t *out, es_out_id_t *es,
+                             const es_format_t *fmt, bool from_decoder )
 {
     es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
     input_thread_t *p_input = p_sys->p_input;
-    const es_format_t *p_fmt_es = &es->fmt;
 
-    if( es->fmt.i_cat == fmt->i_cat )
+    assert( es->fmt.i_cat == fmt->i_cat && es->fmt.i_id == fmt->i_id );
+
+    es_format_t update = *fmt;
+
+    vlc_mutex_lock( &es->lock );
+
+    /* Update infos that could have been lost by the decoder */
+    if (from_decoder)
     {
-        es_format_t update = *fmt;
         update.i_codec = es->fmt.i_codec;
         update.i_original_fourcc = es->fmt.i_original_fourcc;
 
-        /* Update infos that could have been lost by the decoder (no need to
-         * dup them since input_item_UpdateTracksInfo() will do it). */
         if (update.psz_language == NULL)
+        {
             update.psz_language = es->fmt.psz_language;
+            es->fmt.psz_language = NULL;
+        }
+        else
+        {
+            free( es->psz_language );
+            free( es->psz_language_code );
+        }
         if (update.psz_description == NULL)
+        {
             update.psz_description = es->fmt.psz_description;
+            es->fmt.psz_description = NULL;
+        }
         if (update.i_cat == SPU_ES)
         {
             if (update.subs.psz_encoding == NULL)
+            {
                 update.subs.psz_encoding = es->fmt.subs.psz_encoding;
+                es->fmt.subs.psz_encoding = NULL;
+            }
         }
         if (update.i_extra_languages == 0)
         {
             assert(update.p_extra_languages == NULL);
             update.i_extra_languages = es->fmt.i_extra_languages;
             update.p_extra_languages = es->fmt.p_extra_languages;
+            es->fmt.i_extra_languages = 0;
+            es->fmt.p_extra_languages = NULL;
         }
+    }
 
-        /* No need to update codec specific data */
-        update.i_extra = 0;
-        update.p_extra = NULL;
+    es_format_Clean(&es->fmt);
+    int ret = es_format_Copy(&es->fmt, &update);
+    if (ret == VLC_SUCCESS)
+    {
+        free( es->psz_language );
+        free( es->psz_language_code );
 
-        input_SendEventEsUpdate(p_input, &update);
+        es->psz_language = LanguageGetName( es->fmt.psz_language );
+        es->psz_language_code = LanguageGetCode( es->fmt.psz_language );
 
-        update.i_id = es->i_meta_id;
-        input_item_UpdateTracksInfo(input_GetItem(p_input), &update);
+        input_item_UpdateTracksInfo(input_GetItem(p_input), &es->fmt);
     }
 
+    vlc_mutex_unlock( &es->lock );
+    return ret;
+}
+
+/****************************************************************************
+ * EsOutUpdateInfo:
+ * - add meta info to the playlist item
+ ****************************************************************************/
+static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const vlc_meta_t *p_meta )
+{
+    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
+    input_thread_t *p_input = p_sys->p_input;
+    const es_format_t *fmt = &es->fmt;
+
     /* Create category */
     char* psz_cat = EsInfoCategoryName( es );
 
@@ -3175,10 +3275,9 @@ static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *
         info_category_AddInfo( p_cat, _("Original ID"),
                        "%d", es->i_id );
 
-    const vlc_fourcc_t i_codec_fourcc = ( p_fmt_es->i_original_fourcc )?
-                               p_fmt_es->i_original_fourcc : p_fmt_es->i_codec;
+    const vlc_fourcc_t i_codec_fourcc = es->i_input_original_fourcc;
     const char *psz_codec_description =
-        vlc_fourcc_GetDescription( p_fmt_es->i_cat, i_codec_fourcc );
+        vlc_fourcc_GetDescription( fmt->i_cat, i_codec_fourcc );
     if( psz_codec_description && *psz_codec_description )
         info_category_AddInfo( p_cat, _("Codec"), "%s (%.4s)",
                                psz_codec_description, (char*)&i_codec_fourcc );
@@ -3212,7 +3311,7 @@ static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *
 
         unsigned int i_bitspersample = fmt->audio.i_bitspersample;
         if( i_bitspersample == 0 )
-            i_bitspersample = aout_BitsPerSample( p_fmt_es->i_codec );
+            i_bitspersample = aout_BitsPerSample( fmt->i_codec );
         if( i_bitspersample != 0 )
             info_category_AddInfo( p_cat, _("Bits per sample"), "%u",
                                    i_bitspersample );
@@ -3263,7 +3362,7 @@ static void EsOutUpdateInfo( es_out_t *out, es_out_id_t *es, const es_format_t *
                                       (double)fmt->video.i_frame_rate
                                       / (double)fmt->video.i_frame_rate_base );
        }
-       if( fmt->i_codec != p_fmt_es->i_codec )
+       if( fmt->i_codec != es->i_input_codec )
        {
            const char *psz_chroma_description =
                 vlc_fourcc_GetDescription( VIDEO_ES, fmt->i_codec );
@@ -3489,3 +3588,53 @@ static void EsOutDeleteInfoEs( es_out_t *out, es_out_id_t *es )
         free( psz_info_category );
     }
 }
+
+static inline es_out_id_t *vlc_es_get_id( vlc_es_t *es )
+{
+    return container_of( es, es_out_id_t, id );
+}
+
+vlc_es_t *
+vlc_es_Hold(vlc_es_t *es)
+{
+    EsHold(vlc_es_get_id(es));
+    return es;
+}
+
+void
+vlc_es_Release(vlc_es_t *es)
+{
+    EsRelease(vlc_es_get_id(es));
+}
+
+int
+vlc_es_GetInfo(vlc_es_t *es, struct vlc_es_info *info)
+{
+    es_out_id_t *esid = vlc_es_get_id(es);
+
+    vlc_mutex_lock(&esid->lock);
+
+    info->title = EsGetTitle(esid);
+    int ret = es_format_Copy(&info->fmt, &esid->fmt);
+    if (!info->title || ret != VLC_SUCCESS)
+    {
+        free(info->title);
+        vlc_mutex_unlock(&esid->lock);
+        return VLC_ENOMEM;
+    }
+
+    info->fmt.i_original_fourcc = esid->i_input_original_fourcc;
+    info->selected = esid->b_selected;
+    info->terminated = esid->b_terminated;
+
+    vlc_mutex_unlock(&esid->lock);
+
+    return VLC_SUCCESS;
+}
+
+int
+vlc_es_GetId(vlc_es_t *es)
+{
+    /* This variable is const, no lock required */
+    return vlc_es_get_id(es)->i_id;
+}
diff --git a/src/input/event.c b/src/input/event.c
index ba9f39b629..e15a0d9e76 100644
--- a/src/input/event.c
+++ b/src/input/event.c
@@ -218,64 +218,12 @@ void input_SendEventProgramScrambled( input_thread_t *p_input, int i_group, bool
     });
 }
 
-void input_SendEventEsAdd( input_thread_t *p_input, const es_format_t *p_fmt,
-                           const char *psz_title)
-{
-    input_thread_private_t *priv = input_priv(p_input);
-    priv->i_last_es_cat = p_fmt->i_cat;
-    priv->i_last_es_id = p_fmt->i_id;
-
-    input_SendEvent( p_input, &(struct vlc_input_event) {
-        .type = INPUT_EVENT_ES,
-        .es = {
-            .action = VLC_INPUT_ES_ADDED,
-            .title = psz_title,
-            .fmt = p_fmt,
-        }
-    });
-}
-void input_SendEventEsUpdate( input_thread_t *p_input, const es_format_t *p_fmt )
-{
-    input_SendEvent( p_input, &(struct vlc_input_event) {
-        .type = INPUT_EVENT_ES,
-        .es = {
-            .action = VLC_INPUT_ES_UPDATED,
-            .fmt = p_fmt,
-        }
-    });
-}
-void input_SendEventEsDel( input_thread_t *p_input,
-                           const es_format_t *p_fmt )
+void input_SendEventEs( input_thread_t *p_input,
+                        const struct vlc_input_event_es *es_event )
 {
     input_SendEvent( p_input, &(struct vlc_input_event) {
         .type = INPUT_EVENT_ES,
-        .es = {
-            .action = VLC_INPUT_ES_DELETED,
-            .fmt = p_fmt,
-        }
-    });
-}
-void input_SendEventEsSelect( input_thread_t *p_input,
-                              const es_format_t *p_fmt )
-{
-    input_SendEvent( p_input, &(struct vlc_input_event) {
-        .type = INPUT_EVENT_ES,
-        .es = {
-            .action = VLC_INPUT_ES_SELECTED,
-            .fmt = p_fmt,
-        }
-    });
-}
-
-void input_SendEventEsUnselect( input_thread_t *p_input,
-                                const es_format_t *p_fmt )
-{
-    input_SendEvent( p_input, &(struct vlc_input_event) {
-        .type = INPUT_EVENT_ES,
-        .es = {
-            .action = VLC_INPUT_ES_UNSELECTED,
-            .fmt = p_fmt,
-        }
+        .es = *es_event,
     });
 }
 
diff --git a/src/input/event.h b/src/input/event.h
index 5057458565..a2fcfe5541 100644
--- a/src/input/event.h
+++ b/src/input/event.h
@@ -60,12 +60,7 @@ void input_SendEventProgramDel( input_thread_t *p_input, int i_program );
 void input_SendEventProgramSelect( input_thread_t *p_input, int i_program );
 void input_SendEventProgramScrambled( input_thread_t *p_input, int i_group, bool b_scrambled );
 
-void input_SendEventEsDel( input_thread_t *p_input, const es_format_t *fmt );
-void input_SendEventEsAdd( input_thread_t *p_input,
-                           const es_format_t *fmt, const char *psz_title );
-void input_SendEventEsUpdate( input_thread_t *p_input, const es_format_t *fmt );
-void input_SendEventEsSelect( input_thread_t *p_input, const es_format_t *fmt );
-void input_SendEventEsUnselect( input_thread_t *p_input, const es_format_t *fmt );
+void input_SendEventEs( input_thread_t *p_input, const struct vlc_input_event_es *es_event );
 
 /*****************************************************************************
  * Event for decoder.c
diff --git a/src/input/var.c b/src/input/var.c
index 9795785ef9..d2b401de15 100644
--- a/src/input/var.c
+++ b/src/input/var.c
@@ -325,11 +325,15 @@ void input_LegacyEvents( input_thread_t *p_input, void *user_data,
             }
             break;
         case INPUT_EVENT_ES:
+        {
+            struct vlc_es_info info;
+            if (vlc_es_GetInfo(event->es.id, &info) != VLC_SUCCESS)
+                break;
             switch (event->es.action)
             {
                 case VLC_INPUT_ES_ADDED:
                 {
-                    const char *varname = GetEsVarName( event->es.fmt->i_cat );
+                    const char *varname = GetEsVarName( info.fmt.i_cat );
                     if( varname )
                     {
                         size_t count;
@@ -339,47 +343,48 @@ void input_LegacyEvents( input_thread_t *p_input, void *user_data,
                             /* First one, we need to add the "Disable" choice */
                             VarListAdd( p_input, varname, -1, _("Disable") );
                         }
-                        VarListAdd( p_input, varname, event->es.fmt->i_id,
-                                    event->es.title );
+                        VarListAdd( p_input, varname, info.fmt.i_id, info.title );
                     }
 
-                    if( EsFmtIsTeletext( event->es.fmt ) )
+                    if( EsFmtIsTeletext( &info.fmt ) )
                     {
                         char psz_page[3+1];
                         snprintf( psz_page, sizeof(psz_page), "%d%2.2x",
-                                  event->es.fmt->subs.teletext.i_magazine,
-                                  event->es.fmt->subs.teletext.i_page );
-                        VarListAdd( p_input, "teletext-es", event->es.fmt->i_id,
-                                    event->es.fmt->subs.teletext.i_magazine >= 0 ? psz_page : "" );
+                                  info.fmt.subs.teletext.i_magazine,
+                                  info.fmt.subs.teletext.i_page );
+                        VarListAdd( p_input, "teletext-es", info.fmt.i_id,
+                                    info.fmt.subs.teletext.i_magazine >= 0 ? psz_page : "" );
                     }
                     break;
                 }
                 case VLC_INPUT_ES_DELETED:
                 {
-                    const char *varname = GetEsVarName( event->es.fmt->i_cat );
+                    const char *varname = GetEsVarName( info.fmt.i_cat );
                     if( varname )
-                        VarListDel( p_input, varname, event->es.fmt->i_id );
+                        VarListDel( p_input, varname, info.fmt.i_id );
 
-                    if( EsFmtIsTeletext( event->es.fmt ) )
-                        VarListDel( p_input, "teletext-es", event->es.fmt->i_id );
+                    if( EsFmtIsTeletext( &info.fmt ) )
+                        VarListDel( p_input, "teletext-es", info.fmt.i_id );
                     break;
                 }
                 case VLC_INPUT_ES_SELECTED:
                 case VLC_INPUT_ES_UNSELECTED:
                 {
                     int i_id = event->es.action == VLC_INPUT_ES_SELECTED
-                             ? event->es.fmt->i_id : -1;
-                    const char *varname = GetEsVarName( event->es.fmt->i_cat );
+                             ? info.fmt.i_id : -1;
+                    const char *varname = GetEsVarName( info.fmt.i_cat );
                     if( varname )
                         VarListSelect( p_input, varname, i_id );
-                    if( EsFmtIsTeletext( event->es.fmt ) )
+                    if( EsFmtIsTeletext( &info.fmt ) )
                         VarListSelect( p_input, "teletext-es", i_id );
                     break;
                 }
                 case VLC_INPUT_ES_UPDATED:
                     break;
             }
+            vlc_es_info_Clean(&info);
             break;
+        }
         case INPUT_EVENT_RECORD:
             val.b_bool = event->record;
             var_Change( p_input, "record", VLC_VAR_SETVALUE, val );
-- 
2.18.0



More information about the vlc-devel mailing list