diff options
author | Paul B Mahol <onemda@gmail.com> | 2018-04-22 11:52:32 +0200 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2018-04-22 12:00:43 +0200 |
commit | 5d3efe9e1f0b56595bd5d1287ae07a8f4277d71a (patch) | |
tree | 7f5a232bf192b13b9f9d43fb8b4a7fa4a5559733 /libavformat | |
parent | f97fa89925a5d4df7deb8ed49262d497f07e1b0a (diff) | |
download | ffmpeg-5d3efe9e1f0b56595bd5d1287ae07a8f4277d71a.tar.gz |
avformat/dsfdec: properly handle padded last packet
Fixes #5489.
Signed-off-by: Paul B Mahol <onemda@gmail.com>
Diffstat (limited to 'libavformat')
-rw-r--r-- | libavformat/dsfdec.c | 36 |
1 files changed, 34 insertions, 2 deletions
diff --git a/libavformat/dsfdec.c b/libavformat/dsfdec.c index 41538fd83c..e0485f1492 100644 --- a/libavformat/dsfdec.c +++ b/libavformat/dsfdec.c @@ -26,6 +26,8 @@ typedef struct { uint64_t data_end; + uint64_t audio_size; + uint64_t data_size; } DSFContext; static int dsf_probe(AVProbeData *p) @@ -120,7 +122,7 @@ static int dsf_read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; } - avio_skip(pb, 8); + dsf->audio_size = avio_rl64(pb) / 8 * st->codecpar->channels; st->codecpar->block_align = avio_rl32(pb); if (st->codecpar->block_align > INT_MAX / st->codecpar->channels) { avpriv_request_sample(s, "block_align overflow"); @@ -135,7 +137,9 @@ static int dsf_read_header(AVFormatContext *s) dsf->data_end = avio_tell(pb); if (avio_rl32(pb) != MKTAG('d', 'a', 't', 'a')) return AVERROR_INVALIDDATA; - dsf->data_end += avio_rl64(pb); + dsf->data_size = avio_rl64(pb); + dsf->data_end += dsf->data_size; + s->internal->data_offset = avio_tell(pb); return 0; } @@ -151,6 +155,34 @@ static int dsf_read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_EOF; pkt->stream_index = 0; + if (dsf->data_size > dsf->audio_size) { + int last_packet = pos == (dsf->data_end - st->codecpar->block_align); + + if (last_packet) { + int64_t data_pos = pos - s->internal->data_offset; + int64_t packet_size = dsf->audio_size - data_pos; + int64_t skip_size = dsf->data_size - data_pos - packet_size; + uint8_t *dst; + int ch, ret; + + if (packet_size <= 0 || skip_size <= 0) + return AVERROR_INVALIDDATA; + + if (av_new_packet(pkt, packet_size) < 0) + return AVERROR(ENOMEM); + dst = pkt->data; + for (ch = 0; ch < st->codecpar->channels; ch++) { + ret = avio_read(pb, dst, packet_size / st->codecpar->channels); + if (ret < packet_size / st->codecpar->channels) + return AVERROR_EOF; + + dst += ret; + avio_skip(pb, skip_size / st->codecpar->channels); + } + + return 0; + } + } return av_get_packet(pb, pkt, FFMIN(dsf->data_end - pos, st->codecpar->block_align)); } |