vlc | branch: master | Thomas Guillem <[email protected]> | Wed Nov 14 16:33:43 2018 +0100| [c1ef70263f5eff833755fafd03d2d6917b368060] | committer: Thomas Guillem
es_out: add controls to cycle through ES tracks With 2 new internal controls: ES_OUT_SET_ES_NEXT and ES_OUT_SET_ES_PREV. This will fix a TOCTOU issue when selecting next or previous tracks. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=c1ef70263f5eff833755fafd03d2d6917b368060 --- src/input/es_out.c | 96 ++++++++++++++++++++++++++++++++++++++++++++ src/input/es_out.h | 3 ++ src/input/es_out_timeshift.c | 2 + 3 files changed, 101 insertions(+) diff --git a/src/input/es_out.c b/src/input/es_out.c index 0cdd08cfe2..2960374175 100644 --- a/src/input/es_out.c +++ b/src/input/es_out.c @@ -2373,6 +2373,94 @@ static int EsOutControlLocked( es_out_t *out, int i_query, ... ) return ret; } +static int EsOutControlCycleEsLocked(es_out_t *out, enum es_format_category_e cat, + bool next, vlc_es_id_t **new_id) +{ + es_out_sys_t *p_sys = container_of(out, es_out_sys_t, out); + es_out_id_t *es, *selected_es = NULL, *next_es = NULL; + + es_out_es_props_t *props = GetPropsByCat(p_sys, cat); + /* Can't cycle through ES if we are not in exclusive mode */ + if (!props || props->e_policy != ES_OUT_ES_POLICY_EXCLUSIVE) + return VLC_EGENERIC; + + /* Get the selected ES */ + foreach_es_then_es_slaves(es) + { + if (es->fmt.i_cat != cat || !EsIsSelected(es)) + continue; + + if (selected_es == NULL) + selected_es = es; + else + { + /* Can't select a next/prev track if there are more than + * one ES selected */ + return VLC_EGENERIC; + } + } + + if (selected_es) + { + /* Find the closest ES that is after or before the current one */ + size_t selected_pos = selected_es->i_pos; + foreach_es_then_es_slaves(es) + { + if (es->fmt.i_cat != cat || EsIsSelected(es)) + continue; + assert(es->i_pos != selected_pos); + + if ((next && es->i_pos < selected_pos) || + (!next && es->i_pos > selected_pos)) + continue; + + if (next_es == NULL) + { + next_es = es; + continue; + } + + const int distance = abs(es->i_pos - selected_pos); + const int closest_distance = abs(next_es->i_pos - selected_pos); + if (distance < closest_distance) + next_es = es; + } + } + else + { + /* No ES currently selected: find the first or last ES to select */ + foreach_es_then_es_slaves(es) + { + if (es->fmt.i_cat != cat) + continue; + if (next_es == NULL) + { + next_es = es; + continue; + } + if ((next && es->i_pos < next_es->i_pos) || + (!next && es->i_pos > next_es->i_pos)) + next_es = es; + } + } + + if (next_es) + { + int ret = EsOutControlLocked(out, ES_OUT_SET_ES, next_es); + if (ret == VLC_SUCCESS) + *new_id = &next_es->id; + return ret; + } + else + { + assert(selected_es); + int ret = EsOutControlLocked(out, ES_OUT_UNSET_ES, selected_es); + if (ret == VLC_SUCCESS) + *new_id = NULL; + return ret; + } +} + /** * Control query handler * @@ -2537,6 +2625,14 @@ static int EsOutVaControlLocked( es_out_t *out, int i_query, va_list args ) return VLC_SUCCESS; } + case ES_OUT_SET_ES_NEXT: + case ES_OUT_SET_ES_PREV: + { + const enum es_format_category_e cat = va_arg(args, int); + vlc_es_id_t **new_id = va_arg(args, vlc_es_id_t **); + return EsOutControlCycleEsLocked(out, cat, + i_query == ES_OUT_SET_ES_NEXT, new_id); + } 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.h b/src/input/es_out.h index f94a7cc516..5f216905bd 100644 --- a/src/input/es_out.h +++ b/src/input/es_out.h @@ -50,6 +50,9 @@ enum es_out_query_private_e ES_OUT_SET_ES_DEFAULT_BY_ID, ES_OUT_GET_ES_OBJECTS_BY_ID, /* arg1=int id, vlc_object_t **dec, vout_thread_t **, audio_output_t ** res=can fail*/ + ES_OUT_SET_ES_NEXT, /* arg1=es_category_e, arg2= vlc_es_id_t **, res=can fail */ + ES_OUT_SET_ES_PREV, /* arg1=es_category_e, arg2= vlc_es_id_t **, res=can fail */ + /* Stop all selected ES and save the stopped state in a context. free the * context or call ES_OUT_STOP_ALL_ES */ ES_OUT_STOP_ALL_ES, /* arg1=void ** */ diff --git a/src/input/es_out_timeshift.c b/src/input/es_out_timeshift.c index 7237ca8799..5e7ffcd8e6 100644 --- a/src/input/es_out_timeshift.c +++ b/src/input/es_out_timeshift.c @@ -740,6 +740,8 @@ 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_NEXT: + case ES_OUT_SET_ES_PREV: case ES_OUT_RESTART_ES_BY_ID: case ES_OUT_SET_ES_DEFAULT_BY_ID: case ES_OUT_GET_ES_OBJECTS_BY_ID: _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
