From 848546f2de52b54f78077cb4ca968e089e3e010a Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 18 Jul 2014 15:08:38 +0200 Subject: demux: fix problems with EOF It was easy to get into a wakeup feedback loop on EOF. The reason that EOF is complicated is that we try to retry reading when EOF is reached, in case the EOF state actually disappears (e.g. when watching a currently downloaded file). This feature is probably worthless, since in practice you have to do a seek to "unstuck" it anyway, but since the old code also did this, we want to keep this behavior for now. Avoid the feedback loop by introducing another EOF flag (last_eof), that contains the actual previous EOF state, and is not overwritten when retrying reading. Wakeup is skipped if the EOF state didn't change. Also, actually call the wakeup callback when EOF is detected. The line that adds "ds->active = false;" actually does nothing, but in theory it's cleaner. --- demux/demux.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/demux/demux.c b/demux/demux.c index dc4caf12f0..028fde324f 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -107,7 +107,8 @@ struct demux_internal { void *wakeup_cb_ctx; bool warned_queue_overflow; - bool eof; // last global EOF status + bool last_eof; // last actual global EOF status + bool eof; // whether we're in EOF state (reset for retry) bool autoselect; int min_packs; int min_bytes; @@ -289,6 +290,7 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) } // obviously not true anymore ds->eof = false; + in->last_eof = in->eof = false; // For video, PTS determination is not trivial, but for other media types // distinguishing PTS and DTS is not useful. @@ -359,15 +361,21 @@ static bool read_packet(struct demux_internal *in) update_cache(in); - in->eof = eof; - if (in->eof) { + if (eof) { for (int n = 0; n < in->d_buffer->num_streams; n++) { struct demux_stream *ds = in->d_buffer->streams[n]->ds; ds->eof = true; + ds->active = false; + } + // If we had EOF previously, then donn't wakeup (avoids wakeup loop) + if (!in->last_eof) { + if (in->wakeup_cb) + in->wakeup_cb(in->wakeup_cb_ctx); + pthread_cond_signal(&in->wakeup); + MP_VERBOSE(in, "EOF reached.\n"); } - pthread_cond_signal(&in->wakeup); - MP_VERBOSE(in, "EOF reached.\n"); } + in->eof = in->last_eof = eof; return true; } @@ -851,6 +859,7 @@ void demux_flush(demuxer_t *demuxer) ds_flush(demuxer->streams[n]->ds); demuxer->in->warned_queue_overflow = false; demuxer->in->eof = false; + demuxer->in->last_eof = false; pthread_mutex_unlock(&demuxer->in->lock); } -- cgit v1.2.3