summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-10-21 13:16:48 +0200
committerwm4 <wm4@nowhere>2014-10-21 13:19:20 +0200
commitf0f83ff36600abc8715f3a11c31b2eeeda6c8c92 (patch)
tree38c6faba94976b08052fed67615d6680c748022e
parentbcc3d72995e926f899c0baa215599c50e23b9523 (diff)
downloadmpv-f0f83ff36600abc8715f3a11c31b2eeeda6c8c92.tar.bz2
mpv-f0f83ff36600abc8715f3a11c31b2eeeda6c8c92.tar.xz
player: add stream selection by ffmpeg index
Apparently using the stream index is the best way to refer to the same streams across multiple FFmpeg-using programs, even if the stream index itself is rarely meaningful in any way. For Matroska, there are some possible problems, depending how FFmpeg actually adds streams. Normally they seem to match though.
-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];