* [FFmpeg-devel] [RFC][WIP][PATCH] RK Audio demuxer and decoder @ 2023-02-04 9:04 Paul B Mahol 2023-02-05 19:17 ` [FFmpeg-devel] [PATCH] " Paul B Mahol 0 siblings, 1 reply; 4+ messages in thread From: Paul B Mahol @ 2023-02-04 9:04 UTC (permalink / raw) To: FFmpeg development discussions and patches [-- Attachment #1: Type: text/plain, Size: 124 bytes --] Hi, Patches attached, decoder is not bit by bit exact yet for lossless mode because some samples are not properly rounded. [-- Attachment #2: 0001-avformat-add-RKA-demuxer.patch --] [-- Type: text/x-patch, Size: 6828 bytes --] From 71bfdb9eadc988b1154f8202b12a380839096d48 Mon Sep 17 00:00:00 2001 From: Paul B Mahol <onemda@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 <onemda@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 [-- Attachment #3: 0002-avcodec-add-RKA-decoder.patch --] [-- Type: text/x-patch, Size: 32255 bytes --] From f3d05a9ac45177eeb3e3cbbbce9e53980c4047f5 Mon Sep 17 00:00:00 2001 From: Paul B Mahol <onemda@gmail.com> Date: Tue, 31 Jan 2023 21:03:38 +0100 Subject: [PATCH 2/2] avcodec: add RKA decoder Signed-off-by: Paul B Mahol <onemda@gmail.com> --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 + libavcodec/codec_id.h | 1 + libavcodec/rka.c | 1066 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 1076 insertions(+) create mode 100644 libavcodec/rka.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 4971832ff4..389253f5d0 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -631,6 +631,7 @@ OBJS-$(CONFIG_RASC_DECODER) += rasc.o OBJS-$(CONFIG_RAWVIDEO_DECODER) += rawdec.o OBJS-$(CONFIG_RAWVIDEO_ENCODER) += rawenc.o OBJS-$(CONFIG_REALTEXT_DECODER) += realtextdec.o ass.o +OBJS-$(CONFIG_RKA_DECODER) += rka.o OBJS-$(CONFIG_RL2_DECODER) += rl2.o OBJS-$(CONFIG_ROQ_DECODER) += roqvideodec.o roqvideo.o OBJS-$(CONFIG_ROQ_ENCODER) += roqvideoenc.o roqvideo.o elbg.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b80b6983e9..e593ad19af 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -287,6 +287,7 @@ extern const FFCodec ff_r210_decoder; extern const FFCodec ff_rasc_decoder; extern const FFCodec ff_rawvideo_encoder; extern const FFCodec ff_rawvideo_decoder; +extern const FFCodec ff_rka_decoder; extern const FFCodec ff_rl2_decoder; extern const FFCodec ff_roq_encoder; extern const FFCodec ff_roq_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 57d0f98211..199f62df15 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3360,6 +3360,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Waveform Archiver"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_RKA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "rka", + .long_name = NULL_IF_CONFIG_SMALL("RKA (RK Audio)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, /* subtitle codecs */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ad1131b464..89a4a0cb89 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -537,6 +537,7 @@ enum AVCodecID { AV_CODEC_ID_APAC, AV_CODEC_ID_FTR, AV_CODEC_ID_WAVARC, + AV_CODEC_ID_RKA, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/rka.c b/libavcodec/rka.c new file mode 100644 index 0000000000..629978ff2d --- /dev/null +++ b/libavcodec/rka.c @@ -0,0 +1,1066 @@ +/* + * RKA decoder + * Copyright (c) 2023 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <limits.h> + +#include "libavutil/avassert.h" +#include "libavutil/channel_layout.h" +#include "libavutil/intreadwrite.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "bytestream.h" +#include "decode.h" +#include "unary.h" + +typedef struct ACoder { + GetByteContext gb; + uint32_t low, high; + uint32_t value; +} ACoder; + +typedef struct FiltCoeffs { + int32_t coeffs[257]; + unsigned size; +} FiltCoeffs; + +typedef struct Model64 { + int32_t zero_prob0; + int32_t zero_prob1; + int32_t sign_prob0; + int32_t sign_prob1; + unsigned size; + int bits; + + uint16_t buf_val4[65]; + uint16_t buf_val1[65]; +} Model64; + +typedef struct AdaptiveModel { + int last; + int total; + int buf_size; + int16_t sum; + uint16_t aprob0; + uint16_t aprob1; + uint16_t *prob; + uint16_t *ptr; +} AdaptiveModel; + +typedef struct ChContext { + int start; + int end; + int cmode; + int cmode2; + unsigned srate_pad; + unsigned pos_mod11; + + AdaptiveModel *filt_size; + AdaptiveModel *filt_bits; + + int *bprob0; + int *bprob1; + + AdaptiveModel pos_update; + AdaptiveModel fshift; + AdaptiveModel nb_segments; + AdaptiveModel coeff_bits[11]; + + Model64 mdl64[4][11]; + + int32_t buf0[12001]; + int32_t buf1[12001]; +} ChContext; + +typedef struct RKAContext { + AVClass *class; + + ACoder ac; + ChContext ch[2]; + + int bps; + int align; + int cur_chan; + int channels; + int frame_samples; + int last_nb_samples; + uint32_t total_nb_samples; + uint32_t samples_left; + + int bprob0[257]; + int bprob1[257]; + + AdaptiveModel filt_size; + AdaptiveModel filt_bits; +} RKAContext; + +static int adaptive_model_init(AdaptiveModel *am, int buf_size) +{ + am->total = 0; + am->aprob0 = 0; + am->aprob1 = 0; + am->buf_size = buf_size; + am->sum = 2000; + + if (!am->prob) + am->prob = av_malloc_array(buf_size + 5, sizeof(*am->prob)); + if (!am->ptr) + am->ptr = av_malloc_array(buf_size + 5, sizeof(*am->ptr)); + + if (!am->prob || !am->ptr) + return AVERROR(ENOMEM); + memset(am->prob, 0, (buf_size + 5) * sizeof(*am->prob)); + memset(am->ptr, 0, (buf_size + 5) * sizeof(*am->ptr)); + return 0; +} + +static void adaptive_model_free(AdaptiveModel *am) +{ + av_freep(&am->prob); + av_freep(&am->ptr); +} + +static av_cold int rka_decode_init(AVCodecContext *avctx) +{ + RKAContext *s = avctx->priv_data; + int cmode; + + if (avctx->extradata_size < 16) + return AVERROR_INVALIDDATA; + + s->bps = avctx->bits_per_raw_sample = avctx->extradata[13]; + + switch (s->bps) { + case 8: + avctx->sample_fmt = AV_SAMPLE_FMT_U8; + break; + case 16: + avctx->sample_fmt = AV_SAMPLE_FMT_S16; + break; + default: + return AVERROR_INVALIDDATA; + } + + s->channels = avctx->ch_layout.nb_channels; + if (s->channels < 1 || s->channels > 2) + return AVERROR_INVALIDDATA; + + s->align = (s->channels * (avctx->bits_per_raw_sample >> 3)); + s->samples_left = s->total_nb_samples = (AV_RL32(avctx->extradata + 4)) / s->align; + s->frame_samples = 131072 / s->align; + s->last_nb_samples = s->total_nb_samples % s->frame_samples; + + cmode = avctx->extradata[14] & 0xf; + if ((avctx->extradata[15] & 4) != 0) + cmode = -cmode; + + s->ch[0].cmode = s->ch[1].cmode = cmode; + s->ch[0].cmode2 = -s->ch[0].cmode; + s->ch[1].cmode2 = -s->ch[1].cmode; + av_log(NULL, AV_LOG_DEBUG, "cmode: %d\n", cmode); + + return 0; +} + +static void model64_init(Model64 *m, unsigned bits) +{ + unsigned x; + + m->bits = bits; + m->size = 64; + m->zero_prob1 = 1; + + x = (1 << (bits >> 1)) + 3; + x = FFMIN(x, 20); + + m->zero_prob0 = x; + m->sign_prob0 = 1; + m->sign_prob1 = 1; + + for (int i = 0; i < FF_ARRAY_ELEMS(m->buf_val4); i++) { + m->buf_val4[i] = 4; + m->buf_val1[i] = 1; + } +} + +static int chctx_init(RKAContext *s, ChContext *c, + int sample_rate, int bps) +{ + int ret; + + memset(c->buf0, 0, sizeof(c->buf0)); + memset(c->buf1, 0, sizeof(c->buf1)); + + c->filt_size = &s->filt_size; + c->filt_bits = &s->filt_bits; + + c->bprob0 = s->bprob0; + c->bprob1 = s->bprob1; + + c->start = c->end = 2560; + c->srate_pad = (sample_rate << 13) / 44100 & 0xFFFFFFFCU; + c->pos_mod11 = 1; + + for (int i = 0; i < FF_ARRAY_ELEMS(s->bprob0); i++) + c->bprob0[i] = c->bprob1[i] = 1; + + for (int i = 0; i < 11; i++) { + ret = adaptive_model_init(&c->coeff_bits[i], 32); + if (ret < 0) + return ret; + + model64_init(&c->mdl64[0][i], i); + model64_init(&c->mdl64[1][i], i); + model64_init(&c->mdl64[2][i], i+1); + model64_init(&c->mdl64[3][i], i+1); + } + + ret = adaptive_model_init(c->filt_size, 256); + if (ret < 0) + return ret; + ret = adaptive_model_init(c->filt_bits, 16); + if (ret < 0) + return ret; + ret = adaptive_model_init(&c->pos_update, 16); + if (ret < 0) + return ret; + ret = adaptive_model_init(&c->nb_segments, 8); + if (ret < 0) + return ret; + return adaptive_model_init(&c->fshift, 32); +} + +static void init_acoder(ACoder *ac) +{ + ac->low = 0x0; + ac->high = 0xffffffff; + ac->value = bytestream2_get_be32(&ac->gb); +} + +static int ac_decode_bool(ACoder *ac, int freq1, int freq2) +{ + unsigned help, add, high; + int value, low; + + low = ac->low; + help = ac->high / (unsigned int)(freq2 + freq1); + value = ac->value; + add = freq1 * help; + ac->high = help; + + if (value - low >= add) { + ac->low = low = add + low; + ac->high = high = freq2 * help; + while (1) { + if ((low ^ (high + low)) > 0xFFFFFF) { + if (high > 0xFFFF) + return 1; + ac->high = (uint16_t)-(int16_t)low; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } + return -1; + } + + ac->high = add; + while (1) { + if ((low ^ (add + low)) > 0xFFFFFF) { + if (add > 0xFFFF) + return 0; + ac->high = (uint16_t)-(int16_t)low; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8); + ac->high = add = ac->high << 8; + ac->low = low = ac->low << 8; + } + return -1; +} + +static int decode_bool(ACoder *ac, ChContext *c, int idx) +{ + int x, b; + + x = c->bprob0[idx]; + if (x + c->bprob1[idx] > 4096) { + c->bprob0[idx] = (x >> 1) + 1; + c->bprob1[idx] = (c->bprob1[idx] >> 1) + 1; + } + + b = ac_decode_bool(ac, c->bprob0[idx], c->bprob1[idx]); + if (b == 1) { + c->bprob1[idx]++; + } else if (b == 0) { + c->bprob0[idx]++; + } + + return b; +} + +static int ac_get_freq(ACoder *ac, unsigned freq, int *result) +{ + uint32_t new_high; + + if (freq == 0) + return -1; + + new_high = ac->high / freq; + ac->high = new_high; + + if (new_high == 0) + return -1; + + *result = (ac->value - ac->low) / new_high; + + return 0; +} + +static int ac_update(ACoder *ac, int freq, int mul) +{ + uint32_t low, high; + + low = ac->low = ac->high * freq + ac->low; + high = ac->high = ac->high * mul; + + while (1) { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 0; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + low = ac->low = ac->low << 8; + high = ac->high = ac->high << 8; + } + + return -1; +} + +static void update_ch_subobj(AdaptiveModel *am) +{ + int idx2, idx = am->buf_size - 1; + + if (idx >= 0) { + do { + uint16_t *prob = am->prob; + int prob_idx = prob[idx]; + int diff, left; + + idx2 = idx - 1; + if (idx > 0) { + int idx3 = idx - 1; + + if ((idx2 & idx) != idx2) { + do { + prob_idx -= prob[idx3]; + idx3 &= idx3 - 1; + } while ((idx2 & idx) != idx3); + } + } + + diff = ((prob_idx > 0) - prob_idx) >> 1; + left = idx; + am->aprob0 += diff; + if ( idx <= 0 ) { + am->prob[0] += diff; + } else { + do { + am->prob[left] += diff; + left += (left & -left); + } + while (left < am->buf_size); + } + idx--; + } while (idx2 >= 0); + } + + if (am->sum < 8000) + am->sum += 200; + + am->aprob1 = (am->aprob1 + 1) >> 1; +} + +static int amdl_decode_int(AdaptiveModel *am, ACoder *ac, unsigned *dst, unsigned size) +{ + int val_1; + int v5; + unsigned int i; + int v7; + int v8; + uint16_t v9; + int v10; + uint16_t v11; + uint16_t *v12; + int v13; + int v14; + int k; + int v17; + unsigned v18; + int val; + int v24; + unsigned int freq; + signed int freqa; + uint16_t v27; + uint16_t j; + uint16_t v29; + + val_1 = size; + if (size > am->buf_size - 1) + val_1 = am->buf_size - 1; + if (am->aprob0 >= am->sum) + update_ch_subobj(am); + + if (am->aprob1 && (am->total == am->buf_size || + ac_decode_bool(ac, am->aprob0, am->aprob1) == 0)) { + if (am->total <= 1) { + dst[0] = am->last; + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0]++; + } else { + do { + am->prob[val]++; + val += (val & -val); + } while ( val < am->buf_size ); + } + return 0; + } + if (val_1 == am->buf_size - 1) { + freq = am->aprob0; + } else { + if (val_1 != -1) { + v5 = val_1; + for ( i = am->prob[0]; v5 > 0; v5 &= (v5 - 1) ) + i += am->prob[v5]; + freq = i; + } else { + freq = 0; + } + } + v24 = 0; + ac_get_freq(ac, freq, &v7); + v8 = am->buf_size >> 1; + v9 = am->prob[0]; + if (v7 >= v9) { + for ( j = v7 - v9; v8; v8 >>= 1 ) { + v11 = am->prob[v8 + v24]; + if ( j >= v11 ) { + v24 += v8; + j -= v11; + } + } + v27 = v7 - j; + v10 = v24 + 1; + } else { + v27 = 0; + v10 = 0; + } + dst[0] = v10; + v12 = am->prob; + v13 = v12[v10]; + if (v10 > 0) { + v14 = v10 & (v10 - 1); + for (k = v10 - 1; v14 != k; k &= k - 1) + v13 -= v12[k]; + } + ac_update(ac, v27, v13); + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0]++; + } else { + do { + am->prob[val]++; + val += (val & -val); + } while (val < am->buf_size); + } + return 0; + } + v17 = am->buf_size; + am->aprob1++; + if (val_1 == v17 - 1) { + ac_get_freq(ac, v17 - am->total, &v18); + } else { + freqa = 1; + dst[0] = 0; + if (val_1 > 0) { + do { + if (!am->ptr[dst[0]]) + freqa++; + dst[0]++; + } while (dst[0] < val_1); + } + ac_get_freq(ac, freqa, &v18); + } + v29 = 0; + dst[0] = 0; + if (v18 > 0 && am->buf_size > 0) { + do { + val = dst[0]; + if (!am->ptr[dst[0]]) + ++v29; + dst[0] = val + 1; + } + while ( v29 < v18 && val + 1 < am->buf_size ); + } + if (am->ptr[dst[0]]) { + do { + val = dst[0]++; + } while (val + 1 < am->buf_size && am->ptr[val + 1]); + } + ac_update(ac, v29, 1); + am->ptr[dst[0]]++; + am->total++; + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0]++; + } else { + do { + am->prob[val]++; + val += (val & -val); + } while (val < am->buf_size); + } + + am->last = dst[0]; + + return 0; +} + +static int decode_filt_coeffs(RKAContext *s, ChContext *ctx, ACoder *ac, FiltCoeffs *dst) +{ + unsigned val, bits; + int i; + + if (amdl_decode_int(ctx->filt_size, ac, &dst->size, 256) < 0) + return -1; + + if (dst->size == 0) + return 0; + + if (amdl_decode_int(ctx->filt_bits, ac, &bits, 10) < 0) + return -1; + + i = 0; + do { + if (((i == 8) || (i == 20)) && (0 < bits)) + bits--; + + if (bits > 10) + return -1; + + if (amdl_decode_int(&ctx->coeff_bits[bits], ac, &val, 31) < 0) + return -1; + + if (val == 31) { + ac_get_freq(ac, 0x10000, &val); + ac_update(ac, val, 1); + } + + if (val == 0) { + dst->coeffs[i] = 0; + } else { + unsigned freq = 0; + int sign; + + if (bits > 0) { + ac_get_freq(ac, 1 << bits, &freq); + ac_update(ac, freq, 1); + } + dst->coeffs[i] = freq + 1 + ((val - 1U) << bits); + sign = decode_bool(ac, ctx, i); + if (sign < 0) + return -1; + if (sign == 1) + dst->coeffs[i] = -dst->coeffs[i]; + } + } while (++i < dst->size); + + return 0; +} + +static int ac_dec_bit(ACoder *ac) + +{ + uint32_t high, low; + + low = ac->low; + high = ac->high >> 1; + ac->high = high; + if (ac->value - low < high) { + do { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 0; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + high = ac->high << 8; + ac->high = high; + low = ac->low << 8; + ac->low = low; + } while (1); + + return -1; + } + ac->low = low = low + high; + do { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 1; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } while (1); + + return -1; +} + +static int mdl64_decode(ACoder *ac, Model64 *ctx, int *dst) +{ + uint16_t *psVar1; + int bVar3; + int sign; + int iVar5; + unsigned val; + int bits; + + val = 0; + if ((unsigned)(ctx->zero_prob0 + ctx->zero_prob1) > 4000) { + ctx->zero_prob0 = (ctx->zero_prob0 >> 1) + 1; + ctx->zero_prob1 = (ctx->zero_prob1 >> 1) + 1; + } + if ((unsigned)(ctx->sign_prob1 + ctx->sign_prob0) > 4000) { + ctx->sign_prob0 = (ctx->sign_prob0 >> 1) + 1; + ctx->sign_prob1 = (ctx->sign_prob1 >> 1) + 1; + } + sign = ac_decode_bool(ac,ctx->zero_prob1,ctx->zero_prob0); + if (sign == 0) { + ctx->zero_prob1 += 2; + dst[0] = 0; + return 0; + } else if (sign < 0) + return -1; + + ctx->zero_prob0 += 2; + sign = ac_decode_bool(ac,ctx->sign_prob0,ctx->sign_prob1); + if (sign == 1) { + ctx->sign_prob1++; + } else if (sign == 0) { + ctx->sign_prob0++; + } else { + return -1; + } + bits = ctx->bits; + if (bits > 0) { + if (bits < 13) { + ac_get_freq(ac, 1 << bits, &val); + ac_update(ac,val,1); + } else { + ac_get_freq(ac, 1 << (bits / 2), &val); + ac_update(ac,val,1); + ac_get_freq(ac,1 << (ctx->bits - (bits / 2)), &bits); + ac_update(ac,val,1); + val = val + (bits << (bits / 2)); + } + } + bits = ctx->size; + iVar5 = 0; + if (bits >= 0) { + do { + psVar1 = ctx->buf_val4; + if (2000U < (unsigned)(psVar1[iVar5] + ctx->buf_val1[iVar5])) { + psVar1[iVar5] = (psVar1[iVar5] >> 1) + 1; + ctx->buf_val1[iVar5] = (ctx->buf_val1[iVar5] >> 1) + 1; + } + bVar3 = ac_decode_bool(ac, ctx->buf_val4[iVar5], ctx->buf_val1[iVar5]); + if (bVar3 == 1) { + ctx->buf_val1[iVar5] = ctx->buf_val1[iVar5] + 4; + break; + } else if (bVar3 < 0) + return -1; + ctx->buf_val4[iVar5] = ctx->buf_val4[iVar5] + 4; + iVar5 = iVar5 + 1; + } while (iVar5 <= ctx->size); + bits = ctx->size; + if (iVar5 <= bits) { + bits = val + 1 + (iVar5 << ((uint8_t)ctx->bits & 0x1f)); + dst[0] = bits; + if (sign) + dst[0] *= -1; + return 0; + } + } + bits = bits + 1; + while (ac_dec_bit(ac) == 0) + bits = bits + 64; + ac_get_freq(ac, 64, &iVar5); + ac_update(ac,iVar5,1); + iVar5 = bits + iVar5; + bits = val + 1 + (iVar5 << ((uint8_t)ctx->bits & 0x1f)); + dst[0] = bits; + if (sign) + dst[0] = -dst[0]; + + return 0; +} + +static const uint8_t tab[] = { 0, 3, 3, 2, 2, 1, 1, 1, 1 }; + +static int decode_filter(RKAContext *s, ChContext *ctx, ACoder *ac, int off, unsigned size) +{ + FiltCoeffs filt; + Model64 *mdl64; + unsigned bits; + int ret; + int aval; + uint8_t shift; + int iVar3; + int i; + int local_c40; + int local_c3c; + int local_c30; + int last_val; + int local_c28; + unsigned pos_mod11; + int cmode2; + + pos_mod11 = 3; + last_val = 0; + bits = 0; + if (ctx->cmode == 0) { + if (amdl_decode_int(&ctx->fshift, ac, &bits, 15) < 0) + return -1; + bits &= 31U; + } + ret = decode_filt_coeffs(s, ctx, ac, &filt); + if (ret < 0) + return ret; + + if (size < 512) + local_c30 = size / 2; + else + local_c30 = size >> 4; + cmode2 = 0; + if (size > 0) { + do { + local_c40 = 0; + local_c3c = local_c30 + cmode2; + if (size < local_c3c) { + local_c30 = size - cmode2; + local_c3c = size; + } + if (amdl_decode_int(&ctx->pos_update, ac, &pos_mod11, 10) < 0) + return -1; + pos_mod11 = (ctx->pos_mod11 + pos_mod11) % 11; + ctx->pos_mod11 = pos_mod11; + iVar3 = local_c30 + cmode2; + if (cmode2 < local_c3c) { + do { + int *src, sum = 16; + + aval = FFABS(last_val); + shift = (uint8_t)pos_mod11; + if (aval >> (shift & 0x1f) < 0xf) { + aval = FFABS(last_val); + if (aval >> (shift & 0x1f) < 7) { + last_val = FFABS(last_val); + if (last_val >> (shift & 0x1f) < 4) + mdl64 = &ctx->mdl64[0][pos_mod11]; + else + mdl64 = &ctx->mdl64[1][pos_mod11]; + } else { + mdl64 = &ctx->mdl64[2][pos_mod11]; + } + } else { + mdl64 = &ctx->mdl64[3][pos_mod11]; + } + ret = mdl64_decode(ac, mdl64, &local_c28); + if (ret < 0) + return -1; + last_val = local_c28; + aval = cmode2 + 1; + src = &ctx->buf1[off + cmode2 + -1]; + for (i = 0; i < filt.size && i < 15; i++) + sum += filt.coeffs[i] * src[-i]; + sum = sum * 2; + for (; i < filt.size; i++) + sum += filt.coeffs[i] * src[-i]; + sum = sum >> 6; + if (ctx->cmode == 0) { + if (bits == 0) { + ctx->buf1[off + cmode2] = sum + local_c28; + } else { + ctx->buf1[off + cmode2] = + (local_c28 + (sum >> bits) * (1U << bits)) + + (((1U << bits) - 1U) & ctx->buf1[off + cmode2 + -1]); + } + ctx->buf0[off + cmode2] = ctx->buf1[off + cmode2] + ctx->buf0[off + cmode2 + -1]; + } else { + local_c28 = local_c28 * (1 << ctx->cmode & 0x1f); + sum = sum + ctx->buf0[off + cmode2 + -1] + local_c28; + switch (s->bps) { + case 16: sum = av_clip_int16(sum); break; + case 8: sum = av_clip_int8(sum); break; + } + ctx->buf1[off + cmode2] = sum - ctx->buf0[off + cmode2 + -1]; + ctx->buf0[off + cmode2] = sum; + cmode2 = FFABS(ctx->buf1[off + cmode2]); + local_c40 += cmode2; + } + cmode2 = aval; + } while (aval < local_c3c); + } + cmode2 = ctx->cmode2; + if (cmode2 != 0) { + int sum = 0; + for (aval = (local_c40 << 6) / local_c30; 0 < aval; aval = aval >> 1) + sum = sum + 1; + sum = sum - (cmode2 + 7); + aval = tab[cmode2]; + if (tab[cmode2] < sum) + aval = sum; + ctx->cmode = aval; + } + cmode2 = iVar3; + } while (iVar3 < size); + } + + return 0; +} + +static int decode_samples(AVCodecContext *avctx, ACoder *ac, ChContext *ctx, int offset) +{ + RKAContext *s = avctx->priv_data; + int segment_size, size, offset2, mode, ret; + + ret = amdl_decode_int(&ctx->nb_segments, ac, &mode, 5); + if (ret < 0) + return ret; + + if (mode == 5) { + ret = ac_get_freq(ac, ctx->srate_pad >> 2, &segment_size); + if (ret < 0) + return ret; + ac_update(ac, segment_size, 1); + segment_size *= 4; + decode_filter(s, ctx, ac, offset, segment_size); + } else { + segment_size = ctx->srate_pad; + + if (mode) { + if (mode > 2) { + decode_filter(s, ctx, ac, offset, segment_size / 4); + offset2 = segment_size / 4 + offset; + decode_filter(s, ctx, ac, offset2, segment_size / 4); + size = segment_size / 4 + offset2; + } else { + decode_filter(s, ctx, ac, offset, segment_size / 2); + size = segment_size / 2 + offset; + } + if (mode & 1) { + decode_filter(s, ctx, ac, size, segment_size / 2); + } else { + decode_filter(s, ctx, ac, size, segment_size / 4); + decode_filter(s, ctx, ac, segment_size / 4 + size, segment_size / 4); + } + } else { + decode_filter(s, ctx, ac, offset, ctx->srate_pad); + } + } + + return segment_size; +} + +static int decode_ch_sample(AVCodecContext *avctx, int *sample) +{ + RKAContext *s = avctx->priv_data; + ACoder *ac = &s->ac; + ChContext *c; + + c = &s->ch[s->cur_chan]; + if (c->start >= c->end) { + int i = 0; + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + return AVERROR_EOF; + + do { + c->buf0[i] = c->buf0[i + c->end - 2560]; + c->buf1[i] = c->buf1[i + c->end - 2560]; + i++; + } while (i < 2560); + + c->start = c->end = 2560; + + i = decode_samples(avctx, ac, c, 2560); + if (i < 0) + return i; + c->end += i; + } + + sample[0] = c->buf0[c->start]; + c->start++; + + s->cur_chan++; + if (s->cur_chan >= s->channels) + s->cur_chan = 0; + + return 0; +} + +static int rka_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + RKAContext *s = avctx->priv_data; + ACoder *ac = &s->ac; + int ret; + + bytestream2_init(&ac->gb, avpkt->data, avpkt->size); + init_acoder(ac); + s->cur_chan = 0; + + for (int ch = 0; ch < s->channels; ch++) { + ret = chctx_init(s, &s->ch[ch], avctx->sample_rate, + avctx->bits_per_raw_sample); + if (ret < 0) + return ret; + } + + frame->nb_samples = s->frame_samples; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + if (s->channels == 2) { + int16_t *dst = (int16_t *)frame->data[0]; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16: + for (int n = 0; n < frame->nb_samples; n++) { + int l, r; + + ret = decode_ch_sample(avctx, &l); + if (ret == AVERROR_EOF) { + frame->nb_samples = n; + break; + } + if (ret < 0) + return AVERROR_INVALIDDATA; + + ret = decode_ch_sample(avctx, &r); + if (ret == AVERROR_EOF) { + frame->nb_samples = n; + break; + } + if (ret < 0) + return AVERROR_INVALIDDATA; + + dst[2 * n + 0] = (l * 2 + r + 1) / 2; + dst[2 * n + 1] = (l * 2 - r + 1) / 2; + } + break; + default: + return AVERROR_INVALIDDATA; + } + } else { + int16_t *dst = (int16_t *)frame->data[0]; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16: + for (int n = 0; n < frame->nb_samples; n++) { + int m; + + ret = decode_ch_sample(avctx, &m); + if (ret == AVERROR_EOF) { + frame->nb_samples = n; + break; + } + if (ret < 0) + return AVERROR_INVALIDDATA; + + dst[n] = m; + } + break; + default: + return AVERROR_INVALIDDATA; + } + } + + *got_frame_ptr = 1; + + return avpkt->size; +} + +static av_cold int rka_decode_close(AVCodecContext *avctx) +{ + RKAContext *s = avctx->priv_data; + + for (int ch = 0; ch < 2; ch++) { + ChContext *c = &s->ch[ch]; + + for (int i = 0; i < 11; i++) + adaptive_model_free(&c->coeff_bits[i]); + + adaptive_model_free(&c->pos_update); + adaptive_model_free(&c->nb_segments); + adaptive_model_free(&c->fshift); + } + + adaptive_model_free(&s->filt_size); + adaptive_model_free(&s->filt_bits); + + return 0; +} + +const FFCodec ff_rka_decoder = { + .p.name = "rka", + CODEC_LONG_NAME("RKA (RK Audio"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_RKA, + .priv_data_size = sizeof(RKAContext), + .init = rka_decode_init, + .close = rka_decode_close, + FF_CODEC_DECODE_CB(rka_decode_frame), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; -- 2.39.1 [-- Attachment #4: Type: text/plain, Size: 251 bytes --] _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". ^ permalink raw reply [flat|nested] 4+ messages in thread
* [FFmpeg-devel] [PATCH] RK Audio demuxer and decoder 2023-02-04 9:04 [FFmpeg-devel] [RFC][WIP][PATCH] RK Audio demuxer and decoder Paul B Mahol @ 2023-02-05 19:17 ` Paul B Mahol 2023-02-10 18:13 ` Paul B Mahol 2023-02-15 11:59 ` James Almer 0 siblings, 2 replies; 4+ messages in thread From: Paul B Mahol @ 2023-02-05 19:17 UTC (permalink / raw) To: FFmpeg development discussions and patches [-- Attachment #1: Type: text/plain, Size: 216 bytes --] On 2/4/23, Paul B Mahol <onemda@gmail.com> wrote: > Hi, > > Patches attached, decoder is not bit by bit exact yet for lossless > mode because some samples are not properly rounded. > Now lossless mode is bit exact. [-- Attachment #2: 0001-avformat-add-RKA-demuxer.patch --] [-- Type: text/x-patch, Size: 6925 bytes --] From 232125e5bbbd6ac0b8049cc32e5ca61c484d1bd8 Mon Sep 17 00:00:00 2001 From: Paul B Mahol <onemda@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 <onemda@gmail.com> --- libavformat/Makefile | 1 + libavformat/allformats.c | 1 + libavformat/rka.c | 173 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+) create mode 100644 libavformat/rka.c diff --git a/libavformat/Makefile b/libavformat/Makefile index f0408a58b1..cd9c7a36a8 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 apetag.o img2.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..c1e64ebcb3 --- /dev/null +++ b/libavformat/rka.c @@ -0,0 +1,173 @@ +/* + * 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)); + + if (s->pb->seekable & AVIO_SEEKABLE_NORMAL) + ff_ape_parse_tag(s); + + 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 [-- Attachment #3: 0002-avcodec-add-RKA-decoder.patch --] [-- Type: text/x-patch, Size: 30010 bytes --] From 217b459cea1e6468835240d1c2313e89918e6d7b Mon Sep 17 00:00:00 2001 From: Paul B Mahol <onemda@gmail.com> Date: Tue, 31 Jan 2023 21:03:38 +0100 Subject: [PATCH 2/2] avcodec: add RKA decoder Signed-off-by: Paul B Mahol <onemda@gmail.com> --- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/codec_desc.c | 7 + libavcodec/codec_id.h | 1 + libavcodec/rka.c | 999 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1009 insertions(+) create mode 100644 libavcodec/rka.c diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 4971832ff4..389253f5d0 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -631,6 +631,7 @@ OBJS-$(CONFIG_RASC_DECODER) += rasc.o OBJS-$(CONFIG_RAWVIDEO_DECODER) += rawdec.o OBJS-$(CONFIG_RAWVIDEO_ENCODER) += rawenc.o OBJS-$(CONFIG_REALTEXT_DECODER) += realtextdec.o ass.o +OBJS-$(CONFIG_RKA_DECODER) += rka.o OBJS-$(CONFIG_RL2_DECODER) += rl2.o OBJS-$(CONFIG_ROQ_DECODER) += roqvideodec.o roqvideo.o OBJS-$(CONFIG_ROQ_ENCODER) += roqvideoenc.o roqvideo.o elbg.o diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b80b6983e9..e593ad19af 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -287,6 +287,7 @@ extern const FFCodec ff_r210_decoder; extern const FFCodec ff_rasc_decoder; extern const FFCodec ff_rawvideo_encoder; extern const FFCodec ff_rawvideo_decoder; +extern const FFCodec ff_rka_decoder; extern const FFCodec ff_rl2_decoder; extern const FFCodec ff_roq_encoder; extern const FFCodec ff_roq_decoder; diff --git a/libavcodec/codec_desc.c b/libavcodec/codec_desc.c index 57d0f98211..199f62df15 100644 --- a/libavcodec/codec_desc.c +++ b/libavcodec/codec_desc.c @@ -3360,6 +3360,13 @@ static const AVCodecDescriptor codec_descriptors[] = { .long_name = NULL_IF_CONFIG_SMALL("Waveform Archiver"), .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSLESS, }, + { + .id = AV_CODEC_ID_RKA, + .type = AVMEDIA_TYPE_AUDIO, + .name = "rka", + .long_name = NULL_IF_CONFIG_SMALL("RKA (RK Audio)"), + .props = AV_CODEC_PROP_INTRA_ONLY | AV_CODEC_PROP_LOSSY | AV_CODEC_PROP_LOSSLESS, + }, /* subtitle codecs */ { diff --git a/libavcodec/codec_id.h b/libavcodec/codec_id.h index ad1131b464..89a4a0cb89 100644 --- a/libavcodec/codec_id.h +++ b/libavcodec/codec_id.h @@ -537,6 +537,7 @@ enum AVCodecID { AV_CODEC_ID_APAC, AV_CODEC_ID_FTR, AV_CODEC_ID_WAVARC, + AV_CODEC_ID_RKA, /* subtitle codecs */ AV_CODEC_ID_FIRST_SUBTITLE = 0x17000, ///< A dummy ID pointing at the start of subtitle codecs. diff --git a/libavcodec/rka.c b/libavcodec/rka.c new file mode 100644 index 0000000000..d916227483 --- /dev/null +++ b/libavcodec/rka.c @@ -0,0 +1,999 @@ +/* + * RKA decoder + * Copyright (c) 2023 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/channel_layout.h" +#include "libavutil/intreadwrite.h" + +#include "avcodec.h" +#include "codec_internal.h" +#include "bytestream.h" +#include "decode.h" + +typedef struct ACoder { + GetByteContext gb; + uint32_t low, high; + uint32_t value; +} ACoder; + +typedef struct FiltCoeffs { + int32_t coeffs[257]; + unsigned size; +} FiltCoeffs; + +typedef struct Model64 { + uint32_t zero[2]; + uint32_t sign[2]; + unsigned size; + int bits; + + uint16_t val4[65]; + uint16_t val1[65]; +} Model64; + +typedef struct AdaptiveModel { + int last; + int total; + int buf_size; + int16_t sum; + uint16_t aprob0; + uint16_t aprob1; + uint16_t *prob[2]; +} AdaptiveModel; + +typedef struct ChContext { + int cmode; + int cmode2; + int last_nb_decoded; + unsigned srate_pad; + unsigned pos_idx; + + AdaptiveModel *filt_size; + AdaptiveModel *filt_bits; + + int *bprob0; + int *bprob1; + + AdaptiveModel position; + AdaptiveModel fshift; + AdaptiveModel nb_segments; + AdaptiveModel coeff_bits[11]; + + Model64 mdl64[4][11]; + + int32_t buf0[12001]; + int32_t buf1[12001]; +} ChContext; + +typedef struct RKAContext { + AVClass *class; + + ACoder ac; + ChContext ch[2]; + + int bps; + int align; + int channels; + int frame_samples; + int last_nb_samples; + uint32_t total_nb_samples; + uint32_t samples_left; + + int bprob0[257]; + int bprob1[257]; + + AdaptiveModel filt_size; + AdaptiveModel filt_bits; +} RKAContext; + +static int adaptive_model_init(AdaptiveModel *am, int buf_size) +{ + am->buf_size = buf_size; + am->sum = 2000; + am->aprob0 = 0; + am->aprob1 = 0; + am->total = 0; + + if (!am->prob[0]) + am->prob[0] = av_malloc_array(buf_size + 5, sizeof(*am->prob[0])); + if (!am->prob[1]) + am->prob[1] = av_malloc_array(buf_size + 5, sizeof(*am->prob[1])); + + if (!am->prob[0] || !am->prob[1]) + return AVERROR(ENOMEM); + memset(am->prob[0], 0, (buf_size + 5) * sizeof(*am->prob[0])); + memset(am->prob[1], 0, (buf_size + 5) * sizeof(*am->prob[1])); + return 0; +} + +static void adaptive_model_free(AdaptiveModel *am) +{ + av_freep(&am->prob[0]); + av_freep(&am->prob[1]); +} + +static av_cold int rka_decode_init(AVCodecContext *avctx) +{ + RKAContext *s = avctx->priv_data; + int cmode; + + if (avctx->extradata_size < 16) + return AVERROR_INVALIDDATA; + + s->bps = avctx->bits_per_raw_sample = avctx->extradata[13]; + + switch (s->bps) { + case 8: + avctx->sample_fmt = AV_SAMPLE_FMT_U8P; + break; + case 16: + avctx->sample_fmt = AV_SAMPLE_FMT_S16P; + break; + default: + return AVERROR_INVALIDDATA; + } + + s->channels = avctx->ch_layout.nb_channels; + if (s->channels < 1 || s->channels > 2) + return AVERROR_INVALIDDATA; + + s->align = (s->channels * (avctx->bits_per_raw_sample >> 3)); + s->samples_left = s->total_nb_samples = (AV_RL32(avctx->extradata + 4)) / s->align; + s->frame_samples = 131072 / s->align; + s->last_nb_samples = s->total_nb_samples % s->frame_samples; + + cmode = avctx->extradata[14] & 0xf; + if ((avctx->extradata[15] & 4) != 0) + cmode = -cmode; + + s->ch[0].cmode = s->ch[1].cmode = cmode; + s->ch[0].cmode2 = -s->ch[0].cmode; + s->ch[1].cmode2 = -s->ch[1].cmode; + av_log(avctx, AV_LOG_DEBUG, "cmode: %d\n", cmode); + + return 0; +} + +static void model64_init(Model64 *m, unsigned bits) +{ + unsigned x; + + m->bits = bits; + m->size = 64; + m->zero[0] = 1; + + x = (1 << (bits >> 1)) + 3; + x = FFMIN(x, 20); + + m->zero[1] = x; + m->sign[0] = 1; + m->sign[1] = 1; + + for (int i = 0; i < FF_ARRAY_ELEMS(m->val4); i++) { + m->val4[i] = 4; + m->val1[i] = 1; + } +} + +static int chctx_init(RKAContext *s, ChContext *c, + int sample_rate, int bps) +{ + int ret; + + memset(c->buf0, 0, sizeof(c->buf0)); + memset(c->buf1, 0, sizeof(c->buf1)); + + c->filt_size = &s->filt_size; + c->filt_bits = &s->filt_bits; + + c->bprob0 = s->bprob0; + c->bprob1 = s->bprob1; + + c->srate_pad = (sample_rate << 13) / 44100 & 0xFFFFFFFCU; + c->pos_idx = 1; + + for (int i = 0; i < FF_ARRAY_ELEMS(s->bprob0); i++) + c->bprob0[i] = c->bprob1[i] = 1; + + for (int i = 0; i < 11; i++) { + ret = adaptive_model_init(&c->coeff_bits[i], 32); + if (ret < 0) + return ret; + + model64_init(&c->mdl64[0][i], i); + model64_init(&c->mdl64[1][i], i); + model64_init(&c->mdl64[2][i], i+1); + model64_init(&c->mdl64[3][i], i+1); + } + + ret = adaptive_model_init(c->filt_size, 256); + if (ret < 0) + return ret; + ret = adaptive_model_init(c->filt_bits, 16); + if (ret < 0) + return ret; + ret = adaptive_model_init(&c->position, 16); + if (ret < 0) + return ret; + ret = adaptive_model_init(&c->nb_segments, 8); + if (ret < 0) + return ret; + return adaptive_model_init(&c->fshift, 32); +} + +static void init_acoder(ACoder *ac) +{ + ac->low = 0x0; + ac->high = 0xffffffff; + ac->value = bytestream2_get_be32(&ac->gb); +} + +static int ac_decode_bool(ACoder *ac, int freq1, int freq2) +{ + unsigned help, add, high; + int value, low; + + low = ac->low; + help = ac->high / (unsigned int)(freq2 + freq1); + value = ac->value; + add = freq1 * help; + ac->high = help; + + if (value - low >= add) { + ac->low = low = add + low; + ac->high = high = freq2 * help; + while (1) { + if ((low ^ (high + low)) > 0xFFFFFF) { + if (high > 0xFFFF) + return 1; + ac->high = (uint16_t)-(int16_t)low; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } + return -1; + } + + ac->high = add; + while (1) { + if ((low ^ (add + low)) > 0xFFFFFF) { + if (add > 0xFFFF) + return 0; + ac->high = (uint16_t)-(int16_t)low; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + ac->value = bytestream2_get_byteu(&ac->gb) | (ac->value << 8); + ac->high = add = ac->high << 8; + ac->low = low = ac->low << 8; + } + return -1; +} + +static int decode_bool(ACoder *ac, ChContext *c, int idx) +{ + int x, b; + + x = c->bprob0[idx]; + if (x + c->bprob1[idx] > 4096) { + c->bprob0[idx] = (x >> 1) + 1; + c->bprob1[idx] = (c->bprob1[idx] >> 1) + 1; + } + + b = ac_decode_bool(ac, c->bprob0[idx], c->bprob1[idx]); + if (b == 1) { + c->bprob1[idx]++; + } else if (b == 0) { + c->bprob0[idx]++; + } + + return b; +} + +static int ac_get_freq(ACoder *ac, unsigned freq, int *result) +{ + uint32_t new_high; + + if (freq == 0) + return -1; + + new_high = ac->high / freq; + ac->high = new_high; + + if (new_high == 0) + return -1; + + *result = (ac->value - ac->low) / new_high; + + return 0; +} + +static int ac_update(ACoder *ac, int freq, int mul) +{ + uint32_t low, high; + + low = ac->low = ac->high * freq + ac->low; + high = ac->high = ac->high * mul; + + while (1) { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 0; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + low = ac->low = ac->low << 8; + high = ac->high = ac->high << 8; + } + + return -1; +} + +static void update_ch_subobj(AdaptiveModel *am) +{ + int idx2, idx = am->buf_size - 1; + + if (idx >= 0) { + do { + uint16_t *prob = am->prob[0]; + int prob_idx = prob[idx]; + int diff, left; + + idx2 = idx - 1; + if (idx > 0) { + int idx3 = idx - 1; + + if ((idx2 & idx) != idx2) { + do { + prob_idx -= prob[idx3]; + idx3 &= idx3 - 1; + } while ((idx2 & idx) != idx3); + } + } + + diff = ((prob_idx > 0) - prob_idx) >> 1; + left = idx; + am->aprob0 += diff; + if (idx <= 0) { + am->prob[0][0] += diff; + } else { + do { + am->prob[0][left] += diff; + left += (left & -left); + } + while (left < am->buf_size); + } + idx--; + } while (idx2 >= 0); + } + + if (am->sum < 8000) + am->sum += 200; + + am->aprob1 = (am->aprob1 + 1) >> 1; +} + +static int amdl_decode_int(AdaptiveModel *am, ACoder *ac, unsigned *dst, unsigned size) +{ + unsigned int freq; + int val_1; + int v7; + int v8; + uint16_t v9; + int v10; + uint16_t v11; + uint16_t *v12; + int v13; + int v14; + int k; + int v17; + unsigned v18; + int val; + int v24; + int freqa; + uint16_t v27; + uint16_t j; + uint16_t v29; + + val_1 = FFMIN(size, am->buf_size - 1); + + if (am->aprob0 >= am->sum) + update_ch_subobj(am); + + if (am->aprob1 && (am->total == am->buf_size || + ac_decode_bool(ac, am->aprob0, am->aprob1) == 0)) { + if (am->total <= 1) { + dst[0] = am->last; + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0][0]++; + } else { + do { + am->prob[0][val]++; + val += (val & -val); + } while (val < am->buf_size); + } + return 0; + } + if (val_1 == am->buf_size - 1) { + freq = am->aprob0; + } else { + unsigned i = am->prob[0][0]; + + for (int j = val_1; j > 0; j &= (j - 1) ) + i += am->prob[0][j]; + freq = i; + } + v24 = 0; + ac_get_freq(ac, freq, &v7); + v8 = am->buf_size >> 1; + v9 = am->prob[0][0]; + if (v7 >= v9) { + for (j = v7 - v9; v8; v8 >>= 1) { + v11 = am->prob[0][v8 + v24]; + if (j >= v11) { + v24 += v8; + j -= v11; + } + } + v27 = v7 - j; + v10 = v24 + 1; + } else { + v27 = 0; + v10 = 0; + } + dst[0] = v10; + v12 = am->prob[0]; + v13 = v12[v10]; + if (v10 > 0) { + v14 = v10 & (v10 - 1); + for (k = v10 - 1; v14 != k; k &= k - 1) + v13 -= v12[k]; + } + ac_update(ac, v27, v13); + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0][0]++; + } else { + do { + am->prob[0][val]++; + val += (val & -val); + } while (val < am->buf_size); + } + return 0; + } + v17 = am->buf_size; + am->aprob1++; + if (val_1 == v17 - 1) { + ac_get_freq(ac, v17 - am->total, &v18); + } else { + freqa = 1; + dst[0] = 0; + if (val_1 > 0) { + do { + if (!am->prob[1][dst[0]]) + freqa++; + dst[0]++; + } while (dst[0] < val_1); + } + ac_get_freq(ac, freqa, &v18); + } + v29 = 0; + dst[0] = 0; + if (v18 > 0 && am->buf_size > 0) { + do { + val = dst[0]; + if (!am->prob[1][dst[0]]) + ++v29; + dst[0] = val + 1; + } + while (v29 < v18 && val + 1 < am->buf_size); + } + if (am->prob[1][dst[0]]) { + do { + val = dst[0]++; + } while (val + 1 < am->buf_size && am->prob[1][val + 1]); + } + ac_update(ac, v29, 1); + am->prob[1][dst[0]]++; + am->total++; + val = dst[0]; + am->aprob0++; + if (val <= 0) { + am->prob[0][0]++; + } else { + do { + am->prob[0][val]++; + val += (val & -val); + } while (val < am->buf_size); + } + + am->last = dst[0]; + + return 0; +} + +static int decode_filt_coeffs(RKAContext *s, ChContext *ctx, ACoder *ac, FiltCoeffs *dst) +{ + unsigned val, bits; + int idx = 0; + + if (amdl_decode_int(ctx->filt_size, ac, &dst->size, 256) < 0) + return -1; + + if (dst->size == 0) + return 0; + + if (amdl_decode_int(ctx->filt_bits, ac, &bits, 10) < 0) + return -1; + + do { + if (((idx == 8) || (idx == 20)) && (0 < bits)) + bits--; + + if (bits > 10) + return -1; + + if (amdl_decode_int(&ctx->coeff_bits[bits], ac, &val, 31) < 0) + return -1; + + if (val == 31) { + ac_get_freq(ac, 65536, &val); + ac_update(ac, val, 1); + } + + if (val == 0) { + dst->coeffs[idx++] = 0; + } else { + unsigned freq = 0; + int sign; + + if (bits > 0) { + ac_get_freq(ac, 1 << bits, &freq); + ac_update(ac, freq, 1); + } + dst->coeffs[idx] = freq + 1 + ((val - 1U) << bits); + sign = decode_bool(ac, ctx, idx); + if (sign < 0) + return -1; + if (sign == 1) + dst->coeffs[idx] = -dst->coeffs[idx]; + idx++; + } + } while (idx < dst->size); + + return 0; +} + +static int ac_dec_bit(ACoder *ac) +{ + uint32_t high, low; + + low = ac->low; + ac->high = high = ac->high >> 1; + if (ac->value - low < high) { + do { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 0; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } while (1); + + return -1; + } + ac->low = low = low + high; + do { + if (((high + low) ^ low) > 0xffffff) { + if (high > 0xffff) + return 1; + ac->high = (-(int16_t)low) & 0xffff; + } + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + break; + + ac->value = (ac->value << 8) | bytestream2_get_byteu(&ac->gb); + ac->high = high = ac->high << 8; + ac->low = low = ac->low << 8; + } while (1); + + return -1; +} + +static int mdl64_decode(ACoder *ac, Model64 *ctx, int *dst) +{ + int sign, idx, bits; + unsigned val = 0; + + if (ctx->zero[0] + ctx->zero[1] > 4000) { + ctx->zero[0] = (ctx->zero[0] >> 1) + 1; + ctx->zero[1] = (ctx->zero[1] >> 1) + 1; + } + if (ctx->sign[0] + ctx->sign[1] > 4000) { + ctx->sign[0] = (ctx->sign[0] >> 1) + 1; + ctx->sign[1] = (ctx->sign[1] >> 1) + 1; + } + sign = ac_decode_bool(ac, ctx->zero[0], ctx->zero[1]); + if (sign == 0) { + ctx->zero[0] += 2; + dst[0] = 0; + return 0; + } else if (sign < 0) + return -1; + + ctx->zero[1] += 2; + sign = ac_decode_bool(ac, ctx->sign[0], ctx->sign[1]); + if (sign < 0) + return -1; + ctx->sign[sign]++; + bits = ctx->bits; + if (bits > 0) { + if (bits < 13) { + ac_get_freq(ac, 1 << bits, &val); + ac_update(ac,val,1); + } else { + ac_get_freq(ac, 1 << (bits / 2), &val); + ac_update(ac,val,1); + ac_get_freq(ac,1 << (ctx->bits - (bits / 2)), &bits); + ac_update(ac,val,1); + val = val + (bits << (bits / 2)); + } + } + bits = ctx->size; + idx = 0; + if (bits >= 0) { + do { + uint16_t *val4 = ctx->val4; + int b; + + if (val4[idx] + ctx->val1[idx] > 2000U) { + val4[idx] = (val4[idx] >> 1) + 1; + ctx->val1[idx] = (ctx->val1[idx] >> 1) + 1; + } + b = ac_decode_bool(ac, ctx->val4[idx], ctx->val1[idx]); + if (b == 1) { + ctx->val1[idx] += 4; + break; + } else if (b < 0) { + return -1; + } + ctx->val4[idx] += 4; + idx++; + } while (idx <= ctx->size); + bits = ctx->size; + if (idx <= bits) { + dst[0] = val + 1 + (idx << ctx->bits); + if (sign) + dst[0] = -dst[0]; + return 0; + } + } + bits = bits + 1; + while (ac_dec_bit(ac) == 0) + bits = bits + 64; + ac_get_freq(ac, 64, &idx); + ac_update(ac, idx, 1); + idx += bits; + bits = val + 1 + (idx << ctx->bits); + dst[0] = bits; + if (sign) + dst[0] = -dst[0]; + + return 0; +} + +static const uint8_t tab[] = { 0, 3, 3, 2, 2, 1, 1, 1, 1 }; + +static int decode_filter(RKAContext *s, ChContext *ctx, ACoder *ac, int off, unsigned size) +{ + FiltCoeffs filt; + Model64 *mdl64; + int m = 0, split, val, last_val = 0, ret; + unsigned idx = 3, bits = 0; + + if (ctx->cmode == 0) { + if (amdl_decode_int(&ctx->fshift, ac, &bits, 15) < 0) + return -1; + bits &= 31U; + } + + ret = decode_filt_coeffs(s, ctx, ac, &filt); + if (ret < 0) + return ret; + + if (size < 512) + split = size / 2; + else + split = size >> 4; + + if (size <= 0) + return 0; + + for (int x = 0; x < size;) { + if (amdl_decode_int(&ctx->position, ac, &idx, 10) < 0) + return -1; + + idx = (ctx->pos_idx + idx) % 11; + ctx->pos_idx = idx; + + for (int y = 0; y < split; y++, off++) { + int midx, shift = idx, *src, sum = 16; + + midx = FFABS(last_val) >> shift; + if (midx >= 15) { + mdl64 = &ctx->mdl64[3][idx]; + } else if (midx >= 7) { + mdl64 = &ctx->mdl64[2][idx]; + } else if (midx >= 4) { + mdl64 = &ctx->mdl64[1][idx]; + } else { + mdl64 = &ctx->mdl64[0][idx]; + } + ret = mdl64_decode(ac, mdl64, &val); + if (ret < 0) + return -1; + last_val = val; + src = &ctx->buf1[off + -1]; + for (int i = 0; i < filt.size && i < 15; i++) + sum += filt.coeffs[i] * src[-i]; + sum = sum * 2; + for (int i = 15; i < filt.size; i++) + sum += filt.coeffs[i] * src[-i]; + sum = sum >> 6; + if (ctx->cmode == 0) { + if (bits == 0) { + ctx->buf1[off] = sum + val; + } else { + ctx->buf1[off] = (val + (sum >> bits) * (1U << bits)) + + (((1U << bits) - 1U) & ctx->buf1[off + -1]); + } + ctx->buf0[off] = ctx->buf1[off] + ctx->buf0[off + -1]; + } else { + val = val * (1 << ctx->cmode & 0x1f); + sum += ctx->buf0[off + -1] + val; + switch (s->bps) { + case 16: sum = av_clip_int16(sum); break; + case 8: sum = av_clip_int8(sum); break; + } + ctx->buf1[off] = sum - ctx->buf0[off + -1]; + ctx->buf0[off] = sum; + m += FFABS(ctx->buf1[off]); + } + } + if (ctx->cmode2 != 0) { + int sum = 0; + for (int i = (m << 6) / split; i > 0; i = i >> 1) + sum++; + sum = sum - (ctx->cmode2 + 7); + ctx->cmode = FFMAX(sum, tab[ctx->cmode2]); + } + + x += split; + } + + return 0; +} + +static int decode_samples(AVCodecContext *avctx, ACoder *ac, ChContext *ctx, int offset) +{ + RKAContext *s = avctx->priv_data; + int segment_size, size, offset2, mode, ret; + + ret = amdl_decode_int(&ctx->nb_segments, ac, &mode, 5); + if (ret < 0) + return ret; + + if (mode == 5) { + ret = ac_get_freq(ac, ctx->srate_pad >> 2, &segment_size); + if (ret < 0) + return ret; + ac_update(ac, segment_size, 1); + segment_size *= 4; + decode_filter(s, ctx, ac, offset, segment_size); + } else { + segment_size = ctx->srate_pad; + + if (mode) { + if (mode > 2) { + decode_filter(s, ctx, ac, offset, segment_size / 4); + offset2 = segment_size / 4 + offset; + decode_filter(s, ctx, ac, offset2, segment_size / 4); + size = segment_size / 4 + offset2; + } else { + decode_filter(s, ctx, ac, offset, segment_size / 2); + size = segment_size / 2 + offset; + } + if (mode & 1) { + decode_filter(s, ctx, ac, size, segment_size / 2); + } else { + decode_filter(s, ctx, ac, size, segment_size / 4); + decode_filter(s, ctx, ac, segment_size / 4 + size, segment_size / 4); + } + } else { + decode_filter(s, ctx, ac, offset, ctx->srate_pad); + } + } + + return segment_size; +} + +static int decode_ch_samples(AVCodecContext *avctx, ChContext *c) +{ + RKAContext *s = avctx->priv_data; + ACoder *ac = &s->ac; + int nb_decoded = 0; + + if (bytestream2_get_bytes_left(&ac->gb) <= 0) + return 0; + + memmove(c->buf0, &c->buf0[c->last_nb_decoded], 2560 * sizeof(*c->buf0)); + memmove(c->buf1, &c->buf1[c->last_nb_decoded], 2560 * sizeof(*c->buf1)); + + nb_decoded = decode_samples(avctx, ac, c, 2560); + if (nb_decoded < 0) + return nb_decoded; + c->last_nb_decoded = nb_decoded; + + return nb_decoded; +} + +static int rka_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame_ptr, AVPacket *avpkt) +{ + RKAContext *s = avctx->priv_data; + ACoder *ac = &s->ac; + int ret; + + bytestream2_init(&ac->gb, avpkt->data, avpkt->size); + init_acoder(ac); + + for (int ch = 0; ch < s->channels; ch++) { + ret = chctx_init(s, &s->ch[ch], avctx->sample_rate, + avctx->bits_per_raw_sample); + if (ret < 0) + return ret; + } + + frame->nb_samples = s->frame_samples; + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) + return ret; + + if (s->channels == 2) { + int16_t *l16 = (int16_t *)frame->extended_data[0]; + int16_t *r16 = (int16_t *)frame->extended_data[1]; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16P: + for (int n = 0; n < frame->nb_samples;) { + ret = decode_ch_samples(avctx, &s->ch[0]); + if (ret == 0) { + frame->nb_samples = n; + break; + } + if (ret < 0 || n + ret > frame->nb_samples) + return AVERROR_INVALIDDATA; + + ret = decode_ch_samples(avctx, &s->ch[1]); + if (ret == 0) { + frame->nb_samples = n; + break; + } + if (ret < 0 || n + ret > frame->nb_samples) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < ret; i++) { + int l = s->ch[0].buf0[2560 + i]; + int r = s->ch[1].buf0[2560 + i]; + + l16[n + i] = (l * 2 + r + 1) >> 1; + r16[n + i] = (l * 2 - r + 1) >> 1; + } + + n += ret; + } + break; + default: + return AVERROR_INVALIDDATA; + } + } else { + int16_t *m16 = (int16_t *)frame->data[0]; + + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_S16P: + for (int n = 0; n < frame->nb_samples;) { + ret = decode_ch_samples(avctx, &s->ch[0]); + if (ret == 0) { + frame->nb_samples = n; + break; + } + if (ret < 0 || n + ret > frame->nb_samples) + return AVERROR_INVALIDDATA; + + for (int i = 0; i < ret; i++) { + int m = s->ch[0].buf0[2560 + i]; + + m16[n + i] = m; + } + + n += ret; + } + break; + default: + return AVERROR_INVALIDDATA; + } + } + + *got_frame_ptr = 1; + + return avpkt->size; +} + +static av_cold int rka_decode_close(AVCodecContext *avctx) +{ + RKAContext *s = avctx->priv_data; + + for (int ch = 0; ch < 2; ch++) { + ChContext *c = &s->ch[ch]; + + for (int i = 0; i < 11; i++) + adaptive_model_free(&c->coeff_bits[i]); + + adaptive_model_free(&c->position); + adaptive_model_free(&c->nb_segments); + adaptive_model_free(&c->fshift); + } + + adaptive_model_free(&s->filt_size); + adaptive_model_free(&s->filt_bits); + + return 0; +} + +const FFCodec ff_rka_decoder = { + .p.name = "rka", + CODEC_LONG_NAME("RKA (RK Audio"), + .p.type = AVMEDIA_TYPE_AUDIO, + .p.id = AV_CODEC_ID_RKA, + .priv_data_size = sizeof(RKAContext), + .init = rka_decode_init, + .close = rka_decode_close, + FF_CODEC_DECODE_CB(rka_decode_frame), + .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, + .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, +}; -- 2.39.1 [-- Attachment #4: Type: text/plain, Size: 251 bytes --] _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [FFmpeg-devel] [PATCH] RK Audio demuxer and decoder 2023-02-05 19:17 ` [FFmpeg-devel] [PATCH] " Paul B Mahol @ 2023-02-10 18:13 ` Paul B Mahol 2023-02-15 11:59 ` James Almer 1 sibling, 0 replies; 4+ messages in thread From: Paul B Mahol @ 2023-02-10 18:13 UTC (permalink / raw) To: FFmpeg development discussions and patches will apply _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". ^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [FFmpeg-devel] [PATCH] RK Audio demuxer and decoder 2023-02-05 19:17 ` [FFmpeg-devel] [PATCH] " Paul B Mahol 2023-02-10 18:13 ` Paul B Mahol @ 2023-02-15 11:59 ` James Almer 1 sibling, 0 replies; 4+ messages in thread From: James Almer @ 2023-02-15 11:59 UTC (permalink / raw) To: ffmpeg-devel On 2/5/2023 4:17 PM, Paul B Mahol wrote: > On 2/4/23, Paul B Mahol <onemda@gmail.com> wrote: >> Hi, >> >> Patches attached, decoder is not bit by bit exact yet for lossless >> mode because some samples are not properly rounded. >> > > Now lossless mode is bit exact. [...] > +static av_cold int rka_decode_init(AVCodecContext *avctx) > +{ > + RKAContext *s = avctx->priv_data; > + int cmode; > + > + if (avctx->extradata_size < 16) > + return AVERROR_INVALIDDATA; > + > + s->bps = avctx->bits_per_raw_sample = avctx->extradata[13]; > + > + switch (s->bps) { > + case 8: > + avctx->sample_fmt = AV_SAMPLE_FMT_U8P; > + break; > + case 16: > + avctx->sample_fmt = AV_SAMPLE_FMT_S16P; > + break; > + default: > + return AVERROR_INVALIDDATA; > + } > + > + s->channels = avctx->ch_layout.nb_channels; You're ignoring the channels reported by the extradata despite flagging this decoder as AV_CODEC_CAP_CHANNEL_CONF. It should be the other way around, and ignore the user set layout, if any, with av_channel_layout_uninit(&avctx->ch_layout); s->channels = avctx->ch_layout.nb_channels = avctx->extradata[12]; Because the stream may not necessarily come from the lavf demuxer. Extradata presence is required given you check for it above, but the avctx fields could be set to whatever if the source is not the lavf rka demuxer. > + if (s->channels < 1 || s->channels > 2) > + return AVERROR_INVALIDDATA; > + > + s->align = (s->channels * (avctx->bits_per_raw_sample >> 3)); > + s->samples_left = s->total_nb_samples = (AV_RL32(avctx->extradata + 4)) / s->align; > + s->frame_samples = 131072 / s->align; > + s->last_nb_samples = s->total_nb_samples % s->frame_samples; > + > + cmode = avctx->extradata[14] & 0xf; > + if ((avctx->extradata[15] & 4) != 0) > + cmode = -cmode; > + > + s->ch[0].cmode = s->ch[1].cmode = cmode; > + s->ch[0].cmode2 = -s->ch[0].cmode; > + s->ch[1].cmode2 = -s->ch[1].cmode; > + av_log(avctx, AV_LOG_DEBUG, "cmode: %d\n", cmode); > + > + return 0; > +} _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-devel To unsubscribe, visit link above, or email ffmpeg-devel-request@ffmpeg.org with subject "unsubscribe". ^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-02-15 11:59 UTC | newest] Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2023-02-04 9:04 [FFmpeg-devel] [RFC][WIP][PATCH] RK Audio demuxer and decoder Paul B Mahol 2023-02-05 19:17 ` [FFmpeg-devel] [PATCH] " Paul B Mahol 2023-02-10 18:13 ` Paul B Mahol 2023-02-15 11:59 ` James Almer
Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel This inbox may be cloned and mirrored by anyone: git clone --mirror https://master.gitmailbox.com/ffmpegdev/0 ffmpegdev/git/0.git # If you have public-inbox 1.1+ installed, you may # initialize and index your mirror using the following commands: public-inbox-init -V2 ffmpegdev ffmpegdev/ https://master.gitmailbox.com/ffmpegdev \ ffmpegdev@gitmailbox.com public-inbox-index ffmpegdev Example config snippet for mirrors. AGPL code for this site: git clone https://public-inbox.org/public-inbox.git