vlc | branch: master | Francois Cartegnie <[email protected]> | Sun Dec 20 21:12:10 2015 +0100| [928acb9ece7b319aa4f0eb60fbd0ccae5d3ccfe7] | committer: Francois Cartegnie
hxxx_nal: add generic AnnexB to AVC/HVC converter Converts any AnnexB prefix to any xVC prefix. Adds zero copy optimizations for single NAL. > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=928acb9ece7b319aa4f0eb60fbd0ccae5d3ccfe7 --- modules/packetizer/h264_nal.c | 22 +++-- modules/packetizer/hxxx_nal.c | 182 +++++++++++++++++++++++++++++++++++++++++ modules/packetizer/hxxx_nal.h | 5 ++ 3 files changed, 200 insertions(+), 9 deletions(-) diff --git a/modules/packetizer/h264_nal.c b/modules/packetizer/h264_nal.c index d771cf3..70808dc 100644 --- a/modules/packetizer/h264_nal.c +++ b/modules/packetizer/h264_nal.c @@ -166,30 +166,34 @@ static block_t *h264_increase_startcode_size( block_t *p_block, size_t i_new_ofs; /* Search all startcode of size 3 */ - while( i_buf > 0 ) + unsigned i_bitflow = 0; + unsigned i_nalcount = 0; + while( i_buf-- ) { - if( i_buf > 3 && memcmp( &p_buf[i_ofs], annexb_startcode3, 3 ) == 0 ) + i_bitflow <<= 1; + if( *(p_buf++) != 0x01 ) { - if( i_ofs == 0 || p_buf[i_ofs - 1] != 0 ) - i_grow++; - i_buf -= 3; - i_ofs += 3; + i_bitflow |= 1; } - else + else if( (i_bitflow & 0x06) == 0x06 ) /* two zero prefixed 1 */ { - i_buf--; - i_ofs++; + i_nalcount++; + if( !(i_bitflow & 0x08) ) /* max two zero prefixed 1 */ + i_grow++; } } if( i_grow == 0 ) return p_block; + + /* Alloc a bigger buffer */ p_new = block_Alloc( p_block->i_buffer + i_grow ); if( !p_new ) return NULL; i_buf = p_block->i_buffer - i_start_ofs; + p_buf = p_block->p_buffer; p_new_buf = p_new->p_buffer; i_new_ofs = i_ofs = i_start_ofs; diff --git a/modules/packetizer/hxxx_nal.c b/modules/packetizer/hxxx_nal.c new file mode 100644 index 0000000..dc49570 --- /dev/null +++ b/modules/packetizer/hxxx_nal.c @@ -0,0 +1,182 @@ +/***************************************************************************** + * Copyright © 2015 VideoLAN Authors + * + * 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 "hxxx_nal.h" + +#include <vlc_block.h> + +static bool block_WillRealloc( block_t *p_block, ssize_t i_prebody, size_t i_body ) +{ + if( i_prebody <= 0 && i_body <= (size_t)(-i_prebody) ) + return false; + else + return ( i_prebody + i_body <= p_block->i_size ); +} + +static inline void hxxx_WritePrefix( uint8_t i_nal_length_size, uint8_t *p_dest, uint32_t i_payload ) +{ + if( i_nal_length_size == 4 ) + SetDWBE( p_dest, i_payload ); + else if( i_nal_length_size == 2 ) + SetWBE( p_dest, i_payload ); + else + *p_dest = i_payload; +} + +static block_t *hxxx_AnnexB_to_xVC( block_t *p_block, uint8_t i_nal_length_size ) +{ + unsigned i_nalcount = 0; + unsigned i_list = 16; + struct nalmoves_e + { + const uint8_t *p; /* start of prefixed nal */ + uint8_t prefix; /* startcode length */ + off_t move; /* move offset */ + } *p_list = NULL; + + if(!p_block->i_buffer || p_block->p_buffer[0]) + goto error; + + if(! (p_list = malloc( sizeof(*p_list) * i_list )) ) + goto error; + + /* Search all startcode of size 3 */ + const uint8_t *p_buf = p_block->p_buffer; + const uint8_t *p_end = &p_block->p_buffer[p_block->i_buffer]; + unsigned i_bitflow = 0; + off_t i_move = 0; + while( p_buf != p_end ) + { + i_bitflow <<= 1; + if( !*p_buf ) + { + i_bitflow |= 1; + } + else if( *p_buf == 0x01 && (i_bitflow & 0x06) == 0x06 ) /* >= two zero prefixed 1 */ + { + if( i_bitflow & 0x08 ) /* three zero prefixed 1 */ + { + p_list[i_nalcount].p = &p_buf[-3]; + p_list[i_nalcount].prefix = 4; + } + else /* two zero prefixed 1 */ + { + p_list[i_nalcount].p = &p_buf[-2]; + p_list[i_nalcount].prefix = 3; + } + i_move += (off_t) i_nal_length_size - p_list[i_nalcount].prefix; + p_list[i_nalcount++].move = i_move; + + /* Check and realloc our list */ + if(i_nalcount == i_list) + { + i_list += 16; + struct nalmoves_e *p_new = malloc( sizeof(*p_new) * i_list ); + if(unlikely(!p_new)) + goto error; + p_list = p_new; + } + } + p_buf++; + } + + if( !i_nalcount ) + goto error; + + /* Optimization for 1 NAL block only case */ + if( i_nalcount == 1 && block_WillRealloc( p_block, p_list[0].move, p_block->i_buffer ) ) + { + uint32_t i_payload = p_block->i_buffer - p_list[0].prefix; + block_t *p_newblock = block_Realloc( p_block, p_list[0].move, p_block->i_buffer ); + if( unlikely(!p_newblock) ) + goto error; + p_block = p_newblock; + hxxx_WritePrefix( i_nal_length_size, p_block->p_buffer , i_payload ); + free( p_list ); + return p_block; + } + + block_t *p_release = NULL; + const uint8_t *p_source = NULL; + const uint8_t *p_sourceend = NULL; + uint8_t *p_dest = NULL; + const size_t i_dest = p_block->i_buffer + p_list[i_nalcount - 1].move; + + if( p_list[i_nalcount - 1].move != 0 || i_nal_length_size != 4 ) /* We'll need to grow or shrink */ + { + /* If we grow in size, try using realloc to avoid memcpy */ + if( p_list[i_nalcount - 1].move > 0 && block_WillRealloc( p_block, 0, i_dest ) ) + { + uint32_t i_sizebackup = p_block->i_buffer; + block_t *p_newblock = block_Realloc( p_block, 0, i_dest ); + if( unlikely(!p_newblock) ) + goto error; + + p_block = p_newblock; + p_sourceend = &p_block->p_buffer[i_sizebackup]; + p_source = p_dest = p_block->p_buffer; + } + else + { + block_t *p_newblock = block_Alloc( i_dest ); + if( unlikely(!p_newblock) ) + goto error; + + p_release = p_block; /* Will be released after use */ + p_source = p_release->p_buffer; + p_sourceend = &p_release->p_buffer[p_release->i_buffer]; + + p_block = p_newblock; + p_dest = p_newblock->p_buffer; + } + } + else + { + p_source = p_dest = p_block->p_buffer; + p_sourceend = &p_block->p_buffer[p_block->i_buffer]; + } + + if(!p_dest) + goto error; + + /* Do reverse order moves, so we never overlap when growing only */ + for( unsigned i=i_nalcount; i!=0; i-- ) + { + const uint8_t *p_readstart = p_list[i - 1].p; + uint32_t i_payload = p_sourceend - p_readstart - p_list[i - 1].prefix; + off_t offset = p_list[i - 1].p - p_source + p_list[i - 1].prefix + p_list[i - 1].move; +// printf(" move offset %ld, length = %ld prefix %ld move %ld\n", p_readstart - p_source, i_payload, p_list[i - 1].prefix, p_list[i-1].move); + + /* move in same / copy between buffers */ + memmove( &p_dest[ offset ], &p_list[i - 1].p[ p_list[i - 1].prefix ], i_payload ); + + hxxx_WritePrefix( i_nal_length_size, &p_dest[ offset - i_nal_length_size ] , i_payload ); + + p_sourceend = p_readstart; + } + + if( p_release ) + block_Release( p_release ); + free( p_list ); + return p_block; + +error: + free( p_list ); + block_Release( p_block ); + return NULL; +} diff --git a/modules/packetizer/hxxx_nal.h b/modules/packetizer/hxxx_nal.h index 768c223..70d2eae 100644 --- a/modules/packetizer/hxxx_nal.h +++ b/modules/packetizer/hxxx_nal.h @@ -103,4 +103,9 @@ static inline uint8_t * hxxx_ep3b_to_rbsp(const uint8_t *p_src, size_t i_src, si } #endif +/* Declarations */ + +/* Takes any AnnexB NAL buffer and converts it to prefixed size (AVC/HEVC) */ +block_t *hxxx_AnnexB_to_xVC( block_t *p_block, uint8_t i_nal_length_size ); + #endif // HXXX_NAL_H _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
