]> git.sesse.net Git - x264/blobdiff - common/bs.h
Faster chroma CBP handling
[x264] / common / bs.h
index a30cf3431f09c5818587bf63eb7afe1f8651377b..a090988b11eddb8c36632efe2d03fd33bda7fa86 100644 (file)
@@ -31,6 +31,14 @@ typedef struct
     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
 {
     uint8_t *p_start;
@@ -42,31 +50,60 @@ typedef struct bs_s
     int     i_bits_encoded; /* RD only */
 } bs_t;
 
-extern const vlc_t x264_coeff_token[5][17*4];
+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][15];
+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 )
 {
-    int offset = ((intptr_t)p_data & (WORD_SIZE-1));
+    int offset = ((intptr_t)p_data & 3);
     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 );
+    s->i_left  = (WORD_SIZE - offset)*8;
+    s->cur_bits = endian_fix32( M32(s->p) );
+    s->cur_bits >>= (4-offset)*8;
 }
 static inline int bs_pos( bs_t *s )
 {
     return( 8 * (s->p - s->p_start) + (WORD_SIZE*8) - s->i_left );
 }
 
-/* Write the rest of cur_bits to the bitstream; results in a bitstream no longer 32/64-bit aligned. */
+/* Write the rest of cur_bits to the bitstream; results in a bitstream no longer 32-bit aligned. */
 static inline void bs_flush( bs_t *s )
 {
-    *(intptr_t*)s->p = endian_fix( s->cur_bits << s->i_left );
+    M32( s->p ) = endian_fix32( s->cur_bits << (s->i_left&31) );
     s->p += WORD_SIZE - s->i_left / 8;
     s->i_left = WORD_SIZE*8;
 }
+/* The inverse of bs_flush: prepare the bitstream to be written to again. */
+static inline void bs_realign( bs_t *s )
+{
+    int offset = ((intptr_t)s->p & 3);
+    if( offset )
+    {
+        s->p       = (uint8_t*)s->p - offset;
+        s->i_left  = (WORD_SIZE - offset)*8;
+        s->cur_bits = endian_fix32( M32(s->p) );
+        s->cur_bits >>= (4-offset)*8;
+    }
+}
 
 static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
 {
@@ -76,7 +113,11 @@ static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
         s->i_left -= i_count;
         if( s->i_left <= 32 )
         {
-            *(uint32_t*)s->p = endian_fix( s->cur_bits << s->i_left );
+#ifdef WORDS_BIGENDIAN
+            M32( s->p ) = s->cur_bits >> (32 - s->i_left);
+#else
+            M32( s->p ) = endian_fix( s->cur_bits << s->i_left );
+#endif
             s->i_left += 32;
             s->p += 4;
         }
@@ -92,7 +133,7 @@ static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
         {
             i_count -= s->i_left;
             s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count);
-            *(uint32_t*)s->p = endian_fix( s->cur_bits );
+            M32( s->p ) = endian_fix( s->cur_bits );
             s->p += 4;
             s->cur_bits = i_bits;
             s->i_left = 32 - i_count;
@@ -115,7 +156,7 @@ static inline void bs_write1( bs_t *s, uint32_t i_bit )
     s->i_left--;
     if( s->i_left == WORD_SIZE*8-32 )
     {
-        *(uint32_t*)s->p = endian_fix32( s->cur_bits );
+        M32( s->p ) = endian_fix32( s->cur_bits );
         s->p += 4;
         s->i_left = WORD_SIZE*8;
     }
@@ -123,23 +164,19 @@ static inline void bs_write1( bs_t *s, uint32_t i_bit )
 
 static inline void bs_align_0( bs_t *s )
 {
-    if( s->i_left&7 )
-    {
-        s->cur_bits <<= s->i_left&7;
-        s->i_left &= ~7;
-    }
+    bs_write( s, s->i_left&7, 0 );
     bs_flush( s );
 }
 static inline void bs_align_1( bs_t *s )
 {
-    if( s->i_left&7 )
-    {
-        s->cur_bits <<= s->i_left&7;
-        s->cur_bits |= (1 << (s->i_left&7)) - 1;
-        s->i_left &= ~7;
-    }
+    bs_write( s, s->i_left&7, (1 << (s->i_left&7)) - 1 );
     bs_flush( s );
 }
+static inline void bs_align_10( bs_t *s )
+{
+    if( s->i_left&7 )
+        bs_write( s, s->i_left&7, 1 << ( (s->i_left&7) - 1 ) );
+}
 
 /* golomb functions */
 
@@ -191,7 +228,12 @@ static inline void bs_write_ue( bs_t *s, int val )
 static inline void bs_write_se( bs_t *s, int val )
 {
     int size = 0;
-    int tmp = val = val <= 0 ? -val*2+1 : val*2;
+    /* Faster than (val <= 0 ? -val*2+1 : val*2) */
+    /* 4 instructions on x86, 3 on ARM */
+    int tmp = 1 - val*2;
+    if( tmp < 0 ) tmp = val*2;
+    val = tmp;
+
     if( tmp >= 0x100 )
     {
         size = 16;
@@ -205,22 +247,22 @@ static inline void bs_write_te( bs_t *s, int x, int val )
 {
     if( x == 1 )
         bs_write1( s, 1^val );
-    else if( x > 1 )
+    else //if( x > 1 )
         bs_write_ue( s, val );
 }
 
 static inline void bs_rbsp_trailing( bs_t *s )
 {
     bs_write1( s, 1 );
-    bs_flush( s );
+    bs_write( s, s->i_left&7, 0  );
 }
 
-static inline int bs_size_ue( unsigned int val )
+static ALWAYS_INLINE int bs_size_ue( unsigned int val )
 {
     return x264_ue_size_tab[val+1];
 }
 
-static inline int bs_size_ue_big( unsigned int val )
+static ALWAYS_INLINE int bs_size_ue_big( unsigned int val )
 {
     if( val < 255 )
         return x264_ue_size_tab[val+1];
@@ -228,19 +270,22 @@ static inline int bs_size_ue_big( unsigned int val )
         return x264_ue_size_tab[(val+1)>>8] + 16;
 }
 
-static inline int bs_size_se( int val )
+static ALWAYS_INLINE int bs_size_se( int val )
 {
-    return bs_size_ue_big( val <= 0 ? -val*2 : val*2-1 );
+    int tmp = 1 - val*2;
+    if( tmp < 0 ) tmp = val*2;
+    if( tmp < 256 )
+        return x264_ue_size_tab[tmp];
+    else
+        return x264_ue_size_tab[tmp>>8]+16;
 }
 
-static inline int bs_size_te( int x, int val )
+static ALWAYS_INLINE int bs_size_te( int x, int val )
 {
     if( x == 1 )
         return 1;
-    else if( x > 1 )
+    else //if( x > 1 )
         return x264_ue_size_tab[val+1];
-    else
-        return 0;
 }
 
 #endif