summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2019-05-17 23:41:03 +0200
committerwm4 <wm4@nowhere>2019-09-19 20:37:04 +0200
commit62e9a0c5f6be63c4cbe6387cbd3419fe19e98b74 (patch)
tree7696768e7aa86a77d5bb9ed3f7ebb603237c29d0
parent8a58355a23ec85ff5b33196ccc6d31d660d2805f (diff)
downloadmpv-62e9a0c5f6be63c4cbe6387cbd3419fe19e98b74.tar.bz2
mpv-62e9a0c5f6be63c4cbe6387cbd3419fe19e98b74.tar.xz
demux: add shitty start of stream detection
The demuxer cache benefits slightly from knowing where the current file or stream begins. For example, seeking "left most" when the start is cached would not trigger a low level seek (which would be followed by messy range joining when it notices that the newly demuxed packets overlap with an existing range). Unfortunately, since multimedia is so crazy (or actually FFmpeg in its quite imperfect attempt to be able to demux anything), it's hard to tell where a file starts. There is no feedback whether a specific seek went to the start of the file. Packets are not tagged with a flag indicating they were demuxed from the start position. There is no index available that could be used to cross-check this (even if the file contains a full and "perfect" index, like mp4). You could go by the timestamps, but who says streams start at 0? Streams can start somewhere at an extremely high timestamps (transport streams like to do that), or they could start at negative times (e.g. files with audio pre-padding will do that), and maybe some file formats simply allow negative timestamps and could start at any negative time. Even if the affected file formats don't allow it in theory, they may in practice. In addition, FFmpeg exports a start_time field, which may or may not be useful. (mpv's internal mkv demuxer also exports such a field, but doesn't bother to set it for efficiency and robustness reasons.) Anyway, this is all a huge load of crap, so I decided that if the user performs a seek command to time 0 or earlier, we consider the first packet demuxed from each stream to be at the start of the file. In addition, just trust the start_time field. This is the "shitty" part of this commit. One common case of negative timestamps is audio pre-padding. Demuxers normally behave sanely, and will treat 0 as the start of the file, and the first packets demuxed will have negative timestamps (since they contain data to discard), which doesn't break our assumptions in this commit. (Although, unfortunately, do break some other demuxer cache assumptions, and the first cached range will be shown as starting at a negative time.) Implementation-wise, this is quite simple. Just split the existing initial_state flag into two, since we want to deal with two separate aspects. In addition, this avoids the refresh seek on track switching when it happens right after a seek, instead of only after opening the demuxer.
-rw-r--r--demux/demux.c25
1 files changed, 17 insertions, 8 deletions
diff --git a/demux/demux.c b/demux/demux.c
index ff62c4e95f..3022469b18 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -175,10 +175,13 @@ struct demux_internal {
// Do this to allow the decoder thread to select streams before starting.
bool reading;
- // Set if we know that we are at the start of the file. This is used to
+ // Set if we just performed a seek, without reading packets yet. Used to
// avoid a redundant initial seek after enabling streams. We could just
// allow it, but to avoid buggy seeking affecting normal playback, we don't.
- bool initial_state;
+ bool after_seek;
+ // Set in addition to after_seek if we think we seeked to the start of the
+ // file (or if the demuxer was just opened).
+ bool after_seek_to_start;
bool tracks_switched; // thread needs to inform demuxer of this
@@ -1419,7 +1422,8 @@ static void add_packet_locked(struct sh_stream *stream, demux_packet_t *dp)
}
struct demux_internal *in = ds->in;
- in->initial_state = false;
+ in->after_seek = false;
+ in->after_seek_to_start = false;
double ts = dp->dts == MP_NOPTS_VALUE ? dp->pts : dp->dts;
if (dp->segmented)
@@ -1616,7 +1620,7 @@ static bool read_packet(struct demux_internal *in)
if (!read_more && !prefetch_more && !refresh_more)
return false;
- if (in->initial_state) {
+ if (in->after_seek_to_start) {
for (int n = 0; n < in->num_streams; n++)
in->current_range->streams[n]->is_bof = in->streams[n]->ds->selected;
}
@@ -1624,7 +1628,8 @@ static bool read_packet(struct demux_internal *in)
// Actually read a packet. Drop the lock while doing so, because waiting
// for disk or network I/O can take time.
in->idle = false;
- in->initial_state = false;
+ in->after_seek = false;
+ in->after_seek_to_start = false;
pthread_mutex_unlock(&in->lock);
struct demuxer *demux = in->d_thread;
@@ -1767,7 +1772,10 @@ static void execute_seek(struct demux_internal *in)
in->seeking_in_progress = pts;
in->demux_ts = MP_NOPTS_VALUE;
in->low_level_seeks += 1;
- in->initial_state = false;
+ in->after_seek = true;
+ in->after_seek_to_start =
+ !(flags & (SEEK_FORWARD | SEEK_FACTOR)) &&
+ pts <= in->d_thread->start_time;
pthread_mutex_unlock(&in->lock);
@@ -2357,7 +2365,8 @@ static struct demuxer *open_given_type(struct mpv_global *global,
.min_secs = opts->min_secs,
.max_bytes = opts->max_bytes,
.max_bytes_bw = opts->max_bytes_bw,
- .initial_state = true,
+ .after_seek = true, // (assumed identical to initial demuxer state)
+ .after_seek_to_start = true,
.highest_av_pts = MP_NOPTS_VALUE,
.seeking_in_progress = MP_NOPTS_VALUE,
.demux_ts = MP_NOPTS_VALUE,
@@ -2957,7 +2966,7 @@ void demuxer_select_track(struct demuxer *demuxer, struct sh_stream *stream,
ds->selected = selected;
update_stream_selection_state(in, ds);
in->tracks_switched = true;
- if (ds->selected && !in->initial_state)
+ if (ds->selected && !in->after_seek)
initiate_refresh_seek(in, ds, MP_ADD_PTS(ref_pts, -in->ts_offset));
if (in->threading) {
pthread_cond_signal(&in->wakeup);