summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/options.rst9
-rw-r--r--demux/demux.c1
-rw-r--r--demux/demux_lavf.c1
-rw-r--r--demux/stheader.h2
-rw-r--r--options/options.c6
-rw-r--r--options/options.h3
-rw-r--r--player/command.c36
-rw-r--r--player/core.h4
-rw-r--r--player/loadfile.c26
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];