diff mbox series

[FFmpeg-devel] RK Audio demuxer and decoder

Message ID CAPYw7P7b+nghh7c64KYPzJnBFtfOGbwpCSU-X527UWMpt-StWw@mail.gmail.com
State New
Headers show
Series [FFmpeg-devel] RK Audio demuxer and decoder | expand

Checks

Context Check Description
yinshiyou/configure_loongarch64 warning Failed to apply patch
andriy/make_x86 success Make finished
andriy/make_fate_x86 success Make fate finished

Commit Message

Paul B Mahol Feb. 5, 2023, 7:17 p.m. UTC
On 2/4/23, Paul B Mahol <onemda@gmail.com> wrote:
> Hi,
>
> Patches attached, decoder is not bit by bit exact yet for lossless
> mode because some samples are not properly rounded.
>

Now lossless mode is bit exact.

Comments

Paul B Mahol Feb. 10, 2023, 6:13 p.m. UTC | #1
will apply
James Almer Feb. 15, 2023, 11:59 a.m. UTC | #2
On 2/5/2023 4:17 PM, Paul B Mahol wrote:
> On 2/4/23, Paul B Mahol <onemda@gmail.com> wrote:
>> Hi,
>>
>> Patches attached, decoder is not bit by bit exact yet for lossless
>> mode because some samples are not properly rounded.
>>
> 
> Now lossless mode is bit exact.

[...]

> +static av_cold int rka_decode_init(AVCodecContext *avctx)
> +{
> +    RKAContext *s = avctx->priv_data;
> +    int cmode;
> +
> +    if (avctx->extradata_size < 16)
> +        return AVERROR_INVALIDDATA;
> +
> +    s->bps = avctx->bits_per_raw_sample = avctx->extradata[13];
> +
> +    switch (s->bps) {
> +    case 8:
> +        avctx->sample_fmt = AV_SAMPLE_FMT_U8P;
> +        break;
> +    case 16:
> +        avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
> +        break;
> +    default:
> +        return AVERROR_INVALIDDATA;
> +    }
> +
> +    s->channels = avctx->ch_layout.nb_channels;

You're ignoring the channels reported by the extradata despite flagging 
this decoder as AV_CODEC_CAP_CHANNEL_CONF. It should be the other way 
around, and ignore the user set layout, if any, with

av_channel_layout_uninit(&avctx->ch_layout);
s->channels = avctx->ch_layout.nb_channels = avctx->extradata[12];

Because the stream may not necessarily come from the lavf demuxer. 
Extradata presence is required given you check for it above, but the 
avctx fields could be set to whatever if the source is not the lavf rka 
demuxer.

> +    if (s->channels < 1 || s->channels > 2)
> +        return AVERROR_INVALIDDATA;
> +
> +    s->align = (s->channels * (avctx->bits_per_raw_sample >> 3));
> +    s->samples_left = s->total_nb_samples = (AV_RL32(avctx->extradata + 4)) / s->align;
> +    s->frame_samples = 131072 / s->align;
> +    s->last_nb_samples = s->total_nb_samples % s->frame_samples;
> +
> +    cmode = avctx->extradata[14] & 0xf;
> +    if ((avctx->extradata[15] & 4) != 0)
> +        cmode = -cmode;
> +
> +    s->ch[0].cmode = s->ch[1].cmode = cmode;
> +    s->ch[0].cmode2 = -s->ch[0].cmode;
> +    s->ch[1].cmode2 = -s->ch[1].cmode;
> +    av_log(avctx, AV_LOG_DEBUG, "cmode: %d\n", cmode);
> +
> +    return 0;
> +}
diff mbox series

Patch

From 217b459cea1e6468835240d1c2313e89918e6d7b Mon Sep 17 00:00:00 2001
From: Paul B Mahol <onemda@gmail.com>
Date: Tue, 31 Jan 2023 21:03:38 +0100
Subject: [PATCH 2/2] avcodec: add RKA decoder

Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
 libavcodec/Makefile     |   1 +
 libavcodec/allcodecs.c  |   1 +
 libavcodec/codec_desc.c |   7 +
 libavcodec/codec_id.h   |   1 +
 libavcodec/rka.c        | 999 ++++++++++++++++++++++++++++++++++++++++
 5 files changed, 1009 insertions(+)
 create mode 100644 libavcodec/rka.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 4971832ff4..389253f5d0 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -631,6 +631,7 @@  OBJS-$(CONFIG_RASC_DECODER)            += rasc.o
 OBJS-$(CONFIG_RAWVIDEO_DECODER)        += rawdec.o
 OBJS-$(CONFIG_RAWVIDEO_ENCODER)        += rawenc.o
 OBJS-$(CONFIG_REALTEXT_DECODER)        += realtextdec.o ass.o
