media/libvpx/vp9/encoder/vp9_segmentation.c

Thu, 15 Jan 2015 15:59:08 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:59:08 +0100
branch
TOR_BUG_9701
changeset 10
ac0c01689b40
permissions
-rw-r--r--

Implement a real Private Browsing Mode condition by changing the API/ABI;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

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

mercurial