Git Inbox Mirror of the ffmpeg-devel mailing list - see https://ffmpeg.org/mailman/listinfo/ffmpeg-devel
 help / color / mirror / Atom feed
* [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder
@ 2022-10-07 20:20 Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 2/9] avcodec/opusenc_psy: Remove unused function parameter Andreas Rheinhardt
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:20 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Write-only since e7d977b446194649aa30f2aacc6c17bce7aeb90b
(and local to ff_opus_rc_enc_end() before that).

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opus_rc.c | 2 --
 libavcodec/opus_rc.h | 3 ---
 2 files changed, 5 deletions(-)

diff --git a/libavcodec/opus_rc.c b/libavcodec/opus_rc.c
index c432eb90c9..2061418e52 100644
--- a/libavcodec/opus_rc.c
+++ b/libavcodec/opus_rc.c
@@ -383,8 +383,6 @@ void ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size)
     rng_bytes = rc->rng_cur - rc->buf;
     memcpy(dst, rc->buf, rng_bytes);
 
-    rc->waste = size*8 - (rc->rb.bytes*8 + rc->rb.cachelen) - rng_bytes*8;
-
     /* Put the rawbits part, if any */
     if (rc->rb.bytes || rc->rb.cachelen) {
         int i, lap;
diff --git a/libavcodec/opus_rc.h b/libavcodec/opus_rc.h
index 627f83229e..1b3cb93a15 100644
--- a/libavcodec/opus_rc.h
+++ b/libavcodec/opus_rc.h
@@ -49,9 +49,6 @@ typedef struct OpusRangeCoder {
     uint8_t *rng_cur;                      /* Current range coded byte */
     int ext;                               /* Awaiting propagation */
     int rem;                               /* Carryout flag */
-
-    /* Encoding stats */
-    int waste;
 } OpusRangeCoder;
 
 /**
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 2/9] avcodec/opusenc_psy: Remove unused function parameter
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 3/9] avcodec/opusenc_psy: Remove unused/write-only context members Andreas Rheinhardt
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opusenc.c     | 2 +-
 libavcodec/opusenc_psy.c | 2 +-
 libavcodec/opusenc_psy.h | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/libavcodec/opusenc.c b/libavcodec/opusenc.c
index 7695e95884..280425c74f 100644
--- a/libavcodec/opusenc.c
+++ b/libavcodec/opusenc.c
@@ -594,7 +594,7 @@ static int opus_encode_frame(AVCodecContext *avctx, AVPacket *avpkt,
     opus_packet_assembler(s, avpkt);
 
     /* Update the psychoacoustic system */
-    ff_opus_psy_postencode_update(&s->psyctx, s->frame, s->rc);
+    ff_opus_psy_postencode_update(&s->psyctx, s->frame);
 
     /* Remove samples from queue and skip if needed */
     ff_af_queue_remove(&s->afq, s->packet.frames*frame_size, &avpkt->pts, &avpkt->duration);
diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c
index 9b11651dbe..94c37fb8b1 100644
--- a/libavcodec/opusenc_psy.c
+++ b/libavcodec/opusenc_psy.c
@@ -479,7 +479,7 @@ int ff_opus_psy_celt_frame_process(OpusPsyContext *s, CeltFrame *f, int index)
     return 0;
 }
 
-void ff_opus_psy_postencode_update(OpusPsyContext *s, CeltFrame *f, OpusRangeCoder *rc)
+void ff_opus_psy_postencode_update(OpusPsyContext *s, CeltFrame *f)
 {
     int i, frame_size = OPUS_BLOCK_SIZE(s->p.framesize);
     int steps_out = s->p.frames*(frame_size/120);
diff --git a/libavcodec/opusenc_psy.h b/libavcodec/opusenc_psy.h
index 67e96b2fa5..ee58b0cdf9 100644
--- a/libavcodec/opusenc_psy.h
+++ b/libavcodec/opusenc_psy.h
@@ -98,7 +98,7 @@ typedef struct OpusPsyContext {
 int  ff_opus_psy_process           (OpusPsyContext *s, OpusPacketInfo *p);
 void ff_opus_psy_celt_frame_init   (OpusPsyContext *s, CeltFrame *f, int index);
 int  ff_opus_psy_celt_frame_process(OpusPsyContext *s, CeltFrame *f, int index);
-void ff_opus_psy_postencode_update (OpusPsyContext *s, CeltFrame *f, OpusRangeCoder *rc);
+void ff_opus_psy_postencode_update (OpusPsyContext *s, CeltFrame *f);
 
 int  ff_opus_psy_init(OpusPsyContext *s, AVCodecContext *avctx,
                       struct FFBufQueue *bufqueue, OpusEncOptions *options);
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 3/9] avcodec/opusenc_psy: Remove unused/write-only context members
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 2/9] avcodec/opusenc_psy: Remove unused function parameter Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 4/9] avcodec/opus: Use prefix for defines Andreas Rheinhardt
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opusenc_psy.c |  5 -----
 libavcodec/opusenc_psy.h | 11 -----------
 2 files changed, 16 deletions(-)

diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c
index 94c37fb8b1..5c768ae68e 100644
--- a/libavcodec/opusenc_psy.c
+++ b/libavcodec/opusenc_psy.c
@@ -470,12 +470,9 @@ int ff_opus_psy_celt_frame_process(OpusPsyContext *s, CeltFrame *f, int index)
 
     if (f->transient != start_transient_flag) {
         f->blocks = f->transient ? OPUS_BLOCK_SIZE(s->p.framesize)/CELT_OVERLAP : 1;
-        s->redo_analysis = 1;
         return 1;
     }
 
-    s->redo_analysis = 0;
-
     return 0;
 }
 
@@ -509,7 +506,6 @@ void ff_opus_psy_postencode_update(OpusPsyContext *s, CeltFrame *f)
 
     s->avg_is_band /= (s->p.frames + 1);
 
-    s->cs_num = 0;
     s->steps_to_process = 0;
     s->buffered_steps -= steps_out;
     s->total_packets_out += s->p.frames;
@@ -521,7 +517,6 @@ av_cold int ff_opus_psy_init(OpusPsyContext *s, AVCodecContext *avctx,
 {
     int i, ch, ret;
 
-    s->redo_analysis = 0;
     s->lambda = 1.0f;
     s->options = options;
     s->avctx = avctx;
diff --git a/libavcodec/opusenc_psy.h b/libavcodec/opusenc_psy.h
index ee58b0cdf9..bc1a88c03d 100644
--- a/libavcodec/opusenc_psy.h
+++ b/libavcodec/opusenc_psy.h
@@ -49,20 +49,12 @@ typedef struct OpusBandExcitation {
     float excitation_init;
 } OpusBandExcitation;
 
-typedef struct PsyChain {
-    int start;
-    int end;
-} PsyChain;
-
 typedef struct OpusPsyContext {
     AVCodecContext *avctx;
     AVFloatDSPContext *dsp;
     struct FFBufQueue *bufqueue;
     OpusEncOptions *options;
 
-    PsyChain cs[128];
-    int cs_num;
-
     OpusBandExcitation ex[OPUS_MAX_CHANNELS][CELT_MAX_BANDS];
     FFBesselFilter bfilter_lo[OPUS_MAX_CHANNELS][CELT_MAX_BANDS];
     FFBesselFilter bfilter_hi[OPUS_MAX_CHANNELS][CELT_MAX_BANDS];
@@ -78,15 +70,12 @@ typedef struct OpusPsyContext {
     DECLARE_ALIGNED(32, float, scratch)[2048];
 
     /* Stats */
-    float rc_waste;
     float avg_is_band;
     int64_t dual_stereo_used;
     int64_t total_packets_out;
 
     /* State */
-    FFBesselFilter lambda_lp;
     OpusPacketInfo p;
-    int redo_analysis;
     int buffered_steps;
     int steps_to_process;
     int eof;
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 4/9] avcodec/opus: Use prefix for defines
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 2/9] avcodec/opusenc_psy: Remove unused function parameter Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 3/9] avcodec/opusenc_psy: Remove unused/write-only context members Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 5/9] avcodec/opus_rc: Don't duplicate define Andreas Rheinhardt
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opus.h       |  6 +++---
 libavcodec/opus_parse.c | 12 ++++++------
 libavcodec/opus_parse.h |  4 ++--
 3 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/libavcodec/opus.h b/libavcodec/opus.h
index 4d061cf5f8..f87b63aaca 100644
--- a/libavcodec/opus.h
+++ b/libavcodec/opus.h
@@ -25,9 +25,9 @@
 
 #include <stdint.h>
 
-#define MAX_FRAME_SIZE               1275
-#define MAX_FRAMES                   48
-#define MAX_PACKET_DUR               5760
+#define OPUS_MAX_FRAME_SIZE          1275
+#define OPUS_MAX_FRAMES                48
+#define OPUS_MAX_PACKET_DUR          5760
 
 #define OPUS_TS_HEADER     0x7FE0        // 0x3ff (11 bits)
 #define OPUS_TS_MASK       0xFFE0        // top 11 bits
diff --git a/libavcodec/opus_parse.c b/libavcodec/opus_parse.c
index 39765c5b79..e922d1f304 100644
--- a/libavcodec/opus_parse.c
+++ b/libavcodec/opus_parse.c
@@ -128,7 +128,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size,
         }
 
         frame_bytes = end - ptr;
-        if (frame_bytes > MAX_FRAME_SIZE)
+        if (frame_bytes > OPUS_MAX_FRAME_SIZE)
             goto fail;
         pkt->frame_offset[0] = ptr - buf;
         pkt->frame_size[0]   = frame_bytes;
@@ -147,7 +147,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size,
         }
 
         frame_bytes = end - ptr;
-        if (frame_bytes & 1 || frame_bytes >> 1 > MAX_FRAME_SIZE)
+        if (frame_bytes & 1 || frame_bytes >> 1 > OPUS_MAX_FRAME_SIZE)
             goto fail;
         pkt->frame_offset[0] = ptr - buf;
         pkt->frame_size[0]   = frame_bytes >> 1;
@@ -177,7 +177,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size,
 
         /* calculate 2nd frame size */
         frame_bytes = end - ptr - pkt->frame_size[0];
-        if (frame_bytes < 0 || frame_bytes > MAX_FRAME_SIZE)
+        if (frame_bytes < 0 || frame_bytes > OPUS_MAX_FRAME_SIZE)
             goto fail;
         pkt->frame_offset[1] = pkt->frame_offset[0] + pkt->frame_size[0];
         pkt->frame_size[1]   = frame_bytes;
@@ -189,7 +189,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size,
         padding          = (i >> 6) & 0x01;
         pkt->vbr         = (i >> 7) & 0x01;
 
-        if (pkt->frame_count == 0 || pkt->frame_count > MAX_FRAMES)
+        if (pkt->frame_count == 0 || pkt->frame_count > OPUS_MAX_FRAMES)
             goto fail;
 
         /* read padding size */
@@ -239,7 +239,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size,
             } else {
                 frame_bytes = end - ptr - padding;
                 if (frame_bytes % pkt->frame_count ||
-                    frame_bytes / pkt->frame_count > MAX_FRAME_SIZE)
+                    frame_bytes / pkt->frame_count > OPUS_MAX_FRAME_SIZE)
                     goto fail;
                 frame_bytes /= pkt->frame_count;
             }
@@ -258,7 +258,7 @@ int ff_opus_parse_packet(OpusPacket *pkt, const uint8_t *buf, int buf_size,
 
     /* total packet duration cannot be larger than 120ms */
     pkt->frame_duration = opus_frame_duration[pkt->config];
-    if (pkt->frame_duration * pkt->frame_count > MAX_PACKET_DUR)
+    if (pkt->frame_duration * pkt->frame_count > OPUS_MAX_PACKET_DUR)
         goto fail;
 
     /* set mode and bandwidth */
diff --git a/libavcodec/opus_parse.h b/libavcodec/opus_parse.h
index 8e5c6a880c..83ed3c7887 100644
--- a/libavcodec/opus_parse.h
+++ b/libavcodec/opus_parse.h
@@ -37,8 +37,8 @@ typedef struct OpusPacket {
     int config;                     /**< configuration: tells the audio mode,
                                      **                bandwidth, and frame duration */
     int frame_count;                /**< frame count */
-    int frame_offset[MAX_FRAMES];   /**< frame offsets */
-    int frame_size[MAX_FRAMES];     /**< frame sizes */
+    int frame_offset[OPUS_MAX_FRAMES]; /**< frame offsets */
+    int frame_size[OPUS_MAX_FRAMES]; /**< frame sizes */
     int frame_duration;             /**< frame duration, in samples @ 48kHz */
     enum OpusMode mode;             /**< mode */
     enum OpusBandwidth bandwidth;   /**< bandwidth */
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 5/9] avcodec/opus_rc: Don't duplicate define
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
                   ` (2 preceding siblings ...)
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 4/9] avcodec/opus: Use prefix for defines Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 6/9] avcodec/opus_pvq: Don't build ppp_pvq_search_c when unused Andreas Rheinhardt
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opus_rc.c     | 4 ++--
 libavcodec/opus_rc.h     | 5 ++---
 libavcodec/opusenc_psy.c | 2 +-
 3 files changed, 5 insertions(+), 6 deletions(-)

diff --git a/libavcodec/opus_rc.c b/libavcodec/opus_rc.c
index 2061418e52..1a26d889b7 100644
--- a/libavcodec/opus_rc.c
+++ b/libavcodec/opus_rc.c
@@ -388,7 +388,7 @@ void ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size)
         int i, lap;
         uint8_t *rb_src, *rb_dst;
         ff_opus_rc_put_raw(rc, 0, 32 - rc->rb.cachelen);
-        rb_src = rc->buf + OPUS_MAX_PACKET_SIZE + 12 - rc->rb.bytes;
+        rb_src = rc->buf + OPUS_MAX_FRAME_SIZE + 12 - rc->rb.bytes;
         rb_dst = dst + FFMAX(size - rc->rb.bytes, 0);
         lap = &dst[rng_bytes] - rb_dst;
         for (i = 0; i < lap; i++)
@@ -405,5 +405,5 @@ void ff_opus_rc_enc_init(OpusRangeCoder *rc)
     rc->rem = -1;
     rc->ext =  0;
     rc->rng_cur = rc->buf;
-    ff_opus_rc_dec_raw_init(rc, rc->buf + OPUS_MAX_PACKET_SIZE + 8, 0);
+    ff_opus_rc_dec_raw_init(rc, rc->buf + OPUS_MAX_FRAME_SIZE + 8, 0);
 }
diff --git a/libavcodec/opus_rc.h b/libavcodec/opus_rc.h
index 1b3cb93a15..72e683b075 100644
--- a/libavcodec/opus_rc.h
+++ b/libavcodec/opus_rc.h
@@ -25,8 +25,7 @@
 
 #include <stdint.h>
 #include "get_bits.h"
-
-#define OPUS_MAX_PACKET_SIZE 1275
+#include "opus.h"
 
 #define opus_ilog(i) (av_log2(i) + !!(i))
 
@@ -45,7 +44,7 @@ typedef struct OpusRangeCoder {
     uint32_t total_bits;
 
     /* Encoder */
-    uint8_t buf[OPUS_MAX_PACKET_SIZE + 12]; /* memcpy vs (memmove + overreading) */
+    uint8_t buf[OPUS_MAX_FRAME_SIZE + 12]; /* memcpy vs (memmove + overreading) */
     uint8_t *rng_cur;                      /* Current range coded byte */
     int ext;                               /* Awaiting propagation */
     int rem;                               /* Carryout flag */
diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c
index 5c768ae68e..48ccd2ebd0 100644
--- a/libavcodec/opusenc_psy.c
+++ b/libavcodec/opusenc_psy.c
@@ -359,7 +359,7 @@ static void celt_gauge_psy_weight(OpusPsyContext *s, OpusPsyStep **start,
     rate /= s->avctx->sample_rate/frame_size;
 
     f_out->framebits = lrintf(rate);
-    f_out->framebits = FFMIN(f_out->framebits, OPUS_MAX_PACKET_SIZE*8);
+    f_out->framebits = FFMIN(f_out->framebits, OPUS_MAX_FRAME_SIZE * 8);
     f_out->framebits = FFALIGN(f_out->framebits, 8);
 }
 
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 6/9] avcodec/opus_pvq: Don't build ppp_pvq_search_c when unused
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
                   ` (3 preceding siblings ...)
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 5/9] avcodec/opus_rc: Don't duplicate define Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 7/9] avcodec/opus_rc: Split de/encoder-only parts off OpusRangeContext Andreas Rheinhardt
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opus_pvq.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c
index 79101847af..d08dcd7413 100644
--- a/libavcodec/opus_pvq.c
+++ b/libavcodec/opus_pvq.c
@@ -366,6 +366,7 @@ static inline float celt_decode_pulses(OpusRangeCoder *rc, int *y, uint32_t N, u
     return celt_cwrsi(N, K, idx, y);
 }
 
+#if CONFIG_OPUS_ENCODER
 /*
  * Faster than libopus's search, operates entirely in the signed domain.
  * Slightly worse/better depending on N, K and the input vector.
@@ -418,6 +419,7 @@ static float ppp_pvq_search_c(float *X, int *y, int K, int N)
 
     return (float)y_norm;
 }
+#endif
 
 static uint32_t celt_alg_quant(OpusRangeCoder *rc, float *X, uint32_t N, uint32_t K,
                                enum CeltSpread spread, uint32_t blocks, float gain,
@@ -907,11 +909,13 @@ int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode)
     if (!s)
         return AVERROR(ENOMEM);
 
-    s->pvq_search = ppp_pvq_search_c;
     s->quant_band = encode ? pvq_encode_band : pvq_decode_band;
 
-#if CONFIG_OPUS_ENCODER && ARCH_X86
+#if CONFIG_OPUS_ENCODER
+    s->pvq_search = ppp_pvq_search_c;
+#if ARCH_X86
     ff_celt_pvq_init_x86(s);
+#endif
 #endif
 
     *pvq = s;
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 7/9] avcodec/opus_rc: Split de/encoder-only parts off OpusRangeContext
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
                   ` (4 preceding siblings ...)
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 6/9] avcodec/opus_pvq: Don't build ppp_pvq_search_c when unused Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 8/9] avcodec/opus: Rename opus.c->opus_celt.c, opus_celt.c->opusdec_celt.c Andreas Rheinhardt
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

The decoder currently only uses 72 bytes of 1376; furthermore,
the GetBitContext in OpusRangeCoder is unused by the encoder,
but its existence adds an unnecessary inclusion of get_bits.h
to the encoder-only files. So split OpusRangeContext;
also split opus_rc.c into an encoder- and a decoder-only part.

This necessitated trivial changes in several other files.
The only part where the changes where these changes were involved
was opus_pvq.c, where the quant_band functions are now defined
in a template file instead of being created via an av_always_inline
function.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/Makefile            |   8 +-
 libavcodec/opus.c              |  62 ++++-
 libavcodec/opus_celt.c         |  39 +--
 libavcodec/opus_celt.h         |   3 +-
 libavcodec/opus_pvq.c          | 456 +++------------------------------
 libavcodec/opus_pvq_template.c | 432 +++++++++++++++++++++++++++++++
 libavcodec/opus_rc.c           | 409 -----------------------------
 libavcodec/opus_rc.h           |  66 ++---
 libavcodec/opus_silk.c         |  11 +-
 libavcodec/opus_silk.h         |   4 +-
 libavcodec/opusdec.c           |  11 +-
 libavcodec/opusdec_rc.c        | 214 ++++++++++++++++
 libavcodec/opusdec_rc.h        |  53 ++++
 libavcodec/opusenc.c           |  39 +--
 libavcodec/opusenc_psy.c       |  14 +-
 libavcodec/opusenc_psy.h       |   1 +
 libavcodec/opusenc_rc.c        | 210 +++++++++++++++
 libavcodec/opusenc_rc.h        |  64 +++++
 18 files changed, 1139 insertions(+), 957 deletions(-)
 create mode 100644 libavcodec/opus_pvq_template.c
 delete mode 100644 libavcodec/opus_rc.c
 create mode 100644 libavcodec/opusdec_rc.c
 create mode 100644 libavcodec/opusdec_rc.h
 create mode 100644 libavcodec/opusenc_rc.c
 create mode 100644 libavcodec/opusenc_rc.h

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 592d9347f6..b7eb3b1e48 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -554,11 +554,11 @@ OBJS-$(CONFIG_NELLYMOSER_ENCODER)      += nellymoserenc.o nellymoser.o
 OBJS-$(CONFIG_NOTCHLC_DECODER)         += notchlc.o
 OBJS-$(CONFIG_NUV_DECODER)             += nuv.o rtjpeg.o
 OBJS-$(CONFIG_ON2AVC_DECODER)          += on2avc.o on2avcdata.o
-OBJS-$(CONFIG_OPUS_DECODER)            += opusdec.o opus.o opus_celt.o opus_rc.o \
+OBJS-$(CONFIG_OPUS_DECODER)            += opusdec.o opus.o opus_celt.o \
                                           opus_pvq.o opus_silk.o opustab.o vorbis_data.o \
-                                          opusdsp.o opus_parse.o
-OBJS-$(CONFIG_OPUS_ENCODER)            += opusenc.o opus.o opus_rc.o opustab.o opus_pvq.o \
-                                          opusenc_psy.o
+                                          opusdec_rc.o opusdsp.o opus_parse.o
+OBJS-$(CONFIG_OPUS_ENCODER)            += opusenc.o opus.o opusenc_psy.o \
+                                          opusenc_rc.o opustab.o opus_pvq.o
 OBJS-$(CONFIG_PAF_AUDIO_DECODER)       += pafaudio.o
 OBJS-$(CONFIG_PAF_VIDEO_DECODER)       += pafvideo.o
 OBJS-$(CONFIG_PAM_DECODER)             += pnmdec.o pnm.o
diff --git a/libavcodec/opus.c b/libavcodec/opus.c
index a24c38be52..8def5e6e34 100644
--- a/libavcodec/opus.c
+++ b/libavcodec/opus.c
@@ -21,9 +21,45 @@
 
 #include <stdint.h>
 
+#include "config_components.h"
 #include "opus_celt.h"
 #include "opus_pvq.h"
 #include "opustab.h"
+#include "opus_rc.h"
+#include "opusdec_rc.h"
+#include "opusenc_rc.h"
+
+#if !CONFIG_OPUS_ENCODER
+#define ff_opus_rc_enc_log(...)
+#define ff_opus_rc_enc_cdf(...)
+#define ff_opus_rc_enc_uint(...)
+#endif
+
+#if !CONFIG_OPUS_DECODER
+#define ff_opus_rc_dec_log(...) 0
+#define ff_opus_rc_dec_cdf(...) 0
+#define ff_opus_rc_dec_uint(...) 0
+#endif
+
+static inline void opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits)
+{
+    ff_opus_rc_enc_log((OpusEncRangeCoder*)rc, val, bits);
+}
+
+static inline uint32_t opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits)
+{
+    return ff_opus_rc_dec_log((OpusDecRangeCoder*)rc, bits);
+}
+
+static inline void opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf)
+{
+    ff_opus_rc_enc_cdf((OpusEncRangeCoder*)rc, val, cdf);
+}
+
+static inline uint32_t opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf)
+{
+    return ff_opus_rc_dec_cdf((OpusDecRangeCoder*)rc, cdf);
+}
 
 void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc)
 {
@@ -150,12 +186,14 @@ void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
     int bits1[CELT_MAX_BANDS];
     int bits2[CELT_MAX_BANDS];
 
+    if (!CONFIG_OPUS_DECODER || !CONFIG_OPUS_ENCODER)
+        encode = CONFIG_OPUS_ENCODER;
     /* Spread */
     if (opus_rc_tell(rc) + 4 <= f->framebits) {
         if (encode)
-            ff_opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread);
+            opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread);
         else
-            f->spread = ff_opus_rc_dec_cdf(rc, ff_celt_model_spread);
+            f->spread = opus_rc_dec_cdf(rc, ff_celt_model_spread);
     } else {
         f->spread = CELT_SPREAD_NORMAL;
     }
@@ -176,9 +214,9 @@ void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
             int is_boost;
             if (encode) {
                 is_boost = boost_amount--;
-                ff_opus_rc_enc_log(rc, is_boost, b_dynalloc);
+                opus_rc_enc_log(rc, is_boost, b_dynalloc);
             } else {
-                is_boost = ff_opus_rc_dec_log(rc, b_dynalloc);
+                is_boost = opus_rc_dec_log(rc, b_dynalloc);
             }
 
             if (!is_boost)
@@ -199,9 +237,9 @@ void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
         f->alloc_trim = 5;
     if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths)
         if (encode)
-            ff_opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim);
+            opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim);
         else
-            f->alloc_trim = ff_opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim);
+            f->alloc_trim = opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim);
 
     /* Anti-collapse bit reservation */
     tbits_8ths = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1;
@@ -358,9 +396,9 @@ void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
             int do_not_skip;
             if (encode) {
                 do_not_skip = f->coded_bands <= f->skip_band_floor;
-                ff_opus_rc_enc_log(rc, do_not_skip, 1);
+                opus_rc_enc_log(rc, do_not_skip, 1);
             } else {
-                do_not_skip = ff_opus_rc_dec_log(rc, 1);
+                do_not_skip = opus_rc_dec_log(rc, 1);
             }
 
             if (do_not_skip)
@@ -385,12 +423,12 @@ void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
     if (encode) {
         if (intensitystereo_bit) {
             f->intensity_stereo = FFMIN(f->intensity_stereo, f->coded_bands);
-            ff_opus_rc_enc_uint(rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band);
+            ff_opus_rc_enc_uint((OpusEncRangeCoder*)rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band);
         }
     } else {
         f->intensity_stereo = f->dual_stereo = 0;
         if (intensitystereo_bit)
-            f->intensity_stereo = f->start_band + ff_opus_rc_dec_uint(rc, f->coded_bands + 1 - f->start_band);
+            f->intensity_stereo = f->start_band + ff_opus_rc_dec_uint((OpusDecRangeCoder*)rc, f->coded_bands + 1 - f->start_band);
     }
 
     /* DS flag */
@@ -398,9 +436,9 @@ void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
         tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */
     else if (dualstereo_bit)
         if (encode)
-            ff_opus_rc_enc_log(rc, f->dual_stereo, 1);
+            opus_rc_enc_log(rc, f->dual_stereo, 1);
         else
-            f->dual_stereo = ff_opus_rc_dec_log(rc, 1);
+            f->dual_stereo = opus_rc_dec_log(rc, 1);
 
     /* Supply the remaining bits in this frame to lower bands */
     remaining = tbits_8ths - total;
diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c
index c2904cc9e0..a14764ec18 100644
--- a/libavcodec/opus_celt.c
+++ b/libavcodec/opus_celt.c
@@ -28,12 +28,13 @@
 #include <float.h>
 
 #include "opus_celt.h"
+#include "opusdec_rc.h"
 #include "opustab.h"
 #include "opus_pvq.h"
 
 /* Use the 2D z-transform to apply prediction in both the time domain (alpha)
  * and the frequency domain (beta) */
-static void celt_decode_coarse_energy(CeltFrame *f, OpusRangeCoder *rc)
+static void celt_decode_coarse_energy(CeltFrame *f, OpusDecRangeCoder *rc)
 {
     int i, j;
     float prev[2] = { 0 };
@@ -42,7 +43,7 @@ static void celt_decode_coarse_energy(CeltFrame *f, OpusRangeCoder *rc)
     const uint8_t *model = ff_celt_coarse_energy_dist[f->size][0];
 
     /* intra frame */
-    if (opus_rc_tell(rc) + 3 <= f->framebits && ff_opus_rc_dec_log(rc, 3)) {
+    if (opus_rc_tell(&rc->c) + 3 <= f->framebits && ff_opus_rc_dec_log(rc, 3)) {
         alpha = 0.0f;
         beta  = 1.0f - (4915.0f/32768.0f);
         model = ff_celt_coarse_energy_dist[f->size][1];
@@ -59,7 +60,7 @@ static void celt_decode_coarse_energy(CeltFrame *f, OpusRangeCoder *rc)
                 continue;
             }
 
-            available = f->framebits - opus_rc_tell(rc);
+            available = f->framebits - opus_rc_tell(&rc->c);
             if (available >= 15) {
                 /* decode using a Laplace distribution */
                 int k = FFMIN(i, 20) << 1;
@@ -77,7 +78,7 @@ static void celt_decode_coarse_energy(CeltFrame *f, OpusRangeCoder *rc)
     }
 }
 
-static void celt_decode_fine_energy(CeltFrame *f, OpusRangeCoder *rc)
+static void celt_decode_fine_energy(CeltFrame *f, OpusDecRangeCoder *rc)
 {
     int i;
     for (i = f->start_band; i < f->end_band; i++) {
@@ -96,10 +97,10 @@ static void celt_decode_fine_energy(CeltFrame *f, OpusRangeCoder *rc)
     }
 }
 
-static void celt_decode_final_energy(CeltFrame *f, OpusRangeCoder *rc)
+static void celt_decode_final_energy(CeltFrame *f, OpusDecRangeCoder *rc)
 {
     int priority, i, j;
-    int bits_left = f->framebits - opus_rc_tell(rc);
+    int bits_left = f->framebits - opus_rc_tell(&rc->c);
 
     for (priority = 0; priority < 2; priority++) {
         for (i = f->start_band; i < f->end_band && bits_left >= f->channels; i++) {
@@ -118,18 +119,18 @@ static void celt_decode_final_energy(CeltFrame *f, OpusRangeCoder *rc)
     }
 }
 
-static void celt_decode_tf_changes(CeltFrame *f, OpusRangeCoder *rc)
+static void celt_decode_tf_changes(CeltFrame *f, OpusDecRangeCoder *rc)
 {
     int i, diff = 0, tf_select = 0, tf_changed = 0, tf_select_bit;
     int consumed, bits = f->transient ? 2 : 4;
 
-    consumed = opus_rc_tell(rc);
+    consumed = opus_rc_tell(&rc->c);
     tf_select_bit = (f->size != 0 && consumed+bits+1 <= f->framebits);
 
     for (i = f->start_band; i < f->end_band; i++) {
         if (consumed+bits+tf_select_bit <= f->framebits) {
             diff ^= ff_opus_rc_dec_log(rc, bits);
-            consumed = opus_rc_tell(rc);
+            consumed = opus_rc_tell(&rc->c);
             tf_changed |= diff;
         }
         f->tf_change[i] = diff;
@@ -232,7 +233,7 @@ static void celt_postfilter(CeltFrame *f, CeltBlock *block)
     memmove(block->buf, block->buf + len, (1024 + CELT_OVERLAP / 2) * sizeof(float));
 }
 
-static int parse_postfilter(CeltFrame *f, OpusRangeCoder *rc, int consumed)
+static int parse_postfilter(CeltFrame *f, OpusDecRangeCoder *rc, int consumed)
 {
     int i;
 
@@ -248,7 +249,7 @@ static int parse_postfilter(CeltFrame *f, OpusRangeCoder *rc, int consumed)
             octave = ff_opus_rc_dec_uint(rc, 6);
             period = (16 << octave) + ff_opus_rc_get_raw(rc, 4 + octave) - 1;
             gain   = 0.09375f * (ff_opus_rc_get_raw(rc, 3) + 1);
-            tapset = (opus_rc_tell(rc) + 2 <= f->framebits) ?
+            tapset = (opus_rc_tell(&rc->c) + 2 <= f->framebits) ?
                      ff_opus_rc_dec_cdf(rc, ff_celt_model_tapset) : 0;
 
             for (i = 0; i < 2; i++) {
@@ -261,7 +262,7 @@ static int parse_postfilter(CeltFrame *f, OpusRangeCoder *rc, int consumed)
             }
         }
 
-        consumed = opus_rc_tell(rc);
+        consumed = opus_rc_tell(&rc->c);
     }
 
     return consumed;
@@ -319,7 +320,7 @@ static void process_anticollapse(CeltFrame *f, CeltBlock *block, float *X)
     }
 }
 
-int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
+int ff_celt_decode_frame(CeltFrame *f, OpusDecRangeCoder *rc,
                          float **output, int channels, int frame_size,
                          int start_band,  int end_band)
 {
@@ -346,7 +347,7 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
     f->channels       = channels;
     f->start_band     = start_band;
     f->end_band       = end_band;
-    f->framebits      = rc->rb.bytes * 8;
+    f->framebits      = rc->c.rb.bytes * 8;
 
     f->size = av_log2(frame_size / CELT_SHORT_BLOCKSIZE);
     if (f->size > CELT_MAX_LOG_BLOCKS ||
@@ -364,7 +365,7 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
         memset(f->block[i].collapse_masks, 0, sizeof(f->block[i].collapse_masks));
     }
 
-    consumed = opus_rc_tell(rc);
+    consumed = opus_rc_tell(&rc->c);
 
     /* obtain silence flag */
     if (consumed >= f->framebits)
@@ -375,7 +376,7 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
 
     if (f->silence) {
         consumed = f->framebits;
-        rc->total_bits += f->framebits - opus_rc_tell(rc);
+        rc->c.total_bits += f->framebits - opus_rc_tell(&rc->c);
     }
 
     /* obtain post-filter options */
@@ -398,9 +399,9 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
 
     celt_decode_coarse_energy(f, rc);
     celt_decode_tf_changes   (f, rc);
-    ff_celt_bitalloc         (f, rc, 0);
+    ff_celt_bitalloc         (f, &rc->c, 0);
     celt_decode_fine_energy  (f, rc);
-    ff_celt_quant_bands      (f, rc);
+    ff_celt_quant_bands      (f, &rc->c);
 
     if (f->anticollapse_needed)
         f->anticollapse = ff_opus_rc_get_raw(rc, 1);
@@ -486,7 +487,7 @@ int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc,
         }
     }
 
-    f->seed = rc->range;
+    f->seed = rc->c.range;
 
     return 0;
 }
diff --git a/libavcodec/opus_celt.h b/libavcodec/opus_celt.h
index 2dbb79be6c..beb6abd55d 100644
--- a/libavcodec/opus_celt.h
+++ b/libavcodec/opus_celt.h
@@ -171,7 +171,8 @@ void ff_celt_free(CeltFrame **f);
 
 void ff_celt_flush(CeltFrame *f);
 
-int ff_celt_decode_frame(CeltFrame *f, OpusRangeCoder *rc, float **output,
+struct OpusDecRangeCoder;
+int ff_celt_decode_frame(CeltFrame *f, struct OpusDecRangeCoder *rc, float **output,
                          int coded_channels, int frame_size, int startband, int endband);
 
 /* Encode or decode CELT bands */
diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c
index d08dcd7413..8ef0f85a81 100644
--- a/libavcodec/opus_pvq.c
+++ b/libavcodec/opus_pvq.c
@@ -30,6 +30,9 @@
 #include "mathops.h"
 #include "opustab.h"
 #include "opus_pvq.h"
+#include "opus_rc.h"
+#include "opusdec_rc.h"
+#include "opusenc_rc.h"
 
 #define ROUND_MUL16(a,b)  ((MUL16(a, b) + 16384) >> 15)
 
@@ -355,18 +358,12 @@ static inline uint64_t celt_cwrsi(uint32_t N, uint32_t K, uint32_t i, int *y)
     return norm;
 }
 
-static inline void celt_encode_pulses(OpusRangeCoder *rc, int *y, uint32_t N, uint32_t K)
+#if CONFIG_OPUS_ENCODER
+static inline void celt_encode_pulses(OpusEncRangeCoder *rc, int *y, uint32_t N, uint32_t K)
 {
     ff_opus_rc_enc_uint(rc, celt_icwrsi(N, K, y), CELT_PVQ_V(N, K));
 }
 
-static inline float celt_decode_pulses(OpusRangeCoder *rc, int *y, uint32_t N, uint32_t K)
-{
-    const uint32_t idx = ff_opus_rc_dec_uint(rc, CELT_PVQ_V(N, K));
-    return celt_cwrsi(N, K, idx, y);
-}
-
-#if CONFIG_OPUS_ENCODER
 /*
  * Faster than libopus's search, operates entirely in the signed domain.
  * Slightly worse/better depending on N, K and the input vector.
@@ -419,9 +416,8 @@ static float ppp_pvq_search_c(float *X, int *y, int K, int N)
 
     return (float)y_norm;
 }
-#endif
 
-static uint32_t celt_alg_quant(OpusRangeCoder *rc, float *X, uint32_t N, uint32_t K,
+static uint32_t celt_alg_quant(OpusEncRangeCoder *rc, float *X, uint32_t N, uint32_t K,
                                enum CeltSpread spread, uint32_t blocks, float gain,
                                CeltPVQ *pvq)
 {
@@ -434,10 +430,18 @@ static uint32_t celt_alg_quant(OpusRangeCoder *rc, float *X, uint32_t N, uint32_
     celt_exp_rotation(X, N, blocks, K, spread, 0);
     return celt_extract_collapse_mask(y, N, blocks);
 }
+#endif
+
+#if CONFIG_OPUS_DECODER
+static inline float celt_decode_pulses(OpusDecRangeCoder *rc, int *y, uint32_t N, uint32_t K)
+{
+    const uint32_t idx = ff_opus_rc_dec_uint(rc, CELT_PVQ_V(N, K));
+    return celt_cwrsi(N, K, idx, y);
+}
 
 /** Decode pulse vector and combine the result with the pitch vector to produce
     the final normalised signal in the current band. */
-static uint32_t celt_alg_unquant(OpusRangeCoder *rc, float *X, uint32_t N, uint32_t K,
+static uint32_t celt_alg_unquant(OpusDecRangeCoder *rc, float *X, uint32_t N, uint32_t K,
                                  enum CeltSpread spread, uint32_t blocks, float gain,
                                  CeltPVQ *pvq)
 {
@@ -448,6 +452,7 @@ static uint32_t celt_alg_unquant(OpusRangeCoder *rc, float *X, uint32_t N, uint3
     celt_exp_rotation(X, N, blocks, K, spread, 0);
     return celt_extract_collapse_mask(y, N, blocks);
 }
+#endif
 
 static int celt_calc_theta(const float *X, const float *Y, int coupling, int N)
 {
@@ -467,6 +472,7 @@ static int celt_calc_theta(const float *X, const float *Y, int coupling, int N)
     return lrintf(32768.0f*atan2f(sqrtf(e[1]), sqrtf(e[0]))/M_PI);
 }
 
+#if CONFIG_OPUS_ENCODER
 static void celt_stereo_is_decouple(float *X, float *Y, float e_l, float e_r, int N)
 {
     int i;
@@ -487,421 +493,15 @@ static void celt_stereo_ms_decouple(float *X, float *Y, int N)
     }
 }
 
-static av_always_inline uint32_t quant_band_template(CeltPVQ *pvq, CeltFrame *f,
-                                                     OpusRangeCoder *rc,
-                                                     const int band, float *X,
-                                                     float *Y, int N, int b,
-                                                     uint32_t blocks, float *lowband,
-                                                     int duration, float *lowband_out,
-                                                     int level, float gain,
-                                                     float *lowband_scratch,
-                                                     int fill, int quant)
-{
-    int i;
-    const uint8_t *cache;
-    int stereo = !!Y, split = stereo;
-    int imid = 0, iside = 0;
-    uint32_t N0 = N;
-    int N_B = N / blocks;
-    int N_B0 = N_B;
-    int B0 = blocks;
-    int time_divide = 0;
-    int recombine = 0;
-    int inv = 0;
-    float mid = 0, side = 0;
-    int longblocks = (B0 == 1);
-    uint32_t cm = 0;
-
-    if (N == 1) {
-        float *x = X;
-        for (i = 0; i <= stereo; i++) {
-            int sign = 0;
-            if (f->remaining2 >= 1 << 3) {
-                if (quant) {
-                    sign = x[0] < 0;
-                    ff_opus_rc_put_raw(rc, sign, 1);
-                } else {
-                    sign = ff_opus_rc_get_raw(rc, 1);
-                }
-                f->remaining2 -= 1 << 3;
-            }
-            x[0] = 1.0f - 2.0f*sign;
-            x = Y;
-        }
-        if (lowband_out)
-            lowband_out[0] = X[0];
-        return 1;
-    }
-
-    if (!stereo && level == 0) {
-        int tf_change = f->tf_change[band];
-        int k;
-        if (tf_change > 0)
-            recombine = tf_change;
-        /* Band recombining to increase frequency resolution */
-
-        if (lowband &&
-            (recombine || ((N_B & 1) == 0 && tf_change < 0) || B0 > 1)) {
-            for (i = 0; i < N; i++)
-                lowband_scratch[i] = lowband[i];
-            lowband = lowband_scratch;
-        }
-
-        for (k = 0; k < recombine; k++) {
-            if (quant || lowband)
-                celt_haar1(quant ? X : lowband, N >> k, 1 << k);
-            fill = ff_celt_bit_interleave[fill & 0xF] | ff_celt_bit_interleave[fill >> 4] << 2;
-        }
-        blocks >>= recombine;
-        N_B <<= recombine;
-
-        /* Increasing the time resolution */
-        while ((N_B & 1) == 0 && tf_change < 0) {
-            if (quant || lowband)
-                celt_haar1(quant ? X : lowband, N_B, blocks);
-            fill |= fill << blocks;
-            blocks <<= 1;
-            N_B >>= 1;
-            time_divide++;
-            tf_change++;
-        }
-        B0 = blocks;
-        N_B0 = N_B;
-
-        /* Reorganize the samples in time order instead of frequency order */
-        if (B0 > 1 && (quant || lowband))
-            celt_deinterleave_hadamard(pvq->hadamard_tmp, quant ? X : lowband,
-                                       N_B >> recombine, B0 << recombine,
-                                       longblocks);
-    }
-
-    /* If we need 1.5 more bit than we can produce, split the band in two. */
-    cache = ff_celt_cache_bits +
-            ff_celt_cache_index[(duration + 1) * CELT_MAX_BANDS + band];
-    if (!stereo && duration >= 0 && b > cache[cache[0]] + 12 && N > 2) {
-        N >>= 1;
-        Y = X + N;
-        split = 1;
-        duration -= 1;
-        if (blocks == 1)
-            fill = (fill & 1) | (fill << 1);
-        blocks = (blocks + 1) >> 1;
-    }
-
-    if (split) {
-        int qn;
-        int itheta = quant ? celt_calc_theta(X, Y, stereo, N) : 0;
-        int mbits, sbits, delta;
-        int qalloc;
-        int pulse_cap;
-        int offset;
-        int orig_fill;
-        int tell;
-
-        /* Decide on the resolution to give to the split parameter theta */
-        pulse_cap = ff_celt_log_freq_range[band] + duration * 8;
-        offset = (pulse_cap >> 1) - (stereo && N == 2 ? CELT_QTHETA_OFFSET_TWOPHASE :
-                                                          CELT_QTHETA_OFFSET);
-        qn = (stereo && band >= f->intensity_stereo) ? 1 :
-             celt_compute_qn(N, b, offset, pulse_cap, stereo);
-        tell = opus_rc_tell_frac(rc);
-        if (qn != 1) {
-            if (quant)
-                itheta = (itheta*qn + 8192) >> 14;
-            /* Entropy coding of the angle. We use a uniform pdf for the
-             * time split, a step for stereo, and a triangular one for the rest. */
-            if (quant) {
-                if (stereo && N > 2)
-                    ff_opus_rc_enc_uint_step(rc, itheta, qn / 2);
-                else if (stereo || B0 > 1)
-                    ff_opus_rc_enc_uint(rc, itheta, qn + 1);
-                else
-                    ff_opus_rc_enc_uint_tri(rc, itheta, qn);
-                itheta = itheta * 16384 / qn;
-                if (stereo) {
-                    if (itheta == 0)
-                        celt_stereo_is_decouple(X, Y, f->block[0].lin_energy[band],
-                                                f->block[1].lin_energy[band], N);
-                    else
-                        celt_stereo_ms_decouple(X, Y, N);
-                }
-            } else {
-                if (stereo && N > 2)
-                    itheta = ff_opus_rc_dec_uint_step(rc, qn / 2);
-                else if (stereo || B0 > 1)
-                    itheta = ff_opus_rc_dec_uint(rc, qn+1);
-                else
-                    itheta = ff_opus_rc_dec_uint_tri(rc, qn);
-                itheta = itheta * 16384 / qn;
-            }
-        } else if (stereo) {
-            if (quant) {
-                inv = f->apply_phase_inv ? itheta > 8192 : 0;
-                 if (inv) {
-                    for (i = 0; i < N; i++)
-                       Y[i] *= -1;
-                 }
-                 celt_stereo_is_decouple(X, Y, f->block[0].lin_energy[band],
-                                         f->block[1].lin_energy[band], N);
-
-                if (b > 2 << 3 && f->remaining2 > 2 << 3) {
-                    ff_opus_rc_enc_log(rc, inv, 2);
-                } else {
-                    inv = 0;
-                }
-            } else {
-                inv = (b > 2 << 3 && f->remaining2 > 2 << 3) ? ff_opus_rc_dec_log(rc, 2) : 0;
-                inv = f->apply_phase_inv ? inv : 0;
-            }
-            itheta = 0;
-        }
-        qalloc = opus_rc_tell_frac(rc) - tell;
-        b -= qalloc;
-
-        orig_fill = fill;
-        if (itheta == 0) {
-            imid = 32767;
-            iside = 0;
-            fill = av_mod_uintp2(fill, blocks);
-            delta = -16384;
-        } else if (itheta == 16384) {
-            imid = 0;
-            iside = 32767;
-            fill &= ((1 << blocks) - 1) << blocks;
-            delta = 16384;
-        } else {
-            imid = celt_cos(itheta);
-            iside = celt_cos(16384-itheta);
-            /* This is the mid vs side allocation that minimizes squared error
-            in that band. */
-            delta = ROUND_MUL16((N - 1) << 7, celt_log2tan(iside, imid));
-        }
-
-        mid  = imid  / 32768.0f;
-        side = iside / 32768.0f;
-
-        /* This is a special case for N=2 that only works for stereo and takes
-        advantage of the fact that mid and side are orthogonal to encode
-        the side with just one bit. */
-        if (N == 2 && stereo) {
-            int c;
-            int sign = 0;
-            float tmp;
-            float *x2, *y2;
-            mbits = b;
-            /* Only need one bit for the side */
-            sbits = (itheta != 0 && itheta != 16384) ? 1 << 3 : 0;
-            mbits -= sbits;
-            c = (itheta > 8192);
-            f->remaining2 -= qalloc+sbits;
-
-            x2 = c ? Y : X;
-            y2 = c ? X : Y;
-            if (sbits) {
-                if (quant) {
-                    sign = x2[0]*y2[1] - x2[1]*y2[0] < 0;
-                    ff_opus_rc_put_raw(rc, sign, 1);
-                } else {
-                    sign = ff_opus_rc_get_raw(rc, 1);
-                }
-            }
-            sign = 1 - 2 * sign;
-            /* We use orig_fill here because we want to fold the side, but if
-            itheta==16384, we'll have cleared the low bits of fill. */
-            cm = pvq->quant_band(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration,
-                                 lowband_out, level, gain, lowband_scratch, orig_fill);
-            /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
-            and there's no need to worry about mixing with the other channel. */
-            y2[0] = -sign * x2[1];
-            y2[1] =  sign * x2[0];
-            X[0] *= mid;
-            X[1] *= mid;
-            Y[0] *= side;
-            Y[1] *= side;
-            tmp = X[0];
-            X[0] = tmp - Y[0];
-            Y[0] = tmp + Y[0];
-            tmp = X[1];
-            X[1] = tmp - Y[1];
-            Y[1] = tmp + Y[1];
-        } else {
-            /* "Normal" split code */
-            float *next_lowband2     = NULL;
-            float *next_lowband_out1 = NULL;
-            int next_level = 0;
-            int rebalance;
-            uint32_t cmt;
-
-            /* Give more bits to low-energy MDCTs than they would
-             * otherwise deserve */
-            if (B0 > 1 && !stereo && (itheta & 0x3fff)) {
-                if (itheta > 8192)
-                    /* Rough approximation for pre-echo masking */
-                    delta -= delta >> (4 - duration);
-                else
-                    /* Corresponds to a forward-masking slope of
-                     * 1.5 dB per 10 ms */
-                    delta = FFMIN(0, delta + (N << 3 >> (5 - duration)));
-            }
-            mbits = av_clip((b - delta) / 2, 0, b);
-            sbits = b - mbits;
-            f->remaining2 -= qalloc;
-
-            if (lowband && !stereo)
-                next_lowband2 = lowband + N; /* >32-bit split case */
-
-            /* Only stereo needs to pass on lowband_out.
-             * Otherwise, it's handled at the end */
-            if (stereo)
-                next_lowband_out1 = lowband_out;
-            else
-                next_level = level + 1;
-
-            rebalance = f->remaining2;
-            if (mbits >= sbits) {
-                /* In stereo mode, we do not apply a scaling to the mid
-                 * because we need the normalized mid for folding later */
-                cm = pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks,
-                                     lowband, duration, next_lowband_out1, next_level,
-                                     stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
-                rebalance = mbits - (rebalance - f->remaining2);
-                if (rebalance > 3 << 3 && itheta != 0)
-                    sbits += rebalance - (3 << 3);
-
-                /* For a stereo split, the high bits of fill are always zero,
-                 * so no folding will be done to the side. */
-                cmt = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
-                                      next_lowband2, duration, NULL, next_level,
-                                      gain * side, NULL, fill >> blocks);
-                cm |= cmt << ((B0 >> 1) & (stereo - 1));
-            } else {
-                /* For a stereo split, the high bits of fill are always zero,
-                 * so no folding will be done to the side. */
-                cm = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
-                                     next_lowband2, duration, NULL, next_level,
-                                     gain * side, NULL, fill >> blocks);
-                cm <<= ((B0 >> 1) & (stereo - 1));
-                rebalance = sbits - (rebalance - f->remaining2);
-                if (rebalance > 3 << 3 && itheta != 16384)
-                    mbits += rebalance - (3 << 3);
-
-                /* In stereo mode, we do not apply a scaling to the mid because
-                 * we need the normalized mid for folding later */
-                cm |= pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks,
-                                      lowband, duration, next_lowband_out1, next_level,
-                                      stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
-            }
-        }
-    } else {
-        /* This is the basic no-split case */
-        uint32_t q         = celt_bits2pulses(cache, b);
-        uint32_t curr_bits = celt_pulses2bits(cache, q);
-        f->remaining2 -= curr_bits;
-
-        /* Ensures we can never bust the budget */
-        while (f->remaining2 < 0 && q > 0) {
-            f->remaining2 += curr_bits;
-            curr_bits      = celt_pulses2bits(cache, --q);
-            f->remaining2 -= curr_bits;
-        }
-
-        if (q != 0) {
-            /* Finally do the actual (de)quantization */
-            if (quant) {
-                cm = celt_alg_quant(rc, X, N, (q < 8) ? q : (8 + (q & 7)) << ((q >> 3) - 1),
-                                    f->spread, blocks, gain, pvq);
-            } else {
-                cm = celt_alg_unquant(rc, X, N, (q < 8) ? q : (8 + (q & 7)) << ((q >> 3) - 1),
-                                      f->spread, blocks, gain, pvq);
-            }
-        } else {
-            /* If there's no pulse, fill the band anyway */
-            uint32_t cm_mask = (1 << blocks) - 1;
-            fill &= cm_mask;
-            if (fill) {
-                if (!lowband) {
-                    /* Noise */
-                    for (i = 0; i < N; i++)
-                        X[i] = (((int32_t)celt_rng(f)) >> 20);
-                    cm = cm_mask;
-                } else {
-                    /* Folded spectrum */
-                    for (i = 0; i < N; i++) {
-                        /* About 48 dB below the "normal" folding level */
-                        X[i] = lowband[i] + (((celt_rng(f)) & 0x8000) ? 1.0f / 256 : -1.0f / 256);
-                    }
-                    cm = fill;
-                }
-                celt_renormalize_vector(X, N, gain);
-            } else {
-                memset(X, 0, N*sizeof(float));
-            }
-        }
-    }
-
-    /* This code is used by the decoder and by the resynthesis-enabled encoder */
-    if (stereo) {
-        if (N > 2)
-            celt_stereo_merge(X, Y, mid, N);
-        if (inv) {
-            for (i = 0; i < N; i++)
-                Y[i] *= -1;
-        }
-    } else if (level == 0) {
-        int k;
-
-        /* Undo the sample reorganization going from time order to frequency order */
-        if (B0 > 1)
-            celt_interleave_hadamard(pvq->hadamard_tmp, X, N_B >> recombine,
-                                     B0 << recombine, longblocks);
-
-        /* Undo time-freq changes that we did earlier */
-        N_B = N_B0;
-        blocks = B0;
-        for (k = 0; k < time_divide; k++) {
-            blocks >>= 1;
-            N_B <<= 1;
-            cm |= cm >> blocks;
-            celt_haar1(X, N_B, blocks);
-        }
-
-        for (k = 0; k < recombine; k++) {
-            cm = ff_celt_bit_deinterleave[cm];
-            celt_haar1(X, N0>>k, 1<<k);
-        }
-        blocks <<= recombine;
-
-        /* Scale output for later folding */
-        if (lowband_out) {
-            float n = sqrtf(N0);
-            for (i = 0; i < N0; i++)
-                lowband_out[i] = n * X[i];
-        }
-        cm = av_mod_uintp2(cm, blocks);
-    }
-
-    return cm;
-}
-
-static QUANT_FN(pvq_decode_band)
-{
-#if CONFIG_OPUS_DECODER
-    return quant_band_template(pvq, f, rc, band, X, Y, N, b, blocks, lowband, duration,
-                               lowband_out, level, gain, lowband_scratch, fill, 0);
-#else
-    return 0;
+#define ENCODING 1
+#include "opus_pvq_template.c"
 #endif
-}
 
-static QUANT_FN(pvq_encode_band)
-{
-#if CONFIG_OPUS_ENCODER
-    return quant_band_template(pvq, f, rc, band, X, Y, N, b, blocks, lowband, duration,
-                               lowband_out, level, gain, lowband_scratch, fill, 1);
-#else
-    return 0;
+#if CONFIG_OPUS_DECODER
+#undef ENCODING
+#define ENCODING 0
+#include "opus_pvq_template.c"
 #endif
-}
 
 int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode)
 {
@@ -909,13 +509,19 @@ int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode)
     if (!s)
         return AVERROR(ENOMEM);
 
-    s->quant_band = encode ? pvq_encode_band : pvq_decode_band;
-
 #if CONFIG_OPUS_ENCODER
+#if CONFIG_OPUS_DECODER
+    s->quant_band = encode ? pvq_quant_band_enc : pvq_quant_band_dec;
+#else
+    s->quant_band = pvq_quant_band_enc;
+#endif
     s->pvq_search = ppp_pvq_search_c;
 #if ARCH_X86
     ff_celt_pvq_init_x86(s);
 #endif
+#else
+    s->quant_band = pvq_quant_band_dec;
+    s->pvq_search = NULL;
 #endif
 
     *pvq = s;
diff --git a/libavcodec/opus_pvq_template.c b/libavcodec/opus_pvq_template.c
new file mode 100644
index 0000000000..5f03f3d415
--- /dev/null
+++ b/libavcodec/opus_pvq_template.c
@@ -0,0 +1,432 @@
+/*
+ * Copyright (c) 2007-2008 CSIRO
+ * Copyright (c) 2007-2009 Xiph.Org Foundation
+ * Copyright (c) 2008-2009 Gregory Maxwell
+ * Copyright (c) 2012 Andrew D'Addesio
+ * Copyright (c) 2013-2014 Mozilla Corporation
+ * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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
+ */
+
+#undef FUNC
+
+#if ENCODING
+#define FUNC(name) name ## _enc
+#else
+#define FUNC(name) name ## _dec
+#endif
+
+static
+uint32_t FUNC(pvq_quant_band)(CeltPVQ *const pvq, CeltFrame *const f,
+                              OpusRangeCoder *const rc,
+                              const int band, float *X,
+                              float *Y, int N, int b,
+                              uint32_t blocks, float *lowband,
+                              int duration, float *lowband_out,
+                              int level, float gain,
+                              float *lowband_scratch,
+                              int fill)
+{
+#if ENCODING
+    OpusEncRangeCoder *const rce = (OpusEncRangeCoder*)rc;
+#else
+    OpusDecRangeCoder *const rcd = (OpusDecRangeCoder*)rc;
+#endif
+    const uint8_t *cache;
+    int stereo = !!Y, split = stereo;
+    uint32_t N0 = N;
+    int N_B = N / blocks;
+    int N_B0 = N_B;
+    int B0 = blocks;
+    int time_divide = 0;
+    int recombine = 0;
+    int inv = 0;
+    float mid = 0, side = 0;
+    int longblocks = (B0 == 1);
+    uint32_t cm = 0;
+
+    if (N == 1) {
+        float *x = X;
+        for (int i = 0; i <= stereo; i++) {
+            int sign = 0;
+            if (f->remaining2 >= 1 << 3) {
+#if ENCODING
+                sign = x[0] < 0;
+                ff_opus_rc_put_raw(rce, sign, 1);
+#else
+                sign = ff_opus_rc_get_raw(rcd, 1);
+#endif
+                f->remaining2 -= 1 << 3;
+            }
+            x[0] = 1.0f - 2.0f*sign;
+            x = Y;
+        }
+        if (lowband_out)
+            lowband_out[0] = X[0];
+        return 1;
+    }
+
+    if (!stereo && level == 0) {
+        int tf_change = f->tf_change[band];
+        int k;
+        if (tf_change > 0)
+            recombine = tf_change;
+        /* Band recombining to increase frequency resolution */
+
+        if (lowband &&
+            (recombine || ((N_B & 1) == 0 && tf_change < 0) || B0 > 1)) {
+            for (int i = 0; i < N; i++)
+                lowband_scratch[i] = lowband[i];
+            lowband = lowband_scratch;
+        }
+
+        for (k = 0; k < recombine; k++) {
+            if (ENCODING || lowband)
+                celt_haar1(ENCODING ? X : lowband, N >> k, 1 << k);
+            fill = ff_celt_bit_interleave[fill & 0xF] | ff_celt_bit_interleave[fill >> 4] << 2;
+        }
+        blocks >>= recombine;
+        N_B <<= recombine;
+
+        /* Increasing the time resolution */
+        while ((N_B & 1) == 0 && tf_change < 0) {
+            if (ENCODING || lowband)
+                celt_haar1(ENCODING ? X : lowband, N_B, blocks);
+            fill |= fill << blocks;
+            blocks <<= 1;
+            N_B >>= 1;
+            time_divide++;
+            tf_change++;
+        }
+        B0 = blocks;
+        N_B0 = N_B;
+
+        /* Reorganize the samples in time order instead of frequency order */
+        if (B0 > 1 && (ENCODING || lowband))
+            celt_deinterleave_hadamard(pvq->hadamard_tmp, ENCODING ? X : lowband,
+                                       N_B >> recombine, B0 << recombine,
+                                       longblocks);
+    }
+
+    /* If we need 1.5 more bit than we can produce, split the band in two. */
+    cache = ff_celt_cache_bits +
+            ff_celt_cache_index[(duration + 1) * CELT_MAX_BANDS + band];
+    if (!stereo && duration >= 0 && b > cache[cache[0]] + 12 && N > 2) {
+        N >>= 1;
+        Y = X + N;
+        split = 1;
+        duration -= 1;
+        if (blocks == 1)
+            fill = (fill & 1) | (fill << 1);
+        blocks = (blocks + 1) >> 1;
+    }
+
+    if (split) {
+        int qn;
+        int itheta = ENCODING ? celt_calc_theta(X, Y, stereo, N) : 0;
+        int mbits, sbits, delta;
+        int imid = 0, iside = 0;
+        int qalloc;
+        int pulse_cap;
+        int offset;
+        int orig_fill;
+        int tell;
+
+        /* Decide on the resolution to give to the split parameter theta */
+        pulse_cap = ff_celt_log_freq_range[band] + duration * 8;
+        offset = (pulse_cap >> 1) - (stereo && N == 2 ? CELT_QTHETA_OFFSET_TWOPHASE :
+                                                          CELT_QTHETA_OFFSET);
+        qn = (stereo && band >= f->intensity_stereo) ? 1 :
+             celt_compute_qn(N, b, offset, pulse_cap, stereo);
+        tell = opus_rc_tell_frac(rc);
+        if (qn != 1) {
+#if ENCODING
+            itheta = (itheta * qn + 8192) >> 14;
+            /* Entropy coding of the angle. We use a uniform pdf for the
+             * time split, a step for stereo, and a triangular one for the rest. */
+            if (stereo && N > 2)
+                ff_opus_rc_enc_uint_step(rce, itheta, qn / 2);
+            else if (stereo || B0 > 1)
+                ff_opus_rc_enc_uint(rce, itheta, qn + 1);
+            else
+                ff_opus_rc_enc_uint_tri(rce, itheta, qn);
+            itheta = itheta * 16384 / qn;
+            if (stereo) {
+                if (itheta == 0)
+                    celt_stereo_is_decouple(X, Y, f->block[0].lin_energy[band],
+                                            f->block[1].lin_energy[band], N);
+                else
+                    celt_stereo_ms_decouple(X, Y, N);
+            }
+#else
+            if (stereo && N > 2)
+                itheta = ff_opus_rc_dec_uint_step(rcd, qn / 2);
+            else if (stereo || B0 > 1)
+                itheta = ff_opus_rc_dec_uint(rcd, qn+1);
+            else
+                itheta = ff_opus_rc_dec_uint_tri(rcd, qn);
+            itheta = itheta * 16384 / qn;
+#endif
+        } else if (stereo) {
+#if ENCODING
+            inv = f->apply_phase_inv ? itheta > 8192 : 0;
+            if (inv) {
+                for (int i = 0; i < N; i++)
+                    Y[i] *= -1;
+            }
+            celt_stereo_is_decouple(X, Y, f->block[0].lin_energy[band],
+                                    f->block[1].lin_energy[band], N);
+
+            if (b > 2 << 3 && f->remaining2 > 2 << 3) {
+                ff_opus_rc_enc_log(rce, inv, 2);
+            } else {
+                inv = 0;
+            }
+#else
+            inv = (b > 2 << 3 && f->remaining2 > 2 << 3) ? ff_opus_rc_dec_log(rcd, 2) : 0;
+            inv = f->apply_phase_inv ? inv : 0;
+#endif
+            itheta = 0;
+        }
+        qalloc = opus_rc_tell_frac(rc) - tell;
+        b -= qalloc;
+
+        orig_fill = fill;
+        if (itheta == 0) {
+            imid = 32767;
+            iside = 0;
+            fill = av_mod_uintp2(fill, blocks);
+            delta = -16384;
+        } else if (itheta == 16384) {
+            imid = 0;
+            iside = 32767;
+            fill &= ((1 << blocks) - 1) << blocks;
+            delta = 16384;
+        } else {
+            imid = celt_cos(itheta);
+            iside = celt_cos(16384 - itheta);
+            /* This is the mid vs side allocation that minimizes squared error
+            in that band. */
+            delta = ROUND_MUL16((N - 1) << 7, celt_log2tan(iside, imid));
+        }
+
+        mid  = imid  / 32768.0f;
+        side = iside / 32768.0f;
+
+        /* This is a special case for N=2 that only works for stereo and takes
+        advantage of the fact that mid and side are orthogonal to encode
+        the side with just one bit. */
+        if (N == 2 && stereo) {
+            int c;
+            int sign = 0;
+            float tmp;
+            float *x2, *y2;
+            mbits = b;
+            /* Only need one bit for the side */
+            sbits = (itheta != 0 && itheta != 16384) ? 1 << 3 : 0;
+            mbits -= sbits;
+            c = (itheta > 8192);
+            f->remaining2 -= qalloc + sbits;
+
+            x2 = c ? Y : X;
+            y2 = c ? X : Y;
+            if (sbits) {
+#if ENCODING
+                sign = x2[0]*y2[1] - x2[1]*y2[0] < 0;
+                ff_opus_rc_put_raw(rce, sign, 1);
+#else
+                sign = ff_opus_rc_get_raw(rcd, 1);
+#endif
+            }
+            sign = 1 - 2 * sign;
+            /* We use orig_fill here because we want to fold the side, but if
+            itheta==16384, we'll have cleared the low bits of fill. */
+            cm = pvq->quant_band(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration,
+                                 lowband_out, level, gain, lowband_scratch, orig_fill);
+            /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
+            and there's no need to worry about mixing with the other channel. */
+            y2[0] = -sign * x2[1];
+            y2[1] =  sign * x2[0];
+            X[0] *= mid;
+            X[1] *= mid;
+            Y[0] *= side;
+            Y[1] *= side;
+            tmp = X[0];
+            X[0] = tmp - Y[0];
+            Y[0] = tmp + Y[0];
+            tmp = X[1];
+            X[1] = tmp - Y[1];
+            Y[1] = tmp + Y[1];
+        } else {
+            /* "Normal" split code */
+            float *next_lowband2     = NULL;
+            float *next_lowband_out1 = NULL;
+            int next_level = 0;
+            int rebalance;
+            uint32_t cmt;
+
+            /* Give more bits to low-energy MDCTs than they would
+             * otherwise deserve */
+            if (B0 > 1 && !stereo && (itheta & 0x3fff)) {
+                if (itheta > 8192)
+                    /* Rough approximation for pre-echo masking */
+                    delta -= delta >> (4 - duration);
+                else
+                    /* Corresponds to a forward-masking slope of
+                     * 1.5 dB per 10 ms */
+                    delta = FFMIN(0, delta + (N << 3 >> (5 - duration)));
+            }
+            mbits = av_clip((b - delta) / 2, 0, b);
+            sbits = b - mbits;
+            f->remaining2 -= qalloc;
+
+            if (lowband && !stereo)
+                next_lowband2 = lowband + N; /* >32-bit split case */
+
+            /* Only stereo needs to pass on lowband_out.
+             * Otherwise, it's handled at the end */
+            if (stereo)
+                next_lowband_out1 = lowband_out;
+            else
+                next_level = level + 1;
+
+            rebalance = f->remaining2;
+            if (mbits >= sbits) {
+                /* In stereo mode, we do not apply a scaling to the mid
+                 * because we need the normalized mid for folding later */
+                cm = pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks,
+                                     lowband, duration, next_lowband_out1, next_level,
+                                     stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
+                rebalance = mbits - (rebalance - f->remaining2);
+                if (rebalance > 3 << 3 && itheta != 0)
+                    sbits += rebalance - (3 << 3);
+
+                /* For a stereo split, the high bits of fill are always zero,
+                 * so no folding will be done to the side. */
+                cmt = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
+                                      next_lowband2, duration, NULL, next_level,
+                                      gain * side, NULL, fill >> blocks);
+                cm |= cmt << ((B0 >> 1) & (stereo - 1));
+            } else {
+                /* For a stereo split, the high bits of fill are always zero,
+                 * so no folding will be done to the side. */
+                cm = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
+                                     next_lowband2, duration, NULL, next_level,
+                                     gain * side, NULL, fill >> blocks);
+                cm <<= ((B0 >> 1) & (stereo - 1));
+                rebalance = sbits - (rebalance - f->remaining2);
+                if (rebalance > 3 << 3 && itheta != 16384)
+                    mbits += rebalance - (3 << 3);
+
+                /* In stereo mode, we do not apply a scaling to the mid because
+                 * we need the normalized mid for folding later */
+                cm |= pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks,
+                                      lowband, duration, next_lowband_out1, next_level,
+                                      stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
+            }
+        }
+    } else {
+        /* This is the basic no-split case */
+        uint32_t q         = celt_bits2pulses(cache, b);
+        uint32_t curr_bits = celt_pulses2bits(cache, q);
+        f->remaining2 -= curr_bits;
+
+        /* Ensures we can never bust the budget */
+        while (f->remaining2 < 0 && q > 0) {
+            f->remaining2 += curr_bits;
+            curr_bits      = celt_pulses2bits(cache, --q);
+            f->remaining2 -= curr_bits;
+        }
+
+        if (q != 0) {
+            /* Finally do the actual (de)quantization */
+#if ENCODING
+            cm = celt_alg_quant(rce, X, N, (q < 8) ? q : (8 + (q & 7)) << ((q >> 3) - 1),
+                                f->spread, blocks, gain, pvq);
+#else
+            cm = celt_alg_unquant(rcd, X, N, (q < 8) ? q : (8 + (q & 7)) << ((q >> 3) - 1),
+                                  f->spread, blocks, gain, pvq);
+#endif
+        } else {
+            /* If there's no pulse, fill the band anyway */
+            uint32_t cm_mask = (1 << blocks) - 1;
+            fill &= cm_mask;
+            if (fill) {
+                if (!lowband) {
+                    /* Noise */
+                    for (int i = 0; i < N; i++)
+                        X[i] = (((int32_t)celt_rng(f)) >> 20);
+                    cm = cm_mask;
+                } else {
+                    /* Folded spectrum */
+                    for (int i = 0; i < N; i++) {
+                        /* About 48 dB below the "normal" folding level */
+                        X[i] = lowband[i] + (((celt_rng(f)) & 0x8000) ? 1.0f / 256 : -1.0f / 256);
+                    }
+                    cm = fill;
+                }
+                celt_renormalize_vector(X, N, gain);
+            } else {
+                memset(X, 0, N*sizeof(float));
+            }
+        }
+    }
+
+    /* This code is used by the decoder and by the resynthesis-enabled encoder */
+    if (stereo) {
+        if (N > 2)
+            celt_stereo_merge(X, Y, mid, N);
+        if (inv) {
+            for (int i = 0; i < N; i++)
+                Y[i] *= -1;
+        }
+    } else if (level == 0) {
+        int k;
+
+        /* Undo the sample reorganization going from time order to frequency order */
+        if (B0 > 1)
+            celt_interleave_hadamard(pvq->hadamard_tmp, X, N_B >> recombine,
+                                     B0 << recombine, longblocks);
+
+        /* Undo time-freq changes that we did earlier */
+        N_B = N_B0;
+        blocks = B0;
+        for (k = 0; k < time_divide; k++) {
+            blocks >>= 1;
+            N_B <<= 1;
+            cm |= cm >> blocks;
+            celt_haar1(X, N_B, blocks);
+        }
+
+        for (k = 0; k < recombine; k++) {
+            cm = ff_celt_bit_deinterleave[cm];
+            celt_haar1(X, N0>>k, 1<<k);
+        }
+        blocks <<= recombine;
+
+        /* Scale output for later folding */
+        if (lowband_out) {
+            float n = sqrtf(N0);
+            for (int i = 0; i < N0; i++)
+                lowband_out[i] = n * X[i];
+        }
+        cm = av_mod_uintp2(cm, blocks);
+    }
+
+    return cm;
+}
diff --git a/libavcodec/opus_rc.c b/libavcodec/opus_rc.c
deleted file mode 100644
index 1a26d889b7..0000000000
--- a/libavcodec/opus_rc.c
+++ /dev/null
@@ -1,409 +0,0 @@
-/*
- * Copyright (c) 2012 Andrew D'Addesio
- * Copyright (c) 2013-2014 Mozilla Corporation
- * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
- *
- * 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 "opus_rc.h"
-
-#define OPUS_RC_BITS 32
-#define OPUS_RC_SYM  8
-#define OPUS_RC_CEIL ((1 << OPUS_RC_SYM) - 1)
-#define OPUS_RC_TOP (1u << 31)
-#define OPUS_RC_BOT (OPUS_RC_TOP >> OPUS_RC_SYM)
-#define OPUS_RC_SHIFT (OPUS_RC_BITS - OPUS_RC_SYM - 1)
-
-static av_always_inline void opus_rc_enc_carryout(OpusRangeCoder *rc, int cbuf)
-{
-    const int cb = cbuf >> OPUS_RC_SYM, mb = (OPUS_RC_CEIL + cb) & OPUS_RC_CEIL;
-    if (cbuf == OPUS_RC_CEIL) {
-        rc->ext++;
-        return;
-    }
-    rc->rng_cur[0] = rc->rem + cb;
-    rc->rng_cur += (rc->rem >= 0);
-    for (; rc->ext > 0; rc->ext--)
-        *rc->rng_cur++ = mb;
-    av_assert0(rc->rng_cur < rc->rb.position);
-    rc->rem = cbuf & OPUS_RC_CEIL; /* Propagate */
-}
-
-static av_always_inline void opus_rc_dec_normalize(OpusRangeCoder *rc)
-{
-    while (rc->range <= OPUS_RC_BOT) {
-        rc->value = ((rc->value << OPUS_RC_SYM) | (get_bits(&rc->gb, OPUS_RC_SYM) ^ OPUS_RC_CEIL)) & (OPUS_RC_TOP - 1);
-        rc->range     <<= OPUS_RC_SYM;
-        rc->total_bits += OPUS_RC_SYM;
-    }
-}
-
-static av_always_inline void opus_rc_enc_normalize(OpusRangeCoder *rc)
-{
-    while (rc->range <= OPUS_RC_BOT) {
-        opus_rc_enc_carryout(rc, rc->value >> OPUS_RC_SHIFT);
-        rc->value = (rc->value << OPUS_RC_SYM) & (OPUS_RC_TOP - 1);
-        rc->range     <<= OPUS_RC_SYM;
-        rc->total_bits += OPUS_RC_SYM;
-    }
-}
-
-static av_always_inline void opus_rc_dec_update(OpusRangeCoder *rc, uint32_t scale,
-                                                uint32_t low, uint32_t high,
-                                                uint32_t total)
-{
-    rc->value -= scale * (total - high);
-    rc->range  = low ? scale * (high - low)
-                      : rc->range - scale * (total - high);
-    opus_rc_dec_normalize(rc);
-}
-
-/* Main encoding function, this needs to go fast */
-static av_always_inline void opus_rc_enc_update(OpusRangeCoder *rc, uint32_t b, uint32_t p,
-                                                uint32_t p_tot, const int ptwo)
-{
-    uint32_t rscaled, cnd = !!b;
-    if (ptwo) /* Whole function is inlined so hopefully branch is optimized out */
-        rscaled = rc->range >> ff_log2(p_tot);
-    else
-        rscaled = rc->range/p_tot;
-    rc->value +=    cnd*(rc->range - rscaled*(p_tot - b));
-    rc->range  = (!cnd)*(rc->range - rscaled*(p_tot - p)) + cnd*rscaled*(p - b);
-    opus_rc_enc_normalize(rc);
-}
-
-uint32_t ff_opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf)
-{
-    unsigned int k, scale, total, symbol, low, high;
-
-    total = *cdf++;
-
-    scale   = rc->range / total;
-    symbol = rc->value / scale + 1;
-    symbol = total - FFMIN(symbol, total);
-
-    for (k = 0; cdf[k] <= symbol; k++);
-    high = cdf[k];
-    low  = k ? cdf[k-1] : 0;
-
-    opus_rc_dec_update(rc, scale, low, high, total);
-
-    return k;
-}
-
-void ff_opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf)
-{
-    opus_rc_enc_update(rc, (!!val)*cdf[val], cdf[val + 1], cdf[0], 1);
-}
-
-uint32_t ff_opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits)
-{
-    uint32_t k, scale;
-    scale = rc->range >> bits; // in this case, scale = symbol
-
-    if (rc->value >= scale) {
-        rc->value -= scale;
-        rc->range -= scale;
-        k = 0;
-    } else {
-        rc->range = scale;
-        k = 1;
-    }
-    opus_rc_dec_normalize(rc);
-    return k;
-}
-
-void ff_opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits)
-{
-    bits = (1 << bits) - 1;
-    opus_rc_enc_update(rc, (!!val)*bits, bits + !!val, bits + 1, 1);
-}
-
-/**
- * CELT: read 1-25 raw bits at the end of the frame, backwards byte-wise
- */
-uint32_t ff_opus_rc_get_raw(OpusRangeCoder *rc, uint32_t count)
-{
-    uint32_t value = 0;
-
-    while (rc->rb.bytes && rc->rb.cachelen < count) {
-        rc->rb.cacheval |= *--rc->rb.position << rc->rb.cachelen;
-        rc->rb.cachelen += 8;
-        rc->rb.bytes--;
-    }
-
-    value = av_mod_uintp2(rc->rb.cacheval, count);
-    rc->rb.cacheval    >>= count;
-    rc->rb.cachelen     -= count;
-    rc->total_bits      += count;
-
-    return value;
-}
-
-/**
- * CELT: write 0 - 31 bits to the rawbits buffer
- */
-void ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count)
-{
-    const int to_write = FFMIN(32 - rc->rb.cachelen, count);
-
-    rc->total_bits += count;
-    rc->rb.cacheval |= av_mod_uintp2(val, to_write) << rc->rb.cachelen;
-    rc->rb.cachelen = (rc->rb.cachelen + to_write) % 32;
-
-    if (!rc->rb.cachelen && count) {
-        AV_WB32((uint8_t *)rc->rb.position, rc->rb.cacheval);
-        rc->rb.bytes    += 4;
-        rc->rb.position -= 4;
-        rc->rb.cachelen = count - to_write;
-        rc->rb.cacheval = av_mod_uintp2(val >> to_write, rc->rb.cachelen);
-        av_assert0(rc->rng_cur < rc->rb.position);
-    }
-}
-
-/**
- * CELT: read a uniform distribution
- */
-uint32_t ff_opus_rc_dec_uint(OpusRangeCoder *rc, uint32_t size)
-{
-    uint32_t bits, k, scale, total;
-
-    bits  = opus_ilog(size - 1);
-    total = (bits > 8) ? ((size - 1) >> (bits - 8)) + 1 : size;
-
-    scale  = rc->range / total;
-    k      = rc->value / scale + 1;
-    k      = total - FFMIN(k, total);
-    opus_rc_dec_update(rc, scale, k, k + 1, total);
-
-    if (bits > 8) {
-        k = k << (bits - 8) | ff_opus_rc_get_raw(rc, bits - 8);
-        return FFMIN(k, size - 1);
-    } else
-        return k;
-}
-
-/**
- * CELT: write a uniformly distributed integer
- */
-void ff_opus_rc_enc_uint(OpusRangeCoder *rc, uint32_t val, uint32_t size)
-{
-    const int ps = FFMAX(opus_ilog(size - 1) - 8, 0);
-    opus_rc_enc_update(rc, val >> ps, (val >> ps) + 1, ((size - 1) >> ps) + 1, 0);
-    ff_opus_rc_put_raw(rc, val, ps);
-}
-
-uint32_t ff_opus_rc_dec_uint_step(OpusRangeCoder *rc, int k0)
-{
-    /* Use a probability of 3 up to itheta=8192 and then use 1 after */
-    uint32_t k, scale, symbol, total = (k0+1)*3 + k0;
-    scale  = rc->range / total;
-    symbol = rc->value / scale + 1;
-    symbol = total - FFMIN(symbol, total);
-
-    k = (symbol < (k0+1)*3) ? symbol/3 : symbol - (k0+1)*2;
-
-    opus_rc_dec_update(rc, scale, (k <= k0) ? 3*(k+0) : (k-1-k0) + 3*(k0+1),
-                       (k <= k0) ? 3*(k+1) : (k-0-k0) + 3*(k0+1), total);
-    return k;
-}
-
-void ff_opus_rc_enc_uint_step(OpusRangeCoder *rc, uint32_t val, int k0)
-{
-    const uint32_t a = val <= k0, b = 2*a + 1;
-    k0 = (k0 + 1) << 1;
-    val = b*(val + k0) - 3*a*k0;
-    opus_rc_enc_update(rc, val, val + b, (k0 << 1) - 1, 0);
-}
-
-uint32_t ff_opus_rc_dec_uint_tri(OpusRangeCoder *rc, int qn)
-{
-    uint32_t k, scale, symbol, total, low, center;
-
-    total = ((qn>>1) + 1) * ((qn>>1) + 1);
-    scale   = rc->range / total;
-    center = rc->value / scale + 1;
-    center = total - FFMIN(center, total);
-
-    if (center < total >> 1) {
-        k      = (ff_sqrt(8 * center + 1) - 1) >> 1;
-        low    = k * (k + 1) >> 1;
-        symbol = k + 1;
-    } else {
-        k      = (2*(qn + 1) - ff_sqrt(8*(total - center - 1) + 1)) >> 1;
-        low    = total - ((qn + 1 - k) * (qn + 2 - k) >> 1);
-        symbol = qn + 1 - k;
-    }
-
-    opus_rc_dec_update(rc, scale, low, low + symbol, total);
-
-    return k;
-}
-
-void ff_opus_rc_enc_uint_tri(OpusRangeCoder *rc, uint32_t k, int qn)
-{
-    uint32_t symbol, low, total;
-
-    total = ((qn>>1) + 1) * ((qn>>1) + 1);
-
-    if (k <= qn >> 1) {
-        low    = k * (k + 1) >> 1;
-        symbol = k + 1;
-    } else {
-        low    = total - ((qn + 1 - k) * (qn + 2 - k) >> 1);
-        symbol = qn + 1 - k;
-    }
-
-    opus_rc_enc_update(rc, low, low + symbol, total, 0);
-}
-
-int ff_opus_rc_dec_laplace(OpusRangeCoder *rc, uint32_t symbol, int decay)
-{
-    /* extends the range coder to model a Laplace distribution */
-    int value = 0;
-    uint32_t scale, low = 0, center;
-
-    scale  = rc->range >> 15;
-    center = rc->value / scale + 1;
-    center = (1 << 15) - FFMIN(center, 1 << 15);
-
-    if (center >= symbol) {
-        value++;
-        low = symbol;
-        symbol = 1 + ((32768 - 32 - symbol) * (16384-decay) >> 15);
-
-        while (symbol > 1 && center >= low + 2 * symbol) {
-            value++;
-            symbol *= 2;
-            low    += symbol;
-            symbol  = (((symbol - 2) * decay) >> 15) + 1;
-        }
-
-        if (symbol <= 1) {
-            int distance = (center - low) >> 1;
-            value += distance;
-            low   += 2 * distance;
-        }
-
-        if (center < low + symbol)
-            value *= -1;
-        else
-            low += symbol;
-    }
-
-    opus_rc_dec_update(rc, scale, low, FFMIN(low + symbol, 32768), 32768);
-
-    return value;
-}
-
-void ff_opus_rc_enc_laplace(OpusRangeCoder *rc, int *value, uint32_t symbol, int decay)
-{
-    uint32_t low = symbol;
-    int i = 1, val = FFABS(*value), pos = *value > 0;
-    if (!val) {
-        opus_rc_enc_update(rc, 0, symbol, 1 << 15, 1);
-        return;
-    }
-    symbol = ((32768 - 32 - symbol)*(16384 - decay)) >> 15;
-    for (; i < val && symbol; i++) {
-        low   += (symbol << 1) + 2;
-        symbol = (symbol*decay) >> 14;
-    }
-    if (symbol) {
-        low += (++symbol)*pos;
-    } else {
-        const int distance = FFMIN(val - i, (((32768 - low) - !pos) >> 1) - 1);
-        low   += pos + (distance << 1);
-        symbol = FFMIN(1, 32768 - low);
-        *value = FFSIGN(*value)*(distance + i);
-    }
-    opus_rc_enc_update(rc, low, low + symbol, 1 << 15, 1);
-}
-
-int ff_opus_rc_dec_init(OpusRangeCoder *rc, const uint8_t *data, int size)
-{
-    int ret = init_get_bits8(&rc->gb, data, size);
-    if (ret < 0)
-        return ret;
-
-    rc->range = 128;
-    rc->value = 127 - get_bits(&rc->gb, 7);
-    rc->total_bits = 9;
-    opus_rc_dec_normalize(rc);
-
-    return 0;
-}
-
-void ff_opus_rc_dec_raw_init(OpusRangeCoder *rc, const uint8_t *rightend, uint32_t bytes)
-{
-    rc->rb.position = rightend;
-    rc->rb.bytes    = bytes;
-    rc->rb.cachelen = 0;
-    rc->rb.cacheval = 0;
-}
-
-void ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size)
-{
-    int rng_bytes, bits = OPUS_RC_BITS - opus_ilog(rc->range);
-    uint32_t mask = (OPUS_RC_TOP - 1) >> bits;
-    uint32_t end = (rc->value + mask) & ~mask;
-
-    if ((end | mask) >= rc->value + rc->range) {
-        bits++;
-        mask >>= 1;
-        end = (rc->value + mask) & ~mask;
-    }
-
-    /* Finish what's left */
-    while (bits > 0) {
-        opus_rc_enc_carryout(rc, end >> OPUS_RC_SHIFT);
-        end = (end << OPUS_RC_SYM) & (OPUS_RC_TOP - 1);
-        bits -= OPUS_RC_SYM;
-    }
-
-    /* Flush out anything left or marked */
-    if (rc->rem >= 0 || rc->ext > 0)
-        opus_rc_enc_carryout(rc, 0);
-
-    rng_bytes = rc->rng_cur - rc->buf;
-    memcpy(dst, rc->buf, rng_bytes);
-
-    /* Put the rawbits part, if any */
-    if (rc->rb.bytes || rc->rb.cachelen) {
-        int i, lap;
-        uint8_t *rb_src, *rb_dst;
-        ff_opus_rc_put_raw(rc, 0, 32 - rc->rb.cachelen);
-        rb_src = rc->buf + OPUS_MAX_FRAME_SIZE + 12 - rc->rb.bytes;
-        rb_dst = dst + FFMAX(size - rc->rb.bytes, 0);
-        lap = &dst[rng_bytes] - rb_dst;
-        for (i = 0; i < lap; i++)
-            rb_dst[i] |= rb_src[i];
-        memcpy(&rb_dst[lap], &rb_src[lap], FFMAX(rc->rb.bytes - lap, 0));
-    }
-}
-
-void ff_opus_rc_enc_init(OpusRangeCoder *rc)
-{
-    rc->value = 0;
-    rc->range = OPUS_RC_TOP;
-    rc->total_bits = OPUS_RC_BITS + 1;
-    rc->rem = -1;
-    rc->ext =  0;
-    rc->rng_cur = rc->buf;
-    ff_opus_rc_dec_raw_init(rc, rc->buf + OPUS_MAX_FRAME_SIZE + 8, 0);
-}
diff --git a/libavcodec/opus_rc.h b/libavcodec/opus_rc.h
index 72e683b075..332f3fa883 100644
--- a/libavcodec/opus_rc.h
+++ b/libavcodec/opus_rc.h
@@ -24,11 +24,16 @@
 #define AVCODEC_OPUS_RC_H
 
 #include <stdint.h>