+OBJS-$(CONFIG_RKA_DECODER)             += rka.o
 OBJS-$(CONFIG_RL2_DECODER)             += rl2.o
 OBJS-$(CONFIG_ROQ_DECODER)             += roqvideodec.o roqvideo.o
 OBJS-$(CONFIG_ROQ_ENCODER)             += roqvideoenc.o roqvideo.o elbg.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index b80b6983e9..e593ad19af 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -287,6 +287,7 @@  extern const FFCodec ff_r210_decoder;
 extern const FFCodec ff_rasc_decoder;
 extern const FFCodec ff_rawvideo_encoder;
 extern const FFCodec ff_rawvideo_decoder;
+extern const FFCodec ff_rka_decoder;
 extern const FFCodec ff_rl2_decoder;
 extern const FFCodec ff_roq_encoder;
 extern const FFCodec ff_roq_decoder;
diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c
index 57d0f98211..199f62df15 100644
--- a/libavcodec/codec_desc.c
+++ b/libavcodec/codec_desc.c
@@ -3360,6 +3360,13 @@  static const AVCodecDescriptor codec_descriptors[] = {
         .long_name = NULL_IF_CONFIG_SMALL("Waveform Archiver"),
         .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS,
     },
+    {
+        .id        = AV_CODEC_ID_RKA,
+        .type      = AVMEDIA_TYPE_AUDIO,
+        .name      = "rka",
+        .long_name = NULL_IF_CONFIG_SMALL("RKA (RK Audio)"),
+        .props     = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS,
+    },
 
     /* subtitle codecs */
     {
diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h
index ad1131b464..89a4a0cb89 100644
--- a/libavcodec/codec_id.h
+++ b/libavcodec/codec_id.h
@@ -537,6 +537,7 @@  enum AVCodecID {
     AV_CODEC_ID_APAC,
     AV_CODEC_ID_FTR,
     AV_CODEC_ID_WAVARC,
+    AV_CODEC_ID_RKA,
 
     /* subtitle codecs */
     AV_CODEC_ID_FIRST_SUBTITLE = 0x17000,          ///< A dummy ID pointing at the start of subtitle codecs.
diff --git a/libavcodec/rka.c b/libavcodec/rka.c
new file mode 100644
index 0000000000..d916227483
--- /dev/null
+++ b/libavcodec/rka.c
@@ -0,0 +1,999 @@ 
+/*
+ * RKA decoder
+ * Copyright (c) 2023 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 "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "bytestream.h"
+#include "decode.h"
+
+typedef struct ACoder {
+    GetByteContext gb;
+    uint32_t low, high;
+    uint32_t value;
+} ACoder;
+
+typedef struct FiltCoeffs {
+    int32_t coeffs[257];
+    unsigned size;
+} FiltCoeffs;
+
+typedef struct Model64 {
+    uint32_t zero[2];
+    uint32_t sign[2];
+    unsigned size;
+    int bits;
+
+    uint16_t val4[65];
+    uint16_t val1[65];
+} Model64;
+
+typedef struct AdaptiveModel {
+    int last;
+    int total;
+    int buf_size;
+    int16_t sum;
+    uint16_t aprob0;
+    uint16_t aprob1;
+    uint16_t *prob[2];
+} AdaptiveModel;
+
+typedef struct ChContext {
+    int cmode;
+    int cmode2;
+    int last_nb_decoded;
+    unsigned srate_pad;
+    unsigned pos_idx;
+
+    AdaptiveModel *filt_size;
+    AdaptiveModel *filt_bits;
+
+    int *bprob0;
+    int *bprob1;
+
+    AdaptiveModel position;
+    AdaptiveModel fshift;
+    AdaptiveModel nb_segments;
+    AdaptiveModel coeff_bits[11];
+
+    Model64 mdl64[4][11];
+
+    int32_t buf0[12001];
+    int32_t buf1[12001];
+} ChContext;
+
+typedef struct RKAContext {
+    AVClass *class;
+
+    ACoder ac;
+    ChContext ch[2];
+
+    int bps;
+    int align;
+    int channels;
+    int frame_samples;
+    int last_nb_samples;
+    uint32_t total_nb_samples;
+    uint32_t samples_left;
+
+    int bprob0[257];
+    int bprob1[257];
+
+    AdaptiveModel filt_size;
+    AdaptiveModel filt_bits;
+} RKAContext;
+
+static int adaptive_model_init(AdaptiveModel *am, int buf_size)
+{
+    am->buf_size = buf_size;
+    am->sum = 2000;
+    am->aprob0 = 0;
+    am->aprob1 = 0;
+    am->total = 0;
+
+    if (!am->prob[0])
+        am->prob[0] = av_malloc_array(buf_size + 5, sizeof(*am->prob[0]));
+    if (!am->prob[1])
+        am->prob[1] = av_malloc_array(buf_size + 5, sizeof(*am->prob[1]));
+
+    if (!am->prob[0] || !am->prob[1])
+        return AVERROR(ENOMEM);
+    memset(am->prob[0], 0, (buf_size + 5) * sizeof(*am->prob[0]));
+    memset(am->prob[1], 0, (buf_size + 5) * sizeof(*am->prob[1]));
+    return 0;
+}
+
+static void adaptive_model_free(AdaptiveModel *am)
+{
+    av_freep(&am->prob[0]);
+    av_freep(&am->prob[1]);
+}
+
+static av_cold int rka_decode_init(AVCodecContext *avctx)
+{
+    RKAContext *s = avctx->priv_data;
+    int cmode;
+
+    if (avctx->extradata_size < 16)
+        return AVERROR_INVALIDDATA;
+
+    s->bps = avctx->bits_per_raw_sample = avctx->extradata[13];
+
+    switch (s->bps) {
+    case 8:
+        avctx->sample_fmt = AV_SAMPLE_FMT_U8P;
+        break;
+    case 16:
+        avctx->sample_fmt = AV_SAMPLE_FMT_S16P;
+        break;
+    default:
+        return AVERROR_INVALIDDATA;
+    }
+
+    s->channels = avctx->ch_layout.nb_channels;
+    if (s->channels < 1 || s->channels > 2)
+        return AVERROR_INVALIDDATA;
+
+    s->align = (s->channels * (avctx->bits_per_raw_sample >> 3));
+    s->samples_left = s->total_nb_samples = (AV_RL32(avctx->extradata + 4)) / s->align;
+    s->frame_samples = 131072 / s->align;
+    s->last_nb_samples = s->total_nb_samples % s->frame_samples;
+
+    cmode = avctx->extradata[14] & 0xf;
+    if ((avctx->extradata[15] & 4) != 0)
+        cmode = -cmode;
+
+    s->ch[0].cmode = s->ch[1].cmode = cmode;
+    s->ch[0].cmode2 = -s->ch[0].cmode;
+    s->ch[1].cmode2 = -s->ch[1].cmode;
+    av_log(avctx, AV_LOG_DEBUG, "cmode: %d\n", cmode);
+
+    return 0;
+}
+
+static void model64_init(Model64 *m, unsigned bits)
+{
+    unsigned x;
+
+    m->bits = bits;
+    m->size = 64;
+    m->zero[0] = 1;
+
+    x = (1 << (bits >> 1)) + 3;
+    x = FFMIN(x, 20);
+
+    m->zero[1] = x;
+    m->sign[0] = 1;
+    m->sign[1] = 1;
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(m->val4); i++) {
+        m->val4[i] = 4;
+        m->val1[i] = 1;
+    }
+}
+
+static int chctx_init(RKAContext *s, ChContext *c,
+                      int sample_rate, int bps)
+{
+    int ret;
+
+    memset(c->buf0, 0, sizeof(c->buf0));
+    memset(c->buf1, 0, sizeof(c->buf1));
+
+    c->filt_size = &s->filt_size;
+    c->filt_bits = &s->filt_bits;
+
+    c->bprob0 = s->bprob0;
+    c->bprob1 = s->bprob1;
+
+    c->srate_pad = (sample_rate << 13) / 44100 & 0xFFFFFFFCU;
+    c->pos_idx = 1;
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(s->bprob0); i++)
+        c->bprob0[i] = c->bprob1[i] = 1;
+
+    for (int i = 0; i < 11; i++) {
+        ret = adaptive_model_init(&c->coeff_bits[i], 32);
+        if (ret < 0)
+            return ret;
+
+        model64_init(&c->mdl64[0][i], i);
+        model64_init(&c->mdl64[1][i], i);
+        model64_init(&c->mdl64[2][i], i+1);
+        model64_init(&c->mdl64[3][i], i+1);
+    }
+
+    ret = adaptive_model_init(c->filt_size, 256);
+    if (ret < 0)
+        return ret;
+    ret = adaptive_model_init(c->filt_bits, 16);
+    if (ret < 0)
+        return ret;
+    ret = adaptive_model_init(&c->position, 16);
+    if (ret < 0)
+        return ret;
+    ret = adaptive_model_init(&c->nb_segments, 8);
+    if (ret < 0)
+        return ret;
+    return adaptive_model_init(&c->fshift, 32);
+}
+
+static void init_acoder(ACoder *ac)
+{
+    ac->low = 0x0;
+    ac->high = 0xffffffff;
+    ac->value = bytestream2_get_be32(&ac->gb);
+}
+
+static int ac_decode_bool(ACoder *ac, int freq1, int freq2)
+{
+    unsigned help, add, high;
+    int value, low;
+
+    low = ac->low;
+    help = ac->high / (unsigned int)(freq2 + freq1);
+    value = ac->value;
+    add = freq1 * help;
+    ac->high = help;
+
+    if (value - low >= add) {
+        ac->low = low = add + low;
+        ac->high = high = freq2 * help;
+        while (1) {
+            if ((low ^ (high + low)) > 0xFFFFFF) {
+                if (high > 0xFFFF)
+                    return 1;
+                ac->high = (uint16_t)-(int16_t)low;
+            }
+
+            if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+                break;
+            ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8);
+            ac->high = high = ac->high << 8;
+            ac->low = low = ac->low << 8;
+        }
+        return -1;
+    }
+
+    ac->high = add;
+    while (1) {
+        if ((low ^ (add + low)) > 0xFFFFFF) {
+            if (add > 0xFFFF)
+                return 0;
+            ac->high = (uint16_t)-(int16_t)low;
+        }
+
+        if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+            break;
+        ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8);
+        ac->high = add = ac->high << 8;
+        ac->low = low = ac->low << 8;
+    }
+    return -1;
+}
+
+static int decode_bool(ACoder *ac, ChContext *c, int idx)
+{
+    int x, b;
+
+    x = c->bprob0[idx];
+    if (x + c->bprob1[idx] > 4096) {
+        c->bprob0[idx] = (x >> 1) + 1;
+        c->bprob1[idx] = (c->bprob1[idx] >> 1) + 1;
+    }
+
+    b = ac_decode_bool(ac, c->bprob0[idx], c->bprob1[idx]);
+    if (b == 1) {
+        c->bprob1[idx]++;
+    } else if (b == 0) {
+        c->bprob0[idx]++;
+    }
+
+    return b;
+}
+
+static int ac_get_freq(ACoder *ac, unsigned freq, int *result)
+{
+    uint32_t new_high;
+
+    if (freq == 0)
+        return -1;
+
+    new_high = ac->high / freq;
+    ac->high = new_high;
+
+    if (new_high == 0)
+        return -1;
+
+    *result = (ac->value - ac->low) / new_high;
+
+    return 0;
+}
+
+static int ac_update(ACoder *ac, int freq, int mul)
+{
+    uint32_t low, high;
+
+    low = ac->low = ac->high * freq + ac->low;
+    high = ac->high = ac->high * mul;
+
+    while (1) {
+        if (((high + low) ^ low) > 0xffffff) {
+            if (high > 0xffff)
+                return 0;
+            ac->high = (-(int16_t)low) & 0xffff;
+        }
+
+        if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+            break;
+
+        ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb);
+        low = ac->low = ac->low << 8;
+        high = ac->high = ac->high << 8;
+    }
+
+    return -1;
+}
+
+static void update_ch_subobj(AdaptiveModel *am)
+{
+    int idx2, idx = am->buf_size - 1;
+
+    if (idx >= 0) {
+        do {
+            uint16_t *prob = am->prob[0];
+            int prob_idx = prob[idx];
+            int diff, left;
+
+            idx2 = idx - 1;
+            if (idx > 0) {
+                int idx3 = idx - 1;
+
+                if ((idx2 & idx) != idx2) {
+                    do {
+                        prob_idx -= prob[idx3];
+                        idx3 &= idx3 - 1;
+                    } while ((idx2 & idx) != idx3);
+                }
+            }
+
+            diff = ((prob_idx > 0) - prob_idx) >> 1;
+            left = idx;
+            am->aprob0 += diff;
+            if (idx <= 0) {
+                am->prob[0][0] += diff;
+            } else {
+                do {
+                    am->prob[0][left] += diff;
+                    left += (left & -left);
+                }
+                while (left < am->buf_size);
+            }
+            idx--;
+        } while (idx2 >= 0);
+    }
+
+    if (am->sum < 8000)
+        am->sum += 200;
+
+    am->aprob1 = (am->aprob1 + 1) >> 1;
+}
+
+static int amdl_decode_int(AdaptiveModel *am, ACoder *ac, unsigned *dst, unsigned size)
+{
+    unsigned int freq;
+    int val_1;
+    int v7;
+    int v8;
+    uint16_t v9;
+    int v10;
+    uint16_t v11;
+    uint16_t *v12;
+    int v13;
+    int v14;
+    int k;
+    int v17;
+    unsigned v18;
+    int val;
+    int v24;
+    int freqa;
+    uint16_t v27;
+    uint16_t j;
+    uint16_t v29;
+
+    val_1 = FFMIN(size, am->buf_size - 1);
+
+    if (am->aprob0 >= am->sum)
+        update_ch_subobj(am);
+
+    if (am->aprob1 && (am->total == am->buf_size ||
+                       ac_decode_bool(ac, am->aprob0, am->aprob1) == 0)) {
+        if (am->total <= 1) {
+            dst[0] = am->last;
+            val = dst[0];
+            am->aprob0++;
+            if (val <= 0) {
+                am->prob[0][0]++;
+            } else {
+                do {
+                    am->prob[0][val]++;
+                    val += (val & -val);
+                } while (val < am->buf_size);
+            }
+            return 0;
+        }
+        if (val_1 == am->buf_size - 1) {
+            freq = am->aprob0;
+        } else {
+            unsigned i = am->prob[0][0];
+
+            for (int j = val_1; j > 0; j &= (j - 1) )
+                i += am->prob[0][j];
+            freq = i;
+        }
+        v24 = 0;
+        ac_get_freq(ac, freq, &v7);
+        v8 = am->buf_size >> 1;
+        v9 = am->prob[0][0];
+        if (v7 >= v9) {
+            for (j = v7 - v9; v8; v8 >>= 1) {
+                v11 = am->prob[0][v8 + v24];
+                if (j >= v11) {
+                    v24 += v8;
+                    j -= v11;
+                }
+            }
+            v27 = v7 - j;
+            v10 = v24 + 1;
+        } else {
+            v27 = 0;
+            v10 = 0;
+        }
+        dst[0] = v10;
+        v12 = am->prob[0];
+        v13 = v12[v10];
+        if (v10 > 0) {
+            v14 = v10 & (v10 - 1);
+            for (k = v10 - 1; v14 != k; k &= k - 1)
+                v13 -= v12[k];
+        }
+        ac_update(ac, v27, v13);
+        val = dst[0];
+        am->aprob0++;
+        if (val <= 0) {
+            am->prob[0][0]++;
+        } else {
+            do {
+                am->prob[0][val]++;
+                val += (val & -val);
+            } while (val < am->buf_size);
+        }
+        return 0;
+    }
+    v17 = am->buf_size;
+    am->aprob1++;
+    if (val_1 == v17 - 1) {
+        ac_get_freq(ac, v17 - am->total, &v18);
+    } else {
+        freqa = 1;
+        dst[0] = 0;
+        if (val_1 > 0) {
+            do {
+                if (!am->prob[1][dst[0]])
+                    freqa++;
+                dst[0]++;
+            } while (dst[0] < val_1);
+        }
+        ac_get_freq(ac, freqa, &v18);
+    }
+    v29 = 0;
+    dst[0] = 0;
+    if (v18 > 0 && am->buf_size > 0) {
+        do {
+            val = dst[0];
+            if (!am->prob[1][dst[0]])
+                ++v29;
+            dst[0] = val + 1;
+        }
+        while (v29 < v18 && val + 1 < am->buf_size);
+    }
+    if (am->prob[1][dst[0]]) {
+        do {
+            val = dst[0]++;
+        } while (val + 1 < am->buf_size && am->prob[1][val + 1]);
+    }
+    ac_update(ac, v29, 1);
+    am->prob[1][dst[0]]++;
+    am->total++;
+    val = dst[0];
+    am->aprob0++;
+    if (val <= 0) {
+        am->prob[0][0]++;
+    } else {
+        do {
+            am->prob[0][val]++;
+            val += (val & -val);
+        } while (val < am->buf_size);
+    }
+
+    am->last = dst[0];
+
+    return 0;
+}
+
+static int decode_filt_coeffs(RKAContext *s, ChContext *ctx, ACoder *ac, FiltCoeffs *dst)
+{
+    unsigned val, bits;
+    int idx = 0;
+
+    if (amdl_decode_int(ctx->filt_size, ac, &dst->size, 256) < 0)
+        return -1;
+
+    if (dst->size == 0)
+        return 0;
+
+    if (amdl_decode_int(ctx->filt_bits, ac, &bits, 10) < 0)
+        return -1;
+
+    do {
+        if (((idx == 8) || (idx == 20)) && (0 < bits))
+            bits--;
+
+        if (bits > 10)
+            return -1;
+
+        if (amdl_decode_int(&ctx->coeff_bits[bits], ac, &val, 31) < 0)
+            return -1;
+
+        if (val == 31) {
+            ac_get_freq(ac, 65536, &val);
+            ac_update(ac, val, 1);
+        }
+
+        if (val == 0) {
+            dst->coeffs[idx++] = 0;
+        } else {
+            unsigned freq = 0;
+            int sign;
+
+            if (bits > 0) {
+                ac_get_freq(ac, 1 << bits, &freq);
+                ac_update(ac, freq, 1);
+            }
+            dst->coeffs[idx] = freq + 1 + ((val - 1U) << bits);
+            sign = decode_bool(ac, ctx, idx);
+            if (sign < 0)
+                return -1;
+            if (sign == 1)
+                dst->coeffs[idx] = -dst->coeffs[idx];
+            idx++;
+        }
+    } while (idx < dst->size);
+
+    return 0;
+}
+
+static int ac_dec_bit(ACoder *ac)
+{
+    uint32_t high, low;
+
+    low = ac->low;
+    ac->high = high = ac->high >> 1;
+    if (ac->value - low < high) {
+        do {
+            if (((high + low) ^ low) > 0xffffff) {
+                if (high > 0xffff)
+                    return 0;
+                ac->high = (-(int16_t)low) & 0xffff;
+            }
+
+            if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+                break;
+
+            ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb);
+            ac->high = high = ac->high << 8;
+            ac->low = low = ac->low << 8;
+        } while (1);
+
+        return -1;
+    }
+    ac->low = low = low + high;
+    do {
+        if (((high + low) ^ low) > 0xffffff) {
+            if (high > 0xffff)
+                return 1;
+            ac->high = (-(int16_t)low) & 0xffff;
+        }
+
+        if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+            break;
+
+        ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb);
+        ac->high = high = ac->high << 8;
+        ac->low = low = ac->low << 8;
+    } while (1);
+
+    return -1;
+}
+
+static int mdl64_decode(ACoder *ac, Model64 *ctx, int *dst)
+{
+    int sign, idx, bits;
+    unsigned val = 0;
+
+    if (ctx->zero[0] + ctx->zero[1] > 4000) {
+        ctx->zero[0] = (ctx->zero[0] >> 1) + 1;
+        ctx->zero[1] = (ctx->zero[1] >> 1) + 1;
+    }
+    if (ctx->sign[0] + ctx->sign[1] > 4000) {
+        ctx->sign[0] = (ctx->sign[0] >> 1) + 1;
+        ctx->sign[1] = (ctx->sign[1] >> 1) + 1;
+    }
+    sign = ac_decode_bool(ac, ctx->zero[0], ctx->zero[1]);
+    if (sign == 0) {
+        ctx->zero[0] += 2;
+        dst[0] = 0;
+        return 0;
+    } else if (sign < 0)
+        return -1;
+
+    ctx->zero[1] += 2;
+    sign = ac_decode_bool(ac, ctx->sign[0], ctx->sign[1]);
+    if (sign < 0)
+        return -1;
+    ctx->sign[sign]++;
+    bits = ctx->bits;
+    if (bits > 0) {
+        if (bits < 13) {
+            ac_get_freq(ac, 1 << bits, &val);
+            ac_update(ac,val,1);
+        } else {
+            ac_get_freq(ac, 1 << (bits / 2), &val);
+            ac_update(ac,val,1);
+            ac_get_freq(ac,1 << (ctx->bits - (bits / 2)), &bits);
+            ac_update(ac,val,1);
+            val = val + (bits << (bits / 2));
+        }
+    }
+    bits = ctx->size;
+    idx = 0;
+    if (bits >= 0) {
+        do {
+            uint16_t *val4 = ctx->val4;
+            int b;
+
+            if (val4[idx] + ctx->val1[idx] > 2000U) {
+                val4[idx] = (val4[idx] >> 1) + 1;
+                ctx->val1[idx] = (ctx->val1[idx] >> 1) + 1;
+            }
+            b = ac_decode_bool(ac, ctx->val4[idx], ctx->val1[idx]);
+            if (b == 1) {
+                ctx->val1[idx] += 4;
+                break;
+            } else if (b < 0) {
+                return -1;
+            }
+            ctx->val4[idx] += 4;
+            idx++;
+        } while (idx <= ctx->size);
+        bits = ctx->size;
+        if (idx <= bits) {
+            dst[0] = val + 1 + (idx << ctx->bits);
+            if (sign)
+                dst[0] = -dst[0];
+            return 0;
+        }
+    }
+    bits = bits + 1;
+    while (ac_dec_bit(ac) == 0)
+        bits = bits + 64;
+    ac_get_freq(ac, 64, &idx);
+    ac_update(ac, idx, 1);
+    idx += bits;
+    bits = val + 1 + (idx << ctx->bits);
+    dst[0] = bits;
+    if (sign)
+        dst[0] = -dst[0];
+
+    return 0;
+}
+
+static const uint8_t tab[] = { 0, 3, 3, 2, 2, 1, 1, 1, 1 };
+
+static int decode_filter(RKAContext *s, ChContext *ctx, ACoder *ac, int off, unsigned size)
+{
+    FiltCoeffs filt;
+    Model64 *mdl64;
+    int m = 0, split, val, last_val = 0, ret;
+    unsigned idx = 3, bits = 0;
+
+    if (ctx->cmode == 0) {
+        if (amdl_decode_int(&ctx->fshift, ac, &bits, 15) < 0)
+            return -1;
+        bits &= 31U;
+    }
+
+    ret = decode_filt_coeffs(s, ctx, ac, &filt);
+    if (ret < 0)
+        return ret;
+
+    if (size < 512)
+        split = size / 2;
+    else
+        split = size >> 4;
+
+    if (size <= 0)
+        return 0;
+
+    for (int x = 0; x < size;) {
+        if (amdl_decode_int(&ctx->position, ac, &idx, 10) < 0)
+            return -1;
+
+        idx = (ctx->pos_idx + idx) % 11;
+        ctx->pos_idx = idx;
+
+        for (int y = 0; y < split; y++, off++) {
+            int midx, shift = idx, *src, sum = 16;
+
+            midx = FFABS(last_val) >> shift;
+            if (midx >= 15) {
+                mdl64 = &ctx->mdl64[3][idx];
+            } else if (midx >= 7) {
+                mdl64 = &ctx->mdl64[2][idx];
+            } else if (midx >= 4) {
+                mdl64 = &ctx->mdl64[1][idx];
+            } else {
+                mdl64 = &ctx->mdl64[0][idx];
+            }
+            ret = mdl64_decode(ac, mdl64, &val);
+            if (ret < 0)
+                return -1;
+            last_val = val;
+            src = &ctx->buf1[off + -1];
+            for (int i = 0; i < filt.size && i < 15; i++)
+                sum += filt.coeffs[i] * src[-i];
+            sum = sum * 2;
+            for (int i = 15; i < filt.size; i++)
+                sum += filt.coeffs[i] * src[-i];
+            sum = sum >> 6;
+            if (ctx->cmode == 0) {
+                if (bits == 0) {
+                    ctx->buf1[off] = sum + val;
+                } else {
+                    ctx->buf1[off] = (val + (sum >> bits) * (1U << bits)) +
+                        (((1U << bits) - 1U) & ctx->buf1[off + -1]);
+                }
+                ctx->buf0[off] = ctx->buf1[off] + ctx->buf0[off + -1];
+            } else {
+                val = val * (1 << ctx->cmode & 0x1f);
+                sum += ctx->buf0[off + -1] + val;
+                switch (s->bps) {
+                    case 16: sum = av_clip_int16(sum); break;
+                    case  8: sum = av_clip_int8(sum);  break;
+                }
+                ctx->buf1[off] = sum - ctx->buf0[off + -1];
+                ctx->buf0[off] = sum;
+                m += FFABS(ctx->buf1[off]);
+            }
+        }
+        if (ctx->cmode2 != 0) {
+            int sum = 0;
+            for (int i = (m << 6) / split; i > 0; i = i >> 1)
+                sum++;
+            sum = sum - (ctx->cmode2 + 7);
+            ctx->cmode = FFMAX(sum, tab[ctx->cmode2]);
+        }
+
+        x += split;
+    }
+
+    return 0;
+}
+
+static int decode_samples(AVCodecContext *avctx, ACoder *ac, ChContext *ctx, int offset)
+{
+    RKAContext *s = avctx->priv_data;
+    int segment_size, size, offset2, mode, ret;
+
+    ret = amdl_decode_int(&ctx->nb_segments, ac, &mode, 5);
+    if (ret < 0)
+        return ret;
+
+    if (mode == 5) {
+        ret = ac_get_freq(ac, ctx->srate_pad >> 2, &segment_size);
+        if (ret < 0)
+            return ret;
+        ac_update(ac, segment_size, 1);
+        segment_size *= 4;
+        decode_filter(s, ctx, ac, offset, segment_size);
+    } else {
+        segment_size = ctx->srate_pad;
+
+        if (mode) {
+            if (mode > 2) {
+                decode_filter(s, ctx, ac, offset, segment_size / 4);
+                offset2 = segment_size / 4 + offset;
+                decode_filter(s, ctx, ac, offset2, segment_size / 4);
+                size = segment_size / 4 + offset2;
+            } else {
+                decode_filter(s, ctx, ac, offset, segment_size / 2);
+                size = segment_size / 2 + offset;
+            }
+            if (mode & 1) {
+                decode_filter(s, ctx, ac, size, segment_size / 2);
+            } else {
+                decode_filter(s, ctx, ac, size, segment_size / 4);
+                decode_filter(s, ctx, ac, segment_size / 4 + size, segment_size / 4);
+            }
+        } else {
+            decode_filter(s, ctx, ac, offset, ctx->srate_pad);
+        }
+    }
+
+    return segment_size;
+}
+
+static int decode_ch_samples(AVCodecContext *avctx, ChContext *c)
+{
+    RKAContext *s = avctx->priv_data;
+    ACoder *ac = &s->ac;
+    int nb_decoded = 0;
+
+    if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+        return 0;
+
+    memmove(c->buf0, &c->buf0[c->last_nb_decoded], 2560 * sizeof(*c->buf0));
+    memmove(c->buf1, &c->buf1[c->last_nb_decoded], 2560 * sizeof(*c->buf1));
+
+    nb_decoded = decode_samples(avctx, ac, c, 2560);
+    if (nb_decoded < 0)
+        return nb_decoded;
+    c->last_nb_decoded = nb_decoded;
+
+    return nb_decoded;
+}
+
+static int rka_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+                            int *got_frame_ptr, AVPacket *avpkt)
+{
+    RKAContext *s = avctx->priv_data;
+    ACoder *ac = &s->ac;
+    int ret;
+
+    bytestream2_init(&ac->gb, avpkt->data, avpkt->size);
+    init_acoder(ac);
+
+    for (int ch = 0; ch < s->channels; ch++) {
+        ret = chctx_init(s, &s->ch[ch], avctx->sample_rate,
+                         avctx->bits_per_raw_sample);
+        if (ret < 0)
+            return ret;
+    }
+
+    frame->nb_samples = s->frame_samples;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    if (s->channels == 2) {
+        int16_t *l16 = (int16_t *)frame->extended_data[0];
+        int16_t *r16 = (int16_t *)frame->extended_data[1];
+
+        switch (avctx->sample_fmt) {
+        case AV_SAMPLE_FMT_S16P:
+            for (int n = 0; n < frame->nb_samples;) {
+                ret = decode_ch_samples(avctx, &s->ch[0]);
+                if (ret == 0) {
+                    frame->nb_samples = n;
+                    break;
+                }
+                if (ret < 0 || n + ret > frame->nb_samples)
+                    return AVERROR_INVALIDDATA;
+
+                ret = decode_ch_samples(avctx, &s->ch[1]);
+                if (ret == 0) {
+                    frame->nb_samples = n;
+                    break;
+                }
+                if (ret < 0 || n + ret > frame->nb_samples)
+                    return AVERROR_INVALIDDATA;
+
+                for (int i = 0; i < ret; i++) {
+                    int l = s->ch[0].buf0[2560 + i];
+                    int r = s->ch[1].buf0[2560 + i];
+
+                    l16[n + i] = (l * 2 + r + 1) >> 1;
+                    r16[n + i] = (l * 2 - r + 1) >> 1;
+                }
+
+                n += ret;
+            }
+            break;
+        default:
+            return AVERROR_INVALIDDATA;
+        }
+    } else {
+        int16_t *m16 = (int16_t *)frame->data[0];
+
+        switch (avctx->sample_fmt) {
+        case AV_SAMPLE_FMT_S16P:
+            for (int n = 0; n < frame->nb_samples;) {
+                ret = decode_ch_samples(avctx, &s->ch[0]);
+                if (ret == 0) {
+                    frame->nb_samples = n;
+                    break;
+                }
+                if (ret < 0 || n + ret > frame->nb_samples)
+                    return AVERROR_INVALIDDATA;
+
+                for (int i = 0; i < ret; i++) {
+                    int m = s->ch[0].buf0[2560 + i];
+
+                    m16[n + i] = m;
+                }
+
+                n += ret;
+            }
+            break;
+        default:
+            return AVERROR_INVALIDDATA;
+        }
+    }
+
+    *got_frame_ptr = 1;
+
+    return avpkt->size;
+}
+
+static av_cold int rka_decode_close(AVCodecContext *avctx)
+{
+    RKAContext *s = avctx->priv_data;
+
+    for (int ch = 0; ch < 2; ch++) {
+        ChContext *c = &s->ch[ch];
+
+        for (int i = 0; i < 11; i++)
+            adaptive_model_free(&c->coeff_bits[i]);
+
+        adaptive_model_free(&c->position);
+        adaptive_model_free(&c->nb_segments);
+        adaptive_model_free(&c->fshift);
+    }
+
+    adaptive_model_free(&s->filt_size);
+    adaptive_model_free(&s->filt_bits);
+
+    return 0;
+}
+
+const FFCodec ff_rka_decoder = {
+    .p.name         = "rka",
+    CODEC_LONG_NAME("RKA (RK Audio"),
+    .p.type         = AVMEDIA_TYPE_AUDIO,
+    .p.id           = AV_CODEC_ID_RKA,
+    .priv_data_size = sizeof(RKAContext),
+    .init           = rka_decode_init,
+    .close          = rka_decode_close,
+    FF_CODEC_DECODE_CB(rka_decode_frame),
+    .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF,
+    .caps_internal  = FF_CODEC_CAP_INIT_CLEANUP,
+};
-- 
2.39.1