media/libvpx/vp8/encoder/picklpf.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) 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 }

mercurial