/****************************************************************************** * * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ /*! ************************************************************************** * \file isvcd_nal.c * * \brief * Contains routines that resample for SVC resampling * * Detailed_description * * \date * * * \author : Kishore ************************************************************************** */ /****************************************************************************** * * Copyright (C) 2022 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ***************************************************************************** * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore */ /*****************************************************************************/ /* */ /* File Name : isvcd_nal.c */ /* */ /* Description : Contains fucntions which help in NAL extraction from */ /* the bitstream */ /* */ /* List of Functions : isvcd_nal_find_start_code, */ /* isvcd_get_annex_b_nal_unit, */ /* isvcd_get_rfc_nal_unit, */ /* isvcd_nal_rbsp_to_sodb, */ /* isvcd_reset_emulation_ctxt, */ /* isvcd_nal_byte_swap_emulation, */ /* isvcd_set_default_nal_header_prms, */ /* isvcd_dec_nal_hdr, */ /* isvcd_parse_part_slice_hdr, */ /* isvcd_get_int_tgt_lyr_attr, */ /* isvcd_discard_nal */ /* */ /* Issues / Problems : None */ /* */ /* Revision History: */ /* DD MM YYYY Author(s) Changes */ /* 14 09 2021 Kishore Draft */ /* */ /*****************************************************************************/ /*****************************************************************************/ /* File Includes */ /*****************************************************************************/ /* System include files */ #include #include #include #include #include #include /* standard interface include files */ #include "ih264_typedefs.h" #include "ih264_macros.h" #include "ih264_platform_macros.h" #include "ih264d_tables.h" #include "iv.h" #include "ivd.h" #include "ih264d_defs.h" #include "ih264_debug.h" #include "ih264d_parse_cavlc.h" #include "ih264d_inter_pred.h" #include "isvcd_structs.h" #include "ih264d_nal.h" #include "ih264d_error_handler.h" #include "ih264d_defs.h" /*****************************************************************************/ /*Extern Variable Declarations */ /*****************************************************************************/ /*****************************************************************************/ /* Global Variable Definitions */ /*****************************************************************************/ /*****************************************************************************/ /* Static Global Variable Definitions */ /*****************************************************************************/ /*****************************************************************************/ /* Static function Definitions */ /*****************************************************************************/ /*****************************************************************************/ /* */ /* Function Name : isvcd_reset_nal_buf */ /* */ /* Description : Performs the reset of NAL buffer structure */ /* Inputs : 1. Pointer to NAL buffer structure */ /* Globals : None */ /* Processing : Updates different fields of the structure */ /* Outputs : None */ /* Returns : */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ void isvcd_nal_buf_reset(void *pv_nal_buf) { nal_buf_t *ps_nal_buf = pv_nal_buf; ps_nal_buf->i4_valid_flag = SVCD_FALSE; ps_nal_buf->i4_buf_size = 0; ps_nal_buf->u4_max_bits = 0; ps_nal_buf->pu1_buf = NULL; } /*****************************************************************************/ /* */ /* Function Name :svcd_nal_find_start_code */ /* */ /* Description : Finds the position of the start code in the stream */ /* */ /* */ /* Inputs : 1. Pointer to buffer start */ /* 2. start position */ /* 3. Maximum number of bytes in the buffer */ /* 4. pointer to zero byte count */ /* 5. pointer to bytes consumed variable */ /* Globals : */ /* Processing : Searches for the start code in the bitstream and updates */ /* consumed variable */ /* */ /* Outputs : Bytes consumed variable */ /* Returns : If start code is found then it returns SC_FOUND otherwise*/ /* it returns SC_NOT_FOUND */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ WORD32 isvcd_nal_find_start_code(UWORD8 *pu1_buf_start, WORD32 i4_cur_pos, WORD32 i4_max_num_bytes, WORD32 *pi4_zero_cnt, UWORD32 *pu4_bytes_consumed) { UWORD8 *pu1_buf = pu1_buf_start + i4_cur_pos; WORD32 i4_i; for(i4_i = 0; i4_i < (i4_max_num_bytes - i4_cur_pos); i4_i++) { /*-------------------------------------------------------------------*/ /* If zero increment the zero byte counter */ /*-------------------------------------------------------------------*/ if(0 == *pu1_buf) { (*pi4_zero_cnt)++; } /*-------------------------------------------------------------------*/ /* If start code found then increment the byte consumed and return */ /*-------------------------------------------------------------------*/ else if(0x01 == *pu1_buf && *pi4_zero_cnt >= NUM_OF_ZERO_BYTES_BEFORE_START_CODE) { (*pu4_bytes_consumed)++; return (SC_FOUND); } /*-------------------------------------------------------------------*/ /* If non zero byte and value is not equal to 1 a then reset zero */ /* byte counter */ /*-------------------------------------------------------------------*/ else { *pi4_zero_cnt = 0; } (*pu4_bytes_consumed)++; pu1_buf++; } return (SC_NOT_FOUND); } /*****************************************************************************/ /* */ /* Function Name : isvcd_get_first_start_code */ /* */ /* Description : Searches for the first start code in the bitstream */ /* */ /* */ /* Inputs : 1. input buffer structure */ /* 2. Bytes consumed variable */ /* Globals : None */ /* Processing : None */ /* */ /* Outputs : Updates bytes consumed variable */ /* Returns : Start code is found or not */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ WORD32 isvcd_get_first_start_code(UWORD8 *pu1_stream_buffer, UWORD32 *pu4_bytes_consumed, UWORD32 *pu4_num_bytes) { WORD32 i4_zero_cnt = 0, i4_status; UWORD32 u4_bytes_consumed_temp = 0; i4_status = isvcd_nal_find_start_code(pu1_stream_buffer, 0, *pu4_num_bytes, &i4_zero_cnt, &u4_bytes_consumed_temp); /*-----------------------------------------------------------------------*/ /* If start code is not found then return and start searching for it */ /* again in the next process call. This process is repeated till we */ /* get a start code */ /*-----------------------------------------------------------------------*/ if(SC_NOT_FOUND == i4_status) { *pu4_bytes_consumed += u4_bytes_consumed_temp; return (i4_status); } else { /*-------------------------------------------------------------------*/ /* If start code found then proceed with bitstream extraction */ /*-------------------------------------------------------------------*/ *pu4_bytes_consumed += u4_bytes_consumed_temp; return (i4_status); } } /*****************************************************************************/ /* */ /* Function Name : isvcd_get_annex_b_nal_unit */ /* */ /* Description : This function gets one NAL unit from the Annex B based */ /* input bitstream */ /* */ /* */ /* Inputs : 1. Input buffer pointer */ /* 2. Current position in the input buffer */ /* 3. Input buffer size */ /* 4. Pointer to state of NAL boundary detection variable */ /* 5. Pointer to bytes consumed variable */ /* 6. pointer to nal structure */ /* Globals : */ /* Processing : This fucntion searches for start code from the current */ /* position and once gets one start code it searches for */ /* another start code to get a NAL unit. */ /* */ /* Outputs : Updates the state of NAL boundary detection logic */ /* Updates the bytes consumed variable from 0 to bytes */ /* consumed in this call */ /* Returns : start of nal flag */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ WORD32 isvcd_get_annex_b_nal_unit(UWORD8 *pu1_buf_start, WORD32 i4_cur_pos, WORD32 i4_max_num_bytes, WORD32 *pi4_state, WORD32 *pi4_zero_byte_cnt, UWORD32 *pu4_bytes_consumed, void *pv_nal_unit, WORD32 *pi4_more_data_flag) { nal_unit_t *ps_nal_unit = (nal_unit_t *) pv_nal_unit; WORD32 i4_status, i4_nal_start_flag = SVCD_FALSE; /*-----------------------------------------------------------------------*/ /* Initialization */ /*-----------------------------------------------------------------------*/ *pu4_bytes_consumed = 0; *pi4_more_data_flag = SVCD_TRUE; /*------------------------ check ----------------------------------------*/ /* Assumptions is that this fucntion should not be called with this state*/ /* hence it is responsibility of the caller to reset the state after the */ /* NAL_END. */ /*-----------------------------------------------------------------------*/ if(NAL_END == *pi4_state) { return i4_nal_start_flag; } /*-----------------------------------------------------------------------*/ /* ps_nal_unit->apu1_bufs[0] is expected to point to start of buffer of */ /* current NAL unit of the current process call. If a NAL unit is frag- */ /* -mented across multiple process call then this buffer should point to */ /* start address of buffers. But when start of NAL is present in the */ /* buffer of current process call then ps_nal_unit->apu1_bufs[0] is */ /* expected to point to start adress of NAL unit (should be pointing to) */ /* NAL header) */ /*-----------------------------------------------------------------------*/ ps_nal_unit->pu1_bufs = pu1_buf_start + i4_cur_pos; if(NAL_START == *pi4_state) { if(0 != *pi4_zero_byte_cnt) { return i4_nal_start_flag; } i4_nal_start_flag = SVCD_TRUE; ps_nal_unit->i4_num_bufs = 1; ps_nal_unit->i4_buf_sizes = 0; *pi4_state = FIND_NAL_END; } i4_status = isvcd_nal_find_start_code(pu1_buf_start, i4_cur_pos, i4_max_num_bytes, pi4_zero_byte_cnt, pu4_bytes_consumed); if(SC_NOT_FOUND == i4_status) { /*-------------------------------------------------------------------*/ /* If start code is not found then there are 2 possibilities */ /* 1. We are in the middle of decoding the start code. This means */ /* that we might have decoded the one or 2 zeroes of the start */ /* code. In such cases, we should not consume these bytes. Though */ /* doing so we might encounter spurious cases where 0's are not */ /* actually corresponds to start code but these will not harm us */ /* 2. Not of above case. Straightforward one */ /*-------------------------------------------------------------------*/ ps_nal_unit->i4_buf_sizes = *pu4_bytes_consumed; *pi4_more_data_flag = SVCD_FALSE; return (i4_nal_start_flag); } else { /*-------------------------------------------------------------------*/ /* If NAL END is found then increment the bytes consumed appropriatly*/ /* reset the zero byte counter */ /*-------------------------------------------------------------------*/ *pi4_state = NAL_END; ps_nal_unit->i4_buf_sizes = *pu4_bytes_consumed - 1; *pi4_zero_byte_cnt = 0; return (i4_nal_start_flag); } } /*****************************************************************************/ /* */ /* Function Name : isvcd_nal_rbsp_to_sodb */ /* */ /* Description : Converts the RBSP data to SODB data */ /* */ /* */ /* Inputs : 1. Input buffer containing the NAL unit */ /* 2. Length of NAL unit (in bytes) */ /* Globals : None */ /* Processing : Finds the RBSP stop bit, if present then finds the length*/ /* of SODB data */ /* */ /* Outputs : */ /* Returns : Number of bits in the SODB data */ /* */ /* Issues : */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ UWORD32 isvcd_nal_rbsp_to_sodb(UWORD8 *pu1_buf, WORD32 i4_nal_len_in_bytes, UWORD8 u1_ecd_mode) { UWORD32 u4_last_word_pos; UWORD32 u4_word, u4_max_bit_offset; UWORD8 i4_num_bits; WORD32 i4_i; WORD64 i8_nal_len; UWORD32 *pu4_buf; if(0 >= i4_nal_len_in_bytes) { return (0); } /* Get offset in bits */ i8_nal_len = (WORD64) i4_nal_len_in_bytes << 3; u4_max_bit_offset = (UWORD32) i8_nal_len; /* If NAL is coded in CABAC then SODB */ /* length has to account for CABAC */ /* ZERO WORDS also */ if(1 == u1_ecd_mode) { return (u4_max_bit_offset); } /* Calculate the position of last word */ u4_last_word_pos = i4_nal_len_in_bytes >> 2; /* Load the last word */ i4_i = i4_nal_len_in_bytes & 0x03; if(0 != i4_i) { pu4_buf = (UWORD32 *) pu1_buf; pu4_buf += u4_last_word_pos; u4_word = *pu4_buf; i4_num_bits = i4_i << 3; u4_word >>= (32 - i4_num_bits); } else { pu4_buf = (UWORD32 *) pu1_buf; pu4_buf += (u4_last_word_pos - 1); u4_word = *pu4_buf; i4_num_bits = 32; } /* Search for RBSP stop bit */ do { for(i4_i = 0; (i4_i < i4_num_bits) && !CHECKBIT(u4_word, i4_i); i4_i++) ; u4_max_bit_offset -= i4_i; /* RBSP stop bit is found then */ /* come out of the loop */ if(0 != CHECKBIT(u4_word, i4_i)) { /* Remove RBSP stop bit */ u4_max_bit_offset -= 1; break; } pu4_buf -= 1; u4_word = *pu4_buf; i4_num_bits = 32; } while(u4_max_bit_offset > 0); return (u4_max_bit_offset); } /*****************************************************************************/ /* */ /* Function Name : isvcd_reset_emulation_ctxt */ /* */ /* Description : Resets the emulation prevention context structure */ /* */ /* Inputs : pv_emulation_ctxt - pointer to emulation prevention */ /* context structure */ /* */ /* Globals : None */ /* */ /* Processing : None */ /* */ /* Outputs : None */ /* */ /* Returns : None */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* DD MM YYYY Author(s) Changes */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ void isvcd_reset_emulation_ctxt(void *pv_emulation_ctxt) { emulation_prevent_ctxt_t *ps_emulation_ctxt = (emulation_prevent_ctxt_t *) pv_emulation_ctxt; /*! Reset the emulation prevention context */ ps_emulation_ctxt->i4_state = NOT_STUFFED_BYTE; ps_emulation_ctxt->i4_zeroes_cnt = 0; ps_emulation_ctxt->u4_bytes_in_word = 0; ps_emulation_ctxt->u4_word = 0; } /****************************************************************************/ /* */ /* Function Name : isvcd_nal_byte_swap_emulation */ /* */ /* Description : This function is does byte swap or emulation or both */ /* in the stream. */ /* */ /* Inputs : pu4_out_stream : Pointer to bitstream out buffer */ /* pu4_out_len : Pointer to variable for out len */ /* pu1_in_stream : Pointer to bitstream in buffer */ /* u4_in_len : Input bitstream buffer length */ /* u4_prev_0s : In case of fragemented NAL 0s in last */ /* fragmented unit */ /* u4_0s_bfr_sc : Number of zeros before start code */ /* u4_bytes : Number of bytes in last fragmented */ /* word */ /* u4_word : Last fragmented word */ /* */ /* Globals : None */ /* */ /* Processing : It has three mode of operations */ /* 1. Byte Swap and Emulation for H.264 WMV9 AP DEC */ /* supports both fragmented and non fragmented packets */ /* set u4_prev_0s = last valid zeros for this operation*/ /* 2. Byte Swap only for MPEG2 and MPEG4 WMV9 MP DEC */ /* supports both fragmented and non fragmented packets */ /* set u4_prev_0s = 0 and u4_0s_bfr_sc = u4_in_len */ /* 3. Annex B stream */ /* only non fragmented */ /* set u4_prev_0s = 0 for this operation */ /* Outputs : pu4_out_len output length of the bit stream */ /* */ /* Returns : Number of zeros in case of framented start code */ /* */ /* Known Issues : */ /* */ /* Revision History */ /* */ /* DD MM YY Author Changes */ /* 06 09 2021 Vijay */ /****************************************************************************/ UWORD32 isvcd_nal_byte_swap_emulation(UWORD32 *pu4_out_stream, UWORD32 *pu4_out_len, UWORD8 *pu1_in_stream, UWORD32 u4_in_len, WORD32 i4_0s_bfr_sc, void *pv_emulation_ctxt) { UWORD32 u4_i, u4_num_bytes, u4_offset; UWORD8 u1_cur_byte; emulation_prevent_ctxt_t *ps_emulation_ctxt = (emulation_prevent_ctxt_t *) pv_emulation_ctxt; u4_offset = ps_emulation_ctxt->u4_bytes_in_word; u4_num_bytes = ps_emulation_ctxt->u4_bytes_in_word; for(u4_i = 0; u4_i < u4_in_len; u4_i++) { UWORD8 u1_cur_byte_emu, u1_cur_byte_sc; UWORD64 u8_sft_word; u1_cur_byte = *pu1_in_stream++; u1_cur_byte_emu = (EMULATION_PREVENTION_BYTE == u1_cur_byte); u1_cur_byte_sc = (START_CODE_BYTE == u1_cur_byte); if((ps_emulation_ctxt->i4_zeroes_cnt >= i4_0s_bfr_sc) & (u1_cur_byte_emu | u1_cur_byte_sc) & (NOT_STUFFED_BYTE == ps_emulation_ctxt->i4_state)) { if(u1_cur_byte_sc) { break; } ps_emulation_ctxt->i4_zeroes_cnt = 0; ps_emulation_ctxt->i4_state = STUFFED_BYTE; continue; } u8_sft_word = (UWORD64) ps_emulation_ctxt->u4_word << 8; ps_emulation_ctxt->u4_word = (UWORD32) (u8_sft_word | u1_cur_byte); ps_emulation_ctxt->u4_bytes_in_word++; u4_num_bytes++; ps_emulation_ctxt->i4_zeroes_cnt++; if(u1_cur_byte != 0x00) { ps_emulation_ctxt->i4_zeroes_cnt = 0; } if((u4_num_bytes & 0x03) == 0x00) { *pu4_out_stream = ps_emulation_ctxt->u4_word; ps_emulation_ctxt->u4_bytes_in_word = 0; pu4_out_stream++; } ps_emulation_ctxt->i4_state = NOT_STUFFED_BYTE; } if(ps_emulation_ctxt->u4_bytes_in_word) { UWORD64 temp_out_stream = (UWORD64) ps_emulation_ctxt->u4_word << ((4 - ps_emulation_ctxt->u4_bytes_in_word) << 3); *pu4_out_stream = (UWORD32) temp_out_stream; } *pu4_out_len = (u4_num_bytes - u4_offset); return ((u4_num_bytes & 0xFFFFFFFC)); } /*****************************************************************************/ /* */ /* Function Name : isvcd_set_default_nal_header_prms */ /* */ /* Description : Sets the members of NAL header structures to default */ /* values */ /* */ /* Inputs : pv_nal_prms - pointer nal header prms structure */ /* i4_temp_id - default value of temporal id */ /* */ /* Globals : None */ /* */ /* Processing : None */ /* */ /* Outputs : None */ /* */ /* Returns : None */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* DD MM YYYY Author(s) Changes */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ void isvcd_set_default_nal_prms(void *pv_nal_prms) { nal_prms_t *ps_nal_prms; ps_nal_prms = (nal_prms_t *) pv_nal_prms; /* Set default values */ ps_nal_prms->i4_dependency_id = 0; ps_nal_prms->i4_derived_nal_type = 0xFF; ps_nal_prms->i4_idr_pic_flag = SVCD_FALSE; ps_nal_prms->i4_nal_header_len = 0; ps_nal_prms->i4_nal_ref_idc = 0xFF; ps_nal_prms->i4_nal_unit_type = 0xFF; ps_nal_prms->i4_no_int_lyr_pred = 1; ps_nal_prms->i4_priority_id = 0; ps_nal_prms->i4_quality_id = 0; ps_nal_prms->i4_discard_flag = 0; ps_nal_prms->i4_dqid = 0; ps_nal_prms->i4_use_ref_base_pic_flag = 0; ps_nal_prms->i4_temporal_id = 0; ps_nal_prms->i4_idr_pic_num = 0; ps_nal_prms->u2_frm_num = 0; ps_nal_prms->i4_poc_lsb = 0; ps_nal_prms->i4_delta_poc_bot = 0; ps_nal_prms->ai4_delta_poc[0] = 0; ps_nal_prms->ai4_delta_poc[1] = 0; ps_nal_prms->u1_pps_id = 0; } /*****************************************************************************/ /* */ /* Function Name : isvcd_dec_nal_hdr */ /* */ /* Description : None */ /* */ /* Inputs : pv_buf_ptr - Pointer to buffer constaining start of NAL */ /* pv_nal_header_buf - Temporray working buffer */ /* pv_nal_prms - Pointer to nal header prms */ /* structure */ /* */ /* Globals : None */ /* */ /* Processing : None */ /* */ /* Outputs : None */ /* */ /* Returns : None */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* DD MM YYYY Author(s) Changes */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ void isvcd_dec_nal_hdr(void *pv_buf_ptr, WORD32 i4_buf_size, void *pv_nal_header_buf, void *pv_nal_prms, void *pv_prefix_nal_buf, void *pv_prefix_nal_prms, UWORD32 *pu4_err_code) { nal_prms_t *ps_nal_prms; nal_prms_t *ps_prefix_nal_prms; nal_buf_t *ps_prefix_nal_buf; dec_bit_stream_t s_stream_ctxt = {0}; WORD32 i4_forbidden_zero_bit; /* byte swapping */ UWORD8 *pu1_buf = (UWORD8 *) pv_nal_header_buf; UWORD8 *pu1_src = (UWORD8 *) pv_buf_ptr; ps_nal_prms = (nal_prms_t *) pv_nal_prms; ps_prefix_nal_prms = (nal_prms_t *) pv_prefix_nal_prms; ps_prefix_nal_buf = (nal_buf_t *) pv_prefix_nal_buf; /* The NAL header syntax elements are read through bitstream fucntions. */ /* Hence bitstream context structure initializaton is needed before */ /* parsing from the bitstream */ /* Also bitstream fucntions assume the buffer is byteswapped. Hence the */ /* byte swapping is also done for 4 bytes */ s_stream_ctxt.u4_ofst = 0; s_stream_ctxt.pu4_buffer = pv_nal_header_buf; s_stream_ctxt.u4_max_ofst = (i4_buf_size << 3); *pu4_err_code = 0; /* Check the size of bitstream buffer */ if(s_stream_ctxt.u4_max_ofst < 8) { *pu4_err_code = (UWORD32) NAL_INSUFFICIENT_DATA; return; } if(s_stream_ctxt.u4_max_ofst >= 32) { *pu1_buf++ = *(pu1_src + 3); *pu1_buf++ = *(pu1_src + 2); *pu1_buf++ = *(pu1_src + 1); *pu1_buf++ = *pu1_src; } else { *pu1_buf++ = *pu1_src; } /*-----------------------------------------------------------------------*/ /*! Parse the NAL header and update the NAL header structure members */ /*-----------------------------------------------------------------------*/ /* Read forbidden 0 bit */ i4_forbidden_zero_bit = ih264d_get_bit_h264(&s_stream_ctxt); if(0 != i4_forbidden_zero_bit) { *pu4_err_code = (UWORD32) NAL_CORRUPT_DATA; return; } /*---------------- Read NAL ref idc -----------------------------*/ ps_nal_prms->i4_nal_ref_idc = ih264d_get_bits_h264(&s_stream_ctxt, 2); /*----------------- Read NAL type -------------------------------*/ ps_nal_prms->i4_nal_unit_type = ih264d_get_bits_h264(&s_stream_ctxt, 5); if(ps_nal_prms->i4_nal_unit_type > CODED_SLICE_EXTENSION_NAL) { *pu4_err_code = (UWORD32) NAL_CORRUPT_DATA; return; } if(ACCESS_UNIT_DELIMITER_RBSP == ps_nal_prms->i4_nal_unit_type) { ps_nal_prms->i4_derived_nal_type = NON_VCL_NAL; return; } /* set idr pic flag */ if(IDR_SLICE_NAL == ps_nal_prms->i4_nal_unit_type) { ps_nal_prms->i4_idr_pic_flag = SVCD_TRUE; } else { ps_nal_prms->i4_idr_pic_flag = SVCD_FALSE; } /*----------------- Read SVC extension NAL header ---------------*/ if(CODED_SLICE_EXTENSION_NAL == ps_nal_prms->i4_nal_unit_type || PREFIX_UNIT_NAL == ps_nal_prms->i4_nal_unit_type) { WORD32 i4_svc_extension_flag, i4_idr_flag; /* check the size of the buffer */ if(s_stream_ctxt.u4_max_ofst < 32) { *pu4_err_code = (UWORD32) NAL_INSUFFICIENT_DATA; return; } i4_svc_extension_flag = ih264d_get_bit_h264(&s_stream_ctxt); UNUSED(i4_svc_extension_flag); i4_idr_flag = ih264d_get_bit_h264(&s_stream_ctxt); /* Set idr pic flag based on idr flag */ if(1 == i4_idr_flag) { ps_nal_prms->i4_idr_pic_flag = SVCD_TRUE; } else { ps_nal_prms->i4_idr_pic_flag = SVCD_FALSE; } /* parse priorit id */ ps_nal_prms->i4_priority_id = ih264d_get_bits_h264(&s_stream_ctxt, 6); /* parse the no inter layer prediction flag */ ps_nal_prms->i4_no_int_lyr_pred = ih264d_get_bit_h264(&s_stream_ctxt); /* parse dependency id */ ps_nal_prms->i4_dependency_id = ih264d_get_bits_h264(&s_stream_ctxt, 3); /* parse quality id */ ps_nal_prms->i4_quality_id = ih264d_get_bits_h264(&s_stream_ctxt, 4); if((ps_nal_prms->i4_quality_id > 0) || (ps_nal_prms->i4_dependency_id > 2)) { *pu4_err_code = (UWORD32) NAL_CORRUPT_DATA; return; } /* parse temporal id */ ps_nal_prms->i4_temporal_id = ih264d_get_bits_h264(&s_stream_ctxt, 3); /* parse use ref base pic flag */ ps_nal_prms->i4_use_ref_base_pic_flag = ih264d_get_bit_h264(&s_stream_ctxt); if(0 != ps_nal_prms->i4_use_ref_base_pic_flag) { *pu4_err_code = (UWORD32) NAL_CORRUPT_DATA; return; } /* parse discrad flag */ ps_nal_prms->i4_discard_flag = ih264d_get_bit_h264(&s_stream_ctxt); /* parse the reserved bits */ ih264d_get_bits_h264(&s_stream_ctxt, 3); } /* update NAL hedaer length in bytes */ ps_nal_prms->i4_nal_header_len = s_stream_ctxt.u4_ofst >> 3; /*************************************************************************/ /* PREFIX NAL UNIT ASSOCIATION WITH ASSOCIATED NAL UNIT */ /*************************************************************************/ /* if current NAL is not a AVC NAL unit then */ /* discard the prefix NAL unit if present */ if(CODED_SLICE_EXTENSION_NAL == ps_nal_prms->i4_nal_unit_type) { isvcd_nal_buf_reset(ps_prefix_nal_buf); } if(SVCD_TRUE == ps_prefix_nal_buf->i4_valid_flag) { /* Copy the required parameters from the prefix NAL unit */ ps_nal_prms->i4_dependency_id = ps_prefix_nal_prms->i4_dependency_id; ps_nal_prms->i4_quality_id = ps_prefix_nal_prms->i4_quality_id; ps_nal_prms->i4_priority_id = ps_prefix_nal_prms->i4_priority_id; ps_nal_prms->i4_temporal_id = ps_prefix_nal_prms->i4_temporal_id; ps_nal_prms->i4_no_int_lyr_pred = ps_prefix_nal_prms->i4_no_int_lyr_pred; ps_nal_prms->i4_use_ref_base_pic_flag = ps_prefix_nal_prms->i4_use_ref_base_pic_flag; ps_nal_prms->i4_discard_flag = ps_prefix_nal_prms->i4_discard_flag; } /*-----------------------------------------------------------------------*/ /* Set the derived NAL unit type and also update the DQID for VCL NAL */ /* units */ /*-----------------------------------------------------------------------*/ if(CODED_SLICE_EXTENSION_NAL == ps_nal_prms->i4_nal_unit_type || SLICE_NAL == ps_nal_prms->i4_nal_unit_type || IDR_SLICE_NAL == ps_nal_prms->i4_nal_unit_type || PREFIX_UNIT_NAL == ps_nal_prms->i4_nal_unit_type) { ps_nal_prms->i4_derived_nal_type = VCL_NAL; /* calculate the DQID and modified DQID */ ps_nal_prms->i4_dqid = (ps_nal_prms->i4_dependency_id << 4) + ps_nal_prms->i4_quality_id; } else { ps_nal_prms->i4_derived_nal_type = NON_VCL_NAL; } } /*****************************************************************************/ /* */ /* Function Name : isvcd_parse_part_slice_hdr */ /* */ /* Description : This routine parses the slice till POC parameters */ /* */ /* Inputs : 1. Pointer to input bitstream */ /* 2. Temporary input buffer */ /* 3. PPS start buffer */ /* 4. SPS start buffer */ /* 5. Pointer to NAL paramter structure */ /* 6. Place holder for error code */ /* Globals : None */ /* Processing : Parses the slice header */ /* */ /* Outputs : Updated NAL prms structure */ /* Updated error code */ /* Returns : status */ /* */ /* Issues : Does not support interlaced content */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ WORD32 isvcd_parse_part_slice_hdr(UWORD8 *pu1_input_buf, WORD32 i4_input_buf_size, UWORD8 *pu1_temp_buf, void *pv_sps, void *pv_pps, nal_prms_t *ps_nal_prms, UWORD32 *pu4_err_code, WORD32 *pi4_sps_pps_status) { UWORD32 u4_slice_type; dec_seq_params_t *ps_sps = (dec_seq_params_t *) pv_sps; dec_pic_params_t *ps_pps = (dec_pic_params_t *) pv_pps; dec_bit_stream_t s_stream_ctxt = {0}; dec_bit_stream_t *ps_stream_ctxt; UWORD32 *pu4_bitstrm_buf; UWORD32 *pu4_bitstrm_ofst; *pi4_sps_pps_status = NAL_CORRUPT_DATA; /* Perform the emulation prevention and byte swap */ { emulation_prevent_ctxt_t s_emulation_ctxt = {0}; WORD32 i4_size, i4_temp; isvcd_reset_emulation_ctxt((void *) &s_emulation_ctxt); i4_size = MIN(i4_input_buf_size, HEADER_BUFFER_LEN_BEFORE_EP); isvcd_nal_byte_swap_emulation((UWORD32 *) pu1_temp_buf, (UWORD32 *) &i4_temp, pu1_input_buf, (UWORD32) i4_size, NUM_OF_ZERO_BYTES_BEFORE_START_CODE, &s_emulation_ctxt); /* Initialize the stream context structure */ s_stream_ctxt.pu4_buffer = (UWORD32 *) pu1_temp_buf; s_stream_ctxt.u4_ofst = 0; s_stream_ctxt.u4_max_ofst = (i4_size << 3); } ps_stream_ctxt = &s_stream_ctxt; /* Parse the first mb address in slice */ pu4_bitstrm_buf = ps_stream_ctxt->pu4_buffer; pu4_bitstrm_ofst = &ps_stream_ctxt->u4_ofst; ps_nal_prms->u4_first_mb_addr = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_nal_prms->u4_first_mb_addr >= (MAX_MBS_LEVEL_51)) { return ERROR_CORRUPTED_SLICE; } /* Parse slice type */ u4_slice_type = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(u4_slice_type > 9) return ERROR_INV_SLC_TYPE_T; /* Check the validity of slice prms */ switch(u4_slice_type) { case 0: case 5: u4_slice_type = P_SLICE; /* P slice */ break; case 1: case 6: u4_slice_type = B_SLICE; /* B slice */ break; case 2: case 7: /* I slice */ u4_slice_type = I_SLICE; break; default: break; } /* Parse the pps id */ ps_nal_prms->u1_pps_id = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_nal_prms->u1_pps_id & MASK_ERR_PIC_SET_ID) return ERROR_INV_SLICE_HDR_T; /* validate pps id */ ps_pps += ps_nal_prms->u1_pps_id; if(0 == ps_pps->u1_is_valid) { return NOT_OK; } /* Derive sps id */ ps_sps = ps_pps->ps_sps; ps_nal_prms->u1_sps_id = ps_sps->u1_seq_parameter_set_id; if(CODED_SLICE_EXTENSION_NAL == ps_nal_prms->i4_nal_unit_type) { ps_sps += MAX_NUM_SEQ_PARAMS; ps_nal_prms->u1_sps_id = ps_sps->u1_seq_parameter_set_id; ps_nal_prms->u1_sps_id += MAX_NUM_SEQ_PARAMS; } if(NULL == ps_sps) { return NOT_OK; } if(FALSE == ps_sps->u1_is_valid) { return ERROR_INV_SLICE_HDR_T; } if(ps_nal_prms->u4_first_mb_addr > (ps_sps->u2_frm_ht_in_mbs * ps_sps->u2_frm_wd_in_mbs)) { return ERROR_CORRUPTED_SLICE; } *pi4_sps_pps_status = 0; /* Parse frame number */ ps_nal_prms->u2_frm_num = ih264d_get_bits_h264(ps_stream_ctxt, ps_sps->u1_bits_in_frm_num); /* IDR picture number */ if(SVCD_TRUE == ps_nal_prms->i4_idr_pic_flag) { ps_nal_prms->i4_idr_pic_num = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_nal_prms->i4_idr_pic_num > 65535) return ERROR_INV_SLICE_HDR_T; } /* Poc lsb */ if(0 == ps_sps->u1_pic_order_cnt_type) { ps_nal_prms->i4_poc_lsb = ih264d_get_bits_h264(ps_stream_ctxt, ps_sps->u1_log2_max_pic_order_cnt_lsb_minus); if(ps_nal_prms->i4_poc_lsb < 0 || ps_nal_prms->i4_poc_lsb >= ps_sps->i4_max_pic_order_cntLsb) return ERROR_INV_SLICE_HDR_T; if(SVCD_TRUE == ps_pps->u1_pic_order_present_flag) { ps_nal_prms->i4_delta_poc_bot = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } } else if((1 == ps_sps->u1_pic_order_cnt_type) && (!ps_sps->u1_delta_pic_order_always_zero_flag)) { ps_nal_prms->ai4_delta_poc[0] = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(SVCD_TRUE == ps_pps->u1_pic_order_present_flag) { ps_nal_prms->ai4_delta_poc[1] = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } } *pu4_err_code = 0; return (OK); } /*****************************************************************************/ /* */ /* Function Name : isvcd_get_int_tgt_lyr_attr */ /* */ /* Description : This routine returns the target layer attributes */ /* (dependency id, temporal id and quality id) */ /* */ /* Inputs : 1. Application attributes */ /* 2. Internal attributes (input and output) */ /* 3. Nal prms structure */ /* Globals : None */ /* Processing : */ /* */ /* Outputs : Updated internal target layer attributes */ /* Returns : status */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* */ /* DD MM YYYY Author(s) Changes (Describe the changes made) */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ WORD32 isvcd_get_int_tgt_lyr_attr(target_lyr_attr_t *ps_app_attr, target_lyr_attr_t *ps_int_attr, nal_prms_t *ps_nal_prms) { WORD32 i4_dep_id; WORD32 i4_quality_id; WORD32 i4_temp_id; WORD32 i4_prior_id; /* sanity checks */ if((NULL == ps_app_attr) || (NULL == ps_int_attr) || (NULL == ps_nal_prms)) { return NOT_OK; } i4_dep_id = ps_int_attr->i4_dependency_id; i4_quality_id = ps_int_attr->i4_quality_id; i4_temp_id = ps_int_attr->i4_temporal_id; i4_prior_id = ps_int_attr->i4_priority_id; /* check for idr pic flag */ /* dependency & temporal id is updated only for IDR picture */ if(SVCD_TRUE == ps_nal_prms->i4_idr_pic_flag) { if(ps_int_attr->i4_dependency_id < ps_app_attr->i4_dependency_id) { /* update the internal attributes only if */ /* current dep_id -1 == highest dep id decoded so far */ /* and quality id is equal to 0 */ if((ps_nal_prms->i4_dependency_id - 1 == ps_int_attr->i4_dependency_id) && (0 == ps_nal_prms->i4_quality_id)) { /* Set revised target dependency id */ i4_dep_id = ps_nal_prms->i4_dependency_id; i4_temp_id = ps_app_attr->i4_temporal_id; i4_prior_id = ps_app_attr->i4_priority_id; } } else { /* cases when the curr dep is greater than or equal to app dep */ i4_dep_id = ps_app_attr->i4_dependency_id; i4_temp_id = ps_app_attr->i4_temporal_id; i4_prior_id = ps_app_attr->i4_priority_id; } } /* Set quality id */ if(i4_dep_id == ps_app_attr->i4_dependency_id) { i4_quality_id = ps_app_attr->i4_quality_id; } else { i4_quality_id = MAX_QUALITY_ID; } /* Update the internal attributes */ ps_int_attr->i4_dependency_id = i4_dep_id; ps_int_attr->i4_quality_id = i4_quality_id; ps_int_attr->i4_temporal_id = i4_temp_id; ps_int_attr->i4_priority_id = i4_prior_id; return (OK); } /*****************************************************************************/ /* */ /* Function Name : isvcd_discard_nal */ /* */ /* Description : Determines whether current NAL unit has to be discarded */ /* or not */ /* */ /* Inputs : pv_nal_prms - Pointer to NAL header prms */ /* structure */ /* pv_app_lyr_attr - Pointer to application target layer */ /* attributes structure */ /* pv_app_lyr_attr - Pointer to internal target layer */ /* attributes structure */ /* i4_update_flag - This flag indicates whether the internal*/ /* target attrbutes should be updated or not */ /* Globals : None */ /* */ /* Processing : None */ /* */ /* Outputs : None */ /* */ /* Returns : None */ /* */ /* Issues : None */ /* */ /* Revision History: */ /* DD MM YYYY Author(s) Changes */ /* 06 09 2021 Vijay Draft */ /* */ /*****************************************************************************/ WORD32 isvcd_discard_nal(void *pv_nal_prms, void *pv_app_attr, void *pv_int_attr, WORD32 i4_update_flag) { WORD32 i4_discard_nal_flag; nal_prms_t *ps_nal_prms; target_lyr_attr_t *ps_app_attr; target_lyr_attr_t *ps_int_attr; WORD32 i4_status; ps_nal_prms = (nal_prms_t *) pv_nal_prms; ps_app_attr = (target_lyr_attr_t *) pv_app_attr; ps_int_attr = (target_lyr_attr_t *) pv_int_attr; /* Get the updated target layer attributes */ if(SVCD_TRUE == i4_update_flag) { i4_status = isvcd_get_int_tgt_lyr_attr(ps_app_attr, ps_int_attr, ps_nal_prms); if(OK != i4_status) { return NOT_OK; } } i4_discard_nal_flag = SVCD_FALSE; if(VCL_NAL == ps_nal_prms->i4_derived_nal_type) { /*-------------------------------------------------------------------*/ /*!Discard VCL NAL if any of following is true */ /*! - Dependency id is greater than target dependency id */ /*! - Dependency id is equal to target dependency id but quality id */ /*! is greater than target quality id */ /*! - priority id is greater than target priority id */ /*! - Temporal id is greater than target temporal id */ /*! - If dependency id is greater than a NAL unit for which discard */ /*! flag of the NAL header is set */ /*-------------------------------------------------------------------*/ if(PREFIX_UNIT_NAL != ps_nal_prms->i4_nal_unit_type) { if(ps_nal_prms->i4_dependency_id > ps_int_attr->i4_dependency_id) { i4_discard_nal_flag = SVCD_TRUE; } if(ps_nal_prms->i4_dependency_id == ps_int_attr->i4_dependency_id && ps_nal_prms->i4_quality_id > ps_int_attr->i4_quality_id) { i4_discard_nal_flag = SVCD_TRUE; } if(ps_nal_prms->i4_temporal_id > ps_int_attr->i4_temporal_id) { i4_discard_nal_flag = SVCD_TRUE; } if(ps_nal_prms->i4_priority_id > ps_int_attr->i4_priority_id) { i4_discard_nal_flag = SVCD_TRUE; } } else { if(0 == ps_int_attr->i4_quality_id && 0 == ps_int_attr->i4_dependency_id) { i4_discard_nal_flag = SVCD_TRUE; } } } return (i4_discard_nal_flag); }