]> git.sesse.net Git - vlc/blobdiff - modules/packetizer/h264.c
playlist: Make sure we don't pl_Release(p_playlist).
[vlc] / modules / packetizer / h264.c
index a2db1e2954d6abf749cdb859ff178d2b5637daa5..78e354bff9add343eb739aa713dc667d90e1e0a1 100644 (file)
@@ -83,6 +83,8 @@ typedef struct
     int i_delta_pic_order_cnt1;
 } slice_t;
 
+#define SPS_MAX (32)
+#define PPS_MAX (256)
 struct decoder_sys_t
 {
     block_bytestream_t bytestream;
@@ -91,17 +93,17 @@ struct decoder_sys_t
     size_t  i_offset;
     uint8_t startcode[4];
 
-    bool b_slice;
-    block_t    *p_frame;
+    bool    b_slice;
+    block_t *p_frame;
 
+    bool   b_header;
     bool   b_sps;
     bool   b_pps;
-    bool   b_header;
+    block_t *pp_sps[SPS_MAX];
+    block_t *pp_pps[PPS_MAX];
 
     /* avcC data */
     int i_avcC_length_size;
-    block_t *p_sps;
-    block_t *p_pps;
 
     /* Useful values of the Sequence Parameter Set */
     int i_log2_max_frame_num;
@@ -115,6 +117,10 @@ struct decoder_sys_t
 
     /* Useful values of the Slice Header */
     slice_t slice;
+
+    /* */
+    mtime_t i_frame_pts;
+    mtime_t i_frame_dts;
 };
 
 enum
@@ -146,7 +152,7 @@ enum nal_priority_e
     NAL_PRIORITY_HIGHEST    = 3,
 };
 
-static block_t *ParseNALBlock( decoder_t *, block_t * );
+static block_t *ParseNALBlock( decoder_t *, bool *pb_used_ts, block_t * );
 
 static block_t *CreateAnnexbNAL( decoder_t *, const uint8_t *p, int );
 
@@ -166,6 +172,7 @@ static int Open( vlc_object_t *p_this )
 {
     decoder_t     *p_dec = (decoder_t*)p_this;
     decoder_sys_t *p_sys;
+    int i;
 
     if( p_dec->fmt_in.i_codec != VLC_FOURCC( 'h', '2', '6', '4') &&
         p_dec->fmt_in.i_codec != VLC_FOURCC( 'H', '2', '6', '4') &&
@@ -192,11 +199,13 @@ static int Open( vlc_object_t *p_this )
     p_sys->bytestream = block_BytestreamInit();
     p_sys->b_slice = false;
     p_sys->p_frame = NULL;
+    p_sys->b_header= false;
     p_sys->b_sps   = false;
     p_sys->b_pps   = false;
-    p_sys->p_sps   = 0;
-    p_sys->p_pps   = 0;
-    p_sys->b_header= false;
+    for( i = 0; i < SPS_MAX; i++ )
+        p_sys->pp_sps[i] = NULL;
+    for( i = 0; i < PPS_MAX; i++ )
+        p_sys->pp_pps[i] = NULL;
 
     p_sys->slice.i_nal_type = -1;
     p_sys->slice.i_nal_ref_idc = -1;
@@ -209,6 +218,9 @@ static int Open( vlc_object_t *p_this )
     p_sys->slice.i_pic_order_cnt_lsb = -1;
     p_sys->slice.i_delta_pic_order_cnt_bottom = -1;
 
+    p_sys->i_frame_dts = -1;
+    p_sys->i_frame_pts = -1;
+
     /* Setup properties */
     es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in );
     p_dec->fmt_out.i_codec = VLC_FOURCC( 'h', '2', '6', '4' );
@@ -221,6 +233,7 @@ static int Open( vlc_object_t *p_this )
          * The fmt_out.p_extra should contain all the SPS and PPS with 4 byte startcodes */
         uint8_t *p = &((uint8_t*)p_dec->fmt_in.p_extra)[4];
         int i_sps, i_pps;
+        bool b_dummy;
         int i;
 
         /* Parse avcC */
@@ -239,7 +252,7 @@ static int Open( vlc_object_t *p_this )
             block_t *p_sps = CreateAnnexbNAL( p_dec, p, i_length );
             if( !p_sps )
                 return VLC_EGENERIC;
-            ParseNALBlock( p_dec, p_sps );
+            ParseNALBlock( p_dec, &b_dummy, p_sps );
             p += i_length;
         }
         /* Read PPS */
