diff mbox series

[FFmpeg-devel,RFC,WIP] RK Audio demuxer and decoder

Message ID CAPYw7P7upPN5ebUzux17vZoik1K2mpXXDQ1VNbaSvmPa+JJD4Q@mail.gmail.com
State New
Headers show
Series [FFmpeg-devel,RFC,WIP] 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. 4, 2023, 9:04 a.m. UTC
Hi,

Patches attached, decoder is not bit by bit exact yet for lossless
mode because some samples are not properly rounded.
diff mbox series

Patch

From f3d05a9ac45177eeb3e3cbbbce9e53980c4047f5 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        | 1066 +++++++++++++++++++++++++++++++++++++++
 5 files changed, 1076 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..629978ff2d
--- /dev/null
+++ b/libavcodec/rka.c
@@ -0,0 +1,1066 @@ 
+/*
+ * 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 <limits.h>
+
+#include "libavutil/avassert.h"
+#include "libavutil/channel_layout.h"
+#include "libavutil/intreadwrite.h"
+
+#include "avcodec.h"
+#include "codec_internal.h"
+#include "bytestream.h"
+#include "decode.h"
+#include "unary.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 {
+    int32_t zero_prob0;
+    int32_t zero_prob1;
+    int32_t sign_prob0;
+    int32_t sign_prob1;
+    unsigned size;
+    int bits;
+
+    uint16_t buf_val4[65];
+    uint16_t buf_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;
+    uint16_t *ptr;
+} AdaptiveModel;
+
+typedef struct ChContext {
+    int start;
+    int end;
+    int cmode;
+    int cmode2;
+    unsigned srate_pad;
+    unsigned pos_mod11;
+
+    AdaptiveModel *filt_size;
+    AdaptiveModel *filt_bits;
+
+    int *bprob0;
+    int *bprob1;
+
+    AdaptiveModel pos_update;
+    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 cur_chan;
+    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->total = 0;
+    am->aprob0 = 0;
+    am->aprob1 = 0;
+    am->buf_size = buf_size;
+    am->sum = 2000;
+
+    if (!am->prob)
+        am->prob = av_malloc_array(buf_size + 5, sizeof(*am->prob));
+    if (!am->ptr)
+        am->ptr = av_malloc_array(buf_size + 5, sizeof(*am->ptr));
+
+    if (!am->prob || !am->ptr)
+        return AVERROR(ENOMEM);
+    memset(am->prob, 0, (buf_size + 5) * sizeof(*am->prob));
+    memset(am->ptr, 0, (buf_size + 5) * sizeof(*am->ptr));
+    return 0;
+}
+
+static void adaptive_model_free(AdaptiveModel *am)
+{
+    av_freep(&am->prob);
+    av_freep(&am->ptr);
+}
+
+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_U8;
+        break;
+    case 16:
+        avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+        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(NULL, 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_prob1 = 1;
+
+    x = (1 << (bits >> 1)) + 3;
+    x = FFMIN(x, 20);
+
+    m->zero_prob0 = x;
+    m->sign_prob0 = 1;
+    m->sign_prob1 = 1;
+
+    for (int i = 0; i < FF_ARRAY_ELEMS(m->buf_val4); i++) {
+        m->buf_val4[i] = 4;
+        m->buf_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->start = c->end = 2560;
+    c->srate_pad = (sample_rate << 13) / 44100 & 0xFFFFFFFCU;
+    c->pos_mod11 = 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->pos_update, 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;
+            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] += diff;
+            } else {
+                do {
+                    am->prob[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)
+{
+    int val_1;
+    int v5;
+    unsigned int i;
+    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;
+    unsigned int freq;
+    signed int freqa;
+    uint16_t v27;
+    uint16_t j;
+    uint16_t v29;
+
+    val_1 = size;
+    if (size > am->buf_size - 1)
+        val_1 = 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]++;
+            } else {
+                do {
+                    am->prob[val]++;
+                    val += (val & -val);
+                } while ( val < am->buf_size );
+            }
+            return 0;
+        }
+        if (val_1 == am->buf_size - 1) {
+            freq = am->aprob0;
+        } else {
+            if (val_1 != -1) {
+                v5 = val_1;
+                for ( i = am->prob[0]; v5 > 0; v5 &= (v5 - 1) )
+                    i += am->prob[v5];
+                freq = i;
+            } else {
+                freq = 0;
+            }
+        }
+        v24 = 0;
+        ac_get_freq(ac, freq, &v7);
+        v8 = am->buf_size >> 1;
+        v9 = am->prob[0];
+        if (v7 >= v9) {
+            for ( j = v7 - v9; v8; v8 >>= 1 ) {
+                v11 = am->prob[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;
+        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]++;
+        } else {
+            do {
+                am->prob[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->ptr[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->ptr[dst[0]])
+                ++v29;
+            dst[0] = val + 1;
+        }
+        while ( v29 < v18 && val + 1 < am->buf_size );
+    }
+    if (am->ptr[dst[0]]) {
+        do {
+            val = dst[0]++;
+        } while (val + 1 < am->buf_size && am->ptr[val + 1]);
+    }
+    ac_update(ac, v29, 1);
+    am->ptr[dst[0]]++;
+    am->total++;
+    val = dst[0];
+    am->aprob0++;
+    if (val <= 0) {
+        am->prob[0]++;
+    } else {
+        do {
+            am->prob[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 i;
+
+    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;
+
+    i = 0;
+    do {
+        if (((i == 8) || (i == 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, 0x10000, &val);
+            ac_update(ac, val, 1);
+        }
+
+        if (val == 0) {
+            dst->coeffs[i] = 0;
+        } else {
+            unsigned freq = 0;
+            int sign;
+
+            if (bits > 0) {
+                ac_get_freq(ac, 1 << bits, &freq);
+                ac_update(ac, freq, 1);
+            }
+            dst->coeffs[i] = freq + 1 + ((val - 1U) << bits);
+            sign = decode_bool(ac, ctx, i);
+            if (sign < 0)
+                return -1;
+            if (sign == 1)
+                dst->coeffs[i] = -dst->coeffs[i];
+        }
+    } while (++i < dst->size);
+
+    return 0;
+}
+
+static int ac_dec_bit(ACoder *ac)
+
+{
+    uint32_t high, low;
+
+    low = ac->low;
+    high = ac->high >> 1;
+    ac->high = high;
+    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);
+            high = ac->high << 8;
+            ac->high = high;
+            low = ac->low << 8;
+            ac->low = low;
+        } 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)
+{
+    uint16_t *psVar1;
+    int bVar3;
+    int sign;
+    int iVar5;
+    unsigned val;
+    int bits;
+
+    val = 0;
+    if ((unsigned)(ctx->zero_prob0 + ctx->zero_prob1) > 4000) {
+        ctx->zero_prob0 = (ctx->zero_prob0 >> 1) + 1;
+        ctx->zero_prob1 = (ctx->zero_prob1 >> 1) + 1;
+    }
+    if ((unsigned)(ctx->sign_prob1 + ctx->sign_prob0) > 4000) {
+        ctx->sign_prob0 = (ctx->sign_prob0 >> 1) + 1;
+        ctx->sign_prob1 = (ctx->sign_prob1 >> 1) + 1;
+    }
+    sign = ac_decode_bool(ac,ctx->zero_prob1,ctx->zero_prob0);
+    if (sign == 0) {
+        ctx->zero_prob1 += 2;
+        dst[0] = 0;
+        return 0;
+    } else if (sign < 0)
+        return -1;
+
+    ctx->zero_prob0 += 2;
+    sign = ac_decode_bool(ac,ctx->sign_prob0,ctx->sign_prob1);
+    if (sign == 1) {
+        ctx->sign_prob1++;
+    } else if (sign == 0) {
+        ctx->sign_prob0++;
+    } else {
+        return -1;
+    }
+    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;
+    iVar5 = 0;
+    if (bits >= 0) {
+        do {
+            psVar1 = ctx->buf_val4;
+            if (2000U < (unsigned)(psVar1[iVar5] + ctx->buf_val1[iVar5])) {
+                psVar1[iVar5] = (psVar1[iVar5] >> 1) + 1;
+                ctx->buf_val1[iVar5] = (ctx->buf_val1[iVar5] >> 1) + 1;
+            }
+            bVar3 = ac_decode_bool(ac, ctx->buf_val4[iVar5], ctx->buf_val1[iVar5]);
+            if (bVar3 == 1) {
+                ctx->buf_val1[iVar5] = ctx->buf_val1[iVar5] + 4;
+                break;
+            } else if (bVar3 < 0)
+                return -1;
+            ctx->buf_val4[iVar5] = ctx->buf_val4[iVar5] + 4;
+            iVar5 = iVar5 + 1;
+        } while (iVar5 <= ctx->size);
+        bits = ctx->size;
+        if (iVar5 <= bits) {
+            bits = val + 1 + (iVar5 << ((uint8_t)ctx->bits & 0x1f));
+            dst[0] = bits;
+            if (sign)
+                dst[0] *= -1;
+            return 0;
+        }
+    }
+    bits = bits + 1;
+    while (ac_dec_bit(ac) == 0)
+        bits = bits + 64;
+    ac_get_freq(ac, 64, &iVar5);
+    ac_update(ac,iVar5,1);
+    iVar5 = bits + iVar5;
+    bits = val + 1 + (iVar5 << ((uint8_t)ctx->bits & 0x1f));
+    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;
+    unsigned bits;
+    int ret;
+    int aval;
+    uint8_t shift;
+    int iVar3;
+    int i;
+    int local_c40;
+    int local_c3c;
+    int local_c30;
+    int last_val;
+    int local_c28;
+    unsigned pos_mod11;
+    int cmode2;
+
+    pos_mod11 = 3;
+    last_val = 0;
+    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)
+        local_c30 = size / 2;
+    else
+        local_c30 = size >> 4;
+    cmode2 = 0;
+    if (size > 0) {
+        do {
+            local_c40 = 0;
+            local_c3c = local_c30 + cmode2;
+            if (size < local_c3c) {
+                local_c30 = size - cmode2;
+                local_c3c = size;
+            }
+            if (amdl_decode_int(&ctx->pos_update, ac, &pos_mod11, 10) < 0)
+                return -1;
+            pos_mod11 = (ctx->pos_mod11 + pos_mod11) % 11;
+            ctx->pos_mod11 = pos_mod11;
+            iVar3 = local_c30 + cmode2;
+            if (cmode2 < local_c3c) {
+                do {
+                    int *src, sum = 16;
+
+                    aval = FFABS(last_val);
+                    shift = (uint8_t)pos_mod11;
+                    if (aval >> (shift & 0x1f) < 0xf) {
+                        aval = FFABS(last_val);
+                        if (aval >> (shift & 0x1f) < 7) {
+                            last_val = FFABS(last_val);
+                            if (last_val >> (shift & 0x1f) < 4)
+                                mdl64 = &ctx->mdl64[0][pos_mod11];
+                            else
+                                mdl64 = &ctx->mdl64[1][pos_mod11];
+                        } else {
+                            mdl64 = &ctx->mdl64[2][pos_mod11];
+                        }
+                    } else {
+                        mdl64 = &ctx->mdl64[3][pos_mod11];
+                    }
+                    ret = mdl64_decode(ac, mdl64, &local_c28);
+                    if (ret < 0)
+                        return -1;
+                    last_val = local_c28;
+                    aval = cmode2 + 1;
+                    src = &ctx->buf1[off + cmode2 + -1];
+                    for (i = 0; i < filt.size && i < 15; i++)
+                        sum += filt.coeffs[i] * src[-i];
+                    sum = sum * 2;
+                    for (; i < filt.size; i++)
+                        sum += filt.coeffs[i] * src[-i];
+                    sum = sum >> 6;
+                    if (ctx->cmode == 0) {
+                        if (bits == 0) {
+                            ctx->buf1[off + cmode2] = sum + local_c28;
+                        } else {
+                            ctx->buf1[off + cmode2] =
+                                (local_c28 + (sum >> bits) * (1U << bits)) +
+                                (((1U << bits) - 1U) & ctx->buf1[off + cmode2 + -1]);
+                        }
+                        ctx->buf0[off + cmode2] = ctx->buf1[off + cmode2] + ctx->buf0[off + cmode2 + -1];
+                    } else {
+                        local_c28 = local_c28 * (1 << ctx->cmode & 0x1f);
+                        sum = sum + ctx->buf0[off + cmode2 + -1] + local_c28;
+                        switch (s->bps) {
+                        case 16: sum = av_clip_int16(sum); break;
+                        case  8: sum = av_clip_int8(sum);  break;
+                        }
+                        ctx->buf1[off + cmode2] = sum - ctx->buf0[off + cmode2 + -1];
+                        ctx->buf0[off + cmode2] = sum;
+                        cmode2 = FFABS(ctx->buf1[off + cmode2]);
+                        local_c40 += cmode2;
+                    }
+                    cmode2 = aval;
+                } while (aval < local_c3c);
+            }
+            cmode2 = ctx->cmode2;
+            if (cmode2 != 0) {
+                int sum = 0;
+                for (aval = (local_c40 << 6) / local_c30; 0 < aval; aval = aval >> 1)
+                    sum = sum + 1;
+                sum = sum - (cmode2 + 7);
+                aval = tab[cmode2];
+                if (tab[cmode2] < sum)
+                    aval = sum;
+                ctx->cmode = aval;
+            }
+            cmode2 = iVar3;
+        } while (iVar3 < size);
+    }
+
+    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_sample(AVCodecContext *avctx, int *sample)
+{
+    RKAContext *s = avctx->priv_data;
+    ACoder *ac = &s->ac;
+    ChContext *c;
+
+    c = &s->ch[s->cur_chan];
+    if (c->start >= c->end) {
+        int i = 0;
+
+        if (bytestream2_get_bytes_left(&ac->gb) <= 0)
+            return AVERROR_EOF;
+
+        do {
+            c->buf0[i] = c->buf0[i + c->end - 2560];
+            c->buf1[i] = c->buf1[i + c->end - 2560];
+            i++;
+        } while (i < 2560);
+
+        c->start = c->end = 2560;
+
+        i = decode_samples(avctx, ac, c, 2560);
+        if (i < 0)
+            return i;
+        c->end += i;
+    }
+
+    sample[0] = c->buf0[c->start];
+    c->start++;
+
+    s->cur_chan++;
+    if (s->cur_chan >= s->channels)
+        s->cur_chan = 0;
+
+    return 0;
+}
+
+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);
+    s->cur_chan = 0;
+
+    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 *dst = (int16_t *)frame->data[0];
+
+        switch (avctx->sample_fmt) {
+        case AV_SAMPLE_FMT_S16:
+            for (int n = 0; n < frame->nb_samples; n++) {
+                int l, r;
+
+                ret = decode_ch_sample(avctx, &l);
+                if (ret == AVERROR_EOF) {
+                    frame->nb_samples = n;
+                    break;
+                }
+                if (ret < 0)
+                    return AVERROR_INVALIDDATA;
+
+                ret = decode_ch_sample(avctx, &r);
+                if (ret == AVERROR_EOF) {
+                    frame->nb_samples = n;
+                    break;
+                }
+                if (ret < 0)
+                    return AVERROR_INVALIDDATA;
+
+                dst[2 * n + 0] = (l * 2 + r + 1) / 2;
+                dst[2 * n + 1] = (l * 2 - r + 1) / 2;
+            }
+            break;
+        default:
+            return AVERROR_INVALIDDATA;
+        }
+    } else {
+        int16_t *dst = (int16_t *)frame->data[0];
+
+        switch (avctx->sample_fmt) {
+        case AV_SAMPLE_FMT_S16:
+            for (int n = 0; n < frame->nb_samples; n++) {
+                int m;
+
+                ret = decode_ch_sample(avctx, &m);
+                if (ret == AVERROR_EOF) {
+                    frame->nb_samples = n;
+                    break;
+                }
+                if (ret < 0)
+                    return AVERROR_INVALIDDATA;
+
+                dst[n] = m;
+            }
+            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->pos_update);
+        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