x86 assembly code for NAL escaping
authorJason Garrett-Glaser <darkshikari@gmail.com>
Thu, 27 May 2010 21:27:32 +0000 (14:27 -0700)
committerJason Garrett-Glaser <darkshikari@gmail.com>
Wed, 2 Jun 2010 02:51:24 +0000 (19:51 -0700)
Up to ~10x faster than C depending on CPU.
Helps the most at very high bitrates (e.g. lossless).
Also make the C code faster and simpler.

Makefile
common/bitstream.c [new file with mode: 0644]
common/bitstream.h [new file with mode: 0644]
common/bs.h [deleted file]
common/common.c
common/common.h
common/x86/bitstream-a.asm [new file with mode: 0644]
common/x86/deblock-a.asm
encoder/encoder.c
tools/checkasm.c

index 0b43a3e..519e181 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@ SRCS = common/mc.c common/predict.c common/pixel.c common/macroblock.c \
        common/frame.c common/dct.c common/cpu.c common/cabac.c \
        common/common.c common/mdate.c common/rectangle.c \
        common/set.c common/quant.c common/deblock.c common/vlc.c \
-       common/mvpred.c \
+       common/mvpred.c common/bitstream.c \
        encoder/analyse.c encoder/me.c encoder/ratecontrol.c \
        encoder/set.c encoder/macroblock.c encoder/cabac.c \
        encoder/cavlc.c encoder/encoder.c encoder/lookahead.c
@@ -52,7 +52,7 @@ endif
 ifneq ($(AS),)
 X86SRC0 = const-a.asm cabac-a.asm dct-a.asm deblock-a.asm mc-a.asm \
           mc-a2.asm pixel-a.asm predict-a.asm quant-a.asm sad-a.asm \
-          cpu-a.asm dct-32.asm
+          cpu-a.asm dct-32.asm bitstream-a.asm
 X86SRC = $(X86SRC0:%=common/x86/%)
 
 ifeq ($(ARCH),X86)
