[vlc-commits] [Git][videolan/vlc][master] 6 commits: packetizer: h264: refactor sps/pps duplication

Jean-Baptiste Kempf (@jbk) gitlab at videolan.org
Mon Apr 10 01:48:56 UTC 2023



Jean-Baptiste Kempf pushed to branch master at VideoLAN / VLC


Commits:
3ea4bcad by Francois Cartegnie at 2023-04-09T16:17:08+00:00
packetizer: h264: refactor sps/pps duplication

- - - - -
86393842 by Francois Cartegnie at 2023-04-09T16:17:08+00:00
packetizer: h264: compare sps/pps before replacement

- - - - -
c85581f4 by Francois Cartegnie at 2023-04-09T16:17:08+00:00
packetizer: h264: add h264_get_xps_id shortcut

- - - - -
21a329cc by Francois Cartegnie at 2023-04-09T16:17:08+00:00
packetizer: h264: refactor sps/pps handling

- - - - -
d8898afb by Francois Cartegnie at 2023-04-09T16:17:08+00:00
packetizer: h264: refactor gathering sps/pps

- - - - -
ed97dd9f by Francois Cartegnie at 2023-04-09T16:17:08+00:00
packetizer: h264: add all sps/pps sets to extradata

- - - - -


3 changed files:

- modules/packetizer/h264.c
- modules/packetizer/h264_nal.c
- modules/packetizer/h264_nal.h


Changes:

=====================================
modules/packetizer/h264.c
=====================================
@@ -152,9 +152,8 @@ static block_t * PacketizeDrain( void *p_private );
 static block_t *ParseNALBlock( decoder_t *, bool *pb_ts_used, block_t * );
 
 static block_t *OutputPicture( decoder_t *p_dec );
-static void PutSPS( decoder_t *p_dec, block_t *p_frag );
-static void PutPPS( decoder_t *p_dec, block_t *p_frag );
-static void PutSPSEXT( decoder_t *p_dec, block_t *p_frag );
+static void ReleaseXPS( decoder_sys_t *p_sys );
+static bool PutXPS( decoder_t *p_dec, uint8_t i_nal_type, block_t *p_frag );
 static bool ParseSliceHeader( decoder_t *p_dec, const block_t *p_frag, h264_slice_t *p_slice );
 static bool ParseSeiCallback( const hxxx_sei_data_t *, void * );
 
@@ -164,38 +163,33 @@ static const uint8_t p_h264_startcode[3] = { 0x00, 0x00, 0x01 };
 /*****************************************************************************
  * Helpers
  *****************************************************************************/
-
-static void StoreSPS( decoder_sys_t *p_sys, uint8_t i_id,
-                      block_t *p_block, h264_sequence_parameter_set_t *p_sps )
-{
-    if( p_sys->sps[i_id].p_block )
-        block_Release( p_sys->sps[i_id].p_block );
-    if( p_sys->sps[i_id].p_sps )
-        h264_release_sps( p_sys->sps[i_id].p_sps );
-    if( p_sys->sps[i_id].p_sps == p_sys->p_active_sps )
-        p_sys->p_active_sps = NULL;
-    p_sys->sps[i_id].p_block = p_block;
-    p_sys->sps[i_id].p_sps = p_sps;
-}
-
-static void StorePPS( decoder_sys_t *p_sys, uint8_t i_id,
-                      block_t *p_block, h264_picture_parameter_set_t *p_pps )
+static void LastAppendXPSCopy( const block_t *p_block, block_t ***ppp_last )
 {
-    if( p_sys->pps[i_id].p_block )
-        block_Release( p_sys->pps[i_id].p_block );
-    if( p_sys->pps[i_id].p_pps )
-        h264_release_pps( p_sys->pps[i_id].p_pps );
-    if( p_sys->pps[i_id].p_pps == p_sys->p_active_pps )
-        p_sys->p_active_pps = NULL;
-    p_sys->pps[i_id].p_block = p_block;
-    p_sys->pps[i_id].p_pps = p_pps;
+    if( !p_block )
+        return;
+    block_t *p_dup = block_Alloc( 4 + p_block->i_buffer );
+    if( p_dup )
+    {
+        memcpy( &p_dup->p_buffer[0], annexb_startcode4, 4 );
+        memcpy( &p_dup->p_buffer[4], p_block->p_buffer, p_block->i_buffer );
+        block_ChainLastAppend( ppp_last, p_dup );
+    }
 }
 
