📄 nut.c
字号:
if (class == 32) /* AUDIO */ { st->codec.sample_rate = (get_v(bc) * nom) / denom; 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; } 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, 8, 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 %d\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")){ int value= 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 missmatch\n"); return -1; } return 0;}static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap){ NUTContext *nut = s->priv_data; ByteIOContext *bc = &s->pb; int64_t pos; int inited_stream_count; nut->avf= s; av_set_pts_info(s, 60, 1, AV_TIME_BASE); /* main header */ pos=0; for(;;){ pos= find_startcode(bc, MAIN_STARTCODE, pos)+1; if (pos<0){ av_log(s, AV_LOG_ERROR, "no main startcode found\n"); return -1; } if(decode_main_header(nut) >= 0) break; } s->bit_rate = 0; nut->stream = av_malloc(sizeof(StreamContext)*nut->stream_count); /* stream headers */ pos=0; for(inited_stream_count=0; inited_stream_count < nut->stream_count;){ pos= find_startcode(bc, STREAM_STARTCODE, pos)+1; if (pos<0){ av_log(s, AV_LOG_ERROR, "not all stream headers found\n"); return -1; } if(decode_stream_header(nut) >= 0) inited_stream_count++; } /* info headers */ pos=0; for(;;){ uint64_t startcode= find_any_startcode(bc, pos); pos= url_ftell(bc); if(startcode==0){ av_log(s, AV_LOG_ERROR, "EOF before video frames\n"); return -1; }else if(startcode == KEYFRAME_STARTCODE){ nut->next_startcode= startcode; break; }else if(startcode != INFO_STARTCODE){ continue; } decode_info_header(nut); } return 0;}static int decode_frame(NUTContext *nut, AVPacket *pkt, int frame_code, int frame_type){ AVFormatContext *s= nut->avf; StreamContext *stream; ByteIOContext *bc = &s->pb; int size, flags, size_mul, size_lsb, stream_id; int key_frame = 0; int64_t pts = 0; const int prefix_len= frame_type == 2 ? 8+1 : 1; const int64_t frame_start= url_ftell(bc) - prefix_len; 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; } if(stream_id==-1) stream_id= get_v(bc); if(stream_id >= s->nb_streams){ av_log(s, AV_LOG_ERROR, "illegal stream_id\n"); return -1; } 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]); key_frame= !!(flags & FLAG_KEY_FRAME); if(flags & FLAG_PTS){ if(flags & FLAG_FULL_PTS){ pts= get_v(bc); if(frame_type && key_frame){ int64_t av_pts= pts * AV_TIME_BASE * stream->rate_den / stream->rate_num; av_add_index_entry( s->streams[stream_id], frame_start, av_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); } }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; } }else{ pts= stream->last_pts + stream->lru_pts_delta[(flags&12)>>2]; } 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; } //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); if(url_ftell(bc) - nut->packet_start + size > nut->written_packet_size){ av_log(s, AV_LOG_ERROR, "frame size too large\n"); 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; update(nut, stream_id, frame_start, frame_type, frame_code, key_frame, size, pts); return 0;}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; for(;;){ int frame_type= 0; uint64_t tmp= nut->next_startcode; nut->next_startcode=0; if (url_feof(bc)) return -1; if(!tmp){ frame_code = get_byte(bc); if(frame_code == 'N'){ tmp= frame_code; for(i=1; i<8; i++) tmp = (tmp<<8) + get_byte(bc); } } switch(tmp){ 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); break; case INFO_STARTCODE: if(decode_info_header(nut)<0) goto resync; break; case KEYFRAME_STARTCODE: frame_type = 2; frame_code = get_byte(bc); case 0: if(decode_frame(nut, pkt, frame_code, frame_type)>=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); 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; } }}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;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) break; step= FFMIN(2*step, pos); }while(step); if(!code) //nothing found, not even after pos_arg return AV_NOPTS_VALUE; url_fseek(bc, -8, SEEK_CUR); for(i=0; i<s->nb_streams; i++) nut->stream[i].last_sync_pos= url_ftell(bc); for(;;){ int64_t pos= url_ftell(bc); uint64_t tmp=0; int prefix_len=1; if(pos > pos_limit) return AV_NOPTS_VALUE; frame_code = get_byte(bc); if(frame_code == 'N'){ tmp= frame_code; for(i=1; i<8; i++) tmp = (tmp<<8) + get_byte(bc); }//av_log(s, AV_LOG_DEBUG, "before switch %llX at=%lld\n", tmp, pos); switch(tmp){ case MAIN_STARTCODE: 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); break; case KEYFRAME_STARTCODE: nut->written_packet_size= -1; prefix_len+=8; 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) goto resync; stream= &nut->stream[stream_id]; pts= get_v(bc) * AV_TIME_BASE * stream->rate_den / stream->rate_num; 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); break; } *pos_arg= nut->packet_start; assert(nut->packet_start == 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)) return AV_NOPTS_VALUE; url_fseek(bc, -8, SEEK_CUR); } } return AV_NOPTS_VALUE;}static int nut_read_seek(AVFormatContext *s, int stream_index, int64_t target_ts){ NUTContext *nut = s->priv_data; int64_t pos; int i; if(av_seek_frame_binary(s, stream_index, target_ts) < 0) return -1; nut->written_packet_size= -1; pos= url_ftell(&s->pb); for(i=0; i<s->nb_streams; i++) nut->stream[i].last_sync_pos= pos; return 0;}static int nut_read_close(AVFormatContext *s){ NUTContext *nut = s->priv_data; int i; for(i=0;i<s->nb_streams;i++) { av_freep(&s->streams[i]->codec.extradata); } av_freep(&nut->stream); return 0;}static AVInputFormat nut_iformat = { "nut", "nut format", sizeof(NUTContext), nut_probe, nut_read_header, nut_read_packet, nut_read_close, nut_read_seek, nut_read_timestamp, .extensions = "nut",};#ifdef CONFIG_ENCODERSstatic AVOutputFormat nut_oformat = { "nut", "nut format", "video/x-nut", "nut", sizeof(NUTContext),#ifdef CONFIG_VORBIS CODEC_ID_VORBIS,#elif defined(CONFIG_MP3LAME) CODEC_ID_MP3,#else CODEC_ID_MP2, /* AC3 needs liba52 decoder */#endif CODEC_ID_MPEG4, nut_write_header, nut_write_packet, nut_write_trailer,};#endif //CONFIG_ENCODERSint nut_init(void){ av_register_input_format(&nut_iformat);#ifdef CONFIG_ENCODERS av_register_output_format(&nut_oformat);#endif //CONFIG_ENCODERS return 0;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -