From 055dc116fcf75f7f38c64b689ebda7480a7da8c2 Mon Sep 17 00:00:00 2001 From: Stefan Gehrer Date: Sat, 17 Jan 2009 20:08:43 +0000 Subject: [PATCH] added demuxer for FunCom ISS audio files, extended ADPCM decoder by ISS specific IMA variant Originally committed as revision 16658 to svn://svn.ffmpeg.org/ffmpeg/trunk --- Changelog | 1 + doc/general.texi | 4 ++ libavcodec/adpcm.c | 28 +++++++++ libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 3 +- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/avformat.h | 2 +- libavformat/iss.c | 130 +++++++++++++++++++++++++++++++++++++++ 9 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 libavformat/iss.c diff --git a/Changelog b/Changelog index 315a8db273..577980f0f6 100644 --- a/Changelog +++ b/Changelog @@ -226,6 +226,7 @@ version 0.4.9-pre1: - more accurate deblock filter - padding support - many optimizations and bugfixes +- FunCom ISS audio file demuxer and according ADPCM decoding version 0.4.8: diff --git a/doc/general.texi b/doc/general.texi index b594fe157c..17d2cd5cb9 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -74,6 +74,8 @@ library: @tab .fli/.flc files @item FLV @tab X @tab X @tab Macromedia Flash video files +@item FunCom ISS @tab @tab X + @tab Audio format used in various games from FunCom like The Longest Journey. @item GXF @tab X @tab X @tab General eXchange Format SMPTE 360M, used by Thomson Grass Valley playout servers. @@ -385,6 +387,8 @@ following image formats are supported: @item Intel Music Coder @tab @tab X @item Interplay MVE DPCM @tab @tab X @tab Used in various Interplay computer games. +@item ISS IMA ADPCM @tab @tab X + @tab Used in FunCom games. @item MAXIS EA ADPCM @tab @tab X @tab Used in Sim City 3000. @item Microsoft ADPCM @tab X @tab X diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index b13a376ea3..883b723c6f 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -1131,6 +1131,33 @@ static int adpcm_decode_frame(AVCodecContext *avctx, *samples++ = c->status[0].predictor - c->status[1].predictor; } break; + case CODEC_ID_ADPCM_IMA_ISS: + c->status[0].predictor = (int16_t)AV_RL16(src + 0); + c->status[0].step_index = src[2]; + src += 4; + if(st) { + c->status[1].predictor = (int16_t)AV_RL16(src + 0); + c->status[1].step_index = src[2]; + src += 4; + } + + while (src < buf + buf_size) { + + if (st) { + *samples++ = adpcm_ima_expand_nibble(&c->status[0], + src[0] >> 4 , 3); + *samples++ = adpcm_ima_expand_nibble(&c->status[1], + src[0] & 0x0F, 3); + } else { + *samples++ = adpcm_ima_expand_nibble(&c->status[0], + src[0] & 0x0F, 3); + *samples++ = adpcm_ima_expand_nibble(&c->status[0], + src[0] >> 4 , 3); + } + + src++; + } + break; case CODEC_ID_ADPCM_IMA_WS: /* no per-block initialization; just start decoding the data */ while (src < buf + buf_size) { @@ -1641,6 +1668,7 @@ ADPCM_DECODER(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3, "IMA Duck DK3 ADPCM"); ADPCM_DECODER(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4, "IMA Duck DK4 ADPCM"); ADPCM_DECODER(CODEC_ID_ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs, "IMA Electronic Arts EACS ADPCM"); ADPCM_DECODER(CODEC_ID_ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead, "IMA Electronic Arts SEAD ADPCM"); +ADPCM_DECODER(CODEC_ID_ADPCM_IMA_ISS, adpcm_ima_iss, "IMA Funcom ISS ADPCM"); ADPCM_CODEC (CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt, "IMA QuickTime ADPCM"); ADPCM_DECODER(CODEC_ID_ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg, "IMA Loki SDL MJPEG ADPCM"); ADPCM_CODEC (CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav, "IMA Wav ADPCM"); diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 8c3133e735..6c61d44463 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -264,6 +264,7 @@ void avcodec_register_all(void) REGISTER_DECODER (ADPCM_IMA_DK4, adpcm_ima_dk4); REGISTER_DECODER (ADPCM_IMA_EA_EACS, adpcm_ima_ea_eacs); REGISTER_DECODER (ADPCM_IMA_EA_SEAD, adpcm_ima_ea_sead); + REGISTER_DECODER (ADPCM_IMA_ISS, adpcm_ima_iss); REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt); REGISTER_DECODER (ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 4fa2f1ee14..958ba8c30d 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVCODEC_VERSION_MAJOR 52 -#define LIBAVCODEC_VERSION_MINOR 10 +#define LIBAVCODEC_VERSION_MINOR 11 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ @@ -245,6 +245,7 @@ enum CodecID { CODEC_ID_ADPCM_IMA_EA_EACS, CODEC_ID_ADPCM_EA_XAS, CODEC_ID_ADPCM_EA_MAXIS_XA, + CODEC_ID_ADPCM_IMA_ISS, /* AMR */ CODEC_ID_AMR_NB= 0x12000, diff --git a/libavformat/Makefile b/libavformat/Makefile index dd216d5fa0..231afbba6f 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -78,6 +78,7 @@ OBJS-$(CONFIG_IMAGE2PIPE_MUXER) += img2.o OBJS-$(CONFIG_INGENIENT_DEMUXER) += raw.o OBJS-$(CONFIG_IPMOVIE_DEMUXER) += ipmovie.o OBJS-$(CONFIG_IPOD_MUXER) += movenc.o riff.o isom.o avc.o +OBJS-$(CONFIG_ISS_DEMUXER) += iss.o OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o OBJS-$(CONFIG_M4V_DEMUXER) += raw.o OBJS-$(CONFIG_M4V_MUXER) += raw.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 1f695d1f31..c7c0cc83e0 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -101,6 +101,7 @@ void av_register_all(void) REGISTER_DEMUXER (INGENIENT, ingenient); REGISTER_DEMUXER (IPMOVIE, ipmovie); REGISTER_MUXER (IPOD, ipod); + REGISTER_DEMUXER (ISS, iss); REGISTER_DEMUXER (LMLM4, lmlm4); REGISTER_MUXDEMUX (M4V, m4v); REGISTER_MUXDEMUX (MATROSKA, matroska); diff --git a/libavformat/avformat.h b/libavformat/avformat.h index e8b71004e7..0df48ab85b 100644 --- a/libavformat/avformat.h +++ b/libavformat/avformat.h @@ -22,7 +22,7 @@ #define AVFORMAT_AVFORMAT_H #define LIBAVFORMAT_VERSION_MAJOR 52 -#define LIBAVFORMAT_VERSION_MINOR 23 +#define LIBAVFORMAT_VERSION_MINOR 24 #define LIBAVFORMAT_VERSION_MICRO 1 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/libavformat/iss.c b/libavformat/iss.c new file mode 100644 index 0000000000..4a16318481 --- /dev/null +++ b/libavformat/iss.c @@ -0,0 +1,130 @@ +/* + * ISS (.iss) file demuxer + * Copyright (c) 2008 Jaikrishnan Menon + * + * 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 + */ + +/** + * @file iss.c + * Funcom ISS file demuxer + * @author Jaikrishnan Menon + * for more information on the .iss file format, visit: + * http://wiki.multimedia.cx/index.php?title=FunCom_ISS + */ + +#include "avformat.h" +#include "libavutil/avstring.h" + +#define ISS_SIG "IMA_ADPCM_Sound" +#define ISS_SIG_LEN 15 +#define MAX_TOKEN_SIZE 20 + +typedef struct { + int packet_size; + int sample_start_pos; +} IssDemuxContext; + +static void get_token(ByteIOContext *s, char *buf, int maxlen) +{ + int i = 0; + char c; + + while ((c = get_byte(s))) { + if(c == ' ') + break; + if (i < maxlen-1) + buf[i++] = c; + } + + buf[i] = 0; /* Ensure null terminated, but may be truncated */ +} + +static int iss_probe(AVProbeData *p) +{ + if (strncmp(p->buf, ISS_SIG, ISS_SIG_LEN)) + return 0; + + return AVPROBE_SCORE_MAX; +} + +static av_cold int iss_read_header(AVFormatContext *s, AVFormatParameters *ap) +{ + IssDemuxContext *iss = s->priv_data; + ByteIOContext *pb = s->pb; + AVStream *st; + char token[MAX_TOKEN_SIZE]; + int stereo, rate_divisor; + + get_token(pb, token, sizeof(token)); //"IMA_ADPCM_Sound" + get_token(pb, token, sizeof(token)); //packet size + sscanf(token, "%d", &iss->packet_size); + get_token(pb, token, sizeof(token)); //File ID + get_token(pb, token, sizeof(token)); //out size + get_token(pb, token, sizeof(token)); //stereo + sscanf(token, "%d", &stereo); + get_token(pb, token, sizeof(token)); //Unknown1 + get_token(pb, token, sizeof(token)); //RateDivisor + sscanf(token, "%d", &rate_divisor); + get_token(pb, token, sizeof(token)); //Unknown2 + get_token(pb, token, sizeof(token)); //Version ID + get_token(pb, token, sizeof(token)); //Size + + iss->sample_start_pos = url_ftell(pb); + + st = av_new_stream(s, 0); + if (!st) + return AVERROR(ENOMEM); + st->codec->codec_type = CODEC_TYPE_AUDIO; + st->codec->codec_id = CODEC_ID_ADPCM_IMA_ISS; + st->codec->channels = stereo ? 2 : 1; + st->codec->sample_rate = 44100; + if(rate_divisor > 0) + st->codec->sample_rate /= rate_divisor; + st->codec->bits_per_coded_sample = 4; + st->codec->bit_rate = st->codec->channels * st->codec->sample_rate + * st->codec->bits_per_coded_sample; + st->codec->block_align = iss->packet_size; + av_set_pts_info(st, 32, 1, st->codec->sample_rate); + + return 0; +} + +static int iss_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + IssDemuxContext *iss = s->priv_data; + int ret = av_get_packet(s->pb, pkt, iss->packet_size); + + if(ret < 0) + return ret; + + pkt->stream_index = 0; + pkt->pts = url_ftell(s->pb) - iss->sample_start_pos; + if(s->streams[0]->codec->channels > 0) + pkt->pts /= s->streams[0]->codec->channels*2; + return 0; +} + +AVInputFormat iss_demuxer = { + "ISS", + NULL_IF_CONFIG_SMALL("Funcom ISS format"), + sizeof(IssDemuxContext), + iss_probe, + iss_read_header, + iss_read_packet, +}; + -- GitLab