[vlc-commits] h264_nal: add convert_annexb_to_h264
Thomas Guillem
git at videolan.org
Fri Jul 31 15:43:09 CEST 2015
vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | 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 <fkuehne at videolan.org>
> 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,
More information about the vlc-commits
mailing list