summaryrefslogtreecommitdiffstats
path: root/demux/demux.c
diff options
context:
space:
mode:
authorAman Gupta <aman@tmm1.net>2017-10-13 15:16:32 -0700
committerwm4 <wm4@nowhere>2017-10-21 13:29:37 +0200
commit83c9f169c411a60bc6e025ce4feb46742690dad3 (patch)
treecb8cd7a8bcbe3ca0eb9be29857d95705e4b8bad7 /demux/demux.c
parent044af63d98b926fc6d4dd32068476707fd0bce88 (diff)
downloadmpv-83c9f169c411a60bc6e025ce4feb46742690dad3.tar.bz2
mpv-83c9f169c411a60bc6e025ce4feb46742690dad3.tar.xz
demux: optimize seeks within readahead cache
If a suitable keyframe cannot be found in each stream's readahead cache, fallback to a regular seek.
Diffstat (limited to 'demux/demux.c')
-rw-r--r--demux/demux.c116
1 files changed, 104 insertions, 12 deletions
diff --git a/demux/demux.c b/demux/demux.c
index fe7e434ec6..fecccbabc0 100644
--- a/demux/demux.c
+++ b/demux/demux.c
@@ -225,6 +225,7 @@ struct demux_stream {
static void demuxer_sort_chapters(demuxer_t *demuxer);
static void *demux_thread(void *pctx);
static void update_cache(struct demux_internal *in);
+static int cached_demux_control(struct demux_internal *in, int cmd, void *arg);
// called locked
static void ds_flush(struct demux_stream *ds)
@@ -1425,10 +1426,8 @@ struct demuxer *demux_open_url(const char *url,
return d;
}
-static void flush_locked(demuxer_t *demuxer)
+static void flush_locked_state(demuxer_t *demuxer)
{
- for (int n = 0; n < demuxer->in->num_streams; n++)
- ds_flush(demuxer->in->streams[n]->ds);
demuxer->in->warned_queue_overflow = false;
demuxer->in->eof = false;
demuxer->in->last_eof = false;
@@ -1436,6 +1435,13 @@ static void flush_locked(demuxer_t *demuxer)
demuxer->filepos = -1; // implicitly synchronized
}
+static void flush_locked(demuxer_t *demuxer)
+{
+ for (int n = 0; n < demuxer->in->num_streams; n++)
+ ds_flush(demuxer->in->streams[n]->ds);
+ flush_locked_state(demuxer);
+}
+
// clear the packet queues
void demux_flush(demuxer_t *demuxer)
{
@@ -1444,6 +1450,87 @@ void demux_flush(demuxer_t *demuxer)
pthread_mutex_unlock(&demuxer->in->lock);
}
+static bool demux_seek_cache_maybe(demuxer_t *demuxer, double seek_pts, int flags)
+{
+ struct demux_internal *in = demuxer->in;
+ struct demux_ctrl_reader_state rstate;
+ bool seeked = true;
+ double seek_pts_offset = MP_ADD_PTS(seek_pts, -in->ts_offset);
+ assert(demuxer == in->d_user);
+
+ if ((flags & SEEK_FACTOR))
+ return false;
+
+ if (cached_demux_control(in, DEMUXER_CTRL_GET_READER_STATE, &rstate) < 0)
+ return false;
+
+ MP_VERBOSE(in, "in-cache seek range = %f <-> %f (%f)\n",
+ rstate.ts_range[0], rstate.ts_range[1], seek_pts);
+
+ if (seek_pts < rstate.ts_range[0] ||
+ seek_pts > rstate.ts_range[1])
+ return false;
+
+ MP_VERBOSE(in, "in-cache seek is possible..\n");
+
+ for (int n = 0; n < in->num_streams; n++) {
+ struct demux_stream *ds = in->streams[n]->ds;
+ demux_packet_t *dp = ds->head;
+ bool found_keyframe = false;
+ int idx = 0;
+ if (!ds->active || (ds->eof && !ds->head))
+ continue;
+ // find idx of pts
+ while (dp) {
+ demux_packet_t *dn = dp->next;
+ if (dp->pts >= seek_pts_offset)
+ break;
+ idx++;
+ dp = dn;
+ }
+ if ((flags & SEEK_FORWARD)) {
+ // increment idx until keyframe
+ while (dp) {
+ demux_packet_t *dn = dp->next;
+ if (dp->keyframe) {
+ found_keyframe = true;
+ break;
+ }
+ idx++;
+ dp = dn;
+ }
+ } else {
+ // find last keyframe before idx
+ int i = 0, key_idx = 0;
+ dp = ds->head;
+ while (dp && i < idx) {
+ demux_packet_t *dn = dp->next;
+ if (dp->keyframe) {
+ found_keyframe = true;
+ key_idx = i;
+ }
+ i++;
+ dp = dn;
+ }
+ idx = key_idx;
+ }
+
+ if (!found_keyframe) {
+ seeked = false;
+ break;
+ }
+
+ while (idx-- > 0) {
+ demux_packet_t *pkt = dequeue_packet(ds);
+ free_demux_packet(pkt);
+ }
+
+ assert(ds->head && ds->head->keyframe);
+ }
+
+ return seeked;
+}
+
int demux_seek(demuxer_t *demuxer, double seek_pts, int flags)
{
struct demux_internal *in = demuxer->in;
@@ -1465,15 +1552,20 @@ int demux_seek(demuxer_t *demuxer, double seek_pts, int flags)
MP_VERBOSE(in, "queuing seek to %f%s\n", seek_pts,
in->seeking ? " (cascade)" : "");
- flush_locked(demuxer);
- in->seeking = true;
- in->seek_flags = flags;
- in->seek_pts = seek_pts;
- if (!(flags & SEEK_FACTOR))
- in->seek_pts = MP_ADD_PTS(in->seek_pts, -in->ts_offset);
-
- if (!in->threading)
- execute_seek(in);
+ if (demux_seek_cache_maybe(demuxer, seek_pts, flags)) {
+ MP_VERBOSE(in, "in-cache seek worked!\n");
+ flush_locked_state(demuxer);
+ } else {
+ flush_locked(demuxer);
+ in->seeking = true;
+ in->seek_flags = flags;
+ in->seek_pts = seek_pts;
+ if (!(flags & SEEK_FACTOR))
+ in->seek_pts = MP_ADD_PTS(in->seek_pts, -in->ts_offset);
+
+ if (!in->threading)
+ execute_seek(in);
+ }
pthread_cond_signal(&in->wakeup);
pthread_mutex_unlock(&in->lock);