13447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein/* 23447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * Copyright (c) 2014 The WebM project authors. All Rights Reserved. 33447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * 43447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * Use of this source code is governed by a BSD-style license 53447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * that can be found in the LICENSE file in the root of the source 63447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * tree. An additional intellectual property rights grant can be found 73447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * in the file PATENTS. All contributing project authors may 83447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein * be found in the AUTHORS file in the root of the source tree. 93447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein */ 103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein#include "./vpx_config.h" 123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein#include "./vp9_rtcd.h" 133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein#include "./vpx_dsp_rtcd.h" 143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein#include "./vpx_scale_rtcd.h" 153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein#include "vp9/common/vp9_onyxc_int.h" 173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein#include "vp9/common/vp9_postproc.h" 183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein// TODO(jackychen): Replace this function with SSE2 code. There is 203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein// one SSE2 implementation in vp8, so will consider how to share it 213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein// between vp8 and vp9. 223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void filter_by_weight(const uint8_t *src, int src_stride, uint8_t *dst, 233447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int dst_stride, int block_size, int src_weight) { 243447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein const int dst_weight = (1 << MFQE_PRECISION) - src_weight; 253447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein const int rounding_bit = 1 << (MFQE_PRECISION - 1); 263447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int r, c; 273447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 283447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein for (r = 0; r < block_size; r++) { 293447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein for (c = 0; c < block_size; c++) { 303447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst[c] = (src[c] * src_weight + dst[c] * dst_weight + rounding_bit) >> 313447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein MFQE_PRECISION; 323447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } 333447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein src += src_stride; 343447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst += dst_stride; 353447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } 363447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 373447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 383447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinvoid vp9_filter_by_weight8x8_c(const uint8_t *src, int src_stride, uint8_t *dst, 393447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int dst_stride, int src_weight) { 403447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight(src, src_stride, dst, dst_stride, 8, src_weight); 413447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 423447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 433447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinvoid vp9_filter_by_weight16x16_c(const uint8_t *src, int src_stride, 443447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein uint8_t *dst, int dst_stride, int src_weight) { 453447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight(src, src_stride, dst, dst_stride, 16, src_weight); 463447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 473447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 483447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void filter_by_weight32x32(const uint8_t *src, int src_stride, 493447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein uint8_t *dst, int dst_stride, int weight) { 503447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(src, src_stride, dst, dst_stride, weight); 513447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(src + 16, src_stride, dst + 16, dst_stride, weight); 523447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(src + src_stride * 16, src_stride, 533447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst + dst_stride * 16, dst_stride, weight); 543447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(src + src_stride * 16 + 16, src_stride, 553447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst + dst_stride * 16 + 16, dst_stride, weight); 563447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 573447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 583447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void filter_by_weight64x64(const uint8_t *src, int src_stride, 593447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein uint8_t *dst, int dst_stride, int weight) { 603447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(src, src_stride, dst, dst_stride, weight); 613447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(src + 32, src_stride, dst + 32, dst_stride, weight); 623447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(src + src_stride * 32, src_stride, 633447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst + dst_stride * 32, dst_stride, weight); 643447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(src + src_stride * 32 + 32, src_stride, 653447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst + dst_stride * 32 + 32, dst_stride, weight); 663447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 673447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 683447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void apply_ifactor(const uint8_t *y, int y_stride, uint8_t *yd, 693447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int yd_stride, const uint8_t *u, const uint8_t *v, 703447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int uv_stride, uint8_t *ud, uint8_t *vd, 713447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int uvd_stride, BLOCK_SIZE block_size, int weight) { 723447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein if (block_size == BLOCK_16X16) { 733447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(y, y_stride, yd, yd_stride, weight); 743447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight8x8(u, uv_stride, ud, uvd_stride, weight); 753447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight8x8(v, uv_stride, vd, uvd_stride, weight); 763447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } else if (block_size == BLOCK_32X32) { 773447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(y, y_stride, yd, yd_stride, weight); 783447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(u, uv_stride, ud, uvd_stride, weight); 793447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein vp9_filter_by_weight16x16(v, uv_stride, vd, uvd_stride, weight); 803447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } else if (block_size == BLOCK_64X64) { 813447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight64x64(y, y_stride, yd, yd_stride, weight); 823447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(u, uv_stride, ud, uvd_stride, weight); 833447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein filter_by_weight32x32(v, uv_stride, vd, uvd_stride, weight); 843447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } 853447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 863447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 873447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein// TODO(jackychen): Determine whether replace it with assembly code. 883447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void copy_mem8x8(const uint8_t *src, int src_stride, uint8_t *dst, 893447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int dst_stride) { 903447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int r; 913447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein for (r = 0; r < 8; r++) { 923447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein memcpy(dst, src, 8); 933447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein src += src_stride; 943447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst += dst_stride; 953447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } 963447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 973447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 983447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void copy_mem16x16(const uint8_t *src, int src_stride, uint8_t *dst, 993447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int dst_stride) { 1003447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int r; 1013447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein for (r = 0; r < 16; r++) { 1023447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein memcpy(dst, src, 16); 1033447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein src += src_stride; 1043447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst += dst_stride; 1053447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein } 1063447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 1073447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 1083447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void copy_mem32x32(const uint8_t *src, int src_stride, uint8_t *dst, 1093447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int dst_stride) { 1103447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem16x16(src, src_stride, dst, dst_stride); 1113447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem16x16(src + 16, src_stride, dst + 16, dst_stride); 1123447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem16x16(src + src_stride * 16, src_stride, dst + dst_stride * 16, 1133447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst_stride); 1143447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem16x16(src + src_stride * 16 + 16, src_stride, 1153447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein dst + dst_stride * 16 + 16, dst_stride); 1163447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein} 1173447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein 1183447a5916aa62f44de24cc441fc9987116ddff52Andrew Sappersteinstatic void copy_mem64x64(const uint8_t *src, int src_stride, uint8_t *dst, 1193447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein int dst_stride) { 1203447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem32x32(src, src_stride, dst, dst_stride); 1213447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem32x32(src + 32, src_stride, dst + 32, dst_stride); 1223447a5916aa62f44de24cc441fc9987116ddff52Andrew Sapperstein copy_mem32x32(src + src_stride * 32, src_stride, dst + src_stride * 32, 123 dst_stride); 124 copy_mem32x32(src + src_stride * 32 + 32, src_stride, 125 dst + src_stride * 32 + 32, dst_stride); 126} 127 128static void copy_block(const uint8_t *y, const uint8_t *u, const uint8_t *v, 129 int y_stride, int uv_stride, uint8_t *yd, uint8_t *ud, 130 uint8_t *vd, int yd_stride, int uvd_stride, 131 BLOCK_SIZE bs) { 132 if (bs == BLOCK_16X16) { 133 copy_mem16x16(y, y_stride, yd, yd_stride); 134 copy_mem8x8(u, uv_stride, ud, uvd_stride); 135 copy_mem8x8(v, uv_stride, vd, uvd_stride); 136 } else if (bs == BLOCK_32X32) { 137 copy_mem32x32(y, y_stride, yd, yd_stride); 138 copy_mem16x16(u, uv_stride, ud, uvd_stride); 139 copy_mem16x16(v, uv_stride, vd, uvd_stride); 140 } else { 141 copy_mem64x64(y, y_stride, yd, yd_stride); 142 copy_mem32x32(u, uv_stride, ud, uvd_stride); 143 copy_mem32x32(v, uv_stride, vd, uvd_stride); 144 } 145} 146 147static void get_thr(BLOCK_SIZE bs, int qdiff, int *sad_thr, int *vdiff_thr) { 148 const int adj = qdiff >> MFQE_PRECISION; 149 if (bs == BLOCK_16X16) { 150 *sad_thr = 7 + adj; 151 } else if (bs == BLOCK_32X32) { 152 *sad_thr = 6 + adj; 153 } else { // BLOCK_64X64 154 *sad_thr = 5 + adj; 155 } 156 *vdiff_thr = 125 + qdiff; 157} 158 159static void mfqe_block(BLOCK_SIZE bs, const uint8_t *y, const uint8_t *u, 160 const uint8_t *v, int y_stride, int uv_stride, 161 uint8_t *yd, uint8_t *ud, uint8_t *vd, int yd_stride, 162 int uvd_stride, int qdiff) { 163 int sad, sad_thr, vdiff, vdiff_thr; 164 uint32_t sse; 165 166 get_thr(bs, qdiff, &sad_thr, &vdiff_thr); 167 168 if (bs == BLOCK_16X16) { 169 vdiff = (vpx_variance16x16(y, y_stride, yd, yd_stride, &sse) + 128) >> 8; 170 sad = (vpx_sad16x16(y, y_stride, yd, yd_stride) + 128) >> 8; 171 } else if (bs == BLOCK_32X32) { 172 vdiff = (vpx_variance32x32(y, y_stride, yd, yd_stride, &sse) + 512) >> 10; 173 sad = (vpx_sad32x32(y, y_stride, yd, yd_stride) + 512) >> 10; 174 } else /* if (bs == BLOCK_64X64) */ { 175 vdiff = (vpx_variance64x64(y, y_stride, yd, yd_stride, &sse) + 2048) >> 12; 176 sad = (vpx_sad64x64(y, y_stride, yd, yd_stride) + 2048) >> 12; 177 } 178 179 // vdiff > sad * 3 means vdiff should not be too small, otherwise, 180 // it might be a lighting change in smooth area. When there is a 181 // lighting change in smooth area, it is dangerous to do MFQE. 182 if (sad > 1 && vdiff > sad * 3) { 183 const int weight = 1 << MFQE_PRECISION; 184 int ifactor = weight * sad * vdiff / (sad_thr * vdiff_thr); 185 // When ifactor equals weight, no MFQE is done. 186 if (ifactor > weight) { 187 ifactor = weight; 188 } 189 apply_ifactor(y, y_stride, yd, yd_stride, u, v, uv_stride, ud, vd, 190 uvd_stride, bs, ifactor); 191 } else { 192 // Copy the block from current frame (i.e., no mfqe is done). 193 copy_block(y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride, uvd_stride, 194 bs); 195 } 196} 197 198static int mfqe_decision(MODE_INFO *mi, BLOCK_SIZE cur_bs) { 199 // Check the motion in current block(for inter frame), 200 // or check the motion in the correlated block in last frame (for keyframe). 201 const int mv_len_square = mi->mv[0].as_mv.row * mi->mv[0].as_mv.row + 202 mi->mv[0].as_mv.col * mi->mv[0].as_mv.col; 203 const int mv_threshold = 100; 204 return mi->mode >= NEARESTMV && // Not an intra block 205 cur_bs >= BLOCK_16X16 && mv_len_square <= mv_threshold; 206} 207 208// Process each partiton in a super block, recursively. 209static void mfqe_partition(VP9_COMMON *cm, MODE_INFO *mi, BLOCK_SIZE bs, 210 const uint8_t *y, const uint8_t *u, const uint8_t *v, 211 int y_stride, int uv_stride, uint8_t *yd, 212 uint8_t *ud, uint8_t *vd, int yd_stride, 213 int uvd_stride) { 214 int mi_offset, y_offset, uv_offset; 215 const BLOCK_SIZE cur_bs = mi->sb_type; 216 const int qdiff = cm->base_qindex - cm->postproc_state.last_base_qindex; 217 const int bsl = b_width_log2_lookup[bs]; 218 PARTITION_TYPE partition = partition_lookup[bsl][cur_bs]; 219 const BLOCK_SIZE subsize = get_subsize(bs, partition); 220 221 if (cur_bs < BLOCK_8X8) { 222 // If there are blocks smaller than 8x8, it must be on the boundary. 223 return; 224 } 225 // No MFQE on blocks smaller than 16x16 226 if (bs == BLOCK_16X16) { 227 partition = PARTITION_NONE; 228 } 229 if (bs == BLOCK_64X64) { 230 mi_offset = 4; 231 y_offset = 32; 232 uv_offset = 16; 233 } else { 234 mi_offset = 2; 235 y_offset = 16; 236 uv_offset = 8; 237 } 238 switch (partition) { 239 BLOCK_SIZE mfqe_bs, bs_tmp; 240 case PARTITION_HORZ: 241 if (bs == BLOCK_64X64) { 242 mfqe_bs = BLOCK_64X32; 243 bs_tmp = BLOCK_32X32; 244 } else { 245 mfqe_bs = BLOCK_32X16; 246 bs_tmp = BLOCK_16X16; 247 } 248 if (mfqe_decision(mi, mfqe_bs)) { 249 // Do mfqe on the first square partition. 250 mfqe_block(bs_tmp, y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride, 251 uvd_stride, qdiff); 252 // Do mfqe on the second square partition. 253 mfqe_block(bs_tmp, y + y_offset, u + uv_offset, v + uv_offset, y_stride, 254 uv_stride, yd + y_offset, ud + uv_offset, vd + uv_offset, 255 yd_stride, uvd_stride, qdiff); 256 } 257 if (mfqe_decision(mi + mi_offset * cm->mi_stride, mfqe_bs)) { 258 // Do mfqe on the first square partition. 259 mfqe_block(bs_tmp, y + y_offset * y_stride, u + uv_offset * uv_stride, 260 v + uv_offset * uv_stride, y_stride, uv_stride, 261 yd + y_offset * yd_stride, ud + uv_offset * uvd_stride, 262 vd + uv_offset * uvd_stride, yd_stride, uvd_stride, qdiff); 263 // Do mfqe on the second square partition. 264 mfqe_block(bs_tmp, y + y_offset * y_stride + y_offset, 265 u + uv_offset * uv_stride + uv_offset, 266 v + uv_offset * uv_stride + uv_offset, y_stride, uv_stride, 267 yd + y_offset * yd_stride + y_offset, 268 ud + uv_offset * uvd_stride + uv_offset, 269 vd + uv_offset * uvd_stride + uv_offset, yd_stride, 270 uvd_stride, qdiff); 271 } 272 break; 273 case PARTITION_VERT: 274 if (bs == BLOCK_64X64) { 275 mfqe_bs = BLOCK_32X64; 276 bs_tmp = BLOCK_32X32; 277 } else { 278 mfqe_bs = BLOCK_16X32; 279 bs_tmp = BLOCK_16X16; 280 } 281 if (mfqe_decision(mi, mfqe_bs)) { 282 // Do mfqe on the first square partition. 283 mfqe_block(bs_tmp, y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride, 284 uvd_stride, qdiff); 285 // Do mfqe on the second square partition. 286 mfqe_block(bs_tmp, y + y_offset * y_stride, u + uv_offset * uv_stride, 287 v + uv_offset * uv_stride, y_stride, uv_stride, 288 yd + y_offset * yd_stride, ud + uv_offset * uvd_stride, 289 vd + uv_offset * uvd_stride, yd_stride, uvd_stride, qdiff); 290 } 291 if (mfqe_decision(mi + mi_offset, mfqe_bs)) { 292 // Do mfqe on the first square partition. 293 mfqe_block(bs_tmp, y + y_offset, u + uv_offset, v + uv_offset, y_stride, 294 uv_stride, yd + y_offset, ud + uv_offset, vd + uv_offset, 295 yd_stride, uvd_stride, qdiff); 296 // Do mfqe on the second square partition. 297 mfqe_block(bs_tmp, y + y_offset * y_stride + y_offset, 298 u + uv_offset * uv_stride + uv_offset, 299 v + uv_offset * uv_stride + uv_offset, y_stride, uv_stride, 300 yd + y_offset * yd_stride + y_offset, 301 ud + uv_offset * uvd_stride + uv_offset, 302 vd + uv_offset * uvd_stride + uv_offset, yd_stride, 303 uvd_stride, qdiff); 304 } 305 break; 306 case PARTITION_NONE: 307 if (mfqe_decision(mi, cur_bs)) { 308 // Do mfqe on this partition. 309 mfqe_block(cur_bs, y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride, 310 uvd_stride, qdiff); 311 } else { 312 // Copy the block from current frame(i.e., no mfqe is done). 313 copy_block(y, u, v, y_stride, uv_stride, yd, ud, vd, yd_stride, 314 uvd_stride, bs); 315 } 316 break; 317 case PARTITION_SPLIT: 318 // Recursion on four square partitions, e.g. if bs is 64X64, 319 // then look into four 32X32 blocks in it. 320 mfqe_partition(cm, mi, subsize, y, u, v, y_stride, uv_stride, yd, ud, vd, 321 yd_stride, uvd_stride); 322 mfqe_partition(cm, mi + mi_offset, subsize, y + y_offset, u + uv_offset, 323 v + uv_offset, y_stride, uv_stride, yd + y_offset, 324 ud + uv_offset, vd + uv_offset, yd_stride, uvd_stride); 325 mfqe_partition(cm, mi + mi_offset * cm->mi_stride, subsize, 326 y + y_offset * y_stride, u + uv_offset * uv_stride, 327 v + uv_offset * uv_stride, y_stride, uv_stride, 328 yd + y_offset * yd_stride, ud + uv_offset * uvd_stride, 329 vd + uv_offset * uvd_stride, yd_stride, uvd_stride); 330 mfqe_partition(cm, mi + mi_offset * cm->mi_stride + mi_offset, subsize, 331 y + y_offset * y_stride + y_offset, 332 u + uv_offset * uv_stride + uv_offset, 333 v + uv_offset * uv_stride + uv_offset, y_stride, uv_stride, 334 yd + y_offset * yd_stride + y_offset, 335 ud + uv_offset * uvd_stride + uv_offset, 336 vd + uv_offset * uvd_stride + uv_offset, yd_stride, 337 uvd_stride); 338 break; 339 default: assert(0); 340 } 341} 342 343void vp9_mfqe(VP9_COMMON *cm) { 344 int mi_row, mi_col; 345 // Current decoded frame. 346 const YV12_BUFFER_CONFIG *show = cm->frame_to_show; 347 // Last decoded frame and will store the MFQE result. 348 YV12_BUFFER_CONFIG *dest = &cm->post_proc_buffer; 349 // Loop through each super block. 350 for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE) { 351 for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE) { 352 MODE_INFO *mi; 353 MODE_INFO *mi_local = cm->mi + (mi_row * cm->mi_stride + mi_col); 354 // Motion Info in last frame. 355 MODE_INFO *mi_prev = 356 cm->postproc_state.prev_mi + (mi_row * cm->mi_stride + mi_col); 357 const uint32_t y_stride = show->y_stride; 358 const uint32_t uv_stride = show->uv_stride; 359 const uint32_t yd_stride = dest->y_stride; 360 const uint32_t uvd_stride = dest->uv_stride; 361 const uint32_t row_offset_y = mi_row << 3; 362 const uint32_t row_offset_uv = mi_row << 2; 363 const uint32_t col_offset_y = mi_col << 3; 364 const uint32_t col_offset_uv = mi_col << 2; 365 const uint8_t *y = 366 show->y_buffer + row_offset_y * y_stride + col_offset_y; 367 const uint8_t *u = 368 show->u_buffer + row_offset_uv * uv_stride + col_offset_uv; 369 const uint8_t *v = 370 show->v_buffer + row_offset_uv * uv_stride + col_offset_uv; 371 uint8_t *yd = dest->y_buffer + row_offset_y * yd_stride + col_offset_y; 372 uint8_t *ud = dest->u_buffer + row_offset_uv * uvd_stride + col_offset_uv; 373 uint8_t *vd = dest->v_buffer + row_offset_uv * uvd_stride + col_offset_uv; 374 if (frame_is_intra_only(cm)) { 375 mi = mi_prev; 376 } else { 377 mi = mi_local; 378 } 379 mfqe_partition(cm, mi, BLOCK_64X64, y, u, v, y_stride, uv_stride, yd, ud, 380 vd, yd_stride, uvd_stride); 381 } 382 } 383} 384