[vlc-devel] [PATCH 12/15] Add hotkey support for secondary subtitles (Part 3)

Roland Bewick roland.bewick at gmail.com
Tue May 14 11:40:11 CEST 2019


-Secondary subtitle track cycling won't overwrite existing primary subtitle selection.

-Using the secondary subtitle control hotkey now enables dual subtitles so it doesn't have to be selected in the UI.

-Update OSD message to show secondary subtitle selection
---
 include/vlc_input.h       |  4 ++
 include/vlc_player.h      | 16 +++++++-
 modules/control/hotkeys.c |  7 ++++
 src/input/es_out.c        |  3 ++
 src/input/input.c         |  3 +-
 src/input/player.c        | 93 ++++++++++++++++++++++++++++++++++++++++++-----
 src/libvlccore.sym        |  1 +
 7 files changed, 116 insertions(+), 11 deletions(-)

diff --git a/include/vlc_input.h b/include/vlc_input.h
index a5f1eb8b16..20c3ea63e7 100644
--- a/include/vlc_input.h
+++ b/include/vlc_input.h
@@ -461,6 +461,10 @@ struct vlc_input_event_es {
      * ES track information, can be updated after the VLC_INPUT_ES_UPDATED event.
      */
     const es_format_t *fmt;
+    /**
+     * SPU ID for this ES, can be updated after the VLC_INPUT_ES_UPDATED event.
+     */
+    unsigned int spu_id;
 };
 
 struct vlc_input_event_signal {
diff --git a/include/vlc_player.h b/include/vlc_player.h
index 8a7acf63bb..22eef4745c 100644
--- a/include/vlc_player.h
+++ b/include/vlc_player.h
@@ -111,6 +111,8 @@ struct vlc_player_track
     es_format_t fmt;
     /** True if the track is selected */
     bool selected;
+    /** SPU ID of the track if selected */
+    unsigned int i_spu_id;
 };
 
 /**
@@ -2273,7 +2275,7 @@ VLC_API float
 vlc_player_GetAssociatedSubsFPS(vlc_player_t *player);
 
 /**
- * Enable or disable the abiltity to select multiple sub tracks.
+ * Enable or disable the ability to select multiple sub tracks.
  *
  * @note A successful call will trigger the
  * vlc_player_cbs.on_dual_subtitles_enabled_changed event.
@@ -2468,6 +2470,18 @@ VLC_API void
 vlc_player_SetSubtitleMultipleSelection(vlc_player_t *player, bool multiple);
 
 /**
+ * Cycle sub track matching the given SPU ID.
+ *
+ * @note This must be returned to SPU_ID_PRIMARY immediately after
+ * selection of the subtitle.
+ *
+ * @param player locked player instance
+ * @param select true to allow selection of multiple subtitles
+ */
+VLC_API void
+vlc_player_SetCycleSpuId(vlc_player_t *player, int spu_id);
+
+/**
  * Get the signal quality and strength of the current media
  *
  * @param player locked player instance
diff --git a/modules/control/hotkeys.c b/modules/control/hotkeys.c
index f30a9cf695..e14f081664 100644
--- a/modules/control/hotkeys.c
+++ b/modules/control/hotkeys.c
@@ -350,6 +350,8 @@ PLAYER_ACTION_HANDLER(NavigateMedia)
 
 PLAYER_ACTION_HANDLER(Track)
 {
+    vlc_player_SetSubtitleMultipleSelection(player, i_control_spu_id > 1);
+    vlc_player_SetCycleSpuId(player, i_control_spu_id);
     switch (action_id)
     {
         case ACTIONID_AUDIO_TRACK:
@@ -364,6 +366,8 @@ PLAYER_ACTION_HANDLER(Track)
         default:
             vlc_assert_unreachable();
     }
+    vlc_player_SetCycleSpuId(player, SPU_ID_PRIMARY);
+    vlc_player_SetSubtitleMultipleSelection(player, false);
 }
 
 PLAYER_ACTION_HANDLER(Delay)
@@ -459,6 +463,9 @@ PLAYER_ACTION_HANDLER(ControlSubtitleSecondary)
     if (++i_control_spu_id > SPU_MAX_CLOCKS)
         i_control_spu_id = SPU_ID_PRIMARY;
 
+    if (i_control_spu_id > SPU_ID_PRIMARY)
+        vlc_player_SetDualSubtitlesEnabled(player, true);
+
     vlc_player_vout_OSDMessage(player, _("%s subtitle control"),
         i_control_spu_id > SPU_ID_PRIMARY ? "Secondary" : "Primary");
 }
diff --git a/src/input/es_out.c b/src/input/es_out.c
index 20631027ed..54b3884f11 100644
--- a/src/input/es_out.c
+++ b/src/input/es_out.c
@@ -1061,6 +1061,8 @@ static void EsOutSendEsEvent(es_out_t *out, es_out_id_t *es, int action)
         .id = &es->id,
         .title = es->psz_title ? es->psz_title : "",
         .fmt = es->fmt_out.i_cat != UNKNOWN_ES ? &es->fmt_out : &es->fmt,
+        .spu_id = es->fmt.i_cat == SPU_ES && es->p_dec ?
+                  input_DecoderGetSpuId(es->p_dec) : SPU_ID_PRIMARY,
     });
 }
 
@@ -2251,6 +2253,7 @@ static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
     {
         input_DecoderSetSpuId( es->p_dec, EsOutCountSelected( p_sys, es->fmt.i_cat ) );
         EsOutDecoderChangeDelay(out, es);
+        EsOutSendEsEvent( out, es, VLC_INPUT_ES_UPDATED );
     }
 }
 
diff --git a/src/input/input.c b/src/input/input.c
index 5fc25bed76..bdd5abd5dd 100644
--- a/src/input/input.c
+++ b/src/input/input.c
@@ -1062,7 +1062,8 @@ static void SetSubtitlesOptions( input_thread_t *p_input )
     if( sub_delay != 0 )
     {
         priv->spu_delays[0] = vlc_tick_from_samples(sub_delay, 10);
-        input_SendEventSubtitleDelay( p_input, priv->spu_delays[0], false );
+        input_SendEventSubtitleDelay( p_input, priv->spu_delays[0],
+                                      SPU_ID_PRIMARY );
         /* UpdatePtsDelay will be called next by InitPrograms */
     }
 
