Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/fsb.c | 150 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+) create mode 100644 libavformat/fsb.c
diff --git a/libavformat/Makefile b/libavformat/Makefile index f2326df..714dba0 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -170,6 +170,7 @@ OBJS-$(CONFIG_FOURXM_DEMUXER) += 4xm.o OBJS-$(CONFIG_FRAMECRC_MUXER) += framecrcenc.o framehash.o OBJS-$(CONFIG_FRAMEMD5_MUXER) += md5enc.o framehash.o OBJS-$(CONFIG_FRM_DEMUXER) += frmdec.o +OBJS-$(CONFIG_FSB_DEMUXER) += fsb.o OBJS-$(CONFIG_GIF_MUXER) += gif.o OBJS-$(CONFIG_GIF_DEMUXER) += gifdec.o OBJS-$(CONFIG_GSM_DEMUXER) += gsmdec.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 92e321c..1b0fb54 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -138,6 +138,7 @@ void av_register_all(void) REGISTER_MUXER (FRAMECRC, framecrc); REGISTER_MUXER (FRAMEMD5, framemd5); REGISTER_DEMUXER (FRM, frm); + REGISTER_DEMUXER (FSB, fsb); REGISTER_MUXDEMUX(G722, g722); REGISTER_MUXDEMUX(G723_1, g723_1); REGISTER_DEMUXER (G729, g729); diff --git a/libavformat/fsb.c b/libavformat/fsb.c new file mode 100644 index 0000000..2881966 --- /dev/null +++ b/libavformat/fsb.c @@ -0,0 +1,150 @@ +/* + * FSB demuxer + * Copyright (c) 2015 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavcodec/bytestream.h" +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "avio.h" +#include "internal.h" + +static int fsb_probe(AVProbeData *p) +{ + if (memcmp(p->buf, "FSB", 3) || p->buf[3] - '0' < 1 || p->buf[3] - '0' > 5) + return 0; + if (AV_RL32(p->buf + 4) != 1) + return 0; + return AVPROBE_SCORE_MAX; +} + +static int fsb_read_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + unsigned format, version, c; + int64_t offset; + AVCodecContext *codec; + AVStream *st = avformat_new_stream(s, NULL); + + avio_skip(pb, 3); // "FSB" + version = avio_r8(pb) - '0'; + if (version != 4) { + avpriv_request_sample(s, "version %d", version); + return AVERROR_PATCHWELCOME; + } + avio_skip(pb, 4); + offset = avio_rl32(pb) + 0x30; + avio_skip(pb, 84); + + if (!st) + return AVERROR(ENOMEM); + codec = st->codec; + codec->codec_type = AVMEDIA_TYPE_AUDIO; + codec->codec_tag = 0; + + format = avio_rb32(pb); + switch(format) { + case 0x40001001: + codec->codec_id = AV_CODEC_ID_XMA2; + break; + case 0x40000802: + codec->codec_id = AV_CODEC_ID_ADPCM_THP; + break; + default: + avpriv_request_sample(s, "format 0x%X", format); + return AVERROR_PATCHWELCOME; + } + + codec->sample_rate = avio_rl32(pb); + if (!codec->sample_rate) + return AVERROR_INVALIDDATA; + avio_skip(pb, 6); + + codec->channels = avio_rl16(pb); + if (!codec->channels) + return AVERROR_INVALIDDATA; + + switch (codec->codec_id) { + case AV_CODEC_ID_XMA2: + ff_alloc_extradata(codec, 34); + if (!codec->extradata) + return AVERROR(ENOMEM); + memset(codec->extradata, 0, 34); + codec->block_align = 2048; + break; + case AV_CODEC_ID_ADPCM_THP: + if (codec->channels > INT_MAX / 32) + return AVERROR_INVALIDDATA; + ff_alloc_extradata(codec, 32 * codec->channels); + if (!codec->extradata) + return AVERROR(ENOMEM); + avio_seek(pb, 0x80, SEEK_SET); + for (c = 0; c < codec->channels; c++) { + avio_read(pb, codec->extradata + 32 * c, 32); + avio_skip(pb, 14); + } + codec->block_align = 8 * codec->channels; + break; + } + + avio_skip(pb, offset - avio_tell(pb)); + + avpriv_set_pts_info(st, 64, 1, codec->sample_rate); + + return 0; +} + +static int fsb_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + AVCodecContext *codec = s->streams[0]->codec; + int ret; + + if (avio_feof(s->pb)) + return AVERROR_EOF; + + if (codec->codec_id == AV_CODEC_ID_ADPCM_THP && + codec->channels > 1) { + int i, ch; + + ret = av_new_packet(pkt, codec->block_align); + if (ret < 0) + return ret; + for (i = 0; i < 4; i++) { + for (ch = 0; ch < codec->channels; ch++) { + pkt->data[ch * 8 + i * 2 + 0] = avio_r8(s->pb); + pkt->data[ch * 8 + i * 2 + 1] = avio_r8(s->pb); + } + } + ret = 0; + } else { + ret = av_get_packet(s->pb, pkt, codec->block_align); + } + pkt->stream_index = 0; + + return ret; +} + +AVInputFormat ff_fsb_demuxer = { + .name = "fsb", + .long_name = NULL_IF_CONFIG_SMALL("FMOD Sample Bank"), + .read_probe = fsb_probe, + .read_header = fsb_read_header, + .read_packet = fsb_read_packet, + .extensions = "fsb", +}; -- 1.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel