[vlc-devel] [PATCH 2/4] h264_nal: add convert_annexb_to_h264

Thomas Guillem thomas at gllm.fr
Thu Jul 30 16:45:35 CEST 2015


This function converts Annex B to avcC format.
---
 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,
-- 
2.1.4




More information about the vlc-devel mailing list