X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Favidec.c;h=21d501902990dc9ef2c545b4485dee219351ebd7;hb=8ac17293d328b3642872445fc77e1f98eca90175;hp=2fede8452854ae9d1ff4ecef15c65d5e5d7645b3;hpb=30a43f2d09d4ddb7f6335dfd32796896e64b2655;p=ffmpeg diff --git a/libavformat/avidec.c b/libavformat/avidec.c index 2fede845285..21d50190299 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -19,6 +19,7 @@ #include "avformat.h" #include "avi.h" #include "dv.h" +#include "riff.h" #undef NDEBUG #include @@ -34,8 +35,7 @@ typedef struct AVIStream { int scale; int rate; - int sample_size; /* audio only data */ - int start; + int sample_size; /* size of one sample (or packet) (in the rate/scale sense) in bytes */ int64_t cum_len; /* temporary storage (used during seek) */ @@ -87,6 +87,7 @@ static int get_riff(AVIContext *avi, ByteIOContext *pb) } static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ + AVIContext *avi = s->priv_data; ByteIOContext *pb = &s->pb; int longs_pre_entry= get_le16(pb); int index_sub_type = get_byte(pb); @@ -98,9 +99,13 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ AVStream *st; AVIStream *ast; int i; + int64_t last_pos= -1; + int64_t filesize= url_fsize(&s->pb); -// av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%Ld\n", -// longs_pre_entry,index_type, entries_in_use, chunk_id, base); +#ifdef DEBUG_SEEK + av_log(s, AV_LOG_ERROR, "longs_pre_entry:%d index_type:%d entries_in_use:%d chunk_id:%X base:%16LX\n", + longs_pre_entry,index_type, entries_in_use, chunk_id, base); +#endif if(stream_id > s->nb_streams || stream_id < 0) return -1; @@ -117,6 +122,14 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ if(index_type>1) return -1; + if(filesize > 0 && base >= filesize){ + av_log(s, AV_LOG_ERROR, "ODML index invalid\n"); + if(base>>32 == (base & 0xFFFFFFFF) && (base & 0xFFFFFFFF) < filesize && filesize <= 0xFFFFFFFF) + base &= 0xFFFFFFFF; + else + return -1; + } + for(i=0; i= 0; len &= 0x7FFFFFFF; -//av_log(s, AV_LOG_ERROR, "pos:%Ld, len:%X\n", pos, len); - av_add_index_entry(st, pos, ast->cum_len, len, 0, key ? AVINDEX_KEYFRAME : 0); +#ifdef DEBUG_SEEK + av_log(s, AV_LOG_ERROR, "pos:%Ld, len:%X\n", pos, len); +#endif + if(last_pos == pos || pos == base - 8) + avi->non_interleaved= 1; + else + av_add_index_entry(st, pos, ast->cum_len, len, 0, key ? AVINDEX_KEYFRAME : 0); if(ast->sample_size) ast->cum_len += len / ast->sample_size; else ast->cum_len ++; + last_pos= pos; }else{ - int64_t offset= get_le64(pb); - int size = get_le32(pb); - int duration = get_le32(pb); - int64_t pos= url_ftell(pb); + int64_t offset, pos; + int duration; + offset = get_le64(pb); + get_le32(pb); /* size */ + duration = get_le32(pb); + pos = url_ftell(pb); url_fseek(pb, offset+8, SEEK_SET); read_braindead_odml_indx(s, frame_num); @@ -144,6 +165,42 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num){ url_fseek(pb, pos, SEEK_SET); } } + avi->index_loaded=1; + return 0; +} + +static void clean_index(AVFormatContext *s){ + int i; + int64_t j; + + for(i=0; inb_streams; i++){ + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + int n= st->nb_index_entries; + int max= ast->sample_size; + int64_t pos, size, ts; + + if(n != 1 || ast->sample_size==0) + continue; + + while(max < 1024) max+=max; + + pos= st->index_entries[0].pos; + size= st->index_entries[0].size; + ts= st->index_entries[0].timestamp; + + for(j=0; jsample_size, FFMIN(max, size-j), 0, AVINDEX_KEYFRAME); + } + } +} + +static int avi_read_tag(ByteIOContext *pb, char *buf, int maxlen, unsigned int size) +{ + offset_t i = url_ftell(pb); + size += (size & 1); + get_strz(pb, buf, maxlen); + url_fseek(pb, i+size, SEEK_SET); return 0; } @@ -156,7 +213,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) unsigned int size, nb_frames; int i, n; AVStream *st; - AVIStream *ast; + AVIStream *ast = NULL; int xan_video = 0; /* hack to support Xan A/V */ avi->stream_index= -1; @@ -203,7 +260,10 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) /* using frame_period is bad idea */ frame_period = get_le32(pb); bit_rate = get_le32(pb) * 8; - url_fskip(pb, 4 * 4); + get_le32(pb); + avi->non_interleaved |= get_le32(pb) & AVIF_MUSTUSEINDEX; + + url_fskip(pb, 2 * 4); n = get_le32(pb); for(i=0;i= s->nb_streams) { url_fskip(pb, size - 8); + /* ignore padding stream */ + if (tag1 == MKTAG('p', 'a', 'd', 's')) + stream_index--; break; } st = s->streams[stream_index]; @@ -279,7 +342,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) } av_set_pts_info(st, 64, ast->scale, ast->rate); - ast->start= get_le32(pb); /* start */ + ast->cum_len=get_le32(pb); /* start */ nb_frames = get_le32(pb); st->start_time = 0; @@ -310,6 +373,7 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1); goto fail; } + ast->frame_offset= ast->cum_len * FFMAX(ast->sample_size, 1); url_fskip(pb, size - 12 * 4); break; case MKTAG('s', 't', 'r', 'f'): @@ -369,6 +433,8 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) break; case CODEC_TYPE_AUDIO: get_wav_header(pb, st->codec, size); + if(ast->sample_size && st->codec->block_align && ast->sample_size % st->codec->block_align) + av_log(s, AV_LOG_DEBUG, "invalid sample size or block align detected\n"); if (size%2) /* 2-aligned (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ url_fskip(pb, 1); /* special case time: To support Xan DPCM, hardcode @@ -390,10 +456,26 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) break; case MKTAG('i', 'n', 'd', 'x'): i= url_ftell(pb); - read_braindead_odml_indx(s, 0); - avi->index_loaded=1; + if(!url_is_streamed(pb)){ + read_braindead_odml_indx(s, 0); + } url_fseek(pb, i+size, SEEK_SET); break; + case MKTAG('I', 'N', 'A', 'M'): + avi_read_tag(pb, s->title, sizeof(s->title), size); + break; + case MKTAG('I', 'A', 'R', 'T'): + avi_read_tag(pb, s->author, sizeof(s->author), size); + break; + case MKTAG('I', 'C', 'O', 'P'): + avi_read_tag(pb, s->copyright, sizeof(s->copyright), size); + break; + case MKTAG('I', 'C', 'M', 'T'): + avi_read_tag(pb, s->comment, sizeof(s->comment), size); + break; + case MKTAG('I', 'G', 'N', 'R'): + avi_read_tag(pb, s->genre, sizeof(s->genre), size); + break; default: /* skip tag */ size += (size & 1); @@ -412,10 +494,12 @@ static int avi_read_header(AVFormatContext *s, AVFormatParameters *ap) return -1; } - if(!avi->index_loaded) + if(!avi->index_loaded && !url_is_streamed(pb)) avi_load_index(s); avi->index_loaded = 1; avi->non_interleaved |= guess_ni_flag(s); + if(avi->non_interleaved) + clean_index(s); return 0; } @@ -467,14 +551,16 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) // av_log(NULL, AV_LOG_DEBUG, "%d\n", i); if(i>=0){ int64_t pos= best_st->index_entries[i].pos; - pos += avi->movi_list + best_ast->packet_size - best_ast->remaining; - url_fseek(&s->pb, pos, SEEK_SET); + pos += best_ast->packet_size - best_ast->remaining; + url_fseek(&s->pb, pos + 8, SEEK_SET); // av_log(NULL, AV_LOG_DEBUG, "pos=%Ld\n", pos); - if(best_ast->remaining) - avi->stream_index= best_stream_index; - else - avi->stream_index= -1; + assert(best_ast->remaining <= best_ast->packet_size); + + avi->stream_index= best_stream_index; + if(!best_ast->remaining) + best_ast->packet_size= + best_ast->remaining= best_st->index_entries[i].size; } } @@ -484,7 +570,7 @@ resync: AVIStream *ast= st->priv_data; int size; - if(ast->sample_size == 0) + if(ast->sample_size <= 1) // minorityreport.AVI block_align=1024 sample_size=1 IMA-ADPCM size= INT_MAX; else if(ast->sample_size < 32) size= 64*ast->sample_size; @@ -507,7 +593,7 @@ resync: // pkt->dts += ast->start; if(ast->sample_size) pkt->dts /= ast->sample_size; -//av_log(NULL, AV_LOG_DEBUG, "dts:%Ld offset:%d %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, n, size); +//av_log(NULL, AV_LOG_DEBUG, "dts:%Ld offset:%Ld %d/%d smpl_siz:%d base:%d st:%d size:%d\n", pkt->dts, ast->frame_offset, ast->scale, ast->rate, ast->sample_size, AV_TIME_BASE, avi->stream_index, size); pkt->stream_index = avi->stream_index; if (st->codec->codec_type == CODEC_TYPE_VIDEO) { @@ -689,6 +775,7 @@ static int avi_read_idx1(AVFormatContext *s, int size) #endif if(i==0 && pos > avi->movi_list) avi->movi_list= 0; //FIXME better check + pos += avi->movi_list; index = ((tag & 0xff) - '0') * 10; index += ((tag >> 8) & 0xff) - '0'; @@ -698,7 +785,7 @@ static int avi_read_idx1(AVFormatContext *s, int size) ast = st->priv_data; #if defined(DEBUG_SEEK) - av_log(NULL, AV_LOG_DEBUG, "%d cum_len=%d\n", len, ast->cum_len); + av_log(NULL, AV_LOG_DEBUG, "%d cum_len=%Ld\n", len, ast->cum_len); #endif if(last_pos == pos) avi->non_interleaved= 1; @@ -811,7 +898,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp if (st2->nb_index_entries <= 0) continue; -// assert(st2->codec.block_align); +// assert(st2->codec->block_align); assert(st2->time_base.den == ast2->rate); assert(st2->time_base.num == ast2->scale); index = av_index_search_timestamp( @@ -838,7 +925,6 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp if (avi->dv_demux) dv_flush_audio_packets(avi->dv_demux); /* do the seek */ - pos += avi->movi_list; url_fseek(&s->pb, pos, SEEK_SET); avi->stream_index= -1; return 0; @@ -853,7 +939,6 @@ static int avi_read_close(AVFormatContext *s) AVStream *st = s->streams[i]; AVIStream *ast = st->priv_data; av_free(ast); - av_free(st->codec->extradata); av_free(st->codec->palctrl); } @@ -877,7 +962,7 @@ static int avi_probe(AVProbeData *p) return 0; } -static AVInputFormat avi_iformat = { +AVInputFormat avi_demuxer = { "avi", "avi format", sizeof(AVIContext), @@ -887,9 +972,3 @@ static AVInputFormat avi_iformat = { avi_read_close, avi_read_seek, }; - -int avidec_init(void) -{ - av_register_input_format(&avi_iformat); - return 0; -}