Hi,

Patches attached, decoder is not bit by bit exact yet for lossless
mode because some samples are not properly rounded.
From 71bfdb9eadc988b1154f8202b12a380839096d48 Mon Sep 17 00:00:00 2001
From: Paul B Mahol <one...@gmail.com>
Date: Tue, 31 Jan 2023 19:27:09 +0100
Subject: [PATCH 1/2] avformat: add RKA demuxer

Signed-off-by: Paul B Mahol <one...@gmail.com>
---
 libavformat/Makefile     |   1 +
 libavformat/allformats.c |   1 +
 libavformat/rka.c        | 170 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 172 insertions(+)
 create mode 100644 libavformat/rka.c

diff --git a/libavformat/Makefile b/libavformat/Makefile
index f0408a58b1..28cbf91382 100644
--- a/libavformat/Makefile
+++ b/libavformat/Makefile
@@ -482,6 +482,7 @@ OBJS-$(CONFIG_RAWVIDEO_DEMUXER)          += rawvideodec.o
 OBJS-$(CONFIG_RAWVIDEO_MUXER)            += rawenc.o
 OBJS-$(CONFIG_REALTEXT_DEMUXER)          += realtextdec.o subtitles.o
 OBJS-$(CONFIG_REDSPARK_DEMUXER)          += redspark.o
+OBJS-$(CONFIG_RKA_DEMUXER)               += rka.o
 OBJS-$(CONFIG_RL2_DEMUXER)               += rl2.o
 OBJS-$(CONFIG_RM_DEMUXER)                += rmdec.o rm.o rmsipr.o
 OBJS-$(CONFIG_RM_MUXER)                  += rmenc.o rm.o
diff --git a/libavformat/allformats.c b/libavformat/allformats.c
index 9ca8d2692f..4903bf7f9d 100644
--- a/libavformat/allformats.c
+++ b/libavformat/allformats.c
@@ -380,6 +380,7 @@ extern const AVInputFormat  ff_rawvideo_demuxer;
 extern const AVOutputFormat ff_rawvideo_muxer;
 extern const AVInputFormat  ff_realtext_demuxer;
 extern const AVInputFormat  ff_redspark_demuxer;
+extern const AVInputFormat  ff_rka_demuxer;
 extern const AVInputFormat  ff_rl2_demuxer;
 extern const AVInputFormat  ff_rm_demuxer;
 extern const AVOutputFormat ff_rm_muxer;
diff --git a/libavformat/rka.c b/libavformat/rka.c
new file mode 100644
index 0000000000..0f670a89a3
--- /dev/null
+++ b/libavformat/rka.c
@@ -0,0 +1,170 @@
+/*
+ * RKA demuxer
+ * 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/dict.h"
+#include "libavutil/intreadwrite.h"
+
+#include "apetag.h"
+#include "avformat.h"
+#include "avio_internal.h"
+#include "demux.h"
+#include "internal.h"
+
+typedef struct RKAContext {
+    int total_frames, currentframe;
+    int frame_size;
+    int last_frame_size;
+} RKAContext;
+
+static int rka_probe(const AVProbeData *p)
+{
+    if (AV_RL32(&p->buf[0]) == MKTAG('R', 'K', 'A', '7') &&
+        AV_RL32(&p->buf[4]) > 0 &&
+        AV_RL32(&p->buf[8]) > 0 &&
+        p->buf[12] > 0 &&
+        p->buf[12] <= 2 &&
+        (p->buf[13] == 8 || p->buf[13] == 16) &&
+        p->buf[15] & 2 != 0)
+        return AVPROBE_SCORE_EXTENSION + 30;
+    return 0;
+}
+
+static int rka_read_header(AVFormatContext *s)
+{
+    int64_t nb_samples, size_offset;
+    RKAContext *c = s->priv_data;
+    int channels, bps, samplerate;
+    AVCodecParameters *par;
+    int64_t framepos;
+    AVStream *st;
+    int ret;
+
+    st = avformat_new_stream(s, NULL);
+    if (!st)
+        return AVERROR(ENOMEM);
+
+    par = st->codecpar;
+    ret = ff_get_extradata(s, par, s->pb, 16);
+    if (ret < 0)
+        return ret;
+
+    nb_samples = AV_RL32(par->extradata + 4);
+    samplerate = AV_RL32(par->extradata + 8);
+    channels = par->extradata[12];
+    if (channels == 0)
+        return AVERROR_INVALIDDATA;
+    bps = par->extradata[13];
+    if (bps == 0)
+        return AVERROR_INVALIDDATA;
+    size_offset = avio_rl32(s->pb);
+    framepos = avio_tell(s->pb);
+    c->frame_size = 131072;
+
+    avpriv_set_pts_info(st, 64, 1, samplerate);
+    st->start_time = 0;
+
+    avio_seek(s->pb, size_offset, SEEK_SET);
+    c->total_frames = (nb_samples + c->frame_size - 1) / c->frame_size;
+    c->last_frame_size = nb_samples % c->frame_size;
+
+    for (int i = 0; i < c->total_frames; i++) {
+        int r, end = 0;
+        int64_t size;
+
+        if (avio_feof(s->pb))
+            break;
+
+        size = avio_rl24(s->pb);
+        if (size == 0) {
+            end = 1;
+            size = size_offset - framepos;
+            if (size <= 0)
+                break;
+        }
+
+        if ((r = av_add_index_entry(st, framepos, (i * 131072LL) / (channels * (bps >> 3)),
+                                    size, 0, AVINDEX_KEYFRAME)) < 0)
+            return r;
+        framepos += size;
+
+        if (end)
+            break;
+    }
+
+    par->codec_type = AVMEDIA_TYPE_AUDIO;
+    par->codec_id = AV_CODEC_ID_RKA;
+    par->ch_layout.nb_channels = channels;
+    par->sample_rate = samplerate;
+    par->bits_per_raw_sample = bps;
+    st->duration = nb_samples / (channels * (bps >> 3));
+
+    avio_seek(s->pb, 20, SEEK_SET);
+
+    return 0;
+}
+
+static int rka_read_packet(AVFormatContext *s, AVPacket *pkt)
+{
+    RKAContext *c = s->priv_data;
+    AVStream *st = s->streams[0];
+    FFStream *const sti = ffstream(st);
+    int size, ret;
+
+    if (avio_feof(s->pb))
+        return AVERROR_EOF;
+
+    if (c->currentframe >= sti->nb_index_entries)
+        return AVERROR_EOF;
+
+    size = sti->index_entries[c->currentframe].size;
+
+    ret = av_get_packet(s->pb, pkt, size);
+    pkt->dts = sti->index_entries[c->currentframe++].timestamp;
+    pkt->duration = c->currentframe == c->total_frames ? c->last_frame_size :
+                                                         131072;
+    return ret;
+}
+
+static int rka_read_seek(AVFormatContext *s, int stream_index, int64_t timestamp, int flags)
+{
+    RKAContext *c = s->priv_data;
+    AVStream *st = s->streams[stream_index];
+    int index = av_index_search_timestamp(st, timestamp, flags);
+    if (index < 0)
+        return -1;
+    if (avio_seek(s->pb, ffstream(st)->index_entries[index].pos, SEEK_SET) < 0)
+        return -1;
+
+    c->currentframe = index;
+
+    return 0;
+}
+
+const AVInputFormat ff_rka_demuxer = {
+    .name           = "rka",
+    .long_name      = NULL_IF_CONFIG_SMALL("RKA (RK Audio)"),
+    .priv_data_size = sizeof(RKAContext),
+    .read_probe     = rka_probe,
+    .read_header    = rka_read_header,
+    .read_packet    = rka_read_packet,
+    .read_seek      = rka_read_seek,
+    .extensions     = "rka",
+};
-- 
2.39.1

From f3d05a9ac45177eeb3e3cbbbce9e53980c4047f5 Mon Sep 17 00:00:00 2001
From: Paul B Mahol <one...@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 <one...@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

_______________________________________________
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
https://ffmpeg.org/mailman/listinfo/ffmpeg-devel

To unsubscribe, visit link above, or email
ffmpeg-devel-requ...@ffmpeg.org with subject "unsubscribe".

Reply via email to