Thu, 15 Jan 2015 15:59:08 +0100
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 | } |