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) 2010 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 "./vpx_scale_rtcd.h" |
michael@0 | 13 | #include "vp8/common/onyxc_int.h" |
michael@0 | 14 | #include "onyx_int.h" |
michael@0 | 15 | #include "quantize.h" |
michael@0 | 16 | #include "vpx_mem/vpx_mem.h" |
michael@0 | 17 | #include "vpx_scale/vpx_scale.h" |
michael@0 | 18 | #include "vp8/common/alloccommon.h" |
michael@0 | 19 | #include "vp8/common/loopfilter.h" |
michael@0 | 20 | #if ARCH_ARM |
michael@0 | 21 | #include "vpx_ports/arm.h" |
michael@0 | 22 | #endif |
michael@0 | 23 | |
michael@0 | 24 | extern int vp8_calc_ss_err(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *dest); |
michael@0 | 25 | |
michael@0 | 26 | void vp8_yv12_copy_partial_frame_c(YV12_BUFFER_CONFIG *src_ybc, |
michael@0 | 27 | YV12_BUFFER_CONFIG *dst_ybc) |
michael@0 | 28 | { |
michael@0 | 29 | unsigned char *src_y, *dst_y; |
michael@0 | 30 | int yheight; |
michael@0 | 31 | int ystride; |
michael@0 | 32 | int yoffset; |
michael@0 | 33 | int linestocopy; |
michael@0 | 34 | |
michael@0 | 35 | yheight = src_ybc->y_height; |
michael@0 | 36 | ystride = src_ybc->y_stride; |
michael@0 | 37 | |
michael@0 | 38 | /* number of MB rows to use in partial filtering */ |
michael@0 | 39 | linestocopy = (yheight >> 4) / PARTIAL_FRAME_FRACTION; |
michael@0 | 40 | linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */ |
michael@0 | 41 | |
michael@0 | 42 | /* Copy extra 4 so that full filter context is available if filtering done |
michael@0 | 43 | * on the copied partial frame and not original. Partial filter does mb |
michael@0 | 44 | * filtering for top row also, which can modify3 pixels above. |
michael@0 | 45 | */ |
michael@0 | 46 | linestocopy += 4; |
michael@0 | 47 | /* partial image starts at ~middle of frame (macroblock border)*/ |
michael@0 | 48 | yoffset = ystride * (((yheight >> 5) * 16) - 4); |
michael@0 | 49 | src_y = src_ybc->y_buffer + yoffset; |
michael@0 | 50 | dst_y = dst_ybc->y_buffer + yoffset; |
michael@0 | 51 | |
michael@0 | 52 | vpx_memcpy(dst_y, src_y, ystride * linestocopy); |
michael@0 | 53 | } |
michael@0 | 54 | |
michael@0 | 55 | static int calc_partial_ssl_err(YV12_BUFFER_CONFIG *source, |
michael@0 | 56 | YV12_BUFFER_CONFIG *dest) |
michael@0 | 57 | { |
michael@0 | 58 | int i, j; |
michael@0 | 59 | int Total = 0; |
michael@0 | 60 | int srcoffset, dstoffset; |
michael@0 | 61 | unsigned char *src = source->y_buffer; |
michael@0 | 62 | unsigned char *dst = dest->y_buffer; |
michael@0 | 63 | |
michael@0 | 64 | int linestocopy; |
michael@0 | 65 | |
michael@0 | 66 | /* number of MB rows to use in partial filtering */ |
michael@0 | 67 | linestocopy = (source->y_height >> 4) / PARTIAL_FRAME_FRACTION; |
michael@0 | 68 | linestocopy = linestocopy ? linestocopy << 4 : 16; /* 16 lines per MB */ |
michael@0 | 69 | |
michael@0 | 70 | |
michael@0 | 71 | /* partial image starts at ~middle of frame (macroblock border)*/ |
michael@0 | 72 | srcoffset = source->y_stride * ((dest->y_height >> 5) * 16); |
michael@0 | 73 | dstoffset = dest->y_stride * ((dest->y_height >> 5) * 16); |
michael@0 | 74 | |
michael@0 | 75 | src += srcoffset; |
michael@0 | 76 | dst += dstoffset; |
michael@0 | 77 | |
michael@0 | 78 | /* Loop through the Y plane raw and reconstruction data summing |
michael@0 | 79 | * (square differences) |
michael@0 | 80 | */ |
michael@0 | 81 | for (i = 0; i < linestocopy; i += 16) |
michael@0 | 82 | { |
michael@0 | 83 | for (j = 0; j < source->y_width; j += 16) |
michael@0 | 84 | { |
michael@0 | 85 | unsigned int sse; |
michael@0 | 86 | Total += vp8_mse16x16(src + j, source->y_stride, |
michael@0 | 87 | dst + j, dest->y_stride, |
michael@0 | 88 | &sse); |
michael@0 | 89 | } |
michael@0 | 90 | |
michael@0 | 91 | src += 16 * source->y_stride; |
michael@0 | 92 | dst += 16 * dest->y_stride; |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | return Total; |
michael@0 | 96 | } |
michael@0 | 97 | |
michael@0 | 98 | /* Enforce a minimum filter level based upon baseline Q */ |
michael@0 | 99 | static int get_min_filter_level(VP8_COMP *cpi, int base_qindex) |
michael@0 | 100 | { |
michael@0 | 101 | int min_filter_level; |
michael@0 | 102 | |
michael@0 | 103 | if (cpi->source_alt_ref_active && cpi->common.refresh_golden_frame && |
michael@0 | 104 | !cpi->common.refresh_alt_ref_frame) |
michael@0 | 105 | min_filter_level = 0; |
michael@0 | 106 | else |
michael@0 | 107 | { |
michael@0 | 108 | if (base_qindex <= 6) |
michael@0 | 109 | min_filter_level = 0; |
michael@0 | 110 | else if (base_qindex <= 16) |
michael@0 | 111 | min_filter_level = 1; |
michael@0 | 112 | else |
michael@0 | 113 | min_filter_level = (base_qindex / 8); |
michael@0 | 114 | } |
michael@0 | 115 | |
michael@0 | 116 | return min_filter_level; |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | /* Enforce a maximum filter level based upon baseline Q */ |
michael@0 | 120 | static int get_max_filter_level(VP8_COMP *cpi, int base_qindex) |
michael@0 | 121 | { |
michael@0 | 122 | /* PGW August 2006: Highest filter values almost always a bad idea */ |
michael@0 | 123 | |
michael@0 | 124 | /* jbb chg: 20100118 - not so any more with this overquant stuff allow |
michael@0 | 125 | * high values with lots of intra coming in. |
michael@0 | 126 | */ |
michael@0 | 127 | int max_filter_level = MAX_LOOP_FILTER; |
michael@0 | 128 | (void)base_qindex; |
michael@0 | 129 | |
michael@0 | 130 | if (cpi->twopass.section_intra_rating > 8) |
michael@0 | 131 | max_filter_level = MAX_LOOP_FILTER * 3 / 4; |
michael@0 | 132 | |
michael@0 | 133 | return max_filter_level; |
michael@0 | 134 | } |
michael@0 | 135 | |
michael@0 | 136 | void vp8cx_pick_filter_level_fast(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) |
michael@0 | 137 | { |
michael@0 | 138 | VP8_COMMON *cm = &cpi->common; |
michael@0 | 139 | |
michael@0 | 140 | int best_err = 0; |
michael@0 | 141 | int filt_err = 0; |
michael@0 | 142 | int min_filter_level = get_min_filter_level(cpi, cm->base_qindex); |
michael@0 | 143 | int max_filter_level = get_max_filter_level(cpi, cm->base_qindex); |
michael@0 | 144 | int filt_val; |
michael@0 | 145 | int best_filt_val = cm->filter_level; |
michael@0 | 146 | YV12_BUFFER_CONFIG * saved_frame = cm->frame_to_show; |
michael@0 | 147 | |
michael@0 | 148 | /* Replace unfiltered frame buffer with a new one */ |
michael@0 | 149 | cm->frame_to_show = &cpi->pick_lf_lvl_frame; |
michael@0 | 150 | |
michael@0 | 151 | if (cm->frame_type == KEY_FRAME) |
michael@0 | 152 | cm->sharpness_level = 0; |
michael@0 | 153 | else |
michael@0 | 154 | cm->sharpness_level = cpi->oxcf.Sharpness; |
michael@0 | 155 | |
michael@0 | 156 | if (cm->sharpness_level != cm->last_sharpness_level) |
michael@0 | 157 | { |
michael@0 | 158 | vp8_loop_filter_update_sharpness(&cm->lf_info, cm->sharpness_level); |
michael@0 | 159 | cm->last_sharpness_level = cm->sharpness_level; |
michael@0 | 160 | } |
michael@0 | 161 | |
michael@0 | 162 | /* Start the search at the previous frame filter level unless it is |
michael@0 | 163 | * now out of range. |
michael@0 | 164 | */ |
michael@0 | 165 | if (cm->filter_level < min_filter_level) |
michael@0 | 166 | cm->filter_level = min_filter_level; |
michael@0 | 167 | else if (cm->filter_level > max_filter_level) |
michael@0 | 168 | cm->filter_level = max_filter_level; |
michael@0 | 169 | |
michael@0 | 170 | filt_val = cm->filter_level; |
michael@0 | 171 | best_filt_val = filt_val; |
michael@0 | 172 | |
michael@0 | 173 | /* Get the err using the previous frame's filter value. */ |
michael@0 | 174 | |
michael@0 | 175 | /* Copy the unfiltered / processed recon buffer to the new buffer */ |
michael@0 | 176 | vp8_yv12_copy_partial_frame(saved_frame, cm->frame_to_show); |
michael@0 | 177 | vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val); |
michael@0 | 178 | |
michael@0 | 179 | best_err = calc_partial_ssl_err(sd, cm->frame_to_show); |
michael@0 | 180 | |
michael@0 | 181 | filt_val -= 1 + (filt_val > 10); |
michael@0 | 182 | |
michael@0 | 183 | /* Search lower filter levels */ |
michael@0 | 184 | while (filt_val >= min_filter_level) |
michael@0 | 185 | { |
michael@0 | 186 | /* Apply the loop filter */ |
michael@0 | 187 | vp8_yv12_copy_partial_frame(saved_frame, cm->frame_to_show); |
michael@0 | 188 | vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val); |
michael@0 | 189 | |
michael@0 | 190 | /* Get the err for filtered frame */ |
michael@0 | 191 | filt_err = calc_partial_ssl_err(sd, cm->frame_to_show); |
michael@0 | 192 | |
michael@0 | 193 | /* Update the best case record or exit loop. */ |
michael@0 | 194 | if (filt_err < best_err) |
michael@0 | 195 | { |
michael@0 | 196 | best_err = filt_err; |
michael@0 | 197 | best_filt_val = filt_val; |
michael@0 | 198 | } |
michael@0 | 199 | else |
michael@0 | 200 | break; |
michael@0 | 201 | |
michael@0 | 202 | /* Adjust filter level */ |
michael@0 | 203 | filt_val -= 1 + (filt_val > 10); |
michael@0 | 204 | } |
michael@0 | 205 | |
michael@0 | 206 | /* Search up (note that we have already done filt_val = cm->filter_level) */ |
michael@0 | 207 | filt_val = cm->filter_level + 1 + (filt_val > 10); |
michael@0 | 208 | |
michael@0 | 209 | if (best_filt_val == cm->filter_level) |
michael@0 | 210 | { |
michael@0 | 211 | /* Resist raising filter level for very small gains */ |
michael@0 | 212 | best_err -= (best_err >> 10); |
michael@0 | 213 | |
michael@0 | 214 | while (filt_val < max_filter_level) |
michael@0 | 215 | { |
michael@0 | 216 | /* Apply the loop filter */ |
michael@0 | 217 | vp8_yv12_copy_partial_frame(saved_frame, cm->frame_to_show); |
michael@0 | 218 | |
michael@0 | 219 | vp8_loop_filter_partial_frame(cm, &cpi->mb.e_mbd, filt_val); |
michael@0 | 220 | |
michael@0 | 221 | /* Get the err for filtered frame */ |
michael@0 | 222 | filt_err = calc_partial_ssl_err(sd, cm->frame_to_show); |
michael@0 | 223 | |
michael@0 | 224 | /* Update the best case record or exit loop. */ |
michael@0 | 225 | if (filt_err < best_err) |
michael@0 | 226 | { |
michael@0 | 227 | /* Do not raise filter level if improvement is < 1 part |
michael@0 | 228 | * in 4096 |
michael@0 | 229 | */ |
michael@0 | 230 | best_err = filt_err - (filt_err >> 10); |
michael@0 | 231 | |
michael@0 | 232 | best_filt_val = filt_val; |
michael@0 | 233 | } |
michael@0 | 234 | else |
michael@0 | 235 | break; |
michael@0 | 236 | |
michael@0 | 237 | /* Adjust filter level */ |
michael@0 | 238 | filt_val += 1 + (filt_val > 10); |
michael@0 | 239 | } |
michael@0 | 240 | } |
michael@0 | 241 | |
michael@0 | 242 | cm->filter_level = best_filt_val; |
michael@0 | 243 | |
michael@0 | 244 | if (cm->filter_level < min_filter_level) |
michael@0 | 245 | cm->filter_level = min_filter_level; |
michael@0 | 246 | |
michael@0 | 247 | if (cm->filter_level > max_filter_level) |
michael@0 | 248 | cm->filter_level = max_filter_level; |
michael@0 | 249 | |
michael@0 | 250 | /* restore unfiltered frame pointer */ |
michael@0 | 251 | cm->frame_to_show = saved_frame; |
michael@0 | 252 | } |
michael@0 | 253 | |
michael@0 | 254 | /* Stub function for now Alt LF not used */ |
michael@0 | 255 | void vp8cx_set_alt_lf_level(VP8_COMP *cpi, int filt_val) |
michael@0 | 256 | { |
michael@0 | 257 | MACROBLOCKD *mbd = &cpi->mb.e_mbd; |
michael@0 | 258 | (void) filt_val; |
michael@0 | 259 | |
michael@0 | 260 | mbd->segment_feature_data[MB_LVL_ALT_LF][0] = cpi->segment_feature_data[MB_LVL_ALT_LF][0]; |
michael@0 | 261 | mbd->segment_feature_data[MB_LVL_ALT_LF][1] = cpi->segment_feature_data[MB_LVL_ALT_LF][1]; |
michael@0 | 262 | mbd->segment_feature_data[MB_LVL_ALT_LF][2] = cpi->segment_feature_data[MB_LVL_ALT_LF][2]; |
michael@0 | 263 | mbd->segment_feature_data[MB_LVL_ALT_LF][3] = cpi->segment_feature_data[MB_LVL_ALT_LF][3]; |
michael@0 | 264 | } |
michael@0 | 265 | |
michael@0 | 266 | void vp8cx_pick_filter_level(YV12_BUFFER_CONFIG *sd, VP8_COMP *cpi) |
michael@0 | 267 | { |
michael@0 | 268 | VP8_COMMON *cm = &cpi->common; |
michael@0 | 269 | |
michael@0 | 270 | int best_err = 0; |
michael@0 | 271 | int filt_err = 0; |
michael@0 | 272 | int min_filter_level = get_min_filter_level(cpi, cm->base_qindex); |
michael@0 | 273 | int max_filter_level = get_max_filter_level(cpi, cm->base_qindex); |
michael@0 | 274 | |
michael@0 | 275 | int filter_step; |
michael@0 | 276 | int filt_high = 0; |
michael@0 | 277 | /* Start search at previous frame filter level */ |
michael@0 | 278 | int filt_mid = cm->filter_level; |
michael@0 | 279 | int filt_low = 0; |
michael@0 | 280 | int filt_best; |
michael@0 | 281 | int filt_direction = 0; |
michael@0 | 282 | |
michael@0 | 283 | /* Bias against raising loop filter and in favor of lowering it */ |
michael@0 | 284 | int Bias = 0; |
michael@0 | 285 | |
michael@0 | 286 | int ss_err[MAX_LOOP_FILTER + 1]; |
michael@0 | 287 | |
michael@0 | 288 | YV12_BUFFER_CONFIG * saved_frame = cm->frame_to_show; |
michael@0 | 289 | |
michael@0 | 290 | vpx_memset(ss_err, 0, sizeof(ss_err)); |
michael@0 | 291 | |
michael@0 | 292 | /* Replace unfiltered frame buffer with a new one */ |
michael@0 | 293 | cm->frame_to_show = &cpi->pick_lf_lvl_frame; |
michael@0 | 294 | |
michael@0 | 295 | if (cm->frame_type == KEY_FRAME) |
michael@0 | 296 | cm->sharpness_level = 0; |
michael@0 | 297 | else |
michael@0 | 298 | cm->sharpness_level = cpi->oxcf.Sharpness; |
michael@0 | 299 | |
michael@0 | 300 | /* Start the search at the previous frame filter level unless it is |
michael@0 | 301 | * now out of range. |
michael@0 | 302 | */ |
michael@0 | 303 | filt_mid = cm->filter_level; |
michael@0 | 304 | |
michael@0 | 305 | if (filt_mid < min_filter_level) |
michael@0 | 306 | filt_mid = min_filter_level; |
michael@0 | 307 | else if (filt_mid > max_filter_level) |
michael@0 | 308 | filt_mid = max_filter_level; |
michael@0 | 309 | |
michael@0 | 310 | /* Define the initial step size */ |
michael@0 | 311 | filter_step = (filt_mid < 16) ? 4 : filt_mid / 4; |
michael@0 | 312 | |
michael@0 | 313 | /* Get baseline error score */ |
michael@0 | 314 | |
michael@0 | 315 | /* Copy the unfiltered / processed recon buffer to the new buffer */ |
michael@0 | 316 | vpx_yv12_copy_y(saved_frame, cm->frame_to_show); |
michael@0 | 317 | |
michael@0 | 318 | vp8cx_set_alt_lf_level(cpi, filt_mid); |
michael@0 | 319 | vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_mid); |
michael@0 | 320 | |
michael@0 | 321 | best_err = vp8_calc_ss_err(sd, cm->frame_to_show); |
michael@0 | 322 | |
michael@0 | 323 | ss_err[filt_mid] = best_err; |
michael@0 | 324 | |
michael@0 | 325 | filt_best = filt_mid; |
michael@0 | 326 | |
michael@0 | 327 | while (filter_step > 0) |
michael@0 | 328 | { |
michael@0 | 329 | Bias = (best_err >> (15 - (filt_mid / 8))) * filter_step; |
michael@0 | 330 | |
michael@0 | 331 | if (cpi->twopass.section_intra_rating < 20) |
michael@0 | 332 | Bias = Bias * cpi->twopass.section_intra_rating / 20; |
michael@0 | 333 | |
michael@0 | 334 | filt_high = ((filt_mid + filter_step) > max_filter_level) ? max_filter_level : (filt_mid + filter_step); |
michael@0 | 335 | filt_low = ((filt_mid - filter_step) < min_filter_level) ? min_filter_level : (filt_mid - filter_step); |
michael@0 | 336 | |
michael@0 | 337 | if ((filt_direction <= 0) && (filt_low != filt_mid)) |
michael@0 | 338 | { |
michael@0 | 339 | if(ss_err[filt_low] == 0) |
michael@0 | 340 | { |
michael@0 | 341 | /* Get Low filter error score */ |
michael@0 | 342 | vpx_yv12_copy_y(saved_frame, cm->frame_to_show); |
michael@0 | 343 | vp8cx_set_alt_lf_level(cpi, filt_low); |
michael@0 | 344 | vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_low); |
michael@0 | 345 | |
michael@0 | 346 | filt_err = vp8_calc_ss_err(sd, cm->frame_to_show); |
michael@0 | 347 | ss_err[filt_low] = filt_err; |
michael@0 | 348 | } |
michael@0 | 349 | else |
michael@0 | 350 | filt_err = ss_err[filt_low]; |
michael@0 | 351 | |
michael@0 | 352 | /* If value is close to the best so far then bias towards a |
michael@0 | 353 | * lower loop filter value. |
michael@0 | 354 | */ |
michael@0 | 355 | if ((filt_err - Bias) < best_err) |
michael@0 | 356 | { |
michael@0 | 357 | /* Was it actually better than the previous best? */ |
michael@0 | 358 | if (filt_err < best_err) |
michael@0 | 359 | best_err = filt_err; |
michael@0 | 360 | |
michael@0 | 361 | filt_best = filt_low; |
michael@0 | 362 | } |
michael@0 | 363 | } |
michael@0 | 364 | |
michael@0 | 365 | /* Now look at filt_high */ |
michael@0 | 366 | if ((filt_direction >= 0) && (filt_high != filt_mid)) |
michael@0 | 367 | { |
michael@0 | 368 | if(ss_err[filt_high] == 0) |
michael@0 | 369 | { |
michael@0 | 370 | vpx_yv12_copy_y(saved_frame, cm->frame_to_show); |
michael@0 | 371 | vp8cx_set_alt_lf_level(cpi, filt_high); |
michael@0 | 372 | vp8_loop_filter_frame_yonly(cm, &cpi->mb.e_mbd, filt_high); |
michael@0 | 373 | |
michael@0 | 374 | filt_err = vp8_calc_ss_err(sd, cm->frame_to_show); |
michael@0 | 375 | ss_err[filt_high] = filt_err; |
michael@0 | 376 | } |
michael@0 | 377 | else |
michael@0 | 378 | filt_err = ss_err[filt_high]; |
michael@0 | 379 | |
michael@0 | 380 | /* Was it better than the previous best? */ |
michael@0 | 381 | if (filt_err < (best_err - Bias)) |
michael@0 | 382 | { |
michael@0 | 383 | best_err = filt_err; |
michael@0 | 384 | filt_best = filt_high; |
michael@0 | 385 | } |
michael@0 | 386 | } |
michael@0 | 387 | |
michael@0 | 388 | /* Half the step distance if the best filter value was the same |
michael@0 | 389 | * as last time |
michael@0 | 390 | */ |
michael@0 | 391 | if (filt_best == filt_mid) |
michael@0 | 392 | { |
michael@0 | 393 | filter_step = filter_step / 2; |
michael@0 | 394 | filt_direction = 0; |
michael@0 | 395 | } |
michael@0 | 396 | else |
michael@0 | 397 | { |
michael@0 | 398 | filt_direction = (filt_best < filt_mid) ? -1 : 1; |
michael@0 | 399 | filt_mid = filt_best; |
michael@0 | 400 | } |
michael@0 | 401 | } |
michael@0 | 402 | |
michael@0 | 403 | cm->filter_level = filt_best; |
michael@0 | 404 | |
michael@0 | 405 | /* restore unfiltered frame pointer */ |
michael@0 | 406 | cm->frame_to_show = saved_frame; |
michael@0 | 407 | } |