-#include "get_bits.h"
-#include "opus.h"
+
+#include "libavutil/common.h"
 
 #define opus_ilog(i) (av_log2(i) + !!(i))
 
+#define OPUS_RC_SYM  8
+#define OPUS_RC_CEIL ((1 << OPUS_RC_SYM) - 1)
+#define OPUS_RC_TOP (1u << 31)
+#define OPUS_RC_BOT (OPUS_RC_TOP >> OPUS_RC_SYM)
+
 typedef struct RawBitsContext {
     const uint8_t *position;
     uint32_t bytes;
@@ -37,19 +42,21 @@ typedef struct RawBitsContext {
 } RawBitsContext;
 
 typedef struct OpusRangeCoder {
-    GetBitContext gb;
     RawBitsContext rb;
     uint32_t range;
     uint32_t value;
     uint32_t total_bits;
-
-    /* Encoder */
-    uint8_t buf[OPUS_MAX_FRAME_SIZE + 12]; /* memcpy vs (memmove + overreading) */
-    uint8_t *rng_cur;                      /* Current range coded byte */
-    int ext;                               /* Awaiting propagation */
-    int rem;                               /* Carryout flag */
 } OpusRangeCoder;
 
+static inline void ff_opus_rc_raw_init(OpusRangeCoder *rc, const uint8_t *rightend,
+                                       uint32_t bytes)
+{
+    rc->rb.position = rightend;
+    rc->rb.bytes    = bytes;
+    rc->rb.cachelen = 0;
+    rc->rb.cacheval = 0;
+}
+
 /**
  * CELT: estimate bits of entropy that have thus far been consumed for the
  *       current CELT frame, to integer and fractional (1/8th bit) precision
@@ -78,45 +85,4 @@ static av_always_inline uint32_t opus_rc_tell_frac(const OpusRangeCoder *rc)
     return total_bits - rcbuffer;
 }
 
-uint32_t ff_opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf);
-void     ff_opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf);
-
-uint32_t ff_opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits);
-void     ff_opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits);
-
-uint32_t ff_opus_rc_dec_uint_step(OpusRangeCoder *rc, int k0);
-void     ff_opus_rc_enc_uint_step(OpusRangeCoder *rc, uint32_t val, int k0);
-
-uint32_t ff_opus_rc_dec_uint_tri(OpusRangeCoder *rc, int qn);
-void     ff_opus_rc_enc_uint_tri(OpusRangeCoder *rc, uint32_t k, int qn);
-
-uint32_t ff_opus_rc_dec_uint(OpusRangeCoder *rc, uint32_t size);
-void     ff_opus_rc_enc_uint(OpusRangeCoder *rc, uint32_t val, uint32_t size);
-
-uint32_t ff_opus_rc_get_raw(OpusRangeCoder *rc, uint32_t count);
-void     ff_opus_rc_put_raw(OpusRangeCoder *rc, uint32_t val, uint32_t count);
-
-int      ff_opus_rc_dec_laplace(OpusRangeCoder *rc, uint32_t symbol, int decay);
-void     ff_opus_rc_enc_laplace(OpusRangeCoder *rc, int *value, uint32_t symbol, int decay);
-
-int      ff_opus_rc_dec_init(OpusRangeCoder *rc, const uint8_t *data, int size);
-void     ff_opus_rc_dec_raw_init(OpusRangeCoder *rc, const uint8_t *rightend, uint32_t bytes);
-
-void     ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size);
-void     ff_opus_rc_enc_init(OpusRangeCoder *rc);
-
-#define OPUS_RC_CHECKPOINT_UPDATE(rc) \
-    rc_rollback_bits = opus_rc_tell_frac(rc); \
-    rc_rollback_ctx  = *rc
-
-#define OPUS_RC_CHECKPOINT_SPAWN(rc) \
-    uint32_t rc_rollback_bits = opus_rc_tell_frac(rc); \
-    OpusRangeCoder rc_rollback_ctx = *rc \
-
-#define OPUS_RC_CHECKPOINT_BITS(rc) \
-    (opus_rc_tell_frac(rc) - rc_rollback_bits)
-
-#define OPUS_RC_CHECKPOINT_ROLLBACK(rc) \
-    memcpy(rc, &rc_rollback_ctx, sizeof(OpusRangeCoder)); \
-
 #endif /* AVCODEC_OPUS_RC_H */
diff --git a/libavcodec/opus_silk.c b/libavcodec/opus_silk.c
index cf8b16acff..99696e26d2 100644
--- a/libavcodec/opus_silk.c
+++ b/libavcodec/opus_silk.c
@@ -29,6 +29,7 @@
 #include "mathops.h"
 #include "opus.h"
 #include "opus_rc.h"
+#include "opusdec_rc.h"
 #include "opus_silk.h"
 #include "opustab.h"
 
@@ -308,7 +309,7 @@ static void silk_lsf2lpc(const int16_t nlsf[16], float lpcf[16], int order)
 }
 
 static inline void silk_decode_lpc(SilkContext *s, SilkFrame *frame,
-                                   OpusRangeCoder *rc,
+                                   OpusDecRangeCoder *rc,
                                    float lpc_leadin[16], float lpc[16],
                                    int *lpc_order, int *has_lpc_leadin, int voiced)
 {
@@ -404,7 +405,7 @@ static inline void silk_decode_lpc(SilkContext *s, SilkFrame *frame,
     memcpy(frame->lpc,  lpc,  order * sizeof(lpc[0]));
 }
 
-static inline void silk_count_children(OpusRangeCoder *rc, int model, int32_t total,
+static inline void silk_count_children(OpusDecRangeCoder *rc, int model, int32_t total,
                                        int32_t child[2])
 {
     if (total != 0) {
@@ -417,7 +418,7 @@ static inline void silk_count_children(OpusRangeCoder *rc, int model, int32_t to
     }
 }
 
-static inline void silk_decode_excitation(SilkContext *s, OpusRangeCoder *rc,
+static inline void silk_decode_excitation(SilkContext *s, OpusDecRangeCoder *rc,
                                           float* excitationf,
                                           int qoffset_high, int active, int voiced)
 {
@@ -511,7 +512,7 @@ static inline void silk_decode_excitation(SilkContext *s, OpusRangeCoder *rc,
 /** Order of the LTP filter */
 #define LTP_ORDER 5
 
-static void silk_decode_frame(SilkContext *s, OpusRangeCoder *rc,
+static void silk_decode_frame(SilkContext *s, OpusDecRangeCoder *rc,
                               int frame_num, int channel, int coded_channels,
                               int active, int active1, int redundant)
 {
@@ -788,7 +789,7 @@ static void silk_flush_frame(SilkFrame *frame)
     frame->coded       = 0;
 }
 
-int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc,
+int ff_silk_decode_superframe(SilkContext *s, OpusDecRangeCoder *rc,
                               float *output[2],
                               enum OpusBandwidth bandwidth,
                               int coded_channels,
diff --git a/libavcodec/opus_silk.h b/libavcodec/opus_silk.h
index 6552c166a4..cd6920920e 100644
--- a/libavcodec/opus_silk.h
+++ b/libavcodec/opus_silk.h
@@ -25,7 +25,7 @@
 
 #include "avcodec.h"
 #include "opus.h"
-#include "opus_rc.h"
+#include "opusdec_rc.h"
 
 #define SILK_HISTORY                 322
 #define SILK_MAX_LPC                 16
@@ -40,7 +40,7 @@ void ff_silk_flush(SilkContext *s);
  * Decode the LP layer of one Opus frame (which may correspond to several SILK
  * frames).
  */
-int ff_silk_decode_superframe(SilkContext *s, OpusRangeCoder *rc,
+int ff_silk_decode_superframe(SilkContext *s, OpusDecRangeCoder *rc,
                               float *output[2],
                               enum OpusBandwidth bandwidth, int coded_channels,
                               int duration_ms);
diff --git a/libavcodec/opusdec.c b/libavcodec/opusdec.c
index c5f06e0600..468bc6ddff 100644
--- a/libavcodec/opusdec.c
+++ b/libavcodec/opusdec.c
@@ -54,6 +54,7 @@
 #include "opus_celt.h"
 #include "opus_parse.h"
 #include "opus_rc.h"
+#include "opusdec_rc.h"
 #include "opus_silk.h"
 
 static const uint16_t silk_frame_duration_ms[16] = {
@@ -83,8 +84,8 @@ typedef struct OpusStreamContext {
      * the streams when they have different resampling delays */
     AVAudioFifo *sync_buffer;
 
-    OpusRangeCoder rc;
-    OpusRangeCoder redundancy_rc;
+    OpusDecRangeCoder rc;
+    OpusDecRangeCoder redundancy_rc;
     SilkContext *silk;
     CeltFrame *celt;
     AVFloatDSPContext *fdsp;
@@ -218,7 +219,7 @@ static int opus_decode_redundancy(OpusStreamContext *s, const uint8_t *data, int
     int ret = ff_opus_rc_dec_init(&s->redundancy_rc, data, size);
     if (ret < 0)
         goto fail;
-    ff_opus_rc_dec_raw_init(&s->redundancy_rc, data + size, size);
+    ff_opus_rc_raw_init(&s->redundancy_rc.c, data + size, size);
 
     ret = ff_celt_decode_frame(s->celt, &s->redundancy_rc,
                                s->redundancy_output,
@@ -274,7 +275,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size
         ff_silk_flush(s->silk);
 
     // decode redundancy information
-    consumed = opus_rc_tell(&s->rc);
+    consumed = opus_rc_tell(&s->rc.c);
     if (s->packet.mode == OPUS_MODE_HYBRID && consumed + 37 <= size * 8)
         redundancy = ff_opus_rc_dec_log(&s->rc, 12);
     else if (s->packet.mode == OPUS_MODE_SILK && consumed + 17 <= size * 8)
@@ -328,7 +329,7 @@ static int opus_decode_frame(OpusStreamContext *s, const uint8_t *data, int size
             }
         }
 
-        ff_opus_rc_dec_raw_init(&s->rc, data + size, size);
+        ff_opus_rc_raw_init(&s->rc.c, data + size, size);
 
         ret = ff_celt_decode_frame(s->celt, &s->rc, dst,
                                    s->packet.stereo + 1,
diff --git a/libavcodec/opusdec_rc.c b/libavcodec/opusdec_rc.c
new file mode 100644
index 0000000000..fb2bce0b72
--- /dev/null
+++ b/libavcodec/opusdec_rc.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2012 Andrew D'Addesio
+ * Copyright (c) 2013-2014 Mozilla Corporation
+ * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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 "opus_rc.h"
+#include "opusdec_rc.h"
+
+static av_always_inline void opus_rc_dec_normalize(OpusDecRangeCoder *rc)
+{
+    while (rc->c.range <= OPUS_RC_BOT) {
+        rc->c.value = ((rc->c.value << OPUS_RC_SYM) | (get_bits(&rc->gb, OPUS_RC_SYM) ^ OPUS_RC_CEIL)) & (OPUS_RC_TOP - 1);
+        rc->c.range     <<= OPUS_RC_SYM;
+        rc->c.total_bits += OPUS_RC_SYM;
+    }
+}
+
+static av_always_inline void opus_rc_dec_update(OpusDecRangeCoder *rc, uint32_t scale,
+                                                uint32_t low, uint32_t high,
+                                                uint32_t total)
+{
+    rc->c.value -= scale * (total - high);
+    rc->c.range  = low ? scale * (high - low)
+                      : rc->c.range - scale * (total - high);
+    opus_rc_dec_normalize(rc);
+}
+
+uint32_t ff_opus_rc_dec_cdf(OpusDecRangeCoder *rc, const uint16_t *cdf)
+{
+    unsigned int k, scale, total, symbol, low, high;
+
+    total = *cdf++;
+
+    scale   = rc->c.range / total;
+    symbol = rc->c.value / scale + 1;
+    symbol = total - FFMIN(symbol, total);
+
+    for (k = 0; cdf[k] <= symbol; k++);
+    high = cdf[k];
+    low  = k ? cdf[k-1] : 0;
+
+    opus_rc_dec_update(rc, scale, low, high, total);
+
+    return k;
+}
+
+uint32_t ff_opus_rc_dec_log(OpusDecRangeCoder *rc, uint32_t bits)
+{
+    uint32_t k, scale;
+    scale = rc->c.range >> bits; // in this case, scale = symbol
+
+    if (rc->c.value >= scale) {
+        rc->c.value -= scale;
+        rc->c.range -= scale;
+        k = 0;
+    } else {
+        rc->c.range = scale;
+        k = 1;
+    }
+    opus_rc_dec_normalize(rc);
+    return k;
+}
+
+/**
+ * CELT: read 1-25 raw bits at the end of the frame, backwards byte-wise
+ */
+uint32_t ff_opus_rc_get_raw(OpusDecRangeCoder *rc, uint32_t count)
+{
+    uint32_t value = 0;
+
+    while (rc->c.rb.bytes && rc->c.rb.cachelen < count) {
+        rc->c.rb.cacheval |= *--rc->c.rb.position << rc->c.rb.cachelen;
+        rc->c.rb.cachelen += 8;
+        rc->c.rb.bytes--;
+    }
+
+    value = av_mod_uintp2(rc->c.rb.cacheval, count);
+    rc->c.rb.cacheval    >>= count;
+    rc->c.rb.cachelen     -= count;
+    rc->c.total_bits      += count;
+
+    return value;
+}
+
+/**
+ * CELT: read a uniform distribution
+ */
+uint32_t ff_opus_rc_dec_uint(OpusDecRangeCoder *rc, uint32_t size)
+{
+    uint32_t bits, k, scale, total;
+
+    bits  = opus_ilog(size - 1);
+    total = (bits > 8) ? ((size - 1) >> (bits - 8)) + 1 : size;
+
+    scale  = rc->c.range / total;
+    k      = rc->c.value / scale + 1;
+    k      = total - FFMIN(k, total);
+    opus_rc_dec_update(rc, scale, k, k + 1, total);
+
+    if (bits > 8) {
+        k = k << (bits - 8) | ff_opus_rc_get_raw(rc, bits - 8);
+        return FFMIN(k, size - 1);
+    } else
+        return k;
+}
+
+uint32_t ff_opus_rc_dec_uint_step(OpusDecRangeCoder *rc, int k0)
+{
+    /* Use a probability of 3 up to itheta=8192 and then use 1 after */
+    uint32_t k, scale, symbol, total = (k0+1)*3 + k0;
+    scale  = rc->c.range / total;
+    symbol = rc->c.value / scale + 1;
+    symbol = total - FFMIN(symbol, total);
+
+    k = (symbol < (k0+1)*3) ? symbol/3 : symbol - (k0+1)*2;
+
+    opus_rc_dec_update(rc, scale, (k <= k0) ? 3*(k+0) : (k-1-k0) + 3*(k0+1),
+                       (k <= k0) ? 3*(k+1) : (k-0-k0) + 3*(k0+1), total);
+    return k;
+}
+
+uint32_t ff_opus_rc_dec_uint_tri(OpusDecRangeCoder *rc, int qn)
+{
+    uint32_t k, scale, symbol, total, low, center;
+
+    total = ((qn>>1) + 1) * ((qn>>1) + 1);
+    scale   = rc->c.range / total;
+    center = rc->c.value / scale + 1;
+    center = total - FFMIN(center, total);
+
+    if (center < total >> 1) {
+        k      = (ff_sqrt(8 * center + 1) - 1) >> 1;
+        low    = k * (k + 1) >> 1;
+        symbol = k + 1;
+    } else {
+        k      = (2*(qn + 1) - ff_sqrt(8*(total - center - 1) + 1)) >> 1;
+        low    = total - ((qn + 1 - k) * (qn + 2 - k) >> 1);
+        symbol = qn + 1 - k;
+    }
+
+    opus_rc_dec_update(rc, scale, low, low + symbol, total);
+
+    return k;
+}
+
+int ff_opus_rc_dec_laplace(OpusDecRangeCoder *rc, uint32_t symbol, int decay)
+{
+    /* extends the range coder to model a Laplace distribution */
+    int value = 0;
+    uint32_t scale, low = 0, center;
+
+    scale  = rc->c.range >> 15;
+    center = rc->c.value / scale + 1;
+    center = (1 << 15) - FFMIN(center, 1 << 15);
+
+    if (center >= symbol) {
+        value++;
+        low = symbol;
+        symbol = 1 + ((32768 - 32 - symbol) * (16384-decay) >> 15);
+
+        while (symbol > 1 && center >= low + 2 * symbol) {
+            value++;
+            symbol *= 2;
+            low    += symbol;
+            symbol  = (((symbol - 2) * decay) >> 15) + 1;
+        }
+
+        if (symbol <= 1) {
+            int distance = (center - low) >> 1;
+            value += distance;
+            low   += 2 * distance;
+        }
+
+        if (center < low + symbol)
+            value *= -1;
+        else
+            low += symbol;
+    }
+
+    opus_rc_dec_update(rc, scale, low, FFMIN(low + symbol, 32768), 32768);
+
+    return value;
+}
+
+int ff_opus_rc_dec_init(OpusDecRangeCoder *rc, const uint8_t *data, int size)
+{
+    int ret = init_get_bits8(&rc->gb, data, size);
+    if (ret < 0)
+        return ret;
+
+    rc->c.range = 128;
+    rc->c.value = 127 - get_bits(&rc->gb, 7);
+    rc->c.total_bits = 9;
+    opus_rc_dec_normalize(rc);
+
+    return 0;
+}
diff --git a/libavcodec/opusdec_rc.h b/libavcodec/opusdec_rc.h
new file mode 100644
index 0000000000..96889e3d7f
--- /dev/null
+++ b/libavcodec/opusdec_rc.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2012 Andrew D'Addesio
+ * Copyright (c) 2013-2014 Mozilla Corporation
+ * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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
+ */
+
+#ifndef AVCODEC_OPUSDEC_RC_H
+#define AVCODEC_OPUSDEC_RC_H
+
+#include <stdint.h>
+
+#include "get_bits.h"
+#include "opus_rc.h"
+
+typedef struct OpusDecRangeCoder {
+    OpusRangeCoder c;
+
+    GetBitContext gb;
+} OpusDecRangeCoder;
+
+uint32_t ff_opus_rc_dec_cdf(OpusDecRangeCoder *rc, const uint16_t *cdf);
+
+uint32_t ff_opus_rc_dec_log(OpusDecRangeCoder *rc, uint32_t bits);
+
+uint32_t ff_opus_rc_dec_uint_step(OpusDecRangeCoder *rc, int k0);
+
+uint32_t ff_opus_rc_dec_uint_tri(OpusDecRangeCoder *rc, int qn);
+
+uint32_t ff_opus_rc_dec_uint(OpusDecRangeCoder *rc, uint32_t size);
+
+uint32_t ff_opus_rc_get_raw(OpusDecRangeCoder *rc, uint32_t count);
+
+int      ff_opus_rc_dec_laplace(OpusDecRangeCoder *rc, uint32_t symbol, int decay);
+
+int      ff_opus_rc_dec_init(OpusDecRangeCoder *rc, const uint8_t *data, int size);
+
+#endif /* AVCODEC_OPUSDEC_RC_H */
diff --git a/libavcodec/opusenc.c b/libavcodec/opusenc.c
index 280425c74f..f1283827b7 100644
--- a/libavcodec/opusenc.c
+++ b/libavcodec/opusenc.c
@@ -25,6 +25,7 @@
 #include "opusenc.h"
 #include "opus_pvq.h"
 #include "opusenc_psy.h"
+#include "opusenc_rc.h"
 #include "opustab.h"
 
 #include "libavutil/channel_layout.h"
@@ -55,7 +56,7 @@ typedef struct OpusEncContext {
     int channels;
 
     CeltFrame *frame;
-    OpusRangeCoder *rc;
+    OpusEncRangeCoder *rc;
 
     /* Actual energy the decoder will have */
     float last_quantized_energy[OPUS_MAX_CHANNELS][CELT_MAX_BANDS];
@@ -258,15 +259,15 @@ static void celt_frame_mdct(OpusEncContext *s, CeltFrame *f)
     }
 }
 
-static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc)
+static void celt_enc_tf(CeltFrame *f, OpusEncRangeCoder *rc)
 {
     int tf_select = 0, diff = 0, tf_changed = 0, tf_select_needed;
     int bits = f->transient ? 2 : 4;
 
-    tf_select_needed = ((f->size && (opus_rc_tell(rc) + bits + 1) <= f->framebits));
+    tf_select_needed = ((f->size && (opus_rc_tell(&rc->c) + bits + 1) <= f->framebits));
 
     for (int i = f->start_band; i < f->end_band; i++) {
-        if ((opus_rc_tell(rc) + bits + tf_select_needed) <= f->framebits) {
+        if ((opus_rc_tell(&rc->c) + bits + tf_select_needed) <= f->framebits) {
             const int tbit = (diff ^ 1) == f->tf_change[i];
             ff_opus_rc_enc_log(rc, tbit, bits);
             diff ^= tbit;
@@ -285,7 +286,7 @@ static void celt_enc_tf(CeltFrame *f, OpusRangeCoder *rc)
         f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]];
 }
 
-static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f)
+static void celt_enc_quant_pfilter(OpusEncRangeCoder *rc, CeltFrame *f)
 {
     float gain = f->pf_gain;
     int txval, octave = f->pf_octave, period = f->pf_period, tapset = f->pf_tapset;
@@ -307,7 +308,7 @@ static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f)
     ff_opus_rc_put_raw(rc, txval, 3);
     gain   = 0.09375f * (txval + 1);
     /* Tapset */
-    if ((opus_rc_tell(rc) + 2) <= f->framebits)
+    if ((opus_rc_tell(&rc->c) + 2) <= f->framebits)
         ff_opus_rc_enc_cdf(rc, tapset, ff_celt_model_tapset);
     else
         tapset = 0;
@@ -322,14 +323,14 @@ static void celt_enc_quant_pfilter(OpusRangeCoder *rc, CeltFrame *f)
     }
 }
 
-static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f,
+static void exp_quant_coarse(OpusEncRangeCoder *rc, CeltFrame *f,
                              float last_energy[][CELT_MAX_BANDS], int intra)
 {
     float alpha, beta, prev[2] = { 0, 0 };
     const uint8_t *pmod = ff_celt_coarse_energy_dist[f->size][intra];
 
     /* Inter is really just differential coding */
-    if (opus_rc_tell(rc) + 3 <= f->framebits)
+    if (opus_rc_tell(&rc->c) + 3 <= f->framebits)
         ff_opus_rc_enc_log(rc, intra, 3);
     else
         intra = 0;
@@ -345,7 +346,7 @@ static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f,
     for (int i = f->start_band; i < f->end_band; i++) {
         for (int ch = 0; ch < f->channels; ch++) {
             CeltBlock *block = &f->block[ch];
-            const int left = f->framebits - opus_rc_tell(rc);
+            const int left = f->framebits - opus_rc_tell(&rc->c);
             const float last = FFMAX(-9.0f, last_energy[ch][i]);
             float diff = block->energy[i] - prev[ch] - last*alpha;
             int q_en = lrintf(diff);
@@ -365,7 +366,7 @@ static void exp_quant_coarse(OpusRangeCoder *rc, CeltFrame *f,
     }
 }
 
-static void celt_quant_coarse(CeltFrame *f, OpusRangeCoder *rc,
+static void celt_quant_coarse(CeltFrame *f, OpusEncRangeCoder *rc,
                               float last_energy[][CELT_MAX_BANDS])
 {
     uint32_t inter, intra;
@@ -385,7 +386,7 @@ static void celt_quant_coarse(CeltFrame *f, OpusRangeCoder *rc,
     }
 }
 
-static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc)
+static void celt_quant_fine(CeltFrame *f, OpusEncRangeCoder *rc)
 {
     for (int i = f->start_band; i < f->end_band; i++) {
         if (!f->fine_bits[i])
@@ -402,10 +403,10 @@ static void celt_quant_fine(CeltFrame *f, OpusRangeCoder *rc)
     }
 }
 
-static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f)
+static void celt_quant_final(OpusEncContext *s, OpusEncRangeCoder *rc, CeltFrame *f)
 {
     for (int priority = 0; priority < 2; priority++) {
-        for (int i = f->start_band; i < f->end_band && (f->framebits - opus_rc_tell(rc)) >= f->channels; i++) {
+        for (int i = f->start_band; i < f->end_band && (f->framebits - opus_rc_tell(&rc->c)) >= f->channels; i++) {
             if (f->fine_priority[i] != priority || f->fine_bits[i] >= CELT_MAX_FINE_BITS)
                 continue;
             for (int ch = 0; ch < f->channels; ch++) {
@@ -420,7 +421,7 @@ static void celt_quant_final(OpusEncContext *s, OpusRangeCoder *rc, CeltFrame *f
     }
 }
 
-static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc,
+static void celt_encode_frame(OpusEncContext *s, OpusEncRangeCoder *rc,
                               CeltFrame *f, int index)
 {
     ff_opus_rc_enc_init(rc);
@@ -457,19 +458,19 @@ static void celt_encode_frame(OpusEncContext *s, OpusRangeCoder *rc,
     ff_opus_rc_enc_log(rc, 0, 15);
 
     /* Pitch filter */
-    if (!f->start_band && opus_rc_tell(rc) + 16 <= f->framebits)
+    if (!f->start_band && opus_rc_tell(&rc->c) + 16 <= f->framebits)
         celt_enc_quant_pfilter(rc, f);
 
     /* Transient flag */
-    if (f->size && opus_rc_tell(rc) + 3 <= f->framebits)
+    if (f->size && opus_rc_tell(&rc->c) + 3 <= f->framebits)
         ff_opus_rc_enc_log(rc, f->transient, 3);
 
     /* Main encoding */
     celt_quant_coarse  (f, rc, s->last_quantized_energy);
     celt_enc_tf        (f, rc);
-    ff_celt_bitalloc   (f, rc, 1);
+    ff_celt_bitalloc   (f, &rc->c, 1);
     celt_quant_fine    (f, rc);
-    ff_celt_quant_bands(f, rc);
+    ff_celt_quant_bands(f, &rc->c);
 
     /* Anticollapse bit */
     if (f->anticollapse_needed)
@@ -694,7 +695,7 @@ static av_cold int opus_encode_init(AVCodecContext *avctx)
     s->frame = av_malloc(max_frames*sizeof(CeltFrame));
     if (!s->frame)
         return AVERROR(ENOMEM);
-    s->rc = av_malloc(max_frames*sizeof(OpusRangeCoder));
+    s->rc = av_malloc_array(max_frames, sizeof(*s->rc));
     if (!s->rc)
         return AVERROR(ENOMEM);
 
diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c
index 48ccd2ebd0..17a2efd8d5 100644
--- a/libavcodec/opusenc_psy.c
+++ b/libavcodec/opusenc_psy.c
@@ -22,12 +22,13 @@
 #include <float.h>
 
 #include "opusenc_psy.h"
+#include "opusenc_rc.h"
 #include "opus_celt.h"
 #include "opus_pvq.h"
 #include "opustab.h"
 #include "libavfilter/window_func.h"
 
-static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int band,
+static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusEncRangeCoder *rce, int band,
                            float *bits, float lambda)
 {
     int i, b = 0;
@@ -39,7 +40,8 @@ static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int b
     float *X_orig = f->block[0].coeffs + (ff_celt_freq_bands[band] << f->size);
     float *Y = (f->channels == 2) ? &buf[176] : NULL;
     float *Y_orig = f->block[1].coeffs + (ff_celt_freq_bands[band] << f->size);
-    OPUS_RC_CHECKPOINT_SPAWN(rc);
+    OpusRangeCoder *const rc = &rce->c;
+    OPUS_RC_CHECKPOINT_SPAWN(rce);
 
     memcpy(X, X_orig, band_size*sizeof(float));
     if (Y)
@@ -69,10 +71,10 @@ static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusRangeCoder *rc, int b
     }
 
     dist = sqrtf(err_x) + sqrtf(err_y);
-    cost = OPUS_RC_CHECKPOINT_BITS(rc)/8.0f;
+    cost = OPUS_RC_CHECKPOINT_BITS(rce)/8.0f;
     *bits += cost;
 
-    OPUS_RC_CHECKPOINT_ROLLBACK(rc);
+    OPUS_RC_CHECKPOINT_ROLLBACK(rce);
 
     return lambda*dist*cost;
 }
@@ -366,10 +368,10 @@ static void celt_gauge_psy_weight(OpusPsyContext *s, OpusPsyStep **start,
 static int bands_dist(OpusPsyContext *s, CeltFrame *f, float *total_dist)
 {
     int i, tdist = 0.0f;
-    OpusRangeCoder dump;
+    OpusEncRangeCoder dump;
 
     ff_opus_rc_enc_init(&dump);
-    ff_celt_bitalloc(f, &dump, 1);
+    ff_celt_bitalloc(f, &dump.c, 1);
 
     for (i = 0; i < CELT_MAX_BANDS; i++) {
         float bits = 0.0f;
diff --git a/libavcodec/opusenc_psy.h b/libavcodec/opusenc_psy.h
index bc1a88c03d..2d35e76d2c 100644
--- a/libavcodec/opusenc_psy.h
+++ b/libavcodec/opusenc_psy.h
@@ -26,6 +26,7 @@
 #include "libavutil/mem_internal.h"
 
 #include "opusenc.h"
+#include "opusenc_rc.h"
 #include "opus_celt.h"
 #include "opusenc_utils.h"
 
diff --git a/libavcodec/opusenc_rc.c b/libavcodec/opusenc_rc.c
new file mode 100644
index 0000000000..6c749c3a34
--- /dev/null
+++ b/libavcodec/opusenc_rc.c
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2012 Andrew D'Addesio
+ * Copyright (c) 2013-2014 Mozilla Corporation
+ * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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/avassert.h"
+#include "libavutil/intreadwrite.h"
+
+#include "opusenc_rc.h"
+
+#define OPUS_RC_BITS 32
+#define OPUS_RC_SHIFT (OPUS_RC_BITS - OPUS_RC_SYM - 1)
+
+static av_always_inline void opus_rc_enc_carryout(OpusEncRangeCoder *rc, int cbuf)
+{
+    const int cb = cbuf >> OPUS_RC_SYM, mb = (OPUS_RC_CEIL + cb) & OPUS_RC_CEIL;
+    if (cbuf == OPUS_RC_CEIL) {
+        rc->ext++;
+        return;
+    }
+    rc->rng_cur[0] = rc->rem + cb;
+    rc->rng_cur += (rc->rem >= 0);
+    for (; rc->ext > 0; rc->ext--)
+        *rc->rng_cur++ = mb;
+    av_assert0(rc->rng_cur < rc->c.rb.position);
+    rc->rem = cbuf & OPUS_RC_CEIL; /* Propagate */
+}
+
+static av_always_inline void opus_rc_enc_normalize(OpusEncRangeCoder *rc)
+{
+    while (rc->c.range <= OPUS_RC_BOT) {
+        opus_rc_enc_carryout(rc, rc->c.value >> OPUS_RC_SHIFT);
+        rc->c.value = (rc->c.value << OPUS_RC_SYM) & (OPUS_RC_TOP - 1);
+        rc->c.range     <<= OPUS_RC_SYM;
+        rc->c.total_bits += OPUS_RC_SYM;
+    }
+}
+
+/* Main encoding function, this needs to go fast */
+static av_always_inline void opus_rc_enc_update(OpusEncRangeCoder *rc, uint32_t b, uint32_t p,
+                                                uint32_t p_tot, const int ptwo)
+{
+    uint32_t rscaled, cnd = !!b;
+    if (ptwo) /* Whole function is inlined so hopefully branch is optimized out */
+        rscaled = rc->c.range >> ff_log2(p_tot);
+    else
+        rscaled = rc->c.range/p_tot;
+    rc->c.value +=    cnd*(rc->c.range - rscaled*(p_tot - b));
+    rc->c.range  = (!cnd)*(rc->c.range - rscaled*(p_tot - p)) + cnd*rscaled*(p - b);
+    opus_rc_enc_normalize(rc);
+}
+
+void ff_opus_rc_enc_cdf(OpusEncRangeCoder *rc, int val, const uint16_t *cdf)
+{
+    opus_rc_enc_update(rc, (!!val)*cdf[val], cdf[val + 1], cdf[0], 1);
+}
+
+void ff_opus_rc_enc_log(OpusEncRangeCoder *rc, int val, uint32_t bits)
+{
+    bits = (1 << bits) - 1;
+    opus_rc_enc_update(rc, (!!val)*bits, bits + !!val, bits + 1, 1);
+}
+
+/**
+ * CELT: write 0 - 31 bits to the rawbits buffer
+ */
+void ff_opus_rc_put_raw(OpusEncRangeCoder *rc, uint32_t val, uint32_t count)
+{
+    const int to_write = FFMIN(32 - rc->c.rb.cachelen, count);
+
+    rc->c.total_bits += count;
+    rc->c.rb.cacheval |= av_mod_uintp2(val, to_write) << rc->c.rb.cachelen;
+    rc->c.rb.cachelen = (rc->c.rb.cachelen + to_write) % 32;
+
+    if (!rc->c.rb.cachelen && count) {
+        AV_WB32((uint8_t *)rc->c.rb.position, rc->c.rb.cacheval);
+        rc->c.rb.bytes    += 4;
+        rc->c.rb.position -= 4;
+        rc->c.rb.cachelen = count - to_write;
+        rc->c.rb.cacheval = av_mod_uintp2(val >> to_write, rc->c.rb.cachelen);
+        av_assert0(rc->rng_cur < rc->c.rb.position);
+    }
+}
+
+/**
+ * CELT: write a uniformly distributed integer
+ */
+void ff_opus_rc_enc_uint(OpusEncRangeCoder *rc, uint32_t val, uint32_t size)
+{
+    const int ps = FFMAX(opus_ilog(size - 1) - 8, 0);
+    opus_rc_enc_update(rc, val >> ps, (val >> ps) + 1, ((size - 1) >> ps) + 1, 0);
+    ff_opus_rc_put_raw(rc, val, ps);
+}
+
+void ff_opus_rc_enc_uint_step(OpusEncRangeCoder *rc, uint32_t val, int k0)
+{
+    const uint32_t a = val <= k0, b = 2*a + 1;
+    k0 = (k0 + 1) << 1;
+    val = b*(val + k0) - 3*a*k0;
+    opus_rc_enc_update(rc, val, val + b, (k0 << 1) - 1, 0);
+}
+
+void ff_opus_rc_enc_uint_tri(OpusEncRangeCoder *rc, uint32_t k, int qn)
+{
+    uint32_t symbol, low, total;
+
+    total = ((qn>>1) + 1) * ((qn>>1) + 1);
+
+    if (k <= qn >> 1) {
+        low    = k * (k + 1) >> 1;
+        symbol = k + 1;
+    } else {
+        low    = total - ((qn + 1 - k) * (qn + 2 - k) >> 1);
+        symbol = qn + 1 - k;
+    }
+
+    opus_rc_enc_update(rc, low, low + symbol, total, 0);
+}
+
+void ff_opus_rc_enc_laplace(OpusEncRangeCoder *rc, int *value, uint32_t symbol, int decay)
+{
+    uint32_t low = symbol;
+    int i = 1, val = FFABS(*value), pos = *value > 0;
+    if (!val) {
+        opus_rc_enc_update(rc, 0, symbol, 1 << 15, 1);
+        return;
+    }
+    symbol = ((32768 - 32 - symbol)*(16384 - decay)) >> 15;
+    for (; i < val && symbol; i++) {
+        low   += (symbol << 1) + 2;
+        symbol = (symbol*decay) >> 14;
+    }
+    if (symbol) {
+        low += (++symbol)*pos;
+    } else {
+        const int distance = FFMIN(val - i, (((32768 - low) - !pos) >> 1) - 1);
+        low   += pos + (distance << 1);
+        symbol = FFMIN(1, 32768 - low);
+        *value = FFSIGN(*value)*(distance + i);
+    }
+    opus_rc_enc_update(rc, low, low + symbol, 1 << 15, 1);
+}
+
+void ff_opus_rc_enc_end(OpusEncRangeCoder *rc, uint8_t *dst, int size)
+{
+    int rng_bytes, bits = OPUS_RC_BITS - opus_ilog(rc->c.range);
+    uint32_t mask = (OPUS_RC_TOP - 1) >> bits;
+    uint32_t end = (rc->c.value + mask) & ~mask;
+
+    if ((end | mask) >= rc->c.value + rc->c.range) {
+        bits++;
+        mask >>= 1;
+        end = (rc->c.value + mask) & ~mask;
+    }
+
+    /* Finish what's left */
+    while (bits > 0) {
+        opus_rc_enc_carryout(rc, end >> OPUS_RC_SHIFT);
+        end = (end << OPUS_RC_SYM) & (OPUS_RC_TOP - 1);
+        bits -= OPUS_RC_SYM;
+    }
+
+    /* Flush out anything left or marked */
+    if (rc->rem >= 0 || rc->ext > 0)
+        opus_rc_enc_carryout(rc, 0);
+
+    rng_bytes = rc->rng_cur - rc->buf;
+    memcpy(dst, rc->buf, rng_bytes);
+
+    /* Put the rawbits part, if any */
+    if (rc->c.rb.bytes || rc->c.rb.cachelen) {
+        int lap;
+        uint8_t *rb_src, *rb_dst;
+        ff_opus_rc_put_raw(rc, 0, 32 - rc->c.rb.cachelen);
+        rb_src = rc->buf + OPUS_MAX_FRAME_SIZE + 12 - rc->c.rb.bytes;
+        rb_dst = dst + FFMAX(size - rc->c.rb.bytes, 0);
+        lap = &dst[rng_bytes] - rb_dst;
+        for (int i = 0; i < lap; i++)
+            rb_dst[i] |= rb_src[i];
+        memcpy(&rb_dst[lap], &rb_src[lap], FFMAX(rc->c.rb.bytes - lap, 0));
+    }
+}
+
+void ff_opus_rc_enc_init(OpusEncRangeCoder *rc)
+{
+    rc->c.value = 0;
+    rc->c.range = OPUS_RC_TOP;
+    rc->c.total_bits = OPUS_RC_BITS + 1;
+    rc->rem = -1;
+    rc->ext =  0;
+    rc->rng_cur = rc->buf;
+    ff_opus_rc_raw_init(&rc->c, rc->buf + OPUS_MAX_FRAME_SIZE + 8, 0);
+}
diff --git a/libavcodec/opusenc_rc.h b/libavcodec/opusenc_rc.h
new file mode 100644
index 0000000000..40c48d04f0
--- /dev/null
+++ b/libavcodec/opusenc_rc.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2012 Andrew D'Addesio
+ * Copyright (c) 2013-2014 Mozilla Corporation
+ * Copyright (c) 2017 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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
+ */
+
+#ifndef AVCODEC_OPUSENC_RC_H
+#define AVCODEC_OPUSENC_RC_H
+
+#include <stdint.h>
+
+#include "opus.h"
+#include "opus_rc.h"
+
+typedef struct OpusEncRangeCoder {
+    OpusRangeCoder c;
+
+    uint8_t *rng_cur;                      /* Current range coded byte */
+    int ext;                               /* Awaiting propagation */
+    int rem;                               /* Carryout flag */
+    uint8_t buf[OPUS_MAX_FRAME_SIZE + 12]; /* memcpy vs (memmove + overreading) */
+} OpusEncRangeCoder;
+
+void ff_opus_rc_enc_cdf(OpusEncRangeCoder *rc, int val, const uint16_t *cdf);
+void ff_opus_rc_enc_log(OpusEncRangeCoder *rc, int val, uint32_t bits);
+void ff_opus_rc_enc_uint_step(OpusEncRangeCoder *rc, uint32_t val, int k0);
+void ff_opus_rc_enc_uint_tri(OpusEncRangeCoder *rc, uint32_t k, int qn);
+void ff_opus_rc_enc_uint(OpusEncRangeCoder *rc, uint32_t val, uint32_t size);
+void ff_opus_rc_put_raw(OpusEncRangeCoder *rc, uint32_t val, uint32_t count);
+void ff_opus_rc_enc_laplace(OpusEncRangeCoder *rc, int *value, uint32_t symbol, int decay);
+void ff_opus_rc_enc_end(OpusEncRangeCoder *rc, uint8_t *dst, int size);
+void ff_opus_rc_enc_init(OpusEncRangeCoder *rc);
+
+#define OPUS_RC_CHECKPOINT_UPDATE(rc) \
+    rc_rollback_bits = opus_rc_tell_frac(&rc->c); \
+    rc_rollback_ctx  = *rc
+
+#define OPUS_RC_CHECKPOINT_SPAWN(rc) \
+    uint32_t rc_rollback_bits = opus_rc_tell_frac(&rc->c); \
+    OpusEncRangeCoder rc_rollback_ctx = *rc \
+
+#define OPUS_RC_CHECKPOINT_BITS(rc) \
+    (opus_rc_tell_frac(&rc->c) - rc_rollback_bits)
+
+#define OPUS_RC_CHECKPOINT_ROLLBACK(rc) \
+    memcpy(rc, &rc_rollback_ctx, sizeof(*rc)); \
+
+#endif /* AVCODEC_OPUSENC_RC_H */
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 8/9] avcodec/opus: Rename opus.c->opus_celt.c, opus_celt.c->opusdec_celt.c
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
                   ` (5 preceding siblings ...)
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 7/9] avcodec/opus_rc: Split de/encoder-only parts off OpusRangeContext Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 9/9] avcodec/opus_pvq: Avoid indirection when possible Andreas Rheinhardt
  2022-10-08  3:25 ` [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Lynne
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Since commit 4fc2531fff112836026aad2bdaf128c9d15a72e3 opus.c
contains only the celt stuff shared between decoder and encoder.
meanwhile, opus_celt.c is decoder-only. So the new names
reflect the actual content better than the current ones.

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/Makefile       |   4 +-
 libavcodec/opus.c         | 522 ----------------------
 libavcodec/opus_celt.c    | 899 ++++++++++++++++++--------------------
 libavcodec/opusdec_celt.c | 587 +++++++++++++++++++++++++
 4 files changed, 1006 insertions(+), 1006 deletions(-)
 delete mode 100644 libavcodec/opus.c
 create mode 100644 libavcodec/opusdec_celt.c

diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index b7eb3b1e48..949c65a0e3 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -554,10 +554,10 @@ OBJS-$(CONFIG_NELLYMOSER_ENCODER)      += nellymoserenc.o nellymoser.o
 OBJS-$(CONFIG_NOTCHLC_DECODER)         += notchlc.o
 OBJS-$(CONFIG_NUV_DECODER)             += nuv.o rtjpeg.o
 OBJS-$(CONFIG_ON2AVC_DECODER)          += on2avc.o on2avcdata.o
-OBJS-$(CONFIG_OPUS_DECODER)            += opusdec.o opus.o opus_celt.o \
+OBJS-$(CONFIG_OPUS_DECODER)            += opusdec.o opusdec_celt.o opus_celt.o \
                                           opus_pvq.o opus_silk.o opustab.o vorbis_data.o \
                                           opusdec_rc.o opusdsp.o opus_parse.o
-OBJS-$(CONFIG_OPUS_ENCODER)            += opusenc.o opus.o opusenc_psy.o \
+OBJS-$(CONFIG_OPUS_ENCODER)            += opusenc.o opus_celt.o opusenc_psy.o \
                                           opusenc_rc.o opustab.o opus_pvq.o
 OBJS-$(CONFIG_PAF_AUDIO_DECODER)       += pafaudio.o
 OBJS-$(CONFIG_PAF_VIDEO_DECODER)       += pafvideo.o
diff --git a/libavcodec/opus.c b/libavcodec/opus.c
deleted file mode 100644
index 8def5e6e34..0000000000
--- a/libavcodec/opus.c
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * Copyright (c) 2012 Andrew D'Addesio
- * Copyright (c) 2013-2014 Mozilla Corporation
- *
- * 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 <stdint.h>
-
-#include "config_components.h"
-#include "opus_celt.h"
-#include "opus_pvq.h"
-#include "opustab.h"
-#include "opus_rc.h"
-#include "opusdec_rc.h"
-#include "opusenc_rc.h"
-
-#if !CONFIG_OPUS_ENCODER
-#define ff_opus_rc_enc_log(...)
-#define ff_opus_rc_enc_cdf(...)
-#define ff_opus_rc_enc_uint(...)
-#endif
-
-#if !CONFIG_OPUS_DECODER
-#define ff_opus_rc_dec_log(...) 0
-#define ff_opus_rc_dec_cdf(...) 0
-#define ff_opus_rc_dec_uint(...) 0
-#endif
-
-static inline void opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits)
-{
-    ff_opus_rc_enc_log((OpusEncRangeCoder*)rc, val, bits);
-}
-
-static inline uint32_t opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits)
-{
-    return ff_opus_rc_dec_log((OpusDecRangeCoder*)rc, bits);
-}
-
-static inline void opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf)
-{
-    ff_opus_rc_enc_cdf((OpusEncRangeCoder*)rc, val, cdf);
-}
-
-static inline uint32_t opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf)
-{
-    return ff_opus_rc_dec_cdf((OpusDecRangeCoder*)rc, cdf);
-}
-
-void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc)
-{
-    float lowband_scratch[8 * 22];
-    float norm1[2 * 8 * 100];
-    float *norm2 = norm1 + 8 * 100;
-
-    int totalbits = (f->framebits << 3) - f->anticollapse_needed;
-
-    int update_lowband = 1;
-    int lowband_offset = 0;
-
-    int i, j;
-
-    for (i = f->start_band; i < f->end_band; i++) {
-        uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 };
-        int band_offset = ff_celt_freq_bands[i] << f->size;
-        int band_size   = ff_celt_freq_range[i] << f->size;
-        float *X = f->block[0].coeffs + band_offset;
-        float *Y = (f->channels == 2) ? f->block[1].coeffs + band_offset : NULL;
-        float *norm_loc1, *norm_loc2;
-
-        int consumed = opus_rc_tell_frac(rc);
-        int effective_lowband = -1;
-        int b = 0;
-
-        /* Compute how many bits we want to allocate to this band */
-        if (i != f->start_band)
-            f->remaining -= consumed;
-        f->remaining2 = totalbits - consumed - 1;
-        if (i <= f->coded_bands - 1) {
-            int curr_balance = f->remaining / FFMIN(3, f->coded_bands-i);
-            b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[i] + curr_balance), 14);
-        }
-
-        if ((ff_celt_freq_bands[i] - ff_celt_freq_range[i] >= ff_celt_freq_bands[f->start_band] ||
-            i == f->start_band + 1) && (update_lowband || lowband_offset == 0))
-            lowband_offset = i;
-
-        if (i == f->start_band + 1) {
-            /* Special Hybrid Folding (RFC 8251 section 9). Copy the first band into
-            the second to ensure the second band never has to use the LCG. */
-            int count = (ff_celt_freq_range[i] - ff_celt_freq_range[i-1]) << f->size;
-
-            memcpy(&norm1[band_offset], &norm1[band_offset - count], count * sizeof(float));
-
-            if (f->channels == 2)
-                memcpy(&norm2[band_offset], &norm2[band_offset - count], count * sizeof(float));
-        }
-
-        /* Get a conservative estimate of the collapse_mask's for the bands we're
-           going to be folding from. */
-        if (lowband_offset != 0 && (f->spread != CELT_SPREAD_AGGRESSIVE ||
-                                    f->blocks > 1 || f->tf_change[i] < 0)) {
-            int foldstart, foldend;
-
-            /* This ensures we never repeat spectral content within one band */
-            effective_lowband = FFMAX(ff_celt_freq_bands[f->start_band],
-                                      ff_celt_freq_bands[lowband_offset] - ff_celt_freq_range[i]);
-            foldstart = lowband_offset;
-            while (ff_celt_freq_bands[--foldstart] > effective_lowband);
-            foldend = lowband_offset - 1;
-            while (++foldend < i && ff_celt_freq_bands[foldend] < effective_lowband + ff_celt_freq_range[i]);
-
-            cm[0] = cm[1] = 0;
-            for (j = foldstart; j < foldend; j++) {
-                cm[0] |= f->block[0].collapse_masks[j];
-                cm[1] |= f->block[f->channels - 1].collapse_masks[j];
-            }
-        }
-
-        if (f->dual_stereo && i == f->intensity_stereo) {
-            /* Switch off dual stereo to do intensity */
-            f->dual_stereo = 0;
-            for (j = ff_celt_freq_bands[f->start_band] << f->size; j < band_offset; j++)
-                norm1[j] = (norm1[j] + norm2[j]) / 2;
-        }
-
-        norm_loc1 = effective_lowband != -1 ? norm1 + (effective_lowband << f->size) : NULL;
-        norm_loc2 = effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL;
-
-        if (f->dual_stereo) {
-            cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X, NULL, band_size, b >> 1,
-                                       f->blocks, norm_loc1, f->size,
-                                       norm1 + band_offset, 0, 1.0f,
-                                       lowband_scratch, cm[0]);
-
-            cm[1] = f->pvq->quant_band(f->pvq, f, rc, i, Y, NULL, band_size, b >> 1,
-                                       f->blocks, norm_loc2, f->size,
-                                       norm2 + band_offset, 0, 1.0f,
-                                       lowband_scratch, cm[1]);
-        } else {
-            cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X,    Y, band_size, b >> 0,
-                                       f->blocks, norm_loc1, f->size,
-                                       norm1 + band_offset, 0, 1.0f,
-                                       lowband_scratch, cm[0] | cm[1]);
-            cm[1] = cm[0];
-        }
-
-        f->block[0].collapse_masks[i]               = (uint8_t)cm[0];
-        f->block[f->channels - 1].collapse_masks[i] = (uint8_t)cm[1];
-        f->remaining += f->pulses[i] + consumed;
-
-        /* Update the folding position only as long as we have 1 bit/sample depth */
-        update_lowband = (b > band_size << 3);
-    }
-}
-
-#define NORMC(bits) ((bits) << (f->channels - 1) << f->size >> 2)
-
-void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
-{
-    int i, j, low, high, total, done, bandbits, remaining, tbits_8ths;
-    int skip_startband      = f->start_band;
-    int skip_bit            = 0;
-    int intensitystereo_bit = 0;
-    int dualstereo_bit      = 0;
-    int dynalloc            = 6;
-    int extrabits           = 0;
-
-    int boost[CELT_MAX_BANDS] = { 0 };
-    int trim_offset[CELT_MAX_BANDS];
-    int threshold[CELT_MAX_BANDS];
-    int bits1[CELT_MAX_BANDS];
-    int bits2[CELT_MAX_BANDS];
-
-    if (!CONFIG_OPUS_DECODER || !CONFIG_OPUS_ENCODER)
-        encode = CONFIG_OPUS_ENCODER;
-    /* Spread */
-    if (opus_rc_tell(rc) + 4 <= f->framebits) {
-        if (encode)
-            opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread);
-        else
-            f->spread = opus_rc_dec_cdf(rc, ff_celt_model_spread);
-    } else {
-        f->spread = CELT_SPREAD_NORMAL;
-    }
-
-    /* Initialize static allocation caps */
-    for (i = 0; i < CELT_MAX_BANDS; i++)
-        f->caps[i] = NORMC((ff_celt_static_caps[f->size][f->channels - 1][i] + 64) * ff_celt_freq_range[i]);
-
-    /* Band boosts */
-    tbits_8ths = f->framebits << 3;
-    for (i = f->start_band; i < f->end_band; i++) {
-        int quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size;
-        int b_dynalloc = dynalloc;
-        int boost_amount = f->alloc_boost[i];
-        quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta));
-
-        while (opus_rc_tell_frac(rc) + (b_dynalloc << 3) < tbits_8ths && boost[i] < f->caps[i]) {
-            int is_boost;
-            if (encode) {
-                is_boost = boost_amount--;
-                opus_rc_enc_log(rc, is_boost, b_dynalloc);
-            } else {
-                is_boost = opus_rc_dec_log(rc, b_dynalloc);
-            }
-
-            if (!is_boost)
-                break;
-
-            boost[i]   += quanta;
-            tbits_8ths -= quanta;
-
-            b_dynalloc = 1;
-        }
-
-        if (boost[i])
-            dynalloc = FFMAX(dynalloc - 1, 2);
-    }
-
-    /* Allocation trim */
-    if (!encode)
-        f->alloc_trim = 5;
-    if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths)
-        if (encode)
-            opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim);
-        else
-            f->alloc_trim = opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim);
-
-    /* Anti-collapse bit reservation */
-    tbits_8ths = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1;
-    f->anticollapse_needed = 0;
-    if (f->transient && f->size >= 2 && tbits_8ths >= ((f->size + 2) << 3))
-        f->anticollapse_needed = 1 << 3;
-    tbits_8ths -= f->anticollapse_needed;
-
-    /* Band skip bit reservation */
-    if (tbits_8ths >= 1 << 3)
-        skip_bit = 1 << 3;
-    tbits_8ths -= skip_bit;
-
-    /* Intensity/dual stereo bit reservation */
-    if (f->channels == 2) {
-        intensitystereo_bit = ff_celt_log2_frac[f->end_band - f->start_band];
-        if (intensitystereo_bit <= tbits_8ths) {
-            tbits_8ths -= intensitystereo_bit;
-            if (tbits_8ths >= 1 << 3) {
-                dualstereo_bit = 1 << 3;
-                tbits_8ths -= 1 << 3;
-            }
-        } else {
-            intensitystereo_bit = 0;
-        }
-    }
-
-    /* Trim offsets */
-    for (i = f->start_band; i < f->end_band; i++) {
-        int trim     = f->alloc_trim - 5 - f->size;
-        int band     = ff_celt_freq_range[i] * (f->end_band - i - 1);
-        int duration = f->size + 3;
-        int scale    = duration + f->channels - 1;
-
-        /* PVQ minimum allocation threshold, below this value the band is
-         * skipped */
-        threshold[i] = FFMAX(3 * ff_celt_freq_range[i] << duration >> 4,
-                             f->channels << 3);
-
-        trim_offset[i] = trim * (band << scale) >> 6;
-
-        if (ff_celt_freq_range[i] << f->size == 1)
-            trim_offset[i] -= f->channels << 3;
-    }
-
-    /* Bisection */
-    low  = 1;
-    high = CELT_VECTORS - 1;
-    while (low <= high) {
-        int center = (low + high) >> 1;
-        done = total = 0;
-
-        for (i = f->end_band - 1; i >= f->start_band; i--) {
-            bandbits = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[center][i]);
-
-            if (bandbits)
-                bandbits = FFMAX(bandbits + trim_offset[i], 0);
-            bandbits += boost[i];
-
-            if (bandbits >= threshold[i] || done) {
-                done = 1;
-                total += FFMIN(bandbits, f->caps[i]);
-            } else if (bandbits >= f->channels << 3) {
-                total += f->channels << 3;
-            }
-        }
-
-        if (total > tbits_8ths)
-            high = center - 1;
-        else
-            low = center + 1;
-    }
-    high = low--;
-
-    /* Bisection */
-    for (i = f->start_band; i < f->end_band; i++) {
-        bits1[i] = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[low][i]);
-        bits2[i] = high >= CELT_VECTORS ? f->caps[i] :
-                   NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[high][i]);
-
-        if (bits1[i])
-            bits1[i] = FFMAX(bits1[i] + trim_offset[i], 0);
-        if (bits2[i])
-            bits2[i] = FFMAX(bits2[i] + trim_offset[i], 0);
-
-        if (low)
-            bits1[i] += boost[i];
-        bits2[i] += boost[i];
-
-        if (boost[i])
-            skip_startband = i;
-        bits2[i] = FFMAX(bits2[i] - bits1[i], 0);
-    }
-
-    /* Bisection */
-    low  = 0;
-    high = 1 << CELT_ALLOC_STEPS;
-    for (i = 0; i < CELT_ALLOC_STEPS; i++) {
-        int center = (low + high) >> 1;
-        done = total = 0;
-
-        for (j = f->end_band - 1; j >= f->start_band; j--) {
-            bandbits = bits1[j] + (center * bits2[j] >> CELT_ALLOC_STEPS);
-
-            if (bandbits >= threshold[j] || done) {
-                done = 1;
-                total += FFMIN(bandbits, f->caps[j]);
-            } else if (bandbits >= f->channels << 3)
-                total += f->channels << 3;
-        }
-        if (total > tbits_8ths)
-            high = center;
-        else
-            low = center;
-    }
-
-    /* Bisection */
-    done = total = 0;
-    for (i = f->end_band - 1; i >= f->start_band; i--) {
-        bandbits = bits1[i] + (low * bits2[i] >> CELT_ALLOC_STEPS);
-
-        if (bandbits >= threshold[i] || done)
-            done = 1;
-        else
-            bandbits = (bandbits >= f->channels << 3) ?
-            f->channels << 3 : 0;
-
-        bandbits     = FFMIN(bandbits, f->caps[i]);
-        f->pulses[i] = bandbits;
-        total      += bandbits;
-    }
-
-    /* Band skipping */
-    for (f->coded_bands = f->end_band; ; f->coded_bands--) {
-        int allocation;
-        j = f->coded_bands - 1;
-
-        if (j == skip_startband) {
-            /* all remaining bands are not skipped */
-            tbits_8ths += skip_bit;
-            break;
-        }
-
-        /* determine the number of bits available for coding "do not skip" markers */
-        remaining   = tbits_8ths - total;
-        bandbits    = remaining / (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]);
-        remaining  -= bandbits  * (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]);
-        allocation  = f->pulses[j] + bandbits * ff_celt_freq_range[j];
-        allocation += FFMAX(remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band]), 0);
-
-        /* a "do not skip" marker is only coded if the allocation is
-         * above the chosen threshold */
-        if (allocation >= FFMAX(threshold[j], (f->channels + 1) << 3)) {
-            int do_not_skip;
-            if (encode) {
-                do_not_skip = f->coded_bands <= f->skip_band_floor;
-                opus_rc_enc_log(rc, do_not_skip, 1);
-            } else {
-                do_not_skip = opus_rc_dec_log(rc, 1);
-            }
-
-            if (do_not_skip)
-                break;
-
-            total      += 1 << 3;
-            allocation -= 1 << 3;
-        }
-
-        /* the band is skipped, so reclaim its bits */
-        total -= f->pulses[j];
-        if (intensitystereo_bit) {
-            total -= intensitystereo_bit;
-            intensitystereo_bit = ff_celt_log2_frac[j - f->start_band];
-            total += intensitystereo_bit;
-        }
-
-        total += f->pulses[j] = (allocation >= f->channels << 3) ? f->channels << 3 : 0;
-    }
-
-    /* IS start band */
-    if (encode) {
-        if (intensitystereo_bit) {
-            f->intensity_stereo = FFMIN(f->intensity_stereo, f->coded_bands);
-            ff_opus_rc_enc_uint((OpusEncRangeCoder*)rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band);
-        }
-    } else {
-        f->intensity_stereo = f->dual_stereo = 0;
-        if (intensitystereo_bit)
-            f->intensity_stereo = f->start_band + ff_opus_rc_dec_uint((OpusDecRangeCoder*)rc, f->coded_bands + 1 - f->start_band);
-    }
-
-    /* DS flag */
-    if (f->intensity_stereo <= f->start_band)
-        tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */
-    else if (dualstereo_bit)
-        if (encode)
-            opus_rc_enc_log(rc, f->dual_stereo, 1);
-        else
-            f->dual_stereo = opus_rc_dec_log(rc, 1);
-
-    /* Supply the remaining bits in this frame to lower bands */
-    remaining = tbits_8ths - total;
-    bandbits  = remaining / (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]);
-    remaining -= bandbits * (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]);
-    for (i = f->start_band; i < f->coded_bands; i++) {
-        const int bits = FFMIN(remaining, ff_celt_freq_range[i]);
-        f->pulses[i] += bits + bandbits * ff_celt_freq_range[i];
-        remaining    -= bits;
-    }
-
-    /* Finally determine the allocation */
-    for (i = f->start_band; i < f->coded_bands; i++) {
-        int N = ff_celt_freq_range[i] << f->size;
-        int prev_extra = extrabits;
-        f->pulses[i] += extrabits;
-
-        if (N > 1) {
-            int dof;        /* degrees of freedom */
-            int temp;       /* dof * channels * log(dof) */
-            int fine_bits;
-            int max_bits;
-            int offset;     /* fine energy quantization offset, i.e.
-                             * extra bits assigned over the standard
-                             * totalbits/dof */
-
-            extrabits = FFMAX(f->pulses[i] - f->caps[i], 0);
-            f->pulses[i] -= extrabits;
-
-            /* intensity stereo makes use of an extra degree of freedom */
-            dof = N * f->channels + (f->channels == 2 && N > 2 && !f->dual_stereo && i < f->intensity_stereo);
-            temp = dof * (ff_celt_log_freq_range[i] + (f->size << 3));
-            offset = (temp >> 1) - dof * CELT_FINE_OFFSET;
-            if (N == 2) /* dof=2 is the only case that doesn't fit the model */
-                offset += dof << 1;
-
-            /* grant an additional bias for the first and second pulses */
-            if (f->pulses[i] + offset < 2 * (dof << 3))
-                offset += temp >> 2;
-            else if (f->pulses[i] + offset < 3 * (dof << 3))
-                offset += temp >> 3;
-
-            fine_bits = (f->pulses[i] + offset + (dof << 2)) / (dof << 3);
-            max_bits  = FFMIN((f->pulses[i] >> 3) >> (f->channels - 1), CELT_MAX_FINE_BITS);
-            max_bits  = FFMAX(max_bits, 0);
-            f->fine_bits[i] = av_clip(fine_bits, 0, max_bits);
-
-            /* If fine_bits was rounded down or capped,
-             * give priority for the final fine energy pass */
-            f->fine_priority[i] = (f->fine_bits[i] * (dof << 3) >= f->pulses[i] + offset);
-
-            /* the remaining bits are assigned to PVQ */
-            f->pulses[i] -= f->fine_bits[i] << (f->channels - 1) << 3;
-        } else {
-            /* all bits go to fine energy except for the sign bit */
-            extrabits = FFMAX(f->pulses[i] - (f->channels << 3), 0);
-            f->pulses[i] -= extrabits;
-            f->fine_bits[i] = 0;
-            f->fine_priority[i] = 1;
-        }
-
-        /* hand back a limited number of extra fine energy bits to this band */
-        if (extrabits > 0) {
-            int fineextra = FFMIN(extrabits >> (f->channels + 2),
-                                  CELT_MAX_FINE_BITS - f->fine_bits[i]);
-            f->fine_bits[i] += fineextra;
-
-            fineextra <<= f->channels + 2;
-            f->fine_priority[i] = (fineextra >= extrabits - prev_extra);
-            extrabits -= fineextra;
-        }
-    }
-    f->remaining = extrabits;
-
-    /* skipped bands dedicate all of their bits for fine energy */
-    for (; i < f->end_band; i++) {
-        f->fine_bits[i]     = f->pulses[i] >> (f->channels - 1) >> 3;
-        f->pulses[i]        = 0;
-        f->fine_priority[i] = f->fine_bits[i] < 1;
-    }
-}
diff --git a/libavcodec/opus_celt.c b/libavcodec/opus_celt.c
index a14764ec18..8def5e6e34 100644
--- a/libavcodec/opus_celt.c
+++ b/libavcodec/opus_celt.c
@@ -1,7 +1,6 @@
 /*
  * Copyright (c) 2012 Andrew D'Addesio
  * Copyright (c) 2013-2014 Mozilla Corporation
- * Copyright (c) 2016 Rostislav Pehlivanov <atomnuker@gmail.com>
  *
  * This file is part of FFmpeg.
  *
@@ -20,568 +19,504 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
-/**
- * @file
- * Opus CELT decoder
- */
-
-#include <float.h>
+#include <stdint.h>
 
+#include "config_components.h"
 #include "opus_celt.h"
-#include "opusdec_rc.h"
-#include "opustab.h"
 #include "opus_pvq.h"
+#include "opustab.h"
+#include "opus_rc.h"
+#include "opusdec_rc.h"
+#include "opusenc_rc.h"
 
-/* Use the 2D z-transform to apply prediction in both the time domain (alpha)
- * and the frequency domain (beta) */
-static void celt_decode_coarse_energy(CeltFrame *f, OpusDecRangeCoder *rc)
-{
-    int i, j;
-    float prev[2] = { 0 };
-    float alpha = ff_celt_alpha_coef[f->size];
-    float beta  = ff_celt_beta_coef[f->size];
-    const uint8_t *model = ff_celt_coarse_energy_dist[f->size][0];
-
-    /* intra frame */
-    if (opus_rc_tell(&rc->c) + 3 <= f->framebits && ff_opus_rc_dec_log(rc, 3)) {
-        alpha = 0.0f;
-        beta  = 1.0f - (4915.0f/32768.0f);
-        model = ff_celt_coarse_energy_dist[f->size][1];
-    }
-
-    for (i = 0; i < CELT_MAX_BANDS; i++) {
-        for (j = 0; j < f->channels; j++) {
-            CeltBlock *block = &f->block[j];
-            float value;
-            int available;
-
-            if (i < f->start_band || i >= f->end_band) {
-                block->energy[i] = 0.0;
-                continue;
-            }
+#if !CONFIG_OPUS_ENCODER
+#define ff_opus_rc_enc_log(...)
+#define ff_opus_rc_enc_cdf(...)
+#define ff_opus_rc_enc_uint(...)
+#endif
 
-            available = f->framebits - opus_rc_tell(&rc->c);
-            if (available >= 15) {
-                /* decode using a Laplace distribution */
-                int k = FFMIN(i, 20) << 1;
-                value = ff_opus_rc_dec_laplace(rc, model[k] << 7, model[k+1] << 6);
-            } else if (available >= 2) {
-                int x = ff_opus_rc_dec_cdf(rc, ff_celt_model_energy_small);
-                value = (x>>1) ^ -(x&1);
-            } else if (available >= 1) {
-                value = -(float)ff_opus_rc_dec_log(rc, 1);
-            } else value = -1;
-
-            block->energy[i] = FFMAX(-9.0f, block->energy[i]) * alpha + prev[j] + value;
-            prev[j] += beta * value;
-        }
-    }
-}
+#if !CONFIG_OPUS_DECODER
+#define ff_opus_rc_dec_log(...) 0
+#define ff_opus_rc_dec_cdf(...) 0
+#define ff_opus_rc_dec_uint(...) 0
+#endif
 
-static void celt_decode_fine_energy(CeltFrame *f, OpusDecRangeCoder *rc)
+static inline void opus_rc_enc_log(OpusRangeCoder *rc, int val, uint32_t bits)
 {
-    int i;
-    for (i = f->start_band; i < f->end_band; i++) {
-        int j;
-        if (!f->fine_bits[i])
-            continue;
-
-        for (j = 0; j < f->channels; j++) {
-            CeltBlock *block = &f->block[j];
-            int q2;
-            float offset;
-            q2 = ff_opus_rc_get_raw(rc, f->fine_bits[i]);
-            offset = (q2 + 0.5f) * (1 << (14 - f->fine_bits[i])) / 16384.0f - 0.5f;
-            block->energy[i] += offset;
-        }
-    }
+    ff_opus_rc_enc_log((OpusEncRangeCoder*)rc, val, bits);
 }
 
-static void celt_decode_final_energy(CeltFrame *f, OpusDecRangeCoder *rc)
+static inline uint32_t opus_rc_dec_log(OpusRangeCoder *rc, uint32_t bits)
 {
-    int priority, i, j;
-    int bits_left = f->framebits - opus_rc_tell(&rc->c);
-
-    for (priority = 0; priority < 2; priority++) {
-        for (i = f->start_band; i < f->end_band && bits_left >= f->channels; i++) {
-            if (f->fine_priority[i] != priority || f->fine_bits[i] >= CELT_MAX_FINE_BITS)
-                continue;
-
-            for (j = 0; j < f->channels; j++) {
-                int q2;
-                float offset;
-                q2 = ff_opus_rc_get_raw(rc, 1);
-                offset = (q2 - 0.5f) * (1 << (14 - f->fine_bits[i] - 1)) / 16384.0f;
-                f->block[j].energy[i] += offset;
-                bits_left--;
-            }
-        }
-    }
+    return ff_opus_rc_dec_log((OpusDecRangeCoder*)rc, bits);
 }
 
-static void celt_decode_tf_changes(CeltFrame *f, OpusDecRangeCoder *rc)
+static inline void opus_rc_enc_cdf(OpusRangeCoder *rc, int val, const uint16_t *cdf)
 {
-    int i, diff = 0, tf_select = 0, tf_changed = 0, tf_select_bit;
-    int consumed, bits = f->transient ? 2 : 4;
-
-    consumed = opus_rc_tell(&rc->c);
-    tf_select_bit = (f->size != 0 && consumed+bits+1 <= f->framebits);
-
-    for (i = f->start_band; i < f->end_band; i++) {
-        if (consumed+bits+tf_select_bit <= f->framebits) {
-            diff ^= ff_opus_rc_dec_log(rc, bits);
-            consumed = opus_rc_tell(&rc->c);
-            tf_changed |= diff;
-        }
-        f->tf_change[i] = diff;
-        bits = f->transient ? 4 : 5;
-    }
-
-    if (tf_select_bit && ff_celt_tf_select[f->size][f->transient][0][tf_changed] !=
-                         ff_celt_tf_select[f->size][f->transient][1][tf_changed])
-        tf_select = ff_opus_rc_dec_log(rc, 1);
-
-    for (i = f->start_band; i < f->end_band; i++) {
-        f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]];
-    }
+    ff_opus_rc_enc_cdf((OpusEncRangeCoder*)rc, val, cdf);
 }
 
-static void celt_denormalize(CeltFrame *f, CeltBlock *block, float *data)
+static inline uint32_t opus_rc_dec_cdf(OpusRangeCoder *rc, const uint16_t *cdf)
 {
-    int i, j;
-
-    for (i = f->start_band; i < f->end_band; i++) {
-        float *dst = data + (ff_celt_freq_bands[i] << f->size);
-        float log_norm = block->energy[i] + ff_celt_mean_energy[i];
-        float norm = exp2f(FFMIN(log_norm, 32.0f));
-
-        for (j = 0; j < ff_celt_freq_range[i] << f->size; j++)
-            dst[j] *= norm;
-    }
+    return ff_opus_rc_dec_cdf((OpusDecRangeCoder*)rc, cdf);
 }
 
-static void celt_postfilter_apply_transition(CeltBlock *block, float *data)
+void ff_celt_quant_bands(CeltFrame *f, OpusRangeCoder *rc)
 {
-    const int T0 = block->pf_period_old;
-    const int T1 = block->pf_period;
-
-    float g00, g01, g02;
-    float g10, g11, g12;
-
-    float x0, x1, x2, x3, x4;
-
-    int i;
-
-    if (block->pf_gains[0]     == 0.0 &&
-        block->pf_gains_old[0] == 0.0)
-        return;
-
-    g00 = block->pf_gains_old[0];
-    g01 = block->pf_gains_old[1];
-    g02 = block->pf_gains_old[2];
-    g10 = block->pf_gains[0];
-    g11 = block->pf_gains[1];
-    g12 = block->pf_gains[2];
-
-    x1 = data[-T1 + 1];
-    x2 = data[-T1];
-    x3 = data[-T1 - 1];
-    x4 = data[-T1 - 2];
-
-    for (i = 0; i < CELT_OVERLAP; i++) {
-        float w = ff_celt_window2[i];
-        x0 = data[i - T1 + 2];
-
-        data[i] +=  (1.0 - w) * g00 * data[i - T0]                          +
-                    (1.0 - w) * g01 * (data[i - T0 - 1] + data[i - T0 + 1]) +
-                    (1.0 - w) * g02 * (data[i - T0 - 2] + data[i - T0 + 2]) +
-                    w         * g10 * x2                                    +
-                    w         * g11 * (x1 + x3)                             +
-                    w         * g12 * (x0 + x4);
-        x4 = x3;
-        x3 = x2;
-        x2 = x1;
-        x1 = x0;
-    }
-}
+    float lowband_scratch[8 * 22];
+    float norm1[2 * 8 * 100];
+    float *norm2 = norm1 + 8 * 100;
 
-static void celt_postfilter(CeltFrame *f, CeltBlock *block)
-{
-    int len = f->blocksize * f->blocks;
-    const int filter_len = len - 2 * CELT_OVERLAP;
+    int totalbits = (f->framebits << 3) - f->anticollapse_needed;
 
-    celt_postfilter_apply_transition(block, block->buf + 1024);
+    int update_lowband = 1;
+    int lowband_offset = 0;
 
-    block->pf_period_old = block->pf_period;
-    memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains));
+    int i, j;
 
-    block->pf_period = block->pf_period_new;
-    memcpy(block->pf_gains, block->pf_gains_new, sizeof(block->pf_gains));
+    for (i = f->start_band; i < f->end_band; i++) {
+        uint32_t cm[2] = { (1 << f->blocks) - 1, (1 << f->blocks) - 1 };
+        int band_offset = ff_celt_freq_bands[i] << f->size;
+        int band_size   = ff_celt_freq_range[i] << f->size;
+        float *X = f->block[0].coeffs + band_offset;
+        float *Y = (f->channels == 2) ? f->block[1].coeffs + band_offset : NULL;
+        float *norm_loc1, *norm_loc2;
+
+        int consumed = opus_rc_tell_frac(rc);
+        int effective_lowband = -1;
+        int b = 0;
+
+        /* Compute how many bits we want to allocate to this band */
+        if (i != f->start_band)
+            f->remaining -= consumed;
+        f->remaining2 = totalbits - consumed - 1;
+        if (i <= f->coded_bands - 1) {
+            int curr_balance = f->remaining / FFMIN(3, f->coded_bands-i);
+            b = av_clip_uintp2(FFMIN(f->remaining2 + 1, f->pulses[i] + curr_balance), 14);
+        }
 
-    if (len > CELT_OVERLAP) {
-        celt_postfilter_apply_transition(block, block->buf + 1024 + CELT_OVERLAP);
+        if ((ff_celt_freq_bands[i] - ff_celt_freq_range[i] >= ff_celt_freq_bands[f->start_band] ||
+            i == f->start_band + 1) && (update_lowband || lowband_offset == 0))
+            lowband_offset = i;
 
-        if (block->pf_gains[0] > FLT_EPSILON && filter_len > 0)
-            f->opusdsp.postfilter(block->buf + 1024 + 2 * CELT_OVERLAP,
-                                  block->pf_period, block->pf_gains,
-                                  filter_len);
+        if (i == f->start_band + 1) {
+            /* Special Hybrid Folding (RFC 8251 section 9). Copy the first band into
+            the second to ensure the second band never has to use the LCG. */
+            int count = (ff_celt_freq_range[i] - ff_celt_freq_range[i-1]) << f->size;
 
-        block->pf_period_old = block->pf_period;
-        memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains));
-    }
+            memcpy(&norm1[band_offset], &norm1[band_offset - count], count * sizeof(float));
 
-    memmove(block->buf, block->buf + len, (1024 + CELT_OVERLAP / 2) * sizeof(float));
-}
+            if (f->channels == 2)
+                memcpy(&norm2[band_offset], &norm2[band_offset - count], count * sizeof(float));
+        }
 
