static int ProbeHEVC( const uint8_t *p_peek, size_t i_peek, void *p_priv ) { hevc_probe_ctx_t *p_ctx = (hevc_probe_ctx_t *) p_priv; if( i_peek < 2 ) return -1; if( p_peek[0] & 0x80 ) return -1; const uint8_t i_type = hevc_getNALType( p_peek ); const uint8_t i_layer = hevc_getNALLayer( p_peek ); if ( i_type == HEVC_NAL_VPS ) /* VPS */ { if( i_layer != 0 || i_peek < 6 || p_peek[4] != 0xFF || p_peek[5] != 0xFF ) /* Check reserved bits */ return -1; p_ctx->b_vps = true; return 0; } else if( i_type == HEVC_NAL_SPS ) /* SPS */ { if( i_layer != 0 ) return -1; p_ctx->b_sps = true; return 0; } else if( i_type == HEVC_NAL_PPS ) /* PPS */ { if( i_layer != 0 ) return -1; p_ctx->b_pps = true; return 0; } else if( i_type >= HEVC_NAL_BLA_W_LP && i_type <= HEVC_NAL_CRA ) /* Key Frame */ { if( p_ctx->b_vps && p_ctx->b_sps && p_ctx->b_pps && i_layer == 0 ) return 1; } else if( i_type == HEVC_NAL_AUD ) /* AU */ { if( i_peek < H26X_MIN_PEEK || p_peek[4] != 0 || p_peek[5] != 0 ) /* Must prefix another NAL */ return -1; } else if( i_type == HEVC_NAL_PREF_SEI ) /* Prefix SEI */ { if( p_peek[2] == 0xFF ) /* empty SEI */ return -1; } else { return -1; /* See 7.4.2.4.4 for sequence order */ } return 0; /* Probe more */ }
/***************************************************************************** * 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_ret = NULL; if(unlikely(p_frag->i_buffer < 5)) { msg_Warn(p_dec,"NAL too small"); block_Release(p_frag); return NULL; } if(p_frag->p_buffer[4] & 0x80) { msg_Warn(p_dec,"Forbidden zero bit not null, corrupted NAL"); block_ChainRelease(p_sys->p_frame); block_Release(p_frag); p_sys->p_frame = NULL; p_sys->pp_frame_last = &p_sys->p_frame; return NULL; } /* Get NALU type */ uint8_t i_nal_type = hevc_getNALType(&p_frag->p_buffer[4]); if (i_nal_type < HEVC_NAL_VPS) { /* NAL is a VCL NAL */ p_ret = ParseVCL(p_dec, i_nal_type, p_frag); } else { p_ret = ParseNonVCL(p_dec, i_nal_type, p_frag); if (p_sys->p_frame) { p_frag = p_ret; if( (p_ret = block_ChainGather(p_sys->p_frame)) ) { p_sys->p_frame = NULL; p_sys->pp_frame_last = &p_sys->p_frame; p_ret->p_next = p_frag; } else p_ret = p_frag; } } *pb_ts_used = false; return p_ret; }
/* Shortcut for retrieving vps/sps/pps id */ bool hevc_get_xps_id(const uint8_t *p_buf, size_t i_buf, uint8_t *pi_id) { if(unlikely(!hxxx_strip_AnnexB_startcode(&p_buf, &i_buf) || i_buf < 3)) return false; /* No need to lookup convert from emulation for that data */ uint8_t i_nal_type = hevc_getNALType(p_buf); bs_t bs; bs_init(&bs, &p_buf[2], i_buf - 2); if(i_nal_type == HEVC_NAL_PPS) *pi_id = bs_read_ue( &bs ); else *pi_id = bs_read( &bs, 4 ); return true; }
/***************************************************************************** * 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; if(unlikely(p_frag->i_buffer < 5)) { msg_Warn(p_dec,"NAL too small"); block_Release(p_frag); *pb_ts_used = false; return NULL; } if(p_frag->p_buffer[4] & 0x80) { msg_Warn(p_dec,"Forbidden zero bit not null, corrupted NAL"); block_Release(p_frag); *pb_ts_used = false; return GatherAndValidateChain(OutputQueues(p_sys, false)); /* will drop */ } /* Get NALU type */ block_t * p_output = NULL; uint8_t i_nal_type = hevc_getNALType(&p_frag->p_buffer[4]); if (i_nal_type < HEVC_NAL_VPS) { /* NAL is a VCL NAL */ p_output = ParseVCL(p_dec, i_nal_type, p_frag); if (p_output && (p_output->i_flags & BLOCK_FLAG_CORRUPTED)) msg_Info(p_dec, "Waiting for VPS/SPS/PPS"); } else { p_output = ParseNonVCL(p_dec, i_nal_type, p_frag); } p_output = GatherAndValidateChain(p_output); *pb_ts_used = (p_output != NULL); return p_output; }