@@ -255,32 +268,59 @@ static int Open( vlc_object_t *p_this )
             block_t *p_pps = CreateAnnexbNAL( p_dec, p, i_length );
             if( !p_pps )
                 return VLC_EGENERIC;
-            ParseNALBlock( p_dec, p_pps );
+            ParseNALBlock( p_dec, &b_dummy, p_pps );
             p += i_length;
         }
         msg_Dbg( p_dec, "avcC length size=%d, sps=%d, pps=%d",
                  p_sys->i_avcC_length_size, i_sps, i_pps );
 
-        if( !p_sys->p_sps || p_sys->p_pps )
+        if( !p_sys->b_sps || !p_sys->b_pps )
             return VLC_EGENERIC;
 
         /* FIXME: FFMPEG isn't happy at all if you leave this */
-        if( p_dec->fmt_out.i_extra > 0 ) free( p_dec->fmt_out.p_extra );
+        if( p_dec->fmt_out.i_extra > 0 )
+            free( p_dec->fmt_out.p_extra );
         p_dec->fmt_out.i_extra = 0;
         p_dec->fmt_out.p_extra = NULL;
 
         /* Set the new extradata */
-        p_dec->fmt_out.i_extra = p_sys->p_pps->i_buffer + p_sys->p_sps->i_buffer;
+        for( i = 0; i < SPS_MAX; i++ )
+        {
+            if( p_sys->pp_sps[i] )
+                p_dec->fmt_out.i_extra += p_sys->pp_sps[i]->i_buffer;
+        }
+        for( i = 0; i < PPS_MAX; i++ )
+        {
+            if( p_sys->pp_pps[i] )
+                p_dec->fmt_out.i_extra += p_sys->pp_pps[i]->i_buffer;
+        }
         p_dec->fmt_out.p_extra = malloc( p_dec->fmt_out.i_extra );
         if( p_dec->fmt_out.p_extra )
         {
-            memcpy( (uint8_t*)p_dec->fmt_out.p_extra,
-                    p_sys->p_sps->p_buffer, p_sys->p_sps->i_buffer);
-            memcpy( (uint8_t*)p_dec->fmt_out.p_extra+p_sys->p_sps->i_buffer,
-                    p_sys->p_pps->p_buffer, p_sys->p_pps->i_buffer);
+            uint8_t *p_dst = p_dec->fmt_out.p_extra;
+
+            for( i = 0; i < SPS_MAX; i++ )
+            {
+                if( p_sys->pp_sps[i] )
+                {
+                    memcpy( p_dst, p_sys->pp_sps[i]->p_buffer, p_sys->pp_sps[i]->i_buffer );
+                    p_dst += p_sys->pp_sps[i]->i_buffer;
+                }
+            }
+            for( i = 0; i < PPS_MAX; i++ )
+            {
+                if( p_sys->pp_pps[i] )
+                {
+                    memcpy( p_dst, p_sys->pp_pps[i]->p_buffer, p_sys->pp_pps[i]->i_buffer );
+                    p_dst += p_sys->pp_pps[i]->i_buffer;
+                }
+            }
             p_sys->b_header = true;
         }
-        else p_dec->fmt_out.i_extra = 0;
+        else
+        {
+            p_dec->fmt_out.i_extra = 0;
+        }
 
         /* Set callback */
         p_dec->pf_packetize = PacketizeAVC1;
@@ -321,10 +361,19 @@ 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;
 
     if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame );
