/src/libvpx/vp9/encoder/vp9_segmentation.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
3 | | * |
4 | | * Use of this source code is governed by a BSD-style license |
5 | | * that can be found in the LICENSE file in the root of the source |
6 | | * tree. An additional intellectual property rights grant can be found |
7 | | * in the file PATENTS. All contributing project authors may |
8 | | * be found in the AUTHORS file in the root of the source tree. |
9 | | */ |
10 | | |
11 | | #include <limits.h> |
12 | | #include <math.h> |
13 | | |
14 | | #include "vpx_mem/vpx_mem.h" |
15 | | |
16 | | #include "vp9/common/vp9_pred_common.h" |
17 | | #include "vp9/common/vp9_tile_common.h" |
18 | | |
19 | | #include "vp9/encoder/vp9_cost.h" |
20 | | #include "vp9/encoder/vp9_segmentation.h" |
21 | | |
22 | 0 | void vp9_enable_segmentation(struct segmentation *seg) { |
23 | 0 | seg->enabled = 1; |
24 | 0 | seg->update_map = 1; |
25 | 0 | seg->update_data = 1; |
26 | 0 | } |
27 | | |
28 | 0 | void vp9_disable_segmentation(struct segmentation *seg) { |
29 | 0 | seg->enabled = 0; |
30 | 0 | seg->update_map = 0; |
31 | 0 | seg->update_data = 0; |
32 | 0 | } |
33 | | |
34 | | void vp9_set_segment_data(struct segmentation *seg, signed char *feature_data, |
35 | 0 | unsigned char abs_delta) { |
36 | 0 | seg->abs_delta = abs_delta; |
37 | |
|
38 | 0 | memcpy(seg->feature_data, feature_data, sizeof(seg->feature_data)); |
39 | 0 | } |
40 | | void vp9_disable_segfeature(struct segmentation *seg, int segment_id, |
41 | 15.5k | SEG_LVL_FEATURES feature_id) { |
42 | 15.5k | seg->feature_mask[segment_id] &= ~(1u << feature_id); |
43 | 15.5k | } |
44 | | |
45 | | void vp9_clear_segdata(struct segmentation *seg, int segment_id, |
46 | 0 | SEG_LVL_FEATURES feature_id) { |
47 | 0 | seg->feature_data[segment_id][feature_id] = 0; |
48 | 0 | } |
49 | | |
50 | 0 | void vp9_psnr_aq_mode_setup(struct segmentation *seg) { |
51 | 0 | int i; |
52 | |
|
53 | 0 | vp9_enable_segmentation(seg); |
54 | 0 | vp9_clearall_segfeatures(seg); |
55 | 0 | seg->abs_delta = SEGMENT_DELTADATA; |
56 | |
|
57 | 0 | for (i = 0; i < MAX_SEGMENTS; ++i) { |
58 | 0 | vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 2 * (i - (MAX_SEGMENTS / 2))); |
59 | 0 | vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi, |
64 | 0 | struct segmentation *seg) { |
65 | 0 | const VP9_COMMON *cm = &cpi->common; |
66 | 0 | const int seg_counts = cpi->kmeans_ctr_num; |
67 | 0 | const int base_qindex = cm->base_qindex; |
68 | 0 | const double base_qstep = vp9_convert_qindex_to_q(base_qindex, cm->bit_depth); |
69 | 0 | const double mid_ctr = cpi->kmeans_ctr_ls[seg_counts / 2]; |
70 | 0 | const double var_diff_scale = 4.0; |
71 | 0 | int i; |
72 | |
|
73 | 0 | assert(seg_counts <= MAX_SEGMENTS); |
74 | |
|
75 | 0 | vp9_enable_segmentation(seg); |
76 | 0 | vp9_clearall_segfeatures(seg); |
77 | 0 | seg->abs_delta = SEGMENT_DELTADATA; |
78 | |
|
79 | 0 | for (i = 0; i < seg_counts / 2; ++i) { |
80 | 0 | double wiener_var_diff = mid_ctr - cpi->kmeans_ctr_ls[i]; |
81 | 0 | double target_qstep = base_qstep / (1.0 + wiener_var_diff / var_diff_scale); |
82 | 0 | int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth); |
83 | 0 | assert(wiener_var_diff >= 0.0); |
84 | |
|
85 | 0 | vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex); |
86 | 0 | vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); |
87 | 0 | } |
88 | |
|
89 | 0 | vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 0); |
90 | 0 | vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); |
91 | |
|
92 | 0 | for (; i < seg_counts; ++i) { |
93 | 0 | double wiener_var_diff = cpi->kmeans_ctr_ls[i] - mid_ctr; |
94 | 0 | double target_qstep = base_qstep * (1.0 + wiener_var_diff / var_diff_scale); |
95 | 0 | int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth); |
96 | 0 | assert(wiener_var_diff >= 0.0); |
97 | |
|
98 | 0 | vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex); |
99 | 0 | vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q); |
100 | 0 | } |
101 | 0 | } |
102 | | |
103 | | // Based on set of segment counts calculate a probability tree |
104 | 0 | static void calc_segtree_probs(int *segcounts, vpx_prob *segment_tree_probs) { |
105 | | // Work out probabilities of each segment |
106 | 0 | const int c01 = segcounts[0] + segcounts[1]; |
107 | 0 | const int c23 = segcounts[2] + segcounts[3]; |
108 | 0 | const int c45 = segcounts[4] + segcounts[5]; |
109 | 0 | const int c67 = segcounts[6] + segcounts[7]; |
110 | |
|
111 | 0 | segment_tree_probs[0] = get_binary_prob(c01 + c23, c45 + c67); |
112 | 0 | segment_tree_probs[1] = get_binary_prob(c01, c23); |
113 | 0 | segment_tree_probs[2] = get_binary_prob(c45, c67); |
114 | 0 | segment_tree_probs[3] = get_binary_prob(segcounts[0], segcounts[1]); |
115 | 0 | segment_tree_probs[4] = get_binary_prob(segcounts[2], segcounts[3]); |
116 | 0 | segment_tree_probs[5] = get_binary_prob(segcounts[4], segcounts[5]); |
117 | 0 | segment_tree_probs[6] = get_binary_prob(segcounts[6], segcounts[7]); |
118 | 0 | } |
119 | | |
120 | | // Based on set of segment counts and probabilities calculate a cost estimate |
121 | 0 | static int cost_segmap(int *segcounts, vpx_prob *probs) { |
122 | 0 | const int c01 = segcounts[0] + segcounts[1]; |
123 | 0 | const int c23 = segcounts[2] + segcounts[3]; |
124 | 0 | const int c45 = segcounts[4] + segcounts[5]; |
125 | 0 | const int c67 = segcounts[6] + segcounts[7]; |
126 | 0 | const int c0123 = c01 + c23; |
127 | 0 | const int c4567 = c45 + c67; |
128 | | |
129 | | // Cost the top node of the tree |
130 | 0 | int cost = c0123 * vp9_cost_zero(probs[0]) + c4567 * vp9_cost_one(probs[0]); |
131 | | |
132 | | // Cost subsequent levels |
133 | 0 | if (c0123 > 0) { |
134 | 0 | cost += c01 * vp9_cost_zero(probs[1]) + c23 * vp9_cost_one(probs[1]); |
135 | |
|
136 | 0 | if (c01 > 0) |
137 | 0 | cost += segcounts[0] * vp9_cost_zero(probs[3]) + |
138 | 0 | segcounts[1] * vp9_cost_one(probs[3]); |
139 | 0 | if (c23 > 0) |
140 | 0 | cost += segcounts[2] * vp9_cost_zero(probs[4]) + |
141 | 0 | segcounts[3] * vp9_cost_one(probs[4]); |
142 | 0 | } |
143 | |
|
144 | 0 | if (c4567 > 0) { |
145 | 0 | cost += c45 * vp9_cost_zero(probs[2]) + c67 * vp9_cost_one(probs[2]); |
146 | |
|
147 | 0 | if (c45 > 0) |
148 | 0 | cost += segcounts[4] * vp9_cost_zero(probs[5]) + |
149 | 0 | segcounts[5] * vp9_cost_one(probs[5]); |
150 | 0 | if (c67 > 0) |
151 | 0 | cost += segcounts[6] * vp9_cost_zero(probs[6]) + |
152 | 0 | segcounts[7] * vp9_cost_one(probs[6]); |
153 | 0 | } |
154 | |
|
155 | 0 | return cost; |
156 | 0 | } |
157 | | |
158 | | static void count_segs(const VP9_COMMON *cm, MACROBLOCKD *xd, |
159 | | const TileInfo *tile, MODE_INFO **mi, |
160 | | int *no_pred_segcounts, |
161 | | int (*temporal_predictor_count)[2], |
162 | | int *t_unpred_seg_counts, int bw, int bh, int mi_row, |
163 | 0 | int mi_col) { |
164 | 0 | int segment_id; |
165 | |
|
166 | 0 | if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; |
167 | | |
168 | 0 | xd->mi = mi; |
169 | 0 | segment_id = xd->mi[0]->segment_id; |
170 | |
|
171 | 0 | set_mi_row_col(xd, tile, mi_row, bh, mi_col, bw, cm->mi_rows, cm->mi_cols); |
172 | | |
173 | | // Count the number of hits on each segment with no prediction |
174 | 0 | no_pred_segcounts[segment_id]++; |
175 | | |
176 | | // Temporal prediction not allowed on key frames |
177 | 0 | if (cm->frame_type != KEY_FRAME) { |
178 | 0 | const BLOCK_SIZE bsize = xd->mi[0]->sb_type; |
179 | | // Test to see if the segment id matches the predicted value. |
180 | 0 | const int pred_segment_id = |
181 | 0 | get_segment_id(cm, cm->last_frame_seg_map, bsize, mi_row, mi_col); |
182 | 0 | const int pred_flag = pred_segment_id == segment_id; |
183 | 0 | const int pred_context = vp9_get_pred_context_seg_id(xd); |
184 | | |
185 | | // Store the prediction status for this mb and update counts |
186 | | // as appropriate |
187 | 0 | xd->mi[0]->seg_id_predicted = pred_flag; |
188 | 0 | temporal_predictor_count[pred_context][pred_flag]++; |
189 | | |
190 | | // Update the "unpredicted" segment count |
191 | 0 | if (!pred_flag) t_unpred_seg_counts[segment_id]++; |
192 | 0 | } |
193 | 0 | } |
194 | | |
195 | | static void count_segs_sb(const VP9_COMMON *cm, MACROBLOCKD *xd, |
196 | | const TileInfo *tile, MODE_INFO **mi, |
197 | | int *no_pred_segcounts, |
198 | | int (*temporal_predictor_count)[2], |
199 | | int *t_unpred_seg_counts, int mi_row, int mi_col, |
200 | 0 | BLOCK_SIZE bsize) { |
201 | 0 | const int mis = cm->mi_stride; |
202 | 0 | int bw, bh; |
203 | 0 | const int bs = num_8x8_blocks_wide_lookup[bsize], hbs = bs / 2; |
204 | |
|
205 | 0 | if (mi_row >= cm->mi_rows || mi_col >= cm->mi_cols) return; |
206 | | |
207 | 0 | bw = num_8x8_blocks_wide_lookup[mi[0]->sb_type]; |
208 | 0 | bh = num_8x8_blocks_high_lookup[mi[0]->sb_type]; |
209 | |
|
210 | 0 | if (bw == bs && bh == bs) { |
211 | 0 | count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count, |
212 | 0 | t_unpred_seg_counts, bs, bs, mi_row, mi_col); |
213 | 0 | } else if (bw == bs && bh < bs) { |
214 | 0 | count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count, |
215 | 0 | t_unpred_seg_counts, bs, hbs, mi_row, mi_col); |
216 | 0 | count_segs(cm, xd, tile, mi + hbs * mis, no_pred_segcounts, |
217 | 0 | temporal_predictor_count, t_unpred_seg_counts, bs, hbs, |
218 | 0 | mi_row + hbs, mi_col); |
219 | 0 | } else if (bw < bs && bh == bs) { |
220 | 0 | count_segs(cm, xd, tile, mi, no_pred_segcounts, temporal_predictor_count, |
221 | 0 | t_unpred_seg_counts, hbs, bs, mi_row, mi_col); |
222 | 0 | count_segs(cm, xd, tile, mi + hbs, no_pred_segcounts, |
223 | 0 | temporal_predictor_count, t_unpred_seg_counts, hbs, bs, mi_row, |
224 | 0 | mi_col + hbs); |
225 | 0 | } else { |
226 | 0 | const BLOCK_SIZE subsize = subsize_lookup[PARTITION_SPLIT][bsize]; |
227 | 0 | int n; |
228 | |
|
229 | 0 | assert(bw < bs && bh < bs); |
230 | |
|
231 | 0 | for (n = 0; n < 4; n++) { |
232 | 0 | const int mi_dc = hbs * (n & 1); |
233 | 0 | const int mi_dr = hbs * (n >> 1); |
234 | |
|
235 | 0 | count_segs_sb(cm, xd, tile, &mi[mi_dr * mis + mi_dc], no_pred_segcounts, |
236 | 0 | temporal_predictor_count, t_unpred_seg_counts, |
237 | 0 | mi_row + mi_dr, mi_col + mi_dc, subsize); |
238 | 0 | } |
239 | 0 | } |
240 | 0 | } |
241 | | |
242 | 0 | void vp9_choose_segmap_coding_method(VP9_COMMON *cm, MACROBLOCKD *xd) { |
243 | 0 | struct segmentation *seg = &cm->seg; |
244 | |
|
245 | 0 | int no_pred_cost; |
246 | 0 | int t_pred_cost = INT_MAX; |
247 | |
|
248 | 0 | int i, tile_col, mi_row, mi_col; |
249 | |
|
250 | 0 | int temporal_predictor_count[PREDICTION_PROBS][2] = { { 0 } }; |
251 | 0 | int no_pred_segcounts[MAX_SEGMENTS] = { 0 }; |
252 | 0 | int t_unpred_seg_counts[MAX_SEGMENTS] = { 0 }; |
253 | |
|
254 | 0 | vpx_prob no_pred_tree[SEG_TREE_PROBS]; |
255 | 0 | vpx_prob t_pred_tree[SEG_TREE_PROBS]; |
256 | 0 | vpx_prob t_nopred_prob[PREDICTION_PROBS]; |
257 | | |
258 | | // Set default state for the segment tree probabilities and the |
259 | | // temporal coding probabilities |
260 | 0 | memset(seg->tree_probs, 255, sizeof(seg->tree_probs)); |
261 | 0 | memset(seg->pred_probs, 255, sizeof(seg->pred_probs)); |
262 | | |
263 | | // First of all generate stats regarding how well the last segment map |
264 | | // predicts this one |
265 | 0 | for (tile_col = 0; tile_col < 1 << cm->log2_tile_cols; tile_col++) { |
266 | 0 | TileInfo tile; |
267 | 0 | MODE_INFO **mi_ptr; |
268 | 0 | vp9_tile_init(&tile, cm, 0, tile_col); |
269 | |
|
270 | 0 | mi_ptr = cm->mi_grid_visible + tile.mi_col_start; |
271 | 0 | for (mi_row = 0; mi_row < cm->mi_rows; |
272 | 0 | mi_row += 8, mi_ptr += 8 * cm->mi_stride) { |
273 | 0 | MODE_INFO **mi = mi_ptr; |
274 | 0 | for (mi_col = tile.mi_col_start; mi_col < tile.mi_col_end; |
275 | 0 | mi_col += 8, mi += 8) |
276 | 0 | count_segs_sb(cm, xd, &tile, mi, no_pred_segcounts, |
277 | 0 | temporal_predictor_count, t_unpred_seg_counts, mi_row, |
278 | 0 | mi_col, BLOCK_64X64); |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | | // Work out probability tree for coding segments without prediction |
283 | | // and the cost. |
284 | 0 | calc_segtree_probs(no_pred_segcounts, no_pred_tree); |
285 | 0 | no_pred_cost = cost_segmap(no_pred_segcounts, no_pred_tree); |
286 | | |
287 | | // Key frames cannot use temporal prediction |
288 | 0 | if (!frame_is_intra_only(cm)) { |
289 | | // Work out probability tree for coding those segments not |
290 | | // predicted using the temporal method and the cost. |
291 | 0 | calc_segtree_probs(t_unpred_seg_counts, t_pred_tree); |
292 | 0 | t_pred_cost = cost_segmap(t_unpred_seg_counts, t_pred_tree); |
293 | | |
294 | | // Add in the cost of the signaling for each prediction context. |
295 | 0 | for (i = 0; i < PREDICTION_PROBS; i++) { |
296 | 0 | const int count0 = temporal_predictor_count[i][0]; |
297 | 0 | const int count1 = temporal_predictor_count[i][1]; |
298 | |
|
299 | 0 | t_nopred_prob[i] = get_binary_prob(count0, count1); |
300 | | |
301 | | // Add in the predictor signaling cost |
302 | 0 | t_pred_cost += count0 * vp9_cost_zero(t_nopred_prob[i]) + |
303 | 0 | count1 * vp9_cost_one(t_nopred_prob[i]); |
304 | 0 | } |
305 | 0 | } |
306 | | |
307 | | // Now choose which coding method to use. |
308 | 0 | if (t_pred_cost < no_pred_cost) { |
309 | 0 | seg->temporal_update = 1; |
310 | 0 | memcpy(seg->tree_probs, t_pred_tree, sizeof(t_pred_tree)); |
311 | 0 | memcpy(seg->pred_probs, t_nopred_prob, sizeof(t_nopred_prob)); |
312 | 0 | } else { |
313 | 0 | seg->temporal_update = 0; |
314 | 0 | memcpy(seg->tree_probs, no_pred_tree, sizeof(no_pred_tree)); |
315 | 0 | } |
316 | 0 | } |
317 | | |
318 | 33.4k | void vp9_reset_segment_features(struct segmentation *seg) { |
319 | | // Set up default state for MB feature flags |
320 | 33.4k | seg->enabled = 0; |
321 | 33.4k | seg->update_map = 0; |
322 | 33.4k | seg->update_data = 0; |
323 | 33.4k | memset(seg->tree_probs, 255, sizeof(seg->tree_probs)); |
324 | 33.4k | vp9_clearall_segfeatures(seg); |
325 | 33.4k | } |