-static int parse_postfilter(CeltFrame *f, OpusDecRangeCoder *rc, int consumed)
-{
-    int i;
-
-    memset(f->block[0].pf_gains_new, 0, sizeof(f->block[0].pf_gains_new));
-    memset(f->block[1].pf_gains_new, 0, sizeof(f->block[1].pf_gains_new));
-
-    if (f->start_band == 0 && consumed + 16 <= f->framebits) {
-        int has_postfilter = ff_opus_rc_dec_log(rc, 1);
-        if (has_postfilter) {
-            float gain;
-            int tapset, octave, period;
-
-            octave = ff_opus_rc_dec_uint(rc, 6);
-            period = (16 << octave) + ff_opus_rc_get_raw(rc, 4 + octave) - 1;
-            gain   = 0.09375f * (ff_opus_rc_get_raw(rc, 3) + 1);
-            tapset = (opus_rc_tell(&rc->c) + 2 <= f->framebits) ?
-                     ff_opus_rc_dec_cdf(rc, ff_celt_model_tapset) : 0;
-
-            for (i = 0; i < 2; i++) {
-                CeltBlock *block = &f->block[i];
-
-                block->pf_period_new = FFMAX(period, CELT_POSTFILTER_MINPERIOD);
-                block->pf_gains_new[0] = gain * ff_celt_postfilter_taps[tapset][0];
-                block->pf_gains_new[1] = gain * ff_celt_postfilter_taps[tapset][1];
-                block->pf_gains_new[2] = gain * ff_celt_postfilter_taps[tapset][2];
+        /* Get a conservative estimate of the collapse_mask's for the bands we're
+           going to be folding from. */
+        if (lowband_offset != 0 && (f->spread != CELT_SPREAD_AGGRESSIVE ||
+                                    f->blocks > 1 || f->tf_change[i] < 0)) {
+            int foldstart, foldend;
+
+            /* This ensures we never repeat spectral content within one band */
+            effective_lowband = FFMAX(ff_celt_freq_bands[f->start_band],
+                                      ff_celt_freq_bands[lowband_offset] - ff_celt_freq_range[i]);
+            foldstart = lowband_offset;
+            while (ff_celt_freq_bands[--foldstart] > effective_lowband);
+            foldend = lowband_offset - 1;
+            while (++foldend < i && ff_celt_freq_bands[foldend] < effective_lowband + ff_celt_freq_range[i]);
+
+            cm[0] = cm[1] = 0;
+            for (j = foldstart; j < foldend; j++) {
+                cm[0] |= f->block[0].collapse_masks[j];
+                cm[1] |= f->block[f->channels - 1].collapse_masks[j];
             }
         }
 
-        consumed = opus_rc_tell(&rc->c);
-    }
+        if (f->dual_stereo && i == f->intensity_stereo) {
+            /* Switch off dual stereo to do intensity */
+            f->dual_stereo = 0;
+            for (j = ff_celt_freq_bands[f->start_band] << f->size; j < band_offset; j++)
+                norm1[j] = (norm1[j] + norm2[j]) / 2;
+        }
 
-    return consumed;
-}
+        norm_loc1 = effective_lowband != -1 ? norm1 + (effective_lowband << f->size) : NULL;
+        norm_loc2 = effective_lowband != -1 ? norm2 + (effective_lowband << f->size) : NULL;
 
-static void process_anticollapse(CeltFrame *f, CeltBlock *block, float *X)
-{
-    int i, j, k;
+        if (f->dual_stereo) {
+            cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X, NULL, band_size, b >> 1,
+                                       f->blocks, norm_loc1, f->size,
+                                       norm1 + band_offset, 0, 1.0f,
+                                       lowband_scratch, cm[0]);
 
-    for (i = f->start_band; i < f->end_band; i++) {
-        int renormalize = 0;
-        float *xptr;
-        float prev[2];
-        float Ediff, r;
-        float thresh, sqrt_1;
-        int depth;
-
-        /* depth in 1/8 bits */
-        depth = (1 + f->pulses[i]) / (ff_celt_freq_range[i] << f->size);
-        thresh = exp2f(-1.0 - 0.125f * depth);
-        sqrt_1 = 1.0f / sqrtf(ff_celt_freq_range[i] << f->size);
-
-        xptr = X + (ff_celt_freq_bands[i] << f->size);
-
-        prev[0] = block->prev_energy[0][i];
-        prev[1] = block->prev_energy[1][i];
-        if (f->channels == 1) {
-            CeltBlock *block1 = &f->block[1];
-
-            prev[0] = FFMAX(prev[0], block1->prev_energy[0][i]);
-            prev[1] = FFMAX(prev[1], block1->prev_energy[1][i]);
-        }
-        Ediff = block->energy[i] - FFMIN(prev[0], prev[1]);
-        Ediff = FFMAX(0, Ediff);
-
-        /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because
-        short blocks don't have the same energy as long */
-        r = exp2f(1 - Ediff);
-        if (f->size == 3)
-            r *= M_SQRT2;
-        r = FFMIN(thresh, r) * sqrt_1;
-        for (k = 0; k < 1 << f->size; k++) {
-            /* Detect collapse */
-            if (!(block->collapse_masks[i] & 1 << k)) {
-                /* Fill with noise */
-                for (j = 0; j < ff_celt_freq_range[i]; j++)
-                    xptr[(j << f->size) + k] = (celt_rng(f) & 0x8000) ? r : -r;
-                renormalize = 1;
-            }
+            cm[1] = f->pvq->quant_band(f->pvq, f, rc, i, Y, NULL, band_size, b >> 1,
+                                       f->blocks, norm_loc2, f->size,
+                                       norm2 + band_offset, 0, 1.0f,
+                                       lowband_scratch, cm[1]);
+        } else {
+            cm[0] = f->pvq->quant_band(f->pvq, f, rc, i, X,    Y, band_size, b >> 0,
+                                       f->blocks, norm_loc1, f->size,
+                                       norm1 + band_offset, 0, 1.0f,
+                                       lowband_scratch, cm[0] | cm[1]);
+            cm[1] = cm[0];
         }
 
-        /* We just added some energy, so we need to renormalize */
-        if (renormalize)
-            celt_renormalize_vector(xptr, ff_celt_freq_range[i] << f->size, 1.0f);
+        f->block[0].collapse_masks[i]               = (uint8_t)cm[0];
+        f->block[f->channels - 1].collapse_masks[i] = (uint8_t)cm[1];
+        f->remaining += f->pulses[i] + consumed;
+
+        /* Update the folding position only as long as we have 1 bit/sample depth */
+        update_lowband = (b > band_size << 3);
     }
 }
 
-int ff_celt_decode_frame(CeltFrame *f, OpusDecRangeCoder *rc,
-                         float **output, int channels, int frame_size,
-                         int start_band,  int end_band)
-{
-    int i, j, downmix = 0;
-    int consumed;           // bits of entropy consumed thus far for this frame
-    AVTXContext *imdct;
-    av_tx_fn imdct_fn;
-
-    if (channels != 1 && channels != 2) {
-        av_log(f->avctx, AV_LOG_ERROR, "Invalid number of coded channels: %d\n",
-               channels);
-        return AVERROR_INVALIDDATA;
-    }
-    if (start_band < 0 || start_band > end_band || end_band > CELT_MAX_BANDS) {
-        av_log(f->avctx, AV_LOG_ERROR, "Invalid start/end band: %d %d\n",
-               start_band, end_band);
-        return AVERROR_INVALIDDATA;
-    }
+#define NORMC(bits) ((bits) << (f->channels - 1) << f->size >> 2)
 
-    f->silence        = 0;
-    f->transient      = 0;
-    f->anticollapse   = 0;
-    f->flushed        = 0;
-    f->channels       = channels;
-    f->start_band     = start_band;
-    f->end_band       = end_band;
-    f->framebits      = rc->c.rb.bytes * 8;
-
-    f->size = av_log2(frame_size / CELT_SHORT_BLOCKSIZE);
-    if (f->size > CELT_MAX_LOG_BLOCKS ||
-        frame_size != CELT_SHORT_BLOCKSIZE * (1 << f->size)) {
-        av_log(f->avctx, AV_LOG_ERROR, "Invalid CELT frame size: %d\n",
-               frame_size);
-        return AVERROR_INVALIDDATA;
+void ff_celt_bitalloc(CeltFrame *f, OpusRangeCoder *rc, int encode)
+{
+    int i, j, low, high, total, done, bandbits, remaining, tbits_8ths;
+    int skip_startband      = f->start_band;
+    int skip_bit            = 0;
+    int intensitystereo_bit = 0;
+    int dualstereo_bit      = 0;
+    int dynalloc            = 6;
+    int extrabits           = 0;
+
+    int boost[CELT_MAX_BANDS] = { 0 };
+    int trim_offset[CELT_MAX_BANDS];
+    int threshold[CELT_MAX_BANDS];
+    int bits1[CELT_MAX_BANDS];
+    int bits2[CELT_MAX_BANDS];
+
+    if (!CONFIG_OPUS_DECODER || !CONFIG_OPUS_ENCODER)
+        encode = CONFIG_OPUS_ENCODER;
+    /* Spread */
+    if (opus_rc_tell(rc) + 4 <= f->framebits) {
+        if (encode)
+            opus_rc_enc_cdf(rc, f->spread, ff_celt_model_spread);
+        else
+            f->spread = opus_rc_dec_cdf(rc, ff_celt_model_spread);
+    } else {
+        f->spread = CELT_SPREAD_NORMAL;
     }
 
-    if (!f->output_channels)
-        f->output_channels = channels;
+    /* Initialize static allocation caps */
+    for (i = 0; i < CELT_MAX_BANDS; i++)
+        f->caps[i] = NORMC((ff_celt_static_caps[f->size][f->channels - 1][i] + 64) * ff_celt_freq_range[i]);
 
-    for (i = 0; i < f->channels; i++) {
-        memset(f->block[i].coeffs,         0, sizeof(f->block[i].coeffs));
-        memset(f->block[i].collapse_masks, 0, sizeof(f->block[i].collapse_masks));
-    }
+    /* Band boosts */
+    tbits_8ths = f->framebits << 3;
+    for (i = f->start_band; i < f->end_band; i++) {
+        int quanta = ff_celt_freq_range[i] << (f->channels - 1) << f->size;
+        int b_dynalloc = dynalloc;
+        int boost_amount = f->alloc_boost[i];
+        quanta = FFMIN(quanta << 3, FFMAX(6 << 3, quanta));
+
+        while (opus_rc_tell_frac(rc) + (b_dynalloc << 3) < tbits_8ths && boost[i] < f->caps[i]) {
+            int is_boost;
+            if (encode) {
+                is_boost = boost_amount--;
+                opus_rc_enc_log(rc, is_boost, b_dynalloc);
+            } else {
+                is_boost = opus_rc_dec_log(rc, b_dynalloc);
+            }
 
-    consumed = opus_rc_tell(&rc->c);
+            if (!is_boost)
+                break;
 
-    /* obtain silence flag */
-    if (consumed >= f->framebits)
-        f->silence = 1;
-    else if (consumed == 1)
-        f->silence = ff_opus_rc_dec_log(rc, 15);
+            boost[i]   += quanta;
+            tbits_8ths -= quanta;
 
+            b_dynalloc = 1;
+        }
 
-    if (f->silence) {
-        consumed = f->framebits;
-        rc->c.total_bits += f->framebits - opus_rc_tell(&rc->c);
+        if (boost[i])
+            dynalloc = FFMAX(dynalloc - 1, 2);
     }
 
-    /* obtain post-filter options */
-    consumed = parse_postfilter(f, rc, consumed);
-
-    /* obtain transient flag */
-    if (f->size != 0 && consumed+3 <= f->framebits)
-        f->transient = ff_opus_rc_dec_log(rc, 3);
-
-    f->blocks    = f->transient ? 1 << f->size : 1;
-    f->blocksize = frame_size / f->blocks;
-
-    imdct = f->tx[f->transient ? 0 : f->size];
-    imdct_fn = f->tx_fn[f->transient ? 0 : f->size];
-
-    if (channels == 1) {
-        for (i = 0; i < CELT_MAX_BANDS; i++)
-            f->block[0].energy[i] = FFMAX(f->block[0].energy[i], f->block[1].energy[i]);
+    /* Allocation trim */
+    if (!encode)
+        f->alloc_trim = 5;
+    if (opus_rc_tell_frac(rc) + (6 << 3) <= tbits_8ths)
+        if (encode)
+            opus_rc_enc_cdf(rc, f->alloc_trim, ff_celt_model_alloc_trim);
+        else
+            f->alloc_trim = opus_rc_dec_cdf(rc, ff_celt_model_alloc_trim);
+
+    /* Anti-collapse bit reservation */
+    tbits_8ths = (f->framebits << 3) - opus_rc_tell_frac(rc) - 1;
+    f->anticollapse_needed = 0;
+    if (f->transient && f->size >= 2 && tbits_8ths >= ((f->size + 2) << 3))
+        f->anticollapse_needed = 1 << 3;
+    tbits_8ths -= f->anticollapse_needed;
+
+    /* Band skip bit reservation */
+    if (tbits_8ths >= 1 << 3)
+        skip_bit = 1 << 3;
+    tbits_8ths -= skip_bit;
+
+    /* Intensity/dual stereo bit reservation */
+    if (f->channels == 2) {
+        intensitystereo_bit = ff_celt_log2_frac[f->end_band - f->start_band];
+        if (intensitystereo_bit <= tbits_8ths) {
+            tbits_8ths -= intensitystereo_bit;
+            if (tbits_8ths >= 1 << 3) {
+                dualstereo_bit = 1 << 3;
+                tbits_8ths -= 1 << 3;
+            }
+        } else {
+            intensitystereo_bit = 0;
+        }
     }
 
-    celt_decode_coarse_energy(f, rc);
-    celt_decode_tf_changes   (f, rc);
-    ff_celt_bitalloc         (f, &rc->c, 0);
-    celt_decode_fine_energy  (f, rc);
-    ff_celt_quant_bands      (f, &rc->c);
-
-    if (f->anticollapse_needed)
-        f->anticollapse = ff_opus_rc_get_raw(rc, 1);
-
-    celt_decode_final_energy(f, rc);
+    /* Trim offsets */
+    for (i = f->start_band; i < f->end_band; i++) {
+        int trim     = f->alloc_trim - 5 - f->size;
+        int band     = ff_celt_freq_range[i] * (f->end_band - i - 1);
+        int duration = f->size + 3;
+        int scale    = duration + f->channels - 1;
 
-    /* apply anti-collapse processing and denormalization to
-     * each coded channel */
-    for (i = 0; i < f->channels; i++) {
-        CeltBlock *block = &f->block[i];
+        /* PVQ minimum allocation threshold, below this value the band is
+         * skipped */
+        threshold[i] = FFMAX(3 * ff_celt_freq_range[i] << duration >> 4,
+                             f->channels << 3);
 
-        if (f->anticollapse)
-            process_anticollapse(f, block, f->block[i].coeffs);
+        trim_offset[i] = trim * (band << scale) >> 6;
 
-        celt_denormalize(f, block, f->block[i].coeffs);
+        if (ff_celt_freq_range[i] << f->size == 1)
+            trim_offset[i] -= f->channels << 3;
     }
 
-    /* stereo -> mono downmix */
-    if (f->output_channels < f->channels) {
-        f->dsp->vector_fmac_scalar(f->block[0].coeffs, f->block[1].coeffs, 1.0, FFALIGN(frame_size, 16));
-        downmix = 1;
-    } else if (f->output_channels > f->channels)
-        memcpy(f->block[1].coeffs, f->block[0].coeffs, frame_size * sizeof(float));
-
-    if (f->silence) {
-        for (i = 0; i < 2; i++) {
-            CeltBlock *block = &f->block[i];
-
-            for (j = 0; j < FF_ARRAY_ELEMS(block->energy); j++)
-                block->energy[j] = CELT_ENERGY_SILENCE;
+    /* Bisection */
+    low  = 1;
+    high = CELT_VECTORS - 1;
+    while (low <= high) {
+        int center = (low + high) >> 1;
+        done = total = 0;
+
+        for (i = f->end_band - 1; i >= f->start_band; i--) {
+            bandbits = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[center][i]);
+
+            if (bandbits)
+                bandbits = FFMAX(bandbits + trim_offset[i], 0);
+            bandbits += boost[i];
+
+            if (bandbits >= threshold[i] || done) {
+                done = 1;
+                total += FFMIN(bandbits, f->caps[i]);
+            } else if (bandbits >= f->channels << 3) {
+                total += f->channels << 3;
+            }
         }
-        memset(f->block[0].coeffs, 0, sizeof(f->block[0].coeffs));
-        memset(f->block[1].coeffs, 0, sizeof(f->block[1].coeffs));
-    }
 
-    /* transform and output for each output channel */
-    for (i = 0; i < f->output_channels; i++) {
-        CeltBlock *block = &f->block[i];
+        if (total > tbits_8ths)
+            high = center - 1;
+        else
+            low = center + 1;
+    }
+    high = low--;
 
-        /* iMDCT and overlap-add */
-        for (j = 0; j < f->blocks; j++) {
-            float *dst  = block->buf + 1024 + j * f->blocksize;
+    /* Bisection */
+    for (i = f->start_band; i < f->end_band; i++) {
+        bits1[i] = NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[low][i]);
+        bits2[i] = high >= CELT_VECTORS ? f->caps[i] :
+                   NORMC(ff_celt_freq_range[i] * ff_celt_static_alloc[high][i]);
+
+        if (bits1[i])
+            bits1[i] = FFMAX(bits1[i] + trim_offset[i], 0);
+        if (bits2[i])
+            bits2[i] = FFMAX(bits2[i] + trim_offset[i], 0);
+
+        if (low)
+            bits1[i] += boost[i];
+        bits2[i] += boost[i];
+
+        if (boost[i])
+            skip_startband = i;
+        bits2[i] = FFMAX(bits2[i] - bits1[i], 0);
+    }
 
-            imdct_fn(imdct, dst + CELT_OVERLAP / 2, f->block[i].coeffs + j,
-                     sizeof(float)*f->blocks);
-            f->dsp->vector_fmul_window(dst, dst, dst + CELT_OVERLAP / 2,
-                                       ff_celt_window, CELT_OVERLAP / 2);
+    /* Bisection */
+    low  = 0;
+    high = 1 << CELT_ALLOC_STEPS;
+    for (i = 0; i < CELT_ALLOC_STEPS; i++) {
+        int center = (low + high) >> 1;
+        done = total = 0;
+
+        for (j = f->end_band - 1; j >= f->start_band; j--) {
+            bandbits = bits1[j] + (center * bits2[j] >> CELT_ALLOC_STEPS);
+
+            if (bandbits >= threshold[j] || done) {
+                done = 1;
+                total += FFMIN(bandbits, f->caps[j]);
+            } else if (bandbits >= f->channels << 3)
+                total += f->channels << 3;
         }
-
-        if (downmix)
-            f->dsp->vector_fmul_scalar(&block->buf[1024], &block->buf[1024], 0.5f, frame_size);
-
-        /* postfilter */
-        celt_postfilter(f, block);
-
-        /* deemphasis */
-        block->emph_coeff = f->opusdsp.deemphasis(output[i],
-                                                  &block->buf[1024 - frame_size],
-                                                  block->emph_coeff, frame_size);
+        if (total > tbits_8ths)
+            high = center;
+        else
+            low = center;
     }
 
-    if (channels == 1)
-        memcpy(f->block[1].energy, f->block[0].energy, sizeof(f->block[0].energy));
+    /* Bisection */
+    done = total = 0;
+    for (i = f->end_band - 1; i >= f->start_band; i--) {
+        bandbits = bits1[i] + (low * bits2[i] >> CELT_ALLOC_STEPS);
 
-    for (i = 0; i < 2; i++ ) {
-        CeltBlock *block = &f->block[i];
+        if (bandbits >= threshold[i] || done)
+            done = 1;
+        else
+            bandbits = (bandbits >= f->channels << 3) ?
+            f->channels << 3 : 0;
 
-        if (!f->transient) {
-            memcpy(block->prev_energy[1], block->prev_energy[0], sizeof(block->prev_energy[0]));
-            memcpy(block->prev_energy[0], block->energy,         sizeof(block->prev_energy[0]));
-        } else {
-            for (j = 0; j < CELT_MAX_BANDS; j++)
-                block->prev_energy[0][j] = FFMIN(block->prev_energy[0][j], block->energy[j]);
-        }
-
-        for (j = 0; j < f->start_band; j++) {
-            block->prev_energy[0][j] = CELT_ENERGY_SILENCE;
-            block->energy[j]         = 0.0;
-        }
-        for (j = f->end_band; j < CELT_MAX_BANDS; j++) {
-            block->prev_energy[0][j] = CELT_ENERGY_SILENCE;
-            block->energy[j]         = 0.0;
-        }
+        bandbits     = FFMIN(bandbits, f->caps[i]);
+        f->pulses[i] = bandbits;
+        total      += bandbits;
     }
 
-    f->seed = rc->c.range;
+    /* Band skipping */
+    for (f->coded_bands = f->end_band; ; f->coded_bands--) {
+        int allocation;
+        j = f->coded_bands - 1;
 
-    return 0;
-}
-
-void ff_celt_flush(CeltFrame *f)
-{
-    int i, j;
-
-    if (f->flushed)
-        return;
+        if (j == skip_startband) {
+            /* all remaining bands are not skipped */
+            tbits_8ths += skip_bit;
+            break;
+        }
 
-    for (i = 0; i < 2; i++) {
-        CeltBlock *block = &f->block[i];
+        /* determine the number of bits available for coding "do not skip" markers */
+        remaining   = tbits_8ths - total;
+        bandbits    = remaining / (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]);
+        remaining  -= bandbits  * (ff_celt_freq_bands[j+1] - ff_celt_freq_bands[f->start_band]);
+        allocation  = f->pulses[j] + bandbits * ff_celt_freq_range[j];
+        allocation += FFMAX(remaining - (ff_celt_freq_bands[j] - ff_celt_freq_bands[f->start_band]), 0);
+
+        /* a "do not skip" marker is only coded if the allocation is
+         * above the chosen threshold */
+        if (allocation >= FFMAX(threshold[j], (f->channels + 1) << 3)) {
+            int do_not_skip;
+            if (encode) {
+                do_not_skip = f->coded_bands <= f->skip_band_floor;
+                opus_rc_enc_log(rc, do_not_skip, 1);
+            } else {
+                do_not_skip = opus_rc_dec_log(rc, 1);
+            }
 
-        for (j = 0; j < CELT_MAX_BANDS; j++)
-            block->prev_energy[0][j] = block->prev_energy[1][j] = CELT_ENERGY_SILENCE;
+            if (do_not_skip)
+                break;
 
-        memset(block->energy, 0, sizeof(block->energy));
-        memset(block->buf,    0, sizeof(block->buf));
+            total      += 1 << 3;
+            allocation -= 1 << 3;
+        }
 
-        memset(block->pf_gains,     0, sizeof(block->pf_gains));
-        memset(block->pf_gains_old, 0, sizeof(block->pf_gains_old));
-        memset(block->pf_gains_new, 0, sizeof(block->pf_gains_new));
+        /* the band is skipped, so reclaim its bits */
+        total -= f->pulses[j];
+        if (intensitystereo_bit) {
+            total -= intensitystereo_bit;
+            intensitystereo_bit = ff_celt_log2_frac[j - f->start_band];
+            total += intensitystereo_bit;
+        }
 
-        /* libopus uses CELT_EMPH_COEFF on init, but 0 is better since there's
-         * a lesser discontinuity when seeking.
-         * The deemphasis functions differ from libopus in that they require
-         * an initial state divided by the coefficient. */
-        block->emph_coeff = 0.0f / CELT_EMPH_COEFF;
+        total += f->pulses[j] = (allocation >= f->channels << 3) ? f->channels << 3 : 0;
     }
-    f->seed = 0;
-
-    f->flushed = 1;
-}
-
-void ff_celt_free(CeltFrame **f)
-{
-    CeltFrame *frm = *f;
-    int i;
-
-    if (!frm)
-        return;
 
-    for (i = 0; i < FF_ARRAY_ELEMS(frm->tx); i++)
-        av_tx_uninit(&frm->tx[i]);
-
-    ff_celt_pvq_uninit(&frm->pvq);
-
-    av_freep(&frm->dsp);
-    av_freep(f);
-}
-
-int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels,
-                 int apply_phase_inv)
-{
-    CeltFrame *frm;
-    int i, ret;
+    /* IS start band */
+    if (encode) {
+        if (intensitystereo_bit) {
+            f->intensity_stereo = FFMIN(f->intensity_stereo, f->coded_bands);
+            ff_opus_rc_enc_uint((OpusEncRangeCoder*)rc, f->intensity_stereo, f->coded_bands + 1 - f->start_band);
+        }
+    } else {
+        f->intensity_stereo = f->dual_stereo = 0;
+        if (intensitystereo_bit)
+            f->intensity_stereo = f->start_band + ff_opus_rc_dec_uint((OpusDecRangeCoder*)rc, f->coded_bands + 1 - f->start_band);
+    }
 
-    if (output_channels != 1 && output_channels != 2) {
-        av_log(avctx, AV_LOG_ERROR, "Invalid number of output channels: %d\n",
-               output_channels);
-        return AVERROR(EINVAL);
+    /* DS flag */
+    if (f->intensity_stereo <= f->start_band)
+        tbits_8ths += dualstereo_bit; /* no intensity stereo means no dual stereo */
+    else if (dualstereo_bit)
+        if (encode)
+            opus_rc_enc_log(rc, f->dual_stereo, 1);
+        else
+            f->dual_stereo = opus_rc_dec_log(rc, 1);
+
+    /* Supply the remaining bits in this frame to lower bands */
+    remaining = tbits_8ths - total;
+    bandbits  = remaining / (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]);
+    remaining -= bandbits * (ff_celt_freq_bands[f->coded_bands] - ff_celt_freq_bands[f->start_band]);
+    for (i = f->start_band; i < f->coded_bands; i++) {
+        const int bits = FFMIN(remaining, ff_celt_freq_range[i]);
+        f->pulses[i] += bits + bandbits * ff_celt_freq_range[i];
+        remaining    -= bits;
     }
 
-    frm = av_mallocz(sizeof(*frm));
-    if (!frm)
-        return AVERROR(ENOMEM);
+    /* Finally determine the allocation */
+    for (i = f->start_band; i < f->coded_bands; i++) {
+        int N = ff_celt_freq_range[i] << f->size;
+        int prev_extra = extrabits;
+        f->pulses[i] += extrabits;
+
+        if (N > 1) {
+            int dof;        /* degrees of freedom */
+            int temp;       /* dof * channels * log(dof) */
+            int fine_bits;
+            int max_bits;
+            int offset;     /* fine energy quantization offset, i.e.
+                             * extra bits assigned over the standard
+                             * totalbits/dof */
+
+            extrabits = FFMAX(f->pulses[i] - f->caps[i], 0);
+            f->pulses[i] -= extrabits;
+
+            /* intensity stereo makes use of an extra degree of freedom */
+            dof = N * f->channels + (f->channels == 2 && N > 2 && !f->dual_stereo && i < f->intensity_stereo);
+            temp = dof * (ff_celt_log_freq_range[i] + (f->size << 3));
+            offset = (temp >> 1) - dof * CELT_FINE_OFFSET;
+            if (N == 2) /* dof=2 is the only case that doesn't fit the model */
+                offset += dof << 1;
+
+            /* grant an additional bias for the first and second pulses */
+            if (f->pulses[i] + offset < 2 * (dof << 3))
+                offset += temp >> 2;
+            else if (f->pulses[i] + offset < 3 * (dof << 3))
+                offset += temp >> 3;
+
+            fine_bits = (f->pulses[i] + offset + (dof << 2)) / (dof << 3);
+            max_bits  = FFMIN((f->pulses[i] >> 3) >> (f->channels - 1), CELT_MAX_FINE_BITS);
+            max_bits  = FFMAX(max_bits, 0);
+            f->fine_bits[i] = av_clip(fine_bits, 0, max_bits);
+
+            /* If fine_bits was rounded down or capped,
+             * give priority for the final fine energy pass */
+            f->fine_priority[i] = (f->fine_bits[i] * (dof << 3) >= f->pulses[i] + offset);
+
+            /* the remaining bits are assigned to PVQ */
+            f->pulses[i] -= f->fine_bits[i] << (f->channels - 1) << 3;
+        } else {
+            /* all bits go to fine energy except for the sign bit */
+            extrabits = FFMAX(f->pulses[i] - (f->channels << 3), 0);
+            f->pulses[i] -= extrabits;
+            f->fine_bits[i] = 0;
+            f->fine_priority[i] = 1;
+        }
 
-    frm->avctx           = avctx;
-    frm->output_channels = output_channels;
-    frm->apply_phase_inv = apply_phase_inv;
+        /* hand back a limited number of extra fine energy bits to this band */
+        if (extrabits > 0) {
+            int fineextra = FFMIN(extrabits >> (f->channels + 2),
+                                  CELT_MAX_FINE_BITS - f->fine_bits[i]);
+            f->fine_bits[i] += fineextra;
 
-    for (i = 0; i < FF_ARRAY_ELEMS(frm->tx); i++) {
-        const float scale = -1.0f/32768;
-        if ((ret = av_tx_init(&frm->tx[i], &frm->tx_fn[i], AV_TX_FLOAT_MDCT, 1, 15 << (i + 3), &scale, 0)) < 0)
-            goto fail;
+            fineextra <<= f->channels + 2;
+            f->fine_priority[i] = (fineextra >= extrabits - prev_extra);
+            extrabits -= fineextra;
+        }
     }
+    f->remaining = extrabits;
 
-    if ((ret = ff_celt_pvq_init(&frm->pvq, 0)) < 0)
-        goto fail;
-
-    frm->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT);
-    if (!frm->dsp) {
-        ret = AVERROR(ENOMEM);
-        goto fail;
+    /* skipped bands dedicate all of their bits for fine energy */
+    for (; i < f->end_band; i++) {
+        f->fine_bits[i]     = f->pulses[i] >> (f->channels - 1) >> 3;
+        f->pulses[i]        = 0;
+        f->fine_priority[i] = f->fine_bits[i] < 1;
     }
-
-    ff_opus_dsp_init(&frm->opusdsp);
-    ff_celt_flush(frm);
-
-    *f = frm;
-
-    return 0;
-fail:
-    ff_celt_free(&frm);
-    return ret;
 }
diff --git a/libavcodec/opusdec_celt.c b/libavcodec/opusdec_celt.c
new file mode 100644
index 0000000000..a14764ec18
--- /dev/null
+++ b/libavcodec/opusdec_celt.c
@@ -0,0 +1,587 @@
+/*
+ * Copyright (c) 2012 Andrew D'Addesio
+ * Copyright (c) 2013-2014 Mozilla Corporation
+ * Copyright (c) 2016 Rostislav Pehlivanov <atomnuker@gmail.com>
+ *
+ * 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
+ */
+
+/**
+ * @file
+ * Opus CELT decoder
+ */
+
+#include <float.h>
+
+#include "opus_celt.h"
+#include "opusdec_rc.h"
+#include "opustab.h"
+#include "opus_pvq.h"
+
+/* Use the 2D z-transform to apply prediction in both the time domain (alpha)
+ * and the frequency domain (beta) */
+static void celt_decode_coarse_energy(CeltFrame *f, OpusDecRangeCoder *rc)
+{
+    int i, j;
+    float prev[2] = { 0 };
+    float alpha = ff_celt_alpha_coef[f->size];
+    float beta  = ff_celt_beta_coef[f->size];
+    const uint8_t *model = ff_celt_coarse_energy_dist[f->size][0];
+
+    /* intra frame */
+    if (opus_rc_tell(&rc->c) + 3 <= f->framebits && ff_opus_rc_dec_log(rc, 3)) {
+        alpha = 0.0f;
+        beta  = 1.0f - (4915.0f/32768.0f);
+        model = ff_celt_coarse_energy_dist[f->size][1];
+    }
+
+    for (i = 0; i < CELT_MAX_BANDS; i++) {
+        for (j = 0; j < f->channels; j++) {
+            CeltBlock *block = &f->block[j];
+            float value;
+            int available;
+
+            if (i < f->start_band || i >= f->end_band) {
+                block->energy[i] = 0.0;
+                continue;
+            }
+
+            available = f->framebits - opus_rc_tell(&rc->c);
+            if (available >= 15) {
+                /* decode using a Laplace distribution */
+                int k = FFMIN(i, 20) << 1;
+                value = ff_opus_rc_dec_laplace(rc, model[k] << 7, model[k+1] << 6);
+            } else if (available >= 2) {
+                int x = ff_opus_rc_dec_cdf(rc, ff_celt_model_energy_small);
+                value = (x>>1) ^ -(x&1);
+            } else if (available >= 1) {
+                value = -(float)ff_opus_rc_dec_log(rc, 1);
+            } else value = -1;
+
+            block->energy[i] = FFMAX(-9.0f, block->energy[i]) * alpha + prev[j] + value;
+            prev[j] += beta * value;
+        }
+    }
+}
+
+static void celt_decode_fine_energy(CeltFrame *f, OpusDecRangeCoder *rc)
+{
+    int i;
+    for (i = f->start_band; i < f->end_band; i++) {
+        int j;
+        if (!f->fine_bits[i])
+            continue;
+
+        for (j = 0; j < f->channels; j++) {
+            CeltBlock *block = &f->block[j];
+            int q2;
+            float offset;
+            q2 = ff_opus_rc_get_raw(rc, f->fine_bits[i]);
+            offset = (q2 + 0.5f) * (1 << (14 - f->fine_bits[i])) / 16384.0f - 0.5f;
+            block->energy[i] += offset;
+        }
+    }
+}
+
+static void celt_decode_final_energy(CeltFrame *f, OpusDecRangeCoder *rc)
+{
+    int priority, i, j;
+    int bits_left = f->framebits - opus_rc_tell(&rc->c);
+
+    for (priority = 0; priority < 2; priority++) {
+        for (i = f->start_band; i < f->end_band && bits_left >= f->channels; i++) {
+            if (f->fine_priority[i] != priority || f->fine_bits[i] >= CELT_MAX_FINE_BITS)
+                continue;
+
+            for (j = 0; j < f->channels; j++) {
+                int q2;
+                float offset;
+                q2 = ff_opus_rc_get_raw(rc, 1);
+                offset = (q2 - 0.5f) * (1 << (14 - f->fine_bits[i] - 1)) / 16384.0f;
+                f->block[j].energy[i] += offset;
+                bits_left--;
+            }
+        }
+    }
+}
+
+static void celt_decode_tf_changes(CeltFrame *f, OpusDecRangeCoder *rc)
+{
+    int i, diff = 0, tf_select = 0, tf_changed = 0, tf_select_bit;
+    int consumed, bits = f->transient ? 2 : 4;
+
+    consumed = opus_rc_tell(&rc->c);
+    tf_select_bit = (f->size != 0 && consumed+bits+1 <= f->framebits);
+
+    for (i = f->start_band; i < f->end_band; i++) {
+        if (consumed+bits+tf_select_bit <= f->framebits) {
+            diff ^= ff_opus_rc_dec_log(rc, bits);
+            consumed = opus_rc_tell(&rc->c);
+            tf_changed |= diff;
+        }
+        f->tf_change[i] = diff;
+        bits = f->transient ? 4 : 5;
+    }
+
+    if (tf_select_bit && ff_celt_tf_select[f->size][f->transient][0][tf_changed] !=
+                         ff_celt_tf_select[f->size][f->transient][1][tf_changed])
+        tf_select = ff_opus_rc_dec_log(rc, 1);
+
+    for (i = f->start_band; i < f->end_band; i++) {
+        f->tf_change[i] = ff_celt_tf_select[f->size][f->transient][tf_select][f->tf_change[i]];
+    }
+}
+
+static void celt_denormalize(CeltFrame *f, CeltBlock *block, float *data)
+{
+    int i, j;
+
+    for (i = f->start_band; i < f->end_band; i++) {
+        float *dst = data + (ff_celt_freq_bands[i] << f->size);
+        float log_norm = block->energy[i] + ff_celt_mean_energy[i];
+        float norm = exp2f(FFMIN(log_norm, 32.0f));
+
+        for (j = 0; j < ff_celt_freq_range[i] << f->size; j++)
+            dst[j] *= norm;
+    }
+}
+
+static void celt_postfilter_apply_transition(CeltBlock *block, float *data)
+{
+    const int T0 = block->pf_period_old;
+    const int T1 = block->pf_period;
+
+    float g00, g01, g02;
+    float g10, g11, g12;
+
+    float x0, x1, x2, x3, x4;
+
+    int i;
+
+    if (block->pf_gains[0]     == 0.0 &&
+        block->pf_gains_old[0] == 0.0)
+        return;
+
+    g00 = block->pf_gains_old[0];
+    g01 = block->pf_gains_old[1];
+    g02 = block->pf_gains_old[2];
+    g10 = block->pf_gains[0];
+    g11 = block->pf_gains[1];
+    g12 = block->pf_gains[2];
+
+    x1 = data[-T1 + 1];
+    x2 = data[-T1];
+    x3 = data[-T1 - 1];
+    x4 = data[-T1 - 2];
+
+    for (i = 0; i < CELT_OVERLAP; i++) {
+        float w = ff_celt_window2[i];
+        x0 = data[i - T1 + 2];
+
+        data[i] +=  (1.0 - w) * g00 * data[i - T0]                          +
+                    (1.0 - w) * g01 * (data[i - T0 - 1] + data[i - T0 + 1]) +
+                    (1.0 - w) * g02 * (data[i - T0 - 2] + data[i - T0 + 2]) +
+                    w         * g10 * x2                                    +
+                    w         * g11 * (x1 + x3)                             +
+                    w         * g12 * (x0 + x4);
+        x4 = x3;
+        x3 = x2;
+        x2 = x1;
+        x1 = x0;
+    }
+}
+
+static void celt_postfilter(CeltFrame *f, CeltBlock *block)
+{
+    int len = f->blocksize * f->blocks;
+    const int filter_len = len - 2 * CELT_OVERLAP;
+
+    celt_postfilter_apply_transition(block, block->buf + 1024);
+
+    block->pf_period_old = block->pf_period;
+    memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains));
+
+    block->pf_period = block->pf_period_new;
+    memcpy(block->pf_gains, block->pf_gains_new, sizeof(block->pf_gains));
+
+    if (len > CELT_OVERLAP) {
+        celt_postfilter_apply_transition(block, block->buf + 1024 + CELT_OVERLAP);
+
+        if (block->pf_gains[0] > FLT_EPSILON && filter_len > 0)
+            f->opusdsp.postfilter(block->buf + 1024 + 2 * CELT_OVERLAP,
+                                  block->pf_period, block->pf_gains,
+                                  filter_len);
+
+        block->pf_period_old = block->pf_period;
+        memcpy(block->pf_gains_old, block->pf_gains, sizeof(block->pf_gains));
+    }
+
+    memmove(block->buf, block->buf + len, (1024 + CELT_OVERLAP / 2) * sizeof(float));
+}
+
+static int parse_postfilter(CeltFrame *f, OpusDecRangeCoder *rc, int consumed)
+{
+    int i;
+
+    memset(f->block[0].pf_gains_new, 0, sizeof(f->block[0].pf_gains_new));
+    memset(f->block[1].pf_gains_new, 0, sizeof(f->block[1].pf_gains_new));
+
+    if (f->start_band == 0 && consumed + 16 <= f->framebits) {
+        int has_postfilter = ff_opus_rc_dec_log(rc, 1);
+        if (has_postfilter) {
+            float gain;
+            int tapset, octave, period;
+
+            octave = ff_opus_rc_dec_uint(rc, 6);
+            period = (16 << octave) + ff_opus_rc_get_raw(rc, 4 + octave) - 1;
+            gain   = 0.09375f * (ff_opus_rc_get_raw(rc, 3) + 1);
+            tapset = (opus_rc_tell(&rc->c) + 2 <= f->framebits) ?
+                     ff_opus_rc_dec_cdf(rc, ff_celt_model_tapset) : 0;
+
+            for (i = 0; i < 2; i++) {
+                CeltBlock *block = &f->block[i];
+
+                block->pf_period_new = FFMAX(period, CELT_POSTFILTER_MINPERIOD);
+                block->pf_gains_new[0] = gain * ff_celt_postfilter_taps[tapset][0];
+                block->pf_gains_new[1] = gain * ff_celt_postfilter_taps[tapset][1];
+                block->pf_gains_new[2] = gain * ff_celt_postfilter_taps[tapset][2];
+            }
+        }
+
+        consumed = opus_rc_tell(&rc->c);
+    }
+
+    return consumed;
+}
+
+static void process_anticollapse(CeltFrame *f, CeltBlock *block, float *X)
+{
+    int i, j, k;
+
+    for (i = f->start_band; i < f->end_band; i++) {
+        int renormalize = 0;
+        float *xptr;
+        float prev[2];
+        float Ediff, r;
+        float thresh, sqrt_1;
+        int depth;
+
+        /* depth in 1/8 bits */
+        depth = (1 + f->pulses[i]) / (ff_celt_freq_range[i] << f->size);
+        thresh = exp2f(-1.0 - 0.125f * depth);
+        sqrt_1 = 1.0f / sqrtf(ff_celt_freq_range[i] << f->size);
+
+        xptr = X + (ff_celt_freq_bands[i] << f->size);
+
+        prev[0] = block->prev_energy[0][i];
+        prev[1] = block->prev_energy[1][i];
+        if (f->channels == 1) {
+            CeltBlock *block1 = &f->block[1];
+
+            prev[0] = FFMAX(prev[0], block1->prev_energy[0][i]);
+            prev[1] = FFMAX(prev[1], block1->prev_energy[1][i]);
+        }
+        Ediff = block->energy[i] - FFMIN(prev[0], prev[1]);
+        Ediff = FFMAX(0, Ediff);
+
+        /* r needs to be multiplied by 2 or 2*sqrt(2) depending on LM because
+        short blocks don't have the same energy as long */
+        r = exp2f(1 - Ediff);
+        if (f->size == 3)
+            r *= M_SQRT2;
+        r = FFMIN(thresh, r) * sqrt_1;
+        for (k = 0; k < 1 << f->size; k++) {
+            /* Detect collapse */
+            if (!(block->collapse_masks[i] & 1 << k)) {
+                /* Fill with noise */
+                for (j = 0; j < ff_celt_freq_range[i]; j++)
+                    xptr[(j << f->size) + k] = (celt_rng(f) & 0x8000) ? r : -r;
+                renormalize = 1;
+            }
+        }
+
+        /* We just added some energy, so we need to renormalize */
+        if (renormalize)
+            celt_renormalize_vector(xptr, ff_celt_freq_range[i] << f->size, 1.0f);
+    }
+}
+
+int ff_celt_decode_frame(CeltFrame *f, OpusDecRangeCoder *rc,
+                         float **output, int channels, int frame_size,
+                         int start_band,  int end_band)
+{
+    int i, j, downmix = 0;
+    int consumed;           // bits of entropy consumed thus far for this frame
+    AVTXContext *imdct;
+    av_tx_fn imdct_fn;
+
+    if (channels != 1 && channels != 2) {
+        av_log(f->avctx, AV_LOG_ERROR, "Invalid number of coded channels: %d\n",
+               channels);
+        return AVERROR_INVALIDDATA;
+    }
+    if (start_band < 0 || start_band > end_band || end_band > CELT_MAX_BANDS) {
+        av_log(f->avctx, AV_LOG_ERROR, "Invalid start/end band: %d %d\n",
+               start_band, end_band);
+        return AVERROR_INVALIDDATA;
+    }
+
+    f->silence        = 0;
+    f->transient      = 0;
+    f->anticollapse   = 0;
+    f->flushed        = 0;
+    f->channels       = channels;
+    f->start_band     = start_band;
+    f->end_band       = end_band;
+    f->framebits      = rc->c.rb.bytes * 8;
+
+    f->size = av_log2(frame_size / CELT_SHORT_BLOCKSIZE);
+    if (f->size > CELT_MAX_LOG_BLOCKS ||
+        frame_size != CELT_SHORT_BLOCKSIZE * (1 << f->size)) {
+        av_log(f->avctx, AV_LOG_ERROR, "Invalid CELT frame size: %d\n",
+               frame_size);
+        return AVERROR_INVALIDDATA;
+    }
+
+    if (!f->output_channels)
+        f->output_channels = channels;
+
+    for (i = 0; i < f->channels; i++) {
+        memset(f->block[i].coeffs,         0, sizeof(f->block[i].coeffs));
+        memset(f->block[i].collapse_masks, 0, sizeof(f->block[i].collapse_masks));
+    }
+
+    consumed = opus_rc_tell(&rc->c);
+
+    /* obtain silence flag */
+    if (consumed >= f->framebits)
+        f->silence = 1;
+    else if (consumed == 1)
+        f->silence = ff_opus_rc_dec_log(rc, 15);
+
+
+    if (f->silence) {
+        consumed = f->framebits;
+        rc->c.total_bits += f->framebits - opus_rc_tell(&rc->c);
+    }
+
+    /* obtain post-filter options */
+    consumed = parse_postfilter(f, rc, consumed);
+
+    /* obtain transient flag */
+    if (f->size != 0 && consumed+3 <= f->framebits)
+        f->transient = ff_opus_rc_dec_log(rc, 3);
+
+    f->blocks    = f->transient ? 1 << f->size : 1;
+    f->blocksize = frame_size / f->blocks;
+
+    imdct = f->tx[f->transient ? 0 : f->size];
+    imdct_fn = f->tx_fn[f->transient ? 0 : f->size];
+
+    if (channels == 1) {
+        for (i = 0; i < CELT_MAX_BANDS; i++)
+            f->block[0].energy[i] = FFMAX(f->block[0].energy[i], f->block[1].energy[i]);
+    }
+
+    celt_decode_coarse_energy(f, rc);
+    celt_decode_tf_changes   (f, rc);
+    ff_celt_bitalloc         (f, &rc->c, 0);
+    celt_decode_fine_energy  (f, rc);
+    ff_celt_quant_bands      (f, &rc->c);
+
+    if (f->anticollapse_needed)
+        f->anticollapse = ff_opus_rc_get_raw(rc, 1);
+
+    celt_decode_final_energy(f, rc);
+
+    /* apply anti-collapse processing and denormalization to
+     * each coded channel */
+    for (i = 0; i < f->channels; i++) {
+        CeltBlock *block = &f->block[i];
+
+        if (f->anticollapse)
+            process_anticollapse(f, block, f->block[i].coeffs);
+
+        celt_denormalize(f, block, f->block[i].coeffs);
+    }
+
+    /* stereo -> mono downmix */
+    if (f->output_channels < f->channels) {
+        f->dsp->vector_fmac_scalar(f->block[0].coeffs, f->block[1].coeffs, 1.0, FFALIGN(frame_size, 16));
+        downmix = 1;
+    } else if (f->output_channels > f->channels)
+        memcpy(f->block[1].coeffs, f->block[0].coeffs, frame_size * sizeof(float));
+
+    if (f->silence) {
+        for (i = 0; i < 2; i++) {
+            CeltBlock *block = &f->block[i];
+
+            for (j = 0; j < FF_ARRAY_ELEMS(block->energy); j++)
+                block->energy[j] = CELT_ENERGY_SILENCE;
+        }
+        memset(f->block[0].coeffs, 0, sizeof(f->block[0].coeffs));
+        memset(f->block[1].coeffs, 0, sizeof(f->block[1].coeffs));
+    }
+
+    /* transform and output for each output channel */
+    for (i = 0; i < f->output_channels; i++) {
+        CeltBlock *block = &f->block[i];
+
+        /* iMDCT and overlap-add */
+        for (j = 0; j < f->blocks; j++) {
+            float *dst  = block->buf + 1024 + j * f->blocksize;
+
+            imdct_fn(imdct, dst + CELT_OVERLAP / 2, f->block[i].coeffs + j,
+                     sizeof(float)*f->blocks);
+            f->dsp->vector_fmul_window(dst, dst, dst + CELT_OVERLAP / 2,
+                                       ff_celt_window, CELT_OVERLAP / 2);
+        }
+
+        if (downmix)
+            f->dsp->vector_fmul_scalar(&block->buf[1024], &block->buf[1024], 0.5f, frame_size);
+
+        /* postfilter */
+        celt_postfilter(f, block);
+
+        /* deemphasis */
+        block->emph_coeff = f->opusdsp.deemphasis(output[i],
+                                                  &block->buf[1024 - frame_size],
+                                                  block->emph_coeff, frame_size);
+    }
+
+    if (channels == 1)
+        memcpy(f->block[1].energy, f->block[0].energy, sizeof(f->block[0].energy));
+
+    for (i = 0; i < 2; i++ ) {
+        CeltBlock *block = &f->block[i];
+
+        if (!f->transient) {
+            memcpy(block->prev_energy[1], block->prev_energy[0], sizeof(block->prev_energy[0]));
+            memcpy(block->prev_energy[0], block->energy,         sizeof(block->prev_energy[0]));
+        } else {
+            for (j = 0; j < CELT_MAX_BANDS; j++)
+                block->prev_energy[0][j] = FFMIN(block->prev_energy[0][j], block->energy[j]);
+        }
+
+        for (j = 0; j < f->start_band; j++) {
+            block->prev_energy[0][j] = CELT_ENERGY_SILENCE;
+            block->energy[j]         = 0.0;
+        }
+        for (j = f->end_band; j < CELT_MAX_BANDS; j++) {
+            block->prev_energy[0][j] = CELT_ENERGY_SILENCE;
+            block->energy[j]         = 0.0;
+        }
+    }
+
+    f->seed = rc->c.range;
+
+    return 0;
+}
+
+void ff_celt_flush(CeltFrame *f)
+{
+    int i, j;
+
+    if (f->flushed)
+        return;
+
+    for (i = 0; i < 2; i++) {
+        CeltBlock *block = &f->block[i];
+
+        for (j = 0; j < CELT_MAX_BANDS; j++)
+            block->prev_energy[0][j] = block->prev_energy[1][j] = CELT_ENERGY_SILENCE;
+
+        memset(block->energy, 0, sizeof(block->energy));
+        memset(block->buf,    0, sizeof(block->buf));
+
+        memset(block->pf_gains,     0, sizeof(block->pf_gains));
+        memset(block->pf_gains_old, 0, sizeof(block->pf_gains_old));
+        memset(block->pf_gains_new, 0, sizeof(block->pf_gains_new));
+
+        /* libopus uses CELT_EMPH_COEFF on init, but 0 is better since there's
+         * a lesser discontinuity when seeking.
+         * The deemphasis functions differ from libopus in that they require
+         * an initial state divided by the coefficient. */
+        block->emph_coeff = 0.0f / CELT_EMPH_COEFF;
+    }
+    f->seed = 0;
+
+    f->flushed = 1;
+}
+
+void ff_celt_free(CeltFrame **f)
+{
+    CeltFrame *frm = *f;
+    int i;
+
+    if (!frm)
+        return;
+
+    for (i = 0; i < FF_ARRAY_ELEMS(frm->tx); i++)
+        av_tx_uninit(&frm->tx[i]);
+
+    ff_celt_pvq_uninit(&frm->pvq);
+
+    av_freep(&frm->dsp);
+    av_freep(f);
+}
+
+int ff_celt_init(AVCodecContext *avctx, CeltFrame **f, int output_channels,
+                 int apply_phase_inv)
+{
+    CeltFrame *frm;
+    int i, ret;
+
+    if (output_channels != 1 && output_channels != 2) {
+        av_log(avctx, AV_LOG_ERROR, "Invalid number of output channels: %d\n",
+               output_channels);
+        return AVERROR(EINVAL);
+    }
+
+    frm = av_mallocz(sizeof(*frm));
+    if (!frm)
+        return AVERROR(ENOMEM);
+
+    frm->avctx           = avctx;
+    frm->output_channels = output_channels;
+    frm->apply_phase_inv = apply_phase_inv;
+
+    for (i = 0; i < FF_ARRAY_ELEMS(frm->tx); i++) {
+        const float scale = -1.0f/32768;
+        if ((ret = av_tx_init(&frm->tx[i], &frm->tx_fn[i], AV_TX_FLOAT_MDCT, 1, 15 << (i + 3), &scale, 0)) < 0)
+            goto fail;
+    }
+
+    if ((ret = ff_celt_pvq_init(&frm->pvq, 0)) < 0)
+        goto fail;
+
+    frm->dsp = avpriv_float_dsp_alloc(avctx->flags & AV_CODEC_FLAG_BITEXACT);
+    if (!frm->dsp) {
+        ret = AVERROR(ENOMEM);
+        goto fail;
+    }
+
+    ff_opus_dsp_init(&frm->opusdsp);
+    ff_celt_flush(frm);
+
+    *f = frm;
+
+    return 0;
+fail:
+    ff_celt_free(&frm);
+    return ret;
+}
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* [FFmpeg-devel] [PATCH 9/9] avcodec/opus_pvq: Avoid indirection when possible
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
                   ` (6 preceding siblings ...)
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 8/9] avcodec/opus: Rename opus.c->opus_celt.c, opus_celt.c->opusdec_celt.c Andreas Rheinhardt
@ 2022-10-07 20:25 ` Andreas Rheinhardt
  2022-10-08  3:25 ` [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Lynne
  8 siblings, 0 replies; 10+ messages in thread
From: Andreas Rheinhardt @ 2022-10-07 20:25 UTC (permalink / raw)
  To: ffmpeg-devel; +Cc: Andreas Rheinhardt

Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
---
 libavcodec/opus_pvq.c          |  4 ++--
 libavcodec/opus_pvq.h          |  3 +++
 libavcodec/opus_pvq_template.c | 35 ++++++++++++++++++----------------
 libavcodec/opusenc_psy.c       | 12 ++++++------
 4 files changed, 30 insertions(+), 24 deletions(-)

diff --git a/libavcodec/opus_pvq.c b/libavcodec/opus_pvq.c
index 8ef0f85a81..26d4e436e1 100644
--- a/libavcodec/opus_pvq.c
+++ b/libavcodec/opus_pvq.c
@@ -511,9 +511,9 @@ int av_cold ff_celt_pvq_init(CeltPVQ **pvq, int encode)
 
 #if CONFIG_OPUS_ENCODER
 #if CONFIG_OPUS_DECODER
-    s->quant_band = encode ? pvq_quant_band_enc : pvq_quant_band_dec;
+    s->quant_band = encode ? ff_pvq_quant_band_enc : pvq_quant_band_dec;
 #else
-    s->quant_band = pvq_quant_band_enc;
+    s->quant_band = ff_pvq_quant_band_enc;
 #endif
     s->pvq_search = ppp_pvq_search_c;
 #if ARCH_X86
diff --git a/libavcodec/opus_pvq.h b/libavcodec/opus_pvq.h
index b71bc49034..4907025125 100644
--- a/libavcodec/opus_pvq.h
+++ b/libavcodec/opus_pvq.h
@@ -26,6 +26,7 @@
 #include "libavutil/mem_internal.h"
 
 #include "opus_celt.h"
+#include "opus_rc.h"
 
 #define QUANT_FN(name) uint32_t (name)(struct CeltPVQ *pvq, CeltFrame *f,            \
                                        OpusRangeCoder *rc, const int band, float *X, \
@@ -47,4 +48,6 @@ void ff_celt_pvq_init_x86(struct CeltPVQ *s);
 int  ff_celt_pvq_init(struct CeltPVQ **pvq, int encode);
 void ff_celt_pvq_uninit(struct CeltPVQ **pvq);
 
+QUANT_FN(ff_pvq_quant_band_enc);
+
 #endif /* AVCODEC_OPUS_PVQ_H */
diff --git a/libavcodec/opus_pvq_template.c b/libavcodec/opus_pvq_template.c
index 5f03f3d415..79e8e4ca52 100644
--- a/libavcodec/opus_pvq_template.c
+++ b/libavcodec/opus_pvq_template.c
@@ -24,14 +24,17 @@
  */
 
 #undef FUNC
+#undef STATIC
 
 #if ENCODING
-#define FUNC(name) name ## _enc
+#define STATIC
+#define FUNC(name) ff_ ## name ## _enc
 #else
+#define STATIC static
 #define FUNC(name) name ## _dec
 #endif
 
-static
+STATIC
 uint32_t FUNC(pvq_quant_band)(CeltPVQ *const pvq, CeltFrame *const f,
                               OpusRangeCoder *const rc,
                               const int band, float *X,
@@ -256,8 +259,8 @@ uint32_t FUNC(pvq_quant_band)(CeltPVQ *const pvq, CeltFrame *const f,
             sign = 1 - 2 * sign;
             /* We use orig_fill here because we want to fold the side, but if
             itheta==16384, we'll have cleared the low bits of fill. */
-            cm = pvq->quant_band(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration,
-                                 lowband_out, level, gain, lowband_scratch, orig_fill);
+            cm = FUNC(pvq_quant_band)(pvq, f, rc, band, x2, NULL, N, mbits, blocks, lowband, duration,
+                                      lowband_out, level, gain, lowband_scratch, orig_fill);
             /* We don't split N=2 bands, so cm is either 1 or 0 (for a fold-collapse),
             and there's no need to worry about mixing with the other channel. */
             y2[0] = -sign * x2[1];
@@ -309,25 +312,25 @@ uint32_t FUNC(pvq_quant_band)(CeltPVQ *const pvq, CeltFrame *const f,
             if (mbits >= sbits) {
                 /* In stereo mode, we do not apply a scaling to the mid
                  * because we need the normalized mid for folding later */
-                cm = pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks,
-                                     lowband, duration, next_lowband_out1, next_level,
-                                     stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
+                cm = FUNC(pvq_quant_band)(pvq, f, rc, band, X, NULL, N, mbits, blocks,
+                                          lowband, duration, next_lowband_out1, next_level,
+                                          stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
                 rebalance = mbits - (rebalance - f->remaining2);
                 if (rebalance > 3 << 3 && itheta != 0)
                     sbits += rebalance - (3 << 3);
 
                 /* For a stereo split, the high bits of fill are always zero,
                  * so no folding will be done to the side. */
-                cmt = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
-                                      next_lowband2, duration, NULL, next_level,
-                                      gain * side, NULL, fill >> blocks);
+                cmt = FUNC(pvq_quant_band)(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
+                                           next_lowband2, duration, NULL, next_level,
+                                           gain * side, NULL, fill >> blocks);
                 cm |= cmt << ((B0 >> 1) & (stereo - 1));
             } else {
                 /* For a stereo split, the high bits of fill are always zero,
                  * so no folding will be done to the side. */
-                cm = pvq->quant_band(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
-                                     next_lowband2, duration, NULL, next_level,
-                                     gain * side, NULL, fill >> blocks);
+                cm = FUNC(pvq_quant_band)(pvq, f, rc, band, Y, NULL, N, sbits, blocks,
+                                          next_lowband2, duration, NULL, next_level,
+                                          gain * side, NULL, fill >> blocks);
                 cm <<= ((B0 >> 1) & (stereo - 1));
                 rebalance = sbits - (rebalance - f->remaining2);
                 if (rebalance > 3 << 3 && itheta != 16384)
@@ -335,9 +338,9 @@ uint32_t FUNC(pvq_quant_band)(CeltPVQ *const pvq, CeltFrame *const f,
 
                 /* In stereo mode, we do not apply a scaling to the mid because
                  * we need the normalized mid for folding later */
-                cm |= pvq->quant_band(pvq, f, rc, band, X, NULL, N, mbits, blocks,
-                                      lowband, duration, next_lowband_out1, next_level,
-                                      stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
+                cm |= FUNC(pvq_quant_band)(pvq, f, rc, band, X, NULL, N, mbits, blocks,
+                                           lowband, duration, next_lowband_out1, next_level,
+                                           stereo ? 1.0f : (gain * mid), lowband_scratch, fill);
             }
         }
     } else {
diff --git a/libavcodec/opusenc_psy.c b/libavcodec/opusenc_psy.c
index 17a2efd8d5..0ec915d3c5 100644
--- a/libavcodec/opusenc_psy.c
+++ b/libavcodec/opusenc_psy.c
@@ -54,14 +54,14 @@ static float pvq_band_cost(CeltPVQ *pvq, CeltFrame *f, OpusEncRangeCoder *rce, i
     }
 
     if (f->dual_stereo) {
-        pvq->quant_band(pvq, f, rc, band, X, NULL, band_size, b / 2, f->blocks, NULL,
-                        f->size, norm1, 0, 1.0f, lowband_scratch, cm[0]);
+        ff_pvq_quant_band_enc(pvq, f, rc, band, X, NULL, band_size, b / 2, f->blocks, NULL,
+                              f->size, norm1, 0, 1.0f, lowband_scratch, cm[0]);
 
-        pvq->quant_band(pvq, f, rc, band, Y, NULL, band_size, b / 2, f->blocks, NULL,
-                        f->size, norm2, 0, 1.0f, lowband_scratch, cm[1]);
+        ff_pvq_quant_band_enc(pvq, f, rc, band, Y, NULL, band_size, b / 2, f->blocks, NULL,
+                              f->size, norm2, 0, 1.0f, lowband_scratch, cm[1]);
     } else {
-        pvq->quant_band(pvq, f, rc, band, X, Y, band_size, b, f->blocks, NULL, f->size,
-                        norm1, 0, 1.0f, lowband_scratch, cm[0] | cm[1]);
+        ff_pvq_quant_band_enc(pvq, f, rc, band, X, Y, band_size, b, f->blocks, NULL, f->size,
+                              norm1, 0, 1.0f, lowband_scratch, cm[0] | cm[1]);
     }
 
     for (i = 0; i < band_size; i++) {
-- 
2.34.1

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

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

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder
  2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
                   ` (7 preceding siblings ...)
  2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 9/9] avcodec/opus_pvq: Avoid indirection when possible Andreas Rheinhardt
@ 2022-10-08  3:25 ` Lynne
  8 siblings, 0 replies; 10+ messages in thread
From: Lynne @ 2022-10-08  3:25 UTC (permalink / raw)
  To: FFmpeg development discussions and patches

Oct 7, 2022, 22:20 by andreas.rheinhardt@outlook.com:

> Write-only since e7d977b446194649aa30f2aacc6c17bce7aeb90b
> (and local to ff_opus_rc_enc_end() before that).
>
> Signed-off-by: Andreas Rheinhardt <andreas.rheinhardt@outlook.com>
> ---
>  libavcodec/opus_rc.c | 2 --
>  libavcodec/opus_rc.h | 3 ---
>  2 files changed, 5 deletions(-)
>
> diff --git a/libavcodec/opus_rc.c b/libavcodec/opus_rc.c
> index c432eb90c9..2061418e52 100644
> --- a/libavcodec/opus_rc.c
> +++ b/libavcodec/opus_rc.c
> @@ -383,8 +383,6 @@ void ff_opus_rc_enc_end(OpusRangeCoder *rc, uint8_t *dst, int size)
>  rng_bytes = rc->rng_cur - rc->buf;
>  memcpy(dst, rc->buf, rng_bytes);
>  
> -    rc->waste = size*8 - (rc->rb.bytes*8 + rc->rb.cachelen) - rng_bytes*8;
> -
>  /* Put the rawbits part, if any */
>  if (rc->rb.bytes || rc->rb.cachelen) {
>  int i, lap;
> diff --git a/libavcodec/opus_rc.h b/libavcodec/opus_rc.h
> index 627f83229e..1b3cb93a15 100644
> --- a/libavcodec/opus_rc.h
> +++ b/libavcodec/opus_rc.h
> @@ -49,9 +49,6 @@ typedef struct OpusRangeCoder {
>  uint8_t *rng_cur;                      /* Current range coded byte */
>  int ext;                               /* Awaiting propagation */
>  int rem;                               /* Carryout flag */
> -
> -    /* Encoding stats */
> -    int waste;
>  } OpusRangeCoder;
>

Not really to patch 1. The purpose of the waste field was to know how many
bits were spare and usable to put stuff like encoder settings into. It's only a
small field, compilers probably eliminate it anyway, and it's useful for debugging,
just leave it there for now. It's not something I'd argue about, so if you'd really like
to get rid of it, do tell.

LGTM to patches 2-6. Whatever for the opusenc_psy file, I have a rewrite
I need to finish at some point.

Definite NAK to patch 7. The RC system is very easy to read and well-organized.
I'd like to keep it that way than hunt for spare bytes that any LTO trivially removes.
I'd accept a patch that changes the encoder array to heap allocated one (better yet
a framepool) if you'd still like to save on the struct size.

LGTM to patches 8-9.
_______________________________________________
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] 10+ messages in thread

end of thread, other threads:[~2022-10-08  3:26 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-10-07 20:20 [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 2/9] avcodec/opusenc_psy: Remove unused function parameter Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 3/9] avcodec/opusenc_psy: Remove unused/write-only context members Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 4/9] avcodec/opus: Use prefix for defines Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 5/9] avcodec/opus_rc: Don't duplicate define Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 6/9] avcodec/opus_pvq: Don't build ppp_pvq_search_c when unused Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 7/9] avcodec/opus_rc: Split de/encoder-only parts off OpusRangeContext Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 8/9] avcodec/opus: Rename opus.c->opus_celt.c, opus_celt.c->opusdec_celt.c Andreas Rheinhardt
2022-10-07 20:25 ` [FFmpeg-devel] [PATCH 9/9] avcodec/opus_pvq: Avoid indirection when possible Andreas Rheinhardt
2022-10-08  3:25 ` [FFmpeg-devel] [PATCH 1/9] avcodec/opus_rc: Remove write-only waste from OpusRangeCoder Lynne

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