X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Favidec.c;h=f5705e54364e039f67946a84584eb4d2513d2362;hb=79fdbfdb3e50f3f906903e027714ee04c1a00e89;hp=c71d545d4677d64f4885004cba1fcca53a4a68a8;hpb=ce9bba5340a5fb6f38974a19af019dd6aa2da035;p=ffmpeg diff --git a/libavformat/avidec.c b/libavformat/avidec.c index c71d545d467..f5705e54364 100644 --- a/libavformat/avidec.c +++ b/libavformat/avidec.c @@ -19,6 +19,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#include + #include "libavutil/avstring.h" #include "libavutil/bswap.h" #include "libavutil/dict.h" @@ -29,6 +31,7 @@ #include "avi.h" #include "dv.h" #include "internal.h" +#include "isom.h" #include "riff.h" #undef NDEBUG @@ -40,6 +43,7 @@ typedef struct AVIStream { int remaining; int packet_size; + uint32_t handler; uint32_t scale; uint32_t rate; int sample_size; /* size of one sample (or packet) @@ -58,7 +62,7 @@ typedef struct AVIStream { uint8_t *sub_buffer; } AVIStream; -typedef struct { +typedef struct AVIContext { int64_t riff_end; int64_t movi_end; int64_t fsize; @@ -91,7 +95,7 @@ static int avi_load_index(AVFormatContext *s); static int guess_ni_flag(AVFormatContext *s); #define print_tag(str, tag, size) \ - av_dlog(NULL, "%s: tag=%c%c%c%c size=0x%x\n", \ + av_log(NULL, AV_LOG_TRACE, "%s: tag=%c%c%c%c size=0x%x\n", \ str, tag & 0xff, \ (tag >> 8) & 0xff, \ (tag >> 16) & 0xff, \ @@ -149,9 +153,9 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) AVIStream *ast; int i; int64_t last_pos = -1; - int64_t filesize = avio_size(s->pb); + int64_t filesize = avi->fsize; - av_dlog(s, + av_log(s, AV_LOG_TRACE, "longs_pre_entry:%d index_type:%d entries_in_use:%d " "chunk_id:%X base:%16"PRIX64"\n", longs_pre_entry, @@ -192,7 +196,7 @@ static int read_braindead_odml_indx(AVFormatContext *s, int frame_num) int key = len >= 0; len &= 0x7FFFFFFF; - av_dlog(s, "pos:%"PRId64", len:%X\n", pos, len); + av_log(s, AV_LOG_TRACE, "pos:%"PRId64", len:%X\n", pos, len); if (pb->eof_reached) return AVERROR_INVALIDDATA; @@ -363,6 +367,7 @@ static int avi_read_header(AVFormatContext *s) int avih_width = 0, avih_height = 0; int amv_file_format = 0; uint64_t list_end = 0; + int64_t pos; int ret; avi->stream_index = -1; @@ -372,7 +377,7 @@ static int avi_read_header(AVFormatContext *s) return ret; avi->fsize = avio_size(pb); - if (avi->fsize <= 0) + if (avi->fsize <= 0 || avi->fsize < avi->riff_end) avi->fsize = avi->riff_end == 8 ? INT64_MAX : avi->riff_end; /* first list tag */ @@ -400,8 +405,8 @@ static int avi_read_header(AVFormatContext *s) if (size) avi->movi_end = avi->movi_list + size + (size & 1); else - avi->movi_end = avio_size(pb); - av_dlog(NULL, "movi end=%"PRIx64"\n", avi->movi_end); + avi->movi_end = avi->fsize; + av_log(NULL, AV_LOG_TRACE, "movi end=%"PRIx64"\n", avi->movi_end); goto end_of_header; } else if (tag1 == MKTAG('I', 'N', 'F', 'O')) ff_read_riff_info(s, size - 4); @@ -482,8 +487,8 @@ static int avi_read_header(AVFormatContext *s) goto fail; ast = s->streams[0]->priv_data; - av_freep(&s->streams[0]->codec->extradata); - av_freep(&s->streams[0]->codec); + av_freep(&s->streams[0]->codecpar->extradata); + av_freep(&s->streams[0]->codecpar); av_freep(&s->streams[0]->info); av_freep(&s->streams[0]); s->nb_streams = 0; @@ -513,7 +518,7 @@ static int avi_read_header(AVFormatContext *s) } assert(stream_index < s->nb_streams); - st->codec->stream_codec_tag = handler; + ast->handler = handler; avio_rl32(pb); /* flags */ avio_rl16(pb); /* priority */ @@ -523,7 +528,7 @@ static int avi_read_header(AVFormatContext *s) ast->rate = avio_rl32(pb); if (!(ast->scale && ast->rate)) { av_log(s, AV_LOG_WARNING, - "scale/rate is %u/%u which is invalid. " + "scale/rate is %"PRIu32"/%"PRIu32" which is invalid. " "(This file has been generated by broken software.)\n", ast->scale, ast->rate); @@ -545,7 +550,7 @@ static int avi_read_header(AVFormatContext *s) avio_rl32(pb); /* quality */ ast->sample_size = avio_rl32(pb); /* sample ssize */ ast->cum_len *= FFMAX(1, ast->sample_size); - av_dlog(s, "%"PRIu32" %"PRIu32" %d\n", + av_log(s, AV_LOG_TRACE, "%"PRIu32" %"PRIu32" %d\n", ast->rate, ast->scale, ast->sample_size); switch (tag1) { @@ -567,6 +572,23 @@ static int avi_read_header(AVFormatContext *s) av_log(s, AV_LOG_ERROR, "unknown stream type %X\n", tag1); goto fail; } + + if (ast->sample_size < 0) { + if (s->error_recognition & AV_EF_EXPLODE) { + av_log(s, AV_LOG_ERROR, + "Invalid sample_size %d at stream %d\n", + ast->sample_size, + stream_index); + goto fail; + } + av_log(s, AV_LOG_WARNING, + "Invalid sample_size %d at stream %d " + "setting it to 0\n", + ast->sample_size, + stream_index); + ast->sample_size = 0; + } + if (ast->sample_size == 0) st->duration = st->nb_frames; ast->frame_offset = ast->cum_len; @@ -584,10 +606,10 @@ static int avi_read_header(AVFormatContext *s) switch (codec_type) { case AVMEDIA_TYPE_VIDEO: if (amv_file_format) { - st->codec->width = avih_width; - st->codec->height = avih_height; - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_id = AV_CODEC_ID_AMV; + st->codecpar->width = avih_width; + st->codecpar->height = avih_height; + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_id = AV_CODEC_ID_AMV; avio_skip(pb, size); break; } @@ -595,41 +617,41 @@ static int avi_read_header(AVFormatContext *s) if (tag1 == MKTAG('D', 'X', 'S', 'B') || tag1 == MKTAG('D', 'X', 'S', 'A')) { - st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - st->codec->codec_tag = tag1; - st->codec->codec_id = AV_CODEC_ID_XSUB; + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_tag = tag1; + st->codecpar->codec_id = AV_CODEC_ID_XSUB; break; } if (size > 10 * 4 && size < (1 << 30)) { - st->codec->extradata_size = size - 10 * 4; - st->codec->extradata = av_malloc(st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { - st->codec->extradata_size = 0; + st->codecpar->extradata_size = size - 10 * 4; + st->codecpar->extradata = av_malloc(st->codecpar->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE); + if (!st->codecpar->extradata) { + st->codecpar->extradata_size = 0; return AVERROR(ENOMEM); } avio_read(pb, - st->codec->extradata, - st->codec->extradata_size); + st->codecpar->extradata, + st->codecpar->extradata_size); } // FIXME: check if the encoder really did this correctly - if (st->codec->extradata_size & 1) + if (st->codecpar->extradata_size & 1) avio_r8(pb); /* Extract palette from extradata if bpp <= 8. * This code assumes that extradata contains only palette. * This is true for all paletted codecs implemented in * Libav. */ - if (st->codec->extradata_size && - (st->codec->bits_per_coded_sample <= 8)) { - int pal_size = (1 << st->codec->bits_per_coded_sample) << 2; + if (st->codecpar->extradata_size && + (st->codecpar->bits_per_coded_sample <= 8)) { + int pal_size = (1 << st->codecpar->bits_per_coded_sample) << 2; const uint8_t *pal_src; - pal_size = FFMIN(pal_size, st->codec->extradata_size); - pal_src = st->codec->extradata + - st->codec->extradata_size - pal_size; + pal_size = FFMIN(pal_size, st->codecpar->extradata_size); + pal_src = st->codecpar->extradata + + st->codecpar->extradata_size - pal_size; #if HAVE_BIGENDIAN for (i = 0; i < pal_size / 4; i++) ast->pal[i] = av_bswap32(((uint32_t *)pal_src)[i]); @@ -641,48 +663,64 @@ static int avi_read_header(AVFormatContext *s) print_tag("video", tag1, 0); - st->codec->codec_type = AVMEDIA_TYPE_VIDEO; - st->codec->codec_tag = tag1; - st->codec->codec_id = ff_codec_get_id(ff_codec_bmp_tags, + st->codecpar->codec_type = AVMEDIA_TYPE_VIDEO; + st->codecpar->codec_tag = tag1; + st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag1); + /* If codec is not found yet, try with the mov tags. */ + if (!st->codecpar->codec_id) { + char tag_buf[32]; + av_get_codec_tag_string(tag_buf, sizeof(tag_buf), tag1); + st->codecpar->codec_id = + ff_codec_get_id(ff_codec_movvideo_tags, tag1); + if (st->codecpar->codec_id) + av_log(s, AV_LOG_WARNING, + "mov tag found in avi (fourcc %s)\n", + tag_buf); + } /* This is needed to get the pict type which is necessary * for generating correct pts. */ st->need_parsing = AVSTREAM_PARSE_HEADERS; + + if (st->codecpar->codec_id == AV_CODEC_ID_MPEG4 && + ast->handler == MKTAG('X', 'V', 'I', 'D')) + st->codecpar->codec_tag = MKTAG('X', 'V', 'I', 'D'); + // Support "Resolution 1:1" for Avid AVI Codec if (tag1 == MKTAG('A', 'V', 'R', 'n') && - st->codec->extradata_size >= 31 && - !memcmp(&st->codec->extradata[28], "1:1", 3)) - st->codec->codec_id = AV_CODEC_ID_RAWVIDEO; - - if (st->codec->codec_tag == 0 && st->codec->height > 0 && - st->codec->extradata_size < 1U << 30) { - st->codec->extradata_size += 9; - if ((ret = av_reallocp(&st->codec->extradata, - st->codec->extradata_size + - FF_INPUT_BUFFER_PADDING_SIZE)) < 0) { - st->codec->extradata_size = 0; + st->codecpar->extradata_size >= 31 && + !memcmp(&st->codecpar->extradata[28], "1:1", 3)) + st->codecpar->codec_id = AV_CODEC_ID_RAWVIDEO; + + if (st->codecpar->codec_tag == 0 && st->codecpar->height > 0 && + st->codecpar->extradata_size < 1U << 30) { + st->codecpar->extradata_size += 9; + if ((ret = av_reallocp(&st->codecpar->extradata, + st->codecpar->extradata_size + + AV_INPUT_BUFFER_PADDING_SIZE)) < 0) { + st->codecpar->extradata_size = 0; return ret; } else - memcpy(st->codec->extradata + st->codec->extradata_size - 9, + memcpy(st->codecpar->extradata + st->codecpar->extradata_size - 9, "BottomUp", 9); } - st->codec->height = FFABS(st->codec->height); + st->codecpar->height = FFABS(st->codecpar->height); // avio_skip(pb, size - 5 * 4); break; case AVMEDIA_TYPE_AUDIO: - ret = ff_get_wav_header(pb, st->codec, size); + ret = ff_get_wav_header(s, pb, st->codecpar, size); if (ret < 0) return ret; - ast->dshow_block_align = st->codec->block_align; - if (ast->sample_size && st->codec->block_align && - ast->sample_size != st->codec->block_align) { + ast->dshow_block_align = st->codecpar->block_align; + if (ast->sample_size && st->codecpar->block_align && + ast->sample_size != st->codecpar->block_align) { av_log(s, AV_LOG_WARNING, "sample size (%d) != block align (%d)\n", ast->sample_size, - st->codec->block_align); - ast->sample_size = st->codec->block_align; + st->codecpar->block_align); + ast->sample_size = st->codecpar->block_align; } /* 2-aligned * (fix for Stargate SG-1 - 3x18 - Shades of Grey.avi) */ @@ -694,40 +732,40 @@ static int avi_read_header(AVFormatContext *s) /* ADTS header is in extradata, AAC without header must be * stored as exact frames. Parser not needed and it will * fail. */ - if (st->codec->codec_id == AV_CODEC_ID_AAC && - st->codec->extradata_size) + if (st->codecpar->codec_id == AV_CODEC_ID_AAC && + st->codecpar->extradata_size) st->need_parsing = AVSTREAM_PARSE_NONE; /* AVI files with Xan DPCM audio (wrongly) declare PCM * audio in the header but have Axan as stream_code_tag. */ - if (st->codec->stream_codec_tag == AV_RL32("Axan")) { - st->codec->codec_id = AV_CODEC_ID_XAN_DPCM; - st->codec->codec_tag = 0; + if (ast->handler == AV_RL32("Axan")) { + st->codecpar->codec_id = AV_CODEC_ID_XAN_DPCM; + st->codecpar->codec_tag = 0; } if (amv_file_format) { - st->codec->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV; + st->codecpar->codec_id = AV_CODEC_ID_ADPCM_IMA_AMV; ast->dshow_block_align = 0; } break; case AVMEDIA_TYPE_SUBTITLE: - st->codec->codec_type = AVMEDIA_TYPE_SUBTITLE; - st->codec->codec_id = AV_CODEC_ID_PROBE; + st->codecpar->codec_type = AVMEDIA_TYPE_SUBTITLE; + st->codecpar->codec_id = AV_CODEC_ID_PROBE; break; default: - st->codec->codec_type = AVMEDIA_TYPE_DATA; - st->codec->codec_id = AV_CODEC_ID_NONE; - st->codec->codec_tag = 0; + st->codecpar->codec_type = AVMEDIA_TYPE_DATA; + st->codecpar->codec_id = AV_CODEC_ID_NONE; + st->codecpar->codec_tag = 0; avio_skip(pb, size); break; } } break; case MKTAG('i', 'n', 'd', 'x'): - i = avio_tell(pb); + pos = avio_tell(pb); if (pb->seekable && !(s->flags & AVFMT_FLAG_IGNIDX) && read_braindead_odml_indx(s, 0) < 0 && (s->error_recognition & AV_EF_EXPLODE)) goto fail; - avio_seek(pb, i + size, SEEK_SET); + avio_seek(pb, pos + size, SEEK_SET); break; case MKTAG('v', 'p', 'r', 'p'): if (stream_index < (unsigned)s->nb_streams && size > 9 * 4) { @@ -749,7 +787,7 @@ static int avi_read_header(AVFormatContext *s) if (active_aspect.num && active_aspect.den && active.num && active.den) { st->sample_aspect_ratio = av_div_q(active_aspect, active); - av_dlog(s, "vprp %d/%d %d/%d\n", + av_log(s, AV_LOG_TRACE, "vprp %d/%d %d/%d\n", active_aspect.num, active_aspect.den, active.num, active.den); } @@ -772,7 +810,7 @@ static int avi_read_header(AVFormatContext *s) if (s->error_recognition & AV_EF_EXPLODE) goto fail; avi->movi_list = avio_tell(pb) - 4; - avi->movi_end = avio_size(pb); + avi->movi_end = avi->fsize; goto end_of_header; } /* skip tag */ @@ -793,7 +831,11 @@ fail: if (!avi->index_loaded && pb->seekable) avi_load_index(s); avi->index_loaded = 1; - avi->non_interleaved |= guess_ni_flag(s); + + if ((ret = guess_ni_flag(s)) < 0) + return ret; + + avi->non_interleaved |= ret; for (i = 0; i < s->nb_streams; i++) { AVStream *st = s->streams[i]; if (st->nb_index_entries) @@ -853,8 +895,7 @@ static int read_gab2_sub(AVStream *st, AVPacket *pkt) ast->sub_ctx->pb = pb; if (!avformat_open_input(&ast->sub_ctx, "", sub_demuxer, NULL)) { ff_read_packet(ast->sub_ctx, &ast->sub_pkt); - *st->codec = *ast->sub_ctx->streams[0]->codec; - ast->sub_ctx->streams[0]->codec->extradata = NULL; + avcodec_parameters_copy(st->codecpar, ast->sub_ctx->streams[0]->codecpar); time_base = ast->sub_ctx->streams[0]->time_base; avpriv_set_pts_info(st, 64, time_base.num, time_base.den); } @@ -933,7 +974,7 @@ start_sync: size = d[4] + (d[5] << 8) + (d[6] << 16) + (d[7] << 24); n = get_stream_idx(d + 2); - av_dlog(s, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n", + av_log(s, AV_LOG_TRACE, "%X %X %X %X %X %X %X %X %"PRId64" %u %d\n", d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], i, size, n); if (i + (uint64_t)size > avi->fsize || d[0] > 127) continue; @@ -953,7 +994,7 @@ start_sync: goto start_sync; } - n = avi->dv_demux ? 0 : get_stream_idx(d); + n = get_stream_idx(d); if (!((i - avi->last_pkt_pos) & 1) && get_stream_idx(d + 1) < s->nb_streams) @@ -965,6 +1006,9 @@ start_sync: goto start_sync; } + if (avi->dv_demux && n != 0) + continue; + // parse ##dc/##wb if (n < s->nb_streams) { AVStream *st; @@ -977,8 +1021,8 @@ start_sync: AVIStream *ast1 = st1->priv_data; // workaround for broken small-file-bug402.avi if (d[2] == 'w' && d[3] == 'b' && n == 0 && - st->codec->codec_type == AVMEDIA_TYPE_VIDEO && - st1->codec->codec_type == AVMEDIA_TYPE_AUDIO && + st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO && + st1->codecpar->codec_type == AVMEDIA_TYPE_AUDIO && ast->prefix == 'd' * 256 + 'c' && (d[2] * 256 + d[3] == ast1->prefix || !ast1->prefix_count)) { @@ -1049,14 +1093,80 @@ start_sync: return AVERROR_EOF; } +static int ni_prepare_read(AVFormatContext *s) +{ + AVIContext *avi = s->priv_data; + int best_stream_index = 0; + AVStream *best_st = NULL; + AVIStream *best_ast; + int64_t best_ts = INT64_MAX; + int i; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + int64_t ts = ast->frame_offset; + int64_t last_ts; + + if (!st->nb_index_entries) + continue; + + last_ts = st->index_entries[st->nb_index_entries - 1].timestamp; + if (!ast->remaining && ts > last_ts) + continue; + + ts = av_rescale_q(ts, st->time_base, + (AVRational) { FFMAX(1, ast->sample_size), + AV_TIME_BASE }); + + av_log(s, AV_LOG_TRACE, "%"PRId64" %d/%d %"PRId64"\n", ts, + st->time_base.num, st->time_base.den, ast->frame_offset); + if (ts < best_ts) { + best_ts = ts; + best_st = st; + best_stream_index = i; + } + } + if (!best_st) + return AVERROR_EOF; + + best_ast = best_st->priv_data; + best_ts = av_rescale_q(best_ts, + (AVRational) { FFMAX(1, best_ast->sample_size), + AV_TIME_BASE }, + best_st->time_base); + if (best_ast->remaining) { + i = av_index_search_timestamp(best_st, + best_ts, + AVSEEK_FLAG_ANY | + AVSEEK_FLAG_BACKWARD); + } else { + i = av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY); + if (i >= 0) + best_ast->frame_offset = best_st->index_entries[i].timestamp; + } + + if (i >= 0) { + int64_t pos = best_st->index_entries[i].pos; + pos += best_ast->packet_size - best_ast->remaining; + avio_seek(s->pb, pos + 8, SEEK_SET); + + 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; + } + + return 0; +} + static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) { AVIContext *avi = s->priv_data; AVIOContext *pb = s->pb; int err; -#if FF_API_DESTRUCT_PACKET - void *dstr; -#endif if (CONFIG_DV_DEMUXER && avi->dv_demux) { int size = avpriv_dv_get_packet(avi->dv_demux, pkt); @@ -1067,68 +1177,9 @@ static int avi_read_packet(AVFormatContext *s, AVPacket *pkt) } if (avi->non_interleaved) { - int best_stream_index = 0; - AVStream *best_st = NULL; - AVIStream *best_ast; - int64_t best_ts = INT64_MAX; - int i; - - for (i = 0; i < s->nb_streams; i++) { - AVStream *st = s->streams[i]; - AVIStream *ast = st->priv_data; - int64_t ts = ast->frame_offset; - int64_t last_ts; - - if (!st->nb_index_entries) - continue; - - last_ts = st->index_entries[st->nb_index_entries - 1].timestamp; - if (!ast->remaining && ts > last_ts) - continue; - - ts = av_rescale_q(ts, st->time_base, - (AVRational) { FFMAX(1, ast->sample_size), - AV_TIME_BASE }); - - av_dlog(s, "%"PRId64" %d/%d %"PRId64"\n", ts, - st->time_base.num, st->time_base.den, ast->frame_offset); - if (ts < best_ts) { - best_ts = ts; - best_st = st; - best_stream_index = i; - } - } - if (!best_st) - return AVERROR_EOF; - - best_ast = best_st->priv_data; - best_ts = av_rescale_q(best_ts, - (AVRational) { FFMAX(1, best_ast->sample_size), - AV_TIME_BASE }, - best_st->time_base); - if (best_ast->remaining) { - i = av_index_search_timestamp(best_st, - best_ts, - AVSEEK_FLAG_ANY | - AVSEEK_FLAG_BACKWARD); - } else { - i = av_index_search_timestamp(best_st, best_ts, AVSEEK_FLAG_ANY); - if (i >= 0) - best_ast->frame_offset = best_st->index_entries[i].timestamp; - } - - if (i >= 0) { - int64_t pos = best_st->index_entries[i].pos; - pos += best_ast->packet_size - best_ast->remaining; - avio_seek(s->pb, pos + 8, SEEK_SET); - - 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; - } + err = ni_prepare_read(s); + if (err < 0) + return err; } resync: @@ -1172,24 +1223,14 @@ resync: if (CONFIG_DV_DEMUXER && avi->dv_demux) { AVBufferRef *avbuf = pkt->buf; -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - dstr = pkt->destruct; -FF_ENABLE_DEPRECATION_WARNINGS -#endif size = avpriv_dv_produce_packet(avi->dv_demux, pkt, pkt->data, pkt->size); -#if FF_API_DESTRUCT_PACKET -FF_DISABLE_DEPRECATION_WARNINGS - pkt->destruct = dstr; -FF_ENABLE_DEPRECATION_WARNINGS -#endif pkt->buf = avbuf; pkt->flags |= AV_PKT_FLAG_KEY; if (size < 0) - av_free_packet(pkt); - } else if (st->codec->codec_type == AVMEDIA_TYPE_SUBTITLE && - !st->codec->codec_tag && read_gab2_sub(st, pkt)) { + av_packet_unref(pkt); + } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE && + !st->codecpar->codec_tag && read_gab2_sub(st, pkt)) { ast->frame_offset++; avi->stream_index = -1; ast->remaining = 0; @@ -1200,7 +1241,7 @@ FF_ENABLE_DEPRECATION_WARNINGS // pkt->dts += ast->start; if (ast->sample_size) pkt->dts /= ast->sample_size; - av_dlog(s, + av_log(s, AV_LOG_TRACE, "dts:%"PRId64" offset:%"PRId64" %d/%d smpl_siz:%d " "base:%d st:%d size:%d\n", pkt->dts, @@ -1213,7 +1254,7 @@ FF_ENABLE_DEPRECATION_WARNINGS size); pkt->stream_index = avi->stream_index; - if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { + if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { AVIndexEntry *e; int index; assert(st->index_entries); @@ -1273,7 +1314,7 @@ static int avi_read_idx1(AVFormatContext *s, int size) flags = avio_rl32(pb); pos = avio_rl32(pb); len = avio_rl32(pb); - av_dlog(s, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/", + av_log(s, AV_LOG_TRACE, "%d: tag=0x%x flags=0x%x pos=0x%x len=%d/", i, tag, flags, pos, len); index = ((tag & 0xff) - '0') * 10; @@ -1289,7 +1330,7 @@ static int avi_read_idx1(AVFormatContext *s, int size) } pos += data_offset; - av_dlog(s, "%d cum_len=%"PRId64"\n", len, ast->cum_len); + av_log(s, AV_LOG_TRACE, "%d cum_len=%"PRId64"\n", len, ast->cum_len); if (pb->eof_reached) return AVERROR_INVALIDDATA; @@ -1305,6 +1346,64 @@ static int avi_read_idx1(AVFormatContext *s, int size) return 0; } +/* Scan the index and consider any file with streams more than + * 2 seconds or 64MB apart non-interleaved. */ +static int check_stream_max_drift(AVFormatContext *s) +{ + int64_t min_pos, pos; + int i; + int *idx = av_mallocz_array(s->nb_streams, sizeof(*idx)); + if (!idx) + return AVERROR(ENOMEM); + + for (min_pos = pos = 0; min_pos != INT64_MAX; pos = min_pos + 1LU) { + int64_t max_dts = INT64_MIN / 2; + int64_t min_dts = INT64_MAX / 2; + int64_t max_buffer = 0; + + min_pos = INT64_MAX; + + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + int n = st->nb_index_entries; + while (idx[i] < n && st->index_entries[idx[i]].pos < pos) + idx[i]++; + if (idx[i] < n) { + int64_t dts; + dts = av_rescale_q(st->index_entries[idx[i]].timestamp / + FFMAX(ast->sample_size, 1), + st->time_base, AV_TIME_BASE_Q); + min_dts = FFMIN(min_dts, dts); + min_pos = FFMIN(min_pos, st->index_entries[idx[i]].pos); + } + } + for (i = 0; i < s->nb_streams; i++) { + AVStream *st = s->streams[i]; + AVIStream *ast = st->priv_data; + + if (idx[i] && min_dts != INT64_MAX / 2) { + int64_t dts; + dts = av_rescale_q(st->index_entries[idx[i] - 1].timestamp / + FFMAX(ast->sample_size, 1), + st->time_base, AV_TIME_BASE_Q); + max_dts = FFMAX(max_dts, dts); + max_buffer = FFMAX(max_buffer, + av_rescale(dts - min_dts, + st->codecpar->bit_rate, + AV_TIME_BASE)); + } + } + if (max_dts - min_dts > 2 * AV_TIME_BASE || + max_buffer > 1024 * 1024 * 8 * 8) { + av_free(idx); + return 1; + } + } + av_free(idx); + return 0; +} + static int guess_ni_flag(AVFormatContext *s) { int i; @@ -1334,7 +1433,11 @@ static int guess_ni_flag(AVFormatContext *s) first_end = st->index_entries[n - 1].pos; } avio_seek(s->pb, oldpos, SEEK_SET); - return last_start > first_end; + + if (last_start > first_end) + return 1; + + return check_stream_max_drift(s); } static int avi_load_index(AVFormatContext *s) @@ -1347,13 +1450,13 @@ static int avi_load_index(AVFormatContext *s) if (avio_seek(pb, avi->movi_end, SEEK_SET) < 0) goto the_end; // maybe truncated file - av_dlog(s, "movi_end=0x%"PRIx64"\n", avi->movi_end); + av_log(s, AV_LOG_TRACE, "movi_end=0x%"PRIx64"\n", avi->movi_end); for (;;) { if (pb->eof_reached) break; tag = avio_rl32(pb); size = avio_rl32(pb); - av_dlog(s, "tag=%c%c%c%c size=0x%x\n", + av_log(s, AV_LOG_TRACE, "tag=%c%c%c%c size=0x%x\n", tag & 0xff, (tag >> 8) & 0xff, (tag >> 16) & 0xff, @@ -1380,7 +1483,7 @@ static void seek_subtitle(AVStream *st, AVStream *st2, int64_t timestamp) { AVIStream *ast2 = st2->priv_data; int64_t ts2 = av_rescale_q(timestamp, st->time_base, st2->time_base); - av_free_packet(&ast2->sub_pkt); + av_packet_unref(&ast2->sub_pkt); if (avformat_seek_file(ast2->sub_ctx, 0, INT64_MIN, ts2, ts2, 0) >= 0 || avformat_seek_file(ast2->sub_ctx, 0, ts2, ts2, INT64_MAX, 0) >= 0) ff_read_packet(ast2->sub_ctx, &ast2->sub_pkt); @@ -1419,7 +1522,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, pos = st->index_entries[index].pos; timestamp = st->index_entries[index].timestamp / FFMAX(ast->sample_size, 1); - av_dlog(s, "XX %"PRId64" %d %"PRId64"\n", + av_log(s, AV_LOG_TRACE, "XX %"PRId64" %d %"PRId64"\n", timestamp, index, st->index_entries[index].timestamp); if (CONFIG_DV_DEMUXER && avi->dv_demux) { @@ -1451,7 +1554,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, if (st2->nb_index_entries <= 0) continue; -// assert(st2->codec->block_align); +// assert(st2->codecpar->block_align); assert((int64_t)st2->time_base.num * ast2->rate == (int64_t)st2->time_base.den * ast2->scale); index = av_index_search_timestamp(st2, @@ -1471,7 +1574,7 @@ static int avi_read_seek(AVFormatContext *s, int stream_index, index++; } - av_dlog(s, "%"PRId64" %d %"PRId64"\n", + av_log(s, AV_LOG_TRACE, "%"PRId64" %d %"PRId64"\n", timestamp, index, st2->index_entries[index].timestamp); /* extract the current frame number */ ast2->frame_offset = st2->index_entries[index].timestamp; @@ -1497,7 +1600,7 @@ static int avi_read_close(AVFormatContext *s) avformat_close_input(&ast->sub_ctx); } av_free(ast->sub_buffer); - av_free_packet(&ast->sub_pkt); + av_packet_unref(&ast->sub_pkt); } } @@ -1523,6 +1626,7 @@ AVInputFormat ff_avi_demuxer = { .name = "avi", .long_name = NULL_IF_CONFIG_SMALL("AVI (Audio Video Interleaved)"), .priv_data_size = sizeof(AVIContext), + .extensions = "avi", .read_probe = avi_probe, .read_header = avi_read_header, .read_packet = avi_read_packet,