]> git.sesse.net Git - x264/blobdiff - common/bs.h
Faster 8x8dct+CAVLC interleave
[x264] / common / bs.h
index d95efab4d96624a2b4018e2a2a9bb0ae57602184..0765f50aa3ac0b9f2c2f22ce7989e1f13e644292 100644 (file)
@@ -1,10 +1,11 @@
 /*****************************************************************************
  * bs.h :
  *****************************************************************************
- * Copyright (C) 2003 Laurent Aimar
- * $Id: bs.h,v 1.1 2004/06/03 19:27:06 fenrir Exp $
+ * Copyright (C) 2003-2008 x264 project
  *
- * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ * Authors: Loren Merritt <lorenm@u.washington.edu>
+ *          Fiona Glaser <fiona@x264.com>
+ *          Laurent Aimar <fenrir@via.ecp.fr>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
  *****************************************************************************/
 
-#ifdef _BS_H
-#warning FIXME Multiple inclusion of bs.h
-#else
-#define _BS_H
+#ifndef X264_BS_H
+#define X264_BS_H
+
+typedef struct
+{
+    uint8_t i_bits;
+    uint8_t i_size;
+} vlc_t;
+
+typedef struct
+{
+    uint16_t i_bits;
+    uint8_t  i_size;
+    /* Next level table to use */
+    uint8_t  i_next;
+} vlc_large_t;
 
 typedef struct bs_s
 {
@@ -32,382 +45,230 @@ typedef struct bs_s
     uint8_t *p;
     uint8_t *p_end;
 
+    intptr_t cur_bits;
     int     i_left;    /* i_count number of available bits */
     int     i_bits_encoded; /* RD only */
 } bs_t;
 
+typedef struct
+{
+    int     last;
+    int16_t level[16];
+    uint8_t run[16];
+} x264_run_level_t;
+
+extern const vlc_t x264_coeff0_token[5];
+extern const vlc_t x264_coeff_token[5][16*4];
+extern const vlc_t x264_total_zeros[15][16];
+extern const vlc_t x264_total_zeros_dc[3][4];
+extern const vlc_t x264_run_before[7][16];
+
+/* A larger level table size theoretically could help a bit at extremely
+ * high bitrates, but the cost in cache is usually too high for it to be
+ * useful.
+ * This size appears to be optimal for QP18 encoding on a Nehalem CPU.
+ * FIXME: Do further testing? */
+#define LEVEL_TABLE_SIZE 128
+extern vlc_large_t x264_level_token[7][LEVEL_TABLE_SIZE];
+
 static inline void bs_init( bs_t *s, void *p_data, int i_data )
 {
-    s->p_start = p_data;
-    s->p       = p_data;
-    s->p_end   = s->p + i_data;
-    s->i_left  = 8;
+    int offset = ((intptr_t)p_data & (WORD_SIZE-1));
+    s->p       = s->p_start = (uint8_t*)p_data - offset;
+    s->p_end   = (uint8_t*)p_data + i_data;
+    s->i_left  = offset ? 8*offset : (WORD_SIZE*8);
+    s->cur_bits = endian_fix( *(intptr_t*)s->p );
 }
 static inline int bs_pos( bs_t *s )
 {
-    return( 8 * ( s->p - s->p_start ) + 8 - s->i_left );
-}
-static inline int bs_eof( bs_t *s )
-{
-    return( s->p >= s->p_end ? 1: 0 );
+    return( 8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left );
 }
-static inline uint32_t bs_read( bs_t *s, int i_count )
-{
-     static uint32_t i_mask[33] ={0x00,
-                                  0x01,      0x03,      0x07,      0x0f,
-                                  0x1f,      0x3f,      0x7f,      0xff,
-                                  0x1ff,     0x3ff,     0x7ff,     0xfff,
-                                  0x1fff,    0x3fff,    0x7fff,    0xffff,
-                                  0x1ffff,   0x3ffff,   0x7ffff,   0xfffff,
-                                  0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,
-                                  0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
-                                  0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
-    int      i_shr;
-    uint32_t i_result = 0;
-
-    while( i_count > 0 )
-    {
-        if( s->p >= s->p_end )
-        {
-            break;
-        }
 
-        if( ( i_shr = s->i_left - i_count ) >= 0 )
-        {
-            /* more in the buffer than requested */
-            i_result |= ( *s->p >> i_shr )&i_mask[i_count];
-            s->i_left -= i_count;
-            if( s->i_left == 0 )
-            {
-                s->p++;
-                s->i_left = 8;
-            }
-            return( i_result );
-        }
-        else
-        {
-            /* less in the buffer than requested */
-           i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
-           i_count  -= s->i_left;
-           s->p++;
-           s->i_left = 8;
-        }
-    }
-
-    return( i_result );
-}
-
-#if 0
-/* Only > i386 */
-static uint32_t bswap32( uint32_t x )
+/* Write the rest of cur_bits to the bitstream; results in a bitstream no longer 32/64-bit aligned. */
+static inline void bs_flush( bs_t *s )
 {
-    asm( "bswap   %0": "=r" (x):"0" (x));
-    return x;
+    *(intptr_t*)s->p = endian_fix( s->cur_bits << s->i_left );
+    s->p += WORD_SIZE - s->i_left / 8;
+    s->i_left = WORD_SIZE*8;
 }
-/* work only for i_count <= 32 - 7 */
-static inline uint32_t bs_read( bs_t *s, int i_count )
+
+static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
 {
-    if( s->p < s->p_end && i_count > 0 )
+    if( WORD_SIZE == 8 )
     {
-#if 0
-        uint32_t i_cache = ((s->p[0] << 24)+(s->p[1] << 16)+(s->p[2] << 8)+s->p[3]) << (8-s->i_left);
-#else
-        uint32_t i_cache = bswap32( *((uint32_t*)s->p) ) << (8-s->i_left);
-#endif
-        uint32_t i_ret = i_cache >> ( 32 - i_count);
-
+        s->cur_bits = (s->cur_bits << i_count) | i_bits;
         s->i_left -= i_count;
-#if 0
-        if( s->i_left <= 0 )
+        if( s->i_left <= 32 )
         {
-            int i_skip = (8-s->i_left) >> 3;
-
-            s->p += i_skip;
-
-            s->i_left += i_skip << 3;
-        }
+#ifdef WORDS_BIGENDIAN
+            *(uint32_t*)s->p = s->cur_bits >> (32 - s->i_left);
 #else
-        while( s->i_left <= 0 )
-        {
-            s->p++;
-            s->i_left += 8;
-        }
-#endif
-        return i_ret;
-    }
-    return 0;
-}
-
+            *(uint32_t*)s->p = endian_fix( s->cur_bits << s->i_left );
 #endif
-static inline uint32_t bs_read1( bs_t *s )
-{
-
-    if( s->p < s->p_end )
-    {
-        unsigned int i_result;
-
-        s->i_left--;
-        i_result = ( *s->p >> s->i_left )&0x01;
-        if( s->i_left == 0 )
-        {
-            s->p++;
-            s->i_left = 8;
+            s->i_left += 32;
+            s->p += 4;
         }
-        return i_result;
-    }
-
-    return 0;
-}
-static inline uint32_t bs_show( bs_t *s, int i_count )
-{
-#if 0
-    bs_t     s_tmp = *s;
-    return bs_read( &s_tmp, i_count );
-#else
-    if( s->p < s->p_end && i_count > 0 )
-    {
-        uint32_t i_cache = ((s->p[0] << 24)+(s->p[1] << 16)+(s->p[2] << 8)+s->p[3]) << (8-s->i_left);
-        return( i_cache >> ( 32 - i_count) );
-    }
-    return 0;
-#endif
-}
-
-/* TODO optimize */
-static inline void bs_skip( bs_t *s, int i_count )
-{
-    s->i_left -= i_count;
-
-    while( s->i_left <= 0 )
-    {
-        s->p++;
-        s->i_left += 8;
-    }
-}
-
-
-static inline int bs_read_ue( bs_t *s )
-{
-    int i = 0;
-
-    while( bs_read1( s ) == 0 && s->p < s->p_end && i < 32 )
-    {
-        i++;
-    }
-    return( ( 1 << i) - 1 + bs_read( s, i ) );
-}
-static inline int bs_read_se( bs_t *s )
-{
-    int val = bs_read_ue( s );
-
-    return val&0x01 ? (val+1)/2 : -(val/2);
-}
-
-static inline int bs_read_te( bs_t *s, int x )
-{
-    if( x == 1 )
-    {
-        return 1 - bs_read1( s );
     }
-    else if( x > 1 )
-    {
-        return bs_read_ue( s );
-    }
-    return 0;
-}
-
-static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
-{
-    if( s->p >= s->p_end - 4 )
-        return;
-    while( i_count > 0 )
+    else
     {
-        if( i_count < 32 )
-            i_bits &= (1<<i_count)-1;
         if( i_count < s->i_left )
         {
-            *s->p = (*s->p << i_count) | i_bits;
+            s->cur_bits = (s->cur_bits << i_count) | i_bits;
             s->i_left -= i_count;
-            break;
         }
         else
         {
-            *s->p = (*s->p << s->i_left) | (i_bits >> (i_count - s->i_left));
             i_count -= s->i_left;
-            s->p++;
-            s->i_left = 8;
+            s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count);
+            *(uint32_t*)s->p = endian_fix( s->cur_bits );
+            s->p += 4;
+            s->cur_bits = i_bits;
+            s->i_left = 32 - i_count;
         }
     }
 }
 
