📄 nut.c
字号:
/* * "NUT" Container Format muxer and demuxer (DRAFT-200403??) * Copyright (c) 2003 Alex Beregszaszi * Copyright (c) 2004 Michael Niedermayer * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * NUT DRAFT can be found in MPlayer CVS at DOCS/tech/mpcf.txt * * AND http://people.fsn.hu/~alex/nut/ (TeX, pdf, ps, dvi, ..) * *//* * TODO: * - index writing * - index packet reading support*///#define DEBUG 1#include <limits.h>#include "avformat.h"#include "mpegaudio.h"#include "avi.h"#undef NDEBUG#include <assert.h>//#define TRACE//from /dev/random#define MAIN_STARTCODE (0x7A561F5F04ADULL + (((uint64_t)('N'<<8) + 'M')<<48)) #define STREAM_STARTCODE (0x11405BF2F9DBULL + (((uint64_t)('N'<<8) + 'S')<<48)) #define KEYFRAME_STARTCODE (0xE4ADEECA4569ULL + (((uint64_t)('N'<<8) + 'K')<<48)) #define INDEX_STARTCODE (0xDD672F23E64EULL + (((uint64_t)('N'<<8) + 'X')<<48)) #define INFO_STARTCODE (0xAB68B596BA78ULL + (((uint64_t)('N'<<8) + 'I')<<48)) #define ID_STRING "nut/multimedia container\0"#define MAX_DISTANCE (1024*16-1)#define MAX_SHORT_DISTANCE (1024*4-1)#define FLAG_DATA_SIZE 1#define FLAG_KEY_FRAME 2#define FLAG_INVALID 4typedef struct { uint8_t flags; uint8_t stream_id_plus1; uint16_t size_mul; uint16_t size_lsb; int16_t timestamp_delta; uint8_t reserved_count;} FrameCode;typedef struct { int last_key_frame; int msb_timestamp_shift; int rate_num; int rate_den; int64_t last_pts; int64_t last_sync_pos; ///<pos of last 1/2 type frame int decode_delay;} StreamContext;typedef struct { AVFormatContext *avf; int written_packet_size; 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]={ {NULL , NULL }, // end {NULL , NULL }, {NULL , "UTF8"}, {NULL , "v"}, {NULL , "s"}, {"StreamId" , "v"}, {"SegmentId" , "v"}, {"StartTimestamp" , "v"}, {"EndTimestamp" , "v"}, {"Author" , "UTF8"}, {"Title" , "UTF8"}, {"Description" , "UTF8"}, {"Copyright" , "UTF8"}, {"Encoder" , "UTF8"}, {"Keyword" , "UTF8"}, {"Cover" , "JPEG"}, {"Cover" , "PNG"},};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]; stream->last_key_frame= key_frame; nut->packet_start[ frame_type ]= frame_start; stream->last_pts= pts;}static void reset(AVFormatContext *s, int64_t global_ts){ NUTContext *nut = s->priv_data; int i; for(i=0; i<s->nb_streams; i++){ StreamContext *stream= &nut->stream[i]; stream->last_key_frame= 1; 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, 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 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++){ int start2= start + (end-start)*stream_id / s->nb_streams; int end2 = start + (end-start)*(stream_id+1) / s->nb_streams; AVCodecContext *codec = &s->streams[stream_id]->codec; int is_audio= codec->codec_type == CODEC_TYPE_AUDIO; int intra_only= /*codec->intra_only || */is_audio; int pred_count; for(key_frame=0; key_frame<2; key_frame++){ if(intra_only && keyframe_0_esc && key_frame==0) continue; { 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++; } } key_frame= intra_only;#if 1 if(is_audio){ int frame_bytes= codec->frame_size*(int64_t)codec->bit_rate / (8*codec->sample_rate); 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; ft->stream_id_plus1= stream_id + 1; ft->size_mul=frame_bytes + 2; ft->size_lsb=frame_bytes + pred; ft->timestamp_delta=pts; start2++; } } }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 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; 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]; } } } memmove(&nut->frame_code['N'+1], &nut->frame_code['N'], sizeof(FrameCode)*(255-'N')); nut->frame_code['N'].flags= FLAG_INVALID;}static uint64_t get_v(ByteIOContext *bc){ uint64_t val = 0; for(;;) { int tmp = get_byte(bc); if (tmp&0x80) val= (val<<7) + tmp - 0x80; else{//av_log(NULL, AV_LOG_DEBUG, "get_v()= %lld\n", (val<<7) + tmp); return (val<<7) + tmp; } } return -1;}static int get_str(ByteIOContext *bc, char *string, int maxlen){ int len= get_v(bc); if(len && maxlen) get_buffer(bc, string, FFMIN(len, maxlen)); while(len > maxlen){ get_byte(bc); len--; } if(maxlen) string[FFMIN(len, maxlen-1)]= 0; if(maxlen == len) return -1; else 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); if(i>8) return UINT64_MAX; while(i--) val = (val<<8) + get_byte(bc); //av_log(NULL, AV_LOG_DEBUG, "get_vb()= %lld\n", val); return val;}#ifdef TRACEstatic 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__)#endifstatic int get_packetheader(NUTContext *nut, ByteIOContext *bc, int calculate_checksum){ int64_t start, size; start= url_ftell(bc) - 8; init_checksum(bc, calculate_checksum ? update_adler32 : NULL, 0); size= get_v(bc); nut->packet_start[2] = start; nut->written_packet_size= size; return size;}static int check_checksum(ByteIOContext *bc){ unsigned long checksum= get_checksum(bc); return checksum != get_be32(bc);}/** * */static int get_length(uint64_t val){ int i; for (i=7; val>>i; i+=7); return i;}static uint64_t find_any_startcode(ByteIOContext *bc, int64_t pos){ uint64_t state=0; if(pos >= 0) url_fseek(bc, pos, SEEK_SET); //note, this may fail if the stream isnt seekable, but that shouldnt matter, as in this case we simply start where we are currently while(!url_feof(bc)){ state= (state<<8) | get_byte(bc); if((state>>56) != 'N') continue; switch(state){ case MAIN_STARTCODE: case STREAM_STARTCODE: case KEYFRAME_STARTCODE: case INFO_STARTCODE: case INDEX_STARTCODE: return state; } } return 0;}/** * find the given startcode. * @param code the startcode * @param pos the start position of the search, or -1 if the current position * @returns the position of the startcode or -1 if not found */static int64_t find_startcode(ByteIOContext *bc, uint64_t code, int64_t pos){ for(;;){ uint64_t startcode= find_any_startcode(bc, pos); if(startcode == code) return url_ftell(bc) - 8; else if(startcode == 0) return -1; pos=-1; }}#ifdef CONFIG_ENCODERSstatic 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); for (i-=7; i>0; i-=7){ put_byte(bc, 0x80 | (val>>i)); } put_byte(bc, val&0x7f);}/** * stores a string as vb. */static void put_str(ByteIOContext *bc, const char *string){ int len= strlen(string); put_v(bc, len); 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; for (i=8; val>>i; i+=8); put_v(bc, i>>3); for(i-=8; i>=0; i-=8) put_byte(bc, (val>>i)&0xFF);}#ifdef TRACEstatic 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__)#endifstatic int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum){ put_flush_packet(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) init_checksum(bc, update_adler32, 0); /* packet header */ put_v(bc, nut->written_packet_size); /* forward ptr */ return 0;}static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){ int64_t start= nut->packet_start[2]; int64_t cur= url_ftell(bc); int size= cur - start + additional_size; if(calculate_checksum)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -