diff options
author | Rodger Combs <rodger.combs@gmail.com> | 2015-06-20 05:01:20 -0500 |
---|---|---|
committer | Paul B Mahol <onemda@gmail.com> | 2015-06-21 10:32:12 +0000 |
commit | 70a39bcf1c95471a79ba1f3a2ccedb4471df5b32 (patch) | |
tree | 14cdeecbcb83292286aaa125248a7c721b61ce5e | |
parent | 6c56827e629bc6db1d0c307b5e704e9c20d1187d (diff) | |
download | ffmpeg-70a39bcf1c95471a79ba1f3a2ccedb4471df5b32.tar.gz |
lavf/brstm: cleanup; fix short-block demuxing
-rw-r--r-- | libavformat/brstm.c | 77 |
1 files changed, 43 insertions, 34 deletions
diff --git a/libavformat/brstm.c b/libavformat/brstm.c index e314de76be..e3c6142511 100644 --- a/libavformat/brstm.c +++ b/libavformat/brstm.c @@ -30,6 +30,8 @@ typedef struct BRSTMDemuxContext { uint32_t current_block; uint32_t samples_per_block; uint32_t last_block_used_bytes; + uint32_t last_block_size; + uint32_t last_block_samples; uint8_t *table; uint8_t *adpc; int little_endian; @@ -86,8 +88,8 @@ static int read_header(AVFormatContext *s) { BRSTMDemuxContext *b = s->priv_data; int bom, major, minor, codec, chunk; - int64_t h1offset, pos, toffset, data_offset = 0; - uint32_t size, start, asize; + int64_t h1offset, pos, toffset; + uint32_t size, asize, start = 0; AVStream *st; int ret = AVERROR_EOF; int bfstm = !strcmp("bfstm", s->iformat->name); @@ -131,7 +133,7 @@ static int read_header(AVFormatContext *s) section_count = read16(s); avio_skip(s->pb, 2); // padding for (i = 0; avio_tell(s->pb) < header_size - && !(data_offset && info_offset) + && !(start && info_offset) && i < section_count; i++) { uint16_t flag = read16(s); avio_skip(s->pb, 2); @@ -145,7 +147,7 @@ static int read_header(AVFormatContext *s) avio_skip(s->pb, 4); // seek size break; case 0x4002: - data_offset = read32(s); + start = read32(s) + 8; avio_skip(s->pb, 4); //data_size = read32(s); break; case 0x4003: @@ -155,11 +157,9 @@ static int read_header(AVFormatContext *s) } } - if (!info_offset || !data_offset) + if (!info_offset || !start) return AVERROR_INVALIDDATA; - start = data_offset + 8; - avio_skip(s->pb, info_offset - avio_tell(s->pb)); pos = avio_tell(s->pb); if (avio_rl32(s->pb) != MKTAG('I','N','F','O')) @@ -223,16 +223,16 @@ static int read_header(AVFormatContext *s) b->block_size = read32(s); if (b->block_size > UINT32_MAX / st->codec->channels) return AVERROR_INVALIDDATA; - b->block_size *= st->codec->channels; b->samples_per_block = read32(s); b->last_block_used_bytes = read32(s); - if (b->last_block_used_bytes > UINT16_MAX / st->codec->channels) + b->last_block_samples = read32(s); + b->last_block_size = read32(s); + if (b->last_block_size > UINT32_MAX / st->codec->channels) + return AVERROR_INVALIDDATA; + if (b->last_block_used_bytes > b->last_block_size) return AVERROR_INVALIDDATA; - b->last_block_used_bytes *= st->codec->channels; - avio_skip(s->pb, 4); // last block samples - avio_skip(s->pb, 4); // last block size if (codec == AV_CODEC_ID_ADPCM_THP || codec == AV_CODEC_ID_ADPCM_THP_LE) { int ch; @@ -255,15 +255,7 @@ static int read_header(AVFormatContext *s) ret = AVERROR_INVALIDDATA; goto fail; } - avio_skip(s->pb, b->bfstm ? 14 : 24); - } - - if (b->bfstm) { - st->codec->extradata_size = 32 * st->codec->channels; - st->codec->extradata = av_malloc(st->codec->extradata_size); - if (!st->codec->extradata) - return AVERROR(ENOMEM); - memcpy(st->codec->extradata, b->table, st->codec->extradata_size); + avio_skip(s->pb, bfstm ? 14 : 24); } } @@ -283,6 +275,7 @@ static int read_header(AVFormatContext *s) } size -= 8; switch (chunk) { + case MKTAG('S','E','E','K'): case MKTAG('A','D','P','C'): if (codec != AV_CODEC_ID_ADPCM_THP && codec != AV_CODEC_ID_ADPCM_THP_LE) @@ -309,13 +302,16 @@ static int read_header(AVFormatContext *s) case MKTAG('D','A','T','A'): if ((start < avio_tell(s->pb)) || (!b->adpc && (codec == AV_CODEC_ID_ADPCM_THP || - codec == AV_CODEC_ID_ADPCM_THP_LE) - && !bfstm)) { + codec == AV_CODEC_ID_ADPCM_THP_LE))) { ret = AVERROR_INVALIDDATA; goto fail; } avio_skip(s->pb, start - avio_tell(s->pb)); + if (bfstm && (codec == AV_CODEC_ID_ADPCM_THP || + codec == AV_CODEC_ID_ADPCM_THP_LE)) + avio_skip(s->pb, 24); + if ((major != 1 || minor) && !bfstm) avpriv_request_sample(s, "Version %d.%d", major, minor); @@ -337,15 +333,16 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) { AVCodecContext *codec = s->streams[0]->codec; BRSTMDemuxContext *b = s->priv_data; - uint32_t samples, size; - int ret; + uint32_t samples, size, skip = 0; + int ret, i; if (avio_feof(s->pb)) return AVERROR_EOF; b->current_block++; if (b->current_block == b->block_count) { size = b->last_block_used_bytes; - samples = size / (8 * codec->channels) * 14; + samples = b->last_block_samples; + skip = b->last_block_size - b->last_block_used_bytes; } else if (b->current_block < b->block_count) { size = b->block_size; samples = b->samples_per_block; @@ -353,24 +350,36 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_EOF; } - if ((codec->codec_id == AV_CODEC_ID_ADPCM_THP || - codec->codec_id == AV_CODEC_ID_ADPCM_THP_LE) && !codec->extradata) { + if (codec->codec_id == AV_CODEC_ID_ADPCM_THP || + codec->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { uint8_t *dst; - if (av_new_packet(pkt, 8 + (32 + 4) * codec->channels + size) < 0) + if (av_new_packet(pkt, 8 + (32 + 4 + size) * codec->channels) < 0) return AVERROR(ENOMEM); dst = pkt->data; - bytestream_put_be32(&dst, size); - bytestream_put_be32(&dst, samples); + if (codec->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { + bytestream_put_le32(&dst, size * codec->channels); + bytestream_put_le32(&dst, samples); + } else { + bytestream_put_be32(&dst, size * codec->channels); + bytestream_put_be32(&dst, samples); + } bytestream_put_buffer(&dst, b->table, 32 * codec->channels); bytestream_put_buffer(&dst, b->adpc + 4 * codec->channels * (b->current_block - 1), 4 * codec->channels); - ret = avio_read(s->pb, dst, size); - if (ret != size) - av_free_packet(pkt); + for (i = 0; i < codec->channels; i++) { + ret = avio_read(s->pb, dst, size); + dst += size; + avio_skip(s->pb, skip); + if (ret != size) { + av_free_packet(pkt); + break; + } + } pkt->duration = samples; } else { + size *= codec->channels; ret = av_get_packet(s->pb, pkt, size); } |