diff --git a/crates/vp9/src/boolcoder.rs b/crates/vp9/src/boolcoder.rs
--- a/crates/vp9/src/boolcoder.rs
+++ b/crates/vp9/src/boolcoder.rs
@@ -75,6 +75,26 @@ impl<'a> BoolDecoder<'a> {
         bit
     }
 
+    /// `read_bool(128)`: the split is `1 + ((range - 1) >> 1) == (range + 1) >> 1`.
+    #[inline(always)]
+    pub fn read_bool_half(&mut self) -> bool {
+        if self.count < 8 {
+            self.fill();
+        }
+        let split = (self.range + 1) >> 1;
+        let bigsplit = (split as u64) << 56;
+        let bit = self.value >= bigsplit;
+        let m = (bit as u64).wrapping_neg();
+        self.value -= bigsplit & m;
+        let m32 = m as u32;
+        self.range = ((self.range - split) & m32) | (split & !m32);
+        let shift = self.range.leading_zeros() - 24;
+        self.range <<= shift;
+        self.value <<= shift;
+        self.count -= shift as i32;
+        bit
+    }
+
     /// read_literal (9.2.4).
     pub fn read_literal(&mut self, n: u32) -> u32 {
         let mut x = 0;
diff --git a/crates/vp9/src/tile/recon.rs b/crates/vp9/src/tile/recon.rs
--- a/crates/vp9/src/tile/recon.rs
+++ b/crates/vp9/src/tile/recon.rs
@@ -127,10 +127,29 @@ impl<'a> TileDecoder<'a> {
     /// of block position and the number of leading coefficient rows that may be non-zero.
     #[allow(clippy::too_many_arguments)]
     fn tokens(&mut self, bd: &mut BoolDecoder, b: &Blk, plane: usize, start_x: usize, start_y: usize, tx_sz: u8, tx_type: u8) -> (usize, usize) {
+        if self.s.counting {
+            self.tokens_impl::<true>(bd, b, plane, start_x, start_y, tx_sz, tx_type)
+        } else {
+            self.tokens_impl::<false>(bd, b, plane, start_x, start_y, tx_sz, tx_type)
+        }
+    }
+
+    #[allow(clippy::too_many_arguments)]
+    fn tokens_impl<const COUNTING: bool>(
+        &mut self,
+        bd: &mut BoolDecoder,
+        b: &Blk,
+        plane: usize,
+        start_x: usize,
+        start_y: usize,
+        tx_sz: u8,
+        tx_type: u8,
+    ) -> (usize, usize) {
         let seg_eob = 16usize << (tx_sz << 1);
         let sc = scan(tx_sz, tx_type);
         let nb = neighbors(tx_sz, tx_type);
         let bands: &[u8] = if tx_sz == 0 { &COEFBAND_4X4 } else { &COEFBAND_8X8PLUS };
+        let (sc, nb, bands) = (&sc[..seg_eob], &nb[..seg_eob], &bands[..seg_eob]);
         let ptype = (plane > 0) as usize;
         let rtype = b.is_inter as usize;
         let probs = &self.fc.coef[tx_sz as usize][ptype][rtype];
@@ -153,7 +172,6 @@ impl<'a> TileDecoder<'a> {
         let q = self.s.seg_q[b.seg_id as usize][ptype];
         let dq_shift = (tx_sz == TX_32X32) as u32;
         let pareto = pareto_full();
-        let counting = self.s.counting;
         let log2n = 2 + tx_sz as usize;
         let bit_depth = self.bit_depth;
         let mut max_row = 0usize;
@@ -162,6 +180,7 @@ impl<'a> TileDecoder<'a> {
         let tc = &mut self.token_cache;
         let coefs = &mut self.coefs;
         let counts = &mut self.strip.counts;
+        let (more_counts, token_counts) = (&mut counts.more_coefs[tx_sz as usize][ptype][rtype], &mut counts.token[tx_sz as usize][ptype][rtype]);
         while c < seg_eob {
             let pos = sc[c] as usize;
             let band = bands[c] as usize;
@@ -174,8 +193,8 @@ impl<'a> TileDecoder<'a> {
             let p = &probs[band][ctx];
             if check_eob {
                 let more = bd.read_bool(p[0]);
-                if counting {
-                    counts.more_coefs[tx_sz as usize][ptype][rtype][band][ctx][more as usize] += 1;
+                if COUNTING {
+                    more_counts[band][ctx][more as usize] += 1;
                 }
                 if !more {
                     break;
@@ -183,8 +202,8 @@ impl<'a> TileDecoder<'a> {
             }
             if !bd.read_bool(p[1]) {
                 tc[pos] = 0;
-                if counting {
-                    counts.token[tx_sz as usize][ptype][rtype][band][ctx][0] += 1;
+                if COUNTING {
+                    token_counts[band][ctx][0] += 1;
                 }
                 check_eob = false;
                 c += 1;
@@ -194,14 +213,14 @@ impl<'a> TileDecoder<'a> {
             let token: usize;
             let coef: i64;
             if !bd.read_bool(p[2]) {
-                if counting {
-                    counts.token[tx_sz as usize][ptype][rtype][band][ctx][1] += 1;
+                if COUNTING {
+                    token_counts[band][ctx][1] += 1;
                 }
                 token = 1;
                 coef = 1;
             } else {
-                if counting {
-                    counts.token[tx_sz as usize][ptype][rtype][band][ctx][2] += 1;
+                if COUNTING {
+                    token_counts[band][ctx][2] += 1;
                 }
                 let pp = &pareto[p[2].max(1) as usize - 1];
                 token = if !bd.read_bool(pp[0]) {
@@ -240,7 +259,7 @@ impl<'a> TileDecoder<'a> {
                 coef = v;
             }
             tc[pos] = ENERGY_CLASS[token];
-            let sign = bd.read_bool(128);
+            let sign = bd.read_bool_half();
             let qv = if pos == 0 { q[0] } else { q[1] } as i64;
             let d = ((coef * qv) >> dq_shift) as i32;
             coefs[pos] = if sign { d.wrapping_neg() } else { d };
