diff --git a/libavformat/wav.c b/libavformat/wav.c index cf815ef3df..a8312e254e 100644 --- a/libavformat/wav.c +++ b/libavformat/wav.c @@ -296,7 +296,7 @@ static int wav_read_header(AVFormatContext *s, AVStream *st; WAVContext *wav = s->priv_data; int ret, got_fmt = 0; - int64_t next_tag_ofs; + int64_t next_tag_ofs, data_ofs = -1; /* check RIFF header */ tag = avio_rl32(pb); @@ -327,13 +327,13 @@ static int wav_read_header(AVFormatContext *s, avio_skip(pb, size - 16); /* skip rest of ds64 chunk */ } - for (;;) { - if (pb->eof_reached) - return -1; size = next_tag(pb, &tag); next_tag_ofs = avio_tell(pb) + size; + if (pb->eof_reached) + break; + switch (tag) { case MKTAG('f', 'm', 't', ' '): /* only parse the first 'fmt ' tag found */ @@ -350,26 +350,43 @@ static int wav_read_header(AVFormatContext *s, return AVERROR_INVALIDDATA; } - goto break_loop; + if (rf64) { + next_tag_ofs = wav->data_end = avio_tell(pb) + data_size; + } else { + data_size = size; + next_tag_ofs = wav->data_end = size ? next_tag_ofs : INT64_MAX; + } + + data_ofs = avio_tell(pb); + + /* don't look for footer metadata if we can't seek or if we don't + * know where the data tag ends + */ + if (!pb->seekable || (!rf64 && !size)) + goto break_loop; + break; case MKTAG('f','a','c','t'): if (!sample_count) sample_count = avio_rl32(pb); break; } - avio_seek(pb, next_tag_ofs, SEEK_SET); + + /* seek to next tag unless we know that we'll run into EOF */ + if ((avio_size(pb) > 0 && next_tag_ofs >= avio_size(pb)) || + avio_seek(pb, next_tag_ofs, SEEK_SET) < 0) { + break; + } } break_loop: - if (rf64) - size = data_size; - if (size < 0) - return -1; - if (!size) { - wav->data_end = INT64_MAX; - } else - wav->data_end= avio_tell(pb) + size; + if (data_ofs < 0) { + av_log(s, AV_LOG_ERROR, "no 'data' tag found\n"); + return AVERROR_INVALIDDATA; + } + + avio_seek(pb, data_ofs, SEEK_SET); if (!sample_count && st->codec->channels && av_get_bits_per_sample(st->codec->codec_id)) - sample_count = (size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); + sample_count = (data_size<<3) / (st->codec->channels * (uint64_t)av_get_bits_per_sample(st->codec->codec_id)); if (sample_count) st->duration = sample_count; return 0;