From: Andrew D'Addesio <[email protected]>
Fully functional range decoder, tested against libopus's entdec.c
Includes opusrac-test in opusrac.c
---
libavcodec/Makefile | 1 +
libavcodec/opusrac.c | 120 ++++++++++++++++++++++++++++++++++++++++++++++++++
libavcodec/opusrac.h | 90 +++++++++++++++++++++++++++++++++++++
3 files changed, 211 insertions(+)
create mode 100644 libavcodec/opusrac.c
create mode 100644 libavcodec/opusrac.h
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index bd6567e..b00f7e8 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -686,6 +686,7 @@ TESTPROGS = cabac
\
golomb \
iirfilter \
rangecoder \
+ opusrac \
TESTOBJS = dctref.o
diff --git a/libavcodec/opusrac.c b/libavcodec/opusrac.c
new file mode 100644
index 0000000..66052fc
--- /dev/null
+++ b/libavcodec/opusrac.c
@@ -0,0 +1,120 @@
+/*
+ * Opus range decoder
+ * Copyright (c) 2012 Andrew D'Addesio
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include "get_bits.h"
+#include "opusrac.h"
+
+void ff_opus_rac_init(OpusRangeCoder *rc, uint8_t *buf, int buf_size)
+{
+ init_get_bits(&rc->gb, buf, buf_size << 3);
+
+ rc->range = 128;
+ rc->value = 127 - get_bits(&rc->gb, 7);
+ rc->total_read_bits = 9;
+ opus_rac_normalize(rc);
+}
+
+#ifdef TEST
+
+#include "libavutil/lfg.h"
+#include "avcodec.h"
+
+#define SIZE 10240
+
+/* Opus context table chosen at random */
+static const uint16_t silk_model_gain_delta[] = {
+ 256, 6, 11, 22, 53, 185, 206, 214, 218, 221, 223, 225, 227, 228, 229,
230,
+ 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245,
246,
+ 247, 248, 249, 250, 251, 252, 253, 254, 255, 256
+};
+
+static void opus_rac_normalize_ref(OpusRangeCoder *rc)
+{
+ while (rc->range <= 1 << 23) {
+ av_dlog(NULL, "--start-- value: %u\n range: %u\n", rc->value,
rc->range);
+ rc->value = ((rc->value << 8) | (255 - get_bits(&rc->gb, 8)))
+ & ((1u<<31)-1);
+ rc->range <<= 8;
+ av_dlog(NULL, "--end-- value: %u\n range: %u\n", rc->value,
rc->range);
+ rc->total_read_bits += 8;
+ }
+}
+
+static void opus_rac_seek_ref(OpusRangeCoder *rc, unsigned int scale,
+ unsigned int plow, unsigned int
phigh,
+ unsigned int ptotal)
+{
+ rc->value -= scale * (ptotal - phigh);
+ rc->range = plow ? scale * (phigh - plow) : rc->range - scale * (ptotal -
phigh);
+ opus_rac_normalize_ref(rc);
+}
+
+
+static unsigned int opus_rac_getsymbol_ref(OpusRangeCoder *rc, const uint16_t
*cdf)
+{
+ unsigned int k, scale, ptotal, psymbol, plow, phigh;
+
+ ptotal = *cdf++;
+
+ scale = rc->range / ptotal;
+ psymbol = rc->value / scale + 1;
+ psymbol = ptotal - FFMIN(psymbol, ptotal);
+
+ for (k = 0; (phigh = cdf[k]) <= psymbol; k++);
+ plow = k ? cdf[k-1] : 0;
+
+ opus_rac_seek_ref(rc, scale, plow, phigh, ptotal);
+
+ return k;
+}
+
+int main(void)
+{
+ AVLFG prng;
+ OpusRangeCoder rac;
+ uint8_t rnd[SIZE];
+ uint8_t ref[SIZE];
+ uint8_t buf[SIZE];
+ int i;
+
+ av_lfg_init(&prng, 1);
+
+ for (i = 0; i < SIZE; i++)
+ rnd[i] = av_lfg_get(&prng);
+
+ ff_opus_rac_init(&rac, rnd, SIZE);
+ for (i = 0; i < SIZE; i++)
+ ref[i] = opus_rac_getsymbol_ref(&rac, silk_model_gain_delta);
+
+ ff_opus_rac_init(&rac, rnd, SIZE);
+ for (i = 0; i < SIZE; i++)
+ buf[i] = opus_rac_getsymbol(&rac, silk_model_gain_delta);
+
+ for (i = 0; i < SIZE; i++) {
+ if (buf[i] != ref[i]) {
+ av_log(NULL, AV_LOG_INFO, "Opus RAC failure. ref: %d, buf: %d, i:
%d\n", ref[i], buf[i], i);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+#endif /* TEST */
diff --git a/libavcodec/opusrac.h b/libavcodec/opusrac.h
new file mode 100644
index 0000000..372b82a
--- /dev/null
+++ b/libavcodec/opusrac.h
@@ -0,0 +1,90 @@
+/*
+ * Opus range decoder
+ * Copyright (c) 2012 Andrew D'Addesio
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVCODEC_OPUSRAC_H
+#define AVCODEC_OPUSRAC_H
+
+#include <stdint.h>
+
+#include "get_bits.h"
+
+typedef struct OpusRangeCoder {
+ GetBitContext gb;
+ unsigned int range;
+ unsigned int value;
+ unsigned int total_read_bits;
+} OpusRangeCoder;
+
+static av_always_inline void opus_rac_normalize(OpusRangeCoder *rc)
+{
+ while (rc->range <= 1 << 23) {
+ rc->value <<= 8;
+ rc->range <<= 8;
+ rc->value |= 255 - get_bits(&rc->gb, 8);
+ rc->total_read_bits += 8;
+ }
+}
+
+static av_always_inline void opus_rac_seek(OpusRangeCoder *rc, unsigned int
scale,
+ unsigned int plow, unsigned int
phigh,
+ unsigned int ptotal)
+{
+ rc->value -= scale * (ptotal - phigh);
+ rc->range = plow ? scale * (phigh - plow) : rc->range - scale * (ptotal -
phigh);
+ opus_rac_normalize(rc);
+}
+
+
+static av_always_inline unsigned int opus_rac_getsymbol(OpusRangeCoder *rc,
const uint16_t *cdf)
+{
+ unsigned int k, scale, ptotal, psymbol, plow, phigh;
+
+ ptotal = *cdf++;
+
+ scale = rc->range / ptotal;
+ psymbol = rc->value / scale + 1;
+ psymbol = ptotal - FFMIN(psymbol, ptotal);
+
+ for (k = 0; (phigh = cdf[k]) <= psymbol; k++);
+ plow = k ? cdf[k-1] : 0;
+
+ opus_rac_seek(rc, scale, plow, phigh, ptotal);
+
+ return k;
+}
+
+static av_always_inline unsigned int opus_rac_p2model(OpusRangeCoder *rc,
unsigned int bits)
+{
+ unsigned int k, scale;
+ scale = rc->range >> bits; // in this case, scale = psymbol
+ k = rc->value < scale; // in this case, k = plow
+
+ if (!k)
+ rc->value -= scale;
+ rc->range = k ? scale : rc->range - scale;
+ opus_rac_normalize(rc);
+
+ return k;
+}
+
+void ff_opus_rac_init(OpusRangeCoder *rc, uint8_t *buf, int buf_size);
+
+#endif /* AVCODEC_OPUSRAC_H */
--
1.7.9.5
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel