From b9250569cdae1d31b728cfd8f5d7f7c8f41090d3 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 3 Jun 2019 02:15:19 +0200 Subject: demux: fix assertion when switching tracks during backward playback Someone who rams a knife into his own hand just to see what happens is normally put in a psychiatric ward. But in software, this is acceptable behavior. Programs are not supposed to crash just because a user did something unreasonably dumb. Switching tracks during backward playback is such a thing. It triggered an assertion because the newly enabled stream was not properly initialized for backward playback. Fix this, and make it actually work (mostly; it still takes a "while" until playback recovers fully). This actually makes some aspects of initialization slightly cleaner. --- demux/demux.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) (limited to 'demux') diff --git a/demux/demux.c b/demux/demux.c index 3f65b2f158..b3048aacdd 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -787,8 +787,8 @@ static void ds_clear_reader_state(struct demux_stream *ds, ds->back_restart_pos = -1; ds->back_restart_dts = MP_NOPTS_VALUE; ds->back_restart_eof = false; - ds->back_restart_next = false; - ds->back_restarting = false; + ds->back_restart_next = ds->in->back_demuxing; + ds->back_restarting = ds->in->back_demuxing && ds->eager; ds->back_seek_pos = MP_NOPTS_VALUE; ds->back_resume_pos = -1; ds->back_resume_dts = MP_NOPTS_VALUE; @@ -821,8 +821,6 @@ static void update_stream_selection_state(struct demux_internal *in, ds->eof = false; ds->refreshing = false; - ds_clear_reader_state(ds, true); - // We still have to go over the whole stream list to update ds->eager for // other streams too, because they depend on other stream's selections. @@ -862,6 +860,8 @@ static void update_stream_selection_state(struct demux_internal *in, if (!any_streams) in->blocked = false; + ds_clear_reader_state(ds, true); + // Make sure any stream reselection or addition is reflected in the seek // ranges, and also get rid of data that is not needed anymore (or // rather, which can't be kept consistent). This has to happen after we've @@ -1511,8 +1511,10 @@ resume_earlier: } } - ds->back_seek_pos -= in->opts->back_seek_size; - in->need_back_seek = true; + if (ds->back_seek_pos != MP_NOPTS_VALUE) { + ds->back_seek_pos -= in->opts->back_seek_size; + in->need_back_seek = true; + } } // Process that one or multiple packets were added. @@ -3347,14 +3349,14 @@ static bool queue_seek(struct demux_internal *in, double seek_pts, int flags, } } - clear_reader_state(in, clear_back_state); - in->eof = false; in->last_eof = false; in->idle = true; in->reading = false; in->back_demuxing = set_backwards; + clear_reader_state(in, clear_back_state); + if (cache_target) { execute_cache_seek(in, cache_target, seek_pts, flags); } else { @@ -3368,22 +3370,15 @@ static bool queue_seek(struct demux_internal *in, double seek_pts, int flags, for (int n = 0; n < in->num_streams; n++) { struct demux_stream *ds = in->streams[n]->ds; - if (in->back_demuxing && clear_back_state) { + // Process possibly cached packets. + if (in->back_demuxing) { ds->back_seek_pos = seek_pts; - ds->back_restarting = ds->eager; - ds->back_restart_next = true; + back_demux_see_packets(in->streams[n]->ds); } wakeup_ds(ds); } - if (in->back_demuxing) { - // Process possibly cached packets. Separate from the loop above, since - // all flags must be set on all streams before this function is called. - for (int n = 0; n < in->num_streams; n++) - back_demux_see_packets(in->streams[n]->ds); - } - if (!in->threading && in->seeking) execute_seek(in); @@ -3488,14 +3483,19 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream, struct demux_internal *in = demuxer->in; struct demux_stream *ds = stream->ds; pthread_mutex_lock(&in->lock); + ref_pts = MP_ADD_PTS(ref_pts, -in->ts_offset); // don't flush buffers if stream is already selected / unselected if (ds->selected != selected) { MP_VERBOSE(in, "%sselect track %d\n", selected ? "" : "de", stream->index); ds->selected = selected; update_stream_selection_state(in, ds); in->tracks_switched = true; - if (ds->selected && !in->after_seek) - initiate_refresh_seek(in, ds, MP_ADD_PTS(ref_pts, -in->ts_offset)); + if (ds->selected) { + if (in->back_demuxing) + ds->back_seek_pos = ref_pts; + if (!in->after_seek) + initiate_refresh_seek(in, ds, ref_pts); + } if (in->threading) { pthread_cond_signal(&in->wakeup); } else { -- cgit v1.2.3