-
-
Save rcombs/31d41ffacb44c11d5757 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
commit 5051fe3579463accdf48d3bab2ab3217e190c3b0 | |
Author: Rodger Combs <rodger.combs@gmail.com> | |
Date: Wed Apr 22 17:06:04 2015 -0500 | |
WIP: Add BFSTM demuxer (extension of BRSTM) | |
diff --git a/libavcodec/utils.c b/libavcodec/utils.c | |
index 8695cb9..c4995f6 100644 | |
--- a/libavcodec/utils.c | |
+++ b/libavcodec/utils.c | |
@@ -3429,6 +3429,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 / (8 * ch) * 14; | |
+ 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 aab3b3b..3710d0b 100644 | |
--- a/libavformat/Makefile | |
+++ b/libavformat/Makefile | |
@@ -106,6 +106,7 @@ OBJS-$(CONFIG_BIT_MUXER) += bit.o | |
OBJS-$(CONFIG_BMV_DEMUXER) += bmv.o | |
OBJS-$(CONFIG_BOA_DEMUXER) += boadec.o | |
OBJS-$(CONFIG_BRSTM_DEMUXER) += brstm.o | |
+OBJS-$(CONFIG_BFSTM_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 \ | |
isom.o replaygain.o | |
diff --git a/libavformat/allformats.c b/libavformat/allformats.c | |
index e58ddd5..efdca2a 100644 | |
--- a/libavformat/allformats.c | |
+++ b/libavformat/allformats.c | |
@@ -93,6 +93,7 @@ void av_register_all(void) | |
REGISTER_MUXDEMUX(BIT, bit); | |
REGISTER_DEMUXER (BMV, bmv); | |
REGISTER_DEMUXER (BRSTM, brstm); | |
+ REGISTER_DEMUXER (BFSTM, bfstm); | |
REGISTER_DEMUXER (BOA, boa); | |
REGISTER_DEMUXER (C93, c93); | |
REGISTER_MUXDEMUX(CAF, caf); | |
diff --git a/libavformat/brstm.c b/libavformat/brstm.c | |
index 19a4a2a..9386322 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; | |
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,17 +91,43 @@ 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, info_size; | |
+ | |
+ avio_skip(s->pb, 2); // size of header | |
+ avio_skip(s->pb, 4); // unknown constant 1 | |
+ avio_skip(s->pb, 4); // size of file | |
+ avio_skip(s->pb, 4); // unknown constant 2 | |
+ avio_skip(s->pb, 4); // section 0 flag | |
+ info_offset = avio_rb32(s->pb); | |
+ info_size = avio_rb32(s->pb); | |
+ avio_skip(s->pb, 4); // section 1 flag | |
+ avio_skip(s->pb, 4); // seek offset | |
+ avio_skip(s->pb, 4); // seek size | |
+ avio_skip(s->pb, 4); // section 2 flag | |
+ data_offset = avio_rb32(s->pb); | |
+ avio_skip(s->pb, 4); //data_size = avio_rb32(s->pb); | |
+ | |
+ start = data_offset + 0x20; | |
+ | |
+ 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) | |
return AVERROR_INVALIDDATA; | |
@@ -103,6 +141,7 @@ static int read_header(AVFormatContext *s) | |
return AVERROR_INVALIDDATA; | |
avio_skip(s->pb, pos + h1offset + 8 - avio_tell(s->pb)); | |
+ | |
codec = avio_r8(s->pb); | |
switch (codec) { | |
@@ -121,17 +160,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) { | |
@@ -156,12 +200,20 @@ static int read_header(AVFormatContext *s) | |
if (codec == AV_CODEC_ID_ADPCM_THP) { | |
int ch; | |
+ toffset = 168 - pos; | |
avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); | |
- toffset = avio_rb32(s->pb) + 16LL; | |
- if (toffset > size) | |
- return AVERROR_INVALIDDATA; | |
+ if (!b->bfstm) { | |
+ toffset = avio_rb32(s->pb) + 16LL; | |
+ if (toffset > size) | |
+ return AVERROR_INVALIDDATA; | |
+ | |
+ avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); | |
+ } else { | |
+ avio_skip(s->pb, 4); | |
+ toffset = pos + toffset + avio_rb32(s->pb) + st->codec->channels * 8 - 4; | |
+ avio_skip(s->pb, toffset - avio_tell(s->pb)); | |
+ } | |
- avio_skip(s->pb, pos + toffset - avio_tell(s->pb)); | |
b->table = av_mallocz(32 * st->codec->channels); | |
if (!b->table) | |
return AVERROR(ENOMEM); | |
@@ -171,7 +223,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 +239,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); | |
@@ -193,7 +257,6 @@ static int read_header(AVFormatContext *s) | |
case MKTAG('A','D','P','C'): | |
if (codec != AV_CODEC_ID_ADPCM_THP) | |
goto skip; | |
- | |
asize = b->block_count * st->codec->channels * 4; | |
if (size < asize) { | |
ret = AVERROR_INVALIDDATA; | |
@@ -214,13 +277,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 +320,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 +358,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", | |
+}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment