From e7814ed839d16bf2fe1ce3d4954af89b0323c99d Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 3 May 2013 18:07:13 -0300 Subject: [PATCH 1/6] ADPCM DTK decoder Signed-off-by: James Almer --- Changelog | 1 + doc/general.texi | 1 + libavcodec/Makefile | 1 + libavcodec/adpcm.c | 54 +++++++++++++++++++++++++++++++++++++++++ libavcodec/adpcm.h | 4 +-- libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 ++++++ libavcodec/utils.c | 2 ++ libavcodec/version.h | 2 +- 10 files changed, 71 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index c8d4b81d90..b7ade4f5aa 100644 --- a/Changelog +++ b/Changelog @@ -40,6 +40,7 @@ version : - Matroska muxer can now put the index at the beginning of the file. - extractplanes filter - avectorscope filter +- ADPCM DTK decoder version 1.2: diff --git a/doc/general.texi b/doc/general.texi index b6e731a437..215abe6198 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -771,6 +771,7 @@ following image formats are supported: @item ADPCM Microsoft @tab X @tab X @item ADPCM MS IMA @tab X @tab X @item ADPCM Nintendo Gamecube AFC @tab @tab X +@item ADPCM Nintendo Gamecube DTK @tab @tab X @item ADPCM Nintendo Gamecube THP @tab @tab X @item ADPCM QT IMA @tab X @tab X @item ADPCM SEGA CRI ADX @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index ba53df80a5..34fb5c5601 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -569,6 +569,7 @@ OBJS-$(CONFIG_ADPCM_ADX_DECODER) += adxdec.o adx.o OBJS-$(CONFIG_ADPCM_ADX_ENCODER) += adxenc.o adx.o OBJS-$(CONFIG_ADPCM_AFC_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_CT_DECODER) += adpcm.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_DTK_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_EA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_EA_MAXIS_XA_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_EA_R1_DECODER) += adpcm.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index d1c2aa7bdf..4edc46f222 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -95,6 +95,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) unsigned int max_channels = 2; switch(avctx->codec->id) { + case AV_CODEC_ID_ADPCM_DTK: case AV_CODEC_ID_ADPCM_EA: min_channels = 2; break; @@ -147,6 +148,7 @@ static av_cold int adpcm_decode_init(AVCodecContext * avctx) case AV_CODEC_ID_ADPCM_EA_XAS: case AV_CODEC_ID_ADPCM_THP: case AV_CODEC_ID_ADPCM_AFC: + case AV_CODEC_ID_ADPCM_DTK: avctx->sample_fmt = AV_SAMPLE_FMT_S16P; break; case AV_CODEC_ID_ADPCM_IMA_WS: @@ -602,6 +604,9 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, case AV_CODEC_ID_ADPCM_XA: nb_samples = (buf_size / 128) * 224 / ch; break; + case AV_CODEC_ID_ADPCM_DTK: + nb_samples = buf_size / (16 * ch) * 28; + break; } /* validate coded sample count */ @@ -1362,6 +1367,54 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, } break; } + case AV_CODEC_ID_ADPCM_DTK: + for (channel = 0; channel < avctx->channels; channel++) { + samples = samples_p[channel]; + + /* Read in every sample for this channel. */ + for (i = 0; i < nb_samples / 28; i++) { + int byte, header; + if (channel) + bytestream2_skipu(&gb, 1); + header = bytestream2_get_byteu(&gb); + bytestream2_skipu(&gb, 3 - channel); + + /* Decode 28 samples. */ + for (n = 0; n < 28; n++) { + int32_t sampledat, prev; + + switch (header >> 4) { + case 1: + prev = (c->status[channel].sample1 * 0x3c); + break; + case 2: + prev = (c->status[channel].sample1 * 0x73) - (c->status[channel].sample2 * 0x34); + break; + case 3: + prev = (c->status[channel].sample1 * 0x62) - (c->status[channel].sample2 * 0x37); + break; + default: + prev = 0; + } + + prev = av_clip((prev + 0x20) >> 6, -0x200000, 0x1fffff); + + byte = bytestream2_get_byteu(&gb); + if (!channel) + sampledat = sign_extend(byte, 4); + else + sampledat = sign_extend(byte >> 4, 4); + + sampledat = (((sampledat << 12) >> (header & 0xf)) << 6) + prev; + *samples++ = av_clip_int16(sampledat >> 6); + c->status[channel].sample2 = c->status[channel].sample1; + c->status[channel].sample1 = sampledat; + } + } + if (!channel) + bytestream2_seek(&gb, 0, SEEK_SET); + } + break; default: return -1; @@ -1403,6 +1456,7 @@ AVCodec ff_ ## name_ ## _decoder = { \ ADPCM_DECODER(AV_CODEC_ID_ADPCM_4XM, sample_fmts_s16p, adpcm_4xm, "ADPCM 4X Movie"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_AFC, sample_fmts_s16p, adpcm_afc, "ADPCM Nintendo Gamecube AFC"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_CT, sample_fmts_s16, adpcm_ct, "ADPCM Creative Technology"); +ADPCM_DECODER(AV_CODEC_ID_ADPCM_DTK, sample_fmts_s16p, adpcm_dtk, "ADPCM Nintendo Gamecube DTK"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA, sample_fmts_s16, adpcm_ea, "ADPCM Electronic Arts"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_MAXIS_XA, sample_fmts_s16, adpcm_ea_maxis_xa, "ADPCM Electronic Arts Maxis CDROM XA"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_EA_R1, sample_fmts_s16p, adpcm_ea_r1, "ADPCM Electronic Arts R1"); diff --git a/libavcodec/adpcm.h b/libavcodec/adpcm.h index 08fd23f87b..f43a28cafe 100644 --- a/libavcodec/adpcm.h +++ b/libavcodec/adpcm.h @@ -38,8 +38,8 @@ typedef struct ADPCMChannelStatus { int prev_sample; /* MS version */ - int16_t sample1; - int16_t sample2; + int sample1; + int sample2; int coeff1; int coeff2; int idelta; diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index d5b69164e6..145f7e437f 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -419,6 +419,7 @@ void avcodec_register_all(void) REGISTER_ENCDEC (ADPCM_ADX, adpcm_adx); REGISTER_DECODER(ADPCM_AFC, adpcm_afc); REGISTER_DECODER(ADPCM_CT, adpcm_ct); + REGISTER_DECODER(ADPCM_DTK, adpcm_dtk); REGISTER_DECODER(ADPCM_EA, adpcm_ea); REGISTER_DECODER(ADPCM_EA_MAXIS_XA, adpcm_ea_maxis_xa); REGISTER_DECODER(ADPCM_EA_R1, adpcm_ea_r1); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 1978054230..8db0af4849 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -362,6 +362,7 @@ enum AVCodecID { AV_CODEC_ID_VIMA = MKBETAG('V','I','M','A'), AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '), AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '), + AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '), /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index c973025daa..a36aaad71f 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1816,6 +1816,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Dialogic OKI"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_DTK, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_dtk", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube DTK"), + .props = AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 0d8306b54c..2040e6fc0d 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -2835,6 +2835,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) switch (id) { case AV_CODEC_ID_ADPCM_AFC: return frame_bytes / (9 * ch) * 16; + case AV_CODEC_ID_ADPCM_DTK: + return frame_bytes / (16 * ch) * 28; case AV_CODEC_ID_ADPCM_4XM: case AV_CODEC_ID_ADPCM_IMA_ISS: return (frame_bytes - 4 * ch) * 2 / ch; diff --git a/libavcodec/version.h b/libavcodec/version.h index 859ed97abd..e34e506513 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "libavutil/avutil.h" #define LIBAVCODEC_VERSION_MAJOR 55 -#define LIBAVCODEC_VERSION_MINOR 7 +#define LIBAVCODEC_VERSION_MINOR 8 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From b4866f717ced04b85ecfb9f3706b52cf6353280f Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 3 May 2013 18:08:05 -0300 Subject: [PATCH 2/6] ADP demuxer Signed-off-by: James Almer --- Changelog | 1 + doc/general.texi | 2 + libavformat/Makefile | 1 + libavformat/adp.c | 91 ++++++++++++++++++++++++++++++++++++++++ libavformat/allformats.c | 1 + libavformat/version.h | 4 +- tests/fate/adpcm.mak | 3 ++ tests/ref/fate/adpcm-dtk | 33 +++++++++++++++ 8 files changed, 134 insertions(+), 2 deletions(-) create mode 100644 libavformat/adp.c create mode 100644 tests/ref/fate/adpcm-dtk diff --git a/Changelog b/Changelog index b7ade4f5aa..bc02e72e38 100644 --- a/Changelog +++ b/Changelog @@ -41,6 +41,7 @@ version : - extractplanes filter - avectorscope filter - ADPCM DTK decoder +- ADP demuxer version 1.2: diff --git a/doc/general.texi b/doc/general.texi index 215abe6198..6bb3603e14 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -147,6 +147,8 @@ library: @tab Multimedia format used in game Heart Of Darkness. @item Apple HTTP Live Streaming @tab @tab X @item Artworx Data Format @tab @tab X +@item ADP @tab @tab X + @tab Audio format used on the Nintendo Gamecube. @item AFC @tab @tab X @tab Audio format used on the Nintendo Gamecube. @item ASF @tab X @tab X diff --git a/libavformat/Makefile b/libavformat/Makefile index 36797085a0..578b44ccc8 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -55,6 +55,7 @@ OBJS-$(CONFIG_AC3_DEMUXER) += ac3dec.o rawdec.o OBJS-$(CONFIG_AC3_MUXER) += rawenc.o OBJS-$(CONFIG_ACT_DEMUXER) += act.o OBJS-$(CONFIG_ADF_DEMUXER) += bintext.o sauce.o +OBJS-$(CONFIG_ADP_DEMUXER) += adp.o OBJS-$(CONFIG_ADX_DEMUXER) += adxdec.o OBJS-$(CONFIG_ADX_MUXER) += rawenc.o OBJS-$(CONFIG_ADTS_MUXER) += adtsenc.o diff --git a/libavformat/adp.c b/libavformat/adp.c new file mode 100644 index 0000000000..c5feac4fa5 --- /dev/null +++ b/libavformat/adp.c @@ -0,0 +1,91 @@ +/* + * ADP demuxer + * Copyright (c) 2013 James Almer + * + * 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 "libavutil/channel_layout.h" +#include "libavutil/intreadwrite.h" +#include "avformat.h" +#include "internal.h" + +static int adp_probe(AVProbeData *p) +{ + int i; + + if (p->buf_size < 32) + return 0; + + for (i = 0; i < p->buf_size - 3; i+=32) + if (p->buf[i] != p->buf[i+2] || p->buf[i+1] != p->buf[i+3]) + return 0; + + return p->buf_size < 260 ? 1 : AVPROBE_SCORE_MAX / 4; +} + +static int adp_read_header(AVFormatContext *s) +{ + AVStream *st; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + + st->codec->codec_type = AVMEDIA_TYPE_AUDIO; + st->codec->codec_id = AV_CODEC_ID_ADPCM_DTK; + st->codec->channel_layout = AV_CH_LAYOUT_STEREO; + st->codec->channels = 2; + st->codec->sample_rate = 48000; + st->start_time = 0; + if (s->pb->seekable) + st->duration = av_get_audio_frame_duration(st->codec, avio_size(s->pb)); + + avpriv_set_pts_info(st, 64, 1, st->codec->sample_rate); + + return 0; +} + +static int adp_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int ret, size = 1024; + + if (url_feof(s->pb)) + return AVERROR_EOF; + + ret = av_get_packet(s->pb, pkt, size); + + if (ret != size) { + if (ret < 0) { + av_free_packet(pkt); + return ret; + } + av_shrink_packet(pkt, ret); + } + pkt->stream_index = 0; + + return ret; +} + +AVInputFormat ff_adp_demuxer = { + .name = "adp", + .long_name = NULL_IF_CONFIG_SMALL("ADP"), + .read_probe = adp_probe, + .read_header = adp_read_header, + .read_packet = adp_read_packet, + .extensions = "adp,dtk", +}; diff --git a/libavformat/allformats.c b/libavformat/allformats.c index bca2c401a5..b4e1ea8d55 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -65,6 +65,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(AC3, ac3); REGISTER_DEMUXER (ACT, act); REGISTER_DEMUXER (ADF, adf); + REGISTER_DEMUXER (ADP, adp); REGISTER_MUXER (ADTS, adts); REGISTER_MUXDEMUX(ADX, adx); REGISTER_DEMUXER (AEA, aea); diff --git a/libavformat/version.h b/libavformat/version.h index 4666640d02..23bab230f2 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,8 +30,8 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 4 -#define LIBAVFORMAT_VERSION_MICRO 101 +#define LIBAVFORMAT_VERSION_MINOR 5 +#define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ diff --git a/tests/fate/adpcm.mak b/tests/fate/adpcm.mak index 71764cc80f..280eb83db9 100644 --- a/tests/fate/adpcm.mak +++ b/tests/fate/adpcm.mak @@ -16,6 +16,9 @@ fate-adpcm-creative-8-2.6bit: CMD = md5 -i $(SAMPLES)/creative/BBC_3BIT.VOC -f s FATE_ADPCM-$(call DEMDEC, VOC, ADPCM_SBPRO_4) += fate-adpcm-creative-8-4bit fate-adpcm-creative-8-4bit: CMD = md5 -i $(SAMPLES)/creative/BBC_4BIT.VOC -f s16le +FATE_ADPCM-$(call DEMDEC, ADP, ADPCM_DTK) += fate-adpcm-dtk +fate-adpcm-dtk: CMD = framecrc -i $(SAMPLES)/adp/shakespr_partial.adp -f s16le + FATE_ADPCM-$(call DEMDEC, EA, ADPCM_EA) += fate-adpcm-ea-1 fate-adpcm-ea-1: CMD = framecrc -i $(SAMPLES)/ea-wve/networkBackbone-partial.wve -frames:a 26 -vn diff --git a/tests/ref/fate/adpcm-dtk b/tests/ref/fate/adpcm-dtk new file mode 100644 index 0000000000..3640e1cb14 --- /dev/null +++ b/tests/ref/fate/adpcm-dtk @@ -0,0 +1,33 @@ +#tb 0: 1/48000 +0, 0, 0, 896, 3584, 0xdae789d5 +0, 896, 896, 896, 3584, 0x168ed9b6 +0, 1792, 1792, 896, 3584, 0x8920c8d5 +0, 2688, 2688, 896, 3584, 0xaf0a3245 +0, 3584, 3584, 896, 3584, 0x884ee935 +0, 4480, 4480, 896, 3584, 0xe6a832ad +0, 5376, 5376, 896, 3584, 0x1fa12ea2 +0, 6272, 6272, 896, 3584, 0xf119198c +0, 7168, 7168, 896, 3584, 0x0a6dbf72 +0, 8064, 8064, 896, 3584, 0xd3467881 +0, 8960, 8960, 896, 3584, 0x25d504ec +0, 9856, 9856, 896, 3584, 0x452730c9 +0, 10752, 10752, 896, 3584, 0x42b92ff1 +0, 11648, 11648, 896, 3584, 0x85c67bf3 +0, 12544, 12544, 896, 3584, 0xab4d99e9 +0, 13440, 13440, 896, 3584, 0xe5bfc4da +0, 14336, 14336, 896, 3584, 0x7a5210e9 +0, 15232, 15232, 896, 3584, 0x5265fcd3 +0, 16128, 16128, 896, 3584, 0x76531427 +0, 17024, 17024, 896, 3584, 0xb2b8d7ab +0, 17920, 17920, 896, 3584, 0x05a453e8 +0, 18816, 18816, 896, 3584, 0x742c45bb +0, 19712, 19712, 896, 3584, 0x57aaee3b +0, 20608, 20608, 896, 3584, 0x997bf703 +0, 21504, 21504, 896, 3584, 0xe2d14b13 +0, 22400, 22400, 896, 3584, 0xdafbdd2f +0, 23296, 23296, 896, 3584, 0x448cec3a +0, 24192, 24192, 896, 3584, 0xe6f6fb9c +0, 25088, 25088, 896, 3584, 0x0310276a +0, 25984, 25984, 896, 3584, 0x44bf04e9 +0, 26880, 26880, 896, 3584, 0xe2105d33 +0, 27776, 27776, 896, 3584, 0x08b7d5e0 From 22c7784f60c1459ad1b88670857bf71ef2942613 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 10 May 2013 15:42:40 -0300 Subject: [PATCH 3/6] adpcm_thp: Allow the use of extradata for the adpcm table There are several containers that support adpcm_thp (Also known as Gamecube DSP) streams, but only thp files contain the coeff table and previous sample inside each frame. Some don't even contain previous sample information at all. This change will make it easier to implement demuxers for said containers without having to create a new decoder. Signed-off-by: James Almer --- libavcodec/adpcm.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index 4edc46f222..aa2a40f792 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -592,6 +592,10 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, break; } case AV_CODEC_ID_ADPCM_THP: + if (avctx->extradata) { + nb_samples = buf_size / (8 * ch) * 14; + break; + } has_coded_samples = 1; bytestream2_skip(gb, 4); // channel size *coded_samples = bytestream2_get_be32(gb); @@ -1325,6 +1329,18 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, int table[6][16]; int ch; + if (avctx->extradata) { + GetByteContext tb; + if (avctx->extradata_size < 32 * avctx->channels) { + av_log(avctx, AV_LOG_ERROR, "Missing coeff table\n"); + return AVERROR_INVALIDDATA; + } + + bytestream2_init(&tb, avctx->extradata, avctx->extradata_size); + for (i = 0; i < avctx->channels; i++) + for (n = 0; n < 16; n++) + table[i][n] = sign_extend(bytestream2_get_be16u(&tb), 16); + } else { for (i = 0; i < avctx->channels; i++) for (n = 0; n < 16; n++) table[i][n] = sign_extend(bytestream2_get_be16u(&gb), 16); @@ -1334,6 +1350,7 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, c->status[i].sample1 = sign_extend(bytestream2_get_be16u(&gb), 16); c->status[i].sample2 = sign_extend(bytestream2_get_be16u(&gb), 16); } + } for (ch = 0; ch < avctx->channels; ch++) { samples = samples_p[ch]; From d3710c51d9f1128887a471d47747d47e1377ba81 Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 10 May 2013 16:52:10 -0300 Subject: [PATCH 4/6] RSD demuxer Signed-off-by: James Almer --- Changelog | 1 + doc/general.texi | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/rsd.c | 161 +++++++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- tests/fate/demux.mak | 3 + tests/ref/fate/rsd-demux | 1 + 8 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 libavformat/rsd.c create mode 100644 tests/ref/fate/rsd-demux diff --git a/Changelog b/Changelog index bc02e72e38..38035fa75c 100644 --- a/Changelog +++ b/Changelog @@ -42,6 +42,7 @@ version : - avectorscope filter - ADPCM DTK decoder - ADP demuxer +- RSD demuxer version 1.2: diff --git a/doc/general.texi b/doc/general.texi index 6bb3603e14..a11fa5ee62 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -355,6 +355,7 @@ library: @tab Audio and video format used in some games by Entertainment Software Partners. @item RPL/ARMovie @tab @tab X @item Lego Mindstorms RSO @tab X @tab X +@item RSD @tab @tab X @item RTMP @tab X @tab X @tab Output is performed by publishing stream to RTMP server @item RTP @tab X @tab X diff --git a/libavformat/Makefile b/libavformat/Makefile index 578b44ccc8..bd36bcb2d5 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -313,6 +313,7 @@ OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o rm.o rmsipr.o OBJS-$(CONFIG_RM_MUXER) += rmenc.o rm.o OBJS-$(CONFIG_ROQ_DEMUXER) += idroqdec.o OBJS-$(CONFIG_ROQ_MUXER) += idroqenc.o rawenc.o +OBJS-$(CONFIG_RSD_DEMUXER) += rsd.o OBJS-$(CONFIG_RSO_DEMUXER) += rsodec.o rso.o pcm.o OBJS-$(CONFIG_RSO_MUXER) += rsoenc.o rso.o OBJS-$(CONFIG_RPL_DEMUXER) += rpl.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index b4e1ea8d55..668719adc3 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -237,6 +237,7 @@ void av_register_all(void) REGISTER_MUXDEMUX(RM, rm); REGISTER_MUXDEMUX(ROQ, roq); REGISTER_DEMUXER (RPL, rpl); + REGISTER_DEMUXER (RSD, rsd); REGISTER_MUXDEMUX(RSO, rso); REGISTER_MUXDEMUX(RTP, rtp); REGISTER_MUXDEMUX(RTSP, rtsp); diff --git a/libavformat/rsd.c b/libavformat/rsd.c new file mode 100644 index 0000000000..b9352551c7 --- /dev/null +++ b/libavformat/rsd.c @@ -0,0 +1,161 @@ +/* + * RSD demuxer + * Copyright (c) 2013 James Almer + * + * 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 const AVCodecTag rsd_tags[] = { + { AV_CODEC_ID_ADPCM_THP, MKTAG('G','A','D','P') }, + { AV_CODEC_ID_PCM_S16BE, MKTAG('P','C','M','B') }, + { AV_CODEC_ID_PCM_S16LE, MKTAG('P','C','M',' ') }, + { AV_CODEC_ID_NONE, 0 }, +}; + +static const uint32_t rsd_unsupported_tags[] = { + MKTAG('O','G','G',' '), + MKTAG('R','A','D','P'), + MKTAG('V','A','G',' '), + MKTAG('W','A','D','P'), + MKTAG('X','A','D','P'), + MKTAG('X','M','A',' '), +}; + +static int rsd_probe(AVProbeData *p) +{ + if (!memcmp(p->buf, "RSD", 3) && + p->buf[3] - '0' >= 2 && p->buf[3] - '0' <= 6) + return AVPROBE_SCORE_EXTENSION; + return 0; +} + +static int rsd_read_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + int i, version, start = 0x800; + AVCodecContext *codec; + AVStream *st = avformat_new_stream(s, NULL); + + if (!st) + return AVERROR(ENOMEM); + + avio_skip(pb, 3); // "RSD" + version = avio_r8(pb) - '0'; + + codec = st->codec; + codec->codec_type = AVMEDIA_TYPE_AUDIO; + codec->codec_tag = avio_rl32(pb); + codec->codec_id = ff_codec_get_id(rsd_tags, codec->codec_tag); + if (!codec->codec_id) { + char tag_buf[5]; + + av_get_codec_tag_string(tag_buf, sizeof(tag_buf), codec->codec_tag); + for (i=0; i < FF_ARRAY_ELEMS(rsd_unsupported_tags); i++) { + if (codec->codec_tag == rsd_unsupported_tags[i]) { + avpriv_request_sample(s, "Codec tag: %s", tag_buf); + return AVERROR_PATCHWELCOME; + } + } + av_log(s, AV_LOG_ERROR, "Unknown codec tag: %s\n", tag_buf); + return AVERROR_INVALIDDATA; + } + + codec->channels = avio_rl32(pb); + if (!codec->channels) + return AVERROR_INVALIDDATA; + + avio_skip(pb, 4); // Bit depth + codec->sample_rate = avio_rl32(pb); + if (!codec->sample_rate) + return AVERROR_INVALIDDATA; + + avio_skip(pb, 4); // Unknown + + switch (codec->codec_id) { + case AV_CODEC_ID_ADPCM_THP: + /* RSD3GADP is mono, so only alloc enough memory + to store the coeff table for a single channel. */ + + codec->extradata_size = 32; + codec->extradata = av_malloc(codec->extradata_size); + if (!codec->extradata) + return AVERROR(ENOMEM); + + start = avio_rl32(pb); + + if (avio_read(s->pb, codec->extradata, 32) != 32) + return AVERROR_INVALIDDATA; + + for (i = 0; i < 16; i++) + AV_WB16(codec->extradata + i * 2, AV_RL16(codec->extradata + i * 2)); + + if (pb->seekable) + st->duration = (avio_size(pb) - start) / 8 * 14; + break; + case AV_CODEC_ID_PCM_S16LE: + case AV_CODEC_ID_PCM_S16BE: + if (version != 4) + start = avio_rl32(pb); + + if (pb->seekable) + st->duration = (avio_size(pb) - start) / 2 / codec->channels; + break; + } + + avio_skip(pb, start - avio_tell(pb)); + + avpriv_set_pts_info(st, 64, 1, codec->sample_rate); + + return 0; +} + +static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + int ret, size = 1024; + + if (url_feof(s->pb)) + return AVERROR_EOF; + + ret = av_get_packet(s->pb, pkt, size); + + if (ret != size) { + if (ret < 0) { + av_free_packet(pkt); + return ret; + } + av_shrink_packet(pkt, ret); + } + pkt->stream_index = 0; + + return ret; +} + +AVInputFormat ff_rsd_demuxer = { + .name = "rsd", + .long_name = NULL_IF_CONFIG_SMALL("GameCube RSD"), + .read_probe = rsd_probe, + .read_header = rsd_read_header, + .read_packet = rsd_read_packet, + .extensions = "rsd", + .codec_tag = (const AVCodecTag* const []){rsd_tags, 0}, +}; diff --git a/libavformat/version.h b/libavformat/version.h index 23bab230f2..84f8552cad 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 5 +#define LIBAVFORMAT_VERSION_MINOR 6 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index dcbb7b4e9c..df112ed5b0 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -67,6 +67,9 @@ fate-paf-demux: CMD = framecrc -i $(SAMPLES)/paf/hod1-partial.paf -vcodec copy - FATE_SAMPLES_DEMUX-$(CONFIG_PMP_DEMUXER) += fate-pmp-demux fate-pmp-demux: CMD = framecrc -i $(SAMPLES)/pmp/demo.pmp -vn -c:a copy +FATE_SAMPLES_DEMUX-$(CONFIG_RSD_DEMUXER) += fate-rsd-demux +fate-rsd-demux: CMD = crc -i $(SAMPLES)/rsd/hum01_partial.rsd -c:a copy + FATE_SAMPLES_DEMUX-$(CONFIG_STR_DEMUXER) += fate-psx-str-demux fate-psx-str-demux: CMD = framecrc -i $(SAMPLES)/psx-str/descent-partial.str -c copy diff --git a/tests/ref/fate/rsd-demux b/tests/ref/fate/rsd-demux new file mode 100644 index 0000000000..3aa2573f78 --- /dev/null +++ b/tests/ref/fate/rsd-demux @@ -0,0 +1 @@ +CRC=0x7b7807d8 From e5e86db178b76026981f97889365ca9701705f2b Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 10 May 2013 16:53:02 -0300 Subject: [PATCH 5/6] RedSpark demuxer Signed-off-by: James Almer --- Changelog | 1 + doc/general.texi | 1 + libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/redspark.c | 157 ++++++++++++++++++++++++++++++++++ libavformat/version.h | 2 +- tests/fate/demux.mak | 3 + tests/ref/fate/redspark-demux | 1 + 8 files changed, 166 insertions(+), 1 deletion(-) create mode 100644 libavformat/redspark.c create mode 100644 tests/ref/fate/redspark-demux diff --git a/Changelog b/Changelog index 38035fa75c..41d84a4780 100644 --- a/Changelog +++ b/Changelog @@ -43,6 +43,7 @@ version : - ADPCM DTK decoder - ADP demuxer - RSD demuxer +- RedSpark demuxer version 1.2: diff --git a/doc/general.texi b/doc/general.texi index a11fa5ee62..ff9858c2ba 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -350,6 +350,7 @@ library: @tab File format used by RED Digital cameras, contains JPEG 2000 frames and PCM audio. @item RealMedia @tab X @tab X @item Redirector @tab @tab X +@item RedSpark @tab @tab X @item Renderware TeXture Dictionary @tab @tab X @item RL2 @tab @tab X @tab Audio and video format used in some games by Entertainment Software Partners. diff --git a/libavformat/Makefile b/libavformat/Makefile index bd36bcb2d5..24dd3cdc3f 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -308,6 +308,7 @@ OBJS-$(CONFIG_R3D_DEMUXER) += r3d.o OBJS-$(CONFIG_RAWVIDEO_DEMUXER) += rawvideodec.o OBJS-$(CONFIG_RAWVIDEO_MUXER) += rawenc.o OBJS-$(CONFIG_REALTEXT_DEMUXER) += realtextdec.o subtitles.o +OBJS-$(CONFIG_REDSPARK_DEMUXER) += redspark.o OBJS-$(CONFIG_RL2_DEMUXER) += rl2.o OBJS-$(CONFIG_RM_DEMUXER) += rmdec.o rm.o rmsipr.o OBJS-$(CONFIG_RM_MUXER) += rmenc.o rm.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index 668719adc3..2b2d46dee1 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -233,6 +233,7 @@ void av_register_all(void) REGISTER_DEMUXER (R3D, r3d); REGISTER_MUXDEMUX(RAWVIDEO, rawvideo); REGISTER_DEMUXER (REALTEXT, realtext); + REGISTER_DEMUXER (REDSPARK, redspark); REGISTER_DEMUXER (RL2, rl2); REGISTER_MUXDEMUX(RM, rm); REGISTER_MUXDEMUX(ROQ, roq); diff --git a/libavformat/redspark.c b/libavformat/redspark.c new file mode 100644 index 0000000000..f98c1156ed --- /dev/null +++ b/libavformat/redspark.c @@ -0,0 +1,157 @@ +/* + * RedSpark demuxer + * Copyright (c) 2013 James Almer + * + * 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" + +#define HEADER_SIZE 4096 + +typedef struct RedSparkContext { + int samples_count; +} RedSparkContext; + +static int redspark_probe(AVProbeData *p) +{ + uint32_t key, data; + uint8_t header[8]; + + /* Decrypt first 8 bytes of the header */ + data = AV_RB32(p->buf); + data = data ^ (key = data ^ 0x52656453); + AV_WB32(header, data); + key = (key << 11) | (key >> 21); + + data = AV_RB32(p->buf + 4) ^ (((key << 3) | (key >> 29)) + key); + AV_WB32(header + 4, data); + + if (AV_RB64(header) == AV_RB64("RedSpark")) + return AVPROBE_SCORE_MAX; + + return 0; +} + +static int redspark_read_header(AVFormatContext *s) +{ + AVIOContext *pb = s->pb; + RedSparkContext *redspark = s->priv_data; + AVCodecContext *codec; + GetByteContext gbc; + int i, coef_off; + uint32_t key, data; + uint8_t *header, *pbc; + AVStream *st; + + st = avformat_new_stream(s, NULL); + if (!st) + return AVERROR(ENOMEM); + codec = st->codec; + + header = av_malloc(HEADER_SIZE); + if (!header) + return AVERROR(ENOMEM); + pbc = header; + + /* Decrypt header */ + data = avio_rb32(pb); + data = data ^ (key = data ^ 0x52656453); + bytestream_put_be32(&pbc, data); + key = (key << 11) | (key >> 21); + + for (i = 4; i < HEADER_SIZE; i += 4) { + data = avio_rb32(pb) ^ (key = ((key << 3) | (key >> 29)) + key); + bytestream_put_be32(&pbc, data); + } + + codec->codec_id = AV_CODEC_ID_ADPCM_THP; + codec->codec_type = AVMEDIA_TYPE_AUDIO; + + bytestream2_init(&gbc, header, HEADER_SIZE); + bytestream2_seek(&gbc, 0x3c, SEEK_SET); + codec->sample_rate = bytestream2_get_be32u(&gbc); + if (codec->sample_rate <= 0 || codec->sample_rate > 96000) { + av_log(s, AV_LOG_ERROR, "Invalid sample rate: %d\n", codec->sample_rate); + return AVERROR_INVALIDDATA; + } + + st->duration = bytestream2_get_be32u(&gbc) * 14; + redspark->samples_count = 0; + bytestream2_skipu(&gbc, 10); + codec->channels = bytestream2_get_byteu(&gbc); + if (!codec->channels) + return AVERROR_INVALIDDATA; + + coef_off = 0x54 + codec->channels * 8; + if (bytestream2_get_byteu(&gbc)) // Loop flag + coef_off += 16; + + codec->extradata_size = 32 * codec->channels; + codec->extradata = av_malloc(codec->extradata_size); + if (!codec->extradata) + return AVERROR(ENOMEM); + + /* Get the ADPCM table */ + bytestream2_seek(&gbc, coef_off, SEEK_SET); + for (i = 0; i < codec->channels; i++) { + if (bytestream2_get_bufferu(&gbc, codec->extradata + i * 32, 32) != 32) + return AVERROR_INVALIDDATA; + bytestream2_skipu(&gbc, 14); + } + + avpriv_set_pts_info(st, 64, 1, codec->sample_rate); + + return 0; +} + +static int redspark_read_packet(AVFormatContext *s, AVPacket *pkt) +{ + AVCodecContext *codec = s->streams[0]->codec; + RedSparkContext *redspark = s->priv_data; + uint32_t size = 8 * codec->channels; + int ret; + + if (url_feof(s->pb) || redspark->samples_count == s->streams[0]->duration) + return AVERROR_EOF; + + ret = av_get_packet(s->pb, pkt, size); + if (ret != size) { + av_free_packet(pkt); + return AVERROR(EIO); + } + + pkt->duration = 14; + redspark->samples_count += pkt->duration; + pkt->stream_index = 0; + + return ret; +} + +AVInputFormat ff_redspark_demuxer = { + .name = "redspark", + .long_name = NULL_IF_CONFIG_SMALL("RedSpark"), + .priv_data_size = sizeof(RedSparkContext), + .read_probe = redspark_probe, + .read_header = redspark_read_header, + .read_packet = redspark_read_packet, + .extensions = "rsd", +}; diff --git a/libavformat/version.h b/libavformat/version.h index 84f8552cad..e9fd748c7a 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -30,7 +30,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 55 -#define LIBAVFORMAT_VERSION_MINOR 6 +#define LIBAVFORMAT_VERSION_MINOR 7 #define LIBAVFORMAT_VERSION_MICRO 100 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ diff --git a/tests/fate/demux.mak b/tests/fate/demux.mak index df112ed5b0..ce54f8f9a1 100644 --- a/tests/fate/demux.mak +++ b/tests/fate/demux.mak @@ -70,6 +70,9 @@ fate-pmp-demux: CMD = framecrc -i $(SAMPLES)/pmp/demo.pmp -vn -c:a copy FATE_SAMPLES_DEMUX-$(CONFIG_RSD_DEMUXER) += fate-rsd-demux fate-rsd-demux: CMD = crc -i $(SAMPLES)/rsd/hum01_partial.rsd -c:a copy +FATE_SAMPLES_DEMUX-$(CONFIG_REDSPARK_DEMUXER) += fate-redspark-demux +fate-redspark-demux: CMD = crc -i $(SAMPLES)/redspark/jingle04_partial.rsd -c:a copy + FATE_SAMPLES_DEMUX-$(CONFIG_STR_DEMUXER) += fate-psx-str-demux fate-psx-str-demux: CMD = framecrc -i $(SAMPLES)/psx-str/descent-partial.str -c copy diff --git a/tests/ref/fate/redspark-demux b/tests/ref/fate/redspark-demux new file mode 100644 index 0000000000..fadfe933ed --- /dev/null +++ b/tests/ref/fate/redspark-demux @@ -0,0 +1 @@ +CRC=0xc0fd1aa2 From 67fad0d221458d43edb9037c30171d0adb1d609a Mon Sep 17 00:00:00 2001 From: James Almer Date: Fri, 10 May 2013 16:53:50 -0300 Subject: [PATCH 6/6] ADPCM IMA Radical decoder Signed-off-by: James Almer --- Changelog | 1 + doc/general.texi | 1 + libavcodec/Makefile | 1 + libavcodec/adpcm.c | 31 +++++++++++++++++++++++++++++++ libavcodec/allcodecs.c | 1 + libavcodec/avcodec.h | 1 + libavcodec/codec_desc.c | 7 +++++++ libavcodec/utils.c | 2 ++ libavcodec/version.h | 2 +- libavformat/rsd.c | 13 +++++++++++-- tests/fate/adpcm.mak | 3 +++ tests/ref/fate/adpcm-ima-rad | 1 + 12 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 tests/ref/fate/adpcm-ima-rad diff --git a/Changelog b/Changelog index 41d84a4780..98c06227a2 100644 --- a/Changelog +++ b/Changelog @@ -44,6 +44,7 @@ version : - ADP demuxer - RSD demuxer - RedSpark demuxer +- ADPCM IMA Radical decoder version 1.2: diff --git a/doc/general.texi b/doc/general.texi index ff9858c2ba..4f45497fa6 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -772,6 +772,7 @@ following image formats are supported: @tab Used in some Sega Saturn console games. @item ADPCM IMA Duck DK4 @tab @tab X @tab Used in some Sega Saturn console games. +@item ADPCM IMA Radical @tab @tab X @item ADPCM Microsoft @tab X @tab X @item ADPCM MS IMA @tab X @tab X @item ADPCM Nintendo Gamecube AFC @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 34fb5c5601..49455924f7 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -590,6 +590,7 @@ OBJS-$(CONFIG_ADPCM_IMA_ISS_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_OKI_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_QT_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_QT_ENCODER) += adpcmenc.o adpcm_data.o +OBJS-$(CONFIG_ADPCM_IMA_RAD_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_SMJPEG_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WAV_DECODER) += adpcm.o adpcm_data.o OBJS-$(CONFIG_ADPCM_IMA_WAV_ENCODER) += adpcmenc.o adpcm_data.o diff --git a/libavcodec/adpcm.c b/libavcodec/adpcm.c index aa2a40f792..1259bd4df6 100644 --- a/libavcodec/adpcm.c +++ b/libavcodec/adpcm.c @@ -551,6 +551,11 @@ static int get_nb_samples(AVCodecContext *avctx, GetByteContext *gb, buf_size = FFMIN(buf_size, avctx->block_align); nb_samples = 1 + (buf_size - 4 * ch) * 2 / ch; break; + case AV_CODEC_ID_ADPCM_IMA_RAD: + if (avctx->block_align > 0) + buf_size = FFMIN(buf_size, avctx->block_align); + nb_samples = (buf_size - 4 * ch) * 2 / ch; + break; case AV_CODEC_ID_ADPCM_IMA_WAV: if (avctx->block_align > 0) buf_size = FFMIN(buf_size, avctx->block_align); @@ -912,6 +917,31 @@ static int adpcm_decode_frame(AVCodecContext *avctx, void *data, *samples++ = adpcm_ima_oki_expand_nibble(&c->status[st], v & 0x0F); } break; + case AV_CODEC_ID_ADPCM_IMA_RAD: + for (channel = 0; channel < avctx->channels; channel++) { + cs = &c->status[channel]; + cs->step_index = sign_extend(bytestream2_get_le16u(&gb), 16); + cs->predictor = sign_extend(bytestream2_get_le16u(&gb), 16); + if (cs->step_index > 88u){ + av_log(avctx, AV_LOG_ERROR, "ERROR: step_index[%d] = %i\n", + channel, cs->step_index); + return AVERROR_INVALIDDATA; + } + } + for (n = 0; n < nb_samples / 2; n++) { + int byte[2]; + + byte[0] = bytestream2_get_byteu(&gb); + if (st) + byte[1] = bytestream2_get_byteu(&gb); + for(channel = 0; channel < avctx->channels; channel++) { + *samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] & 0x0F, 3); + } + for(channel = 0; channel < avctx->channels; channel++) { + *samples++ = adpcm_ima_expand_nibble(&c->status[channel], byte[channel] >> 4 , 3); + } + } + break; case AV_CODEC_ID_ADPCM_IMA_WS: if (c->vqa_version == 3) { for (channel = 0; channel < avctx->channels; channel++) { @@ -1489,6 +1519,7 @@ ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_EA_SEAD, sample_fmts_s16, adpcm_ima_ea_sead ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_ISS, sample_fmts_s16, adpcm_ima_iss, "ADPCM IMA Funcom ISS"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_OKI, sample_fmts_s16, adpcm_ima_oki, "ADPCM IMA Dialogic OKI"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_QT, sample_fmts_s16p, adpcm_ima_qt, "ADPCM IMA QuickTime"); +ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_RAD, sample_fmts_s16, adpcm_ima_rad, "ADPCM IMA Radical"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_SMJPEG, sample_fmts_s16, adpcm_ima_smjpeg, "ADPCM IMA Loki SDL MJPEG"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WAV, sample_fmts_s16p, adpcm_ima_wav, "ADPCM IMA WAV"); ADPCM_DECODER(AV_CODEC_ID_ADPCM_IMA_WS, sample_fmts_both, adpcm_ima_ws, "ADPCM IMA Westwood"); diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index 145f7e437f..4d5af67dce 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -437,6 +437,7 @@ void avcodec_register_all(void) REGISTER_DECODER(ADPCM_IMA_ISS, adpcm_ima_iss); REGISTER_DECODER(ADPCM_IMA_OKI, adpcm_ima_oki); REGISTER_ENCDEC (ADPCM_IMA_QT, adpcm_ima_qt); + REGISTER_DECODER(ADPCM_IMA_RAD, adpcm_ima_rad); REGISTER_DECODER(ADPCM_IMA_SMJPEG, adpcm_ima_smjpeg); REGISTER_ENCDEC (ADPCM_IMA_WAV, adpcm_ima_wav); REGISTER_DECODER(ADPCM_IMA_WS, adpcm_ima_ws); diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h index 8db0af4849..21e585684f 100644 --- a/libavcodec/avcodec.h +++ b/libavcodec/avcodec.h @@ -363,6 +363,7 @@ enum AVCodecID { AV_CODEC_ID_ADPCM_AFC = MKBETAG('A','F','C',' '), AV_CODEC_ID_ADPCM_IMA_OKI = MKBETAG('O','K','I',' '), AV_CODEC_ID_ADPCM_DTK = MKBETAG('D','T','K',' '), + AV_CODEC_ID_ADPCM_IMA_RAD = MKBETAG('R','A','D',' '), /* AMR */ AV_CODEC_ID_AMR_NB = 0x12000, diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index a36aaad71f..b4fdd9422f 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -1823,6 +1823,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("ADPCM Nintendo Gamecube DTK"), .props = AV_CODEC_PROP_LOSSY, }, + { + .id = AV_CODEC_ID_ADPCM_IMA_RAD, + .type = AVMEDIA_TYPE_AUDIO, + .name = "adpcm_ima_rad", + .long_name = NULL_IF_CONFIG_SMALL("ADPCM IMA Radical"), + .props = AV_CODEC_PROP_LOSSY, + }, /* AMR */ { diff --git a/libavcodec/utils.c b/libavcodec/utils.c index 2040e6fc0d..d647a23289 100644 --- a/libavcodec/utils.c +++ b/libavcodec/utils.c @@ -2883,6 +2883,8 @@ int av_get_audio_frame_duration(AVCodecContext *avctx, int frame_bytes) return blocks * (((ba - 16) * 2 / 3 * 4) / ch); case AV_CODEC_ID_ADPCM_IMA_DK4: return blocks * (1 + (ba - 4 * ch) * 2 / ch); + case AV_CODEC_ID_ADPCM_IMA_RAD: + return blocks * ((ba - 4 * ch) * 2 / ch); case AV_CODEC_ID_ADPCM_MS: return blocks * (2 + (ba - 7 * ch) * 2 / ch); } diff --git a/libavcodec/version.h b/libavcodec/version.h index e34e506513..f5aa53b68d 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,7 +29,7 @@ #include "libavutil/avutil.h" #define LIBAVCODEC_VERSION_MAJOR 55 -#define LIBAVCODEC_VERSION_MINOR 8 +#define LIBAVCODEC_VERSION_MINOR 9 #define LIBAVCODEC_VERSION_MICRO 100 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ diff --git a/libavformat/rsd.c b/libavformat/rsd.c index b9352551c7..5b53cef9c0 100644 --- a/libavformat/rsd.c +++ b/libavformat/rsd.c @@ -27,6 +27,7 @@ static const AVCodecTag rsd_tags[] = { { AV_CODEC_ID_ADPCM_THP, MKTAG('G','A','D','P') }, + { AV_CODEC_ID_ADPCM_IMA_RAD, MKTAG('R','A','D','P') }, { AV_CODEC_ID_PCM_S16BE, MKTAG('P','C','M','B') }, { AV_CODEC_ID_PCM_S16LE, MKTAG('P','C','M',' ') }, { AV_CODEC_ID_NONE, 0 }, @@ -34,7 +35,6 @@ static const AVCodecTag rsd_tags[] = { static const uint32_t rsd_unsupported_tags[] = { MKTAG('O','G','G',' '), - MKTAG('R','A','D','P'), MKTAG('V','A','G',' '), MKTAG('W','A','D','P'), MKTAG('X','A','D','P'), @@ -92,6 +92,11 @@ static int rsd_read_header(AVFormatContext *s) avio_skip(pb, 4); // Unknown switch (codec->codec_id) { + case AV_CODEC_ID_ADPCM_IMA_RAD: + codec->block_align = 20 * codec->channels; + if (pb->seekable) + st->duration = av_get_audio_frame_duration(codec, avio_size(pb) - start); + break; case AV_CODEC_ID_ADPCM_THP: /* RSD3GADP is mono, so only alloc enough memory to store the coeff table for a single channel. */ @@ -131,12 +136,16 @@ static int rsd_read_header(AVFormatContext *s) static int rsd_read_packet(AVFormatContext *s, AVPacket *pkt) { + AVCodecContext *codec = s->streams[0]->codec; int ret, size = 1024; if (url_feof(s->pb)) return AVERROR_EOF; - ret = av_get_packet(s->pb, pkt, size); + if (codec->codec_id == AV_CODEC_ID_ADPCM_IMA_RAD) + ret = av_get_packet(s->pb, pkt, codec->block_align); + else + ret = av_get_packet(s->pb, pkt, size); if (ret != size) { if (ret < 0) { diff --git a/tests/fate/adpcm.mak b/tests/fate/adpcm.mak index 280eb83db9..c87d7c9b04 100644 --- a/tests/fate/adpcm.mak +++ b/tests/fate/adpcm.mak @@ -61,6 +61,9 @@ fate-adpcm-ima-iss: CMD = md5 -i $(SAMPLES)/funcom-iss/0004010100.iss -f s16le FATE_ADPCM-$(call DEMDEC, WAV, ADPCM_IMA_OKI) += fate-adpcm-ima-oki fate-adpcm-ima-oki: CMD = md5 -i $(SAMPLES)/oki/test.wav -f s16le +FATE_ADPCM-$(call DEMDEC, RSD, ADPCM_IMA_RAD) += fate-adpcm-ima-rad +fate-adpcm-ima-rad: CMD = md5 -i $(SAMPLES)/rsd/hit_run_partial.rsd -f s16le + FATE_ADPCM-$(call DEMDEC, SMJPEG, ADPCM_IMA_SMJPEG) += fate-adpcm-ima-smjpeg fate-adpcm-ima-smjpeg: CMD = framecrc -i $(SAMPLES)/smjpeg/scenwin.mjpg -vn diff --git a/tests/ref/fate/adpcm-ima-rad b/tests/ref/fate/adpcm-ima-rad new file mode 100644 index 0000000000..c5de1a64e6 --- /dev/null +++ b/tests/ref/fate/adpcm-ima-rad @@ -0,0 +1 @@ +495f0ae514c28c6bdcbd40811a17e2a5