1/* 2 * Copyright (c) 2012 The WebM project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11 12/* MFQE: Multiframe Quality Enhancement 13 * In rate limited situations keyframes may cause significant visual artifacts 14 * commonly referred to as "popping." This file implements a postproccesing 15 * algorithm which blends data from the preceeding frame when there is no 16 * motion and the q from the previous frame is lower which indicates that it is 17 * higher quality. 18 */ 19 20#include "./vp8_rtcd.h" 21#include "./vpx_dsp_rtcd.h" 22#include "vp8/common/postproc.h" 23#include "vpx_dsp/variance.h" 24#include "vpx_mem/vpx_mem.h" 25#include "vpx_scale/yv12config.h" 26 27#include <limits.h> 28#include <stdlib.h> 29 30static void filter_by_weight(unsigned char *src, int src_stride, 31 unsigned char *dst, int dst_stride, 32 int block_size, int src_weight) 33{ 34 int dst_weight = (1 << MFQE_PRECISION) - src_weight; 35 int rounding_bit = 1 << (MFQE_PRECISION - 1); 36 int r, c; 37 38 for (r = 0; r < block_size; r++) 39 { 40 for (c = 0; c < block_size; c++) 41 { 42 dst[c] = (src[c] * src_weight + 43 dst[c] * dst_weight + 44 rounding_bit) >> MFQE_PRECISION; 45 } 46 src += src_stride; 47 dst += dst_stride; 48 } 49} 50 51void vp8_filter_by_weight16x16_c(unsigned char *src, int src_stride, 52 unsigned char *dst, int dst_stride, 53 int src_weight) 54{ 55 filter_by_weight(src, src_stride, dst, dst_stride, 16, src_weight); 56} 57 58void vp8_filter_by_weight8x8_c(unsigned char *src, int src_stride, 59 unsigned char *dst, int dst_stride, 60 int src_weight) 61{ 62 filter_by_weight(src, src_stride, dst, dst_stride, 8, src_weight); 63} 64 65void vp8_filter_by_weight4x4_c(unsigned char *src, int src_stride, 66 unsigned char *dst, int dst_stride, 67 int src_weight) 68{ 69 filter_by_weight(src, src_stride, dst, dst_stride, 4, src_weight); 70} 71 72static void apply_ifactor(unsigned char *y_src, 73 int y_src_stride, 74 unsigned char *y_dst, 75 int y_dst_stride, 76 unsigned char *u_src, 77 unsigned char *v_src, 78 int uv_src_stride, 79 unsigned char *u_dst, 80 unsigned char *v_dst, 81 int uv_dst_stride, 82 int block_size, 83 int src_weight) 84{ 85 if (block_size == 16) 86 { 87 vp8_filter_by_weight16x16(y_src, y_src_stride, y_dst, y_dst_stride, src_weight); 88 vp8_filter_by_weight8x8(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight); 89 vp8_filter_by_weight8x8(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight); 90 } 91 else /* if (block_size == 8) */ 92 { 93 vp8_filter_by_weight8x8(y_src, y_src_stride, y_dst, y_dst_stride, src_weight); 94 vp8_filter_by_weight4x4(u_src, uv_src_stride, u_dst, uv_dst_stride, src_weight); 95 vp8_filter_by_weight4x4(v_src, uv_src_stride, v_dst, uv_dst_stride, src_weight); 96 } 97} 98 99static unsigned int int_sqrt(unsigned int x) 100{ 101 unsigned int y = x; 102 unsigned int guess; 103 int p = 1; 104 while (y>>=1) p++; 105 p>>=1; 106 107 guess=0; 108 while (p>=0) 109 { 110 guess |= (1<<p); 111 if (x<guess*guess) 112 guess -= (1<<p); 113 p--; 114 } 115 /* choose between guess or guess+1 */ 116 return guess+(guess*guess+guess+1<=x); 117} 118 119#define USE_SSD 120static void multiframe_quality_enhance_block 121( 122 int blksize, /* Currently only values supported are 16, 8 */ 123 int qcurr, 124 int qprev, 125 unsigned char *y, 126 unsigned char *u, 127 unsigned char *v, 128 int y_stride, 129 int uv_stride, 130 unsigned char *yd, 131 unsigned char *ud, 132 unsigned char *vd, 133 int yd_stride, 134 int uvd_stride 135) 136{ 137 static const unsigned char VP8_ZEROS[16]= 138 { 139 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 140 }; 141 int uvblksize = blksize >> 1; 142 int qdiff = qcurr - qprev; 143 144 int i; 145 unsigned char *up; 146 unsigned char *udp; 147 unsigned char *vp; 148 unsigned char *vdp; 149 150 unsigned int act, actd, sad, usad, vsad, sse, thr, thrsq, actrisk; 151 152 if (blksize == 16) 153 { 154 actd = (vpx_variance16x16(yd, yd_stride, VP8_ZEROS, 0, &sse)+128)>>8; 155 act = (vpx_variance16x16(y, y_stride, VP8_ZEROS, 0, &sse)+128)>>8; 156#ifdef USE_SSD 157 vpx_variance16x16(y, y_stride, yd, yd_stride, &sse); 158 sad = (sse + 128)>>8; 159 vpx_variance8x8(u, uv_stride, ud, uvd_stride, &sse); 160 usad = (sse + 32)>>6; 161 vpx_variance8x8(v, uv_stride, vd, uvd_stride, &sse); 162 vsad = (sse + 32)>>6; 163#else 164 sad = (vpx_sad16x16(y, y_stride, yd, yd_stride) + 128) >> 8; 165 usad = (vpx_sad8x8(u, uv_stride, ud, uvd_stride) + 32) >> 6; 166 vsad = (vpx_sad8x8(v, uv_stride, vd, uvd_stride)+ 32) >> 6; 167#endif 168 } 169 else /* if (blksize == 8) */ 170 { 171 actd = (vpx_variance8x8(yd, yd_stride, VP8_ZEROS, 0, &sse)+32)>>6; 172 act = (vpx_variance8x8(y, y_stride, VP8_ZEROS, 0, &sse)+32)>>6; 173#ifdef USE_SSD 174 vpx_variance8x8(y, y_stride, yd, yd_stride, &sse); 175 sad = (sse + 32)>>6; 176 vpx_variance4x4(u, uv_stride, ud, uvd_stride, &sse); 177 usad = (sse + 8)>>4; 178 vpx_variance4x4(v, uv_stride, vd, uvd_stride, &sse); 179 vsad = (sse + 8)>>4; 180#else 181 sad = (vpx_sad8x8(y, y_stride, yd, yd_stride) + 32) >> 6; 182 usad = (vpx_sad4x4(u, uv_stride, ud, uvd_stride) + 8) >> 4; 183 vsad = (vpx_sad4x4(v, uv_stride, vd, uvd_stride) + 8) >> 4; 184#endif 185 } 186 187 actrisk = (actd > act * 5); 188 189 /* thr = qdiff/16 + log2(act) + log4(qprev) */ 190 thr = (qdiff >> 4); 191 while (actd >>= 1) thr++; 192 while (qprev >>= 2) thr++; 193 194#ifdef USE_SSD 195 thrsq = thr * thr; 196 if (sad < thrsq && 197 /* additional checks for color mismatch and excessive addition of 198 * high-frequencies */ 199 4 * usad < thrsq && 4 * vsad < thrsq && !actrisk) 200#else 201 if (sad < thr && 202 /* additional checks for color mismatch and excessive addition of 203 * high-frequencies */ 204 2 * usad < thr && 2 * vsad < thr && !actrisk) 205#endif 206 { 207 int ifactor; 208#ifdef USE_SSD 209 /* TODO: optimize this later to not need sqr root */ 210 sad = int_sqrt(sad); 211#endif 212 ifactor = (sad << MFQE_PRECISION) / thr; 213 ifactor >>= (qdiff >> 5); 214 215 if (ifactor) 216 { 217 apply_ifactor(y, y_stride, yd, yd_stride, 218 u, v, uv_stride, 219 ud, vd, uvd_stride, 220 blksize, ifactor); 221 } 222 } 223 else /* else implicitly copy from previous frame */ 224 { 225 if (blksize == 16) 226 { 227 vp8_copy_mem16x16(y, y_stride, yd, yd_stride); 228 vp8_copy_mem8x8(u, uv_stride, ud, uvd_stride); 229 vp8_copy_mem8x8(v, uv_stride, vd, uvd_stride); 230 } 231 else /* if (blksize == 8) */ 232 { 233 vp8_copy_mem8x8(y, y_stride, yd, yd_stride); 234 for (up = u, udp = ud, i = 0; i < uvblksize; ++i, up += uv_stride, udp += uvd_stride) 235 memcpy(udp, up, uvblksize); 236 for (vp = v, vdp = vd, i = 0; i < uvblksize; ++i, vp += uv_stride, vdp += uvd_stride) 237 memcpy(vdp, vp, uvblksize); 238 } 239 } 240} 241 242static int qualify_inter_mb(const MODE_INFO *mode_info_context, int *map) 243{ 244 if (mode_info_context->mbmi.mb_skip_coeff) 245 map[0] = map[1] = map[2] = map[3] = 1; 246 else if (mode_info_context->mbmi.mode==SPLITMV) 247 { 248 static int ndx[4][4] = 249 { 250 {0, 1, 4, 5}, 251 {2, 3, 6, 7}, 252 {8, 9, 12, 13}, 253 {10, 11, 14, 15} 254 }; 255 int i, j; 256 for (i=0; i<4; ++i) 257 { 258 map[i] = 1; 259 for (j=0; j<4 && map[j]; ++j) 260 map[i] &= (mode_info_context->bmi[ndx[i][j]].mv.as_mv.row <= 2 && 261 mode_info_context->bmi[ndx[i][j]].mv.as_mv.col <= 2); 262 } 263 } 264 else 265 { 266 map[0] = map[1] = map[2] = map[3] = 267 (mode_info_context->mbmi.mode > B_PRED && 268 abs(mode_info_context->mbmi.mv.as_mv.row) <= 2 && 269 abs(mode_info_context->mbmi.mv.as_mv.col) <= 2); 270 } 271 return (map[0]+map[1]+map[2]+map[3]); 272} 273 274void vp8_multiframe_quality_enhance 275( 276 VP8_COMMON *cm 277) 278{ 279 YV12_BUFFER_CONFIG *show = cm->frame_to_show; 280 YV12_BUFFER_CONFIG *dest = &cm->post_proc_buffer; 281 282 FRAME_TYPE frame_type = cm->frame_type; 283 /* Point at base of Mb MODE_INFO list has motion vectors etc */ 284 const MODE_INFO *mode_info_context = cm->show_frame_mi; 285 int mb_row; 286 int mb_col; 287 int totmap, map[4]; 288 int qcurr = cm->base_qindex; 289 int qprev = cm->postproc_state.last_base_qindex; 290 291 unsigned char *y_ptr, *u_ptr, *v_ptr; 292 unsigned char *yd_ptr, *ud_ptr, *vd_ptr; 293 294 /* Set up the buffer pointers */ 295 y_ptr = show->y_buffer; 296 u_ptr = show->u_buffer; 297 v_ptr = show->v_buffer; 298 yd_ptr = dest->y_buffer; 299 ud_ptr = dest->u_buffer; 300 vd_ptr = dest->v_buffer; 301 302 /* postprocess each macro block */ 303 for (mb_row = 0; mb_row < cm->mb_rows; mb_row++) 304 { 305 for (mb_col = 0; mb_col < cm->mb_cols; mb_col++) 306 { 307 /* if motion is high there will likely be no benefit */ 308 if (frame_type == INTER_FRAME) totmap = qualify_inter_mb(mode_info_context, map); 309 else totmap = (frame_type == KEY_FRAME ? 4 : 0); 310 if (totmap) 311 { 312 if (totmap < 4) 313 { 314 int i, j; 315 for (i=0; i<2; ++i) 316 for (j=0; j<2; ++j) 317 { 318 if (map[i*2+j]) 319 { 320 multiframe_quality_enhance_block(8, qcurr, qprev, 321 y_ptr + 8*(i*show->y_stride+j), 322 u_ptr + 4*(i*show->uv_stride+j), 323 v_ptr + 4*(i*show->uv_stride+j), 324 show->y_stride, 325 show->uv_stride, 326 yd_ptr + 8*(i*dest->y_stride+j), 327 ud_ptr + 4*(i*dest->uv_stride+j), 328 vd_ptr + 4*(i*dest->uv_stride+j), 329 dest->y_stride, 330 dest->uv_stride); 331 } 332 else 333 { 334 /* copy a 8x8 block */ 335 int k; 336 unsigned char *up = u_ptr + 4*(i*show->uv_stride+j); 337 unsigned char *udp = ud_ptr + 4*(i*dest->uv_stride+j); 338 unsigned char *vp = v_ptr + 4*(i*show->uv_stride+j); 339 unsigned char *vdp = vd_ptr + 4*(i*dest->uv_stride+j); 340 vp8_copy_mem8x8(y_ptr + 8*(i*show->y_stride+j), show->y_stride, 341 yd_ptr + 8*(i*dest->y_stride+j), dest->y_stride); 342 for (k = 0; k < 4; ++k, up += show->uv_stride, udp += dest->uv_stride, 343 vp += show->uv_stride, vdp += dest->uv_stride) 344 { 345 memcpy(udp, up, 4); 346 memcpy(vdp, vp, 4); 347 } 348 } 349 } 350 } 351 else /* totmap = 4 */ 352 { 353 multiframe_quality_enhance_block(16, qcurr, qprev, y_ptr, 354 u_ptr, v_ptr, 355 show->y_stride, 356 show->uv_stride, 357 yd_ptr, ud_ptr, vd_ptr, 358 dest->y_stride, 359 dest->uv_stride); 360 } 361 } 362 else 363 { 364 vp8_copy_mem16x16(y_ptr, show->y_stride, yd_ptr, dest->y_stride); 365 vp8_copy_mem8x8(u_ptr, show->uv_stride, ud_ptr, dest->uv_stride); 366 vp8_copy_mem8x8(v_ptr, show->uv_stride, vd_ptr, dest->uv_stride); 367 } 368 y_ptr += 16; 369 u_ptr += 8; 370 v_ptr += 8; 371 yd_ptr += 16; 372 ud_ptr += 8; 373 vd_ptr += 8; 374 mode_info_context++; /* step to next MB */ 375 } 376 377 y_ptr += show->y_stride * 16 - 16 * cm->mb_cols; 378 u_ptr += show->uv_stride * 8 - 8 * cm->mb_cols; 379 v_ptr += show->uv_stride * 8 - 8 * cm->mb_cols; 380 yd_ptr += dest->y_stride * 16 - 16 * cm->mb_cols; 381 ud_ptr += dest->uv_stride * 8 - 8 * cm->mb_cols; 382 vd_ptr += dest->uv_stride * 8 - 8 * cm->mb_cols; 383 384 mode_info_context++; /* Skip border mb */ 385 } 386} 387