Commit 4d5be986 authored by Michael Niedermayer's avatar Michael Niedermayer

index less seeking in O(log n) time

Originally committed as revision 7056 to svn://svn.ffmpeg.org/ffmpeg/trunk
parent 47404f9f
...@@ -50,9 +50,10 @@ typedef enum{ ...@@ -50,9 +50,10 @@ typedef enum{
}flag_t; }flag_t;
typedef struct { typedef struct {
uint32_t pos; //64gb limit if div16 (change this to 64 if thats too little) uint64_t pos;
uint64_t global_key_pts; uint64_t back_ptr;
uint32_t back_ptr_div16; //is stored /16 // uint64_t global_key_pts;
int64_t ts;
} syncpoint_t; } syncpoint_t;
typedef struct { typedef struct {
...@@ -85,6 +86,7 @@ typedef struct { ...@@ -85,6 +86,7 @@ typedef struct {
unsigned int time_base_count; unsigned int time_base_count;
int64_t last_syncpoint_pos; int64_t last_syncpoint_pos;
AVRational *time_base; AVRational *time_base;
struct AVTreeNode *syncpoints;
} NUTContext; } NUTContext;
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
* *
*/ */
#include "tree.h"
#include "nut.h" #include "nut.h"
#undef NDEBUG #undef NDEBUG
...@@ -432,11 +433,29 @@ static int decode_info_header(NUTContext *nut){ ...@@ -432,11 +433,29 @@ static int decode_info_header(NUTContext *nut){
return 0; 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; AVFormatContext *s= nut->avf;
ByteIOContext *bc = &s->pb; ByteIOContext *bc = &s->pb;
int64_t end; int64_t end, tmp;
uint64_t tmp;
int i; int i;
AVRational time_base; AVRational time_base;
...@@ -446,7 +465,9 @@ static int decode_syncpoint(NUTContext *nut){ ...@@ -446,7 +465,9 @@ static int decode_syncpoint(NUTContext *nut){
end += url_ftell(bc); end += url_ftell(bc);
tmp= get_v(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]; time_base= nut->time_base[tmp % nut->time_base_count];
for(i=0; i<s->nb_streams; i++){ for(i=0; i<s->nb_streams; i++){
...@@ -463,6 +484,10 @@ static int decode_syncpoint(NUTContext *nut){ ...@@ -463,6 +484,10 @@ static int decode_syncpoint(NUTContext *nut){
av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n"); av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
return -1; 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; return 0;
} }
...@@ -715,6 +740,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -715,6 +740,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
NUTContext *nut = s->priv_data; NUTContext *nut = s->priv_data;
ByteIOContext *bc = &s->pb; ByteIOContext *bc = &s->pb;
int i, frame_code=0, ret, skip; int i, frame_code=0, ret, skip;
int64_t ts, back_ptr;
for(;;){ for(;;){
int64_t pos= url_ftell(bc); int64_t pos= url_ftell(bc);
...@@ -746,7 +772,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) ...@@ -746,7 +772,7 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
goto resync; goto resync;
break; break;
case SYNCPOINT_STARTCODE: case SYNCPOINT_STARTCODE:
if(decode_syncpoint(nut)<0) if(decode_syncpoint(nut, &ts, &back_ptr)<0)
goto resync; goto resync;
frame_code = get_byte(bc); frame_code = get_byte(bc);
case 0: case 0:
...@@ -770,7 +796,7 @@ av_log(s, AV_LOG_DEBUG, "sync\n"); ...@@ -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){ static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
NUTContext *nut = s->priv_data; NUTContext *nut = s->priv_data;
ByteIOContext *bc = &s->pb; ByteIOContext *bc = &s->pb;
int64_t pos, pts; int64_t pos, pts, back_ptr;
int frame_code, stream_id,size, flags; 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); av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit);
...@@ -783,10 +809,15 @@ resync: ...@@ -783,10 +809,15 @@ resync:
av_log(s, AV_LOG_ERROR, "read_timestamp failed\n"); av_log(s, AV_LOG_ERROR, "read_timestamp failed\n");
return AV_NOPTS_VALUE; return AV_NOPTS_VALUE;
} }
}while(decode_syncpoint(nut) < 0); }while(decode_syncpoint(nut, &pts, &back_ptr) < 0);
*pos_arg = pos-1; *pos_arg = pos-1;
assert(nut->last_syncpoint_pos == *pos_arg); 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{ do{
frame_code= get_byte(bc); frame_code= get_byte(bc);
if(frame_code == 'N'){ if(frame_code == 'N'){
...@@ -807,6 +838,45 @@ resync: ...@@ -807,6 +838,45 @@ resync:
return pts; 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) static int nut_read_close(AVFormatContext *s)
{ {
NUTContext *nut = s->priv_data; NUTContext *nut = s->priv_data;
...@@ -826,8 +896,8 @@ AVInputFormat nut_demuxer = { ...@@ -826,8 +896,8 @@ AVInputFormat nut_demuxer = {
nut_read_header, nut_read_header,
nut_read_packet, nut_read_packet,
nut_read_close, nut_read_close,
NULL, read_seek,
nut_read_timestamp, // nut_read_timestamp,
.extensions = "nut", .extensions = "nut",
}; };
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment