[vlc-commits] vlc_bits: rework for custom handler pos/remain accounting

Francois Cartegnie git at videolan.org
Mon Aug 20 16:53:22 CEST 2018


vlc | branch: master | Francois Cartegnie <fcvlcdev at free.fr> | Fri Aug 10 14:51:33 2018 +0200| [273e38d0c35a65f11cdc524ce4e664b60fc0d982] | committer: Francois Cartegnie

vlc_bits: rework for custom handler pos/remain accounting

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=273e38d0c35a65f11cdc524ce4e664b60fc0d982
---

 include/vlc_bits.h              | 224 +++++++++++++++++++++++-----------------
 modules/packetizer/Makefile.am  |   3 +
 modules/packetizer/h264_nal.c   |  10 +-
 modules/packetizer/h264_slice.c |   8 +-
 modules/packetizer/hevc_nal.c   |  32 +++---
 modules/packetizer/hxxx_ep3b.h  | 137 ++++++++++++++++++++++++
 modules/packetizer/hxxx_nal.h   |  48 ---------
 modules/packetizer/hxxx_sei.c   |  24 ++---
 modules/packetizer/vc1.c        |  25 ++---
 test/src/misc/bits.c            |  24 +++--
 10 files changed, 327 insertions(+), 208 deletions(-)

diff --git a/include/vlc_bits.h b/include/vlc_bits.h
index 1e3d845b3a..7a941933fc 100644
--- a/include/vlc_bits.h
+++ b/include/vlc_bits.h
@@ -32,59 +32,140 @@
  * This file defines functions, structures for handling streams of bits in vlc
  */
 
+typedef struct bs_s bs_t;
+
+typedef struct
+{
+    /* forward read modifier (p_start, p_end, p_fwpriv, count, pos, remain) */
+    size_t (*pf_byte_forward)(bs_t *, size_t);
+    size_t (*pf_byte_pos)(const bs_t *);
+    size_t (*pf_byte_remain)(const bs_t *);
+} bs_byte_callbacks_t;
+
 typedef struct bs_s
 {
     uint8_t *p_start;
-    uint8_t *p;
+    uint8_t *p;         /* points to currently read/written byte */
     uint8_t *p_end;
 
-    ssize_t  i_left;    /* i_count number of available bits */
+    uint8_t  i_left;    /* i_count number of available bits */
     bool     b_read_only;
 
-     /* forward read modifier (p_start, p_end, p_fwpriv, count) */
-    uint8_t *(*pf_forward)(uint8_t *, uint8_t *, void *, size_t);
-    void    *p_fwpriv;
+    bs_byte_callbacks_t cb;
+    void    *p_priv;
 } bs_t;
 
-static inline void bs_write_init( bs_t *s, void *p_data, size_t i_data )
+static size_t bs_impl_bytes_forward( bs_t *s, size_t i_count )
+{
+    if( s->p == NULL )
+    {
+        s->p = s->p_start;
+        return 1;
+    }
+
+    if( s->p >= s->p_end )
+        return 0;
+
+    if( (size_t) (s->p_end - s->p) < i_count )
+        i_count = s->p_end - s->p;
+    s->p += i_count;
+    return i_count;
+}
+
+static size_t bs_impl_bytes_remain( const bs_t *s )
+{
+    if( s->p )
+        return s->p < s->p_end ? s->p_end - s->p - 1: 0;
+    else
+        return s->p_end - s->p_start;
+}
+
+static size_t bs_impl_bytes_pos( const bs_t *s )
+{
+    if( s->p )
+        return s->p < s->p_end ? s->p - s->p_start + 1 : s->p - s->p_start;
+    else
+        return 0;
+}
+
+static inline void bs_init_custom( bs_t *s, const void *p_data, size_t i_data,
+                                   const bs_byte_callbacks_t *cb, void *priv )
 {
     s->p_start = (uint8_t *)p_data;
-    s->p       = s->p_start;
+    s->p       = NULL;
     s->p_end   = s->p_start + i_data;
-    s->i_left  = 8;
-    s->b_read_only = false;
-    s->p_fwpriv = NULL;
-    s->pf_forward = NULL;
+    s->i_left  = 0;
+    s->b_read_only = true;
+    s->p_priv = priv;
+    s->cb = *cb;
 }
 
 static inline void bs_init( bs_t *s, const void *p_data, size_t i_data )
 {
-    bs_write_init( s, (void*) p_data, i_data );
-    s->b_read_only = true;
+    bs_byte_callbacks_t cb = {
+        bs_impl_bytes_forward,
+        bs_impl_bytes_pos,
+        bs_impl_bytes_remain,
+    };
+    bs_init_custom( s, p_data, i_data, &cb, NULL );
 }
 
