[vlc-devel] [PATCH 01/15] Enable selection of secondary SPU ES in the core

Thomas Guillem thomas at gllm.fr
Fri May 17 10:16:43 CEST 2019



On Thu, May 16, 2019, at 15:40, Roland Bewick wrote:
> Hi,
> 
> I've chosen the following implementation for vlc_player_SelectTrackList:
> 1. Deselect all selected tracks not matching the provided list.
> 2. Sequentially select the tracks that aren't already selected.
> 
> When a track is selected in the QT GUI, I check the category of the track.
> - If Not SPU_ES, use vlc_player_SelectTrack as usual.
> - If SPU_ES:
>      1. find which tracks are already selected by looping through all 
> tracks of the same category
>      2. If more than one track is already selected, do not proceed with 
> the selection
>      3. Call vlc_player_SelectTrackList using the ids of the new track 
> and the already selected tracks
> 
> To ensure that multiple tracks get selected in the core (es_out.c) I've 
> added a new parameter to EsOutSelect.

Fine wih me, that is what I had in mind. 

For es_out implementation, I prefer to send directly the list of ES via a new control. This allow to select multiples tracks atomically (only one lock held). 

> 
> Please let me know if you have any comments.
> Thanks,
> Roland
> 
> Diff:
> 
> diff --git a/include/vlc_es_out.h b/include/vlc_es_out.h
> index b690d570e9..ead0e7a0e0 100644
> --- a/include/vlc_es_out.h
> +++ b/include/vlc_es_out.h
> @@ -35,9 +35,10 @@
>   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_UNSET_ES,    /* arg1= es_out_id_t* res=can fail      */
> -    ES_OUT_RESTART_ES,  /* arg1= es_out_id_t*                   */
> +    ES_OUT_SET_ES,          /* arg1= es_out_id_t* arg2=bool      */
> +    ES_OUT_SET_ES_MULTIPLE, /* arg1= int, arg2=bool              */
> +    ES_OUT_UNSET_ES,        /* arg1= es_out_id_t* res=can fail   */
> +    ES_OUT_RESTART_ES,      /* arg1= es_out_id_t*                */
> 
>       /* set 'default' tag on ES (copied across from container) */
>       ES_OUT_SET_ES_DEFAULT, /* arg1= es_out_id_t*                */
> diff --git a/include/vlc_player.h b/include/vlc_player.h
> index 1aa5f8e687..aa641a712e 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 the dual subtitles setting is 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/gui/qt/util/input_models.cpp 
> b/modules/gui/qt/util/input_models.cpp
> index e381fbb917..857cfee972 100644
> --- a/modules/gui/qt/util/input_models.cpp
> +++ b/modules/gui/qt/util/input_models.cpp
> @@ -62,7 +62,47 @@ bool TrackListModel::setData(const QModelIndex 
> &index, const QVariant &value, in
>       vlc_player_locker lock{ m_player };
> 
>       if (select)
> -        vlc_player_SelectTrack(m_player, m_data[row].m_id.get());
> +    {
> +        vlc_es_id_t *esId = m_data[row].m_id.get();
> +        const struct vlc_player_track *trackToSelect = 
> vlc_player_GetTrack(m_player, esId);
> +        assert(trackToSelect);
> +
> +        if (trackToSelect->fmt.i_cat != SPU_ES)
> +        {
> +            /* For now, use existing behaviour for video/audio tracks */
> +            vlc_player_SelectTrack(m_player, esId);
> +        }
> +        else
> +        {
> +            /* Try to select a maximum of two tracks. */
> +            const int maxIds = 2;
> +            enum es_format_category_e cat = trackToSelect->fmt.i_cat;
> +            vlc_es_id_t *esIds[maxIds + 1] = { esId }; /* null 
> terminated */
> +
> +            size_t count = vlc_player_GetTrackCount(m_player, cat);
> +            if (!count)
> +                return false;
> +
> +            unsigned int index = 1;
> +            for (size_t i = 0; i < count; ++i)
> +            {
> +                const struct vlc_player_track *track =
> +                    vlc_player_GetTrackAt(m_player, SPU_ES, i);
> +                assert(track);
> +
> +                if (track->selected)
> +                {
> +                    if (index == maxIds)
> +                    {
> + updateTrackSelection(trackToSelect->es_id, false);
> +                        return false;
> +                    }
> +                    esIds[index++] = track->es_id;
> +                }
> +            }
> +            vlc_player_SelectTrackList(m_player, cat, esIds);
> +        }
> +    }
>       else
>           vlc_player_UnselectTrack(m_player, m_data[row].m_id.get());
>       return true;
> diff --git a/src/input/es_out.c b/src/input/es_out.c
> index 2026fb8c22..4523efce54 100644
> --- a/src/input/es_out.c
> +++ b/src/input/es_out.c
> @@ -216,7 +216,7 @@ static void         EsOutDelLocked( es_out_t *, 
> es_out_id_t * );
>   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         EsOutSelect( es_out_t *, es_out_id_t *es, bool 
> b_force, bool b_multiple );
>   static void         EsOutUpdateInfo( es_out_t *, es_out_id_t *es, 
> const vlc_meta_t * );
>   static int          EsOutSetRecord(  es_out_t *, bool b_record );
> 
> @@ -1114,7 +1114,7 @@ static void EsOutProgramSelect( es_out_t *out, 
> es_out_pgrm_t *p_pgrm )
>               EsOutUpdateInfo(out, es, NULL);
>           }
> 
> -        EsOutSelect(out, es, false);
> +        EsOutSelect(out, es, false, false);
>       }
> 
>       /* Ensure the correct running EPG table is selected */
> @@ -1774,7 +1774,7 @@ static es_out_id_t *EsOutAddSlaveLocked( es_out_t 
> *out, const es_format_t *fmt,
>           EsOutSendEsEvent( out, es, VLC_INPUT_ES_ADDED );
> 
>       EsOutUpdateInfo( out, es, NULL );
> -    EsOutSelect( out, es, false );
> +    EsOutSelect( out, es, false, false );
> 
>       if( es->b_scrambled )
>           EsOutProgramUpdateScrambled( out, es->p_pgrm );
> @@ -2043,9 +2043,11 @@ static void EsOutUnselectEs( es_out_t *out, 
> es_out_id_t *es, bool b_update )
>    * \param out The es_out structure
>    * \param es es_out_id structure
>    * \param b_force ...
> + * \param b_multiple preserve currently selected ES
>    * \return nothing
>    */
> -static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force )
> +static void EsOutSelect( es_out_t *out, es_out_id_t *es, bool b_force,
> +                         bool b_multiple )
>   {
>       es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out);
>       es_out_es_props_t *p_esprops = GetPropsByCat( p_sys, es->fmt.i_cat );
> @@ -2058,7 +2060,8 @@ static void EsOutSelect( es_out_t *out, 
> es_out_id_t *es, bool b_force )
> 
>       bool b_auto_unselect = p_esprops && p_sys->i_mode == 
> ES_OUT_MODE_AUTO &&
>                              p_esprops->e_policy == 
> ES_OUT_ES_POLICY_EXCLUSIVE &&
> -                           p_esprops->p_main_es && p_esprops->p_main_es 
> != es;
> +                           p_esprops->p_main_es && p_esprops->p_main_es 
> != es &&
> +                           !b_multiple;
> 
>       if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
>       {
> @@ -2218,7 +2221,7 @@ static void EsOutCreateCCChannels( es_out_t *out, 
> vlc_fourcc_t codec, uint64_t i
> 
>           /* Enable if user specified on command line */
>           if (p_sys->sub.i_channel == i)
> -            EsOutSelect(out, *pp_es, true);
> +            EsOutSelect(out, *pp_es, true, false);
>       }
>   }
> 
> @@ -2410,7 +2413,7 @@ static void EsOutDelLocked( es_out_t *out, 
> es_out_id_t *es )
>                           p_esprops->p_main_es = other;
>                   }
>                   else
> -                    EsOutSelect(out, other, false);
> +                    EsOutSelect(out, other, false, false);
>               }
>       }
> 
> @@ -2532,7 +2535,7 @@ static int EsOutVaControlLocked( es_out_t *out, 
> int i_query, va_list args )
>           }
>           foreach_es_then_es_slaves(es)
>           {
> -            EsOutSelect(out, es, false);
> +            EsOutSelect(out, es, false, false);
>           }
> 
>           if( i_mode == ES_OUT_MODE_END )
> @@ -2540,6 +2543,7 @@ static int EsOutVaControlLocked( es_out_t *out, 
> int i_query, va_list args )
>           return VLC_SUCCESS;
>       }
> 
> +    case ES_OUT_SET_ES_MULTIPLE:
>       case ES_OUT_SET_ES:
>       case ES_OUT_RESTART_ES:
>       {
> @@ -2573,9 +2577,11 @@ static int EsOutVaControlLocked( es_out_t *out, 
> int i_query, va_list args )
>                           EsOutDestroyDecoder(out, es);
>                           EsOutCreateDecoder(out, es);
>                       }
> -                    else if( i_query == ES_OUT_SET_ES )
> +                    else if( i_query == ES_OUT_SET_ES ||
> +                             i_query == ES_OUT_SET_ES_MULTIPLE )
>                       {
> -                        EsOutSelect(out, es, true);
> +                        bool b_multiple = i_query == 
> ES_OUT_SET_ES_MULTIPLE;
> +                        EsOutSelect(out, es, true, b_multiple);
>                       }
>                       break;
>                   }
> diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c
> index 406c6f2237..ddec6fbec3 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_MULTIPLE:
>       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..0f9772211c 100644
> --- a/src/input/input.c
> +++ b/src/input/input.c
> @@ -1708,6 +1708,7 @@ static void ControlRelease( int i_type, const 
> input_control_param_t *p_param )
>               vlc_renderer_item_release( p_param->val.p_address );
>           break;
>       case INPUT_CONTROL_SET_ES:
> +    case INPUT_CONTROL_SET_ES_MULTIPLE:
>       case INPUT_CONTROL_UNSET_ES:
>       case INPUT_CONTROL_RESTART_ES:
>           vlc_es_id_Release( p_param->id );
> @@ -2124,12 +2125,17 @@ static bool Control( input_thread_t *p_input,
>                               ES_OUT_RESTART_ES_BY_ID, 
> (int)param.val.i_int );
>               break;
> 
> -        case INPUT_CONTROL_SET_ES:
> +        case INPUT_CONTROL_SET_ES: case INPUT_CONTROL_SET_ES_MULTIPLE:
> +        {
> +            int i_query = i_type == INPUT_CONTROL_SET_ES ?
> +                          ES_OUT_SET_ES : ES_OUT_SET_ES_MULTIPLE;
> +
>               if( es_out_Control( input_priv(p_input)->p_es_out_display,
> -                                ES_OUT_SET_ES, param.id ) == VLC_SUCCESS )
> +                                i_query, param.id ) == VLC_SUCCESS )
>                   demux_Control( input_priv(p_input)->master->p_demux, 
> DEMUX_SET_ES,
>                                  vlc_es_id_GetInputId( param.id ) );
>               break;
> +        }
>           case INPUT_CONTROL_UNSET_ES:
>               es_out_Control( input_priv(p_input)->p_es_out_display,
>                               ES_OUT_UNSET_ES, param.id );
> @@ -3425,7 +3431,7 @@ static int input_SlaveSourceAdd( input_thread_t 
> *p_input,
>       es_out_Control( priv->p_es_out_display, ES_OUT_SET_ES_DEFAULT_BY_ID,
>                       priv->i_last_es_id );
>       es_out_Control( priv->p_es_out_display, ES_OUT_SET_ES_BY_ID,
> -                    priv->i_last_es_id, false );
> +                    priv->i_last_es_id, false, false );
> 
>       return VLC_SUCCESS;
>   }
> diff --git a/src/input/input_internal.h b/src/input/input_internal.h
> index 18495881c2..1bb1ffe091 100644
> --- a/src/input/input_internal.h
> +++ b/src/input/input_internal.h
> @@ -247,6 +247,7 @@ enum input_control_e
>       INPUT_CONTROL_RESTART_ES_BY_ID,
> 
>       INPUT_CONTROL_SET_ES,
> +    INPUT_CONTROL_SET_ES_MULTIPLE,  // select without deselecting other ES
>       INPUT_CONTROL_UNSET_ES,
>       INPUT_CONTROL_RESTART_ES,
> 
> @@ -294,7 +295,8 @@ static inline void input_ControlPushEsHelper( 
> input_thread_t *p_input, int i_typ
> vlc_es_id_t *id )
>   {
>       assert( i_type == INPUT_CONTROL_SET_ES || i_type == 
> INPUT_CONTROL_UNSET_ES ||
> -            i_type == INPUT_CONTROL_RESTART_ES );
> +            i_type == INPUT_CONTROL_RESTART_ES ||
> +            i_type == INPUT_CONTROL_SET_ES_MULTIPLE );
>       input_ControlPush( p_input, i_type, &(input_control_param_t) {
>           .id = vlc_es_id_Hold( id ),
>       } );
> diff --git a/src/input/player.c b/src/input/player.c
> index da02375a66..a896d5285d 100644
> --- a/src/input/player.c
> +++ b/src/input/player.c
> @@ -1312,6 +1312,67 @@ 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, deselect any currently selected tracks not in es_id_list */
> +    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 deselect = true;
> +            for (size_t j = 0; ; j++)
> +            {
> +                vlc_es_id_t *es_id = es_id_list[j];
> +                if (es_id == NULL)
> +                    break;
> +
> +                if (es_id == track->es_id)
> +                {
> +                    deselect = false;
> +                    break;
> +                }
> +            }
> +            if (deselect)
> +                vlc_player_UnselectTrack(player, track->es_id);
> +        }
> +    }
> +
> +    /* Second, Select each track sequentially.
> +        Already selected tracks will be ignored */
> +
> +    for (size_t j = 0; ; j++)
> +    {
> +        vlc_es_id_t *es_id = es_id_list[j];
> +        if (es_id == NULL)
> +            break;
> +
> +        const struct vlc_player_track *track = 
> vlc_player_GetTrack(player, es_id);
> +        assert(track);
> +
> +        if (!track->selected)
> +        {
> +            input_ControlPushEsHelper(input->thread,
> + INPUT_CONTROL_SET_ES_MULTIPLE,
> +                                      es_id);
> +            vlc_player_vout_OSDTrack(player, es_id, true);
> +        }
> +    }
> +}
> +
>   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
> 
> 
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list