diff --git a/src/input/player.c b/src/input/player.c
index 2c486b9749..b59d005421 100644
--- a/src/input/player.c
+++ b/src/input/player.c
@@ -133,6 +133,9 @@ struct vlc_player_input
     bool teletext_transparent;
     unsigned teletext_page;
 
+    bool b_select_secondary_subtitle;
+    unsigned int i_cycle_spu_id;
+
     struct
     {
         vlc_tick_t time;
@@ -432,6 +435,7 @@ vlc_player_track_New(vlc_es_id_t *id, const char *name, const es_format_t *fmt)
     }
     track->es_id = vlc_es_id_Hold(id);
     track->selected = false;
+    track->i_spu_id = SPU_ID_PRIMARY;
 
     return track;
 }
@@ -459,7 +463,8 @@ vlc_player_track_Delete(struct vlc_player_track *track)
 
 static int
 vlc_player_track_Update(struct vlc_player_track *track,
-                        const char *name, const es_format_t *fmt)
+                        const char *name, const es_format_t *fmt,
+                        unsigned int spu_id)
 {
     if (strcmp(name, track->name) != 0)
     {
@@ -477,6 +482,8 @@ vlc_player_track_Update(struct vlc_player_track *track,
 
     es_format_Clean(&track->fmt);
     track->fmt = fmtdup;
+
+    track->i_spu_id = spu_id;
     return VLC_SUCCESS;
 }
 
@@ -659,6 +666,9 @@ vlc_player_input_New(vlc_player_t *player, input_item_t *item)
     input->subsync.audio_time =
     input->subsync.subtitle_time = VLC_TICK_INVALID;
 
+    input->b_select_secondary_subtitle = false;
+    input->i_cycle_spu_id = SPU_ID_PRIMARY;
+
     vlc_vector_init(&input->program_vector);
     vlc_vector_init(&input->video_track_vector);
     vlc_vector_init(&input->audio_track_vector);
@@ -1294,7 +1304,24 @@ es_format_category_to_string(enum es_format_category_e cat)
 static void
 vlc_player_vout_OSDTrack(vlc_player_t *player, vlc_es_id_t *id, bool select)
 {
+    struct vlc_player_input *input = vlc_player_get_input_locked(player);
     enum es_format_category_e cat = vlc_es_id_GetCat(id);
+    size_t spu_selected_count = 0;
+
+    if (cat == SPU_ES && input && var_GetBool(input->thread, "multiple-spus") &&
+        input->b_select_secondary_subtitle)
+    {
+        size_t count = vlc_player_GetTrackCount(player, SPU_ES);
+        for (size_t i = 0; i < count; ++i)
+        {
+            const struct vlc_player_track *track =
+                vlc_player_GetTrackAt(player, SPU_ES, i);
+            assert(track);
+            if (track->selected && track->es_id != id)
+                ++spu_selected_count;
+        }
+    }
+
     const struct vlc_player_track *track = vlc_player_GetTrack(player, id);
     if (!track && select)
         return;
@@ -1302,7 +1329,10 @@ vlc_player_vout_OSDTrack(vlc_player_t *player, vlc_es_id_t *id, bool select)
     const char *cat_name = es_format_category_to_string(cat);
     assert(cat_name);
     const char *track_name = select ? track->name : _("N/A");
-    vlc_player_vout_OSDMessage(player, _("%s track: %s"), cat_name, track_name);
+    bool b_track_secondary = spu_selected_count > 0;
+    const char *track_secondary = b_track_secondary ? _("Secondary ") : _("");
+    vlc_player_vout_OSDMessage(player, _("%s%s track: %s"),
+                               track_secondary, cat_name, track_name);
 }
 
 void
@@ -1320,6 +1350,9 @@ static void
 vlc_player_CycleTrack(vlc_player_t *player, enum es_format_category_e cat,
                       bool next)
 {
+    struct vlc_player_input *input = vlc_player_get_input_locked(player);
+    unsigned int i_cycle_spu_id = input ? input->i_cycle_spu_id : SPU_ID_PRIMARY;
+
     size_t count = vlc_player_GetTrackCount(player, cat);
     if (!count)
         return;
@@ -1331,12 +1364,12 @@ vlc_player_CycleTrack(vlc_player_t *player, enum es_format_category_e cat,
         const struct vlc_player_track *track =
             vlc_player_GetTrackAt(player, cat, i);
         assert(track);
-        if (track->selected)
+        if (track->selected && (cat != SPU_ES || track->i_spu_id == i_cycle_spu_id))
         {
             if (selected)
             {
                 /* Can't cycle through tracks if there are more than one
-                 * selected */
+                 * selected for the same spu id */
                 return;
             }
             index = i;
@@ -1344,19 +1377,51 @@ vlc_player_CycleTrack(vlc_player_t *player, enum es_format_category_e cat,
         }
     }
 
+    size_t original_index = index;
+    bool was_selected = selected;
+    bool b_check_first = false;
+
     if (!selected)
     {
-        /* No track selected: select the first or the last track */
+        /* No track selected: try to select the first or the last track. */
         index = next ? 0 : count - 1;
+        b_check_first = true;
         selected = true;
     }
-    else
+
+    /* Search until we find an unselected track */
+    while (true)
     {
         /* Unselect if we reach the end of the cycle */
         if ((next && index + 1 == count) || (!next && index == 0))
+        {
+            if (was_selected)
+                index = original_index;
             selected = false;
-        else /* Switch to the next or previous track */
-            index = index + (next ? 1 : -1);
+            break;
+        }
+        else /* Switch to the next or previous unselected track */
+        {
+            if (!b_check_first)
+                index = index + (next ? 1 : -1);
+            else
+                b_check_first = false;
+            const struct vlc_player_track *track =
+                vlc_player_GetTrackAt(player, cat, index);
+            if (!track->selected)
+                break;
+        }
+    }
+
+    if (!selected && !was_selected)
+        return; /* no track available nor selected matching request */
+
+    if (i_cycle_spu_id > SPU_ID_PRIMARY && selected && was_selected)
+    {
+        /* Deselect the old secondary sub track so we can select a new one */
+        const struct vlc_player_track *track =
+            vlc_player_GetTrackAt(player, cat, original_index);
+        vlc_player_UnselectTrack(player, track->es_id);
     }
 
     const struct vlc_player_track *track =
@@ -1584,7 +1649,7 @@ vlc_player_input_HandleEsEvent(struct vlc_player_input *input,
             track = vlc_player_track_vector_FindById(vec, ev->id, NULL);
             if (!track)
                 break;
-            if (vlc_player_track_Update(track, ev->title, ev->fmt) != 0)
+            if (vlc_player_track_Update(track, ev->title, ev->fmt, ev->spu_id) != 0)
                 break;
             vlc_player_SendEvent(player, on_track_list_changed,
                                  VLC_PLAYER_LIST_UPDATED, track);
@@ -2921,11 +2986,21 @@ vlc_player_SetSubtitleMultipleSelection(vlc_player_t *player, bool multiple)
     struct vlc_player_input *input = vlc_player_get_input_locked(player);
     if (!input)
         return;
+    input->b_select_secondary_subtitle = multiple;
     input_ControlPushHelper(input->thread,
                             INPUT_CONTROL_SET_MULTIPLE_SUBTITLE_SELECTION,
                             &(vlc_value_t){ .b_bool = multiple });
 }
 
+void
+vlc_player_SetCycleSpuId(vlc_player_t *player, int spu_id)
+{
+    struct vlc_player_input *input = vlc_player_get_input_locked(player);
+    if (!input)
+        return;
+    input->i_cycle_spu_id = spu_id;
+}
+
 vlc_tick_t
 vlc_player_GetSubtitleDelay(vlc_player_t *player, int i_spu_id)
 {
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 175d9a9639..baef0ba9dd 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -869,6 +869,7 @@ vlc_player_SetSubtitleDelay
 vlc_player_SetSubtitleSync
 vlc_player_SetSubtitleTextScale
 vlc_player_SetSubtitleMultipleSelection
+vlc_player_SetCycleSpuId
 vlc_player_SetDualSubtitlesEnabled
 vlc_player_SetTeletextEnabled
 vlc_player_SetTeletextTransparency
-- 
2.11.0



More information about the vlc-devel mailing list