+/* Special case to eliminate branch in normal bs_write. */
+/* Golomb never writes an even-size code, so this is only used in slice headers. */
+static inline void bs_write32( bs_t *s, uint32_t i_bits )
+{
+    bs_write( s, 16, i_bits >> 16 );
+    bs_write( s, 16, i_bits );
+}
+
 static inline void bs_write1( bs_t *s, uint32_t i_bit )
 {
-    if( s->p < s->p_end )
+    s->cur_bits <<= 1;
+    s->cur_bits |= i_bit;
+    s->i_left--;
+    if( s->i_left == WORD_SIZE*8-32 )
     {
-        *s->p <<= 1;
-        *s->p |= i_bit;
-        s->i_left--;
-        if( s->i_left == 0 )
-        {
-            s->p++;
-            s->i_left = 8;
-        }
+        *(uint32_t*)s->p = endian_fix32( s->cur_bits );
+        s->p += 4;
+        s->i_left = WORD_SIZE*8;
     }
 }
 
 static inline void bs_align_0( bs_t *s )
 {
-    if( s->i_left != 8 )
+    if( s->i_left&7 )
     {
-        *s->p <<= s->i_left;
-        s->i_left = 8;
-        s->p++;
+        s->cur_bits <<= s->i_left&7;
+        s->i_left &= ~7;
     }
+    bs_flush( s );
 }
 static inline void bs_align_1( bs_t *s )
 {
-    if( s->i_left != 8 )
+    if( s->i_left&7 )
     {
-        *s->p <<= s->i_left;
-        *s->p |= (1 << s->i_left) - 1;
-        s->i_left = 8;
-        s->p++;
+        s->cur_bits <<= s->i_left&7;
+        s->cur_bits |= (1 << (s->i_left&7)) - 1;
+        s->i_left &= ~7;
     }
+    bs_flush( s );
 }
-static inline void bs_align( bs_t *s )
-{
-    bs_align_0( s );
-}
-
-
 
 /* golomb functions */
 
