diff --git a/src/parser/avc_defines.h b/src/parser/avc_defines.h index 43eef3e551..5bb13eeb3a 100644 --- a/src/parser/avc_defines.h +++ b/src/parser/avc_defines.h @@ -37,6 +37,8 @@ THE SOFTWARE. #define AVC_MACRO_BLOCK_SIZE 16 +#define NO_LONG_TERM_FRAME_INDICES -1 + // AVC spec. Table 7-1 – NAL unit type codes, syntax element categories, and NAL unit type classes. enum AvcNalUnitType { kAvcNalTypeUnspecified = 0, diff --git a/src/parser/avc_parser.cpp b/src/parser/avc_parser.cpp index a9bb26cd3b..dda123d977 100644 --- a/src/parser/avc_parser.cpp +++ b/src/parser/avc_parser.cpp @@ -33,7 +33,7 @@ AvcVideoParser::AvcVideoParser() { curr_has_mmco_5_ = 0; prev_ref_pic_bottom_field_ = 0; curr_ref_pic_bottom_field_ = 0; - max_long_term_frame_idx_ = 0; + max_long_term_frame_idx_ = NO_LONG_TERM_FRAME_INDICES; slice_info_list_.assign(INIT_SLICE_LIST_NUM, {0}); slice_param_list_.assign(INIT_SLICE_LIST_NUM, {0}); @@ -200,10 +200,8 @@ ParserResult AvcVideoParser::ParsePictureData(const uint8_t *p_stream, uint32_t ParserResult ret2; // Reference picture lists construction (8.2.4) - if (p_slice_header->slice_type != kAvcSliceTypeI && p_slice_header->slice_type != kAvcSliceTypeSI && p_slice_header->slice_type != kAvcSliceTypeI_7 && p_slice_header->slice_type != kAvcSliceTypeSI_9) { - if ((ret2 = SetupReflist(&slice_info_list_[num_slices_])) != PARSER_OK) { - return ret2; - } + if ((ret2 = SetupReflist(&slice_info_list_[num_slices_])) != PARSER_OK) { + return ret2; } if (num_slices_ == 0) { @@ -383,6 +381,24 @@ void AvcVideoParser::SendSeiMsgPayload() { if (pfn_get_sei_message_cb_) pfn_get_sei_message_cb_(parser_params_.user_data, &sei_message_info_params_); } +static const int diag_scan_4x4[16] = { + 0, 1, 4, 8, + 5, 2, 3, 6, + 9, 12, 13, 10, + 7, 11, 14, 15 +}; + +static const int diag_scan_8x8[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + ParserResult AvcVideoParser::SendPicForDecode() { int i, j; AvcSeqParameterSet *p_sps = &sps_list_[active_sps_id_]; @@ -518,37 +534,46 @@ ParserResult AvcVideoParser::SendPicForDecode() { p_slice_param->chroma_log2_weight_denom = p_slice_header->pred_weight_table.chroma_log2_weight_denom; // Ref lists - for (i = 0; i < dpb_buffer_.num_short_term + dpb_buffer_.num_long_term; i++) { - AvcPicture *p_ref_pic = &p_slice_info->ref_list_0_[i]; - if (p_ref_pic->is_reference != kUnusedForReference) { - p_slice_param->ref_pic_list_0[i].pic_idx = p_ref_pic->pic_idx; - if ( p_ref_pic->is_reference == kUsedForLongTerm) { - p_slice_param->ref_pic_list_0[i].frame_idx = p_ref_pic->long_term_pic_num; - } else { - p_slice_param->ref_pic_list_0[i].frame_idx = p_ref_pic->frame_num; + for (j = 0; j < 32; j++) { + p_slice_param->ref_pic_list_0[j].pic_idx = 0xFF; + p_slice_param->ref_pic_list_1[j].pic_idx = 0xFF; + } + + if (p_slice_header->slice_type == kAvcSliceTypeP || p_slice_header->slice_type == kAvcSliceTypeP_5 || p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6) { + for (i = 0; i <= p_slice_info->slice_header.num_ref_idx_l0_active_minus1; i++) { + AvcPicture *p_ref_pic = &p_slice_info->ref_list_0_[i]; + if (p_ref_pic->is_reference != kUnusedForReference) { + p_slice_param->ref_pic_list_0[i].pic_idx = p_ref_pic->pic_idx; + if ( p_ref_pic->is_reference == kUsedForLongTerm) { + p_slice_param->ref_pic_list_0[i].frame_idx = p_ref_pic->long_term_pic_num; + } else { + p_slice_param->ref_pic_list_0[i].frame_idx = p_ref_pic->frame_num; + } + p_slice_param->ref_pic_list_0[i].flags = 0; + if (p_ref_pic->pic_structure != kFrame) { + p_slice_param->ref_pic_list_0[i].flags |= p_ref_pic->pic_structure == kBottomField ? RocdecAvcPicture_FLAGS_BOTTOM_FIELD : RocdecAvcPicture_FLAGS_TOP_FIELD; + } + p_slice_param->ref_pic_list_0[i].flags |= p_ref_pic->is_reference == kUsedForShortTerm ? RocdecAvcPicture_FLAGS_SHORT_TERM_REFERENCE : RocdecAvcPicture_FLAGS_LONG_TERM_REFERENCE; } - p_slice_param->ref_pic_list_0[i].flags = 0; - if (p_ref_pic->pic_structure != kFrame) { - p_slice_param->ref_pic_list_0[i].flags |= p_ref_pic->pic_structure == kBottomField ? RocdecAvcPicture_FLAGS_BOTTOM_FIELD : RocdecAvcPicture_FLAGS_TOP_FIELD; - } - p_slice_param->ref_pic_list_0[i].flags |= p_ref_pic->is_reference == kUsedForShortTerm ? RocdecAvcPicture_FLAGS_SHORT_TERM_REFERENCE : RocdecAvcPicture_FLAGS_LONG_TERM_REFERENCE; } } if (p_slice_header->slice_type == kAvcSliceTypeB || p_slice_header->slice_type == kAvcSliceTypeB_6 ) { - AvcPicture *p_ref_pic = &p_slice_info->ref_list_1_[i]; - if (p_ref_pic->is_reference != kUnusedForReference) { - p_slice_param->ref_pic_list_1[i].pic_idx = p_ref_pic->pic_idx; - if ( p_ref_pic->is_reference == kUsedForLongTerm) { - p_slice_param->ref_pic_list_1[i].frame_idx = p_ref_pic->long_term_pic_num; - } else { - p_slice_param->ref_pic_list_1[i].frame_idx = p_ref_pic->frame_num; + for (i = 0; i <= p_slice_info->slice_header.num_ref_idx_l1_active_minus1; i++) { + AvcPicture *p_ref_pic = &p_slice_info->ref_list_1_[i]; + if (p_ref_pic->is_reference != kUnusedForReference) { + p_slice_param->ref_pic_list_1[i].pic_idx = p_ref_pic->pic_idx; + if ( p_ref_pic->is_reference == kUsedForLongTerm) { + p_slice_param->ref_pic_list_1[i].frame_idx = p_ref_pic->long_term_pic_num; + } else { + p_slice_param->ref_pic_list_1[i].frame_idx = p_ref_pic->frame_num; + } + p_slice_param->ref_pic_list_1[i].flags = 0; + if (p_ref_pic->pic_structure != kFrame) { + p_slice_param->ref_pic_list_1[i].flags |= p_ref_pic->pic_structure == kBottomField ? RocdecAvcPicture_FLAGS_BOTTOM_FIELD : RocdecAvcPicture_FLAGS_TOP_FIELD; + } + p_slice_param->ref_pic_list_1[i].flags |= p_ref_pic->is_reference == kUsedForShortTerm ? RocdecAvcPicture_FLAGS_SHORT_TERM_REFERENCE : RocdecAvcPicture_FLAGS_LONG_TERM_REFERENCE; } - p_slice_param->ref_pic_list_1[i].flags = 0; - if (p_ref_pic->pic_structure != kFrame) { - p_slice_param->ref_pic_list_1[i].flags |= p_ref_pic->pic_structure == kBottomField ? RocdecAvcPicture_FLAGS_BOTTOM_FIELD : RocdecAvcPicture_FLAGS_TOP_FIELD; - } - p_slice_param->ref_pic_list_1[i].flags |= p_ref_pic->is_reference == kUsedForShortTerm ? RocdecAvcPicture_FLAGS_SHORT_TERM_REFERENCE : RocdecAvcPicture_FLAGS_LONG_TERM_REFERENCE; } } @@ -591,12 +616,12 @@ ParserResult AvcVideoParser::SendPicForDecode() { RocdecAvcIQMatrix *p_iq_matrix = &dec_pic_params_.iq_matrix.avc; for (i = 0; i < 6; i++) { for (j = 0; j < 16; j++) { - p_iq_matrix->scaling_list_4x4[i][j] = p_pps->scaling_list_4x4[i][j]; + p_iq_matrix->scaling_list_4x4[i][diag_scan_4x4[j]] = p_pps->scaling_list_4x4[i][j]; } } for (i = 0; i < 2; i++) { for (j = 0; j < 64; j++) { - p_iq_matrix->scaling_list_8x8[i][j] = p_pps->scaling_list_8x8[i][j]; + p_iq_matrix->scaling_list_8x8[i][diag_scan_8x8[j]] = p_pps->scaling_list_8x8[i][j]; } } @@ -1335,6 +1360,9 @@ ParserResult AvcVideoParser::ParseSliceHeader(uint8_t *p_stream, size_t stream_s p_slice_header->slice_group_change_cycle = Parser::ReadBits(p_stream, offset, size); } +#if DBGINFO + PrintSliceHeader(p_slice_header); +#endif // DBGINFO return PARSER_OK; } @@ -1749,7 +1777,6 @@ ParserResult AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) { p_ref_pic->pic_num = 2 * p_ref_pic->frame_num_wrap; // Eq. 8-31 } } else if (p_ref_pic->is_reference == kUsedForLongTerm) { - // Note: Todo: assign long_term_frame_idx in MarkDecodedRefPics() if (curr_pic_.pic_structure == kFrame) { p_ref_pic->long_term_pic_num = p_ref_pic->long_term_frame_idx; // Eq. 8-29 } else if (((curr_pic_.pic_structure == kTopField) && (p_ref_pic->pic_structure == kTopField)) || ((curr_pic_.pic_structure == kBottomField) && (p_ref_pic->pic_structure == kBottomField))) { @@ -1761,6 +1788,11 @@ ParserResult AvcVideoParser::SetupReflist(AvcSliceInfo *p_slice_info) { } } + if (p_slice_header->slice_type == kAvcSliceTypeI || p_slice_header->slice_type == kAvcSliceTypeSI || p_slice_header->slice_type == kAvcSliceTypeI_7 || p_slice_header->slice_type == kAvcSliceTypeSI_9) { + // We still need to do 8.2.4.1 above for I pictures but will not go furhter. + return PARSER_OK; + } + // 8.2.4.2 Initialisation process for reference picture lists if (p_slice_header->slice_type == kAvcSliceTypeP || p_slice_header->slice_type == kAvcSliceTypeP_5) { if (curr_pic_.pic_structure == kFrame) { // 8.2.4.2.1 @@ -1933,8 +1965,11 @@ ParserResult AvcVideoParser::ModifiyRefList(AvcPicture *ref_pic_list_x, AvcListM int pic_num_lx_pred = curr_pic_num; // picNumLXPred int max_frame_num = 1 << (p_sps->log2_max_frame_num_minus4 + 4); // MaxFrameNum int max_pic_num = p_slice_header->field_pic_flag ? 2 * max_frame_num : max_frame_num; + AvcPicture ref_pic_list_mod[AVC_MAX_REF_FRAME_NUM]; int i; + memcpy(ref_pic_list_mod, ref_pic_list_x, sizeof(AvcPicture) * num_ref_idx_lx_active); + while (p_list_mod->modification_of_pic_nums_idc != 3) { if (p_list_mod->modification_of_pic_nums_idc < 2) { // 8.2.4.3.1 Modification process of reference picture lists for short-term reference pictures @@ -1963,59 +1998,37 @@ ParserResult AvcVideoParser::ModifiyRefList(AvcPicture *ref_pic_list_x, AvcListM pic_num_lx = pic_num_lx_no_wrap; } // (8-37) - // Shift further - for (int c_idx = num_ref_idx_lx_active; c_idx > ref_idx_lx; c_idx--) { - ref_pic_list_x[c_idx] = ref_pic_list_x[c_idx - 1]; - } // Find short-term reference picture with PicNum equal to pic_num_lx - for (i = 0; i <= num_ref_idx_lx_active; i++) { + for (i = 0; i < num_ref_idx_lx_active; i++) { if (ref_pic_list_x[i].is_reference == kUsedForShortTerm && ref_pic_list_x[i].pic_num == pic_num_lx) { break; } } - if (i > num_ref_idx_lx_active) { + if (i == num_ref_idx_lx_active) { ERR("Could not find a short-term reference with the modified pic num."); return PARSER_OUT_OF_RANGE; } - ref_pic_list_x[ref_idx_lx] = ref_pic_list_x[i]; - ref_idx_lx++; - int n_idx = ref_idx_lx; - for (int c_idx = ref_idx_lx; c_idx <= num_ref_idx_lx_active; c_idx++) { - int pic_num_f = ref_pic_list_x[c_idx].is_reference == kUsedForShortTerm ? ref_pic_list_x[c_idx].pic_num : max_pic_num; - if ( pic_num_f != pic_num_lx) { - ref_pic_list_x[n_idx++] = ref_pic_list_x[c_idx]; - } - } + ref_pic_list_mod[ref_idx_lx] = ref_pic_list_x[i]; } else if (p_list_mod->modification_of_pic_nums_idc == 2) { // 8.2.4.3.2 Modification process of reference picture lists for long-term reference pictures // (8-38) - // Shift further - for (int c_idx = num_ref_idx_lx_active; c_idx > ref_idx_lx; c_idx--) { - ref_pic_list_x[c_idx] = ref_pic_list_x[c_idx - 1]; - } // Find long-term reference picture with LongTermPicNum equal to long_term_pic_num - for (i = 0; i <= num_ref_idx_lx_active; i++) { + for (i = 0; i < num_ref_idx_lx_active; i++) { if (ref_pic_list_x[i].is_reference == kUsedForLongTerm && ref_pic_list_x[i].long_term_pic_num == p_list_mod->long_term_pic_num) { break; } } - if (i > num_ref_idx_lx_active) { + if (i == num_ref_idx_lx_active) { ERR("Could not find long-term reference with the modified long term pic num."); return PARSER_OUT_OF_RANGE; } - ref_pic_list_x[ref_idx_lx] = ref_pic_list_x[i]; - ref_idx_lx++; - int n_idx = ref_idx_lx; - for (int c_idx = ref_idx_lx; c_idx <= num_ref_idx_lx_active; c_idx++) { - int long_term_pic_num_f = ref_pic_list_x[c_idx].is_reference == kUsedForLongTerm ? ref_pic_list_x[c_idx].long_term_pic_num : 2 * (max_long_term_frame_idx_ + 1); - if ( long_term_pic_num_f != p_list_mod->long_term_pic_num) { - ref_pic_list_x[n_idx++] = ref_pic_list_x[c_idx]; - } - } + ref_pic_list_mod[ref_idx_lx] = ref_pic_list_x[i]; } + ref_idx_lx++; p_list_mod = &p_slice_header->ref_pic_list.modification_l0[ref_idx_lx]; } + memcpy(ref_pic_list_x, ref_pic_list_mod, sizeof(AvcPicture) * num_ref_idx_lx_active); return PARSER_OK; } @@ -2092,17 +2105,124 @@ ParserResult AvcVideoParser::MarkDecodedRefPics() { max_long_term_frame_idx_ = 0; } else { curr_pic_.is_reference = kUsedForShortTerm; + max_long_term_frame_idx_ = NO_LONG_TERM_FRAME_INDICES; dpb_buffer_.num_short_term = 0; } } else { + curr_pic_.is_reference = kUsedForShortTerm; // 8.2.5.1: 3. if (p_slice_header->dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag == 1) { // 8.2.5.4 Adaptive memory control decoded reference picture marking process - ERR("8.2.5.4 Adaptive memory control decoded reference picture marking process not supported yet."); - return PARSER_NOT_IMPLEMENTED; + for (i = 0; i < p_slice_header->dec_ref_pic_marking.mmco_count; i++) { + AvcMmco *p_mmco = &p_slice_header->dec_ref_pic_marking.mmco[i]; + switch (p_mmco->memory_management_control_operation) { + case 1: { // 8.2.5.4.1 Marking process of a short-term reference picture as "unused for reference" + int curr_pic_num = p_slice_header->field_pic_flag ? 2 * p_slice_header->frame_num + 1 : p_slice_header->frame_num; + int pic_num_x = curr_pic_num - (p_mmco->difference_of_pic_nums_minus1 + 1); + if (p_slice_header->field_pic_flag) { + ERR("Field picture not supported.\n"); + return PARSER_NOT_IMPLEMENTED; + } else { + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + if (dpb_buffer_.frame_buffer_list[j].is_reference == kUsedForShortTerm && dpb_buffer_.frame_buffer_list[j].pic_num == pic_num_x) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUnusedForReference; + dpb_buffer_.num_short_term--; + } + } + } + } + break; + + case 2: { // 8.2.5.4.2 Marking process of a long-term reference picture as "unused for reference" + if (p_slice_header->field_pic_flag) { + ERR("Field picture not supported.\n"); + return PARSER_NOT_IMPLEMENTED; + } else { + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + if (dpb_buffer_.frame_buffer_list[j].is_reference == kUsedForLongTerm && dpb_buffer_.frame_buffer_list[j].long_term_pic_num == p_mmco->long_term_pic_num) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUnusedForReference; + dpb_buffer_.num_long_term--; + } + } + } + } + break; + + case 3: { // Assignment process of a LongTermFrameIdx to a short-term reference picture + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + if (dpb_buffer_.frame_buffer_list[j].is_reference == kUsedForLongTerm && dpb_buffer_.frame_buffer_list[j].long_term_frame_idx == p_mmco->long_term_frame_idx) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUnusedForReference; + dpb_buffer_.num_long_term--; + } + } + int curr_pic_num = p_slice_header->field_pic_flag ? 2 * p_slice_header->frame_num + 1 : p_slice_header->frame_num; + int pic_num_x = curr_pic_num - (p_mmco->difference_of_pic_nums_minus1 + 1); + if (p_slice_header->field_pic_flag) { + ERR("Field picture not supported.\n"); + return PARSER_NOT_IMPLEMENTED; + } else { + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + if (dpb_buffer_.frame_buffer_list[j].is_reference == kUsedForShortTerm && dpb_buffer_.frame_buffer_list[j].pic_num == pic_num_x) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUsedForLongTerm; + dpb_buffer_.frame_buffer_list[j].long_term_frame_idx = p_mmco->long_term_frame_idx; + dpb_buffer_.num_short_term--; + dpb_buffer_.num_long_term++; + } + } + } + } + break; + + case 4: { // 8.2.5.4.4 Decoding process for MaxLongTermFrameIdx + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + if (dpb_buffer_.frame_buffer_list[j].is_reference == kUsedForLongTerm && dpb_buffer_.frame_buffer_list[j].long_term_frame_idx > (p_mmco->max_long_term_frame_idx_plus1 - 1)) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUnusedForReference; + dpb_buffer_.num_long_term--; + } + } + if (p_mmco->max_long_term_frame_idx_plus1 == 0) { + max_long_term_frame_idx_ = NO_LONG_TERM_FRAME_INDICES; + } else { + max_long_term_frame_idx_ = p_mmco->max_long_term_frame_idx_plus1 - 1; + } + } + break; + + case 5: { // 8.2.5.4.5 Marking process of all reference pictures as "unused for reference" and setting MaxLongTermFrameIdx to "no long-term frame indices" + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUnusedForReference; + } + max_long_term_frame_idx_ = NO_LONG_TERM_FRAME_INDICES; + dpb_buffer_.num_short_term = 0; + dpb_buffer_.num_long_term = 0; + } + break; + + case 6: { // 8.2.5.4.6 Process for assigning a long-term frame index to the current picture + for (int j = 0; j < dpb_buffer_.dpb_size; j++) { + if (dpb_buffer_.frame_buffer_list[j].is_reference == kUsedForLongTerm && dpb_buffer_.frame_buffer_list[j].long_term_frame_idx == p_mmco->long_term_frame_idx) { + dpb_buffer_.frame_buffer_list[j].is_reference = kUnusedForReference; + dpb_buffer_.num_long_term--; + } + } + if (p_slice_header->field_pic_flag) { + ERR("Field picture not supported.\n"); + return PARSER_NOT_IMPLEMENTED; + } else { + curr_pic_.is_reference = kUsedForLongTerm; + curr_pic_.long_term_frame_idx = p_mmco->long_term_frame_idx; + } + } + break; + + default: { + ERR("Invalid memory management control operation!"); + return PARSER_INVALID_ARG; + } + } + + } } else { // 8.2.5.3 Sliding window decoded reference picture marking process - curr_pic_.is_reference = kUsedForShortTerm; // 8.2.5.1: 3. - if (dpb_buffer_.num_short_term + dpb_buffer_.num_long_term == p_sps->max_num_ref_frames) { int32_t min_frame_num_wrap = 0xFFFFFF; // more than the largest possible value of FrameNumWrap (2 ^ 16) int min_index = AVC_MAX_DPB_FRAMES; @@ -2456,6 +2576,7 @@ void AvcVideoParser::PrintSliceHeader(AvcSliceHeader *p_slice_header) { for (j = 0; j < AVC_MAX_REF_PICTURE_NUM; j++) { MSG_NO_NEWLINE("(" << refMarking->mmco[j].memory_management_control_operation << ", " << refMarking->mmco[j].difference_of_pic_nums_minus1 << ", " << refMarking->mmco[j].long_term_pic_num << ", " << refMarking->mmco[j].long_term_frame_idx << ", " << refMarking->mmco[j].max_long_term_frame_idx_plus1 << ") "); } + MSG(""); } MSG("cabac_init_idc = " << p_slice_header->cabac_init_idc); @@ -2510,5 +2631,20 @@ void AvcVideoParser::PrintVappiBufInfo() { MSG(", flags = 0x" << std::hex << p_ref_pic->flags); MSG_NO_NEWLINE(std::dec); } + + MSG("Slice ref lists:") + for (int slice_index = 0; slice_index < num_slices_; slice_index++) { + RocdecAvcSliceParams *p_slice_param = &slice_param_list_[slice_index]; + MSG_NO_NEWLINE("Slice " << slice_index << " ref list 0: "); + for (int i = 0; i < 32; i++) { + MSG_NO_NEWLINE(p_slice_param->ref_pic_list_0[i].pic_idx << ", "); + } + MSG(""); + MSG_NO_NEWLINE("Slice " << slice_index << " ref list 1: "); + for (int i = 0; i < 32; i++) { + MSG_NO_NEWLINE(p_slice_param->ref_pic_list_1[i].pic_idx << ", "); + } + MSG(""); + } } #endif // DBGINFO \ No newline at end of file