[vlc-devel] [PATCH 01/16] Add vlc_player_SelectTrackList

Roland Bewick roland.bewick at gmail.com
Tue May 21 20:08:25 CEST 2019


---
 include/vlc_es_out.h                          |  1 +
 include/vlc_player.h                          | 26 ++++++++
 modules/access/bluray.c                       |  1 +
 modules/demux/adaptive/plumbing/FakeESOut.cpp |  1 +
 src/input/es_out.c                            | 44 ++++++++++++++
 src/input/es_out_timeshift.c                  |  1 +
 src/input/input.c                             | 22 +++++++
 src/input/input_internal.h                    |  5 ++
 src/input/player.c                            | 85 +++++++++++++++++++++++++++
 src/libvlccore.sym                            |  1 +
 10 files changed, 187 insertions(+)

diff --git a/include/vlc_es_out.h b/include/vlc_es_out.h
index b690d570e9..47e2012ab9 100644
--- a/include/vlc_es_out.h
+++ b/include/vlc_es_out.h
@@ -36,6 +36,7 @@ enum es_out_query_e
 {
     /* set or change the selected ES in its category (audio/video/spu) */
     ES_OUT_SET_ES,      /* arg1= es_out_id_t*                   */
+    ES_OUT_SET_ES_LIST, /* arg1= es_out_id_t**                  */
     ES_OUT_UNSET_ES,    /* arg1= es_out_id_t* res=can fail      */
     ES_OUT_RESTART_ES,  /* arg1= es_out_id_t*                   */
 
diff --git a/include/vlc_player.h b/include/vlc_player.h
index 1aa5f8e687..f2df800797 100644
--- a/include/vlc_player.h
+++ b/include/vlc_player.h
@@ -1675,6 +1675,32 @@ vlc_player_GetSelectedTrack(vlc_player_t *player, enum es_format_category_e cat)
 VLC_API void
 vlc_player_SelectTrack(vlc_player_t *player, vlc_es_id_t *es_id);
 
+
+/**
+ * Select multiple tracks from a list of ES identifiers. Any currently
+ * selected track not referenced in the list will be unselected.
+ * 
+ * @warning there is no guarantee all requested tracks will be selected.
+ * Only one audio track can be selected at a time. Two subtitle tracks
+ * can be selected simultaneously if dual subtitles are enabled.
+ * 
+ * @warning behaviour is undefined if the list is not null-terminated.
+ *
+ * @note A successful call will trigger the
+ * vlc_player_cbs.on_track_selection_changed event for each track that has
+ * its selection state changed.
+ *
+ * @param player locked player instance
+ * @param cat VIDEO_ES, AUDIO_ES or SPU_ES
+ * @param es_id_list a null-terminated list of ES identifiers.
+ * (ES IDs can be retrieved from vlc_player_cbs.on_track_list_changed or
+ * vlc_player_GetTrackAt())
+ */
+VLC_API void
+vlc_player_SelectTrackList(vlc_player_t *player,
+                           enum es_format_category_e cat,
+                           vlc_es_id_t *const es_id_list[]);
+
 /**
  * Select the next track
  *
diff --git a/modules/access/bluray.c b/modules/access/bluray.c
index c452327aeb..cd88dcc4cf 100644
--- a/modules/access/bluray.c
+++ b/modules/access/bluray.c
@@ -1546,6 +1546,7 @@ static int bluray_esOutControl(es_out_t *p_out, int i_query, va_list args)
 
         case ES_OUT_SET_ES_DEFAULT:
         case ES_OUT_SET_ES:
+        case ES_OUT_SET_ES_LIST:
         case ES_OUT_UNSET_ES:
         case ES_OUT_SET_ES_STATE:
             i_ret = VLC_EGENERIC;
diff --git a/modules/demux/adaptive/plumbing/FakeESOut.cpp b/modules/demux/adaptive/plumbing/FakeESOut.cpp
index 69d00f7e7f..f1f274e0cf 100644
--- a/modules/demux/adaptive/plumbing/FakeESOut.cpp
+++ b/modules/demux/adaptive/plumbing/FakeESOut.cpp
@@ -470,6 +470,7 @@ int FakeESOut::esOutControl_Callback(es_out_t *fakees, int i_query, va_list args
         }
 
         case ES_OUT_SET_ES:
+        case ES_OUT_SET_ES_LIST:
         case ES_OUT_SET_ES_DEFAULT:
         case ES_OUT_SET_ES_STATE:
             return VLC_SUCCESS;
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 2026fb8c22..933249c39b 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -217,6 +217,8 @@ 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         EsOutSelectList( es_out_t *, enum es_format_category_e cat,
+                                     vlc_es_id_t **es_id_list );
 static void         EsOutUpdateInfo( es_out_t *, es_out_id_t *es, const vlc_meta_t * );
 static int          EsOutSetRecord(  es_out_t *, bool b_record );
 
@@ -2182,6 +2184,41 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
         p_esprops->p_main_es = es;
 }
 
+static void EsOutSelectList( es_out_t *out, enum es_format_category_e cat,
+                             vlc_es_id_t **es_id_list )
+{
+
+    es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
+    es_out_id_t *other;
+
+    foreach_es_then_es_slaves(other)
+    {
+        if( other->fmt.i_cat == cat )
+        {
+            bool select = false;
+            for( size_t i = 0; ; i++ )
+            {
+                vlc_es_id_t *es_id = es_id_list[i];
+                if( es_id == NULL )
+                    break;
+                else if( es_id->i_id == other->id.i_id )
+                {
+                    select = true;
+                    break;
+                }
+            }
+            if( !select && EsIsSelected( other ) )
+            {
+                EsOutUnselectEs( out, other, other->p_pgrm == p_sys->p_pgrm );
+            }
+            else if( select && !EsIsSelected( other ) )
+            {
+                EsOutSelectEs( out, other );
+            }
+        }
+    }
+}
+
 static void EsOutCreateCCChannels( es_out_t *out, vlc_fourcc_t codec, uint64_t i_bitmap,
                                    const char *psz_descfmt, es_out_id_t *parent )
 {
@@ -2601,6 +2638,13 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args )
         EsOutStopFreeVout( out );
         return VLC_SUCCESS;
     }
+    case ES_OUT_SET_ES_LIST:
+    {
+        enum es_format_category_e cat = va_arg( args, enum es_format_category_e );
+        vlc_es_id_t **es_id_list = va_arg( args, vlc_es_id_t ** );
+        EsOutSelectList( out, cat, es_id_list );
+        return VLC_SUCCESS;
+    }
     case ES_OUT_UNSET_ES:
     {
         es_out_id_t *es = va_arg( args, es_out_id_t * ), *other;
diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c
index 406c6f2237..21a041a1f8 100644
--- a/src/input/es_out_timeshift.c
+++ b/src/input/es_out_timeshift.c
@@ -738,6 +738,7 @@ static int ControlLocked( es_out_t *p_out, int i_query, va_list args )
 
     /* Invalid queries for this es_out level */
     case ES_OUT_SET_ES_BY_ID:
+    case ES_OUT_SET_ES_LIST:
     case ES_OUT_RESTART_ES_BY_ID:
     case ES_OUT_SET_ES_DEFAULT_BY_ID:
     case ES_OUT_GET_ES_OBJECTS_BY_ID:
diff --git a/src/input/input.c b/src/input/input.c
index 381b85a9fd..eea40b59c1 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -1712,6 +1712,18 @@ static void ControlRelease( int i_type, const input_control_param_t *p_param )
     case INPUT_CONTROL_RESTART_ES:
         vlc_es_id_Release( p_param->id );
         break;
+    case INPUT_CONTROL_SET_ES_LIST:
+    {
+        for( size_t i = 0; ; i++ )
+        {
+            vlc_es_id_t *es_id = p_param->list.ids[i];
+            if( es_id == NULL )
+                break;
+            vlc_es_id_Release( es_id );
+        }
+        free( p_param->list.ids );
+        break;
+    }
 
     default:
         break;
@@ -2130,6 +2142,16 @@ static bool Control( input_thread_t *p_input,
                 demux_Control( input_priv(p_input)->master->p_demux, DEMUX_SET_ES,
                                vlc_es_id_GetInputId( param.id ) );
             break;
+        case INPUT_CONTROL_SET_ES_LIST:
+        {
+            if( es_out_Control( input_priv(p_input)->p_es_out_display,
+                                ES_OUT_SET_ES_LIST, param.list.cat,
+                                param.list.ids ) == VLC_SUCCESS )
+            {
+                /* TODO: demux_Control(..., DEMUX_SET_ES_LIST, ... ) */
+            }
+            break;
+        }
         case INPUT_CONTROL_UNSET_ES:
             es_out_Control( input_priv(p_input)->p_es_out_display,
                             ES_OUT_UNSET_ES, param.id );
diff --git a/src/input/input_internal.h b/src/input/input_internal.h
index 18495881c2..3bcb5a9f83 100644
--- a/src/input/input_internal.h
+++ b/src/input/input_internal.h
@@ -85,6 +85,10 @@ typedef union
     vlc_viewpoint_t viewpoint;
     vlc_es_id_t *id;
     struct {
+        enum es_format_category_e cat;
+        vlc_es_id_t **ids;
+    } list;
+    struct {
         bool b_fast_seek;
         vlc_tick_t i_val;
     } time;
@@ -247,6 +251,7 @@ enum input_control_e
     INPUT_CONTROL_RESTART_ES_BY_ID,
 
     INPUT_CONTROL_SET_ES,
+    INPUT_CONTROL_SET_ES_LIST,  // select a list of ES atomically
     INPUT_CONTROL_UNSET_ES,
     INPUT_CONTROL_RESTART_ES,
 
diff --git a/src/input/player.c b/src/input/player.c
index da02375a66..551b9928f1 100644
--- a/src/input/player.c
+++ b/src/input/player.c
@@ -1312,6 +1312,91 @@ vlc_player_SelectTrack(vlc_player_t *player, vlc_es_id_t *id)
     vlc_player_vout_OSDTrack(player, id, true);
 }
 
+void
+vlc_player_SelectTrackList(vlc_player_t *player,
+                           enum es_format_category_e cat,
+                           vlc_es_id_t *const es_id_list[])
+{
+    struct vlc_player_input *input = vlc_player_get_input_locked(player);
+    if (!input)
+        return;
+
+    /* First, count and hold all the ES Ids.
+       Ids will be released in input.c:ControlRelease */
+    size_t id_count;
+    for (id_count = 0; ; id_count++)
+    {
+        vlc_es_id_t *es_id = es_id_list[id_count];
+        if (es_id == NULL)
+            break;
+
+        vlc_es_id_Hold( es_id );
+    }
+
+    /* Copy es_id_list into an allocated list so that it remains in memory until
+       selection completes. The list will be freed in input.c:ControlRelease */
+    struct vlc_es_id_t **allocated_ids =
+        malloc(sizeof(vlc_es_id_t *) * (id_count + 1));
+
+    for (size_t i = 0; i <= id_count; i++)
+    {
+        allocated_ids[i] = es_id_list[i];
+    }
+
+    /* Attempt to select all the requested tracks */
+    input_ControlPush( input->thread, INPUT_CONTROL_SET_ES_LIST,
+        &(input_control_param_t) {
+            .list.cat = cat,
+            .list.ids = allocated_ids,
+        } );
+
+    /* Display track selection message */
+    bool selected_new_track = false;
+    for (size_t i = 0; i < id_count; i++)
+    {
+        vlc_es_id_t *es_id = es_id_list[i];
+
+        const struct vlc_player_track *track = vlc_player_GetTrack(player, es_id);
+        assert(track);
+
+        if (!track->selected)
+        {
+            vlc_player_vout_OSDTrack(player, es_id, true);
+            selected_new_track = true;
+        }
+    }
+
+    if (!selected_new_track)
+    {
+        /* Display track deselection message */
+        size_t count = vlc_player_GetTrackCount(player, cat);
+        if (!count)
+            return;
+
+        for (size_t i = 0; i < count; ++i)
+        {
+            const struct vlc_player_track *track =
+                vlc_player_GetTrackAt(player, cat, i);
+            assert(track);
+            if (track->selected)
+            {
+                bool selected = false;
+                for (size_t j = 0; j < id_count; j++)
+                {
+                    if (es_id_list[j] == track->es_id)
+                    {
+                        selected = true;
+                        break;
+                    }
+                }
+
+                if (!selected)
+                    vlc_player_vout_OSDTrack(player, track->es_id, false);
+            }
+        }
+    }
+}
+
 static void
 vlc_player_CycleTrack(vlc_player_t *player, enum es_format_category_e cat,
                       bool next)
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index efc07fbb25..03a503e1ea 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -856,6 +856,7 @@ vlc_player_SelectTeletextPage
 vlc_player_SelectTitle
 vlc_player_SelectTitleIdx
 vlc_player_SelectTrack
+vlc_player_SelectTrackList
 vlc_player_SetAssociatedSubsFPS
 vlc_player_SetAtoBLoop
 vlc_player_SetAudioDelay
-- 
2.11.0



More information about the vlc-devel mailing list