[FFmpeg-devel] [PATCH] Move seek-related functions to seek.c

Mans Rullgard mans
Sat Mar 6 23:22:43 CET 2010


---
 libavformat/internal.h |    2 +
 libavformat/seek.c     |  484 +++++++++++++++++++++++++++++++++++++++++++++++-
 libavformat/utils.c    |  489 +-----------------------------------------------
 3 files changed, 485 insertions(+), 490 deletions(-)

diff --git a/libavformat/internal.h b/libavformat/internal.h
index 15f4dd7..64d2c03 100644
--- a/libavformat/internal.h
+++ b/libavformat/internal.h
@@ -35,4 +35,6 @@ void av_program_add_stream_index(AVFormatContext *ac, int progid, unsigned int i
 void ff_interleave_add_packet(AVFormatContext *s, AVPacket *pkt,
                               int (*compare)(AVFormatContext *, AVPacket *, AVPacket *));
 
+void ff_flush_packet_queue(AVFormatContext *s);
+
 #endif /* AVFORMAT_INTERNAL_H */
diff --git a/libavformat/seek.c b/libavformat/seek.c
index 3f77b34..9ad3e92 100644
--- a/libavformat/seek.c
+++ b/libavformat/seek.c
@@ -23,10 +23,6 @@
 #include "seek.h"
 #include "libavutil/mem.h"
 
-// NOTE: implementation should be moved here in another patch, to keep patches
-// separated.
-extern void av_read_frame_flush(AVFormatContext *s);
-
 /**
  * helper structure describing keyframe search state of one stream
  */
@@ -47,6 +43,486 @@ typedef struct {
     int         terminated;  ///< termination flag for the current iteration
 } AVSyncPoint;
 
+int av_find_default_stream_index(AVFormatContext *s)
+{
+    int first_audio_index = -1;
+    int i;
+    AVStream *st;
+
+    if (s->nb_streams <= 0)
+        return -1;
+    for(i = 0; i < s->nb_streams; i++) {
+        st = s->streams[i];
+        if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
+            return i;
+        }
+        if (first_audio_index < 0 && st->codec->codec_type == CODEC_TYPE_AUDIO)
+            first_audio_index = i;
+    }
+    return first_audio_index >= 0 ? first_audio_index : 0;
+}
+
+/**
+ * Flush the frame reader.
+ */
+static void av_read_frame_flush(AVFormatContext *s)
+{
+    AVStream *st;
+    int i, j;
+
+    flush_packet_queue(s);
+
+    s->cur_st = NULL;
+
+    /* for each stream, reset read state */
+    for(i = 0; i < s->nb_streams; i++) {
+        st = s->streams[i];
+
+        if (st->parser) {
+            av_parser_close(st->parser);
+            st->parser = NULL;
+            av_free_packet(&st->cur_pkt);
+        }
+        st->last_IP_pts = AV_NOPTS_VALUE;
+        st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */
+        st->reference_dts = AV_NOPTS_VALUE;
+        /* fail safe */
+        st->cur_ptr = NULL;
+        st->cur_len = 0;
+
+        st->probe_packets = MAX_PROBE_PACKETS;
+
+        for(j=0; j<MAX_REORDER_DELAY+1; j++)
+            st->pts_buffer[j]= AV_NOPTS_VALUE;
+    }
+}
+
+void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp){
+    int i;
+
+    for(i = 0; i < s->nb_streams; i++) {
+        AVStream *st = s->streams[i];
+
+        st->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];
+    unsigned int max_entries= s->max_index_size / sizeof(AVIndexEntry);
+
+    if((unsigned)st->nb_index_entries >= max_entries){
+        int i;
+        for(i=0; 2*i<st->nb_index_entries; i++)
+            st->index_entries[i]= st->index_entries[2*i];
+        st->nb_index_entries= i;
+    }
+}
+
+int av_add_index_entry(AVStream *st,
+                            int64_t pos, int64_t timestamp, int size, int distance, int flags)
+{
+    AVIndexEntry *entries, *ie;
+    int index;
+
+    if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
+        return -1;
+
+    entries = av_fast_realloc(st->index_entries,
+                              &st->index_entries_allocated_size,
+                              (st->nb_index_entries + 1) *
+                              sizeof(AVIndexEntry));
+    if(!entries)
+        return -1;
+
+    st->index_entries= entries;
+
+    index= av_index_search_timestamp(st, timestamp, AVSEEK_FLAG_ANY);
+
+    if(index<0){
+        index= st->nb_index_entries++;
+        ie= &entries[index];
+        assert(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)*(st->nb_index_entries - index));
+            st->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_index_search_timestamp(AVStream *st, int64_t wanted_timestamp,
+                              int flags)
+{
+    AVIndexEntry *entries= st->index_entries;
+    int nb_entries= st->nb_index_entries;
+    int a, b, m;
+    int64_t timestamp;
+
+    a = - 1;
+    b = nb_entries;
+
+    while (b - a > 1) {
+        m = (a + b) >> 1;
+        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;
+}
+
+#define DEBUG_SEEK
+
+int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
+    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;
+
+    if (stream_index < 0)
+        return -1;
+
+#ifdef DEBUG_SEEK
+    av_log(s, AV_LOG_DEBUG, "read_seek: %d %"PRId64"\n", stream_index, target_ts);
+#endif
+
+    ts_max=
+    ts_min= AV_NOPTS_VALUE;
+    pos_limit= -1; //gcc falsely says it may be uninitialized
+
+    st= s->streams[stream_index];
+    if(st->index_entries){
+        AVIndexEntry *e;
+
+        index= av_index_search_timestamp(st, target_ts, flags | AVSEEK_FLAG_BACKWARD); //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp()
+        index= FFMAX(index, 0);
+        e= &st->index_entries[index];
+
+        if(e->timestamp <= target_ts || e->pos == e->min_distance){
+            pos_min= e->pos;
+            ts_min= e->timestamp;
+#ifdef DEBUG_SEEK
+            av_log(s, AV_LOG_DEBUG, "using cached pos_min=0x%"PRIx64" dts_min=%"PRId64"\n",
+                   pos_min,ts_min);
+#endif
+        }else{
+            assert(index==0);
+        }
+
+        index= av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD);
+        assert(index < st->nb_index_entries);
+        if(index >= 0){
+            e= &st->index_entries[index];
+            assert(e->timestamp >= target_ts);
+            pos_max= e->pos;
+            ts_max= e->timestamp;
+            pos_limit= pos_max - e->min_distance;
+#ifdef DEBUG_SEEK
+            av_log(s, AV_LOG_DEBUG, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64" dts_max=%"PRId64"\n",
+                   pos_max,pos_limit, ts_max);
+#endif
+        }
+    }
+
+    pos= av_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 = url_fseek(s->pb, pos, SEEK_SET)) < 0)
+        return ret;
+
+    av_update_cur_dts(s, st, ts);
+
+    return 0;
+}
+
+int64_t av_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 )){
+    int64_t pos, ts;
+    int64_t start_pos, filesize;
+    int no_change;
+
+#ifdef DEBUG_SEEK
+    av_log(s, AV_LOG_DEBUG, "gen_seek: %d %"PRId64"\n", stream_index, target_ts);
+#endif
+
+    if(ts_min == AV_NOPTS_VALUE){
+        pos_min = s->data_offset;
+        ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
+        if (ts_min == AV_NOPTS_VALUE)
+            return -1;
+    }
+
+    if(ts_max == AV_NOPTS_VALUE){
+        int step= 1024;
+        filesize = url_fsize(s->pb);
+        pos_max = filesize - 1;
+        do{
+            pos_max -= step;
+            ts_max = read_timestamp(s, stream_index, &pos_max, pos_max + step);
+            step += step;
+        }while(ts_max == AV_NOPTS_VALUE && pos_max >= 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);
+            if(tmp_ts == AV_NOPTS_VALUE)
+                break;
+            ts_max= tmp_ts;
+            pos_max= tmp_pos;
+            if(tmp_pos >= filesize)
+                break;
+        }
+        pos_limit= pos_max;
+    }
+
+    if(ts_min > ts_max){
+        return -1;
+    }else if(ts_min == ts_max){
+        pos_limit= pos_min;
+    }
+
+    no_change=0;
+    while (pos_min < pos_limit) {
+#ifdef DEBUG_SEEK
+        av_log(s, AV_LOG_DEBUG, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%"PRId64" dts_max=%"PRId64"\n",
+               pos_min, pos_max,
+               ts_min, ts_max);
+#endif
+        assert(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 failed to change min or 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;
+
+        ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
+        if(pos == pos_max)
+            no_change++;
+        else
+            no_change=0;
+#ifdef DEBUG_SEEK
+        av_log(s, AV_LOG_DEBUG, "%"PRId64" %"PRId64" %"PRId64" / %"PRId64" %"PRId64" %"PRId64" target:%"PRId64" limit:%"PRId64" start:%"PRId64" noc:%d\n",
+               pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit,
+               start_pos, no_change);
+#endif
+        if(ts == AV_NOPTS_VALUE){
+            av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
+            return -1;
+        }
+        assert(ts != AV_NOPTS_VALUE);
+        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;
+#ifdef DEBUG_SEEK
+    pos_min = pos;
+    ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
+    pos_min++;
+    ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
+    av_log(s, AV_LOG_DEBUG, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n",
+           pos, ts_min, target_ts, ts_max);
+#endif
+    *ts_ret= ts;
+    return pos;
+}
+
+static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){
+    int64_t pos_min, pos_max;
+#if 0
+    AVStream *st;
+
+    if (stream_index < 0)
+        return -1;
+
+    st= s->streams[stream_index];
+#endif
+
+    pos_min = s->data_offset;
+    pos_max = url_fsize(s->pb) - 1;
+
+    if     (pos < pos_min) pos= pos_min;
+    else if(pos > pos_max) pos= pos_max;
+
+    url_fseek(s->pb, pos, SEEK_SET);
+
+#if 0
+    av_update_cur_dts(s, st, ts);
+#endif
+    return 0;
+}
+
+static int av_seek_frame_generic(AVFormatContext *s,
+                                 int stream_index, int64_t timestamp, int flags)
+{
+    int index;
+    int64_t ret;
+    AVStream *st;
+    AVIndexEntry *ie;
+
+    st = s->streams[stream_index];
+
+    index = av_index_search_timestamp(st, timestamp, flags);
+
+    if(index < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp)
+        return -1;
+
+    if(index < 0 || index==st->nb_index_entries-1){
+        int i;
+        AVPacket pkt;
+
+        if(st->nb_index_entries){
+            assert(st->index_entries);
+            ie= &st->index_entries[st->nb_index_entries-1];
+            if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
+                return ret;
+            av_update_cur_dts(s, st, ie->timestamp);
+        }else{
+            if ((ret = url_fseek(s->pb, s->data_offset, SEEK_SET)) < 0)
+                return ret;
+        }
+        for(i=0;; i++) {
+            int ret;
+            do{
+                ret = av_read_frame(s, &pkt);
+            }while(ret == AVERROR(EAGAIN));
+            if(ret<0)
+                break;
+            av_free_packet(&pkt);
+            if(stream_index == pkt.stream_index){
+                if((pkt.flags & PKT_FLAG_KEY) && pkt.dts > timestamp)
+                    break;
+            }
+        }
+        index = av_index_search_timestamp(st, timestamp, flags);
+    }
+    if (index < 0)
+        return -1;
+
+    av_read_frame_flush(s);
+    if (s->iformat->read_seek){
+        if(s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
+            return 0;
+    }
+    ie = &st->index_entries[index];
+    if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
+        return ret;
+    av_update_cur_dts(s, st, ie->timestamp);
+
+    return 0;
+}
+
+int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+    int ret;
+    AVStream *st;
+
+    av_read_frame_flush(s);
+
+    if(flags & AVSEEK_FLAG_BYTE)
+        return av_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)
+        ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
+    else
+        ret = -1;
+    if (ret >= 0) {
+        return 0;
+    }
+
+    if(s->iformat->read_timestamp)
+        return av_seek_frame_binary(s, stream_index, timestamp, flags);
+    else
+        return av_seek_frame_generic(s, stream_index, timestamp, flags);
+}
+
+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;
+
+    av_read_frame_flush(s);
+
+    if (s->iformat->read_seek2)
+        return s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags);
+
+    if(s->iformat->read_timestamp){
+        //try to seek via read_timestamp()
+    }
+
+    //Fallback to old API if new is not implemented but old is
+    //Note the old has somewat different sematics
+    if(s->iformat->read_seek || 1)
+        return av_seek_frame(s, stream_index, ts, flags | (ts - min_ts > (uint64_t)(max_ts - ts) ? AVSEEK_FLAG_BACKWARD : 0));
+
+    // try some generic seek like av_seek_frame_generic() but with new ts semantics
+}
+
 /**
  * Compute a distance between timestamps.
  *
diff --git a/libavformat/utils.c b/libavformat/utils.c
index 080f4bd..31f5e19 100644
--- a/libavformat/utils.c
+++ b/libavformat/utils.c
@@ -1152,7 +1152,7 @@ int av_read_frame(AVFormatContext *s, AVPacket *pkt)
 }
 
 /* XXX: suppress the packet queue */
