+static int decode_main_header(NUTContext *nut){
+ AVFormatContext *s= nut->avf;
+ ByteIOContext *bc = &s->pb;
+ uint64_t tmp;
+ int i, j, tmp_stream, tmp_mul, tmp_time, tmp_size, count, tmp_res;
+
+ get_packetheader(nut, bc, 1);
+
+ tmp = get_v(bc);
+ if (tmp != 2){
+ av_log(s, AV_LOG_ERROR, "bad version (%"PRId64")\n", tmp);
+ return -1;
+ }
+
+ nut->stream_count = get_v(bc);
+ if(nut->stream_count > MAX_STREAMS){
+ av_log(s, AV_LOG_ERROR, "too many streams\n");
+ return -1;
+ }
+ 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_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_stream > nut->stream_count + 1){
+ av_log(s, AV_LOG_ERROR, "illegal stream number\n");
+ return -1;
+ }
+
+ for(j=0; j<count; j++,i++){
+ 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+j;
+ nut->frame_code[i].reserved_count = tmp_res ;
+ }
+ }
+ if(nut->frame_code['N'].flags != FLAG_INVALID){
+ av_log(s, AV_LOG_ERROR, "illegal frame_code table\n");
+ return -1;
+ }
+
+ if(check_checksum(bc)){
+ av_log(s, AV_LOG_ERROR, "Main header checksum mismatch\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int decode_stream_header(NUTContext *nut){
+ AVFormatContext *s= nut->avf;
+ ByteIOContext *bc = &s->pb;
+ int class, nom, denom, stream_id;
+ uint64_t tmp;
+ AVStream *st;
+
+ get_packetheader(nut, bc, 1);
+ stream_id= get_v(bc);
+ if(stream_id >= nut->stream_count || s->streams[stream_id])
+ return -1;
+
+ 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:
+ st->codec->codec_type = CODEC_TYPE_VIDEO;
+ st->codec->codec_id = codec_get_bmp_id(tmp);
+ if (st->codec->codec_id == CODEC_ID_NONE)
+ av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
+ break;
+ case 1:
+ case 32: //compatibility
+ st->codec->codec_type = CODEC_TYPE_AUDIO;
+ st->codec->codec_id = codec_get_wav_id(tmp);
+ if (st->codec->codec_id == CODEC_ID_NONE)
+ av_log(s, AV_LOG_ERROR, "Unknown codec?!\n");
+ break;
+ case 2:
+// st->codec->codec_type = CODEC_TYPE_TEXT;
+// break;
+ case 3:
+ st->codec->codec_type = CODEC_TYPE_DATA;
+ break;
+ default:
+ av_log(s, AV_LOG_ERROR, "Unknown stream class (%d)\n", class);
+ return -1;
+ }
+ s->bit_rate += get_v(bc);
+ get_vb(bc); /* language code */
+ nom = get_v(bc);
+ denom = get_v(bc);
+ nut->stream[stream_id].msb_timestamp_shift = get_v(bc);
+ st->codec->has_b_frames=
+ 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);
+ if((unsigned)st->codec->extradata_size > (1<<30))
+ return -1;
+ 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));
+ }
+
+ if (st->codec->codec_type == CODEC_TYPE_VIDEO) /* VIDEO */
+ {
+ st->codec->width = get_v(bc);
+ st->codec->height = get_v(bc);
+ st->codec->sample_aspect_ratio.num= get_v(bc);
+ st->codec->sample_aspect_ratio.den= get_v(bc);
+ get_v(bc); /* csp type */
+ }
+ if (st->codec->codec_type == CODEC_TYPE_AUDIO) /* AUDIO */
+ {
+ 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 mismatch\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;
+}
+
+static int decode_info_header(NUTContext *nut){
+ AVFormatContext *s= nut->avf;
+ ByteIOContext *bc = &s->pb;
+
+ get_packetheader(nut, bc, 1);
+
+ for(;;){
+ int id= get_v(bc);
+ char *name, *type, custom_name[256], custom_type[256];
+
+ if(!id)
+ break;
+ else if(id >= sizeof(info_table)/sizeof(info_table[0])){
+ av_log(s, AV_LOG_ERROR, "info id is too large %d %zd\n", id, sizeof(info_table)/sizeof(info_table[0]));
+ return -1;
+ }
+
+ type= info_table[id][1];
+ name= info_table[id][0];
+//av_log(s, AV_LOG_DEBUG, "%d %s %s\n", id, type, name);
+
+ if(!type){
+ get_str(bc, custom_type, sizeof(custom_type));
+ type= custom_type;
+ }
+ if(!name){
+ get_str(bc, custom_name, sizeof(custom_name));
+ name= custom_name;
+ }
+
+ if(!strcmp(type, "v")){
+ get_v(bc);
+ }else{
+ if(!strcmp(name, "Author"))
+ get_str(bc, s->author, sizeof(s->author));
+ else if(!strcmp(name, "Title"))
+ get_str(bc, s->title, sizeof(s->title));
+ else if(!strcmp(name, "Copyright"))
+ get_str(bc, s->copyright, sizeof(s->copyright));
+ else if(!strcmp(name, "Description"))
+ get_str(bc, s->comment, sizeof(s->comment));
+ else
+ get_str(bc, NULL, 0);
+ }
+ }
+ if(check_checksum(bc)){
+ av_log(s, AV_LOG_ERROR, "Info header checksum mismatch\n");
+ return -1;
+ }
+ return 0;
+}
+