diff --git a/libavformat/avio.h b/libavformat/avio.h index f668c0ceb0..53ed22a3a1 100644 --- a/libavformat/avio.h +++ b/libavformat/avio.h @@ -78,6 +78,9 @@ typedef struct { int write_flag; /* true if open for writing */ int is_streamed; int max_packet_size; + unsigned long checksum; + unsigned char *checksum_ptr; + unsigned long (*update_checksum)(unsigned long checksum, const uint8_t *buf, unsigned int size); } ByteIOContext; int init_put_byte(ByteIOContext *s, @@ -150,6 +153,10 @@ int url_open_dyn_buf(ByteIOContext *s); int url_open_dyn_packet_buf(ByteIOContext *s, int max_packet_size); int url_close_dyn_buf(ByteIOContext *s, uint8_t **pbuffer); +unsigned long get_checksum(ByteIOContext *s); +void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum); +unsigned long update_adler32(unsigned long adler, const uint8_t *buf, unsigned int len); + /* file.c */ extern URLProtocol file_protocol; extern URLProtocol pipe_protocol; diff --git a/libavformat/aviobuf.c b/libavformat/aviobuf.c index 75f97a5b40..ebc2f74910 100644 --- a/libavformat/aviobuf.c +++ b/libavformat/aviobuf.c @@ -48,6 +48,8 @@ int init_put_byte(ByteIOContext *s, s->eof_reached = 0; s->is_streamed = 0; s->max_packet_size = 0; + s->checksum_ptr= NULL; + s->update_checksum= NULL; return 0; } @@ -58,6 +60,10 @@ static void flush_buffer(ByteIOContext *s) if (s->buf_ptr > s->buffer) { if (s->write_packet) s->write_packet(s->opaque, s->buffer, s->buf_ptr - s->buffer); + if(s->checksum_ptr){ + s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr); + s->checksum_ptr= s->buffer; + } s->pos += s->buf_ptr - s->buffer; } s->buf_ptr = s->buffer; @@ -243,6 +249,12 @@ static void fill_buffer(ByteIOContext *s) /* no need to do anything if EOF already reached */ if (s->eof_reached) return; + + if(s->checksum_ptr){ + s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_end - s->checksum_ptr); + s->checksum_ptr= s->buffer; + } + len = s->read_packet(s->opaque, s->buffer, s->buffer_size); if (len <= 0) { /* do not modify buffer if EOF reached so that a seek back can @@ -255,6 +267,18 @@ static void fill_buffer(ByteIOContext *s) } } +unsigned long get_checksum(ByteIOContext *s){ + s->checksum= s->update_checksum(s->checksum, s->checksum_ptr, s->buf_ptr - s->checksum_ptr); + s->checksum_ptr= NULL; + return s->checksum; +} + +void init_checksum(ByteIOContext *s, unsigned long (*update_checksum)(unsigned long c, const uint8_t *p, unsigned int len), unsigned long checksum){ + s->update_checksum= update_checksum; + s->checksum= s->update_checksum(checksum, NULL, 0); + s->checksum_ptr= s->buf_ptr; +} + /* NOTE: return 0 if EOF, so you cannot use it if EOF handling is necessary */ /* XXX: put an inline version */ diff --git a/libavformat/crc.c b/libavformat/crc.c index c9f8360a51..1b8d6a4df3 100644 --- a/libavformat/crc.c +++ b/libavformat/crc.c @@ -33,7 +33,7 @@ #define DO8(buf) DO4(buf); DO4(buf); #define DO16(buf) DO8(buf); DO8(buf); -static uint32_t adler32(uint32_t adler, const uint8_t *buf, unsigned int len) +unsigned long update_adler32(unsigned long adler, const uint8_t *buf, unsigned int len) { unsigned long s1 = adler & 0xffff; unsigned long s2 = (adler >> 16) & 0xffff; @@ -66,7 +66,7 @@ static int crc_write_header(struct AVFormatContext *s) CRCState *crc = s->priv_data; /* init CRC */ - crc->crcval = adler32(0, NULL, 0); + crc->crcval = update_adler32(0, NULL, 0); return 0; } @@ -76,7 +76,7 @@ static int crc_write_packet(struct AVFormatContext *s, const uint8_t *buf, int size, int64_t pts) { CRCState *crc = s->priv_data; - crc->crcval = adler32(crc->crcval, buf, size); + crc->crcval = update_adler32(crc->crcval, buf, size); return 0; } diff --git a/libavformat/nut.c b/libavformat/nut.c index a84d00cbcc..efe4debd9b 100644 --- a/libavformat/nut.c +++ b/libavformat/nut.c @@ -25,7 +25,6 @@ /* * TODO: - * - checksumming * - seeking * - index writing * - index packet reading support @@ -284,7 +283,7 @@ static int get_str(ByteIOContext *bc, char *string, int maxlen){ return 0; } -static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int prefix_length) +static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int prefix_length, int calculate_checksum) { int64_t start, size, last_size; start= url_ftell(bc) - prefix_length; @@ -293,6 +292,9 @@ static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int prefix_lengt av_log(nut->avf, AV_LOG_ERROR, "get_packetheader called at weird position\n"); return -1; } + + if(calculate_checksum) + init_checksum(bc, update_adler32, 0); size= get_v(bc); last_size= get_v(bc); @@ -308,6 +310,11 @@ static int get_packetheader(NUTContext *nut, ByteIOContext *bc, int prefix_lengt return size; } +static int check_checksum(ByteIOContext *bc){ + unsigned long checksum= get_checksum(bc); + return checksum != get_be32(bc); +} + /** * */ @@ -352,13 +359,16 @@ static int put_str(ByteIOContext *bc, const char *string){ return 0; } -static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size) +static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size, int calculate_checksum) { put_flush_packet(bc); nut->last_packet_start= nut->packet_start; nut->packet_start+= nut->written_packet_size; nut->packet_size_pos = url_ftell(bc); 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 */ @@ -367,11 +377,14 @@ static int put_packetheader(NUTContext *nut, ByteIOContext *bc, int max_size) return 0; } -static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size){ +static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additional_size, int calculate_checksum){ int64_t start= nut->packet_start; int64_t cur= url_ftell(bc); int size= cur - start + additional_size; + if(calculate_checksum) + size += 4; + if(size != nut->written_packet_size){ int i; @@ -384,6 +397,9 @@ static int update_packetheader(NUTContext *nut, ByteIOContext *bc, int additiona url_fseek(bc, cur, SEEK_SET); nut->written_packet_size= size; //FIXME may fail if multiple updates with differing sizes, as get_length may differ + + if(calculate_checksum) + put_be32(bc, get_checksum(bc)); } return 0; @@ -405,10 +421,10 @@ static int nut_write_header(AVFormatContext *s) /* main header */ put_be64(bc, MAIN_STARTCODE); - put_packetheader(nut, bc, 120+5*256); + put_packetheader(nut, bc, 120+5*256, 1); put_v(bc, 1); /* version */ put_v(bc, s->nb_streams); - put_v(bc, 3); /* checksum threshold */ + put_v(bc, 3); build_frame_code(s); assert(nut->frame_code['N'].flags == 1); @@ -435,9 +451,7 @@ static int nut_write_header(AVFormatContext *s) put_v(bc, j); } - put_be32(bc, 0); /* FIXME: checksum */ - - update_packetheader(nut, bc, 0); + update_packetheader(nut, bc, 0, 1); /* stream headers */ for (i = 0; i < s->nb_streams; i++) @@ -447,7 +461,7 @@ static int nut_write_header(AVFormatContext *s) codec = &s->streams[i]->codec; put_be64(bc, STREAM_STARTCODE); - put_packetheader(nut, bc, 120 + codec->extradata_size); + put_packetheader(nut, bc, 120 + codec->extradata_size, 1); put_v(bc, i /*s->streams[i]->index*/); put_v(bc, (codec->codec_type == CODEC_TYPE_AUDIO) ? 32 : 0); if (codec->codec_tag) @@ -520,14 +534,13 @@ static int nut_write_header(AVFormatContext *s) default: break; } - put_be32(bc, 0); /* FIXME: checksum */ - update_packetheader(nut, bc, 0); + update_packetheader(nut, bc, 0, 1); } /* info header */ put_be64(bc, INFO_STARTCODE); put_packetheader(nut, bc, 30+strlen(s->author)+strlen(s->title)+ - strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT)); + strlen(s->comment)+strlen(s->copyright)+strlen(LIBAVFORMAT_IDENT), 1); if (s->author[0]) { put_v(bc, 9); /* type */ @@ -553,9 +566,7 @@ static int nut_write_header(AVFormatContext *s) put_str(bc, LIBAVFORMAT_IDENT); put_v(bc, 0); /* eof info */ - - put_be32(bc, 0); /* FIXME: checksum */ - update_packetheader(nut, bc, 0); + update_packetheader(nut, bc, 0, 1); put_flush_packet(bc); @@ -594,7 +605,7 @@ static int nut_write_packet(AVFormatContext *s, int stream_index, } if(frame_type>0){ - update_packetheader(nut, bc, 0); + update_packetheader(nut, bc, 0, 0); reset(s); full_pts=1; } @@ -684,7 +695,7 @@ static int nut_write_packet(AVFormatContext *s, int stream_index, put_byte(bc, frame_code); if(frame_type>0) - put_packetheader(nut, bc, FFMAX(size+20, MAX_TYPE1_DISTANCE)); + put_packetheader(nut, bc, FFMAX(size+20, MAX_TYPE1_DISTANCE), 0); if(nut->frame_code[frame_code].stream_id_plus1 == 0) put_v(bc, stream_index); if (flags & FLAG_PTS){ @@ -697,7 +708,7 @@ static int nut_write_packet(AVFormatContext *s, int stream_index, put_v(bc, size / size_mul); if(size > MAX_TYPE1_DISTANCE){ assert(frame_type > 0); - update_packetheader(nut, bc, size); + update_packetheader(nut, bc, size, 0); } put_buffer(bc, buf, size); @@ -712,7 +723,7 @@ static int nut_write_trailer(AVFormatContext *s) NUTContext *nut = s->priv_data; ByteIOContext *bc = &s->pb; - update_packetheader(nut, bc, 0); + update_packetheader(nut, bc, 0, 0); #if 0 int i; @@ -722,11 +733,10 @@ static int nut_write_trailer(AVFormatContext *s) for (i = 0; s->nb_streams; i++) { put_be64(bc, INDEX_STARTCODE); - put_packetheader(nut, bc, 64); + put_packetheader(nut, bc, 64, 1); put_v(bc, s->streams[i]->id); put_v(bc, ...); - put_be32(bc, 0); /* FIXME: checksum */ - update_packetheader(nut, bc, 0); + update_packetheader(nut, bc, 0, 1); } #endif @@ -768,7 +778,7 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) tmp = get_be64(bc); if (tmp != MAIN_STARTCODE) av_log(s, AV_LOG_ERROR, "damaged? startcode!=1 (%Ld)\n", tmp); - get_packetheader(nut, bc, 8); + get_packetheader(nut, bc, 8, 1); tmp = get_v(bc); if (tmp != 1) @@ -821,7 +831,10 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) return -1; } - get_be32(bc); /* checkusm */ + if(check_checksum(bc)){ + av_log(s, AV_LOG_ERROR, "Main header checksum missmatch\n"); + return -1; + } s->bit_rate = 0; @@ -836,7 +849,7 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) tmp = get_be64(bc); if (tmp != STREAM_STARTCODE) av_log(s, AV_LOG_ERROR, "damaged? startcode!=1 (%Ld)\n", tmp); - get_packetheader(nut, bc, 8); + get_packetheader(nut, bc, 8, 1); st = av_new_stream(s, get_v(bc)); if (!st) return AVERROR_NOMEM; @@ -895,14 +908,17 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) st->codec.sample_rate = (get_v(bc) * nom) / denom; st->codec.channels = get_v(bc); } - get_be32(bc); /* checksum */ + if(check_checksum(bc)){ + av_log(s, AV_LOG_ERROR, "Stream header %d checksum missmatch\n", cur_stream); + return -1; + } nut->stream[cur_stream].rate_num= nom; nut->stream[cur_stream].rate_den= denom; } tmp = get_be64(bc); if (tmp == INFO_STARTCODE){ - get_packetheader(nut, bc, 8); + get_packetheader(nut, bc, 8, 1); for(;;){ int id= get_v(bc); @@ -943,7 +959,9 @@ static int nut_read_header(AVFormatContext *s, AVFormatParameters *ap) get_str(bc, NULL, 0); } } - get_be32(bc); /* checksum */ + if(check_checksum(bc)){ + av_log(s, AV_LOG_ERROR, "Info header checksum missmatch\n"); + } }else url_fseek(bc, -8, SEEK_CUR); @@ -986,9 +1004,9 @@ static int nut_read_packet(AVFormatContext *s, AVPacket *pkt) if(flags & FLAG_FRAME_TYPE){ reset(s); if(frame_type==2){ - get_packetheader(nut, bc, 8+1); + get_packetheader(nut, bc, 8+1, 0); }else{ - get_packetheader(nut, bc, 1); + get_packetheader(nut, bc, 1, 0); frame_type= 1; } }