-static void flush_packet_queue(AVFormatContext *s)
+void ff_flush_packet_queue(AVFormatContext *s)
 {
     AVPacketList *pktl;
 
@@ -1176,489 +1176,6 @@ static void flush_packet_queue(AVFormatContext *s)
 }
 
 /*******************************************************/
-/* seek support */
-
-int av_find_default_stream_index(AVFormatContext *s)
-{
-    int first_audio_index = -1;
-    int i;
-    AVStream *st;
-
-    if (s->nb_streams <= 0)
-        return -1;
-    for(i = 0; i < s->nb_streams; i++) {
-        st = s->streams[i];
-        if (st->codec->codec_type == CODEC_TYPE_VIDEO) {
-            return i;
-        }
-        if (first_audio_index < 0 && st->codec->codec_type == CODEC_TYPE_AUDIO)
-            first_audio_index = i;
-    }
-    return first_audio_index >= 0 ? first_audio_index : 0;
-}
-
-/**
- * Flush the frame reader.
- */
-void av_read_frame_flush(AVFormatContext *s)
-{
-    AVStream *st;
-    int i, j;
-
-    flush_packet_queue(s);
-
-    s->cur_st = NULL;
-
-    /* for each stream, reset read state */
-    for(i = 0; i < s->nb_streams; i++) {
-        st = s->streams[i];
-
-        if (st->parser) {
-            av_parser_close(st->parser);
-            st->parser = NULL;
-            av_free_packet(&st->cur_pkt);
-        }
-        st->last_IP_pts = AV_NOPTS_VALUE;
-        st->cur_dts = AV_NOPTS_VALUE; /* we set the current DTS to an unspecified origin */
-        st->reference_dts = AV_NOPTS_VALUE;
-        /* fail safe */
-        st->cur_ptr = NULL;
-        st->cur_len = 0;
-
-        st->probe_packets = MAX_PROBE_PACKETS;
-
-        for(j=0; j<MAX_REORDER_DELAY+1; j++)
-            st->pts_buffer[j]= AV_NOPTS_VALUE;
-    }
-}
-
-void av_update_cur_dts(AVFormatContext *s, AVStream *ref_st, int64_t timestamp){
-    int i;
-
-    for(i = 0; i < s->nb_streams; i++) {
-        AVStream *st = s->streams[i];
-
-        st->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];
-    unsigned int max_entries= s->max_index_size / sizeof(AVIndexEntry);
-
-    if((unsigned)st->nb_index_entries >= max_entries){
-        int i;
-        for(i=0; 2*i<st->nb_index_entries; i++)
-            st->index_entries[i]= st->index_entries[2*i];
-        st->nb_index_entries= i;
-    }
-}
-
-int av_add_index_entry(AVStream *st,
-                            int64_t pos, int64_t timestamp, int size, int distance, int flags)
-{
-    AVIndexEntry *entries, *ie;
-    int index;
-
-    if((unsigned)st->nb_index_entries + 1 >= UINT_MAX / sizeof(AVIndexEntry))
-        return -1;
-
-    entries = av_fast_realloc(st->index_entries,
-                              &st->index_entries_allocated_size,
-                              (st->nb_index_entries + 1) *
-                              sizeof(AVIndexEntry));
-    if(!entries)
-        return -1;
-
-    st->index_entries= entries;
-
-    index= av_index_search_timestamp(st, timestamp, AVSEEK_FLAG_ANY);
-
-    if(index<0){
-        index= st->nb_index_entries++;
-        ie= &entries[index];
-        assert(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)*(st->nb_index_entries - index));
-            st->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_index_search_timestamp(AVStream *st, int64_t wanted_timestamp,
-                              int flags)
-{
-    AVIndexEntry *entries= st->index_entries;
-    int nb_entries= st->nb_index_entries;
-    int a, b, m;
-    int64_t timestamp;
-
-    a = - 1;
-    b = nb_entries;
-
-    while (b - a > 1) {
-        m = (a + b) >> 1;
-        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;
-}
-
-#define DEBUG_SEEK
-
-int av_seek_frame_binary(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
-    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;
-
-    if (stream_index < 0)
-        return -1;
-
-#ifdef DEBUG_SEEK
-    av_log(s, AV_LOG_DEBUG, "read_seek: %d %"PRId64"\n", stream_index, target_ts);
-#endif
-
-    ts_max=
-    ts_min= AV_NOPTS_VALUE;
-    pos_limit= -1; //gcc falsely says it may be uninitialized
-
-    st= s->streams[stream_index];
-    if(st->index_entries){
-        AVIndexEntry *e;
-
-        index= av_index_search_timestamp(st, target_ts, flags | AVSEEK_FLAG_BACKWARD); //FIXME whole func must be checked for non-keyframe entries in index case, especially read_timestamp()
-        index= FFMAX(index, 0);
-        e= &st->index_entries[index];
-
-        if(e->timestamp <= target_ts || e->pos == e->min_distance){
-            pos_min= e->pos;
-            ts_min= e->timestamp;
-#ifdef DEBUG_SEEK
-            av_log(s, AV_LOG_DEBUG, "using cached pos_min=0x%"PRIx64" dts_min=%"PRId64"\n",
-                   pos_min,ts_min);
-#endif
-        }else{
-            assert(index==0);
-        }
-
-        index= av_index_search_timestamp(st, target_ts, flags & ~AVSEEK_FLAG_BACKWARD);
-        assert(index < st->nb_index_entries);
-        if(index >= 0){
-            e= &st->index_entries[index];
-            assert(e->timestamp >= target_ts);
-            pos_max= e->pos;
-            ts_max= e->timestamp;
-            pos_limit= pos_max - e->min_distance;
-#ifdef DEBUG_SEEK
-            av_log(s, AV_LOG_DEBUG, "using cached pos_max=0x%"PRIx64" pos_limit=0x%"PRIx64" dts_max=%"PRId64"\n",
-                   pos_max,pos_limit, ts_max);
-#endif
-        }
-    }
-
-    pos= av_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 = url_fseek(s->pb, pos, SEEK_SET)) < 0)
-        return ret;
-
-    av_update_cur_dts(s, st, ts);
-
-    return 0;
-}
-
-int64_t av_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 )){
-    int64_t pos, ts;
-    int64_t start_pos, filesize;
-    int no_change;
-
-#ifdef DEBUG_SEEK
-    av_log(s, AV_LOG_DEBUG, "gen_seek: %d %"PRId64"\n", stream_index, target_ts);
-#endif
-
-    if(ts_min == AV_NOPTS_VALUE){
-        pos_min = s->data_offset;
-        ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
-        if (ts_min == AV_NOPTS_VALUE)
-            return -1;
-    }
-
-    if(ts_max == AV_NOPTS_VALUE){
-        int step= 1024;
-        filesize = url_fsize(s->pb);
-        pos_max = filesize - 1;
-        do{
-            pos_max -= step;
-            ts_max = read_timestamp(s, stream_index, &pos_max, pos_max + step);
-            step += step;
-        }while(ts_max == AV_NOPTS_VALUE && pos_max >= 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);
-            if(tmp_ts == AV_NOPTS_VALUE)
-                break;
-            ts_max= tmp_ts;
-            pos_max= tmp_pos;
-            if(tmp_pos >= filesize)
-                break;
-        }
-        pos_limit= pos_max;
-    }
-
-    if(ts_min > ts_max){
-        return -1;
-    }else if(ts_min == ts_max){
-        pos_limit= pos_min;
-    }
-
-    no_change=0;
-    while (pos_min < pos_limit) {
-#ifdef DEBUG_SEEK
-        av_log(s, AV_LOG_DEBUG, "pos_min=0x%"PRIx64" pos_max=0x%"PRIx64" dts_min=%"PRId64" dts_max=%"PRId64"\n",
-               pos_min, pos_max,
-               ts_min, ts_max);
-#endif
-        assert(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 failed to change min or 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;
-
-        ts = read_timestamp(s, stream_index, &pos, INT64_MAX); //may pass pos_limit instead of -1
-        if(pos == pos_max)
-            no_change++;
-        else
-            no_change=0;
-#ifdef DEBUG_SEEK
-        av_log(s, AV_LOG_DEBUG, "%"PRId64" %"PRId64" %"PRId64" / %"PRId64" %"PRId64" %"PRId64" target:%"PRId64" limit:%"PRId64" start:%"PRId64" noc:%d\n",
-               pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit,
-               start_pos, no_change);
-#endif
-        if(ts == AV_NOPTS_VALUE){
-            av_log(s, AV_LOG_ERROR, "read_timestamp() failed in the middle\n");
-            return -1;
-        }
-        assert(ts != AV_NOPTS_VALUE);
-        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;
-#ifdef DEBUG_SEEK
-    pos_min = pos;
-    ts_min = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
-    pos_min++;
-    ts_max = read_timestamp(s, stream_index, &pos_min, INT64_MAX);
-    av_log(s, AV_LOG_DEBUG, "pos=0x%"PRIx64" %"PRId64"<=%"PRId64"<=%"PRId64"\n",
-           pos, ts_min, target_ts, ts_max);
-#endif
-    *ts_ret= ts;
-    return pos;
-}
-
-static int av_seek_frame_byte(AVFormatContext *s, int stream_index, int64_t pos, int flags){
-    int64_t pos_min, pos_max;
-#if 0
-    AVStream *st;
-
-    if (stream_index < 0)
-        return -1;
-
-    st= s->streams[stream_index];
-#endif
-
-    pos_min = s->data_offset;
-    pos_max = url_fsize(s->pb) - 1;
-
-    if     (pos < pos_min) pos= pos_min;
-    else if(pos > pos_max) pos= pos_max;
-
-    url_fseek(s->pb, pos, SEEK_SET);
-
-#if 0
-    av_update_cur_dts(s, st, ts);
-#endif
-    return 0;
-}
-
-static int av_seek_frame_generic(AVFormatContext *s,
-                                 int stream_index, int64_t timestamp, int flags)
-{
-    int index;
-    int64_t ret;
-    AVStream *st;
-    AVIndexEntry *ie;
-
-    st = s->streams[stream_index];
-
-    index = av_index_search_timestamp(st, timestamp, flags);
-
-    if(index < 0 && st->nb_index_entries && timestamp < st->index_entries[0].timestamp)
-        return -1;
-
-    if(index < 0 || index==st->nb_index_entries-1){
-        int i;
-        AVPacket pkt;
-
-        if(st->nb_index_entries){
-            assert(st->index_entries);
-            ie= &st->index_entries[st->nb_index_entries-1];
-            if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
-                return ret;
-            av_update_cur_dts(s, st, ie->timestamp);
-        }else{
-            if ((ret = url_fseek(s->pb, s->data_offset, SEEK_SET)) < 0)
-                return ret;
-        }
-        for(i=0;; i++) {
-            int ret;
-            do{
-                ret = av_read_frame(s, &pkt);
-            }while(ret == AVERROR(EAGAIN));
-            if(ret<0)
-                break;
-            av_free_packet(&pkt);
-            if(stream_index == pkt.stream_index){
-                if((pkt.flags & PKT_FLAG_KEY) && pkt.dts > timestamp)
-                    break;
-            }
-        }
-        index = av_index_search_timestamp(st, timestamp, flags);
-    }
-    if (index < 0)
-        return -1;
-
-    av_read_frame_flush(s);
-    if (s->iformat->read_seek){
-        if(s->iformat->read_seek(s, stream_index, timestamp, flags) >= 0)
-            return 0;
-    }
-    ie = &st->index_entries[index];
-    if ((ret = url_fseek(s->pb, ie->pos, SEEK_SET)) < 0)
-        return ret;
-    av_update_cur_dts(s, st, ie->timestamp);
-
-    return 0;
-}
-
-int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
-{
-    int ret;
-    AVStream *st;
-
-    av_read_frame_flush(s);
-
-    if(flags & AVSEEK_FLAG_BYTE)
-        return av_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)
-        ret = s->iformat->read_seek(s, stream_index, timestamp, flags);
-    else
-        ret = -1;
-    if (ret >= 0) {
-        return 0;
-    }
-
-    if(s->iformat->read_timestamp)
-        return av_seek_frame_binary(s, stream_index, timestamp, flags);
-    else
-        return av_seek_frame_generic(s, stream_index, timestamp, flags);
-}
-
-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;
-
-    av_read_frame_flush(s);
-
-    if (s->iformat->read_seek2)
-        return s->iformat->read_seek2(s, stream_index, min_ts, ts, max_ts, flags);
-
-    if(s->iformat->read_timestamp){
-        //try to seek via read_timestamp()
-    }
-
-    //Fallback to old API if new is not implemented but old is
-    //Note the old has somewat different sematics
-    if(s->iformat->read_seek || 1)
-        return av_seek_frame(s, stream_index, ts, flags | (ts - min_ts > (uint64_t)(max_ts - ts) ? AVSEEK_FLAG_BACKWARD : 0));
-
-    // try some generic seek like av_seek_frame_generic() but with new ts semantics
-}
-
-/*******************************************************/
 
 /**
  * Returns TRUE if the stream has accurate duration in any stream.
@@ -1794,7 +1311,7 @@ static void av_estimate_timings_from_pts(AVFormatContext *ic, int64_t old_offset
     ic->cur_st = NULL;
 
     /* flush packet queue */
-    flush_packet_queue(ic);
+    ff_flush_packet_queue(ic);
 
     for(i=0;i<ic->nb_streams;i++) {
         st = ic->streams[i];
@@ -2384,7 +1901,7 @@ void av_close_input_stream(AVFormatContext *s)
         av_freep(&s->programs[i]);
     }
     av_freep(&s->programs);
-    flush_packet_queue(s);
+    ff_flush_packet_queue(s);
     av_freep(&s->priv_data);
     while(s->nb_chapters--) {
 #if LIBAVFORMAT_VERSION_INT < (53<<16)
-- 
1.7.0




More information about the ffmpeg-devel mailing list