vlc | branch: master | Thomas Guillem <[email protected]> | Thu Jul 30 16:45:35 2015 +0200| [3f5766886f264f288d5a6a8f702cbc4190adce6b] | committer: Felix Paul Kühne
h264_nal: add convert_annexb_to_h264 This function converts Annex B to avcC format. Signed-off-by: Felix Paul Kühne <[email protected]> > http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=3f5766886f264f288d5a6a8f702cbc4190adce6b --- modules/packetizer/h264_nal.c | 161 +++++++++++++++++++++++++++++++++++++++++ modules/packetizer/h264_nal.h | 7 ++ 2 files changed, 168 insertions(+) diff --git a/modules/packetizer/h264_nal.c b/modules/packetizer/h264_nal.c index 3eaf81c..15dda26 100644 --- a/modules/packetizer/h264_nal.c +++ b/modules/packetizer/h264_nal.c @@ -147,6 +147,167 @@ void convert_h264_to_annexb( uint8_t *p_buf, uint32_t i_len, } } +static block_t *h264_increase_startcode_size( block_t *p_block, + size_t i_start_ofs ) +{ + block_t *p_new; + uint32_t i_buf = p_block->i_buffer - i_start_ofs; + uint8_t *p_buf = p_block->p_buffer; + uint8_t *p_new_buf; + size_t i_ofs = i_start_ofs; + size_t i_grow = 0; + size_t i_new_ofs; + + /* Search all startcode of size 3 */ + while( i_buf > 0 ) + { + if( i_buf > 3 && memcmp( &p_buf[i_ofs], annexb_startcode, 3 ) == 0 ) + { + if( i_ofs == 0 || p_buf[i_ofs - 1] != 0 ) + i_grow++; + i_buf -= 3; + i_ofs += 3; + } + else + { + i_buf--; + i_ofs++; + } + } + + 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_new_buf = p_new->p_buffer; + i_new_ofs = i_ofs = i_start_ofs; + + /* Copy the beginning of the buffer (same data) */ + if( i_start_ofs ) + memcpy( p_new_buf, p_buf, i_start_ofs ); + + /* Copy the rest of the buffer and append a 0 before each 000001 */ + while( i_buf > 0 ) + { + if( i_buf > 3 && memcmp( &p_buf[i_ofs], annexb_startcode, 3 ) == 0 ) + { + if( i_ofs == 0 || p_buf[i_ofs - 1] != 0 ) + p_new_buf[i_new_ofs++] = 0; + for( int i = 0; i < 3; ++i ) + p_new_buf[i_new_ofs++] = p_buf[i_ofs++]; + i_buf -= 3; + } else + { + p_new_buf[i_new_ofs++] = p_buf[i_ofs++]; + i_buf--; + } + } + + block_Release( p_block ); + return p_new; +} + +static int h264_replace_startcode( uint8_t *p_buf, + size_t i_nal_length_size, + size_t i_startcode_ofs, + size_t i_nal_size ) +{ + if( i_nal_size < (unsigned) 1 << ( 8 * i_nal_length_size) ) + { + /* NAL is too big to fit in i_nal_length_size */ + return -1; + } + + p_buf[i_startcode_ofs++] = i_nal_size >> (--i_nal_length_size * 8); + if( !i_nal_length_size ) + return 0; + p_buf[i_startcode_ofs++] = i_nal_size >> (--i_nal_length_size * 8); + if( !i_nal_length_size ) + return 0; + p_buf[i_startcode_ofs++] = i_nal_size >> (--i_nal_length_size * 8); + p_buf[i_startcode_ofs] = i_nal_size; + return 0; +} + +block_t *convert_annexb_to_h264( block_t *p_block, size_t i_nal_length_size ) +{ + size_t i_startcode_ofs = 0; + size_t i_startcode_size = 0; + uint32_t i_buf = p_block->i_buffer; + uint8_t *p_buf = p_block->p_buffer; + size_t i_ofs = 0; + + /* The length of the NAL size is encoded using 1, 2 or 4 bytes */ + if( i_nal_length_size != 1 && i_nal_length_size != 2 + && i_nal_length_size != 4 ) + goto error; + + /* Replace the Annex B start code with the size of the NAL. */ + while( i_buf > 0 ) + { + if( i_buf > 3 && memcmp( &p_buf[i_ofs], annexb_startcode, 3 ) == 0 ) + { + if( i_startcode_size ) + { + size_t i_nal_size = i_ofs - i_startcode_ofs - i_startcode_size; + + if( i_ofs > 0 && p_buf[i_ofs - 1] == 0 ) + i_nal_size--; + if( h264_replace_startcode( p_buf, i_nal_length_size, + i_startcode_ofs, + i_nal_size ) ) + goto error; + } + if( i_ofs > 0 && p_buf[i_ofs - 1] == 0 ) + { + /* startcode of size 3 */ + i_startcode_ofs = i_ofs - 1; + i_startcode_size = 4; + } + else + { + i_startcode_ofs = i_ofs; + i_startcode_size = 3; + } + + if( i_startcode_size < i_nal_length_size ) + { + /* i_nal_length_size can't fit in i_startcode_size. Therefore, + * reallocate a buffer in order to increase all startcode that + * are smaller than i_nal_length_size. This is not efficient but + * it's a corner case that won't happen often */ + p_block = h264_increase_startcode_size( p_block, i_startcode_ofs ); + if( !p_block ) + return NULL; + + p_buf = p_block->p_buffer; + i_startcode_size++; + } + i_buf -= 3; + i_ofs += 3; + } + else + { + i_buf--; + i_ofs++; + } + } + + if( i_startcode_size + && h264_replace_startcode( p_buf, i_nal_length_size, i_startcode_ofs, + i_ofs - i_startcode_ofs - i_startcode_size) ) + return NULL; + else + return p_block; +error: + block_Release( p_block ); + return NULL; +} + int h264_get_spspps( uint8_t *p_buf, size_t i_buf, uint8_t **pp_sps, size_t *p_sps_size, uint8_t **pp_pps, size_t *p_pps_size ) diff --git a/modules/packetizer/h264_nal.h b/modules/packetizer/h264_nal.h index d75ccab..d2183db 100644 --- a/modules/packetizer/h264_nal.h +++ b/modules/packetizer/h264_nal.h @@ -120,9 +120,16 @@ int convert_sps_pps( decoder_t *p_dec, const uint8_t *p_buf, uint32_t i_out_buf_size, uint32_t *p_sps_pps_size, uint32_t *p_nal_length_size); +/* Convert avcC format to Annex B in-place */ void convert_h264_to_annexb( uint8_t *p_buf, uint32_t i_len, size_t i_nal_length_size ); +/* Convert Annex B to avcC format in-place + * Returns the same p_block or a new p_block if there is not enough room to put + * the NAL size. In case of error, NULL is returned and p_block is released. + * */ +block_t *convert_annexb_to_h264( block_t *p_block, size_t i_nal_length_size ); + /* Get the SPS/PPS pointers from an Annex B buffer * Returns 0 if a SPS and/or a PPS is found */ int h264_get_spspps( uint8_t *p_buf, size_t i_buf, _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