diff --git a/common/bitstream.c b/common/bitstream.c
new file mode 100644 (file)
index 0000000..0aaac21
--- /dev/null
@@ -0,0 +1,92 @@
+/*****************************************************************************
+ * bitstream.c: h264 encoder library
+ *****************************************************************************
+ * Copyright (C) 2010 x264 project
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *          Jason Garrett-Glaser <darkshikari@gmail.com>
+ *
+ * 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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#include "common.h"
+
+static uint8_t *x264_nal_escape_c( uint8_t *dst, uint8_t *src, uint8_t *end )
+{
+    if( src < end ) *dst++ = *src++;
+    if( src < end ) *dst++ = *src++;
+    while( src < end )
+    {
+        if( src[0] <= 0x03 && !dst[-2] && !dst[-1] )
+            *dst++ = 0x03;
+        *dst++ = *src++;
+    }
+    return dst;
+}
+
+#ifdef HAVE_MMX
+uint8_t *x264_nal_escape_mmxext( uint8_t *dst, uint8_t *src, uint8_t *end );
+uint8_t *x264_nal_escape_sse2( uint8_t *dst, uint8_t *src, uint8_t *end );
+#endif
+
+/****************************************************************************
+ * x264_nal_encode:
+ ****************************************************************************/
+int x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal, int b_long_startcode )
+{
+    uint8_t *src = nal->p_payload;
+    uint8_t *end = nal->p_payload + nal->i_payload;
+    uint8_t *orig_dst = dst;
+
+    if( h->param.b_annexb )
+    {
+        if( b_long_startcode )
+            *dst++ = 0x00;
+        *dst++ = 0x00;
+        *dst++ = 0x00;
+        *dst++ = 0x01;
+    }
+    else /* save room for size later */
+        dst += 4;
+
+    /* nal header */
+    *dst++ = ( 0x00 << 7 ) | ( nal->i_ref_idc << 5 ) | nal->i_type;
+
+    dst = h->bsf.nal_escape( dst, src, end );
+    int size = (dst - orig_dst) - 4;
+
+    /* Write the size header for mp4/etc */
+    if( !h->param.b_annexb )
+    {
+        /* Size doesn't include the size of the header we're writing now. */
+        orig_dst[0] = size>>24;
+        orig_dst[1] = size>>16;
+        orig_dst[2] = size>> 8;
+        orig_dst[3] = size>> 0;
+    }
+
+    return size+4;
+}
+
+void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf )
+{
+    pf->nal_escape = x264_nal_escape_c;
+#ifdef HAVE_MMX
+    if( cpu&X264_CPU_MMXEXT )
+        pf->nal_escape = x264_nal_escape_mmxext;
+    if( (cpu&X264_CPU_SSE2) && (cpu&X264_CPU_SSE2_IS_FAST) )
+        pf->nal_escape = x264_nal_escape_sse2;
+#endif
+}
diff --git a/common/bitstream.h b/common/bitstream.h
new file mode 100644 (file)
index 0000000..d018c7d
--- /dev/null
@@ -0,0 +1,299 @@
+/*****************************************************************************
+ * bitstream.h: h264 encoder library
+ *****************************************************************************
+ * Copyright (C) 2003-2008 x264 project
+ *
+ * Authors: Loren Merritt <lorenm@u.washington.edu>
+ *          Jason Garrett-Glaser <darkshikari@gmail.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
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#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
+{
+    uint8_t *p_start;
+    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];
+
+typedef struct
+{
+    uint8_t *(*nal_escape) ( uint8_t *dst, uint8_t *src, uint8_t *end );
+} x264_bitstream_function_t;
+
+int x264_nal_encode( x264_t *h, uint8_t *dst, x264_nal_t *nal, int b_long_startcode );
+void x264_bitstream_init( int cpu, x264_bitstream_function_t *pf );
+
+/* 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 & 3);
+    s->p       = s->p_start = (uint8_t*)p_data - offset;
+    s->p_end   = (uint8_t*)p_data + i_data;
+    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-bit aligned. */
+static inline void bs_flush( bs_t *s )
+{
+    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 )
+{
+    if( WORD_SIZE == 8 )
+    {
+        s->cur_bits = (s->cur_bits << i_count) | i_bits;
+        s->i_left -= i_count;
+        if( s->i_left <= 32 )
+        {
+#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;
+        }
+    }
+    else
+    {
+        if( i_count < s->i_left )
+        {
+            s->cur_bits = (s->cur_bits << i_count) | i_bits;
+            s->i_left -= i_count;
+        }
+        else
+        {
+            i_count -= s->i_left;
+            s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count);
+            M32( 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 )
+{
+    s->cur_bits <<= 1;
+    s->cur_bits |= i_bit;
+    s->i_left--;
+    if( s->i_left == WORD_SIZE*8-32 )
+    {
+        M32( 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 )
+{
+    bs_write( s, s->i_left&7, 0 );
+    bs_flush( s );
+}
+static inline void bs_align_1( bs_t *s )
+{
+    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 */
+
+static const uint8_t x264_ue_size_tab[256] =
+{
+     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 )
+    {
+        size = 32;
+        tmp >>= 16;
+    }
+    if( tmp >= 0x100 )
+    {
+        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 )
+{
+    int size = 0;
+    /* 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;
+        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 );
+    else //if( x > 1 )
+        bs_write_ue( s, val );
+}
+
+static inline void bs_rbsp_trailing( bs_t *s )
+{
+    bs_write1( s, 1 );
+    bs_write( s, s->i_left&7, 0  );
+}
+
+static ALWAYS_INLINE int bs_size_ue( unsigned int val )
+{
+    return x264_ue_size_tab[val+1];
+}
+
+static ALWAYS_INLINE int bs_size_ue_big( unsigned int val )
+{
+    if( val < 255 )
+        return x264_ue_size_tab[val+1];
+    else
+        return x264_ue_size_tab[(val+1)>>8] + 16;
+}
+
+static ALWAYS_INLINE int bs_size_se( int val )
+{
+    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 ALWAYS_INLINE int bs_size_te( int x, int val )
+{
+    if( x == 1 )
+        return 1;
+    else //if( x > 1 )
+        return x264_ue_size_tab[val+1];
+}
+
+#endif
diff --git a/common/bs.h b/common/bs.h
deleted file mode 100644 (file)
index 343a3c9..0000000
+++ /dev/null
@@ -1,291 +0,0 @@
-/*****************************************************************************
- * bs.h :
- *****************************************************************************
- * Copyright (C) 2003-2008 x264 project
- *
- * Authors: Loren Merritt <lorenm@u.washington.edu>
- *          Jason Garrett-Glaser <darkshikari@gmail.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
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program 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 General Public License for more details.
- *
- * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
- *****************************************************************************/
-
-#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
-{
-    uint8_t *p_start;
-    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 )
-{
-    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  = (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-bit aligned. */
-static inline void bs_flush( bs_t *s )
-{
-    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 )
-{
-    if( WORD_SIZE == 8 )
-    {
-        s->cur_bits = (s->cur_bits << i_count) | i_bits;
-        s->i_left -= i_count;
-        if( s->i_left <= 32 )
-        {
-#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;
-        }
-    }
-    else
-    {
-        if( i_count < s->i_left )
-        {
-            s->cur_bits = (s->cur_bits << i_count) | i_bits;
-            s->i_left -= i_count;
-        }
-        else
-        {
-            i_count -= s->i_left;
-            s->cur_bits = (s->cur_bits << s->i_left) | (i_bits >> i_count);
-            M32( 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 )
-{
-    s->cur_bits <<= 1;
-    s->cur_bits |= i_bit;
-    s->i_left--;
-    if( s->i_left == WORD_SIZE*8-32 )
-    {
-        M32( 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 )
-{
-    bs_write( s, s->i_left&7, 0 );
-    bs_flush( s );
-}
-static inline void bs_align_1( bs_t *s )
-{
-    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 */
-
-static const uint8_t x264_ue_size_tab[256] =
-{
-     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 )
-    {
-        size = 32;
-        tmp >>= 16;
-    }
-    if( tmp >= 0x100 )
-    {
-        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 )
-{
-    int size = 0;
-    /* 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;
-        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 );
-    else //if( x > 1 )
-        bs_write_ue( s, val );
-}
-
-static inline void bs_rbsp_trailing( bs_t *s )
-{
-    bs_write1( s, 1 );
-    bs_write( s, s->i_left&7, 0  );
-}
-
-static ALWAYS_INLINE int bs_size_ue( unsigned int val )
-{
-    return x264_ue_size_tab[val+1];
-}
-
-static ALWAYS_INLINE int bs_size_ue_big( unsigned int val )
-{
-    if( val < 255 )
-        return x264_ue_size_tab[val+1];
-    else
-        return x264_ue_size_tab[(val+1)>>8] + 16;
-}
-
-static ALWAYS_INLINE int bs_size_se( int val )
-{
-    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 ALWAYS_INLINE int bs_size_te( int x, int val )
-{
-    if( x == 1 )
-        return 1;
-    else //if( x > 1 )
-        return x264_ue_size_tab[val+1];
-}
-
-#endif
index fccf2b0..2458f65 100644 (file)
@@ -1027,60 +1027,6 @@ void x264_picture_clean( x264_picture_t *pic )
 }
 
 /****************************************************************************
- * x264_nal_encode:
- ****************************************************************************/
-int x264_nal_encode( uint8_t *dst, x264_nal_t *nal, int b_annexb, int b_long_startcode )
-{
-    uint8_t *src = nal->p_payload;
-    uint8_t *end = nal->p_payload + nal->i_payload;
-    uint8_t *orig_dst = dst;
-    int i_count = 0, size;
-
-    if( b_annexb )
-    {
-        if( b_long_startcode )
-            *dst++ = 0x00;
-        *dst++ = 0x00;
-        *dst++ = 0x00;
-        *dst++ = 0x01;
-    }
-    else /* save room for size later */
-        dst += 4;
-
-    /* nal header */
-    *dst++ = ( 0x00 << 7 ) | ( nal->i_ref_idc << 5 ) | nal->i_type;
-
-    while( src < end )
-    {
-        if( i_count == 2 && *src <= 0x03 )
-        {
-            *dst++ = 0x03;
-            i_count = 0;
-        }
-        if( *src == 0 )
-            i_count++;
-        else
-            i_count = 0;
-        *dst++ = *src++;
-    }
-    size = (dst - orig_dst) - 4;
-
-    /* Write the size header for mp4/etc */
-    if( !b_annexb )
-    {
-        /* Size doesn't include the size of the header we're writing now. */
-        orig_dst[0] = size>>24;
-        orig_dst[1] = size>>16;
-        orig_dst[2] = size>> 8;
-        orig_dst[3] = size>> 0;
-    }
-
-    return size+4;
-}
-
-
-
-/****************************************************************************
  * x264_malloc:
  ****************************************************************************/
 void *x264_malloc( int i_size )
index 539ea65..93712fe 100644 (file)
@@ -137,7 +137,7 @@ static const int x264_scan8[16+2*4+3] =
 */
 
 #include "x264.h"
-#include "bs.h"
+#include "bitstream.h"
 #include "set.h"
 #include "predict.h"
 #include "pixel.h"
@@ -166,8 +166,6 @@ int64_t x264_mdate( void );
  * the encoding options */
 char *x264_param2string( x264_param_t *p, int b_res );
 
-int x264_nal_encode( uint8_t *dst, x264_nal_t *nal, int b_annexb, int b_long_startcode );
-
 /* log */
 void x264_log( x264_t *h, int i_level, const char *psz_fmt, ... );
 
@@ -796,6 +794,7 @@ struct x264_t
     x264_zigzag_function_t zigzagf;
     x264_quant_function_t quantf;
     x264_deblock_function_t loopf;
+    x264_bitstream_function_t bsf;
 
 #ifdef HAVE_VISUALIZE
     struct visualize_t *visualize;
diff --git a/common/x86/bitstream-a.asm b/common/x86/bitstream-a.asm
new file mode 100644 (file)
index 0000000..69a47a7
--- /dev/null
@@ -0,0 +1,112 @@
+;*****************************************************************************
+;* bitstream-a.asm: h264 encoder library
+;*****************************************************************************
+;* Copyright (C) 2010 x264 project
+;*
+;* Authors: Jason Garrett-Glaser <darkshikari@gmail.com>
+;*
+;* 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
+;* the Free Software Foundation; either version 2 of the License, or
+;* (at your option) any later version.
+;*
+;* This program 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 General Public License for more details.
+;*
+;* 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., 51 Franklin Street, Fifth Floor, Boston, MA  02111, USA.
+;*****************************************************************************
+
+%include "x86inc.asm"
+%include "x86util.asm"
+
+SECTION .text
+
+;-----------------------------------------------------------------------------
+; uint8_t *x264_nal_escape( uint8_t *dst, uint8_t *src, uint8_t *end )
+;-----------------------------------------------------------------------------
+
+%macro NAL_LOOP 2
+ALIGN 16
+%1:
+    mova      m0, [r1+r2]
+    mova      m1, m0
+%if mmsize == 8
+    psllq     m0, 8
+%else
+    pslldq    m0, 1
+%endif
+    %2   [r0+r1], m1
+    por       m1, m0
+    pcmpeqb   m1, m2
+    pmovmskb r3d, m1
+    test     r3d, r3d
+    jnz .escape
+    add       r1, mmsize
+    jl %1
+%endmacro
+
+%macro NAL_ESCAPE 1
+
+cglobal nal_escape_%1, 3,5
+    pxor      m2, m2
+    sub       r1, r2 ; r1 = offset of current src pointer from end of src
+    sub       r0, r1 ; r0 = projected end of dst, assuming no more escapes
+
+    mov      r3b, [r1+r2]
+    mov  [r0+r1], r3b
+    inc       r1
+    jge .ret
+
+    ; Start off by jumping into the escape loop in
+    ; case there's an escape at the start.
+    ; And do a few more in scalar until src is aligned again.
+    lea      r4d, [r1+r2]
+    or       r4d, -mmsize
+    neg      r4d
+    jmp .first_escape
+
+    NAL_LOOP .loop_aligned, mova
+%if mmsize==16
+    NAL_LOOP .loop_unaligned, movu
+%endif
+
+.ret:
+    movifnidn rax, r0
+    RET
+ALIGN 16
+.escape:
+    mov      r4d, mmsize
+.first_escape:
+    mov      r3b, [r1+r2]
+.escape_loop:
+    mov  [r0+r1], r3b
+    inc      r1
+    jge .ret
+    mov      r3b, [r1+r2]
+    cmp      r3b, 3
+    jna .escape_check
+.no_escape:
+    dec      r4d
+    jg .escape_loop
+%if mmsize==16
+    lea      r4d, [r0+r1]
+    test     r4d, mmsize-1
+    jnz .loop_unaligned
+%endif
+    jmp .loop_aligned
+.escape_check:
+    cmp word [r0+r1-2], 0
+    jnz .no_escape
+    mov byte [r0+r1], 3
+    inc      r0
+    jmp .no_escape
+%endmacro
+
+INIT_MMX
+NAL_ESCAPE mmxext
+INIT_XMM
+NAL_ESCAPE sse2
index aedd688..3a31e26 100644 (file)
@@ -4,6 +4,7 @@
 ;* Copyright (C) 2005-2008 x264 project
 ;*
 ;* Authors: Loren Merritt <lorenm@u.washington.edu>
+;*          Jason Garrett-Glaser <darkshikari@gmail.com>
 ;*
 ;* 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
index 7717ea8..2f9e7f6 100644 (file)
@@ -987,6 +987,7 @@ x264_t *x264_encoder_open( x264_param_t *param )
     x264_mc_init( h->param.cpu, &h->mc );
     x264_quant_init( h, h->param.cpu, &h->quantf );
     x264_deblock_init( h->param.cpu, &h->loopf );
+    x264_bitstream_init( h->param.cpu, &h->bsf );
     x264_dct_init_weights();
 
     mbcmp_init( h );
@@ -1273,7 +1274,7 @@ static int x264_encoder_encapsulate_nals( x264_t *h, int start )
     for( int i = start; i < h->out.i_nal; i++ )
     {
         int long_startcode = !i || h->out.nal[i].i_type == NAL_SPS || h->out.nal[i].i_type == NAL_PPS;
-        int size = x264_nal_encode( nal_buffer, &h->out.nal[i], h->param.b_annexb, long_startcode );
+        int size = x264_nal_encode( h, nal_buffer, &h->out.nal[i], long_startcode );
         h->out.nal[i].i_payload = size;
         h->out.nal[i].p_payload = nal_buffer;
         nal_buffer += size;
index a0a9d54..8293fdc 100644 (file)
@@ -1661,6 +1661,56 @@ static int check_cabac( int cpu_ref, int cpu_new )
     return ret;
 }
 
+static int check_bitstream( int cpu_ref, int cpu_new )
+{
+    x264_bitstream_function_t bs_c;
+    x264_bitstream_function_t bs_ref;
+    x264_bitstream_function_t bs_a;
+
+    int ret = 0, ok = 1, used_asm = 0;
+
+    x264_bitstream_init( 0, &bs_c );
+    x264_bitstream_init( cpu_ref, &bs_ref );
+    x264_bitstream_init( cpu_new, &bs_a );
+    if( bs_a.nal_escape != bs_ref.nal_escape )
+    {
+        int size = 0x4000;
+        uint8_t *input = malloc(size+100);
+        uint8_t *output1 = malloc(size*2);
+        uint8_t *output2 = malloc(size*2);
+        used_asm = 1;
+        set_func_name( "nal_escape" );
+        for( int i = 0; i < 100; i++ )
+        {
+            /* Test corner-case sizes */
+            int test_size = i < 10 ? i+1 : rand() & 0x3fff;
+            /* Test 8 different probability distributions of zeros */
+            for( int j = 0; j < test_size; j++ )
+                input[j] = (rand()&((1 << ((i&7)+1)) - 1)) * rand();
+            uint8_t *end_c = (uint8_t*)call_c1( bs_c.nal_escape, output1, input, input+test_size );
+            uint8_t *end_a = (uint8_t*)call_a1( bs_a.nal_escape, output2, input, input+test_size );
+            int size_c = end_c-output1;
+            int size_a = end_a-output2;
+            if( size_c != size_a || memcmp( output1, output2, size_c ) )
+            {
+                fprintf( stderr, "nal_escape :  [FAILED] %d %d\n", size_c, size_a );
+                ok = 0;
+                break;
+            }
+        }
+        for( int j = 0; j < size; j++ )
+            input[j] = rand();
+        call_c2( bs_c.nal_escape, output1, input, input+size );
+        call_a2( bs_a.nal_escape, output2, input, input+size );
+        free(input);
+        free(output1);
+        free(output2);
+    }
+    report( "nal escape:" );
+
+    return ret;
+}
+
 static int check_all_funcs( int cpu_ref, int cpu_new )
 {
     return check_pixel( cpu_ref, cpu_new )
@@ -1669,7 +1719,8 @@ static int check_all_funcs( int cpu_ref, int cpu_new )
          + check_intra( cpu_ref, cpu_new )
          + check_deblock( cpu_ref, cpu_new )
          + check_quant( cpu_ref, cpu_new )
-         + check_cabac( cpu_ref, cpu_new );
+         + check_cabac( cpu_ref, cpu_new )
+         + check_bitstream( cpu_ref, cpu_new );
 }
 
 static int add_flags( int *cpu_ref, int *cpu_new, int flags, const char *name )