diff options
author | wm4 <wm4@nowhere> | 2018-01-17 07:07:15 +0100 |
---|---|---|
committer | Kevin Mitchell <kevmitch@gmail.com> | 2018-01-18 01:25:53 -0800 |
commit | 082029f8503f68c903ec6eda4bf4e37cc0065760 (patch) | |
tree | 778708f90951a8a50f526a163d360925c381c6a0 /demux/demux.c | |
parent | ca67928d7ab176c080a7e99f0d4ce0c5d1070844 (diff) | |
download | mpv-082029f8503f68c903ec6eda4bf4e37cc0065760.tar.bz2 mpv-082029f8503f68c903ec6eda4bf4e37cc0065760.tar.xz |
player: redo hack for video keyframe seeks with external audio
If you play a video with an external audio track, and do backwards
keyframe seeks, then audio can be missing. This is because a backwards
seek can end up way before the seek target (this is just how this seek
mode works). The audio file will be seeked at the correct seek target
(since audio usually has a much higher seek granularity), which results
in silence being played until the video reaches the originally intended
seek target.
There was a hack in audio.c to deal with this. Replace it with a
different hack. The new hack probably works about as well as the old
hack, except it doesn't add weird crap to the audio resync path (which
is some of the worst code here, so this is some nice preparation for
rewriting it). As a more practical advantage, it doesn't discard the
audio demuxer packet cache. The old code did, which probably ruined
seeking in youtube DASH streams.
A non-hacky solution would be handling external files in the demuxer
layer. Then chaining the seeks would be pretty easy. But we're pretty
far from that, because it would either require intrusive changes to the
demuxer layer, or wouldn't be flexible enough to load/unload external
files at runtime. Maybe later.
Diffstat (limited to 'demux/demux.c')
-rw-r--r-- | demux/demux.c | 31 |
1 files changed, 27 insertions, 4 deletions
diff --git a/demux/demux.c b/demux/demux.c index 9646bf4f64..4ccb03a17d 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -197,6 +197,8 @@ struct demux_internal { double highest_av_pts; // highest non-subtitle PTS seen - for duration + bool blocked; + // Cached state. bool force_cache_update; struct mp_tags *stream_metadata; @@ -605,6 +607,7 @@ static void update_stream_selection_state(struct demux_internal *in, // other streams too, because they depend on other stream's selections. bool any_av_streams = false; + bool any_streams = false; for (int n = 0; n < in->num_streams; n++) { struct demux_stream *s = in->streams[n]->ds; @@ -612,6 +615,7 @@ static void update_stream_selection_state(struct demux_internal *in, s->eager = s->selected && !s->sh->attached_picture; if (s->eager) any_av_streams |= s->type != STREAM_SUB; + any_streams |= s->selected; } // Subtitles are only eagerly read if there are no other eagerly read @@ -625,6 +629,9 @@ static void update_stream_selection_state(struct demux_internal *in, } } + if (!any_streams) + in->blocked = false; + // 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 @@ -1279,7 +1286,7 @@ static bool read_packet(struct demux_internal *in) in->eof = false; in->idle = true; - if (!in->reading) + if (!in->reading || in->blocked) return false; // Check if we need to read a new packet. We do this if all queues are below @@ -1552,7 +1559,7 @@ static struct demux_packet *dequeue_packet(struct demux_stream *ds) pkt->stream = ds->sh->index; return pkt; } - if (!ds->reader_head) + if (!ds->reader_head || ds->in->blocked) return NULL; struct demux_packet *pkt = ds->reader_head; ds->reader_head = pkt->next; @@ -1622,7 +1629,7 @@ struct demux_packet *demux_read_packet(struct sh_stream *sh) const char *t = stream_type_name(ds->type); MP_DBG(in, "reading packet for %s\n", t); in->eof = false; // force retry - while (ds->selected && !ds->reader_head) { + while (ds->selected && !ds->reader_head && !in->blocked) { in->reading = true; // Note: the following code marks EOF if it can't continue if (in->threading) { @@ -1673,6 +1680,8 @@ int demux_read_packet_async(struct sh_stream *sh, struct demux_packet **out_pkt) r = *out_pkt ? 1 : -1; } pthread_mutex_unlock(&ds->in->lock); + } else if (ds->in->blocked) { + r = 0; } else { *out_pkt = demux_read_packet(sh); r = *out_pkt ? 1 : -1; @@ -1698,7 +1707,7 @@ struct demux_packet *demux_read_any_packet(struct demuxer *demuxer) struct demux_internal *in = demuxer->in; assert(!in->threading); // doesn't work with threading bool read_more = true; - while (read_more) { + while (read_more && !in->blocked) { for (int n = 0; n < in->num_streams; n++) { in->reading = true; // force read_packet() to read struct demux_packet *pkt = dequeue_packet(in->streams[n]->ds); @@ -2223,6 +2232,7 @@ static void clear_reader_state(struct demux_internal *in) ds_clear_reader_state(in->streams[n]->ds); in->warned_queue_overflow = false; in->d_user->filepos = -1; // implicitly synchronized + in->blocked = false; assert(in->fw_bytes == 0); } @@ -2719,6 +2729,19 @@ void demux_disable_cache(demuxer_t *demuxer) pthread_mutex_unlock(&in->lock); } +// Disallow reading any packets and make readers think there is no new data +// yet, until a seek is issued. +void demux_block_reading(struct demuxer *demuxer, bool block) +{ + struct demux_internal *in = demuxer->in; + assert(demuxer == in->d_user); + + pthread_mutex_lock(&in->lock); + in->blocked = block; + pthread_cond_signal(&in->wakeup); + pthread_mutex_unlock(&in->lock); +} + // must be called not locked static void update_cache(struct demux_internal *in) { |