-static void StoreSPSEXT( decoder_sys_t *p_sys, uint8_t i_id, block_t *p_block )
+static block_t * GatherSets( decoder_sys_t *p_sys, bool b_need_sps, bool b_need_pps )
 {
-    if( p_sys->spsext[i_id].p_block )
-        block_Release( p_sys->spsext[i_id].p_block );
-    p_sys->spsext[i_id].p_block = p_block;
+    block_t *p_xpsnal = NULL;
+    block_t **pp_xpsnal_tail = &p_xpsnal;
+    for( int i = 0; i <= H264_SPS_ID_MAX && b_need_sps; i++ )
+    {
+        LastAppendXPSCopy( p_sys->sps[i].p_block, &pp_xpsnal_tail );
+        /* 7.4.1.2.3,  shall be the next NAL unit after a sequence parameter set NAL unit
+         * having the same value of seq_parameter_set_id */
+        LastAppendXPSCopy( p_sys->spsext[i].p_block, &pp_xpsnal_tail );
+    }
+    for( int i = 0; i < H264_PPS_ID_MAX && b_need_pps; i++ )
+        LastAppendXPSCopy( p_sys->pps[i].p_block, &pp_xpsnal_tail );
+    return p_xpsnal;
 }
 
 static void ActivateSets( decoder_t *p_dec, const h264_sequence_parameter_set_t *p_sps,
@@ -250,29 +244,18 @@ static void ActivateSets( decoder_t *p_dec, const h264_sequence_parameter_set_t
 
         if( p_dec->fmt_out.i_extra == 0 && p_pps )
         {
-            const block_t *p_spsblock = p_sys->sps[p_sps->i_id].p_block;
-            const block_t *p_ppsblock = p_sys->pps[p_pps->i_id].p_block;
-            const block_t *p_spsextblock = p_sys->spsext[p_sps->i_id].p_block;
-
-            if( p_spsblock && p_ppsblock )
+            block_t *p_xpsblocks = GatherSets( p_sys, true, true );
+            if( p_xpsblocks )
             {
-                size_t i_alloc = p_ppsblock->i_buffer + p_spsblock->i_buffer;
-                if( p_spsextblock )
-                    i_alloc += p_spsextblock->i_buffer;
-                p_dec->fmt_out.p_extra = malloc( i_alloc );
+                size_t i_total;
+                block_ChainProperties( p_xpsblocks, NULL, &i_total, NULL );
+                p_dec->fmt_out.p_extra = malloc( i_total );
                 if( p_dec->fmt_out.p_extra )
                 {
-                    uint8_t*p_buf = p_dec->fmt_out.p_extra;
-                    p_dec->fmt_out.i_extra = i_alloc;
-                    memcpy( p_buf, p_spsblock->p_buffer, p_spsblock->i_buffer );
-                    p_buf += p_spsblock->i_buffer;
-                    if( p_spsextblock )
-                    {
-                        memcpy( p_buf, p_spsextblock->p_buffer, p_spsextblock->i_buffer );
-                        p_buf += p_spsextblock->i_buffer;
-                    }
-                    memcpy( p_buf, p_ppsblock->p_buffer, p_ppsblock->i_buffer );
+                    p_dec->fmt_out.i_extra = i_total;
+                    block_ChainExtract( p_xpsblocks, p_dec->fmt_out.p_extra, i_total );
                 }
+                block_ChainRelease( p_xpsblocks );
             }
         }
     }
@@ -485,15 +468,9 @@ static void Close( vlc_object_t *p_this )
 {
     decoder_t *p_dec = (decoder_t*)p_this;
     decoder_sys_t *p_sys = p_dec->p_sys;
-    int i;
 
     DropStoredNAL( p_sys );
-    for( i = 0; i <= H264_SPS_ID_MAX; i++ )
-        StoreSPS( p_sys, i, NULL, NULL );
-    for( i = 0; i <= H264_PPS_ID_MAX; i++ )
-        StorePPS( p_sys, i, NULL, NULL );
-    for( i = 0; i <= H264_SPSEXT_ID_MAX; i++ )
-        StoreSPSEXT( p_sys, i, NULL );
+    ReleaseXPS( p_sys );
 
     packetizer_Clean( &p_sys->packetizer );
 
@@ -714,15 +691,9 @@ static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_ts_used, block_t *p_fr
 
             /* Stored for insert on keyframes */
             if( i_nal_type == H264_NAL_SPS )
-            {
-                PutSPS( p_dec, p_frag );
-                p_sys->b_new_sps = true;
-            }
+                p_sys->b_new_sps |= PutXPS( p_dec, i_nal_type, p_frag );
             else
-            {
-                PutPPS( p_dec, p_frag );
-                p_sys->b_new_pps = true;
-            }
+                p_sys->b_new_pps |= PutXPS( p_dec, i_nal_type, p_frag );
         break;
 
         case H264_NAL_SEI:
@@ -734,7 +705,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_ts_used, block_t *p_fr
         break;
 
         case H264_NAL_SPS_EXT:
-            PutSPSEXT( p_dec, p_frag );
+            PutXPS( p_dec, i_nal_type, p_frag );
             if( p_sys->b_slice )
                 p_pic = OutputPicture( p_dec );
             break;
@@ -875,25 +846,8 @@ static block_t *OutputPicture( decoder_t *p_dec )
     }
 
     /* Gather PPS/SPS if required */
-    block_t *p_xpsnal = NULL;
-    block_t **pp_xpsnal_tail = &p_xpsnal;
-    if( b_need_sps_pps || p_sys->b_new_sps || p_sys->b_new_pps )
-    {
-        for( int i = 0; i <= H264_SPS_ID_MAX && (b_need_sps_pps || p_sys->b_new_sps); i++ )
-        {
-            if( p_sys->sps[i].p_block )
-                block_ChainLastAppend( &pp_xpsnal_tail, block_Duplicate( p_sys->sps[i].p_block ) );
-            /* 7.4.1.2.3,  shall be the next NAL unit after a sequence parameter set NAL unit
-             * having the same value of seq_parameter_set_id */
-            if( p_sys->spsext[i].p_block )
-                block_ChainLastAppend( &pp_xpsnal_tail, block_Duplicate( p_sys->spsext[i].p_block ) );
-        }
-        for( int i = 0; i < H264_PPS_ID_MAX && (b_need_sps_pps || p_sys->b_new_pps); i++ )
-        {
-            if( p_sys->pps[i].p_block )
-                block_ChainLastAppend( &pp_xpsnal_tail, block_Duplicate( p_sys->pps[i].p_block ) );
-        }
-    }
+    block_t *p_xpsnal = GatherSets( p_sys, b_need_sps_pps|p_sys->b_new_sps,
+                                           b_need_sps_pps|p_sys->b_new_pps );
 
     /* Now rebuild NAL Sequence, inserting PPS/SPS if any */
     if( p_sys->leading.p_head &&
@@ -1089,90 +1043,130 @@ static block_t *OutputPicture( decoder_t *p_dec )
     return p_pic;
 }
 
-static void PutSPS( decoder_t *p_dec, block_t *p_frag )
+static int CmpXPS( const block_t *p_ref, const block_t *p_nal )
 {
-    decoder_sys_t *p_sys = p_dec->p_sys;
+    return p_ref == NULL ||
+           p_ref->i_buffer != p_nal->i_buffer ||
+           memcmp( p_ref->p_buffer, p_nal->p_buffer, p_nal->i_buffer );
+}
+
+#define wrap_h264_xps_decode(funcname ) \
+    static void *funcname ## _wrapper ( const uint8_t *a, size_t b, bool c ) \
+    { return funcname(a,b,c); }
 
-    const uint8_t *p_buffer = p_frag->p_buffer;
-    size_t i_buffer = p_frag->i_buffer;
+wrap_h264_xps_decode(h264_decode_sps)
+wrap_h264_xps_decode(h264_decode_pps)
 
-    if( !hxxx_strip_AnnexB_startcode( &p_buffer, &i_buffer ) )
+#define wrap_h264_xps_release(funcname, typecast) \
+    static void funcname ## _wrapper ( void *a ) { funcname((typecast *)a); }
+
+wrap_h264_xps_release(h264_release_sps, h264_sequence_parameter_set_t)
+wrap_h264_xps_release(h264_release_pps, h264_picture_parameter_set_t)
+
+static void ReleaseXPS( decoder_sys_t *p_sys )
+{
+    for( int i = 0; i <= H264_SPS_ID_MAX; i++ )
     {
-        block_Release( p_frag );
-        return;
+        if( !p_sys->sps[i].p_block )
+            continue;
+        block_Release( p_sys->sps[i].p_block );
+        h264_release_sps( p_sys->sps[i].p_sps );
     }
-
-    h264_sequence_parameter_set_t *p_sps = h264_decode_sps( p_buffer, i_buffer, true );
-    if( !p_sps )
+    for( int i = 0; i <= H264_PPS_ID_MAX; i++ )
     {
-        msg_Warn( p_dec, "invalid SPS" );
-        block_Release( p_frag );
-        return;
+        if( !p_sys->pps[i].p_block )
+            continue;
+        block_Release( p_sys->pps[i].p_block );
+        h264_release_pps( p_sys->pps[i].p_pps );
     }
-
-    /* We have a new SPS */
-    if( !p_sys->sps[p_sps->i_id].p_sps )
-        msg_Dbg( p_dec, "found NAL_SPS (sps_id=%d)", p_sps->i_id );
-
-    StoreSPS( p_sys, p_sps->i_id, p_frag, p_sps );
+    for( int i = 0; i <= H264_SPSEXT_ID_MAX; i++ )
+    {
+        if( p_sys->spsext[i].p_block )
+            block_Release( p_sys->spsext[i].p_block );
+    }
+    p_sys->p_active_sps = NULL;
+    p_sys->p_active_pps = NULL;
 }
 
-static void PutPPS( decoder_t *p_dec, block_t *p_frag )
+static bool PutXPS( decoder_t *p_dec, uint8_t i_nal_type, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
-    const uint8_t *p_buffer = p_frag->p_buffer;
-    size_t i_buffer = p_frag->i_buffer;
 
-    if( !hxxx_strip_AnnexB_startcode( &p_buffer, &i_buffer ) )
+    uint8_t i_id;
+    if( !hxxx_strip_AnnexB_startcode( (const uint8_t **)&p_frag->p_buffer,
+                                      &p_frag->i_buffer ) ||
+        !h264_get_xps_id( p_frag->p_buffer, p_frag->i_buffer, &i_id ) )
     {
         block_Release( p_frag );
-        return;
+        return false;
     }
 
-    h264_picture_parameter_set_t *p_pps = h264_decode_pps( p_buffer, i_buffer, true );
-    if( !p_pps )
+    const char * rgsz_types[3] = {"SPS", "PPS", "SPSEXT"};
+    const char *psz_type;
+    block_t **pp_block_dst;
+    /* all depend on pp_xps_dst */
+    void **pp_xps_dst = NULL;
+    const void **pp_active; /* optional */
+    void * (* pf_decode_xps)(const uint8_t *, size_t, bool);
+    void   (* pf_release_xps)(void *);
+
+    switch( i_nal_type )
     {
-        msg_Warn( p_dec, "invalid PPS" );
-        block_Release( p_frag );
-        return;
+        case H264_NAL_SPS:
+            psz_type = rgsz_types[0];
+            pp_active = (const void **) &p_sys->p_active_sps;
+            pp_block_dst = &p_sys->sps[i_id].p_block;
+            pp_xps_dst = (void **) &p_sys->sps[i_id].p_sps;
+            pf_decode_xps = h264_decode_sps_wrapper;
+            pf_release_xps = h264_release_sps_wrapper;
+            break;
+        case H264_NAL_PPS:
+            psz_type = rgsz_types[1];
+            pp_active = (const void **) &p_sys->p_active_pps;
+            pp_block_dst = &p_sys->pps[i_id].p_block;
+            pp_xps_dst = (void **) &p_sys->pps[i_id].p_pps;
+            pf_decode_xps = h264_decode_pps_wrapper;
+            pf_release_xps = h264_release_pps_wrapper;
+            break;
+        case H264_NAL_SPS_EXT:
+            psz_type = rgsz_types[2];
+            pp_block_dst = &p_sys->spsext[i_id].p_block;
+            break;
+        default:
+            block_Release( p_frag );
+            return false;
     }
 
-    /* We have a new PPS */
-    if( !p_sys->pps[p_pps->i_id].p_pps )
-        msg_Dbg( p_dec, "found NAL_PPS (pps_id=%d sps_id=%d)", p_pps->i_id, p_pps->i_sps_id );
-
-    StorePPS( p_sys, p_pps->i_id, p_frag, p_pps );
-}
-
-static void PutSPSEXT( decoder_t *p_dec, block_t *p_frag )
-{
-    decoder_sys_t *p_sys = p_dec->p_sys;
-    const uint8_t *p_buffer = p_frag->p_buffer;
-    size_t i_buffer = p_frag->i_buffer;
-
-    if( !hxxx_strip_AnnexB_startcode( &p_buffer, &i_buffer ) )
+    if( !CmpXPS( *pp_block_dst, p_frag ) )
     {
         block_Release( p_frag );
-        return;
+        return false;
     }
 
-    h264_sequence_parameter_set_extension_t *p_spsext =
-            h264_decode_sps_extension( p_buffer, i_buffer, true );
-    if( !p_spsext )
+    msg_Dbg( p_dec, "found NAL_%s (id=%" PRIu8 ")", psz_type, i_id );
+
+    if( pp_xps_dst != NULL )
     {
-        msg_Warn( p_dec, "invalid SPSEXT" );
-        block_Release( p_frag );
-        return;
+        void *p_xps = pf_decode_xps( p_frag->p_buffer, p_frag->i_buffer, true );
+        if( !p_xps )
+        {
+            block_Release( p_frag );
+            return false;
+        }
+        if( *pp_xps_dst )
+        {
+            if( pp_active && *pp_active == *pp_xps_dst )
+                *pp_active = NULL;
+            pf_release_xps( *pp_xps_dst );
+        }
+        *pp_xps_dst = p_xps;
     }
 
-    /* We have a new SPSEXT */
-    if( !p_sys->spsext[p_spsext->i_sps_id].p_block )
-        msg_Dbg( p_dec, "found NAL_SPSEXT (sps_id=%d)", p_spsext->i_sps_id );
+    if( *pp_block_dst )
+        block_Release( *pp_block_dst );
+    *pp_block_dst = p_frag;
 
-    StoreSPSEXT( p_sys, p_spsext->i_sps_id, p_frag );
-
-    /* we don't need a decoded one */
-    h264_release_sps_extension( p_spsext );
+    return true;
 }
 
 static void GetSPSPPS( uint8_t i_pps_id, void *priv,


=====================================
modules/packetizer/h264_nal.c
=====================================
@@ -740,6 +740,41 @@ block_t *h264_NAL_to_avcC( uint8_t i_nal_length_size,
     return bo.b;
 }
 
+bool h264_get_xps_id( const uint8_t *p_buf, size_t i_buf, uint8_t *pi_id )
+{
+    if( i_buf < 2 )
+        return false;
+
+    /* No need to lookup convert from emulation for that data */
+    uint8_t i_max, i_offset;
+    switch( h264_getNALType(p_buf) )
+    {
+        case H264_NAL_SPS:
+            i_offset = 1 + 3 /* profile constraint level */;
+            i_max = H264_SPS_ID_MAX;
+            break;
+        case H264_NAL_PPS:
+            i_offset = 1;
+            i_max = H264_PPS_ID_MAX;
+            break;
+        case H264_NAL_SPS_EXT:
+            i_offset = 1;
+            i_max = H264_SPSEXT_ID_MAX;
+            break;
+        default:
+            return false;
+    }
+
+    if( i_buf <= i_offset )
+        return false;
+
+    bs_t bs;
+    bs_init( &bs, &p_buf[i_offset], i_buf - i_offset );
+    *pi_id = bs_read_ue( &bs );
+
+    return !bs_error( &bs ) && *pi_id <= i_max;
+}
+
 static const h264_level_limits_t * h264_get_level_limits( const h264_sequence_parameter_set_t *p_sps )
 {
     uint16_t i_level_number = p_sps->i_level;


=====================================
modules/packetizer/h264_nal.h
=====================================
@@ -89,6 +89,8 @@ typedef struct h264_sequence_parameter_set_t h264_sequence_parameter_set_t;
 typedef struct h264_picture_parameter_set_t h264_picture_parameter_set_t;
 typedef struct h264_sequence_parameter_set_extension_t h264_sequence_parameter_set_extension_t;
 
+bool h264_get_xps_id(const uint8_t *p_nalbuf, size_t i_nalbuf, uint8_t *pi_id);
+
 h264_sequence_parameter_set_t * h264_decode_sps( const uint8_t *, size_t, bool );
 h264_picture_parameter_set_t *  h264_decode_pps( const uint8_t *, size_t, bool );
 h264_sequence_parameter_set_extension_t * h264_decode_sps_extension( const uint8_t *, size_t, bool );



View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/120ce6a393099f95e414785bf45b12cd84d67742...ed97dd9fb80a2d02de8c3b756aaeb263f8b807bb

-- 
View it on GitLab: https://code.videolan.org/videolan/vlc/-/compare/120ce6a393099f95e414785bf45b12cd84d67742...ed97dd9fb80a2d02de8c3b756aaeb263f8b807bb
You're receiving this email because of your account on code.videolan.org.


VideoLAN code repository instance


More information about the vlc-commits mailing list