diff mbox series

[FFmpeg-devel,v2,1/2] avcodec: add decoder for argonaut games' adpcm codec

Message ID 20200119083325.3377-2-zane@zanevaniperen.com
State Superseded
Headers show
Series Argonaut Games ASF and ADPCM decoding support | expand

Checks

Context Check Description
andriy/ffmpeg-patchwork success Make fate finished

Commit Message

Zane van Iperen Jan. 19, 2020, 8:33 a.m. UTC
Adds support for the ADPCM variant used by some Argonaut Games' games,
such as 'Croc! Legend of the Gobbos', and 'Croc 2'.

Signed-off-by: Zane van Iperen <zane@zanevaniperen.com>
---
 Changelog               |   2 +-
 doc/general.texi        |   1 +
 libavcodec/Makefile     |   1 +
 libavcodec/adpcm_argo.c | 264 ++++++++++++++++++++++++++++++++++++++++
 libavcodec/allcodecs.c  |   1 +
 libavcodec/avcodec.h    |   1 +
 libavcodec/codec_desc.c |   7 ++
 libavcodec/version.h    |   2 +-
 8 files changed, 277 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/adpcm_argo.c

Comments

Moritz Barsnick Jan. 19, 2020, 1:22 p.m. UTC | #1
On Sun, Jan 19, 2020 at 08:33:39 +0000, Zane van Iperen wrote:
> Adds support for the ADPCM variant used by some Argonaut Games' games,
> such as 'Croc! Legend of the Gobbos', and 'Croc 2'.

Some small nitpicks here:

>  - thistogram filter
>  - freezeframes filter
> -
> +- Argonaut Games ADPCM decoder
>

Please don't steal the empty line. ;-)

> +static int16_t *adpcm_decoder_1(uint8_t c, int16_t *dst, const uint8_t *src,
> +                          const int16_t *prev_,
> +                          int nsamples, int stride)

The arguments are usually aligned after line breaks - check other
implementation within ffmpeg.

