X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavformat%2Fbrstm.c;h=f1f0f86ed50f450f090a84bc8fd7d37aa29d9934;hb=bc70684e74a185d7b80c8b80bdedda659cb581b8;hp=87690e3f73e421ebf870edc15ae9417bf92ff4c5;hpb=fb4a12cda4033f2f3d3d1039739f6e0e6f9afb82;p=ffmpeg diff --git a/libavformat/brstm.c b/libavformat/brstm.c index 87690e3f73e..f1f0f86ed50 100644 --- a/libavformat/brstm.c +++ b/libavformat/brstm.c @@ -24,6 +24,11 @@ #include "avformat.h" #include "internal.h" +typedef struct BRSTMCoeffOffset { + uint8_t channel; + uint32_t offset; +} BRSTMCoeffOffset; + typedef struct BRSTMDemuxContext { uint32_t block_size; uint32_t block_count; @@ -33,12 +38,13 @@ typedef struct BRSTMDemuxContext { uint32_t last_block_size; uint32_t last_block_samples; uint32_t data_start; - uint8_t *table; + uint8_t table[256 * 32]; uint8_t *adpc; + BRSTMCoeffOffset offsets[256]; int little_endian; } BRSTMDemuxContext; -static int probe(AVProbeData *p) +static int probe(const AVProbeData *p) { if (AV_RL32(p->buf) == MKTAG('R','S','T','M') && (AV_RL16(p->buf + 4) == 0xFFFE || @@ -47,7 +53,7 @@ static int probe(AVProbeData *p) return 0; } -static int probe_bfstm(AVProbeData *p) +static int probe_bfstm(const AVProbeData *p) { if ((AV_RL32(p->buf) == MKTAG('F','S','T','M') || AV_RL32(p->buf) == MKTAG('C','S','T','M')) && @@ -61,12 +67,18 @@ static int read_close(AVFormatContext *s) { BRSTMDemuxContext *b = s->priv_data; - av_freep(&b->table); av_freep(&b->adpc); return 0; } +static int sort_offsets(const void *a, const void *b) +{ + const BRSTMCoeffOffset *s1 = a; + const BRSTMCoeffOffset *s2 = b; + return FFDIFFSIGN(s1->offset, s2->offset); +} + static av_always_inline unsigned int read16(AVFormatContext *s) { BRSTMDemuxContext *b = s->priv_data; @@ -259,17 +271,30 @@ static int read_header(AVFormatContext *s) if (toffset > size) return AVERROR_INVALIDDATA; + if (!bfstm) { + avio_skip(s->pb, pos + toffset - avio_tell(s->pb) - 8LL * (st->codecpar->channels + 1)); + for (ch = 0; ch < st->codecpar->channels; ch++) { + avio_skip(s->pb, 4); + b->offsets[ch].channel = ch; + b->offsets[ch].offset = read32(s); + } + + qsort(b->offsets, st->codecpar->channels, sizeof(*b->offsets), sort_offsets); + } + avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); - b->table = av_mallocz(32 * st->codecpar->channels); - if (!b->table) - return AVERROR(ENOMEM); for (ch = 0; ch < st->codecpar->channels; ch++) { + if (!bfstm) + avio_skip(s->pb, pos + 16LL + b->offsets[ch].offset - avio_tell(s->pb)); + if (avio_read(s->pb, b->table + ch * 32, 32) != 32) { ret = AVERROR_INVALIDDATA; goto fail; } - avio_skip(s->pb, bfstm ? 14 : 24); + + if (bfstm) + avio_skip(s->pb, 14); } } @@ -393,18 +418,13 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) av_log(s, AV_LOG_ERROR, "adpcm_thp requires ADPC chunk, but none was found.\n"); return AVERROR_INVALIDDATA; } - if (!b->table) { - b->table = av_mallocz(32 * par->channels); - if (!b->table) - return AVERROR(ENOMEM); - } if (size > (INT_MAX - 32 - 4) || (32 + 4 + size) > (INT_MAX / par->channels) || (32 + 4 + size) * par->channels > INT_MAX - 8) return AVERROR_INVALIDDATA; - if (av_new_packet(pkt, 8 + (32 + 4 + size) * par->channels) < 0) - return AVERROR(ENOMEM); + if ((ret = av_new_packet(pkt, 8 + (32 + 4 + size) * par->channels)) < 0) + return ret; dst = pkt->data; if (par->codec_id == AV_CODEC_ID_ADPCM_THP_LE) { bytestream_put_le32(&dst, size * par->channels); @@ -422,8 +442,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) dst += size; avio_skip(s->pb, skip); if (ret != size) { - av_packet_unref(pkt); - break; + return AVERROR(EIO); } } pkt->duration = samples; @@ -447,7 +466,11 @@ static int read_seek(AVFormatContext *s, int stream_index, BRSTMDemuxContext *b = s->priv_data; int64_t ret = 0; + if (timestamp < 0) + timestamp = 0; timestamp /= b->samples_per_block; + if (timestamp >= b->block_count) + timestamp = b->block_count - 1; ret = avio_seek(s->pb, b->data_start + timestamp * b->block_size * st->codecpar->channels, SEEK_SET); if (ret < 0) @@ -458,7 +481,7 @@ static int read_seek(AVFormatContext *s, int stream_index, return 0; } -AVInputFormat ff_brstm_demuxer = { +const AVInputFormat ff_brstm_demuxer = { .name = "brstm", .long_name = NULL_IF_CONFIG_SMALL("BRSTM (Binary Revolution Stream)"), .priv_data_size = sizeof(BRSTMDemuxContext), @@ -470,7 +493,7 @@ AVInputFormat ff_brstm_demuxer = { .extensions = "brstm", }; -AVInputFormat ff_bfstm_demuxer = { +const AVInputFormat ff_bfstm_demuxer = { .name = "bfstm", .long_name = NULL_IF_CONFIG_SMALL("BFSTM (Binary Cafe Stream)"), .priv_data_size = sizeof(BRSTMDemuxContext),