• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • Examples
  • File List
  • Globals

libavformat/nutdec.c

Go to the documentation of this file.
00001 /*
00002  * "NUT" Container Format demuxer
00003  * Copyright (c) 2004-2006 Michael Niedermayer
00004  * Copyright (c) 2003 Alex Beregszaszi
00005  *
00006  * This file is part of FFmpeg.
00007  *
00008  * FFmpeg is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU Lesser General Public
00010  * License as published by the Free Software Foundation; either
00011  * version 2.1 of the License, or (at your option) any later version.
00012  *
00013  * FFmpeg is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016  * Lesser General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU Lesser General Public
00019  * License along with FFmpeg; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00021  */
00022 
00023 #include <strings.h>
00024 #include "libavutil/avstring.h"
00025 #include "libavutil/bswap.h"
00026 #include "libavutil/dict.h"
00027 #include "libavutil/tree.h"
00028 #include "avio_internal.h"
00029 #include "nut.h"
00030 
00031 #undef NDEBUG
00032 #include <assert.h>
00033 
00034 #if FF_API_MAX_STREAMS
00035 #define NUT_MAX_STREAMS MAX_STREAMS
00036 #else
00037 #define NUT_MAX_STREAMS 256    /* arbitrary sanity check value */
00038 #endif
00039 
00040 static int get_str(AVIOContext *bc, char *string, unsigned int maxlen){
00041     unsigned int len= ffio_read_varlen(bc);
00042 
00043     if(len && maxlen)
00044         avio_read(bc, string, FFMIN(len, maxlen));
00045     while(len > maxlen){
00046         avio_r8(bc);
00047         len--;
00048     }
00049 
00050     if(maxlen)
00051         string[FFMIN(len, maxlen-1)]= 0;
00052 
00053     if(maxlen == len)
00054         return -1;
00055     else
00056         return 0;
00057 }
00058 
00059 static int64_t get_s(AVIOContext *bc){
00060     int64_t v = ffio_read_varlen(bc) + 1;
00061 
00062     if (v&1) return -(v>>1);
00063     else     return  (v>>1);
00064 }
00065 
00066 static uint64_t get_fourcc(AVIOContext *bc){
00067     unsigned int len= ffio_read_varlen(bc);
00068 
00069     if     (len==2) return avio_rl16(bc);
00070     else if(len==4) return avio_rl32(bc);
00071     else            return -1;
00072 }
00073 
00074 #ifdef TRACE
00075 static inline uint64_t get_v_trace(AVIOContext *bc, char *file, char *func, int line){
00076     uint64_t v= ffio_read_varlen(bc);
00077 
00078     av_log(NULL, AV_LOG_DEBUG, "get_v %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
00079     return v;
00080 }
00081 
00082 static inline int64_t get_s_trace(AVIOContext *bc, char *file, char *func, int line){
00083     int64_t v= get_s(bc);
00084 
00085     av_log(NULL, AV_LOG_DEBUG, "get_s %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
00086     return v;
00087 }
00088 
00089 static inline uint64_t get_vb_trace(AVIOContext *bc, char *file, char *func, int line){
00090     uint64_t v= get_vb(bc);
00091 
00092     av_log(NULL, AV_LOG_DEBUG, "get_vb %5"PRId64" / %"PRIX64" in %s %s:%d\n", v, v, file, func, line);
00093     return v;
00094 }
00095 #define ffio_read_varlen(bc)  get_v_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00096 #define get_s(bc)  get_s_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00097 #define get_vb(bc)  get_vb_trace(bc, __FILE__, __PRETTY_FUNCTION__, __LINE__)
00098 #endif
00099 
00100 static int get_packetheader(NUTContext *nut, AVIOContext *bc, int calculate_checksum, uint64_t startcode)
00101 {
00102     int64_t size;
00103 //    start= avio_tell(bc) - 8;
00104 
00105     startcode= av_be2ne64(startcode);
00106     startcode= ff_crc04C11DB7_update(0, (uint8_t*)&startcode, 8);
00107 
00108     ffio_init_checksum(bc, ff_crc04C11DB7_update, startcode);
00109     size= ffio_read_varlen(bc);
00110     if(size > 4096)
00111         avio_rb32(bc);
00112     if(ffio_get_checksum(bc) && size > 4096)
00113         return -1;
00114 
00115     ffio_init_checksum(bc, calculate_checksum ? ff_crc04C11DB7_update : NULL, 0);
00116 
00117     return size;
00118 }
00119 
00120 static uint64_t find_any_startcode(AVIOContext *bc, int64_t pos){
00121     uint64_t state=0;
00122 
00123     if(pos >= 0)
00124         avio_seek(bc, pos, SEEK_SET); //note, this may fail if the stream is not seekable, but that should not matter, as in this case we simply start where we currently are
00125 
00126     while(!url_feof(bc)){
00127         state= (state<<8) | avio_r8(bc);
00128         if((state>>56) != 'N')
00129             continue;
00130         switch(state){
00131         case MAIN_STARTCODE:
00132         case STREAM_STARTCODE:
00133         case SYNCPOINT_STARTCODE:
00134         case INFO_STARTCODE:
00135         case INDEX_STARTCODE:
00136             return state;
00137         }
00138     }
00139 
00140     return 0;
00141 }
00142 
00149 static int64_t find_startcode(AVIOContext *bc, uint64_t code, int64_t pos){
00150     for(;;){
00151         uint64_t startcode= find_any_startcode(bc, pos);
00152         if(startcode == code)
00153             return avio_tell(bc) - 8;
00154         else if(startcode == 0)
00155             return -1;
00156         pos=-1;
00157     }
00158 }
00159 
00160 static int nut_probe(AVProbeData *p){
00161     int i;
00162     uint64_t code= 0;
00163 
00164     for (i = 0; i < p->buf_size; i++) {
00165         code = (code << 8) | p->buf[i];
00166         if (code == MAIN_STARTCODE)
00167             return AVPROBE_SCORE_MAX;
00168     }
00169     return 0;
00170 }
00171 
00172 #define GET_V(dst, check) \
00173     tmp= ffio_read_varlen(bc);\
00174     if(!(check)){\
00175         av_log(s, AV_LOG_ERROR, "Error " #dst " is (%"PRId64")\n", tmp);\
00176         return -1;\
00177     }\
00178     dst= tmp;
00179 
00180 static int skip_reserved(AVIOContext *bc, int64_t pos){
00181     pos -= avio_tell(bc);
00182     if(pos<0){
00183         avio_seek(bc, pos, SEEK_CUR);
00184         return -1;
00185     }else{
00186         while(pos--)
00187             avio_r8(bc);
00188         return 0;
00189     }
00190 }
00191 
00192 static int decode_main_header(NUTContext *nut){
00193     AVFormatContext *s= nut->avf;
00194     AVIOContext *bc = s->pb;
00195     uint64_t tmp, end;
00196     unsigned int stream_count;
00197     int i, j, tmp_stream, tmp_mul, tmp_pts, tmp_size, count, tmp_res, tmp_head_idx;
00198 
00199     end= get_packetheader(nut, bc, 1, MAIN_STARTCODE);
00200     end += avio_tell(bc);
00201 
00202     GET_V(tmp              , tmp >=2 && tmp <= 3)
00203     GET_V(stream_count     , tmp > 0 && tmp <= NUT_MAX_STREAMS)
00204 
00205     nut->max_distance = ffio_read_varlen(bc);
00206     if(nut->max_distance > 65536){
00207         av_log(s, AV_LOG_DEBUG, "max_distance %d\n", nut->max_distance);
00208         nut->max_distance= 65536;
00209     }
00210 
00211     GET_V(nut->time_base_count, tmp>0 && tmp<INT_MAX / sizeof(AVRational))
00212     nut->time_base= av_malloc(nut->time_base_count * sizeof(AVRational));
00213 
00214     for(i=0; i<nut->time_base_count; i++){
00215         GET_V(nut->time_base[i].num, tmp>0 && tmp<(1ULL<<31))
00216         GET_V(nut->time_base[i].den, tmp>0 && tmp<(1ULL<<31))
00217         if(av_gcd(nut->time_base[i].num, nut->time_base[i].den) != 1){
00218             av_log(s, AV_LOG_ERROR, "time base invalid\n");
00219             return AVERROR_INVALIDDATA;
00220         }
00221     }
00222     tmp_pts=0;
00223     tmp_mul=1;
00224     tmp_stream=0;
00225     tmp_head_idx= 0;
00226     for(i=0; i<256;){
00227         int tmp_flags = ffio_read_varlen(bc);
00228         int tmp_fields= ffio_read_varlen(bc);
00229         if(tmp_fields>0) tmp_pts   = get_s(bc);
00230         if(tmp_fields>1) tmp_mul   = ffio_read_varlen(bc);
00231         if(tmp_fields>2) tmp_stream= ffio_read_varlen(bc);
00232         if(tmp_fields>3) tmp_size  = ffio_read_varlen(bc);
00233         else             tmp_size  = 0;
00234         if(tmp_fields>4) tmp_res   = ffio_read_varlen(bc);
00235         else             tmp_res   = 0;
00236         if(tmp_fields>5) count     = ffio_read_varlen(bc);
00237         else             count     = tmp_mul - tmp_size;
00238         if(tmp_fields>6) get_s(bc);
00239         if(tmp_fields>7) tmp_head_idx= ffio_read_varlen(bc);
00240 
00241         while(tmp_fields-- > 8)
00242            ffio_read_varlen(bc);
00243 
00244         if(count == 0 || i+count > 256){
00245             av_log(s, AV_LOG_ERROR, "illegal count %d at %d\n", count, i);
00246             return AVERROR_INVALIDDATA;
00247         }
00248         if(tmp_stream >= stream_count){
00249             av_log(s, AV_LOG_ERROR, "illegal stream number\n");
00250             return AVERROR_INVALIDDATA;
00251         }
00252 
00253         for(j=0; j<count; j++,i++){
00254             if (i == 'N') {
00255                 nut->frame_code[i].flags= FLAG_INVALID;
00256                 j--;
00257                 continue;
00258             }
00259             nut->frame_code[i].flags           = tmp_flags ;
00260             nut->frame_code[i].pts_delta       = tmp_pts   ;
00261             nut->frame_code[i].stream_id       = tmp_stream;
00262             nut->frame_code[i].size_mul        = tmp_mul   ;
00263             nut->frame_code[i].size_lsb        = tmp_size+j;
00264             nut->frame_code[i].reserved_count  = tmp_res   ;
00265             nut->frame_code[i].header_idx      = tmp_head_idx;
00266         }
00267     }
00268     assert(nut->frame_code['N'].flags == FLAG_INVALID);
00269 
00270     if(end > avio_tell(bc) + 4){
00271         int rem= 1024;
00272         GET_V(nut->header_count, tmp<128U)
00273         nut->header_count++;
00274         for(i=1; i<nut->header_count; i++){
00275             GET_V(nut->header_len[i], tmp>0 && tmp<256);
00276             rem -= nut->header_len[i];
00277             if(rem < 0){
00278                 av_log(s, AV_LOG_ERROR, "invalid elision header\n");
00279                 return AVERROR_INVALIDDATA;
00280             }
00281             nut->header[i]= av_malloc(nut->header_len[i]);
00282             avio_read(bc, nut->header[i], nut->header_len[i]);
00283         }
00284         assert(nut->header_len[0]==0);
00285     }
00286 
00287     if(skip_reserved(bc, end) || ffio_get_checksum(bc)){
00288         av_log(s, AV_LOG_ERROR, "main header checksum mismatch\n");
00289         return AVERROR_INVALIDDATA;
00290     }
00291 
00292     nut->stream = av_mallocz(sizeof(StreamContext)*stream_count);
00293     for(i=0; i<stream_count; i++){
00294         av_new_stream(s, i);
00295     }
00296 
00297     return 0;
00298 }
00299 
00300 static int decode_stream_header(NUTContext *nut){
00301     AVFormatContext *s= nut->avf;
00302     AVIOContext *bc = s->pb;
00303     StreamContext *stc;
00304     int class, stream_id;
00305     uint64_t tmp, end;
00306     AVStream *st;
00307 
00308     end= get_packetheader(nut, bc, 1, STREAM_STARTCODE);
00309     end += avio_tell(bc);
00310 
00311     GET_V(stream_id, tmp < s->nb_streams && !nut->stream[tmp].time_base);
00312     stc= &nut->stream[stream_id];
00313 
00314     st = s->streams[stream_id];
00315     if (!st)
00316         return AVERROR(ENOMEM);
00317 
00318     class = ffio_read_varlen(bc);
00319     tmp = get_fourcc(bc);
00320     st->codec->codec_tag= tmp;
00321     switch(class)
00322     {
00323         case 0:
00324             st->codec->codec_type = AVMEDIA_TYPE_VIDEO;
00325             st->codec->codec_id = av_codec_get_id(
00326                 (const AVCodecTag * const []) { ff_codec_bmp_tags, ff_nut_video_tags, 0 },
00327                 tmp);
00328             break;
00329         case 1:
00330             st->codec->codec_type = AVMEDIA_TYPE_AUDIO;
00331             st->codec->codec_id = ff_codec_get_id(ff_codec_wav_tags, tmp);
00332             break;
00333         case 2:
00334             st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE;
00335             st->codec->codec_id = ff_codec_get_id(ff_nut_subtitle_tags, tmp);
00336             break;
00337         case 3:
00338             st->codec->codec_type = AVMEDIA_TYPE_DATA;
00339             break;
00340         default:
00341             av_log(s, AV_LOG_ERROR, "unknown stream class (%d)\n", class);
00342             return -1;
00343     }
00344     if(class<3 && st->codec->codec_id == CODEC_ID_NONE)
00345         av_log(s, AV_LOG_ERROR, "Unknown codec tag '0x%04x' for stream number %d\n",
00346                (unsigned int)tmp, stream_id);
00347 
00348     GET_V(stc->time_base_id    , tmp < nut->time_base_count);
00349     GET_V(stc->msb_pts_shift   , tmp < 16);
00350     stc->max_pts_distance= ffio_read_varlen(bc);
00351     GET_V(stc->decode_delay    , tmp < 1000); //sanity limit, raise this if Moore's law is true
00352     st->codec->has_b_frames= stc->decode_delay;
00353     ffio_read_varlen(bc); //stream flags
00354 
00355     GET_V(st->codec->extradata_size, tmp < (1<<30));
00356     if(st->codec->extradata_size){
00357         st->codec->extradata= av_mallocz(st->codec->extradata_size + FF_INPUT_BUFFER_PADDING_SIZE);
00358         avio_read(bc, st->codec->extradata, st->codec->extradata_size);
00359     }
00360 
00361     if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO){
00362         GET_V(st->codec->width , tmp > 0)
00363         GET_V(st->codec->height, tmp > 0)
00364         st->sample_aspect_ratio.num= ffio_read_varlen(bc);
00365         st->sample_aspect_ratio.den= ffio_read_varlen(bc);
00366         if((!st->sample_aspect_ratio.num) != (!st->sample_aspect_ratio.den)){
00367             av_log(s, AV_LOG_ERROR, "invalid aspect ratio %d/%d\n", st->sample_aspect_ratio.num, st->sample_aspect_ratio.den);
00368             return -1;
00369         }
00370         ffio_read_varlen(bc); /* csp type */
00371     }else if (st->codec->codec_type == AVMEDIA_TYPE_AUDIO){
00372         GET_V(st->codec->sample_rate , tmp > 0)
00373         ffio_read_varlen(bc); // samplerate_den
00374         GET_V(st->codec->channels, tmp > 0)
00375     }
00376     if(skip_reserved(bc, end) || ffio_get_checksum(bc)){
00377         av_log(s, AV_LOG_ERROR, "stream header %d checksum mismatch\n", stream_id);
00378         return -1;
00379     }
00380     stc->time_base= &nut->time_base[stc->time_base_id];
00381     av_set_pts_info(s->streams[stream_id], 63, stc->time_base->num, stc->time_base->den);
00382     return 0;
00383 }
00384 
00385 static void set_disposition_bits(AVFormatContext* avf, char* value, int stream_id){
00386     int flag = 0, i;
00387     for (i=0; ff_nut_dispositions[i].flag; ++i) {
00388         if (!strcmp(ff_nut_dispositions[i].str, value))
00389             flag = ff_nut_dispositions[i].flag;
00390     }
00391     if (!flag)
00392         av_log(avf, AV_LOG_INFO, "unknown disposition type '%s'\n", value);
00393     for (i = 0; i < avf->nb_streams; ++i)
00394         if (stream_id == i || stream_id == -1)
00395             avf->streams[i]->disposition |= flag;
00396 }
00397 
00398 static int decode_info_header(NUTContext *nut){
00399     AVFormatContext *s= nut->avf;
00400     AVIOContext *bc = s->pb;
00401     uint64_t tmp, chapter_start, chapter_len;
00402     unsigned int stream_id_plus1, count;
00403     int chapter_id, i;
00404     int64_t value, end;
00405     char name[256], str_value[1024], type_str[256];
00406     const char *type;
00407     AVChapter *chapter= NULL;
00408     AVStream *st= NULL;
00409     AVDictionary **metadata = NULL;
00410 
00411     end= get_packetheader(nut, bc, 1, INFO_STARTCODE);
00412     end += avio_tell(bc);
00413 
00414     GET_V(stream_id_plus1, tmp <= s->nb_streams)
00415     chapter_id   = get_s(bc);
00416     chapter_start= ffio_read_varlen(bc);
00417     chapter_len  = ffio_read_varlen(bc);
00418     count        = ffio_read_varlen(bc);
00419 
00420     if(chapter_id && !stream_id_plus1){
00421         int64_t start= chapter_start / nut->time_base_count;
00422         chapter= ff_new_chapter(s, chapter_id,
00423                                 nut->time_base[chapter_start % nut->time_base_count],
00424                                 start, start + chapter_len, NULL);
00425         metadata = &chapter->metadata;
00426     } else if(stream_id_plus1) {
00427         st= s->streams[stream_id_plus1 - 1];
00428         metadata = &st->metadata;
00429     } else
00430         metadata = &s->metadata;
00431 
00432     for(i=0; i<count; i++){
00433         get_str(bc, name, sizeof(name));
00434         value= get_s(bc);
00435         if(value == -1){
00436             type= "UTF-8";
00437             get_str(bc, str_value, sizeof(str_value));
00438         }else if(value == -2){
00439             get_str(bc, type_str, sizeof(type_str));
00440             type= type_str;
00441             get_str(bc, str_value, sizeof(str_value));
00442         }else if(value == -3){
00443             type= "s";
00444             value= get_s(bc);
00445         }else if(value == -4){
00446             type= "t";
00447             value= ffio_read_varlen(bc);
00448         }else if(value < -4){
00449             type= "r";
00450             get_s(bc);
00451         }else{
00452             type= "v";
00453         }
00454 
00455         if (stream_id_plus1 > s->nb_streams) {
00456             av_log(s, AV_LOG_ERROR, "invalid stream id for info packet\n");
00457             continue;
00458         }
00459 
00460         if(!strcmp(type, "UTF-8")){
00461             if(chapter_id==0 && !strcmp(name, "Disposition")) {
00462                 set_disposition_bits(s, str_value, stream_id_plus1 - 1);
00463                 continue;
00464             }
00465             if(metadata && strcasecmp(name,"Uses")
00466                && strcasecmp(name,"Depends") && strcasecmp(name,"Replaces"))
00467                 av_dict_set(metadata, name, str_value, 0);
00468         }
00469     }
00470 
00471     if(skip_reserved(bc, end) || ffio_get_checksum(bc)){
00472         av_log(s, AV_LOG_ERROR, "info header checksum mismatch\n");
00473         return -1;
00474     }
00475     return 0;
00476 }
00477 
00478 static int decode_syncpoint(NUTContext *nut, int64_t *ts, int64_t *back_ptr){
00479     AVFormatContext *s= nut->avf;
00480     AVIOContext *bc = s->pb;
00481     int64_t end, tmp;
00482 
00483     nut->last_syncpoint_pos= avio_tell(bc)-8;
00484 
00485     end= get_packetheader(nut, bc, 1, SYNCPOINT_STARTCODE);
00486     end += avio_tell(bc);
00487 
00488     tmp= ffio_read_varlen(bc);
00489     *back_ptr= nut->last_syncpoint_pos - 16*ffio_read_varlen(bc);
00490     if(*back_ptr < 0)
00491         return -1;
00492 
00493     ff_nut_reset_ts(nut, nut->time_base[tmp % nut->time_base_count], tmp / nut->time_base_count);
00494 
00495     if(skip_reserved(bc, end) || ffio_get_checksum(bc)){
00496         av_log(s, AV_LOG_ERROR, "sync point checksum mismatch\n");
00497         return -1;
00498     }
00499 
00500     *ts= tmp / s->nb_streams * av_q2d(nut->time_base[tmp % s->nb_streams])*AV_TIME_BASE;
00501     ff_nut_add_sp(nut, nut->last_syncpoint_pos, *back_ptr, *ts);
00502 
00503     return 0;
00504 }
00505 
00506 static int find_and_decode_index(NUTContext *nut){
00507     AVFormatContext *s= nut->avf;
00508     AVIOContext *bc = s->pb;
00509     uint64_t tmp, end;
00510     int i, j, syncpoint_count;
00511     int64_t filesize= avio_size(bc);
00512     int64_t *syncpoints;
00513     int8_t *has_keyframe;
00514     int ret= -1;
00515 
00516     avio_seek(bc, filesize-12, SEEK_SET);
00517     avio_seek(bc, filesize-avio_rb64(bc), SEEK_SET);
00518     if(avio_rb64(bc) != INDEX_STARTCODE){
00519         av_log(s, AV_LOG_ERROR, "no index at the end\n");
00520         return -1;
00521     }
00522 
00523     end= get_packetheader(nut, bc, 1, INDEX_STARTCODE);
00524     end += avio_tell(bc);
00525 
00526     ffio_read_varlen(bc); //max_pts
00527     GET_V(syncpoint_count, tmp < INT_MAX/8 && tmp > 0)
00528     syncpoints= av_malloc(sizeof(int64_t)*syncpoint_count);
00529     has_keyframe= av_malloc(sizeof(int8_t)*(syncpoint_count+1));
00530     for(i=0; i<syncpoint_count; i++){
00531         syncpoints[i] = ffio_read_varlen(bc);
00532         if(syncpoints[i] <= 0)
00533             goto fail;
00534         if(i)
00535             syncpoints[i] += syncpoints[i-1];
00536     }
00537 
00538     for(i=0; i<s->nb_streams; i++){
00539         int64_t last_pts= -1;
00540         for(j=0; j<syncpoint_count;){
00541             uint64_t x= ffio_read_varlen(bc);
00542             int type= x&1;
00543             int n= j;
00544             x>>=1;
00545             if(type){
00546                 int flag= x&1;
00547                 x>>=1;
00548                 if(n+x >= syncpoint_count + 1){
00549                     av_log(s, AV_LOG_ERROR, "index overflow A\n");
00550                     goto fail;
00551                 }
00552                 while(x--)
00553                     has_keyframe[n++]= flag;
00554                 has_keyframe[n++]= !flag;
00555             }else{
00556                 while(x != 1){
00557                     if(n>=syncpoint_count + 1){
00558                         av_log(s, AV_LOG_ERROR, "index overflow B\n");
00559                         goto fail;
00560                     }
00561                     has_keyframe[n++]= x&1;
00562                     x>>=1;
00563                 }
00564             }
00565             if(has_keyframe[0]){
00566                 av_log(s, AV_LOG_ERROR, "keyframe before first syncpoint in index\n");
00567                 goto fail;
00568             }
00569             assert(n<=syncpoint_count+1);
00570             for(; j<n && j<syncpoint_count; j++){
00571                 if(has_keyframe[j]){
00572                     uint64_t B, A= ffio_read_varlen(bc);
00573                     if(!A){
00574                         A= ffio_read_varlen(bc);
00575                         B= ffio_read_varlen(bc);
00576                         //eor_pts[j][i] = last_pts + A + B
00577                     }else
00578                         B= 0;
00579                     av_add_index_entry(
00580                         s->streams[i],
00581                         16*syncpoints[j-1],
00582                         last_pts + A,
00583                         0,
00584                         0,
00585                         AVINDEX_KEYFRAME);
00586                     last_pts += A + B;
00587                 }
00588             }
00589         }
00590     }
00591 
00592     if(skip_reserved(bc, end) || ffio_get_checksum(bc)){
00593         av_log(s, AV_LOG_ERROR, "index checksum mismatch\n");
00594         goto fail;
00595     }
00596     ret= 0;
00597 fail:
00598     av_free(syncpoints);
00599     av_free(has_keyframe);
00600     return ret;
00601 }
00602 
00603 static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap)
00604 {
00605     NUTContext *nut = s->priv_data;
00606     AVIOContext *bc = s->pb;
00607     int64_t pos;
00608     int initialized_stream_count;
00609 
00610     nut->avf= s;
00611 
00612     /* main header */
00613     pos=0;
00614     do{
00615         pos= find_startcode(bc, MAIN_STARTCODE, pos)+1;
00616         if (pos<0+1){
00617             av_log(s, AV_LOG_ERROR, "No main startcode found.\n");
00618             return AVERROR_INVALIDDATA;
00619         }
00620     }while(decode_main_header(nut) < 0);
00621 
00622     /* stream headers */
00623     pos=0;
00624     for(initialized_stream_count=0; initialized_stream_count < s->nb_streams;){
00625         pos= find_startcode(bc, STREAM_STARTCODE, pos)+1;
00626         if (pos<0+1){
00627             av_log(s, AV_LOG_ERROR, "Not all stream headers found.\n");
00628             return AVERROR_INVALIDDATA;
00629         }
00630         if(decode_stream_header(nut) >= 0)
00631             initialized_stream_count++;
00632     }
00633 
00634     /* info headers */
00635     pos=0;
00636     for(;;){
00637         uint64_t startcode= find_any_startcode(bc, pos);
00638         pos= avio_tell(bc);
00639 
00640         if(startcode==0){
00641             av_log(s, AV_LOG_ERROR, "EOF before video frames\n");
00642             return AVERROR_INVALIDDATA;
00643         }else if(startcode == SYNCPOINT_STARTCODE){
00644             nut->next_startcode= startcode;
00645             break;
00646         }else if(startcode != INFO_STARTCODE){
00647             continue;
00648         }
00649 
00650         decode_info_header(nut);
00651     }
00652 
00653     s->data_offset= pos-8;
00654 
00655     if(bc->seekable){
00656         int64_t orig_pos= avio_tell(bc);
00657         find_and_decode_index(nut);
00658         avio_seek(bc, orig_pos, SEEK_SET);
00659     }
00660     assert(nut->next_startcode == SYNCPOINT_STARTCODE);
00661 
00662     ff_metadata_conv_ctx(s, NULL, ff_nut_metadata_conv);
00663 
00664     return 0;
00665 }
00666 
00667 static int decode_frame_header(NUTContext *nut, int64_t *pts, int *stream_id, uint8_t *header_idx, int frame_code){
00668     AVFormatContext *s= nut->avf;
00669     AVIOContext *bc = s->pb;
00670     StreamContext *stc;
00671     int size, flags, size_mul, pts_delta, i, reserved_count;
00672     uint64_t tmp;
00673 
00674     if(avio_tell(bc) > nut->last_syncpoint_pos + nut->max_distance){
00675         av_log(s, AV_LOG_ERROR, "Last frame must have been damaged %"PRId64" > %"PRId64" + %d\n", avio_tell(bc), nut->last_syncpoint_pos, nut->max_distance);
00676         return AVERROR_INVALIDDATA;
00677     }
00678 
00679     flags          = nut->frame_code[frame_code].flags;
00680     size_mul       = nut->frame_code[frame_code].size_mul;
00681     size           = nut->frame_code[frame_code].size_lsb;
00682     *stream_id     = nut->frame_code[frame_code].stream_id;
00683     pts_delta      = nut->frame_code[frame_code].pts_delta;
00684     reserved_count = nut->frame_code[frame_code].reserved_count;
00685     *header_idx    = nut->frame_code[frame_code].header_idx;
00686 
00687     if(flags & FLAG_INVALID)
00688         return AVERROR_INVALIDDATA;
00689     if(flags & FLAG_CODED)
00690         flags ^= ffio_read_varlen(bc);
00691     if(flags & FLAG_STREAM_ID){
00692         GET_V(*stream_id, tmp < s->nb_streams)
00693     }
00694     stc= &nut->stream[*stream_id];
00695     if(flags&FLAG_CODED_PTS){
00696         int coded_pts= ffio_read_varlen(bc);
00697 //FIXME check last_pts validity?
00698         if(coded_pts < (1<<stc->msb_pts_shift)){
00699             *pts=ff_lsb2full(stc, coded_pts);
00700         }else
00701             *pts=coded_pts - (1<<stc->msb_pts_shift);
00702     }else
00703         *pts= stc->last_pts + pts_delta;
00704     if(flags&FLAG_SIZE_MSB){
00705         size += size_mul*ffio_read_varlen(bc);
00706     }
00707     if(flags&FLAG_MATCH_TIME)
00708         get_s(bc);
00709     if(flags&FLAG_HEADER_IDX)
00710         *header_idx= ffio_read_varlen(bc);
00711     if(flags&FLAG_RESERVED)
00712         reserved_count= ffio_read_varlen(bc);
00713     for(i=0; i<reserved_count; i++)
00714         ffio_read_varlen(bc);
00715 
00716     if(*header_idx >= (unsigned)nut->header_count){
00717         av_log(s, AV_LOG_ERROR, "header_idx invalid\n");
00718         return AVERROR_INVALIDDATA;
00719     }
00720     if(size > 4096)
00721         *header_idx=0;
00722     size -= nut->header_len[*header_idx];
00723 
00724     if(flags&FLAG_CHECKSUM){
00725         avio_rb32(bc); //FIXME check this
00726     }else if(size > 2*nut->max_distance || FFABS(stc->last_pts - *pts) > stc->max_pts_distance){
00727         av_log(s, AV_LOG_ERROR, "frame size > 2max_distance and no checksum\n");
00728         return AVERROR_INVALIDDATA;
00729     }
00730 
00731     stc->last_pts= *pts;
00732     stc->last_flags= flags;
00733 
00734     return size;
00735 }
00736 
00737 static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code){
00738     AVFormatContext *s= nut->avf;
00739     AVIOContext *bc = s->pb;
00740     int size, stream_id, discard;
00741     int64_t pts, last_IP_pts;
00742     StreamContext *stc;
00743     uint8_t header_idx;
00744 
00745     size= decode_frame_header(nut, &pts, &stream_id, &header_idx, frame_code);
00746     if(size < 0)
00747         return size;
00748 
00749     stc= &nut->stream[stream_id];
00750 
00751     if (stc->last_flags & FLAG_KEY)
00752         stc->skip_until_key_frame=0;
00753 
00754     discard= s->streams[ stream_id ]->discard;
00755     last_IP_pts= s->streams[ stream_id ]->last_IP_pts;
00756     if(  (discard >= AVDISCARD_NONKEY && !(stc->last_flags & FLAG_KEY))
00757        ||(discard >= AVDISCARD_BIDIR && last_IP_pts != AV_NOPTS_VALUE && last_IP_pts > pts)
00758        || discard >= AVDISCARD_ALL
00759        || stc->skip_until_key_frame){
00760         avio_skip(bc, size);
00761         return 1;
00762     }
00763 
00764     av_new_packet(pkt, size + nut->header_len[header_idx]);
00765     memcpy(pkt->data, nut->header[header_idx], nut->header_len[header_idx]);
00766     pkt->pos= avio_tell(bc); //FIXME
00767     avio_read(bc, pkt->data + nut->header_len[header_idx], size);
00768 
00769     pkt->stream_index = stream_id;
00770     if (stc->last_flags & FLAG_KEY)
00771         pkt->flags |= AV_PKT_FLAG_KEY;
00772     pkt->pts = pts;
00773 
00774     return 0;
00775 }
00776 
00777 static int nut_read_packet(AVFormatContext *s, AVPacket *pkt)
00778 {
00779     NUTContext *nut = s->priv_data;
00780     AVIOContext *bc = s->pb;
00781     int i, frame_code=0, ret, skip;
00782     int64_t ts, back_ptr;
00783 
00784     for(;;){
00785         int64_t pos= avio_tell(bc);
00786         uint64_t tmp= nut->next_startcode;
00787         nut->next_startcode=0;
00788 
00789         if(tmp){
00790             pos-=8;
00791         }else{
00792             frame_code = avio_r8(bc);
00793             if(url_feof(bc))
00794                 return -1;
00795             if(frame_code == 'N'){
00796                 tmp= frame_code;
00797                 for(i=1; i<8; i++)
00798                     tmp = (tmp<<8) + avio_r8(bc);
00799             }
00800         }
00801         switch(tmp){
00802         case MAIN_STARTCODE:
00803         case STREAM_STARTCODE:
00804         case INDEX_STARTCODE:
00805             skip= get_packetheader(nut, bc, 0, tmp);
00806             avio_skip(bc, skip);
00807             break;
00808         case INFO_STARTCODE:
00809             if(decode_info_header(nut)<0)
00810                 goto resync;
00811             break;
00812         case SYNCPOINT_STARTCODE:
00813             if(decode_syncpoint(nut, &ts, &back_ptr)<0)
00814                 goto resync;
00815             frame_code = avio_r8(bc);
00816         case 0:
00817             ret= decode_frame(nut, pkt, frame_code);
00818             if(ret==0)
00819                 return 0;
00820             else if(ret==1) //ok but discard packet
00821                 break;
00822         default:
00823 resync:
00824 av_log(s, AV_LOG_DEBUG, "syncing from %"PRId64"\n", pos);
00825             tmp= find_any_startcode(bc, nut->last_syncpoint_pos+1);
00826             if(tmp==0)
00827                 return AVERROR_INVALIDDATA;
00828 av_log(s, AV_LOG_DEBUG, "sync\n");
00829             nut->next_startcode= tmp;
00830         }
00831     }
00832 }
00833 
00834 static int64_t nut_read_timestamp(AVFormatContext *s, int stream_index, int64_t *pos_arg, int64_t pos_limit){
00835     NUTContext *nut = s->priv_data;
00836     AVIOContext *bc = s->pb;
00837     int64_t pos, pts, back_ptr;
00838 av_log(s, AV_LOG_DEBUG, "read_timestamp(X,%d,%"PRId64",%"PRId64")\n", stream_index, *pos_arg, pos_limit);
00839 
00840     pos= *pos_arg;
00841     do{
00842         pos= find_startcode(bc, SYNCPOINT_STARTCODE, pos)+1;
00843         if(pos < 1){
00844             assert(nut->next_startcode == 0);
00845             av_log(s, AV_LOG_ERROR, "read_timestamp failed.\n");
00846             return AV_NOPTS_VALUE;
00847         }
00848     }while(decode_syncpoint(nut, &pts, &back_ptr) < 0);
00849     *pos_arg = pos-1;
00850     assert(nut->last_syncpoint_pos == *pos_arg);
00851 
00852     av_log(s, AV_LOG_DEBUG, "return %"PRId64" %"PRId64"\n", pts,back_ptr );
00853     if     (stream_index == -1) return pts;
00854     else if(stream_index == -2) return back_ptr;
00855 
00856 assert(0);
00857 }
00858 
00859 static int read_seek(AVFormatContext *s, int stream_index, int64_t pts, int flags){
00860     NUTContext *nut = s->priv_data;
00861     AVStream *st= s->streams[stream_index];
00862     Syncpoint dummy={.ts= pts*av_q2d(st->time_base)*AV_TIME_BASE};
00863     Syncpoint nopts_sp= {.ts= AV_NOPTS_VALUE, .back_ptr= AV_NOPTS_VALUE};
00864     Syncpoint *sp, *next_node[2]= {&nopts_sp, &nopts_sp};
00865     int64_t pos, pos2, ts;
00866     int i;
00867 
00868     if(st->index_entries){
00869         int index= av_index_search_timestamp(st, pts, flags);
00870         if(index<0)
00871             return -1;
00872 
00873         pos2= st->index_entries[index].pos;
00874         ts  = st->index_entries[index].timestamp;
00875     }else{
00876         av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pts_cmp,
00877                      (void **) next_node);
00878         av_log(s, AV_LOG_DEBUG, "%"PRIu64"-%"PRIu64" %"PRId64"-%"PRId64"\n", next_node[0]->pos, next_node[1]->pos,
00879                                                     next_node[0]->ts , next_node[1]->ts);
00880         pos= av_gen_search(s, -1, dummy.ts, next_node[0]->pos, next_node[1]->pos, next_node[1]->pos,
00881                                             next_node[0]->ts , next_node[1]->ts, AVSEEK_FLAG_BACKWARD, &ts, nut_read_timestamp);
00882 
00883         if(!(flags & AVSEEK_FLAG_BACKWARD)){
00884             dummy.pos= pos+16;
00885             next_node[1]= &nopts_sp;
00886             av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp,
00887                          (void **) next_node);
00888             pos2= av_gen_search(s, -2, dummy.pos, next_node[0]->pos     , next_node[1]->pos, next_node[1]->pos,
00889                                                 next_node[0]->back_ptr, next_node[1]->back_ptr, flags, &ts, nut_read_timestamp);
00890             if(pos2>=0)
00891                 pos= pos2;
00892             //FIXME dir but I think it does not matter
00893         }
00894         dummy.pos= pos;
00895         sp= av_tree_find(nut->syncpoints, &dummy, (void *) ff_nut_sp_pos_cmp,
00896                          NULL);
00897 
00898         assert(sp);
00899         pos2= sp->back_ptr  - 15;
00900     }
00901     av_log(NULL, AV_LOG_DEBUG, "SEEKTO: %"PRId64"\n", pos2);
00902     pos= find_startcode(s->pb, SYNCPOINT_STARTCODE, pos2);
00903     avio_seek(s->pb, pos, SEEK_SET);
00904     av_log(NULL, AV_LOG_DEBUG, "SP: %"PRId64"\n", pos);
00905     if(pos2 > pos || pos2 + 15 < pos){
00906         av_log(NULL, AV_LOG_ERROR, "no syncpoint at backptr pos\n");
00907     }
00908     for(i=0; i<s->nb_streams; i++)
00909         nut->stream[i].skip_until_key_frame=1;
00910 
00911     return 0;
00912 }
00913 
00914 static int nut_read_close(AVFormatContext *s)
00915 {
00916     NUTContext *nut = s->priv_data;
00917     int i;
00918 
00919     av_freep(&nut->time_base);
00920     av_freep(&nut->stream);
00921     ff_nut_free_sp(nut);
00922     for(i = 1; i < nut->header_count; i++)
00923         av_freep(&nut->header[i]);
00924 
00925     return 0;
00926 }
00927 
00928 #if CONFIG_NUT_DEMUXER
00929 AVInputFormat ff_nut_demuxer = {
00930     "nut",
00931     NULL_IF_CONFIG_SMALL("NUT format"),
00932     sizeof(NUTContext),
00933     nut_probe,
00934     nut_read_header,
00935     nut_read_packet,
00936     nut_read_close,
00937     read_seek,
00938     .extensions = "nut",
00939     .codec_tag = (const AVCodecTag * const []) { ff_codec_bmp_tags, ff_nut_video_tags, ff_codec_wav_tags, ff_nut_subtitle_tags, 0 },
00940 };
00941 #endif

Generated on Wed Apr 11 2012 07:31:36 for FFmpeg by  doxygen 1.7.1