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