/****************************************************************************** * * Copyright (C) 2021 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 : imvcd_nalu_parser.h */ /* */ /* Description : Functions for MVC NALU parsing */ /* */ /*****************************************************************************/ #include #include "ih264_typedefs.h" #include "iv.h" #include "imvcd.h" #include "ih264d_error_handler.h" #include "ih264d_bitstrm.h" #include "ih264d_defs.h" #include "ih264d_nal.h" #include "ih264d_parse_cavlc.h" #include "ih264d_structs.h" #include "ih264d_vui.h" #include "imvcd_defs.h" #include "imvcd_slice_functions.h" #include "imvcd_structs.h" #include "imvcd_utils.h" static WORD32 imvcd_nalu_mvc_ext_parser(mvc_dec_ctxt_t *ps_mvcd_ctxt, dec_bit_stream_t *ps_bitstrm) { nalu_mvc_ext_t *ps_nalu_mvc_ext = &ps_mvcd_ctxt->as_nalu_mvc_ext[ps_mvcd_ctxt->u2_num_views_decoded]; ps_nalu_mvc_ext->u1_non_idr_flag = ih264d_get_bit_h264(ps_bitstrm); ps_nalu_mvc_ext->u1_priority_id = ih264d_get_bits_h264(ps_bitstrm, 6); ps_nalu_mvc_ext->u2_view_id = ih264d_get_bits_h264(ps_bitstrm, 10); if((ps_nalu_mvc_ext->u2_view_id >= MAX_NUM_VIEWS) || (ps_nalu_mvc_ext->u2_view_id >= ps_mvcd_ctxt->u2_num_views)) { return IVD_INVALID_BITSTREAM; } ps_nalu_mvc_ext->u1_temporal_id = ih264d_get_bits_h264(ps_bitstrm, 3); ps_nalu_mvc_ext->u1_anchor_pic_flag = ih264d_get_bit_h264(ps_bitstrm); ps_nalu_mvc_ext->u1_inter_view_flag = ih264d_get_bit_h264(ps_bitstrm); if(0 == ih264d_get_bit_h264(ps_bitstrm)) { return IVD_INVALID_BITSTREAM; } return OK; } static WORD32 imvcd_parse_subset_sps(mvc_dec_ctxt_t *ps_mvcd_ctxt, dec_bit_stream_t *ps_bitstrm) { subset_sps_t *ps_subset_sps = NULL; dec_seq_params_t *ps_sps = NULL; WORD32 i, j, k; UWORD8 u1_profile_idc; UWORD8 au1_constraint_set_flags[6]; UWORD8 u1_level_idc; UWORD8 u1_seq_parameter_set_id; UWORD32 *pu4_bitstrm_buf = ps_bitstrm->pu4_buffer; UWORD32 *pu4_bitstrm_ofst = &ps_bitstrm->u4_ofst; UWORD32 u4_temp; UWORD16 u2_num_views_m1; UWORD8 u1_num_refs; UWORD8 u1_num_level_values_signalled_m1; UWORD8 u2_num_ops_m1; dec_struct_t *ps_view_ctxt = &ps_mvcd_ctxt->s_view_dec_ctxt; WORD32 i4_error_code = OK; if(0 == ps_mvcd_ctxt->u1_num_sps) { return ERROR_INV_SPS_PPS_T; } for(i = 0; i < MAX_NUM_SEQ_PARAMS; i++) { if(ps_view_ctxt->ps_sps[i].u1_is_valid) { ps_sps = &ps_view_ctxt->ps_sps[i]; break; } } if(NULL == ps_sps) { return ERROR_INV_SPS_PPS_T; } u1_profile_idc = ih264d_get_bits_h264(ps_bitstrm, 8); for(i = 0; i < 6; i++) { au1_constraint_set_flags[i] = ih264d_get_bit_h264(ps_bitstrm); } if((u1_profile_idc != MULTIVIEW_HIGH_PROFILE_IDC) || (au1_constraint_set_flags[1] == 1)) { return ERROR_FEATURE_UNAVAIL; } /*****************************************************/ /* Read reserved_zero_2bits (2 bits) */ /*****************************************************/ ih264d_get_bits_h264(ps_bitstrm, 2); u1_level_idc = ih264d_get_bits_h264(ps_bitstrm, 8); u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); u1_seq_parameter_set_id = u4_temp; if(u4_temp & MASK_ERR_SEQ_SET_ID) { return ERROR_INV_SPS_PPS_T; } if(ps_sps->u1_level_idc != u1_level_idc) { ps_view_ctxt->u1_res_changed = 1; return IVD_RES_CHANGED; } ps_subset_sps = &ps_mvcd_ctxt->as_subset_sps[u1_seq_parameter_set_id]; /* Accounting for the idiocy in 'ih264d_parse_pps' */ ps_subset_sps->s_sps_data.u1_profile_idc = HIGH_PROFILE_IDC; ps_subset_sps->s_sps_data.u1_level_idc = u1_level_idc; ps_subset_sps->s_sps_data.u1_seq_parameter_set_id = u1_seq_parameter_set_id; ps_subset_sps->s_sps_data.i4_chroma_format_idc = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.i4_chroma_format_idc != 1) { return ERROR_FEATURE_UNAVAIL; } ps_subset_sps->s_sps_data.i4_bit_depth_luma_minus8 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.i4_bit_depth_luma_minus8 != 0) { return ERROR_FEATURE_UNAVAIL; } ps_subset_sps->s_sps_data.i4_bit_depth_chroma_minus8 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.i4_bit_depth_chroma_minus8 != 0) { return ERROR_FEATURE_UNAVAIL; } ps_subset_sps->s_sps_data.i4_qpprime_y_zero_transform_bypass_flag = ih264d_get_bit_h264(ps_bitstrm); if(ps_subset_sps->s_sps_data.i4_qpprime_y_zero_transform_bypass_flag != 0) { return ERROR_INV_SPS_PPS_T; } ps_subset_sps->s_sps_data.i4_seq_scaling_matrix_present_flag = ih264d_get_bit_h264(ps_bitstrm); if(ps_subset_sps->s_sps_data.i4_seq_scaling_matrix_present_flag) { for(i = 0; i < 8; i++) { ps_subset_sps->s_sps_data.u1_seq_scaling_list_present_flag[i] = ih264d_get_bit_h264(ps_bitstrm); } } u4_temp = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(u4_temp > (MAX_BITS_IN_FRAME_NUM - 4)) { return ERROR_INV_SPS_PPS_T; } ps_subset_sps->s_sps_data.u1_bits_in_frm_num = 4 + u4_temp; ps_subset_sps->s_sps_data.u2_u4_max_pic_num_minus1 = (1 << (ps_subset_sps->s_sps_data.u1_bits_in_frm_num)) - 1; ps_subset_sps->s_sps_data.u1_pic_order_cnt_type = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.u1_pic_order_cnt_type > MAX_PIC_ORDER_CNT_TYPE) { return ERROR_INV_POC_TYPE_T; } ps_subset_sps->s_sps_data.u1_num_ref_frames_in_pic_order_cnt_cycle = 1; if(ps_subset_sps->s_sps_data.u1_pic_order_cnt_type == 0) { UWORD32 u1_log2_max_pic_order_cnt_lsb_minus4 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(u1_log2_max_pic_order_cnt_lsb_minus4 > (MAX_BITS_IN_POC_LSB - 4)) { return ERROR_INV_SPS_PPS_T; } ps_subset_sps->s_sps_data.u1_log2_max_pic_order_cnt_lsb_minus = 4 + u1_log2_max_pic_order_cnt_lsb_minus4; ps_subset_sps->s_sps_data.i4_max_pic_order_cntLsb = (1 << ps_subset_sps->s_sps_data.u1_log2_max_pic_order_cnt_lsb_minus); } else if(ps_subset_sps->s_sps_data.u1_pic_order_cnt_type == 1) { ps_subset_sps->s_sps_data.u1_delta_pic_order_always_zero_flag = ih264d_get_bit_h264(ps_bitstrm); ps_subset_sps->s_sps_data.i4_ofst_for_non_ref_pic = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_data.i4_ofst_for_top_to_bottom_field = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_data.u1_num_ref_frames_in_pic_order_cnt_cycle = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.u1_num_ref_frames_in_pic_order_cnt_cycle > MVC_MAX_REF_PICS) { return ERROR_INV_SPS_PPS_T; } for(i = 0; i < ps_subset_sps->s_sps_data.u1_num_ref_frames_in_pic_order_cnt_cycle; i++) { ps_subset_sps->s_sps_data.i4_ofst_for_ref_frame[i] = ih264d_sev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } } ps_subset_sps->s_sps_data.u1_num_ref_frames = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if((ps_subset_sps->s_sps_data.u1_num_ref_frames > MVC_MAX_REF_PICS)) { return ERROR_NUM_REF; } ps_subset_sps->s_sps_data.u1_gaps_in_frame_num_value_allowed_flag = ih264d_get_bit_h264(ps_bitstrm); ps_subset_sps->s_sps_data.u2_frm_wd_in_mbs = 1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.u2_frm_wd_in_mbs > (H264_MAX_FRAME_WIDTH >> 4)) { return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED; } ps_subset_sps->s_sps_data.u2_frm_ht_in_mbs = 1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(ps_subset_sps->s_sps_data.u2_frm_ht_in_mbs > (H264_MAX_FRAME_HEIGHT >> 4)) { return IVD_STREAM_WIDTH_HEIGHT_NOT_SUPPORTED; } ps_subset_sps->s_sps_data.u2_max_mb_addr = ps_subset_sps->s_sps_data.u2_frm_wd_in_mbs * ps_subset_sps->s_sps_data.u2_frm_ht_in_mbs - 1; ps_subset_sps->s_sps_data.u2_total_num_of_mbs = ps_subset_sps->s_sps_data.u2_max_mb_addr + 1; ps_subset_sps->s_sps_data.u1_frame_mbs_only_flag = ih264d_get_bit_h264(ps_bitstrm); if(!ps_subset_sps->s_sps_data.u1_frame_mbs_only_flag) { return ERROR_FEATURE_UNAVAIL; } ps_subset_sps->s_sps_data.u1_mb_aff_flag = 0; ps_subset_sps->s_sps_data.u1_direct_8x8_inference_flag = ih264d_get_bit_h264(ps_bitstrm); /* Frame cropping flag */ u4_temp = ih264d_get_bit_h264(ps_bitstrm); if(u4_temp) { ps_subset_sps->s_disp_offsets.u2_left_offset = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_disp_offsets.u2_right_offset = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_disp_offsets.u2_top_offset = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_disp_offsets.u2_bottom_offset = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } else { memset(&ps_subset_sps->s_disp_offsets, 0, sizeof(ps_subset_sps->s_disp_offsets)); } if(ps_sps->u2_frm_wd_in_mbs != ps_subset_sps->s_sps_data.u2_frm_wd_in_mbs) { ps_view_ctxt->u1_res_changed = 1; return IVD_RES_CHANGED; } if(ps_sps->u2_frm_ht_in_mbs != ps_subset_sps->s_sps_data.u2_frm_ht_in_mbs) { ps_view_ctxt->u1_res_changed = 1; return IVD_RES_CHANGED; } if(ps_view_ctxt->u2_disp_width != (ps_subset_sps->s_sps_data.u2_frm_wd_in_mbs * MB_SIZE - ps_subset_sps->s_disp_offsets.u2_left_offset - ps_subset_sps->s_disp_offsets.u2_right_offset)) { ps_view_ctxt->u1_res_changed = 1; return IVD_RES_CHANGED; } if(ps_view_ctxt->u2_disp_height != (ps_subset_sps->s_sps_data.u2_frm_ht_in_mbs * MB_SIZE - ps_subset_sps->s_disp_offsets.u2_top_offset - ps_subset_sps->s_disp_offsets.u2_bottom_offset)) { ps_view_ctxt->u1_res_changed = 1; return IVD_RES_CHANGED; } ps_subset_sps->s_sps_data.u1_vui_parameters_present_flag = ih264d_get_bit_h264(ps_bitstrm); if(ps_subset_sps->s_sps_data.u1_vui_parameters_present_flag) { i4_error_code = ih264d_parse_vui_parametres(&ps_subset_sps->s_sps_data.s_vui, ps_bitstrm); if(i4_error_code != OK) { return i4_error_code; } if(ps_subset_sps->s_sps_data.s_vui.u1_bitstream_restriction_flag && (ps_sps->s_vui.u4_num_reorder_frames != ps_subset_sps->s_sps_data.s_vui.u4_num_reorder_frames)) { ps_view_ctxt->u1_res_changed = 1; return IVD_RES_CHANGED; } } if(ih264d_get_bit_h264(ps_bitstrm) != 1) { return ERROR_INV_SPS_PPS_T; } u2_num_views_m1 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); if(u2_num_views_m1 >= MAX_NUM_VIEWS) { return ERROR_INVALID_SEQ_PARAM; } ps_subset_sps->s_sps_mvc_ext.u2_num_views = 1 + u2_num_views_m1; if(ps_view_ctxt->i4_decode_header) { ps_mvcd_ctxt->u2_num_views = MAX(ps_mvcd_ctxt->u2_num_views, 1 + u2_num_views_m1); } else if(ps_mvcd_ctxt->u2_num_views != (1 + u2_num_views_m1)) { return ERROR_INVALID_SEQ_PARAM; } for(i = 0; i <= u2_num_views_m1; i++) { ps_subset_sps->s_sps_mvc_ext.au2_view_ids[i] = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } for(i = 0; i < 2; i++) { ps_subset_sps->s_sps_mvc_ext.as_anchor_ref_data[i][0].u1_num_refs = 0; ps_subset_sps->s_sps_mvc_ext.as_non_anchor_ref_data[i][0].u1_num_refs = 0; } for(i = 1; i <= u2_num_views_m1; i++) { u1_num_refs = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.as_anchor_ref_data[0][i].u1_num_refs = u1_num_refs; if(u1_num_refs > MAX_NUM_IVP_REFS) { return ERROR_INVALID_SEQ_PARAM; } for(j = 0; j < u1_num_refs; j++) { ps_subset_sps->s_sps_mvc_ext.as_anchor_ref_data[0][i].au2_ref_view_ids[j] = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } u1_num_refs = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.as_anchor_ref_data[1][i].u1_num_refs = u1_num_refs; if(u1_num_refs > MAX_NUM_IVP_REFS) { return ERROR_INVALID_SEQ_PARAM; } for(j = 0; j < u1_num_refs; j++) { ps_subset_sps->s_sps_mvc_ext.as_anchor_ref_data[1][i].au2_ref_view_ids[j] = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } } for(i = 1; i <= u2_num_views_m1; i++) { u1_num_refs = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.as_non_anchor_ref_data[0][i].u1_num_refs = u1_num_refs; if(u1_num_refs > MAX_NUM_IVP_REFS) { return ERROR_INVALID_SEQ_PARAM; } for(j = 0; j < u1_num_refs; j++) { ps_subset_sps->s_sps_mvc_ext.as_non_anchor_ref_data[0][i].au2_ref_view_ids[j] = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } u1_num_refs = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.as_non_anchor_ref_data[1][i].u1_num_refs = u1_num_refs; if(u1_num_refs > MAX_NUM_IVP_REFS) { return ERROR_INVALID_SEQ_PARAM; } for(j = 0; j < u1_num_refs; j++) { ps_subset_sps->s_sps_mvc_ext.as_non_anchor_ref_data[1][i].au2_ref_view_ids[j] = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } } u1_num_level_values_signalled_m1 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.u1_num_level_values_signalled = u1_num_level_values_signalled_m1 + 1; if(u1_num_level_values_signalled_m1 >= MAX_NUM_LEVEL_VALUES_SIGNALLED) { return ERROR_INVALID_SEQ_PARAM; } for(i = 0; i <= u1_num_level_values_signalled_m1; i++) { ps_subset_sps->s_sps_mvc_ext.as_mvc_level_info[i].u4_level_idc = ih264d_get_bits_h264(ps_bitstrm, 8); u2_num_ops_m1 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.as_mvc_level_info->as_mvc_op_data[i].u2_num_ops = 1 + u2_num_ops_m1; if(u2_num_ops_m1 >= MAX_NUM_OPERATING_POINTS) { return ERROR_INVALID_SEQ_PARAM; } for(j = 0; j <= u2_num_ops_m1; j++) { UWORD16 u2_num_target_views_m1; ps_subset_sps->s_sps_mvc_ext.as_mvc_level_info->as_mvc_op_data[j].u1_temporal_id = ih264d_get_bits_h264(ps_bitstrm, 3); u2_num_target_views_m1 = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); ps_subset_sps->s_sps_mvc_ext.as_mvc_level_info->as_mvc_op_data[j].u2_num_target_views = 1 + u2_num_target_views_m1; if(u2_num_target_views_m1 >= MAX_NUM_VIEWS) { return ERROR_INVALID_SEQ_PARAM; } for(k = 0; k <= u2_num_target_views_m1; k++) { ps_subset_sps->s_sps_mvc_ext.as_mvc_level_info->as_mvc_op_data[j] .au2_target_view_ids[k] = ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } ps_subset_sps->s_sps_mvc_ext.as_mvc_level_info->as_mvc_op_data[j].u2_num_views = (UWORD16) 1 + ih264d_uev(pu4_bitstrm_ofst, pu4_bitstrm_buf); } } ps_subset_sps->u1_mvc_vui_parameters_present_flag = ih264d_get_bit_h264(ps_bitstrm); if(ps_subset_sps->u1_mvc_vui_parameters_present_flag) { return ERROR_INV_SPS_PPS_T; } /* In case bitstream read has exceeded the filled size, then return an error */ if(EXCEED_OFFSET(ps_bitstrm)) { return ERROR_INV_SPS_PPS_T; } ps_subset_sps->s_sps_data.u1_is_valid = 1; /* This ensures PPS has valid data in SPS array for reference */ ps_view_ctxt->ps_sps[ps_subset_sps->s_sps_data.u1_seq_parameter_set_id] = ps_subset_sps->s_sps_data; ps_mvcd_ctxt->u1_num_subset_sps++; return OK; } /* This function removes emulation byte "0x03" from bitstream(EBSP to RBSP). It also converts bytestream format into 32 bit little - endian format. */ static WORD32 imvcd_transform_nalu(dec_bit_stream_t *ps_bitstrm, UWORD8 *pu1_nal_unit, UWORD32 u4_numbytes_in_nal_unit) { UWORD32 ui4_word; UWORD8 u1_cur_byte; static const UWORD32 u4_num_bytes_in_word = sizeof(ui4_word) / sizeof(u1_cur_byte); UWORD32 u4_num_bytes_in_rbsp = 0; WORD32 i = 0, j; WORD8 c_count = 0; UWORD32 *puc_bitstream_buffer = (UWORD32 *) pu1_nal_unit; UWORD8 u1_nal_header_size = 1; UWORD8 u1_num_bytes_copied = 0; ps_bitstrm->pu4_buffer = puc_bitstream_buffer; ui4_word = *pu1_nal_unit++; u1_num_bytes_copied++; if((NAL_UNIT_TYPE(ui4_word) == PREFIX_NAL) || (NAL_UNIT_TYPE(ui4_word) == CODED_SLICE_EXTENSION)) { u1_nal_header_size += 3; } for(j = 0; j < 2; j++) { u1_cur_byte = *pu1_nal_unit++; ui4_word = ((ui4_word << 8) | u1_cur_byte); u1_num_bytes_copied++; c_count++; u4_num_bytes_in_rbsp++; if(u1_cur_byte != 0x00) { c_count = 0; } } if(u4_numbytes_in_nal_unit > 2) { i = ((u4_numbytes_in_nal_unit - 3)); } for(; i > 8; i -= 4) { // loop 0 u1_cur_byte = *pu1_nal_unit++; if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE && u1_cur_byte == EMULATION_PREVENTION_BYTE) { c_count = 0; u1_cur_byte = *pu1_nal_unit++; i--; } ui4_word = ((ui4_word << 8) | u1_cur_byte); u1_num_bytes_copied++; if(u4_num_bytes_in_word == u1_num_bytes_copied) { *puc_bitstream_buffer = ui4_word; puc_bitstream_buffer++; u1_num_bytes_copied = 0; } c_count++; if(u1_cur_byte != 0x00) c_count = 0; // loop 1 u1_cur_byte = *pu1_nal_unit++; if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE && u1_cur_byte == EMULATION_PREVENTION_BYTE) { c_count = 0; u1_cur_byte = *pu1_nal_unit++; i--; } ui4_word = ((ui4_word << 8) | u1_cur_byte); u1_num_bytes_copied++; if(u4_num_bytes_in_word == u1_num_bytes_copied) { *puc_bitstream_buffer = ui4_word; puc_bitstream_buffer++; u1_num_bytes_copied = 0; } c_count++; if(u1_cur_byte != 0x00) c_count = 0; // loop 2 u1_cur_byte = *pu1_nal_unit++; if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE && u1_cur_byte == EMULATION_PREVENTION_BYTE) { c_count = 0; u1_cur_byte = *pu1_nal_unit++; i--; } ui4_word = ((ui4_word << 8) | u1_cur_byte); u1_num_bytes_copied++; if(u4_num_bytes_in_word == u1_num_bytes_copied) { *puc_bitstream_buffer = ui4_word; puc_bitstream_buffer++; u1_num_bytes_copied = 0; } c_count++; if(u1_cur_byte != 0x00) c_count = 0; // loop 3 u1_cur_byte = *pu1_nal_unit++; if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE && u1_cur_byte == EMULATION_PREVENTION_BYTE) { c_count = 0; u1_cur_byte = *pu1_nal_unit++; i--; } ui4_word = ((ui4_word << 8) | u1_cur_byte); u1_num_bytes_copied++; if(u4_num_bytes_in_word == u1_num_bytes_copied) { *puc_bitstream_buffer = ui4_word; puc_bitstream_buffer++; u1_num_bytes_copied = 0; } c_count++; if(u1_cur_byte != 0x00) c_count = 0; u4_num_bytes_in_rbsp += 4; } for(; i > 0; i--) { u1_cur_byte = *pu1_nal_unit++; if(c_count == NUM_OF_ZERO_BYTES_BEFORE_START_CODE && u1_cur_byte == EMULATION_PREVENTION_BYTE) { c_count = 0; i--; u1_cur_byte = *pu1_nal_unit++; } ui4_word = ((ui4_word << 8) | u1_cur_byte); u4_num_bytes_in_rbsp++; if((u4_num_bytes_in_rbsp & 0x03) == 0x03) { *puc_bitstream_buffer = ui4_word; puc_bitstream_buffer++; } c_count++; if(u1_cur_byte != 0x00) c_count = 0; } *puc_bitstream_buffer = (ui4_word << ((3 - (((u4_num_bytes_in_rbsp << 30) >> 30))) << 3)); ps_bitstrm->u4_ofst = 0; ps_bitstrm->u4_max_ofst = ((u4_num_bytes_in_rbsp + u1_nal_header_size) << 3); return (u4_num_bytes_in_rbsp); } WORD32 imvcd_nalu_parser(mvc_dec_ctxt_t *ps_mvcd_ctxt, UWORD8 *pu1_bitstream_buf, UWORD32 i4_nalu_length) { AVC_EXT_NALU_ID_T e_nalu_id; UWORD8 u1_first_byte; dec_struct_t *ps_view_ctxt = &ps_mvcd_ctxt->s_view_dec_ctxt; dec_bit_stream_t *ps_bitstrm = ps_view_ctxt->ps_bitstrm; WORD32 i4_error_code = NOT_OK; if((NULL != pu1_bitstream_buf) && (i4_nalu_length > 0)) { imvcd_transform_nalu(ps_bitstrm, pu1_bitstream_buf, i4_nalu_length); u1_first_byte = ih264d_get_bits_h264(ps_bitstrm, 8); if(NAL_FORBIDDEN_BIT(u1_first_byte)) { return NOT_OK; } e_nalu_id = NAL_UNIT_TYPE(u1_first_byte); ps_view_ctxt->u1_nal_unit_type = e_nalu_id; // if any other nal unit other than slice nal is encountered in between a // frame break out of loop without consuming header if((ps_view_ctxt->u4_slice_start_code_found == 1) && (ps_view_ctxt->u1_pic_decode_done != 1) && is_slice_nalu_type(e_nalu_id)) { return ERROR_INCOMPLETE_FRAME; } switch(e_nalu_id) { case PREFIX_NAL: { if(!ps_view_ctxt->i4_decode_header) { if(1 == ih264d_get_bit_h264(ps_bitstrm)) { return IVD_INVALID_BITSTREAM; } i4_error_code = imvcd_nalu_mvc_ext_parser(ps_mvcd_ctxt, ps_bitstrm); if(i4_error_code != OK) { return i4_error_code; } } break; } case SUBSET_SPS: { ih264d_rbsp_to_sodb(ps_view_ctxt->ps_bitstrm); i4_error_code = imvcd_parse_subset_sps(ps_mvcd_ctxt, ps_bitstrm); if(OK != i4_error_code) { return i4_error_code; } ps_view_ctxt->i4_header_decoded |= 1 << SUBSET_SPS; break; } case SLICE_NON_IDR: case SLICE_IDR: { if(!ps_view_ctxt->i4_decode_header) { if(is_header_decoded(ps_view_ctxt->i4_header_decoded, SPS) && is_header_decoded(ps_view_ctxt->i4_header_decoded, PPS)) { nalu_mvc_ext_t *ps_nalu_mvc_ext = imvcd_get_cur_nalu_mvc_ext(ps_mvcd_ctxt); ps_view_ctxt->u4_slice_start_code_found = 1; if((0 == ps_mvcd_ctxt->u2_num_views_decoded) && !ps_nalu_mvc_ext->u1_inter_view_flag) { ps_nalu_mvc_ext->u1_inter_view_flag = 1; } ih264d_rbsp_to_sodb(ps_view_ctxt->ps_bitstrm); i4_error_code = imvcd_parse_decode_slice(ps_mvcd_ctxt); if(i4_error_code != OK) { return i4_error_code; } } else { return IVD_INVALID_BITSTREAM; } } break; } case CODED_SLICE_EXTENSION: { if(!ps_view_ctxt->i4_decode_header) { if(is_header_decoded(ps_view_ctxt->i4_header_decoded, SPS) && is_header_decoded(ps_view_ctxt->i4_header_decoded, PPS) && is_header_decoded(ps_view_ctxt->i4_header_decoded, SUBSET_SPS)) { ps_view_ctxt->u4_slice_start_code_found = 1; if(1 == ih264d_get_bit_h264(ps_bitstrm)) { return IVD_INVALID_BITSTREAM; } i4_error_code = imvcd_nalu_mvc_ext_parser(ps_mvcd_ctxt, ps_bitstrm); if(i4_error_code != OK) { return i4_error_code; } ih264d_rbsp_to_sodb(ps_view_ctxt->ps_bitstrm); i4_error_code = imvcd_parse_decode_slice(ps_mvcd_ctxt); if(i4_error_code != OK) { return i4_error_code; } } else { return IVD_INVALID_BITSTREAM; } } break; } default: { i4_error_code = ERROR_UNKNOWN_NAL; break; } } } return i4_error_code; }