From 5808089fce924a3218ed88fe4fa1c442a7ae3ebd Mon Sep 17 00:00:00 2001 From: Geoffrey McRae Date: Fri, 5 Jan 2018 21:36:26 +1100 Subject: [PATCH] [client] nal: added SLICE parser --- client/parsers/nal.c | 281 ++++++++++++++++++++++++++++++++++++++++--- client/parsers/nal.h | 63 +++++++++- 2 files changed, 324 insertions(+), 20 deletions(-) diff --git a/client/parsers/nal.c b/client/parsers/nal.c index a7e6eea1..1dae3282 100644 --- a/client/parsers/nal.c +++ b/client/parsers/nal.c @@ -50,6 +50,9 @@ struct NAL uint32_t pps_slice_groups_size; uint32_t * pps_slice_group_id; uint32_t pps_slice_group_id_size; + + bool slice_valid; + NAL_SLICE slice; }; bool nal_initialize(NAL * ptr) @@ -496,6 +499,68 @@ static bool parse_nal_pps(NAL this, const uint8_t * src, size_t size, size_t * c pps->constrained_intra_pred_flag = get_bit(src, offset); pps->redundant_pic_cnt_present_flag = get_bit(src, offset); + const bool extraData = get_bit(src, offset) == 0; + --*offset; + + if (extraData) + { + pps->transform_8x8_mode_flag = get_bit(src, offset); + pps->pic_scaling_matrix_present_flag = get_bit(src, offset); + if (pps->pic_scaling_matrix_present_flag) + { + } + pps->second_chroma_qp_index_offset = decode_s_golomb(src, offset); + } + +#ifdef DEBUG_NAL + DEBUG_INFO("PPS:\n" + "pic_parameter_set_id : %u\n" + "seq_parameter_set_id : %u\n" + "entropy_coding_mode_flag : %u\n" + "pic_order_present_flag : %u\n" + "num_slice_groups_minus1 : %u\n" + "slice_group_map_type : %u\n" + "slice_group_change_direction_flag : %u\n" + "slice_group_change_rate_minus1 : %u\n" + "pic_size_in_map_units_minus1 : %u\n" + "num_ref_idx_l0_active_minus1 : %u\n" + "num_ref_idx_l1_active_minus1 : %u\n" + "weighted_pred_flag : %u\n" + "weighted_bipred_idc : %u\n" + "pic_init_qp_minus26 : %d\n" + "pic_init_qs_minus26 : %d\n" + "chroma_qp_index_offset : %d\n" + "deblocking_filter_control_present_flag: %u\n" + "constrained_intra_pred_flag : %u\n" + "redundant_pic_cnt_present_flag : %u\n" + "transform_8x8_mode_flag : %u\n" + "pic_scaling_matrix_present_flag : %u\n" + "second_chroma_qp_index_offset : %u", + pps->pic_parameter_set_id, + pps->seq_parameter_set_id, + pps->entropy_coding_mode_flag, + pps->pic_order_present_flag, + pps->num_slice_groups_minus1, + pps->slice_group_map_type, + pps->slice_group_change_direction_flag, + pps->slice_group_change_rate_minus1, + pps->pic_size_in_map_units_minus1, + pps->num_ref_idx_l0_active_minus1, + pps->num_ref_idx_l1_active_minus1, + pps->weighted_pred_flag, + pps->weighted_bipred_idc, + pps->pic_init_qp_minus26, + pps->pic_init_qs_minus26, + pps->chroma_qp_index_offset, + pps->deblocking_filter_control_present_flag, + pps->constrained_intra_pred_flag, + pps->redundant_pic_cnt_present_flag, + pps->transform_8x8_mode_flag, + pps->pic_scaling_matrix_present_flag, + pps->second_chroma_qp_index_offset + ); +#endif + if (!parse_nal_trailing_bits(this, src, size, offset)) return false; @@ -503,23 +568,193 @@ static bool parse_nal_pps(NAL this, const uint8_t * src, size_t size, size_t * c return true; } +static bool parse_nal_ref_pic_list_reordering(NAL this, const uint8_t * src, size_t size, size_t * const offset) +{ + //TODO + return false; +} + +static bool parse_pred_weight_table(NAL this, const uint8_t * src, size_t size, size_t * const offset) +{ + //TODO + return false; +} + +static bool parse_dec_ref_pic_marking(NAL this, const uint8_t * src, size_t size, size_t * const offset) +{ + //TODO + return false; +} + +static bool parse_nal_coded_slice( + NAL this, + const uint8_t ref_idc, + const uint8_t ref_unit_type, + const uint8_t * src, + size_t size, + size_t * const offset +) +{ + if (!this->sps_valid || !this->pps_valid) + return false; + + NAL_SLICE * slice = &this->slice; + memset(slice, 0, sizeof(NAL_SLICE)); + + slice->first_mb_in_slice = decode_u_golomb(src, offset); + slice->slice_type = decode_u_golomb(src, offset); + slice->pic_parameter_set_id = decode_u_golomb(src, offset); + slice->frame_num = get_bits(src, offset, this->sps.log2_max_frame_num_minus4 + 4); + + if (!this->sps.frame_mbs_only_flag) + { + slice->field_pic_flag = get_bit(src, offset); + if (slice->field_pic_flag) + slice->bottom_field_flag = get_bit(src, offset); + } + + if (ref_unit_type == 5) + slice->idr_pic_id = decode_u_golomb(src, offset); + + if (this->sps.pic_order_cnt_type == 0) + { + slice->pic_order_cnt_lsb = get_bits(src, offset, this->sps.log2_max_pic_order_cnt_lsb_minus4 + 4); + if (this->pps.pic_order_present_flag && !slice->field_pic_flag) + slice->delta_pic_order_cnt_bottom = decode_s_golomb(src, offset); + } + else + if (this->sps.pic_order_cnt_type == 1 && !this->sps.delta_pic_order_always_zero_flag) + { + slice->delta_pic_order_cnt[0] = decode_s_golomb(src, offset); + if (this->pps.pic_order_present_flag && !slice->field_pic_flag) + slice->delta_pic_order_cnt[1] = decode_s_golomb(src, offset); + } + + if (this->pps.redundant_pic_cnt_present_flag) + slice->redundant_pic_cnt = decode_u_golomb(src, offset); + + if (slice->slice_type == NAL_SLICE_TYPE_B) + slice->direct_spatial_mv_pred_flag = get_bit(src, offset); + + if (slice->slice_type == NAL_SLICE_TYPE_P || + slice->slice_type == NAL_SLICE_TYPE_SP || + slice->slice_type == NAL_SLICE_TYPE_B) + { + slice->num_ref_idx_active_override_flag = get_bit(src, offset); + if (slice->num_ref_idx_active_override_flag) + { + slice->num_ref_idx_l0_active_minus1 = decode_u_golomb(src, offset); + if (slice->slice_type == NAL_SLICE_TYPE_B) + slice->num_ref_idx_l1_active_minus1 = decode_u_golomb(src, offset); + } + } + + if (!parse_nal_ref_pic_list_reordering(this, src, size, offset)) + return false; + + if ((this->pps.weighted_pred_flag && (slice->slice_type == NAL_SLICE_TYPE_P || slice->slice_type == NAL_SLICE_TYPE_SP)) || + (this->pps.weighted_bipred_idc == 1 && slice->slice_type == NAL_SLICE_TYPE_B)) + { + if (!parse_pred_weight_table(this, src, size, offset)) + return false; + } + + if (ref_idc != 0) + if (!parse_dec_ref_pic_marking(this, src, size, offset)) + return false; + + if (this->pps.entropy_coding_mode_flag && slice->slice_type != NAL_SLICE_TYPE_I && slice->slice_type != NAL_SLICE_TYPE_SI) + slice->cabac_init_idc = decode_u_golomb(src, offset); + + slice->slice_qp_delta = decode_s_golomb(src, offset); + + if (slice->slice_type == NAL_SLICE_TYPE_SP || slice->slice_type == NAL_SLICE_TYPE_SI) + { + if (slice->slice_type == NAL_SLICE_TYPE_SP) + slice->sp_for_switch_flag = get_bit(src, offset); + slice->slice_qs_delta = decode_s_golomb(src, offset); + } + + if (this->pps.deblocking_filter_control_present_flag) + { + slice->disable_deblocking_filter_idc = decode_u_golomb(src, offset); + if (slice->disable_deblocking_filter_idc != 1) + { + slice->slice_alpha_c0_offset_div2 = decode_s_golomb(src, offset); + slice->slice_beta_offset_div2 = decode_s_golomb(src, offset); + } + } + + if (this->pps.num_slice_groups_minus1 > 0 && this->pps.slice_group_map_type >= 3 && this->pps.slice_group_map_type <= 5) + slice->slice_group_change_cycle = decode_u_golomb(src, offset); + +#ifdef DEBUG_NAL + DEBUG_INFO("SLICE:\n" + "first_mb_in_slice : %u\n" + "slice_type : %u\n" + "pic_parameter_set_id : %u\n" + "frame_num : %u\n" + "field_pic_flag : %u\n" + "bottom_field_flag : %u\n" + "idr_pic_id : %u\n" + "pic_order_cnt_lsb : %u\n" + "delta_pic_order_cnt_bottom : %d\n" + "delta_pic_order_cnt[0] : %d\n" + "delta_pic_order_cnt[1] : %d\n" + "redundant_pic_cnt : %u\n" + "direct_spatial_mv_pred_flag : %u\n" + "num_ref_idx_active_override_flag: %u\n" + "num_ref_idx_l0_active_minus1 : %u\n" + "num_ref_idx_l1_active_minus1 : %u", + slice->first_mb_in_slice, + slice->slice_type, + slice->pic_parameter_set_id, + slice->frame_num, + slice->field_pic_flag, + slice->bottom_field_flag, + slice->idr_pic_id, + slice->pic_order_cnt_lsb, + slice->delta_pic_order_cnt_bottom, + slice->delta_pic_order_cnt[0], + slice->delta_pic_order_cnt[1], + slice->redundant_pic_cnt, + slice->direct_spatial_mv_pred_flag, + slice->num_ref_idx_active_override_flag, + slice->num_ref_idx_l0_active_minus1, + slice->num_ref_idx_l1_active_minus1 + ); +#endif + + if (!parse_nal_trailing_bits(this, src, size, offset)) + return false; + + this->slice_valid = true; + return true; +} + bool nal_parse(NAL this, const uint8_t * src, size_t size) { +#ifdef DEBUG_NAL static FILE * fd = NULL; if (!fd) fd = fopen("/tmp/stream.h264", "w"); fwrite(src, size, 1, fd); + fflush(fd); +#endif - const size_t bits = size << 4; - size_t offset = 0; - while(offset < bits) + for(size_t i = 0; i < size - 4; ++i) { - // look for the start header - if (get_bits(src, &offset, 32) != 1) - { - offset -= 24; + if (src[i++] != 0 || src[i++] != 0) continue; - } + + if (src[i] == 0) + ++i; + + if (src[i++] != 1) + continue; + + size_t offset = i << 3; + DEBUG_INFO("nal @ %lu (%lu)", i, offset); // ensure the forbidden zero bit is not set if (get_bit(src, &offset) != 0) @@ -528,12 +763,19 @@ bool nal_parse(NAL this, const uint8_t * src, size_t size) return false; } - uint8_t nal_ref_idc = get_bits(src, &offset, 2); - uint8_t nal_ref_unit_type = get_bits(src, &offset, 5); - DEBUG_INFO("ref idc: %d, ref unit type: %d", nal_ref_idc, nal_ref_unit_type); + uint8_t ref_idc = get_bits(src, &offset, 2); + uint8_t ref_unit_type = get_bits(src, &offset, 5); + DEBUG_INFO("ref idc: %d, ref unit type: %d", ref_idc, ref_unit_type); - switch(nal_ref_unit_type) + switch(ref_unit_type) { + case NAL_TYPE_CODED_SLICE_IDR: + case NAL_TYPE_CODED_SLICE_NON_IDR: + case NAL_TYPE_CODED_SLICE_AUX: + if (!parse_nal_coded_slice(this, ref_idc, ref_unit_type, src, size, &offset)) + return false; + break; + case NAL_TYPE_AUD: { this->primary_pic_type = get_bits(src, &offset, 3); @@ -554,14 +796,14 @@ bool nal_parse(NAL this, const uint8_t * src, size_t size) break; default: - DEBUG_ERROR("Unknown NAL ref unit type: %d", nal_ref_unit_type); + DEBUG_ERROR("Unknown NAL ref unit type: %d", ref_unit_type); return false; } - // byte align - offset = (offset + 0x7) & ~0x7; + i = offset >> 3; } + DEBUG_INFO("return"); return true; } @@ -588,4 +830,13 @@ bool nal_get_pps(NAL this, const NAL_PPS ** pps) *pps = &this->pps; return true; +} + +bool nal_get_slice(NAL this, const NAL_SLICE ** slice) +{ + if (!this->slice_valid) + return false; + + *slice = &this->slice; + return true; } \ No newline at end of file diff --git a/client/parsers/nal.h b/client/parsers/nal.h index 5a20ea98..938f5c0e 100644 --- a/client/parsers/nal.h +++ b/client/parsers/nal.h @@ -21,9 +21,17 @@ Place, Suite 330, Boston, MA 02111-1307 USA #include #include -#define NAL_TYPE_SPS 7 -#define NAL_TYPE_PPS 8 -#define NAL_TYPE_AUD 9 +#define NAL_TYPE_CODED_SLICE_NON_IDR 1 +#define NAL_TYPE_CODED_SLICE_DATA_PARTITION_A 2 +#define NAL_TYPE_CODED_SLICE_DATA_PARTITION_B 3 +#define NAL_TYPE_CODED_SLICE_DATA_PARTITION_C 4 +#define NAL_TYPE_CODED_SLICE_IDR 5 +#define NAL_TYPE_SPS 7 +#define NAL_TYPE_PPS 8 +#define NAL_TYPE_AUD 9 +#define NAL_TYPE_END_OF_SEQUENCE 10 +#define NAL_TYPE_END_OF_STREAM 11 +#define NAL_TYPE_CODED_SLICE_AUX 19 #define IDC_PROFILE_BASELINE 66 #define IDC_PROFILE_MAIN 77 @@ -45,6 +53,12 @@ Place, Suite 330, Boston, MA 02111-1307 USA #define NAL_PICTURE_TYPE_P 1 #define NAL_PICTURE_TYPE_B 2 +#define NAL_SLICE_TYPE_P 0 +#define NAL_SLICE_TYPE_B 1 +#define NAL_SLICE_TYPE_I 2 +#define NAL_SLICE_TYPE_SP 3 +#define NAL_SLICE_TYPE_SI 4 + typedef struct NAL_SPS { uint8_t profile_idc; @@ -186,9 +200,47 @@ typedef struct NAL_PPS uint8_t deblocking_filter_control_present_flag; uint8_t constrained_intra_pred_flag; uint8_t redundant_pic_cnt_present_flag; + + uint8_t transform_8x8_mode_flag; + uint8_t pic_scaling_matrix_present_flag; + uint8_t pic_scaling_list_present_flag[6]; + int32_t scaling_list_4x4[6]; + int32_t scaling_list_8x8[2]; + int32_t second_chroma_qp_index_offset; } NAL_PPS; +typedef struct NAL_SLICE +{ + uint32_t first_mb_in_slice; + uint32_t slice_type; + uint32_t pic_parameter_set_id; + uint32_t frame_num; + uint8_t field_pic_flag; + uint8_t bottom_field_flag; + uint32_t idr_pic_id; + uint32_t pic_order_cnt_lsb; + int32_t delta_pic_order_cnt_bottom; + int32_t delta_pic_order_cnt[2]; + uint32_t redundant_pic_cnt; + uint8_t direct_spatial_mv_pred_flag; + uint8_t num_ref_idx_active_override_flag; + uint32_t num_ref_idx_l0_active_minus1; + uint32_t num_ref_idx_l1_active_minus1; + //ref_pic_list_reordering + //pred_weight_table + //dec_ref_pic_marking + uint32_t cabac_init_idc; + int32_t slice_qp_delta; + uint8_t sp_for_switch_flag; + int32_t slice_qs_delta; + uint32_t disable_deblocking_filter_idc; + int32_t slice_alpha_c0_offset_div2; + int32_t slice_beta_offset_div2; + uint32_t slice_group_change_cycle; +} +NAL_SLICE; + typedef struct NAL * NAL; bool nal_initialize (NAL * ptr); @@ -196,5 +248,6 @@ void nal_deinitialize(NAL this ); bool nal_parse (NAL this, const uint8_t * src, size_t size); bool nal_get_primary_picture_type(NAL this, uint8_t * pic_type); -bool nal_get_sps(NAL this, const NAL_SPS ** sps); -bool nal_get_pps(NAL this, const NAL_PPS ** pps); \ No newline at end of file +bool nal_get_sps (NAL this, const NAL_SPS ** sps ); +bool nal_get_pps (NAL this, const NAL_PPS ** pps ); +bool nal_get_slice(NAL this, const NAL_SLICE ** slice); \ No newline at end of file