/***************************************************************************** * 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, bool *pb_ts_used, block_t *p_frag ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic = NULL; bool b_new_picture = false; 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 ) ) { block_ChainRelease( p_sys->p_frame ); msg_Warn( p_dec, "waiting for SPS/PPS" ); /* Reset context */ p_sys->slice.i_frame_type = 0; p_sys->p_frame = NULL; p_sys->pp_frame_last = &p_sys->p_frame; p_sys->b_frame_sps = false; p_sys->b_frame_pps = false; p_sys->b_slice = false; cc_storage_reset( p_sys->p_ccs ); } if( ( !p_sys->b_sps || !p_sys->b_pps ) && i_nal_type >= H264_NAL_SLICE && i_nal_type <= H264_NAL_SLICE_IDR ) { p_sys->b_slice = true; /* Fragment will be discarded later on */ } else if( i_nal_type >= H264_NAL_SLICE && i_nal_type <= H264_NAL_SLICE_IDR ) { slice_t slice; if(ParseSlice( p_dec, &b_new_picture, &slice, i_nal_ref_idc, i_nal_type, p_frag )) { /* */ if( b_new_picture && p_sys->b_slice ) p_pic = OutputPicture( p_dec ); /* */ p_sys->slice = slice; p_sys->b_slice = true; } } else if( i_nal_type == H264_NAL_SPS ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); p_sys->b_frame_sps = true; PutSPS( p_dec, p_frag ); /* Do not append the SPS because we will insert it on keyframes */ p_frag = NULL; } else if( i_nal_type == H264_NAL_PPS ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); p_sys->b_frame_pps = true; PutPPS( p_dec, p_frag ); /* Do not append the PPS because we will insert it on keyframes */ p_frag = NULL; } else if( i_nal_type == H264_NAL_AU_DELIMITER || i_nal_type == H264_NAL_SEI || ( i_nal_type >= H264_NAL_PREFIX && i_nal_type <= H264_NAL_RESERVED_18 ) ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); /* Parse SEI for CC support */ if( i_nal_type == H264_NAL_SEI ) { HxxxParse_AnnexB_SEI( p_frag->p_buffer, p_frag->i_buffer, 1 /* nal header */, ParseSeiCallback, p_dec ); } else if( i_nal_type == H264_NAL_AU_DELIMITER ) { if( p_sys->p_frame && (p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD) ) { block_Release( p_frag ); p_frag = NULL; } else { p_frag->i_flags |= BLOCK_FLAG_PRIVATE_AUD; } } } /* Append the block */ if( p_frag ) block_ChainLastAppend( &p_sys->pp_frame_last, p_frag ); *pb_ts_used = false; if( p_sys->i_frame_dts <= VLC_TS_INVALID && p_sys->i_frame_pts <= VLC_TS_INVALID && b_new_picture ) { p_sys->i_frame_dts = i_frag_dts; p_sys->i_frame_pts = i_frag_pts; *pb_ts_used = true; } return p_pic; }
static block_t *ParseVCL(decoder_t *p_dec, uint8_t i_nal_type, block_t *p_frag) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_outputchain = NULL; const uint8_t *p_buffer = p_frag->p_buffer; size_t i_buffer = p_frag->i_buffer; if(unlikely(!hxxx_strip_AnnexB_startcode(&p_buffer, &i_buffer) || i_buffer < 3)) { block_ChainLastAppend(&p_sys->frame.pp_chain_last, p_frag); /* might be corrupted */ return NULL; } const uint8_t i_layer = hevc_getNALLayer( p_buffer ); bool b_first_slice_in_pic = p_buffer[2] & 0x80; if (b_first_slice_in_pic) { if(p_sys->frame.p_chain) { /* Starting new frame: return previous frame data for output */ p_outputchain = OutputQueues(p_sys, p_sys->b_init_sequence_complete); } switch(i_nal_type) { case HEVC_NAL_BLA_W_LP: case HEVC_NAL_BLA_W_RADL: case HEVC_NAL_BLA_N_LP: case HEVC_NAL_IDR_W_RADL: case HEVC_NAL_IDR_N_LP: case HEVC_NAL_CRA: p_frag->i_flags |= BLOCK_FLAG_TYPE_I; break; default: { hevc_slice_segment_header_t *p_sli = hevc_decode_slice_header( p_buffer, i_buffer, true, p_sys->rgi_p_decsps, p_sys->rgi_p_decpps ); if( p_sli ) { enum hevc_slice_type_e type; if( hevc_get_slice_type( p_sli, &type ) ) { if( type == HEVC_SLICE_TYPE_P ) p_frag->i_flags |= BLOCK_FLAG_TYPE_P; else p_frag->i_flags |= BLOCK_FLAG_TYPE_B; } hevc_rbsp_release_slice_header( p_sli ); } else p_frag->i_flags |= BLOCK_FLAG_TYPE_B; } break; } } if(!p_sys->b_init_sequence_complete && i_layer == 0 && (p_frag->i_flags & BLOCK_FLAG_TYPE_I) && XPSReady(p_sys)) { p_sys->b_init_sequence_complete = true; } if( !p_sys->b_init_sequence_complete ) cc_storage_reset( p_sys->p_ccs ); block_ChainLastAppend(&p_sys->frame.pp_chain_last, p_frag); return p_outputchain; }
/***************************************************************************** * 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, bool *pb_ts_used, block_t *p_frag ) { decoder_sys_t *p_sys = p_dec->p_sys; block_t *p_pic = NULL; bool b_new_picture = false; 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->p_active_pps || !p_sys->p_active_sps) ) { msg_Warn( p_dec, "waiting for SPS/PPS" ); /* Reset context */ p_sys->slice.type = H264_SLICE_TYPE_UNKNOWN; p_sys->b_slice = false; DropStoredNAL( p_sys ); /* From SEI */ p_sys->i_dpb_output_delay = 0; p_sys->i_pic_struct = UINT8_MAX; cc_storage_reset( p_sys->p_ccs ); } if( i_nal_type >= H264_NAL_SLICE && i_nal_type <= H264_NAL_SLICE_IDR ) { h264_slice_t newslice; if( i_nal_type == H264_NAL_SLICE_IDR ) { p_sys->b_recovered = true; p_sys->i_recovery_frame_cnt = UINT_MAX; p_sys->i_recoveryfnum = UINT_MAX; } if( ParseSliceHeader( p_dec, p_frag, &newslice ) ) { /* Only IDR carries the id, to be propagated */ if( newslice.i_idr_pic_id == -1 ) newslice.i_idr_pic_id = p_sys->slice.i_idr_pic_id; b_new_picture = IsFirstVCLNALUnit( &p_sys->slice, &newslice ); if( b_new_picture ) { /* Parse SEI for that frame now we should have matched SPS/PPS */ for( block_t *p_sei = p_sys->p_sei; p_sei; p_sei = p_sei->p_next ) { HxxxParse_AnnexB_SEI( p_sei->p_buffer, p_sei->i_buffer, 1 /* nal header */, ParseSeiCallback, p_dec ); } if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); } /* */ p_sys->slice = newslice; } else { p_sys->p_active_pps = NULL; /* Fragment will be discarded later on */ } p_sys->b_slice = true; } else if( i_nal_type == H264_NAL_SPS ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); PutSPS( p_dec, p_frag ); p_sys->b_new_sps = true; /* Do not append the SPS because we will insert it on keyframes */ p_frag = NULL; } else if( i_nal_type == H264_NAL_PPS ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); PutPPS( p_dec, p_frag ); p_sys->b_new_pps = true; /* Do not append the PPS because we will insert it on keyframes */ p_frag = NULL; } else if( i_nal_type == H264_NAL_SEI ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); block_ChainLastAppend( &p_sys->pp_sei_last, p_frag ); p_frag = NULL; } else if( i_nal_type == H264_NAL_END_OF_SEQ || i_nal_type == H264_NAL_END_OF_STREAM ) { /* Early end of packetization */ block_ChainLastAppend( &p_sys->pp_sei_last, p_frag ); p_frag = NULL; /* important for still pictures/menus */ p_sys->i_next_block_flags |= BLOCK_FLAG_END_OF_SEQUENCE; if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); } else if( i_nal_type == H264_NAL_AU_DELIMITER || ( i_nal_type >= H264_NAL_PREFIX && i_nal_type <= H264_NAL_RESERVED_18 ) ) { if( p_sys->b_slice ) p_pic = OutputPicture( p_dec ); if( i_nal_type == H264_NAL_AU_DELIMITER ) { if( p_sys->p_frame && (p_sys->p_frame->i_flags & BLOCK_FLAG_PRIVATE_AUD) ) { block_Release( p_frag ); p_frag = NULL; } else { p_frag->i_flags |= BLOCK_FLAG_PRIVATE_AUD; } } } /* Append the block */ if( p_frag ) block_ChainLastAppend( &p_sys->pp_frame_last, p_frag ); *pb_ts_used = false; if( p_sys->i_frame_dts <= VLC_TS_INVALID && p_sys->i_frame_pts <= VLC_TS_INVALID && b_new_picture ) { p_sys->i_frame_dts = i_frag_dts; p_sys->i_frame_pts = i_frag_pts; *pb_ts_used = true; if( i_frag_dts > VLC_TS_INVALID ) date_Set( &p_sys->dts, i_frag_dts ); } if( p_pic && (p_pic->i_flags & BLOCK_FLAG_DROP) ) { block_Release( p_pic ); p_pic = NULL; } return p_pic; }