From b796f2bb7693676056d0de98a9a95258909d799b Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 23 Dec 2013 20:14:54 +0100 Subject: player: redo demuxer stream selection Use struct track to decide what stream to select. Add a "selected" field and use that in some places instead of checking mpctx->current_track. --- player/audio.c | 6 ++-- player/command.c | 5 ++- player/core.h | 12 ++++--- player/loadfile.c | 104 +++++++++++++++++++++++++----------------------------- player/playloop.c | 14 ++++---- player/sub.c | 10 +++--- player/video.c | 13 +++---- 7 files changed, 79 insertions(+), 85 deletions(-) diff --git a/player/audio.c b/player/audio.c index 64160e0cd7..69fcb1d38e 100644 --- a/player/audio.c +++ b/player/audio.c @@ -104,7 +104,8 @@ int reinit_audio_filters(struct MPContext *mpctx) void reinit_audio_chain(struct MPContext *mpctx) { struct MPOpts *opts = mpctx->opts; - struct sh_stream *sh = init_demux_stream(mpctx, STREAM_AUDIO); + struct track *track = mpctx->current_track[STREAM_AUDIO]; + struct sh_stream *sh = init_demux_stream(mpctx, track); if (!sh) { uninit_player(mpctx, INITIALIZED_AO); goto no_audio; @@ -186,9 +187,8 @@ void reinit_audio_chain(struct MPContext *mpctx) init_error: uninit_player(mpctx, INITIALIZED_ACODEC | INITIALIZED_AO); - cleanup_demux_stream(mpctx, STREAM_AUDIO); no_audio: - mpctx->current_track[STREAM_AUDIO] = NULL; + mp_deselect_track(mpctx, track); MP_INFO(mpctx, "Audio: no audio\n"); } diff --git a/player/command.c b/player/command.c index a7ded72836..a3da05a5c7 100644 --- a/player/command.c +++ b/player/command.c @@ -1067,10 +1067,9 @@ static int property_list_tracks(m_option_t *prop, int action, void *arg, if (track->type != type) continue; - bool selected = mpctx->current_track[track->type] == track; res = talloc_asprintf_append(res, "%s: ", track_type_name(track->type)); - if (selected) + if (track->selected) res = talloc_asprintf_append(res, "> "); res = talloc_asprintf_append(res, "(%d) ", track->user_tid); if (track->title) @@ -1079,7 +1078,7 @@ static int property_list_tracks(m_option_t *prop, int action, void *arg, res = talloc_asprintf_append(res, "(%s) ", track->lang); if (track->is_external) res = talloc_asprintf_append(res, "(external) "); - if (selected) + if (track->selected) res = talloc_asprintf_append(res, "<"); res = talloc_asprintf_append(res, "\n"); } diff --git a/player/core.h b/player/core.h index 5b4cc738e5..2f0622de7c 100644 --- a/player/core.h +++ b/player/core.h @@ -108,6 +108,10 @@ enum seek_type { struct track { enum stream_type type; + + // Currently used for decoding. + bool selected; + // The type specific ID, also called aid (audio), sid (subs), vid (video). // For UI purposes only; this ID doesn't have anything to do with any // IDs coming from demuxers or container files. @@ -198,8 +202,6 @@ typedef struct MPContext { // Selected tracks. NULL if no track selected. struct track *current_track[STREAM_TYPE_COUNT]; - struct sh_stream *sh[STREAM_TYPE_COUNT]; - struct dec_video *d_video; struct dec_audio *d_audio; struct dec_sub *d_sub; @@ -367,13 +369,13 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask); struct track *mp_add_subtitles(struct MPContext *mpctx, char *filename); void mp_switch_track(struct MPContext *mpctx, enum stream_type type, struct track *track); +void mp_deselect_track(struct MPContext *mpctx, struct track *track); struct track *mp_track_by_tid(struct MPContext *mpctx, enum stream_type type, int tid); bool timeline_set_part(struct MPContext *mpctx, int i, bool force); double timeline_set_from_time(struct MPContext *mpctx, double pts, bool *need_reset); -struct sh_stream *init_demux_stream(struct MPContext *mpctx, - enum stream_type type); -void cleanup_demux_stream(struct MPContext *mpctx, enum stream_type type); +struct sh_stream *init_demux_stream(struct MPContext *mpctx, struct track *track); +void reselect_demux_streams(struct MPContext *mpctx); void add_demuxer_tracks(struct MPContext *mpctx, struct demuxer *demuxer); bool mp_remove_track(struct MPContext *mpctx, struct track *track); struct playlist_entry *mp_next_file(struct MPContext *mpctx, int direction, diff --git a/player/loadfile.c b/player/loadfile.c index 44fcdcc04f..389a205dc8 100644 --- a/player/loadfile.c +++ b/player/loadfile.c @@ -75,17 +75,17 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) mixer_uninit_audio(mpctx->mixer); audio_uninit(mpctx->d_audio); mpctx->d_audio = NULL; - cleanup_demux_stream(mpctx, STREAM_AUDIO); + reselect_demux_streams(mpctx); } if (mask & INITIALIZED_SUB) { mpctx->initialized_flags &= ~INITIALIZED_SUB; if (mpctx->d_sub) sub_reset(mpctx->d_sub); - cleanup_demux_stream(mpctx, STREAM_SUB); mpctx->d_sub = NULL; // Note: not free'd. mpctx->osd->dec_sub = NULL; reset_subtitles(mpctx); + reselect_demux_streams(mpctx); } if (mask & INITIALIZED_LIBASS) { @@ -103,8 +103,8 @@ void uninit_player(struct MPContext *mpctx, unsigned int mask) if (mpctx->d_video) video_uninit(mpctx->d_video); mpctx->d_video = NULL; - cleanup_demux_stream(mpctx, STREAM_VIDEO); mpctx->sync_audio_to_video = false; + reselect_demux_streams(mpctx); } if (mask & INITIALIZED_DEMUXER) { @@ -200,8 +200,7 @@ static void print_stream(struct MPContext *mpctx, struct track *t) tname = "Subs"; selopt = "sid"; langopt = "slang"; iid = "SID"; break; } - MP_INFO(mpctx, "[stream] %-5s %3s", - tname, mpctx->current_track[t->type] == t ? "(+)" : ""); + MP_INFO(mpctx, "[stream] %-5s %3s", tname, t->selected ? "(+)" : ""); MP_INFO(mpctx, " --%s=%d", selopt, t->user_tid); if (t->lang && langopt) MP_INFO(mpctx, " --%s=%s", langopt, t->lang); @@ -260,52 +259,29 @@ static void print_file_properties(struct MPContext *mpctx) } } -struct sh_stream *init_demux_stream(struct MPContext *mpctx, - enum stream_type type) +// Enable needed streams, disable others. +// Note that switching all tracks at once (instead when initializing something) +// can be important, because reading from a demuxer stream (e.g. during init) +// will implicitly discard interleaved packets from unselected streams. +void reselect_demux_streams(struct MPContext *mpctx) { - struct track *track = mpctx->current_track[type]; - struct sh_stream *stream = track ? track->stream : NULL; - mpctx->sh[type] = stream; - if (stream) { - demuxer_switch_track(stream->demuxer, type, stream); - if (track->is_external) { - double pts = get_main_demux_pts(mpctx); - demux_seek(stream->demuxer, pts, SEEK_ABSOLUTE); - } + // Note: we assume that all demuxer streams are covered by the track list. + for (int t = 0; t < mpctx->num_tracks; t++) { + struct track *track = mpctx->tracks[t]; + if (track->demuxer) + demuxer_select_track(track->demuxer, track->stream, track->selected); } - return stream; -} - -void cleanup_demux_stream(struct MPContext *mpctx, enum stream_type type) -{ - struct sh_stream *stream = mpctx->sh[type]; - if (stream) - demuxer_switch_track(stream->demuxer, type, NULL); - mpctx->sh[type] = NULL; } -// Switch the demuxers to current track selection. This is possibly important -// for intialization: if something reads packets from the demuxer (like at least -// reinit_audio_chain does, or when seeking), packets from the other streams -// should be queued instead of discarded. So all streams should be enabled -// before the first initialization function is called. -static void preselect_demux_streams(struct MPContext *mpctx) +// External demuxers might need a seek to the current playback position. +// Also return the stream for convenience. +struct sh_stream *init_demux_stream(struct MPContext *mpctx, struct track *track) { - // Disable all streams, just to be sure no unwanted streams are selected. - for (int n = 0; n < mpctx->num_sources; n++) { - for (int type = 0; type < STREAM_TYPE_COUNT; type++) { - struct track *track = mpctx->current_track[type]; - if (!(track && track->demuxer == mpctx->sources[n] && - demuxer_stream_is_selected(track->demuxer, track->stream))) - demuxer_switch_track(mpctx->sources[n], type, NULL); - } - } - - for (int type = 0; type < STREAM_TYPE_COUNT; type++) { - struct track *track = mpctx->current_track[type]; - if (track && track->stream) - demuxer_switch_track(track->stream->demuxer, type, track->stream); + if (track && track->demuxer && track->selected && track->is_external) { + double pts = get_main_demux_pts(mpctx); + demux_seek(track->demuxer, pts, SEEK_ABSOLUTE); } + return track ? track->stream : NULL; } static struct sh_stream *select_fallback_stream(struct demuxer *d, @@ -359,7 +335,7 @@ bool timeline_set_part(struct MPContext *mpctx, int i, bool force) } } } - preselect_demux_streams(mpctx); + reselect_demux_streams(mpctx); return true; } @@ -416,9 +392,8 @@ static struct track *add_stream_track(struct MPContext *mpctx, track->stream = stream; track->demuxer_id = stream->demuxer_id; // Initialize lazily selected track - bool selected = track == mpctx->current_track[STREAM_SUB]; - demuxer_select_track(track->demuxer, stream, selected); - if (selected) + demuxer_select_track(track->demuxer, stream, track->selected); + if (track->selected) reinit_subs(mpctx); return track; } @@ -617,8 +592,18 @@ void mp_switch_track(struct MPContext *mpctx, enum stream_type type, uninit_player(mpctx, INITIALIZED_SUB); } + if (current) + current->selected = false; + + reselect_demux_streams(mpctx); + mpctx->current_track[type] = track; + if (track) + track->selected = true; + + reselect_demux_streams(mpctx); + int user_tid = track ? track->user_tid : -2; if (type == STREAM_VIDEO) { mpctx->opts->video_id = user_tid; @@ -638,6 +623,12 @@ void mp_switch_track(struct MPContext *mpctx, enum stream_type type, mpctx->track_layout_hash = talloc_steal(mpctx, track_layout_hash(mpctx)); } +void mp_deselect_track(struct MPContext *mpctx, struct track *track) +{ + if (track && track->selected) + mp_switch_track(mpctx, track->type, NULL); +} + struct track *mp_track_by_tid(struct MPContext *mpctx, enum stream_type type, int tid) { @@ -658,11 +649,9 @@ bool mp_remove_track(struct MPContext *mpctx, struct track *track) if (!track->is_external) return false; - if (mpctx->current_track[track->type] == track) { - mp_switch_track(mpctx, track->type, NULL); - if (mpctx->current_track[track->type] == track) - return false; - } + mp_deselect_track(mpctx, track); + if (track->selected) + return false; int index = 0; while (index < mpctx->num_tracks && mpctx->tracks[index] != track) @@ -1157,12 +1146,15 @@ goto_reopen_demuxer: ; mpctx->current_track[STREAM_SUB] = select_track(mpctx, STREAM_SUB, mpctx->opts->sub_id, mpctx->opts->sub_lang); + for (int t = 0; t < mpctx->num_tracks; t++) { + struct track *track = mpctx->tracks[t]; + track->selected = track == mpctx->current_track[track->type]; + } + reselect_demux_streams(mpctx); demux_info_print(mpctx->master_demuxer); print_file_properties(mpctx); - preselect_demux_streams(mpctx); - #if HAVE_ENCODING if (mpctx->encode_lavc_ctx && mpctx->current_track[STREAM_VIDEO]) encode_lavc_expect_stream(mpctx->encode_lavc_ctx, AVMEDIA_TYPE_VIDEO); diff --git a/player/playloop.c b/player/playloop.c index 9078853fb5..1a38f74cd8 100644 --- a/player/playloop.c +++ b/player/playloop.c @@ -301,9 +301,10 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek, // If audio or demuxer subs come from different files, seek them too: bool have_external_tracks = false; - for (int type = 0; type < STREAM_TYPE_COUNT; type++) { - struct track *track = mpctx->current_track[type]; - have_external_tracks |= track && track->is_external && track->demuxer; + for (int t = 0; t < mpctx->num_tracks; t++) { + struct track *track = mpctx->tracks[t]; + have_external_tracks |= track->selected && track->is_external && + track->demuxer; } if (have_external_tracks) { double main_new_pos; @@ -312,9 +313,9 @@ static int mp_seek(MPContext *mpctx, struct seek_params seek, } else { main_new_pos = get_main_demux_pts(mpctx); } - for (int type = 0; type < STREAM_TYPE_COUNT; type++) { - struct track *track = mpctx->current_track[type]; - if (track && track->is_external && track->demuxer) + for (int t = 0; t < mpctx->num_tracks; t++) { + struct track *track = mpctx->tracks[t]; + if (track->selected && track->is_external && track->demuxer) demux_seek(track->demuxer, main_new_pos, SEEK_ABSOLUTE); } } @@ -1027,7 +1028,6 @@ void run_playloop(struct MPContext *mpctx) if (!opts->force_vo) uninit |= INITIALIZED_VO; uninit_player(mpctx, uninit); - mpctx->current_track[STREAM_VIDEO] = NULL; if (!mpctx->current_track[STREAM_AUDIO]) mpctx->stop_play = PT_NEXT_ENTRY; mpctx->error_playing = true; diff --git a/player/sub.c b/player/sub.c index ba8f7d70eb..a2455589db 100644 --- a/player/sub.c +++ b/player/sub.c @@ -57,9 +57,10 @@ static bool is_interleaved(struct MPContext *mpctx, struct track *track) return false; struct demuxer *demuxer = track->demuxer; - for (int type = 0; type < STREAM_TYPE_COUNT; type++) { - struct track *other = mpctx->current_track[type]; - if (other && other != track && other->demuxer && other->demuxer == demuxer) + for (int t = 0; t < mpctx->num_tracks; t++) { + struct track *other = mpctx->tracks[t]; + if (other != track && other->selected && other->demuxer == demuxer && + (other->type == STREAM_VIDEO || other->type == STREAM_AUDIO)) return true; } return false; @@ -175,8 +176,7 @@ void reinit_subs(struct MPContext *mpctx) assert(!(mpctx->initialized_flags & INITIALIZED_SUB)); - init_demux_stream(mpctx, STREAM_SUB); - struct sh_stream *sh = mpctx->sh[STREAM_SUB]; + struct sh_stream *sh = init_demux_stream(mpctx, track); // No track selected, or lazily added DVD track (will actually be created // on first sub packet) diff --git a/player/video.c b/player/video.c index 9b26209d2a..38e86a395b 100644 --- a/player/video.c +++ b/player/video.c @@ -136,8 +136,8 @@ int reinit_video_chain(struct MPContext *mpctx) struct MPOpts *opts = mpctx->opts; assert(!(mpctx->initialized_flags & INITIALIZED_VCODEC)); assert(!mpctx->d_video); - init_demux_stream(mpctx, STREAM_VIDEO); - struct sh_stream *sh = mpctx->sh[STREAM_VIDEO]; + struct track *track = mpctx->current_track[STREAM_VIDEO]; + struct sh_stream *sh = init_demux_stream(mpctx, track); if (!sh) goto no_video; @@ -216,8 +216,7 @@ int reinit_video_chain(struct MPContext *mpctx) err_out: no_video: uninit_player(mpctx, INITIALIZED_VCODEC | (opts->force_vo ? 0 : INITIALIZED_VO)); - cleanup_demux_stream(mpctx, STREAM_VIDEO); - mpctx->current_track[STREAM_VIDEO] = NULL; + mp_deselect_track(mpctx, track); handle_force_window(mpctx, true); MP_INFO(mpctx, "Video: no video\n"); return 0; @@ -319,9 +318,11 @@ void video_execute_format_change(struct MPContext *mpctx) static int check_framedrop(struct MPContext *mpctx, double frame_time) { struct MPOpts *opts = mpctx->opts; + struct track *t_audio = mpctx->current_track[STREAM_AUDIO]; + struct sh_stream *sh_audio = t_audio ? t_audio->stream : NULL; // check for frame-drop: - if (mpctx->d_audio && !mpctx->ao->untimed && - !demux_stream_eof(mpctx->sh[STREAM_AUDIO])) + if (mpctx->d_audio && !mpctx->ao->untimed && sh_audio && + !demux_stream_eof(sh_audio)) { float delay = opts->playback_speed * ao_get_delay(mpctx->ao); float d = delay - mpctx->delay; -- cgit v1.2.3