-static inline void bs_write_ue( bs_t *s, unsigned int val )
+static const uint8_t x264_ue_size_tab[256] =
 {
-    int i_size = 0;
-    static const int i_size0_255[256] =
-    {
-        1,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
-        6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
-        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-        7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
-        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
-        8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8
-    };
-
-    if( val == 0 )
+     1, 1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7,
+     9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+    11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+    11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
+    13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+    13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+    13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+    13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+    15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
+};
+
+static inline void bs_write_ue_big( bs_t *s, unsigned int val )
+{
+    int size = 0;
+    int tmp = ++val;
+    if( tmp >= 0x10000 )
     {
-        bs_write1( s, 1 );
+        size = 32;
+        tmp >>= 16;
     }
-    else
+    if( tmp >= 0x100 )
     {
-        unsigned int tmp = ++val;
-
-        if( tmp >= 0x00010000 )
-        {
-            i_size += 16;
-            tmp >>= 16;
-        }
-        if( tmp >= 0x100 )
-        {
-            i_size += 8;
-            tmp >>= 8;
-        }
-        i_size += i_size0_255[tmp];
-
-        bs_write( s, 2 * i_size - 1, val );
+        size += 16;
+        tmp >>= 8;
     }
+    size += x264_ue_size_tab[tmp];
+    bs_write( s, size>>1, 0 );
+    bs_write( s, (size>>1)+1, val );
+}
+
+/* Only works on values under 255. */
+static inline void bs_write_ue( bs_t *s, int val )
+{
+    bs_write( s, x264_ue_size_tab[val+1], val+1 );
 }
 
 static inline void bs_write_se( bs_t *s, int val )
 {
-    bs_write_ue( s, val <= 0 ? -val * 2 : val * 2 - 1);
+    int size = 0;
+    int tmp = val = val <= 0 ? -val*2+1 : val*2;
+    if( tmp >= 0x100 )
+    {
+        size = 16;
+        tmp >>= 8;
+    }
+    size += x264_ue_size_tab[tmp];
+    bs_write( s, size, val );
 }
 
 static inline void bs_write_te( bs_t *s, int x, int val )
 {
     if( x == 1 )
-    {
-        bs_write1( s, 1&~val );
-    }
+        bs_write1( s, 1^val );
     else if( x > 1 )
-    {
         bs_write_ue( s, val );
-    }
 }
 
 static inline void bs_rbsp_trailing( bs_t *s )
 {
     bs_write1( s, 1 );
-    if( s->i_left != 8 )
-    {
-        bs_write( s, s->i_left, 0x00 );
-    }
+    bs_flush( s );
 }
 
 static inline int bs_size_ue( unsigned int val )
 {
-    static const int i_size0_254[255] =
-    {
-        1, 3, 3, 5, 5, 5, 5, 7, 7, 7, 7, 7, 7, 7, 7,
-        9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
-        11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,
-        11,11,11,11,11,11,11,11,11,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
-        13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
-        13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,
-        13,13,13,13,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
-        15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
-        15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
-        15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
-        15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,
-        15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15
-    };
+    return x264_ue_size_tab[val+1];
+}
 
+static inline int bs_size_ue_big( unsigned int val )
+{
     if( val < 255 )
-    {
-        return i_size0_254[val];
-    }
+        return x264_ue_size_tab[val+1];
     else
-    {
-        int i_size = 0;
-
-        val++;
-
-        if( val >= 0x10000 )
-        {
-            i_size += 32;
-            val = (val >> 16) - 1;
-        }
-        if( val >= 0x100 )
-        {
-            i_size += 16;
-            val = (val >> 8) - 1;
-        }
-        return i_size0_254[val] + i_size;
-    }
+        return x264_ue_size_tab[(val+1)>>8] + 16;
 }
 
 static inline int bs_size_se( int val )
 {
-    return bs_size_ue( val <= 0 ? -val * 2 : val * 2 - 1);
+    return bs_size_ue_big( val <= 0 ? -val*2 : val*2-1 );
 }
 
 static inline int bs_size_te( int x, int val )
 {
     if( x == 1 )
-    {
         return 1;
-    }
     else if( x > 1 )
-    {
-        return bs_size_ue( val );
-    }
-    return 0;
+        return x264_ue_size_tab[val+1];
+    else
+        return 0;
 }
 
-
-
 #endif