From 4d5be986f0f84d38b4859e04eba2ca0381c6f8c4 Mon Sep 17 00:00:00 2001 From: Michael Niedermayer Date: Tue, 14 Nov 2006 13:19:51 +0000 Subject: [PATCH] index less seeking in O(log n) time Originally committed as revision 7056 to svn://svn.ffmpeg.org/ffmpeg/trunk --- libavformat/nut.h | 8 ++-- libavformat/nutdec.c | 88 +++++++++++++++++++++++++++++++++++++++----- 2 files changed, 84 insertions(+), 12 deletions(-) diff --git a/libavformat/nut.h b/libavformat/nut.h index af42a57720..b8e8242526 100644 --- a/libavformat/nut.h +++ b/libavformat/nut.h @@ -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; diff --git a/libavformat/nutdec.c b/libavformat/nutdec.c index 462d63eb73..7c3e88ac95 100644 --- a/libavformat/nutdec.c +++ b/libavformat/nutdec.c @@ -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; inb_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