diff options
author | Rodger Combs <rodger.combs@gmail.com> | 2015-06-17 03:09:52 -0500 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2015-06-17 13:24:11 +0200 |
commit | bb42a7d4d4011101ddbd817c3a5f6d0d86ee26bd (patch) | |
tree | 66694ca9f6310854cb7443c260b941ae833e6115 | |
parent | dc87758775e2ce8be84e4fe598e12416e83d2845 (diff) | |
download | ffmpeg-bb42a7d4d4011101ddbd817c3a5f6d0d86ee26bd.tar.gz |
lavf/brstm: add support for BFSTM files
Previous version reviewed-by: Paul B Mahol <onemda@gmail.com>
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
-rw-r--r-- | Changelog | 1 | ||||
-rw-r--r-- | doc/general.texi | 2 | ||||
-rw-r--r-- | libavcodec/utils.c | 4 | ||||
-rw-r--r-- | libavformat/Makefile | 1 | ||||
-rw-r--r-- | libavformat/allformats.c | 1 | ||||
-rw-r--r-- | libavformat/brstm.c | 129 | ||||
-rw-r--r-- | libavformat/version.h | 2 |
7 files changed, 119 insertions, 21 deletions
@@ -3,6 +3,7 @@ releases are sorted from youngest to oldest. version <next>: - colorkey video filter +- BFSTM demuxer version 2.7: diff --git a/doc/general.texi b/doc/general.texi index ba79503d3f..471a11bb82 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -243,6 +243,8 @@ library: @tab Used in Z and Z95 games. @item Brute Force & Ignorance @tab @tab X @tab Used in the game Flash Traffic: City of Angels. +@item BFSTM @tab @tab X + @tab Audio format used on the Nintendo WiiU (based on BRSTM). @item BRSTM @tab @tab X @tab Audio format used on the Nintendo Wii. @item BWF @tab X @tab X diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 558afebc2f..a444a5ead8 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -3430,6 +3430,10 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) return (frame_bytes - 4) * 2 / ch; case AV_CODEC_ID_ADPCM_IMA_AMV: return (frame_bytes - 8) * 2 / ch; + case AV_CODEC_ID_ADPCM_THP: + if (avctx->extradata) + return frame_bytes * 14 / (8 * ch); + break; case AV_CODEC_ID_ADPCM_XA: return (frame_bytes / 128) * 224 / ch; case AV_CODEC_ID_INTERPLAY_DPCM: diff --git a/libavformat/Makefile b/libavformat/Makefile index b9169d94af..993ec09837 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -105,6 +105,7 @@ OBJS-$(CONFIG_BIT_DEMUXER) += bit.o OBJS-$(CONFIG_BIT_MUXER) += bit.o OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o +OBJS-$(CONFIG_BFSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o OBJS-$(CONFIG_C93_DEMUXER) += c93.o vocdec.o voc.o OBJS-$(CONFIG_CAF_DEMUXER) += cafdec.o caf.o mov.o mov_chan.o \ diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 3a49650cee..306e0c9876 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -92,6 +92,7 @@ void av_register_all(void) REGISTER_DEMUXER (BINK, bink); REGISTER_MUXDEMUX(BIT, bit); REGISTER_DEMUXER (BMV, bmv); + REGISTER_DEMUXER (BFSTM, bfstm); REGISTER_DEMUXER (BRSTM, brstm); REGISTER_DEMUXER (BOA, boa); REGISTER_DEMUXER (C93, c93); diff --git a/libavformat/brstm.c b/libavformat/brstm.c index 19a4a2a96b..1eba943e51 100644 --- a/libavformat/brstm.c +++ b/libavformat/brstm.c @@ -32,6 +32,7 @@ typedef struct BRSTMDemuxContext { uint32_t last_block_used_bytes; uint8_t *table; uint8_t *adpc; + int bfstm; } BRSTMDemuxContext; static int probe(AVProbeData *p) @@ -43,6 +44,15 @@ static int probe(AVProbeData *p) return 0; } +static int probe_bfstm(AVProbeData *p) +{ + if (AV_RL32(p->buf) == MKTAG('F','S','T','M') && + (AV_RL16(p->buf + 4) == 0xFFFE || + AV_RL16(p->buf + 4) == 0xFEFF)) + return AVPROBE_SCORE_MAX / 3 * 2; + return 0; +} + static int read_close(AVFormatContext *s) { BRSTMDemuxContext *b = s->priv_data; @@ -57,11 +67,13 @@ static int read_header(AVFormatContext *s) { BRSTMDemuxContext *b = s->priv_data; int bom, major, minor, codec, chunk; - int64_t pos, h1offset, toffset; + int64_t h1offset, pos, toffset, data_offset = 0; uint32_t size, start, asize; AVStream *st; int ret = AVERROR_EOF; + b->bfstm = !strcmp("bfstm", s->iformat->name); + st = avformat_new_stream(s, NULL); if (!st) return AVERROR(ENOMEM); @@ -79,19 +91,65 @@ static int read_header(AVFormatContext *s) return AVERROR_PATCHWELCOME; } - major = avio_r8(s->pb); - minor = avio_r8(s->pb); - avio_skip(s->pb, 4); // size of file - size = avio_rb16(s->pb); - if (size < 14) - return AVERROR_INVALIDDATA; + if (!b->bfstm) { + major = avio_r8(s->pb); + minor = avio_r8(s->pb); + avio_skip(s->pb, 4); // size of file + size = avio_rb16(s->pb); + if (size < 14) + return AVERROR_INVALIDDATA; + + avio_skip(s->pb, size - 14); + pos = avio_tell(s->pb); + if (avio_rl32(s->pb) != MKTAG('H','E','A','D')) + return AVERROR_INVALIDDATA; + } else { + uint32_t info_offset = 0, info_size; + uint16_t section_count, header_size, i; + + header_size = avio_rb16(s->pb); // 6 + + avio_skip(s->pb, 4); // Unknown constant 0x00030000 + avio_skip(s->pb, 4); // size of file + section_count = avio_rb16(s->pb); + avio_skip(s->pb, 2); // padding + for (i = 0; avio_tell(s->pb) < header_size + && !(data_offset && info_offset) + && i < section_count; i++) { + uint32_t flag = avio_rb32(s->pb); + switch (flag) { + case 0x40000000: + info_offset = avio_rb32(s->pb); + info_size = avio_rb32(s->pb); + break; + case 0x40010000: + avio_skip(s->pb, 4); // seek offset + avio_skip(s->pb, 4); // seek size + break; + case 0x40020000: + data_offset = avio_rb32(s->pb); + avio_skip(s->pb, 4); //data_size = avio_rb32(s->pb); + break; + case 0x40030000: + avio_skip(s->pb, 4); // REGN offset + avio_skip(s->pb, 4); // REGN size + break; + } + } + + if (!info_offset || !data_offset) + 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')) + return AVERROR_INVALIDDATA; + } - avio_skip(s->pb, size - 14); - pos = avio_tell(s->pb); - if (avio_rl32(s->pb) != MKTAG('H','E','A','D')) - return AVERROR_INVALIDDATA; size = avio_rb32(s->pb); - if (size < 256) + if (size < 192) return AVERROR_INVALIDDATA; avio_skip(s->pb, 4); // unknown h1offset = avio_rb32(s->pb); @@ -121,17 +179,22 @@ static int read_header(AVFormatContext *s) return AVERROR_INVALIDDATA; avio_skip(s->pb, 1); // padding + if (b->bfstm) + avio_skip(s->pb, 2); // padding + st->codec->sample_rate = avio_rb16(s->pb); if (!st->codec->sample_rate) return AVERROR_INVALIDDATA; - avio_skip(s->pb, 2); // padding + if (!b->bfstm) + avio_skip(s->pb, 2); // padding avio_skip(s->pb, 4); // loop start sample st->start_time = 0; st->duration = avio_rb32(s->pb); avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); - start = avio_rb32(s->pb); + if (!b->bfstm) + start = avio_rb32(s->pb); b->current_block = 0; b->block_count = avio_rb32(s->pb); if (b->block_count > UINT16_MAX) { @@ -157,7 +220,10 @@ static int read_header(AVFormatContext *s) int ch; avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); - toffset = avio_rb32(s->pb) + 16LL; + if (!b->bfstm) + toffset = avio_rb32(s->pb) + 16LL; + else + toffset = toffset + avio_rb32(s->pb) + st->codec->channels * 8 - 8; if (toffset > size) return AVERROR_INVALIDDATA; @@ -171,7 +237,15 @@ static int read_header(AVFormatContext *s) ret = AVERROR_INVALIDDATA; goto fail; } - avio_skip(s->pb, 24); + 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); } } @@ -179,7 +253,11 @@ static int read_header(AVFormatContext *s) ret = AVERROR_INVALIDDATA; goto fail; } - avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); + + if (!b->bfstm) + avio_skip(s->pb, size - (avio_tell(s->pb) - pos)); + else + avio_skip(s->pb, data_offset - avio_tell(s->pb)); while (!avio_feof(s->pb)) { chunk = avio_rl32(s->pb); @@ -214,13 +292,13 @@ static int read_header(AVFormatContext *s) break; case MKTAG('D','A','T','A'): if ((start < avio_tell(s->pb)) || - (!b->adpc && codec == AV_CODEC_ID_ADPCM_THP)) { + (!b->adpc && codec == AV_CODEC_ID_ADPCM_THP && !b->bfstm)) { ret = AVERROR_INVALIDDATA; goto fail; } avio_skip(s->pb, start - avio_tell(s->pb)); - if (major != 1 || minor) + if ((major != 1 || minor) && !b->bfstm) avpriv_request_sample(s, "Version %d.%d", major, minor); return 0; @@ -257,7 +335,7 @@ static int read_packet(AVFormatContext *s, AVPacket *pkt) return AVERROR_EOF; } - if (codec->codec_id == AV_CODEC_ID_ADPCM_THP) { + if (codec->codec_id == AV_CODEC_ID_ADPCM_THP && !codec->extradata) { uint8_t *dst; if (av_new_packet(pkt, 8 + (32 + 4) * codec->channels + size) < 0) @@ -295,3 +373,14 @@ AVInputFormat ff_brstm_demuxer = { .read_close = read_close, .extensions = "brstm", }; + +AVInputFormat ff_bfstm_demuxer = { + .name = "bfstm", + .long_name = NULL_IF_CONFIG_SMALL("BFSTM (Binary Cafe Stream)"), + .priv_data_size = sizeof(BRSTMDemuxContext), + .read_probe = probe_bfstm, + .read_header = read_header, + .read_packet = read_packet, + .read_close = read_close, + .extensions = "bfstm", +}; diff --git a/libavformat/version.h b/libavformat/version.h index c0920d54a1..99b71906ba 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/version.h" #define LIBAVFORMAT_VERSION_MAJOR 56 -#define LIBAVFORMAT_VERSION_MINOR 36 +#define LIBAVFORMAT_VERSION_MINOR 37 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ |