diff --git a/libavformat/Makefile b/libavformat/Makefile
index f7e47563da..f67d261402 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -19,6 +19,7 @@ OBJS = allformats.o         \
        protocols.o          \
        riff.o               \
        sdp.o                \
+       seek.o               \
        url.o                \
        utils.o              \
 
diff --git a/libavformat/internal.h b/libavformat/internal.h
index 13e0a3df30..d0b9d6200a 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -450,6 +450,24 @@ do {\
 } while(0)
 #endif
 
+#define RELATIVE_TS_BASE (INT64_MAX - (1LL << 48))
+
+static av_always_inline int is_relative(int64_t ts)
+{
+    return ts > (RELATIVE_TS_BASE - (1LL << 48));
+}
+
+/**
+ * Wrap a given time stamp, if there is an indication for an overflow
+ *
+ * @param st stream
+ * @param timestamp the time stamp to wrap
+ * @return resulting time stamp
+ */
+int64_t ff_wrap_timestamp(const AVStream *st, int64_t timestamp);
+
+void ff_flush_packet_queue(AVFormatContext *s);
+
 /**
  * Automatically create sub-directories
  *
diff --git a/libavformat/seek.c b/libavformat/seek.c
new file mode 100644
index 0000000000..a9262cfa0a
--- /dev/null
+++ b/libavformat/seek.c
@@ -0,0 +1,754 @@
+/*
+ * Seeking and index-related functions
+ * Copyright (c) 2000, 2001, 2002 Fabrice Bellard
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdint.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/mathematics.h"
+#include "libavutil/timestamp.h"
+
+#include "avformat.h"
+#include "avio_internal.h"
+#include "internal.h"
+
+void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
+{
+    for (unsigned i = 0; i < s->nb_streams; i++) {
+        AVStream *const st  = s->streams[i];
+        FFStream *const sti = ffstream(st);
+
+        sti->cur_dts =
+            av_rescale(timestamp,
+                       st->time_base.den * (int64_t) ref_st->time_base.num,
+                       st->time_base.num * (int64_t) ref_st->time_base.den);
+    }
+}
+
+void ff_reduce_index(AVFormatContext *s, int stream_index)
+{
+    AVStream *const st  = s->streams[stream_index];
+    FFStream *const sti = ffstream(st);
+    unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry);
+
+    if ((unsigned) sti->nb_index_entries >= max_entries) {
+        int i;
+        for (i = 0; 2 * i < sti->nb_index_entries; i++)
+            sti->index_entries[i] = sti->index_entries[2 * i];
+        sti->nb_index_entries = i;
+    }
+}
+
+int ff_add_index_entry(AVIndexEntry **index_entries,
+                       int *nb_index_entries,
+                       unsigned int *index_entries_allocated_size,
+                       int64_t pos, int64_t timestamp,
+                       int size, int distance, int flags)
+{
+    AVIndexEntry *entries, *ie;
+    int index;
+
+    if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
+        return -1;
+
+    if (timestamp == AV_NOPTS_VALUE)
+        return AVERROR(EINVAL);
+
+    if (size < 0 || size > 0x3FFFFFFF)
+        return AVERROR(EINVAL);
+
+    if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
+        timestamp -= RELATIVE_TS_BASE;
+
+    entries = av_fast_realloc(*index_entries,
+                              index_entries_allocated_size,
+                              (*nb_index_entries + 1) *
+                              sizeof(AVIndexEntry));
+    if (!entries)
+        return -1;
+
+    *index_entries = entries;
+
+    index = ff_index_search_timestamp(*index_entries, *nb_index_entries,
+                                      timestamp, AVSEEK_FLAG_ANY);
+
+    if (index < 0) {
+        index = (*nb_index_entries)++;
+        ie    = &entries[index];
+        av_assert0(index == 0 || ie[-1].timestamp < timestamp);
+    } else {
+        ie = &entries[index];
+        if (ie->timestamp != timestamp) {
+            if (ie->timestamp <= timestamp)
+                return -1;
+            memmove(entries + index + 1, entries + index,
+                    sizeof(AVIndexEntry) * (*nb_index_entries - index));
+            (*nb_index_entries)++;
+        } else if (ie->pos == pos && distance < ie->min_distance)
+            // do not reduce the distance
+            distance = ie->min_distance;
+    }
+
+    ie->pos          = pos;
+    ie->timestamp    = timestamp;
+    ie->min_distance = distance;
+    ie->size         = size;
+    ie->flags        = flags;
+
+    return index;
+}
+
+int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
+                       int size, int distance, int flags)
+{
+    FFStream *const sti = ffstream(st);
+    timestamp = ff_wrap_timestamp(st, timestamp);
+    return ff_add_index_entry(&sti->index_entries, &sti->nb_index_entries,
+                              &sti->index_entries_allocated_size, pos,
+                              timestamp, size, distance, flags);
+}
+
+int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries,
+                              int64_t wanted_timestamp, int flags)
+{
+    int a, b, m;
+    int64_t timestamp;
+
+    a = -1;
+    b = nb_entries;
+
+    // Optimize appending index entries at the end.
+    if (b && entries[b - 1].timestamp < wanted_timestamp)
+        a = b - 1;
+
+    while (b - a > 1) {
+        m         = (a + b) >> 1;
+
+        // Search for the next non-discarded packet.
+        while ((entries[m].flags & AVINDEX_DISCARD_FRAME) && m < b && m < nb_entries - 1) {
+            m++;
+            if (m == b && entries[m].timestamp >= wanted_timestamp) {
+                m = b - 1;
+                break;
+            }
+        }
+
+        timestamp = entries[m].timestamp;
+        if (timestamp >= wanted_timestamp)
+            b = m;
+        if (timestamp <= wanted_timestamp)
+            a = m;
+    }
+    m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b;
+
+    if (!(flags & AVSEEK_FLAG_ANY))
+        while (m >= 0 && m < nb_entries &&
+               !(entries[m].flags & AVINDEX_KEYFRAME))
+            m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1;
+
+    if (m == nb_entries)
+        return -1;
+    return m;
+}
+
+void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
+{
+    int64_t pos_delta = 0;
+    int64_t skip = 0;
+    //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable
+    const char *proto = avio_find_protocol_name(s->url);
+    FFIOContext *ctx;
+
+    av_assert0(time_tolerance >= 0);
+
+    if (!proto) {
+        av_log(s, AV_LOG_INFO,
+               "Protocol name not provided, cannot determine if input is local or "
+               "a network protocol, buffers and access patterns cannot be configured "
+               "optimally without knowing the protocol\n");
+    }
+
+    if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache")))
+        return;
+
+    for (unsigned ist1 = 0; ist1 < s->nb_streams; ist1++) {
+        AVStream *const st1  = s->streams[ist1];
+        FFStream *const sti1 = ffstream(st1);
+        for (unsigned ist2 = 0; ist2 < s->nb_streams; ist2++) {
+            AVStream *const st2  = s->streams[ist2];
+            FFStream *const sti2 = ffstream(st2);
+
+            if (ist1 == ist2)
+                continue;
+
+            for (int i1 = 0, i2 = 0; i1 < sti1->nb_index_entries; i1++) {
+                const AVIndexEntry *const e1 = &sti1->index_entries[i1];
+                int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q);
+
+                skip = FFMAX(skip, e1->size);
+                for (; i2 < sti2->nb_index_entries; i2++) {
+                    const AVIndexEntry *const e2 = &sti2->index_entries[i2];
+                    int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q);
+                    if (e2_pts < e1_pts || e2_pts - (uint64_t)e1_pts < time_tolerance)
+                        continue;
+                    pos_delta = FFMAX(pos_delta, e1->pos - e2->pos);
+                    break;
+                }
+            }
+        }
+    }
+
+    pos_delta *= 2;
+    ctx = ffiocontext(s->pb);
+    /* XXX This could be adjusted depending on protocol*/
+    if (s->pb->buffer_size < pos_delta && pos_delta < (1<<24)) {
+        av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta);
+
+        /* realloc the buffer and the original data will be retained */
+        if (ffio_realloc_buf(s->pb, pos_delta)) {
+            av_log(s, AV_LOG_ERROR, "Realloc buffer fail.\n");
+            return;
+        }
+
+        ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, pos_delta/2);
+    }
+
+    if (skip < (1<<23)) {
+        ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, skip);
+    }
+}
+
+int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
+{
+    const FFStream *const sti = ffstream(st);
+    return ff_index_search_timestamp(sti->index_entries, sti->nb_index_entries,
+                                     wanted_timestamp, flags);
+}
+
+int avformat_index_get_entries_count(const AVStream *st)
+{
+    return cffstream(st)->nb_index_entries;
+}
+
+const AVIndexEntry *avformat_index_get_entry(AVStream *st, int idx)
+{
+    const FFStream *const sti = ffstream(st);
+    if (idx < 0 || idx >= sti->nb_index_entries)
+        return NULL;
+
+    return &sti->index_entries[idx];
+}
+
+const AVIndexEntry *avformat_index_get_entry_from_timestamp(AVStream *st,
+                                                            int64_t wanted_timestamp,
+                                                            int flags)
+{
+    const FFStream *const sti = ffstream(st);
+    int idx = ff_index_search_timestamp(sti->index_entries,
+                                        sti->nb_index_entries,
+                                        wanted_timestamp, flags);
+
+    if (idx < 0)
+        return NULL;
+
+    return &sti->index_entries[idx];
+}
+
+static int64_t read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
+                              int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
+{
+    int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit);
+    if (stream_index >= 0)
+        ts = ff_wrap_timestamp(s->streams[stream_index], ts);
+    return ts;
+}
+
+int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
+                         int64_t target_ts, int flags)
+{
+    const AVInputFormat *const avif = s->iformat;
+    int64_t av_uninit(pos_min), av_uninit(pos_max), pos, pos_limit;
+    int64_t ts_min, ts_max, ts;
+    int index;
+    int64_t ret;
+    AVStream *st;
+    FFStream *sti;
+
+    if (stream_index < 0)
+        return -1;
+
+    av_log(s, AV_LOG_TRACE, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts));
+
+    ts_max =
+    ts_min = AV_NOPTS_VALUE;
+    pos_limit = -1; // GCC falsely says it may be uninitialized.
+
+    st  = s->streams[stream_index];
+    sti = ffstream(st);
+    if (sti->index_entries) {
+        const AVIndexEntry *e;
+
+        /* FIXME: Whole function must be checked for non-keyframe entries in
+         * index case, especially read_timestamp(). */
+        index = av_index_search_timestamp(st, target_ts,
+                                          flags | AVSEEK_FLAG_BACKWARD);
+        index = FFMAX(index, 0);
+        e     = &sti->index_entries[index];
+
+        if (e->timestamp <= target_ts || e->pos == e->min_distance) {
+            pos_min = e->pos;
+            ts_min  = e->timestamp;
+            av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%s\n",
+                    pos_min, av_ts2str(ts_min));
+        } else {
+            av_assert1(index == 0);
+        }
+
+        index = av_index_search_timestamp(st, target_ts,
+                                          flags & ~AVSEEK_FLAG_BACKWARD);
+        av_assert0(index < sti->nb_index_entries);
+        if (index >= 0) {
+            e = &sti->index_entries[index];
+            av_assert1(e->timestamp >= target_ts);
+            pos_max   = e->pos;
+            ts_max    = e->timestamp;
+            pos_limit = pos_max - e->min_distance;
+            av_log(s, AV_LOG_TRACE, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64
+                    " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max));
+        }
+    }
+
+    pos = ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit,
+                        ts_min, ts_max, flags, &ts, avif->read_timestamp);
+    if (pos < 0)
+        return -1;
+
+    /* do the seek */
+    if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0)
+        return ret;
+
+    ff_read_frame_flush(s);
+    avpriv_update_cur_dts(s, st, ts);
+
+    return 0;
+}
+
+int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos,
+                    int64_t (*read_timestamp_func)(struct AVFormatContext *, int , int64_t *, int64_t ))
+{
+    int64_t step = 1024;
+    int64_t limit, ts_max;
+    int64_t filesize = avio_size(s->pb);
+    int64_t pos_max  = filesize - 1;
+    do {
+        limit   = pos_max;
+        pos_max = FFMAX(0, (pos_max) - step);
+        ts_max  = read_timestamp(s, stream_index,
+                                 &pos_max, limit, read_timestamp_func);
+        step   += step;
+    } while (ts_max == AV_NOPTS_VALUE && 2*limit > step);
+    if (ts_max == AV_NOPTS_VALUE)
+        return -1;
+
+    for (;;) {
+        int64_t tmp_pos = pos_max + 1;
+        int64_t tmp_ts  = read_timestamp(s, stream_index,
+                                         &tmp_pos, INT64_MAX, read_timestamp_func);
+        if (tmp_ts == AV_NOPTS_VALUE)
+            break;
+        av_assert0(tmp_pos > pos_max);
+        ts_max  = tmp_ts;
+        pos_max = tmp_pos;
+        if (tmp_pos >= filesize)
+            break;
+    }
+
+    if (ts)
+        *ts  = ts_max;
+    if (pos)
+        *pos = pos_max;
+
+    return 0;
+}
+
+int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
+                      int64_t pos_min, int64_t pos_max, int64_t pos_limit,
+                      int64_t ts_min, int64_t ts_max,
+                      int flags, int64_t *ts_ret,
+                      int64_t (*read_timestamp_func)(struct AVFormatContext *,
+                                                     int, int64_t *, int64_t))
+{
+    FFFormatContext *const si = ffformatcontext(s);
+    int64_t pos, ts;
+    int64_t start_pos;
+    int no_change;
+    int ret;
+
+    av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
+
+    if (ts_min == AV_NOPTS_VALUE) {
+        pos_min = si->data_offset;
+        ts_min  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
+        if (ts_min == AV_NOPTS_VALUE)
+            return -1;
+    }
+
+    if (ts_min >= target_ts) {
+        *ts_ret = ts_min;
+        return pos_min;
+    }
+
+    if (ts_max == AV_NOPTS_VALUE) {
+        if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp_func)) < 0)
+            return ret;
+        pos_limit = pos_max;
+    }
+
+    if (ts_max <= target_ts) {
+        *ts_ret = ts_max;
+        return pos_max;
+    }
+
+    av_assert0(ts_min < ts_max);
+
+    no_change = 0;
+    while (pos_min < pos_limit) {
+        av_log(s, AV_LOG_TRACE,
+                "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n",
+                pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max));
+        av_assert0(pos_limit <= pos_max);
+
+        if (no_change == 0) {
+            int64_t approximate_keyframe_distance = pos_max - pos_limit;
+            // interpolate position (better than dichotomy)
+            pos = av_rescale(target_ts - ts_min, pos_max - pos_min,
+                             ts_max - ts_min) +
+                  pos_min - approximate_keyframe_distance;
+        } else if (no_change == 1) {
+            // bisection if interpolation did not change min / max pos last time
+            pos = (pos_min + pos_limit) >> 1;
+        } else {
+            /* linear search if bisection failed, can only happen if there
+             * are very few or no keyframes between min/max */
+            pos = pos_min;
+        }
+        if (pos <= pos_min)
+            pos = pos_min + 1;
+        else if (pos > pos_limit)
+            pos = pos_limit;
+        start_pos = pos;
+
+        // May pass pos_limit instead of -1.
+        ts = read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp_func);
+        if (pos == pos_max)
+            no_change++;
+        else
+            no_change = 0;
+        av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s"
+                " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n",
+                pos_min, pos, pos_max,
+                av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts),
+                pos_limit, start_pos, no_change);
+        if (ts == AV_NOPTS_VALUE) {
+            av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
+            return -1;
+        }
+        if (target_ts <= ts) {
+            pos_limit = start_pos - 1;
+            pos_max   = pos;
+            ts_max    = ts;
+        }
+        if (target_ts >= ts) {
+            pos_min = pos;
+            ts_min  = ts;
+        }
+    }
+
+    pos     = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
+    ts      = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min  : ts_max;
+#if 0
+    pos_min = pos;
+    ts_min  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
+    pos_min++;
+    ts_max  = read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp_func);
+    av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %s<=%s<=%s\n",
+            pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
+#endif
+    *ts_ret = ts;
+    return pos;
+}
+
+static int seek_frame_byte(AVFormatContext *s, int stream_index,
+                           int64_t pos, int flags)
+{
+    FFFormatContext *const si = ffformatcontext(s);
+    int64_t pos_min, pos_max;
+
+    pos_min = si->data_offset;
+    pos_max = avio_size(s->pb) - 1;
+
+    if (pos < pos_min)
+        pos = pos_min;
+    else if (pos > pos_max)
+        pos = pos_max;
+
+    avio_seek(s->pb, pos, SEEK_SET);
+
+    s->io_repositioned = 1;
+
+    return 0;
+}
+
+static int seek_frame_generic(AVFormatContext *s, int stream_index,
+                              int64_t timestamp, int flags)
+{
+    FFFormatContext *const si = ffformatcontext(s);
+    AVStream *const st  = s->streams[stream_index];
+    FFStream *const sti = ffstream(st);
+    const AVIndexEntry *ie;
+    int index;
+    int64_t ret;
+
+    index = av_index_search_timestamp(st, timestamp, flags);
+
+    if (index < 0 && sti->nb_index_entries &&
+        timestamp < sti->index_entries[0].timestamp)
+        return -1;
+
+    if (index < 0 || index == sti->nb_index_entries - 1) {
+        AVPacket *const pkt = si->pkt;
+        int nonkey = 0;
+
+        if (sti->nb_index_entries) {
+            av_assert0(sti->index_entries);
+            ie = &sti->index_entries[sti->nb_index_entries - 1];
+            if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
+                return ret;
+            s->io_repositioned = 1;
+            avpriv_update_cur_dts(s, st, ie->timestamp);
+        } else {
+            if ((ret = avio_seek(s->pb, si->data_offset, SEEK_SET)) < 0)
+                return ret;
+            s->io_repositioned = 1;
+        }
+        av_packet_unref(pkt);
+        for (;;) {
+            int read_status;
+            do {
+                read_status = av_read_frame(s, pkt);
+            } while (read_status == AVERROR(EAGAIN));
+            if (read_status < 0)
+                break;
+            if (stream_index == pkt->stream_index && pkt->dts > timestamp) {
+                if (pkt->flags & AV_PKT_FLAG_KEY) {
+                    av_packet_unref(pkt);
+                    break;
+                }
+                if (nonkey++ > 1000 && st->codecpar->codec_id != AV_CODEC_ID_CDGRAPHICS) {
+                    av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey);
+                    av_packet_unref(pkt);
+                    break;
+                }
+            }
+            av_packet_unref(pkt);
+        }
+        index = av_index_search_timestamp(st, timestamp, flags);
+    }
+    if (index < 0)
+        return -1;
+
+    ff_read_frame_flush(s);
+    if (s->iformat->read_seek)
+        if (s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
+            return 0;
+    ie = &sti->index_entries[index];
+    if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
+        return ret;
+    s->io_repositioned = 1;
+    avpriv_update_cur_dts(s, st, ie->timestamp);
+
+    return 0;
+}
+
+static int seek_frame_internal(AVFormatContext *s, int stream_index,
+                               int64_t timestamp, int flags)
+{
+    AVStream *st;
+    int ret;
+
+    if (flags & AVSEEK_FLAG_BYTE) {
+        if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
+            return -1;
+        ff_read_frame_flush(s);
+        return seek_frame_byte(s, stream_index, timestamp, flags);
+    }
+
+    if (stream_index < 0) {
+        stream_index = av_find_default_stream_index(s);
+        if (stream_index < 0)
+            return -1;
+
+        st = s->streams[stream_index];
+        /* timestamp for default must be expressed in AV_TIME_BASE units */
+        timestamp = av_rescale(timestamp, st->time_base.den,
+                               AV_TIME_BASE * (int64_t) st->time_base.num);
+    }
+
+    /* first, we try the format specific seek */
+    if (s->iformat->read_seek) {
+        ff_read_frame_flush(s);
+        ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
+    } else
+        ret = -1;
+    if (ret >= 0)
+        return 0;
+
+    if (s->iformat->read_timestamp &&
+        !(s->iformat->flags & AVFMT_NOBINSEARCH)) {
+        ff_read_frame_flush(s);
+        return ff_seek_frame_binary(s, stream_index, timestamp, flags);
+    } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) {
+        ff_read_frame_flush(s);
+        return seek_frame_generic(s, stream_index, timestamp, flags);
+    } else
+        return -1;
+}
+
+int av_seek_frame(AVFormatContext *s, int stream_index,
+                  int64_t timestamp, int flags)
+{
+    int ret;
+
+    if (s->iformat->read_seek2 && !s->iformat->read_seek) {
+        int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
+        if ((flags & AVSEEK_FLAG_BACKWARD))
+            max_ts = timestamp;
+        else
+            min_ts = timestamp;
+        return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
+                                  flags & ~AVSEEK_FLAG_BACKWARD);
+    }
+
+    ret = seek_frame_internal(s, stream_index, timestamp, flags);
+
+    if (ret >= 0)
+        ret = avformat_queue_attached_pictures(s);
+
+    return ret;
+}
+
+int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
+                       int64_t ts, int64_t max_ts, int flags)
+{
+    if (min_ts > ts || max_ts < ts)
+        return -1;
+    if (stream_index < -1 || stream_index >= (int)s->nb_streams)
+        return AVERROR(EINVAL);
+
+    if (s->seek2any > 0)
+        flags |= AVSEEK_FLAG_ANY;
+    flags &= ~AVSEEK_FLAG_BACKWARD;
+
+    if (s->iformat->read_seek2) {
+        int ret;
+        ff_read_frame_flush(s);
+
+        if (stream_index == -1 && s->nb_streams == 1) {
+            AVRational time_base = s->streams[0]->time_base;
+            ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
+            min_ts = av_rescale_rnd(min_ts, time_base.den,
+                                    time_base.num * (int64_t)AV_TIME_BASE,
+                                    AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
+            max_ts = av_rescale_rnd(max_ts, time_base.den,
+                                    time_base.num * (int64_t)AV_TIME_BASE,
+                                    AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
+            stream_index = 0;
+        }
+
+        ret = s->iformat->read_seek2(s, stream_index, min_ts,
+                                     ts, max_ts, flags);
+
+        if (ret >= 0)
+            ret = avformat_queue_attached_pictures(s);
+        return ret;
+    }
+
+    if (s->iformat->read_timestamp) {
+        // try to seek via read_timestamp()
+    }
+
+    // Fall back on old API if new is not implemented but old is.
+    // Note the old API has somewhat different semantics.
+    if (s->iformat->read_seek || 1) {
+        int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
+        int ret = av_seek_frame(s, stream_index, ts, flags | dir);
+        if (ret < 0 && ts != min_ts && max_ts != ts) {
+            ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
+            if (ret >= 0)
+                ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
+        }
+        return ret;
+    }
+
+    // try some generic seek like seek_frame_generic() but with new ts semantics
+    return -1; //unreachable
+}
+
+/** Flush the frame reader. */
+void ff_read_frame_flush(AVFormatContext *s)
+{
+    FFFormatContext *const si = ffformatcontext(s);
+
+    ff_flush_packet_queue(s);
+
+    /* Reset read state for each stream. */
+    for (unsigned i = 0; i < s->nb_streams; i++) {
+        AVStream *const st  = s->streams[i];
+        FFStream *const sti = ffstream(st);
+
+        if (sti->parser) {
+            av_parser_close(sti->parser);
+            sti->parser = NULL;
+        }
+        sti->last_IP_pts = AV_NOPTS_VALUE;
+        sti->last_dts_for_order_check = AV_NOPTS_VALUE;
+        if (sti->first_dts == AV_NOPTS_VALUE)
+            sti->cur_dts = RELATIVE_TS_BASE;
+        else
+            /* We set the current DTS to an unspecified origin. */
+            sti->cur_dts = AV_NOPTS_VALUE;
+
+        sti->probe_packets = s->max_probe_packets;
+
+        for (int j = 0; j < MAX_REORDER_DELAY + 1; j++)
+            sti->pts_buffer[j] = AV_NOPTS_VALUE;
+
+        if (si->inject_global_side_data)
+            sti->inject_global_side_data = 1;
+
+        sti->skip_samples = 0;
+    }
+}
+
+int avformat_flush(AVFormatContext *s)
+{
+    ff_read_frame_flush(s);
+    return 0;
+}
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 25285f62ab..61acaf16a2 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -88,19 +88,6 @@ int ff_unlock_avformat(void)
     return ff_mutex_unlock(&avformat_mutex) ? -1 : 0;
 }
 
-#define RELATIVE_TS_BASE (INT64_MAX - (1LL<<48))
-
-static int is_relative(int64_t ts) {
-    return ts > (RELATIVE_TS_BASE - (1LL<<48));
-}
-
-/**
- * Wrap a given time stamp, if there is an indication for an overflow
- *
- * @param st stream
- * @param timestamp the time stamp to wrap
- * @return resulting time stamp
- */
 static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp)
 {
     const FFStream *const sti = cffstream(st);
@@ -116,6 +103,11 @@ static int64_t wrap_timestamp(const AVStream *st, int64_t timestamp)
     return timestamp;
 }
 
