demux: improve stream selection state

This replaces the previous commit and makes more sense. The internal
demux marked tracks as eager depending on their type and for subtitles
it would always lazily read them unless there happened to be no
available av stream. However, we want the sub stream to be eager if the
player is paused. The existing subtitle is still preserved on the
screen, but if the user changes tracks that's when the problem occurs.
So to handle this case, propagate the mpctx->paused down to the stream
selection logic. This modifies both demuxer_refresh_track and
demuxer_select_track to take that boolean value. A few other parts of
the player use this, but we can just assume false there (no change in
behavior from before) since they should never be related to subtitles.
The core player code is aware of its own state naturally, and can always
pass the appropriate value so go ahead and do so. When we change the
pause state, a refresh seek is done on all existing subtitle tracks to
make sure their eager state is the appropriate value (i.e. so it's not
still set to eager after a pause and a track switch). Slightly invasive
change, but it works with the existing logic instead of going around it
so ultimately it should be a better approach. We can additionally remove
the old force boolean from sub_read_packets since it is no longer
needed.
This commit is contained in:
Dudemanguy 2023-09-27 21:52:44 -05:00
parent 09b04fbf09
commit f40bbfec4f
9 changed files with 29 additions and 19 deletions

View File

@ -864,7 +864,8 @@ static void wakeup_ds(struct demux_stream *ds)
}
static void update_stream_selection_state(struct demux_internal *in,
struct demux_stream *ds)
struct demux_stream *ds,
bool paused)
{
ds->eof = false;
ds->refreshing = false;
@ -886,8 +887,8 @@ static void update_stream_selection_state(struct demux_internal *in,
}
// Subtitles are only eagerly read if there are no other eagerly read
// streams.
if (any_av_streams) {
// streams or the player is paused.
if (any_av_streams && !paused) {
for (int n = 0; n < in->num_streams; n++) {
struct demux_stream *s = in->streams[n]->ds;
@ -1002,7 +1003,7 @@ static void demux_add_sh_stream_locked(struct demux_internal *in,
sh->ds->queue = in->current_range->streams[sh->ds->index];
}
update_stream_selection_state(in, sh->ds);
update_stream_selection_state(in, sh->ds, false);
switch (ds->type) {
case STREAM_AUDIO:
@ -3961,7 +3962,7 @@ static void initiate_refresh_seek(struct demux_internal *in,
// ref_pts is used only if the stream is enabled. Then it serves as approximate
// start pts for this stream (in the worst case it is ignored).
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
double ref_pts, bool selected)
double ref_pts, bool selected, bool paused)
{
struct demux_internal *in = demuxer->in;
struct demux_stream *ds = stream->ds;
@ -3971,7 +3972,7 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
if (ds->selected != selected) {
MP_VERBOSE(in, "%sselect track %d\n", selected ? "" : "de", stream->index);
ds->selected = selected;
update_stream_selection_state(in, ds);
update_stream_selection_state(in, ds, paused);
in->tracks_switched = true;
if (ds->selected) {
if (in->back_demuxing)
@ -3991,7 +3992,7 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
// Execute a refresh seek on the given stream.
// ref_pts has the same meaning as with demuxer_select_track()
void demuxer_refresh_track(struct demuxer *demuxer, struct sh_stream *stream,
double ref_pts)
double ref_pts, bool paused)
{
struct demux_internal *in = demuxer->in;
struct demux_stream *ds = stream->ds;
@ -3999,7 +4000,7 @@ void demuxer_refresh_track(struct demuxer *demuxer, struct sh_stream *stream,
ref_pts = MP_ADD_PTS(ref_pts, -in->ts_offset);
if (ds->selected) {
MP_VERBOSE(in, "refresh track %d\n", stream->index);
update_stream_selection_state(in, ds);
update_stream_selection_state(in, ds, paused);
if (in->back_demuxing)
ds->back_seek_pos = ref_pts;
if (!in->after_seek)

View File

@ -319,9 +319,9 @@ void demux_get_reader_state(struct demuxer *demuxer, struct demux_reader_state *
void demux_block_reading(struct demuxer *demuxer, bool block);
void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
double ref_pts, bool selected);
double ref_pts, bool selected, bool paused);
void demuxer_refresh_track(struct demuxer *demuxer, struct sh_stream *stream,
double ref_pts);
double ref_pts, bool paused);
int demuxer_help(struct mp_log *log, const m_option_t *opt, struct bstr name);

View File

@ -59,7 +59,7 @@ static void reselect_streams(demuxer_t *demuxer)
for (int n = 0; n < MPMIN(num_slave, p->num_streams); n++) {
if (p->streams[n]) {
demuxer_select_track(p->slave, demux_get_stream(p->slave, n),
MP_NOPTS_VALUE, demux_stream_is_selected(p->streams[n]));
MP_NOPTS_VALUE, demux_stream_is_selected(p->streams[n]), false);
}
}
}

View File

@ -170,7 +170,7 @@ static void reselect_streams(struct demuxer *demuxer)
if (!src->current || seg->d != src->current->d)
selected = false;
struct sh_stream *sh = demux_get_stream(seg->d, i);
demuxer_select_track(seg->d, sh, MP_NOPTS_VALUE, selected);
demuxer_select_track(seg->d, sh, MP_NOPTS_VALUE, selected, false);
update_slave_stats(demuxer, seg->d);
}

View File

@ -381,9 +381,9 @@ void reselect_demux_stream(struct MPContext *mpctx, struct track *track,
pts -= 10.0;
}
if (refresh_only)
demuxer_refresh_track(track->demuxer, track->stream, pts);
demuxer_refresh_track(track->demuxer, track->stream, pts, mpctx->paused);
else
demuxer_select_track(track->demuxer, track->stream, pts, track->selected);
demuxer_select_track(track->demuxer, track->stream, pts, track->selected, mpctx->paused);
}
static void enable_demux_thread(struct MPContext *mpctx, struct demuxer *demux)
@ -1178,7 +1178,7 @@ static void *open_demux_thread(void *ctx)
int num_streams = demux_get_num_stream(demux);
for (int n = 0; n < num_streams; n++) {
struct sh_stream *sh = demux_get_stream(demux, n);
demuxer_select_track(demux, sh, MP_NOPTS_VALUE, true);
demuxer_select_track(demux, sh, MP_NOPTS_VALUE, true, mpctx->paused);
}
demux_set_wakeup_cb(demux, wakeup_demux, mpctx);

View File

@ -180,6 +180,15 @@ void set_pause_state(struct MPContext *mpctx, bool user_pause)
} else {
(void)get_relative_time(mpctx); // ignore time that passed during pause
}
if (mpctx->demuxer) {
double pts = get_current_time(mpctx);
for (int n = 0; n < num_ptracks[STREAM_SUB]; n++) {
struct track *track = mpctx->current_track[n][STREAM_SUB];
if (track)
demuxer_refresh_track(mpctx->demuxer, track->stream, pts, mpctx->paused);
}
}
}
update_core_idle_state(mpctx);

View File

@ -100,7 +100,7 @@ static bool update_subtitle(struct MPContext *mpctx, double video_pts,
sub_preload(dec_sub);
}
if (!sub_read_packets(dec_sub, video_pts, mpctx->paused))
if (!sub_read_packets(dec_sub, video_pts))
return false;
// Handle displaying subtitles on terminal; never done for secondary subs

View File

@ -269,7 +269,7 @@ static bool is_new_segment(struct dec_sub *sub, struct demux_packet *p)
// Read packets from the demuxer stream passed to sub_create(). Return true if
// enough packets were read, false if the player should wait until the demuxer
// signals new packets available (and then should retry).
bool sub_read_packets(struct dec_sub *sub, double video_pts, bool force)
bool sub_read_packets(struct dec_sub *sub, double video_pts)
{
bool r = true;
pthread_mutex_lock(&sub->lock);
@ -291,7 +291,7 @@ bool sub_read_packets(struct dec_sub *sub, double video_pts, bool force)
break;
// (Use this mechanism only if sub_delay matters to avoid corner cases.)
double min_pts = sub->opts->sub_delay < 0 || force ? video_pts : MP_NOPTS_VALUE;
double min_pts = sub->opts->sub_delay < 0 ? video_pts : MP_NOPTS_VALUE;
struct demux_packet *pkt;
int st = demux_read_packet_async_until(sub->sh, min_pts, &pkt);

View File

@ -43,7 +43,7 @@ void sub_destroy(struct dec_sub *sub);
bool sub_can_preload(struct dec_sub *sub);
void sub_preload(struct dec_sub *sub);
bool sub_read_packets(struct dec_sub *sub, double video_pts, bool force);
bool sub_read_packets(struct dec_sub *sub, double video_pts);
struct sub_bitmaps *sub_get_bitmaps(struct dec_sub *sub, struct mp_osd_res dim,
int format, double pts);
char *sub_get_text(struct dec_sub *sub, double pts, enum sd_text_type type);