summaryrefslogtreecommitdiffstats
path: root/demux
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-01-17 07:07:15 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-01-18 01:25:53 -0800
commit082029f8503f68c903ec6eda4bf4e37cc0065760 (patch)
tree778708f90951a8a50f526a163d360925c381c6a0 /demux
parentca67928d7ab176c080a7e99f0d4ce0c5d1070844 (diff)
downloadmpv-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')
-rw-r--r--demux/demux.c31
-rw-r--r--demux/demux.h2
2 files changed, 29 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)
{
diff --git a/demux/demux.h b/demux/demux.h
index e0c68a82cb..ffed39c770 100644
--- a/demux/demux.h
+++ b/demux/demux.h
@@ -285,6 +285,8 @@ void demux_set_ts_offset(struct demuxer *demuxer, double offset);
int demux_control(struct demuxer *demuxer, int cmd, void *arg);
+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);
void demux_set_stream_autoselect(struct demuxer *demuxer, bool autoselect);