-static inline int bs_pos( const bs_t *s )
+static inline void bs_write_init( bs_t *s, void *p_data, size_t i_data )
 {
-    return( 8 * ( s->p - s->p_start ) + 8 - s->i_left );
+    bs_init( s, (const void *) p_data, i_data );
+    s->b_read_only = false;
 }
 
-static inline int bs_remain( const bs_t *s )
+static inline int bs_refill( bs_t *s )
 {
-    if( s->p >= s->p_end )
-        return 0;
-    else
-    return( 8 * ( s->p_end - s->p ) - 8 + s->i_left );
+    if( s->i_left == 0 )
+    {
+       if( s->cb.pf_byte_forward( s, 1 ) != 1 )
+           return -1;
+
+       if( s->p < s->p_end )
+            s->i_left = 8;
+    }
+    return s->i_left > 0 ? 0 : 1;
+}
+
+static inline bool bs_eof( bs_t *s )
+{
+    return bs_refill( s ) != 0;
 }
 
-static inline int bs_eof( const bs_t *s )
+static inline size_t bs_pos( const bs_t *s )
 {
-    return( s->p >= s->p_end ? 1: 0 );
+    return 8 * s->cb.pf_byte_pos( s ) - s->i_left;
 }
 
-#define bs_forward( s, i ) \
-    s->p = s->pf_forward ? s->pf_forward( s->p, s->p_end, s->p_fwpriv, i ) : s->p + i
+static inline size_t bs_remain( const bs_t *s )
+{
+    return 8 * s->cb.pf_byte_remain( s ) + s->i_left;
+}
 
-static inline uint32_t bs_read( bs_t *s, int i_count )
+static inline void bs_skip( bs_t *s, size_t i_count )
+{
+    if( i_count == 0 )
+        return;
+
+    if( bs_refill( s ) )
+        return;
+
+    if( i_count > s->i_left )
+    {
+        i_count -= s->i_left;
+        s->i_left = 0;
+        if( i_count / 8 )
+            s->cb.pf_byte_forward( s, i_count / 8 );
+        i_count = i_count % 8;
+        if( i_count > 0 && !bs_refill( s ) )
+            s->i_left = 8 - i_count;
+    }
+    else s->i_left -= i_count;
+}
+
+static inline uint32_t bs_read( bs_t *s, uint8_t i_count )
 {
      static const uint32_t i_mask[33] =
      {  0x00,
@@ -96,7 +177,7 @@ static inline uint32_t bs_read( bs_t *s, int i_count )
         0x1fffff,  0x3fffff,  0x7fffff,  0xffffff,
         0x1ffffff, 0x3ffffff, 0x7ffffff, 0xfffffff,
         0x1fffffff,0x3fffffff,0x7fffffff,0xffffffff};
-    int      i_shr, i_drop = 0;
+    uint8_t  i_shr, i_drop = 0;
     uint32_t i_result = 0;
 
     if( i_count > 32 )
@@ -107,87 +188,53 @@ static inline uint32_t bs_read( bs_t *s, int i_count )
 
     while( i_count > 0 )
     {
-        if( s->p >= s->p_end )
-        {
+        if( bs_refill( s ) )
             break;
-        }
 
-        if( ( i_shr = s->i_left - i_count ) >= 0 )
+        if( s->i_left > i_count )
         {
+            i_shr = s->i_left - i_count;
             /* 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 )
-            {
-                bs_forward( s, 1 );
-                s->i_left = 8;
-            }
             break;
         }
         else
         {
+            i_shr = i_count - s->i_left;
             /* less in the buffer than requested */
-           if( -i_shr == 32 )
+           if( i_shr >= 32 )
                i_result = 0;
            else
-               i_result |= (*s->p&i_mask[s->i_left]) << -i_shr;
+               i_result |= (*s->p&i_mask[s->i_left]) << i_shr;
            i_count  -= s->i_left;
-           bs_forward( s, 1);
-           s->i_left = 8;
+           s->i_left = 0;
         }
     }
 
     if( i_drop )
-        bs_forward( s, i_drop );
+        bs_skip( s, i_drop );
 
     return( i_result );
 }
 
 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 )
-        {
-            bs_forward( s, 1 );
-            s->i_left = 8;
-        }
-        return i_result;
-    }
-
-    return 0;
-}
-
-static inline void bs_skip( bs_t *s, ssize_t i_count )
-{
-    s->i_left -= i_count;
-
-    if( s->i_left <= 0 )
-    {
-        const size_t i_bytes = 1 + s->i_left / -8;
-        bs_forward( s, i_bytes );
-        if( i_bytes * 8 < i_bytes /* ofw */ )
-            s->i_left = i_bytes;
-        else
-            s->i_left += 8 * i_bytes;
-    }
+    if( bs_refill( s ) )
+        return 0;
+    s->i_left--;
+    return ( *s->p >> s->i_left )&0x01;
 }
 
-static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
+static inline void bs_write( bs_t *s, uint8_t i_count, uint32_t i_bits )
 {
     if( s->b_read_only )
         return;
 
     while( i_count > 0 )
     {
-        if( s->p >= s->p_end )
-        {
+        if( bs_refill( s ) )
             break;
-        }
 
         i_count--;
 
@@ -200,11 +247,6 @@ static inline void bs_write( bs_t *s, int i_count, uint32_t i_bits )
             *s->p &= ~( 1 << ( s->i_left - 1 ) );
         }
         s->i_left--;
-        if( s->i_left == 0 )
-        {
-            bs_forward( s, 1 );
-            s->i_left = 8;
-        }
     }
 }
 
@@ -215,28 +257,18 @@ static inline bool bs_aligned( bs_t *s )
 
 static inline void bs_align( bs_t *s )
 {
-    if( s->i_left != 8 )
-    {
-        s->i_left = 8;
-        s->p++;
-    }
+    if( s->i_left % 8 )
+        s->i_left = 0;
 }
 
-static inline void bs_align_0( bs_t *s )
+static inline void bs_write_align( bs_t *s, uint8_t v )
 {
-    if( s->i_left != 8 )
-    {
-        bs_write( s, s->i_left, 0 );
-    }
+    if( !s->b_read_only && (s->i_left % 8) )
+        bs_write( s, s->i_left, v ? 0xFF : 0 );
 }
 
-static inline void bs_align_1( bs_t *s )
-{
-    while( !s->b_read_only && s->i_left != 8 )
-    {
-        bs_write( s, 1, 1 );
-    }
-}
+#define bs_align_0( s ) bs_write_align( s, 0 )
+#define bs_align_1( s ) bs_write_align( s, 1 )
 
 /* Read unsigned Exp-Golomb code */
 static inline uint_fast32_t bs_read_ue( bs_t * bs )
diff --git a/modules/packetizer/Makefile.am b/modules/packetizer/Makefile.am
index 4945ed7aca..0551c4d0a7 100644
--- a/modules/packetizer/Makefile.am
+++ b/modules/packetizer/Makefile.am
@@ -14,8 +14,10 @@ libpacketizer_h264_plugin_la_SOURCES = \
 	packetizer/h264.c packetizer/hxxx_nal.h \
 	packetizer/hxxx_sei.c packetizer/hxxx_sei.h \
 	packetizer/hxxx_common.c packetizer/hxxx_common.h \
+        packetizer/hxxx_ep3b.h \
         packetizer/iso_color_tables.h
 libpacketizer_vc1_plugin_la_SOURCES = packetizer/vc1.c \
+        packetizer/hxxx_ep3b.h \
         packetizer/hxxx_nal.h
 libpacketizer_mlp_plugin_la_SOURCES = packetizer/mlp.c
 libpacketizer_flac_plugin_la_SOURCES = packetizer/flac.c \
@@ -25,6 +27,7 @@ libpacketizer_hevc_plugin_la_SOURCES = packetizer/hevc.c \
 	packetizer/hxxx_sei.c packetizer/hxxx_sei.h \
 	packetizer/hxxx_nal.h \
 	packetizer/hxxx_common.c packetizer/hxxx_common.h \
+        packetizer/hxxx_ep3b.h \
         packetizer/iso_color_tables.h
 libpacketizer_a52_plugin_la_SOURCES = packetizer/a52.c packetizer/a52.h
 libpacketizer_dts_plugin_la_SOURCES = packetizer/dts.c \
diff --git a/modules/packetizer/h264_nal.c b/modules/packetizer/h264_nal.c
index d5144c69d8..74d4ba6b85 100644
--- a/modules/packetizer/h264_nal.c
+++ b/modules/packetizer/h264_nal.c
@@ -25,6 +25,7 @@
 
 #include "h264_nal.h"
 #include "hxxx_nal.h"
+#include "hxxx_ep3b.h"
 #include "iso_color_tables.h"
 
 #include <vlc_bits.h>
@@ -615,14 +616,13 @@ static bool h264_parse_picture_parameter_set_rbsp( bs_t *p_bs,
         if(likely(p_h264type)) \
         { \
             bs_t bs; \
-            bs_init( &bs, p_buf, i_buf ); \
-            unsigned i_bitflow = 0; \
+            struct hxxx_bsfw_ep3b_ctx_s bsctx; \
             if( b_escaped ) \
             { \
-                bs.p_fwpriv = &i_bitflow; \
-                bs.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */ \
+                hxxx_bsfw_ep3b_ctx_init( &bsctx ); \
+                bs_init_custom( &bs, p_buf, i_buf, &hxxx_bsfw_ep3b_callbacks, &bsctx );\
             } \
-            else (void) i_bitflow;\
+            else bs_init( &bs, p_buf, i_buf ); \
             bs_skip( &bs, 8 ); /* Skip nal_unit_header */ \
             if( !decode( &bs, p_h264type ) ) \
             { \
diff --git a/modules/packetizer/h264_slice.c b/modules/packetizer/h264_slice.c
index d05256e93e..91b43a3a7e 100644
--- a/modules/packetizer/h264_slice.c
+++ b/modules/packetizer/h264_slice.c
@@ -27,6 +27,7 @@
 #include "h264_nal.h"
 #include "h264_slice.h"
 #include "hxxx_nal.h"
+#include "hxxx_ep3b.h"
 
 bool h264_decode_slice( const uint8_t *p_buffer, size_t i_buffer,
                         void (* get_sps_pps)(uint8_t, void *,
@@ -37,10 +38,9 @@ bool h264_decode_slice( const uint8_t *p_buffer, size_t i_buffer,
     int i_slice_type;
     h264_slice_init( p_slice );
     bs_t s;
-    unsigned i_bitflow = 0;
-    bs_init( &s, p_buffer, i_buffer );
-    s.p_fwpriv = &i_bitflow;
-    s.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
+    struct hxxx_bsfw_ep3b_ctx_s bsctx;
+    hxxx_bsfw_ep3b_ctx_init( &bsctx );
+    bs_init_custom( &s, p_buffer, i_buffer, &hxxx_bsfw_ep3b_callbacks, &bsctx );
 
     /* nal unit header */
     bs_skip( &s, 1 );
diff --git a/modules/packetizer/hevc_nal.c b/modules/packetizer/hevc_nal.c
index bc47f79e55..1a281b74ec 100644
--- a/modules/packetizer/hevc_nal.c
+++ b/modules/packetizer/hevc_nal.c
@@ -23,6 +23,7 @@
 
 #include "hevc_nal.h"
 #include "hxxx_nal.h"
+#include "hxxx_ep3b.h"
 #include "iso_color_tables.h"
 
 #include <vlc_common.h>
@@ -700,14 +701,13 @@ void hevc_rbsp_release_vps( hevc_video_parameter_set_t *p_vps )
         if(likely(p_hevctype)) \
         { \
             bs_t bs; \
-            bs_init( &bs, p_buf, i_buf ); \
-            unsigned i_bitflow = 0; \
+            struct hxxx_bsfw_ep3b_ctx_s bsctx; \
             if( b_escaped ) \
             { \
-                bs.p_fwpriv = &i_bitflow; \
-                bs.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */ \
+                hxxx_bsfw_ep3b_ctx_init( &bsctx ); \
+                bs_init_custom( &bs, p_buf, i_buf, &hxxx_bsfw_ep3b_callbacks, &bsctx );\
             } \
-            else (void) i_bitflow;\
+            else bs_init( &bs, p_buf, i_buf ); \
             bs_skip( &bs, 7 ); /* nal_unit_header */ \
             uint8_t i_nuh_layer_id = bs_read( &bs, 6 ); \
             bs_skip( &bs, 3 ); /* !nal_unit_header */ \
@@ -762,7 +762,7 @@ static bool hevc_parse_st_ref_pic_set( bs_t *p_bs, unsigned stRpsIdx,
     {
         nal_ue_t num_negative_pics = bs_read_ue( p_bs );
         nal_ue_t num_positive_pics = bs_read_ue( p_bs );
-        if( bs_remain( p_bs ) < ((int64_t)num_negative_pics + num_positive_pics) * 2 )
+        if( bs_remain( p_bs ) < (num_negative_pics + num_positive_pics) * 2 )
             return false;
         for(unsigned int i=0; i<num_negative_pics; i++)
         {
@@ -977,8 +977,8 @@ static bool hevc_parse_pic_parameter_set_rbsp( bs_t *p_bs,
         p_pps->uniform_spacing_flag = bs_read1( p_bs );
         if( !p_pps->uniform_spacing_flag )
         {
-            if( bs_remain( p_bs ) < (int64_t) p_pps->num_tile_columns_minus1 +
-                                               p_pps->num_tile_rows_minus1 + 1 )
+            if( bs_remain( p_bs ) < p_pps->num_tile_columns_minus1 +
+                                    p_pps->num_tile_rows_minus1 + 1 )
                 return false;
             for( unsigned i=0; i< p_pps->num_tile_columns_minus1; i++ )
                 (void) bs_read_ue( p_bs );
@@ -1296,14 +1296,13 @@ hevc_slice_segment_header_t * hevc_decode_slice_header( const uint8_t *p_buf, si
     if(likely(p_sh))
     {
         bs_t bs;
-        bs_init( &bs, p_buf, i_buf );
-        unsigned i_bitflow = 0;
+        struct hxxx_bsfw_ep3b_ctx_s bsctx;
         if( b_escaped )
         {
-            bs.p_fwpriv = &i_bitflow;
-            bs.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
+            hxxx_bsfw_ep3b_ctx_init( &bsctx );
+            bs_init_custom( &bs, p_buf, i_buf, &hxxx_bsfw_ep3b_callbacks, &bsctx );
         }
-        else (void) i_bitflow;
+        else bs_init( &bs, p_buf, i_buf );
         bs_skip( &bs, 1 );
         p_sh->nal_type = bs_read( &bs, 6 );
         p_sh->nuh_layer_id = bs_read( &bs, 6 );
@@ -1359,10 +1358,9 @@ static void hevc_dcr_params_from_vps( const uint8_t * p_buffer, size_t i_buffer,
         return;
 
     bs_t bs;
-    bs_init( &bs, p_buffer, i_buffer );
-    unsigned i_bitflow = 0;
-    bs.p_fwpriv = &i_bitflow;
-    bs.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
+    struct hxxx_bsfw_ep3b_ctx_s bsctx;
+    hxxx_bsfw_ep3b_ctx_init( &bsctx );
+    bs_init_custom( &bs, p_buffer, i_buffer, &hxxx_bsfw_ep3b_callbacks, &bsctx );
 
     /* first two bytes are the NAL header, 3rd and 4th are:
         vps_video_parameter_set_id(4)
diff --git a/modules/packetizer/hxxx_ep3b.h b/modules/packetizer/hxxx_ep3b.h
new file mode 100644
index 0000000000..6e134b65a0
--- /dev/null
+++ b/modules/packetizer/hxxx_ep3b.h
@@ -0,0 +1,137 @@
+/*****************************************************************************
+ * hxxx_ep3b.h
+ *****************************************************************************
+ * Copyright (C) 2014-2015 VLC authors and VideoLAN
+ *                    2018 VideoLabs
+ *
+ * This program 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.
+ *
+ * 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 Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+#include <vlc_bits.h>
+
+static inline uint8_t *hxxx_ep3b_to_rbsp( uint8_t *p, uint8_t *end, unsigned *pi_prev, size_t i_count )
+{
+    for( size_t i=0; i<i_count; i++ )
+    {
+        if( ++p >= end )
+            return p;
+
+        *pi_prev = (*pi_prev << 1) | (!*p);
+
+        if( *p == 0x03 &&
+           ( p + 1 ) != end ) /* Never escape sequence if no next byte */
+        {
+            if( (*pi_prev & 0x06) == 0x06 )
+            {
+                ++p;
+                *pi_prev = ((*pi_prev >> 1) << 1) | (!*p);
+            }
+        }
+    }
+    return p;
+}
+
+#if 0
+/* Discards emulation prevention three bytes */
+static inline uint8_t * hxxx_ep3b_to_rbsp(const uint8_t *p_src, size_t i_src, size_t *pi_ret)
+{
+    uint8_t *p_dst;
+    if(!p_src || !(p_dst = malloc(i_src)))
+        return NULL;
+
+    size_t j = 0;
+    for (size_t i = 0; i < i_src; i++) {
+        if (i < i_src - 3 &&
+            p_src[i] == 0 && p_src[i+1] == 0 && p_src[i+2] == 3) {
+            p_dst[j++] = 0;
+            p_dst[j++] = 0;
+            i += 2;
+            continue;
+        }
+        p_dst[j++] = p_src[i];
+    }
+    *pi_ret = j;
+    return p_dst;
+}
+#endif
+
+/* vlc_bits's bs_t forward callback for stripping emulation prevention three bytes */
+struct hxxx_bsfw_ep3b_ctx_s
+{
+    unsigned i_prev;
+    size_t i_bytepos;
+    size_t i_bytesize;
+};
+
+static void hxxx_bsfw_ep3b_ctx_init( struct hxxx_bsfw_ep3b_ctx_s *ctx )
+{
+    ctx->i_prev = 0;
+    ctx->i_bytepos = 0;
+    ctx->i_bytesize = 0;
+}
+
+static size_t hxxx_ep3b_total_size( const uint8_t *p, const uint8_t *p_end )
+{
+    /* compute final size */
+    unsigned i_prev = 0;
+    size_t i = 0;
+    while( p < p_end )
+    {
+        uint8_t *n = hxxx_ep3b_to_rbsp( (uint8_t *)p, (uint8_t *)p_end, &i_prev, 1 );
+        if( n > p )
+            ++i;
+        p = n;
+    }
+    return i;
+}
+
+static size_t hxxx_bsfw_byte_forward_ep3b( bs_t *s, size_t i_count )
+{
+    struct hxxx_bsfw_ep3b_ctx_s *ctx = (struct hxxx_bsfw_ep3b_ctx_s *) s->p_priv;
+    if( s->p == NULL )
+    {
+        ctx->i_bytesize = hxxx_ep3b_total_size( s->p_start, s->p_end );
+        s->p = s->p_start;
+        ctx->i_bytepos = 1;
+        return 1;
+    }
+
+    if( s->p >= s->p_end )
+        return 0;
+
+    s->p = hxxx_ep3b_to_rbsp( s->p, s->p_end, &ctx->i_prev, i_count );
+    ctx->i_bytepos += i_count;
+    return i_count;
+}
+
+static size_t hxxx_bsfw_byte_pos_ep3b( const bs_t *s )
+{
+    struct hxxx_bsfw_ep3b_ctx_s *ctx = (struct hxxx_bsfw_ep3b_ctx_s *) s->p_priv;
+    return ctx->i_bytepos;
+}
+
+static size_t hxxx_bsfw_byte_remain_ep3b( const bs_t *s )
+{
+    struct hxxx_bsfw_ep3b_ctx_s *ctx = (struct hxxx_bsfw_ep3b_ctx_s *) s->p_priv;
+    if( ctx->i_bytesize == 0 && s->p_start != s->p_end )
+        ctx->i_bytesize = hxxx_ep3b_total_size( s->p_start, s->p_end );
+    return ctx->i_bytesize - ctx->i_bytepos;
+}
+
+static const bs_byte_callbacks_t hxxx_bsfw_ep3b_callbacks =
+{
+    hxxx_bsfw_byte_forward_ep3b,
+    hxxx_bsfw_byte_pos_ep3b,
+    hxxx_bsfw_byte_remain_ep3b,
+};
diff --git a/modules/packetizer/hxxx_nal.h b/modules/packetizer/hxxx_nal.h
index 4da89a01b7..81ef497f49 100644
--- a/modules/packetizer/hxxx_nal.h
+++ b/modules/packetizer/hxxx_nal.h
@@ -53,54 +53,6 @@ static inline bool hxxx_strip_AnnexB_startcode( const uint8_t **pp_data, size_t
     return false;
 }
 
-/* vlc_bits's bs_t forward callback for stripping emulation prevention three bytes */
-static inline uint8_t *hxxx_bsfw_ep3b_to_rbsp( uint8_t *p, uint8_t *end, void *priv, size_t i_count )
-{
-    unsigned *pi_prev = (unsigned *) priv;
-    for( size_t i=0; i<i_count; i++ )
-    {
-        if( ++p >= end )
-            return p;
-
-        *pi_prev = (*pi_prev << 1) | (!*p);
-
-        if( *p == 0x03 &&
-           ( p + 1 ) != end ) /* Never escape sequence if no next byte */
-        {
-            if( (*pi_prev & 0x06) == 0x06 )
-            {
-                ++p;
-                *pi_prev = ((*pi_prev >> 1) << 1) | (!*p);
-            }
-        }
-    }
-    return p;
-}
-
-#if 0
-/* Discards emulation prevention three bytes */
-static inline uint8_t * hxxx_ep3b_to_rbsp(const uint8_t *p_src, size_t i_src, size_t *pi_ret)
-{
-    uint8_t *p_dst;
-    if(!p_src || !(p_dst = malloc(i_src)))
-        return NULL;
-
-    size_t j = 0;
-    for (size_t i = 0; i < i_src; i++) {
-        if (i < i_src - 3 &&
-            p_src[i] == 0 && p_src[i+1] == 0 && p_src[i+2] == 3) {
-            p_dst[j++] = 0;
-            p_dst[j++] = 0;
-            i += 2;
-            continue;
-        }
-        p_dst[j++] = p_src[i];
-    }
-    *pi_ret = j;
-    return p_dst;
-}
-#endif
-
 /* Declarations */
 
 typedef struct
diff --git a/modules/packetizer/hxxx_sei.c b/modules/packetizer/hxxx_sei.c
index 18a249cdaa..79cfa91b3d 100644
--- a/modules/packetizer/hxxx_sei.c
+++ b/modules/packetizer/hxxx_sei.c
@@ -22,11 +22,12 @@
 #endif
 
 #include <vlc_common.h>
-#include <vlc_bits.h>
 #include <vlc_block.h>
+#include <vlc_bits.h>
 
 #include "hxxx_sei.h"
 #include "hxxx_nal.h"
+#include "hxxx_ep3b.h"
 
 void HxxxParse_AnnexB_SEI(const uint8_t *p_buf, size_t i_buf,
                           uint8_t i_header, pf_hxxx_sei_callback cb, void *cbdata)
@@ -38,30 +39,17 @@ void HxxxParse_AnnexB_SEI(const uint8_t *p_buf, size_t i_buf,
 void HxxxParseSEI(const uint8_t *p_buf, size_t i_buf,
                   uint8_t i_header, pf_hxxx_sei_callback pf_callback, void *cbdata)
 {
-    bs_t s_ep3b;
     bs_t s;
-    unsigned i_bitflow = 0;
     bool b_continue = true;
-    char buf[256];
-    int i = 0;
 
     if( i_buf <= i_header )
         return;
 
-    bs_init( &s_ep3b, &p_buf[i_header], i_buf - i_header ); /* skip nal unit header */
-    s_ep3b.p_fwpriv = &i_bitflow;
-    s_ep3b.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
-
-    /* While a NAL can technically be up to 65535 bytes, an SEI NAL
-       will never be anywhere near that size */
-    if (bs_remain(&s_ep3b) / 8 > sizeof(buf))
-        return;
-
-    while (bs_remain(&s_ep3b) > 0)
-        buf[i++] = bs_read(&s_ep3b, 8);
+    struct hxxx_bsfw_ep3b_ctx_s bsctx;
+    hxxx_bsfw_ep3b_ctx_init( &bsctx );
+    bs_init_custom( &s, &p_buf[i_header], i_buf - i_header, /* skip nal unit header */
+                    &hxxx_bsfw_ep3b_callbacks, &bsctx );
 
-    /* Parse the resulting RBSP bytes as SEI */
-    bs_init( &s, buf, i);
 
     while( bs_remain( &s ) >= 8 && bs_aligned( &s ) && b_continue )
     {
diff --git a/modules/packetizer/vc1.c b/modules/packetizer/vc1.c
index 53b5bc1836..6f70214f73 100644
--- a/modules/packetizer/vc1.c
+++ b/modules/packetizer/vc1.c
@@ -40,6 +40,7 @@
 #include "../codec/cc.h"
 #include "packetizer_helper.h"
 #include "hxxx_nal.h"
+#include "hxxx_ep3b.h"
 #include "startcode_helper.h"
 
 /*****************************************************************************
@@ -327,6 +328,7 @@ static void BuildExtraData( decoder_t *p_dec )
     memcpy( (uint8_t*)p_es->p_extra + p_sys->sh.p_sh->i_buffer,
             p_sys->ep.p_ep->p_buffer, p_sys->ep.p_ep->i_buffer );
 }
+
 /* ParseIDU: parse an Independent Decoding Unit */
 static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag )
 {
@@ -438,7 +440,6 @@ static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag )
     {
         es_format_t *p_es = &p_dec->fmt_out;
         bs_t s;
-        unsigned i_bitflow = 0;
         int i_profile;
 
         /* */
@@ -473,9 +474,10 @@ static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag )
         }
 
         /* Parse it */
-        bs_init( &s, &p_frag->p_buffer[4], p_frag->i_buffer - 4 );
-        s.p_fwpriv = &i_bitflow;
-        s.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
+        struct hxxx_bsfw_ep3b_ctx_s bsctx;
+        hxxx_bsfw_ep3b_ctx_init( &bsctx );
+        bs_init_custom( &s, &p_frag->p_buffer[4], p_frag->i_buffer - 4,
+                        &hxxx_bsfw_ep3b_callbacks, &bsctx );
 
         i_profile = bs_read( &s, 2 );
         if( i_profile == 3 )
@@ -645,12 +647,12 @@ static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag )
     else if( idu == IDU_TYPE_FRAME )
     {
         bs_t s;
-        unsigned i_bitflow = 0;
 
         /* Parse it + interpolate pts/dts if possible */
-        bs_init( &s, &p_frag->p_buffer[4], p_frag->i_buffer - 4 );
-        s.p_fwpriv = &i_bitflow;
-        s.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
+        struct hxxx_bsfw_ep3b_ctx_s bsctx;
+        hxxx_bsfw_ep3b_ctx_init( &bsctx );
+        bs_init_custom( &s, &p_frag->p_buffer[4], p_frag->i_buffer - 4,
+                        &hxxx_bsfw_ep3b_callbacks, &bsctx );
 
         if( p_sys->sh.b_advanced_profile )
         {
@@ -724,11 +726,10 @@ static block_t *ParseIDU( decoder_t *p_dec, bool *pb_ts_used, block_t *p_frag )
     else if( idu == IDU_TYPE_FRAME_USER_DATA )
     {
         bs_t s;
-        unsigned i_bitflow = 0;
         const size_t i_size = p_frag->i_buffer - 4;
-        bs_init( &s, &p_frag->p_buffer[4], i_size );
-        s.p_fwpriv = &i_bitflow;
-        s.pf_forward = hxxx_bsfw_ep3b_to_rbsp;  /* Does the emulated 3bytes conversion to rbsp */
+        struct hxxx_bsfw_ep3b_ctx_s bsctx;
+        hxxx_bsfw_ep3b_ctx_init( &bsctx );
+        bs_init_custom( &s, &p_frag->p_buffer[4], i_size, &hxxx_bsfw_ep3b_callbacks, &bsctx );
 
         unsigned i_data;
         uint8_t *p_data = malloc( i_size );
diff --git a/test/src/misc/bits.c b/test/src/misc/bits.c
index bd64eaefb3..18ff7d6574 100644
--- a/test/src/misc/bits.c
+++ b/test/src/misc/bits.c
@@ -29,16 +29,24 @@
         return 1; \
     } } while( 0 )
 
-static uint8_t *skip1( uint8_t *p, uint8_t *end, void *priv, size_t i_count )
+static size_t skip1( bs_t *s, size_t i_count )
 {
-    (void) priv;
-    for( size_t i=0; i<i_count; i++ )
+    if( s->p == NULL )
     {
-        p += 2;
-        if( p >= end )
-            return p;
+        s->p = s->p_start;
+        return 1 + skip1( s, i_count - 1 );
+    }
+
+    if( s->p_end - s->p > (ssize_t) i_count * 2 )
+    {
+        s->p += i_count * 2;
+        return i_count;
+    }
+    else
+    {
+        s->p = s->p_end;
+        return 0;
     }
-    return p;
 }
 
 int main( void )
@@ -126,7 +134,7 @@ int main( void )
     const uint8_t ok[6] = { 0xAA, 0xCC, 0xEE, /* ovfw fillers */ 0, 0, 0 };
     uint8_t work[6] = { 0 };
     bs_init( &bs, &abc, 6 );
-    bs.pf_forward = skip1;
+    bs.cb.pf_byte_forward = skip1;
     for( unsigned i=0; i<6 && !bs_eof( &bs ); i++ )
         work[i] = bs_read( &bs, 8 );
     test_assert(memcmp( &work, &ok, 6 ), 0);



More information about the vlc-commits mailing list