-    if( p_sys->p_sps ) block_Release( p_sys->p_sps );
-    if( p_sys->p_pps ) block_Release( p_sys->p_pps );
+    for( i = 0; i < SPS_MAX; i++ )
+    {
+        if( p_sys->pp_sps[i] )
+            block_Release( p_sys->pp_sps[i] );
+    }
+    for( i = 0; i < PPS_MAX; i++ )
+    {
+        if( p_sys->pp_pps[i] )
+            block_Release( p_sys->pp_pps[i] );
+    }
     block_BytestreamRelease( &p_sys->bytestream );
     free( p_sys );
 }
@@ -363,6 +412,8 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
 
     for( ;; )
     {
+        bool b_used_ts;
+
         switch( p_sys->i_state )
         {
             case STATE_NOSYNC:
@@ -397,11 +448,15 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
                     /* Need more data */
                     return NULL;
                 }
+                block_BytestreamFlush( &p_sys->bytestream );
 
                 /* Get the new fragment and set the pts/dts */
+                block_t *p_block_bytestream = p_sys->bytestream.p_block;
+
                 p_pic = block_New( p_dec, p_sys->i_offset +1 );
-                p_pic->i_pts = p_sys->bytestream.p_block->i_pts;
-                p_pic->i_dts = p_sys->bytestream.p_block->i_dts;
+                p_pic->i_pts = p_block_bytestream->i_pts;
+                p_pic->i_dts = p_block_bytestream->i_dts;
+
                 /* Force 4 byte startcode 0 0 0 1 */
                 p_pic->p_buffer[0] = 0;
 
@@ -414,7 +469,14 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
                 p_sys->i_offset = 0;
 
                 /* Parse the NAL */
-                if( !( p_pic = ParseNALBlock( p_dec, p_pic ) ) )
+                p_pic = ParseNALBlock( p_dec, &b_used_ts, p_pic );
+                if( b_used_ts )
+                {
+                    p_block_bytestream->i_dts = -1;
+                    p_block_bytestream->i_pts = -1;
+                }
+
+                if( !p_pic )
                 {
                     p_sys->i_state = STATE_NOSYNC;
                     break;
@@ -460,6 +522,7 @@ static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block )
     for( p = p_block->p_buffer; p < &p_block->p_buffer[p_block->i_buffer]; )
     {
         block_t *p_pic;
+        bool b_dummy;
         int i_size = 0;
         int i;
 
@@ -478,11 +541,12 @@ static block_t *PacketizeAVC1( decoder_t *p_dec, block_t **pp_block )
         block_t *p_part = CreateAnnexbNAL( p_dec, p, i_size );
         if( !p_part )
             break;
+
         p_part->i_dts = p_block->i_dts;
         p_part->i_pts = p_block->i_pts;
 
         /* Parse the NAL */
-        if( ( p_pic = ParseNALBlock( p_dec, p_part ) ) )
+        if( ( p_pic = ParseNALBlock( p_dec, &b_dummy, p_part ) ) )
         {
             block_ChainAppend( &p_ret, p_pic );
         }
@@ -565,13 +629,15 @@ static inline int bs_read_se( bs_t *s )
  * ParseNALBlock: parses annexB type NALs
  * All p_frag blocks are required to start with 0 0 0 1 4-byte startcode
  *****************************************************************************/
-static block_t *ParseNALBlock( decoder_t *p_dec, block_t *p_frag )
+static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     block_t *p_pic = NULL;
 
     const int i_nal_ref_idc = (p_frag->p_buffer[4] >> 5)&0x03;
     const int i_nal_type = p_frag->p_buffer[4]&0x1f;
+    const mtime_t i_frag_dts = p_frag->i_dts;
+    const mtime_t i_frag_pts = p_frag->i_pts;
 
     if( p_sys->b_slice && ( !p_sys->b_sps || !p_sys->b_pps ) )
     {
@@ -593,7 +659,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, block_t *p_frag )
     else if( i_nal_type >= NAL_SLICE && i_nal_type <= NAL_SLICE_IDR )
     {
         slice_t slice;
-        bool b_new_picture;
+        bool  b_new_picture;
 
         ParseSlice( p_dec, &b_new_picture, &slice, i_nal_ref_idc, i_nal_type, p_frag );
 
@@ -613,7 +679,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, block_t *p_frag )
         PutSPS( p_dec, p_frag );
 
         /* Do not append the SPS because we will insert it on keyframes */
-        return p_pic;
+        p_frag = NULL;
     }
     else if( i_nal_type == NAL_PPS )
     {
@@ -623,7 +689,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, block_t *p_frag )
         PutPPS( p_dec, p_frag );
 
         /* Do not append the PPS because we will insert it on keyframes */
-        return p_pic;
+        p_frag = NULL;
     }
     else if( i_nal_type == NAL_AU_DELIMITER ||
              i_nal_type == NAL_SEI ||
@@ -636,8 +702,16 @@ static block_t *ParseNALBlock( decoder_t *p_dec, block_t *p_frag )
     }
 
     /* Append the block */
