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 */
