index less seeking in O(log n) time
authorMichael Niedermayer <michaelni@gmx.at>
Tue, 14 Nov 2006 13:19:51 +0000 (13:19 +0000)
committerMichael Niedermayer <michaelni@gmx.at>
Tue, 14 Nov 2006 13:19:51 +0000 (13:19 +0000)
Originally committed as revision 7056 to svn://svn.ffmpeg.org/ffmpeg/trunk

libavformat/nut.h
libavformat/nutdec.c

index af42a57..b8e8242 100644 (file)
@@ -50,9 +50,10 @@ typedef enum{
 }flag_t;
 
 typedef struct {
-    uint32_t pos; //64gb limit if div16 (change this to 64 if thats too little)
-    uint64_t global_key_pts;
-    uint32_t back_ptr_div16; //is stored /16
+    uint64_t pos;
+    uint64_t back_ptr;
+//    uint64_t global_key_pts;
+    int64_t ts;
 } syncpoint_t;
 
 typedef struct {
@@ -85,6 +86,7 @@ typedef struct {
     unsigned int time_base_count;
     int64_t last_syncpoint_pos;
     AVRational *time_base;
+    struct AVTreeNode *syncpoints;
 } NUTContext;
 
 
index 462d63e..7c3e88a 100644 (file)
@@ -21,6 +21,7 @@
  *
  */
 
+#include "tree.h"
 #include "nut.h"
 
 #undef NDEBUG
@@ -432,11 +433,29 @@ static int decode_info_header(NUTContext *nut){
     return 0;
 }
 
-static int decode_syncpoint(NUTContext *nut){
+int sp_pos_cmp(syncpoint_t *a, syncpoint_t *b){
+    return (a->pos - b->pos>>32) - (b->pos - a->pos>>32);
+}
+
+int sp_pts_cmp(syncpoint_t *a, syncpoint_t *b){
+    return (a->ts - b->ts>>32) - (b->ts - a->ts>>32);
+}
+
+static void add_sp(NUTContext *nut, int64_t pos, int64_t back_ptr, int64_t ts){
+    syncpoint_t *sp2, *sp= av_mallocz(sizeof(syncpoint_t));
+
+    sp->pos= pos;
+    sp->back_ptr= back_ptr;
+    sp->ts= ts;
+    sp2= av_tree_insert(&nut->syncpoints, sp, sp_pos_cmp);
+    if(sp2 && sp2 != sp)
+        av_free(sp);
+}
+
+static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr){
     AVFormatContext *s= nut->avf;
     ByteIOContext *bc = &s->pb;
-    int64_t end;
-    uint64_t tmp;
+    int64_t end, tmp;
     int i;
     AVRational time_base;
 
@@ -446,7 +465,9 @@ static int decode_syncpoint(NUTContext *nut){
     end += url_ftell(bc);
 
     tmp= get_v(bc);
-    get_v(bc); //back_ptr_div16
+    *back_ptr= nut->last_syncpoint_pos - 16*get_v(bc);
+    if(*back_ptr < 0)
+        return -1;
 
     time_base= nut->time_base[tmp % nut->time_base_count];
     for(i=0; i<s->nb_streams; i++){
@@ -463,6 +484,10 @@ static int decode_syncpoint(NUTContext *nut){
         av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
         return -1;
     }
+
+    *ts= tmp / s->nb_streams * av_q2d(nut->time_base[tmp % s->nb_streams])*AV_TIME_BASE;
+    add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts);
+
     return 0;
 }
 
@@ -715,6 +740,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
     NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
     int i, frame_code=0, ret, skip;
+    int64_t ts, back_ptr;
 
     for(;;){
         int64_t pos= url_ftell(bc);
@@ -746,7 +772,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
                 goto resync;
             break;
         case SYNCPOINT_STARTCODE:
-            if(decode_syncpoint(nut)<0)
+            if(decode_syncpoint(nut, &ts, &back_ptr)<0)
                 goto resync;
             frame_code = get_byte(bc);
         case 0:
@@ -770,7 +796,7 @@ av_log(s, AV_LOG_DEBUG, "sync\n");
 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
     NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
-    int64_t pos, pts;
+    int64_t pos, pts, back_ptr;
     int frame_code, stream_id,size, flags;
 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit);
 
@@ -783,10 +809,15 @@ resync:
             av_log(s, AV_LOG_ERROR, "read_timestamp failed\n");
             return AV_NOPTS_VALUE;
         }
-    }while(decode_syncpoint(nut) < 0);
+    }while(decode_syncpoint(nut, &pts, &back_ptr) < 0);
     *pos_arg = pos-1;
     assert(nut->last_syncpoint_pos == *pos_arg);
 
+    av_log(s, AV_LOG_DEBUG, "return %Ld %Ld\n", pts,back_ptr );
+    if     (stream_index == -1) return pts;
+    else if(stream_index == -2) return back_ptr;
+
+assert(0);
     do{
         frame_code= get_byte(bc);
         if(frame_code == 'N'){
@@ -807,6 +838,45 @@ resync:
     return pts;
 }
 
+static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags){
+    NUTContext *nut = s->priv_data;
+    AVStream *st= s->streams[stream_index];
+    syncpoint_t dummy={.ts= pts*av_q2d(st->time_base)*AV_TIME_BASE};
+    syncpoint_t nopts_sp= {.ts= AV_NOPTS_VALUE, .back_ptr= AV_NOPTS_VALUE};
+    syncpoint_t *sp, *next_node[2]= {&nopts_sp, &nopts_sp};
+    int64_t pos, pos2, ts;
+
+    av_tree_find(nut->syncpoints, &dummy, sp_pts_cmp, next_node);
+    av_log(s, AV_LOG_DEBUG, "%Ld-%Ld %Ld-%Ld\n", next_node[0]->pos, next_node[1]->pos,
+                                                 next_node[0]->ts , next_node[1]->ts);
+    pos= av_gen_search(s, -1, dummy.ts, next_node[0]->pos, next_node[1]->pos, next_node[1]->pos,
+                                        next_node[0]->ts , next_node[1]->ts, AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp);
+
+    if(!(flags & AVSEEK_FLAG_BACKWARD)){
+        dummy.pos= pos+16;
+        next_node[1]= &nopts_sp;
+        av_tree_find(nut->syncpoints, &dummy, sp_pos_cmp, next_node);
+        pos2= av_gen_search(s, -2, dummy.pos, next_node[0]->pos     , next_node[1]->pos, next_node[1]->pos,
+                                              next_node[0]->back_ptr, next_node[1]->back_ptr, flags, &ts, nut_read_timestamp);
+        if(pos2>=0)
+            pos= pos2;
+        //FIXME dir but i think it doesnt matter
+    }
+    dummy.pos= pos;
+    sp= av_tree_find(nut->syncpoints, &dummy, sp_pos_cmp, NULL);
+
+    assert(sp);
+
+    av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", sp->back_ptr);
+    pos= find_startcode(&s->pb, SYNCPOINT_STARTCODE, sp->back_ptr - 15);
+    url_fseek(&s->pb, pos, SEEK_SET);
+    av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos);
+    if(sp->back_ptr - 15 > pos || sp->back_ptr < pos){
+        av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n");
+    }
+    return 0;
+}
+
 static int nut_read_close(AVFormatContext *s)
 {
     NUTContext *nut = s->priv_data;
@@ -826,8 +896,8 @@ AVInputFormat nut_demuxer = {
     nut_read_header,
     nut_read_packet,
     nut_read_close,
-    NULL,
-    nut_read_timestamp,
+    read_seek,
+//    nut_read_timestamp,
     .extensions = "nut",
 };
 #endif