From dd3b609a096cf1637aae4adbdd849383bcf0ee5d Mon Sep 17 00:00:00 2001
From: jeffqjiangNew <142832361+jeffqjiangNew@users.noreply.github.com>
Date: Mon, 4 Dec 2023 11:53:26 -0500
Subject: [PATCH] * rocDecode/HEVC: Fix for decode errors on a few conformance
streams. (#114)
- Re-wrote short term RPS parsing function. The previous code generates incorrect results on some conformance streams.
- No longer skip the additional buffer bumping specified in process C.5.2.2. This avoids the situation where the current frame overwrites the previously decoded buffer that is being output/displayed.
[ROCm/rocdecode commit: 5e65788bddd2d40939a84f7b807c7b4d8594810d]
---
projects/rocdecode/src/parser/hevc_parser.cpp | 192 ++++++++++--------
projects/rocdecode/src/parser/hevc_parser.h | 44 ++--
2 files changed, 125 insertions(+), 111 deletions(-)
diff --git a/projects/rocdecode/src/parser/hevc_parser.cpp b/projects/rocdecode/src/parser/hevc_parser.cpp
index 3ca7522163..03e7a530a5 100644
--- a/projects/rocdecode/src/parser/hevc_parser.cpp
+++ b/projects/rocdecode/src/parser/hevc_parser.cpp
@@ -1027,17 +1027,18 @@ void HEVCVideoParser::ParseScalingList(H265ScalingListData * sl_ptr, uint8_t *na
}
}
-void HEVCVideoParser::ParseShortTermRefPicSet(H265ShortTermRPS *rps, int32_t st_rps_idx, uint32_t number_short_term_ref_pic_sets, H265ShortTermRPS rps_ref[], uint8_t *nalu, size_t /*size*/, size_t& offset) {
- int32_t i = 0;
+void HEVCVideoParser::ParseShortTermRefPicSet(H265ShortTermRPS *rps, uint32_t st_rps_idx, uint32_t number_short_term_ref_pic_sets, H265ShortTermRPS rps_ref[], uint8_t *nalu, size_t /*size*/, size_t& offset) {
+ int i, j;
- if (st_rps_idx != 0) {
+ memset(rps, 0, sizeof(H265ShortTermRPS));
+ if (st_rps_idx != 0) {
rps->inter_ref_pic_set_prediction_flag = Parser::GetBit(nalu, offset);
}
else {
rps->inter_ref_pic_set_prediction_flag = 0;
}
if (rps->inter_ref_pic_set_prediction_flag) {
- if (unsigned(st_rps_idx) == number_short_term_ref_pic_sets) {
+ if (st_rps_idx == number_short_term_ref_pic_sets) {
rps->delta_idx_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset);
}
else {
@@ -1045,9 +1046,11 @@ void HEVCVideoParser::ParseShortTermRefPicSet(H265ShortTermRPS *rps, int32_t st_
}
rps->delta_rps_sign = Parser::GetBit(nalu, offset);
rps->abs_delta_rps_minus1 = Parser::ExpGolomb::ReadUe(nalu, offset);
- int32_t delta_rps = (int32_t) (1 - 2 * rps->delta_rps_sign) * (rps->abs_delta_rps_minus1 + 1);
- int32_t ref_idx = st_rps_idx - rps->delta_idx_minus1 - 1;
- for (int j = 0; j <= (rps_ref[ref_idx].num_of_delta_poc); j++) {
+ int ref_rps_idx = st_rps_idx - (rps->delta_idx_minus1 + 1); // (7-59)
+ int delta_rps = (1 - 2 * rps->delta_rps_sign) * (rps->abs_delta_rps_minus1 + 1); // (7-60)
+
+ H265ShortTermRPS *ref_rps = &rps_ref[ref_rps_idx];
+ for (j = 0; j <= ref_rps->num_of_delta_pocs; j++) {
rps->used_by_curr_pic_flag[j] = Parser::GetBit(nalu, offset);
if (!rps->used_by_curr_pic_flag[j]) {
rps->use_delta_flag[j] = Parser::GetBit(nalu, offset);
@@ -1057,74 +1060,74 @@ void HEVCVideoParser::ParseShortTermRefPicSet(H265ShortTermRPS *rps, int32_t st_
}
}
- for (int j = rps_ref[ref_idx].num_positive_pics - 1; j >= 0; j--) {
- int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[rps_ref[ref_idx].num_negative_pics + j]; //positive delta_poc from ref_rps
- if (delta_poc < 0 && rps->use_delta_flag[rps_ref[ref_idx].num_negative_pics + j]) {
- rps->delta_poc[i] = delta_poc;
- rps->used_by_curr_pic[i++] = rps->used_by_curr_pic_flag[rps_ref[ref_idx].num_negative_pics + j];
+ int d_poc;
+ i = 0;
+ for (j = ref_rps->num_positive_pics - 1; j >= 0; j--) {
+ d_poc = ref_rps->delta_poc_s1[j] + delta_rps;
+ if (d_poc < 0 && rps->use_delta_flag[ref_rps->num_negative_pics + j]) {
+ rps->delta_poc_s0[i] = d_poc;
+ rps->used_by_curr_pic_s0[i++] = rps->used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
}
}
- if (delta_rps < 0 && rps->use_delta_flag[rps_ref[ref_idx].num_of_pics]) {
- rps->delta_poc[i] = delta_rps;
- rps->used_by_curr_pic[i++] = rps->used_by_curr_pic_flag[rps_ref[ref_idx].num_of_pics];
+ if (delta_rps < 0 && rps->use_delta_flag[ref_rps->num_of_delta_pocs]) {
+ rps->delta_poc_s0[i] = delta_rps;
+ rps->used_by_curr_pic_s0[i++] = rps->used_by_curr_pic_flag[ref_rps->num_of_delta_pocs];
}
- for (int j = 0; j < rps_ref[ref_idx].num_negative_pics; j++) {
- int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[j];
- if (delta_poc < 0 && rps->use_delta_flag[j]) {
- rps->delta_poc[i]=delta_poc;
- rps->used_by_curr_pic[i++] = rps->used_by_curr_pic_flag[j];
+ for (j = 0; j < ref_rps->num_negative_pics; j++) {
+ d_poc = ref_rps->delta_poc_s0[j] + delta_rps;
+ if (d_poc < 0 && rps->use_delta_flag[j]) {
+ rps->delta_poc_s0[i] = d_poc;
+ rps->used_by_curr_pic_s0[i++] = rps->used_by_curr_pic_flag[j];
}
}
rps->num_negative_pics = i;
-
- for (int j = rps_ref[ref_idx].num_negative_pics - 1; j >= 0; j--) {
- int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[j]; //positive delta_poc from ref_rps
- if (delta_poc > 0 && rps->use_delta_flag[j]) {
- rps->delta_poc[i] = delta_poc;
- rps->used_by_curr_pic[i++] = rps->used_by_curr_pic_flag[j];
+
+ i = 0;
+ for (j = ref_rps->num_negative_pics - 1; j >= 0; j--) {
+ d_poc = ref_rps->delta_poc_s0[j] + delta_rps;
+ if (d_poc > 0 && rps->use_delta_flag[j]) {
+ rps->delta_poc_s1[i] = d_poc;
+ rps->used_by_curr_pic_s1[i++] = rps->used_by_curr_pic_flag[j];
}
}
- if (delta_rps > 0 && rps->use_delta_flag[rps_ref[ref_idx].num_of_pics]) {
- rps->delta_poc[i] = delta_rps;
- rps->used_by_curr_pic[i++] = rps->used_by_curr_pic_flag[rps_ref[ref_idx].num_of_pics];
+ if (delta_rps > 0 && rps->use_delta_flag[ref_rps->num_of_delta_pocs]) {
+ rps->delta_poc_s1[i] = delta_rps;
+ rps->used_by_curr_pic_s1[i++] = rps->used_by_curr_pic_flag[ref_rps->num_of_delta_pocs];
}
- for (int j = 0; j < rps_ref[ref_idx].num_positive_pics; j++) {
- int32_t delta_poc = delta_rps + rps_ref[ref_idx].delta_poc[rps_ref[ref_idx].num_negative_pics+j];
- if (delta_poc > 0 && rps->use_delta_flag[rps_ref[ref_idx].num_negative_pics+j]) {
- rps->delta_poc[i] = delta_poc;
- rps->used_by_curr_pic[i++] = rps->used_by_curr_pic_flag[rps_ref[ref_idx].num_negative_pics+j];
+
+ for (j = 0; j < ref_rps->num_positive_pics; j++) {
+ d_poc = ref_rps->delta_poc_s1[j] + delta_rps;
+ if (d_poc > 0 && rps->use_delta_flag[ref_rps->num_negative_pics + j]) {
+ rps->delta_poc_s1[i] = d_poc;
+ rps->used_by_curr_pic_s1[i++] = rps->used_by_curr_pic_flag[ref_rps->num_negative_pics + j];
}
}
- rps->num_positive_pics = i - rps->num_negative_pics ;
- rps->num_of_delta_poc = rps_ref[ref_idx].num_negative_pics + rps_ref[ref_idx].num_positive_pics;
- rps->num_of_pics = i;
- }
- else {
+ rps->num_positive_pics = i;
+ rps->num_of_delta_pocs = rps->num_negative_pics + rps->num_positive_pics;
+ } else {
rps->num_negative_pics = Parser::ExpGolomb::ReadUe(nalu, offset);
rps->num_positive_pics = Parser::ExpGolomb::ReadUe(nalu, offset);
- int32_t prev = 0;
- int32_t poc;
- // DeltaPocS0, UsedByCurrPicS0
- for (int j = 0; j < rps->num_negative_pics; j++) {
- rps->delta_poc_s0_minus1[j] = Parser::ExpGolomb::ReadUe(nalu, offset);
- poc = prev - rps->delta_poc_s0_minus1[j] - 1;
- prev = poc;
- rps->delta_poc[j] = poc; // DeltaPocS0
- rps->used_by_curr_pic_s0_flag[j] = Parser::GetBit(nalu, offset);
- rps->used_by_curr_pic[j] = rps->used_by_curr_pic_s0_flag[j]; // UsedByCurrPicS0
+ rps->num_of_delta_pocs = rps->num_negative_pics + rps->num_positive_pics;
+
+ for (i = 0; i < rps->num_negative_pics; i++) {
+ rps->delta_poc_s0_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset);
+ if (i == 0) {
+ rps->delta_poc_s0[i] = -(rps->delta_poc_s0_minus1[i] + 1);
+ } else {
+ rps->delta_poc_s0[i] = rps->delta_poc_s0[i - 1] - (rps->delta_poc_s0_minus1[i] + 1);
+ }
+ rps->used_by_curr_pic_s0[i] = Parser::GetBit(nalu, offset);
}
- prev = 0;
- // DeltaPocS1, UsedByCurrPicS1
- for (int j = 0; j < rps->num_positive_pics; j++) {
- rps->delta_poc_s1_minus1[j] = Parser::ExpGolomb::ReadUe(nalu, offset);
- poc = prev + rps->delta_poc_s1_minus1[j] + 1;
- prev = poc;
- rps->delta_poc[j + rps->num_negative_pics] = poc; // DeltaPocS1
- rps->used_by_curr_pic_s1_flag[j] = Parser::GetBit(nalu, offset);
- rps->used_by_curr_pic[j + rps->num_negative_pics] = rps->used_by_curr_pic_s1_flag[j]; // UsedByCurrPicS1
+
+ for (i = 0; i < rps->num_positive_pics; i++) {
+ rps->delta_poc_s1_minus1[i] = Parser::ExpGolomb::ReadUe(nalu, offset);
+ if (i == 0) {
+ rps->delta_poc_s1[i] = rps->delta_poc_s1_minus1[i] + 1;
+ } else {
+ rps->delta_poc_s1[i] = rps->delta_poc_s1[i - 1] + (rps->delta_poc_s1_minus1[i] + 1);
+ }
+ rps->used_by_curr_pic_s1[i] = Parser::GetBit(nalu, offset);
}
- rps->num_of_pics = rps->num_negative_pics + rps->num_positive_pics;
- rps->num_of_delta_poc = rps->num_negative_pics + rps->num_positive_pics;
}
}
@@ -1735,9 +1738,13 @@ bool HEVCVideoParser::ParseSliceHeader(uint8_t *nalu, size_t size) {
// Calculate NumPicTotalCurr
num_pic_total_curr_ = 0;
H265ShortTermRPS *st_rps_ptr = &m_sh_->st_rps;
- // Check the combined list
- for (int i = 0; i < st_rps_ptr->num_of_delta_poc; i++) {
- if (st_rps_ptr->used_by_curr_pic[i]) {
+ for (int i = 0; i < st_rps_ptr->num_negative_pics; i++) {
+ if (st_rps_ptr->used_by_curr_pic_s0[i]) {
+ num_pic_total_curr_++;
+ }
+ }
+ for (int i = 0; i < st_rps_ptr->num_positive_pics; i++) {
+ if (st_rps_ptr->used_by_curr_pic_s1[i]) {
num_pic_total_curr_++;
}
}
@@ -2009,22 +2016,21 @@ void HEVCVideoParser::DecodeRps() {
else {
H265ShortTermRPS *rps_ptr = &m_sh_->st_rps;
for (i = 0, j = 0, k = 0; i < rps_ptr->num_negative_pics; i++) {
- if (rps_ptr->used_by_curr_pic[i]) { // UsedByCurrPicS0
- poc_st_curr_before_[j++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; // DeltaPocS0
+ if (rps_ptr->used_by_curr_pic_s0[i]) {
+ poc_st_curr_before_[j++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc_s0[i];
}
else {
- poc_st_foll_[k++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i];
+ poc_st_foll_[k++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc_s0[i];
}
}
num_poc_st_curr_before_ = j;
- // UsedByCurrPicS1 follows UsedByCurrPicS0 in used_by_curr_pic. DeltaPocS1 follows DeltaPocS0 in delta_poc.
- for (j = 0; i < rps_ptr->num_of_delta_poc; i++ ) {
- if (rps_ptr->used_by_curr_pic[i]) { // UsedByCurrPicS1
- poc_st_curr_after_[j++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; // DeltaPocS1
+ for (i = 0, j = 0; i < rps_ptr->num_positive_pics; i++ ) {
+ if (rps_ptr->used_by_curr_pic_s1[i]) {
+ poc_st_curr_after_[j++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc_s1[i];
}
else {
- poc_st_foll_[k++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc[i]; // DeltaPocS1
+ poc_st_foll_[k++] = curr_pic_info_.pic_order_cnt + rps_ptr->delta_poc_s1[i];
}
}
num_poc_st_curr_after_ = j;
@@ -2337,8 +2343,16 @@ int HEVCVideoParser::FindFreeBufAndMark() {
}
dpb_buffer_.dpb_fullness++;
- // Skip additional bumping after the current picture is added to DPB. This avoids immediate wait for
- // decode completion of the current frame in certain cases.
+ SpsData *sps_ptr = &m_sps_[m_active_sps_id_];
+ uint32_t highest_tid = sps_ptr->sps_max_sub_layers_minus1; // HighestTid
+ uint32_t max_num_reorder_pics = sps_ptr->sps_max_num_reorder_pics[highest_tid];
+
+ while (dpb_buffer_.num_needed_for_output > max_num_reorder_pics) {
+ if (BumpPicFromDpb() != PARSER_OK) {
+ return PARSER_FAIL;
+ }
+ }
+
// Skip SpsMaxLatencyPictures check as SpsMaxLatencyPictures >= sps_max_num_reorder_pics.
return PARSER_OK;
@@ -2762,8 +2776,7 @@ void HEVCVideoParser::PrintStRps(HEVCVideoParser::H265ShortTermRPS *rps_ptr) {
MSG("");
MSG("num_negative_pics = " << rps_ptr->num_negative_pics);
MSG("num_positive_pics = " << rps_ptr->num_positive_pics);
- MSG("num_of_pics = " << rps_ptr->num_of_pics);
- MSG("num_of_delta_poc = " << rps_ptr->num_of_delta_poc);
+ MSG("num_of_delta_pocs = " << rps_ptr->num_of_delta_pocs);
MSG_NO_NEWLINE("delta_poc_s0_minus1[]:");
for(int j = 0; j < 16; j++) {
@@ -2786,14 +2799,24 @@ void HEVCVideoParser::PrintStRps(HEVCVideoParser::H265ShortTermRPS *rps_ptr) {
}
MSG("");
- MSG_NO_NEWLINE("delta_poc[16] (DeltaPocS0 + DeltaPocS1):");
+ MSG_NO_NEWLINE("delta_poc_s0[16]:");
for(int j = 0; j < 16; j++) {
- MSG_NO_NEWLINE(" " << rps_ptr->delta_poc[j]);
+ MSG_NO_NEWLINE(" " << rps_ptr->delta_poc_s0[j]);
}
MSG("");
- MSG_NO_NEWLINE("used_by_curr_pic[16] (UsedByCurrPicS0 + UsedByCurrPicS1):");
+ MSG_NO_NEWLINE("delta_poc_s1[16]:");
for(int j = 0; j < 16; j++) {
- MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic[j]);
+ MSG_NO_NEWLINE(" " << rps_ptr->delta_poc_s1[j]);
+ }
+ MSG("");
+ MSG_NO_NEWLINE("used_by_curr_pic_s0[16]:");
+ for(int j = 0; j < 16; j++) {
+ MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_s0[j]);
+ }
+ MSG("");
+ MSG_NO_NEWLINE("used_by_curr_pic_s1[16]:");
+ for(int j = 0; j < 16; j++) {
+ MSG_NO_NEWLINE(" " << rps_ptr->used_by_curr_pic_s1[j]);
}
MSG("");
}
@@ -2812,15 +2835,4 @@ void HEVCVideoParser::PrintLtRefInfo(HEVCVideoParser::H265LongTermRPS *lt_info_p
}
MSG("");
}
-
-void HEVCVideoParser::PrintSeiMessage(HEVCVideoParser::SeiMessageData *sei_message_ptr) {
- MSG("=== hevc_sei_message_info ===");
- MSG("payload_type = " << sei_message_ptr->payload_type);
- MSG("payload_size = " << sei_message_ptr->payload_size);
- MSG_NO_NEWLINE("reserved[3]: ");
- for(int i = 0; i < 3; i++) {
- MSG_NO_NEWLINE(" " << sei_message_ptr->reserved[i]);
- }
- MSG("");
-}
#endif // DBGINFO
\ No newline at end of file
diff --git a/projects/rocdecode/src/parser/hevc_parser.h b/projects/rocdecode/src/parser/hevc_parser.h
index 54f6beadbf..eea9a5c76c 100644
--- a/projects/rocdecode/src/parser/hevc_parser.h
+++ b/projects/rocdecode/src/parser/hevc_parser.h
@@ -224,7 +224,7 @@ protected:
bool scaling_list_pred_mode_flag[4][6]; //u(1)
uint32_t scaling_list_pred_matrix_id_delta[4][6]; //ue(v)
int32_t scaling_list_dc_coef_minus8[4][6]; //se(v)
- int32_t scaling_list_delta_coef; //se(v) could have issues......
+ int32_t scaling_list_delta_coef; //se(v)
int32_t scaling_list[H265_SCALING_LIST_SIZE_NUM][H265_SCALING_LIST_NUM][H265_SCALING_LIST_MAX_I];
int32_t scaling_list_dc_coef[2][6]; // DC coefficient for 16x16 and 32x32
} H265ScalingListData;
@@ -232,23 +232,26 @@ protected:
/*! \brief Structure for Short Term Reference Picture Set
*/
typedef struct {
- uint32_t inter_ref_pic_set_prediction_flag;
- uint32_t delta_idx_minus1;
- uint32_t delta_rps_sign;
- uint32_t abs_delta_rps_minus1;
- uint32_t used_by_curr_pic_flag[16];
- uint32_t use_delta_flag[16];
- uint32_t num_negative_pics; // NumNegativePics
- uint32_t num_positive_pics; // NumPositivePics
- uint32_t num_of_pics;
- uint32_t num_of_delta_poc; // NumDeltaPocs
- uint32_t delta_poc_s0_minus1[16];
- uint32_t used_by_curr_pic_s0_flag[16];
- uint32_t delta_poc_s1_minus1[16];
- uint32_t used_by_curr_pic_s1_flag[16];
- int32_t delta_poc[16]; // DeltaPocS0 + DeltaPocS1
- bool used_by_curr_pic[16]; // UsedByCurrPicS0 + UsedByCurrPicS1
- } H265ShortTermRPS;
+ uint8_t inter_ref_pic_set_prediction_flag;
+ uint32_t delta_idx_minus1;
+ uint8_t delta_rps_sign;
+ uint32_t abs_delta_rps_minus1;
+ uint8_t used_by_curr_pic_flag[HEVC_MAX_DPB_FRAMES];
+ uint8_t use_delta_flag[HEVC_MAX_DPB_FRAMES];
+
+ uint32_t delta_poc_s0_minus1[HEVC_MAX_DPB_FRAMES];
+ uint8_t used_by_curr_pic_s0_flag[HEVC_MAX_DPB_FRAMES];
+ uint32_t delta_poc_s1_minus1[HEVC_MAX_DPB_FRAMES];
+ uint8_t used_by_curr_pic_s1_flag[HEVC_MAX_DPB_FRAMES];
+
+ uint32_t num_negative_pics; // NumNegativePics
+ uint32_t num_positive_pics; // NumPositivePics
+ uint32_t num_of_delta_pocs; // NumDeltaPocs
+ uint8_t used_by_curr_pic_s0[HEVC_MAX_DPB_FRAMES]; // UsedByCurrPicS0
+ uint8_t used_by_curr_pic_s1[HEVC_MAX_DPB_FRAMES]; // UsedByCurrPicS1
+ int32_t delta_poc_s0[HEVC_MAX_DPB_FRAMES]; // DeltaPocS0
+ int32_t delta_poc_s1[HEVC_MAX_DPB_FRAMES]; // DeltaPocS1
+} H265ShortTermRPS;
/*! \brief Structure for Long Term Reference Picture Set
*/
@@ -824,7 +827,7 @@ protected:
/*! \brief Function to parse Short Term Reference Picture Set
* \param [out] rps A pointer of H265ShortTermRPS for the output from the parsed stream
- * \param [in] st_rps_idx Input of int32_t - specifies the index in the RPS buffer
+ * \param [in] st_rps_idx specifies the index in the RPS buffer
* \param [in] num_short_term_ref_pic_sets Specifies the count of Short Term RPS in uint32_t
* \param [in] rps_ref A reference of H265ShortTermRPS to the RPS buffer
* \param [in] data A pointer of uint8_t for the input stream to be parsed
@@ -832,7 +835,7 @@ protected:
* \param [in] offset Reference to the offset in the input buffer
* \return No return value
*/
- void ParseShortTermRefPicSet(H265ShortTermRPS *rps, int32_t st_rps_idx, uint32_t num_short_term_ref_pic_sets, H265ShortTermRPS rps_ref[], uint8_t *data, size_t size, size_t &offset);
+ void ParseShortTermRefPicSet(H265ShortTermRPS *rps, uint32_t st_rps_idx, uint32_t num_short_term_ref_pic_sets, H265ShortTermRPS rps_ref[], uint8_t *data, size_t size, size_t &offset);
/*! \brief Function to parse weighted prediction table
* \param [in/out] Slice_header_ptr Pointer to the slice segment header
@@ -917,7 +920,6 @@ protected:
void PrintSliceSegHeader(HEVCVideoParser::SliceHeaderData *slice_header_ptr);
void PrintStRps(HEVCVideoParser::H265ShortTermRPS *rps_ptr);
void PrintLtRefInfo(HEVCVideoParser::H265LongTermRPS *lt_info_ptr);
- void PrintSeiMessage(HEVCVideoParser::SeiMessageData *sei_message_ptr);
#endif // DBGINFO
private: