summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2014-07-21 19:27:24 +0200
committerwm4 <wm4@nowhere>2014-07-21 19:29:50 +0200
commit4b4bd9e5f733f47e9c8c68099ba65b446486da81 (patch)
tree02cd0d96399ce16a2d186333871fc429d8a14916
parentb6dd1341d2ac9ed29c97be2705b81c345a973d40 (diff)
downloadmpv-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.
-rw-r--r--demux/demux.c52
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;
}