Commit aa518af8 authored by Dmitry Kovalev's avatar Dmitry Kovalev Committed by Gerrit Code Review
Browse files

Merge "Adding struct tx_probs and struct tx_counts to cleanup the code."

parents 444c8d4c cc662dd7
......@@ -50,8 +50,9 @@ static const vp9_prob default_if_uv_probs[VP9_INTRA_MODES]
{ 101, 21, 107, 181, 192, 103, 19, 67, 125 } /* y = tm */
};
const vp9_prob vp9_partition_probs[NUM_FRAME_TYPES][NUM_PARTITION_CONTEXTS]
[PARTITION_TYPES - 1] = {
static const vp9_prob default_partition_probs[NUM_FRAME_TYPES]
[NUM_PARTITION_CONTEXTS]
[PARTITION_TYPES - 1] = {
{ /* frame_type = keyframe */
/* 8x8 -> 4x4 */
{ 158, 97, 94 } /* a/l both not split */,
......@@ -159,20 +160,15 @@ static const vp9_prob default_single_ref_p[REF_CONTEXTS][2] = {
{ 238, 247 }
};
const vp9_prob vp9_default_tx_probs_32x32p[TX_SIZE_CONTEXTS]
[TX_SIZE_MAX_SB - 1] = {
{ 3, 136, 37, },
{ 5, 52, 13, },
};
const vp9_prob vp9_default_tx_probs_16x16p[TX_SIZE_CONTEXTS]
[TX_SIZE_MAX_SB - 2] = {
{ 20, 152, },
{ 15, 101, },
};
const vp9_prob vp9_default_tx_probs_8x8p[TX_SIZE_CONTEXTS]
[TX_SIZE_MAX_SB - 3] = {
{ 100, },
{ 66, },
static const struct tx_probs default_tx_probs = {
{ { 3, 136, 37 },
{ 5, 52, 13 } },
{ { 20, 152 },
{ 15, 101 } },
{ { 100 },
{ 66 } }
};
void tx_counts_to_branch_counts_32x32(unsigned int *tx_count_32x32p,
......@@ -202,24 +198,30 @@ void tx_counts_to_branch_counts_8x8(unsigned int *tx_count_8x8p,
ct_8x8p[0][1] = tx_count_8x8p[TX_8X8];
}
const vp9_prob vp9_default_mbskip_probs[MBSKIP_CONTEXTS] = {
static const vp9_prob default_mbskip_probs[MBSKIP_CONTEXTS] = {
192, 128, 64
};
static const vp9_prob default_switchable_interp_prob[VP9_SWITCHABLE_FILTERS+1]
[VP9_SWITCHABLE_FILTERS-1] = {
{ 235, 162, },
{ 36, 255, },
{ 34, 3, },
{ 149, 144, },
};
void vp9_init_mbmode_probs(VP9_COMMON *cm) {
vp9_copy(cm->fc.uv_mode_prob, default_if_uv_probs);
vp9_copy(cm->kf_uv_mode_prob, default_kf_uv_probs);
vp9_copy(cm->fc.y_mode_prob, default_if_y_probs);
vp9_copy(cm->fc.switchable_interp_prob, vp9_switchable_interp_prob);
vp9_copy(cm->fc.partition_prob, vp9_partition_probs);
vp9_copy(cm->fc.switchable_interp_prob, default_switchable_interp_prob);
vp9_copy(cm->fc.partition_prob, default_partition_probs);
vp9_copy(cm->fc.intra_inter_prob, default_intra_inter_p);
vp9_copy(cm->fc.comp_inter_prob, default_comp_inter_p);
vp9_copy(cm->fc.comp_ref_prob, default_comp_ref_p);
vp9_copy(cm->fc.single_ref_prob, default_single_ref_p);
vp9_copy(cm->fc.tx_probs_32x32p, vp9_default_tx_probs_32x32p);
vp9_copy(cm->fc.tx_probs_16x16p, vp9_default_tx_probs_16x16p);
vp9_copy(cm->fc.tx_probs_8x8p, vp9_default_tx_probs_8x8p);
vp9_copy(cm->fc.mbskip_probs, vp9_default_mbskip_probs);
cm->fc.tx_probs = default_tx_probs;
vp9_copy(cm->fc.mbskip_probs, default_mbskip_probs);
}
const vp9_tree_index vp9_switchable_interp_tree[VP9_SWITCHABLE_FILTERS*2-2] = {
......@@ -229,14 +231,7 @@ const vp9_tree_index vp9_switchable_interp_tree[VP9_SWITCHABLE_FILTERS*2-2] = {
struct vp9_token vp9_switchable_interp_encodings[VP9_SWITCHABLE_FILTERS];
const INTERPOLATIONFILTERTYPE vp9_switchable_interp[VP9_SWITCHABLE_FILTERS] = {
EIGHTTAP, EIGHTTAP_SMOOTH, EIGHTTAP_SHARP};
const int vp9_switchable_interp_map[SWITCHABLE+1] = {1, 0, 2, -1, -1};
const vp9_prob vp9_switchable_interp_prob [VP9_SWITCHABLE_FILTERS+1]
[VP9_SWITCHABLE_FILTERS-1] = {
{ 235, 162, },
{ 36, 255, },
{ 34, 3, },
{ 149, 144, },
};
const int vp9_switchable_interp_map[SWITCHABLE + 1] = {1, 0, 2, -1, -1};
// Indicates if the filter is interpolating or non-interpolating
const int vp9_is_interpolating_filter[SWITCHABLE + 1] = {1, 1, 1, 1, -1};
......@@ -419,21 +414,21 @@ void vp9_adapt_mode_probs(VP9_COMMON *cm) {
unsigned int branch_ct_32x32p[TX_SIZE_MAX_SB - 1][2];
for (i = 0; i < TX_SIZE_CONTEXTS; ++i) {
tx_counts_to_branch_counts_8x8(fc->tx_count_8x8p[i], branch_ct_8x8p);
tx_counts_to_branch_counts_8x8(fc->tx_counts.p8x8[i], branch_ct_8x8p);
for (j = 0; j < TX_SIZE_MAX_SB - 3; ++j)
fc->tx_probs_8x8p[i][j] = update_tx_ct(fc->pre_tx_probs_8x8p[i][j],
fc->tx_probs.p8x8[i][j] = update_tx_ct(fc->pre_tx_probs.p8x8[i][j],
branch_ct_8x8p[j]);
tx_counts_to_branch_counts_16x16(fc->tx_count_16x16p[i],
tx_counts_to_branch_counts_16x16(fc->tx_counts.p16x16[i],
branch_ct_16x16p);
for (j = 0; j < TX_SIZE_MAX_SB - 2; ++j)
fc->tx_probs_16x16p[i][j] = update_tx_ct(fc->pre_tx_probs_16x16p[i][j],
fc->tx_probs.p16x16[i][j] = update_tx_ct(fc->tx_probs.p16x16[i][j],
branch_ct_16x16p[j]);
tx_counts_to_branch_counts_32x32(fc->tx_count_32x32p[i],
tx_counts_to_branch_counts_32x32(fc->tx_counts.p32x32[i],
branch_ct_32x32p);
for (j = 0; j < TX_SIZE_MAX_SB - 1; ++j)
fc->tx_probs_32x32p[i][j] = update_tx_ct(fc->pre_tx_probs_32x32p[i][j],
fc->tx_probs.p32x32[i][j] = update_tx_ct(fc->pre_tx_probs.p32x32[i][j],
branch_ct_32x32p[j]);
}
}
......
......@@ -21,6 +21,18 @@
// #define MODE_STATS
struct tx_probs {
vp9_prob p32x32[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 1];
vp9_prob p16x16[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
vp9_prob p8x8[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
};
struct tx_counts {
unsigned int p32x32[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB];
unsigned int p16x16[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 1];
unsigned int p8x8[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
};
extern int vp9_mv_cont(const int_mv *l, const int_mv *a);
......@@ -40,9 +52,6 @@ extern struct vp9_token vp9_sb_mv_ref_encoding_array[VP9_INTER_MODES];
// probability models for partition information
extern const vp9_tree_index vp9_partition_tree[];
extern struct vp9_token vp9_partition_encodings[PARTITION_TYPES];
extern const vp9_prob vp9_partition_probs[NUM_FRAME_TYPES]
[NUM_PARTITION_CONTEXTS]
[PARTITION_TYPES - 1];
void vp9_entropy_mode_init(void);
......@@ -77,16 +86,6 @@ extern const vp9_tree_index vp9_switchable_interp_tree
extern struct vp9_token vp9_switchable_interp_encodings[VP9_SWITCHABLE_FILTERS];
extern const vp9_prob vp9_switchable_interp_prob[VP9_SWITCHABLE_FILTERS + 1]
[VP9_SWITCHABLE_FILTERS - 1];
extern const vp9_prob vp9_default_tx_probs_32x32p[TX_SIZE_CONTEXTS]
[TX_SIZE_MAX_SB - 1];
extern const vp9_prob vp9_default_tx_probs_16x16p[TX_SIZE_CONTEXTS]
[TX_SIZE_MAX_SB - 2];
extern const vp9_prob vp9_default_tx_probs_8x8p[TX_SIZE_CONTEXTS]
[TX_SIZE_MAX_SB - 3];
extern void tx_counts_to_branch_counts_32x32(unsigned int *tx_count_32x32p,
unsigned int (*ct_32x32p)[2]);
extern void tx_counts_to_branch_counts_16x16(unsigned int *tx_count_16x16p,
......
......@@ -89,15 +89,9 @@ typedef struct frame_contexts {
unsigned int comp_ref_count[REF_CONTEXTS][2];
// tx_probs
vp9_prob tx_probs_32x32p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 1];
vp9_prob tx_probs_16x16p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
vp9_prob tx_probs_8x8p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 3];
vp9_prob pre_tx_probs_32x32p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 1];
vp9_prob pre_tx_probs_16x16p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
vp9_prob pre_tx_probs_8x8p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 3];
unsigned int tx_count_32x32p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB];
unsigned int tx_count_16x16p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 1];
unsigned int tx_count_8x8p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
struct tx_probs tx_probs;
struct tx_probs pre_tx_probs;
struct tx_counts tx_counts;
// mbskip
vp9_prob mbskip_probs[MBSKIP_CONTEXTS];
......
......@@ -118,11 +118,11 @@ static INLINE const vp9_prob *vp9_get_pred_probs_tx_size(const VP9_COMMON *cm,
const MODE_INFO *const mi = xd->mode_info_context;
const int pred_context = vp9_get_pred_context_tx_size(cm, xd);
if (mi->mbmi.sb_type < BLOCK_SIZE_MB16X16)
return cm->fc.tx_probs_8x8p[pred_context];
return cm->fc.tx_probs.p8x8[pred_context];
else if (mi->mbmi.sb_type < BLOCK_SIZE_SB32X32)
return cm->fc.tx_probs_16x16p[pred_context];
return cm->fc.tx_probs.p16x16[pred_context];
else
return cm->fc.tx_probs_32x32p[pred_context];
return cm->fc.tx_probs.p32x32[pred_context];
}
#endif // VP9_COMMON_VP9_PRED_COMMON_H_
......@@ -60,11 +60,11 @@ static TX_SIZE read_selected_txfm_size(VP9_COMMON *cm, MACROBLOCKD *xd,
}
if (bsize >= BLOCK_SIZE_SB32X32)
cm->fc.tx_count_32x32p[context][txfm_size]++;
cm->fc.tx_counts.p32x32[context][txfm_size]++;
else if (bsize >= BLOCK_SIZE_MB16X16)
cm->fc.tx_count_16x16p[context][txfm_size]++;
cm->fc.tx_counts.p16x16[context][txfm_size]++;
else
cm->fc.tx_count_8x8p[context][txfm_size]++;
cm->fc.tx_counts.p8x8[context][txfm_size]++;
return txfm_size;
}
......
......@@ -68,17 +68,17 @@ static void read_tx_probs(FRAME_CONTEXT *fc, vp9_reader *r) {
for (i = 0; i < TX_SIZE_CONTEXTS; ++i)
for (j = 0; j < TX_SIZE_MAX_SB - 3; ++j)
if (vp9_read(r, VP9_MODE_UPDATE_PROB))
vp9_diff_update_prob(r, &fc->tx_probs_8x8p[i][j]);
vp9_diff_update_prob(r, &fc->tx_probs.p8x8[i][j]);
for (i = 0; i < TX_SIZE_CONTEXTS; ++i)
for (j = 0; j < TX_SIZE_MAX_SB - 2; ++j)
if (vp9_read(r, VP9_MODE_UPDATE_PROB))
vp9_diff_update_prob(r, &fc->tx_probs_16x16p[i][j]);
vp9_diff_update_prob(r, &fc->tx_probs.p16x16[i][j]);
for (i = 0; i < TX_SIZE_CONTEXTS; ++i)
for (j = 0; j < TX_SIZE_MAX_SB - 1; ++j)
if (vp9_read(r, VP9_MODE_UPDATE_PROB))
vp9_diff_update_prob(r, &fc->tx_probs_32x32p[i][j]);
vp9_diff_update_prob(r, &fc->tx_probs.p32x32[i][j]);
}
static void mb_init_dequantizer(VP9_COMMON *pc, MACROBLOCKD *xd) {
......@@ -604,9 +604,7 @@ static void update_frame_context(FRAME_CONTEXT *fc) {
fc->pre_nmvc = fc->nmvc;
vp9_copy(fc->pre_switchable_interp_prob, fc->switchable_interp_prob);
vp9_copy(fc->pre_inter_mode_probs, fc->inter_mode_probs);
vp9_copy(fc->pre_tx_probs_8x8p, fc->tx_probs_8x8p);
vp9_copy(fc->pre_tx_probs_16x16p, fc->tx_probs_16x16p);
vp9_copy(fc->pre_tx_probs_32x32p, fc->tx_probs_32x32p);
fc->pre_tx_probs = fc->tx_probs;
vp9_copy(fc->pre_mbskip_probs, fc->mbskip_probs);
vp9_zero(fc->coef_counts);
......@@ -621,9 +619,7 @@ static void update_frame_context(FRAME_CONTEXT *fc) {
vp9_zero(fc->comp_inter_count);
vp9_zero(fc->single_ref_count);
vp9_zero(fc->comp_ref_count);
vp9_zero(fc->tx_count_8x8p);
vp9_zero(fc->tx_count_16x16p);
vp9_zero(fc->tx_count_32x32p);
vp9_zero(fc->tx_counts);
vp9_zero(fc->mbskip_count);
}
......
......@@ -1075,28 +1075,26 @@ static void encode_txfm_probs(VP9_COMP *cpi, vp9_writer *w) {
for (i = 0; i < TX_SIZE_CONTEXTS; i++) {
tx_counts_to_branch_counts_8x8(cm->fc.tx_count_8x8p[i],
tx_counts_to_branch_counts_8x8(cm->fc.tx_counts.p8x8[i],
ct_8x8p);
for (j = 0; j < TX_SIZE_MAX_SB - 3; j++) {
vp9_cond_prob_diff_update(w, &cm->fc.tx_probs_8x8p[i][j],
for (j = 0; j < TX_SIZE_MAX_SB - 3; j++)
vp9_cond_prob_diff_update(w, &cm->fc.tx_probs.p8x8[i][j],
VP9_MODE_UPDATE_PROB, ct_8x8p[j]);
}
}
for (i = 0; i < TX_SIZE_CONTEXTS; i++) {
tx_counts_to_branch_counts_16x16(cm->fc.tx_count_16x16p[i],
tx_counts_to_branch_counts_16x16(cm->fc.tx_counts.p16x16[i],
ct_16x16p);
for (j = 0; j < TX_SIZE_MAX_SB - 2; j++) {
vp9_cond_prob_diff_update(w, &cm->fc.tx_probs_16x16p[i][j],
for (j = 0; j < TX_SIZE_MAX_SB - 2; j++)
vp9_cond_prob_diff_update(w, &cm->fc.tx_probs.p16x16[i][j],
VP9_MODE_UPDATE_PROB, ct_16x16p[j]);
}
}
for (i = 0; i < TX_SIZE_CONTEXTS; i++) {
tx_counts_to_branch_counts_32x32(cm->fc.tx_count_32x32p[i],
ct_32x32p);
for (j = 0; j < TX_SIZE_MAX_SB - 1; j++) {
vp9_cond_prob_diff_update(w, &cm->fc.tx_probs_32x32p[i][j],
tx_counts_to_branch_counts_32x32(cm->fc.tx_counts.p32x32[i], ct_32x32p);
for (j = 0; j < TX_SIZE_MAX_SB - 1; j++)
vp9_cond_prob_diff_update(w, &cm->fc.tx_probs.p32x32[i][j],
VP9_MODE_UPDATE_PROB, ct_32x32p[j]);
}
}
#ifdef MODE_STATS
if (!cpi->dummy_packing)
......@@ -1505,9 +1503,7 @@ void vp9_pack_bitstream(VP9_COMP *cpi, uint8_t *dest, unsigned long *size) {
vp9_copy(fc->pre_comp_inter_prob, fc->comp_inter_prob);
vp9_copy(fc->pre_comp_ref_prob, fc->comp_ref_prob);
vp9_copy(fc->pre_single_ref_prob, fc->single_ref_prob);
vp9_copy(fc->pre_tx_probs_8x8p, fc->tx_probs_8x8p);
vp9_copy(fc->pre_tx_probs_16x16p, fc->tx_probs_16x16p);
vp9_copy(fc->pre_tx_probs_32x32p, fc->tx_probs_32x32p);
fc->pre_tx_probs = fc->tx_probs;
vp9_copy(fc->pre_mbskip_probs, fc->mbskip_probs);
first_part_size = write_compressed_header(cpi, data);
......
......@@ -1733,9 +1733,7 @@ static void init_encode_frame_mb_context(VP9_COMP *cpi) {
vp9_zero(cpi->comp_inter_count);
vp9_zero(cpi->single_ref_count);
vp9_zero(cpi->comp_ref_count);
vp9_zero(cm->fc.tx_count_32x32p);
vp9_zero(cm->fc.tx_count_16x16p);
vp9_zero(cm->fc.tx_count_8x8p);
vp9_zero(cm->fc.tx_counts);
vp9_zero(cm->fc.mbskip_count);
// Note: this memset assumes above_context[0], [1] and [2]
......@@ -2177,28 +2175,28 @@ void vp9_encode_frame(VP9_COMP *cpi) {
int count32x32 = 0;
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count4x4 += cm->fc.tx_count_32x32p[i][TX_4X4];
count4x4 += cm->fc.tx_counts.p32x32[i][TX_4X4];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count4x4 += cm->fc.tx_count_16x16p[i][TX_4X4];
count4x4 += cm->fc.tx_counts.p16x16[i][TX_4X4];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count4x4 += cm->fc.tx_count_8x8p[i][TX_4X4];
count4x4 += cm->fc.tx_counts.p8x8[i][TX_4X4];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count8x8_lp += cm->fc.tx_count_32x32p[i][TX_8X8];
count8x8_lp += cm->fc.tx_counts.p32x32[i][TX_8X8];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count8x8_lp += cm->fc.tx_count_16x16p[i][TX_8X8];
count8x8_lp += cm->fc.tx_counts.p16x16[i][TX_8X8];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count8x8_8x8p += cm->fc.tx_count_8x8p[i][TX_8X8];
count8x8_8x8p += cm->fc.tx_counts.p8x8[i][TX_8X8];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count16x16_16x16p += cm->fc.tx_count_16x16p[i][TX_16X16];
count16x16_16x16p += cm->fc.tx_counts.p16x16[i][TX_16X16];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count16x16_lp += cm->fc.tx_count_32x32p[i][TX_16X16];
count16x16_lp += cm->fc.tx_counts.p32x32[i][TX_16X16];
for (i = 0; i < TX_SIZE_CONTEXTS; i++)
count32x32 += cm->fc.tx_count_32x32p[i][TX_32X32];
count32x32 += cm->fc.tx_counts.p32x32[i][TX_32X32];
if (count4x4 == 0 && count16x16_lp == 0 && count16x16_16x16p == 0
&& count32x32 == 0) {
......@@ -2374,11 +2372,11 @@ static void encode_superblock(VP9_COMP *cpi, TOKENEXTRA **t, int output_enabled,
vp9_segfeature_active(&xd->seg, segment_id, SEG_LVL_SKIP)))) {
const int context = vp9_get_pred_context_tx_size(cm, xd);
if (bsize >= BLOCK_SIZE_SB32X32) {
cm->fc.tx_count_32x32p[context][mbmi->txfm_size]++;
cm->fc.tx_counts.p32x32[context][mbmi->txfm_size]++;
} else if (bsize >= BLOCK_SIZE_MB16X16) {
cm->fc.tx_count_16x16p[context][mbmi->txfm_size]++;
cm->fc.tx_counts.p16x16[context][mbmi->txfm_size]++;
} else {
cm->fc.tx_count_8x8p[context][mbmi->txfm_size]++;
cm->fc.tx_counts.p8x8[context][mbmi->txfm_size]++;
}
} else {
int x, y;
......
......@@ -89,9 +89,7 @@ typedef struct {
int inter_mode_counts[INTER_MODE_CONTEXTS][VP9_INTER_MODES - 1][2];
vp9_prob inter_mode_probs[INTER_MODE_CONTEXTS][VP9_INTER_MODES - 1];
vp9_prob tx_probs_8x8p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 3];
vp9_prob tx_probs_16x16p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 2];
vp9_prob tx_probs_32x32p[TX_SIZE_CONTEXTS][TX_SIZE_MAX_SB - 1];
struct tx_probs tx_probs;
vp9_prob mbskip_probs[MBSKIP_CONTEXTS];
} CODING_CONTEXT;
......
......@@ -142,9 +142,7 @@ void vp9_save_coding_context(VP9_COMP *cpi) {
vp9_copy(cc->coef_probs, cm->fc.coef_probs);
vp9_copy(cc->switchable_interp_prob, cm->fc.switchable_interp_prob);
vp9_copy(cc->tx_probs_8x8p, cm->fc.tx_probs_8x8p);
vp9_copy(cc->tx_probs_16x16p, cm->fc.tx_probs_16x16p);
vp9_copy(cc->tx_probs_32x32p, cm->fc.tx_probs_32x32p);
cc->tx_probs = cm->fc.tx_probs;
vp9_copy(cc->mbskip_probs, cm->fc.mbskip_probs);
}
......@@ -183,9 +181,7 @@ void vp9_restore_coding_context(VP9_COMP *cpi) {
vp9_copy(cm->fc.coef_probs, cc->coef_probs);
vp9_copy(cm->fc.switchable_interp_prob, cc->switchable_interp_prob);
vp9_copy(cm->fc.tx_probs_8x8p, cc->tx_probs_8x8p);
vp9_copy(cm->fc.tx_probs_16x16p, cc->tx_probs_16x16p);
vp9_copy(cm->fc.tx_probs_32x32p, cc->tx_probs_32x32p);
cm->fc.tx_probs = cc->tx_probs;
vp9_copy(cm->fc.mbskip_probs, cc->mbskip_probs);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment