From patchwork Sat Feb 4 09:04:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Paul B Mahol X-Patchwork-Id: 40244 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp1822941pzk; Sat, 4 Feb 2023 01:05:01 -0800 (PST) X-Google-Smtp-Source: AK7set9dkMJveTrL6KOMktrUFgLL8KXkNGAQ1XApenrB8lKJiLpv9v+vE893DSAXT61yhJvZG/l0 X-Received: by 2002:a17:906:3ca1:b0:86f:ae1f:9234 with SMTP id b1-20020a1709063ca100b0086fae1f9234mr12464167ejh.7.1675501501227; Sat, 04 Feb 2023 01:05:01 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675501501; cv=none; d=google.com; s=arc-20160816; b=i16IdazvuJ2eICOuzY112hGukc3ieFtKPEJ4+eEOaIKTUmlGNFbw2oaawLgvWK76RW Yb14LS7zpXjImIBO07H8IR0QF7dGbd60GTVjNBsYoirwG3ADC2lZXRHtDzRRjwTV+O6G Yp9y1sZ53vMZWPAd+l59hfKpgu0KzqS46zMlqu4UVvWyL9v26vLEC/0mj2lsLtv6C5it Ta0tPkeX98REYrdSsJhVDgngIeUSxw9pfpVkodYG8aFry4sCkU8vXDbr6pxffo4eAS4T u8zOqEDMW97MKRsqVRQ5mblhwNhhCGE35UwBvVpe3e/Vk9cW4NIiR2sGy5XF0C/bEBa7 QqYQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:reply-to:list-subscribe:list-help:list-post :list-archive:list-unsubscribe:list-id:precedence:subject:to :message-id:date:from:mime-version:dkim-signature:delivered-to; bh=wsat0B32pti3URAhssX4unoeNro4Q+8fWsYeMbCisTY=; b=Lx0AtRlgLV0X69rLT4LSI3FBI7JFWCv4LEbqrWOH83XMHAgNC3+vYYnnOFd6Bal77K c0JJjyd7fPRasjyE5Ql7XPkmzPpZ74GgnN21VhhFOKplbfphb4mqCQdNf4KKnAojjttQ OKNnGXpeYjvBdj1Nue33Q8cqQYbh9F/crxjSbAnMVwoitrmkwLNMmfwjjMPLBh6NGRBj aOEd5bVOKjOIFNmOJshcAB2OZT4LXb4y57tjZVpG5PSpOb4uiXk44jmiiKCcNGpmtmlA mjXREQGS2NKWuVWYddLFgztqp55uSL6QXGljkiY8tnafnLhxnfWW+cPP87FqXvsPk+o1 5ZRA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=ZaQcYAoX; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id b8-20020a0564021f0800b004a08f621badsi5347700edb.284.2023.02.04.01.04.37; Sat, 04 Feb 2023 01:05:01 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=ZaQcYAoX; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9A3DB68B526; Sat, 4 Feb 2023 11:04:33 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-ua1-f51.google.com (mail-ua1-f51.google.com [209.85.222.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id B796168BB84 for ; Sat, 4 Feb 2023 11:04:27 +0200 (EET) Received: by mail-ua1-f51.google.com with SMTP id g24so1356144uap.13 for ; Sat, 04 Feb 2023 01:04:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:subject:message-id:date:from:mime-version:from:to:cc:subject :date:message-id:reply-to; bh=lDByrxhBbsVBqEn0w/sfAdEBVvNyeZXTFucHgklw0uM=; b=ZaQcYAoXLYvv3TBf9zuyEMdzCJyILyMwcTpr7Xxe410Fdu6AjwSXFPzwt5/5ckmpuE zRvp7JlLq9ghpGsAsRmEIp9I+mdEzlSwcBpGB8mZ1etP8c0B9VKrIFccJjckgr8pQV1t RKo5PKGElKxyPUdBu8wgqEyWjGbpCTOgB3fNAJkloHMk+Cc8b7fWpnwlceGQqf2qZp3F ssQ+R/c+pLMuMAIgOR3qVquSgiFC24SJ78HvV+I4ZzuS/I2rX/+uHgi7qpdVMvxSQCB8 tJ4S4S17hv+YvF58bX22IAZO4+lSIbAHtOKIJdBNHW5QeWoyw41X3NoqN7j6c1tj22Cf KaLQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:mime-version:x-gm-message-state :from:to:cc:subject:date:message-id:reply-to; bh=lDByrxhBbsVBqEn0w/sfAdEBVvNyeZXTFucHgklw0uM=; b=bGcOvm/j1KjsA7uFltg2FVD8rLnwQhCc76uig+0tqV6QAZVTUTdgUtVLzgWXQ6JP/b MaqBCt9zqSS/WVDeJPVUYhFUybGUnhkRVw2WwhWlWg9SWYoXxyZjumH640b+kY7vRG7M edr9fZO2MS6nhPcKclX1Pq2q8Qakma0ZSM7VCWHcRFGelsR86uyNlXj7Dz3u70dGdeD0 /w0awiMl7SpbbbMHaUz2TYuoY2TGXwwApwujsLjpftkwZzf5OzE3syYqK95D3vGPFiqX RtbqxheZkFrS8HFTH8slFNtmjZYjRT9a0KWsN5KQ1oM7PvHmWhMLWQaTGqFfTh8Vm5s/ 8JIg== X-Gm-Message-State: AO0yUKWRMKEoc24662sYgUCTbOCtCzys86Psu7h7OKuxg4v5GzxF/MJY VdIceBzOaK773SeU4IcW/C1M4LJibccJ+KhM5IfOmcyS X-Received: by 2002:ab0:5a08:0:b0:65d:15a9:7862 with SMTP id l8-20020ab05a08000000b0065d15a97862mr2080495uad.69.1675501465980; Sat, 04 Feb 2023 01:04:25 -0800 (PST) MIME-Version: 1.0 Received: by 2002:a05:612c:2428:b0:32a:5eaa:92e4 with HTTP; Sat, 4 Feb 2023 01:04:24 -0800 (PST) From: Paul B Mahol Date: Sat, 4 Feb 2023 10:04:24 +0100 Message-ID: To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [RFC][WIP][PATCH] RK Audio demuxer and decoder X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 0MQY8jPJTkuc Hi, Patches attached, decoder is not bit by bit exact yet for lossless mode because some samples are not properly rounded. From f3d05a9ac45177eeb3e3cbbbce9e53980c4047f5 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Tue, 31 Jan 2023 21:03:38 +0100 Subject: [PATCH 2/2] avcodec: add RKA decoder Signed-off-by: Paul B Mahol --- 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 + +#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