+int64_t ff_wrap_timestamp(const AVStream *st, int64_t timestamp)
+{
+    return wrap_timestamp(st, timestamp);
+}
+
 int64_t av_stream_get_end_pts(const AVStream *st)
 {
     if (cffstream(st)->priv_pts) {
@@ -1771,7 +1763,7 @@ return_packet:
 }
 
 /* XXX: suppress the packet queue */
-static void flush_packet_queue(AVFormatContext *s)
+void ff_flush_packet_queue(AVFormatContext *s)
 {
     FFFormatContext *const si = ffformatcontext(s);
     avpriv_packet_list_free(&si->parse_queue,       &si->parse_queue_end);
@@ -1781,9 +1773,6 @@ static void flush_packet_queue(AVFormatContext *s)
     si->raw_packet_buffer_remaining_size = RAW_PACKET_BUFFER_SIZE;
 }
 
-/*******************************************************/
-/* seek support */
-
 int av_find_default_stream_index(AVFormatContext *s)
 {
     int best_stream = 0;
@@ -1820,731 +1809,6 @@ int av_find_default_stream_index(AVFormatContext *s)
     return best_stream;
 }
 
-/** Flush the frame reader. */
-void ff_read_frame_flush(AVFormatContext *s)
-{
-    FFFormatContext *const si = ffformatcontext(s);
-
-    flush_packet_queue(s);
-
-    /* Reset read state for each stream. */
-    for (unsigned i = 0; i < s->nb_streams; i++) {
-        AVStream *const st  = s->streams[i];
-        FFStream *const sti = ffstream(st);
-
-        if (sti->parser) {
-            av_parser_close(sti->parser);
-            sti->parser = NULL;
-        }
-        sti->last_IP_pts = AV_NOPTS_VALUE;
-        sti->last_dts_for_order_check = AV_NOPTS_VALUE;
-        if (sti->first_dts == AV_NOPTS_VALUE)
-            sti->cur_dts = RELATIVE_TS_BASE;
-        else
-            /* We set the current DTS to an unspecified origin. */
-            sti->cur_dts = AV_NOPTS_VALUE;
-
-        sti->probe_packets = s->max_probe_packets;
-
-        for (int j = 0; j < MAX_REORDER_DELAY + 1; j++)
-            sti->pts_buffer[j] = AV_NOPTS_VALUE;
-
-        if (si->inject_global_side_data)
-            sti->inject_global_side_data = 1;
-
-        sti->skip_samples = 0;
-    }
-}
-
-void avpriv_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp)
-{
-    for (unsigned i = 0; i < s->nb_streams; i++) {
-        AVStream *st = s->streams[i];
-        FFStream *const sti = ffstream(st);
-
-        sti->cur_dts =
-            av_rescale(timestamp,
-                       st->time_base.den * (int64_t) ref_st->time_base.num,
-                       st->time_base.num * (int64_t) ref_st->time_base.den);
-    }
-}
-
-void ff_reduce_index(AVFormatContext *s, int stream_index)
-{
-    AVStream *st             = s->streams[stream_index];
-    FFStream *const sti = ffstream(st);
-    unsigned int max_entries = s->max_index_size / sizeof(AVIndexEntry);
-
-    if ((unsigned) sti->nb_index_entries >= max_entries) {
-        int i;
-        for (i = 0; 2 * i < sti->nb_index_entries; i++)
-            sti->index_entries[i] = sti->index_entries[2 * i];
-        sti->nb_index_entries = i;
-    }
-}
-
-int ff_add_index_entry(AVIndexEntry **index_entries,
-                       int *nb_index_entries,
-                       unsigned int *index_entries_allocated_size,
-                       int64_t pos, int64_t timestamp,
-                       int size, int distance, int flags)
-{
-    AVIndexEntry *entries, *ie;
-    int index;
-
-    if ((unsigned) *nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
-        return -1;
-
-    if (timestamp == AV_NOPTS_VALUE)
-        return AVERROR(EINVAL);
-
-    if (size < 0 || size > 0x3FFFFFFF)
-        return AVERROR(EINVAL);
-
-    if (is_relative(timestamp)) //FIXME this maintains previous behavior but we should shift by the correct offset once known
-        timestamp -= RELATIVE_TS_BASE;
-
-    entries = av_fast_realloc(*index_entries,
-                              index_entries_allocated_size,
-                              (*nb_index_entries + 1) *
-                              sizeof(AVIndexEntry));
-    if (!entries)
-        return -1;
-
-    *index_entries = entries;
-
-    index = ff_index_search_timestamp(*index_entries, *nb_index_entries,
-                                      timestamp, AVSEEK_FLAG_ANY);
-
-    if (index < 0) {
-        index = (*nb_index_entries)++;
-        ie    = &entries[index];
-        av_assert0(index == 0 || ie[-1].timestamp < timestamp);
-    } else {
-        ie = &entries[index];
-        if (ie->timestamp != timestamp) {
-            if (ie->timestamp <= timestamp)
-                return -1;
-            memmove(entries + index + 1, entries + index,
-                    sizeof(AVIndexEntry) * (*nb_index_entries - index));
-            (*nb_index_entries)++;
-        } else if (ie->pos == pos && distance < ie->min_distance)
-            // do not reduce the distance
-            distance = ie->min_distance;
-    }
-
-    ie->pos          = pos;
-    ie->timestamp    = timestamp;
-    ie->min_distance = distance;
-    ie->size         = size;
-    ie->flags        = flags;
-
-    return index;
-}
-
-int av_add_index_entry(AVStream *st, int64_t pos, int64_t timestamp,
-                       int size, int distance, int flags)
-{
-    FFStream *const sti = ffstream(st);
-    timestamp = wrap_timestamp(st, timestamp);
-    return ff_add_index_entry(&sti->index_entries, &sti->nb_index_entries,
-                              &sti->index_entries_allocated_size, pos,
-                              timestamp, size, distance, flags);
-}
-
-int ff_index_search_timestamp(const AVIndexEntry *entries, int nb_entries,
-                              int64_t wanted_timestamp, int flags)
-{
-    int a, b, m;
-    int64_t timestamp;
-
-    a = -1;
-    b = nb_entries;
-
-    // Optimize appending index entries at the end.
-    if (b && entries[b - 1].timestamp < wanted_timestamp)
-        a = b - 1;
-
-    while (b - a > 1) {
-        m         = (a + b) >> 1;
-
-        // Search for the next non-discarded packet.
-        while ((entries[m].flags & AVINDEX_DISCARD_FRAME) && m < b && m < nb_entries - 1) {
-            m++;
-            if (m == b && entries[m].timestamp >= wanted_timestamp) {
-                m = b - 1;
-                break;
-            }
-        }
-
-        timestamp = entries[m].timestamp;
-        if (timestamp >= wanted_timestamp)
-            b = m;
-        if (timestamp <= wanted_timestamp)
-            a = m;
-    }
-    m = (flags & AVSEEK_FLAG_BACKWARD) ? a : b;
-
-    if (!(flags & AVSEEK_FLAG_ANY))
-        while (m >= 0 && m < nb_entries &&
-               !(entries[m].flags & AVINDEX_KEYFRAME))
-            m += (flags & AVSEEK_FLAG_BACKWARD) ? -1 : 1;
-
-    if (m == nb_entries)
-        return -1;
-    return m;
-}
-
-void ff_configure_buffers_for_index(AVFormatContext *s, int64_t time_tolerance)
-{
-    int64_t pos_delta = 0;
-    int64_t skip = 0;
-    //We could use URLProtocol flags here but as many user applications do not use URLProtocols this would be unreliable
-    const char *proto = avio_find_protocol_name(s->url);
-    FFIOContext *ctx;
-
-    av_assert0(time_tolerance >= 0);
-
-    if (!proto) {
-        av_log(s, AV_LOG_INFO,
-               "Protocol name not provided, cannot determine if input is local or "
-               "a network protocol, buffers and access patterns cannot be configured "
-               "optimally without knowing the protocol\n");
-    }
-
-    if (proto && !(strcmp(proto, "file") && strcmp(proto, "pipe") && strcmp(proto, "cache")))
-        return;
-
-    for (unsigned ist1 = 0; ist1 < s->nb_streams; ist1++) {
-        AVStream *st1 = s->streams[ist1];
-        FFStream *const sti1 = ffstream(st1);
-        for (unsigned ist2 = 0; ist2 < s->nb_streams; ist2++) {
-            AVStream *st2 = s->streams[ist2];
-            FFStream *const sti2 = ffstream(st2);
-
-            if (ist1 == ist2)
-                continue;
-
-            for (int i1 = 0, i2 = 0; i1 < sti1->nb_index_entries; i1++) {
-                const AVIndexEntry *const e1 = &sti1->index_entries[i1];
-                int64_t e1_pts = av_rescale_q(e1->timestamp, st1->time_base, AV_TIME_BASE_Q);
-
-                skip = FFMAX(skip, e1->size);
-                for (; i2 < sti2->nb_index_entries; i2++) {
-                    const AVIndexEntry *const e2 = &sti2->index_entries[i2];
-                    int64_t e2_pts = av_rescale_q(e2->timestamp, st2->time_base, AV_TIME_BASE_Q);
-                    if (e2_pts < e1_pts || e2_pts - (uint64_t)e1_pts < time_tolerance)
-                        continue;
-                    pos_delta = FFMAX(pos_delta, e1->pos - e2->pos);
-                    break;
-                }
-            }
-        }
-    }
-
-    pos_delta *= 2;
-    ctx = ffiocontext(s->pb);
-    /* XXX This could be adjusted depending on protocol*/
-    if (s->pb->buffer_size < pos_delta && pos_delta < (1<<24)) {
-        av_log(s, AV_LOG_VERBOSE, "Reconfiguring buffers to size %"PRId64"\n", pos_delta);
-
-        /* realloc the buffer and the original data will be retained */
-        if (ffio_realloc_buf(s->pb, pos_delta)) {
-            av_log(s, AV_LOG_ERROR, "Realloc buffer fail.\n");
-            return;
-        }
-
-        ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, pos_delta/2);
-    }
-
-    if (skip < (1<<23)) {
-        ctx->short_seek_threshold = FFMAX(ctx->short_seek_threshold, skip);
-    }
-}
-
-int av_index_search_timestamp(AVStream *st, int64_t wanted_timestamp, int flags)
-{
-    FFStream *const sti = ffstream(st);
-    return ff_index_search_timestamp(sti->index_entries, sti->nb_index_entries,
-                                     wanted_timestamp, flags);
-}
-
-int avformat_index_get_entries_count(const AVStream *st)
-{
-    return cffstream(st)->nb_index_entries;
-}
-
-const AVIndexEntry *avformat_index_get_entry(AVStream *st, int idx)
-{
-    const FFStream *const sti = ffstream(st);
-    if (idx < 0 || idx >= sti->nb_index_entries)
-        return NULL;
-
-    return &sti->index_entries[idx];
-}
-
-const AVIndexEntry *avformat_index_get_entry_from_timestamp(AVStream *st,
-                                                            int64_t wanted_timestamp,
-                                                            int flags)
-{
-    const FFStream *const sti = ffstream(st);
-    int idx = ff_index_search_timestamp(sti->index_entries,
-                                        sti->nb_index_entries,
-                                        wanted_timestamp, flags);
-
-    if (idx < 0)
-        return NULL;
-
-    return &sti->index_entries[idx];
-}
-
-static int64_t ff_read_timestamp(AVFormatContext *s, int stream_index, int64_t *ppos, int64_t pos_limit,
-                                 int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
-{
-    int64_t ts = read_timestamp(s, stream_index, ppos, pos_limit);
-    if (stream_index >= 0)
-        ts = wrap_timestamp(s->streams[stream_index], ts);
-    return ts;
-}
-
-int ff_seek_frame_binary(AVFormatContext *s, int stream_index,
-                         int64_t target_ts, int flags)
-{
-    const AVInputFormat *avif = s->iformat;
-    int64_t av_uninit(pos_min), av_uninit(pos_max), pos, pos_limit;
-    int64_t ts_min, ts_max, ts;
-    int index;
-    int64_t ret;
-    AVStream *st;
-    FFStream *sti;
-
-    if (stream_index < 0)
-        return -1;
-
-    av_log(s, AV_LOG_TRACE, "read_seek: %d %s\n", stream_index, av_ts2str(target_ts));
-
-    ts_max =
-    ts_min = AV_NOPTS_VALUE;
-    pos_limit = -1; // GCC falsely says it may be uninitialized.
-
-    st = s->streams[stream_index];
-    sti = ffstream(st);
-    if (sti->index_entries) {
-        AVIndexEntry *e;
-
-        /* FIXME: Whole function must be checked for non-keyframe entries in
-         * index case, especially read_timestamp(). */
-        index = av_index_search_timestamp(st, target_ts,
-                                          flags | AVSEEK_FLAG_BACKWARD);
-        index = FFMAX(index, 0);
-        e     = &sti->index_entries[index];
-
-        if (e->timestamp <= target_ts || e->pos == e->min_distance) {
-            pos_min = e->pos;
-            ts_min  = e->timestamp;
-            av_log(s, AV_LOG_TRACE, "using cached pos_min=0x%"PRIx64" dts_min=%s\n",
-                    pos_min, av_ts2str(ts_min));
-        } else {
-            av_assert1(index == 0);
-        }
-
-        index = av_index_search_timestamp(st, target_ts,
-                                          flags & ~AVSEEK_FLAG_BACKWARD);
-        av_assert0(index < sti->nb_index_entries);
-        if (index >= 0) {
-            e = &sti->index_entries[index];
-            av_assert1(e->timestamp >= target_ts);
-            pos_max   = e->pos;
-            ts_max    = e->timestamp;
-            pos_limit = pos_max - e->min_distance;
-            av_log(s, AV_LOG_TRACE, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64
-                    " dts_max=%s\n", pos_max, pos_limit, av_ts2str(ts_max));
-        }
-    }
-
-    pos = ff_gen_search(s, stream_index, target_ts, pos_min, pos_max, pos_limit,
-                        ts_min, ts_max, flags, &ts, avif->read_timestamp);
-    if (pos < 0)
-        return -1;
-
-    /* do the seek */
-    if ((ret = avio_seek(s->pb, pos, SEEK_SET)) < 0)
-        return ret;
-
-    ff_read_frame_flush(s);
-    avpriv_update_cur_dts(s, st, ts);
-
-    return 0;
-}
-
-int ff_find_last_ts(AVFormatContext *s, int stream_index, int64_t *ts, int64_t *pos,
-                    int64_t (*read_timestamp)(struct AVFormatContext *, int , int64_t *, int64_t ))
-{
-    int64_t step = 1024;
-    int64_t limit, ts_max;
-    int64_t filesize = avio_size(s->pb);
-    int64_t pos_max  = filesize - 1;
-    do {
-        limit = pos_max;
-        pos_max = FFMAX(0, (pos_max) - step);
-        ts_max  = ff_read_timestamp(s, stream_index,
-                                    &pos_max, limit, read_timestamp);
-        step   += step;
-    } while (ts_max == AV_NOPTS_VALUE && 2*limit > step);
-    if (ts_max == AV_NOPTS_VALUE)
-        return -1;
-
-    for (;;) {
-        int64_t tmp_pos = pos_max + 1;
-        int64_t tmp_ts  = ff_read_timestamp(s, stream_index,
-                                            &tmp_pos, INT64_MAX, read_timestamp);
-        if (tmp_ts == AV_NOPTS_VALUE)
-            break;
-        av_assert0(tmp_pos > pos_max);
-        ts_max  = tmp_ts;
-        pos_max = tmp_pos;
-        if (tmp_pos >= filesize)
-            break;
-    }
-
-    if (ts)
-        *ts = ts_max;
-    if (pos)
-        *pos = pos_max;
-
-    return 0;
-}
-
-int64_t ff_gen_search(AVFormatContext *s, int stream_index, int64_t target_ts,
-                      int64_t pos_min, int64_t pos_max, int64_t pos_limit,
-                      int64_t ts_min, int64_t ts_max,
-                      int flags, int64_t *ts_ret,
-                      int64_t (*read_timestamp)(struct AVFormatContext *, int,
-                                                int64_t *, int64_t))
-{
-    FFFormatContext *const si = ffformatcontext(s);
-    int64_t pos, ts;
-    int64_t start_pos;
-    int no_change;
-    int ret;
-
-    av_log(s, AV_LOG_TRACE, "gen_seek: %d %s\n", stream_index, av_ts2str(target_ts));
-
-    if (ts_min == AV_NOPTS_VALUE) {
-        pos_min = si->data_offset;
-        ts_min  = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
-        if (ts_min == AV_NOPTS_VALUE)
-            return -1;
-    }
-
-    if (ts_min >= target_ts) {
-        *ts_ret = ts_min;
-        return pos_min;
-    }
-
-    if (ts_max == AV_NOPTS_VALUE) {
-        if ((ret = ff_find_last_ts(s, stream_index, &ts_max, &pos_max, read_timestamp)) < 0)
-            return ret;
-        pos_limit = pos_max;
-    }
-
-    if (ts_max <= target_ts) {
-        *ts_ret = ts_max;
-        return pos_max;
-    }
-
-    av_assert0(ts_min < ts_max);
-
-    no_change = 0;
-    while (pos_min < pos_limit) {
-        av_log(s, AV_LOG_TRACE,
-                "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%s dts_max=%s\n",
-                pos_min, pos_max, av_ts2str(ts_min), av_ts2str(ts_max));
-        av_assert0(pos_limit <= pos_max);
-
-        if (no_change == 0) {
-            int64_t approximate_keyframe_distance = pos_max - pos_limit;
-            // interpolate position (better than dichotomy)
-            pos = av_rescale(target_ts - ts_min, pos_max - pos_min,
-                             ts_max - ts_min) +
-                  pos_min - approximate_keyframe_distance;
-        } else if (no_change == 1) {
-            // bisection if interpolation did not change min / max pos last time
-            pos = (pos_min + pos_limit) >> 1;
-        } else {
-            /* linear search if bisection failed, can only happen if there
-             * are very few or no keyframes between min/max */
-            pos = pos_min;
-        }
-        if (pos <= pos_min)
-            pos = pos_min + 1;
-        else if (pos > pos_limit)
-            pos = pos_limit;
-        start_pos = pos;
-
-        // May pass pos_limit instead of -1.
-        ts = ff_read_timestamp(s, stream_index, &pos, INT64_MAX, read_timestamp);
-        if (pos == pos_max)
-            no_change++;
-        else
-            no_change = 0;
-        av_log(s, AV_LOG_TRACE, "%"PRId64" %"PRId64" %"PRId64" / %s %s %s"
-                " target:%s limit:%"PRId64" start:%"PRId64" noc:%d\n",
-                pos_min, pos, pos_max,
-                av_ts2str(ts_min), av_ts2str(ts), av_ts2str(ts_max), av_ts2str(target_ts),
-                pos_limit, start_pos, no_change);
-        if (ts == AV_NOPTS_VALUE) {
-            av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
-            return -1;
-        }
-        if (target_ts <= ts) {
-            pos_limit = start_pos - 1;
-            pos_max   = pos;
-            ts_max    = ts;
-        }
-        if (target_ts >= ts) {
-            pos_min = pos;
-            ts_min  = ts;
-        }
-    }
-
-    pos     = (flags & AVSEEK_FLAG_BACKWARD) ? pos_min : pos_max;
-    ts      = (flags & AVSEEK_FLAG_BACKWARD) ? ts_min  : ts_max;
-#if 0
-    pos_min = pos;
-    ts_min  = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
-    pos_min++;
-    ts_max = ff_read_timestamp(s, stream_index, &pos_min, INT64_MAX, read_timestamp);
-    av_log(s, AV_LOG_TRACE, "pos=0x%"PRIx64" %s<=%s<=%s\n",
-            pos, av_ts2str(ts_min), av_ts2str(target_ts), av_ts2str(ts_max));
-#endif
-    *ts_ret = ts;
-    return pos;
-}
-
-static int seek_frame_byte(AVFormatContext *s, int stream_index,
-                           int64_t pos, int flags)
-{
-    FFFormatContext *const si = ffformatcontext(s);
-    int64_t pos_min, pos_max;
-
-    pos_min = si->data_offset;
-    pos_max = avio_size(s->pb) - 1;
-
-    if (pos < pos_min)
-        pos = pos_min;
-    else if (pos > pos_max)
-        pos = pos_max;
-
-    avio_seek(s->pb, pos, SEEK_SET);
-
-    s->io_repositioned = 1;
-
-    return 0;
-}
-
-static int seek_frame_generic(AVFormatContext *s, int stream_index,
-                              int64_t timestamp, int flags)
-{
-    FFFormatContext *const si = ffformatcontext(s);
-    AVStream *const st  = s->streams[stream_index];
-    FFStream *const sti = ffstream(st);
-    int index;
-    int64_t ret;
-    AVIndexEntry *ie;
-
-
-    index = av_index_search_timestamp(st, timestamp, flags);
-
-    if (index < 0 && sti->nb_index_entries &&
-        timestamp < sti->index_entries[0].timestamp)
-        return -1;
-
-    if (index < 0 || index == sti->nb_index_entries - 1) {
-        AVPacket *pkt = ffformatcontext(s)->pkt;
-        int nonkey = 0;
-
-        if (sti->nb_index_entries) {
-            av_assert0(sti->index_entries);
-            ie = &sti->index_entries[sti->nb_index_entries - 1];
-            if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
-                return ret;
-            s->io_repositioned = 1;
-            avpriv_update_cur_dts(s, st, ie->timestamp);
-        } else {
-            if ((ret = avio_seek(s->pb, si->data_offset, SEEK_SET)) < 0)
-                return ret;
-            s->io_repositioned = 1;
-        }
-        av_packet_unref(pkt);
-        for (;;) {
-            int read_status;
-            do {
-                read_status = av_read_frame(s, pkt);
-            } while (read_status == AVERROR(EAGAIN));
-            if (read_status < 0)
-                break;
-            if (stream_index == pkt->stream_index && pkt->dts > timestamp) {
-                if (pkt->flags & AV_PKT_FLAG_KEY) {
-                    av_packet_unref(pkt);
-                    break;
-                }
-                if (nonkey++ > 1000 && st->codecpar->codec_id != AV_CODEC_ID_CDGRAPHICS) {
-                    av_log(s, AV_LOG_ERROR,"seek_frame_generic failed as this stream seems to contain no keyframes after the target timestamp, %d non keyframes found\n", nonkey);
-                    av_packet_unref(pkt);
-                    break;
-                }
-            }
-            av_packet_unref(pkt);
-        }
-        index = av_index_search_timestamp(st, timestamp, flags);
-    }
-    if (index < 0)
-        return -1;
-
-    ff_read_frame_flush(s);
-    if (s->iformat->read_seek)
-        if (s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
-            return 0;
-    ie = &sti->index_entries[index];
-    if ((ret = avio_seek(s->pb, ie->pos, SEEK_SET)) < 0)
-        return ret;
-    s->io_repositioned = 1;
-    avpriv_update_cur_dts(s, st, ie->timestamp);
-
-    return 0;
-}
-
-static int seek_frame_internal(AVFormatContext *s, int stream_index,
-                               int64_t timestamp, int flags)
-{
-    int ret;
-    AVStream *st;
-
-    if (flags & AVSEEK_FLAG_BYTE) {
-        if (s->iformat->flags & AVFMT_NO_BYTE_SEEK)
-            return -1;
-        ff_read_frame_flush(s);
-        return seek_frame_byte(s, stream_index, timestamp, flags);
-    }
-
-    if (stream_index < 0) {
-        stream_index = av_find_default_stream_index(s);
-        if (stream_index < 0)
-            return -1;
-
-        st = s->streams[stream_index];
-        /* timestamp for default must be expressed in AV_TIME_BASE units */
-        timestamp = av_rescale(timestamp, st->time_base.den,
-                               AV_TIME_BASE * (int64_t) st->time_base.num);
-    }
-
-    /* first, we try the format specific seek */
-    if (s->iformat->read_seek) {
-        ff_read_frame_flush(s);
-        ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
-    } else
-        ret = -1;
-    if (ret >= 0)
-        return 0;
-
-    if (s->iformat->read_timestamp &&
-        !(s->iformat->flags & AVFMT_NOBINSEARCH)) {
-        ff_read_frame_flush(s);
-        return ff_seek_frame_binary(s, stream_index, timestamp, flags);
-    } else if (!(s->iformat->flags & AVFMT_NOGENSEARCH)) {
-        ff_read_frame_flush(s);
-        return seek_frame_generic(s, stream_index, timestamp, flags);
-    } else
-        return -1;
-}
-
-int av_seek_frame(AVFormatContext *s, int stream_index,
-                  int64_t timestamp, int flags)
-{
-    int ret;
-
-    if (s->iformat->read_seek2 && !s->iformat->read_seek) {
-        int64_t min_ts = INT64_MIN, max_ts = INT64_MAX;
-        if ((flags & AVSEEK_FLAG_BACKWARD))
-            max_ts = timestamp;
-        else
-            min_ts = timestamp;
-        return avformat_seek_file(s, stream_index, min_ts, timestamp, max_ts,
-                                  flags & ~AVSEEK_FLAG_BACKWARD);
-    }
-
-    ret = seek_frame_internal(s, stream_index, timestamp, flags);
-
-    if (ret >= 0)
-        ret = avformat_queue_attached_pictures(s);
-
-    return ret;
-}
-
-int avformat_seek_file(AVFormatContext *s, int stream_index, int64_t min_ts,
-                       int64_t ts, int64_t max_ts, int flags)
-{
-    if (min_ts > ts || max_ts < ts)
-        return -1;
-    if (stream_index < -1 || stream_index >= (int)s->nb_streams)
-        return AVERROR(EINVAL);
-
-    if (s->seek2any>0)
-        flags |= AVSEEK_FLAG_ANY;
-    flags &= ~AVSEEK_FLAG_BACKWARD;
-
-    if (s->iformat->read_seek2) {
-        int ret;
-        ff_read_frame_flush(s);
-
-        if (stream_index == -1 && s->nb_streams == 1) {
-            AVRational time_base = s->streams[0]->time_base;
-            ts = av_rescale_q(ts, AV_TIME_BASE_Q, time_base);
-            min_ts = av_rescale_rnd(min_ts, time_base.den,
-                                    time_base.num * (int64_t)AV_TIME_BASE,
-                                    AV_ROUND_UP   | AV_ROUND_PASS_MINMAX);
-            max_ts = av_rescale_rnd(max_ts, time_base.den,
-                                    time_base.num * (int64_t)AV_TIME_BASE,
-                                    AV_ROUND_DOWN | AV_ROUND_PASS_MINMAX);
-            stream_index = 0;
-        }
-
-        ret = s->iformat->read_seek2(s, stream_index, min_ts,
-                                     ts, max_ts, flags);
-
-        if (ret >= 0)
-            ret = avformat_queue_attached_pictures(s);
-        return ret;
-    }
-
-    if (s->iformat->read_timestamp) {
-        // try to seek via read_timestamp()
-    }
-
-    // Fall back on old API if new is not implemented but old is.
-    // Note the old API has somewhat different semantics.
-    if (s->iformat->read_seek || 1) {
-        int dir = (ts - (uint64_t)min_ts > (uint64_t)max_ts - ts ? AVSEEK_FLAG_BACKWARD : 0);
-        int ret = av_seek_frame(s, stream_index, ts, flags | dir);
-        if (ret<0 && ts != min_ts && max_ts != ts) {
-            ret = av_seek_frame(s, stream_index, dir ? max_ts : min_ts, flags | dir);
-            if (ret >= 0)
-                ret = av_seek_frame(s, stream_index, ts, flags | (dir^AVSEEK_FLAG_BACKWARD));
-        }
-        return ret;
-    }
-
-    // try some generic seek like seek_frame_generic() but with new ts semantics
-    return -1; //unreachable
-}
-
-int avformat_flush(AVFormatContext *s)
-{
-    ff_read_frame_flush(s);
-    return 0;
-}
-
 /*******************************************************/
 
 /**
@@ -2748,7 +2012,7 @@ static void estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset)
     int retry = 0;
 
     /* flush packet queue */
-    flush_packet_queue(ic);
+    ff_flush_packet_queue(ic);
 
     for (unsigned i = 0; i < ic->nb_streams; i++) {
         AVStream *const st  = ic->streams[i];
@@ -4358,7 +3622,7 @@ void avformat_free_context(AVFormatContext *s)
     av_packet_free(&si->pkt);
     av_packet_free(&si->parse_pkt);
     av_freep(&s->streams);
-    flush_packet_queue(s);
+    ff_flush_packet_queue(s);
     av_freep(&s->url);
     av_free(s);
 }