> +    for (int i = 0; i < nsamples / 2; ++i, ++src) {

ffmpeg prefers the '++' after the variable, not before.
(And some developers prefer you to declare the iterator 'i' outside of
the loop, though I believe the rules on that have changed.)

> +        s = (int8_t) ((*src & 0xF0u) << 0u);

Keep the typecast aligned with the value, no space.

> +        dst += stride;
> +
> +        s = (int8_t) ((*src & 0x0Fu) << 4u);

Ditto.

All comments apply to adpcm_decoder_2() and other functions as well.

> +    unsigned char c;

I'm wondering whether you could stick to uint8_t consistenly?

> +#define MAX_CHANNELS (2)
> +#define PREVIOUS_SAMPLE_COUNT (2)

These brackets aren't required.

> +static av_cold int adpcm_decode_init(AVCodecContext *avctx)
> +{
> +    ADPCMArgoDecoderContext *ctx = avctx->priv_data;
> +
> +    if (avctx->channels > MAX_CHANNELS) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid channel count %d\n", avctx->channels);
> +        return AVERROR(EINVAL);
> +    }
> +
> +    if (avctx->bits_per_coded_sample != 4) {
> +        av_log(avctx, AV_LOG_ERROR, "Invalid number of bits %d\n", avctx->bits_per_coded_sample);
> +        return AVERROR(EINVAL);
> +    }

These should probably be AVERROR_INVALIDDATA. AVERROR(EINVAL) is
"invalid arguments", i.e. if the user supplied an option value which is
not valid.

> +static int adpcm_decode_frame(AVCodecContext * avctx, void *data,
> +                                 int *got_frame_ptr, AVPacket * avpkt)

The '*' aligns with the variable name.

> +    if (avctx->channels == 1 && avpkt->size != 17) {
> +        av_log(avctx, AV_LOG_WARNING,
> +               "unexpected mono packet size, expected 17, got %d\n",
> +               avpkt->size);
> +    } else if(avctx->channels == 2 && avpkt->size != 34) {

Add a space: "if (".

> +    if ((r = ff_get_buffer(avctx, frame, 0)) < 0)
> +        return r;

ffmpeg uses "ret", consistently.

> +    dst = adpcm_decode_block((int16_t *) frame->data[0], avpkt->data, argo->prev, frame->nb_samples, avctx->channels);

Typecast aligns with the value, no space inserted.

Cheers,
Moritz
Zane van Iperen Jan. 19, 2020, 2:21 p.m. UTC | #2
On 19/1/20 11:22 pm, Moritz Barsnick wrote:
> 
> On Sun, Jan 19, 2020 at 08:33:39 +0000, Zane van Iperen wrote:
>> Adds support for the ADPCM variant used by some Argonaut Games' games,
>> such as 'Croc! Legend of the Gobbos', and 'Croc 2'.
> 
> Some small nitpicks here:
> 
>>   - thistogram filter
>>   - freezeframes filter
>> -
>> +- Argonaut Games ADPCM decoder
>>
> 
> Please don't steal the empty line. ;-)
> 

I didn't even notice that!

>> +static int16_t *adpcm_decoder_1(uint8_t c, int16_t *dst, const uint8_t *src,
>> +                          const int16_t *prev_,
>> +                          int nsamples, int stride)
> 
> The arguments are usually aligned after line breaks - check other
> implementation within ffmpeg.
>

Fixed.

>> +    for (int i = 0; i < nsamples / 2; ++i, ++src) {
> 
> ffmpeg prefers the '++' after the variable, not before.
> (And some developers prefer you to declare the iterator 'i' outside of
> the loop, though I believe the rules on that have changed.)
> 

According to https://www.ffmpeg.org/developer.html, declaring 'i' in the loop
is allowed.

$ git grep 'i++' | wc -l
10442
$ git grep '++i' | wc -l
292

...Okay, fixed.

>> +        s = (int8_t) ((*src & 0xF0u) << 0u);
> 
> Keep the typecast aligned with the value, no space.
> 

Fixed.

>> +        dst += stride;
>> +
>> +        s = (int8_t) ((*src & 0x0Fu) << 4u);
> 
> Ditto.

Fixed.

> 
> All comments apply to adpcm_decoder_2() and other functions as well.
> 
>> +    unsigned char c;
> 
> I'm wondering whether you could stick to uint8_t consistenly?
> 

Fixed, that was a relic from a much earlier version of the code.

>> +#define MAX_CHANNELS (2)
>> +#define PREVIOUS_SAMPLE_COUNT (2)
> 
> These brackets aren't required.
> 

Fixed.

>> +static av_cold int adpcm_decode_init(AVCodecContext *avctx)
>> +{
>> +    ADPCMArgoDecoderContext *ctx = avctx->priv_data;
>> +
>> +    if (avctx->channels > MAX_CHANNELS) {
>> +        av_log(avctx, AV_LOG_ERROR, "Invalid channel count %d\n", avctx->channels);
>> +        return AVERROR(EINVAL);
>> +    }
>> +
>> +    if (avctx->bits_per_coded_sample != 4) {
>> +        av_log(avctx, AV_LOG_ERROR, "Invalid number of bits %d\n", avctx->bits_per_coded_sample);
>> +        return AVERROR(EINVAL);
>> +    }
> 
> These should probably be AVERROR_INVALIDDATA. AVERROR(EINVAL) is
> "invalid arguments", i.e. if the user supplied an option value which is
> not valid.
> 

Fixed.

>> +static int adpcm_decode_frame(AVCodecContext * avctx, void *data,
>> +                                 int *got_frame_ptr, AVPacket * avpkt)
> 
> The '*' aligns with the variable name.
> 
>> +    if (avctx->channels == 1 && avpkt->size != 17) {
>> +        av_log(avctx, AV_LOG_WARNING,
>> +               "unexpected mono packet size, expected 17, got %d\n",
>> +               avpkt->size);
>> +    } else if(avctx->channels == 2 && avpkt->size != 34) {
> 
> Add a space: "if (".
> 

Done.

>> +    if ((r = ff_get_buffer(avctx, frame, 0)) < 0)
>> +        return r;
> 
> ffmpeg uses "ret", consistently.
> 

Done.

>> +    dst = adpcm_decode_block((int16_t *) frame->data[0], avpkt->data, argo->prev, frame->nb_samples, avctx->channels);
> 
> Typecast aligns with the value, no space inserted.
> 

Done.

> Cheers,
> Moritz
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 


Thanks,
Zane
Tomas Härdin Jan. 19, 2020, 9:24 p.m. UTC | #3
sön 2020-01-19 klockan 08:33 +0000 skrev Zane van Iperen:
> Adds support for the ADPCM variant used by some Argonaut Games'
> games,
> such as 'Croc! Legend of the Gobbos', and 'Croc 2'.
> 
> Signed-off-by: Zane van Iperen <zane@zanevaniperen.com>
> ---
>  Changelog               |   2 +-
>  doc/general.texi        |   1 +
>  libavcodec/Makefile     |   1 +
>  libavcodec/adpcm_argo.c | 264
> ++++++++++++++++++++++++++++++++++++++++
>  libavcodec/allcodecs.c  |   1 +
>  libavcodec/avcodec.h    |   1 +
>  libavcodec/codec_desc.c |   7 ++
>  libavcodec/version.h    |   2 +-
>  8 files changed, 277 insertions(+), 2 deletions(-)
>  create mode 100644 libavcodec/adpcm_argo.c
> 

Is there any reason why this can't share code with the other ADPCM
decoders?

/Tomas
Zane van Iperen Jan. 19, 2020, 11:01 p.m. UTC | #4
20/1/20 7:24 am, Tomas Härdin пишет:
> 
> sön 2020-01-19 klockan 08:33 +0000 skrev Zane van Iperen:
>> Adds support for the ADPCM variant used by some Argonaut Games'
>> games,
>> such as 'Croc! Legend of the Gobbos', and 'Croc 2'.
>>
>> Signed-off-by: Zane van Iperen <zane@zanevaniperen.com>
>> ---
>>   Changelog               |   2 +-
>>   doc/general.texi        |   1 +
>>   libavcodec/Makefile     |   1 +
>>   libavcodec/adpcm_argo.c | 264
>> ++++++++++++++++++++++++++++++++++++++++
>>   libavcodec/allcodecs.c  |   1 +
>>   libavcodec/avcodec.h    |   1 +
>>   libavcodec/codec_desc.c |   7 ++
>>   libavcodec/version.h    |   2 +-
>>   8 files changed, 277 insertions(+), 2 deletions(-)
>>   create mode 100644 libavcodec/adpcm_argo.c
>>
> 
> Is there any reason why this can't share code with the other ADPCM
> decoders?
> 
> /Tomas
> 
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel@ffmpeg.org
> https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
> 
> To unsubscribe, visit link above, or email
> ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe".
> 

Technically it could, but other than some very minor boilerplate code,
there doesn't seem to be much overlap. Also, adpcm.c is rather big at nearly 2000 lines,
so I'd rather not add it. Personally, I'd prefer to keep it separate.

It seems neater.

Zane
diff mbox series

Patch

diff --git a/Changelog b/Changelog
index 2ccd2645fc..e26320c0ce 100644
--- a/Changelog
+++ b/Changelog
@@ -30,7 +30,7 @@  version <next>:
 - MPEG-H 3D Audio support in mp4
 - thistogram filter
 - freezeframes filter
-
+- Argonaut Games ADPCM decoder
 
 version 4.2:
 - tpad filter
diff --git a/doc/general.texi b/doc/general.texi
index 4bd4b4f6b9..85db50462c 100644
--- a/doc/general.texi
+++ b/doc/general.texi
@@ -1079,6 +1079,7 @@  following image formats are supported:
 @item ACELP.KELVIN           @tab     @tab  X
 @item ADPCM 4X Movie         @tab     @tab  X
 @item APDCM Yamaha AICA      @tab     @tab  X
+@item ADPCM Argonaut Games   @tab     @tab  X
 @item ADPCM CDROM XA         @tab     @tab  X
 @item ADPCM Creative Technology @tab     @tab  X
     @tab 16 -> 4, 8 -> 4, 8 -> 3, 8 -> 2
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index c1f35b40d8..526b3ce96b 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -817,6 +817,7 @@  OBJS-$(CONFIG_ADPCM_ADX_ENCODER)          += adxenc.o adx.o
 OBJS-$(CONFIG_ADPCM_AFC_DECODER)          += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_AGM_DECODER)          += adpcm.o adpcm_data.o
 OBJS-$(CONFIG_ADPCM_AICA_DECODER)         += adpcm.o adpcm_data.o
+OBJS-$(CONFIG_ADPCM_ARGO_DECODER)         += adpcm_argo.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
diff --git a/libavcodec/adpcm_argo.c b/libavcodec/adpcm_argo.c
new file mode 100644
index 0000000000..d5b32e62ba
--- /dev/null
+++ b/libavcodec/adpcm_argo.c
@@ -0,0 +1,264 @@ 
+/*
+ * Argonaut Games ADPCM decoder
+ *
+ * Copyright (C) 2020 Zane van Iperen (zane@zanevaniperen.com)
+ *
+ * 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 "avcodec.h"
+#include "internal.h"
+#include "libavutil/avassert.h"
+
+/*
+ * Sanity Checks:
+ *
+ * ./ffmpeg -loglevel error -i OUTRO.ASF -map 0:a -f md5 -
+ * MD5=e0428a6c55382f48502f04b3a7f7b94b
+ *
+ * ./ffmpeg -loglevel error -i CBK2.asf -map 0:a -f md5 -
+ * MD5=589f3f3c518e5d58aa404b7576db5b70
+*/
+
+/**
+ * Decode a block of 4-bit ADPCM samples for a channel.
+ *
+ * @param c         The shift amount - 2.
+ * @param dst       A pointer to the buffer to write the decoded samples,
+ *                  @p stride elements apart.
+ * @param src       A pointer to the first encoded sample.
+ *                  This should be `nsamples / 2` bytes.
+ * @param prev      The two previous samples, with @p stride elements
+ *                  between each channel.
+ * @param nsamples  The number of samples in the channel.
+ * @param stride    The difference in int16_t's between output samples.
+ *                  This is 0 for mono, 1 for stereo.
+ *
+ * @remark Each iteration does 2 samples at a time to avoid nasty bit-twiddling.
+ */
+typedef int16_t *(*ADPCMDecoder) (
+    uint8_t c,
+    int16_t *dst,
+    const uint8_t *src,
+    const int16_t *prev,
+    int nsamples,
+    int stride
+);
+
+/*
+ * Decoder 1: (prev0 + (s << (c + 2)))
+ */
+static int16_t *adpcm_decoder_1(uint8_t c, int16_t *dst, const uint8_t *src,
+                          const int16_t *prev_,
+                          int nsamples, int stride)
+{
+    int16_t prev;
+    int8_t s;
+
+    av_assert0(stride == 0 || stride == 1);
+    ++stride;
+
+    prev = prev_[stride];
+
+    c += 2;
+    for (int i = 0; i < nsamples / 2; ++i, ++src) {
+        s = (int8_t) ((*src & 0xF0u) << 0u);
+        *dst = prev = ((prev << 6) + (s << c)) >> 6;
+        dst += stride;
+
+        s = (int8_t) ((*src & 0x0Fu) << 4u);
+        *dst = prev = ((prev << 6) + (s << c)) >> 6;
+        dst += stride;
+    }
+
+    return dst;
+}
+
+/*
+ * Decoder 2: (2 * prev0) - (1 * prev1) + (s << (c + 2))
+ */
+static int16_t *adpcm_decoder_2(uint8_t c, int16_t * dst, const uint8_t * src,
+                          const int16_t * prev_,
+                          int nsamples, int stride)
+{
+    int16_t cprev[2];
+    int8_t s;
+
+    av_assert0(stride == 0 || stride == 1);
+    ++stride;
+
+    /* [t-1, t-2] */
+    cprev[0] = prev_[stride];
+    cprev[1] = prev_[0];
+
+    c += 2;
+    for (int i = 0; i < nsamples / 2; ++i, ++src) {
+
+        /* NB: (x << 7) == 2*(x << 6) */
+
+        s = (int8_t) ((*src & 0xF0u) << 0u);
+        *dst = ((cprev[0] << 7) - (cprev[1] << 6) + (s << c)) >> 6;
+        cprev[1] = cprev[0];
+        cprev[0] = *dst;
+        dst += stride;
+
+        s = (int8_t) ((*src & 0x0Fu) << 4u);
+        *dst = ((cprev[0] << 7) - (cprev[1] << 6) + (s << c)) >> 6;
+        cprev[1] = cprev[0];
+        cprev[0] = *dst;
+        dst += stride;
+    }
+
+    return dst;
+}
+
+static ADPCMDecoder adpcm_decoders[2] = { adpcm_decoder_1, adpcm_decoder_2 };
+
+/**
+ * Decode a block of ADPCM samples.
+ *
+ * The format of each block:
+ *   uint8_t left_control;
+ *   uint4_t left_samples[];
+ *   ---- and if stereo ----
+ *   uint8_t right_control;
+ *   uint4_t right_samples[];
+ *
+ * Format of the control byte:
+ * MSB [SSSSDRRR] LSB
+ *   S = (Shift Amount - 2)
+ *   D = Decoder flag. If set, use decoder 2, otherwise use decoder 1
+ *   R = Reserved
+ *
+ * @param dst       A pointer to the buffer to write the samples.
+ *                  This must be at least `nsamples * nchannels`
+ * @param src       A pointer to the current block.
+ * @param prev      A pointer to the previous two decoded samples, one per channel.
+ *                    For mono this is:   [Lt-2, Lt-1]
+ *                    For stereo this is: [Lt-2, Rt-2, Lt-1, Rt-1]
+ * @param nsamples  The number of samples per channel in the block.
+ *                  Must be divisible by and greater than 2.
+ * @param nchannels The number of channels. Must be 1 or 2.
+ */
+static int16_t *adpcm_decode_block(int16_t *dst, const uint8_t *src,
+                                 const int16_t *prev,
+                                 int nsamples, int nchannels)
+{
+    unsigned char c;
+
+    av_assert0(nsamples > 2 && (nsamples & 0x1) == 0);
+    av_assert0(nchannels == 1 || nchannels == 2);
+
+    /* NB: nsamples/2 because samples are 4 bits, not 8. */
+    for (int i = 0; i < nchannels; ++i, src += nsamples / 2) {
+        /* Get the control byte and run the samples through the decoder. */
+        c = *src++;
+        adpcm_decoders[!!(c & 0x04)] (c >> 4, dst + i, src, prev + i, nsamples, nchannels - 1);
+    }
+
+    return dst + (nsamples * nchannels);
+}
+
+
+#define MAX_CHANNELS (2)
+#define PREVIOUS_SAMPLE_COUNT (2)
+
+typedef struct ADPCMArgoDecoderContext {
+    int16_t prev[MAX_CHANNELS * PREVIOUS_SAMPLE_COUNT];
+} ADPCMArgoDecoderContext;
+
+static av_cold int adpcm_decode_init(AVCodecContext *avctx)
+{
+    ADPCMArgoDecoderContext *ctx = avctx->priv_data;
+
+    if (avctx->channels > MAX_CHANNELS) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid channel count %d\n", avctx->channels);
+        return AVERROR(EINVAL);
+    }
+
+    if (avctx->bits_per_coded_sample != 4) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid number of bits %d\n", avctx->bits_per_coded_sample);
+        return AVERROR(EINVAL);
+    }
+
+    avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+
+    for (int i = 0; i < MAX_CHANNELS * PREVIOUS_SAMPLE_COUNT; ++i)
+        ctx->prev[i] = 0;
+
+    return 0;
+}
+
+static int adpcm_decode_frame(AVCodecContext * avctx, void *data,
+                                 int *got_frame_ptr, AVPacket * avpkt)
+{
+    int r;
+    AVFrame *frame = data;
+    ADPCMArgoDecoderContext *argo = avctx->priv_data;
+    int16_t *dst;
+
+    if (avctx->channels == 1 && avpkt->size != 17) {
+        av_log(avctx, AV_LOG_WARNING,
+               "unexpected mono packet size, expected 17, got %d\n",
+               avpkt->size);
+    } else if(avctx->channels == 2 && avpkt->size != 34) {
+        av_log(avctx, AV_LOG_WARNING,
+               "unexpected stereo packet size, expected 34, got %d\n",
+               avpkt->size);
+    }
+
+    frame->nb_samples = ((avpkt->size - avctx->channels) / avctx->channels) *
+                        (8 / avctx->bits_per_coded_sample);
+
+    /* get output buffer */
+    if ((r = ff_get_buffer(avctx, frame, 0)) < 0)
+        return r;
+
+    dst = adpcm_decode_block((int16_t *) frame->data[0], avpkt->data, argo->prev, frame->nb_samples, avctx->channels);
+
+    /* Save the previous samples for the next frame. */
+    r = avctx->channels * PREVIOUS_SAMPLE_COUNT;
+    for (int i = 0; i < r; ++i)
+        argo->prev[i] = *(dst - (r - i));
+
+    *got_frame_ptr = 1;
+    return avpkt->size;
+}
+
+const int64_t channel_layouts[] = {
+    AV_CH_LAYOUT_MONO,
+    AV_CH_LAYOUT_STEREO,
+    0
+};
+
+const enum AVSampleFormat sample_formats[] = {
+    AV_SAMPLE_FMT_S16,
+    AV_SAMPLE_FMT_NONE
+};
+
+
+AVCodec ff_adpcm_argo_decoder = {
+    .name               = "adpcm_argo",
+    .long_name          = NULL_IF_CONFIG_SMALL("ADPCM Argonaut Games"),
+    .type               = AVMEDIA_TYPE_AUDIO,
+    .id                 = AV_CODEC_ID_ADPCM_ARGO,
+    .priv_data_size     = sizeof(ADPCMArgoDecoderContext),
+    .init               = adpcm_decode_init,
+    .decode             = adpcm_decode_frame,
+    .capabilities       = AV_CODEC_CAP_DR1,
+    .sample_fmts        = sample_formats,
+    .channel_layouts    = channel_layouts
+};
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index ec7366144f..01a083d06b 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -582,6 +582,7 @@  extern AVCodec ff_adpcm_adx_decoder;
 extern AVCodec ff_adpcm_afc_decoder;
 extern AVCodec ff_adpcm_agm_decoder;
 extern AVCodec ff_adpcm_aica_decoder;
+extern AVCodec ff_adpcm_argo_decoder;
 extern AVCodec ff_adpcm_ct_decoder;
 extern AVCodec ff_adpcm_dtk_decoder;
 extern AVCodec ff_adpcm_ea_decoder;
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h
index 4b0e7c0853..ce126353b3 100644
--- a/libavcodec/avcodec.h
+++ b/libavcodec/avcodec.h
@@ -545,6 +545,7 @@  enum AVCodecID {
     AV_CODEC_ID_ADPCM_IMA_DAT4,
     AV_CODEC_ID_ADPCM_MTAF,
     AV_CODEC_ID_ADPCM_AGM,
+    AV_CODEC_ID_ADPCM_ARGO,
 
     /* AMR */
     AV_CODEC_ID_AMR_NB = 0x12000,
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 529b838e5b..32f573d58c 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -2297,6 +2297,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("ADPCM AmuseGraphics Movie AGM"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
     },
+    {
+        .id        = AV_CODEC_ID_ADPCM_ARGO,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "adpcm_argo",
+        .long_name = NULL_IF_CONFIG_SMALL("ADPCM Argonaut Games"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY,
+    },
 
     /* AMR */
     {
diff --git a/libavcodec/version.h b/libavcodec/version.h
index 6cf333eeb6..2fba26e8d0 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -28,7 +28,7 @@ 
 #include "libavutil/version.h"
 
 #define LIBAVCODEC_VERSION_MAJOR  58
-#define LIBAVCODEC_VERSION_MINOR  66
+#define LIBAVCODEC_VERSION_MINOR  67
 #define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \