michael@0: /* michael@0: * Copyright (c) 2010 The WebM project authors. All Rights Reserved. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license michael@0: * that can be found in the LICENSE file in the root of the source michael@0: * tree. An additional intellectual property rights grant can be found michael@0: * in the file PATENTS. All contributing project authors may michael@0: * be found in the AUTHORS file in the root of the source tree. michael@0: */ michael@0: michael@0: michael@0: #include "variance.h" michael@0: #include "filter.h" michael@0: michael@0: michael@0: unsigned int vp8_get_mb_ss_c michael@0: ( michael@0: const short *src_ptr michael@0: ) michael@0: { michael@0: unsigned int i = 0, sum = 0; michael@0: michael@0: do michael@0: { michael@0: sum += (src_ptr[i] * src_ptr[i]); michael@0: i++; michael@0: } michael@0: while (i < 256); michael@0: michael@0: return sum; michael@0: } michael@0: michael@0: michael@0: static void variance( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: int w, michael@0: int h, michael@0: unsigned int *sse, michael@0: int *sum) michael@0: { michael@0: int i, j; michael@0: int diff; michael@0: michael@0: *sum = 0; michael@0: *sse = 0; michael@0: michael@0: for (i = 0; i < h; i++) michael@0: { michael@0: for (j = 0; j < w; j++) michael@0: { michael@0: diff = src_ptr[j] - ref_ptr[j]; michael@0: *sum += diff; michael@0: *sse += diff * diff; michael@0: } michael@0: michael@0: src_ptr += source_stride; michael@0: ref_ptr += recon_stride; michael@0: } michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_variance16x16_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: unsigned int var; michael@0: int avg; michael@0: michael@0: michael@0: variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg); michael@0: *sse = var; michael@0: return (var - (((unsigned int)avg * avg) >> 8)); michael@0: } michael@0: michael@0: unsigned int vp8_variance8x16_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: unsigned int var; michael@0: int avg; michael@0: michael@0: michael@0: variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 16, &var, &avg); michael@0: *sse = var; michael@0: return (var - (((unsigned int)avg * avg) >> 7)); michael@0: } michael@0: michael@0: unsigned int vp8_variance16x8_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: unsigned int var; michael@0: int avg; michael@0: michael@0: michael@0: variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 8, &var, &avg); michael@0: *sse = var; michael@0: return (var - (((unsigned int)avg * avg) >> 7)); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_variance8x8_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: unsigned int var; michael@0: int avg; michael@0: michael@0: michael@0: variance(src_ptr, source_stride, ref_ptr, recon_stride, 8, 8, &var, &avg); michael@0: *sse = var; michael@0: return (var - (((unsigned int)avg * avg) >> 6)); michael@0: } michael@0: michael@0: unsigned int vp8_variance4x4_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: unsigned int var; michael@0: int avg; michael@0: michael@0: michael@0: variance(src_ptr, source_stride, ref_ptr, recon_stride, 4, 4, &var, &avg); michael@0: *sse = var; michael@0: return (var - (((unsigned int)avg * avg) >> 4)); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_mse16x16_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: unsigned int var; michael@0: int avg; michael@0: michael@0: variance(src_ptr, source_stride, ref_ptr, recon_stride, 16, 16, &var, &avg); michael@0: *sse = var; michael@0: return var; michael@0: } michael@0: michael@0: michael@0: /**************************************************************************** michael@0: * michael@0: * ROUTINE : filter_block2d_bil_first_pass michael@0: * michael@0: * INPUTS : UINT8 *src_ptr : Pointer to source block. michael@0: * UINT32 src_pixels_per_line : Stride of input block. michael@0: * UINT32 pixel_step : Offset between filter input samples (see notes). michael@0: * UINT32 output_height : Input block height. michael@0: * UINT32 output_width : Input block width. michael@0: * INT32 *vp8_filter : Array of 2 bi-linear filter taps. michael@0: * michael@0: * OUTPUTS : INT32 *output_ptr : Pointer to filtered block. michael@0: * michael@0: * RETURNS : void michael@0: * michael@0: * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in michael@0: * either horizontal or vertical direction to produce the michael@0: * filtered output block. Used to implement first-pass michael@0: * of 2-D separable filter. michael@0: * michael@0: * SPECIAL NOTES : Produces INT32 output to retain precision for next pass. michael@0: * Two filter taps should sum to VP8_FILTER_WEIGHT. michael@0: * pixel_step defines whether the filter is applied michael@0: * horizontally (pixel_step=1) or vertically (pixel_step=stride). michael@0: * It defines the offset required to move from one input michael@0: * to the next. michael@0: * michael@0: ****************************************************************************/ michael@0: static void var_filter_block2d_bil_first_pass michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: unsigned short *output_ptr, michael@0: unsigned int src_pixels_per_line, michael@0: int pixel_step, michael@0: unsigned int output_height, michael@0: unsigned int output_width, michael@0: const short *vp8_filter michael@0: ) michael@0: { michael@0: unsigned int i, j; michael@0: michael@0: for (i = 0; i < output_height; i++) michael@0: { michael@0: for (j = 0; j < output_width; j++) michael@0: { michael@0: /* Apply bilinear filter */ michael@0: output_ptr[j] = (((int)src_ptr[0] * vp8_filter[0]) + michael@0: ((int)src_ptr[pixel_step] * vp8_filter[1]) + michael@0: (VP8_FILTER_WEIGHT / 2)) >> VP8_FILTER_SHIFT; michael@0: src_ptr++; michael@0: } michael@0: michael@0: /* Next row... */ michael@0: src_ptr += src_pixels_per_line - output_width; michael@0: output_ptr += output_width; michael@0: } michael@0: } michael@0: michael@0: /**************************************************************************** michael@0: * michael@0: * ROUTINE : filter_block2d_bil_second_pass michael@0: * michael@0: * INPUTS : INT32 *src_ptr : Pointer to source block. michael@0: * UINT32 src_pixels_per_line : Stride of input block. michael@0: * UINT32 pixel_step : Offset between filter input samples (see notes). michael@0: * UINT32 output_height : Input block height. michael@0: * UINT32 output_width : Input block width. michael@0: * INT32 *vp8_filter : Array of 2 bi-linear filter taps. michael@0: * michael@0: * OUTPUTS : UINT16 *output_ptr : Pointer to filtered block. michael@0: * michael@0: * RETURNS : void michael@0: * michael@0: * FUNCTION : Applies a 1-D 2-tap bi-linear filter to the source block in michael@0: * either horizontal or vertical direction to produce the michael@0: * filtered output block. Used to implement second-pass michael@0: * of 2-D separable filter. michael@0: * michael@0: * SPECIAL NOTES : Requires 32-bit input as produced by filter_block2d_bil_first_pass. michael@0: * Two filter taps should sum to VP8_FILTER_WEIGHT. michael@0: * pixel_step defines whether the filter is applied michael@0: * horizontally (pixel_step=1) or vertically (pixel_step=stride). michael@0: * It defines the offset required to move from one input michael@0: * to the next. michael@0: * michael@0: ****************************************************************************/ michael@0: static void var_filter_block2d_bil_second_pass michael@0: ( michael@0: const unsigned short *src_ptr, michael@0: unsigned char *output_ptr, michael@0: unsigned int src_pixels_per_line, michael@0: unsigned int pixel_step, michael@0: unsigned int output_height, michael@0: unsigned int output_width, michael@0: const short *vp8_filter michael@0: ) michael@0: { michael@0: unsigned int i, j; michael@0: int Temp; michael@0: michael@0: for (i = 0; i < output_height; i++) michael@0: { michael@0: for (j = 0; j < output_width; j++) michael@0: { michael@0: /* Apply filter */ michael@0: Temp = ((int)src_ptr[0] * vp8_filter[0]) + michael@0: ((int)src_ptr[pixel_step] * vp8_filter[1]) + michael@0: (VP8_FILTER_WEIGHT / 2); michael@0: output_ptr[j] = (unsigned int)(Temp >> VP8_FILTER_SHIFT); michael@0: src_ptr++; michael@0: } michael@0: michael@0: /* Next row... */ michael@0: src_ptr += src_pixels_per_line - output_width; michael@0: output_ptr += output_width; michael@0: } michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_sub_pixel_variance4x4_c michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: int src_pixels_per_line, michael@0: int xoffset, michael@0: int yoffset, michael@0: const unsigned char *dst_ptr, michael@0: int dst_pixels_per_line, michael@0: unsigned int *sse michael@0: ) michael@0: { michael@0: unsigned char temp2[20*16]; michael@0: const short *HFilter, *VFilter; michael@0: unsigned short FData3[5*4]; /* Temp data bufffer used in filtering */ michael@0: michael@0: HFilter = vp8_bilinear_filters[xoffset]; michael@0: VFilter = vp8_bilinear_filters[yoffset]; michael@0: michael@0: /* First filter 1d Horizontal */ michael@0: var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 5, 4, HFilter); michael@0: michael@0: /* Now filter Verticaly */ michael@0: var_filter_block2d_bil_second_pass(FData3, temp2, 4, 4, 4, 4, VFilter); michael@0: michael@0: return vp8_variance4x4_c(temp2, 4, dst_ptr, dst_pixels_per_line, sse); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_sub_pixel_variance8x8_c michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: int src_pixels_per_line, michael@0: int xoffset, michael@0: int yoffset, michael@0: const unsigned char *dst_ptr, michael@0: int dst_pixels_per_line, michael@0: unsigned int *sse michael@0: ) michael@0: { michael@0: unsigned short FData3[9*8]; /* Temp data bufffer used in filtering */ michael@0: unsigned char temp2[20*16]; michael@0: const short *HFilter, *VFilter; michael@0: michael@0: HFilter = vp8_bilinear_filters[xoffset]; michael@0: VFilter = vp8_bilinear_filters[yoffset]; michael@0: michael@0: var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 9, 8, HFilter); michael@0: var_filter_block2d_bil_second_pass(FData3, temp2, 8, 8, 8, 8, VFilter); michael@0: michael@0: return vp8_variance8x8_c(temp2, 8, dst_ptr, dst_pixels_per_line, sse); michael@0: } michael@0: michael@0: unsigned int vp8_sub_pixel_variance16x16_c michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: int src_pixels_per_line, michael@0: int xoffset, michael@0: int yoffset, michael@0: const unsigned char *dst_ptr, michael@0: int dst_pixels_per_line, michael@0: unsigned int *sse michael@0: ) michael@0: { michael@0: unsigned short FData3[17*16]; /* Temp data bufffer used in filtering */ michael@0: unsigned char temp2[20*16]; michael@0: const short *HFilter, *VFilter; michael@0: michael@0: HFilter = vp8_bilinear_filters[xoffset]; michael@0: VFilter = vp8_bilinear_filters[yoffset]; michael@0: michael@0: var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 17, 16, HFilter); michael@0: var_filter_block2d_bil_second_pass(FData3, temp2, 16, 16, 16, 16, VFilter); michael@0: michael@0: return vp8_variance16x16_c(temp2, 16, dst_ptr, dst_pixels_per_line, sse); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_variance_halfpixvar16x16_h_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 4, 0, michael@0: ref_ptr, recon_stride, sse); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_variance_halfpixvar16x16_v_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 0, 4, michael@0: ref_ptr, recon_stride, sse); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_variance_halfpixvar16x16_hv_c( michael@0: const unsigned char *src_ptr, michael@0: int source_stride, michael@0: const unsigned char *ref_ptr, michael@0: int recon_stride, michael@0: unsigned int *sse) michael@0: { michael@0: return vp8_sub_pixel_variance16x16_c(src_ptr, source_stride, 4, 4, michael@0: ref_ptr, recon_stride, sse); michael@0: } michael@0: michael@0: michael@0: unsigned int vp8_sub_pixel_mse16x16_c michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: int src_pixels_per_line, michael@0: int xoffset, michael@0: int yoffset, michael@0: const unsigned char *dst_ptr, michael@0: int dst_pixels_per_line, michael@0: unsigned int *sse michael@0: ) michael@0: { michael@0: vp8_sub_pixel_variance16x16_c(src_ptr, src_pixels_per_line, xoffset, yoffset, dst_ptr, dst_pixels_per_line, sse); michael@0: return *sse; michael@0: } michael@0: michael@0: unsigned int vp8_sub_pixel_variance16x8_c michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: int src_pixels_per_line, michael@0: int xoffset, michael@0: int yoffset, michael@0: const unsigned char *dst_ptr, michael@0: int dst_pixels_per_line, michael@0: unsigned int *sse michael@0: ) michael@0: { michael@0: unsigned short FData3[16*9]; /* Temp data bufffer used in filtering */ michael@0: unsigned char temp2[20*16]; michael@0: const short *HFilter, *VFilter; michael@0: michael@0: HFilter = vp8_bilinear_filters[xoffset]; michael@0: VFilter = vp8_bilinear_filters[yoffset]; michael@0: michael@0: var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 9, 16, HFilter); michael@0: var_filter_block2d_bil_second_pass(FData3, temp2, 16, 16, 8, 16, VFilter); michael@0: michael@0: return vp8_variance16x8_c(temp2, 16, dst_ptr, dst_pixels_per_line, sse); michael@0: } michael@0: michael@0: unsigned int vp8_sub_pixel_variance8x16_c michael@0: ( michael@0: const unsigned char *src_ptr, michael@0: int src_pixels_per_line, michael@0: int xoffset, michael@0: int yoffset, michael@0: const unsigned char *dst_ptr, michael@0: int dst_pixels_per_line, michael@0: unsigned int *sse michael@0: ) michael@0: { michael@0: unsigned short FData3[9*16]; /* Temp data bufffer used in filtering */ michael@0: unsigned char temp2[20*16]; michael@0: const short *HFilter, *VFilter; michael@0: michael@0: michael@0: HFilter = vp8_bilinear_filters[xoffset]; michael@0: VFilter = vp8_bilinear_filters[yoffset]; michael@0: michael@0: michael@0: var_filter_block2d_bil_first_pass(src_ptr, FData3, src_pixels_per_line, 1, 17, 8, HFilter); michael@0: var_filter_block2d_bil_second_pass(FData3, temp2, 8, 8, 16, 8, VFilter); michael@0: michael@0: return vp8_variance8x16_c(temp2, 8, dst_ptr, dst_pixels_per_line, sse); michael@0: }