diff options
author | wm4 <wm4@nowhere> | 2014-07-21 19:27:24 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2014-07-21 19:29:50 +0200 |
commit | 4b4bd9e5f733f47e9c8c68099ba65b446486da81 (patch) | |
tree | 02cd0d96399ce16a2d186333871fc429d8a14916 /demux | |
parent | b6dd1341d2ac9ed29c97be2705b81c345a973d40 (diff) | |
download | mpv-4b4bd9e5f733f47e9c8c68099ba65b446486da81.tar.bz2 mpv-4b4bd9e5f733f47e9c8c68099ba65b446486da81.tar.xz |
demux: asynchronous seeking
This tells the demuxer thread that it should seek, instead of waiting
until the demuxer thread is ready.
Care has to be taken about the state between seek request and actual
seeking: newly demuxed packets have to be discarded. We can't just
flush when doing the actual seek, because the user thread could read
these packets.
I'm wondering if this could lead to issues due to relaxed ordering of
operations. But it should be fine, since seeking influences packet
reading only, and seeking is always strictly done before that.
Currently, this will have no advantages; unless audio is disabled. Then
seeking as well as normal playback can be non-blocking.
Diffstat (limited to 'demux')
-rw-r--r-- | demux/demux.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/demux/demux.c b/demux/demux.c index f5553eaa64..72023ad14d 100644 --- a/demux/demux.c +++ b/demux/demux.c @@ -113,6 +113,10 @@ struct demux_internal { int min_packs; int min_bytes; + bool seeking; // there's a seek queued + int seek_flags; // flags for next seek (if seeking==true) + double seek_pts; + // Cached state. double time_length; struct mp_tags *stream_metadata; @@ -269,7 +273,7 @@ int demux_add_packet(struct sh_stream *stream, demux_packet_t *dp) } struct demux_internal *in = ds->in; pthread_mutex_lock(&in->lock); - if (!ds->selected) { + if (!ds->selected || in->seeking) { pthread_mutex_unlock(&in->lock); talloc_free(dp); return 0; @@ -400,6 +404,20 @@ static void ds_get_packets(struct demux_stream *ds) } } +static void execute_seek(struct demux_internal *in) +{ + int flags = in->seek_flags; + double pts = in->seek_pts; + in->seeking = false; + + pthread_mutex_unlock(&in->lock); + + if (in->d_thread->desc->seek) + in->d_thread->desc->seek(in->d_thread, pts, flags); + + pthread_mutex_lock(&in->lock); +} + static void *demux_thread(void *pctx) { struct demux_internal *in = pctx; @@ -411,6 +429,10 @@ static void *demux_thread(void *pctx) pthread_cond_wait(&in->wakeup, &in->lock); continue; } + if (in->seeking) { + execute_seek(in); + continue; + } if (!in->eof) { if (read_packet(in)) continue; // read_packet unlocked, so recheck conditions @@ -862,19 +884,28 @@ done: return demuxer; } -void demux_flush(demuxer_t *demuxer) +static void flush_locked(demuxer_t *demuxer) { - pthread_mutex_lock(&demuxer->in->lock); for (int n = 0; n < demuxer->num_streams; n++) ds_flush(demuxer->streams[n]->ds); demuxer->in->warned_queue_overflow = false; demuxer->in->eof = false; demuxer->in->last_eof = false; +} + +// clear the packet queues +void demux_flush(demuxer_t *demuxer) +{ + pthread_mutex_lock(&demuxer->in->lock); + flush_locked(demuxer); pthread_mutex_unlock(&demuxer->in->lock); } int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags) { + struct demux_internal *in = demuxer->in; + assert(demuxer == in->d_user); + if (!demuxer->seekable) { MP_WARN(demuxer, "Cannot seek in this file.\n"); return 0; @@ -883,15 +914,18 @@ int demux_seek(demuxer_t *demuxer, float rel_seek_secs, int flags) if (rel_seek_secs == MP_NOPTS_VALUE && (flags & SEEK_ABSOLUTE)) return 0; - demux_pause(demuxer); + pthread_mutex_lock(&in->lock); - // clear the packet queues - demux_flush(demuxer); + flush_locked(demuxer); + in->seeking = true; + in->seek_flags = flags; + in->seek_pts = rel_seek_secs; - if (demuxer->desc->seek) - demuxer->desc->seek(demuxer->in->d_thread, rel_seek_secs, flags); + if (!in->threading) + execute_seek(in); - demux_unpause(demuxer); + pthread_cond_signal(&in->wakeup); + pthread_mutex_unlock(&in->lock); return 1; } |