demux_{lavf,timeline}: add --flatten-editions

Lavf exposes programs/renditions as a flat track list tagged with
program_id. We respect this metadata and group tracks into their
respective programs, as tracks from different programs may be completely
unrelated to each other.

This commits adds an option to flatten the editions and ignore the
grouping.

Fixes: https://github.com/mpv-player/mpv/issues/17836#issuecomment-4345930205
This commit is contained in:
Kacper Michajłow committed 2026-05-01 10:42:00 +02:00
1 parent 44ceaa6498
commit b4a7ea306e
7 files changed
+45 -10

No files matched your search

@@ -1,3 +1,4 @@
``track-list`` is now filtered by the currently selected edition
add ``edition-list/N/metadata`` sub-property
add ``program_id`` support to EDL ``!track_meta`` header
add ``--flatten-editions`` option to disable program-based edition grouping
+11
View File
@@ -120,6 +120,17 @@ Track Selection
to ``auto`` (the default), mpv will choose the first edition declared as a
default, or if there is no default, the first edition defined.
``--flatten-editions=<yes|no>``
Some container formats (such as HLS or MPEG-TS with multiple programs)
expose multiple programs or rendition groups. By default, mpv respects the
format and groups tracks into editions, filtering the track list to only
show tracks belonging to the currently selected edition.
Setting this option to ``yes`` ignores the program structure of the file.
No editions are created, and all tracks from all programs are shown as a
flat list. Note that depending on the file, tracks from different programs
may be completely unrelated to each other.
``--track-auto-selection=<yes|no>``
Enable the default track auto-selection (default: yes). Enabling this will
make the player select streams according to ``--aid``, ``--alang``, and
+10 -5
View File
@@ -981,6 +981,16 @@ static void build_editions(demuxer_t *demuxer)
if (avfc->nb_programs <= 1)
return;
struct MPOpts *mp_opts = mp_get_config_group(NULL, demuxer->global, &mp_opt_root);
int hls_bitrate = mp_opts->hls_bitrate;
int edition_id = mp_opts->edition_id;
bool flatten_editions = mp_opts->flatten_editions;
TA_FREEP(&mp_opts);
if (flatten_editions) {
MP_VERBOSE(demuxer, "Flattening track-based editions.\n");
return;
}
for (unsigned i = 0; i < avfc->nb_programs; i++) {
AVProgram *prog = avfc->programs[i];
@@ -1037,11 +1047,6 @@ static void build_editions(demuxer_t *demuxer)
demuxer->edition_is_track_mapping = true;
struct MPOpts *mp_opts = mp_get_config_group(priv, demuxer->global, &mp_opt_root);
int hls_bitrate = mp_opts->hls_bitrate;
int edition_id = mp_opts->edition_id;
TA_FREEP(&mp_opts);
int selected = -1;
if (edition_id >= 0 && edition_id < demuxer->num_editions)
selected = edition_id;
+10 -5
View File
@@ -653,6 +653,16 @@ static void build_editions(struct demuxer *demuxer)
if (demuxer->num_editions > 0)
return;
struct MPOpts *mp_opts = mp_get_config_group(NULL, demuxer->global, &mp_opt_root);
int hls_bitrate = mp_opts->hls_bitrate;
int edition_id = mp_opts->edition_id;
bool flatten_editions = mp_opts->flatten_editions;
TA_FREEP(&mp_opts);
if (flatten_editions) {
MP_VERBOSE(demuxer, "Flattening track-based editions.\n");
return;
}
int num_streams = demux_get_num_stream(demuxer);
for (int n = 0; n < num_streams; n++) {
struct sh_stream *sh = demux_get_stream(demuxer, n);
@@ -693,11 +703,6 @@ static void build_editions(struct demuxer *demuxer)
demuxer->edition_is_track_mapping = true;
struct MPOpts *mp_opts = mp_get_config_group(demuxer, demuxer->global, &mp_opt_root);
int hls_bitrate = mp_opts->hls_bitrate;
int edition_id = mp_opts->edition_id;
TA_FREEP(&mp_opts);
int selected = -1;
if (edition_id >= 0 && edition_id < demuxer->num_editions)
selected = edition_id;
+1
View File
@@ -587,6 +587,7 @@ static const m_option_t mp_opts[] = {
{"dvd", OPT_SUBSTRUCT(dvd_opts, dvd_conf)},
#endif
{"edition", OPT_CHOICE(edition_id, {"auto", -1}), M_RANGE(0, 8190)},
{"flatten-editions", OPT_BOOL(flatten_editions)},
#if HAVE_LIBBLURAY
{"bluray", OPT_SUBSTRUCT(stream_bluray_opts, stream_bluray_conf)},
#endif /* HAVE_LIBBLURAY */
+1
View File
@@ -254,6 +254,7 @@ typedef struct MPOpts {
bool use_filedir_conf;
int hls_bitrate;
int edition_id;
bool flatten_editions;
bool initial_audio_sync;
double sync_max_video_change;
double sync_max_audio_change;
+11
View File
@@ -607,6 +607,14 @@ struct track *select_default_track(struct MPContext *mpctx, int order,
{
struct MPOpts *opts = mpctx->opts;
int tid = opts->stream_id[order][type];
const struct demuxer *demuxer = mpctx->demuxer;
// Prefer tracks from the same program as the selected video when not using editions.
int preferred_program = -1;
if (type != STREAM_VIDEO && mpctx->current_track[0][STREAM_VIDEO] &&
(!demuxer || !demuxer->edition_is_track_mapping || demuxer->num_editions <= 1))
{
preferred_program = mpctx->current_track[0][STREAM_VIDEO]->program_id;
}
if (tid == -2)
return NULL;
char **langs = process_langs(opts->stream_lang[type]);
@@ -636,6 +644,9 @@ struct track *select_default_track(struct MPContext *mpctx, int order,
continue;
if (!opts->autoload_files && track->is_external)
continue;
if (preferred_program != -1 && !track->is_external &&
track->program_id != -1 && track->program_id != preferred_program)
continue;
if (duplicate_track(mpctx, order, type, track))
continue;
if (sub) {