From patchwork Sun Feb 5 19:17:50 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: 40287 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:5494:b0:bf:7b3a:fd32 with SMTP id i20csp2823709pzk; Sun, 5 Feb 2023 11:18:09 -0800 (PST) X-Google-Smtp-Source: AK7set8qi7CcGbjHJrezsNZQFkSIcQOxoauPEFxfJzMy19LioEbumLabWywUDR1K7s1TG//BRB/4 X-Received: by 2002:a05:6402:298c:b0:4a8:452:55a4 with SMTP id eq12-20020a056402298c00b004a8045255a4mr13408980edb.17.1675624688994; Sun, 05 Feb 2023 11:18:08 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1675624688; cv=none; d=google.com; s=arc-20160816; b=YA3OWRxzJ6PQ6OW9sHKeHdcFKWeyHzij+Uhvnrk3QSGrhOFxKL7wkB8dtHtSMauW7T NbxoPJ4AF5LDHJWo7mxMuXdUFLMFpGobRYB+e84f9y7U0dUXhBCv/1euVKZySoXmd7Wm epNIhfMDuiJ/cHeVHwUvroVuXl556Ii1/4JwQRsd7/lgxyitHknAe+kirLrQGyNZ1OvS OjjynpZoZzg34MQUzEcXk0l1ffXqczNg50q1ZdLn7sirNQheD8Iw1hbhPbLr6ri3Vso3 BtlQPYZM63VyMacsF4mPNo3XBAku3nl4HYhxiUJd4FZllq79Xu3zbIPpu+vSxOADhG/r do5A== 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:references:in-reply-to:mime-version :dkim-signature:delivered-to; bh=knFGIgqtdOiUR9G+5ldxKT17PWBQ35H4moj7GnKam8o=; b=oUVVyGDDUbNWIOdcTHA28cR9F4ZLC6DEMhEd0/WpWLu1VV/xyB1oki0lyCI0eBxbnF KdCgAHCOMq/gBSAPaNzy/m2P3N0dDfKjPDkBrKHqr3W+mEoSak4l4j9qwt9UwASIYqSp IEBvsIva5ew+kRNIHMq+RZwOKWjy/l3xn9OlppshvQMnSvR889ZL0dvRLS627izljoV+ J+jqxOiep3in+6BX/wkebo3SnHNsWl45m+b3A5H4G8XcikVOv5AhvYOZYjdO9VZfuzsN HRfkhA6T0GrfHwGZcvG2lzUydF0vLRLrUw78rffLnsy7KhYrYwLUe3oz9MrQqz8gdEi6 jaJw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=l4I65ug2; 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 q9-20020a056402248900b00483bcf2ab07si10836332eda.325.2023.02.05.11.18.08; Sun, 05 Feb 2023 11:18:08 -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=l4I65ug2; 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 27B8568BDCC; Sun, 5 Feb 2023 21:18:03 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-vs1-f54.google.com (mail-vs1-f54.google.com [209.85.217.54]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 63D5368BB41 for ; Sun, 5 Feb 2023 21:17:56 +0200 (EET) Received: by mail-vs1-f54.google.com with SMTP id j7so10605931vsl.11 for ; Sun, 05 Feb 2023 11:17:56 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:subject:message-id:date:from:references:in-reply-to:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=8meGRlVw0J85chSLXa0evqdLQXLK/ixo6dTwVxy5p0U=; b=l4I65ug26RpHmseZuEv+VRxj+RIuvX0j2uxX/Qquxnr66mNlZg2Elx6UVR3/Y+awaS yc+6gW1tHY52qk938C7sU/AycnJxFbh2CmD+DYMGCQUwF33Zq6cH3/WxZTugRJEr0CBB PZ7kXibbGEQZJjY3aXmVhwpWPUhMcUncuE69ZYA55a/rLGSWi+ozAkX36TVCM5qQ3pks b70/p3BnyPR+DvrmKYQPFxpBw5Q8qWkJtp0bgsAG9ypm6iYlRG8wdY2zR/5dPjxPwhDJ NnEW8bzKqJjSJNAkWAjvpmO2lKVVl/ZraJmWCHcXQ8e4HpNnBvW0jAbgCDCBaPYMKd83 +GnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:references:in-reply-to:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=8meGRlVw0J85chSLXa0evqdLQXLK/ixo6dTwVxy5p0U=; b=zzx6InoC+2UByGFa5mRZN49xTMEPAi3aEPmqdgRMtupCE0QqCUBsN0pcOv7fhE501l naW2ubqESP42J8Sq6YkCcomtKXlja+3LybLpjEH44tr9i8aX8vVmuv6YmVGfa44PMV7r /AVT58U5zOi965ZqzPECRGlOFO0paYjBXhQ9sfqsIGeyOX3dQDcUEDCLtcy01ZIVXDXD X/UguneqVvDD2slpSO3+o6BBH8dorwmU7Jr/sLJLuseshkLQrmCiNR169l7nEtEpppTI 3BWWf6uapTwgg+14J+tT/hHIupZfCwONVgjHFNAXAfTHX1i/Z5Qy65hO29YLEAgD3HPc dFSQ== X-Gm-Message-State: AO0yUKU9KbioLeTOx8kKbwn9MKvAm+hPt6KOjUV9f2er76+MTPzw8vyF aZBrkQ9q7XGHO4YZsUFZT/fY9h+ymWv1ExnLFINW/XJ1 X-Received: by 2002:a67:f984:0:b0:3f1:32b7:7185 with SMTP id b4-20020a67f984000000b003f132b77185mr2680452vsq.61.1675624673234; Sun, 05 Feb 2023 11:17:53 -0800 (PST) MIME-Version: 1.0 Received: by 2002:a05:612c:2428:b0:32a:5eaa:92e4 with HTTP; Sun, 5 Feb 2023 11:17:50 -0800 (PST) In-Reply-To: References: From: Paul B Mahol Date: Sun, 5 Feb 2023 20:17:50 +0100 Message-ID: To: FFmpeg development discussions and patches Subject: [FFmpeg-devel] [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: Cm23tWikF3rT On 2/4/23, Paul B Mahol wrote: > Hi, > > Patches attached, decoder is not bit by bit exact yet for lossless > mode because some samples are not properly rounded. > Now lossless mode is bit exact. From 217b459cea1e6468835240d1c2313e89918e6d7b 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 | 999 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1009 insertions(+) create mode 100644 libavcodec/rka.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 4971832ff4..389253f5d0 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -631,6 +631,7 @@ OBJS-$(CONFIG_RASC_DECODER) += rasc.o OBJS-$(CONFIG_RAWVIDEO_DECODER) += rawdec.o OBJS-$(CONFIG_RAWVIDEO_ENCODER) += rawenc.o OBJS-$(CONFIG_REALTEXT_DECODER) += realtextdec.o ass.o +OBJS-$(CONFIG_RKA_DECODER) += rka.o OBJS-$(CONFIG_RL2_DECODER) += rl2.o OBJS-$(CONFIG_ROQ_DECODER) += roqvideodec.o roqvideo.o OBJS-$(CONFIG_ROQ_ENCODER) += roqvideoenc.o roqvideo.o elbg.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b80b6983e9..e593ad19af 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -287,6 +287,7 @@ extern const FFCodec ff_r210_decoder; extern const FFCodec ff_rasc_decoder; extern const FFCodec ff_rawvideo_encoder; extern const FFCodec ff_rawvideo_decoder; +extern const FFCodec ff_rka_decoder; extern const FFCodec ff_rl2_decoder; extern const FFCodec ff_roq_encoder; extern const FFCodec ff_roq_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 57d0f98211..199f62df15 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3360,6 +3360,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Waveform Archiver"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_RKA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "rka", + .long_name = NULL_IF_CONFIG_SMALL("RKA (RK Audio)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, /* subtitle codecs */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ad1131b464..89a4a0cb89 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -537,6 +537,7 @@ enum AVCodecID { AV_CODEC_ID_APAC, AV_CODEC_ID_FTR, AV_CODEC_ID_WAVARC, + AV_CODEC_ID_RKA, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/rka.c b/libavcodec/rka.c new file mode 100644 index 0000000000..d916227483 --- /dev/null +++ b/libavcodec/rka.c @@ -0,0 +1,999 @@ +/* + * RKA decoder + * Copyright (c) 2023 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/intreadwrite.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "bytestream.h" +#include "decode.h" + +typedef struct ACoder { + GetByteContext gb; + uint32_t low, high; + uint32_t value; +} ACoder; + +typedef struct FiltCoeffs { + int32_t coeffs[257]; + unsigned size; +} FiltCoeffs; + +typedef struct Model64 { + uint32_t zero[2]; + uint32_t sign[2]; + unsigned size; + int bits; + + uint16_t val4[65]; + uint16_t val1[65]; +} Model64; + +typedef struct AdaptiveModel { + int last; + int total; + int buf_size; + int16_t sum; + uint16_t aprob0; + uint16_t aprob1; + uint16_t *prob[2]; +} AdaptiveModel; + +typedef struct ChContext { + int cmode; + int cmode2; + int last_nb_decoded; + unsigned srate_pad; + unsigned pos_idx; + + AdaptiveModel *filt_size; + AdaptiveModel *filt_bits; + + int *bprob0; + int *bprob1; + + AdaptiveModel position; + AdaptiveModel fshift; + AdaptiveModel nb_segments; + AdaptiveModel coeff_bits[11]; + + Model64 mdl64[4][11]; + + int32_t buf0[12001]; + int32_t buf1[12001]; +} ChContext; + +typedef struct RKAContext { + AVClass *class; + + ACoder ac; + ChContext ch[2]; + + int bps; + int align; + int channels; + int frame_samples; + int last_nb_samples; + uint32_t total_nb_samples; + uint32_t samples_left; + + int bprob0[257]; + int bprob1[257]; + + AdaptiveModel filt_size; + AdaptiveModel filt_bits; +} RKAContext; + +static int adaptive_model_init(AdaptiveModel *am, int buf_size) +{ + am->buf_size = buf_size; + am->sum = 2000; + am->aprob0 = 0; + am->aprob1 = 0; + am->total = 0; + + if (!am->prob[0]) + am->prob[0] = av_malloc_array(buf_size + 5, sizeof(*am->prob[0])); + if (!am->prob[1]) + am->prob[1] = av_malloc_array(buf_size + 5, sizeof(*am->prob[1])); + + if (!am->prob[0] || !am->prob[1]) + return AVERROR(ENOMEM); + memset(am->prob[0], 0, (buf_size + 5) * sizeof(*am->prob[0])); + memset(am->prob[1], 0, (buf_size + 5) * sizeof(*am->prob[1])); + return 0; +} + +static void adaptive_model_free(AdaptiveModel *am) +{ + av_freep(&am->prob[0]); + av_freep(&am->prob[1]); +} + +static av_cold int rka_decode_init(AVCodecContext *avctx) +{ + RKAContext *s = avctx->priv_data; + int cmode; + + if (avctx->extradata_size < 16) + return AVERROR_INVALIDDATA; + + s->bps = avctx->bits_per_raw_sample = avctx->extradata[13]; + + switch (s->bps) { + case 8: + avctx->sample_fmt = AV_SAMPLE_FMT_U8P; + break; + case 16: + avctx->sample_fmt = AV_SAMPLE_FMT_S16P; + break; + default: + return AVERROR_INVALIDDATA; + } + + s->channels = avctx->ch_layout.nb_channels; + if (s->channels < 1 || s->channels > 2) + return AVERROR_INVALIDDATA; + + s->align = (s->channels * (avctx->bits_per_raw_sample >> 3)); + s->samples_left = s->total_nb_samples = (AV_RL32(avctx->extradata + 4)) / s->align; + s->frame_samples = 131072 / s->align; + s->last_nb_samples = s->total_nb_samples % s->frame_samples; + + cmode = avctx->extradata[14] & 0xf; + if ((avctx->extradata[15] & 4) != 0) + cmode = -cmode; + + s->ch[0].cmode = s->ch[1].cmode = cmode; + s->ch[0].cmode2 = -s->ch[0].cmode; + s->ch[1].cmode2 = -s->ch[1].cmode; + av_log(avctx, AV_LOG_DEBUG, "cmode: %d\n", cmode); + + return 0; +} + +static void model64_init(Model64 *m, unsigned bits) +{ + unsigned x; + + m->bits = bits; + m->size = 64; + m->zero[0] = 1; + + x = (1 << (bits >> 1)) + 3; + x = FFMIN(x, 20); + + m->zero[1] = x; + m->sign[0] = 1; + m->sign[1] = 1; + + for (int i = 0; i < FF_ARRAY_ELEMS(m->val4); i++) { + m->val4[i] = 4; + m->val1[i] = 1; + } +} + +static int chctx_init(RKAContext *s, ChContext *c, + int sample_rate, int bps) +{ + int ret; + + memset(c->buf0, 0, sizeof(c->buf0)); + memset(c->buf1, 0, sizeof(c->buf1)); + + c->filt_size = &s->filt_size; + c->filt_bits = &s->filt_bits; + + c->bprob0 = s->bprob0; + c->bprob1 = s->bprob1; + + c->srate_pad = (sample_rate << 13) / 44100 & 0xFFFFFFFCU; + c->pos_idx = 1; + + for (int i = 0; i < FF_ARRAY_ELEMS(s->bprob0); i++) + c->bprob0[i] = c->bprob1[i] = 1; + + for (int i = 0; i < 11; i++) { + ret = adaptive_model_init(&c->coeff_bits[i], 32); + if (ret < 0) + return ret; + + model64_init(&c->mdl64[0][i], i); + model64_init(&c->mdl64[1][i], i); + model64_init(&c->mdl64[2][i], i+1); + model64_init(&c->mdl64[3][i], i+1); + } + + ret = adaptive_model_init(c->filt_size, 256); + if (ret < 0) + return ret; + ret = adaptive_model_init(c->filt_bits, 16); + if (ret < 0) + return ret; + ret = adaptive_model_init(&c->position, 16); + if (ret < 0) + return ret; + ret = adaptive_model_init(&c->nb_segments, 8); + if (ret < 0) + return ret; + return adaptive_model_init(&c->fshift, 32); +} + +static void init_acoder(ACoder *ac) +{ + ac->low = 0x0; + ac->high = 0xffffffff; + ac->value = bytestream2_get_be32(&ac->gb); +} + +static int ac_decode_bool(ACoder *ac, int freq1, int freq2) +{ + unsigned help, add, high; + int value, low; + + low = ac->low; + help = ac->high / (unsigned int)(freq2 + freq1); + value = ac->value; + add = freq1 * help; + ac->high = help; + + if (value - low >= add) { + ac->low = low = add + low; + ac->high = high = freq2 * help; + while (1) { + if ((low ^ (high + low)) > 0xFFFFFF) { + if (high > 0xFFFF) + return 1; + ac->high = (uint16_t)-(int16_t)low; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } + return -1; + } + + ac->high = add; + while (1) { + if ((low ^ (add + low)) > 0xFFFFFF) { + if (add > 0xFFFF) + return 0; + ac->high = (uint16_t)-(int16_t)low; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8); + ac->high = add = ac->high << 8; + ac->low = low = ac->low << 8; + } + return -1; +} + +static int decode_bool(ACoder *ac, ChContext *c, int idx) +{ + int x, b; + + x = c->bprob0[idx]; + if (x + c->bprob1[idx] > 4096) { + c->bprob0[idx] = (x >> 1) + 1; + c->bprob1[idx] = (c->bprob1[idx] >> 1) + 1; + } + + b = ac_decode_bool(ac, c->bprob0[idx], c->bprob1[idx]); + if (b == 1) { + c->bprob1[idx]++; + } else if (b == 0) { + c->bprob0[idx]++; + } + + return b; +} + +static int ac_get_freq(ACoder *ac, unsigned freq, int *result) +{ + uint32_t new_high; + + if (freq == 0) + return -1; + + new_high = ac->high / freq; + ac->high = new_high; + + if (new_high == 0) + return -1; + + *result = (ac->value - ac->low) / new_high; + + return 0; +} + +static int ac_update(ACoder *ac, int freq, int mul) +{ + uint32_t low, high; + + low = ac->low = ac->high * freq + ac->low; + high = ac->high = ac->high * mul; + + while (1) { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 0; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + low = ac->low = ac->low << 8; + high = ac->high = ac->high << 8; + } + + return -1; +} + +static void update_ch_subobj(AdaptiveModel *am) +{ + int idx2, idx = am->buf_size - 1; + + if (idx >= 0) { + do { + uint16_t *prob = am->prob[0]; + int prob_idx = prob[idx]; + int diff, left; + + idx2 = idx - 1; + if (idx > 0) { + int idx3 = idx - 1; + + if ((idx2 & idx) != idx2) { + do { + prob_idx -= prob[idx3]; + idx3 &= idx3 - 1; + } while ((idx2 & idx) != idx3); + } + } + + diff = ((prob_idx > 0) - prob_idx) >> 1; + left = idx; + am->aprob0 += diff; + if (idx <= 0) { + am->prob[0][0] += diff; + } else { + do { + am->prob[0][left] += diff; + left += (left & -left); + } + while (left < am->buf_size); + } + idx--; + } while (idx2 >= 0); + } + + if (am->sum < 8000) + am->sum += 200; + + am->aprob1 = (am->aprob1 + 1) >> 1; +} + +static int amdl_decode_int(AdaptiveModel *am, ACoder *ac, unsigned *dst, unsigned size) +{ + unsigned int freq; + int val_1; + int v7; + int v8; + uint16_t v9; + int v10; + uint16_t v11; + uint16_t *v12; + int v13; + int v14; + int k; + int v17; + unsigned v18; + int val; + int v24; + int freqa; + uint16_t v27; + uint16_t j; + uint16_t v29; + + val_1 = FFMIN(size, am->buf_size - 1); + + if (am->aprob0 >= am->sum) + update_ch_subobj(am); + + if (am->aprob1 && (am->total == am->buf_size || + ac_decode_bool(ac, am->aprob0, am->aprob1) == 0)) { + if (am->total <= 1) { + dst[0] = am->last; + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0][0]++; + } else { + do { + am->prob[0][val]++; + val += (val & -val); + } while (val < am->buf_size); + } + return 0; + } + if (val_1 == am->buf_size - 1) { + freq = am->aprob0; + } else { + unsigned i = am->prob[0][0]; + + for (int j = val_1; j > 0; j &= (j - 1) ) + i += am->prob[0][j]; + freq = i; + } + v24 = 0; + ac_get_freq(ac, freq, &v7); + v8 = am->buf_size >> 1; + v9 = am->prob[0][0]; + if (v7 >= v9) { + for (j = v7 - v9; v8; v8 >>= 1) { + v11 = am->prob[0][v8 + v24]; + if (j >= v11) { + v24 += v8; + j -= v11; + } + } + v27 = v7 - j; + v10 = v24 + 1; + } else { + v27 = 0; + v10 = 0; + } + dst[0] = v10; + v12 = am->prob[0]; + v13 = v12[v10]; + if (v10 > 0) { + v14 = v10 & (v10 - 1); + for (k = v10 - 1; v14 != k; k &= k - 1) + v13 -= v12[k]; + } + ac_update(ac, v27, v13); + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0][0]++; + } else { + do { + am->prob[0][val]++; + val += (val & -val); + } while (val < am->buf_size); + } + return 0; + } + v17 = am->buf_size; + am->aprob1++; + if (val_1 == v17 - 1) { + ac_get_freq(ac, v17 - am->total, &v18); + } else { + freqa = 1; + dst[0] = 0; + if (val_1 > 0) { + do { + if (!am->prob[1][dst[0]]) + freqa++; + dst[0]++; + } while (dst[0] < val_1); + } + ac_get_freq(ac, freqa, &v18); + } + v29 = 0; + dst[0] = 0; + if (v18 > 0 && am->buf_size > 0) { + do { + val = dst[0]; + if (!am->prob[1][dst[0]]) + ++v29; + dst[0] = val + 1; + } + while (v29 < v18 && val + 1 < am->buf_size); + } + if (am->prob[1][dst[0]]) { + do { + val = dst[0]++; + } while (val + 1 < am->buf_size && am->prob[1][val + 1]); + } + ac_update(ac, v29, 1); + am->prob[1][dst[0]]++; + am->total++; + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0][0]++; + } else { + do { + am->prob[0][val]++; + val += (val & -val); + } while (val < am->buf_size); + } + + am->last = dst[0]; + + return 0; +} + +static int decode_filt_coeffs(RKAContext *s, ChContext *ctx, ACoder *ac, FiltCoeffs *dst) +{ + unsigned val, bits; + int idx = 0; + + if (amdl_decode_int(ctx->filt_size, ac, &dst->size, 256) < 0) + return -1; + + if (dst->size == 0) + return 0; + + if (amdl_decode_int(ctx->filt_bits, ac, &bits, 10) < 0) + return -1; + + do { + if (((idx == 8) || (idx == 20)) && (0 < bits)) + bits--; + + if (bits > 10) + return -1; + + if (amdl_decode_int(&ctx->coeff_bits[bits], ac, &val, 31) < 0) + return -1; + + if (val == 31) { + ac_get_freq(ac, 65536, &val); + ac_update(ac, val, 1); + } + + if (val == 0) { + dst->coeffs[idx++] = 0; + } else { + unsigned freq = 0; + int sign; + + if (bits > 0) { + ac_get_freq(ac, 1 << bits, &freq); + ac_update(ac, freq, 1); + } + dst->coeffs[idx] = freq + 1 + ((val - 1U) << bits); + sign = decode_bool(ac, ctx, idx); + if (sign < 0) + return -1; + if (sign == 1) + dst->coeffs[idx] = -dst->coeffs[idx]; + idx++; + } + } while (idx < dst->size); + + return 0; +} + +static int ac_dec_bit(ACoder *ac) +{ + uint32_t high, low; + + low = ac->low; + ac->high = high = ac->high >> 1; + if (ac->value - low < high) { + do { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 0; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } while (1); + + return -1; + } + ac->low = low = low + high; + do { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 1; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } while (1); + + return -1; +} + +static int mdl64_decode(ACoder *ac, Model64 *ctx, int *dst) +{ + int sign, idx, bits; + unsigned val = 0; + + if (ctx->zero[0] + ctx->zero[1] > 4000) { + ctx->zero[0] = (ctx->zero[0] >> 1) + 1; + ctx->zero[1] = (ctx->zero[1] >> 1) + 1; + } + if (ctx->sign[0] + ctx->sign[1] > 4000) { + ctx->sign[0] = (ctx->sign[0] >> 1) + 1; + ctx->sign[1] = (ctx->sign[1] >> 1) + 1; + } + sign = ac_decode_bool(ac, ctx->zero[0], ctx->zero[1]); + if (sign == 0) { + ctx->zero[0] += 2; + dst[0] = 0; + return 0; + } else if (sign < 0) + return -1; + + ctx->zero[1] += 2; + sign = ac_decode_bool(ac, ctx->sign[0], ctx->sign[1]); + if (sign < 0) + return -1; + ctx->sign[sign]++; + bits = ctx->bits; + if (bits > 0) { + if (bits < 13) { + ac_get_freq(ac, 1 << bits, &val); + ac_update(ac,val,1); + } else { + ac_get_freq(ac, 1 << (bits / 2), &val); + ac_update(ac,val,1); + ac_get_freq(ac,1 << (ctx->bits - (bits / 2)), &bits); + ac_update(ac,val,1); + val = val + (bits << (bits / 2)); + } + } + bits = ctx->size; + idx = 0; + if (bits >= 0) { + do { + uint16_t *val4 = ctx->val4; + int b; + + if (val4[idx] + ctx->val1[idx] > 2000U) { + val4[idx] = (val4[idx] >> 1) + 1; + ctx->val1[idx] = (ctx->val1[idx] >> 1) + 1; + } + b = ac_decode_bool(ac, ctx->val4[idx], ctx->val1[idx]); + if (b == 1) { + ctx->val1[idx] += 4; + break; + } else if (b < 0) { + return -1; + } + ctx->val4[idx] += 4; + idx++; + } while (idx <= ctx->size); + bits = ctx->size; + if (idx <= bits) { + dst[0] = val + 1 + (idx << ctx->bits); + if (sign) + dst[0] = -dst[0]; + return 0; + } + } + bits = bits + 1; + while (ac_dec_bit(ac) == 0) + bits = bits + 64; + ac_get_freq(ac, 64, &idx); + ac_update(ac, idx, 1); + idx += bits; + bits = val + 1 + (idx << ctx->bits); + dst[0] = bits; + if (sign) + dst[0] = -dst[0]; + + return 0; +} + +static const uint8_t tab[] = { 0, 3, 3, 2, 2, 1, 1, 1, 1 }; + +static int decode_filter(RKAContext *s, ChContext *ctx, ACoder *ac, int off, unsigned size) +{ + FiltCoeffs filt; + Model64 *mdl64; + int m = 0, split, val, last_val = 0, ret; + unsigned idx = 3, bits = 0; + + if (ctx->cmode == 0) { + if (amdl_decode_int(&ctx->fshift, ac, &bits, 15) < 0) + return -1; + bits &= 31U; + } + + ret = decode_filt_coeffs(s, ctx, ac, &filt); + if (ret < 0) + return ret; + + if (size < 512) + split = size / 2; + else + split = size >> 4; + + if (size <= 0) + return 0; + + for (int x = 0; x < size;) { + if (amdl_decode_int(&ctx->position, ac, &idx, 10) < 0) + return -1; + + idx = (ctx->pos_idx + idx) % 11; + ctx->pos_idx = idx; + + for (int y = 0; y < split; y++, off++) { + int midx, shift = idx, *src, sum = 16; + + midx = FFABS(last_val) >> shift; + if (midx >= 15) { + mdl64 = &ctx->mdl64[3][idx]; + } else if (midx >= 7) { + mdl64 = &ctx->mdl64[2][idx]; + } else if (midx >= 4) { + mdl64 = &ctx->mdl64[1][idx]; + } else { + mdl64 = &ctx->mdl64[0][idx]; + } + ret = mdl64_decode(ac, mdl64, &val); + if (ret < 0) + return -1; + last_val = val; + src = &ctx->buf1[off + -1]; + for (int i = 0; i < filt.size && i < 15; i++) + sum += filt.coeffs[i] * src[-i]; + sum = sum * 2; + for (int i = 15; i < filt.size; i++) + sum += filt.coeffs[i] * src[-i]; + sum = sum >> 6; + if (ctx->cmode == 0) { + if (bits == 0) { + ctx->buf1[off] = sum + val; + } else { + ctx->buf1[off] = (val + (sum >> bits) * (1U << bits)) + + (((1U << bits) - 1U) & ctx->buf1[off + -1]); + } + ctx->buf0[off] = ctx->buf1[off] + ctx->buf0[off + -1]; + } else { + val = val * (1 << ctx->cmode & 0x1f); + sum += ctx->buf0[off + -1] + val; + switch (s->bps) { + case 16: sum = av_clip_int16(sum); break; + case 8: sum = av_clip_int8(sum); break; + } + ctx->buf1[off] = sum - ctx->buf0[off + -1]; + ctx->buf0[off] = sum; + m += FFABS(ctx->buf1[off]); + } + } + if (ctx->cmode2 != 0) { + int sum = 0; + for (int i = (m << 6) / split; i > 0; i = i >> 1) + sum++; + sum = sum - (ctx->cmode2 + 7); + ctx->cmode = FFMAX(sum, tab[ctx->cmode2]); + } + + x += split; + } + + return 0; +} + +static int decode_samples(AVCodecContext *avctx, ACoder *ac, ChContext *ctx, int offset) +{ + RKAContext *s = avctx->priv_data; + int segment_size, size, offset2, mode, ret; + + ret = amdl_decode_int(&ctx->nb_segments, ac, &mode, 5); + if (ret < 0) + return ret; + + if (mode == 5) { + ret = ac_get_freq(ac, ctx->srate_pad >> 2, &segment_size); + if (ret < 0) + return ret; + ac_update(ac, segment_size, 1); + segment_size *= 4; + decode_filter(s, ctx, ac, offset, segment_size); + } else { + segment_size = ctx->srate_pad; + + if (mode) { + if (mode > 2) { + decode_filter(s, ctx, ac, offset, segment_size / 4); + offset2 = segment_size / 4 + offset; + decode_filter(s, ctx, ac, offset2, segment_size / 4); + size = segment_size / 4 + offset2; + } else { + decode_filter(s, ctx, ac, offset, segment_size / 2); + size = segment_size / 2 + offset; + } + if (mode & 1) { + decode_filter(s, ctx, ac, size, segment_size / 2); + } else { + decode_filter(s, ctx, ac, size, segment_size / 4); + decode_filter(s, ctx, ac, segment_size / 4 + size, segment_size / 4); + } + } else { + decode_filter(s, ctx, ac, offset, ctx->srate_pad); + } + } + + return segment_size; +} + +static int decode_ch_samples(AVCodecContext *avctx, ChContext *c) +{ + RKAContext *s = avctx->priv_data; + ACoder *ac = &s->ac; + int nb_decoded = 0; + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + return 0; + + memmove(c->buf0, &c->buf0[c->last_nb_decoded], 2560 * sizeof(*c->buf0)); + memmove(c->buf1, &c->buf1[c->last_nb_decoded], 2560 * sizeof(*c->buf1)); + + nb_decoded = decode_samples(avctx, ac, c, 2560); + if (nb_decoded < 0) + return nb_decoded; + c->last_nb_decoded = nb_decoded; + + return nb_decoded; +} + +static int rka_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + RKAContext *s = avctx->priv_data; + ACoder *ac = &s->ac; + int ret; + + bytestream2_init(&ac->gb, avpkt->data, avpkt->size); + init_acoder(ac); + + for (int ch = 0; ch < s->channels; ch++) { + ret = chctx_init(s, &s->ch[ch], avctx->sample_rate, + avctx->bits_per_raw_sample); + if (ret < 0) + return ret; + } + + frame->nb_samples = s->frame_samples; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + if (s->channels == 2) { + int16_t *l16 = (int16_t *)frame->extended_data[0]; + int16_t *r16 = (int16_t *)frame->extended_data[1]; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16P: + for (int n = 0; n < frame->nb_samples;) { + ret = decode_ch_samples(avctx, &s->ch[0]); + if (ret == 0) { + frame->nb_samples = n; + break; + } + if (ret < 0 || n + ret > frame->nb_samples) + return AVERROR_INVALIDDATA; + + ret = decode_ch_samples(avctx, &s->ch[1]); + if (ret == 0) { + frame->nb_samples = n; + break; + } + if (ret < 0 || n + ret > frame->nb_samples) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < ret; i++) { + int l = s->ch[0].buf0[2560 + i]; + int r = s->ch[1].buf0[2560 + i]; + + l16[n + i] = (l * 2 + r + 1) >> 1; + r16[n + i] = (l * 2 - r + 1) >> 1; + } + + n += ret; + } + break; + default: + return AVERROR_INVALIDDATA; + } + } else { + int16_t *m16 = (int16_t *)frame->data[0]; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16P: + for (int n = 0; n < frame->nb_samples;) { + ret = decode_ch_samples(avctx, &s->ch[0]); + if (ret == 0) { + frame->nb_samples = n; + break; + } + if (ret < 0 || n + ret > frame->nb_samples) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < ret; i++) { + int m = s->ch[0].buf0[2560 + i]; + + m16[n + i] = m; + } + + n += ret; + } + break; + default: + return AVERROR_INVALIDDATA; + } + } + + *got_frame_ptr = 1; + + return avpkt->size; +} + +static av_cold int rka_decode_close(AVCodecContext *avctx) +{ + RKAContext *s = avctx->priv_data; + + for (int ch = 0; ch < 2; ch++) { + ChContext *c = &s->ch[ch]; + + for (int i = 0; i < 11; i++) + adaptive_model_free(&c->coeff_bits[i]); + + adaptive_model_free(&c->position); + adaptive_model_free(&c->nb_segments); + adaptive_model_free(&c->fshift); + } + + adaptive_model_free(&s->filt_size); + adaptive_model_free(&s->filt_bits); + + return 0; +} + +const FFCodec ff_rka_decoder = { + .p.name = "rka", + CODEC_LONG_NAME("RKA (RK Audio"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_RKA, + .priv_data_size = sizeof(RKAContext), + .init = rka_decode_init, + .close = rka_decode_close, + FF_CODEC_DECODE_CB(rka_decode_frame), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; -- 2.39.1