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