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 | /* |
michael@0 | 3 | * Copyright (c) 2012 The WebM project authors. All Rights Reserved. |
michael@0 | 4 | * |
michael@0 | 5 | * Use of this source code is governed by a BSD-style license |
michael@0 | 6 | * that can be found in the LICENSE file in the root of the source |
michael@0 | 7 | * tree. An additional intellectual property rights grant can be found |
michael@0 | 8 | * in the file PATENTS. All contributing project authors may |
michael@0 | 9 | * be found in the AUTHORS file in the root of the source tree. |
michael@0 | 10 | */ |
michael@0 | 11 | |
michael@0 | 12 | #include "vp9/common/vp9_mvref_common.h" |
michael@0 | 13 | |
michael@0 | 14 | #define MVREF_NEIGHBOURS 8 |
michael@0 | 15 | |
michael@0 | 16 | typedef enum { |
michael@0 | 17 | BOTH_ZERO = 0, |
michael@0 | 18 | ZERO_PLUS_PREDICTED = 1, |
michael@0 | 19 | BOTH_PREDICTED = 2, |
michael@0 | 20 | NEW_PLUS_NON_INTRA = 3, |
michael@0 | 21 | BOTH_NEW = 4, |
michael@0 | 22 | INTRA_PLUS_NON_INTRA = 5, |
michael@0 | 23 | BOTH_INTRA = 6, |
michael@0 | 24 | INVALID_CASE = 9 |
michael@0 | 25 | } motion_vector_context; |
michael@0 | 26 | |
michael@0 | 27 | // This is used to figure out a context for the ref blocks. The code flattens |
michael@0 | 28 | // an array that would have 3 possible counts (0, 1 & 2) for 3 choices by |
michael@0 | 29 | // adding 9 for each intra block, 3 for each zero mv and 1 for each new |
michael@0 | 30 | // motion vector. This single number is then converted into a context |
michael@0 | 31 | // with a single lookup ( counter_to_context ). |
michael@0 | 32 | static const int mode_2_counter[MB_MODE_COUNT] = { |
michael@0 | 33 | 9, // DC_PRED |
michael@0 | 34 | 9, // V_PRED |
michael@0 | 35 | 9, // H_PRED |
michael@0 | 36 | 9, // D45_PRED |
michael@0 | 37 | 9, // D135_PRED |
michael@0 | 38 | 9, // D117_PRED |
michael@0 | 39 | 9, // D153_PRED |
michael@0 | 40 | 9, // D207_PRED |
michael@0 | 41 | 9, // D63_PRED |
michael@0 | 42 | 9, // TM_PRED |
michael@0 | 43 | 0, // NEARESTMV |
michael@0 | 44 | 0, // NEARMV |
michael@0 | 45 | 3, // ZEROMV |
michael@0 | 46 | 1, // NEWMV |
michael@0 | 47 | }; |
michael@0 | 48 | |
michael@0 | 49 | // There are 3^3 different combinations of 3 counts that can be either 0,1 or |
michael@0 | 50 | // 2. However the actual count can never be greater than 2 so the highest |
michael@0 | 51 | // counter we need is 18. 9 is an invalid counter that's never used. |
michael@0 | 52 | static const int counter_to_context[19] = { |
michael@0 | 53 | BOTH_PREDICTED, // 0 |
michael@0 | 54 | NEW_PLUS_NON_INTRA, // 1 |
michael@0 | 55 | BOTH_NEW, // 2 |
michael@0 | 56 | ZERO_PLUS_PREDICTED, // 3 |
michael@0 | 57 | NEW_PLUS_NON_INTRA, // 4 |
michael@0 | 58 | INVALID_CASE, // 5 |
michael@0 | 59 | BOTH_ZERO, // 6 |
michael@0 | 60 | INVALID_CASE, // 7 |
michael@0 | 61 | INVALID_CASE, // 8 |
michael@0 | 62 | INTRA_PLUS_NON_INTRA, // 9 |
michael@0 | 63 | INTRA_PLUS_NON_INTRA, // 10 |
michael@0 | 64 | INVALID_CASE, // 11 |
michael@0 | 65 | INTRA_PLUS_NON_INTRA, // 12 |
michael@0 | 66 | INVALID_CASE, // 13 |
michael@0 | 67 | INVALID_CASE, // 14 |
michael@0 | 68 | INVALID_CASE, // 15 |
michael@0 | 69 | INVALID_CASE, // 16 |
michael@0 | 70 | INVALID_CASE, // 17 |
michael@0 | 71 | BOTH_INTRA // 18 |
michael@0 | 72 | }; |
michael@0 | 73 | |
michael@0 | 74 | static const MV mv_ref_blocks[BLOCK_SIZES][MVREF_NEIGHBOURS] = { |
michael@0 | 75 | // 4X4 |
michael@0 | 76 | {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, |
michael@0 | 77 | // 4X8 |
michael@0 | 78 | {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, |
michael@0 | 79 | // 8X4 |
michael@0 | 80 | {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, |
michael@0 | 81 | // 8X8 |
michael@0 | 82 | {{-1, 0}, {0, -1}, {-1, -1}, {-2, 0}, {0, -2}, {-2, -1}, {-1, -2}, {-2, -2}}, |
michael@0 | 83 | // 8X16 |
michael@0 | 84 | {{0, -1}, {-1, 0}, {1, -1}, {-1, -1}, {0, -2}, {-2, 0}, {-2, -1}, {-1, -2}}, |
michael@0 | 85 | // 16X8 |
michael@0 | 86 | {{-1, 0}, {0, -1}, {-1, 1}, {-1, -1}, {-2, 0}, {0, -2}, {-1, -2}, {-2, -1}}, |
michael@0 | 87 | // 16X16 |
michael@0 | 88 | {{-1, 0}, {0, -1}, {-1, 1}, {1, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}}, |
michael@0 | 89 | // 16X32 |
michael@0 | 90 | {{0, -1}, {-1, 0}, {2, -1}, {-1, -1}, {-1, 1}, {0, -3}, {-3, 0}, {-3, -3}}, |
michael@0 | 91 | // 32X16 |
michael@0 | 92 | {{-1, 0}, {0, -1}, {-1, 2}, {-1, -1}, {1, -1}, {-3, 0}, {0, -3}, {-3, -3}}, |
michael@0 | 93 | // 32X32 |
michael@0 | 94 | {{-1, 1}, {1, -1}, {-1, 2}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-3, -3}}, |
michael@0 | 95 | // 32X64 |
michael@0 | 96 | {{0, -1}, {-1, 0}, {4, -1}, {-1, 2}, {-1, -1}, {0, -3}, {-3, 0}, {2, -1}}, |
michael@0 | 97 | // 64X32 |
michael@0 | 98 | {{-1, 0}, {0, -1}, {-1, 4}, {2, -1}, {-1, -1}, {-3, 0}, {0, -3}, {-1, 2}}, |
michael@0 | 99 | // 64X64 |
michael@0 | 100 | {{-1, 3}, {3, -1}, {-1, 4}, {4, -1}, {-1, -1}, {-1, 0}, {0, -1}, {-1, 6}} |
michael@0 | 101 | }; |
michael@0 | 102 | |
michael@0 | 103 | static const int idx_n_column_to_subblock[4][2] = { |
michael@0 | 104 | {1, 2}, |
michael@0 | 105 | {1, 3}, |
michael@0 | 106 | {3, 2}, |
michael@0 | 107 | {3, 3} |
michael@0 | 108 | }; |
michael@0 | 109 | |
michael@0 | 110 | // clamp_mv_ref |
michael@0 | 111 | #define MV_BORDER (16 << 3) // Allow 16 pels in 1/8th pel units |
michael@0 | 112 | |
michael@0 | 113 | static void clamp_mv_ref(MV *mv, const MACROBLOCKD *xd) { |
michael@0 | 114 | clamp_mv(mv, xd->mb_to_left_edge - MV_BORDER, |
michael@0 | 115 | xd->mb_to_right_edge + MV_BORDER, |
michael@0 | 116 | xd->mb_to_top_edge - MV_BORDER, |
michael@0 | 117 | xd->mb_to_bottom_edge + MV_BORDER); |
michael@0 | 118 | } |
michael@0 | 119 | |
michael@0 | 120 | // This function returns either the appropriate sub block or block's mv |
michael@0 | 121 | // on whether the block_size < 8x8 and we have check_sub_blocks set. |
michael@0 | 122 | static INLINE int_mv get_sub_block_mv(const MODE_INFO *candidate, int which_mv, |
michael@0 | 123 | int search_col, int block_idx) { |
michael@0 | 124 | return block_idx >= 0 && candidate->mbmi.sb_type < BLOCK_8X8 |
michael@0 | 125 | ? candidate->bmi[idx_n_column_to_subblock[block_idx][search_col == 0]] |
michael@0 | 126 | .as_mv[which_mv] |
michael@0 | 127 | : candidate->mbmi.mv[which_mv]; |
michael@0 | 128 | } |
michael@0 | 129 | |
michael@0 | 130 | |
michael@0 | 131 | // Performs mv sign inversion if indicated by the reference frame combination. |
michael@0 | 132 | static INLINE int_mv scale_mv(const MB_MODE_INFO *mbmi, int ref, |
michael@0 | 133 | const MV_REFERENCE_FRAME this_ref_frame, |
michael@0 | 134 | const int *ref_sign_bias) { |
michael@0 | 135 | int_mv mv = mbmi->mv[ref]; |
michael@0 | 136 | if (ref_sign_bias[mbmi->ref_frame[ref]] != ref_sign_bias[this_ref_frame]) { |
michael@0 | 137 | mv.as_mv.row *= -1; |
michael@0 | 138 | mv.as_mv.col *= -1; |
michael@0 | 139 | } |
michael@0 | 140 | return mv; |
michael@0 | 141 | } |
michael@0 | 142 | |
michael@0 | 143 | // This macro is used to add a motion vector mv_ref list if it isn't |
michael@0 | 144 | // already in the list. If it's the second motion vector it will also |
michael@0 | 145 | // skip all additional processing and jump to done! |
michael@0 | 146 | #define ADD_MV_REF_LIST(MV) \ |
michael@0 | 147 | do { \ |
michael@0 | 148 | if (refmv_count) { \ |
michael@0 | 149 | if ((MV).as_int != mv_ref_list[0].as_int) { \ |
michael@0 | 150 | mv_ref_list[refmv_count] = (MV); \ |
michael@0 | 151 | goto Done; \ |
michael@0 | 152 | } \ |
michael@0 | 153 | } else { \ |
michael@0 | 154 | mv_ref_list[refmv_count++] = (MV); \ |
michael@0 | 155 | } \ |
michael@0 | 156 | } while (0) |
michael@0 | 157 | |
michael@0 | 158 | // If either reference frame is different, not INTRA, and they |
michael@0 | 159 | // are different from each other scale and add the mv to our list. |
michael@0 | 160 | #define IF_DIFF_REF_FRAME_ADD_MV(CANDIDATE) \ |
michael@0 | 161 | do { \ |
michael@0 | 162 | if ((CANDIDATE)->ref_frame[0] != ref_frame) \ |
michael@0 | 163 | ADD_MV_REF_LIST(scale_mv((CANDIDATE), 0, ref_frame, ref_sign_bias)); \ |
michael@0 | 164 | if ((CANDIDATE)->ref_frame[1] != ref_frame && \ |
michael@0 | 165 | has_second_ref(CANDIDATE) && \ |
michael@0 | 166 | (CANDIDATE)->mv[1].as_int != (CANDIDATE)->mv[0].as_int) \ |
michael@0 | 167 | ADD_MV_REF_LIST(scale_mv((CANDIDATE), 1, ref_frame, ref_sign_bias)); \ |
michael@0 | 168 | } while (0) |
michael@0 | 169 | |
michael@0 | 170 | |
michael@0 | 171 | // Checks that the given mi_row, mi_col and search point |
michael@0 | 172 | // are inside the borders of the tile. |
michael@0 | 173 | static INLINE int is_inside(const TileInfo *const tile, |
michael@0 | 174 | int mi_col, int mi_row, int mi_rows, |
michael@0 | 175 | const MV *mv) { |
michael@0 | 176 | return !(mi_row + mv->row < 0 || |
michael@0 | 177 | mi_col + mv->col < tile->mi_col_start || |
michael@0 | 178 | mi_row + mv->row >= mi_rows || |
michael@0 | 179 | mi_col + mv->col >= tile->mi_col_end); |
michael@0 | 180 | } |
michael@0 | 181 | |
michael@0 | 182 | // This function searches the neighbourhood of a given MB/SB |
michael@0 | 183 | // to try and find candidate reference vectors. |
michael@0 | 184 | void vp9_find_mv_refs_idx(const VP9_COMMON *cm, const MACROBLOCKD *xd, |
michael@0 | 185 | const TileInfo *const tile, |
michael@0 | 186 | MODE_INFO *mi, const MODE_INFO *prev_mi, |
michael@0 | 187 | MV_REFERENCE_FRAME ref_frame, |
michael@0 | 188 | int_mv *mv_ref_list, |
michael@0 | 189 | int block_idx, |
michael@0 | 190 | int mi_row, int mi_col) { |
michael@0 | 191 | const int *ref_sign_bias = cm->ref_frame_sign_bias; |
michael@0 | 192 | int i, refmv_count = 0; |
michael@0 | 193 | const MV *const mv_ref_search = mv_ref_blocks[mi->mbmi.sb_type]; |
michael@0 | 194 | const MB_MODE_INFO *const prev_mbmi = prev_mi ? &prev_mi->mbmi : NULL; |
michael@0 | 195 | int different_ref_found = 0; |
michael@0 | 196 | int context_counter = 0; |
michael@0 | 197 | |
michael@0 | 198 | // Blank the reference vector list |
michael@0 | 199 | vpx_memset(mv_ref_list, 0, sizeof(*mv_ref_list) * MAX_MV_REF_CANDIDATES); |
michael@0 | 200 | |
michael@0 | 201 | // The nearest 2 blocks are treated differently |
michael@0 | 202 | // if the size < 8x8 we get the mv from the bmi substructure, |
michael@0 | 203 | // and we also need to keep a mode count. |
michael@0 | 204 | for (i = 0; i < 2; ++i) { |
michael@0 | 205 | const MV *const mv_ref = &mv_ref_search[i]; |
michael@0 | 206 | if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { |
michael@0 | 207 | const MODE_INFO *const candidate_mi = xd->mi_8x8[mv_ref->col + mv_ref->row |
michael@0 | 208 | * xd->mode_info_stride]; |
michael@0 | 209 | const MB_MODE_INFO *const candidate = &candidate_mi->mbmi; |
michael@0 | 210 | // Keep counts for entropy encoding. |
michael@0 | 211 | context_counter += mode_2_counter[candidate->mode]; |
michael@0 | 212 | |
michael@0 | 213 | // Check if the candidate comes from the same reference frame. |
michael@0 | 214 | if (candidate->ref_frame[0] == ref_frame) { |
michael@0 | 215 | ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 0, |
michael@0 | 216 | mv_ref->col, block_idx)); |
michael@0 | 217 | different_ref_found = candidate->ref_frame[1] != ref_frame; |
michael@0 | 218 | } else { |
michael@0 | 219 | if (candidate->ref_frame[1] == ref_frame) |
michael@0 | 220 | // Add second motion vector if it has the same ref_frame. |
michael@0 | 221 | ADD_MV_REF_LIST(get_sub_block_mv(candidate_mi, 1, |
michael@0 | 222 | mv_ref->col, block_idx)); |
michael@0 | 223 | different_ref_found = 1; |
michael@0 | 224 | } |
michael@0 | 225 | } |
michael@0 | 226 | } |
michael@0 | 227 | |
michael@0 | 228 | // Check the rest of the neighbors in much the same way |
michael@0 | 229 | // as before except we don't need to keep track of sub blocks or |
michael@0 | 230 | // mode counts. |
michael@0 | 231 | for (; i < MVREF_NEIGHBOURS; ++i) { |
michael@0 | 232 | const MV *const mv_ref = &mv_ref_search[i]; |
michael@0 | 233 | if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { |
michael@0 | 234 | const MB_MODE_INFO *const candidate = &xd->mi_8x8[mv_ref->col + |
michael@0 | 235 | mv_ref->row |
michael@0 | 236 | * xd->mode_info_stride]->mbmi; |
michael@0 | 237 | |
michael@0 | 238 | if (candidate->ref_frame[0] == ref_frame) { |
michael@0 | 239 | ADD_MV_REF_LIST(candidate->mv[0]); |
michael@0 | 240 | different_ref_found = candidate->ref_frame[1] != ref_frame; |
michael@0 | 241 | } else { |
michael@0 | 242 | if (candidate->ref_frame[1] == ref_frame) |
michael@0 | 243 | ADD_MV_REF_LIST(candidate->mv[1]); |
michael@0 | 244 | different_ref_found = 1; |
michael@0 | 245 | } |
michael@0 | 246 | } |
michael@0 | 247 | } |
michael@0 | 248 | |
michael@0 | 249 | // Check the last frame's mode and mv info. |
michael@0 | 250 | if (prev_mbmi) { |
michael@0 | 251 | if (prev_mbmi->ref_frame[0] == ref_frame) |
michael@0 | 252 | ADD_MV_REF_LIST(prev_mbmi->mv[0]); |
michael@0 | 253 | else if (prev_mbmi->ref_frame[1] == ref_frame) |
michael@0 | 254 | ADD_MV_REF_LIST(prev_mbmi->mv[1]); |
michael@0 | 255 | } |
michael@0 | 256 | |
michael@0 | 257 | // Since we couldn't find 2 mvs from the same reference frame |
michael@0 | 258 | // go back through the neighbors and find motion vectors from |
michael@0 | 259 | // different reference frames. |
michael@0 | 260 | if (different_ref_found) { |
michael@0 | 261 | for (i = 0; i < MVREF_NEIGHBOURS; ++i) { |
michael@0 | 262 | const MV *mv_ref = &mv_ref_search[i]; |
michael@0 | 263 | if (is_inside(tile, mi_col, mi_row, cm->mi_rows, mv_ref)) { |
michael@0 | 264 | const MB_MODE_INFO *const candidate = &xd->mi_8x8[mv_ref->col + |
michael@0 | 265 | mv_ref->row |
michael@0 | 266 | * xd->mode_info_stride]->mbmi; |
michael@0 | 267 | |
michael@0 | 268 | // If the candidate is INTRA we don't want to consider its mv. |
michael@0 | 269 | if (is_inter_block(candidate)) |
michael@0 | 270 | IF_DIFF_REF_FRAME_ADD_MV(candidate); |
michael@0 | 271 | } |
michael@0 | 272 | } |
michael@0 | 273 | } |
michael@0 | 274 | |
michael@0 | 275 | // Since we still don't have a candidate we'll try the last frame. |
michael@0 | 276 | if (prev_mbmi && is_inter_block(prev_mbmi)) |
michael@0 | 277 | IF_DIFF_REF_FRAME_ADD_MV(prev_mbmi); |
michael@0 | 278 | |
michael@0 | 279 | Done: |
michael@0 | 280 | |
michael@0 | 281 | mi->mbmi.mode_context[ref_frame] = counter_to_context[context_counter]; |
michael@0 | 282 | |
michael@0 | 283 | // Clamp vectors |
michael@0 | 284 | for (i = 0; i < MAX_MV_REF_CANDIDATES; ++i) |
michael@0 | 285 | clamp_mv_ref(&mv_ref_list[i].as_mv, xd); |
michael@0 | 286 | } |