Commit 273e38d0 authored by François Cartegnie's avatar François Cartegnie 🤞

vlc_bits: rework for custom handler pos/remain accounting

parent 671789ae
......@@ -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 )
{
s->p_start = (uint8_t *)p_data;
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 = 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;
}
if( bs_refill( s ) )
return 0;
s->i_left--;
return ( *s->p >> s->i_left )&0x01;
}
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;
}
}
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 )
......
......@@ -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 \
......
......@@ -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 ) ) \
{ \
......
......@@ -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 );
......
......@@ -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,7 +977,7 @@ 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 +
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++ )
......@@ -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)
......
/*****************************************************************************
* 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,
};
......@@ -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 )