-    block_ChainAppend( &p_sys->p_frame, p_frag );
+    if( p_frag )
+        block_ChainAppend( &p_sys->p_frame, p_frag );
 
+    *pb_used_ts = false;
+    if( p_sys->i_frame_dts < 0 && p_sys->i_frame_pts < 0 )
+    {
+        p_sys->i_frame_dts = i_frag_dts;
+        p_sys->i_frame_pts = i_frag_pts;
+        *pb_used_ts = true;
+    }
     return p_pic;
 }
 
@@ -649,26 +723,40 @@ static block_t *OutputPicture( decoder_t *p_dec )
     if( !p_sys->b_header && p_sys->slice.i_frame_type != BLOCK_FLAG_TYPE_I)
         return NULL;
 
-    if( p_sys->slice.i_frame_type == BLOCK_FLAG_TYPE_I && p_sys->p_sps && p_sys->p_pps )
+    if( p_sys->slice.i_frame_type == BLOCK_FLAG_TYPE_I && p_sys->b_sps && p_sys->b_pps )
     {
-        block_t *p_sps = block_Duplicate( p_sys->p_sps );
-        block_t *p_pps = block_Duplicate( p_sys->p_pps );
-        p_sps->i_dts = p_sys->p_frame->i_dts;
-        p_sps->i_pts = p_sys->p_frame->i_pts;
-        block_ChainAppend( &p_sps, p_pps );
-        block_ChainAppend( &p_sps, p_sys->p_frame );
-        p_sys->b_header = true;
-        p_pic = block_ChainGather( p_sps );
+        block_t *p_list = NULL;
+        int i;
+
+        for( i = 0; i < SPS_MAX; i++ )
+        {
+            if( p_sys->pp_sps[i] )
+                block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_sps[i] ) );
+        }
+        for( i = 0; i < PPS_MAX; i++ )
+        {
+            if( p_sys->pp_pps[i] )
+                block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_pps[i] ) );
+        }
+        if( p_list )
+            p_sys->b_header = true;
+
+        block_ChainAppend( &p_list, p_sys->p_frame );
+        p_pic = block_ChainGather( p_list );
     }
     else
     {
         p_pic = block_ChainGather( p_sys->p_frame );
     }
+    p_pic->i_dts = p_sys->i_frame_dts;
+    p_pic->i_pts = p_sys->i_frame_pts;
     p_pic->i_length = 0;    /* FIXME */
     p_pic->i_flags |= p_sys->slice.i_frame_type;
 
     p_sys->slice.i_frame_type = 0;
     p_sys->p_frame = NULL;
+    p_sys->i_frame_dts = -1;
+    p_sys->i_frame_pts = -1;
     p_sys->b_slice = false;
 
     return p_pic;
@@ -678,24 +766,28 @@ static void PutSPS( decoder_t *p_dec, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
 
-    uint8_t *dec = NULL;
+    uint8_t *pb_dec = NULL;
     int     i_dec = 0;
     bs_t s;
     int i_tmp;
+    int i_sps_id;
 
-    if( !p_sys->b_sps )
-        msg_Dbg( p_dec, "found NAL_SPS" );
-
-    p_sys->b_sps = true;
-
-    CreateDecodedNAL( &dec, &i_dec, &p_frag->p_buffer[5],
+    CreateDecodedNAL( &pb_dec, &i_dec, &p_frag->p_buffer[5],
                      p_frag->i_buffer - 5 );
 
-    bs_init( &s, dec, i_dec );
+    bs_init( &s, pb_dec, i_dec );
     /* Skip profile(8), constraint_set012, reserver(5), level(8) */
     bs_skip( &s, 8 + 1+1+1 + 5 + 8 );
     /* sps id */
-    bs_read_ue( &s );
+    i_sps_id = bs_read_ue( &s );
+    if( i_sps_id >= SPS_MAX )
+    {
+        msg_Warn( p_dec, "invalid SPS (sps_id=%d)", i_sps_id );
+        free( pb_dec );
+        block_Release( p_frag );
+        return;
+    }
+
     /* Skip i_log2_max_frame_num */
     p_sys->i_log2_max_frame_num = bs_read_ue( &s );
     if( p_sys->i_log2_max_frame_num > 12)
@@ -725,6 +817,7 @@ static void PutSPS( decoder_t *p_dec, block_t *p_frag )
         {
             /* skip i_offset_for_ref_frame */
             bs_read_se(&s );
+            i_cycle--;
         }
     }
     /* i_num_ref_frames */
@@ -794,43 +887,54 @@ static void PutSPS( decoder_t *p_dec, block_t *p_frag )
                 h = 0;
             }
             if( h != 0 )
-                p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * w /
-                    h * p_dec->fmt_out.video.i_width /
-                    p_dec->fmt_out.video.i_height;
+                p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR *
+                        ( w * p_dec->fmt_out.video.i_width ) /
+                        ( h * p_dec->fmt_out.video.i_height);
             else
                 p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR;
         }
     }
 
-    free( dec );
+    free( pb_dec );
 
     /* We have a new SPS */
-    if( p_sys->p_sps )
-        block_Release( p_sys->p_sps );
-    p_sys->p_sps = p_frag;
+    if( !p_sys->b_sps )
+        msg_Dbg( p_dec, "found NAL_SPS (sps_id=%d)", i_sps_id );
+    p_sys->b_sps = true;
+
+    if( p_sys->pp_sps[i_sps_id] )
+        block_Release( p_sys->pp_sps[i_sps_id] );
+    p_sys->pp_sps[i_sps_id] = p_frag;
 }
 
 static void PutPPS( decoder_t *p_dec, block_t *p_frag )
 {
     decoder_sys_t *p_sys = p_dec->p_sys;
     bs_t s;
+    int i_pps_id;
+    int i_sps_id;
 
     bs_init( &s, &p_frag->p_buffer[5], p_frag->i_buffer - 5 );
-    bs_read_ue( &s ); // pps id
-    bs_read_ue( &s ); // sps id
+    i_pps_id = bs_read_ue( &s ); // pps id
+    i_sps_id = bs_read_ue( &s ); // sps id
+    if( i_pps_id >= PPS_MAX || i_sps_id >= SPS_MAX )
+    {
+        msg_Warn( p_dec, "invalid PPS (pps_id=%d sps_id=%d)", i_pps_id, i_sps_id );
+        block_Release( p_frag );
+        return;
+    }
     bs_skip( &s, 1 ); // entropy coding mode flag
     p_sys->i_pic_order_present_flag = bs_read( &s, 1 );
+    /* TODO */
 
+    /* We have a new PPS */
     if( !p_sys->b_pps )
-        msg_Dbg( p_dec, "found NAL_PPS" );
+        msg_Dbg( p_dec, "found NAL_PPS (pps_id=%d sps_id=%d)", i_pps_id, i_sps_id );
     p_sys->b_pps = true;
 
-    /* TODO */
-
-    /* We have a new PPS */
-    if( p_sys->p_pps )
-        block_Release( p_sys->p_pps );
-    p_sys->p_pps = p_frag;
+    if( p_sys->pp_pps[i_pps_id] )
+        block_Release( p_sys->pp_pps[i_pps_id] );
+    p_sys->pp_pps[i_pps_id] = p_frag;
 }
 
 static void ParseSlice( decoder_t *p_dec, bool *pb_new_picture, slice_t *p_slice,