diff options
-rw-r--r-- | DOCS/man/options.rst | 9 | ||||
-rw-r--r-- | demux/demux.c | 1 | ||||
-rw-r--r-- | demux/demux_lavf.c | 1 | ||||
-rw-r--r-- | demux/stheader.h | 2 | ||||
-rw-r--r-- | options/options.c | 6 | ||||
-rw-r--r-- | options/options.h | 3 | ||||
-rw-r--r-- | player/command.c | 36 | ||||
-rw-r--r-- | player/core.h | 4 | ||||
-rw-r--r-- | player/loadfile.c | 26 |
9 files changed, 77 insertions, 11 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst index f0e8da5546..b5f87f12e3 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -45,6 +45,15 @@ Track Selection ``--vid=<ID|auto|no>`` Select video channel. ``auto`` selects the default, ``no`` disables video. +``--ff-aid=<ID|auto|no>``, ``--ff-sid=<ID|auto|no>``, ``--ff-vid=<ID|auto|no>`` + Select audio/subtitle/video streams by the FFmpeg stream index. The FFmpeg + stream index is relatively arbitrary, but useful when interacting with + other software using FFmpeg (consider ``ffprobe``). + + Note that with external tracks (added with ``--sub-file`` and similar + options) will have duplicate IDs. In that case, the first stream in order + is selected. + ``--edition=<ID|auto>`` (Matroska files only) Specify the edition (set of chapters) to use, where 0 is the first. If set diff --git a/demux/demux.c b/demux/demux.c index e5cd4d53fe..7c563e9625 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -190,6 +190,7 @@ struct sh_stream *new_sh_stream(demuxer_t *demuxer, enum stream_type type) *sh = (struct sh_stream) { .type = type, .index = demuxer->num_streams, + .ff_index = demuxer->num_streams, .demuxer_id = demuxer_id, // may be overwritten by demuxer .ds = talloc(sh, struct demux_stream), }; diff --git a/demux/demux_lavf.c b/demux/demux_lavf.c index 85db0692e8..553e43aea0 100644 --- a/demux/demux_lavf.c +++ b/demux/demux_lavf.c @@ -587,6 +587,7 @@ static void handle_stream(demuxer_t *demuxer, int i) MP_TARRAY_APPEND(priv, priv->streams, priv->num_streams, sh); if (sh) { + sh->ff_index = st->index; sh->codec = mp_codec_from_av_codec_id(codec->codec_id); sh->lav_headers = codec; diff --git a/demux/stheader.h b/demux/stheader.h index 7c9b182f4b..2b5b43702f 100644 --- a/demux/stheader.h +++ b/demux/stheader.h @@ -36,6 +36,8 @@ struct sh_stream { // Demuxer/format specific ID. Corresponds to the stream IDs as encoded in // some file formats (e.g. MPEG), or an index chosen by demux.c. int demuxer_id; + // FFmpeg stream index (AVFormatContext.streams[index]), or equivalent. + int ff_index; // One of these is non-NULL, the others are NULL, depending on the stream // type. struct sh_audio *audio; diff --git a/options/options.c b/options/options.c index 4621df9b7e..0c2eb6a289 100644 --- a/options/options.c +++ b/options/options.c @@ -190,6 +190,9 @@ const m_option_t mp_opts[] = { OPT_TRACKCHOICE("vid", video_id), OPT_TRACKCHOICE("sid", sub_id), OPT_TRACKCHOICE("secondary-sid", sub2_id), + OPT_TRACKCHOICE("ff-aid", audio_id_ff), + OPT_TRACKCHOICE("ff-vid", video_id_ff), + OPT_TRACKCHOICE("ff-sid", sub_id_ff), OPT_FLAG_STORE("no-sub", sub_id, 0, -2), OPT_FLAG_STORE("no-video", video_id, 0, -2), OPT_FLAG_STORE("no-audio", audio_id, 0, -2), @@ -635,6 +638,9 @@ const struct MPOpts mp_default_opts = { .audio_id = -1, .video_id = -1, .sub_id = -1, + .audio_id_ff = -1, + .video_id_ff = -1, + .sub_id_ff = -1, .sub2_id = -2, .audio_display = 1, .sub_visibility = 1, diff --git a/options/options.h b/options/options.h index adbb70e420..c535cce86c 100644 --- a/options/options.h +++ b/options/options.h @@ -165,6 +165,9 @@ typedef struct MPOpts { int video_id; int sub_id; int sub2_id; + int audio_id_ff; + int video_id_ff; + int sub_id_ff; char **audio_lang; char **sub_lang; int audio_display; diff --git a/player/command.c b/player/command.c index 4e74b690c9..d3d8fecbe6 100644 --- a/player/command.c +++ b/player/command.c @@ -1661,6 +1661,35 @@ static int property_switch_track(struct m_property *prop, int action, void *arg, return mp_property_generic_option(mpctx, prop, action, arg); } +// Similar, less featured, for selecting by ff-index. +static int property_switch_track_ff(void *ctx, struct m_property *prop, + int action, void *arg) +{ + MPContext *mpctx = ctx; + enum stream_type type = (intptr_t)prop->priv; + if (!mpctx->num_sources) + return M_PROPERTY_UNAVAILABLE; + struct track *track = mpctx->current_track[0][type]; + + switch (action) { + case M_PROPERTY_GET: + *(int *) arg = track ? track->ff_index : -2; + return M_PROPERTY_OK; + case M_PROPERTY_SET: { + track = NULL; + for (int n = 0; n < mpctx->num_tracks; n++) { + if (mpctx->tracks[n]->ff_index == *(int *)arg) { + track = mpctx->tracks[n]; + break; + } + } + mp_switch_track_n(mpctx, 0, type, track); + return M_PROPERTY_OK; + } + } + return mp_property_generic_option(mpctx, prop, action, arg); +} + static int get_track_entry(int item, int action, void *arg, void *ctx) { struct MPContext *mpctx = ctx; @@ -1686,6 +1715,7 @@ static int get_track_entry(int item, int action, void *arg, void *ctx) .unavailable = !track->external_filename}, {"codec", SUB_PROP_STR(codec), .unavailable = !codec}, + {"ff-index", SUB_PROP_INT(track->ff_index)}, {0} }; @@ -3030,6 +3060,12 @@ static const struct m_property mp_properties[] = { {"tv-channel", mp_property_tv_channel}, {"dvb-channel", mp_property_dvb_channel}, +#define TRACK_FF(name, type) \ + {name, property_switch_track_ff, (void *)(intptr_t)type} + TRACK_FF("ff-vid", STREAM_VIDEO), + TRACK_FF("ff-aid", STREAM_AUDIO), + TRACK_FF("ff-sid", STREAM_SUB), + M_PROPERTY_ALIAS("video", "vid"), M_PROPERTY_ALIAS("audio", "aid"), M_PROPERTY_ALIAS("sub", "sid"), diff --git a/player/core.h b/player/core.h index 4d4142000c..f883ae2882 100644 --- a/player/core.h +++ b/player/core.h @@ -96,8 +96,8 @@ struct track { // IDs coming from demuxers or container files. int user_tid; - // Same as stream->demuxer_id. -1 if not set. - int demuxer_id; + int demuxer_id; // same as stream->demuxer_id. -1 if not set. + int ff_index; // same as stream->ff_index, or 0. char *title; bool default_track; diff --git a/player/loadfile.c b/player/loadfile.c index 470e0d24eb..b7dab134c7 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -340,6 +340,7 @@ static struct track *add_stream_track(struct MPContext *mpctx, .type = stream->type, .user_tid = find_new_tid(mpctx, stream->type), .demuxer_id = stream->demuxer_id, + .ff_index = stream->ff_index, .title = stream->title, .default_track = stream->default_track, .attached_picture = stream->attached_picture != NULL, @@ -378,7 +379,8 @@ static int match_lang(char **langs, char *lang) * tid is the track ID requested by the user (-2: deselect, -1: default) * lang is a string list, NULL is same as empty list * Sort tracks based on the following criteria, and pick the first: - * 0) track matches tid (always wins) + * 0a) track matches ff-index (always wins) + * 0b) track matches tid (almost always wins) * 1) track is external (no_default cancels this) * 1b) track was passed explicitly (is not an auto-loaded subtitle) * 2) earlier match in lang list @@ -414,9 +416,12 @@ static bool compare_track(struct track *t1, struct track *t2, char **langs, return t1->user_tid <= t2->user_tid; } static struct track *select_track(struct MPContext *mpctx, - enum stream_type type, int tid, char **langs) + enum stream_type type, int tid, int ffid, + char **langs) { - if (tid == -2) + if (ffid != -1) + tid = -1; // prefer selecting ffid + if (tid == -2 || ffid == -2) return NULL; bool select_fallback = type == STREAM_VIDEO || type == STREAM_AUDIO; struct track *pick = NULL; @@ -426,6 +431,8 @@ static struct track *select_track(struct MPContext *mpctx, continue; if (track->user_tid == tid) return track; + if (track->ff_index == ffid) + return track; if (!pick || compare_track(track, pick, langs, mpctx->opts)) pick = track; } @@ -1094,15 +1101,16 @@ goto_reopen_demuxer: ; check_previous_track_selection(mpctx); mpctx->current_track[0][STREAM_VIDEO] = - select_track(mpctx, STREAM_VIDEO, mpctx->opts->video_id, NULL); + select_track(mpctx, STREAM_VIDEO, opts->video_id, opts->video_id_ff, + NULL); mpctx->current_track[0][STREAM_AUDIO] = - select_track(mpctx, STREAM_AUDIO, mpctx->opts->audio_id, - mpctx->opts->audio_lang); + select_track(mpctx, STREAM_AUDIO, opts->audio_id, opts->audio_id_ff, + opts->audio_lang); mpctx->current_track[0][STREAM_SUB] = - select_track(mpctx, STREAM_SUB, mpctx->opts->sub_id, - mpctx->opts->sub_lang); + select_track(mpctx, STREAM_SUB, opts->sub_id, opts->sub_id_ff, + opts->sub_lang); mpctx->current_track[1][STREAM_SUB] = - select_track(mpctx, STREAM_SUB, mpctx->opts->sub2_id, NULL); + select_track(mpctx, STREAM_SUB, opts->sub2_id, -2, NULL); for (int t = 0; t < STREAM_TYPE_COUNT; t++) { for (int i = 0; i < NUM_PTRACKS; i++) { struct track *track = mpctx->current_track[i][t]; |