]> git.sesse.net Git - ffmpeg/blobdiff - libavformat/nut.c
some sanity checks on what is muxed, invalid timestamps in mpeg are very common and...
[ffmpeg] / libavformat / nut.c
index 9f17f14d61012e74d99936e9a6c277ec8f7aeec5..67b317ed692055d9b22fdf9731ae0092d8321eae 100644 (file)
@@ -25,7 +25,6 @@
 
 /*
  * TODO:
- * - seeking
  * - index writing
  * - index packet reading support
 */
@@ -40,6 +39,8 @@
 #undef NDEBUG
 #include <assert.h>
 
+//#define TRACE
+
 //from /dev/random
 
 #define     MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48)) 
 #define    INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48)) 
 #define     INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48)) 
 
-#define MAX_TYPE1_DISTANCE (1024*16-1)
-#define MAX_TYPE2_DISTANCE (1024*64-1)
+#define ID_STRING "nut/multimedia container\0"
 
-#define MAX_SIZE_LRU 2
-#define MAX_PTS_LRU 3
+#define MAX_DISTANCE (1024*16-1)
+#define MAX_SHORT_DISTANCE (1024*4-1)
 
-#define FLAG_FRAME_TYPE      1
-#define FLAG_DATA_SIZE       2
-#define FLAG_PTS            16
-#define FLAG_FULL_PTS        4
-#define FLAG_KEY_FRAME      32
-#define FLAG_PRED_KEY_FRAME 64
+#define FLAG_DATA_SIZE       1
+#define FLAG_KEY_FRAME       2
+#define FLAG_INVALID         4
 
 typedef struct {
     uint8_t flags;
     uint8_t stream_id_plus1;
-    uint8_t size_mul;
-    uint8_t size_lsb;
+    uint16_t size_mul;
+    uint16_t size_lsb;
+    int16_t timestamp_delta;
+    uint8_t reserved_count;
 } FrameCode;
 
 typedef struct {
@@ -74,25 +73,23 @@ typedef struct {
     int rate_num;
     int rate_den;
     int64_t last_pts;
-    int64_t last_full_pts;
-    int lru_pts_delta[MAX_PTS_LRU];
-    int lru_size[MAX_SIZE_LRU];
-    int initial_pts_predictor[MAX_PTS_LRU];
-    int initial_size_predictor[MAX_SIZE_LRU];
     int64_t last_sync_pos;                    ///<pos of last 1/2 type frame
+    int decode_delay;
 } StreamContext;
 
 typedef struct {
     AVFormatContext *avf;
-    int64_t packet_start;
-    int64_t last_packet_start;
     int written_packet_size;
-    int64_t packet_size_pos;
-    int64_t last_frame_start[3];
+    int64_t packet_start[3]; //0-> startcode less, 1-> short startcode 2-> long startcodes
     FrameCode frame_code[256];
     int stream_count;
     uint64_t next_startcode;     ///< stores the next startcode if it has alraedy been parsed but the stream isnt seekable
     StreamContext *stream;
+    int max_distance;
+    int max_short_distance;
+    int rate_num;
+    int rate_den;
+    int short_startcode;
 } NUTContext;
 
 static char *info_table[][2]={
@@ -115,36 +112,15 @@ static char *info_table[][2]={
        {"Cover"                , "PNG"},
 };
 
-static void update_lru(int *lru, int current, int count){
-    int i;
-
-    for(i=0; i<count-1; i++){
-        if(lru[i] == current)
-            break;
-    }
-
-    for(; i; i--){
-        lru[i]= lru[i-1];
-    }
-
-    lru[0]= current;
-}
-
 static void update(NUTContext *nut, int stream_index, int64_t frame_start, int frame_type, int frame_code, int key_frame, int size, int64_t pts){
     StreamContext *stream= &nut->stream[stream_index];
-    const int flags=nut->frame_code[frame_code].flags; 
     
     stream->last_key_frame= key_frame;
-    nut->last_frame_start[ frame_type ]= frame_start;
-    if(frame_type == 0)
-        update_lru(stream->lru_pts_delta, pts - stream->last_pts, 3);
-    update_lru(stream->lru_size, size, 2);
+    nut->packet_start[ frame_type ]= frame_start;
     stream->last_pts= pts;
-    if((flags & FLAG_PTS) && (flags & FLAG_FULL_PTS))
-        stream->last_full_pts= pts;
 }
 
-static void reset(AVFormatContext *s/*, int frame_type*/){
+static void reset(AVFormatContext *s, int64_t global_ts){
     NUTContext *nut = s->priv_data;
     int i;
     
@@ -152,30 +128,27 @@ static void reset(AVFormatContext *s/*, int frame_type*/){
         StreamContext *stream= &nut->stream[i];
     
         stream->last_key_frame= 1;
-        memcpy(stream->lru_pts_delta, stream->initial_pts_predictor, sizeof(int)*MAX_PTS_LRU);
-        memcpy(stream->lru_size, stream->initial_size_predictor, sizeof(int)*MAX_SIZE_LRU);
+
+        stream->last_pts= av_rescale(global_ts, stream->rate_num*(int64_t)nut->rate_den, stream->rate_den*(int64_t)nut->rate_num);
     }
 }
 
 static void build_frame_code(AVFormatContext *s){
     NUTContext *nut = s->priv_data;
-    int key_frame, frame_type, full_pts, index, pred, stream_id;
+    int key_frame, index, pred, stream_id;
     int start=0;
     int end= 255;
     int keyframe_0_esc= s->nb_streams > 2;
+    int pred_table[10];
 
     if(keyframe_0_esc){
-        /* keyframe = 0 escapes, 3 codes */
-        for(frame_type=0; frame_type<2; frame_type++){
-            for(full_pts=frame_type; full_pts<2; full_pts++){
-                FrameCode *ft= &nut->frame_code[start];
-                ft->flags= FLAG_FRAME_TYPE*frame_type + FLAG_FULL_PTS*full_pts;
-                ft->flags|= FLAG_DATA_SIZE | FLAG_PTS; 
-                ft->stream_id_plus1= 0;
-                ft->size_mul=1;
-                start++;
-            }
-        }
+        /* keyframe = 0 escape */
+        FrameCode *ft= &nut->frame_code[start];
+        ft->flags= FLAG_DATA_SIZE;
+        ft->stream_id_plus1= 0;
+        ft->size_mul=1;
+        ft->timestamp_delta=0;
+        start++;
     }
 
     for(stream_id= 0; stream_id<s->nb_streams; stream_id++){
@@ -190,15 +163,14 @@ static void build_frame_code(AVFormatContext *s){
             if(intra_only && keyframe_0_esc && key_frame==0)
                 continue;
             
-            for(frame_type=0; frame_type<2; frame_type++){
-                for(full_pts=frame_type; full_pts<2; full_pts++){
-                    FrameCode *ft= &nut->frame_code[start2];
-                    ft->flags= FLAG_FRAME_TYPE*frame_type + FLAG_FULL_PTS*full_pts + FLAG_KEY_FRAME*key_frame;
-                    ft->flags|= FLAG_DATA_SIZE | FLAG_PTS;
-                    ft->stream_id_plus1= stream_id + 1;
-                    ft->size_mul=1;
-                    start2++;
-                }
+            {
+                FrameCode *ft= &nut->frame_code[start2];
+                ft->flags= FLAG_KEY_FRAME*key_frame;
+                ft->flags|= FLAG_DATA_SIZE;
+                ft->stream_id_plus1= stream_id + 1;
+                ft->size_mul=1;
+                ft->timestamp_delta=0;
+                start2++;
             }
         }
 
@@ -206,44 +178,63 @@ static void build_frame_code(AVFormatContext *s){
 #if 1
         if(is_audio){
             int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate);
-            for(pred=0; pred<MAX_SIZE_LRU; pred++){
-                for(frame_type=0; frame_type<1; frame_type++){
+            int pts;
+            for(pts=0; pts<2; pts++){
+                for(pred=0; pred<2; pred++){
                     FrameCode *ft= &nut->frame_code[start2];
-                    ft->flags= FLAG_KEY_FRAME*key_frame + (FLAG_FULL_PTS+FLAG_PTS+FLAG_FRAME_TYPE)*frame_type;
+                    ft->flags= FLAG_KEY_FRAME*key_frame;
                     ft->stream_id_plus1= stream_id + 1;
-                    ft->size_mul=1;
-                    ft->size_lsb=1 + pred;
+                    ft->size_mul=frame_bytes + 2;
+                    ft->size_lsb=frame_bytes + pred;
+                    ft->timestamp_delta=pts;
                     start2++;
                 }
-                nut->stream[stream_id].initial_size_predictor[pred]= frame_bytes + pred;
             }
         }else{
             FrameCode *ft= &nut->frame_code[start2];
             ft->flags= FLAG_KEY_FRAME | FLAG_DATA_SIZE;
             ft->stream_id_plus1= stream_id + 1;
             ft->size_mul=1;
+            ft->timestamp_delta=1;
             start2++;
         }
 #endif
-        pred_count= 2 + codec->has_b_frames + (codec->codec_id == CODEC_ID_VORBIS);
+
+        if(codec->has_b_frames){
+            pred_count=5;
+            pred_table[0]=-2;
+            pred_table[1]=-1;
+            pred_table[2]=1;
+            pred_table[3]=3;
+            pred_table[4]=4;
+        }else if(codec->codec_id == CODEC_ID_VORBIS){
+            pred_count=3;
+            pred_table[0]=2;
+            pred_table[1]=9;
+            pred_table[2]=16;
+        }else{
+            pred_count=1;
+            pred_table[0]=1;
+        }
+
         for(pred=0; pred<pred_count; pred++){
             int start3= start2 + (end2-start2)*pred / pred_count;
             int end3  = start2 + (end2-start2)*(pred+1) / pred_count;
 
             for(index=start3; index<end3; index++){
                 FrameCode *ft= &nut->frame_code[index];
-                ft->flags= FLAG_KEY_FRAME*key_frame + pred*4;
+                ft->flags= FLAG_KEY_FRAME*key_frame;
                 ft->flags|= FLAG_DATA_SIZE;
                 ft->stream_id_plus1= stream_id + 1;
 //FIXME use single byte size and pred from last
                 ft->size_mul= end3-start3;
                 ft->size_lsb= index - start3;
+                ft->timestamp_delta= pred_table[pred];
             }
-            nut->stream[stream_id].initial_pts_predictor[pred]= pred+1;
         }
     }
     memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N'));
-    nut->frame_code['N'].flags= 1;
+    nut->frame_code['N'].flags= FLAG_INVALID;
 }
 
 static uint64_t get_v(ByteIOContext *bc)
@@ -256,8 +247,10 @@ static uint64_t get_v(ByteIOContext *bc)
 
        if (tmp&0x80)
            val= (val<<7) + tmp - 0x80;
-       else
+       else{
+//av_log(NULL, AV_LOG_DEBUG, "get_v()= %lld\n", (val<<7) + tmp);
            return (val<<7) + tmp;
+        }
     }
     return -1;
 }
@@ -281,6 +274,13 @@ static int get_str(ByteIOContext *bc, char *string, int maxlen){
         return 0;
 }
 
+static int64_t get_s(ByteIOContext *bc){
+    int64_t v = get_v(bc) + 1;
+
+    if (v&1) return -(v>>1);
+    else     return  (v>>1);
+}
+
 static uint64_t get_vb(ByteIOContext *bc){
     uint64_t val=0;
     int i= get_v(bc);
@@ -291,32 +291,47 @@ static uint64_t get_vb(ByteIOContext *bc){
     while(i--)
         val = (val<<8) + get_byte(bc);
     
+//av_log(NULL, AV_LOG_DEBUG, "get_vb()= %lld\n", val);
     return val;
 }
 
-static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int prefix_length, int calculate_checksum)
+#ifdef TRACE
+static inline uint64_t get_v_trace(ByteIOContext *bc, char *file, char *func, int line){
+    uint64_t v= get_v(bc);
+
+    printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
+    return v;
+}
+
+static inline int64_t get_s_trace(ByteIOContext *bc, char *file, char *func, int line){
+    int64_t v= get_s(bc);
+
+    printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
+    return v;
+}
+
+static inline uint64_t get_vb_trace(ByteIOContext *bc, char *file, char *func, int line){
+    uint64_t v= get_vb(bc);
+
+    printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
+    return v;
+}
+#define get_v(bc)  get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#define get_s(bc)  get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#define get_vb(bc)  get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#endif
+
+
+static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum)
 {
-    int64_t start, size, last_size;
-    start= url_ftell(bc) - prefix_length;
+    int64_t start, size;
+    start= url_ftell(bc) - 8;
 
-    if(nut->written_packet_size >= 0 && start != nut->packet_start + nut->written_packet_size){
-        av_log(nut->avf, AV_LOG_ERROR, "get_packetheader called at weird position\n");
-        if(prefix_length<8)
-            return -1;
-    }
-    
     init_checksum(bc, calculate_checksum ? update_adler32 : NULL, 0);
 
     size= get_v(bc);
-    last_size= get_v(bc);
-    if(nut->written_packet_size >= 0 && nut->written_packet_size != last_size){
-        av_log(nut->avf, AV_LOG_ERROR, "packet size missmatch %d != %lld at %lld\n", nut->written_packet_size, last_size, start);
-        if(prefix_length<8)
-            return -1;
-    }
 
-    nut->last_packet_start = nut->packet_start;
-    nut->packet_start = start;
+    nut->packet_start[2] = start;
     nut->written_packet_size= size;
 
     return size;
@@ -379,10 +394,12 @@ static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){
 }
 
 #ifdef CONFIG_ENCODERS
+
 static void put_v(ByteIOContext *bc, uint64_t val)
 {
     int i;
 
+//av_log(NULL, AV_LOG_DEBUG, "put_v()= %lld\n", val);
     val &= 0x7FFFFFFFFFFFFFFFULL; // FIXME can only encode upto 63 bits currently
     i= get_length(val);
 
@@ -403,6 +420,11 @@ static void put_str(ByteIOContext *bc, const char *string){
     put_buffer(bc, string, len);
 }
 
+static void put_s(ByteIOContext *bc, uint64_t val){
+    if (val<=0) put_v(bc, -2*val  );
+    else        put_v(bc,  2*val-1);
+}
+
 static void put_vb(ByteIOContext *bc, uint64_t val){
     int i;
     
@@ -413,12 +435,34 @@ static void put_vb(ByteIOContext *bc, uint64_t val){
         put_byte(bc, (val>>i)&0xFF);
 }
 
+#ifdef TRACE
+static inline void put_v_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
+    printf("get_v %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
+    
+    put_v(bc, v);
+}
+
+static inline void put_s_trace(ByteIOContext *bc, int64_t v, char *file, char *func, int line){
+    printf("get_s %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
+    
+    put_s(bc, v);
+}
+
+static inline void put_vb_trace(ByteIOContext *bc, uint64_t v, char *file, char *func, int line){
+    printf("get_vb %5lld / %llX in %s %s:%d\n", v, v, file, func, line);
+    
+    put_vb(bc, v);
+}
+#define put_v(bc, v)  put_v_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#define put_s(bc, v)  put_s_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#define put_vb(bc, v)  put_vb_trace(bc, v, __FILE__, __PRETTY_FUNCTION__, __LINE__)
+#endif
+
 static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum)
 {
     put_flush_packet(bc);
-    nut->last_packet_start= nut->packet_start;
-    nut->packet_start+= nut->written_packet_size;
-    nut->packet_size_pos = url_ftell(bc);
+    nut->packet_start[2]+= nut->written_packet_size;
+    assert(url_ftell(bc) - 8 == nut->packet_start[2]);
     nut->written_packet_size = max_size;
     
     if(calculate_checksum)
@@ -426,13 +470,12 @@ static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, in
 
     /* packet header */
     put_v(bc, nut->written_packet_size); /* forward ptr */
-    put_v(bc, nut->packet_start - nut->last_packet_start); /* backward ptr */
 
     return 0;
 }
 
 static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){
-    int64_t start= nut->packet_start;
+    int64_t start= nut->packet_start[2];
     int64_t cur= url_ftell(bc);
     int size= cur - start + additional_size;
     
@@ -444,7 +487,7 @@ static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additiona
 
         assert( size <= nut->written_packet_size );
     
-        url_fseek(bc, nut->packet_size_pos, SEEK_SET);
+        url_fseek(bc, start + 8, SEEK_SET);
         for(i=get_length(size); i < get_length(nut->written_packet_size); i+=7)
             put_byte(bc, 0x80);
         put_v(bc, size);
@@ -464,45 +507,68 @@ static int nut_write_header(AVFormatContext *s)
     NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
     AVCodecContext *codec;
-    int i, j;
+    int i, j, tmp_time, tmp_flags,tmp_stream, tmp_mul, tmp_size, tmp_fields;
 
     nut->avf= s;
     
     nut->stream =      
        av_mallocz(sizeof(StreamContext)*s->nb_streams);
-    
-    av_set_pts_info(s, 60, 1, AV_TIME_BASE);
+        
+
+    put_buffer(bc, ID_STRING, strlen(ID_STRING));
+    put_byte(bc, 0);
+    nut->packet_start[2]= url_ftell(bc);
     
     /* main header */
     put_be64(bc, MAIN_STARTCODE);
     put_packetheader(nut, bc, 120+5*256, 1);
-    put_v(bc, 1); /* version */
+    put_v(bc, 2); /* version */
     put_v(bc, s->nb_streams);
-    put_v(bc, 3);
+    put_v(bc, MAX_DISTANCE);
+    put_v(bc, MAX_SHORT_DISTANCE);
+    
+    put_v(bc, nut->rate_num=1);
+    put_v(bc, nut->rate_den=2);
+    put_v(bc, nut->short_startcode=0x4EFE79);
     
     build_frame_code(s);
-    assert(nut->frame_code['N'].flags == 1);
+    assert(nut->frame_code['N'].flags == FLAG_INVALID);
+    
+    tmp_time= tmp_flags= tmp_stream= tmp_mul= tmp_size= /*tmp_res=*/ INT_MAX;
     for(i=0; i<256;){
-        int tmp_flags = nut->frame_code[i].flags;
-        int tmp_stream= nut->frame_code[i].stream_id_plus1;
-        int tmp_mul   = nut->frame_code[i].size_mul;
-        int tmp_size  = nut->frame_code[i].size_lsb;
-        put_v(bc, tmp_flags);
-        put_v(bc, tmp_stream);
-        put_v(bc, tmp_mul);
-        put_v(bc, tmp_size);
-
+        tmp_fields=0;
+        tmp_size= 0;
+        if(tmp_time   != nut->frame_code[i].timestamp_delta) tmp_fields=1;
+        if(tmp_mul    != nut->frame_code[i].size_mul       ) tmp_fields=2;
+        if(tmp_stream != nut->frame_code[i].stream_id_plus1) tmp_fields=3;
+        if(tmp_size   != nut->frame_code[i].size_lsb       ) tmp_fields=4;
+//        if(tmp_res    != nut->frame_code[i].res            ) tmp_fields=5;
+
+        tmp_time  = nut->frame_code[i].timestamp_delta;
+        tmp_flags = nut->frame_code[i].flags;
+        tmp_stream= nut->frame_code[i].stream_id_plus1;
+        tmp_mul   = nut->frame_code[i].size_mul;
+        tmp_size  = nut->frame_code[i].size_lsb;
+//        tmp_res   = nut->frame_code[i].res;
+        
         for(j=0; i<256; j++,i++){
+            if(nut->frame_code[i].timestamp_delta != tmp_time  ) break;
             if(nut->frame_code[i].flags           != tmp_flags ) break;
             if(nut->frame_code[i].stream_id_plus1 != tmp_stream) break;
             if(nut->frame_code[i].size_mul        != tmp_mul   ) break;
-            if(nut->frame_code[i].size_lsb        != tmp_size  ) break;
-            if(++tmp_size >= tmp_mul){
-                tmp_size=0;
-                tmp_stream++;
-            }
+            if(nut->frame_code[i].size_lsb        != tmp_size+j) break;
+//            if(nut->frame_code[i].res             != tmp_res   ) break;
         }
-        put_v(bc, j);
+        if(j != tmp_mul - tmp_size) tmp_fields=6;
+
+        put_v(bc, tmp_flags);
+        put_v(bc, tmp_fields);
+        if(tmp_fields>0) put_s(bc, tmp_time);
+        if(tmp_fields>1) put_v(bc, tmp_mul);
+        if(tmp_fields>2) put_v(bc, tmp_stream);
+        if(tmp_fields>3) put_v(bc, tmp_size);
+        if(tmp_fields>4) put_v(bc, 0 /*tmp_res*/);
+        if(tmp_fields>5) put_v(bc, j);
     }
 
     update_packetheader(nut, bc, 0, 1);
@@ -549,6 +615,7 @@ static int nut_write_header(AVFormatContext *s)
         denom /= gcd;
         nut->stream[i].rate_num= nom;
         nut->stream[i].rate_den= denom;
+        av_set_pts_info(s->streams[i], 60, denom, nom);
 
        put_v(bc, codec->bit_rate);
        put_vb(bc, 0); /* no language code */
@@ -559,10 +626,7 @@ static int nut_write_header(AVFormatContext *s)
         else
            nut->stream[i].msb_timestamp_shift = 14;
        put_v(bc, nut->stream[i].msb_timestamp_shift);
-       for(j=0; j<3; j++)
-               put_v(bc, nut->stream[i].initial_pts_predictor[j]);
-       for(j=0; j<2; j++)
-               put_v(bc, nut->stream[i].initial_size_predictor[j]);
+        put_v(bc, codec->has_b_frames);
        put_byte(bc, 0); /* flags: 0x1 - fixed_fps, 0x2 - index_present */
        
         if(codec->extradata_size){
@@ -575,7 +639,8 @@ static int nut_write_header(AVFormatContext *s)
        switch(codec->codec_type)
        {
            case CODEC_TYPE_AUDIO:
-               put_v(bc, (codec->sample_rate * denom) / nom);
+               put_v(bc, codec->sample_rate);
+               put_v(bc, 1);
                put_v(bc, codec->channels);
                break;
            case CODEC_TYPE_VIDEO:
@@ -616,8 +681,10 @@ static int nut_write_header(AVFormatContext *s)
         put_str(bc, s->copyright);
     }
     /* encoder */
-    put_v(bc, 13); /* type */
-    put_str(bc, LIBAVFORMAT_IDENT);
+    if(!(s->streams[0]->codec.flags & CODEC_FLAG_BITEXACT)){
+        put_v(bc, 13); /* type */
+        put_str(bc, LIBAVFORMAT_IDENT);
+    }
     
     put_v(bc, 0); /* eof info */
     update_packetheader(nut, bc, 0, 1);
@@ -627,99 +694,86 @@ static int nut_write_header(AVFormatContext *s)
     return 0;
 }
 
-static int nut_write_packet(AVFormatContext *s, int stream_index, 
-                           const uint8_t *buf, int size, int64_t pts)
+static int64_t lsb2full(StreamContext *stream, int64_t lsb){
+    int64_t mask = (1<<stream->msb_timestamp_shift)-1;
+    int64_t delta= stream->last_pts - mask/2;
+    return  ((lsb - delta)&mask) + delta;
+}
+
+static int nut_write_packet(AVFormatContext *s, AVPacket *pkt)
 {
     NUTContext *nut = s->priv_data;
-    StreamContext *stream= &nut->stream[stream_index];
+    StreamContext *stream= &nut->stream[pkt->stream_index];
     ByteIOContext *bc = &s->pb;
     int key_frame = 0, full_pts=0;
     AVCodecContext *enc;
-    int64_t lsb_pts, delta_pts;
-    int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb;
+    int64_t coded_pts;
+    int frame_type, best_length, frame_code, flags, i, size_mul, size_lsb, time_delta;
     const int64_t frame_start= url_ftell(bc);
-
-    if (stream_index > s->nb_streams)
-       return 1;
-        
-    pts= (av_rescale(pts, stream->rate_num, stream->rate_den) + AV_TIME_BASE/2) / AV_TIME_BASE;
+    int64_t pts= pkt->pts;
+    int size= pkt->size;
+    int stream_index= pkt->stream_index;
 
     enc = &s->streams[stream_index]->codec;
-    key_frame = enc->coded_frame->key_frame;
-    delta_pts= pts - stream->last_pts;
+    key_frame = !!(pkt->flags & PKT_FLAG_KEY);
     
     frame_type=0;
-    if(frame_start + size + 20 - FFMAX(nut->last_frame_start[1], nut->last_frame_start[2]) > MAX_TYPE1_DISTANCE)
-        frame_type=1;
-    if(key_frame){
-        if(frame_type==1 && frame_start + size - nut->last_frame_start[2] > MAX_TYPE2_DISTANCE)
-            frame_type=2;
-        if(!stream->last_key_frame)
-            frame_type=2;
+    if(frame_start + size + 20 - FFMAX(nut->packet_start[1], nut->packet_start[2]) > MAX_DISTANCE)
+        frame_type=2;
+    if(key_frame && !stream->last_key_frame)
+        frame_type=2;
+
+    if(frame_type>1){
+        int64_t global_ts= av_rescale(pts, stream->rate_den*(int64_t)nut->rate_num, stream->rate_num*(int64_t)nut->rate_den);
+        reset(s, global_ts);
+       put_be64(bc, KEYFRAME_STARTCODE);
+        put_v(bc, global_ts);
     }
-
-    if(frame_type>0){
-        update_packetheader(nut, bc, 0, 0);
-        reset(s);
+    assert(stream->last_pts != AV_NOPTS_VALUE);
+    coded_pts = pts & ((1<<stream->msb_timestamp_shift)-1);
+    if(lsb2full(stream, coded_pts) != pts)
         full_pts=1;
-    }
-    //FIXME ensure that the timestamp can be represented by either delta or lsb or full_pts=1
 
-    lsb_pts = pts & ((1 << stream->msb_timestamp_shift)-1);
+    if(full_pts)
+        coded_pts= pts + (1<<stream->msb_timestamp_shift);
 
     best_length=INT_MAX;
     frame_code= -1;
     for(i=0; i<256; i++){
         int stream_id_plus1= nut->frame_code[i].stream_id_plus1;
-        int fc_key_frame= stream->last_key_frame;
+        int fc_key_frame;
         int length=0;
         size_mul= nut->frame_code[i].size_mul;
         size_lsb= nut->frame_code[i].size_lsb;
+        time_delta= nut->frame_code[i].timestamp_delta;
         flags= nut->frame_code[i].flags;
 
+        assert(size_mul > size_lsb);
+        
         if(stream_id_plus1 == 0) length+= get_length(stream_index);
         else if(stream_id_plus1 - 1 != stream_index)
             continue;
-        if(flags & FLAG_PRED_KEY_FRAME){
-            if(flags & FLAG_KEY_FRAME)
-                fc_key_frame= !fc_key_frame;
-        }else{
-            fc_key_frame= !!(flags & FLAG_KEY_FRAME);
-        }
+        fc_key_frame= !!(flags & FLAG_KEY_FRAME);
+
         assert(key_frame==0 || key_frame==1);
         if(fc_key_frame != key_frame)
             continue;
 
-        if((!!(flags & FLAG_FRAME_TYPE)) != (frame_type > 0))
-            continue;
-        
-        if(size_mul <= size_lsb){
-            int p= stream->lru_size[size_lsb - size_mul];
-            if(p != size)
-                continue;
-        }else{
+        if(flags & FLAG_DATA_SIZE){
             if(size % size_mul != size_lsb)
                 continue;
-            if(flags & FLAG_DATA_SIZE)
-                length += get_length(size / size_mul);
-            else if(size/size_mul)
-                continue;
-        }
+            length += get_length(size / size_mul);
+        }else if(size != size_lsb)
+            continue;
 
-        if(full_pts != ((flags & FLAG_PTS) && (flags & FLAG_FULL_PTS)))
+        if(full_pts && time_delta)
             continue;
             
-        if(flags&FLAG_PTS){
-            if(flags&FLAG_FULL_PTS){
-                length += get_length(pts);
-            }else{
-                length += get_length(lsb_pts);
-            }
+        if(!time_delta){
+            length += get_length(coded_pts);
         }else{
-            int delta= stream->lru_pts_delta[(flags & 12)>>2];
-            if(delta != pts - stream->last_pts)
+            if(time_delta != pts - stream->last_pts)
                 continue;
-            assert(frame_type == 0);
         }
 
         if(length < best_length){
@@ -733,39 +787,34 @@ static int nut_write_packet(AVFormatContext *s, int stream_index,
     flags= nut->frame_code[frame_code].flags;
     size_mul= nut->frame_code[frame_code].size_mul;
     size_lsb= nut->frame_code[frame_code].size_lsb;
-#if 0
+    time_delta= nut->frame_code[frame_code].timestamp_delta;
+#ifdef TRACE
     best_length /= 7;
     best_length ++; //frame_code
-    if(frame_type>0){
-        best_length += 4; //packet header
-        if(frame_type>1)
-            best_length += 8; // startcode
+    if(frame_type==2){
+        best_length += 8; // startcode
     }
-    av_log(s, AV_LOG_DEBUG, "kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d\n", key_frame, frame_type, full_pts ? 2 : ((flags & FLAG_PTS) ? 1 : 0), frame_code, best_length, size, stream_index, flags, size_mul, size_lsb, nut->frame_code[frame_code].stream_id_plus1,(int)(pts - stream->last_pts));
+    av_log(s, AV_LOG_DEBUG, "kf:%d ft:%d pt:%d fc:%2X len:%2d size:%d stream:%d flag:%d mul:%d lsb:%d s+1:%d pts_delta:%d pts:%lld fs:%lld\n", key_frame, frame_type, full_pts ? 1 : 0, frame_code, best_length, size, stream_index, flags, size_mul, size_lsb, nut->frame_code[frame_code].stream_id_plus1,(int)(pts - stream->last_pts), pts, frame_start);
+//    av_log(s, AV_LOG_DEBUG, "%d %d %d\n", stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
 #endif
 
-    if (frame_type==2)
-       put_be64(bc, KEYFRAME_STARTCODE);
+    assert(frame_type != 1); //short startcode not implemented yet
     put_byte(bc, frame_code);
 
-    if(frame_type>0)
-        put_packetheader(nut, bc, FFMAX(size+20, MAX_TYPE1_DISTANCE), 0);
     if(nut->frame_code[frame_code].stream_id_plus1 == 0)
         put_v(bc, stream_index);
-    if (flags & FLAG_PTS){
-        if (flags & FLAG_FULL_PTS)
-            put_v(bc, pts);
-        else
-            put_v(bc, lsb_pts);
+    if (!time_delta){
+        put_v(bc, coded_pts);
     }
     if(flags & FLAG_DATA_SIZE)
         put_v(bc, size / size_mul);
-    if(size > MAX_TYPE1_DISTANCE){
-        assert(frame_type > 0);
-        update_packetheader(nut, bc, size, 0);
+    else
+        assert(size == size_lsb);
+    if(size > MAX_DISTANCE){
+        assert(frame_type > 1);
     }
     
-    put_buffer(bc, buf, size);
+    put_buffer(bc, pkt->data, size);
 
     update(nut, stream_index, frame_start, frame_type, frame_code, key_frame, size, pts);
     
@@ -777,8 +826,6 @@ static int nut_write_trailer(AVFormatContext *s)
     NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
 
-    update_packetheader(nut, bc, 0, 0);
-
 #if 0
     int i;
 
@@ -805,12 +852,10 @@ static int nut_write_trailer(AVFormatContext *s)
 static int nut_probe(AVProbeData *p)
 {
     int i;
-    uint64_t code;
+    uint64_t code= 0xff;
 
-    code = 0xff;
     for (i = 0; i < p->buf_size; i++) {
-        int c = p->buf[i];
-        code = (code << 8) | c;
+        code = (code << 8) | p->buf[i];
         if (code == MAIN_STARTCODE)
             return AVPROBE_SCORE_MAX;
     }
@@ -821,59 +866,62 @@ static int decode_main_header(NUTContext *nut){
     AVFormatContext *s= nut->avf;
     ByteIOContext *bc = &s->pb;
     uint64_t tmp;
-    int i, j;
+    int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res;
     
-    get_packetheader(nut, bc, 8, 1);
+    get_packetheader(nut, bc, 1);
 
     tmp = get_v(bc);
-    if (tmp != 1){
+    if (tmp != 2){
        av_log(s, AV_LOG_ERROR, "bad version (%Ld)\n", tmp);
         return -1;
     }
     
     nut->stream_count = get_v(bc);
-    get_v(bc); //checksum threshold
-
+    nut->max_distance = get_v(bc);
+    nut->max_short_distance = get_v(bc);
+    nut->rate_num= get_v(bc);
+    nut->rate_den= get_v(bc);
+    nut->short_startcode= get_v(bc);
+    if(nut->short_startcode>>16 != 'N'){
+       av_log(s, AV_LOG_ERROR, "invalid short startcode %X\n", nut->short_startcode);
+        return -1;
+    }
+    
     for(i=0; i<256;){
         int tmp_flags = get_v(bc);
-        int tmp_stream= get_v(bc);
-        int tmp_mul   = get_v(bc);
-        int tmp_size  = get_v(bc);
-        int count     = get_v(bc);
-
+        int tmp_fields= get_v(bc);
+        if(tmp_fields>0) tmp_time  = get_s(bc);
+        if(tmp_fields>1) tmp_mul   = get_v(bc);
+        if(tmp_fields>2) tmp_stream= get_v(bc);
+        if(tmp_fields>3) tmp_size  = get_v(bc);
+        else             tmp_size  = 0;
+        if(tmp_fields>4) tmp_res   = get_v(bc);
+        else             tmp_res   = 0;
+        if(tmp_fields>5) count     = get_v(bc);
+        else             count     = tmp_mul - tmp_size;
+        
+        while(tmp_fields-- > 6) 
+           get_v(bc);
+        
         if(count == 0 || i+count > 256){
             av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
             return -1;
         }
-
-        if((tmp_flags & FLAG_FRAME_TYPE) && tmp_flags != 1){
-            if(tmp_flags & FLAG_PRED_KEY_FRAME){
-                av_log(s, AV_LOG_ERROR, "keyframe prediction in non 0 frame type\n");
-                return -1;
-            }
-            if(!(tmp_flags & FLAG_PTS) || !(tmp_flags & FLAG_FULL_PTS) ){
-                av_log(s, AV_LOG_ERROR, "no full pts in non 0 frame type\n");
-                return -1;
-            }
+        if(tmp_stream > nut->stream_count + 1){
+            av_log(s, AV_LOG_ERROR, "illegal stream number\n");
+            return -1;
         }
 
         for(j=0; j<count; j++,i++){
-            if(tmp_stream > nut->stream_count + 1){
-                av_log(s, AV_LOG_ERROR, "illegal stream number\n");
-                return -1;
-            }
-
             nut->frame_code[i].flags           = tmp_flags ;
+            nut->frame_code[i].timestamp_delta = tmp_time  ;
             nut->frame_code[i].stream_id_plus1 = tmp_stream;
             nut->frame_code[i].size_mul        = tmp_mul   ;
-            nut->frame_code[i].size_lsb        = tmp_size  ;
-            if(++tmp_size >= tmp_mul){
-                tmp_size=0;
-                tmp_stream++;
-            }
+            nut->frame_code[i].size_lsb        = tmp_size+j;
+            nut->frame_code[i].reserved_count  = tmp_res   ;
         }
     }
-    if(nut->frame_code['N'].flags != 1){
+    if(nut->frame_code['N'].flags != FLAG_INVALID){
         av_log(s, AV_LOG_ERROR, "illegal frame_code table\n");
         return -1;
     }
@@ -889,11 +937,11 @@ static int decode_main_header(NUTContext *nut){
 static int decode_stream_header(NUTContext *nut){
     AVFormatContext *s= nut->avf;
     ByteIOContext *bc = &s->pb;
-    int class, nom, denom, stream_id, i;
+    int class, nom, denom, stream_id;
     uint64_t tmp;
     AVStream *st;
     
-    get_packetheader(nut, bc, 8, 1);
+    get_packetheader(nut, bc, 1);
     stream_id= get_v(bc);
     if(stream_id >= nut->stream_count || s->streams[stream_id])
         return -1;
@@ -901,8 +949,10 @@ static int decode_stream_header(NUTContext *nut){
     st = av_new_stream(s, stream_id);
     if (!st)
         return AVERROR_NOMEM;
+
     class = get_v(bc);
     tmp = get_vb(bc);
+    st->codec.codec_tag= tmp;
     switch(class)
     {
         case 0:
@@ -926,16 +976,13 @@ static int decode_stream_header(NUTContext *nut){
     nom = get_v(bc);
     denom = get_v(bc);
     nut->stream[stream_id].msb_timestamp_shift = get_v(bc);
-    for(i=0; i<3; i++)
-            nut->stream[stream_id].initial_pts_predictor[i]= get_v(bc);
-    for(i=0; i<2; i++)
-            nut->stream[stream_id].initial_size_predictor[i]= get_v(bc);
+    nut->stream[stream_id].decode_delay= get_v(bc);
     get_byte(bc); /* flags */
 
     /* codec specific data headers */
     while(get_v(bc) != 0){
         st->codec.extradata_size= get_v(bc);
-        st->codec.extradata= av_mallocz(st->codec.extradata_size);
+        st->codec.extradata= av_mallocz(st->codec.extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
         get_buffer(bc, st->codec.extradata, st->codec.extradata_size);            
 //         url_fskip(bc, get_v(bc));
     }
@@ -953,13 +1000,15 @@ static int decode_stream_header(NUTContext *nut){
     }
     if (class == 32) /* AUDIO */
     {
-        st->codec.sample_rate = (get_v(bc) * nom) / denom;
+        st->codec.sample_rate = get_v(bc);
+        get_v(bc); // samplerate_den
         st->codec.channels = get_v(bc);
     }
     if(check_checksum(bc)){
         av_log(s, AV_LOG_ERROR, "Stream header %d checksum missmatch\n", stream_id);
         return -1;
     }
+    av_set_pts_info(s->streams[stream_id], 60, denom, nom);
     nut->stream[stream_id].rate_num= nom;
     nut->stream[stream_id].rate_den= denom;
     return 0;
@@ -969,7 +1018,7 @@ static int decode_info_header(NUTContext *nut){
     AVFormatContext *s= nut->avf;
     ByteIOContext *bc = &s->pb;
     
-    get_packetheader(nut, bc, 8, 1);
+    get_packetheader(nut, bc, 1);
 
     for(;;){
         int id= get_v(bc);
@@ -1026,8 +1075,6 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
 
     nut->avf= s;
     
-    av_set_pts_info(s, 60, 1, AV_TIME_BASE);
-
     /* main header */
     pos=0;
     for(;;){
@@ -1079,29 +1126,27 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
     return 0;
 }
 
-static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type){
+static int decode_frame_header(NUTContext *nut, int *key_frame_ret, int64_t *pts_ret, int *stream_id_ret, int frame_code, int frame_type, int64_t frame_start){
     AVFormatContext *s= nut->avf;
     StreamContext *stream;
     ByteIOContext *bc = &s->pb;
-    int size, flags, size_mul, size_lsb, stream_id;
-    int key_frame = 0;
+    int size, flags, size_mul, size_lsb, stream_id, time_delta;
     int64_t pts = 0;
-    const int prefix_len= frame_type == 2 ? 8+1 : 1;
-    const int64_t frame_start= url_ftell(bc) - prefix_len;
 
+    if(frame_type < 2 && frame_start - nut->packet_start[2] > nut->max_distance){
+        av_log(s, AV_LOG_ERROR, "last frame must have been damaged\n");
+        return -1;
+    }
+
+    if(frame_type)
+        nut->packet_start[ frame_type ]= frame_start; //otherwise 1 goto 1 may happen
+    
     flags= nut->frame_code[frame_code].flags;
     size_mul= nut->frame_code[frame_code].size_mul;
     size_lsb= nut->frame_code[frame_code].size_lsb;
     stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1;
-
-    if(flags & FLAG_FRAME_TYPE){
-        reset(s);
-        if(get_packetheader(nut, bc, prefix_len, 0) < 0)
-            return -1;
-        if(frame_type!=2)
-            frame_type= 1;
-    }
-
+    time_delta= nut->frame_code[frame_code].timestamp_delta;
+    
     if(stream_id==-1)
         stream_id= get_v(bc);
     if(stream_id >= s->nb_streams){
@@ -1111,63 +1156,80 @@ static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int fram
     stream= &nut->stream[stream_id];
 
 //    av_log(s, AV_LOG_DEBUG, "ft:%d ppts:%d %d %d\n", frame_type, stream->lru_pts_delta[0], stream->lru_pts_delta[1], stream->lru_pts_delta[2]);
-    
-    if(flags & FLAG_PRED_KEY_FRAME){
-        if(flags & FLAG_KEY_FRAME)
-            key_frame= !stream->last_key_frame;
-        else
-            key_frame= stream->last_key_frame;
-    }else{
-        key_frame= !!(flags & FLAG_KEY_FRAME);
-    }
 
-    if(flags & FLAG_PTS){
-        if(flags & FLAG_FULL_PTS){
-            pts= get_v(bc);
-            if(frame_type && key_frame){
-                av_add_index_entry(
-                    s->streams[stream_id], 
-                    frame_start, 
-                    pts, 
-                    frame_start - nut->stream[stream_id].last_sync_pos,
-                    AVINDEX_KEYFRAME);
-                nut->stream[stream_id].last_sync_pos= frame_start;
-                assert(nut->packet_start == frame_start);
-            }
+    *key_frame_ret= !!(flags & FLAG_KEY_FRAME);
+
+    if(!time_delta){
+        int64_t mask = (1<<stream->msb_timestamp_shift)-1;
+        pts= get_v(bc);
+        if(pts > mask){
+            pts -= mask+1;
         }else{
-            int64_t mask = (1<<stream->msb_timestamp_shift)-1;
-            int64_t delta= stream->last_pts - mask/2;
-            pts= ((get_v(bc) - delta)&mask) + delta;
+            if(stream->last_pts == AV_NOPTS_VALUE){
+                av_log(s, AV_LOG_ERROR, "no reference pts available\n");
+                return -1;
+            }
+            pts= lsb2full(stream, pts);
         }
     }else{
-        pts= stream->last_pts + stream->lru_pts_delta[(flags&12)>>2];
+        if(stream->last_pts == AV_NOPTS_VALUE){
+            av_log(s, AV_LOG_ERROR, "no reference pts available\n");
+            return -1;
+        }
+        pts= stream->last_pts + time_delta;
     }
-  
-    if(size_mul <= size_lsb){
-        size= stream->lru_size[size_lsb - size_mul];
-    }else{
-        if(flags & FLAG_DATA_SIZE)
-            size= size_mul*get_v(bc) + size_lsb;
-        else
-            size= size_lsb;
+
+    if(*key_frame_ret){
+//        av_log(s, AV_LOG_DEBUG, "stream:%d start:%lld pts:%lld length:%lld\n",stream_id, frame_start, av_pts, frame_start - nut->stream[stream_id].last_sync_pos);
+        av_add_index_entry(
+            s->streams[stream_id], 
+            frame_start, 
+            pts, 
+            frame_start - nut->stream[stream_id].last_sync_pos,
+            AVINDEX_KEYFRAME);
+        nut->stream[stream_id].last_sync_pos= frame_start;
+//                assert(nut->packet_start == frame_start);
     }
+
+    assert(size_mul > size_lsb);
+    size= size_lsb;
+    if(flags & FLAG_DATA_SIZE)
+        size+= size_mul*get_v(bc);
       
-//av_log(s, AV_LOG_DEBUG, "fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d\n", frame_start, frame_code, frame_type, key_frame, pts, size);
+#ifdef TRACE
+av_log(s, AV_LOG_DEBUG, "fs:%lld fc:%d ft:%d kf:%d pts:%lld size:%d mul:%d lsb:%d flags:%d delta:%d\n", frame_start, frame_code, frame_type, *key_frame_ret, pts, size, size_mul, size_lsb, flags, time_delta);
+#endif
 
-    if(url_ftell(bc) - nut->packet_start + size > nut->written_packet_size){
+    if(frame_type==0 && url_ftell(bc) - nut->packet_start[2] + size > nut->max_distance){
         av_log(s, AV_LOG_ERROR, "frame size too large\n");
         return -1;
     }
     
+    *stream_id_ret = stream_id;
+    *pts_ret = pts;
+
+    update(nut, stream_id, frame_start, frame_type, frame_code, *key_frame_ret, size, pts);
+
+    return size;
+}
+
+static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type, int64_t frame_start){
+    AVFormatContext *s= nut->avf;
+    ByteIOContext *bc = &s->pb;
+    int size, stream_id, key_frame;
+    int64_t pts;
+    
+    size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, frame_start);
+    if(size < 0)
+        return -1;
+
     av_new_packet(pkt, size);
     get_buffer(bc, pkt->data, size);
     pkt->stream_index = stream_id;
     if (key_frame)
        pkt->flags |= PKT_FLAG_KEY;
-    pkt->pts = pts * AV_TIME_BASE * stream->rate_den / stream->rate_num;
+    pkt->pts = pts;
 
-    update(nut, stream_id, frame_start, frame_type, frame_code, key_frame, size, pts);
-    
     return 0;
 }
 
@@ -1175,10 +1237,10 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
 {
     NUTContext *nut = s->priv_data;
     ByteIOContext *bc = &s->pb;
-    int size, i, frame_code=0;
-    int64_t pos;
+    int i, frame_code=0;
 
     for(;;){
+        int64_t pos= url_ftell(bc);
         int frame_type= 0;
         uint64_t tmp= nut->next_startcode;
         nut->next_startcode=0;
@@ -1186,7 +1248,9 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
         if (url_feof(bc))
             return -1;
 
-        if(!tmp){
+        if(tmp){
+            pos-=8;
+        }else{
             frame_code = get_byte(bc);
             if(frame_code == 'N'){
                 tmp= frame_code;
@@ -1198,8 +1262,9 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
         case MAIN_STARTCODE:
         case STREAM_STARTCODE:
         case INDEX_STARTCODE:
-            get_packetheader(nut, bc, 8, 0);
-            url_fseek(bc, nut->written_packet_size + nut->packet_start, SEEK_SET);
+            get_packetheader(nut, bc, 0);
+            assert(nut->packet_start[2] == pos);
+            url_fseek(bc, nut->written_packet_size + nut->packet_start[2], SEEK_SET);
             break;
         case INFO_STARTCODE:
             if(decode_info_header(nut)<0)
@@ -1207,67 +1272,42 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
             break;
         case KEYFRAME_STARTCODE:
             frame_type = 2;
+            reset(s, get_v(bc));
             frame_code = get_byte(bc);
         case 0:
-            if(decode_frame(nut, pkt, frame_code, frame_type)>=0)
+            if(decode_frame(nut, pkt, frame_code, frame_type, pos)>=0)
                 return 0;
         default:
 resync:
-av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start+1);
-            tmp= find_any_startcode(bc, nut->packet_start+1);
+av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start[2]+1);
+            tmp= find_any_startcode(bc, nut->packet_start[2]+1);
             if(tmp==0)
                 return -1;
 av_log(s, AV_LOG_DEBUG, "sync\n");
-            if(url_is_streamed(bc)){
-                nut->next_startcode= tmp;
-                break;
-            }
-
-            pos= url_ftell(bc) - 8;
-av_log(s, AV_LOG_DEBUG, "at %lld code=%llX\n", pos, tmp);
-            if(tmp==KEYFRAME_STARTCODE){
-                get_byte(bc);
-            }
-            get_v(bc);
-            size= get_v(bc);
-            
-            while(size > 2 && size < 100000 && nut->packet_start < pos - size){
-                url_fseek(bc, pos - size, SEEK_SET);
-                frame_code= get_byte(bc);
-                if(!(nut->frame_code[ frame_code ].flags & FLAG_FRAME_TYPE))
-                    break;
-                if(get_v(bc) != size)
-                    break;
-                pos -= size;
-                size= get_v(bc);
-av_log(s, AV_LOG_DEBUG, "steping back to %lld next %d\n", pos, size);
-            }
-            url_fseek(bc, pos, SEEK_SET);
-            
-            nut->written_packet_size= -1;
+            nut->next_startcode= tmp;
         }
     }
 }
 
-static int64_t 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;
+    StreamContext *stream;
     ByteIOContext *bc = &s->pb;
     int64_t pos, pts;
     uint64_t code;
-    int frame_code,step, flags, stream_id, i;
+    int frame_code,step, stream_id, i,size, key_frame;
 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_arg, pos_limit);
 
     if(*pos_arg < 0)
         return AV_NOPTS_VALUE;
 
-    // find a previous startcode, FIXME use forward search and follow backward pointers if undamaged stream
     pos= *pos_arg;
     step= FFMIN(16*1024, pos);
     do{
         pos-= step;
         code= find_any_startcode(bc, pos);
 
-        if(code && url_ftell(bc) - 8 < *pos_arg)
+        if(code && url_ftell(bc) - 8 <= *pos_arg)
             break;
         step= FFMIN(2*step, pos);
     }while(step);
@@ -1280,11 +1320,11 @@ av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_a
         nut->stream[i].last_sync_pos= url_ftell(bc);
         
     for(;;){
+        int frame_type=0;
         int64_t pos= url_ftell(bc);
         uint64_t tmp=0;
-        int prefix_len=1;
         
-        if(pos > pos_limit)
+        if(pos > pos_limit || url_feof(bc))
             return AV_NOPTS_VALUE;
 
         frame_code = get_byte(bc);
@@ -1300,52 +1340,31 @@ av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%lld,%lld)\n", stream_index, *pos_a
         case STREAM_STARTCODE:
         case INDEX_STARTCODE:
         case INFO_STARTCODE:
-            nut->written_packet_size= -1;
-            get_packetheader(nut, bc, 8, 0);
-            url_fseek(bc, nut->written_packet_size + nut->packet_start, SEEK_SET);
+            get_packetheader(nut, bc, 0);
+            assert(nut->packet_start[2]==pos);
+            url_fseek(bc, nut->written_packet_size + pos, SEEK_SET);
             break;
         case KEYFRAME_STARTCODE:
-            nut->written_packet_size= -1;
-            prefix_len+=8;
+            frame_type=2;
+            reset(s, get_v(bc));
             frame_code = get_byte(bc);
         case 0:
-            flags= nut->frame_code[frame_code].flags;
-            stream_id= nut->frame_code[frame_code].stream_id_plus1 - 1;
-
-            if(get_packetheader(nut, bc, prefix_len, 0) < 0)
-                goto resync;
-
-            if(!(flags & FLAG_FRAME_TYPE) || !(flags & FLAG_PTS) || !(flags & FLAG_FULL_PTS))
-                goto resync;
-
-            if(stream_id==-1)
-                stream_id= get_v(bc);
-            if(stream_id >= s->nb_streams)
+            size= decode_frame_header(nut, &key_frame, &pts, &stream_id, frame_code, frame_type, pos);
+            if(size < 0)
                 goto resync;
                 
-            pts= get_v(bc);
-    
-            if(flags & FLAG_KEY_FRAME){
-                av_add_index_entry(
-                    s->streams[stream_id], 
-                    pos, 
-                    pts, 
-                    pos - nut->stream[stream_id].last_sync_pos,
-                    AVINDEX_KEYFRAME);
-                nut->stream[stream_id].last_sync_pos= pos;
-            }
-            if(stream_id != stream_index || !(flags & FLAG_KEY_FRAME) || nut->packet_start < *pos_arg){
-                url_fseek(bc, nut->written_packet_size + nut->packet_start, SEEK_SET);
+            stream= &nut->stream[stream_id];
+            if(stream_id != stream_index || !key_frame || pos < *pos_arg){
+                url_fseek(bc, size, SEEK_CUR);
                 break;
             }
  
-            *pos_arg= nut->packet_start;
-            assert(nut->packet_start == pos);
+            *pos_arg= pos;
             return pts;
         default:
 resync:
-av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start+1);
-            if(!find_any_startcode(bc, nut->packet_start+1))
+av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start[2]+1);
+            if(!find_any_startcode(bc, nut->packet_start[2]+1))
                 return AV_NOPTS_VALUE;
 
             url_fseek(bc, -8, SEEK_CUR);
@@ -1354,157 +1373,15 @@ av_log(s, AV_LOG_DEBUG, "syncing from %lld\n", nut->packet_start+1);
     return AV_NOPTS_VALUE;
 }
 
-#define DEBUG_SEEK
-static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){
-    NUTContext *nut = s->priv_data;
-    StreamContext *stream;
-    int64_t pos_min, pos_max, pos, pos_limit;
-    int64_t ts_min, ts_max, ts;
-    int64_t start_pos;
-    int index, no_change,i;
-    AVStream *st;
-
-    if (stream_index < 0) {
-        stream_index = av_find_default_stream_index(s);
-        if (stream_index < 0)
-            return -1;
-    }
-    stream= &nut->stream[stream_index];
-    target_ts= (av_rescale(target_ts, stream->rate_num, stream->rate_den) + AV_TIME_BASE/2) / AV_TIME_BASE;
-
-#ifdef DEBUG_SEEK
-    av_log(s, AV_LOG_DEBUG, "read_seek: %d %lld\n", stream_index, target_ts);
-#endif
-
-    ts_max=
-    ts_min= AV_NOPTS_VALUE;
-    pos_limit= -1; //gcc falsely says it may be uninitalized
-
-    st= s->streams[stream_index];
-    if(st->index_entries){
-        AVIndexEntry *e;
-
-        index= av_index_search_timestamp(st, target_ts);
-        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, "unsing cached pos_min=0x%llx dts_min=%lld\n", 
-               pos_min,ts_min);
-#endif
-        }else{
-            assert(index==0);
-        }
-        index++;
-        if(index < st->nb_index_entries){
-            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, "unsing cached pos_max=0x%llx pos_limit=0x%llx dts_max=%lld\n", 
-               pos_max,pos_limit, ts_max);
-#endif
-        }
-    }
-
-    if(ts_min == AV_NOPTS_VALUE){
-        pos_min = 0;
-        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;
-        pos_max = url_filesize(url_fileno(&s->pb)) - 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;
-        }
-        pos_limit= pos_max;
-    }
+static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts, int flags){
+//    NUTContext *nut = s->priv_data;
+    int64_t pos;
 
-    no_change=0;
-    while (pos_min < pos_limit) {
-#ifdef DEBUG_SEEK
-        av_log(s, AV_LOG_DEBUG, "pos_min=0x%llx pos_max=0x%llx dts_min=%lld dts_max=%lld\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 = (int64_t)((double)(pos_max - pos_min) *
-                            (double)(target_ts - ts_min) /
-                            (double)(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 keframes 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, "%Ld %Ld %Ld / %Ld %Ld %Ld target:%Ld limit:%Ld start:%Ld noc:%d\n", pos_min, pos, pos_max, ts_min, ts, ts_max, target_ts, pos_limit, start_pos, no_change);
-#endif
-        assert(ts != AV_NOPTS_VALUE);
-        if (target_ts < ts) {
-            pos_limit = start_pos - 1;
-            pos_max = pos;
-            ts_max = ts;
-        } else {
-            pos_min = pos;
-            ts_min = ts;
-            /* check if we are lucky */
-            if (target_ts == ts)
-                break;
-        }
-    }
-    
-    pos = pos_min;
-#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%llx %lld<=%lld<=%lld\n", 
-           pos, ts_min, target_ts, ts_max);
-#endif
-    /* do the seek */
-    url_fseek(&s->pb, pos, SEEK_SET);
+    if(av_seek_frame_binary(s, stream_index, target_ts, flags) < 0)
+        return -1;
 
-    nut->written_packet_size= -1;
-    for(i=0; i<s->nb_streams; i++)
-        nut->stream[i].last_sync_pos= pos;
+    pos= url_ftell(&s->pb);
+    nut_read_timestamp(s, stream_index, &pos, pos-1);
 
     return 0;
 }
@@ -1531,6 +1408,7 @@ static AVInputFormat nut_iformat = {
     nut_read_packet,
     nut_read_close,
     nut_read_seek,
+    nut_read_timestamp,
     .extensions = "nut",
 };