X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fpacketizer%2Fh264.c;h=1042f36c11a7350e6ba1ef4d0d3b1ae939446972;hb=33778d4d8c5d4b53793bdfe699315dac4e5baf68;hp=43872e7305d5549fe8a67c29aa66c4ffd9b257e4;hpb=26ae73ad5db4cac8e465a651ee0b8afea5a5dd0b;p=vlc diff --git a/modules/packetizer/h264.c b/modules/packetizer/h264.c index 43872e7305..1042f36c11 100644 --- a/modules/packetizer/h264.c +++ b/modules/packetizer/h264.c @@ -93,12 +93,15 @@ struct decoder_sys_t /* */ bool b_slice; block_t *p_frame; + bool b_frame_sps; + bool b_frame_pps; bool b_header; bool b_sps; bool b_pps; block_t *pp_sps[SPS_MAX]; block_t *pp_pps[PPS_MAX]; + int i_recovery_frames; /* -1 = no recovery */ /* avcC data */ int i_avcC_length_size; @@ -200,11 +203,14 @@ static int Open( vlc_object_t *p_this ) packetizer_Init( &p_sys->packetizer, p_h264_startcode, sizeof(p_h264_startcode), - p_h264_startcode, 1, + p_h264_startcode, 1, 5, PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); p_sys->b_slice = false; p_sys->p_frame = NULL; + p_sys->b_frame_sps = false; + p_sys->b_frame_pps = false; + p_sys->b_header= false; p_sys->b_sps = false; p_sys->b_pps = false; @@ -212,6 +218,7 @@ static int Open( vlc_object_t *p_this ) p_sys->pp_sps[i] = NULL; for( i = 0; i < PPS_MAX; i++ ) p_sys->pp_pps[i] = NULL; + p_sys->i_recovery_frames = -1; p_sys->slice.i_nal_type = -1; p_sys->slice.i_nal_ref_idc = -1; @@ -502,6 +509,8 @@ static void PacketizeReset( void *p_private, bool b_broken ) if( p_sys->p_frame ) block_ChainRelease( p_sys->p_frame ); p_sys->p_frame = NULL; + p_sys->b_frame_sps = false; + p_sys->b_frame_pps = false; p_sys->slice.i_frame_type = 0; p_sys->b_slice = false; } @@ -513,7 +522,7 @@ static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_bl decoder_t *p_dec = p_private; /* Remove trailing 0 bytes */ - while( p_block->i_buffer && p_block->p_buffer[p_block->i_buffer-1] == 0x00 ) + while( p_block->i_buffer > 5 && p_block->p_buffer[p_block->i_buffer-1] == 0x00 ) p_block->i_buffer--; return ParseNALBlock( p_dec, pb_ts_used, p_block ); @@ -612,6 +621,8 @@ static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_used_ts, block_t *p_fr /* Reset context */ p_sys->slice.i_frame_type = 0; p_sys->p_frame = NULL; + p_sys->b_frame_sps = false; + p_sys->b_frame_pps = false; p_sys->b_slice = false; cc_Flush( &p_sys->cc_next ); } @@ -641,6 +652,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_used_ts, block_t *p_fr { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); + p_sys->b_frame_sps = true; PutSPS( p_dec, p_frag ); @@ -651,6 +663,7 @@ static block_t *ParseNALBlock( decoder_t *p_dec, bool *pb_used_ts, block_t *p_fr { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); + p_sys->b_frame_pps = true; PutPPS( p_dec, p_frag ); @@ -703,10 +716,24 @@ static block_t *OutputPicture( decoder_t *p_dec ) decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic; - if( !p_sys->b_header && p_sys->slice.i_frame_type != BLOCK_FLAG_TYPE_I) + if ( !p_sys->b_header && p_sys->i_recovery_frames != -1 ) + { + if( p_sys->i_recovery_frames == 0 ) + { + msg_Dbg( p_dec, "Recovery from SEI recovery point complete" ); + p_sys->b_header = true; + } + --p_sys->i_recovery_frames; + } + + if( !p_sys->b_header && p_sys->i_recovery_frames == -1 && + 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->b_sps && p_sys->b_pps ) + const bool b_sps_pps_i = p_sys->slice.i_frame_type == BLOCK_FLAG_TYPE_I && + p_sys->b_sps && + p_sys->b_pps; + if( b_sps_pps_i || p_sys->b_frame_sps || p_sys->b_frame_pps ) { block_t *p_head = NULL; if( p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD ) @@ -716,17 +743,17 @@ static block_t *OutputPicture( decoder_t *p_dec ) } block_t *p_list = NULL; - for( int i = 0; i < SPS_MAX; i++ ) + for( int i = 0; i < SPS_MAX && (b_sps_pps_i || p_sys->b_frame_sps); i++ ) { if( p_sys->pp_sps[i] ) block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_sps[i] ) ); } - for( int i = 0; i < PPS_MAX; i++ ) + for( int i = 0; i < PPS_MAX && (b_sps_pps_i || p_sys->b_frame_pps); i++ ) { if( p_sys->pp_pps[i] ) block_ChainAppend( &p_list, block_Duplicate( p_sys->pp_pps[i] ) ); } - if( p_list ) + if( b_sps_pps_i && p_list ) p_sys->b_header = true; if( p_head ) @@ -746,11 +773,15 @@ static block_t *OutputPicture( decoder_t *p_dec ) p_pic->i_length = 0; /* FIXME */ p_pic->i_flags |= p_sys->slice.i_frame_type; p_pic->i_flags &= ~BLOCK_FLAG_PRIVATE_AUD; + if( !p_sys->b_header ) + p_pic->i_flags |= BLOCK_FLAG_PREROLL; p_sys->slice.i_frame_type = 0; p_sys->p_frame = NULL; p_sys->i_frame_dts = VLC_TS_INVALID; p_sys->i_frame_pts = VLC_TS_INVALID; + p_sys->b_frame_sps = false; + p_sys->b_frame_pps = false; p_sys->b_slice = false; /* CC */ @@ -805,7 +836,7 @@ static void PutSPS( decoder_t *p_dec, block_t *p_frag ) /* chroma_format_idc */ const int i_chroma_format_idc = bs_read_ue( &s ); if( i_chroma_format_idc == 3 ) - bs_skip( &s, 1 ); /* seperate_colour_plane_flag */ + bs_skip( &s, 1 ); /* separate_colour_plane_flag */ /* bit_depth_luma_minus8 */ bs_read_ue( &s ); /* bit_depth_chroma_minus8 */ @@ -1160,6 +1191,27 @@ static void ParseSei( decoder_t *p_dec, block_t *p_frag ) cc_Extract( &p_sys->cc_next, true, &p_t35[3], i_t35 - 3 ); } } + + /* Look for SEI recovery point */ + if( i_type == 6 ) + { + bs_t s; + const int i_rec = i_size; + const uint8_t *p_rec = &pb_dec[i_used]; + + bs_init( &s, p_rec, i_rec ); + int i_recovery_frames = bs_read_ue( &s ); + //bool b_exact_match = bs_read( &s, 1 ); + //bool b_broken_link = bs_read( &s, 1 ); + //int i_changing_slice_group = bs_read( &s, 2 ); + if( !p_sys->b_header ) + { + msg_Dbg( p_dec, "Seen SEI recovery point, %d recovery frames", i_recovery_frames ); + if ( p_sys->i_recovery_frames == -1 || i_recovery_frames < p_sys->i_recovery_frames ) + p_sys->i_recovery_frames = i_recovery_frames; + } + } + i_used += i_size; }